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

Bug 470076

Summary: The save dialog appears twice when exiting eclipse
Product: [Eclipse Project] Platform Reporter: Mickael LANOE <mickael.lanoe>
Component: UIAssignee: Andrey Loskutov <loskutov>
Status: RESOLVED FIXED QA Contact:
Severity: normal    
Priority: P3 CC: loskutov, matt.casson, pierre-charles.david
Version: 4.5.1Keywords: triaged
Target Milestone: 4.7 M1   
Hardware: PC   
OS: All   
See Also: https://bugs.eclipse.org/bugs/show_bug.cgi?id=372799
https://git.eclipse.org/r/75026
https://git.eclipse.org/c/platform/eclipse.platform.ui.git/commit/?id=2c81696b9663068043a850fd9278fff5e0d03804
Whiteboard:

Description Mickael LANOE CLA 2015-06-12 10:06:06 EDT
Steps to reproduce:

- Modify a representation
- Close Eclipse
- The save dialog appears, click on 'No' -> The save dialog appears a second time
Comment 1 Pierre-Charles David CLA 2015-06-16 06:00:35 EDT
Confirmed. Here is the stack which leads to the dialog. I get the exact same stack both times.

Thread [main] (Suspended (breakpoint at line 505 in org.eclipse.sirius.common.ui.tools.api.util.SWTUtil))	
	org.eclipse.sirius.common.ui.tools.api.util.SWTUtil.createSaveDialog(java.lang.String, boolean, java.util.Map<java.lang.String,java.lang.Integer>, boolean, org.eclipse.ui.IWorkbenchWindow) line: 505	
	org.eclipse.sirius.common.ui.tools.api.util.SWTUtil.openSaveDialog(java.lang.String, boolean, java.util.Map<java.lang.String,java.lang.Integer>, boolean) line: 465	
	org.eclipse.sirius.common.ui.tools.api.util.SWTUtil.showStandardSaveDialog(java.lang.String, boolean, boolean) line: 444	
	org.eclipse.sirius.common.ui.tools.api.util.SWTUtil.access$1(java.lang.String, boolean, boolean) line: 437	
	org.eclipse.sirius.common.ui.tools.api.util.SWTUtil$1.run() line: 375	
	org.eclipse.ui.internal.UISynchronizer(org.eclipse.swt.widgets.Synchronizer).syncExec(java.lang.Runnable) line: 186	
	org.eclipse.ui.internal.UISynchronizer.syncExec(java.lang.Runnable) line: 145	
	org.eclipse.swt.widgets.Display.syncExec(java.lang.Runnable) line: 4633	
	org.eclipse.sirius.common.ui.tools.api.util.SWTUtil.showSaveDialog(java.lang.Object, java.lang.String, boolean, boolean, boolean) line: 384	
	org.eclipse.sirius.ui.business.internal.session.EditingSession.promptToSaveOnClose() line: 254	
	org.eclipse.sirius.diagram.ui.tools.internal.editor.DDiagramEditorImpl.promptToSaveOnClose() line: 1895	
	org.eclipse.ui.internal.SaveableHelper.savePart(org.eclipse.ui.ISaveablePart2, org.eclipse.ui.IWorkbenchWindow, boolean) line: 239	
	org.eclipse.ui.internal.WorkbenchPage.processSaveable2(java.util.List<org.eclipse.ui.IWorkbenchPart>) line: 3703	
	org.eclipse.ui.internal.WorkbenchPage.saveAll(java.util.List<org.eclipse.ui.IWorkbenchPart>, boolean, boolean, boolean, org.eclipse.jface.operation.IRunnableContext, org.eclipse.ui.IWorkbenchWindow) line: 3638	
	org.eclipse.ui.internal.Workbench.saveAllEditors(boolean, boolean) line: 1378	
	org.eclipse.ui.internal.Workbench.busyClose(boolean) line: 1091	
	org.eclipse.ui.internal.Workbench.access$21(org.eclipse.ui.internal.Workbench, boolean) line: 1073	
	org.eclipse.ui.internal.Workbench$19.run() line: 1414	
	org.eclipse.swt.custom.BusyIndicator.showWhile(org.eclipse.swt.widgets.Display, java.lang.Runnable) line: 70	
	org.eclipse.ui.internal.Workbench.close(int, boolean) line: 1411	
	org.eclipse.ui.internal.Workbench.close() line: 1384	
	org.eclipse.ui.internal.WorkbenchWindow.busyClose(boolean) line: 1571	
	org.eclipse.ui.internal.WorkbenchWindow.access$16(org.eclipse.ui.internal.WorkbenchWindow, boolean) line: 1542	
	org.eclipse.ui.internal.WorkbenchWindow$11.run() line: 1603	
	org.eclipse.swt.custom.BusyIndicator.showWhile(org.eclipse.swt.widgets.Display, java.lang.Runnable) line: 70	
	org.eclipse.ui.internal.WorkbenchWindow.close(boolean) line: 1600	
	org.eclipse.ui.internal.WorkbenchWindow.close() line: 1614	
	org.eclipse.ui.internal.WorkbenchWindow$6.close(org.eclipse.e4.ui.model.application.ui.basic.MWindow) line: 523	
	org.eclipse.e4.ui.workbench.renderers.swt.WBWRenderer$7.shellClosed(org.eclipse.swt.events.ShellEvent) line: 518	
	org.eclipse.swt.widgets.TypedListener.handleEvent(org.eclipse.swt.widgets.Event) line: 98	
	org.eclipse.swt.widgets.EventTable.sendEvent(org.eclipse.swt.widgets.Event) line: 84	
	org.eclipse.swt.widgets.Display.sendEvent(org.eclipse.swt.widgets.EventTable, org.eclipse.swt.widgets.Event) line: 4481	
	org.eclipse.swt.widgets.Shell(org.eclipse.swt.widgets.Widget).sendEvent(org.eclipse.swt.widgets.Event) line: 1327	
	org.eclipse.swt.widgets.Shell(org.eclipse.swt.widgets.Widget).sendEvent(int, org.eclipse.swt.widgets.Event, boolean) line: 1351	
	org.eclipse.swt.widgets.Shell(org.eclipse.swt.widgets.Widget).sendEvent(int, org.eclipse.swt.widgets.Event) line: 1336	
	org.eclipse.swt.widgets.Shell.closeWidget() line: 654
