Bug 76768 - [RCP] [ViewMgmt] [EditorMgmt] Need ability to provide custom save prompt when view implements ISaveablePart
Summary: [RCP] [ViewMgmt] [EditorMgmt] Need ability to provide custom save prompt when...
Status: VERIFIED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 3.0.1   Edit
Hardware: PC Windows 2000
: P3 normal (vote)
Target Milestone: 3.1 M6   Edit
Assignee: Tod Creasey CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2004-10-21 15:05 EDT by Matthew Hatem CLA
Modified: 2005-03-31 12:57 EST (History)
5 users (show)

See Also:


Attachments
allows for custom prompt dialog (4.43 KB, patch)
2004-10-21 15:06 EDT, Matthew Hatem CLA
no flags Details | Diff
Preliminary patch for feedback (7.04 KB, patch)
2005-02-17 14:01 EST, Matthew Hatem CLA
no flags Details | Diff
Updated patch to check against head (23.57 KB, patch)
2005-03-07 14:55 EST, Matthew Hatem CLA
no flags Details | Diff
zip file containing changed files (17.37 KB, application/zip)
2005-03-08 10:10 EST, Matthew Hatem CLA
no flags Details
Updated patch to check against head for 03142005 (9.39 KB, patch)
2005-03-14 11:25 EST, Matthew Hatem CLA
no flags Details | Diff
Updated patch to check against head for 03142005 (7.31 KB, patch)
2005-03-14 13:10 EST, Matthew Hatem CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Matthew Hatem CLA 2004-10-21 15:05:34 EDT
Our RCP applications need the ability to provide an application defined custom
dialog when prompting the user to save.

This is specific to ViewParts that implement the ISaveablePart interface.  Patch
to follow.
Comment 1 Matthew Hatem CLA 2004-10-21 15:06:34 EDT
Created attachment 15335 [details]
allows for custom prompt dialog
Comment 2 Matthew Hatem CLA 2004-10-21 15:07:36 EDT
See also bug #72114
Comment 3 Kim Horne CLA 2004-10-21 15:29:05 EDT
Just looking at the patch... you've patched the project file to change the name.  
Comment 4 Nick Edgar CLA 2004-10-21 15:29:44 EDT
To look at for 3.1 M4.
Comment 5 Nick Edgar CLA 2004-12-10 21:22:40 EST
If we allow this for views, should also allow it for editors.
Need to also handle the case where the workbench prompts for multiple editors at
the same time (e.g. close all when multiple editors have unsaved changes).  
In this case, we'll either need to change to prompting for each part separately,
instead of using a single dialog for multiple editors, or come up with some
other way of handling batching in a pluggable way (e.g. delegate to a handler
specified on the editor type extension?)

Comment 6 Nick Edgar CLA 2004-12-14 22:00:49 EST
Sorry, wasn't able to get to this for M4.

In the attached patch, prompt() is responsible not only for prompting, but for
doing the save() as well.  Is this necessary? Can we leave the actual saving up
to the workbench, or are there aspects of this (e.g. progress monitoring labels)
that would need to be customizeable as well)?

If they can't be separated, then we should be more explicit in method names that
it takes over the whole saving process, not just the prompting.
Comment 7 Matthew Hatem CLA 2004-12-15 11:04:26 EST
In response to #5, yes this should apply to editors as well.

During Workbench shutdown the expected behavior (at least for our RCP apps) is 
to prompt the user for each dirty editor/view, switch perspectives as needed.  
We have code to do this in our WorkbenchAdvisor but it's not as robust as we 
would like.  We keep a list of parts that implement ISaveablePart via part 
activation listeners.

In response to #6, yes I think implementors of ISaveablePartWithPrompt should 
be responsible for all cases resulting from the prompt.  In some cases "save" 
is appropriate, in others there may be cases where "send" or "save as draft" 
type actions need to take place.  If we left the "save" up to the Workbench 
how difficult would it be for ISaveablePartWithPrompt implementors to manage 
these different actions?

