From 56fb6afde0bc9ec9d19cded28365aea66ba48f78 Mon Sep 17 00:00:00 2001
From: Florian Hoelzl <hoelzl@fortiss.org>
Date: Mon, 14 Nov 2011 16:14:34 +0000
Subject: [PATCH] Fixed save button behavior. refs 151

---
 .../kernel/ui/internal/ActionService.java     | 15 ++--
 .../kernel/ui/internal/NavigatorService.java  | 77 +++++++++++++++----
 .../ui/internal/editor/BindingEditor.java     | 19 +++--
 .../ui/internal/views/NavigatorViewPart.java  |  2 +-
 .../kernel/internal/CommandStackService.java  | 19 +++++
 .../storage/eclipse/ModelContext.java         | 45 +++++------
 .../kernel/service/ICommandStackService.java  | 11 +++
 7 files changed, 136 insertions(+), 52 deletions(-)

diff --git a/org.fortiss.tooling.kernel.ui/trunk/src/org/fortiss/tooling/kernel/ui/internal/ActionService.java b/org.fortiss.tooling.kernel.ui/trunk/src/org/fortiss/tooling/kernel/ui/internal/ActionService.java
index 766d98923..cd52e45fa 100644
--- a/org.fortiss.tooling.kernel.ui/trunk/src/org/fortiss/tooling/kernel/ui/internal/ActionService.java
+++ b/org.fortiss.tooling.kernel.ui/trunk/src/org/fortiss/tooling/kernel/ui/internal/ActionService.java
@@ -25,6 +25,7 @@ import org.eclipse.jface.action.IMenuManager;
 import org.eclipse.ui.IActionBars;
 import org.eclipse.ui.actions.ActionFactory;
 import org.fortiss.tooling.kernel.extension.data.ITopLevelElement;
+import org.fortiss.tooling.kernel.service.ICommandStackService;
 import org.fortiss.tooling.kernel.service.IPersistencyService;
 import org.fortiss.tooling.kernel.service.listener.IPersistencyServiceListener;
 import org.fortiss.tooling.kernel.ui.internal.actions.DeleteAction;
@@ -64,7 +65,7 @@ public class ActionService implements IActionService,
 
 		for (ITopLevelElement context : IPersistencyService.INSTANCE
 				.getTopLevelElements()) {
-			context.addCommandStackListener(this);
+			topLevelElementAdded(context);
 		}
 		IPersistencyService.INSTANCE.addTopLevelElementListener(this);
 	}
@@ -114,19 +115,21 @@ public class ActionService implements IActionService,
 
 	/** {@inheritDoc} */
 	@Override
