Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 53748

Summary: [RCP][Workbench] StatusLineManager API is not flexible enough for RCP applications
Product: [Eclipse Project] Platform Reporter: Matthew Hatem <Matthew_Hatem>
Component: UIAssignee: Nick Edgar <n.a.edgar>
Status: RESOLVED FIXED QA Contact:
Severity: normal    
Priority: P3 CC: ed.burnette, n.a.edgar
Version: 3.0   
Target Milestone: 3.0 M8   
Hardware: PC   
OS: Windows 2000   
Whiteboard:
Attachments:
Description Flags
Fixes subclassing issues none

Description Matthew Hatem CLA 2004-03-04 10:02:12 EST
The Workbench needs to be opened up to allow more customization around the 
StatusLineManager.

We have the following requirements:

1) No hardwired controls, ie. the progress bar.  We need to supply our own 
implementation

2) Finer control over positioning of StatusLine contributions.  This can be 
done with hardwired group markers.  Something like [BEGIN | MIDDLE | END] would 
satisfy.

3) The existing StatusLineManager is not easily subclassed.  This is do to some 
references to an instance of a package private StatusLine control.

4) Last but not least, RCP applications need the ability to define their own 
implementation of the IStatusLineManager that is consumed by the 
WorkbenchWindow.
Comment 1 Matthew Hatem CLA 2004-03-04 10:17:55 EST
Sorry I could not create an attachment for some reason.  The following post 
will be the content of a patch.
Comment 2 Matthew Hatem CLA 2004-03-04 10:19:19 EST
Index: src/org/eclipse/jface/action/IStatusLineManager.java
===================================================================
retrieving revision 1.3
diff -u -r1.3 IStatusLineManager.java
--- src/org/eclipse/jface/action/IStatusLineManager.java	6 Nov 2003 
00:41:45 -0000	1.3
+++ src/org/eclipse/jface/action/IStatusLineManager.java	4 Mar 2004 
09:47:50 -0000
@@ -12,6 +12,8 @@
 
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
 
 /**
  * The <code>IStatusLineManager</code> interface provides protocol
@@ -98,4 +100,8 @@
  * @param message the message, or <code>null</code> for no message
  */
 public void setMessage(Image image, String message);
+
+
+public Control getControl();
+public Control createControl(Composite parent);
 }
Index: src/org/eclipse/jface/action/StatusLineManager.java
===================================================================
retrieving revision 1.6
diff -u -r1.6 StatusLineManager.java
--- src/org/eclipse/jface/action/StatusLineManager.java	9 Oct 2003 17:08:16 -
0000	1.6
+++ src/org/eclipse/jface/action/StatusLineManager.java	4 Mar 2004 09:47:52 -
0000
@@ -50,7 +50,7 @@
  * @param parent the parent control
  * @return the status line control
  */