I can code up some test cases for this including the code mentioned in 
response to comment #5.
Comment 8 Nick Edgar CLA 2004-12-15 13:00:42 EST
The main reason for wanting to keep going through doSave(IProgressMonitor) was
to allow the workbench to take care of how progress is handled, without
requiring each part to do this.  Even if at the UI level the operation is called
"Send", it would be good to have some common support for saving the contents of
an editor/view.

Tracking which views are in which perspectives via listeners is likely to be
tricky.  I suggest iterating over all perspectives in activation order using
(from WorkbenchPage) perspList.getSortedPerspectives(), then iterating over the
views using Perspective.getViewReferences() and IViewReference.getView(false). 
Use false to avoid forcing creation of the view.  If the view hasn't been
created, it can't have changes.
Comment 9 Nick Edgar CLA 2005-02-09 13:31:29 EST
I propose the following changes:
- rename to ISaveablePart2 (extends ISaveablePart)
- clarify the API that it's determining whether to save on close, and is only
called if the part is dirty
- allow a 3-state return value:
YES: save the part and proceed with close (using the existing doSave API and
progress monitor support)
NO: close the part without saving
CANCEL: cancel the close

This will also allow us to address the problem with editors' handling of
isSaveOnCloseNeeded() described in bug 37221 comment 7.  Instead of implementing
isSaveOnCloseNeeded() to return false, the editor could just implement
ISaveablePart2 and return NO.  We would then likely just deprecate
isSaveOnCloseNeeded() (for both views and editors).
Comment 10 Nick Edgar CLA 2005-02-09 13:38:47 EST
This also needs to handle the WorkbenchPage.closeEditors(IEditorReference[]
editorRefs, boolean save) case (used by File > Close All), where multiple
editors are processed simultaneously using a single dialog currently.
One option would be first process any that implement ISaveablePart2, and then
only include those that return YES in the dialog.

Also need to ensure the prompt to save on window close or shutdown works the
same way (I'm not positive it goes through this method).
Comment 11 Matthew Hatem CLA 2005-02-10 12:49:08 EST
Question about default handling of return codes.  Currently the default is
"cancel".  In order for the Workbench to protect itself from bad return codes
from implementers of ISaveablePart2, we should either change the default to "no"
or provide a typesafe enum for return codes.  Parts that returned a value
outside of yes|no|cancel would either prevent a user from closing a part or
prevent the Workbench from shutting down.  

Providing typesafe enum may be overkill.  Moving the default is not risky since
it doesn't look like "default" is ever hit.  Thoughts?

SaveableHelper.java

static boolean savePart(......
.....
switch (choice) {
	case 0 : //yes
		break;
	case 1 : //no
		return true;
	default :
	case 2 : //cancel
		return false;
}
Comment 12 Nick Edgar CLA 2005-02-10 14:07:50 EST
I don't think the default case can get hit currently.
Changing the default to NO would be fine.
Since we don't use type safe enums anywhere else, let's not start now.
Comment 13 Nick Edgar CLA 2005-02-11 00:04:47 EST
Suggest calling the method promptToSaveOnClose() instead of just prompt() or
doPrompt().

We should add a DEFAULT or UNHANDLED result, which would have the same effect as
if the part did not implement ISaveablePart2, and make this the default case in
the switch.
This way, if other API gets added to ISaveablePart2, or yet another extension
interface is added, clients can still get the default behaviour and aren't
forced to handle the prompting themselves.
Comment 14 Matthew Hatem CLA 2005-02-11 11:23:40 EST
In response to comment #13

>> This way, if other API gets added to ISaveablePart2, or yet another 
extension interface is added, clients can still get the default behaviour and 
aren't forced to handle the prompting themselves.

Wouldn't an Adapter class make more sense for those cases?


Comment 15 Matthew Hatem CLA 2005-02-11 12:30:44 EST
Re comment #11 and comment #12

>> don't think the default case can get hit currently.

This is not true.  Open a file, make a change then close it without saving.  
When the save prompt is presented, close it using the close button in the 
title bar of the dialog.  The return code in this case is a -1.  The default 
is then hit and results in a cancel event.
Comment 16 Matthew Hatem CLA 2005-02-11 13:07:09 EST
So should the Workbench protect itself from parts that do not provide the 
proper return codes or parts that always return a cancel return code?

A part that always returned a cancel return code would do two things, 1) it 
would prevent the part from ever being closed once open and dirty and 2) would 
prevent the Workbench from ever shutting down.

