From 51f1f32123728a59f6a6bd6df726631ed52f5ebb Mon Sep 17 00:00:00 2001
From: Florian Hoelzl <hoelzl@fortiss.org>
Date: Sun, 27 Nov 2011 16:17:59 +0000
Subject: [PATCH] implemented close editors on delete feature renamed
 ProjectRootElementUtils -> ModelElementUtils refs 309

---
 .../internal/ModelEditorBindingService.java   | 119 +++++++++++++++---
 .../kernel/ui/internal/NavigatorService.java  |  10 +-
 .../service/IModelEditorBindingService.java   |   4 +-
 .../extension/data/ITopLevelElement.java      |   7 +-
 .../kernel/internal/CommandStackService.java  |  13 +-
 .../storage/eclipse/ModelContext.java         |   4 +-
 .../kernel/service/ICommandStackService.java  |   3 +-
 ...ementUtils.java => ModelElementUtils.java} |  17 ++-
 8 files changed, 152 insertions(+), 25 deletions(-)
 rename org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/utils/{ProjectRootElementUtils.java => ModelElementUtils.java} (90%)

diff --git a/org.fortiss.tooling.kernel.ui/trunk/src/org/fortiss/tooling/kernel/ui/internal/ModelEditorBindingService.java b/org.fortiss.tooling.kernel.ui/trunk/src/org/fortiss/tooling/kernel/ui/internal/ModelEditorBindingService.java
index 0469ef778..3a18b33fb 100644
--- a/org.fortiss.tooling.kernel.ui/trunk/src/org/fortiss/tooling/kernel/ui/internal/ModelEditorBindingService.java
+++ b/org.fortiss.tooling.kernel.ui/trunk/src/org/fortiss/tooling/kernel/ui/internal/ModelEditorBindingService.java
@@ -19,19 +19,31 @@ package org.fortiss.tooling.kernel.ui.internal;
 
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.EventObject;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import org.conqat.lib.commons.collections.CollectionUtils;
+import org.eclipse.emf.common.command.CommandStackListener;
 import org.eclipse.emf.ecore.EObject;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IPartListener;
+import org.eclipse.ui.IPartService;
+import org.eclipse.ui.IWorkbenchPart;
 import org.eclipse.ui.PartInitException;
 import org.eclipse.ui.PlatformUI;
 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.base.EObjectAwareServiceBase;
 import org.fortiss.tooling.kernel.ui.extension.IModelEditorBinding;
 import org.fortiss.tooling.kernel.ui.internal.editor.ExtendableMultiPageEditor;
 import org.fortiss.tooling.kernel.ui.internal.editor.ModelElementEditorInput;
 import org.fortiss.tooling.kernel.ui.service.IModelEditorBindingService;
 import org.fortiss.tooling.kernel.utils.LoggingUtils;
+import org.fortiss.tooling.kernel.utils.ModelElementUtils;
 
 /**
  * This class implements the {@link IModelEditorBindingService} interface.
@@ -43,7 +55,7 @@ import org.fortiss.tooling.kernel.utils.LoggingUtils;
  */
 public class ModelEditorBindingService extends
 		EObjectAwareServiceBase<IModelEditorBinding<EObject>> implements
-		IModelEditorBindingService {
+		IModelEditorBindingService, IPartListener, CommandStackListener {
 
 	/** The compositor extension point ID. */
 	private static final String EXTENSION_POINT_NAME = "org.fortiss.tooling.kernel.ui.modelEditorBinding";
@@ -54,6 +66,12 @@ public class ModelEditorBindingService extends
 	/** The handler class attribute name. */
 	private static final String HANDLER_CLASS_ATTRIBUTE_NAME = "binding";
 
+	/** Stores the currently opened editors and their model elements. */
+	private final Map<IEditorPart, EObject> currentEditors = new HashMap<IEditorPart, EObject>();
+
+	/** Stores the command stack registrations. */
+	private final Map<EObject, ITopLevelElement> currentCommandStacks = new HashMap<EObject, ITopLevelElement>();
+
 	/** Constructor. */
 	public ModelEditorBindingService() {
 		super();
@@ -71,15 +89,26 @@ public class ModelEditorBindingService extends
 			return;
 		}
 		try {
-			PlatformUI
+			IEditorPart part = PlatformUI
 					.getWorkbench()
 					.getActiveWorkbenchWindow()
 					.getActivePage()
 					.openEditor(new ModelElementEditorInput(element),
 							ExtendableMultiPageEditor.ID);
+			currentEditors.put(part, element);
+			// ensure registration with part service
+			IPartService service = (IPartService) part.getSite().getService(
+					IPartService.class);
+			service.addPartListener(this);
+			// ensure registration with command stack service
+			ITopLevelElement top = IPersistencyService.INSTANCE
+					.getTopLevelElementFor(element);
+			ICommandStackService.INSTANCE.addCommandStackListener(top, this);
+			currentCommandStacks.put(element, top);
 		} catch (final PartInitException e) {
 			LoggingUtils.error(ToolingKernelActivator.getDefault(),
-					"Could not open editor with ID " + ExtendableMultiPageEditor.ID, e);
+					"Could not open editor with ID "
+							+ ExtendableMultiPageEditor.ID, e);
 		}
 	}
 