Comment 2 Pierre-Charles David CLA 2015-06-16 08:29:52 EDT
Analysis: WorkbenchPage.processSaveable2() is called with 2 dirtyParts: the DDiagramEditorImpl (OK), and the PropertySheet (?). It loops over them, triggers the popup for DDiagramEditorImpl (which is its own ISaveablePart2), then asks the second dirtyPart (the PropertySheet) for its ISaveablePart2, which is the DDiagramEditorImpl. Because the user answered "No" to the first popup, the editors asks the question again.
Comment 3 Pierre-Charles David CLA 2015-06-16 08:48:51 EDT
The problem seems specific to Mars: I get only one popup with Luna SR2.
Comment 4 Pierre-Charles David CLA 2015-06-16 09:01:18 EDT
The root cause seems to be a change in WorkbenchPage.getDirtyParts():

// Luna
public ISaveablePart[] getDirtyParts() {
	List result = new ArrayList(3);
	IWorkbenchPartReference[] allParts = getSortedParts();
	for (int i = 0; i < allParts.length; i++) {
		IWorkbenchPartReference reference = allParts[i];

		IWorkbenchPart part = reference.getPart(false);
		if (part != null && part instanceof ISaveablePart) {
			ISaveablePart saveable = (ISaveablePart) part;
			if (saveable.isDirty()) {
				result.add(saveable);
			}
		}
	}

	return (ISaveablePart[]) result.toArray(new ISaveablePart[result.size()]);
}

// Mars
public ISaveablePart[] getDirtyParts() {
	List<ISaveablePart> result = new ArrayList<ISaveablePart>(3);
	IWorkbenchPartReference[] allParts = getSortedParts(true, true, true);
	for (int i = 0; i < allParts.length; i++) {
		IWorkbenchPartReference reference = allParts[i];
		IWorkbenchPart part = reference.getPart(false);
		ISaveablePart saveable = SaveableHelper.getSaveable(part);
		if (saveable != null) {
			if (saveable.isDirty()) {
				result.add(saveable);
			}
		}
	}
	return result.toArray(new ISaveablePart[result.size()]);
}

The test in Luna is a plain "part instanceof ISaveablePart", which is false for the PropertySheet. In Mars it tries to be smarter by calling SaveableHelper.getSaveable(part), which returns a non-null value (in our case the DDiagramEditorImpl). Not sure if this is a regression/unintended side-effect in the platform, or if we need to be smarter on our side.
Comment 5 Pierre-Charles David CLA 2015-06-16 09:12:31 EDT
The platform change was introduced by http://git.eclipse.org/c/platform/eclipse.platform.ui.git/commit/?id=7464658bb4965909cb1936f93a0db6d25ed43e64 as part of bug 372799.
Comment 6 Pierre-Charles David CLA 2015-06-16 09:31:22 EDT
See https://bugs.eclipse.org/bugs/show_bug.cgi?id=372799#c18
Comment 7 Andrey Loskutov CLA 2016-06-09 13:40:26 EDT

*** This bug has been marked as a duplicate of bug 495567 ***
Comment 8 Andrey Loskutov CLA 2016-06-09 14:44:28 EDT
No, this is not a dup.
Comment 9 Eclipse Genie CLA 2016-06-09 15:31:54 EDT
New Gerrit change created: https://git.eclipse.org/r/75026
Comment 11 Andrey Loskutov CLA 2016-06-13 11:52:33 EDT
Schould be in the next nightly build tomorrow.
Comment 12 Andrey Loskutov CLA 2017-03-07 06:52:44 EST
*** Bug 513193 has been marked as a duplicate of this bug. ***