Bug 84406 - [RCP] [ViewMgmt] [EditorMgmt] ISaveablePart not fully implemented
Summary: [RCP] [ViewMgmt] [EditorMgmt] ISaveablePart not fully implemented
Status: VERIFIED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 3.1   Edit
Hardware: All All
: P3 normal (vote)
Target Milestone: 3.1 RC1   Edit
Assignee: Matthew Hatem CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 43464 (view as bug list)
Depends on:
Blocks:
 
Reported: 2005-02-03 20:48 EST by Pascal Rapicault CLA
Modified: 2005-05-13 14:33 EDT (History)
5 users (show)

See Also:


Attachments
patch to fix this bug (9.78 KB, patch)
2005-05-04 09:52 EDT, Matthew Hatem CLA
no flags Details | Diff
updated patch based on Nick's feedback with some optimizations (13.19 KB, patch)
2005-05-05 09:18 EDT, Matthew Hatem CLA
no flags Details | Diff
updated patch to fix active window issues (14.55 KB, patch)
2005-05-05 16:42 EDT, Matthew Hatem CLA
no flags Details | Diff
Smaller faster patch (7.54 KB, patch)
2005-05-05 18:50 EDT, Stefan Xenos CLA
no flags Details | Diff
updated patch to fix active window issues (1.14 KB, patch)
2005-05-07 10:22 EDT, 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 Pascal Rapicault CLA 2005-02-03 20:48:00 EST
You seemed to recall that the ISaveable mechanism was not fully enabled for some obscure reasons of 
compatilibity, but that it needed to be reactivated.
Comment 1 Nick Edgar CLA 2005-02-04 10:14:40 EST
See bug 72114.  The work is to take out the requirement for:
org.eclipse.ui.workbench/fix72114=true

Also to make it work for editors (bug 37221).

Also to support doSaveAs for views.

Question: should view dirty state be indicated automatically in tab, as for editors?
Comment 2 Matthew Hatem CLA 2005-02-04 10:18:54 EST
I think dirty state indication should be a function of the Presentation so RCP 
applications can override any default behavior.
Comment 3 Pascal Rapicault CLA 2005-02-04 10:29:43 EST
For such a basic thing, it would be regrettable to force people into
presentations. However nothing should prevent presentations to overrider it.
Basically I want two mechanisms :-)
Comment 4 Nick Edgar CLA 2005-02-04 14:50:20 EST
I believe showing the dirty state is already a presentation responsibility.
Stefan, can you confirm?
Comment 5 Nick Edgar CLA 2005-02-07 17:48:27 EST
Also need to support Save All.
Comment 6 Stefan Xenos CLA 2005-02-16 12:00:05 EST
The rendering of the dirty state is a presentation responsibility.

It would make sense to render it for views as well as editors in the default
presentation.
Comment 7 Nick Edgar CLA 2005-02-18 10:06:26 EST
Bug 72114 and bug 37221 have been fixed.  Still more to do here in M6.
Comment 8 Nick Edgar CLA 2005-03-23 12:38:23 EST
Anthony and Matt, is there anything critical missing from the current support
need to support your scenarios on 3.1?

I'm moving this to M7 as I'm assuming any further changes will not require new
API.  Please shout ASAP if you think this is not the case.

Comment 9 Anthony Hunter CLA 2005-03-23 14:32:14 EST
No new API required.

I tried out ISaveablePart in M5 and editors are fine, I can now close a dirty 
editor without prompt to save by isSaveOnCloseNeeded() = false.

Views are almost there, I have isDirty() = true and isSaveOnCloseNeeded() = 
true and am prompted to save on view close, but not workbench exit.
Comment 10 Matthew Hatem CLA 2005-03-23 14:35:32 EST
I don't see a need for new API either.
Comment 11 Nick Edgar CLA 2005-04-25 15:03:45 EDT
*** Bug 43464 has been marked as a duplicate of this bug. ***
Comment 12 Matthew Hatem CLA 2005-05-04 09:52:11 EDT
Created attachment 20677 [details]
patch to fix this bug

This is the first cut of a patch to fix this bug.  Please provide feedback.
Comment 13 Nick Edgar CLA 2005-05-04 16:03:14 EDT
This patch has a few issues:

1. It will force materialization of views that were restored but not
materialized from the previous session, due to getPart(true) in the
getViews(Perspective) method.

2. It checks isSaveOnCloseNeeded on all views, not just dirty views.  This
differs from how editors are treated.

3. Save All is not fully supported (see comment 5).  Although I don't think the
current patch was intended to address this, it's pretty clear from testing it
that we should.  Although views are included in the dialog you get from Save
All, Save All is currently only enabled if there is a dirty editor.  It should
be enabled iff there are any dirty editors or views in the current perspective.