-public StatusLine createControl(Composite parent) {
+public Control createControl(Composite parent) {
 	if (!statusLineExist() && parent != null) {
 		statusLine= new StatusLine(parent);
 		update(false);
Index: src/org/eclipse/jface/action/SubStatusLineManager.java
===================================================================
retrieving revision 1.4
diff -u -r1.4 SubStatusLineManager.java
--- src/org/eclipse/jface/action/SubStatusLineManager.java	22 May 2003 
19:14:34 -0000	1.4
+++ src/org/eclipse/jface/action/SubStatusLineManager.java	4 Mar 2004 
09:47:53 -0000
@@ -13,6 +13,8 @@
 
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
 
 /**
  * A <code>SubStatusLineManager</code> is used to define a set of contribution
@@ -134,5 +136,17 @@
 		// call <code>setVisible</code> and then force an update.  At 
that
 		// point we need to update the parent.
 		getParentStatusLineManager().update(force);
+	}
+	/* (non-Javadoc)
+	 * @see org.eclipse.jface.action.IStatusLineManager#createControl
(org.eclipse.swt.widgets.Composite)
+	 */
+	public Control createControl(Composite parent) {
+		return getParentStatusLineManager().createControl(parent);
+	}
+	/* (non-Javadoc)
+	 * @see org.eclipse.jface.action.IStatusLineManager#getControl()
+	 */
+	public Control getControl() {
+		return getParentStatusLineManager().getControl();
 	}
 }
Index: src/org/eclipse/jface/window/ApplicationWindow.java
===================================================================
retrieving revision 1.14
diff -u -r1.14 ApplicationWindow.java
--- src/org/eclipse/jface/window/ApplicationWindow.java	28 Feb 2004 00:06:39 -
0000	1.14
+++ src/org/eclipse/jface/window/ApplicationWindow.java	4 Mar 2004 09:47:59 -
0000
@@ -33,6 +33,7 @@
 
 import org.eclipse.jface.action.CoolBarManager;
 import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.IStatusLineManager;
 import org.eclipse.jface.action.StatusLineManager;
 import org.eclipse.jface.action.ToolBarManager;
 import org.eclipse.jface.operation.IRunnableContext;
@@ -86,7 +87,7 @@
 	 *
 	 * @see #addStatusLine
 	 */
-	private StatusLineManager statusLineManager = null;
+	private IStatusLineManager statusLineManager = null;
 	
 	/**
 	 * Cool bar manager, or <code>null</null> if none (default).
@@ -137,8 +138,8 @@
 						hide = true;
 						result.y+= BAR_SIZE;
 					}
-				}else if (statusLineManager != null && 
statusLineManager.getControl() == w) {
-				} else if (i > 0) { /* we assume this window is 
contents */
+				}
+				else if (i > 0) { /* we assume this window is 
contents */
 					hide= false;
 				}
 				
@@ -361,7 +362,7 @@
  * </p>
  * @return a status line manager
  */
-protected StatusLineManager createStatusLineManager() {
+protected IStatusLineManager createStatusLineManager() {
 	return new StatusLineManager();
 }
 /**
@@ -450,7 +451,7 @@
  *   this window does not have a status line
  * @see #addStatusLine
  */
-protected StatusLineManager getStatusLineManager() {
+protected IStatusLineManager getStatusLineManager() {
 	return statusLineManager;
 }
 
@@ -523,7 +524,7 @@
 public void run(final boolean fork, boolean cancelable, final 
IRunnableWithProgress runnable) throws InvocationTargetException, 
InterruptedException {
 	try {
 		operationInProgress = true;
-		final StatusLineManager mgr = getStatusLineManager();
+		final IStatusLineManager mgr = getStatusLineManager();
 		if (mgr == null) {
 			runnable.run(new NullProgressMonitor());
 			return;
Index: Eclipse UI/org/eclipse/ui/internal/WorkbenchWindow.java
===================================================================
retrieving revision 1.175
diff -u -r1.175 WorkbenchWindow.java
--- Eclipse UI/org/eclipse/ui/internal/WorkbenchWindow.java	1 Mar 2004 
19:03:43 -0000	1.175
+++ Eclipse UI/org/eclipse/ui/internal/WorkbenchWindow.java	4 Mar 2004 
09:46:01 -0000
@@ -28,9 +28,9 @@
 import org.eclipse.jface.action.IContributionItem;
 import org.eclipse.jface.action.IContributionManager;
 import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IStatusLineManager;
 import org.eclipse.jface.action.MenuManager;
 import org.eclipse.jface.action.Separator;
-import org.eclipse.jface.action.StatusLineManager;
 import org.eclipse.jface.action.ToolBarContributionItem;
 import org.eclipse.jface.action.ToolBarManager;
 import org.eclipse.jface.operation.IRunnableWithProgress;
@@ -851,7 +851,7 @@
 	 *   this window does not have a status line
 	 * @see #addStatusLine
 	 */
-	public StatusLineManager getStatusLineManager() {
+	public IStatusLineManager getStatusLineManager() {
 		return super.getStatusLineManager();
 	}
 
Comment 3 Matthew Hatem CLA 2004-03-04 10:20:20 EST
This patch address issue 3, subclassing.
Comment 4 Ed Burnette CLA 2004-03-04 22:00:16 EST
I like this idea too.

Somebody should nominate Matthew for committer, it would save a lot of time.
Comment 5 Nick Edgar CLA 2004-03-05 10:11:41 EST
Padwan must learn about breaking API changes <g>.  Matt, sorry but we can't 
accept the patch as-is because it breaks several API methods by changing the 
return type.  This breaks callers as well as overriders.  Also, adding methods 
to interfaces that don't say "This interface is not intended to be implemented 
by clients" is also a breaking change to existing implementors.

I'm OK with adding a creation method to the interface, but this will have to be 
done by introducing a new interface like IStatusLineManager2 or a mix-in 
interface like IContributionManagerControlCreation.  Instead of passing the 
style bits into the constructor of the manager, I think these should get passed 
to the createControl method.  This would also avoid conflicting with the 
existing createControl methods.
Comment 6 Matthew Hatem CLA 2004-03-06 06:37:52 EST
I'm sorry Obi; I should have explained the patch in more detail.

First off, I would never have expected something like this to get committed.  
It's more or less a preview of how we would like to see the statusline code 
evolve.  And how it should have been done in the first place <g>.

Second, yes this is an API breakage, but the API is already broken.  The return 
type for createControl is package private.  A public method that is API should 
never have a return type that is package private.  And it's impossible to 
subclass this thing because of that.  You might as well remove the comment from 
the javadoc.  I'd be very surprised if anyone out there is subclassing this 
thing. 

I hear you on the additional methods but I had already broken (actually fixed) 
the API with createControl.

Future patches will not have API breakages (fixes <g>).

-m@

Comment 7 Nick Edgar CLA 2004-03-09 11:22:29 EST
The force is strong in you.  Your assessment of the problems with the current 
APIs is bang on.  However, we still can't break existing clients.  The only 
clients that should be affected by the ApplicationWindow and StatusLineManager 
changes are standalone JFace clients, not Workbench clients, but there are 
people out there using JFace standalone.

I think it would make sense to align this with the work to separate out part 
presentations (bug 53673).  For example, we could add the following to 
AbstractPresentationFactory:

public IStatusLineManager createWindowStatusLineManager();
public Control createWindowStatusLineControl(IStatusLineManager);

With these two methods, we give the app flexibility over which manager 
implementation it uses, and which controls it creates, without having to define 
new API for IStatusLineManager.

Comment 8 Nick Edgar CLA 2004-03-09 11:24:08 EST
Would it suffice just to change the return type of 
StatusLineManager.createControl to be Control?  Since StatusLine is package-
private, nobody other than JFace can be calling this now anyway so I wouldn't 
consider this to be a breaking API change.

Comment 9 Matthew Hatem CLA 2004-03-10 01:57:14 EST
Changing the return type is a good start <g>.  What do you think about an 
abstract StatusLine control?  We could make all public methods on the existing 
StatusLine abstract.  I don't think this breaks API.  

So what does this solve.  Currently, if a StatusLineManager subclass refers to 
a status delegate that is not of type StatusLine, the subclass would need to 
override just about every method that referred to the StatusLine.  This is not 
good, I'd hate to have to rewrite update(boolean) from scratch <g>.

I'll provide a patch that will hopefully provide some clarity.

The above does not completely address 1 and 2, but the presentation API can 
probably solve 4.

-m@
Comment 10 Nick Edgar CLA 2004-03-10 10:29:37 EST
For 1, I see this as the same as 3.  We need a default implementation that 
fully implements the IStatusLineManager contract, including getProgressMonitor
().

For 2, I like the suggestion and we should just add it to the base.  Can you 
contribute this?

For 3, if the statusLine field is changed to be Composite, and the return type 
of createControl changed to Control, then StatusLineManager becomes easily 
subclassable and you don't need to reimplement update.  Having an abstract 
StatusLine control would allow for more code sharing though.  I'm fine with 
that approach.

For 4, we will add the ability to provide a different status line manager in 
the presentation factory.
Comment 11 Matthew Hatem CLA 2004-03-10 18:34:26 EST
> For 2, I like the suggestion and we should just add it to the base.  Can you 
contribute this?

Yes.  I'd be happy to.

And I'll take the abstract StatusLine approach and provide a separate patch for 
that.

-m@
Comment 12 Matthew Hatem CLA 2004-03-11 12:49:18 EST
Created attachment 8512 [details]
Fixes subclassing issues

This patch should address all of the subclassing issues without breaking API.  


Nick, you may not like the following.

1) getProgressMonitorDelegate - this was added to allow us to share as much
code as possible.  A new IProgressMonitorDelegate may allow us to share even
more code.  I'm okay with removing this new method, we'll just have to rewrite
the getProgressMonitor() method, sigh...

2) the naming convention for the default group markers.  I'm fine with changing
the names to whatever you see fit.

I'm still looking into refactoring the StatusLine control.  I'm investigating
how much code we can actually share from this class.  It may be pointless.
Comment 13 Nick Edgar CLA 2004-03-11 22:56:12 EST
The following are other problems that will need to be addressed to allow 
subclassing:

- update assumes that there are 3 special controls being created by StatusLine

- StatusLine uses StatusLineLayout as its layout.  This expects 
StatusLineLayoutData (or null) from getLayoutData() on the controls in the 
status line (whether from StatusLine or ContributionItems).  Some existing 
contribution items refer to StatusLineLayoutData, e.g. 
org.eclipse.ui.texteditor.StatusLineContributionItem.  This prevents 
subclassers of StatusLineManager from using different layouts in their 
Composite.  It would be better for StatusLineLayout to just use 
Control.computeSize on the child controls.

Comment 14 Nick Edgar CLA 2004-03-12 01:52:48 EST
Patch released.  Leaving open to address 4.
Comment 15 Nick Edgar CLA 2004-03-12 01:54:10 EST
Note: the fix for bug 54436 has removed the magic number 3 from update().
Comment 16 Nick Edgar CLA 2004-03-12 05:21:34 EST
Released enhancement for 4.
See:
- IWorkbenchWindowConfigurer.setPresentationFactory
(AbstractPresentationFactory) 
AbstractPresentationFactory.createStatusLineManager()
AbstractPresentationFactory.createStatusLineControl(IStatusLineManager, 
Composite)
Comment 17 Nick Edgar CLA 2004-03-12 05:23:10 EST
Matt, what are your thoughts about StatusLineLayoutData on comment #13?
I'm hoping this is something we can defer.

Comment 18 Matthew Hatem CLA 2004-03-12 10:04:40 EST
Re comment 17 and 13, yes I think this is something that we can defer.  Seems 
like it will be up to the subclass to honor the LayoutData for contributions 
that use it. A simple computeSize() should work in most cases.  

I don't think we have fully addressed issue 1).  This is my fault.  I'm looking 
into pulling the 3 hard-wired controls out of the StatusLine and wrapping them 
into a SubStatusLine contribution.  Subclasses can omit or replace this with 
their own implementation.  What do you think?  I would like to do this without 
forcing clients to reinvent StatusLine.  Are you open to a new interface?  This 
interface would provide the following:

isCancelEnabled()
setCancelEnabled(boolean)
setErrorMessage(String)
setErrorMessage(Image, String)
setMessage(String)
setMessage(Image, String)
clearProgress()
setProgressMessage(String)

It could extend IProgressMonitor and be obtained through 
getProgressMonitorDelegate.  Do you consider this an API breakage? 
getProgressMonitorDelegate hasn't been around for too long. <g>

-m@
Comment 19 Ed Burnette CLA 2004-03-12 10:17:58 EST
I was wondering, what's going on with the status line in recent I builds? 
There seems to be essentially two progress bars, one for foreground activities 
(native progress with a big red square stop button) and one for background 
activities (in an inset window, used to be floating but now in the status 
bar). Is there a plan to simplify this in the IDE and does that impact the new 
API being discussed?
Comment 20 Nick Edgar CLA 2004-03-12 11:21:24 EST
Using contribution items instead of a StatusLine makes sense.  I think the real 
problem is that you may want to allow client contributions to get placed 
relative to the message control, progress control and cancel control 
independently (they don't need to be grouped together).

I don't think SubContributionItem is the right approach though.  That is a 
goofy interface intended to be used with SubContributionManagers for 
virtualizing contribution managers between the workbench and regular plugins.

Perhaps the way the Workbench does it would work, where the app gets to 
contribute items first, then regular plugins get to contribution items relative 
to those.  Except in this case, this would be done in StatusLineManager itself, 
but in a way that's subclassable.
Comment 21 Nick Edgar CLA 2004-03-14 22:04:29 EST
Re comment #19, various approaches have been tried, including overloading the 
main status line (there are some vestigial traces of this in 
IStatusLineWithProgressManager, which StatusLineManager implements, but this 
should be removed as it is not currently used by the background progress 
reporting mechanism).  

The current progress reporting mechanism is likely to be the final shape for 
3.0.  Even if it changes, the impact on IStatusLineManager and subclassing 
decisions would be minimal.  

If you have concerns about how progress reporting for background jobs is being 
done, please enter a separate bug report, or add your comments to one of the 
existing ones like bug 54748.
Comment 22 Nick Edgar CLA 2004-03-14 22:07:14 EST
Matt, given all the other loose ends that need to be tied up for M8, I suggest 
we stick with what we have now here, assuming that the patch you've contributed 
give you enough flexibility to change things in a subclass if needed.

Please reopen if you disagree.
Comment 23 Nick Edgar CLA 2004-03-23 14:23:13 EST
No further work planned here for 3.0.  Please open new PRs if there are other
issues with the status line manager for RCP apps.