@@ -126,16 +155,78 @@ public class ModelEditorBindingService extends
 
 	/** {@inheritDoc} */
 	@Override
-	public void closeEditors(EObject rootElement) {
-		// TODO (FH): implement
-
-		// for (final IEditorPart editor : editors) {
-		// editor.getSite().getShell().getDisplay().asyncExec(new Runnable() {
-		// @Override
-		// public void run() {
-		// editor.getSite().getPage().closeEditor(editor, false);
-		// }
-		// });
-		// }
+	public void closeEditors(EObject parentElement) {
+		for (IEditorPart editor : currentEditors.keySet()) {
+			EObject editedElement = currentEditors.get(editor);
+			if (ModelElementUtils
+					.isChildElementOf(editedElement, parentElement)) {
+				closeEditor(editor);
+			}
+		}
+	}
+
+	/** Closes the given editor. */
+	private void closeEditor(final IEditorPart editor) {
+		editor.getSite().getShell().getDisplay().asyncExec(new Runnable() {
+			@Override
+			public void run() {
+				editor.getSite().getPage().closeEditor(editor, false);
+			}
+		});
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	public void partActivated(IWorkbenchPart part) {
+		// ignore
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	public void partBroughtToTop(IWorkbenchPart part) {
+		// ignore
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	public void partClosed(IWorkbenchPart part) {
+		if (currentEditors.containsKey(part)) {
+			EObject eo = currentEditors.get(part);
+			ITopLevelElement top = currentCommandStacks.get(eo);
+			currentCommandStacks.remove(eo);
+			currentEditors.remove(part);
+			// clean up command stack registration
+			for (IEditorPart other : currentEditors.keySet()) {
+				if (top == currentCommandStacks.get(currentEditors.get(other))) {
+					return;
+				}
+			}
+			// no other editor references the command stack of top anymore
+			ICommandStackService.INSTANCE.removeCommandStackListener(top, this);
+		}
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	public void partDeactivated(IWorkbenchPart part) {
+		// ignore
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	public void partOpened(IWorkbenchPart part) {
+		// can be ignored
+	}
+
+	/** {@inheritDoc} */
+	@Override
+	public void commandStackChanged(EventObject event) {
+		for (IEditorPart part : currentEditors.keySet()) {
+			ITopLevelElement top = IPersistencyService.INSTANCE
+					.getTopLevelElementFor(currentEditors.get(part));
+			if (top == null) {
+				closeEditor(part);
+			}
+		}
 	}
 }
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 a0afd321d..70f481b99 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
@@ -114,6 +114,10 @@ public class NavigatorService implements INavigatorService,
 	/** {@inheritDoc} */
 	@Override
 	public void topLevelElementRemoved(final ITopLevelElement element) {
+		if (element == null) {
+			return;
+		}
+
 		new UIJob("NavigatorServiceSafeableRefresh") {
 			@Override
 			public IStatus runInUIThread(IProgressMonitor monitor) {
@@ -153,7 +157,9 @@ public class NavigatorService implements INavigatorService,
 	/** {@inheritDoc} */
 	@Override
 	public void refresh() {
-		navigatorViewPart.refresh();
+		if (navigatorViewPart != null) {
+			navigatorViewPart.refresh();
+		}
 	}
 
 	/** {@inheritDoc} */
@@ -251,7 +257,7 @@ public class NavigatorService implements INavigatorService,
 	private void saveablesChanged(int event, ITopLevelElement element,
 			boolean force) {
 		Saveable saveable = saveables.get(element);
-		if (saveable != null) {
+		if (saveable != null && navigatorViewPart != null) {
 			ISaveablesLifecycleListener listener = (ISaveablesLifecycleListener) PlatformUI
 					.getWorkbench().getService(
 							ISaveablesLifecycleListener.class);
diff --git a/org.fortiss.tooling.kernel.ui/trunk/src/org/fortiss/tooling/kernel/ui/service/IModelEditorBindingService.java b/org.fortiss.tooling.kernel.ui/trunk/src/org/fortiss/tooling/kernel/ui/service/IModelEditorBindingService.java
index 345350157..681e87e6f 100644
--- a/org.fortiss.tooling.kernel.ui/trunk/src/org/fortiss/tooling/kernel/ui/service/IModelEditorBindingService.java
+++ b/org.fortiss.tooling.kernel.ui/trunk/src/org/fortiss/tooling/kernel/ui/service/IModelEditorBindingService.java
@@ -32,7 +32,7 @@ import org.fortiss.tooling.kernel.ui.internal.ModelEditorBindingService;
  * @author hoelzl
  * @author $Author$
  * @version $Rev$
- * @ConQAT.Rating GREEN Hash: 820B5843566C65139914E39B21E01710
+ * @ConQAT.Rating GREEN Hash: 6A80D8ED088608C52D21BC3F4B73BE8B
  */
 public interface IModelEditorBindingService {
 
@@ -43,7 +43,7 @@ public interface IModelEditorBindingService {
 	void openInEditor(EObject element);
 
 	/** Closes editors which depend on the given element or a sub-element. */
-	void closeEditors(EObject rootElement);
+	void closeEditors(EObject parentElement);
 
 	/** Returns registered editor bindings for the given {@link EObject}. */
 	List<IModelEditorBinding<EObject>> getBindings(EObject element);
diff --git a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/extension/data/ITopLevelElement.java b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/extension/data/ITopLevelElement.java
index db8b1de6b..02f9d5498 100644
--- a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/extension/data/ITopLevelElement.java
+++ b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/extension/data/ITopLevelElement.java
@@ -40,7 +40,7 @@ import org.fortiss.tooling.kernel.extension.IStorageProvider;
  * @author hoelzl
  * @author $Author$
  * @version $Rev$
- * @ConQAT.Rating GREEN Hash: 85B4A36E3F052F4BED404969E3CDB7B0
+ * @ConQAT.Rating GREEN Hash: 627F8F0B59A57FB8FE9CD20F70C02C7F
  */
 public interface ITopLevelElement {
 
@@ -50,7 +50,10 @@ public interface ITopLevelElement {
 	/** Executes the given {@link Runnable} as model changing command. */
 	void runAsCommand(Runnable runner);
 
-	/** Adds a command stack listener. */
+	/**
+	 * Adds a command stack listener. Has no effect if an identical listener is
+	 * already registered.
+	 */
 	void addCommandStackListener(CommandStackListener listener);
 
 	/** Removes the command stack listener. */
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 4e56d142a..2b01546bd 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
@@ -41,14 +41,23 @@ public class CommandStackService implements ICommandStackService {
 	@Override
 	public void addCommandStackListener(ITopLevelElement target,
 			CommandStackListener listener) {
-		target.addCommandStackListener(listener);
+		if (target != null) {
+			target.addCommandStackListener(listener);
+		}
 	}
 
 	/** {@inheritDoc} */
 	@Override
 	public void removeCommandStackListener(ITopLevelElement target,
 			CommandStackListener listener) {
-		target.removeCommandStackListener(listener);
+		if (target != null) {
+			target.removeCommandStackListener(listener);
+		} else {
+			for (ITopLevelElement top : IPersistencyService.INSTANCE
+					.getTopLevelElements()) {
+				top.removeCommandStackListener(listener);
+			}
+		}
 	}
 
 	/** {@inheritDoc} */
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 e2eeb0d5e..7b609da21 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
@@ -109,7 +109,9 @@ class ModelContext implements ITopLevelElement, CommandStackListener {
 	/** {@inheritDoc} */
 	@Override
 	public void addCommandStackListener(CommandStackListener listener) {
-		listeners.add(listener);
+		if (!listeners.contains(listener)) {
+			listeners.add(listener);
+		}
 	}
 
 	/** {@inheritDoc} */
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 d0077d5d8..350d3f39d 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
@@ -46,7 +46,8 @@ public interface ICommandStackService {
 
 	/**
 	 * Removes the command stack listener from the stack of the given target
-	 * element.
+	 * element. If the target element is <code>null</code> the listener is
+	 * removed from all current command stacks.
 	 */
 	void removeCommandStackListener(ITopLevelElement target,
 			CommandStackListener listener);
diff --git a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/utils/ProjectRootElementUtils.java b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/utils/ModelElementUtils.java
similarity index 90%
rename from org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/utils/ProjectRootElementUtils.java
rename to org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/utils/ModelElementUtils.java
index 0456bd9d5..ad818bd2b 100644
--- a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/utils/ProjectRootElementUtils.java
+++ b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/utils/ModelElementUtils.java
@@ -36,7 +36,7 @@ import org.fortiss.tooling.kernel.service.IPersistencyService;
  * @version $Rev$
  * @ConQAT.Rating GREEN Hash: AA5BFF29ABFE9DEB170DB51BDB3B5427
  */
-public final class ProjectRootElementUtils {
+public final class ModelElementUtils {
 
 	/**
 	 * Returns the instance of a project root element corresponding to the given
@@ -103,4 +103,19 @@ public final class ProjectRootElementUtils {
 		}
 		return null;
 	}
+
+	/**
+	 * Determines if the given element is an indirect child of the given parent
+	 * element.
+	 */
+	public static boolean isChildElementOf(EObject element,
+			EObject parentElement) {
+		while (element.eContainer() != null) {
+			if (element.eContainer() == parentElement) {
+				return true;
+			}
+			element = element.eContainer();
+		}
+		return false;
+	}
 }
-- 
GitLab