We could do something like the following to protect against these cases:

A) Enable support for ISaveablePart2 via a protected product level ini setting.

B) SaveableHelper will always provide the actions for Cancel and 
No/Close/Dismiss.  The implementers of ISaveablePart2 will only be able to 
provide the other "save-like" actions.  Either through a getter on 
ISaveablePart2 or through an extension point.  

In my opinion A seems simple and allows for more customization, eg. the dialog 
doesn't have to be an SWT dialog.  B may be overkill, paticularly the 
extension point options, but seems more safe since the Workbench keeps 
ownership of some critical actions.

Thoughts?
Comment 17 Matthew Hatem CLA 2005-02-11 13:27:46 EST
Just revisted comment #9

>> Instead of implementing isSaveOnCloseNeeded() to return false, the editor 
could just implement ISaveablePart2 and return NO.  We would then likely just 
deprecate isSaveOnCloseNeeded() (for both views and editors).

Option B metioned in comment #16 would preclude us from doing the above.
Comment 18 Nick Edgar CLA 2005-02-11 18:06:35 EST
I don't think we should worry too much about the scenario in comment 16.
Both A and B sound unnecessarily complex to me.  If we're going to allow the
part to override the close policy, then we're going to have to trust that they
won't do something silly like always return CANCEL.  This isn't the only
opportunity for wayward parts to hose the environment.

I'd also like to phrase the API in such a way that the part isn't required to
bring up a dialog.  It may be that it just wants to take care of the save
silently itself, or always return NO, or whatever.
Comment 19 Nick Edgar CLA 2005-02-11 18:07:27 EST
> Wouldn't an Adapter class make more sense for those cases?

Actually, it probably makes sense in this case too.
Comment 20 Nick Edgar CLA 2005-02-16 00:18:58 EST
Deferring to M6.  Matt to supply updated patch.
Comment 21 Matthew Hatem CLA 2005-02-17 14:01:46 EST
Created attachment 18061 [details]
Preliminary patch for feedback

This patch introduces the ISaveablePart2 interface and supports "close all" and
"close/save all on shutdown" for editors only.

This patch is missing shutdown support for Views that implement ISaveablePart2.
 Patch for that to follow.
Comment 22 Nick Edgar CLA 2005-02-17 23:20:09 EST
Thanks Matt.  Tod, could you please review this patch?
Comment 23 Tod Creasey CLA 2005-03-07 12:37:08 EST
Matt this patch is out of date. Could you update it with one that I can check
against HEAD?
Comment 24 Matthew Hatem CLA 2005-03-07 14:55:05 EST
Created attachment 18505 [details]
Updated patch to check against head
Comment 25 Tod Creasey CLA 2005-03-07 16:09:35 EST
Matt I still can't apply this patch to workbench or org.eclipse.ui.internal.
Could you maybe just export the 3 classes to a zip?
Comment 26 Matthew Hatem CLA 2005-03-08 10:10:59 EST
Created attachment 18533 [details]
zip file containing changed files
Comment 27 Matthew Hatem CLA 2005-03-14 10:08:12 EST
Any updates here?  I would like to move forward with support for "save on close"
for saveable view parts that implement ISaveablePart2 but would like some
feedback on the previous patch before I do.

Thanks
Comment 28 Tod Creasey CLA 2005-03-14 10:36:18 EST
Matt I have the following errors when I apply your changes