-	public void topLevelElementAdded(ITopLevelElement elementContext) {
-		elementContext.addCommandStackListener(this);
+	public void topLevelElementAdded(ITopLevelElement element) {
+		ICommandStackService.INSTANCE.addCommandStackListener(
+				element.getRootModelElement(), this);
 	}
 
 	/** {@inheritDoc} */
 	@Override
-	public void topLevelElementRemoved(ITopLevelElement elementContext) {
-		elementContext.removeCommandStackListener(this);
+	public void topLevelElementRemoved(ITopLevelElement element) {
+		ICommandStackService.INSTANCE.removeCommandStackListener(
+				element.getRootModelElement(), this);
 	}
 
 	/** {@inheritDoc} */
 	@Override
 	public void topLevelElementChanged(ITopLevelElement element) {
-		// ignore these changes
+		// TODO (FH): ignore these changes?
 	}
 }
diff --git a/org.fortiss.tooling.kernel.ui/trunk/src/org/fortiss/tooling/kernel/ui/internal/NavigatorService.java b/org.fortiss.tooling.kernel.ui/trunk/src/org/fortiss/tooling/kernel/ui/internal/NavigatorService.java
index 7fefd2cd0..963a0eebd 100644
--- a/org.fortiss.tooling.kernel.ui/trunk/src/org/fortiss/tooling/kernel/ui/internal/NavigatorService.java
+++ b/org.fortiss.tooling.kernel.ui/trunk/src/org/fortiss/tooling/kernel/ui/internal/NavigatorService.java
@@ -20,9 +20,7 @@ package org.fortiss.tooling.kernel.ui.internal;
 import java.io.IOException;
 import java.util.EventObject;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Map;
-import java.util.Set;
 
 import org.conqat.ide.commons.ui.logging.LoggingUtils;
 import org.eclipse.core.runtime.CoreException;
@@ -31,15 +29,18 @@ import org.eclipse.emf.common.command.CommandStackListener;
 import org.eclipse.emf.ecore.EObject;
 import org.eclipse.jface.resource.ImageDescriptor;
 import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.ui.ISaveablesLifecycleListener;
+import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.Saveable;
+import org.eclipse.ui.SaveablesLifecycleEvent;
 import org.fortiss.tooling.kernel.ToolingKernelActivator;
 import org.fortiss.tooling.kernel.extension.data.ITopLevelElement;
+import org.fortiss.tooling.kernel.service.ICommandStackService;
 import org.fortiss.tooling.kernel.service.IPersistencyService;
 import org.fortiss.tooling.kernel.service.listener.IPersistencyServiceListener;
 import org.fortiss.tooling.kernel.ui.extension.data.ContextMenuContextProvider;
 import org.fortiss.tooling.kernel.ui.internal.views.NavigatorViewPart;
 import org.fortiss.tooling.kernel.ui.service.INavigatorService;
-import org.fortiss.tooling.kernel.ui.util.EObjectSelectionUtils;
 
 /**
  * This class implements the {@link INavigatorService} interface.
@@ -62,7 +63,8 @@ public class NavigatorService implements INavigatorService,
 	public NavigatorService() {
 		for (ITopLevelElement element : IPersistencyService.INSTANCE
 				.getTopLevelElements()) {
-			element.addCommandStackListener(this);
+			ICommandStackService.INSTANCE.addCommandStackListener(
+					element.getRootModelElement(), this);
 			saveables.put(element, new TopLevelElementSaveable(element));
 		}
 		IPersistencyService.INSTANCE.addTopLevelElementListener(this);
@@ -93,30 +95,37 @@ public class NavigatorService implements INavigatorService,
 
 	/** {@inheritDoc} */
 	@Override
-	public void topLevelElementAdded(ITopLevelElement context) {
-		context.addCommandStackListener(this);
-		saveables.put(context, new TopLevelElementSaveable(context));
+	public void topLevelElementAdded(ITopLevelElement element) {
+		element.addCommandStackListener(this);
+		saveables.put(element, new TopLevelElementSaveable(element));
+		notifySaveablesPostOpen(element);
 		refresh();
 	}
 
 	/** {@inheritDoc} */
 	@Override
-	public void topLevelElementRemoved(ITopLevelElement context) {
-		context.removeCommandStackListener(this);
-		saveables.remove(context);
+	public void topLevelElementRemoved(ITopLevelElement element) {
+		notifySaveablesPreClose(element);
+		element.removeCommandStackListener(this);
+		saveables.remove(element);
+		notifySaveablesPostClose(element);
 		refresh();
 	}
 
 	/** {@inheritDoc} */
 	@Override
 	public void topLevelElementChanged(ITopLevelElement element) {
-		// ignore this, {@link MarkerService} will call refresh()
+		notifySaveablesDirtyChanged(element);
+		refresh();
 		// TODO: does {@link MarkerService} call refresh? which method?
 	}
 
 	/** {@inheritDoc} */
 	@Override
 	public void commandStackChanged(EventObject event) {
+		if (event.getSource() instanceof ITopLevelElement) {
+			notifySaveablesDirtyChanged((ITopLevelElement) event.getSource());
+		}
 		refresh();
 	}
 
@@ -135,16 +144,15 @@ public class NavigatorService implements INavigatorService,
 	/** {@inheritDoc} */
 	@Override
 	public Saveable[] getActiveSaveables() {
-		Set<Saveable> result = new HashSet<Saveable>();
-		for (EObject selection : EObjectSelectionUtils
-				.getCurrentSelectionEObjects()) {
+		EObject selection = navigatorViewPart.getSelectedModelElement();
+		if (selection != null) {
 			ITopLevelElement context = IPersistencyService.INSTANCE
 					.getTopLevelElementFor(selection);
 			if (saveables.get(context) != null) {
-				result.add(saveables.get(context));
+				return new Saveable[] { saveables.get(context) };
 			}
 		}
-		return result.toArray(new Saveable[result.size()]);
+		return new Saveable[0];
 	}
 
 	/**
@@ -214,4 +222,41 @@ public class NavigatorService implements INavigatorService,
 	public void revealModelElement(EObject modelElement) {
 		navigatorViewPart.revealModelElement(modelElement);
 	}
+
+	/**
+	 * Notify {@link ISaveablesLifecycleListener} about saveable change of given
+	 * top-level element.
+	 */
+	private void saveablesChanged(int event, ITopLevelElement element) {
+		Saveable saveable = saveables.get(element);
+		if (saveable != null) {
+			ISaveablesLifecycleListener listener = (ISaveablesLifecycleListener) PlatformUI
+					.getWorkbench().getService(
+							ISaveablesLifecycleListener.class);
+			SaveablesLifecycleEvent eventObj = new SaveablesLifecycleEvent(
+					navigatorViewPart, event, new Saveable[] { saveable },
+					false);
+			listener.handleLifecycleEvent(eventObj);
+		}
+	}
+
+	/** Post {@link SaveablesLifecycleEvent#POST_OPEN}. */
+	private void notifySaveablesPostOpen(ITopLevelElement element) {
+		saveablesChanged(SaveablesLifecycleEvent.POST_OPEN, element);
+	}
+
+	/** Post {@link SaveablesLifecycleEvent#POST_CLOSE}. */
+	private void notifySaveablesPostClose(ITopLevelElement element) {
+		saveablesChanged(SaveablesLifecycleEvent.POST_CLOSE, element);
+	}
+
+	/** Post {@link SaveablesLifecycleEvent#PRE_CLOSE}. */
+	private void notifySaveablesPreClose(ITopLevelElement element) {
+		saveablesChanged(SaveablesLifecycleEvent.PRE_CLOSE, element);
+	}
+
+	/** Post {@link SaveablesLifecycleEvent#DIRTY_CHANGED}. */
+	private void notifySaveablesDirtyChanged(ITopLevelElement element) {
+		saveablesChanged(SaveablesLifecycleEvent.DIRTY_CHANGED, element);
+	}
 }
diff --git a/org.fortiss.tooling.kernel.ui/trunk/src/org/fortiss/tooling/kernel/ui/internal/editor/BindingEditor.java b/org.fortiss.tooling.kernel.ui/trunk/src/org/fortiss/tooling/kernel/ui/internal/editor/BindingEditor.java
index eb9529276..007bf67f4 100644
--- a/org.fortiss.tooling.kernel.ui/trunk/src/org/fortiss/tooling/kernel/ui/internal/editor/BindingEditor.java
+++ b/org.fortiss.tooling.kernel.ui/trunk/src/org/fortiss/tooling/kernel/ui/internal/editor/BindingEditor.java
@@ -36,6 +36,9 @@ import org.eclipse.ui.views.properties.IPropertySheetPage;
 import org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor;
 import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;
 import org.fortiss.tooling.kernel.ToolingKernelActivator;
+import org.fortiss.tooling.kernel.extension.data.ITopLevelElement;
+import org.fortiss.tooling.kernel.service.ICommandStackService;
+import org.fortiss.tooling.kernel.service.IPersistencyService;
 import org.fortiss.tooling.kernel.ui.extension.IModelEditorBinding;
 import org.fortiss.tooling.kernel.ui.extension.IModelElementHandler;
 import org.fortiss.tooling.kernel.ui.listener.IBindingEditorPageChangeListener;
@@ -52,7 +55,7 @@ import org.fortiss.tooling.kernel.ui.service.IPropertiesService;
  * @author hoelzlf
  * @author $Author$
  * @version $Rev$
- * @ConQAT.Rating RED Hash: E92400B5E205A0DEA761AE960FA9C463
+ * @ConQAT.Rating YELLOW Hash: 1924980FA5DF4510707A559F25799E8A
  */
 public class BindingEditor extends MultiPageEditorPart implements
 		ITabbedPropertySheetPageContributor {
@@ -174,13 +177,20 @@ public class BindingEditor extends MultiPageEditorPart implements
 	/** {@inheritDoc} */
 	@Override
 	public void doSave(IProgressMonitor monitor) {
-		// TODO (FH): implement issue 151
+		ITopLevelElement topElement = IPersistencyService.INSTANCE
+				.getTopLevelElementFor(editedObject);
+		try {
+			topElement.doSave(monitor);
+		} catch (Exception e) {
+			LoggingUtils.error(ToolingKernelActivator.getDefault(),
+					"Error during save of " + topElement.getSaveableName(), e);
+		}
 	}
 
 	/** {@inheritDoc} */
 	@Override
 	public void doSaveAs() {
-		// TODO (FH): implement issue 151
+		// not needed
 	}
 
 	/** {@inheritDoc} */
@@ -193,8 +203,7 @@ public class BindingEditor extends MultiPageEditorPart implements
 	/** {@inheritDoc} */
 	@Override
 	public boolean isDirty() {
-		// TODO (FH): implement issue 151
-		return false;
+		return ICommandStackService.INSTANCE.isDirty(editedObject);
 	}
 
 	/** {@inheritDoc} */
diff --git a/org.fortiss.tooling.kernel.ui/trunk/src/org/fortiss/tooling/kernel/ui/internal/views/NavigatorViewPart.java b/org.fortiss.tooling.kernel.ui/trunk/src/org/fortiss/tooling/kernel/ui/internal/views/NavigatorViewPart.java
index fe47cf1dd..2b12e05e7 100644
--- a/org.fortiss.tooling.kernel.ui/trunk/src/org/fortiss/tooling/kernel/ui/internal/views/NavigatorViewPart.java
+++ b/org.fortiss.tooling.kernel.ui/trunk/src/org/fortiss/tooling/kernel/ui/internal/views/NavigatorViewPart.java
@@ -180,7 +180,6 @@ public final class NavigatorViewPart extends ViewPart implements
 				ToolingKernelUIActivator.getDefault().getDialogSettings()
 						.put(LINK_WITH_EDITOR_FLAG, this.isChecked());
 			}
-
 		};
 
 		linkWithEditorAction.setImageDescriptor(ToolingKernelUIActivator
@@ -236,6 +235,7 @@ public final class NavigatorViewPart extends ViewPart implements
 	@Override
 	public void selectionChanged(SelectionChangedEvent event) {
 		IActionService.INSTANCE.refresh();
+		firePropertyChange(IWorkbenchPartConstants.PROP_DIRTY);
 	}
 
 	/** {@inheritDoc} */
diff --git a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/CommandStackService.java b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/CommandStackService.java
index 8e2a6eb1c..af6934ac9 100644
--- a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/CommandStackService.java
+++ b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/CommandStackService.java
@@ -18,6 +18,7 @@ $Id$
 package org.fortiss.tooling.kernel.internal;
 
 import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.emf.common.command.CommandStackListener;
 import org.eclipse.emf.ecore.EObject;
 import org.fortiss.tooling.kernel.ToolingKernelActivator;
 import org.fortiss.tooling.kernel.extension.data.ITopLevelElement;
@@ -36,6 +37,24 @@ import org.fortiss.tooling.kernel.utils.LoggingUtils;
  */
 public class CommandStackService implements ICommandStackService {
 
+	/** {@inheritDoc} */
+	@Override
+	public void addCommandStackListener(EObject target,
+			CommandStackListener listener) {
+		ITopLevelElement context = IPersistencyService.INSTANCE
+				.getTopLevelElementFor(target);
+		context.addCommandStackListener(listener);
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	public void removeCommandStackListener(EObject target,
+			CommandStackListener listener) {
+		ITopLevelElement context = IPersistencyService.INSTANCE
+				.getTopLevelElementFor(target);
+		context.removeCommandStackListener(listener);
+	}
+
 	/** {@inheritDoc} */
 	@Override
 	public void runAsCommand(EObject target, Runnable runner) {
diff --git a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/storage/eclipse/ModelContext.java b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/storage/eclipse/ModelContext.java
index 065ee0bdf..f154cc25c 100644
--- a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/storage/eclipse/ModelContext.java
+++ b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/storage/eclipse/ModelContext.java
@@ -21,8 +21,11 @@ import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.lang.reflect.Method;
+import java.util.EventObject;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Set;
 
 import org.eclipse.core.resources.IFile;
@@ -36,7 +39,6 @@ import org.eclipse.emf.common.util.URI;
 import org.eclipse.emf.ecore.EObject;
 import org.eclipse.emf.ecore.resource.Resource;
 import org.eclipse.emf.ecore.resource.ResourceSet;
-import org.eclipse.emf.transaction.TransactionalCommandStack;
 import org.eclipse.emf.transaction.TransactionalEditingDomain;
 import org.fortiss.tooling.kernel.ToolingKernelActivator;
 import org.fortiss.tooling.kernel.extension.data.ITopLevelElement;
@@ -54,7 +56,7 @@ import org.fortiss.tooling.kernel.utils.LoggingUtils;
  * @version $Rev$
  * @ConQAT.Rating GREEN Hash: AAAEB5802D74F212F47C25AD613B97CF
  */
-class ModelContext implements ITopLevelElement {
+class ModelContext implements ITopLevelElement, CommandStackListener {
 
 	/** The resource set we are using. */
 	private final ResourceSet rset;
@@ -71,6 +73,9 @@ class ModelContext implements ITopLevelElement {
 	/** The transactional command stack. */
 	private final AutoUndoCommandStack transactionalCommandStack;
 
+	/** Stores the command stack listener for this context. */
+	private final List<CommandStackListener> listeners = new LinkedList<CommandStackListener>();
+
 	/** Flag for remembering whether the last change of the file was intended. */
 	private boolean lastChangeWasIntended = false;
 
@@ -90,6 +95,7 @@ class ModelContext implements ITopLevelElement {
 		r.load(EMFResourceUtils.buildOptionsMap());
 
 		transactionalCommandStack = new AutoUndoCommandStack(editingDomain);
+		transactionalCommandStack.addCommandStackListener(this);
 
 		checkIDs();
 	}
@@ -103,13 +109,13 @@ class ModelContext implements ITopLevelElement {
 	/** {@inheritDoc} */
 	@Override
 	public void addCommandStackListener(CommandStackListener listener) {
-		transactionalCommandStack.addCommandStackListener(listener);
+		listeners.add(listener);
 	}
 
 	/** {@inheritDoc} */
 	@Override
 	public void removeCommandStackListener(CommandStackListener listener) {
-		transactionalCommandStack.removeCommandStackListener(listener);
+		listeners.remove(listener);
 	}
 
 	/** Checks whether all IDs are present and updates {@link #maxId}. */
@@ -203,7 +209,8 @@ class ModelContext implements ITopLevelElement {
 	public void destroy() {
 		// discard changes
 		((BasicCommandStack) editingDomain.getCommandStack()).saveIsDone();
-
+		// TODO (FH): close editors
+		transactionalCommandStack.removeCommandStackListener(this);
 	}
 
 	/** Returns the file associated with this model. */
@@ -265,25 +272,6 @@ class ModelContext implements ITopLevelElement {
 		lastChangeWasIntended = true;
 	}
 
-	/**
-	 * Returns the editing domain of this model's context. Note that the command
-	 * stack contained in the returned editing domain is raw (i.e. does not deal
-	 * with transactions). Usually you should use the command stack returned
-	 * from {@link #getTransactionalCommandStack()}, unless you know what you
-	 * are doing.
-	 */
-	public TransactionalEditingDomain getEditingDomain() {
-		return editingDomain;
-	}
-
-	/**
-	 * Returns the command stack to be used, which automatically wraps all
-	 * commands in a transaction and provides easy undo/redo.
-	 */
-	public TransactionalCommandStack getTransactionalCommandStack() {
-		return transactionalCommandStack;
-	}
-
 	/** Runs the given runnable as a command. */
 	@Override
 	public void runAsCommand(final Runnable runnable) {
@@ -348,4 +336,13 @@ class ModelContext implements ITopLevelElement {
 	public String getSaveableName() {
 		return getFile().getName();
 	}
+
+	/** {@inheritDoc} */
+	@Override
+	public void commandStackChanged(EventObject event) {
+		EventObject relayEvent = new EventObject(this);
+		for (CommandStackListener l : listeners) {
+			l.commandStackChanged(relayEvent);
+		}
+	}
 }
diff --git a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/service/ICommandStackService.java b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/service/ICommandStackService.java
index 0d8f6b778..0752e5af2 100644
--- a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/service/ICommandStackService.java
+++ b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/service/ICommandStackService.java
@@ -18,6 +18,7 @@ $Id$
 package org.fortiss.tooling.kernel.service;
 
 import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.emf.common.command.CommandStackListener;
 import org.eclipse.emf.ecore.EObject;
 import org.fortiss.tooling.kernel.internal.CommandStackService;
 
@@ -38,6 +39,16 @@ public interface ICommandStackService {
 	/** Returns the singleton instance of the service. */
 	public static final ICommandStackService INSTANCE = new CommandStackService();
 
+	/** Adds a command stack listener to the stack of the given target element. */
+	void addCommandStackListener(EObject target, CommandStackListener listener);
+
+	/**
+	 * Removes the command stack listener from the stack of the given target
+	 * element.
+	 */
+	void removeCommandStackListener(EObject target,
+			CommandStackListener listener);
+
 	/** Runs the given {@link Runnable} within a emfStore transaction. */
 	void runAsCommand(EObject target, Runnable runner);
 
-- 
GitLab