4. It doesn't look like the perspective switching for ISaveablePart2 will work
as expected, since getSortedPerspectives() returns the most recently used
perspective -last- in the list.  I assume we want it to show the most recently
used perspective showing the view, so getFirstPerspectiveWithView should look
through the list in reverse order.


(1) and (2) can be addressed together by getting the dirty views before checking
for isSaveOnCloseNeeded(), similarly to how EditorManager.getDirtyEditors does
it.  Note that collectDirtyEditors uses getPart(false) instead of getPart(true),
since a non-materialized editor cannot be dirty.  There is no way to check
isSaveOnCloseNeeded() without restoring the view.

For (3) take a look at SaveAllAction's current enablement logic.  It could be
changed to track all parts, and make use of a WorkbenchPage.getDirtyViews()
method as suggested above (though it would be more efficient to optimize this to
an isAnyPartDirty() call).
Comment 14 Nick Edgar CLA 2005-05-04 16:04:59 EDT
To test this in the IDE, you can use Window > Show View > Other... > Other >
Saveable Mock View, which comes from org.eclipse.ui.tests.
It has checkbox buttons for isDirty, isSaveOnCloseNeeded() etc.
Comment 15 Matthew Hatem CLA 2005-05-04 21:32:11 EDT
Nick thanks for the great feedback. I have updated the patch and will post it
after I run it through the gamut of tests.

To respond to 4. in comment #13, I think you have it backwards, according the
the Javadoc at least ;-)

    /**
     * Returns the perspectives in activation order (oldest first).
     * 
     * @return all open Perspective objects
     * @since 3.1
     */
Comment 16 Matthew Hatem CLA 2005-05-05 09:18:25 EDT
Created attachment 20731 [details]
updated patch based on Nick's feedback with some optimizations
Comment 17 Nick Edgar CLA 2005-05-05 09:25:57 EDT
I notice in the patch to SaveAllAction.partOpened you have a comment:
+			// We need to temporarily cache the opened part 
+			// because saveable views are not registered 
+			// with a perspective until after this method 
+			// is called.  We can't pass it through to
+			// update because it's protected. An async
+			// call to update may be a better approach
+			openPart = (ISaveablePart)part;

This should not be necessary.  The partOpened event should only be sent after
the view has been fully opened and added to the page and perspective.
If you're not seeing this, does it occur when a view is first opened, or in the
startup sequence when restoring from a previous session?
Comment 18 Matthew Hatem CLA 2005-05-05 10:01:04 EDT
I'm seeing this when the part is first opened.  The call to perspective.getViews
does not return the view that was just opened when called from
SaveAllAction.partOpened.
Comment 19 Nick Edgar CLA 2005-05-05 11:22:52 EDT
Sure enough.  I've filed bug 93784 for this problem.
Comment 20 Matthew Hatem CLA 2005-05-05 11:27:17 EDT
Does this patch/bug now depend on bug 93784?  Is there anything else about the
patch you don't like?
Comment 21 Nick Edgar CLA 2005-05-05 11:42:51 EDT
I've changed the workaround in SaveAllAction to:
        // workaround for Bug 93784 [WorkbenchParts] View not yet added to
perspective when partOpened sent
        if (openPart != null && openPart.isDirty()) {
          setEnabled(true);
        }