Severity	Description	Resource	In Folder	Location	Creation Time
2	The method openEditor(IEditorReference, IEditorReference[], boolean) is
undefined for the type EditorAreaHelper	EditorManager.java
org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal	line 773	March 14,
2005 10:32:12 AM
2	The method openEditor(IEditorReference, boolean) is undefined for the type
EditorAreaHelper	EditorManager.java	org.eclipse.ui.workbench/Eclipse
UI/org/eclipse/ui/internal	line 778	March 14, 2005 10:32:12 AM
2	WorkbenchMessages.EditorManager_unableToInitialize cannot be resolved
EditorManager.java	org.eclipse.ui.workbench/Eclipse
UI/org/eclipse/ui/internal	line 820	March 14, 2005 10:32:12 AM
2	WorkbenchMessages.EditorManager_unableToInstantiate cannot be resolved
EditorManager.java	org.eclipse.ui.workbench/Eclipse
UI/org/eclipse/ui/internal	line 902	March 14, 2005 10:32:12 AM
2	The method createChildControl() is undefined for the type PartPane
EditorManager.java	org.eclipse.ui.workbench/Eclipse
UI/org/eclipse/ui/internal	line 1097	March 14, 2005 10:32:12 AM
2	The method createChildControl() is undefined for the type PartPane
EditorManager.java	org.eclipse.ui.workbench/Eclipse
UI/org/eclipse/ui/internal	line 1101	March 14, 2005 10:32:12 AM
2	The type EditorManager.Editor must implement the inherited abstract method
WorkbenchPartReference.createPane()	EditorManager.java
org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal	line 1339	March 14,
2005 10:32:12 AM
2	The method setPane(PartPane) is undefined for the type EditorManager.Editor
EditorManager.java	org.eclipse.ui.workbench/Eclipse
UI/org/eclipse/ui/internal	line 1491	March 14, 2005 10:32:12 AM
Comment 29 Matthew Hatem CLA 2005-03-14 11:25:59 EST
Created attachment 18768 [details]
Updated patch to check against head for 03142005

Tod, this patch should do the trick if you apply it right..........now ;-)
Comment 30 Tod Creasey CLA 2005-03-14 11:35:55 EST
Matt the patch won't load SaveablePart. Lets try the zip again
Comment 31 Matthew Hatem CLA 2005-03-14 13:03:59 EST
Can you explain what you mean by "wont load SaveablePart"?  I think you mean
SaveableHelper, I'll fix up the patch.  Any ideas why this is happening?

Comment 32 Matthew Hatem CLA 2005-03-14 13:10:37 EST
Created attachment 18771 [details]
Updated patch to check against head for 03142005

This patch works for sure, tested it myself ;-)  

I will remember to test my patches before I submit them.
I will remember to test my patches before I submit them.
I will remember to test my patches before I submit them.
.....
Comment 33 Tod Creasey CLA 2005-03-14 13:51:25 EST
Sorry - I meant SaveableHelper. Send me the files again - the patches don't seem
to be doing it.
Comment 34 Tod Creasey CLA 2005-03-14 13:58:33 EST
OK that worked! Looks fine to me - the only thing I would mention is that
SaveablePart has the code

if (choice == -1) {				
   if (saveable instanceof ISaveablePart2) {
      choice = ((ISaveablePart2)saveable).promptToSaveOnClose();
   }
   if (choice == -1 || choice == ISaveablePart2.DEFAULT

I would make the -1 some sort of constant
Comment 35 Tod Creasey CLA 2005-03-14 13:59:08 EST
Sorry - slip of the button
Comment 36 Tod Creasey CLA 2005-03-14 13:59:52 EST
Patch released to build 20050315
Comment 37 Tod Creasey CLA 2005-03-30 11:38:12 EST
Matt please verify
Comment 38 Matthew Hatem CLA 2005-03-31 12:57:58 EST
Verified in I20050330-0500