Previously it would disable the action if the new part was not dirty, even if
others in the page still were dirty.
Comment 22 Nick Edgar CLA 2005-05-05 11:43:37 EDT
Bug 93784 will not be addressed for 3.1, so we will leave the workaround in. 
I'm still reviewing the rest of the patch.
Comment 23 Nick Edgar CLA 2005-05-05 13:50:52 EDT
It doesn't look like EditorManager.saveAll will properly handle the case where
there are ISaveablePart2 views from windows other than window passed in
(Workbench.saveAllEditors passes in the active one, or the first one if the
active window couldn't be determined.

In particular, page.getFirstPerspectiveWithView will return null if the view is
in a different window or a different page in the same window (though the latter
is highly unlikely since 2.1).  Also, getActivePage() and getActivePerspective()
can both return null.  All of these null cases should be checked for.  Should
also talk to the part's page (part.getSite().gePage()) for revealing the part,
not the active page of the given window.

Comment 24 Nick Edgar CLA 2005-05-05 14:35:49 EDT
I've released the patches, with some extra changes to SaveAllAction and
EditorManager.saveAll to handle the issues above.

I still doubt this is properly handling the case of a dirty ISaveablePart2 in a
non-active window.  We will probably need to force the window to be activated to
show the part.  Matt, would you be able to test this case?  Might be worth
adding a new test view SaveableMockView2, extending SaveableMockView,
implementing ISaveablePart2, and with its own id.
Comment 25 Matthew Hatem CLA 2005-05-05 16:34:37 EDT
In response to comment #24

I tested the case where there are two windows.  The active window has no dirty
parts and the inactive window has some dirty parts that implement ISaveablePart2.

The results were okay but not perfect.  The custom prompt dialog and perspective
switching work as expected.  The one problem I encountered was that the window
that contains the ISaveablePart2 needs to be activiated.
Comment 26 Matthew Hatem CLA 2005-05-05 16:42:08 EDT
Created attachment 20757 [details]
updated patch to fix active window issues

This one-liner patch will address the issue of multiple windows.
Comment 27 Stefan Xenos CLA 2005-05-05 18:50:00 EDT
Created attachment 20760 [details]
Smaller faster patch

I don't like the way the existing patch introduces more special-case code for
views and editors.

Also, the search for parts runs in O(n^2 * p) worst-case time (n = number of
parts, p = number of perspectives) because of the way it iterates over all
perspectives (each of which can contain every part). This can be done in linear
time by calling WorkbenchPage.getAllParts. Performance is an issue since this
code will run on each page event.

This patch reduces the code size by merging the editor and view code paths, and
improves the runtime. 

Note that even with this patch the runtime of SaveAllAction.updateState is
still much too slow (you'll see it in part activation if a very large number of
parts are open). It should incrementally update its enablement state and never
call anything that runs in worse than constant time.
Comment 28 Stefan Xenos CLA 2005-05-05 18:55:17 EDT
Nick and Matt, I didn't want to step on your toes so I haven't committed this
patch yet. But if you approve, can one of you please do so?
Comment 29 Stefan Xenos CLA 2005-05-05 20:59:59 EDT
Btw, this change seems to have introduced a new modal dialog to the test suites,
which (at least on my machine) prevents them from finishing unless it is
manually closed.
Comment 30 Nick Edgar CLA 2005-05-06 10:23:42 EDT
None of the patches above include changes to the test suite, but I'll have a
look out for any blocking dialog.

Looking at Stefan's patch now...
Comment 31 Nick Edgar CLA 2005-05-06 10:25:35 EDT
I was going to congratulate Matt for being the first one to introduce the
"dirtyParts" variable into the Platform UI code, but I think credit has to go to
Stefan for adding the getDirtyParts() method.
Comment 32 Matthew Hatem CLA 2005-05-06 10:40:40 EDT
Stefan's patch looks great so far.  It's missing a fix for the window
activiation issue.  I've posted a patch for that.

I thought getDirtyViews would have been generally useful for EditorManager or
even WorkbenchPage.  With Stefan's patch we only have getDirtyEditors vs.
getDirtyParts.  Just my 2 cents.
Comment 33 Nick Edgar CLA 2005-05-06 10:46:38 EDT
I've applied Stefan's patch, with a minor tweak to EditorManager.saveAll to
avoid creating the list if it would be empty, and to give it the exact size
initially otherwise.  

Note that using getDirtyParts() will change the order of processing of
Workbench.saveAllEditors to process views before editors.  Previously it
processed editors before views.  But I don't think that it really matters.  I
didn't want to change the ordering in getAllParts() since it's also used when
firing the partOpened events when restoring the workbench.

If we need a getDirtyViews() in the future, we can add it.

Matt, your patch in comment 26 is not the right one.
Comment 34 Stefan Xenos CLA 2005-05-06 11:05:01 EDT
Re: comment 32

I've been working toward unifying the editor and view code paths. I hope we'll
never need to add another get*Views or get*Editors method to workbenchPage. :-)
Comment 35 Matthew Hatem CLA 2005-05-07 10:22:36 EDT
Created attachment 20801 [details]
updated patch to fix active window issues

In the previous active window patch the window would not be restored/brought to
front, if it was in a minimized state.	This revised patch should do the trick.
Comment 36 Nick Edgar CLA 2005-05-09 14:45:19 EDT
The patch does the window activation before calling page.bringToTop(part), which
could result in flicker.  I've applied the patch, but could you check this case
out Matt?
Comment 37 Nick Edgar CLA 2005-05-12 12:53:23 EDT
Waiting on response to last question to Matt.  Any further changes here will
have to wait until RC1.
Comment 38 Matthew Hatem CLA 2005-05-12 13:12:55 EDT
Nick, I don't notice any flicker at all in testing.  Thanks.
Comment 39 Nick Edgar CLA 2005-05-12 13:51:02 EDT
Closing then.  

Anthony, could you please verify in 3.1 M7 that all the issues RAD cares about
are covered?
Comment 40 Anthony Hunter CLA 2005-05-13 13:22:22 EDT
Looks good, I gave it a go and all of the issues we were looking for are 
covered and working:
- allow no prompt to save when closing a dirty editor.
- allow prompt to save when closing a dirty view.
- exit workbench prompts as appropriate from above.
Comment 41 Nick Edgar CLA 2005-05-13 14:33:54 EDT
Thanks Anthony.  Marking as verified.