Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra')
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/Activator.java47
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/contentoutline/ContentOutlineRegistry.java263
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/contentoutline/IPapyrusContentOutlinePage.java34
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/contentoutline/NestedEditorDelegatedOutlinePage.java1098
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/AbstractStringValueConverter.java86
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/ConvertedValueContainer.java75
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/EMFStringValueConverter.java373
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/IStringValueConverter.java36
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/MultiConvertedValueContainer.java39
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/StringValueConverterStatus.java60
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/dnd/PapyrusTransfer.java105
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/ContentProviderServiceFactory.java68
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/CoreMultiDiagramEditor.java1244
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/DiSashModelManagerServiceFactory.java114
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/DiSashModelMngrServiceFactory.java101
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/IMultiDiagramEditor.java93
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/IPapyrusPageInput.java35
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/IReloadableEditor.java409
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/MultiDiagramEditorSelectionContext.java291
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/MultiDiagramPropertySheetPage.java178
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/PageIconRegistryServiceFactory.java71
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/PageMngrServiceFactory.java83
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/PapyrusPageInput.java62
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/CompositeReloadContext.java86
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/DelegatingReloadContext.java74
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EMFSelectionContext.java52
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EMFTreeViewerContext.java52
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EditorReloadAdapter.java36
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EditorReloadEvent.java188
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IDisposableReloadContext.java23
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IEditorReloadListener.java44
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IInternalEMFSelectionContext.java109
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IReloadContextProvider.java38
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/SelectionContext.java81
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/TreeViewerContext.java64
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IEditorFactory.java57
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IEditorIconFactory.java64
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IEditorIconFactoryExtended.java30
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IPageIconsRegistry.java40
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IPageIconsRegistryExtended.java32
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/PageIconsRegistry.java118
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/PageModelFactoryRegistry.java165
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/anytype/AnyTypeEditorFactory.java135
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/commands/ICreationCondition.java36
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/commands/IModelCreationCommand.java31
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/commands/PerspectiveContextDependence.java51
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/AbstractEditorFactory.java109
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorDescriptor.java168
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorDescriptorExtensionFactory.java99
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorFactoryProxy.java137
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorIconFactory.java152
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorNotFoundException.java53
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/IPluggableEditorFactory.java39
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/MultiDiagramException.java53
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/PluggableEditorFactoryReader.java143
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/commands/PageLayoutStorageState.java164
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/commands/SashLayoutCommandFactory.java226
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/commands/TogglePageLayoutStorageHandler.java78
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/EditorPreferencePage.java52
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/EditorPreferences.java88
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/Messages.java37
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/YesNo.java21
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/messages.properties18
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/DoSaveEvent.java66
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/IEditorInputChangedListener.java40
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/ILifeCycleEventsProvider.java57
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/ISaveAndDirtyService.java56
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/ISaveEventListener.java27
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/LifeCycleEventsProvider.java291
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/LifeCycleEventsProviderServiceFactory.java79
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/SaveAndDirtyService.java550
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/AbstractParametricOnSelectedElementsAction.java2
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/messages/Messages.java48
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/messages/messages.properties10
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/ActionBarContributorDescriptor.java72
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/ActionBarContributorExtensionFactory.java72
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/ActionBarContributorRegistry.java176
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/CoreComposedActionBarContributor.java122
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/IActionBarContributorFactory.java25
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/AbstractPapyrusPreferenceStore.java300
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/PapyrusScopedPreferenceStore.java858
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/dialog/AbstractApplyValueOnPreferenceKeyDialog.java71
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/dialog/AbstractPreferenceKeyDialog.java105
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/EditorLifecycleEventListener.java55
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/EditorLifecycleManager.java30
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/Messages.java34
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/ResourceUpdateService.java292
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/SaveLayoutBeforeClose.java218
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/internal/EditorLifecycleManagerImpl.java128
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/internal/InternalEditorLifecycleManager.java48
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/messages.properties15
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/AbstractCreateMenuFromCommandCategory.java135
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/DisplayUtils.java47
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/EclipseCommandUtils.java137
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/EditorHelper.java71
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/EditorUtils.java721
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ICallableWithProgress.java45
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/LocalMemento.java285
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/PapyrusImageUtils.java67
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/SelectionHelper.java119
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ServiceUtilsForActionHandlers.java149
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ServiceUtilsForWorkbenchPage.java63
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/TransactionUIHelper.java81
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/UIUtil.java517
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/WorkbenchPartHelper.java71
105 files changed, 14551 insertions, 12 deletions
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/Activator.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/Activator.java
index 27101698e64..730eea20ada 100644
--- a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/Activator.java
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/Activator.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2011 CEA LIST.
+ * Copyright (c) 2011, 2016 CEA LIST, Christian W. Damus, and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,12 +8,22 @@
*
* Contributors:
* Francois Le Fevre (CEA LIST) francois.le-fevre@cea.fr - Initial API and implementation
+ * Christian W. Damus = bug 485220
+ *
*****************************************************************************/
package org.eclipse.papyrus.infra.ui;
import org.eclipse.papyrus.infra.core.log.LogHelper;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.core.services.spi.IContextualServiceRegistryTracker;
+import org.eclipse.papyrus.infra.tools.spi.IExecutorServiceFactory;
+import org.eclipse.papyrus.infra.ui.util.UIUtil;
+import org.eclipse.papyrus.infra.ui.util.WorkbenchPartHelper;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
/**
* The activator class controls the plug-in life cycle
@@ -33,31 +43,46 @@ public class Activator extends AbstractUIPlugin {
*/
public static LogHelper log;
+ private ServiceRegistration<IExecutorServiceFactory> executorFactoryReg;
+ private ServiceRegistration<IContextualServiceRegistryTracker> serviceRegistryTrackerReg;
+
/**
* The constructor
*/
public Activator() {
}
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
- */
@Override
public void start(BundleContext context) throws Exception {
super.start(context);
plugin = this;
log = new LogHelper(this);
+
+ IExecutorServiceFactory executorFactory = () -> UIUtil.createUIExecutor(Display.getDefault());
+ executorFactoryReg = context.registerService(IExecutorServiceFactory.class, executorFactory, null);
+
+ IContextualServiceRegistryTracker serviceRegistryTracker = () -> {
+ ServicesRegistry result = null;
+ IEditorPart editor = WorkbenchPartHelper.getCurrentActiveEditorPart();
+ if (editor != null) {
+ result = editor.getAdapter(ServicesRegistry.class);
+ }
+ return result;
+ };
+ serviceRegistryTrackerReg = context.registerService(IContextualServiceRegistryTracker.class, serviceRegistryTracker, null);
}
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
- */
@Override
public void stop(BundleContext context) throws Exception {
+ if (serviceRegistryTrackerReg != null) {
+ serviceRegistryTrackerReg.unregister();
+ serviceRegistryTrackerReg = null;
+ }
+ if (executorFactoryReg != null) {
+ executorFactoryReg.unregister();
+ executorFactoryReg = null;
+ }
+
plugin = null;
super.stop(context);
}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/contentoutline/ContentOutlineRegistry.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/contentoutline/ContentOutlineRegistry.java
new file mode 100644
index 00000000000..1fb84925184
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/contentoutline/ContentOutlineRegistry.java
@@ -0,0 +1,263 @@
+/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.contentoutline;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.papyrus.infra.core.editor.BackboneException;
+import org.eclipse.papyrus.infra.core.extension.BadClassNameException;
+import org.eclipse.papyrus.infra.core.extension.NotFoundException;
+import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor;
+import org.eclipse.papyrus.infra.ui.extension.diagrameditor.EditorDescriptorExtensionFactory;
+import org.osgi.framework.Bundle;
+
+public class ContentOutlineRegistry {
+
+ /** ID of the editor extension (schema filename) */
+ public static final String EDITOR_EXTENSION_ID = "papyrusContentOutline";
+
+ private static String classAttributeName = "class";
+
+ private static String actionBarContributorIdPropertyName = "actionBarContributorId";
+
+ /** Namespace where to look for the extension points. */
+ protected String extensionPointNamespace;
+
+ /**
+ * The selected content outline.
+ */
+ protected IPapyrusContentOutlinePage contentOutline;
+
+ /**
+ * Associated editor.
+ */
+ private IMultiDiagramEditor multiEditor;
+
+ /**
+ * Constructor. defaultContext, input and site are explicitly required in
+ * order be sure that they are initialized. The multiEditor should be
+ * initialized. In particular, getEditorSite(), getEditorInput() and
+ * getDefaultContext() should return initialized values.
+ *
+ * @param multiEditor
+ * @param defaultContext
+ * @param input
+ * @param site
+ * @param extensionPointNamespace
+ */
+ public ContentOutlineRegistry(IMultiDiagramEditor multiEditor, String extensionPointNamespace) {
+ this.multiEditor = multiEditor;
+ this.extensionPointNamespace = extensionPointNamespace;
+ }
+
+ /**
+ * Returns the single instance of the content outline. Creates one if
+ * necessary.
+ *
+ * @return the contentOutline the single instance of the content outline
+ * @throws BackboneException
+ * exception thrown when the outline can not be created.
+ */
+ public IPapyrusContentOutlinePage getContentOutline() throws BackboneException {
+ if (contentOutline == null) {
+ createContentOutline();
+ }
+ return contentOutline;
+ }
+
+ /**
+ * Return the {@link ContentOutlineDescriptor} with the highest priority.
+ *
+ * @return
+ * @throws BackboneException
+ * @throws NotFoundException
+ * If no ContentOutline can be found in extensions
+ */
+ private ContentOutlineDescriptor getContentOutlineDescriptor() throws BackboneException {
+ IConfigurationElement[] configElements = Platform.getExtensionRegistry().getConfigurationElementsFor(extensionPointNamespace, EDITOR_EXTENSION_ID);
+ ContentOutlineDescriptor found = null;
+
+ // look for the one with the highest priority
+ for (IConfigurationElement ele : configElements) {
+ ContentOutlineDescriptor desc = new ContentOutlineDescriptor(ele);
+ if (desc.isHigher(found)) {
+ found = desc;
+ }
+ }
+
+ // Instanciate the object
+ if (found == null) {
+ throw new NotFoundException("No ContentOutline registered."); //$NON-NLS-1$
+ }
+
+ return found;
+
+ }
+
+ /**
+ * Creates the content outline from the selected extension.
+ *
+ * @throws BackboneException
+ * exception thrown when the outline can not be created.
+ */
+ private void createContentOutline() throws BackboneException {
+
+ ContentOutlineDescriptor found = getContentOutlineDescriptor();
+ // Instanciate the object
+ if (found != null) {
+ contentOutline = found.createContentOutlinePage();
+ }
+ }
+
+ /**
+ * Inner Descriptor for content outline. This class load data from Eclipse
+ * extension mechanism TODO Change the parent class. It is here just to have
+ * quick code.
+ */
+ protected class ContentOutlineDescriptor extends EditorDescriptorExtensionFactory {
+
+ private int priority;
+
+ private String className;
+
+ private String actionBarContributorID;
+
+ private IConfigurationElement element;
+
+ /**
+ * Instance is created when requested.
+ */
+ protected IPapyrusContentOutlinePage instance = null;
+
+ /**
+ * Create a descriptor backuped by the config element.
+ */
+ protected ContentOutlineDescriptor(IConfigurationElement element) throws BackboneException {
+ String tagName = "contentoutline";
+ checkTagName(element, tagName);
+ this.className = element.getAttribute(classAttributeName);
+ this.actionBarContributorID = element.getAttribute(actionBarContributorIdPropertyName);
+ try {
+ this.priority = Integer.parseInt(element.getAttribute("priority"));
+ } catch (NumberFormatException e) {
+ this.priority = 0;
+ }
+
+ this.element = element;
+ // check parameters
+ if (className == null) {
+ throw new BadClassNameException("Class name must be set", "contentoutline", classAttributeName); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ }
+
+ /**
+ * Compare priority. The highest priority win.
+ */
+ public boolean isHigher(ContentOutlineDescriptor found) {
+ if (found == null) {
+ return true;
+ }
+ return this.getPriority() > found.getPriority();
+ }
+
+ /**
+ * Return the higher value of the descriptor. This value is used to
+ * order the contentOutline. The highest priority win.
+ */
+ private int getPriority() {
+ return priority;
+ }
+
+ /**
+ * @return the actionBarContributorID
+ */
+ public String getActionBarContributorID() {
+ return actionBarContributorID;
+ }
+
+ /**
+ * Returns the content outline page instance (lazy initialization)
+ *
+ * @return the context outline page
+ * @throws BackboneException
+ * exception thrown when a problem occurs.
+ */
+ protected IPapyrusContentOutlinePage getContentOutline() throws BackboneException {
+ if (instance == null) {
+ instance = createContentOutlinePage();
+ }
+ return instance;
+ }
+
+ /**
+ * Create the class corresponding to the class attribute.
+ */
+ private Class<IPapyrusContentOutlinePage> loadClass() throws BadClassNameException {
+ if (className == null || className.length() == 0) {
+ throw new BadClassNameException("Classname should be set.", "contentoutline", classAttributeName); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ Class<IPapyrusContentOutlinePage> factoryClass;
+ try {
+ factoryClass = (Class<IPapyrusContentOutlinePage>) Class.forName(className);
+ } catch (ClassNotFoundException e) {
+ // try another way
+ try {
+ String declaringID = element.getContributor().getName();
+ Bundle bundle = Platform.getBundle(declaringID);
+ factoryClass = (Class<IPapyrusContentOutlinePage>) bundle.loadClass(className);
+ } catch (ClassNotFoundException e1) {
+ throw new BadClassNameException("", "contentoutline", classAttributeName, e1); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+ return factoryClass;
+ }
+
+ /**
+ * create the outlinepage by calling constructor without parameter and
+ * then call init method
+ *
+ * @return the outline.
+ * @throws BackboneException
+ */
+ protected IPapyrusContentOutlinePage createContentOutlinePage() throws BackboneException {
+ if (false) {
+ System.out.println("Not yet"); // FIXME : no syso
+ return null;
+ }
+ try {
+ IPapyrusContentOutlinePage outline = loadClass().newInstance();
+ outline.init(multiEditor);
+ return outline;
+
+ } catch (SecurityException e) {
+ // Lets propagate. This is an implementation problem that should
+ // be solved by programmer.
+ throw new RuntimeException(e);
+ }
+
+ catch (InstantiationException e) {
+ // Lets propagate. This is an implementation problem that should
+ // be solved by programmer.
+ // throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ // Lets propagate. This is an implementation problem that should
+ // be solved by programmer.
+ throw new RuntimeException(e);
+ }
+ return null;
+ }
+
+ } // end class
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/contentoutline/IPapyrusContentOutlinePage.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/contentoutline/IPapyrusContentOutlinePage.java
new file mode 100644
index 00000000000..15116aa267b
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/contentoutline/IPapyrusContentOutlinePage.java
@@ -0,0 +1,34 @@
+/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.contentoutline;
+
+import org.eclipse.papyrus.infra.core.editor.BackboneException;
+import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor;
+
+/**
+ * Extends the original interface to add the init method.
+ */
+public interface IPapyrusContentOutlinePage extends org.eclipse.ui.views.contentoutline.IContentOutlinePage {
+
+ /**
+ * Init the content outline.
+ *
+ * @param multiEditor
+ * the multiEditor is used to access to the context
+ * @throws BackboneException
+ * during research of the associated context.
+ */
+ void init(IMultiDiagramEditor multiEditor) throws BackboneException;
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/contentoutline/NestedEditorDelegatedOutlinePage.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/contentoutline/NestedEditorDelegatedOutlinePage.java
new file mode 100644
index 00000000000..4cf52a66930
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/contentoutline/NestedEditorDelegatedOutlinePage.java
@@ -0,0 +1,1098 @@
+/*****************************************************************************
+ * Copyright (c) 2013, 2014 CEA LIST and other.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Remi Schnekenburger (CEA LIST) - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 437217
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.contentoutline;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.PlatformObject;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.papyrus.infra.core.Activator;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.IEditorPage;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.IPage;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.IPageLifeCycleEventsListener;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.ISashWindowsContainer;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.utils.AdapterUtils;
+import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor;
+import org.eclipse.papyrus.infra.ui.editor.IReloadableEditor;
+import org.eclipse.papyrus.infra.ui.editor.reload.EditorReloadEvent;
+import org.eclipse.papyrus.infra.ui.editor.reload.IEditorReloadListener;
+import org.eclipse.papyrus.infra.ui.editor.reload.IReloadContextProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IViewSite;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.SubActionBars;
+import org.eclipse.ui.part.IPageBookViewPage;
+import org.eclipse.ui.part.IPageSite;
+import org.eclipse.ui.part.Page;
+import org.eclipse.ui.part.PageBook;
+import org.eclipse.ui.part.PageSite;
+import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
+
+import com.google.common.collect.Lists;
+
+/**
+ * Page for Papyrus outline when active nested editor is a GMF editor
+ */
+public class NestedEditorDelegatedOutlinePage extends Page implements IPapyrusContentOutlinePage, IPageLifeCycleEventsListener, IEditorReloadListener {
+
+ /** The editor for which I am a slave. */
+ private IMultiDiagramEditor multiEditor;
+
+ /** Sash window container to listen for page changes inside the same editor */
+ private ISashWindowsContainer sashWindowsContainer;
+
+ /** Page book in which all outline controls of nested editors will be stored and displayed one by one */
+ private PageBook sashEditorPageBook;
+
+ /**
+ * Map from papyrus pages (representing nested editors) to outline page records (key type: <code>org.eclipse.papyrus.infra.core.sasheditor.editor.IPage</code>;
+ * value type: <code>OutlinePageRec</code>).
+ */
+ private Map<IPage, OutlinePageRec> mapIPapyrusPageToOutlineRec = new HashMap<IPage, OutlinePageRec>();
+
+ /**
+ * The page rec which provided the current page or <code>null</code>
+ */
+ private OutlinePageRec activeRec;
+
+ /**
+ * Default page rec that displays a simple message
+ */
+ private OutlinePageRec defaultPageRec;
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void init(IMultiDiagramEditor multiEditor) {
+ this.multiEditor = multiEditor;
+
+ internalInit(multiEditor);
+
+ IReloadableEditor.Adapter.getAdapter(multiEditor).addEditorReloadListener(this);
+ }
+
+ private void internalInit(IMultiDiagramEditor multiEditor) {
+ sashWindowsContainer = (ISashWindowsContainer) multiEditor.getAdapter(ISashWindowsContainer.class);
+ sashWindowsContainer.addPageLifeCycleListener(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void init(IPageSite pageSite) {
+ IViewSite viewSite = getViewSite(pageSite);
+
+ DelegatedPageSite delegatedPageSite = new DelegatedPageSite(viewSite, this);
+ super.init(delegatedPageSite);
+ }
+
+ /**
+ * /**
+ * The <code>PageBookView</code> implementation of this <code>IWorkbenchPart</code> method cleans up all the pages. Subclasses
+ * may extend.
+ */
+ @Override
+ public void dispose() {
+ if (multiEditor != null) {
+ IReloadableEditor.Adapter.getAdapter(multiEditor).removeEditorReloadListener(this);
+ }
+
+ internalDispose();
+
+ multiEditor = null;
+
+ // Run super.
+ super.dispose();
+ }
+
+ private void internalDispose() {
+ // Deref all of the pages.
+ activeRec = null;
+ if (defaultPageRec != null) {
+ // check for null since the default page may not have
+ // been created (ex. perspective never visible)
+ defaultPageRec.contentOutlinePage.dispose();
+ defaultPageRec.dispose();
+ defaultPageRec = null;
+ }
+
+ java.util.List<OutlinePageRec> records = new ArrayList<NestedEditorDelegatedOutlinePage.OutlinePageRec>(mapIPapyrusPageToOutlineRec.values());
+ Iterator<OutlinePageRec> itr = records.iterator();
+ while (itr.hasNext()) {
+ OutlinePageRec rec = itr.next();
+ removePage(rec);
+ }
+
+ // remove listener and all refs to editor
+ sashWindowsContainer.removePageLifeCycleListener(this);
+ }
+
+ /**
+ * Refreshes the global actions for the active page.
+ */
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ protected void refreshGlobalActionHandlers() {
+ // Clear old actions.
+ IActionBars bars = getSite().getActionBars();
+ bars.clearGlobalActionHandlers();
+
+ // Set new actions.
+ Map newActionHandlers = ((SubActionBars) activeRec.getPageSite().getActionBars()).getGlobalActionHandlers();
+ if (newActionHandlers != null) {
+ Set<?> keys = newActionHandlers.entrySet();
+ Iterator<?> iter = keys.iterator();
+ while (iter.hasNext()) {
+ Map.Entry<String, IAction> entry = (Map.Entry) iter.next();
+ bars.setGlobalActionHandler(entry.getKey(), entry.getValue());
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addSelectionChangedListener(ISelectionChangedListener listener) {
+ // nothing here
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ISelection getSelection() {
+ // nothing here
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void removeSelectionChangedListener(ISelectionChangedListener listener) {
+ // nothing here
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setSelection(ISelection selection) {
+ // nothing here
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void createControl(Composite parent) {
+ sashEditorPageBook = new PageBook(parent, SWT.BORDER);
+
+ createContents();
+ }
+
+ protected void createContents() {
+ // Create the default page rec.
+ IContentOutlinePage defaultPage = createDefaultPage(sashEditorPageBook);
+ defaultPageRec = new OutlinePageRec(null, defaultPage);
+ preparePage(defaultPageRec);
+
+ // Show the initial active page or the default page
+ IPage activePage = sashWindowsContainer.getActiveSashWindowsPage();
+ if (activePage != null) {
+ OutlinePageRec rec = getOutlinePageRec(activePage);
+ if (rec == null) {
+ rec = createPage(activePage);
+ }
+
+ // Show the page, if it was successfully created
+ if (rec != null) {
+ showOutlinePageRec(rec);
+ } else {
+ showOutlinePageRec(defaultPageRec);
+ }
+ } else {
+ showOutlinePageRec(defaultPageRec);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Control getControl() {
+ return sashEditorPageBook;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void selectionChanged(IWorkbenchPart part, ISelection selection) {
+ // nothing here
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void pageChanged(IPage newPage) {
+ // throw new UnsupportedOperationException("pageChanged not implemented " + newPage);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void pageOpened(IPage page) {
+ // Activator.log.debug("Opened");
+ // create the new Outline
+ // Create a page for the part.
+ OutlinePageRec rec = getOutlinePageRec(page);
+ if (rec == null) {
+ rec = createPage(page);
+ }
+
+ // Show the page, if it was successfully created
+ if (rec != null) {
+ showOutlinePageRec(rec);
+ } else {
+ showOutlinePageRec(defaultPageRec);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void pageClosed(IPage papyrusPage) {
+ // Activator.log.debug("Closed");
+ // Update the active part.
+ if (activeRec != null && activeRec.papyrusPage == papyrusPage) {
+ showOutlinePageRec(defaultPageRec);
+ }
+
+ // Find and remove the part page.
+ OutlinePageRec rec = getOutlinePageRec(papyrusPage);
+ if (rec != null) {
+ removePage(rec);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void pageActivated(IPage page) {
+ // Activator.log.debug("Activated");
+ // Create a page for the partm, if necessary.
+ OutlinePageRec rec = getOutlinePageRec(page, true);
+
+ // Show the page, if it was successfully created
+ if (rec != null) {
+ showOutlinePageRec(rec);
+ } else {
+ showOutlinePageRec(defaultPageRec);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void pageDeactivated(IPage page) {
+ // throw new UnsupportedOperationException("pageDeactivated not implemented " + page);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void pageAboutToBeOpened(IPage page) {
+ // throw new UnsupportedOperationException("pageAboutToBeOpened not implemented "+page);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void pageAboutToBeClosed(IPage page) {
+ // throw new UnsupportedOperationException("pageAboutToBeClosed not implemented " + page);
+ }
+
+ @Override
+ public void editorAboutToReload(EditorReloadEvent event) {
+ event.putContext(new OutlineContext());
+
+ internalDispose();
+ }
+
+ @Override
+ public void editorReloaded(EditorReloadEvent event) {
+ internalInit(event.getEditor());
+ createContents();
+
+ ((OutlineContext) event.getContext()).restore();
+ }
+
+ // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // MAINLY INSPIRED FROM PAGE BOOK VIEW
+ // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Creates and returns the default page for this view.
+ *
+ * @param book
+ * the pagebook control
+ * @return the default page
+ */
+ protected IContentOutlinePage createDefaultPage(PageBook book) {
+ MessageOutlinePage page = new MessageOutlinePage();
+ initPage(page);
+ page.createControl(book);
+ return page;
+ }
+
+ /**
+ * Creates an outline record for a given papyrus Page. Adds it to the pagebook but does not show it.
+ *
+ * @param page
+ * The nested editor we are created an outline.
+ * @return the created outline page record
+ */
+ protected OutlinePageRec createPage(IPage papyrusPage) {
+ OutlinePageRec rec = doCreatePage(papyrusPage);
+ if (rec != null) {
+ mapIPapyrusPageToOutlineRec.put(papyrusPage, rec);
+ preparePage(rec);
+ }
+ return rec;
+ }
+
+ /**
+ * Prepares the page in the given page rec for use in this view.
+ *
+ * @param rec
+ */
+ protected void preparePage(OutlinePageRec rec) {
+ IPageSite site = null;
+
+ if (!doesPageExist(rec.contentOutlinePage)) {
+ if (rec.contentOutlinePage instanceof IPageBookViewPage) {
+ site = ((IPageBookViewPage) rec.contentOutlinePage).getSite();
+ rec.setPageSite(site);
+ }
+ }
+ }
+
+ /**
+ * Initializes the given page with a page site.
+ * <p>
+ * Subclasses should call this method after the page is created but before creating its controls.
+ * </p>
+ * <p>
+ * Subclasses may override
+ * </p>
+ *
+ * @param page
+ * The page to initialize
+ */
+ protected void initPage(IPageBookViewPage page) {
+ try {
+ IPageSite site = super.getSite();
+ // try to create a specific page site for this page
+ page.init(new PageSite(getViewSite(site)));
+ } catch (PartInitException e) {
+ Activator.log.error(e);
+ }
+ }
+
+ /**
+ * @param site
+ * the page site from which parent view site is retrieved
+ * @return the retrieved page site
+ */
+ protected static IViewSite getViewSite(IPageSite site) {
+ if (site instanceof IViewSite) {
+ return ((IViewSite) site);
+ }
+ // no way to get the IViewSite from the page site.
+ if (site instanceof PageSite) {
+ try {
+ Field parentSiteField = PageSite.class.getDeclaredField("parentSite");
+ parentSiteField.setAccessible(true);
+ Object parentSite = parentSiteField.get(site);
+ if (parentSite instanceof IViewSite) {
+ return ((IViewSite) parentSite);
+ }
+ } catch (SecurityException e) {
+ Activator.log.error(e);
+ } catch (NoSuchFieldException e) {
+ Activator.log.error(e);
+ } catch (IllegalArgumentException e) {
+ Activator.log.error(e);
+ } catch (IllegalAccessException e) {
+ Activator.log.error(e);
+ }
+ }
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ * Method declared on PageBookView.
+ */
+ protected OutlinePageRec doCreatePage(IPage papyrusPage) {
+ // Try to get an outline page.
+ if (papyrusPage instanceof IEditorPage) {
+ IEditorPart part = ((IEditorPage) papyrusPage).getIEditorPart();
+ Object obj = getAdapter(part, IContentOutlinePage.class, false);
+ if (obj instanceof IContentOutlinePage) {
+ IContentOutlinePage page = (IContentOutlinePage) obj;
+ if (page instanceof IPageBookViewPage) {
+ initPage((IPageBookViewPage) page);
+ }
+ page.createControl(getPageBook());
+ return new OutlinePageRec(papyrusPage, page);
+ }
+ }
+
+ // There is no content outline
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DelegatedPageSite getSite() {
+ return (DelegatedPageSite) super.getSite();
+ }
+
+ /*
+ * (non-Javadoc)
+ * Method declared on PageBookView.
+ */
+ protected void doDestroyPage(IPage papyrusPage, OutlinePageRec rec) {
+ IContentOutlinePage contentOutlinePage = rec.contentOutlinePage;
+ contentOutlinePage.dispose();
+ rec.dispose();
+ }
+
+ protected Collection<OutlinePageRec> getAllPages() {
+ return mapIPapyrusPageToOutlineRec.values();
+ }
+
+ /**
+ * Returns true if the page has already been created.
+ *
+ * @param page
+ * the page to test
+ * @return true if this page has already been created.
+ */
+ protected boolean doesPageExist(IContentOutlinePage page) {
+ return mapIPapyrusPageToOutlineRec.containsKey(page);
+ }
+
+ /**
+ * Returns the papyrus page which contributed the current outline page to this view.
+ *
+ * @return the page which contributed the current outline page or <code>null</code> if no part contributed the current page
+ */
+ protected IPage getCurrentContributingPage() {
+ if (activeRec == null) {
+ return null;
+ }
+ return activeRec.papyrusPage;
+ }
+
+ /**
+ * Returns the currently visible outline page for this view or <code>null</code> if no page is currently visible.
+ *
+ * @return the currently visible page
+ */
+ public IContentOutlinePage getCurrentOutlinePage() {
+ if (activeRec == null) {
+ return null;
+ }
+ return activeRec.contentOutlinePage;
+ }
+
+ /**
+ * Returns the view site for the given page of this view.
+ *
+ * @param page
+ * the page
+ * @return the corresponding site, or <code>null</code> if not found
+ */
+ protected IPageSite getPageSite(IPage page) {
+ OutlinePageRec rec = getOutlinePageRec(page);
+ if (rec != null) {
+ return rec.getPageSite();
+ }
+ return null;
+ }
+
+ /**
+ * Returns the default page for this view.
+ *
+ * @return the default page
+ */
+ public IContentOutlinePage getDefaultOutlinePage() {
+ return defaultPageRec.contentOutlinePage;
+ }
+
+ /**
+ * Returns the pagebook control for this view.
+ *
+ * @return the pagebook control, or <code>null</code> if not initialized
+ */
+ protected PageBook getPageBook() {
+ return sashEditorPageBook;
+ }
+
+ /**
+ * Returns the page record for the given part.
+ *
+ * @param part
+ * the part
+ * @return the corresponding page record, or <code>null</code> if not
+ * found
+ */
+ protected OutlinePageRec getOutlinePageRec(IPage papyrusPage) {
+ return mapIPapyrusPageToOutlineRec.get(papyrusPage);
+ }
+
+ OutlinePageRec getOutlinePageRec(IPage papyrusPage, boolean create) {
+ OutlinePageRec result = getOutlinePageRec(papyrusPage);
+ if (result == null) {
+ result = createPage(papyrusPage);
+ }
+ return result;
+ }
+
+ /**
+ * Returns the page record for the given page of this view.
+ *
+ * @param page
+ * the page
+ * @return the corresponding page record, or <code>null</code> if not
+ * found
+ */
+ protected OutlinePageRec getPageRec(IContentOutlinePage contentOutlinePage) {
+ Iterator<OutlinePageRec> itr = mapIPapyrusPageToOutlineRec.values().iterator();
+ while (itr.hasNext()) {
+ OutlinePageRec rec = itr.next();
+ if (rec.contentOutlinePage == contentOutlinePage) {
+ return rec;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Removes a page record.
+ *
+ * @param rec
+ * the page record to remove
+ */
+ protected void removePage(OutlinePageRec rec) {
+ mapIPapyrusPageToOutlineRec.remove(rec.papyrusPage);
+
+ Control control = rec.contentOutlinePage.getControl();
+ if (control != null && !control.isDisposed()) {
+ // Dispose the page's control so pages don't have to do this in their dispose method.
+ // The page's control is a child of this view's control so if this view is closed, the page's control will already be disposed.
+ control.dispose();
+ }
+
+ // Do this before destroying the page, otherwise we won't be able to retrieve the page site (it will be null)
+ IPageSite site = rec.getPageSite();
+ if (site instanceof PageSite) { // test null pointer and PageSite
+ ((SubActionBars) ((PageSite) site).getActionBars()).deactivate();
+ ((SubActionBars) ((PageSite) site).getActionBars()).dispose();
+ }
+
+ // Free the page
+ doDestroyPage(rec.papyrusPage, rec);
+ }
+
+ /*
+ * (non-Javadoc) Method declared on IWorkbenchPart.
+ */
+ @Override
+ public void setFocus() {
+ // first set focus on the page book, in case the page
+ // doesn't properly handle setFocus
+ if (sashEditorPageBook != null) {
+ sashEditorPageBook.setFocus();
+ }
+ // then set focus on the page, if any
+ if (activeRec != null) {
+ activeRec.contentOutlinePage.setFocus();
+ }
+ }
+
+ /**
+ * Shows page contained in the given page record in this view. The page
+ * record must be one from this pagebook view.
+ * <p>
+ * The <code>PageBookView</code> implementation of this method asks the pagebook control to show the given page's control, and records that the given page is now current. Subclasses may extend.
+ * </p>
+ *
+ * @param pageRec
+ * the page record containing the page to show
+ */
+ protected void showOutlinePageRec(OutlinePageRec pageRec) {
+ // If already showing do nothing
+ if (activeRec == pageRec) {
+ return;
+ }
+ // If the page is the same, just set activeRec to pageRec
+ if (activeRec != null && pageRec != null && activeRec.contentOutlinePage == pageRec.contentOutlinePage) {
+ activeRec = pageRec;
+ return;
+ }
+
+ activeRec = pageRec;
+ Control pageControl = activeRec.contentOutlinePage.getControl();
+ if (pageControl != null && !pageControl.isDisposed()) {
+ PageSite pageSite = (PageSite) activeRec.getPageSite();
+ // Verify that the page control is not disposed
+ // If we are closing, it may have already been disposed
+ sashEditorPageBook.showPage(pageControl);
+ getSite().setActivePageSite(pageSite);
+ }
+
+ }
+
+ /**
+ * If it is possible to adapt the given object to the given type, this
+ * returns the adapter. Performs the following checks:
+ *
+ * <ol>
+ * <li>Returns <code>sourceObject</code> if it is an instance of the adapter type.</li>
+ * <li>If sourceObject implements IAdaptable, it is queried for adapters.</li>
+ * <li>If sourceObject is not an instance of PlatformObject (which would have already done so), the adapter manager is queried for adapters</li>
+ * </ol>
+ *
+ * Otherwise returns null.
+ *
+ * @param sourceObject
+ * object to adapt, or null
+ * @param adapter
+ * type to adapt to
+ * @param activatePlugins
+ * true if IAdapterManager.loadAdapter should be used (may trigger plugin activation)
+ * @return a representation of sourceObject that is assignable to the
+ * adapter type, or null if no such representation exists
+ */
+ public static Object getAdapter(Object sourceObject, Class<?> adapter, boolean activatePlugins) {
+ Assert.isNotNull(adapter);
+ if (sourceObject == null) {
+ return null;
+ }
+ if (adapter.isInstance(sourceObject)) {
+ return sourceObject;
+ }
+
+ if (sourceObject instanceof IAdaptable) {
+ IAdaptable adaptable = (IAdaptable) sourceObject;
+
+ Object result = adaptable.getAdapter(adapter);
+ if (result != null) {
+ // Sanity-check
+ Assert.isTrue(adapter.isInstance(result));
+ return result;
+ }
+ }
+
+ if (!(sourceObject instanceof PlatformObject)) {
+ Object result;
+ if (activatePlugins) {
+ result = Platform.getAdapterManager().loadAdapter(sourceObject, adapter.getName());
+ } else {
+ result = Platform.getAdapterManager().getAdapter(sourceObject, adapter);
+ }
+ if (result != null) {
+ return result;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * A data structure used to store the information about the editor outline page within the papyrus outline page.
+ */
+ protected static class OutlinePageRec {
+
+ public Object subActionBars;
+
+ /** papyrus page: current editor opened as nested editor */
+ public IPage papyrusPage;
+
+ /** outline page recorded for the given papyrus page */
+ public IContentOutlinePage contentOutlinePage;
+
+ /** page site for the recorded outline page */
+ public IPageSite pageSite;
+
+ /**
+ * Creates a new page record initialized to the given papyrus page and outline page.
+ *
+ * @param papyrusPage
+ * @param contentOutlinePage
+ */
+ public OutlinePageRec(IPage papyrusPage, IContentOutlinePage contentOutlinePage) {
+ this.papyrusPage = papyrusPage;
+ this.contentOutlinePage = contentOutlinePage;
+ }
+
+ /**
+ * Sets the page site
+ *
+ * @param pageSite
+ * the page site for the recorded content outline page
+ */
+ public void setPageSite(IPageSite pageSite) {
+ this.pageSite = pageSite;
+ }
+
+ /**
+ * Sets the page site
+ *
+ * @param pageSite
+ * the page site for the recorded content outline page
+ */
+ public IPageSite getPageSite() {
+ return this.pageSite;
+ }
+
+ /**
+ * Disposes of this page record by <code>null</code>ing its fields.
+ */
+ public void dispose() {
+ papyrusPage = null;
+ contentOutlinePage = null;
+ pageSite = null;
+ }
+ }
+
+ protected static class DelegatedPageSite extends PageSite {
+
+ /** Page site of the active page in the book */
+ protected PageSite activePageSite;
+
+ private NestedEditorDelegatedOutlinePage nestedEditorDelegatedOutlinePage;
+
+ /**
+ * Constructor.
+ *
+ * @param parentViewSite
+ * @param nestedEditorDelegatedOutlinePage
+ */
+ public DelegatedPageSite(IViewSite parentViewSite, NestedEditorDelegatedOutlinePage nestedEditorDelegatedOutlinePage) {
+ super(parentViewSite);
+ this.nestedEditorDelegatedOutlinePage = nestedEditorDelegatedOutlinePage;
+ }
+
+ /**
+ * Sets the active page site
+ *
+ * @param activePageSite
+ * the activePageSite to set
+ */
+ public void setActivePageSite(PageSite activePageSite) {
+ // remove the contribution of the previous active page site
+ if (this.activePageSite != null) {
+ // update the action bars for the current page
+ getActionBars().deactivate();
+ getActionBars().clearGlobalActionHandlers();
+ getActionBars().updateActionBars();
+
+ activePageSite.deactivate();
+
+ }
+ this.activePageSite = activePageSite;
+ if (this.activePageSite != null) {
+ activePageSite.activate();
+ // update the action bars for the current page
+ getActionBars().activate();
+ getActionBars().updateActionBars();
+ }
+ }
+
+ /**
+ * Returns the active page site
+ *
+ * @return the active Page Site
+ */
+ public PageSite getActivePageSite() {
+ return activePageSite;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public SubActionBars getActionBars() {
+ if (activePageSite != null) {
+ return (SubActionBars) activePageSite.getActionBars();
+ }
+ return (SubActionBars) super.getActionBars();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void deactivate() {
+ // deactivate the action bars of the current active page
+ if (activePageSite != null) {
+ activePageSite.deactivate();
+ }
+
+ // deactivate all subcontributions
+ for (OutlinePageRec rec : nestedEditorDelegatedOutlinePage.getAllPages()) {
+ IPageSite site = rec.getPageSite();
+ IActionBars bars = site.getActionBars();
+ if (bars instanceof SubActionBars) {
+ SubActionBars subActionBars = (SubActionBars) bars;
+ subActionBars.deactivate();
+ subActionBars.clearGlobalActionHandlers();
+ subActionBars.updateActionBars();
+ }
+ }
+ super.deactivate();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void activate() {
+
+ // here, we have to desactivate all contributions of all pages of this delegating service.
+ // when the page site is activated, the pagebookview has already tried to update some action bars, even if it should not
+ // so we recompute all the active contributions items here, after desactivating all the contributions.
+ for (OutlinePageRec rec : nestedEditorDelegatedOutlinePage.getAllPages()) {
+ IPageSite site = rec.getPageSite();
+ IActionBars bars = site.getActionBars();
+ if (bars instanceof SubActionBars) {
+ SubActionBars subActionBars = (SubActionBars) bars;
+ subActionBars.deactivate();
+ subActionBars.clearGlobalActionHandlers();
+ subActionBars.updateActionBars();
+ }
+ }
+ if (this.activePageSite != null) {
+ activePageSite.activate();
+ // update the action bars for the current page
+ getActionBars().activate();
+ getActionBars().updateActionBars();
+ }
+ super.activate();
+ }
+ }
+
+ protected static class MessageOutlinePage implements IContentOutlinePage, IPageBookViewPage {
+
+ private Text label;
+
+ private IPageSite site;
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void createControl(Composite parent) {
+ label = new Text(parent, SWT.NONE);
+ label.setText("No outline for this editor");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void dispose() {
+ if (label != null && label.isDisposed()) {
+ label.dispose();
+ label = null;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Control getControl() {
+ return label;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setActionBars(IActionBars actionBars) {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setFocus() {
+ if (label != null && label.isDisposed()) {
+ label.setFocus();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addSelectionChangedListener(ISelectionChangedListener listener) {
+ // nothing here
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ISelection getSelection() {
+ // nothing here
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void removeSelectionChangedListener(ISelectionChangedListener listener) {
+ // nothing here
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setSelection(ISelection selection) {
+ // nothing here
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public IPageSite getSite() {
+ return site;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void init(IPageSite site) throws PartInitException {
+ this.site = site;
+ }
+
+ }
+
+ private class OutlineContext {
+
+ private List<PageContext> pages = Lists.newArrayListWithCapacity(mapIPapyrusPageToOutlineRec.size());
+
+ OutlineContext() {
+ for (OutlinePageRec next : mapIPapyrusPageToOutlineRec.values()) {
+ pages.add(new PageContext(next));
+ }
+ }
+
+ public void restore() {
+ for (PageContext next : pages) {
+ next.restore();
+ }
+ }
+
+ //
+ // Nested types
+ //
+
+ private class PageContext {
+
+ final URI diagramToken;
+
+ final Object context;
+
+ PageContext(OutlinePageRec outlinePage) {
+ Object diagram = outlinePage.papyrusPage.getRawModel();
+ diagramToken = (diagram instanceof EObject) ? EcoreUtil.getURI((EObject) diagram) : null;
+
+ // Can only sensibly manage restoring the state of the page if we can find it again
+ if (diagramToken == null) {
+ context = null;
+ } else {
+ IReloadContextProvider provider = AdapterUtils.adapt(outlinePage.contentOutlinePage, IReloadContextProvider.class, null);
+ context = (provider == null) ? null : provider.createReloadContext();
+ }
+ }
+
+ void restore() {
+ if (diagramToken != null) {
+ try {
+ ModelSet modelSet = multiEditor.getServicesRegistry().getService(ModelSet.class);
+
+ Object diagram = modelSet.getEObject(diagramToken, true);
+ if (diagram != null) {
+ IPage page = sashWindowsContainer.lookupModelPage(diagram);
+ if (page != null) {
+ OutlinePageRec outlinePage = getOutlinePageRec(page, true);
+ if ((outlinePage != null) && (context != null)) {
+ // Restore it. We know it adapts if it provided the reload state in the first place
+ AdapterUtils.adapt(outlinePage.contentOutlinePage, IReloadContextProvider.class, null).restore(context);
+ }
+ }
+ }
+ } catch (ServiceException e) {
+ Activator.log.error(e);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/AbstractStringValueConverter.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/AbstractStringValueConverter.java
new file mode 100644
index 00000000000..813d5a71fbe
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/AbstractStringValueConverter.java
@@ -0,0 +1,86 @@
+/*****************************************************************************
+ * Copyright (c) 2013 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.converter;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.papyrus.infra.ui.Activator;
+import org.eclipse.papyrus.infra.ui.messages.Messages;
+
+/**
+ * Abstract class for String value Container
+ *
+ * @author VL222926
+ *
+ */
+public abstract class AbstractStringValueConverter implements IStringValueConverter {
+
+ protected static final String THE_STRING_X_IS_NOT_VALID_TO_CREATE_Y = Messages.AbstractStringValueConverter_TheStringXIsNotValidToCreateY;
+
+ protected static final String THE_FEATURE_X_CANT_BE_RESOLVED = Messages.AbstractStringValueConverter_TheFeatureXCantBeResolved;
+
+ protected static final String THE_STRING_VALUE_X_CANT_BE_RESOLVED = Messages.AbstractStringValueConverter_TheStringValueXCantBeResolved;
+
+ protected static final String SOME_STRING_ARE_NOT_VALID_TO_CREATE_X = Messages.AbstractStringValueConverter_SomeStringsAreNotValidToCreateY;
+
+ protected static final String SOME_STRING_CANT_BE_RESOLVED_TO_FIND_X = Messages.AbstractStringValueConverter_SomeStringsCantBeResolvedToFindY;
+
+ protected static final String NO_X_REPRESENTED_BY_Y_HAVE_BEEN_FOUND = Messages.AbstractStringValueConverter_NoXReprensentedByYHaveBeenFound;
+
+ private ConvertedValueContainer<?> result;
+
+ /**
+ *
+ * @see org.eclipse.papyrus.infra.ui.converter.IStringValueConverter#deduceValueFromString(java.lang.Object, java.lang.String)
+ *
+ * @param type
+ * @param valueAsString
+ * @return
+ */
+ @Override
+ public final ConvertedValueContainer<?> deduceValueFromString(final Object type, final String valueAsString) {
+ result = doDeduceValueFromString(type, valueAsString);
+ if (result == null) {
+ final IStatus status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, NLS.bind(THE_STRING_VALUE_X_CANT_BE_RESOLVED, valueAsString));
+ result = new ConvertedValueContainer<Object>(null, status);
+ }
+ return result;
+ }
+
+ /**
+ *
+ * @return
+ * the converted value, you should call deduceValueFromString before to call this method
+ */
+ public final ConvertedValueContainer<?> getConvertedValue() {
+ if (this.result == null) {
+ throw new IllegalStateException("You should call deduceValueFromString before to call this method"); //$NON-NLS-1$
+ }
+ return this.result;
+ }
+
+ /**
+ *
+ * @param type
+ * the type of the object
+ * @param valueAsString
+ * the string to resolve
+ * @return
+ * a {@link ConvertedValueContainer} with the resolved values and a status
+ */
+ protected abstract ConvertedValueContainer<?> doDeduceValueFromString(final Object type, final String valueAsString);
+
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/ConvertedValueContainer.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/ConvertedValueContainer.java
new file mode 100644
index 00000000000..e4466c9470d
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/ConvertedValueContainer.java
@@ -0,0 +1,75 @@
+/*****************************************************************************
+ * Copyright (c) 2012 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.converter;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IStatus;
+
+
+/**
+ *
+ * This class allows to store the value created for a pasted String AND a result status associated to this pasted String
+ *
+ * @param <T>
+ */
+
+public class ConvertedValueContainer<T> {
+
+ /**
+ * this field is used when the pasted value is monovalued
+ */
+ private final T value;
+
+ /**
+ * the resulting status of the parsing
+ */
+ private final IStatus status;
+
+ /**
+ *
+ * Constructor.
+ *
+ * @param realValue
+ * a monovalued Value (can be <code>null</code>)
+ * @param realListValue
+ * a collection value (can be <code>null</code>)
+ * @param status
+ * a status (can be <code>null</code>)
+ */
+ public ConvertedValueContainer(final T realValue, final IStatus status) {
+ this.value = realValue;
+ this.status = status;
+ Assert.isNotNull(status);
+ }
+
+
+ /**
+ *
+ * @return
+ * the status of the conversion
+ */
+ public final IStatus getStatus() {
+ return this.status;
+ }
+
+ /**
+ *
+ * @return
+ * the value
+ */
+ public final T getConvertedValue() {
+ return this.value;
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/EMFStringValueConverter.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/EMFStringValueConverter.java
new file mode 100644
index 00000000000..cc42fe5acc9
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/EMFStringValueConverter.java
@@ -0,0 +1,373 @@
+/*****************************************************************************
+ * Copyright (c) 2013 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.converter;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.emf.common.util.Enumerator;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EDataType;
+import org.eclipse.emf.ecore.EEnum;
+import org.eclipse.emf.ecore.EEnumLiteral;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.papyrus.infra.emf.utils.EMFContants;
+import org.eclipse.papyrus.infra.tools.util.BooleanHelper;
+import org.eclipse.papyrus.infra.tools.util.TypesConstants;
+import org.eclipse.papyrus.infra.ui.Activator;
+
+/**
+ * Value solver for EMF
+ *
+ * WARNING : incomplete implementations
+ *
+ * @author vl222926
+ *
+ */
+
+public class EMFStringValueConverter extends AbstractStringValueConverter {
+
+
+
+ /**
+ * Context used for the resolution of the string
+ */
+ private EObject resolutionContext;
+
+ /**
+ * The separator used for multivalue
+ */
+ protected final String multiValueSeparator;
+
+ /**
+ *
+ * Constructor.
+ *
+ * @param resolutionContext
+ * the context used for the resolution of the string
+ */
+ public EMFStringValueConverter(final EObject resolutionContext, final String multiValueSeparator) {
+ this.resolutionContext = resolutionContext;
+ this.multiValueSeparator = multiValueSeparator;
+ }
+
+
+ /**
+ *
+ * @return
+ * the context to use for the resolution
+ */
+ public EObject getResolutionContext() {
+ return resolutionContext;
+ }
+
+ /**
+ *
+ * @see org.eclipse.ui.services.IDisposable#dispose()
+ *
+ */
+ @Override
+ public void dispose() {
+ this.resolutionContext = null;
+ }
+
+ /**
+ *
+ * @param resolutionContext
+ * the table context
+ * @param feature
+ * the feature
+ * @param valueAsString
+ * the pasted string for this feature
+ * @return
+ * the value for the pasted string or <code>null</code> if not found
+ */
+ @Override
+ protected ConvertedValueContainer<?> doDeduceValueFromString(final Object feature, final String valueAsString) {
+ final EClassifier featureType = getFeatureType(feature);
+ if (feature instanceof EStructuralFeature) {
+ return deduceValueFromString(feature, featureType, valueAsString);
+ }
+ return null;
+ }
+
+ /**
+ *
+ * @param feature
+ * @param featureType
+ * @param valueAsString
+ * @return
+ */
+ protected ConvertedValueContainer<?> deduceValueFromString(final Object feature, final EClassifier featureType, final String valueAsString) {
+ ConvertedValueContainer<?> realValue = null;
+ // if(feature instanceof EStructuralFeature) {
+ final int upperbound = getFeatureUpperBound(feature);
+ boolean isMany = (upperbound > 1 || upperbound == -1);
+ if (featureType instanceof EDataType) {
+ if (featureType instanceof EEnum) {
+ realValue = deduceEEnumLiteralValue((EEnum) featureType, isMany, valueAsString);
+ }
+ final String typeName = featureType.getName();
+ if (TypesConstants.STRING.equals(typeName) || EMFContants.ESTRING.equals(typeName)) {
+ realValue = deduceStringValue(isMany, valueAsString);
+ } else if (EMFContants.EBOOLEAN.equals(typeName) || TypesConstants.BOOLEAN.equals(typeName)) {
+ realValue = deduceBooleanValue(isMany, valueAsString);
+ } else if (EMFContants.EINT.equals(typeName) || TypesConstants.INTEGER.equals(typeName)) {
+ realValue = deduceIntValue(isMany, valueAsString);
+ } else if (EMFContants.EDOUBLE.equals(typeName)) {
+ realValue = deduceDoubleValue(isMany, valueAsString);
+ }
+ } else if (featureType instanceof EClass) {
+ realValue = deduceEObjectValue(getResolutionContext(), feature, (EClass) featureType, isMany, valueAsString);
+ }
+ return realValue;
+ }
+
+ protected int getFeatureUpperBound(final Object feature) {
+ return ((EStructuralFeature) feature).getUpperBound();
+ }
+
+
+
+ /**
+ *
+ * @param resolutionContext
+ * the context used for the resolution
+ * @param feature
+ * the feature
+ * @param featureType
+ * the type of the feature
+ * @param isMany
+ * <code>true</code> if the feature isMany
+ * @param valueAsString
+ * the string value to resolve
+ * @return
+ * a value container referencing the eobject represented by the string
+ * @throws StringValueSolverException
+ */
+ protected ConvertedValueContainer<?> deduceEObjectValue(EObject resolutionContext, Object feature, EClass featureType, boolean isMany, String valueAsString) {
+ if (valueAsString == null || valueAsString.equals("")) {
+ return new ConvertedValueContainer<EObject>(null, Status.OK_STATUS);
+ }
+ final IStatus status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, NLS.bind(THE_STRING_VALUE_X_CANT_BE_RESOLVED, valueAsString));
+ return new ConvertedValueContainer<EObject>(null, status);
+ }
+
+ /**
+ *
+ * @param feature
+ * an object representing a feature
+ * @return
+ * the type of the feature
+ */
+ protected EClassifier getFeatureType(final Object feature) {
+ final EClassifier featureType;
+ if (feature instanceof EStructuralFeature) {
+ return ((EStructuralFeature) feature).getEType();
+ } else {
+ featureType = null;
+ }
+ return featureType;
+ }
+
+ /**
+ *
+ * @param eenum
+ * the enumeration
+ * @param isMany
+ * <code>true</code> if the feature is many
+ * @param valueAsString
+ * the value to convert
+ * @return
+ * the converted value
+ */
+ protected ConvertedValueContainer<?> deduceEEnumLiteralValue(final EEnum eenum, final boolean isMany, final String valueAsString) {
+ ConvertedValueContainer<?> returnedValue = null;
+ IStatus iStatus = Status.OK_STATUS;
+ final Collection<String> unresolvedValues = new ArrayList<String>();
+ if (isMany) {
+ final Collection<EEnumLiteral> values = new ArrayList<EEnumLiteral>();
+ for (final String str : valueAsString.split(this.multiValueSeparator)) {
+ final EEnumLiteral literal = eenum.getEEnumLiteral(str);
+ if (literal != null) {
+ values.add(literal);
+ } else {
+ unresolvedValues.add(str);
+ }
+ }
+ if (!unresolvedValues.isEmpty()) {
+ iStatus = new StringValueConverterStatus(IStatus.ERROR, Activator.PLUGIN_ID, NLS.bind(SOME_STRING_ARE_NOT_VALID_TO_CREATE_X, EMFContants.EENUM_LITERAL), unresolvedValues);
+ }
+ returnedValue = new MultiConvertedValueContainer<EEnumLiteral>(values, iStatus);
+ } else {
+ final EEnumLiteral literal = eenum.getEEnumLiteral(valueAsString);
+ if (literal != null) {
+ // returnedValue = new ConvertedValueContainer<EEnumLiteral>(literal, iStatus);
+ // fix a bug on enumerator
+ returnedValue = new ConvertedValueContainer<Enumerator>(literal.getInstance(), iStatus);
+ } else {
+ unresolvedValues.add(valueAsString);
+ iStatus = new StringValueConverterStatus(IStatus.ERROR, Activator.PLUGIN_ID, NLS.bind(THE_STRING_X_IS_NOT_VALID_TO_CREATE_Y, valueAsString, EMFContants.EENUM_LITERAL), unresolvedValues);
+ returnedValue = new ConvertedValueContainer<Boolean>(null, iStatus);
+ }
+ }
+ return returnedValue;
+ }
+
+ /**
+ *
+ * @param isMany
+ * <code>true</code> if the feature isMany
+ * @param valueAsString
+ * the value to parse
+ * @return
+ * the result of the parsing
+ */
+ protected ConvertedValueContainer<?> deduceBooleanValue(final boolean isMany, final String valueAsString) {
+ ConvertedValueContainer<?> returnedValue = null;
+ IStatus iStatus = Status.OK_STATUS;
+ final Collection<String> unresolvedValues = new ArrayList<String>();
+ if (isMany) {
+ final Collection<Boolean> values = new ArrayList<Boolean>();
+ for (final String str : valueAsString.split(this.multiValueSeparator)) {
+ if (BooleanHelper.isBoolean(str)) {
+ values.add(Boolean.valueOf(valueAsString));
+ } else {
+ unresolvedValues.add(str);
+ }
+ }
+ if (!unresolvedValues.isEmpty()) {
+ iStatus = new StringValueConverterStatus(IStatus.ERROR, Activator.PLUGIN_ID, NLS.bind(SOME_STRING_ARE_NOT_VALID_TO_CREATE_X, TypesConstants.BOOLEAN), unresolvedValues);
+ }
+ returnedValue = new MultiConvertedValueContainer<Boolean>(values, iStatus);
+ } else {
+ if (BooleanHelper.isBoolean(valueAsString)) {
+ returnedValue = new ConvertedValueContainer<Boolean>(Boolean.valueOf(valueAsString), iStatus);
+ } else {
+ unresolvedValues.add(valueAsString);
+ iStatus = new StringValueConverterStatus(IStatus.ERROR, Activator.PLUGIN_ID, NLS.bind(THE_STRING_X_IS_NOT_VALID_TO_CREATE_Y, valueAsString, TypesConstants.BOOLEAN), unresolvedValues);
+ returnedValue = new ConvertedValueContainer<Boolean>(null, iStatus);
+ }
+ }
+ return returnedValue;
+ }
+
+ /**
+ *
+ * @param isMany
+ * <code>true</code> if the feature isMany
+ * @param valueAsString
+ * the value to parse
+ * @return
+ * the result of the parsing
+ */
+ protected ConvertedValueContainer<?> deduceDoubleValue(final boolean isMany, final String valueAsString) {
+ ConvertedValueContainer<?> returnedValue = null;
+ IStatus iStatus = Status.OK_STATUS;
+ final Collection<String> unresolvedValues = new ArrayList<String>();
+ if (isMany) {
+ final Collection<Double> values = new ArrayList<Double>();
+ for (final String str : valueAsString.split(this.multiValueSeparator)) {
+ final Double value = Double.valueOf(str);
+ if (value != null) {
+ values.add(value);
+ } else {
+ unresolvedValues.add(str);
+ }
+ }
+ if (!unresolvedValues.isEmpty()) {
+ iStatus = new StringValueConverterStatus(IStatus.ERROR, Activator.PLUGIN_ID, NLS.bind(SOME_STRING_ARE_NOT_VALID_TO_CREATE_X, TypesConstants.DOUBLE), unresolvedValues);
+ }
+ returnedValue = new MultiConvertedValueContainer<Double>(values, iStatus);
+ } else {
+ try {
+ returnedValue = new ConvertedValueContainer<Double>(Double.valueOf(valueAsString), iStatus);
+ } catch (final NumberFormatException e) {
+ unresolvedValues.add(valueAsString);
+ iStatus = new StringValueConverterStatus(IStatus.ERROR, Activator.PLUGIN_ID, NLS.bind(THE_STRING_X_IS_NOT_VALID_TO_CREATE_Y, valueAsString, TypesConstants.DOUBLE), unresolvedValues);
+ returnedValue = new ConvertedValueContainer<Boolean>(null, iStatus);
+ }
+ }
+ return returnedValue;
+ }
+
+ /**
+ *
+ * @param isMany
+ * <code>true</code> if the feature isMany
+ * @param valueAsString
+ * the value to parse
+ * @return
+ * the result of the parsing
+ */
+ protected ConvertedValueContainer<?> deduceIntValue(final boolean isMany, final String valueAsString) {
+ ConvertedValueContainer<?> returnedValue = null;
+ IStatus iStatus = Status.OK_STATUS;
+ final Collection<String> unresolvedValues = new ArrayList<String>();
+ if (isMany) {
+ final Collection<Integer> values = new ArrayList<Integer>();
+ for (final String str : valueAsString.split(this.multiValueSeparator)) {
+ try {
+ values.add(Integer.valueOf(str));
+ } catch (final NumberFormatException e) {
+ unresolvedValues.add(str);
+ }
+ }
+ if (!unresolvedValues.isEmpty()) {
+ iStatus = new StringValueConverterStatus(IStatus.ERROR, Activator.PLUGIN_ID, NLS.bind(SOME_STRING_ARE_NOT_VALID_TO_CREATE_X, TypesConstants.INTEGER), unresolvedValues);
+ }
+ returnedValue = new MultiConvertedValueContainer<Integer>(values, iStatus);
+ } else {
+ try {
+ returnedValue = new ConvertedValueContainer<Integer>(Integer.valueOf(valueAsString), iStatus);
+ } catch (final NumberFormatException e) {
+ unresolvedValues.add(valueAsString);
+ iStatus = new StringValueConverterStatus(IStatus.ERROR, Activator.PLUGIN_ID, NLS.bind(THE_STRING_X_IS_NOT_VALID_TO_CREATE_Y, valueAsString, TypesConstants.INTEGER), unresolvedValues);
+ returnedValue = new ConvertedValueContainer<Boolean>(null, iStatus);
+ }
+ }
+ return returnedValue;
+ }
+
+
+ /**
+ *
+ * @param isMany
+ * <code>true</code> if the feature is many
+ * @param valueAsString
+ * the value as string
+ * @return
+ * the value container with the real value(s)
+ */
+ protected ConvertedValueContainer<?> deduceStringValue(final boolean isMany, final String valueAsString) {
+ ConvertedValueContainer<?> returnedValue = null;
+ final IStatus iStatus = Status.OK_STATUS;
+ if (isMany) {
+ final Collection<String> values = new ArrayList<String>();
+ for (final String str : valueAsString.split(this.multiValueSeparator)) {
+ values.add(str);
+ }
+ returnedValue = new MultiConvertedValueContainer<String>(values, iStatus);
+ } else {
+ returnedValue = new ConvertedValueContainer<String>(valueAsString, iStatus);
+ }
+ return returnedValue;
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/IStringValueConverter.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/IStringValueConverter.java
new file mode 100644
index 00000000000..242c4acc523
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/IStringValueConverter.java
@@ -0,0 +1,36 @@
+/*****************************************************************************
+ * Copyright (c) 2013 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.converter;
+
+import org.eclipse.ui.services.IDisposable;
+
+/**
+ * Common interface for string converter
+ *
+ * @author VL222926
+ *
+ */
+public interface IStringValueConverter extends IDisposable {
+
+ /**
+ *
+ * @param type
+ * an object representing the type of the in which we want to convert the string
+ * @param valueAsString
+ * the value represented by a string
+ * @return
+ * a {@link ConvertedValueContainer}
+ */
+ public ConvertedValueContainer<?> deduceValueFromString(final Object type, final String valueAsString);
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/MultiConvertedValueContainer.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/MultiConvertedValueContainer.java
new file mode 100644
index 00000000000..13aacbf3396
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/MultiConvertedValueContainer.java
@@ -0,0 +1,39 @@
+/*****************************************************************************
+ * Copyright (c) 2012 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.converter;
+
+import java.util.Collection;
+
+import org.eclipse.core.runtime.IStatus;
+
+/**
+ *
+ * This class allows to store the value created for a pasted String AND a result status associated to this pasted String
+ *
+ * @param <T>
+ */
+public class MultiConvertedValueContainer<T> extends ConvertedValueContainer<Collection<T>> {
+
+
+ /**
+ *
+ * Constructor.
+ *
+ * @param realValue
+ * @param status
+ */
+ public MultiConvertedValueContainer(final Collection<T> realValue, final IStatus status) {
+ super(realValue, status);
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/StringValueConverterStatus.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/StringValueConverterStatus.java
new file mode 100644
index 00000000000..8a41a9edaa3
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/StringValueConverterStatus.java
@@ -0,0 +1,60 @@
+/*****************************************************************************
+ * Copyright (c) 2013 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.converter;
+
+import java.util.Collection;
+
+import org.eclipse.core.runtime.Status;
+
+/**
+ * This status is used y the String Value solvers
+ *
+ * @author vl222926
+ *
+ */
+public class StringValueConverterStatus extends Status {
+
+ /**
+ * the list of the uresolved strings
+ */
+ private Collection<String> unresolvedString;
+
+ /**
+ *
+ * Constructor.
+ *
+ * @param severity
+ * the severity of the status
+ * @param pluginId
+ * the plugin id providing this status
+ * @param message
+ * the message for this status
+ * @param unresolvedString
+ * the list of the unresolved string
+ */
+ public StringValueConverterStatus(int severity, String pluginId, String message, Collection<String> unresolvedString) {
+ super(severity, pluginId, message);
+ this.unresolvedString = unresolvedString;
+ }
+
+
+ /**
+ *
+ * @return
+ * the list of the unresolved string
+ */
+ public final Collection<String> getUnresolvedString() {
+ return unresolvedString;
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/dnd/PapyrusTransfer.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/dnd/PapyrusTransfer.java
new file mode 100644
index 00000000000..a31e0562b90
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/dnd/PapyrusTransfer.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 IBM Corporation, Christian W. Damus, and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Christian W. Damus - adapted from GEF for bug 469188
+ *******************************************************************************/
+package org.eclipse.papyrus.infra.ui.dnd;
+
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+
+import org.eclipse.swt.dnd.ByteArrayTransfer;
+import org.eclipse.swt.dnd.TransferData;
+
+/**
+ * A local transfer carrying a single object being dragged. Subclasses should maintain a
+ * single instance of their Transfer and provide a static method to obtain that
+ * instance.
+ */
+public abstract class PapyrusTransfer<T> extends ByteArrayTransfer {
+
+ private final Class<? extends T> objectType;
+ private final String typeName;
+ private final int typeID;
+
+ private Reference<T> object;
+ private long startTime;
+
+ protected PapyrusTransfer(Class<? extends T> objectType) {
+ super();
+
+ this.objectType = objectType;
+
+ typeName = String.format("%s:%x:%x", getClass().getSimpleName(), hashCode(), System.currentTimeMillis());
+ typeID = registerType(typeName);
+ }
+
+ @Override
+ public final int hashCode() {
+ return System.identityHashCode(this);
+ }
+
+ /**
+ * The data object is not converted to bytes. It is held onto in a field.
+ * Instead, a checksum is written out to prevent unwanted drags across
+ * mulitple running copies of Eclipse.
+ *
+ * @see org.eclipse.swt.dnd.Transfer#javaToNative(Object, TransferData)
+ */
+ @Override
+ public void javaToNative(Object object, TransferData transferData) {
+ setObject(objectType.cast(object));
+ startTime = System.currentTimeMillis();
+ if (transferData != null)
+ super.javaToNative(String.valueOf(startTime).getBytes(),
+ transferData);
+ }
+
+ /**
+ * The data object is not converted to bytes. It is held onto in a field.
+ * Instead, a checksum is written out to prevent unwanted drags across
+ * mulitple running. copies of Eclipse.
+ *
+ * @see org.eclipse.swt.dnd.Transfer#nativeToJava(TransferData)
+ */
+ @Override
+ public Object nativeToJava(TransferData transferData) {
+ byte bytes[] = (byte[]) super.nativeToJava(transferData);
+ if (bytes == null) {
+ return null;
+ }
+ long startTime = Long.parseLong(new String(bytes));
+ return (this.startTime == startTime) ? getObject() : null;
+ }
+
+ /**
+ * Obtains the object being dragged.
+ */
+ public T getObject() {
+ return (object == null) ? null : objectType.cast(object.get());
+ }
+
+ /**
+ * Sets the object being dragged.
+ */
+ public void setObject(T object) {
+ this.object = new WeakReference<>(object);
+ }
+
+ @Override
+ protected int[] getTypeIds() {
+ return new int[] { typeID };
+ }
+
+ @Override
+ protected String[] getTypeNames() {
+ return new String[] { typeName };
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/ContentProviderServiceFactory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/ContentProviderServiceFactory.java
new file mode 100644
index 00000000000..e67c81034fb
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/ContentProviderServiceFactory.java
@@ -0,0 +1,68 @@
+/**
+ *
+ */
+package org.eclipse.papyrus.infra.ui.editor;
+
+import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.ISashWindowsContentProvider;
+import org.eclipse.papyrus.infra.core.sasheditor.di.contentprovider.DiSashModelManager;
+import org.eclipse.papyrus.infra.core.services.IServiceFactory;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+
+/**
+ * A service factory to create the {@link ISashWindowsContentProvider} service.
+ * This service depends on {@link DiSashModelMngrServiceFactory}.
+ *
+ * @author cedric dumoulin
+ *
+ */
+public class ContentProviderServiceFactory implements IServiceFactory {
+
+ /**
+ * The sashModelMangr.
+ */
+ private DiSashModelManager sashModelMngr;
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IService#init(org.eclipse.papyrus.infra.core.services.ServicesRegistry)
+ *
+ * @param servicesRegistry
+ * @throws ServiceException
+ */
+ @Override
+ public void init(ServicesRegistry servicesRegistry) throws ServiceException {
+ // Get required services
+ sashModelMngr = servicesRegistry.getService(DiSashModelManager.class);
+
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IService#startService()
+ *
+ * @throws ServiceException
+ */
+ @Override
+ public void startService() throws ServiceException {
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IService#disposeService()
+ *
+ * @throws ServiceException
+ */
+ @Override
+ public void disposeService() throws ServiceException {
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IServiceFactory#createServiceInstance()
+ *
+ * @return
+ * @throws ServiceException
+ */
+ @Override
+ public Object createServiceInstance() throws ServiceException {
+ return sashModelMngr.getISashWindowsContentProvider();
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/CoreMultiDiagramEditor.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/CoreMultiDiagramEditor.java
new file mode 100644
index 00000000000..983e28735ec
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/CoreMultiDiagramEditor.java
@@ -0,0 +1,1244 @@
+/*****************************************************************************
+ * Copyright (c) 2008, 2016 LIFL, CEA LIST, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - manage models by URI, not IFile (CDO)
+ * Christian W. Damus (CEA) - bug 410346
+ * Christian W. Damus (CEA) - bug 431953 (pre-requisite refactoring of ModelSet service start-up)
+ * Christian W. Damus (CEA) - bug 437217
+ * Christian W. Damus - bugs 469464, 469188, 485220
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.ui.editor;
+
+import static org.eclipse.papyrus.infra.core.Activator.log;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.eclipse.core.commands.operations.IUndoContext;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.common.ui.URIEditorInput;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
+import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.emf.edit.domain.IEditingDomainProvider;
+import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
+import org.eclipse.emf.edit.provider.IItemLabelProvider;
+import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.papyrus.infra.core.editor.BackboneException;
+import org.eclipse.papyrus.infra.core.language.ILanguageChangeListener;
+import org.eclipse.papyrus.infra.core.language.ILanguageService;
+import org.eclipse.papyrus.infra.core.language.LanguageChangeEvent;
+import org.eclipse.papyrus.infra.core.resource.ModelMultiException;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.IContentChangedListener;
+import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.ISashWindowsContentProvider;
+import org.eclipse.papyrus.infra.core.sasheditor.di.contentprovider.DiSashModelManager;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.AbstractMultiPageSashEditor;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.ISashWindowsContainer;
+import org.eclipse.papyrus.infra.core.sashwindows.di.service.IPageManager;
+import org.eclipse.papyrus.infra.core.services.ExtensionServicesRegistry;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.services.ServiceMultiException;
+import org.eclipse.papyrus.infra.core.services.ServiceStartKind;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.core.utils.ServiceUtils;
+import org.eclipse.papyrus.infra.ui.Activator;
+import org.eclipse.papyrus.infra.ui.contentoutline.ContentOutlineRegistry;
+import org.eclipse.papyrus.infra.ui.editor.IReloadableEditor.DirtyPolicy;
+import org.eclipse.papyrus.infra.ui.editor.reload.EditorReloadEvent;
+import org.eclipse.papyrus.infra.ui.editor.reload.IEditorReloadListener;
+import org.eclipse.papyrus.infra.ui.lifecycleevents.DoSaveEvent;
+import org.eclipse.papyrus.infra.ui.lifecycleevents.IEditorInputChangedListener;
+import org.eclipse.papyrus.infra.ui.lifecycleevents.ISaveAndDirtyService;
+import org.eclipse.papyrus.infra.ui.multidiagram.actionbarcontributor.ActionBarContributorRegistry;
+import org.eclipse.papyrus.infra.ui.multidiagram.actionbarcontributor.CoreComposedActionBarContributor;
+import org.eclipse.papyrus.infra.ui.services.EditorLifecycleManager;
+import org.eclipse.papyrus.infra.ui.services.internal.EditorLifecycleManagerImpl;
+import org.eclipse.papyrus.infra.ui.services.internal.InternalEditorLifecycleManager;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IEditorActionBarContributor;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.IFileEditorInput;
+import org.eclipse.ui.IURIEditorInput;
+import org.eclipse.ui.IViewReference;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchActionConstants;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.ide.IGotoMarker;
+import org.eclipse.ui.part.FileEditorInput;
+import org.eclipse.ui.progress.UIJob;
+import org.eclipse.ui.statushandlers.StatusManager;
+import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
+import org.eclipse.ui.views.properties.IPropertySheetPage;
+import org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Multi diagram editor allowing to plug various kind of editors. Editors are
+ * registered with the help of the Eclipse extension mechanism. This
+ * implementation allows to register editors and context separately. An editor
+ * should specify which context it need to run. This multi diagram editor allows
+ * to show editor side by side in one or more sash windows.
+ *
+ * The real implementation for the generic type T of SashMultiPageEditorPart is
+ * actually di2.Diagram
+ *
+ * @author cedric dumoulin
+ * @author <a href="mailto:jerome.benois@obeo.fr">Jerome Benois</a>
+ * @author <a href="mailto:thomas.szadel@atosorigin.com">Thomas Szadel</a>
+ * Refactoring.
+ *
+ * TODO : remove GMF dependency !
+ */
+public class CoreMultiDiagramEditor extends AbstractMultiPageSashEditor implements IMultiDiagramEditor, ITabbedPropertySheetPageContributor, IGotoMarker, IEditingDomainProvider {
+
+ /** ContentOutline registry */
+ private ContentOutlineRegistry contentOutlineRegistry;
+
+ /** Services registry. Used to get registered services */
+ private ServicesRegistry servicesRegistry;
+
+ /**
+ * ActionBarContributor Registry. Allows to get an ActionBar by its Id. The
+ * registry is initialized from the Eclipse extension mechanism.
+ */
+ private ActionBarContributorRegistry actionBarContributorRegistry;
+
+ /** SashModelMngr to add pages */
+ protected DiSashModelManager sashModelMngr;
+
+ /**
+ * Service used to maintain the dirty state and to perform save and saveAs.
+ */
+ protected ISaveAndDirtyService saveAndDirtyService;
+
+ private final List<IPropertySheetPage> propertiesPages = new LinkedList<IPropertySheetPage>();
+
+ private final List<Runnable> closeActions = new ArrayList<>();
+
+ /**
+ * Listener on {@link ISaveAndDirtyService#addInputChangedListener(IEditorInputChangedListener)}
+ */
+ private static class EditorInputChangedListener implements IEditorInputChangedListener {
+
+ private CoreMultiDiagramEditor editor;
+
+ public EditorInputChangedListener(CoreMultiDiagramEditor editor) {
+ this.editor = editor;
+ }
+
+ /**
+ * This method is called when the editor input is changed from the
+ * ISaveAndDirtyService.
+ *
+ * @see org.eclipse.papyrus.infra.ui.lifecycleevents.IEditorInputChangedListener#editorInputChanged(org.eclipse.ui.part.FileEditorInput)
+ *
+ * @param fileEditorInput
+ */
+ @Override
+ public void editorInputChanged(FileEditorInput fileEditorInput) {
+ // Change the editor input.
+ editor.setInputWithNotify(fileEditorInput);
+ editor.setPartName(fileEditorInput.getName());
+ }
+
+ /**
+ * The isDirty flag has changed, reflect its new value
+ *
+ * @see org.eclipse.papyrus.infra.ui.lifecycleevents.IEditorInputChangedListener#isDirtyChanged()
+ *
+ */
+ @Override
+ public void isDirtyChanged() {
+
+ // Run it in async way.
+ editor.getSite().getShell().getDisplay().asyncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ // editor can be null if this object has been finalized, but
+ // still queued in the asyncExec queue.
+ // This can happen if the editor is disposed, but some run still in
+ // the exec queue.
+ // When the method is executed asynchronously, the object is already finalized, and so
+ // editor is null.
+ if (editor == null) {
+ return;
+ }
+ editor.firePropertyChange(IEditorPart.PROP_DIRTY);
+ }
+ });
+ }
+
+ public void dispose() {
+ this.editor = null;
+ }
+ }
+
+ protected EditorInputChangedListener editorInputChangedListener;
+
+ private TransactionalEditingDomain transactionalEditingDomain;
+
+ /**
+ * Object managing models lifeCycle.
+ */
+ protected ModelSet resourceSet;
+
+ /**
+ * Cached event that can be reused.
+ */
+ protected DoSaveEvent lifeCycleEvent;
+
+ private class ContentChangedListener implements IContentChangedListener {
+
+ /**
+ * Called when the content is changed. RefreshTabs.
+ */
+ @Override
+ public void contentChanged(ContentEvent event) {
+ scheduleRefresh();
+ }
+ }
+
+ /**
+ * A listener on model change events.
+ */
+ private ContentChangedListener contentChangedListener;
+
+ /**
+ * Undo context used to have the same undo context in all Papyrus related
+ * views and editors. TODO : move away, use a version independent of GMF,
+ * add a listener that will add the context to all commands modifying
+ * attached Resources (==> linked to ModelSet ?)
+ */
+ private IUndoContext undoContext;
+
+ /**
+ * Editor reload listeners.
+ */
+ private CopyOnWriteArrayList<IEditorReloadListener> reloadListeners = new CopyOnWriteArrayList<IEditorReloadListener>();
+
+ /**
+ * A pending reload operation (awaiting next activation of the editor).
+ */
+ private final AtomicReference<DeferredReload> pendingReload = new AtomicReference<DeferredReload>();
+
+ public CoreMultiDiagramEditor() {
+ super();
+
+ addSelfReloadListener();
+ }
+
+ /**
+ * Get the contentOutlineRegistry. Create it if needed.
+ *
+ * @return the contentOutlineRegistry
+ */
+ protected ContentOutlineRegistry getContentOutlineRegistry() {
+ if (contentOutlineRegistry == null) {
+ createContentOutlineRegistry();
+ }
+
+ return contentOutlineRegistry;
+ }
+
+ /**
+ * Create the contentOutlineRegistry.
+ */
+ private void createContentOutlineRegistry() {
+ contentOutlineRegistry = new ContentOutlineRegistry(this, Activator.PLUGIN_ID);
+ }
+
+ /**
+ * Returns the service registry associated to the editor.
+ *
+ * @return the servicesRegistry The registry.
+ */
+ @Override
+ public ServicesRegistry getServicesRegistry() {
+ if (servicesRegistry == null) {
+ servicesRegistry = createServicesRegistry();
+ }
+ return servicesRegistry;
+ }
+
+ /**
+ * Create the ServicesRegistry.
+ *
+ * @return
+ */
+ private ServicesRegistry createServicesRegistry() {
+ // Create Services Registry
+ try {
+ ServicesRegistry servicesRegistry = new ExtensionServicesRegistry(org.eclipse.papyrus.infra.core.Activator.PLUGIN_ID);
+ // servicesRegistry.startRegistry();
+ return servicesRegistry;
+ } catch (ServiceException e) {
+ // Show log and error
+ log.error(e.getMessage(), e);
+ }
+ return null;
+ }
+
+ /**
+ * Do nothing as we create the provider before any calls to this method.
+ * Should not be called by subclasses.
+ *
+ * @see org.eclipse.papyrus.infra.core.sasheditor.editor.AbstractMultiPageSashEditor#createPageProvider()
+ */
+ @Override
+ protected ISashWindowsContentProvider createPageProvider() {
+ throw new UnsupportedOperationException("Not implemented. Should not be called as the ContentProvider is already initialized.");
+ }
+
+ /**
+ * Create the pageContentProvider.
+ *
+ * Removed since 0.10.0
+ *
+ * @param pageFactory
+ * @param diResource
+ * Resource used to load/save the SashModel.
+ *
+ *
+ */
+ // protected ISashWindowsContentProvider createPageProvider(IPageModelFactory pageFactory, Resource diResource, TransactionalEditingDomain editingDomain) {
+ //
+ // sashModelMngr = new TransactionalDiSashModelMngr(pageFactory, diResource, editingDomain);
+ //
+ // ISashWindowsContentProvider pageProvider = sashModelMngr.getISashWindowsContentProvider();
+ //
+ // return pageProvider;
+ // }
+
+ /**
+ * Get The {@link IPageMngr} used to add, open, remove or close a diagram in
+ * the SashWindow. This method is available as soon as the {@link CoreMultiDiagramEditor#init(IEditorSite, IEditorInput)} method is
+ * called.
+ *
+ * @return
+ */
+ protected IPageManager getIPageManager() throws IllegalStateException {
+ try {
+ return sashModelMngr.getIPageManager();
+ } catch (Exception e) {
+ throw new IllegalStateException("Method should be called after CoreMultiDiagramEditor#init(IEditorSite, IEditorInput) is called");
+ }
+ }
+
+ /**
+ * Get the ActionBarContributorRegistry. Creates it if necessary.
+ *
+ * @return
+ */
+ protected ActionBarContributorRegistry getActionBarContributorRegistry() {
+ if (actionBarContributorRegistry != null) {
+ return actionBarContributorRegistry;
+ }
+
+ // Try to got it from CoreComposedActionBarContributor
+ // Get it from the contributor.
+ IEditorActionBarContributor contributor = getEditorSite().getActionBarContributor();
+ if (contributor instanceof CoreComposedActionBarContributor) {
+ log.debug(getClass().getSimpleName() + " - ActionBarContributorRegistry loaded from CoreComposedActionBarContributor.");
+ return ((CoreComposedActionBarContributor) contributor).getActionBarContributorRegistry();
+ } else {
+ // Create a registry.
+ log.debug(getClass().getSimpleName() + " - create an ActionBarContributorRegistry.");
+ return createActionBarContributorRegistry();
+ }
+
+ }
+
+ /**
+ * Create the ActionBarContributorRegistry.
+ *
+ * @return
+ */
+ private ActionBarContributorRegistry createActionBarContributorRegistry() {
+ return new ActionBarContributorRegistry(Activator.PLUGIN_ID);
+ }
+
+ /**
+ *
+ *
+ * @param adapter
+ *
+ * @return
+ */
+ @SuppressWarnings("rawtypes")
+ @Override
+ public Object getAdapter(Class adapter) {
+
+ if (ServicesRegistry.class == adapter) {
+ return getServicesRegistry();
+ }
+
+ if (IPageManager.class == adapter) {
+ return getIPageManager();
+ }
+
+ if (IPropertySheetPage.class == adapter) {
+ // Do not test if tabbedPropertySheetPage is null before calling new
+ // this is managed by Eclipse which only call current method when
+ // necessary
+ return getPropertySheetPage();
+ }
+
+ // Add a viewer
+ if (IContentOutlinePage.class == adapter) {
+ try {
+ ContentOutlineRegistry outlineRegistry = getContentOutlineRegistry();
+ if (outlineRegistry == null) {
+ return null;
+ }
+ IContentOutlinePage contentOutline = outlineRegistry.getContentOutline();
+ if (contentOutline != null) {
+ return contentOutline;
+ }
+ } catch (BackboneException e) {
+ // Ignore: There is not registered outline.
+ }
+ }
+
+ if (EditingDomain.class == adapter || TransactionalEditingDomain.class == adapter) {
+ return transactionalEditingDomain;
+ }
+
+ /*
+ * Return context used for undo/redo. All papyrus views should use this
+ * context. The prefer way to get this is to use undoContext =
+ * servicesRegistry.getService(IUndoContext.class);
+ */
+ if (IUndoContext.class == adapter) {
+ return undoContext;
+ }
+
+ // EMF requirements
+ if (IEditingDomainProvider.class == adapter) {
+ return this;
+ }
+
+ if (adapter == ISelection.class) {
+ return getSite().getSelectionProvider().getSelection();
+ }
+
+ if (adapter == IReloadableEditor.class) {
+ return createReloadAdapter();
+ }
+
+ return super.getAdapter(adapter);
+ }
+
+ /**
+ * Init the editor.
+ */
+ @Override
+ public void init(IEditorSite site, IEditorInput input) throws PartInitException {
+ // Init super
+ super.init(site, input);
+
+ // Set editor name
+ setPartName(input.getName());
+
+ initContents();
+ }
+
+ @Override
+ public void createPartControl(Composite parent) {
+ super.createPartControl(parent);
+
+ // Fire the PreDisplay event synchronously, so that listeners can continue
+ // setting up the UI before the contents are actually rendered fully
+ getLifecycleManager().firePreDisplay(this);
+
+ // Fire the PostDisplay event asynchronously, to leave time to the Eclipse
+ // framework to actually display the contents of the editor
+ Display.getDefault().asyncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ // Because we are asynchronous, the editor may already have been disposed
+ // (Especially in the case of tests running in the UI Thread)
+ if (servicesRegistry == null) {
+ return;
+ }
+ getLifecycleManager().firePostDisplay(CoreMultiDiagramEditor.this);
+ }
+ });
+
+ }
+
+ protected void loadModelAndServices() throws PartInitException {
+ // Create ServicesRegistry and register services
+ servicesRegistry = createServicesRegistry();
+
+ // Add itself as a service
+ servicesRegistry.add(IMultiDiagramEditor.class, 1, this);
+
+ // Create lifeCycle event provider and the event that is used when the editor fire a save event.
+ // lifeCycleEventsProvider = new LifeCycleEventsProvider();
+ // lifeCycleEvent = new DoSaveEvent(servicesRegistry, this);
+ // servicesRegistry.add(ILifeCycleEventsProvider.class, 1, lifeCycleEventsProvider);
+
+ // register services
+ servicesRegistry.add(ActionBarContributorRegistry.class, 1, getActionBarContributorRegistry());
+ // servicesRegistry.add(TransactionalEditingDomain.class, 1, transactionalEditingDomain);
+ // servicesRegistry.add(DiResourceSet.class, 1, resourceSet);
+
+ // Create and initalize editor icons service
+ // PageIconsRegistry pageIconsRegistry = new PageIconsRegistry();
+ // PluggableEditorFactoryReader editorReader = new PluggableEditorFactoryReader(Activator.PLUGIN_ID);
+ // editorReader.populate(pageIconsRegistry);
+ // servicesRegistry.add(IPageIconsRegistry.class, 1, pageIconsRegistry);
+
+
+ // Create PageModelRegistry requested by content provider.
+ // Also populate it from extensions.
+ // PageModelFactoryRegistry pageModelRegistry = new PageModelFactoryRegistry();
+ // editorReader.populate(pageModelRegistry, servicesRegistry);
+
+ // TODO : create appropriate Resource for the contentProvider, and pass it here.
+ // This will allow to remove the old sash stuff.
+ // setContentProvider(createPageProvider(pageModelRegistry, resourceSet.getDiResource(), transactionalEditingDomain));
+ // servicesRegistry.add(ISashWindowsContentProvider.class, 1, getContentProvider());
+ // servicesRegistry.add(IPageMngr.class, 1, getIPageMngr());
+
+ // register a basic label provider
+ // adapter factory used by EMF objects
+ AdapterFactory factory = null;
+ try {
+ EditingDomain domain = ServiceUtils.getInstance().getTransactionalEditingDomain(servicesRegistry);
+ if (domain instanceof AdapterFactoryEditingDomain) {
+ // Use the adapter factory already provided by this editing domain
+ factory = ((AdapterFactoryEditingDomain) domain).getAdapterFactory();
+ }
+ } catch (ServiceException e) {
+ // OK, there's no editing domain. That's fine
+ }
+
+ if (factory == null) {
+ // Must create a new adapter factory
+ factory = new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE);
+ }
+
+ /** label provider for EMF objects */
+ ILabelProvider labelProvider = new AdapterFactoryLabelProvider(factory) {
+
+ /**
+ * This implements {@link ILabelProvider}.getText by forwarding it
+ * to an object that implements {@link IItemLabelProvider#getText
+ * IItemLabelProvider.getText}
+ */
+ @Override
+ public String getText(Object object) {
+ // Get the adapter from the factory.
+ //
+ IItemLabelProvider itemLabelProvider = (IItemLabelProvider) adapterFactory.adapt(object, IItemLabelProvider.class);
+ if (object instanceof EObject) {
+ if (((EObject) object).eIsProxy()) {
+ return "Proxy - " + object;
+ }
+ }
+ return itemLabelProvider != null ? itemLabelProvider.getText(object) : object == null ? "" : object.toString();
+ }
+ };
+ servicesRegistry.add(ILabelProvider.class, 1, labelProvider);
+
+ EditorLifecycleManager lifecycleManager = new EditorLifecycleManagerImpl();
+ servicesRegistry.add(EditorLifecycleManager.class, 1, lifecycleManager, ServiceStartKind.LAZY);
+
+ // Start servicesRegistry
+ URI uri;
+ IEditorInput input = getEditorInput();
+ if (input instanceof IFileEditorInput) {
+ uri = URI.createPlatformResourceURI(((IFileEditorInput) input).getFile().getFullPath().toString(), true);
+ } else if (input instanceof URIEditorInput) {
+ uri = ((URIEditorInput) input).getURI();
+ } else {
+ uri = URI.createURI(((IURIEditorInput) input).getURI().toString());
+ }
+
+ try {
+ // Start the ModelSet first, and load if from the specified File.
+ // Also start me so that I may be retrieved from the registry by other services
+ List<Class<?>> servicesToStart = new ArrayList<Class<?>>(1);
+ servicesToStart.add(ModelSet.class);
+ servicesToStart.add(IMultiDiagramEditor.class);
+
+ servicesRegistry.startServicesByClassKeys(servicesToStart);
+
+ resourceSet = servicesRegistry.getService(ModelSet.class);
+ resourceSet.loadModels(uri);
+
+ // start remaining services
+ servicesRegistry.startRegistry();
+ } catch (ModelMultiException e) {
+ try {
+ // with the ModelMultiException it is still possible to open the
+ // editors that's why the service registry is still started
+ servicesRegistry.startRegistry();
+ warnUser(e);
+ } catch (ServiceException e1) {
+ log.error(e);
+ // throw new PartInitException("could not initialize services", e); //$NON-NLS-1$
+ }
+ } catch (ServiceException e) {
+ log.error(e);
+ // throw new PartInitException("could not initialize services", e);
+ }
+
+
+ // Get required services
+
+ try {
+ transactionalEditingDomain = servicesRegistry.getService(TransactionalEditingDomain.class);
+ sashModelMngr = servicesRegistry.getService(DiSashModelManager.class);
+
+ saveAndDirtyService = servicesRegistry.getService(ISaveAndDirtyService.class);
+ undoContext = servicesRegistry.getService(IUndoContext.class);
+
+ servicesRegistry.getService(ILanguageService.class).addLanguageChangeListener(createLanguageChangeListener());
+ } catch (ServiceException e) {
+ log.error("A required service is missing.", e);
+ // if one of the services above fail to start, the editor can't run
+ // => stop
+ throw new PartInitException("could not initialize services", e);
+ }
+
+
+ // Listen on input changed from the ISaveAndDirtyService
+ editorInputChangedListener = new EditorInputChangedListener(this);
+ saveAndDirtyService.addInputChangedListener(editorInputChangedListener);
+ getLifecycleManager().firePostInit(this);
+ }
+
+ private ILanguageChangeListener createLanguageChangeListener() {
+ return new ILanguageChangeListener() {
+
+ @Override
+ public void languagesChanged(LanguageChangeEvent event) {
+ // Re-load the editor if languages changed, because new ModelSet configurations may be required
+ if (event.getType() == LanguageChangeEvent.ADDED) {
+ new UIJob(getSite().getShell().getDisplay(), NLS.bind("Reload editor {0}", getTitle())) {
+
+ @Override
+ public IStatus runInUIThread(IProgressMonitor monitor) {
+ IStatus result = Status.OK_STATUS;
+ monitor = SubMonitor.convert(monitor, IProgressMonitor.UNKNOWN);
+
+ try {
+ ISashWindowsContainer container = getISashWindowsContainer();
+ if ((container != null) && !container.isDisposed()) {
+ IReloadableEditor.ReloadReason reason = IReloadableEditor.ReloadReason.RESOURCES_CHANGED;
+
+ DirtyPolicy dirtyPolicy = DirtyPolicy.getDefault();
+ try {
+ IReloadableEditor.Adapter.getAdapter(CoreMultiDiagramEditor.this).reloadEditor(resourceSet.getResources(), reason, dirtyPolicy);
+ } catch (CoreException e) {
+ result = e.getStatus();
+ }
+ }
+ } finally {
+ monitor.done();
+ }
+
+ return result;
+ }
+ }.schedule();
+ }
+ }
+ };
+ }
+
+ private InternalEditorLifecycleManager getLifecycleManager() {
+ // I've been disposed
+ if (servicesRegistry == null) {
+ return null;
+ }
+ try {
+ return (InternalEditorLifecycleManager) servicesRegistry.getService(EditorLifecycleManager.class);
+ } catch (ServiceException ex) {
+ Activator.log.error(ex);
+ }
+ return null;
+ }
+
+ protected void loadNestedEditors() throws PartInitException {
+ ISashWindowsContentProvider contentProvider = null;
+ try {
+ contentProvider = servicesRegistry.getService(ISashWindowsContentProvider.class);
+ } catch (ServiceException ex) {
+ log.error("A required service is missing.", ex);
+ // if one of the services above fail to start, the editor can't run
+ // => stop
+ throw new PartInitException("could not initialize services", ex);
+ }
+
+ // Set the content provider providing editors.
+ setContentProvider(contentProvider);
+
+ // Listen on contentProvider changes
+ if (contentChangedListener == null) {
+ contentChangedListener = new ContentChangedListener();
+ }
+ sashModelMngr.getSashModelContentChangedProvider().addListener(contentChangedListener);
+
+ IEditorInput input = getEditorInput();
+
+ if (input instanceof IPapyrusPageInput) {
+ IPapyrusPageInput papyrusPageInput = (IPapyrusPageInput) input;
+ final IPageManager pageManager = getIPageManager();
+
+ if (papyrusPageInput.closeOtherPages()) {
+ pageManager.closeAllOpenedPages();
+ }
+
+ for (URI pageIdentifierURI : papyrusPageInput.getPages()) {
+ final EObject pageIdentifier = resourceSet.getEObject(pageIdentifierURI, true);
+ if (!pageManager.allPages().contains(pageIdentifier)) {
+ Activator.log.warn("The object " + pageIdentifier + " does not reference an existing page");
+ continue;
+ }
+
+ if (pageManager.isOpen(pageIdentifier)) {
+ pageManager.selectPage(pageIdentifier);
+ } else {
+ pageManager.openPage(pageIdentifier);
+ }
+ }
+ }
+ }
+
+ protected void warnUser(ModelMultiException e) {
+ Activator.log.error(e);
+ MessageDialog.openError(getSite().getShell(), "Error", String.format("Your model is corrupted, invalid links have been found :\n" + "%s" + "It is recommended to fix it before editing it", e.getMessage()));
+ }
+
+ /**
+ * Activate this editor. Called after the SWT.control is created.
+ */
+ @Override
+ protected void activate() {
+ super.activate();
+
+ initFolderTabMenus();
+
+ try {
+ // Register ISashWindowsContainer as service
+ // Should be done only once the container is ready.
+ getServicesRegistry().add(ISashWindowsContainer.class, 1, getISashWindowsContainer());
+ getServicesRegistry().startServicesByClassKeys(ISashWindowsContainer.class);
+ // Let the IPageMngr use the ISashWindowsContainer to discover current folder
+ // This should be done after SashWindowContainer initialization.
+ // DiSashModelManager sashModelManager = getServicesRegistry().getService(DiSashModelManager.class);
+ sashModelMngr.setCurrentFolderAndPageMngr(getISashWindowsContainer());
+
+ } catch (ServiceException e) {
+ log.error(e);
+ }
+
+ }
+
+ /**
+ * Init the contextual menu shown in the folder tabs. This popup menu is
+ * contributed by the help of Eclipse extensions, using the Commands
+ * framework. I.e, to add a menu item, create a menu, a command and an
+ * handler in the extension.
+ */
+ protected void initFolderTabMenus() {
+ ISashWindowsContainer container = getISashWindowsContainer();
+
+ // TODO : use a constant
+ MenuManager menuManager = new MenuManager("tabmenu");
+ menuManager.add(new Separator("tabcommands"));
+ menuManager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
+ container.setFolderTabMenuManager(menuManager);
+
+ // TODO : use a constant
+ getSite().registerContextMenu("org.eclipse.papyrus.infra.core.editor.ui.tabmenu", menuManager, getSite().getSelectionProvider());
+
+ }
+
+ /**
+ * Overrides getPropertySheetPage.
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor#getPropertySheetPage()
+ */
+ public IPropertySheetPage getPropertySheetPage() {
+ IPropertySheetPage propertiesPage = new MultiDiagramPropertySheetPage(this);
+ propertiesPages.add(propertiesPage);
+ return propertiesPage;
+ }
+
+ @Override
+ public void dispose() {
+ for (IPropertySheetPage propertiesPage : this.propertiesPages) {
+ propertiesPage.dispose();
+ }
+ propertiesPages.clear();
+
+ // Forget the outline page(s)
+ contentOutlineRegistry = null;
+
+ super.dispose();
+ }
+
+ private IReloadableEditor createReloadAdapter() {
+
+ return new IReloadableEditor() {
+
+ @Override
+ public void reloadEditor(Collection<? extends Resource> triggeringResources, ReloadReason reason, DirtyPolicy dirtyPolicy) throws CoreException {
+ // Attempt to re-load, later
+ pendingReload.set(new DeferredReload(triggeringResources, reason, dirtyPolicy));
+
+ // If I am already active, then do it now. Or, if we're not going to ask the user about it, also do it now
+ IWorkbenchPage page = getSite().getPage();
+ if ((page.getActiveEditor() == CoreMultiDiagramEditor.this) || (dirtyPolicy != DirtyPolicy.PROMPT_TO_SAVE)) {
+ pendingReload.get().reload();
+ }
+ }
+
+ @Override
+ public void addEditorReloadListener(IEditorReloadListener listener) {
+ reloadListeners.addIfAbsent(listener);
+ }
+
+ @Override
+ public void removeEditorReloadListener(IEditorReloadListener listener) {
+ reloadListeners.remove(listener);
+ }
+ };
+ }
+
+ private void addSelfReloadListener() {
+ createReloadAdapter().addEditorReloadListener(new IEditorReloadListener() {
+
+ @Override
+ public void editorAboutToReload(EditorReloadEvent event) {
+ event.putContext(new MultiDiagramEditorSelectionContext(event.getEditor()));
+ }
+
+ @Override
+ public void editorReloaded(EditorReloadEvent event) {
+ ((MultiDiagramEditorSelectionContext) event.getContext()).restore(event.getEditor());
+ }
+ });
+ }
+
+ /**
+ * Register an action to be run when I am closed. Any number of such actions may
+ * be added. note that close actions also run on re-load, which behaves to all
+ * outward appearances like a close and re-open.
+ *
+ * @param closeAction
+ * an action to run when I am closed
+ */
+ public void onClose(Runnable closeAction) {
+ closeActions.add(closeAction);
+ }
+
+ @Override
+ protected void deactivate() {
+ getLifecycleManager().fireBeforeClose(this);
+ if (sashModelMngr != null) {
+ sashModelMngr.getSashModelContentChangedProvider().removeListener(contentChangedListener);
+ }
+
+ super.deactivate();
+
+ // dispose available service
+ if (servicesRegistry != null) {
+ try {
+ servicesRegistry.disposeRegistry();
+ servicesRegistry = null;
+ } catch (ServiceMultiException e) {
+ log.error(e);
+ }
+ }
+
+ if (contentChangedListener != null) {
+ this.contentChangedListener = null;
+ }
+
+ if (editorInputChangedListener != null) {
+ this.editorInputChangedListener.dispose();
+ this.editorInputChangedListener = null;
+ }
+
+ for (Runnable next : closeActions) {
+ try {
+ next.run();
+ } catch (Exception e) {
+ Activator.log.error("Uncaught exception in close action", e); //$NON-NLS-1$
+ }
+ }
+ closeActions.clear();
+
+ transactionalEditingDomain = null;
+ resourceSet = null;
+ undoContext = null;
+ saveAndDirtyService = null;
+ sashModelMngr = null;
+ }
+
+ void initContents() throws PartInitException {
+ loadModelAndServices();
+ loadNestedEditors();
+ }
+
+ @Override
+ public void setFocus() {
+ super.setFocus();
+
+ DeferredReload reload = pendingReload.get();
+ if (reload != null) {
+ reload.reload();
+ }
+ }
+
+ private void doReload() throws CoreException {
+ final IWorkbenchPage page = getSite().getPage();
+ final IWorkbenchPart activePart = page.getActivePart();
+ final IEditorPart activeEditor = page.getActiveEditor();
+
+ final Iterable<? extends IEditorReloadListener> listeners = ImmutableList.copyOf(reloadListeners);
+ final EditorReloadEvent event = new EditorReloadEvent(CoreMultiDiagramEditor.this);
+
+ try {
+ event.dispatchEditorAboutToReload(listeners);
+
+ deactivate();
+
+ initContents();
+
+ activate();
+
+ // My self-listener will be first, to ensure that the pages are all restored before dependents run
+ event.dispatchEditorReloaded(listeners);
+ } finally {
+ event.dispose();
+
+ // Ensure that the editor previously active is active again (if it still exists)
+ if ((activeEditor != null) && page.isPartVisible(activeEditor)) {
+ page.activate(activeEditor);
+ }
+
+ // Ensure that the part previously active is active again (if it still exists and is not the active editor)
+ if ((activePart != null) && (activePart != activeEditor) && page.isPartVisible(activePart)) {
+ page.activate(activePart);
+ }
+ }
+
+ }
+
+ /**
+ * Overrides doSave.
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.part.EditorPart#doSave(org.eclipse.core.runtime.IProgressMonitor)
+ */
+ @Override
+ public void doSave(IProgressMonitor monitor) {
+
+ saveAndDirtyService.doSave(monitor);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isDirty() {
+ // May happen if the editor has not yet been initialized. In this case, the editor cannot be dirty, so we simply return false.
+ // Bug 410286: The isDirty() method can also be called /after/ the editor has been disposed. Most likely an Eclipse bug?
+ if (saveAndDirtyService == null) {
+ return false;
+ }
+ return saveAndDirtyService.isDirty();
+ }
+
+ /**
+ * Overrides doSaveAs.
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.part.EditorPart#doSaveAs()
+ */
+ @Override
+ public void doSaveAs() {
+
+ saveAndDirtyService.doSaveAs();
+ }
+
+ /**
+ * Overrides isSaveAsAllowed.
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.part.EditorPart#isSaveAsAllowed()
+ */
+ @Override
+ public boolean isSaveAsAllowed() {
+ return true;
+ }
+
+ /**
+ * Overrides getContributorId.
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor#getContributorId()
+ */
+ @Override
+ public String getContributorId() {
+ // return Activator.PLUGIN_ID;
+ return "TreeOutlinePage";
+
+ }
+
+ // implements IDiagramWorkbenchPart to restore GMF standard behavior
+ // and delegate to the activeEditor
+
+ /**
+ * Overrides getDiagram.
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart#getDiagram()
+ */
+ // public org.eclipse.gmf.runtime.notation.Diagram getDiagram() {
+ // IEditorPart activeEditor = getActiveEditor();
+ // if(activeEditor instanceof DiagramEditor) {
+ // return ((DiagramEditor)activeEditor).getDiagram();
+ // } else {
+ // return null;
+ // }
+ // }
+
+ /**
+ * This method is called from a GMF diagram. It should only be called from GMF diagram code. Normally, the Diagram under the Mouse is a GMF
+ * Diagram. The active Diagram can be another Diagram, not
+ * under the mouse. This is a GMF issue.
+ */
+ // public DiagramEditPart getDiagramEditPart() {
+ //
+ // // Get the editor under the mouse
+ // // IEditorPart activeEditor = rootContainer.getEditorUnderMouse();
+ // IEditorPart activeEditor = getActiveEditor();
+ // if(activeEditor == null) {
+ // return null;
+ // }
+ // // IEditorPart activeEditor = getActiveEditor();
+ // if(activeEditor instanceof DiagramEditor) {
+ // return ((DiagramEditor)activeEditor).getDiagramEditPart();
+ // } else {
+ // // This case should never happen.
+ // // Return null, as the GMF runtime now support it (since 093009)
+ // return null;
+ // }
+ // }
+
+ /**
+ * Overrides getDiagramGraphicalViewer.
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart#getDiagramGraphicalViewer()
+ */
+ // public IDiagramGraphicalViewer getDiagramGraphicalViewer() {
+ // IEditorPart activeEditor = getActiveEditor();
+ // if(activeEditor instanceof DiagramEditor) {
+ // return ((DiagramEditor)activeEditor).getDiagramGraphicalViewer();
+ // } else {
+ // return null;
+ // }
+ // }
+
+ /**
+ * Overrides getEditingDomain.
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.emf.edit.domain.IEditingDomainProvider#getEditingDomain()
+ */
+ @Override
+ public EditingDomain getEditingDomain() {
+ return transactionalEditingDomain;
+ }
+
+ /**
+ * Throws an UnsupportedOperationException.
+ *
+ * @see org.eclipse.papyrus.infra.core.editor.IMultiDiagramEditor#getDiagramEditDomain()
+ */
+ // public DiagramEditDomain getDiagramEditDomain() {
+ // throw new UnsupportedOperationException("Not implemented. Should not be called.");
+ // }
+
+
+ /**
+ * Change the editor input.<BR>
+ * <U>Note</U>: that method should be called within the UI-Thread.
+ *
+ * @see org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor#setEditorInput(org.eclipse.ui.IEditorInput)
+ *
+ * @param newInput
+ * The new input
+ * @deprecated Not used anymore
+ */
+
+ @Override
+ @Deprecated
+ public void setEditorInput(IEditorInput newInput) {
+ setInputWithNotify(newInput);
+ setPartName(newInput.getName());
+ }
+
+ @Override
+ @Deprecated
+ public void gotoMarker(IMarker marker) {
+ IWorkbench wb = PlatformUI.getWorkbench();
+ IWorkbenchPage page = wb.getActiveWorkbenchWindow().getActivePage();
+ boolean first = true;
+ for (IViewReference view : page.getViewReferences()) {
+ // no longer restrict to model explorer (see bug 387578)
+ IWorkbenchPart part = view.getPart(false);
+ if (part instanceof IGotoMarker) {
+ // activate first view implementing the IGotoMarker interface
+ if (first) {
+ page.activate(view.getPart(false));
+ first = false;
+ }
+ ((IGotoMarker) part).gotoMarker(marker);
+ }
+ }
+ }
+
+ private boolean needsRefresh;
+
+ protected void scheduleRefresh() {
+ needsRefresh = true;
+ Display.getDefault().asyncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ refreshTabs();
+ }
+ });
+ }
+
+ @Override
+ protected void refreshTabs() {
+ if (!needsRefresh) {
+ return;
+ }
+ needsRefresh = false;
+ super.refreshTabs();
+ }
+
+ @Override
+ public synchronized IEditorPart getActiveEditor() {
+ refreshTabs();
+ return super.getActiveEditor();
+ }
+
+ private final class DeferredReload extends IReloadableEditor.Adapter {
+
+ private final Collection<? extends Resource> triggeringResources;
+
+ private final ReloadReason reason;
+
+ private final DirtyPolicy dirtyPolicy;
+
+ DeferredReload(Collection<? extends Resource> triggeringResources, ReloadReason reason, DirtyPolicy dirtyPolicy) {
+ super(CoreMultiDiagramEditor.this);
+
+ this.triggeringResources = ImmutableSet.copyOf(triggeringResources);
+ this.reason = reason;
+ this.dirtyPolicy = dirtyPolicy;
+ }
+
+ void reload() {
+ try {
+ reloadEditor(triggeringResources, reason, dirtyPolicy);
+ } catch (CoreException e) {
+ // Failed to properly unload/load in place, so just close
+ getSite().getPage().closeEditor(CoreMultiDiagramEditor.this, false);
+
+ StatusManager.getManager().handle(e.getStatus(), StatusManager.LOG | StatusManager.SHOW);
+ }
+ }
+
+ @Override
+ public void reloadEditor(Collection<? extends Resource> triggeringResources, ReloadReason reason, DirtyPolicy dirtyPolicy) throws CoreException {
+ if (!pendingReload.compareAndSet(this, null)) {
+ return;
+ }
+
+ final DirtyPolicy action = dirtyPolicy.resolve(CoreMultiDiagramEditor.this, triggeringResources, reason);
+
+ if ((action == DirtyPolicy.SAVE) && isDirty()) {
+ doSave(new NullProgressMonitor());
+ }
+
+ switch (action) {
+ case SAVE:
+ case DO_NOT_SAVE:
+ if (reason.shouldReload(triggeringResources)) {
+ // Attempt to re-load
+ doReload();
+ } else {
+ // Just close 'er down
+ getSite().getPage().closeEditor(CoreMultiDiagramEditor.this, false);
+ }
+ break;
+ case IGNORE:
+ // Pass
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid resolution of editor re-load dirty policy: " + action); //$NON-NLS-1$
+ }
+ }
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/DiSashModelManagerServiceFactory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/DiSashModelManagerServiceFactory.java
new file mode 100644
index 00000000000..1f13fedb84b
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/DiSashModelManagerServiceFactory.java
@@ -0,0 +1,114 @@
+/*****************************************************************************
+ * Copyright (c) 2013 Cedric Dumoulin.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.ui.editor;
+
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.papyrus.infra.core.resource.sasheditor.SashModel;
+import org.eclipse.papyrus.infra.core.resource.sasheditor.SashModelUtils;
+import org.eclipse.papyrus.infra.core.sasheditor.di.contentprovider.DiSashModelManager;
+import org.eclipse.papyrus.infra.core.services.IServiceFactory;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.ui.Activator;
+import org.eclipse.papyrus.infra.ui.editorsfactory.PageModelFactoryRegistry;
+import org.eclipse.papyrus.infra.ui.extension.diagrameditor.PluggableEditorFactoryReader;
+
+/**
+ * Service Factory to create the {@link DiSashModelManager} service.
+ *
+ * @author cedric dumoulin
+ *
+ */
+public class DiSashModelManagerServiceFactory implements IServiceFactory {
+
+ private TransactionalEditingDomain transactionalEditingDomain;
+
+ private SashModel sashModel;
+
+ private DiSashModelManager sashModelMngr;
+
+ private ServicesRegistry servicesRegistry;
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IService#init(org.eclipse.papyrus.infra.core.services.ServicesRegistry)
+ *
+ * @param servicesRegistry
+ * @throws ServiceException
+ */
+ @Override
+ public void init(ServicesRegistry servicesRegistry) throws ServiceException {
+
+ this.servicesRegistry = servicesRegistry;
+ // Get required service
+ transactionalEditingDomain = servicesRegistry.getService(TransactionalEditingDomain.class);
+
+ // Get the model holding the contentProvider
+ sashModel = SashModelUtils.getSashModelChecked(servicesRegistry);
+
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IService#startService()
+ *
+ * @throws ServiceException
+ */
+ @Override
+ public void startService() throws ServiceException {
+
+ // Read declared editors
+ PageModelFactoryRegistry pageModelRegistry = new PageModelFactoryRegistry();
+ PluggableEditorFactoryReader editorReader = new PluggableEditorFactoryReader(Activator.PLUGIN_ID);
+ editorReader.populate(pageModelRegistry, servicesRegistry);
+
+ if (sashModel.getResource() == null) {
+ throw new ServiceException("Can't start " + this.getClass().getSimpleName() + "'. Required model (SashModel) should be loaded prior starting the service."); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ // create the service
+ sashModelMngr = new DiSashModelManager(pageModelRegistry, sashModel.getResource(), transactionalEditingDomain);
+
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IService#disposeService()
+ *
+ * @throws ServiceException
+ */
+ @Override
+ public void disposeService() throws ServiceException {
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IServiceFactory#createServiceInstance()
+ *
+ * @return
+ * @throws ServiceException
+ */
+ @Override
+ public Object createServiceInstance() throws ServiceException {
+
+ // Start locally the service if needed.
+ // Question: Can createServiceInstance() method be called before
+ // startService() is called ?
+ if (sashModelMngr == null) {
+ startService();
+ }
+
+ return sashModelMngr;
+ }
+
+
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/DiSashModelMngrServiceFactory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/DiSashModelMngrServiceFactory.java
new file mode 100644
index 00000000000..ad0806cff77
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/DiSashModelMngrServiceFactory.java
@@ -0,0 +1,101 @@
+/**
+ *
+ */
+package org.eclipse.papyrus.infra.ui.editor;
+
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.papyrus.infra.core.resource.sasheditor.SashModel;
+import org.eclipse.papyrus.infra.core.resource.sasheditor.SashModelUtils;
+import org.eclipse.papyrus.infra.core.sasheditor.di.contentprovider.DiSashModelMngr;
+import org.eclipse.papyrus.infra.core.services.IServiceFactory;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.ui.Activator;
+import org.eclipse.papyrus.infra.ui.editorsfactory.PageModelFactoryRegistry;
+import org.eclipse.papyrus.infra.ui.extension.diagrameditor.PluggableEditorFactoryReader;
+
+/**
+ * Service Factory to create the {@link DiSashModelMngr} service.
+ *
+ * @author cedric dumoulin
+ *
+ */
+public class DiSashModelMngrServiceFactory implements IServiceFactory {
+
+ private TransactionalEditingDomain transactionalEditingDomain;
+
+ private SashModel sashModel;
+
+ private DiSashModelMngr sashModelMngr;
+
+ private ServicesRegistry servicesRegistry;
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IService#init(org.eclipse.papyrus.infra.core.services.ServicesRegistry)
+ *
+ * @param servicesRegistry
+ * @throws ServiceException
+ */
+ @Override
+ public void init(ServicesRegistry servicesRegistry) throws ServiceException {
+
+ this.servicesRegistry = servicesRegistry;
+ // Get required service
+ transactionalEditingDomain = servicesRegistry.getService(TransactionalEditingDomain.class);
+
+ // Get the model holding the contentProvider
+ sashModel = SashModelUtils.getSashModelChecked(servicesRegistry);
+
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IService#startService()
+ *
+ * @throws ServiceException
+ */
+ @Override
+ public void startService() throws ServiceException {
+
+ // Read declared editors
+ PageModelFactoryRegistry pageModelRegistry = new PageModelFactoryRegistry();
+ PluggableEditorFactoryReader editorReader = new PluggableEditorFactoryReader(Activator.PLUGIN_ID);
+ editorReader.populate(pageModelRegistry, servicesRegistry);
+
+ if (sashModel.getResource() == null) {
+ throw new ServiceException("Can't start " + this.getClass().getSimpleName() + "'. Required model (SashModel) should be loaded prior starting the service."); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ // create the service
+ sashModelMngr = new DiSashModelMngr(pageModelRegistry, sashModel.getResource());
+
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IService#disposeService()
+ *
+ * @throws ServiceException
+ */
+ @Override
+ public void disposeService() throws ServiceException {
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IServiceFactory#createServiceInstance()
+ *
+ * @return
+ * @throws ServiceException
+ */
+ @Override
+ public Object createServiceInstance() throws ServiceException {
+
+ // Start locally the service if needed.
+ // Question: Can createServiceInstance() method be called before
+ // startService() is called ?
+ if (sashModelMngr == null) {
+ startService();
+ }
+
+ return sashModelMngr;
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/IMultiDiagramEditor.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/IMultiDiagramEditor.java
new file mode 100644
index 00000000000..7549517199e
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/IMultiDiagramEditor.java
@@ -0,0 +1,93 @@
+/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.editor;
+
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorSite;
+
+/**
+ * Interface implemented by the main multipage editor. This interface list the
+ * methods available to diagram editors. Diagram editors can relies on this
+ * interface to retrieve services from the main multi diagram editor. <br>
+ * This interface should stay minimalist, as the editor is not designed to
+ * handle the services itself. A service should be retrieved by using {@link #getServicesRegistry()}.
+ *
+ *
+ * @author cedric dumoulin
+ *
+ * TODO remove extends IEditingDomainProvider. This interface should be
+ * independant of any technology (EMF, GMF, ...). If the EditingDomain
+ * is required, it can be retrieved by the registry.
+ *
+ */
+public interface IMultiDiagramEditor extends IEditorPart {
+
+ /**
+ * Returns the service registry associated to the editor.
+ *
+ * @return the servicesRegistry The registry.
+ */
+ public ServicesRegistry getServicesRegistry();
+
+ /**
+ * Return the editor site.
+ *
+ * @return
+ */
+ @Override
+ public IEditorSite getEditorSite();
+
+ /**
+ * Get the editor input.
+ *
+ * @return
+ */
+ @Override
+ public IEditorInput getEditorInput();
+
+ /**
+ * Change the editor input.
+ *
+ * @param newInput
+ * The new input.
+ * @deprecated No replacement. Input can't be changed on multi editors.
+ */
+ @Deprecated
+ public void setEditorInput(IEditorInput newInput);
+
+ /**
+ * Returns the edit domain shared among editors
+ *
+ * @return the edit domain shared among editors
+ * @deprecated Use {@link #getServicesRegistry()} or {@link #getAdapter(Class)}
+ */
+ // FIXME Remove it (GMF dependency)
+ // public DiagramEditDomain getDiagramEditDomain();
+
+ /**
+ * Get the currently active nested Editor.
+ */
+ public IEditorPart getActiveEditor();
+
+ /**
+ * Get the property sheet page associated to the Editor.
+ *
+ * @return the property sheet page associated to the Editor.
+ * @deprecated Use {@link #getServicesRegistry()} or {@link #getAdapter(Class)}
+ */
+ // @Deprecated
+ // public IPropertySheetPage getPropertySheetPage();
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/IPapyrusPageInput.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/IPapyrusPageInput.java
new file mode 100644
index 00000000000..a56ab916ec6
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/IPapyrusPageInput.java
@@ -0,0 +1,35 @@
+/*****************************************************************************
+ * Copyright (c) 2013 CEA LIST.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.editor;
+
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.ui.IEditorInput;
+
+/**
+ * An IEditorInput used to reference the page(s) to open
+ *
+ * @author Camille Letavernier
+ *
+ */
+public interface IPapyrusPageInput extends IEditorInput {
+
+ /**
+ * @return the list of pages to open
+ */
+ public URI[] getPages();
+
+ /**
+ *
+ * @return true if the editor should close all other pages
+ */
+ public boolean closeOtherPages();
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/IReloadableEditor.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/IReloadableEditor.java
new file mode 100644
index 00000000000..92bff539cf7
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/IReloadableEditor.java
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2014, 2016 CEA, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ * Christian W. Damus - bug 485220
+ *
+ */
+package org.eclipse.papyrus.infra.ui.editor;
+
+import java.util.Collection;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.emf.common.ui.URIEditorInput;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.emf.transaction.util.TransactionUtil;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.tools.util.CoreExecutors;
+import org.eclipse.papyrus.infra.tools.util.PlatformHelper;
+import org.eclipse.papyrus.infra.ui.Activator;
+import org.eclipse.papyrus.infra.ui.editor.reload.IEditorReloadListener;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IURIEditorInput;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.ide.IDE;
+
+
+/**
+ * An {@linkplain IAdaptable adapter protocol} for editors that know how to internally
+ * reload themselves without disturbing the workbench window's perspective layout.
+ */
+public interface IReloadableEditor {
+
+ /**
+ * Reloads me in-place in the perspective layout.
+ *
+ * @param triggeringResources
+ * the resources that have changed in some way, triggering re-load
+ * @param reason
+ * the reason why the re-load is being requested
+ * @param dirtyPolicy
+ * how the client would like to handle the case of a dirty editor
+ *
+ * @throws CoreException
+ * on any failure to unload, reload, or whatever
+ */
+ void reloadEditor(Collection<? extends Resource> triggeringResources, ReloadReason reason, DirtyPolicy dirtyPolicy) throws CoreException;
+
+ void addEditorReloadListener(IEditorReloadListener listener);
+
+ void removeEditorReloadListener(IEditorReloadListener listener);
+
+ /**
+ * An enumeration of the reason why some resources that an editor has loaded are triggering a re-load (or close).
+ */
+ enum ReloadReason {
+ /** Resources have changed in persistent storage. */
+ RESOURCES_CHANGED,
+ /** Resources have been deleted from persistent storage. */
+ RESOURCES_DELETED;
+
+ /**
+ * Queries whether, under ordinary circumstances, the editor should attempt to re-load to pick up changes in its dependent resources.
+ *
+ * @param triggeringResources
+ * the resources triggering re-load (or close)
+ *
+ * @return whether the editor should re-load
+ */
+ public boolean shouldReload(Collection<? extends Resource> triggeringResources) {
+ return this != RESOURCES_DELETED;
+ }
+ }
+
+ /**
+ * An enumeration of policies that clients may request to govern what to do with the editor before re-load (or close) if it should happen to be
+ * dirty. Note that editors are free to honour the requested policy or not, according to their needs.
+ */
+ enum DirtyPolicy {
+ /**
+ * Save the editor without prompting.
+ */
+ SAVE,
+ /**
+ * Do not save the editor; just discard pending changes and re-load (or close).
+ */
+ DO_NOT_SAVE,
+ /**
+ * Do not re-load (or close) the editor; just keep pending changes and deal with conflicts later.
+ */
+ IGNORE,
+ /**
+ * Prompt the user to inquire whether to save, discard pending changes, or not re-load (or close) at all.
+ * Note that the user prompt must always result in one of the other policies being actually applied.
+ */
+ PROMPT_TO_SAVE {
+
+ @Override
+ public DirtyPolicy resolve(IEditorPart editor, final Collection<? extends Resource> triggeringResources, final ReloadReason reason) throws CoreException {
+ final boolean dirty = editor.isDirty();
+
+ if (!dirty) {
+ if (reason.shouldReload(triggeringResources)) {
+ // Just re-load it. Simple
+ return DO_NOT_SAVE;
+ } else if (isPrincipalResourceAffected(editor, triggeringResources)) {
+ // Just close it. Also simple
+ return DO_NOT_SAVE;
+ }
+ }
+
+ final String editorName = getEditorName(editor);
+
+ final boolean allReadOnly = allReadOnly(triggeringResources);
+ final String promptTitle;
+ final String promptIntro;
+ final String saveOption;
+ final String dontSaveOption;
+ final String ignoreOption = "Ignore";
+
+ switch (reason) {
+ case RESOURCES_DELETED:
+ promptTitle = "Resources Deleted";
+ promptIntro = NLS.bind("Some resources used by \"{0}\" have been deleted.", editorName);
+ saveOption = "Save and Close";
+ dontSaveOption = "Close Editor";
+ break;
+ default:
+ promptTitle = "Resources Changed";
+ promptIntro = NLS.bind("Some resources used by \"{0}\" have changed.", editorName);
+ saveOption = "Save and Re-open";
+ dontSaveOption = "Re-open Editor";
+ break;
+ }
+
+ Callable<DirtyPolicy> result;
+
+ if (allReadOnly) {
+ // Only read-only models have changed. We (most likely) won't save them within this current editor. As they are already loaded, we can just continue.
+ result = new Callable<DirtyPolicy>() {
+
+ @Override
+ public DirtyPolicy call() {
+ Shell parentShell = Display.getCurrent().getActiveShell();
+
+ final String message;
+ final String[] options;
+ if (dirty) {
+ message = promptIntro + " Note: all these resources are loaded in read-only mode and won't be overridden if you choose to save. Unsaved changes will be lost.";
+ options = new String[] { saveOption, dontSaveOption, ignoreOption };
+ } else {
+ message = promptIntro;
+ options = new String[] { dontSaveOption, ignoreOption };
+ }
+
+ final MessageDialog dialog = new MessageDialog(parentShell, promptTitle, null, message, MessageDialog.WARNING, options, 0) {
+
+ @Override
+ protected void setShellStyle(int newShellStyle) {
+ super.setShellStyle(newShellStyle | SWT.SHEET);
+ }
+ };
+ final int answer = dialog.open();
+
+ DirtyPolicy result;
+
+ if (answer == SWT.DEFAULT) {
+ // User hit Esc or dismissed the dialog with the window manager button. Ignore
+ result = IGNORE;
+ } else if (dirty) {
+ result = values()[answer];
+ } else {
+ result = values()[answer + 1]; // Account for the missing "Save and Xxx" option
+ }
+
+ return result;
+ }
+ };
+ } else {
+ // At least one read-write resource has changed. Potential conflicts.
+ result = new Callable<DirtyPolicy>() {
+
+ @Override
+ public DirtyPolicy call() {
+ DirtyPolicy result = IGNORE;
+
+ final Shell parentShell = Display.getCurrent().getActiveShell();
+ final String action = reason.shouldReload(triggeringResources) ? "re-open" : "close";
+ final String message;
+
+ if (dirty) {
+ message = promptIntro + NLS.bind(" Do you wish to {0} the current editor? Unsaved changes will be lost.", action);
+ } else {
+ message = promptIntro + NLS.bind(" Do you wish to {0} the current editor?", action);
+ }
+
+ final String[] options = { IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL };
+ final MessageDialog dialog = new MessageDialog(parentShell, promptTitle, null, message, MessageDialog.WARNING, options, 0) {
+
+ @Override
+ protected void setShellStyle(int newShellStyle) {
+ super.setShellStyle(newShellStyle | SWT.SHEET);
+ }
+ };
+ if (dialog.open() == 0) {
+ result = DO_NOT_SAVE;
+ }
+
+ return result;
+ }
+ };
+ }
+
+ try {
+ return CoreExecutors.getUIExecutorService().syncCall(result);
+ } catch (ExecutionException e) {
+ throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Failed to determine dirty policy for editor re-load.", e));
+ } catch (InterruptedException e) {
+ throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Interrupted in determining dirty policy for editor re-load.", e));
+ }
+ }
+ };
+
+ /**
+ * Queries the default dirty policy currently in effect. The default-default is {@link #PROMPT_TO_SAVE}.
+ *
+ * @return the default policy
+ */
+ public static DirtyPolicy getDefault() {
+ return PROMPT_TO_SAVE;
+ }
+
+ /**
+ * Resolves me to a specific actionable policy, based on the resources that are triggering re-load (or close) and the reason.
+ *
+ * @param editor
+ * the editor to be re-loaded
+ * @param triggeringResources
+ * the resources (possibly an empty collection) that have changed
+ * @param reloadReason
+ * the reason why re-load (or close) is triggered
+ *
+ * @return the specific policy to implement in re-loading the editor
+ *
+ * @throws CoreException
+ * on failure to resolve the specific policy
+ */
+ public DirtyPolicy resolve(IEditorPart editor, Collection<? extends Resource> triggeringResources, ReloadReason reason) throws CoreException {
+ return this;
+ }
+
+ String getEditorName(IEditorPart editor) {
+ ModelSet modelSet = getModelSet(editor);
+ return (modelSet == null) ? editor.getTitle() : modelSet.getURIWithoutExtension().lastSegment();
+ }
+
+ private ModelSet getModelSet(IEditorPart editor) {
+ ModelSet result = null;
+
+ if (editor instanceof IMultiDiagramEditor) {
+ try {
+ result = ((IMultiDiagramEditor) editor).getServicesRegistry().getService(ModelSet.class);
+ } catch (ServiceException e) {
+ // No problem. We have a fall-back
+ Activator.log.error(e);
+ }
+ }
+
+ return result;
+ }
+
+ boolean isPrincipalResourceAffected(IEditorPart editor, Collection<? extends Resource> triggeringResources) {
+ boolean result = false;
+
+ ModelSet modelSet = getModelSet(editor);
+ if (modelSet != null) {
+ URI principalURI = modelSet.getURIWithoutExtension();
+ for (Resource next : triggeringResources) {
+ if (next.getURI().trimFileExtension().equals(principalURI)) {
+ result = true;
+ break;
+ }
+ }
+ } else {
+ URI principalURI = getURI(editor.getEditorInput());
+ if (principalURI != null) {
+ for (Resource next : triggeringResources) {
+ if (next.getURI().equals(principalURI)) {
+ result = true;
+ break;
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ private URI getURI(IEditorInput input) {
+ URI result = null;
+
+ if (input instanceof URIEditorInput) {
+ result = ((URIEditorInput) input).getURI();
+ } else if (input instanceof IURIEditorInput) {
+ result = URI.createURI(((IURIEditorInput) input).getURI().toString());
+ }
+
+ return result;
+ }
+
+ protected boolean allReadOnly(Collection<? extends Resource> resources) {
+ for (Resource resource : resources) {
+ EditingDomain domain = TransactionUtil.getEditingDomain(resource);
+ if ((domain == null) || !domain.isReadOnly(resource)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ }
+
+ /**
+ * A convenience adapter for editors that don't actually know how to reload themselves in place.
+ * It simply closes the editor and then opens it again on the original input.
+ */
+ class Adapter implements IReloadableEditor {
+
+ private final IEditorPart editor;
+
+ public Adapter(IEditorPart editor) {
+ super();
+
+ this.editor = editor;
+ }
+
+ public static IReloadableEditor getAdapter(IMultiDiagramEditor editor) {
+ return PlatformHelper.getAdapter(editor, IReloadableEditor.class, () -> new Adapter(editor));
+ }
+
+ @Override
+ public void reloadEditor(Collection<? extends Resource> triggeringResources, ReloadReason reason, DirtyPolicy dirtyPolicy) throws CoreException {
+ final IWorkbenchPage page = editor.getSite().getPage();
+ final IEditorInput currentInput = editor.getEditorInput();
+
+ final Display display = editor.getSite().getShell().getDisplay();
+
+ final String editorId = editor.getSite().getId();
+
+ final DirtyPolicy action = dirtyPolicy.resolve(editor, triggeringResources, reason);
+ final boolean save = action == DirtyPolicy.SAVE;
+
+ if (save && editor.isDirty()) {
+ editor.doSave(new NullProgressMonitor());
+ }
+
+ if (action != DirtyPolicy.IGNORE) {
+ page.closeEditor(editor, save);
+
+ // If resources were deleted, we close and don't re-open
+ if (reason.shouldReload(triggeringResources)) {
+ display.asyncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ try {
+ IDE.openEditor(page, currentInput, editorId);
+ } catch (PartInitException ex) {
+ Activator.log.error(ex);
+ }
+ }
+ });
+ }
+ }
+ }
+
+ @Override
+ public void addEditorReloadListener(IEditorReloadListener listener) {
+ // Don't need to track these listeners because I never properly reload an editor
+ }
+
+ @Override
+ public void removeEditorReloadListener(IEditorReloadListener listener) {
+ // Don't need to track these listeners because I never properly reload an editor
+ }
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/MultiDiagramEditorSelectionContext.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/MultiDiagramEditorSelectionContext.java
new file mode 100644
index 00000000000..fc0302004dd
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/MultiDiagramEditorSelectionContext.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2014 CEA and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.infra.ui.editor;
+
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.IComponentPage;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.IEditorPage;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.IPage;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.IPageVisitor;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.ISashWindowsContainer;
+import org.eclipse.papyrus.infra.core.utils.AdapterUtils;
+import org.eclipse.papyrus.infra.ui.Activator;
+import org.eclipse.papyrus.infra.ui.editor.reload.CompositeReloadContext;
+import org.eclipse.papyrus.infra.ui.editor.reload.DelegatingReloadContext;
+import org.eclipse.papyrus.infra.ui.editor.reload.EMFSelectionContext;
+import org.eclipse.papyrus.infra.ui.editor.reload.EditorReloadEvent;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+
+/**
+ * A {@linkplain EditorReloadEvent reload event} context that restores the selection of which editor page
+ * is active in an {@link IMultiDiagramEditor} that is reloaded and delegates to its pages to capture
+ * re-load context for each to restore whatever they need to restore (internal selections etc.).
+ */
+class MultiDiagramEditorSelectionContext extends CompositeReloadContext {
+
+ private ISashWindowsContainer sashContainer;
+
+ private final List<URI> resourcesToLoad;
+
+ MultiDiagramEditorSelectionContext(IMultiDiagramEditor editor) {
+ super();
+
+ init(editor);
+
+ resourcesToLoad = computeResourcesToLoad(editor);
+
+ IPage active = sashContainer.getActiveSashWindowsPage();
+ DiagramPageContext activePage = null;
+
+ Set<IPage> visiblePages = Sets.newIdentityHashSet();
+ visiblePages.addAll(sashContainer.getVisiblePages());
+
+ List<IPage> allPages = getAllPages(sashContainer);
+
+ for (IPage page : allPages) {
+ final DelegatingReloadContext delegator = (page instanceof IEditorPage) ? add(new DelegatingReloadContext(((IEditorPage) page).getIEditorPart())) : null;
+ DiagramPageContext context;
+
+ if (page == active) {
+ // This one will have the selection of the active page
+ context = new DiagramPageContext(new VisiblePageSelectionProvider(page), page, delegator);
+ activePage = context;
+ } else {
+ if (visiblePages.contains(page)) {
+ // This one must be selected in its folder in order to make it visible again
+ context = new DiagramPageContext(new VisiblePageSelectionProvider(page), page, delegator);
+ } else {
+ context = new DiagramPageContext(EmptySelectionProvider.INSTANCE, page, delegator);
+ }
+
+ // We make sure always to restore the active page last
+ // so that it will not only be visible but also the
+ // over-all active page
+ add(context);
+ }
+ }
+
+ if (activePage != null) {
+ // Restore this one last
+ add(activePage);
+ }
+ }
+
+ @Override
+ public void dispose() {
+ sashContainer = null;
+ super.dispose();
+ }
+
+ private List<IPage> getAllPages(ISashWindowsContainer container) {
+ final List<IPage> result = Lists.newArrayList();
+
+ container.visit(new IPageVisitor() {
+
+ @Override
+ public void accept(IEditorPage page) {
+ result.add(page);
+ }
+
+ @Override
+ public void accept(IComponentPage page) {
+ result.add(page);
+ }
+ });
+
+ return result;
+ }
+
+ private void init(IMultiDiagramEditor editor) {
+ sashContainer = AdapterUtils.adapt(editor, ISashWindowsContainer.class, null);
+ }
+
+ void restore(IMultiDiagramEditor editor) {
+ init(editor);
+
+ // Forcibly re-load all previously loaded resources to that
+ // (a) we don't lose imports that weren't yet used, and
+ // (b) we can restore selections in resources that wouldn't be loaded until proxies resolve later
+ reloadResources(editor);
+
+ ISelectionProvider selectionProvider = new VisiblePageSelectionProvider();
+ for (DiagramPageContext next : getReloadContexts(DiagramPageContext.class)) {
+ next.restore(selectionProvider);
+ }
+ }
+
+ protected List<URI> computeResourcesToLoad(IMultiDiagramEditor editor) {
+ List<URI> result = null;
+
+ ResourceSet rset = getResourceSet(editor);
+ if (rset != null) {
+ result = Lists.newArrayListWithCapacity(rset.getResources().size());
+
+ for (Resource next : rset.getResources()) {
+ if (next.isLoaded()) {
+ result.add(next.getURI());
+ }
+ }
+ }
+
+ return result;
+ }
+
+ protected void reloadResources(IMultiDiagramEditor editor) {
+ if (resourcesToLoad != null) {
+ ResourceSet rset = getResourceSet(editor);
+ if (rset != null) {
+ for (URI next : resourcesToLoad) {
+ try {
+ rset.getResource(next, true);
+ } catch (Exception e) {
+ Activator.log.error("Failed to restore loaded resource: " + next, e); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+ }
+
+ protected final ResourceSet getResourceSet(IMultiDiagramEditor editor) {
+ ResourceSet result = null;
+
+ EditingDomain editingDomain = editor.getAdapter(EditingDomain.class);
+ if (editingDomain != null) {
+ result = editingDomain.getResourceSet();
+ }
+
+ return result;
+ }
+
+ //
+ // Nested types
+ //
+
+ private class DiagramPageContext extends EMFSelectionContext {
+
+ private URI pageRef;
+
+ private DelegatingReloadContext pageContext;
+
+ DiagramPageContext(ISelectionProvider structuredSelectionProvider, IPage page, DelegatingReloadContext pageContext) {
+ super(structuredSelectionProvider);
+
+ this.pageContext = pageContext;
+ this.pageRef = getToken(page.getRawModel());
+ }
+
+ @Override
+ public void restore(ISelectionProvider structuredSelectionProvider) {
+ IPage page = sashContainer.lookupModelPage(resolveToken(pageRef));
+
+ if ((pageContext != null) && (page instanceof IEditorPage)) {
+ pageContext.restore(((IEditorPage) page).getIEditorPart());
+ }
+
+ super.restore(structuredSelectionProvider);
+ }
+
+ @Override
+ protected Object deresolveSelectableElement(Object selectableElement) {
+ return (selectableElement instanceof IPage) ? ((IPage) selectableElement).getRawModel() : super.deresolveSelectableElement(selectableElement);
+ }
+
+ @Override
+ protected Object resolveSelectableElement(Object deresolved) {
+ return sashContainer.lookupModelPage(deresolved);
+ }
+ }
+
+ private static class EmptySelectionProvider implements ISelectionProvider {
+
+ static final EmptySelectionProvider INSTANCE = new EmptySelectionProvider();
+
+ EmptySelectionProvider() {
+ super();
+ }
+
+ @Override
+ public ISelection getSelection() {
+ return StructuredSelection.EMPTY;
+ }
+
+ @Override
+ public void setSelection(ISelection selection) {
+ // Pass
+ }
+
+ @Override
+ public void addSelectionChangedListener(ISelectionChangedListener listener) {
+ // Not needed because the selection is always empty
+ }
+
+ @Override
+ public void removeSelectionChangedListener(ISelectionChangedListener listener) {
+ // Not needed because the selection is always empty
+ }
+
+ }
+
+ private class VisiblePageSelectionProvider implements ISelectionProvider {
+
+ private final IStructuredSelection selection;
+
+ VisiblePageSelectionProvider() {
+ this(null);
+ }
+
+ VisiblePageSelectionProvider(IPage visible) {
+ super();
+
+ this.selection = (visible == null) ? StructuredSelection.EMPTY : new StructuredSelection(visible);
+ }
+
+ @Override
+ public ISelection getSelection() {
+ return selection;
+ }
+
+ @Override
+ public void setSelection(ISelection selection) {
+ if (!selection.isEmpty()) {
+ IPage page = (IPage) ((IStructuredSelection) selection).getFirstElement();
+ sashContainer.selectPage(page);
+ }
+ }
+
+ @Override
+ public void addSelectionChangedListener(ISelectionChangedListener listener) {
+ // Not needed
+ }
+
+ @Override
+ public void removeSelectionChangedListener(ISelectionChangedListener listener) {
+ // Not needed
+ }
+
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/MultiDiagramPropertySheetPage.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/MultiDiagramPropertySheetPage.java
new file mode 100644
index 00000000000..9ef43cb4cd3
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/MultiDiagramPropertySheetPage.java
@@ -0,0 +1,178 @@
+/*****************************************************************************
+ * Copyright (c) 2014, 2015 CEA LIST, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * CEA LIST - Initial API and implementation
+ * Christian W. Damus - bug 469188
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.ui.editor;
+
+import org.eclipse.core.commands.operations.IUndoContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.emf.common.ui.URIEditorInput;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.papyrus.infra.core.operation.DelegatingUndoContext;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.ISashWindowsContainer;
+import org.eclipse.papyrus.infra.tools.util.PlatformHelper;
+import org.eclipse.papyrus.infra.ui.editor.reload.EditorReloadEvent;
+import org.eclipse.papyrus.infra.ui.editor.reload.IEditorReloadListener;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IFileEditorInput;
+import org.eclipse.ui.IPartListener;
+import org.eclipse.ui.ISelectionListener;
+import org.eclipse.ui.IStorageEditorInput;
+import org.eclipse.ui.IURIEditorInput;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.actions.ActionFactory;
+import org.eclipse.ui.operations.RedoActionHandler;
+import org.eclipse.ui.operations.UndoActionHandler;
+import org.eclipse.ui.part.IShowInSource;
+import org.eclipse.ui.part.ShowInContext;
+import org.eclipse.ui.views.properties.PropertyShowInContext;
+import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;
+
+
+/**
+ * A specialized property-sheet page that knows how to restore the Property Sheet view's input from the workbench part
+ * that most recently gave it its input, after a {@link CoreMultiDiagramEditor} has been re-loaded.
+ */
+class MultiDiagramPropertySheetPage extends TabbedPropertySheetPage implements IEditorReloadListener {
+
+ private final CoreMultiDiagramEditor multiDiagramEditor;
+
+ private UndoActionHandler undo;
+ private RedoActionHandler redo;
+ private DelegatingUndoContext undoContext;
+
+ public MultiDiagramPropertySheetPage(CoreMultiDiagramEditor editor) {
+ super(editor);
+
+ this.multiDiagramEditor = editor;
+ IReloadableEditor.Adapter.getAdapter(editor).addEditorReloadListener(this);
+ }
+
+ @Override
+ public void dispose() {
+ IReloadableEditor.Adapter.getAdapter(multiDiagramEditor).removeEditorReloadListener(this);
+
+ if (undo != null) {
+ undo.dispose();
+ }
+ if (redo != null) {
+ redo.dispose();
+ }
+
+ super.dispose();
+ }
+
+ @Override
+ public void selectionChanged(IWorkbenchPart part, ISelection selection) {
+ if (selection.isEmpty() && (part instanceof IMultiDiagramEditor)) {
+ // Perhaps the user selected a page such as the Welcome Page that
+ // isn't an editor and so doesn't have a selection
+ IMultiDiagramEditor editor = (IMultiDiagramEditor) part;
+ ISashWindowsContainer sash = editor.getAdapter(ISashWindowsContainer.class);
+ if (sash != null) {
+ if ((sash.getActiveEditor() == null) && (sash.getActiveSashWindowsPage() != null)) {
+ // Yep, that's the case, here. So show the properties of the input
+ // resource (usually a DI file)
+ IEditorInput input = editor.getEditorInput();
+ Object newSelection;
+ if (input instanceof IFileEditorInput) {
+ newSelection = ((IFileEditorInput) input).getFile();
+ } else if (input instanceof IStorageEditorInput) {
+ IStorageEditorInput storageInput = (IStorageEditorInput) input;
+ try {
+ newSelection = storageInput.getStorage();
+ } catch (CoreException e) {
+ newSelection = storageInput;
+ }
+ } else if (input instanceof IURIEditorInput) {
+ newSelection = ((IURIEditorInput) input).getURI();
+ } else if (input instanceof URIEditorInput) {
+ newSelection = ((URIEditorInput) input).getURI();
+ } else {
+ newSelection = null;
+ }
+
+ if (newSelection != null) {
+ selection = new StructuredSelection(newSelection);
+ }
+ }
+ }
+ }
+
+ super.selectionChanged(part, selection);
+ }
+
+ @Override
+ public void editorAboutToReload(EditorReloadEvent event) {
+ Object propertySheet = getSite().getService(IViewPart.class);
+ if (propertySheet instanceof IShowInSource) {
+ ShowInContext context = ((IShowInSource) propertySheet).getShowInContext();
+
+ if (context instanceof PropertyShowInContext) {
+ IWorkbenchPart inputPart = ((PropertyShowInContext) context).getPart();
+ if (inputPart != null) {
+ event.putContext(inputPart);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void editorReloaded(EditorReloadEvent event) {
+ final IWorkbenchPart inputPart = (IWorkbenchPart) event.getContext();
+ if (inputPart != null) {
+ final Object propertySheet = getSite().getService(IViewPart.class);
+ if (propertySheet instanceof IPartListener) {
+ // Kick it with this part
+ ((IPartListener) propertySheet).partActivated(inputPart);
+
+ // And again later to get its new selection (we don't know when its selection may be restored relative to us)
+ getSite().getShell().getDisplay().asyncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ ISelectionProvider selectionProvider = inputPart.getSite().getSelectionProvider();
+ if (selectionProvider != null) {
+ ((ISelectionListener) propertySheet).selectionChanged(inputPart, selectionProvider.getSelection());
+ }
+ }
+ });
+ }
+ }
+
+ // The editor will have a new undo context (because it will have a new editing domain)
+ if (undoContext != null) {
+ undoContext.setDelegate(PlatformHelper.getAdapter(multiDiagramEditor, IUndoContext.class));
+ }
+ }
+
+ @Override
+ public void setActionBars(IActionBars actionBars) {
+ super.setActionBars(actionBars);
+
+ undoContext = new DelegatingUndoContext();
+ undoContext.setDelegate(PlatformHelper.getAdapter(multiDiagramEditor, IUndoContext.class));
+
+ undo = new UndoActionHandler(multiDiagramEditor.getSite(), undoContext);
+ redo = new RedoActionHandler(multiDiagramEditor.getSite(), undoContext);
+
+ actionBars.setGlobalActionHandler(ActionFactory.UNDO.getId(), undo);
+ actionBars.setGlobalActionHandler(ActionFactory.REDO.getId(), redo);
+ }
+
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/PageIconRegistryServiceFactory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/PageIconRegistryServiceFactory.java
new file mode 100644
index 00000000000..21eb6a2cfdc
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/PageIconRegistryServiceFactory.java
@@ -0,0 +1,71 @@
+/**
+ *
+ */
+package org.eclipse.papyrus.infra.ui.editor;
+
+import org.eclipse.papyrus.infra.core.services.IServiceFactory;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.ui.Activator;
+import org.eclipse.papyrus.infra.ui.editorsfactory.IPageIconsRegistry;
+import org.eclipse.papyrus.infra.ui.editorsfactory.PageIconsRegistry;
+import org.eclipse.papyrus.infra.ui.extension.diagrameditor.PluggableEditorFactoryReader;
+
+/**
+ * Service Factory to register {@link IPageIconsRegistry}.
+ *
+ * @author cedric dumoulin
+ *
+ */
+public class PageIconRegistryServiceFactory implements IServiceFactory {
+
+ private PageIconsRegistry pageIconsRegistry;
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IService#init(org.eclipse.papyrus.infra.core.services.ServicesRegistry)
+ *
+ * @param servicesRegistry
+ * @throws ServiceException
+ */
+ @Override
+ public void init(ServicesRegistry servicesRegistry) throws ServiceException {
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IService#startService()
+ *
+ * @throws ServiceException
+ */
+ @Override
+ public void startService() throws ServiceException {
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IService#disposeService()
+ *
+ * @throws ServiceException
+ */
+ @Override
+ public void disposeService() throws ServiceException {
+ if (pageIconsRegistry != null) {
+ pageIconsRegistry.dispose();
+ }
+ }
+
+ /**
+ * Create and populate a {@link PageIconsRegistry}. Return it as the service
+ * instance.
+ *
+ * @return
+ */
+ @Override
+ public Object createServiceInstance() {
+ if (pageIconsRegistry == null) {
+ pageIconsRegistry = new PageIconsRegistry();
+ PluggableEditorFactoryReader editorReader = new PluggableEditorFactoryReader(Activator.PLUGIN_ID);
+ editorReader.populate(pageIconsRegistry);
+ }
+ return pageIconsRegistry;
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/PageMngrServiceFactory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/PageMngrServiceFactory.java
new file mode 100644
index 00000000000..b7657e6ce1a
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/PageMngrServiceFactory.java
@@ -0,0 +1,83 @@
+/*****************************************************************************
+ * Copyright (c) 2011, 2016 LIFL, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * LIFL - Initial API and implementation
+ * Christian W. Damus - bugs 415638, 485220
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.editor;
+
+import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.ISashWindowsContentProvider;
+import org.eclipse.papyrus.infra.core.sasheditor.di.contentprovider.DiSashModelManager;
+import org.eclipse.papyrus.infra.core.services.IServiceFactory;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.services.ServiceNotFoundException;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+
+/**
+ * A service factory to create the {@link IPageMngr} service. This
+ * serviceFactory depends on {@link ISashWindowsContentProvider} service.
+ *
+ * @author cedric dumoulin
+ *
+ */
+public class PageMngrServiceFactory implements IServiceFactory {
+
+ /**
+ * The sashModelMangr.
+ */
+ private DiSashModelManager sashModelMngr;
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IService#init(org.eclipse.papyrus.infra.core.services.ServicesRegistry)
+ *
+ * @param servicesRegistry
+ * @throws ServiceException
+ */
+ @Override
+ public void init(ServicesRegistry servicesRegistry) throws ServiceException {
+
+ // Get required services
+ sashModelMngr = servicesRegistry.getService(DiSashModelManager.class);
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IService#startService()
+ *
+ * @throws ServiceException
+ */
+ @Override
+ public void startService() throws ServiceException {
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IService#disposeService()
+ *
+ * @throws ServiceException
+ */
+ @Override
+ public void disposeService() throws ServiceException {
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IServiceFactory#createServiceInstance()
+ *
+ * @return
+ * @throws ServiceException
+ * if the required sash model manager service is unavailable
+ */
+ @Override
+ public Object createServiceInstance() throws ServiceException {
+ if (sashModelMngr == null) {
+ throw new ServiceNotFoundException(DiSashModelManager.class.getName());
+ }
+ return sashModelMngr.getIPageManager();
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/PapyrusPageInput.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/PapyrusPageInput.java
new file mode 100644
index 00000000000..7b69d7863d9
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/PapyrusPageInput.java
@@ -0,0 +1,62 @@
+/*****************************************************************************
+ * Copyright (c) 2013 CEA LIST.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.editor;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.ui.part.FileEditorInput;
+
+/**
+ * Basic implementation of {@link IPapyrusPageInput}
+ *
+ * @author Camille Letavernier
+ */
+public class PapyrusPageInput extends FileEditorInput implements IPapyrusPageInput {
+
+ private final URI[] pages;
+
+ private final boolean closeOtherPages;
+
+ /**
+ * Creates a new PapyrusPageInput
+ *
+ * @param diFile
+ * The file resource
+ * @param pages
+ * The pageIdentifiers of the pages to open
+ * @param closeOtherPages
+ * True if only the selected pages should be opened. All other pages will be closed.
+ */
+ public PapyrusPageInput(IFile diFile, URI[] pages, boolean closeOtherPages) {
+ super(diFile);
+ this.pages = pages;
+ this.closeOtherPages = closeOtherPages;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public URI[] getPages() {
+ return pages;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean closeOtherPages() {
+ return closeOtherPages;
+ }
+
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/CompositeReloadContext.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/CompositeReloadContext.java
new file mode 100644
index 00000000000..3eabad5cbf3
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/CompositeReloadContext.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2014 CEA and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.infra.ui.editor.reload;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.papyrus.infra.core.utils.AdapterUtils;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+
+/**
+ * An {@linkplain EditorReloadEvent#putContext(Object) editor reload context} that composes other reload contexts.
+ * This should be used whenever a {@linkplain IReloadContextProvider reload context provider} supplies multiple
+ * reload contexts, to ensure that they are properly initialized by the reload system.
+ */
+public class CompositeReloadContext implements IDisposableReloadContext, IAdaptable {
+
+ private final Collection<Object> reloadContexts;
+
+ public CompositeReloadContext() {
+ this(Collections.EMPTY_LIST);
+ }
+
+ public CompositeReloadContext(Iterable<?> reloadContexts) {
+ super();
+
+ this.reloadContexts = Lists.newArrayList(reloadContexts);
+ }
+
+ public <T> T add(T reloadContext) {
+ reloadContexts.add(reloadContext);
+ return reloadContext;
+ }
+
+ public Iterable<?> getReloadContexts() {
+ return Collections.unmodifiableCollection(reloadContexts);
+ }
+
+ public <T> Iterable<T> getReloadContexts(Class<T> type) {
+ return Iterables.filter(getReloadContexts(), type);
+ }
+
+ @Override
+ public void dispose() {
+ for (Object next : reloadContexts) {
+ if (next instanceof IDisposableReloadContext) {
+ ((IDisposableReloadContext) next).dispose();
+ }
+ }
+
+ reloadContexts.clear();
+ }
+
+ @Override
+ public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) {
+ return (adapter == IInternalEMFSelectionContext.class) ? getEMFContext() : null;
+ }
+
+ private IInternalEMFSelectionContext getEMFContext() {
+ IInternalEMFSelectionContext result = null;
+
+ for (Object next : reloadContexts) {
+ if (AdapterUtils.adapt(next, IInternalEMFSelectionContext.class, null) != null) {
+ // We need the adapter
+ result = new IInternalEMFSelectionContext.Composite(this);
+ break;
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/DelegatingReloadContext.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/DelegatingReloadContext.java
new file mode 100644
index 00000000000..718b376c2ba
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/DelegatingReloadContext.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2014 CEA and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.infra.ui.editor.reload;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.papyrus.infra.core.utils.AdapterUtils;
+
+
+/**
+ * An {@linkplain EditorReloadEvent#putContext(Object) editor reload context} that delegates to another reload context.
+ * This should be used whenever a {@linkplain IReloadContextProvider reload context provider} is needed to get a reload
+ * context to delegate to.
+ */
+public class DelegatingReloadContext implements IDisposableReloadContext, IAdaptable {
+
+ private Object delegate;
+
+ public DelegatingReloadContext(Object reloadContextProvider) {
+ super();
+
+ IReloadContextProvider provider = AdapterUtils.adapt(reloadContextProvider, IReloadContextProvider.class, null);
+ if (provider != null) {
+ delegate = provider.createReloadContext();
+ }
+ }
+
+ @Override
+ public void dispose() {
+ if (delegate instanceof IDisposableReloadContext) {
+ ((IDisposableReloadContext) delegate).dispose();
+ }
+
+ delegate = null;
+ }
+
+ public Object getDelegate() {
+ return delegate;
+ }
+
+ public void restore(Object reloadContextProvider) {
+ if (delegate != null) {
+ IReloadContextProvider provider = AdapterUtils.adapt(reloadContextProvider, IReloadContextProvider.class, null);
+ if (provider != null) {
+ provider.restore(delegate);
+ }
+ }
+ }
+
+ @Override
+ public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) {
+ return (adapter == IInternalEMFSelectionContext.class) ? getEMFContext() : null;
+ }
+
+ private IInternalEMFSelectionContext getEMFContext() {
+ IInternalEMFSelectionContext result = null;
+
+ if ((delegate != null) && (AdapterUtils.adapt(delegate, IInternalEMFSelectionContext.class, null) != null)) {
+ // We need the adapter
+ result = new IInternalEMFSelectionContext.Delegating(this);
+ }
+
+ return result;
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EMFSelectionContext.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EMFSelectionContext.java
new file mode 100644
index 00000000000..e8eea1033cc
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EMFSelectionContext.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2014 CEA and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.infra.ui.editor.reload;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.jface.viewers.ISelectionProvider;
+
+
+/**
+ * A convenient selection re-load context for UIs that present EMF-based content.
+ */
+public class EMFSelectionContext extends SelectionContext<ISelectionProvider, URI> implements IAdaptable {
+
+ private IInternalEMFSelectionContext emfContext;
+
+ public EMFSelectionContext(ISelectionProvider structuredSelectionProvider) {
+ super(structuredSelectionProvider);
+ }
+
+ @Override
+ public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) {
+ return (adapter == IInternalEMFSelectionContext.class) ? getEMFContext() : null;
+ }
+
+ final IInternalEMFSelectionContext getEMFContext() {
+ if (emfContext == null) {
+ emfContext = new IInternalEMFSelectionContext.Default();
+ }
+ return emfContext;
+ }
+
+ @Override
+ protected URI getToken(Object object) {
+ return getEMFContext().getToken(object);
+ }
+
+ @Override
+ protected Object resolveToken(URI token) {
+ return getEMFContext().resolveToken(token);
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EMFTreeViewerContext.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EMFTreeViewerContext.java
new file mode 100644
index 00000000000..a6f99008f06
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EMFTreeViewerContext.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2014 CEA and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.infra.ui.editor.reload;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.jface.viewers.AbstractTreeViewer;
+
+/**
+ * A convenient context object for {@link IEditorReloadListener}s to store in an {@link EditorReloadEvent} to capture and restore
+ * the expansion and selection state of nodes in an EMF-based tree viewer.
+ */
+public class EMFTreeViewerContext extends TreeViewerContext<URI> implements IAdaptable {
+
+ private IInternalEMFSelectionContext emfContext;
+
+ public EMFTreeViewerContext(AbstractTreeViewer viewer) {
+ super(viewer);
+ }
+
+ @Override
+ public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) {
+ return (adapter == IInternalEMFSelectionContext.class) ? getEMFContext() : null;
+ }
+
+ final IInternalEMFSelectionContext getEMFContext() {
+ if (emfContext == null) {
+ emfContext = new IInternalEMFSelectionContext.Default();
+ }
+ return emfContext;
+ }
+
+ @Override
+ protected URI getToken(Object object) {
+ return getEMFContext().getToken(object);
+ }
+
+ @Override
+ protected Object resolveToken(URI token) {
+ return getEMFContext().resolveToken(token);
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EditorReloadAdapter.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EditorReloadAdapter.java
new file mode 100644
index 00000000000..5015f26011e
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EditorReloadAdapter.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2014 CEA and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.infra.ui.editor.reload;
+
+
+
+/**
+ * Convenience superclass for selective implementation of editor reload call-backs.
+ */
+public class EditorReloadAdapter implements IEditorReloadListener {
+
+ public EditorReloadAdapter() {
+ super();
+ }
+
+ @Override
+ public void editorAboutToReload(EditorReloadEvent event) {
+ // Pass
+ }
+
+ @Override
+ public void editorReloaded(EditorReloadEvent event) {
+ // Pass
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EditorReloadEvent.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EditorReloadEvent.java
new file mode 100644
index 00000000000..c4d13f721b4
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EditorReloadEvent.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2014 CEA and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.infra.ui.editor.reload;
+
+import java.util.EventObject;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.utils.AdapterUtils;
+import org.eclipse.papyrus.infra.ui.Activator;
+import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor;
+import org.eclipse.papyrus.infra.ui.editor.IReloadableEditor;
+
+import com.google.common.base.Supplier;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Maps;
+
+
+/**
+ * The event object for notifications of each phase in the reloading of a {@linkplain IReloadableEditor reloadable editor}.
+ */
+public class EditorReloadEvent extends EventObject {
+
+ private static final long serialVersionUID = 1L;
+
+ public static final int ABOUT_TO_RELOAD = 1;
+
+ public static final int RELOADED = 2;
+
+ private int type;
+
+ private transient Map<IEditorReloadListener, Object> context;
+
+ private transient IEditorReloadListener currentListener;
+
+ public EditorReloadEvent(IMultiDiagramEditor editor) {
+ super(editor);
+ }
+
+ public final IMultiDiagramEditor getEditor() {
+ return (IMultiDiagramEditor) getSource();
+ }
+
+ public final int getEventType() {
+ return type;
+ }
+
+ /**
+ * Puts some opaque representation of contextual state for the caller to retrieve later when an editor is {@linkplain IEditorReloadListener#editorReloaded(EditorReloadEvent) reloaded}.
+ * The canonical example of this usage is storing state such as selection, expanded tree nodes, etc. to restore after re-building a UI that
+ * depends on the reloaded editor. After the editor re-load completes and all listeners are notified of that, then all context objects are
+ * released. Any that implement the {@link IDisposableReloadContext} interface are disposed according to that protocol. This is done even if it
+ * happens that the editor re-load procedure cannot complete normally and the editor is forced to close without notifying the post-reload
+ * listeners.
+ *
+ * @param object
+ * some state to stash for later retrieval following the re-loading of the editor
+ *
+ * @return the previous context object, if any (there normally wouldn't be as each listener that is invoked has its own context storage
+ *
+ * @throws IllegalStateException
+ * on any attempt to invoke this method except during an {@link IEditorReloadListener#editorAboutToReload(EditorReloadEvent)} call-back
+ */
+ public Object putContext(Object object) {
+ checkContext(ABOUT_TO_RELOAD);
+
+ IInternalEMFSelectionContext emfContext = AdapterUtils.adapt(object, IInternalEMFSelectionContext.class, null);
+ if (emfContext != null) {
+ initContext(emfContext);
+ }
+
+ return context.put(currentListener, object);
+ }
+
+ /**
+ * Retrieves an opaque representation of contextual state that was previously {@linkplain #putContext(Object) put} by the caller.
+ *
+ * @return the previously stashed object, or {@code null} if none
+ *
+ * @throws IllegalStateException
+ * on any attempt to invoke this method except during an {@link IEditorReloadListener#editorReloaded(EditorReloadEvent)} call-back
+ */
+ public Object getContext() {
+ checkContext(RELOADED);
+ return context.get(currentListener);
+ }
+
+ private void initContext(IInternalEMFSelectionContext context) {
+ Supplier<ResourceSet> resourceSetSupplier = new Supplier<ResourceSet>() {
+
+ @Override
+ public ResourceSet get() {
+ try {
+ return getEditor().getServicesRegistry().getService(ModelSet.class);
+ } catch (ServiceException e) {
+ Activator.log.error(e);
+ throw new IllegalStateException("Invalid service registry in editor"); //$NON-NLS-1$
+ }
+ }
+ };
+
+ context.setResourceSetSupplier(resourceSetSupplier);
+ }
+
+ protected final void checkContext(int phase) {
+ if (currentListener == null) {
+ throw new IllegalStateException("Not in an IEditorReloadListener call-back"); //$NON-NLS-1$
+ }
+
+ if (phase != this.type) {
+ throw new IllegalStateException(String.format("Not in '%s' listener call-back", (phase == ABOUT_TO_RELOAD) ? "editorAboutToReload" : "editorReloaded"));
+ }
+ }
+
+ public final void dispatchEditorAboutToReload(Iterable<? extends IEditorReloadListener> listeners) {
+ context = Maps.newHashMap();
+ type = ABOUT_TO_RELOAD;
+
+ for (Iterator<? extends IEditorReloadListener> iter = listeners.iterator(); iter.hasNext();) {
+ currentListener = iter.next();
+
+ try {
+ currentListener.editorAboutToReload(this);
+ } catch (Exception e) {
+ Activator.log.error("Uncaught exception in editor reload listener.", e); //$NON-NLS-1$
+ } finally {
+ currentListener = null;
+ }
+ }
+ }
+
+ public final void dispatchEditorReloaded(Iterable<? extends IEditorReloadListener> listeners) {
+ type = RELOADED;
+
+ for (Iterator<? extends IEditorReloadListener> iter = listeners.iterator(); iter.hasNext();) {
+ currentListener = iter.next();
+
+ try {
+ currentListener.editorReloaded(this);
+ } catch (Exception e) {
+ Activator.log.error("Uncaught exception in editor reload listener.", e); //$NON-NLS-1$
+ } finally {
+ currentListener = null;
+ }
+ }
+ }
+
+ public void dispose() {
+ if (context != null) {
+ Error error = null;
+
+ try {
+ for (IDisposableReloadContext next : Iterables.filter(context.values(), IDisposableReloadContext.class)) {
+ try {
+ next.dispose();
+ } catch (Exception e) {
+ Activator.log.error("Uncaught exception in editor reload context disposal.", e); //$NON-NLS-1$
+ } catch (Error e) {
+ if (error == null) {
+ error = e;
+ }
+ Activator.log.error("Uncaught exception in editor reload context disposal.", e); //$NON-NLS-1$
+ }
+ }
+ } finally {
+ context = null;
+ }
+
+ if (error != null) {
+ throw error;
+ }
+ }
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IDisposableReloadContext.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IDisposableReloadContext.java
new file mode 100644
index 00000000000..8aff9ccf83b
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IDisposableReloadContext.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2014 CEA and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.infra.ui.editor.reload;
+
+/**
+ * Protocol implemented by {@link EditorReloadEvent} context objects that must be disposed when they are no longer needed.
+ *
+ * @see EditorReloadEvent#dispose()
+ */
+public interface IDisposableReloadContext {
+
+ void dispose();
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IEditorReloadListener.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IEditorReloadListener.java
new file mode 100644
index 00000000000..2114d555152
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IEditorReloadListener.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2014 CEA and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.infra.ui.editor.reload;
+
+import java.util.EventListener;
+
+import org.eclipse.papyrus.infra.ui.editor.IReloadableEditor;
+
+
+/**
+ * A protocol for notification of the phases of re-loading of an {@link IReloadableEditor}.
+ */
+public interface IEditorReloadListener extends EventListener {
+
+ /**
+ * Notifies that an editor is about to reload. Implementors may put stuff into the {@code event}'s {@link EditorReloadEvent#putContext(Object)
+ * context} to retrieve in an eventual {@linkplain #editorReloaded(EditorReloadEvent) }re-load} notification. The canonical example of this
+ * usage is storing state such as selection, expanded tree nodes, etc. to restore after re-building a UI that depends on the reloaded
+ * editor.
+ *
+ * @param event
+ * notification that an editor is going to re-load itself
+ */
+ void editorAboutToReload(EditorReloadEvent event);
+
+ /**
+ * Notifies that an editor has reloaded. Implementors may retrieve from the {@code event} any {@link EditorReloadEvent#getContext()
+ * context} that they put in {@linkplain #editorAboutToReload(EditorReloadEvent) before} the re-load.
+ *
+ * @param event
+ * notification that an editor has reloaded
+ */
+ void editorReloaded(EditorReloadEvent event);
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IInternalEMFSelectionContext.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IInternalEMFSelectionContext.java
new file mode 100644
index 00000000000..f8bda865a97
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IInternalEMFSelectionContext.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2014 CEA and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.infra.ui.editor.reload;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.papyrus.infra.core.utils.AdapterUtils;
+
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+
+
+/**
+ * An internal interface provided (usually as an {@linkplain IAdaptable#getAdapter(Class) adapter}) by EMF-based {@linkplain SelectionContext
+ * selection contexts}.
+ */
+interface IInternalEMFSelectionContext {
+
+ void setResourceSetSupplier(Supplier<? extends ResourceSet> resourceSetSupplier);
+
+ URI getToken(Object object);
+
+ Object resolveToken(URI token);
+
+ class Default implements IInternalEMFSelectionContext {
+
+ Supplier<? extends ResourceSet> resourceSetSupplier;
+
+ Default() {
+ super();
+ }
+
+ @Override
+ public void setResourceSetSupplier(Supplier<? extends ResourceSet> resourceSetSupplier) {
+ this.resourceSetSupplier = Suppliers.memoize(resourceSetSupplier);
+ }
+
+ @Override
+ public URI getToken(Object object) {
+ return (object instanceof EObject) ? EcoreUtil.getURI((EObject) object) : null;
+ }
+
+ @Override
+ public Object resolveToken(URI token) {
+ ResourceSet rset = (resourceSetSupplier == null) ? null : resourceSetSupplier.get();
+ return (rset == null) ? null : rset.getEObject(token, true);
+ }
+
+ }
+
+ class Composite extends Default {
+
+ private final CompositeReloadContext composite;
+
+ Composite(CompositeReloadContext composite) {
+ super();
+
+ this.composite = composite;
+ }
+
+ @Override
+ public void setResourceSetSupplier(Supplier<? extends ResourceSet> resourceSetSupplier) {
+ super.setResourceSetSupplier(resourceSetSupplier);
+
+ for (Object next : composite.getReloadContexts()) {
+ IInternalEMFSelectionContext emfContext = AdapterUtils.adapt(next, IInternalEMFSelectionContext.class, null);
+ if (emfContext != null) {
+ // Pass along the memoizer so that we can all share it
+ emfContext.setResourceSetSupplier(this.resourceSetSupplier);
+ }
+ }
+ }
+ }
+
+ class Delegating extends Default {
+
+ private final DelegatingReloadContext delegating;
+
+ Delegating(DelegatingReloadContext delegating) {
+ super();
+
+ this.delegating = delegating;
+ }
+
+ @Override
+ public void setResourceSetSupplier(Supplier<? extends ResourceSet> resourceSetSupplier) {
+ super.setResourceSetSupplier(resourceSetSupplier);
+
+ IInternalEMFSelectionContext emfContext = AdapterUtils.adapt(delegating.getDelegate(), IInternalEMFSelectionContext.class, null);
+ if (emfContext != null) {
+ // Pass along the memoizer so that we can all share it
+ emfContext.setResourceSetSupplier(this.resourceSetSupplier);
+ }
+ }
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IReloadContextProvider.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IReloadContextProvider.java
new file mode 100644
index 00000000000..f3449f59be9
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IReloadContextProvider.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2014 CEA and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.infra.ui.editor.reload;
+
+
+/**
+ * An adapter protocol for objects that can provide {@code context}s to be included in the
+ * re-load state of dependent parts in an {@link EditorReloadEvent}, for the purpose of
+ * restoring the state of those objects after re-load has completed.
+ */
+public interface IReloadContextProvider {
+
+ /**
+ * Creates an opaque token from which the receiver can be {@linkplain #restore(Object) restored} after the editor has reloaded.
+ *
+ * @return an opaque editor re-load context, or {@code null} if none is needed on this occasion (for example because the receiver
+ * is in its default state)
+ */
+ Object createReloadContext();
+
+ /**
+ * Reloads the receiver's state from a token previously {@linkplain #createReloadContext() provided}.
+ *
+ * @param reloadContext
+ * the opaque re-load context token
+ */
+ void restore(Object reloadContext);
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/SelectionContext.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/SelectionContext.java
new file mode 100644
index 00000000000..15d58b5c4a1
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/SelectionContext.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2014 CEA and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.infra.ui.editor.reload;
+
+import java.util.List;
+
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+
+import com.google.common.collect.Lists;
+
+/**
+ * A convenient context object for {@link IEditorReloadListener}s to store in an {@link EditorReloadEvent} to capture and restore
+ * the selection state a selection provider;
+ *
+ * @param <V>
+ * the type of selection provider
+ * @param <T>
+ * the type of token used to restore the selection state
+ */
+public abstract class SelectionContext<V extends ISelectionProvider, T> {
+
+ private List<T> selection = Lists.newArrayList();
+
+ public SelectionContext(V structuredSelectionProvider) {
+ for (Object next : ((IStructuredSelection) structuredSelectionProvider.getSelection()).toList()) {
+ T token = token(next);
+ if (token != null) {
+ selection.add(token);
+ }
+ }
+ }
+
+ public void restore(V structuredSelectionProvider) {
+ List<Object> select = Lists.newArrayListWithCapacity(selection.size());
+ for (T next : selection) {
+ Object resolved = resolve(next);
+ if (resolved != null) {
+ select.add(resolved);
+ }
+ }
+ setSelection(structuredSelectionProvider, select);
+ }
+
+ T token(Object selectableElement) {
+ Object deresolved = deresolveSelectableElement(selectableElement);
+ return (deresolved == null) ? null : getToken(deresolved);
+ }
+
+ protected Object deresolveSelectableElement(Object selectableElement) {
+ return selectableElement;
+ }
+
+ protected abstract T getToken(Object object);
+
+ Object resolve(T token) {
+ Object deresolved = resolveToken(token);
+ return (deresolved == null) ? null : resolveSelectableElement(deresolved);
+ }
+
+ protected Object resolveSelectableElement(Object deresolved) {
+ return deresolved;
+ }
+
+ protected abstract Object resolveToken(T token);
+
+ protected void setSelection(V structuredSelectionProvider, List<?> selection) {
+ structuredSelectionProvider.setSelection(new StructuredSelection(selection));
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/TreeViewerContext.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/TreeViewerContext.java
new file mode 100644
index 00000000000..6d70788326c
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/TreeViewerContext.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2014 CEA and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.infra.ui.editor.reload;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.jface.viewers.AbstractTreeViewer;
+import org.eclipse.jface.viewers.StructuredSelection;
+
+import com.google.common.collect.Lists;
+
+/**
+ * A convenient context object for {@link IEditorReloadListener}s to store in an {@link EditorReloadEvent} to capture and restore
+ * the expansion and selection state of nodes in a tree viewer.
+ */
+public abstract class TreeViewerContext<T> extends SelectionContext<AbstractTreeViewer, T> {
+
+ private List<T> expandedNodes = Lists.newArrayList();
+
+ public TreeViewerContext(AbstractTreeViewer viewer) {
+ super(viewer);
+
+ for (Object next : viewer.getExpandedElements()) {
+ T token = token(next);
+ if (token != null) {
+ expandedNodes.add(token);
+ }
+ }
+ }
+
+ @Override
+ public void restore(AbstractTreeViewer viewer) {
+ List<Object> expand = Lists.newArrayListWithCapacity(expandedNodes.size());
+ for (T next : expandedNodes) {
+ Object resolved = resolve(next);
+ if (resolved != null) {
+ expand.add(resolved);
+ }
+ }
+ setExpandedElements(viewer, expand);
+
+ super.restore(viewer);
+ }
+
+ @Override
+ protected void setSelection(AbstractTreeViewer viewer, List<?> selection) {
+ viewer.setSelection(new StructuredSelection(selection), true);
+ }
+
+ protected void setExpandedElements(AbstractTreeViewer viewer, Collection<?> toExpand) {
+ viewer.setExpandedElements(toExpand.toArray());
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IEditorFactory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IEditorFactory.java
new file mode 100644
index 00000000000..182c962b822
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IEditorFactory.java
@@ -0,0 +1,57 @@
+/**
+ *
+ */
+package org.eclipse.papyrus.infra.ui.editorsfactory;
+
+import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.IPageModel;
+
+/**
+ * Factory used to get the Icon associated to the editor used to render the
+ * specified pageIdentifier.
+ *
+ *
+ * @author cedric dumoulin
+ *
+ */
+public interface IEditorFactory {
+
+ /**
+ * Create the {@link IPageModel} for the specified identifier. TODO throw an
+ * exception encapsulating problems encountered while creating the model.
+ *
+ * @param pageIdentifier
+ * Object identifying an Editor.
+ * @return PageModel allowing to create the editor.
+ */
+ public IPageModel createIPageModel(Object pageIdentifier);
+
+ /**
+ * Return true if the factory can create an IPageModel for the specified
+ * pageIdentifier. Return false otherwise TODO throw an exception
+ * encapsulating problems encountered while creating the model.
+ *
+ * @param pageIdentifier
+ * The object representing the page to test
+ * @return
+ */
+ public boolean isPageModelFactoryFor(Object pageIdentifier);
+
+ /**
+ * The ID of this factory
+ *
+ * @return
+ */
+ default String getFactoryID() {
+ return getClass().getName();
+ }
+
+ /**
+ * The display label of this factory
+ *
+ * @return
+ */
+ default String getLabel() {
+ return getClass().getSimpleName();
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IEditorIconFactory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IEditorIconFactory.java
new file mode 100644
index 00000000000..9ccf1af0cfe
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IEditorIconFactory.java
@@ -0,0 +1,64 @@
+/**
+ *
+ */
+package org.eclipse.papyrus.infra.ui.editorsfactory;
+
+import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.IPageModel;
+import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.ISashWindowsContentProvider;
+import org.eclipse.papyrus.infra.core.sasheditor.di.contentprovider.DiSashModelMngr;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.ISashWindowsContainer;
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * Factory used to create an {@link IPageModel} used by the {@link ISashWindowsContainer} to create an instance of the editor represented
+ * by the provided Object. Such factory is required by the {@link DiSashModelMngr}. It is called whenever the ISashWindowsContainer need
+ * to create an editor from an EObject representing this editor in the Di
+ * implementation of the {@link ISashWindowsContentProvider}
+ *
+ *
+ * @author cedric dumoulin
+ *
+ */
+public interface IEditorIconFactory {
+
+ /**
+ * Get the icon associated to the editor used to render the model. Model
+ * represent the top level object of a model editor. Can return a cached
+ * Image.
+ *
+ * @param pageIdentifier
+ * the pageIdentifier representing the Editor. This is usually
+ * the EObject used to reconstruct the editor.
+ * @return the icon representing the editor
+ */
+ public Image getEditorIcon(Object pageIdentifier);
+
+ /**
+ * Create the icon associated to the editor used to render the model. Model
+ * represent the top level object of a model editor. Always return a newly
+ * created Image.
+ *
+ * @param pageIdentifier
+ * the pageIdentifier representing the Editor. This is usually
+ * the EObject used to reconstruct the editor.
+ * @return the icon representing the editor
+ */
+ public Image createEditorIcon(Object pageIdentifier);
+
+ /**
+ * Return true if the factory can create an IPageModel for the specified
+ * pageIdentifier. Return false otherwise TODO throw an exception
+ * encapsulating problems encountered while creating the model.
+ *
+ * @param pageIdentifier
+ * The object representing the page to test
+ * @return
+ */
+ public boolean isPageModelFactoryFor(Object pageIdentifier);
+
+ /**
+ * Dispose this factory
+ */
+ public void dispose();
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IEditorIconFactoryExtended.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IEditorIconFactoryExtended.java
new file mode 100644
index 00000000000..06d9344e865
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IEditorIconFactoryExtended.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2011 Atos.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Atos - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.infra.ui.editorsfactory;
+
+/**
+ *
+ * @author "Arthur Daussy <a href="mailto:arthur.daussy@atos.net">arthur.daussy@atos.net</a>"
+ *
+ */
+public interface IEditorIconFactoryExtended extends IEditorIconFactory {
+
+ /**
+ * Return the icon URL associated to the editor used to render the model. Model represent the top level
+ * object of a model editor.
+ *
+ * @param pageIdentifier
+ * @return
+ */
+ public String getURLMainIcon(Object pageIdentifier);
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IPageIconsRegistry.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IPageIconsRegistry.java
new file mode 100644
index 00000000000..6b117ecbeaa
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IPageIconsRegistry.java
@@ -0,0 +1,40 @@
+/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.editorsfactory;
+
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * Registry used to get Icons associated to an editor.
+ *
+ * @author cedric dumoulin
+ */
+public interface IPageIconsRegistry {
+
+ /**
+ * Get the icon associated to the editor used to render the model. Model
+ * represent the top level object of a model editor.
+ *
+ * @param model
+ * the model representing the Editor. This is usually the EObject
+ * used to reconstruct the editor.
+ * @return the icon representing the editor
+ */
+ public Image getEditorIcon(Object model);
+
+ /**
+ * Dispose this registry
+ */
+ public void dispose();
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IPageIconsRegistryExtended.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IPageIconsRegistryExtended.java
new file mode 100644
index 00000000000..c8153b3bef4
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IPageIconsRegistryExtended.java
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2011 Atos Origin.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Atos Origin - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.infra.ui.editorsfactory;
+
+/**
+ * Extends IPageIconsRegistry in order to offer a second methods which will give back the URL of the requested Icon
+ *
+ * @author "Arthur Daussy <a href="mailto:arthur.daussy@atos.net">arthur.daussy@atos.net</a>"
+ *
+ */
+public interface IPageIconsRegistryExtended extends IPageIconsRegistry {
+
+ /**
+ * Get the URL icon associated to the editor used to render the model. Model represent the top level
+ * object of a model editor.
+ *
+ * @param model
+ * @return {@link String} which represent the URL of the resource
+ */
+ public String getEditorURLIcon(Object model);
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/PageIconsRegistry.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/PageIconsRegistry.java
new file mode 100644
index 00000000000..d60e8f71f96
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/PageIconsRegistry.java
@@ -0,0 +1,118 @@
+/**
+ *
+ */
+package org.eclipse.papyrus.infra.ui.editorsfactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * Concrete implementation of the {@link IPageIconsRegistry}. This
+ * implementation allows to add and remove {@link IPageIconsRegistry}.
+ *
+ *
+ * @author cedric dumoulin
+ */
+public class PageIconsRegistry implements IPageIconsRegistryExtended {
+
+ /** list of registered icon factories */
+ protected List<IEditorIconFactory> pageIcons = new ArrayList<IEditorIconFactory>();
+
+ /**
+ * Constructor.
+ *
+ * @param editorFactoryRegistry
+ * @param servicesRegistry
+ */
+ public PageIconsRegistry() {
+
+ }
+
+ /**
+ * Walk each registered {@link IEditorFactory} to find the one handling the
+ * specified pageIdentifier. Call the corresponding method in the found
+ * pageIdentifier.
+ *
+ * TODO Throw an exception to report errors.
+ *
+ * @see org.eclipse.papyrus.infra.core.sasheditor.di.contentprovider.IPageModelFactory#createIPageModel(java.lang.Object)
+ */
+ @Override
+ public Image getEditorIcon(Object pageIdentifier) {
+
+ for (IEditorIconFactory factory : getPageIcons()) {
+ if (factory.isPageModelFactoryFor(pageIdentifier)) {
+ {
+ // return factory.getEditorIcon(pageIdentifier);
+ return factory.getEditorIcon(pageIdentifier);
+ }
+ }
+ }
+ // no editor found !
+ // TODO Throw an exception.
+ // throw new EditorNotFoundException("No editor registered for '" +
+ // pageIdentifier + "'.");
+ return null;
+ }
+
+ /**
+ * @return the editorFactories
+ */
+ protected List<IEditorIconFactory> getPageIcons() {
+ return pageIcons;
+ }
+
+ /**
+ * Add the specified {@link IEditorFactory}
+ *
+ * @param editorIconFactory
+ */
+ public void add(IEditorIconFactory editorIconFactory) {
+ // This should never happen
+ if (editorIconFactory == null) {
+ throw new RuntimeException("Parameter should not be null."); //$NON-NLS-1$
+ }
+
+ pageIcons.add(editorIconFactory);
+ }
+
+ /**
+ * Remove the specified {@link IEditorFactory}
+ *
+ * @param editorIconFactory
+ */
+ public void remove(IEditorIconFactory editorIconFactory) {
+ pageIcons.remove(editorIconFactory);
+ }
+
+ /**
+ * Return the path to the icon ressource.
+ *
+ * @see org.eclipse.papyrus.infra.ui.editorsfactory.IPageIconsRegistryExtended#getEditorURLIcon(java.lang.Object)
+ *
+ * @param model
+ * @return
+ */
+ @Override
+ public String getEditorURLIcon(Object model) {
+ for (IEditorIconFactory factory : getPageIcons()) {
+ if (factory.isPageModelFactoryFor(model)) {
+ {
+ if (factory instanceof IEditorIconFactoryExtended) {
+ return ((IEditorIconFactoryExtended) factory).getURLMainIcon(model);
+ }
+ }
+ }
+ }
+ return "";
+ }
+
+ @Override
+ public void dispose() {
+ for (IEditorIconFactory factory : pageIcons) {
+ factory.dispose();
+ }
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/PageModelFactoryRegistry.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/PageModelFactoryRegistry.java
new file mode 100644
index 00000000000..32774bb7a25
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/PageModelFactoryRegistry.java
@@ -0,0 +1,165 @@
+/*****************************************************************************
+ * Copyright (c) 2009 - 2015 CEA LIST & LIFL
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ * Camille Letavernier (CEA LIST) - camille.letavernier@cea.fr - Bug 476625
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.editorsfactory;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.IPageModel;
+import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.ISashWindowsContentProvider;
+import org.eclipse.papyrus.infra.core.sasheditor.di.contentprovider.IPageModelFactory;
+import org.eclipse.papyrus.infra.ui.Activator;
+
+/**
+ * Concrete implementation of the {@link IPageModelFactory} required by the di
+ * implementation of {@link ISashWindowsContentProvider}. This implementation
+ * allows to add and remove {@link IEditorFactory}.
+ *
+ *
+ * @author cedric dumoulin
+ */
+public class PageModelFactoryRegistry implements IPageModelFactory {
+
+ /** ordered list of editor factories */
+ protected List<IEditorFactory> editorFactories = new ArrayList<IEditorFactory>();
+
+ /**
+ * Constructor.
+ *
+ * @param editorFactoryRegistry
+ * @param servicesRegistry
+ */
+ public PageModelFactoryRegistry() {
+
+ }
+
+ /**
+ * Walk each registered {@link IEditorFactory} to find the one handling the
+ * specified pageIdentifier. Call the corresponding method in the found
+ * pageIdentifier.
+ *
+ * TODO Throw an exception to report errors.
+ *
+ * @see org.eclipse.papyrus.infra.core.sasheditor.di.contentprovider.IPageModelFactory#createIPageModel(java.lang.Object)
+ */
+ @Override
+ public IPageModel createIPageModel(Object pageIdentifier) {
+ return createIPageModel(pageIdentifier, null);
+ }
+
+ /**
+ * Walk each registered {@link IEditorFactory} to find the one handling the
+ * specified pageIdentifier. Call the corresponding method in the found
+ * pageIdentifier.
+ *
+ * If several factories match the selected page, use the favorite editor.
+ * If the favorite editor is not available, use the priority mechanism
+ *
+ * @see org.eclipse.papyrus.infra.core.sasheditor.di.contentprovider.IPageModelFactory#createIPageModel(java.lang.Object)
+ */
+ @Override
+ public IPageModel createIPageModel(Object pageIdentifier, String favoriteEditorID) {
+
+ IEditorFactory factory = getFactoryFor(pageIdentifier, favoriteEditorID);
+ if (factory == null) {
+ return null;
+ }
+ return factory.createIPageModel(pageIdentifier);
+ }
+
+ /**
+ * Returns the IEditorFactory for the given pageIdentifier.
+ *
+ * If several factories match the page identifier, use the favorite one
+ *
+ * @param pageIdentifier
+ * @return
+ */
+ private IEditorFactory getFactoryFor(Object pageIdentifier, String favoriteEditorID) {
+ List<IEditorFactory> matchingFactories = new LinkedList<>();
+
+ for (IEditorFactory factory : getEditorFactories()) {
+ if (factory.isPageModelFactoryFor(pageIdentifier)) {
+ matchingFactories.add(factory);
+ }
+ }
+
+ if (matchingFactories.isEmpty()) {
+ return null;
+ } else if (matchingFactories.size() == 1) {
+ return matchingFactories.get(0);
+ } else if (favoriteEditorID != null) {
+ for (IEditorFactory matchingFactory : matchingFactories) {
+ if (favoriteEditorID.equals(matchingFactory.getFactoryID())) {
+ return matchingFactory;
+ }
+ }
+ }
+
+ return matchingFactories.get(0);
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.sasheditor.di.contentprovider.IPageModelFactory#getEditorIDsFor(java.lang.Object)
+ *
+ * @param pageIdentifier
+ * @return
+ */
+ @Override
+ public Map<String, String> getEditorIDsFor(Object pageIdentifier) {
+ return getEditorFactories().stream()
+ .filter(f -> f.isPageModelFactoryFor(pageIdentifier))
+ .collect(Collectors
+ .toMap(
+ f -> f.getFactoryID(), f -> f.getLabel(), // key, value
+ (v1, v2) -> { // Conflict merger
+ Activator.log.warn(String.format("Several editors are declared with the same ID: '%s', '%s'", v1, v2));
+ return v1; // Any value
+ } ,
+ LinkedHashMap::new)); // HashMap Supplier
+ }
+
+ /**
+ * @return the editorFactories
+ */
+ protected List<IEditorFactory> getEditorFactories() {
+ return editorFactories;
+ }
+
+ /**
+ * Add the specified {@link IEditorFactory}
+ *
+ * @param editorFactory
+ */
+ public void add(IEditorFactory editorFactory) {
+ // This should never happen
+ if (editorFactory == null) {
+ throw new IllegalArgumentException("Parameter should not be null."); //$NON-NLS-1$
+ }
+
+ editorFactories.add(editorFactory);
+ }
+
+ /**
+ * Remove the specified {@link IEditorFactory}
+ *
+ * @param editorFactory
+ */
+ public void remove(IEditorFactory editorFactory) {
+ editorFactories.remove(editorFactory);
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/anytype/AnyTypeEditorFactory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/anytype/AnyTypeEditorFactory.java
new file mode 100644
index 00000000000..cbb70c2e4e1
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/anytype/AnyTypeEditorFactory.java
@@ -0,0 +1,135 @@
+/*****************************************************************************
+ * Copyright (c) 2013, 2014 CEA LIST and others.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (camille.letavernier@cea.fr) - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 392301
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.editorsfactory.anytype;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.xml.type.AnyType;
+import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.IComponentModel;
+import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.IPageModel;
+import org.eclipse.papyrus.infra.ui.extension.diagrameditor.AbstractEditorFactory;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * An EditorFactory for "AnyType", i.e. EObject deserialized from unknown Packages
+ *
+ * Allows recovery and manipulation of models containing optional EMF components
+ *
+ * @author Camille Letavernier
+ */
+public class AnyTypeEditorFactory extends AbstractEditorFactory {
+
+ public AnyTypeEditorFactory() {
+ super(null, "AnyTypeHandler");
+ }
+
+ @Override
+ public IPageModel createIPageModel(Object pageIdentifier) {
+
+ final AnyType anyTypeModel = (AnyType) pageIdentifier;
+
+ return new IComponentModel() {
+
+ private AnyType anyType = anyTypeModel;
+
+ @Override
+ public void dispose() {
+ // Pass. The tab icon is a workbench-shared image
+ }
+
+ @Override
+ public String getTabTitle() {
+ EClass eClass = anyType.eClass();
+ String label;
+ if (eClass == null) {
+ label = "component";
+ } else {
+ label = eClass.getName();
+ }
+ return "Missing " + label;
+ }
+
+ private String getTypeLabel() {
+ EClass eClass = anyType.eClass();
+ String className = eClass == null ? "None" : eClass.getName();
+ return className;
+ }
+
+ private String getNsURI() {
+ EClass eClass = anyType.eClass();
+ EPackage ePackage = eClass == null ? null : eClass.getEPackage();
+ String ePackageName = ePackage == null ? "None" : ePackage.getNsURI();
+
+ return ePackageName;
+ }
+
+ public Image getComponentIcon() {
+ return Display.getDefault().getSystemImage(SWT.ICON_WARNING);
+ }
+
+ @Override
+ public Image getTabIcon() {
+ return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJS_WARN_TSK);
+ }
+
+ @Override
+ public Object getRawModel() {
+ return anyType;
+ }
+
+ public String getErrorText() {
+ String typeLabel = getTypeLabel();
+ String packageURI = getNsURI();
+ String message = "A component is missing. The following Model cannot be loaded: " + typeLabel + " (from " + packageURI + ")\n";
+ message += "Changes to the model won't be reflected in this editor. This editor will be saved in the current state, i.e. without any data loss. ";
+ message += "However, this may result in an inconsistent state of this editor when the missing component will be restored\n";
+ return message;
+ }
+
+ @Override
+ public Composite createPartControl(Composite parent) {
+ Composite tabComposite = new Composite(parent, SWT.NONE);
+ tabComposite.setLayout(new GridLayout(2, false));
+
+ Image componentIcon = getComponentIcon();
+ if (componentIcon != null) {
+ Label errorImageLabel = new Label(tabComposite, SWT.NONE);
+ errorImageLabel.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
+ errorImageLabel.setImage(componentIcon);
+ }
+
+ Label label = new Label(tabComposite, SWT.WRAP);
+ label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ label.setText(getErrorText());
+
+ return tabComposite;
+ }
+ };
+ }
+
+ @Override
+ public boolean isPageModelFactoryFor(Object pageIdentifier) {
+ return pageIdentifier instanceof AnyType;
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/commands/ICreationCondition.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/commands/ICreationCondition.java
new file mode 100644
index 00000000000..575b769e3ec
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/commands/ICreationCondition.java
@@ -0,0 +1,36 @@
+/*****************************************************************************
+ * Copyright (c) 2009 ATOS ORIGIN.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Tristan Faure (ATOS ORIGIN) tristan.faure@atosorigin.com - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.extension.commands;
+
+import org.eclipse.emf.ecore.EObject;
+
+public interface ICreationCondition {
+
+ /**
+ * This method returns true if the diagram creation is allowed
+ *
+ * @param selectedElement
+ * the element where the diagram is provided
+ * @return true if the diagram can be created
+ */
+ boolean create(EObject selectedElement);
+
+ /**
+ * set the command ID in order to take account the environment in order to
+ * create a diagram
+ *
+ * @param commandID
+ */
+ public void setCommand(String commandID);
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/commands/IModelCreationCommand.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/commands/IModelCreationCommand.java
new file mode 100644
index 00000000000..beb200f6086
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/commands/IModelCreationCommand.java
@@ -0,0 +1,31 @@
+/*****************************************************************************
+ * Copyright (c) 2010 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Tatiana Fesenko (CEA LIST) - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.extension.commands;
+
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+
+/**
+ * The Interface IModelCreationCommand.
+ */
+public interface IModelCreationCommand {
+
+ /**
+ * Creates the model.
+ *
+ * @param modelSet
+ * the modelSet set
+ */
+ void createModel(final ModelSet modelSet);
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/commands/PerspectiveContextDependence.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/commands/PerspectiveContextDependence.java
new file mode 100644
index 00000000000..7d6d993c982
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/commands/PerspectiveContextDependence.java
@@ -0,0 +1,51 @@
+/*****************************************************************************
+ * Copyright (c) 2010 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Patrick Tessier (CEA LIST) Patrick.tessier@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.extension.commands;
+
+import org.eclipse.emf.ecore.EObject;
+
+//FIXME Refactoring Juno : I don't know how to migrate this code
+public class PerspectiveContextDependence implements ICreationCondition {
+
+ protected String commandID = null;
+
+ public PerspectiveContextDependence() {
+ // TODO Auto-generated constructor stub
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean create(EObject selectedElement) {
+ // FIXME Refactoring Juno : I don't know how to migrate this code
+ // // Get the perspective
+ // Perspective perspective = ((WorkbenchPage)PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()).getActivePerspective();
+ // // look for the perspective
+ // // verify if the command has to be displayed
+ // if(perspective.getHiddenMenuItems().contains(commandID) && perspective.getHiddenToolbarItems().contains(commandID)) {
+ // return false;
+ // }
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setCommand(String commandID) {
+ this.commandID = commandID;
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/AbstractEditorFactory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/AbstractEditorFactory.java
new file mode 100644
index 00000000000..bde8a69767e
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/AbstractEditorFactory.java
@@ -0,0 +1,109 @@
+/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.extension.diagrameditor;
+
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.ui.editorsfactory.IEditorFactory;
+
+/**
+ * Abstract base class for Factory of editors. See {@link IEditorFactory}.
+ *
+ *
+ * @author Remi Schnekenburger
+ * @author Patrick Tessier
+ * @author cedric dumoulin
+ */
+public abstract class AbstractEditorFactory implements IPluggableEditorFactory {
+
+ /**
+ * Expected Class of the diagram to create.
+ */
+ private Class<?> diagramClass;
+
+ /** Expected diagram type (@see {@link Diagram#getType()}) */
+ private String expectedType;
+
+ /**
+ * EditorDescriptor associated to the factory. TODO : Maybe use individual
+ * setters to set the requested data (ContributorId and Icon).
+ */
+ protected EditorDescriptor editorDescriptor;
+
+ /**
+ * ServiceRegistry that can be provided to created editors.
+ */
+ private ServicesRegistry serviceRegistry;
+
+ /**
+ * Creates a new AbstractEditorFactory.
+ *
+ * @param diagramClass
+ * expected Class of the diagram to create.
+ * @param expectedType
+ * expected diagram type (@see {@link Diagram#getType()})
+ */
+ public AbstractEditorFactory(Class<?> diagramClass, String expectedType) {
+ assert (expectedType != null);
+ this.diagramClass = diagramClass;
+ this.expectedType = expectedType;
+ }
+
+ /**
+ * Initialize the factory with useful Classes.
+ *
+ * @param serviceRegistry
+ * Service registry that will be provided to created editor.
+ * @param editorDescriptor
+ * Descriptor containing data from the Eclipse Extension.
+ */
+ @Override
+ public void init(ServicesRegistry serviceRegistry, EditorDescriptor editorDescriptor) {
+ this.editorDescriptor = editorDescriptor;
+ this.serviceRegistry = serviceRegistry;
+
+ }
+
+ /**
+ * @return the serviceRegistry
+ */
+ public ServicesRegistry getServiceRegistry() {
+ return serviceRegistry;
+ }
+
+ /**
+ * Returns the expected class for the diagram implementation
+ *
+ * @return the expected class for the diagram implementation
+ */
+ public Class<?> getDiagramClass() {
+ return diagramClass;
+ }
+
+ /**
+ * Returns the expected type of the diagram
+ *
+ * @return the expected diagram type (@see {@link Diagram#getType()})
+ */
+ public String getExpectedType() {
+ return expectedType;
+ }
+
+ /**
+ * @return the editorDescriptor
+ */
+ public EditorDescriptor getEditorDescriptor() {
+ return editorDescriptor;
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorDescriptor.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorDescriptor.java
new file mode 100644
index 00000000000..502360c09d7
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorDescriptor.java
@@ -0,0 +1,168 @@
+/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.extension.diagrameditor;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+/**
+ * This descriptor describes a nested diagram. It is used by MultiDiagramEditor
+ * to know about the nested diagram. It is fill by an extension.
+ *
+ * @author Cedric Dumoulin
+ *
+ */
+public class EditorDescriptor {
+
+ /**
+ * Editor factory implementation class.
+ */
+ private Class<IPluggableEditorFactory> editorFactoryClass;
+
+ /**
+ * EditorActionBarContributor Id used to search the
+ * EditorActionBarContributor requested by the editor.
+ */
+ private String actionBarContributorId;
+
+ /**
+ * The icon representing the diagram
+ */
+ private ImageDescriptor icon;
+
+ /**
+ * Resource path to the icon
+ */
+ private String iconPath;
+
+ /**
+ * The order of this factory. Used when several factories match the same element (Diagram...)
+ * The lower the order, the higher the priority of this factory
+ */
+ private int order;
+
+ /**
+ * Constructor.
+ */
+ public EditorDescriptor() {
+
+ }
+
+ /**
+ *
+ * @param attribute
+ */
+ public void setActionBarContributorId(String actionBarContributorId) {
+ this.actionBarContributorId = actionBarContributorId;
+
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.extension.diagrameditor.IEditorDescriptor#getActionBarContributorId()
+ * @return
+ *
+ */
+ public String getActionBarContributorId() {
+ return actionBarContributorId;
+ }
+
+ /**
+ * get the editor icon path
+ *
+ * @return the editor icon path
+ */
+ public ImageDescriptor getIcon() {
+ return icon;
+ }
+
+ /**
+ * set the editor icon
+ *
+ * @param icon
+ * the icon path
+ */
+ public void setIcon(ImageDescriptor icon) {
+ this.icon = icon;
+ }
+
+ /**
+ * get the class of the editor factory
+ *
+ * @return the class of the editor
+ */
+ public Class<IPluggableEditorFactory> getEditorFactoryClass() {
+ return editorFactoryClass;
+ }
+
+ /**
+ * set the editor facoty to this descriptor
+ *
+ * @param editorFactoryClass
+ * the class that represents the editor factory
+ */
+ public void setEditorFactoryClass(Class<IPluggableEditorFactory> editorFactoryClass) {
+ this.editorFactoryClass = editorFactoryClass;
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ if (editorFactoryClass == null || editorFactoryClass.getName() == null) {
+ return "[nestedEditor editorFactory:" + editorFactoryClass + "(null)]";
+ }
+ return "[nestedEditor editorFactory:" + editorFactoryClass.getName() + "]";
+ }
+
+ public int getOrder() {
+ return order;
+ }
+
+ public void setOrder(int order) {
+ this.order = order;
+ }
+
+ /**
+ * Set the URL of the Icon
+ *
+ * @param iconPath
+ * path of the Icon
+ */
+ public void setIconURL(String iconPath) {
+ this.iconPath = iconPath;
+ }
+
+ /**
+ * Get the URL of the based images
+ *
+ * @return the path of the mai image. can return null if this property is not set
+ */
+ public String getIconURL() {
+ return iconPath;
+ }
+
+ /**
+ * set the Icon thanks to a {@link IConfigurationElement} and {@link String}which represent the path of the Icon
+ *
+ * @param element
+ * @param iconPath
+ */
+ public void setIcon(IConfigurationElement element, String iconPath, String pluginID) {
+ setIcon(AbstractUIPlugin.imageDescriptorFromPlugin(element.getNamespaceIdentifier(), iconPath));
+ setIconURL(element.getNamespaceIdentifier() + '/' + iconPath);
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorDescriptorExtensionFactory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorDescriptorExtensionFactory.java
new file mode 100644
index 00000000000..8d57b2fe3ab
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorDescriptorExtensionFactory.java
@@ -0,0 +1,99 @@
+/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.extension.diagrameditor;
+
+import static org.eclipse.papyrus.infra.core.Activator.log;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.papyrus.infra.core.extension.BadNameExtensionException;
+import org.eclipse.papyrus.infra.core.extension.ExtensionException;
+import org.eclipse.papyrus.infra.core.extension.ExtensionUtils;
+import org.eclipse.papyrus.infra.ui.Activator;
+
+/**
+ * A factory used to create editor descriptor object from Eclipse extensions points elements.
+ *
+ * @author Cedric Dumoulin
+ * @author Patrick Tessier
+ */
+public class EditorDescriptorExtensionFactory extends ExtensionUtils {
+
+ /** singleton eINSTANCE of this class */
+ public final static EditorDescriptorExtensionFactory eINSTANCE = new EditorDescriptorExtensionFactory();
+
+ /** constant for the editor diagram **/
+ public final static String EDITOR_DIAGRAM_EXTENSIONPOINT = "editorDiagram";
+
+ /** constant for the attribute factoryClass **/
+ public final static String FACTORYCLASS_ATTRIBUTE = "factoryClass";
+
+ /** constant for the attribute contextId **/
+ public final static String ACTIONBARCONTRIBUTORID_ATTRIBUTE = "actionBarContributorId";
+
+ /** constant for the attribute icon **/
+ public final static String ICON_ATTRIBUTE = "icon";
+
+ /** constant for the order attribute */
+ public final static String ORDER_ATTRIBUTE = "order";
+
+ /**
+ * @return the eINSTANCE
+ */
+ public static EditorDescriptorExtensionFactory getInstance() {
+ return eINSTANCE;
+ }
+
+ /**
+ * Create a descriptor instance corresponding to the ConfigurationElement.
+ *
+ * @param element
+ * an {@link IConfigurationElement} see eclipse extension point
+ * @return a nestedEditorDescriptor structure that contains information to create diagrams
+ * @throws BadNameExtensionException
+ */
+ @SuppressWarnings("unchecked")
+ public EditorDescriptor createNestedEditorDescriptor(IConfigurationElement element) throws ExtensionException {
+ EditorDescriptor res;
+
+ checkTagName(element, EDITOR_DIAGRAM_EXTENSIONPOINT);
+
+ res = new EditorDescriptor();
+ res.setEditorFactoryClass((Class<IPluggableEditorFactory>) parseClass(element, FACTORYCLASS_ATTRIBUTE, EDITOR_DIAGRAM_EXTENSIONPOINT));
+ res.setActionBarContributorId(element.getAttribute(ACTIONBARCONTRIBUTORID_ATTRIBUTE));
+
+ int order = 0; // Default
+ try {
+ String orderAttribute = element.getAttribute(ORDER_ATTRIBUTE);
+ if (orderAttribute != null) {
+ order = Integer.parseInt(orderAttribute);
+ }
+ } catch (NumberFormatException ex) {
+ Activator.log.warn("Invalid order provided by " + element.getContributor() + ". Order should be an integer value"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ res.setOrder(order);
+
+ String iconPath = element.getAttribute(ICON_ATTRIBUTE);
+ if (iconPath != null) {
+ /** Implementation which set the icon and register the complete URL of the icon : Bug eclipse 358732 */
+ res.setIcon(element, iconPath, Activator.PLUGIN_ID);
+
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("Read editor descriptor " + res); //$NON-NLS-1$
+ }
+ return res;
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorFactoryProxy.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorFactoryProxy.java
new file mode 100644
index 00000000000..05fafa58c5d
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorFactoryProxy.java
@@ -0,0 +1,137 @@
+/**
+ *
+ */
+package org.eclipse.papyrus.infra.ui.extension.diagrameditor;
+
+import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.IPageModel;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.ui.editorsfactory.IEditorFactory;
+
+/**
+ * A proxy implementation of {@link IEditorFactory} used to do lazy
+ * instantiation of concrete {@link IPluggableEditorFactory}. This class is used
+ * by the {@link PluggableEditorFactoryReader}
+ *
+ * @author cedric dumoulin
+ *
+ */
+public class EditorFactoryProxy implements IEditorFactory {
+
+ /**
+ * The concrete implementation.
+ */
+ private IPluggableEditorFactory editorFactory;
+
+ /**
+ * EditorDescriptor associated to the factory.
+ */
+ protected EditorDescriptor editorDescriptor;
+
+ /**
+ * ServiceRegistry that can be provided to created editors.
+ */
+ private ServicesRegistry serviceRegistry;
+
+ /**
+ * Constructor.
+ *
+ * @param serviceRegistry
+ * @param editorDescriptor
+ */
+ public EditorFactoryProxy(ServicesRegistry serviceRegistry, EditorDescriptor editorDescriptor) {
+ this.serviceRegistry = serviceRegistry;
+ this.editorDescriptor = editorDescriptor;
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.ui.editorsfactory.IEditorFactory#createIPageModel(java.lang.Object)
+ *
+ * @param pageIdentifier
+ * @return
+ */
+ @Override
+ public IPageModel createIPageModel(Object pageIdentifier) {
+ try {
+ return getEditorFactory().createIPageModel(pageIdentifier);
+ } catch (Exception ex) {
+ // An error occurred in a contribution. Do not use this factory
+ return null;
+ }
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.ui.editorsfactory.IEditorFactory#isPageModelFactoryFor(java.lang.Object)
+ *
+ * @param pageIdentifier
+ * @return
+ */
+ @Override
+ public boolean isPageModelFactoryFor(Object pageIdentifier) {
+ try {
+ return getEditorFactory().isPageModelFactoryFor(pageIdentifier);
+ } catch (Exception ex) {
+ // An error occurred in a contribution. Do not use this factory
+ return false;
+ }
+ }
+
+ /**
+ * @return the editorFactory
+ */
+ protected IPluggableEditorFactory getEditorFactory() {
+
+ if (editorFactory == null) {
+ editorFactory = createEditorFactory();
+ }
+
+ return editorFactory;
+
+ }
+
+ /**
+ * Create an instance of IPluggableEditorFactory as described in the
+ * editorDescriptor. TODO let propagate the exceptions.
+ *
+ * @return
+ */
+ private IPluggableEditorFactory createEditorFactory() {
+ // Create the requested class.
+ try {
+ editorFactory = editorDescriptor.getEditorFactoryClass().newInstance();
+ // Set the descriptor. USed by the factory to get the ActionBarId
+ // and Icon
+ editorFactory.init(serviceRegistry, editorDescriptor);
+ return editorFactory;
+ } catch (InstantiationException e) {
+ // Lets propagate. This is an implementation problem that should be
+ // solved by programmer.
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ // Lets propagate. This is an implementation problem that should be
+ // solved by programmer.
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.ui.editorsfactory.IEditorFactory#getFactoryID()
+ *
+ * @return
+ */
+ @Override
+ public String getFactoryID() {
+ return getEditorFactory().getFactoryID();
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.ui.editorsfactory.IEditorFactory#getLabel()
+ *
+ * @return
+ */
+ @Override
+ public String getLabel() {
+ return getEditorFactory().getLabel();
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorIconFactory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorIconFactory.java
new file mode 100644
index 00000000000..6449012db9b
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorIconFactory.java
@@ -0,0 +1,152 @@
+/**
+ *
+ */
+package org.eclipse.papyrus.infra.ui.extension.diagrameditor;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.papyrus.infra.ui.editorsfactory.IEditorIconFactoryExtended;
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * A factory used to create the Icon associated to an editor TODO Lets have a
+ * common ancestor for {@link EditorIconFactory} and {@link EditorFactoryProxy}
+ *
+ * @author cedric dumoulin
+ *
+ */
+public class EditorIconFactory implements IEditorIconFactoryExtended {
+
+ /**
+ * The concrete implementation.
+ */
+ private IPluggableEditorFactory editorFactory;
+
+ /**
+ * EditorDescriptor associated to the factory.
+ */
+ protected EditorDescriptor editorDescriptor;
+
+ /**
+ * Cached image for reuse.
+ */
+ protected Image cachedImage;
+
+ /**
+ * Constructor.
+ *
+ * @param serviceRegistry
+ * @param editorDescriptor
+ */
+ public EditorIconFactory(EditorDescriptor editorDescriptor) {
+ this.editorDescriptor = editorDescriptor;
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.ui.editorsfactory.IEditorIconFactory#getEditorIcon(java.lang.Object)
+ *
+ * @param pageIdentifier
+ * @return
+ */
+ @Override
+ public Image getEditorIcon(Object pageIdentifier) {
+
+ if (cachedImage == null) {
+ cachedImage = createEditorIcon(pageIdentifier);
+ }
+
+ return cachedImage;
+ }
+
+ /**
+ * Create an Image associated to the editor used to render the specified
+ * pageIdentifier
+ *
+ * @return
+ */
+ @Override
+ public Image createEditorIcon(Object pageIdentifier) {
+ ImageDescriptor imageDescriptor = editorDescriptor.getIcon();
+ if (imageDescriptor == null) {
+ return null;
+ }
+ Image image = imageDescriptor.createImage();
+ return image;
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.ui.editorsfactory.IEditorFactory#isPageModelFactoryFor(java.lang.Object)
+ *
+ * @param pageIdentifier
+ * @return
+ */
+ @Override
+ public boolean isPageModelFactoryFor(Object pageIdentifier) {
+ return getEditorFactory().isPageModelFactoryFor(pageIdentifier);
+ }
+
+ /**
+ * @return the editorFactory
+ */
+ protected IPluggableEditorFactory getEditorFactory() {
+
+ if (editorFactory == null) {
+ editorFactory = createEditorFactory();
+ }
+
+ return editorFactory;
+
+ }
+
+ /**
+ * Create an instance of IPluggableEditorFactory as described in the
+ * editorDescriptor. TODO let propagate the exceptions.
+ *
+ * @return
+ */
+ private IPluggableEditorFactory createEditorFactory() {
+ // Create the requested class.
+ try {
+ editorFactory = editorDescriptor.getEditorFactoryClass().newInstance();
+ // Set the descriptor. USed by the factory to get the ActionBarId
+ // and Icon
+ // editorFactory.init(serviceRegistry, editorDescriptor);
+ return editorFactory;
+ } catch (InstantiationException e) {
+ // Lets propagate. This is an implementation problem that should be
+ // solved by programmer.
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ // Lets propagate. This is an implementation problem that should be
+ // solved by programmer.
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ /**
+ * Return the URL of the main icon used to create this icon
+ *
+ * @see org.eclipse.papyrus.infra.ui.editorsfactory.IEditorIconFactory#getURLMainIcon(java.lang.Object)
+ *
+ * @param pageIdentifier
+ * @return
+ */
+ @Override
+ public String getURLMainIcon(Object pageIdentifier) {
+ return editorDescriptor.getIconURL();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Dispose the cached image
+ */
+ @Override
+ public void dispose() {
+ if (cachedImage != null) {
+ cachedImage.dispose();
+ cachedImage = null;
+ }
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorNotFoundException.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorNotFoundException.java
new file mode 100644
index 00000000000..6600a83af1b
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorNotFoundException.java
@@ -0,0 +1,53 @@
+/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.extension.diagrameditor;
+
+/**
+ * Editor was not found.
+ *
+ * @author dumoulin
+ *
+ */
+@SuppressWarnings("serial")
+public class EditorNotFoundException extends MultiDiagramException {
+
+ /**
+ *
+ */
+ public EditorNotFoundException() {
+ }
+
+ /**
+ * @param arg0
+ */
+ public EditorNotFoundException(String arg0) {
+ super(arg0);
+ }
+
+ /**
+ * @param arg0
+ */
+ public EditorNotFoundException(Throwable arg0) {
+ super(arg0);
+ }
+
+ /**
+ * @param arg0
+ * @param arg1
+ */
+ public EditorNotFoundException(String arg0, Throwable arg1) {
+ super(arg0, arg1);
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/IPluggableEditorFactory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/IPluggableEditorFactory.java
new file mode 100644
index 00000000000..ee69f2442a5
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/IPluggableEditorFactory.java
@@ -0,0 +1,39 @@
+/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.extension.diagrameditor;
+
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.ui.editorsfactory.IEditorFactory;
+
+/**
+ * This interface should be implemented by Editor Factories that can be declared
+ * as Eclipse extension. It extends the {@link IEditorFactory} by adding methods
+ * to initialize the factory with multieditor ServiceRegistry and associated
+ * editor data.
+ *
+ * @author C�dric Dumoulin
+ *
+ */
+public interface IPluggableEditorFactory extends IEditorFactory {
+
+ /**
+ * Initialize the factory with useful Classes.
+ *
+ * @param serviceRegistry
+ * Service registry that will be provided to created editor.
+ * @param editorDescriptor
+ * Descriptor containing data from the Eclipse Extension.
+ */
+ public void init(ServicesRegistry serviceRegistry, EditorDescriptor editorDescriptor);
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/MultiDiagramException.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/MultiDiagramException.java
new file mode 100644
index 00000000000..81f1f7ccac4
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/MultiDiagramException.java
@@ -0,0 +1,53 @@
+/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.extension.diagrameditor;
+
+/**
+ * Root Exception of MultiDiagram exception
+ *
+ * @author dumoulin
+ *
+ */
+@SuppressWarnings("serial")
+public class MultiDiagramException extends Exception {
+
+ /**
+ *
+ */
+ public MultiDiagramException() {
+ }
+
+ /**
+ * @param arg0
+ */
+ public MultiDiagramException(String arg0) {
+ super(arg0);
+ }
+
+ /**
+ * @param arg0
+ */
+ public MultiDiagramException(Throwable arg0) {
+ super(arg0);
+ }
+
+ /**
+ * @param arg0
+ * @param arg1
+ */
+ public MultiDiagramException(String arg0, Throwable arg1) {
+ super(arg0, arg1);
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/PluggableEditorFactoryReader.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/PluggableEditorFactoryReader.java
new file mode 100644
index 00000000000..75dc1d7cc96
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/PluggableEditorFactoryReader.java
@@ -0,0 +1,143 @@
+/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.extension.diagrameditor;
+
+import static org.eclipse.papyrus.infra.core.Activator.log;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.papyrus.infra.core.extension.ExtensionException;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.ui.editorsfactory.PageIconsRegistry;
+import org.eclipse.papyrus.infra.ui.editorsfactory.PageModelFactoryRegistry;
+
+/**
+ * This reader is used to read PluggableEditorFactory from the Eclipse extension
+ * declarations. It can be used to populate an {@link PageModelFactoryRegistry}.
+ */
+public class PluggableEditorFactoryReader {
+
+ /** ordered list of editor descriptors */
+ protected List<EditorDescriptor> editorDescriptors;
+
+ /** ID of the editor extension (schema filename) */
+ public static final String EDITOR_EXTENSION_ID = "papyrusDiagram";
+
+ /** Namespace where to look for the extension points. */
+ protected String extensionPointNamespace;
+
+ /** indicates if extension is loaded or not */
+ private boolean isExtensionLoaded = false;
+
+ /**
+ * Create a new Registry reading extension from the specified namespace. The
+ * namespace is usually the name of the plugin owning the registry.
+ *
+ * @param extensionPointNamespace
+ */
+ public PluggableEditorFactoryReader(String extensionPointNamespace) {
+ super();
+ this.extensionPointNamespace = extensionPointNamespace;
+ editorDescriptors = new ArrayList<EditorDescriptor>();
+ }
+
+ /**
+ * Populate the provided {@link PageModelFactoryRegistry} with {@link IPluggableEditorFactory} read from Eclipse extension declarations.
+ * For each declared editor, create a proxy encapsulating the real
+ * EditorFactory. Then the proxy is added to the PageModelFactoryRegistry.
+ *
+ * @param pageModelFactoryRegistry
+ * The object to populate
+ * @param serviceRegistry
+ * ServiceRegistry provided to newly instantiated {@link IPluggableEditorFactory}.
+ */
+ public void populate(PageModelFactoryRegistry pageModelFactoryRegistry, ServicesRegistry serviceRegistry) {
+
+ for (EditorDescriptor desc : getEditorDescriptors()) {
+
+ // Create and add a proxy encapsulating the EditorFactory.
+ pageModelFactoryRegistry.add(new EditorFactoryProxy(serviceRegistry, desc));
+ }
+ }
+
+ /**
+ * Populate the provided {@link PageIconsRegistry} with icons read from
+ * Eclipse extension declarations. For each declared editor, create a {@link EditorIconFactory}.
+ *
+ * @param pageModelFactoryRegistry
+ * The object to populate
+ * @param serviceRegistry
+ * ServiceRegistry provided to newly instantiated {@link IPluggableEditorFactory}.
+ */
+ public void populate(PageIconsRegistry registry) {
+
+ for (EditorDescriptor desc : getEditorDescriptors()) {
+
+ // Create and add a proxy encapsulating the EditorFactory.
+ registry.add(new EditorIconFactory(desc));
+ }
+ }
+
+ /**
+ * Get the list of editor descriptor.
+ *
+ * @return the list of editor descriptor.
+ */
+ public List<EditorDescriptor> getEditorDescriptors() {
+ if (!isExtensionLoaded) {
+ isExtensionLoaded = true;
+ initializeEditorDescriptors();
+ }
+ return editorDescriptors;
+ }
+
+ /**
+ * Read editor descriptors from extension points.
+ */
+ private void initializeEditorDescriptors() {
+ // Reading data from plugins
+ IConfigurationElement[] configElements = Platform.getExtensionRegistry().getConfigurationElementsFor(extensionPointNamespace, EDITOR_EXTENSION_ID);
+
+ for (IConfigurationElement ele : configElements) {
+ EditorDescriptor desc;
+ try {
+ if (EditorDescriptorExtensionFactory.EDITOR_DIAGRAM_EXTENSIONPOINT.equals(ele.getName())) {
+ desc = EditorDescriptorExtensionFactory.eINSTANCE.createNestedEditorDescriptor(ele);
+ editorDescriptors.add(desc);
+ }
+ } catch (ExtensionException e) {
+ log.error("Initialization editor problem ", e); //$NON-NLS-1$
+ }
+ }
+
+ Collections.sort(editorDescriptors, (ed1, ed2) -> Integer.compare(ed1.getOrder(), ed2.getOrder()));
+
+ if (log.isDebugEnabled()) {
+ log.debug("Read " + editorDescriptors.size() + " editor descriptors from Eclipse extensions"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return "EditorFactoryRegistry: " + editorDescriptors.toString();
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/commands/PageLayoutStorageState.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/commands/PageLayoutStorageState.java
new file mode 100644
index 00000000000..6e604a90914
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/commands/PageLayoutStorageState.java
@@ -0,0 +1,164 @@
+/*****************************************************************************
+ * Copyright (c) 2015 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.ui.internal.commands;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+
+import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.jface.commands.ToggleState;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.resource.sasheditor.SashModel;
+import org.eclipse.papyrus.infra.core.resource.sasheditor.SashModelUtils;
+import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor;
+import org.eclipse.ui.IPartListener;
+import org.eclipse.ui.IPartService;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * The boolean toggle state of the private page layout storage menu item.
+ */
+public class PageLayoutStorageState extends ToggleState implements IPartListener, PropertyChangeListener {
+
+ private IPartService partService = null;
+
+ private Reference<IMultiDiagramEditor> activeEditor;
+
+ public PageLayoutStorageState() {
+ super();
+
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+
+ if (window != null) {
+ partService = window.getPartService();
+ if (partService != null) {
+ partService.addPartListener(this);
+ update(partService.getActivePart());
+ }
+ }
+ }
+
+ @Override
+ public void dispose() {
+ if (partService != null) {
+ partService.removePartListener(this);
+ }
+
+ super.dispose();
+ }
+
+ @Override
+ public void partDeactivated(IWorkbenchPart part) {
+ if ((activeEditor != null) && (activeEditor.get() == part)) {
+ update(null);
+ }
+ }
+
+ @Override
+ public void partActivated(IWorkbenchPart part) {
+ update(part);
+ }
+
+ private void update(IWorkbenchPart part) {
+ // Default state is private storage
+ boolean state = true;
+
+ unhookSashModelListener();
+
+ activeEditor = null;
+
+ if (part instanceof IMultiDiagramEditor) {
+ IMultiDiagramEditor editor = (IMultiDiagramEditor) part;
+ activeEditor = new WeakReference<>(editor);
+ state = isPrivateLayout(editor);
+ }
+
+ hookSashModelListener();
+
+ // Fires notification if changed from previous state
+ setValue(state);
+ }
+
+ // I am a computed value, actually
+ @Override
+ public Object getValue() {
+ IMultiDiagramEditor editor = (activeEditor == null) ? null : activeEditor.get();
+ return (editor != null) ? isPrivateLayout(editor) : super.getValue();
+ }
+
+ boolean isPrivateLayout(IMultiDiagramEditor editor) {
+ ModelSet modelSet = (ModelSet) editor.getAdapter(EditingDomain.class).getResourceSet();
+ SashModel sashModel = SashModelUtils.getSashModel(modelSet);
+
+ // The default is private layout
+ return (sashModel == null) || !sashModel.isLegacyMode();
+ }
+
+ @Override
+ public void partBroughtToTop(IWorkbenchPart part) {
+ // Pass
+ }
+
+ @Override
+ public void partClosed(IWorkbenchPart part) {
+ // Pass
+ }
+
+ @Override
+ public void partOpened(IWorkbenchPart part) {
+ // Pass
+ }
+
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ if (evt.getSource() instanceof SashModel) {
+ switch (evt.getPropertyName()) {
+ case SashModel.PROPERTY_LEGACY_MODE:
+ setValue(!(Boolean) evt.getNewValue());
+ break;
+ }
+ }
+ }
+
+ private SashModel getSashModel() {
+ SashModel result = null;
+
+ if (activeEditor != null) {
+ IMultiDiagramEditor editor = activeEditor.get();
+ if (editor != null) {
+ result = SashModelUtils.getSashModel(editor.getServicesRegistry());
+ }
+ }
+
+ return result;
+ }
+
+ private void unhookSashModelListener() {
+ SashModel sash = getSashModel();
+ if (sash != null) {
+ sash.removePropertyChangeListener(SashModel.PROPERTY_LEGACY_MODE, this);
+ }
+ }
+
+ private void hookSashModelListener() {
+ SashModel sash = getSashModel();
+ if (sash != null) {
+ sash.addPropertyChangeListener(SashModel.PROPERTY_LEGACY_MODE, this);
+ }
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/commands/SashLayoutCommandFactory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/commands/SashLayoutCommandFactory.java
new file mode 100644
index 00000000000..61c931b1ec4
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/commands/SashLayoutCommandFactory.java
@@ -0,0 +1,226 @@
+/*****************************************************************************
+ * Copyright (c) 2015 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.ui.internal.commands;
+
+import java.util.ArrayList;
+
+import org.eclipse.emf.common.command.AbstractCommand;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.common.command.UnexecutableCommand;
+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.util.EcoreUtil;
+import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.resource.sasheditor.SashModelUtils;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.ISashWindowsContainer;
+import org.eclipse.papyrus.infra.core.sashwindows.di.PageRef;
+import org.eclipse.papyrus.infra.core.sashwindows.di.SashModel;
+import org.eclipse.papyrus.infra.core.sashwindows.di.SashWindowsMngr;
+import org.eclipse.papyrus.infra.core.sashwindows.di.TabFolder;
+import org.eclipse.papyrus.infra.core.sashwindows.di.util.DiUtils;
+import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor;
+
+/**
+ * A factory for commands that manipulate the configuration of the sash editor layout.
+ */
+public class SashLayoutCommandFactory {
+ private final IMultiDiagramEditor editor;
+
+ public SashLayoutCommandFactory(IMultiDiagramEditor editor) {
+ super();
+
+ this.editor = editor;
+ }
+
+ /**
+ * Creates a command that toggles whether the sash model is stored in the private
+ * workspace metadata area or in the shared {@code *.di} file.
+ *
+ * @return a toggle command for the private layout storage
+ */
+ public Command createTogglePrivateLayoutCommand() {
+ Command result = UnexecutableCommand.INSTANCE;
+
+ ModelSet modelSet = (ModelSet) editor.getAdapter(EditingDomain.class).getResourceSet();
+ org.eclipse.papyrus.infra.core.resource.sasheditor.SashModel sashModel = SashModelUtils.getSashModel(modelSet);
+ if (sashModel != null) {
+ result = new AbstractToggleCommand("Toggle Private Editor Layout") {
+ private Command toggleRestoreActivePage;
+
+ {
+ // If we are toggling off private mode, make sure that we stop
+ // tracking the active page selection if we were tracking it.
+ // And remember that for undo
+ if (!sashModel.isLegacyMode()) {
+ SashWindowsMngr sash = DiUtils.lookupSashWindowsMngr(sashModel.getResource());
+ if ((sash != null) && (sash.getSashModel() != null) && sash.getSashModel().isRestoreActivePage()) {
+ toggleRestoreActivePage = createToggleRestoreActivePageCommand();
+ }
+ }
+ }
+
+ @Override
+ public void execute() {
+ // First, if we need to toggle restoring the active page, do that
+ if ((toggleRestoreActivePage != null) && toggleRestoreActivePage.canExecute()) {
+ toggleRestoreActivePage.execute();
+ }
+
+ SashWindowsMngr toMove = DiUtils.lookupSashWindowsMngr(sashModel.getResource());
+
+ // We don't record changes in the sash model for undo/redo,
+ // so we cannot assume that any changes to the current page selections
+ // are undoable in the usual way
+ if (!sashModel.isLegacyMode()) {
+ Resource sashResource = toMove.eResource();
+ URI sharedURI = sashModel.getSharedResourceURI();
+
+ // Move the contents into the DI model. If the DI resource isn't loaded,
+ // give up because something is seriously wrong in that case
+ Resource diResource = modelSet.getResource(sharedURI, false);
+ if ((diResource != null) && diResource.isLoaded()) {
+ moveContents(sashResource, diResource);
+
+ if (sashResource.getContents().isEmpty()) {
+ // Schedule deletion on save
+ modelSet.getResourcesToDeleteOnSave().add(sashResource.getURI());
+ }
+ }
+ } else {
+ Resource sashResource;
+ URI privateURI = sashModel.getPrivateResourceURI();
+
+ // Move the contents into the sash model. If the sash resource isn't loaded
+ // or doesn't exist, it will have to be handled
+ if (modelSet.getURIConverter().exists(privateURI, null)) {
+ sashResource = modelSet.getResource(privateURI, true);
+ } else {
+ sashResource = modelSet.createResource(privateURI);
+ }
+
+ // In case we had marked it for deletion, earlier
+ modelSet.getResourcesToDeleteOnSave().remove(privateURI);
+
+ Resource diResource = toMove.eResource();
+ moveContents(diResource, sashResource);
+ }
+
+ // Re-load from the new resource. Snippets might find this odd, but
+ // it would be even more odd for there to be any snippets on this model
+ sashModel.loadModel(modelSet.getURIWithoutExtension());
+ }
+ };
+ }
+
+ return result;
+ }
+
+ void moveContents(Resource fromResource, Resource toResource) {
+ // Safe copy to allow concurrent modifications
+ for (EObject root : new ArrayList<>(fromResource.getContents())) {
+ EObject toReplace = (EObject) EcoreUtil.getObjectByType(toResource.getContents(), root.eClass());
+ if (toReplace != null) {
+ EcoreUtil.replace(toReplace, root);
+ } else {
+ if (root instanceof SashWindowsMngr) {
+ // This one is expected always to be first
+ toResource.getContents().add(0, root);
+ } else {
+ toResource.getContents().add(root);
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Creates a command that toggles whether the sash model records the currently
+ * active page to restore it on next opening.
+ *
+ * @return a toggle command for the restore-active-page behaviour
+ */
+ public Command createToggleRestoreActivePageCommand() {
+ Command result = UnexecutableCommand.INSTANCE;
+
+ ModelSet modelSet = (ModelSet) editor.getAdapter(EditingDomain.class).getResourceSet();
+ SashWindowsMngr sashWindows = SashModelUtils.getSashWindowsMngr(modelSet);
+ ISashWindowsContainer container = editor.getAdapter(ISashWindowsContainer.class);
+
+ SashModel sashModel = sashWindows.getSashModel();
+ if (sashModel != null) {
+ // We don't record the tracking of the active page for undo/redo,
+ // so we cannot assume that any changes to the current page selections
+ // are undoable in the usual way
+ result = new AbstractToggleCommand("Toggle Restore Active Page") {
+
+ @Override
+ public void execute() {
+ boolean oldValue = sashModel.isRestoreActivePage();
+
+ if (oldValue) {
+ // Clear each tab folder's selection
+ container.getIFolderList().stream()
+ .map(f -> f.getRawModel())
+ .filter(TabFolder.class::isInstance).map(TabFolder.class::cast)
+ .filter(f -> f.getCurrentSelection() != null)
+ .forEach(f -> f.setCurrentSelection(null));
+ } else {
+ // Set each tab folder's selection.
+ // The 'visible pages' are the current selection in each folder
+ container.getVisiblePages().stream()
+ .map(p -> p.getRawModel())
+ .filter(PageRef.class::isInstance).map(PageRef.class::cast)
+ .filter(p -> p.getParent().getCurrentSelection() != p)
+ .forEach(p -> p.getParent().setCurrentSelection(p));
+ }
+
+ // The basic toggle
+ sashModel.setRestoreActivePage(!oldValue);
+ }
+ };
+ }
+
+ return result;
+ }
+
+ //
+ // Nested types
+ //
+
+ private static abstract class AbstractToggleCommand extends AbstractCommand {
+
+ AbstractToggleCommand(String label) {
+ super(label);
+ }
+
+ @Override
+ protected boolean prepare() {
+ // Nothing to prepare
+ return true;
+ }
+
+ @Override
+ public void undo() {
+ // It's a toggle, so yeah, just execute again
+ execute();
+ }
+
+ @Override
+ public void redo() {
+ execute();
+ }
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/commands/TogglePageLayoutStorageHandler.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/commands/TogglePageLayoutStorageHandler.java
new file mode 100644
index 00000000000..12fa47811e9
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/commands/TogglePageLayoutStorageHandler.java
@@ -0,0 +1,78 @@
+/*****************************************************************************
+ * Copyright (c) 2015 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.ui.internal.commands;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.emf.transaction.RollbackException;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.utils.TransactionHelper;
+import org.eclipse.papyrus.infra.ui.Activator;
+import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor;
+import org.eclipse.papyrus.infra.ui.services.SaveLayoutBeforeClose;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * Command handler for the private page-layout storage toggle menu.
+ */
+public class TogglePageLayoutStorageHandler extends AbstractHandler {
+
+ public TogglePageLayoutStorageHandler() {
+ super();
+ }
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ IEditorPart active = HandlerUtil.getActiveEditor(event);
+ if (active instanceof IMultiDiagramEditor) {
+ IMultiDiagramEditor editor = (IMultiDiagramEditor) active;
+
+ // Toggle the storage of the layout
+ togglePrivatePageLayout(editor);
+
+ // And then save the layout immediately if the editor is not dirty
+ // (if it is dirty, then the layout will be saved when the editor
+ // is saved; saving it now would possibly result in inconsistencies)
+ try {
+ SaveLayoutBeforeClose save = editor.getServicesRegistry().getService(SaveLayoutBeforeClose.class);
+ save.saveBeforeClose(editor);
+ } catch (ServiceException e) {
+ // Doesn't matter; we'll just have to rely on the normal editor save
+ }
+ }
+
+ return null;
+ }
+
+ public void togglePrivatePageLayout(IMultiDiagramEditor editor) {
+ Command command = new SashLayoutCommandFactory(editor).createTogglePrivateLayoutCommand();
+ EditingDomain domain = editor.getAdapter(EditingDomain.class);
+
+ // Don't execute on the undo history because the changes in the sash model
+ // are never tracked for undo/redo
+ try {
+ TransactionHelper.run(domain, () -> command.execute());
+ } catch (RollbackException e) {
+ StatusManager.getManager().handle(e.getStatus());
+ } catch (InterruptedException e) {
+ Activator.log.error("Failed to execute page layout toggle command", e); //$NON-NLS-1$
+ }
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/EditorPreferencePage.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/EditorPreferencePage.java
new file mode 100644
index 00000000000..bff4950d394
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/EditorPreferencePage.java
@@ -0,0 +1,52 @@
+/*****************************************************************************
+ * Copyright (c) 2015, 2016 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.ui.internal.preferences;
+
+import org.eclipse.jface.preference.FieldEditorPreferencePage;
+import org.eclipse.jface.preference.RadioGroupFieldEditor;
+import org.eclipse.papyrus.infra.ui.Activator;
+import org.eclipse.swt.SWT;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+
+/**
+ * The preference page for Papyrus Editor general preferences.
+ */
+public class EditorPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage {
+
+ public EditorPreferencePage() {
+ super(Messages.EditorPreferencePage_0, SWT.FLAT);
+
+ setDescription(Messages.EditorPreferencePage_5);
+ }
+
+ @Override
+ public void init(IWorkbench workbench) {
+ setPreferenceStore(Activator.getDefault().getPreferenceStore());
+ }
+
+ @Override
+ protected void createFieldEditors() {
+ addField(new RadioGroupFieldEditor(EditorPreferences.PREF_CONVERT_SHARED_LAYOUT,
+ Messages.EditorPreferencePage_1,
+ 1,
+ new String[][] {
+ { Messages.EditorPreferencePage_2, YesNo.PROMPT.name() },
+ { Messages.EditorPreferencePage_3, YesNo.NO.name() },
+ { Messages.EditorPreferencePage_4, YesNo.YES.name() },
+ },
+ getFieldEditorParent()));
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/EditorPreferences.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/EditorPreferences.java
new file mode 100644
index 00000000000..0b8748f6032
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/EditorPreferences.java
@@ -0,0 +1,88 @@
+/*****************************************************************************
+ * Copyright (c) 2015, 2016 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.ui.internal.preferences;
+
+import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.papyrus.infra.ui.Activator;
+
+/**
+ * Accessor for the Papyrus Editor preferences.
+ */
+public class EditorPreferences {
+ public static final String PREF_CONVERT_SHARED_LAYOUT = "convertSharedLayout"; //$NON-NLS-1$
+
+ private static final EditorPreferences INSTANCE = new EditorPreferences();
+ private final IPreferenceStore store;
+
+ private EditorPreferences() {
+ super();
+
+ store = Activator.getDefault().getPreferenceStore();
+ }
+
+ public static EditorPreferences getInstance() {
+ return INSTANCE;
+ }
+
+ /**
+ * Queries whether the user prefers to migrate shared editor layout to private storage
+ * always, never, or interactively pop up a dialog to ask (the default).
+ *
+ * @return the shared layout conversion on first open preference, which is never
+ * {@code null} and defaults to {@link YesNo#PROMPT}
+ */
+ public YesNo getConvertSharedPageLayoutToPrivate() {
+ return YesNo.valueOf(store.getString(PREF_CONVERT_SHARED_LAYOUT));
+ }
+
+ /**
+ * Sets whether the editor will always, never, or ask the user to migrate shared
+ * (in the {@code *.di} resource) page layout into the private storage ({@code *.sash} resource}
+ * on the first opening of a Papyrus model in the workspace that uses the shared
+ * storage (usually from pre-1.0 release).
+ *
+ * @param convert
+ * the preference setting to assign, or {@code null} for the default, which
+ * is {@link YesNo#PROMPT}
+ */
+ public void setConvertSharedPageLayoutToPrivate(YesNo convert) {
+ if (convert == null) {
+ convert = YesNo.PROMPT;
+ }
+
+ store.setValue(PREF_CONVERT_SHARED_LAYOUT, convert.name());
+ }
+
+ //
+ // Nested types
+ //
+
+ /**
+ * Initializer of defaults for the editor preferences.
+ */
+ public static class Initializer extends AbstractPreferenceInitializer {
+
+ public Initializer() {
+ super();
+ }
+
+ @Override
+ public void initializeDefaultPreferences() {
+ IPreferenceStore store = Activator.getDefault().getPreferenceStore();
+
+ store.setDefault(PREF_CONVERT_SHARED_LAYOUT, YesNo.PROMPT.name());
+ }
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/Messages.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/Messages.java
new file mode 100644
index 00000000000..4fbebcf89bc
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/Messages.java
@@ -0,0 +1,37 @@
+/*****************************************************************************
+ * Copyright (c) 2015 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.ui.internal.preferences;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Translatable strings.
+ */
+class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.papyrus.infra.core.internal.preferences.messages"; //$NON-NLS-1$
+ public static String EditorPreferencePage_0;
+ public static String EditorPreferencePage_1;
+ public static String EditorPreferencePage_2;
+ public static String EditorPreferencePage_3;
+ public static String EditorPreferencePage_4;
+ public static String EditorPreferencePage_5;
+
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/YesNo.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/YesNo.java
new file mode 100644
index 00000000000..a9ee87d9e4f
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/YesNo.java
@@ -0,0 +1,21 @@
+/*****************************************************************************
+ * Copyright (c) 2015 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.ui.internal.preferences;
+
+/**
+ * A tri-state boolean-ish preference data type with a "prompt the user" value.
+ */
+public enum YesNo {
+ PROMPT, NO, YES;
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/messages.properties b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/messages.properties
new file mode 100644
index 00000000000..a34a57ddfbe
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/messages.properties
@@ -0,0 +1,18 @@
+#
+# Copyright (c) 2015 Christian W. Damus and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Christian W. Damus - Initial API and implementation
+#
+
+EditorPreferencePage_0=General Editor Settings
+EditorPreferencePage_1=Convert shared storage of editor layout to private:
+EditorPreferencePage_2=Ask each time
+EditorPreferencePage_3=Never
+EditorPreferencePage_4=Always
+EditorPreferencePage_5=General settings for the Papyrus multi-diagram editor.
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/DoSaveEvent.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/DoSaveEvent.java
new file mode 100644
index 00000000000..d11eb1bc59c
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/DoSaveEvent.java
@@ -0,0 +1,66 @@
+/**
+ *
+ */
+package org.eclipse.papyrus.infra.ui.lifecycleevents;
+
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor;
+
+/**
+ * Event sent whith a Save or SaveAs.
+ *
+ * @author cedric dumoulin
+ *
+ */
+public class DoSaveEvent {
+
+ final protected ServicesRegistry serviceRegistry;
+
+ final protected IMultiDiagramEditor multiDiagramEditor;
+
+ final protected boolean isAutoSave;
+
+ /**
+ * Create an Event that is sent with a Save or SaveAs. The same event can be
+ * reused. Constructor.
+ *
+ * @param serviceRegistry
+ * @param multiDiagramEditor
+ */
+ public DoSaveEvent(ServicesRegistry serviceRegistry, IMultiDiagramEditor multiDiagramEditor) {
+ this(serviceRegistry, multiDiagramEditor, false);
+ }
+
+ /**
+ * Create an Event that is sent with a Save or SaveAs. The same event can be
+ * reused. Constructor.
+ *
+ * @param serviceRegistry
+ * @param multiDiagramEditor
+ * @param isAutoSave
+ */
+ public DoSaveEvent(ServicesRegistry serviceRegistry, IMultiDiagramEditor multiDiagramEditor, boolean isAutoSave) {
+ this.serviceRegistry = serviceRegistry;
+ this.multiDiagramEditor = multiDiagramEditor;
+ this.isAutoSave = isAutoSave;
+ }
+
+ /**
+ * @return the serviceRegistry
+ */
+ public ServicesRegistry getServiceRegistry() {
+ return serviceRegistry;
+ }
+
+ /**
+ * @return the multiDiagramEditor
+ */
+ public IMultiDiagramEditor getMultiDiagramEditor() {
+ return multiDiagramEditor;
+ }
+
+ public boolean isAutoSave() {
+ return isAutoSave;
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/IEditorInputChangedListener.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/IEditorInputChangedListener.java
new file mode 100644
index 00000000000..575e2013934
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/IEditorInputChangedListener.java
@@ -0,0 +1,40 @@
+/*****************************************************************************
+ * Copyright (c) 2010 LIFL & CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin (LIFL) cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.ui.lifecycleevents;
+
+import org.eclipse.ui.part.FileEditorInput;
+
+/**
+ * Interface implemented by classes wishing to be notified of the inputChanged
+ * event after a call to {@link ISaveAndDirtyService#doSaveAs()}.
+ *
+ * @author cedric dumoulin
+ *
+ */
+public interface IEditorInputChangedListener {
+
+ /**
+ *
+ * @param fileEditorInput
+ * The new value of EditorInput
+ */
+ public void editorInputChanged(FileEditorInput fileEditorInput);
+
+ /**
+ * Called when the value of the isDirty() flag has changed.
+ */
+ public void isDirtyChanged();
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/ILifeCycleEventsProvider.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/ILifeCycleEventsProvider.java
new file mode 100644
index 00000000000..cf0bbeee92e
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/ILifeCycleEventsProvider.java
@@ -0,0 +1,57 @@
+/**
+ *
+ */
+package org.eclipse.papyrus.infra.ui.lifecycleevents;
+
+/**
+ * Concrete implementation of this interface allows to listen on various
+ * lifecycle events. This interface is the "public" part of the {@link LifeCycleEventsProvider}.
+ *
+ * @author cedric dumoulin
+ *
+ */
+public interface ILifeCycleEventsProvider {
+
+ /**
+ * Add specified listener.
+ *
+ * @param listener
+ */
+ public void addDoSaveListener(ISaveEventListener listener);
+
+ /**
+ * Remove specified listener.
+ *
+ * @param listener
+ */
+ public void removeDoSaveListener(ISaveEventListener listener);
+
+ /**
+ * Add specified listener.
+ *
+ * @param listener
+ */
+ public void addAboutToDoSaveListener(ISaveEventListener listener);
+
+ /**
+ * Remove specified listener.
+ *
+ * @param listener
+ */
+ public void removeAboutToDoSaveListener(ISaveEventListener listener);
+
+ /**
+ * Add specified listener.
+ *
+ * @param listener
+ */
+ public void addPostDoSaveListener(ISaveEventListener listener);
+
+ /**
+ * Remove specified listener.
+ *
+ * @param listener
+ */
+ public void removePostDoSaveListener(ISaveEventListener listener);
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/ISaveAndDirtyService.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/ISaveAndDirtyService.java
new file mode 100644
index 00000000000..14f6f12d0d3
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/ISaveAndDirtyService.java
@@ -0,0 +1,56 @@
+/*****************************************************************************
+ * Copyright (c) 2010 LIFL & CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin (LIFL) cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.ui.lifecycleevents;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.ui.ISaveablePart;
+
+/**
+ * @author dumoulin
+ *
+ */
+public interface ISaveAndDirtyService extends ISaveablePart {
+
+ /**
+ * Register a nested {@link ISaveablePart} as a listener that will be
+ * notified each time a {@link #doSave(IProgressMonitor)} or {@link #doSaveAs()} is performed. Also, it will be asked for the
+ * dirtyState.
+ *
+ * @param saveablePart
+ */
+ public abstract void registerIsaveablePart(ISaveablePart saveablePart);
+
+ /**
+ * Remove the specified {@link ISaveablePart} from the list of listeners.
+ *
+ * @param saveablePart
+ */
+ public abstract void removeIsaveablePart(ISaveablePart saveablePart);
+
+ /**
+ * Add a listeners on input changed event.
+ *
+ * @param inputChangedListener
+ */
+ public void addInputChangedListener(IEditorInputChangedListener inputChangedListener);
+
+ /**
+ * Remove a listeners on input changed event.
+ *
+ * @param inputChangedListener
+ */
+ public void removeInputChangedListener(IEditorInputChangedListener inputChangedListener);
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/ISaveEventListener.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/ISaveEventListener.java
new file mode 100644
index 00000000000..d936304bcb5
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/ISaveEventListener.java
@@ -0,0 +1,27 @@
+/**
+ *
+ */
+package org.eclipse.papyrus.infra.ui.lifecycleevents;
+
+/**
+ * Interface used to listen on open, save and saveAs events.
+ *
+ * @author cedric dumoulin
+ *
+ * @param <T>
+ * Type of event passed to methods.
+ */
+public interface ISaveEventListener {
+
+ /**
+ *
+ * @param editor
+ */
+ public void doSave(DoSaveEvent event);
+
+ /**
+ *
+ * @param editor
+ */
+ public void doSaveAs(DoSaveEvent event);
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/LifeCycleEventsProvider.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/LifeCycleEventsProvider.java
new file mode 100644
index 00000000000..7dd9dda4c92
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/LifeCycleEventsProvider.java
@@ -0,0 +1,291 @@
+/**
+ *
+ */
+package org.eclipse.papyrus.infra.ui.lifecycleevents;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class provides events about the life cycle of a MultiEditor. Not all
+ * life cycle events are available. Available events:
+ * <ul>
+ * <li>aboutToDoSave, aboutToDoSaveAs - SaveEventListener</li>
+ * <li>doSave, doSaveAs - SaveEventListener</li>
+ * <li>afterDoSave, afterDoSaveAs - SaveEventListener</li>
+ * <li></li>
+ * <li></li>
+ * </ul>
+ *
+ *
+ * @author cedric dumoulin
+ *
+ */
+public class LifeCycleEventsProvider implements ILifeCycleEventsProvider {
+
+ /**
+ *
+ */
+ protected SaveEventListenerLazyList preSaveListeners = new SaveEventListenerLazyList();
+
+ /**
+ *
+ */
+ protected SaveEventListenerLazyList saveListeners = new SaveEventListenerLazyList();
+
+ /**
+ *
+ */
+ protected SaveEventListenerLazyList postSaveListeners = new SaveEventListenerLazyList();
+
+ /**
+ * Add specified listener.
+ *
+ * @param listener
+ */
+ @Override
+ public void addDoSaveListener(ISaveEventListener listener) {
+
+ saveListeners.addListener(listener);
+ }
+
+ /**
+ * Remove specified listener.
+ *
+ * @param listener
+ */
+ @Override
+ public void removeDoSaveListener(ISaveEventListener listener) {
+ saveListeners.removeListener(listener);
+ }
+
+ /**
+ * Add specified listener.
+ *
+ * @param listener
+ */
+ @Override
+ public void addAboutToDoSaveListener(ISaveEventListener listener) {
+
+ preSaveListeners.addListener(listener);
+ }
+
+ /**
+ * Remove specified listener.
+ *
+ * @param listener
+ */
+ @Override
+ public void removeAboutToDoSaveListener(ISaveEventListener listener) {
+ preSaveListeners.removeListener(listener);
+ }
+
+ /**
+ * Add specified listener.
+ *
+ * @param listener
+ */
+ @Override
+ public void addPostDoSaveListener(ISaveEventListener listener) {
+
+ postSaveListeners.addListener(listener);
+ }
+
+ /**
+ * Remove specified listener.
+ *
+ * @param listener
+ */
+ @Override
+ public void removePostDoSaveListener(ISaveEventListener listener) {
+ postSaveListeners.removeListener(listener);
+ }
+
+ // ****************************************************** //
+ // Fire events methods //
+ // ****************************************************** //
+
+ /**
+ * Fire AboutToSaveEvent to registered Listeners.
+ *
+ * @param editorPart
+ */
+ public void fireAboutToDoSaveEvent(DoSaveEvent event) {
+ preSaveListeners.fireSaveEvent(event);
+ }
+
+ /**
+ * Fire AboutToSaveAs to registered Listeners.
+ *
+ * @param editorPart
+ */
+ public void fireAboutToDoSaveAsEvent(DoSaveEvent event) {
+ preSaveListeners.fireSaveAsEvent(event);
+ }
+
+ /**
+ * Fire AboutToSaveEvent to registered Listeners.
+ *
+ * @param editorPart
+ */
+ public void fireDoSaveEvent(DoSaveEvent event) {
+ saveListeners.fireSaveEvent(event);
+ }
+
+ /**
+ * Fire AboutToSaveAs to registered Listeners.
+ *
+ * @param editorPart
+ */
+ public void fireDoSaveAsEvent(DoSaveEvent event) {
+ saveListeners.fireSaveAsEvent(event);
+ }
+
+ /**
+ * Fire AboutToSaveEvent to registered Listeners.
+ *
+ * @param editorPart
+ */
+ public void firePostDoSaveEvent(DoSaveEvent event) {
+ postSaveListeners.fireSaveEvent(event);
+ }
+
+ /**
+ * Fire AboutToSaveAs to registered Listeners.
+ *
+ * @param editorPart
+ */
+ public void firePostDoSaveAsEvent(DoSaveEvent event) {
+ postSaveListeners.fireSaveAsEvent(event);
+ }
+
+ /**
+ * Fire all Save events (about, events, post) to registered Listeners.
+ * Exceptions from listeners are propagated and stop the event chain.
+ *
+ * @param editorPart
+ */
+ public void fireAllDoSaveEvent(DoSaveEvent event) {
+ fireAboutToDoSaveEvent(event);
+ fireDoSaveEvent(event);
+ firePostDoSaveEvent(event);
+ }
+
+ /**
+ * Fire all SaveAs events (about, events, post) to registered Listeners. If
+ * one of the saveAs event fail, post events are not sent.
+ *
+ * @param editorPart
+ */
+ public void fireAllDoSaveAsEvent(DoSaveEvent event) {
+ fireAboutToDoSaveAsEvent(event);
+ fireDoSaveAsEvent(event);
+ firePostDoSaveAsEvent(event);
+ }
+
+ /**
+ * Base class encapsulating a lazy creation list.
+ *
+ * @author cedric dumoulin
+ *
+ * @param <T>
+ */
+ abstract protected class AbstractEventListenersLazyList<T> {
+
+ List<T> listeners;
+
+ /**
+ * Add specified listener.
+ *
+ * @param listener
+ */
+ public void addListener(T listener) {
+ // Lazy creation
+ if (listeners == null) {
+ listeners = new ArrayList<T>();
+ }
+
+ // do not add if already present.
+ if (listeners.contains(listener)) {
+ return;
+ }
+
+ listeners.add(listener);
+ }
+
+ /**
+ * Remove specified listener.
+ *
+ * @param listener
+ */
+ public void removeListener(T listener) {
+ // Lazy creation
+ if (listeners == null) {
+ return;
+ }
+
+ listeners.remove(listener);
+ }
+
+ /**
+ * @return the listeners
+ */
+ protected List<T> getListeners() {
+ return listeners;
+ }
+
+ /**
+ * Remove all listeners.
+ */
+ protected void clear() {
+ if (listeners != null) {
+ listeners.clear();
+ }
+ }
+ }
+
+ /**
+ * List of {@link ISaveEventListener}.
+ *
+ * @author cedric dumoulin
+ *
+ */
+ protected class SaveEventListenerLazyList extends AbstractEventListenersLazyList<ISaveEventListener> {
+
+ /**
+ * Fire OpenEvent to registered Listeners. If a listener throw an
+ * exception, remaining listeners are called, and then the exception is
+ * resent.
+ *
+ * @param editorPart
+ */
+ public void fireSaveEvent(DoSaveEvent event) {
+ // Lazy creation
+ if (listeners == null) {
+ return;
+ }
+
+ for (ISaveEventListener listener : listeners) {
+ listener.doSave(event);
+ }
+ }
+
+ /**
+ * Fire OpenEvent to registered Listeners.
+ *
+ * @param editorPart
+ */
+ public void fireSaveAsEvent(DoSaveEvent event) {
+ // Lazy creation
+ if (listeners == null) {
+ return;
+ }
+
+ for (ISaveEventListener listener : listeners) {
+ listener.doSaveAs(event);
+ }
+
+ }
+
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/LifeCycleEventsProviderServiceFactory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/LifeCycleEventsProviderServiceFactory.java
new file mode 100644
index 00000000000..8bdfb550d1c
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/LifeCycleEventsProviderServiceFactory.java
@@ -0,0 +1,79 @@
+/*****************************************************************************
+ * Copyright (c) 2010 LIFL & CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin (LIFL) cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.ui.lifecycleevents;
+
+import org.eclipse.papyrus.infra.core.services.IServiceFactory;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+
+/**
+ * A service factory to create the {@link ILifeCycleEventsProvider} service.
+ * This provide a nickname for {@link SaveAndDirtyService} service. This
+ * serviceFactory depends on {@link SaveAndDirtyService} service.
+ *
+ * @author cedric dumoulin
+ *
+ */
+public class LifeCycleEventsProviderServiceFactory implements IServiceFactory {
+
+ /**
+ * The sashModelMangr.
+ */
+ private SaveAndDirtyService saveAndDirtyService;
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IService#init(org.eclipse.papyrus.infra.core.services.ServicesRegistry)
+ *
+ * @param servicesRegistry
+ * @throws ServiceException
+ */
+ @Override
+ public void init(ServicesRegistry servicesRegistry) throws ServiceException {
+ // Get required services
+ // This rely on the real implementation.
+ saveAndDirtyService = (SaveAndDirtyService) servicesRegistry.getService(ISaveAndDirtyService.class);
+
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IService#startService()
+ *
+ * @throws ServiceException
+ */
+ @Override
+ public void startService() throws ServiceException {
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IService#disposeService()
+ *
+ * @throws ServiceException
+ */
+ @Override
+ public void disposeService() throws ServiceException {
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IServiceFactory#createServiceInstance()
+ *
+ * @return
+ * @throws ServiceException
+ */
+ @Override
+ public Object createServiceInstance() throws ServiceException {
+ return saveAndDirtyService;
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/SaveAndDirtyService.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/SaveAndDirtyService.java
new file mode 100644
index 00000000000..7e858153695
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/SaveAndDirtyService.java
@@ -0,0 +1,550 @@
+/*****************************************************************************
+ * Copyright (c) 2010, 2013 LIFL & CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin (LIFL) cedric.dumoulin@lifl.fr - Initial API and implementation
+ * Christian W. Damus (CEA) - Don't make editor dirty on empty ResourceSetChangeEvent
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.ui.lifecycleevents;
+
+import static org.eclipse.papyrus.infra.core.Activator.log;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.EventObject;
+import java.util.List;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.emf.common.command.BasicCommandStack;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.common.command.CommandStack;
+import org.eclipse.emf.common.command.CommandStackListener;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.emf.transaction.NotificationFilter;
+import org.eclipse.emf.transaction.ResourceSetChangeEvent;
+import org.eclipse.emf.transaction.ResourceSetListener;
+import org.eclipse.emf.transaction.RollbackException;
+import org.eclipse.emf.transaction.Transaction;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.jface.dialogs.ProgressMonitorDialog;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.services.IService;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.core.utils.ServiceUtils;
+import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IFileEditorInput;
+import org.eclipse.ui.ISaveablePart;
+import org.eclipse.ui.actions.WorkspaceModifyOperation;
+import org.eclipse.ui.dialogs.SaveAsDialog;
+import org.eclipse.ui.part.FileEditorInput;
+
+/**
+ * A Papyrus Service allowing to perform save and saveAs on Papyrus Models. The
+ * service also allows to listen on the dirty state of the Models. <br>
+ * The service implements the {@link ISaveablePart} interface, and can be used
+ * directly in part requiring such interface of adapter.
+ *
+ * <br>
+ * This class allows nested editors to register themselves as nested {@link ISaveablePart}. In this case, the registered part will be notified
+ * each time a save or saveAs is performed. Also, the nested part will be asked
+ * for its dirtyState.
+ *
+ * TODO : Improve the implementation by registering the isDirty flag value, and
+ * firing events only if the value really change. Actually, the event is fired
+ * every time the model is modified, even if the virtual value of the flag
+ * hasn't changed.
+ *
+ * @author cedric dumoulin
+ *
+ */
+public class SaveAndDirtyService extends LifeCycleEventsProvider implements ISaveablePart, IService, ISaveAndDirtyService {
+
+ /**
+ * Class used to propagate life cycle events. This class can be retrieved as
+ * a service using {@link ILifeCycleEventsProvider}.class. This class
+ * extends LifeCycleEventsProvider, so the local variable is set with
+ * ourself (historical reasons). TODO : remove this local variable.
+ */
+ protected LifeCycleEventsProvider lifeCycleEventsProvider = this;
+
+ /**
+ * Cached event that can be reused.
+ */
+ protected DoSaveEvent lifeCycleEvent;
+
+ /**
+ * Model set managing models.
+ */
+ private ModelSet resourceSet;
+
+ /**
+ *
+ */
+ private TransactionalEditingDomain transactionalEditingDomain;
+
+ /**
+ * The serviceRegistry.
+ */
+ // private ServicesRegistry servicesRegistry;
+
+ /**
+ * Associated editor. Needed by saveAs to synchronize editor input.
+ */
+ private IMultiDiagramEditor multiDiagramEditor;
+
+ /**
+ * List of registered {@link ISaveablePart}. This are usually nested
+ * editors.
+ */
+ private ISaveablePartList registeredIsaveablePart;
+
+ /**
+ * List of listeners on input changed event after a call to saveAs.
+ */
+ private List<IEditorInputChangedListener> inputChangedListeners;
+
+ /**
+ * Listener on commandStack changes.
+ */
+ private final CommandStackListener commandStackListener = new CommandStackListener() {
+
+ @Override
+ public void commandStackChanged(EventObject event) {
+
+ fireIsDirtyChanged();
+ };
+ };
+
+ /*
+ * Listener on ResourceSet
+ */
+ private final ResourceSetListener resourceSetListener = new ResourceSetListener() {
+
+ @Override
+ public NotificationFilter getFilter() {
+ return null;
+ }
+
+ @Override
+ public boolean isAggregatePrecommitListener() {
+ return false;
+ }
+
+ @Override
+ public boolean isPostcommitOnly() {
+ return true;
+ }
+
+ @Override
+ public boolean isPrecommitOnly() {
+ return false;
+ }
+
+ @Override
+ public void resourceSetChanged(ResourceSetChangeEvent event) {
+ if (event.getTransaction() != null && event.getTransaction().getStatus().isOK() && madePersistableChanges(event)) {
+ fireIsDirtyChanged();
+ }
+ }
+
+ private boolean madePersistableChanges(ResourceSetChangeEvent event) {
+ return !event.getNotifications().isEmpty() && !isUnprotected(event.getTransaction());
+ }
+
+ private boolean isUnprotected(Transaction transaction) {
+ return !Boolean.TRUE.equals(transaction.getOptions().get(Transaction.OPTION_UNPROTECTED));
+ }
+
+ @Override
+ public Command transactionAboutToCommit(ResourceSetChangeEvent event) throws RollbackException {
+ return null;
+ }
+
+ };
+
+ /**
+ * Constructor.
+ *
+ */
+ public SaveAndDirtyService() {
+ registeredIsaveablePart = new ISaveablePartList();
+ inputChangedListeners = new ArrayList<IEditorInputChangedListener>();
+ }
+
+ /**
+ * Initialize the service. Retrieve other required services (ModelSet,
+ * CoreEditor).
+ *
+ * @see org.eclipse.papyrus.infra.core.services.IService#init(org.eclipse.papyrus.infra.core.services.ServicesRegistry)
+ *
+ * @param servicesRegistry
+ * @throws ServiceException
+ */
+ @Override
+ public void init(ServicesRegistry servicesRegistry) throws ServiceException {
+
+ // this.servicesRegistry = servicesRegistry;
+
+ // Retrieve required services.
+ resourceSet = servicesRegistry.getService(ModelSet.class);
+ multiDiagramEditor = servicesRegistry.getService(IMultiDiagramEditor.class);
+ transactionalEditingDomain = ServiceUtils.getInstance().getTransactionalEditingDomain(servicesRegistry);
+
+ // Initialize and register the ILifeCycleEventsProvider service (which
+ // is ourself).
+ // This mean that the ILifeCycleEventsProvider is not available until we
+ // are started.
+ lifeCycleEvent = new DoSaveEvent(servicesRegistry, multiDiagramEditor);
+ // servicesRegistry.add(ILifeCycleEventsProvider.class, 1,
+ // lifeCycleEventsProvider);
+
+ }
+
+ /**
+ * Do nothing.
+ *
+ * @see org.eclipse.papyrus.infra.core.services.IService#startService()
+ *
+ * @throws ServiceException
+ */
+ @Override
+ public void startService() throws ServiceException {
+
+ // Listen to the modifications of the EMF model
+ transactionalEditingDomain.getCommandStack().addCommandStackListener(commandStackListener);
+
+ // Let's listen to the resource set change
+ transactionalEditingDomain.addResourceSetListener(resourceSetListener);
+ }
+
+ /**
+ * @see org.eclipse.papyrus.infra.core.services.IService#disposeService()
+ *
+ * @throws ServiceException
+ */
+ @Override
+ public void disposeService() throws ServiceException {
+ if (transactionalEditingDomain != null) {
+ // Check if commandStack is null (meaning that transactionalEditingDomain
+ // is disposed
+ CommandStack commandStack = transactionalEditingDomain.getCommandStack();
+ if (commandStack != null) {
+ transactionalEditingDomain.getCommandStack().removeCommandStackListener(commandStackListener);
+ }
+ transactionalEditingDomain.removeResourceSetListener(resourceSetListener);
+ // resourceSetListener = null;
+ }
+
+ // clean properties in order to help GC
+ inputChangedListeners.clear();
+ inputChangedListeners = null;
+ multiDiagramEditor = null;
+ // servicesRegistry = null;
+ transactionalEditingDomain = null;
+ resourceSet = null;
+ lifeCycleEvent = null;
+
+ postSaveListeners.clear();
+ saveListeners.clear();
+ preSaveListeners.clear();
+
+
+ }
+
+ /**
+ * Save the Models
+ *
+ * @see org.eclipse.ui.ISaveablePart#doSave(org.eclipse.core.runtime.IProgressMonitor)
+ *
+ * @param monitor
+ */
+ @Override
+ public void doSave(IProgressMonitor monitor) {
+ // Sent pre doSave event
+ lifeCycleEventsProvider.fireAboutToDoSaveEvent(lifeCycleEvent);
+
+ // sent doSaveEvent
+ lifeCycleEventsProvider.fireDoSaveEvent(lifeCycleEvent);
+ // Perform local doSave
+ // TODO : put it in a listener ?
+ try {
+ // Save each associated resource
+ resourceSet.save(monitor);
+ // notify registered IsaveablePart
+ registeredIsaveablePart.doSave(monitor);
+ markSaveLocation();
+ } catch (IOException e) {
+ log.error("Error during save", e); //$NON-NLS-1$
+ }
+
+ // Sent post Events
+ lifeCycleEventsProvider.firePostDoSaveEvent(lifeCycleEvent);
+
+ }
+
+ /**
+ * @see org.eclipse.ui.ISaveablePart#doSaveAs()
+ *
+ */
+ @Override
+ public void doSaveAs() {
+ // Sent pre doSave event
+ lifeCycleEventsProvider.fireAboutToDoSaveAsEvent(lifeCycleEvent);
+
+ // sent doSaveEvent
+ lifeCycleEventsProvider.fireDoSaveAsEvent(lifeCycleEvent);
+ // Perform local doSaveAs
+
+ // Show a SaveAs dialog
+ Shell shell = multiDiagramEditor.getEditorSite().getWorkbenchWindow().getShell();
+ SaveAsDialog dialog = new SaveAsDialog(shell);
+ dialog.setOriginalFile(((IFileEditorInput) multiDiagramEditor.getEditorInput()).getFile());
+ dialog.open();
+ final IPath path = dialog.getResult();
+ if (path != null) {
+ // try to save the editor's contents under a different file name
+ final IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(path);
+ try {
+ new ProgressMonitorDialog(shell).run(false, // don't fork
+ false, // can't cancel
+ new WorkspaceModifyOperation() { // run this operation
+
+ @Override
+ public void execute(final IProgressMonitor monitor) {
+ try {
+ // to event bad redirection after the saveAs
+ // see bug 319023
+ EcoreUtil.resolveAll(resourceSet);
+ resourceSet.saveAs(path);
+ // notify registered IsaveablePart
+ registeredIsaveablePart.doSave(monitor);
+ } catch (IOException e) {
+ log.error("Unable to saveAs the resource set", e); //$NON-NLS-1$
+ }
+ }
+ });
+ // set input to the new file
+ fireEditorInputChanged(new FileEditorInput(file));
+ markSaveLocation();
+ } catch (InterruptedException e) {
+ // should not happen, since the monitor dialog is not cancelable
+ log.error(e);
+ } catch (InvocationTargetException e) {
+ log.error(e);
+ }
+ }
+
+ // sent doSaveEvent
+ lifeCycleEventsProvider.firePostDoSaveAsEvent(lifeCycleEvent);
+ }
+
+ /**
+ * Change the input of the underlying editor.
+ *
+ * @param fileEditorInput
+ */
+ private void fireEditorInputChanged(FileEditorInput fileEditorInput) {
+
+ for (IEditorInputChangedListener listener : inputChangedListeners) {
+ try {
+ listener.editorInputChanged(fileEditorInput);
+ } catch (Exception e) {
+ log.error("Can't set input for '" + listener + "'", e); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ }
+
+ /**
+ * Fire a PropertyChanged event to registered {@link IEditorInputChangedListener}.
+ *
+ * @param propertyId
+ */
+ private void fireIsDirtyChanged() {
+
+ for (IEditorInputChangedListener listener : inputChangedListeners) {
+ try {
+ listener.isDirtyChanged();
+ } catch (Exception e) {
+ log.error("Can't call listener '" + listener + "'", e); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ }
+
+ /**
+ * Return true if the multiEditor is dirty, false otherwise. The dirty state
+ * is compute as follow:
+ * <ul>
+ * <li>The {@link TransactionalEditingDomain} commandStack is checked</li>
+ * <li>and each registered nested Isaveable.isDirty() state is checked</li>
+ * <li></li>
+ * <li></li>
+ * <li></li>
+ * <li></li>
+ * </ul>
+ * If one of these states is false, the returned value is false. <br>
+ * If all of these states are true, the returned value is true.
+ *
+ * @see org.eclipse.ui.ISaveablePart#isDirty()
+ *
+ * @return
+ */
+ @Override
+ public boolean isDirty() {
+ // First, look if the model part (EMF) is dirty, else look at the
+ // Graphical part (GEF/GMF)
+ if (transactionalEditingDomain == null) {
+ return false;
+ }
+ return ((BasicCommandStack) transactionalEditingDomain.getCommandStack()).isSaveNeeded() || registeredIsaveablePart.isDirty();
+ }
+
+ /**
+ * @see org.eclipse.ui.ISaveablePart#isSaveAsAllowed()
+ *
+ * @return
+ */
+ @Override
+ public boolean isSaveAsAllowed() {
+ return true;
+ }
+
+ /**
+ * @see org.eclipse.ui.ISaveablePart#isSaveOnCloseNeeded()
+ *
+ * @return
+ */
+ @Override
+ public boolean isSaveOnCloseNeeded() {
+ return isDirty();
+ }
+
+ /**
+ * Mark the command stack of all sub-editors. Default implementation do
+ * nothing.
+ */
+ protected void markSaveLocation() {
+ ((BasicCommandStack) transactionalEditingDomain.getCommandStack()).saveIsDone();
+ fireIsDirtyChanged();
+ }
+
+ /**
+ * Register a nested {@link ISaveablePart} as a listener that will be
+ * notified each time a {@link #doSave(IProgressMonitor)} or {@link #doSaveAs()} is performed. Also, it will be asked for the
+ * dirtyState.
+ *
+ * @param saveablePart
+ */
+ @Override
+ public void registerIsaveablePart(ISaveablePart saveablePart) {
+ registeredIsaveablePart.add(saveablePart);
+ }
+
+ /**
+ * Remove the specified {@link ISaveablePart} from the list of listeners.
+ *
+ * @param saveablePart
+ */
+ @Override
+ public void removeIsaveablePart(ISaveablePart saveablePart) {
+ registeredIsaveablePart.remove(saveablePart);
+ }
+
+ /**
+ * Add a listeners on input changed event.
+ *
+ * @param inputChangedListener
+ */
+ @Override
+ public void addInputChangedListener(IEditorInputChangedListener inputChangedListener) {
+ inputChangedListeners.add(inputChangedListener);
+ }
+
+ /**
+ * Remove a listeners on input changed event.
+ *
+ * @param inputChangedListener
+ */
+ @Override
+ public void removeInputChangedListener(IEditorInputChangedListener inputChangedListener) {
+ inputChangedListeners.remove(inputChangedListener);
+ }
+
+ /**
+ * A list of {@link ISaveablePart}.
+ *
+ * @author dumoulin
+ *
+ */
+ public class ISaveablePartList extends ArrayList<ISaveablePart> {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Return true if one of the part is dirty, false if all part are not
+ * dirty.
+ *
+ * @return
+ */
+ public boolean isDirty() {
+ for (ISaveablePart part : this) {
+ if (part.isDirty()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Call doSave on each registered {@link ISaveablePart}.
+ *
+ * @param monitor
+ */
+ public void doSave(IProgressMonitor monitor) {
+ for (ISaveablePart part : this) {
+
+ try {
+ part.doSave(monitor);
+ } catch (Exception e) {
+ log.error("Can't save ISaveablePart '" + part + "'", e); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ }
+
+ /**
+ * Call doSaveAs on each registered {@link ISaveablePart}.
+ *
+ * @param monitor
+ */
+ public void doSaveAs() {
+ for (ISaveablePart part : this) {
+ try {
+ part.doSaveAs();
+ } catch (Exception e) {
+ log.error("Can't save ISaveablePart '" + part + "'", e); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ }
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/AbstractParametricOnSelectedElementsAction.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/AbstractParametricOnSelectedElementsAction.java
index ef2255fc632..72f3fbe87b6 100644
--- a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/AbstractParametricOnSelectedElementsAction.java
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/AbstractParametricOnSelectedElementsAction.java
@@ -19,8 +19,8 @@ import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.papyrus.infra.core.services.ServiceException;
-import org.eclipse.papyrus.infra.core.utils.ServiceUtilsForActionHandlers;
import org.eclipse.papyrus.infra.ui.Activator;
+import org.eclipse.papyrus.infra.ui.util.ServiceUtilsForActionHandlers;
public abstract class AbstractParametricOnSelectedElementsAction {
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/messages/Messages.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/messages/Messages.java
new file mode 100644
index 00000000000..4ece10f8d24
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/messages/Messages.java
@@ -0,0 +1,48 @@
+/*****************************************************************************
+ * Copyright (c) 2013 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.messages;
+
+import org.eclipse.osgi.util.NLS;
+
+public class Messages extends NLS {
+
+ private static final String BUNDLE_NAME = "org.eclipse.papyrus.infra.tools.messages.messages"; //$NON-NLS-1$
+
+ public static String AbstractPreferenceKeyDialog_Level;
+
+ public static String AbstractPreferenceKeyDialog_Localization;
+
+ public static String AbstractPreferenceKeyDialog_Pref_Kind;
+
+ public static String AbstractPreferenceKeyDialog_WouldYouLikeOverloadPreferences;
+
+ public static String AbstractStringValueConverter_NoXReprensentedByYHaveBeenFound;
+
+ public static String AbstractStringValueConverter_SomeStringsAreNotValidToCreateY;
+
+ public static String AbstractStringValueConverter_SomeStringsCantBeResolvedToFindY;
+
+ public static String AbstractStringValueConverter_TheFeatureXCantBeResolved;
+
+ public static String AbstractStringValueConverter_TheStringValueXCantBeResolved;
+
+ public static String AbstractStringValueConverter_TheStringXIsNotValidToCreateY;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/messages/messages.properties b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/messages/messages.properties
new file mode 100644
index 00000000000..845a45e10ab
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/messages/messages.properties
@@ -0,0 +1,10 @@
+AbstractPreferenceKeyDialog_Level=Level
+AbstractPreferenceKeyDialog_Localization=Localization
+AbstractPreferenceKeyDialog_Pref_Kind=Pref. kind
+AbstractPreferenceKeyDialog_WouldYouLikeOverloadPreferences=Would you like to overload those preferences?
+AbstractStringValueConverter_NoXReprensentedByYHaveBeenFound=No {0} represented by {1} have been found
+AbstractStringValueConverter_SomeStringsAreNotValidToCreateY=Some Strings are not valid to create {0}
+AbstractStringValueConverter_SomeStringsCantBeResolvedToFindY=Some Strings can't be resolved to find {0}
+AbstractStringValueConverter_TheFeatureXCantBeResolved=The feature {0} can't be resolved
+AbstractStringValueConverter_TheStringValueXCantBeResolved=The string value {0} can't be resolved
+AbstractStringValueConverter_TheStringXIsNotValidToCreateY=The String {0} is not valid to create {1}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/ActionBarContributorDescriptor.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/ActionBarContributorDescriptor.java
new file mode 100644
index 00000000000..731fffe79dc
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/ActionBarContributorDescriptor.java
@@ -0,0 +1,72 @@
+/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.multidiagram.actionbarcontributor;
+
+import org.eclipse.papyrus.infra.core.editor.BackboneException;
+import org.eclipse.ui.part.EditorActionBarContributor;
+
+/**
+ * Descriptor of an ActionBarContributor. This descriptor is usually loaded from
+ * the Eclipse extension mechanism.
+ *
+ * @author Cedric Dumoulin
+ * @author Patrick Tessier
+ *
+ */
+public class ActionBarContributorDescriptor {
+
+ protected Class<? extends EditorActionBarContributor> contextClass;
+
+ protected String contextId;
+
+ /**
+ * Instance is created when requested.
+ */
+ protected EditorActionBarContributor instance = null;
+
+ /**
+ * constructor.
+ *
+ * @return the context descriptor
+ * @throws BackboneException
+ */
+ protected EditorActionBarContributor getActionBarContributor() throws BackboneException {
+ if (instance == null) {
+ instance = createActionBarContributor();
+ }
+
+ return instance;
+ }
+
+ private EditorActionBarContributor createActionBarContributor() throws BackboneException {
+ try {
+ EditorActionBarContributor context = contextClass.newInstance();
+ return context;
+
+ } catch (SecurityException e) {
+ // Lets propagate. This is an implementation problem that should be
+ // solved by programmer.
+ throw new RuntimeException(e);
+ } catch (InstantiationException e) {
+ // Lets propagate. This is an implementation problem that should be
+ // solved by programmer.
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ // Lets propagate. This is an implementation problem that should be
+ // solved by programmer.
+ throw new RuntimeException(e);
+ }
+ }
+
+} // end class
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/ActionBarContributorExtensionFactory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/ActionBarContributorExtensionFactory.java
new file mode 100644
index 00000000000..fbcda9b915c
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/ActionBarContributorExtensionFactory.java
@@ -0,0 +1,72 @@
+/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.multidiagram.actionbarcontributor;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.papyrus.infra.core.extension.BadNameExtensionException;
+import org.eclipse.papyrus.infra.core.extension.ExtensionException;
+import org.eclipse.papyrus.infra.core.extension.ExtensionUtils;
+import org.eclipse.ui.part.EditorActionBarContributor;
+
+/**
+ * A factory used to create ActionBarContributor object from Eclipse extensions
+ * points elements.
+ *
+ * @author Cedric Dumoulin
+ * @auhtor Patrick Tessier
+ */
+public class ActionBarContributorExtensionFactory extends ExtensionUtils {
+
+ /** singleton eINSTANCE of this class */
+ public final static ActionBarContributorExtensionFactory eINSTANCE = new ActionBarContributorExtensionFactory();
+
+ /** constant for the editor diagram **/
+ public final static String EDITOR_ACTIONBARCONTRIBUTOR_EXTENSIONPOINT = "" + "actionBarContributor";
+
+ /** constant for the attribute factoryClass **/
+ public final static String CONTEXTCLASS_ATTRIBUTE = "implementingClass";
+
+ /** constant for the attribute contextId **/
+ public final static String ID_ATTRIBUTE = "id";
+
+ /**
+ * @return the eINSTANCE
+ */
+ public static ActionBarContributorExtensionFactory getInstance() {
+ return eINSTANCE;
+ }
+
+ /**
+ * Create a ContextDescriptor instance corresponding to the
+ * ConfigurationElement.
+ *
+ * @param element
+ * an {@link IConfigurationElement} see eclipse extension point
+ * @return a ContextDescriptor structure that contains information to the
+ * diagram context
+ * @throws BadNameExtensionException
+ **/
+ public ActionBarContributorDescriptor createActionBarContributorDescriptor(IConfigurationElement element) throws ExtensionException {
+ ActionBarContributorDescriptor res;
+
+ checkTagName(element, EDITOR_ACTIONBARCONTRIBUTOR_EXTENSIONPOINT);
+
+ res = new ActionBarContributorDescriptor();
+ res.contextClass = (Class<EditorActionBarContributor>) parseClass(element, CONTEXTCLASS_ATTRIBUTE, EDITOR_ACTIONBARCONTRIBUTOR_EXTENSIONPOINT);
+ res.contextId = element.getAttribute(ID_ATTRIBUTE);
+
+ return res;
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/ActionBarContributorRegistry.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/ActionBarContributorRegistry.java
new file mode 100644
index 00000000000..5c28baf01e9
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/ActionBarContributorRegistry.java
@@ -0,0 +1,176 @@
+/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.multidiagram.actionbarcontributor;
+
+import static org.eclipse.papyrus.infra.core.Activator.log;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.papyrus.infra.core.editor.BackboneException;
+import org.eclipse.papyrus.infra.core.extension.ExtensionException;
+import org.eclipse.papyrus.infra.core.extension.NotFoundException;
+import org.eclipse.papyrus.infra.core.services.IService;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.ui.part.EditorActionBarContributor;
+
+/**
+ * A factory managing ActionBarContributor creation. The factory is loaded from
+ * ActionBarContributor declared in Eclipse extension mechanism.
+ *
+ * @author dumoulin
+ *
+ */
+public class ActionBarContributorRegistry implements IActionBarContributorFactory, IService {
+
+ /** ID of the editor extension (schema filename) */
+ public static final String EDITOR_EXTENSION_ID = "papyrusDiagram";
+
+ /** Namespace where to look for the extension points. */
+ protected String extensionPointNamespace;
+
+ /**
+ * Registered context descriptors.
+ */
+ private Map<Object, ActionBarContributorDescriptor> editorContextDescriptors;
+
+ /**
+ * Constructor. defaultContext, input and site are explicitly required in
+ * order be sure that they are initialized. The multiEditor should be
+ * initialized. In particular, getEditorSite(), getEditorInput() and
+ * getDefaultContext() should return initialized values.
+ *
+ * @param multiEditor
+ * the multieditor
+ * @param extensionPointNamespace
+ */
+ public ActionBarContributorRegistry(String extensionPointNamespace) {
+
+ this.extensionPointNamespace = extensionPointNamespace;
+ initializeEditorContextDescriptors();
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public EditorActionBarContributor getActionBarContributor(Object key) throws BackboneException {
+ try {
+ ActionBarContributorDescriptor desc = editorContextDescriptors.get(key);
+ return desc.getActionBarContributor();
+ } catch (NullPointerException e) {
+ // no context found.
+ throw new NotFoundException("No ActionBarContributor registered under id '" + key + "'.");
+ }
+ }
+
+ /**
+ * Get the list of descriptors.
+ *
+ * @return
+ * @throws BackboneException
+ * If a contributor fail to be loaded.
+ */
+ public List<EditorActionBarContributor> getActionBarContributors() throws BackboneException {
+ List<EditorActionBarContributor> res = new ArrayList<EditorActionBarContributor>();
+ for (ActionBarContributorDescriptor desc : editorContextDescriptors.values()) {
+ res.add(desc.getActionBarContributor());
+ }
+ return res;
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ */
+ public void registerActionBarContributor(String contextKey, EditorActionBarContributor contributor) {
+ ActionBarContributorDescriptor desc = new ActionBarContributorDescriptor();
+ desc.contextId = contextKey;
+ desc.instance = contributor;
+ desc.contextClass = contributor.getClass();
+
+ editorContextDescriptors.put(contextKey, desc);
+ }
+
+ /**
+ * Read context descriptors from extension points.
+ */
+ private void initializeEditorContextDescriptors() {
+
+ editorContextDescriptors = new HashMap<Object, ActionBarContributorDescriptor>();
+ // Reading data from plugins
+ IConfigurationElement[] configElements = Platform.getExtensionRegistry().getConfigurationElementsFor(extensionPointNamespace, EDITOR_EXTENSION_ID);
+
+ ActionBarContributorExtensionFactory extensionReader = new ActionBarContributorExtensionFactory();
+
+ for (IConfigurationElement ele : configElements) {
+ ActionBarContributorDescriptor desc;
+ try {
+ if (ActionBarContributorExtensionFactory.EDITOR_ACTIONBARCONTRIBUTOR_EXTENSIONPOINT.equals(ele.getName())) {
+ desc = extensionReader.createActionBarContributorDescriptor(ele);
+ // Check double
+ if (editorContextDescriptors.get(desc.contextId) != null) {
+ // Already exists. Check if it is the same
+ ActionBarContributorDescriptor existingDesc = editorContextDescriptors.get(desc.contextId);
+ if (desc.equals(existingDesc)) {
+ log.warn("More than one ActionBarContributor is registered under the name '" + desc.contextId + "', with different parameters. Extra declaration are discarded.");
+ }
+ } else {
+ editorContextDescriptors.put(desc.contextId, desc);
+ }
+ }
+ } catch (ExtensionException e) {
+ log.error(e.getMessage(), e);
+ }
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug(this.getClass().getSimpleName() + " : contributors desc loaded [" + editorContextDescriptors.size() + "]");
+ }
+ }
+
+ /**
+ * Initialize the service. Do nothing here.
+ *
+ * @see org.eclipse.papyrus.infra.core.services.IService#init(org.eclipse.papyrus.infra.core.services.ServicesRegistry)
+ *
+ * @param servicesRegistry
+ */
+ @Override
+ public void init(ServicesRegistry servicesRegistry) {
+
+ }
+
+ /**
+ * Do nothing in this implementation. {@inheritDoc}
+ *
+ * @see org.eclipse.papyrus.infra.core.services.IService#startService()
+ */
+ @Override
+ public void startService() {
+ }
+
+ /**
+ * Do nothing in this implementation.
+ */
+ @Override
+ public void disposeService() {
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/CoreComposedActionBarContributor.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/CoreComposedActionBarContributor.java
new file mode 100644
index 00000000000..0bf82998e36
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/CoreComposedActionBarContributor.java
@@ -0,0 +1,122 @@
+/*****************************************************************************
+ * Copyright (c) 2008 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.multidiagram.actionbarcontributor;
+
+import java.util.List;
+
+import org.eclipse.papyrus.infra.core.editor.BackboneException;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.actionbarcontributor.ComposedActionBarContributor;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.actionbarcontributor.IMultiPageEditorActionBarContributor;
+import org.eclipse.papyrus.infra.ui.Activator;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.part.EditorActionBarContributor;
+
+/**
+ *
+ * An ActionBarContributor composed of ActionBarContributor from multi editor.
+ * This ActionBarContributor switch to the contributor dedicated to the active
+ * editor in a MultiPageEditor environement.
+ *
+ * @author dumoulin
+ *
+ */
+public class CoreComposedActionBarContributor extends ComposedActionBarContributor implements IMultiPageEditorActionBarContributor {
+
+ /**
+ * The registry. Used to initialize the registered actionBars.
+ */
+ protected ActionBarContributorRegistry actionBarContributorRegistry;
+
+ protected List<EditorActionBarContributor> contributors;
+
+ /**
+ * Constructor.
+ *
+ * @throws BackboneException
+ */
+ public CoreComposedActionBarContributor() throws BackboneException {
+ // Init the contributors
+ loadContributors();
+ }
+
+ /**
+ *
+ * @throws BackboneException
+ */
+ private void loadContributors() throws BackboneException {
+ actionBarContributorRegistry = new ActionBarContributorRegistry(Activator.PLUGIN_ID);
+
+ contributors = actionBarContributorRegistry.getActionBarContributors();
+ }
+
+ /**
+ * @return the actionBarContributorRegistry
+ */
+ public ActionBarContributorRegistry getActionBarContributorRegistry() {
+ return actionBarContributorRegistry;
+ }
+
+ /**
+ * Dispose all nested ActionBarContributors.
+ */
+ @Override
+ public void dispose() {
+ // Dispose nested contributors.
+ for (EditorActionBarContributor contributor : contributors) {
+ contributor.dispose();
+ }
+ super.dispose();
+ }
+
+ /**
+ * Call the same method on each registered nested ActionBarContributors.
+ */
+ @Override
+ public void init(IActionBars bars, IWorkbenchPage page) {
+ super.init(bars, page);
+ buildActions();
+
+ // init nested contributors.
+ for (EditorActionBarContributor contributor : contributors) {
+ contributor.init(bars, page);
+ // remove GMF GlobalSaveAction from bar, fix bug 407854 - [Editor] The save action is disabled in Papyrus
+ bars.setGlobalActionHandler("save", null); // GMF is not using IWorkbenchCommandConstants.FILE_SAVE as ID //$NON-NLS-1$
+ }
+
+ }
+
+ /**
+ * Load default actions (undo/redo/delete)
+ *
+ * @see org.eclipse.gef.ui.actions.ActionBarContributor#buildActions()
+ */
+ protected void buildActions() {
+ // getActionBars().getToolBarManager().add(new UndoRetargetAction());
+ // getActionBars().getToolBarManager().add(new RedoRetargetAction());
+ }
+
+ @Override
+ public void setActiveEditor(IEditorPart part) {
+ super.setActiveEditor(part);
+ for (EditorActionBarContributor contributor : contributors) {
+ if (part != null) {
+ contributor.setActiveEditor(part);
+ }
+ }
+
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/IActionBarContributorFactory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/IActionBarContributorFactory.java
new file mode 100644
index 00000000000..d5aa13ef15a
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/IActionBarContributorFactory.java
@@ -0,0 +1,25 @@
+/**
+ *
+ */
+package org.eclipse.papyrus.infra.ui.multidiagram.actionbarcontributor;
+
+import org.eclipse.papyrus.infra.core.editor.BackboneException;
+import org.eclipse.ui.part.EditorActionBarContributor;
+
+/**
+ * Interface used to get an ActionBarContributor from its ID.
+ *
+ * @author dumoulin
+ *
+ */
+public interface IActionBarContributorFactory {
+
+ /**
+ * Get an ActionBarContributor by its key. If an ActionBarContributor
+ * already exists for this key, return it.
+ *
+ * @param key
+ * @return
+ */
+ public EditorActionBarContributor getActionBarContributor(Object key) throws BackboneException;
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/AbstractPapyrusPreferenceStore.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/AbstractPapyrusPreferenceStore.java
new file mode 100644
index 00000000000..3b529b2e091
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/AbstractPapyrusPreferenceStore.java
@@ -0,0 +1,300 @@
+/*****************************************************************************
+ * Copyright (c) 2014 CEA LIST.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *
+ * Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.preferences;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.preferences.IScopeContext;
+import org.eclipse.papyrus.infra.ui.Activator;
+import org.eclipse.papyrus.infra.ui.preferences.dialog.AbstractApplyValueOnPreferenceKeyDialog;
+
+public abstract class AbstractPapyrusPreferenceStore extends PapyrusScopedPreferenceStore {
+
+ /**
+ * key for element level
+ */
+ private final String elementLevelPrefix;
+
+ /**
+ * key for editor level
+ */
+ private final String instanceEditorLevelPrefix;
+
+ /**
+ * key for all editor of the same kind
+ */
+ private final String editorLevelPrefix;
+
+ /**
+ * constructor
+ *
+ * @param context
+ * the scope to store to
+ * @param qualifier
+ * the qualifier used to look up the preference node
+ * @param key
+ * for all editor of the same kind (all diagrams, all tables, ...)
+ * @param key
+ * for an instance of this editor
+ * @param key
+ * for an element
+ */
+ public AbstractPapyrusPreferenceStore(IScopeContext context, String qualifier, String editorLevelPrefix, String instanceEditorLevelPrefix, String elementLevelPrefix) {
+ super(context, qualifier);
+ this.editorLevelPrefix = editorLevelPrefix;
+ this.instanceEditorLevelPrefix = instanceEditorLevelPrefix;
+ this.elementLevelPrefix = elementLevelPrefix;
+ }
+
+ /**
+ * constructor
+ *
+ * @param context
+ * the scope to store to
+ * @param qualifier
+ * the qualifier used to look up the preference node
+ * @param defaultQualifierPath
+ * the qualifier used when looking up the defaults
+ * @param key
+ * for all editor of the same kind (all diagrams, all tables, ...)
+ * @param key
+ * for an instance of this editor
+ * @param key
+ * for an element
+ */
+ public AbstractPapyrusPreferenceStore(IScopeContext context, String qualifier, String defaultQualifierPath, String editorLevelPrefix, String instanceEditorLevelPrefix, String elementLevelPrefix) {
+ super(context, qualifier, defaultQualifierPath);
+ this.editorLevelPrefix = editorLevelPrefix;
+ this.instanceEditorLevelPrefix = instanceEditorLevelPrefix;
+ this.elementLevelPrefix = elementLevelPrefix;
+ }
+
+
+
+
+ /**
+ * this method is used to overload all value under a level of preferences.
+ * In order to overload a pop-up is opened, and the user can choose value to overload
+ *
+ * @param level
+ * of preference: Editor or diagram
+ */
+
+ public void deleteAllSubPreference(String level) {
+ // remove all sub value diagram+ element
+
+ // key to collect
+ List<String> elementKey = new ArrayList<String>();
+ try {
+ for (int i = 0; i < getStorePreferences().keys().length; i++) {
+ // level diagram collect only element
+ if (level.startsWith(instanceEditorLevelPrefix)) {
+ if (getStorePreferences().keys()[i].startsWith(elementLevelPrefix)) {
+ elementKey.add(getStorePreferences().keys()[i]);
+ }
+ }
+ // editor level, collect all element+diagram
+ else if (level.startsWith(editorLevelPrefix)) {
+ if ((getStorePreferences().keys()[i].startsWith(elementLevelPrefix)) || (getStorePreferences().keys()[i].startsWith(instanceEditorLevelPrefix))) {
+ elementKey.add(getStorePreferences().keys()[i]);
+ }
+ }
+
+ }
+
+ } catch (Exception e) {
+ Activator.log.error(e);
+ }
+ if (elementKey.size() > 0) {
+ List<String> keytoRemove = new ArrayList<String>();
+ String[] keyRoconsult = new String[elementKey.size()];
+ AbstractApplyValueOnPreferenceKeyDialog dialog = createPreferenceKeyDialog(elementKey.toArray(keyRoconsult));
+ dialog.open();
+ keytoRemove = dialog.getKeyToRemove();
+
+ // remove key
+ Iterator<String> iterator = keytoRemove.iterator();
+ while (iterator.hasNext()) {
+ String key = iterator.next();
+ getStorePreferences().remove(key);
+ }
+ }
+ }
+
+ /**
+ *
+ * @param keys
+ * @return
+ * the dialog to apply values
+ */
+ protected abstract AbstractApplyValueOnPreferenceKeyDialog createPreferenceKeyDialog(String[] keys);
+
+
+
+ // each get value will be overloaded
+ // if not value is found for an element, a value is look for in DIAGRAM
+ // if a the value is not find for Diagram a value is find for Papyrus editor
+
+
+ /**
+ * this method is used to find a key that a got a value:
+ * if the key is an element. The method look for if this key exist. If no value exists, it look for the key for diagram
+ * if the key for diagram do not exist it look for key for papyrus Editor
+ * the structure of Key is:
+ * element : ELEMENT_DiagramKind_ElementKind.preferenceKind
+ * Diagram : DIAGRAM_DiagramKind.preferenceKind
+ * Editor: PAPYRUS_EDITOR.preferenceKind
+ *
+ */
+ protected String findKeyWithAValue(String initialKey) {
+ String foundedKey = null;
+ // first look for in value stack
+ foundedKey = findKeyAStoreValue(initialKey);
+ // then look for in default stack
+ if (foundedKey == null) {
+ foundedKey = findKeyWithADefaultValue(initialKey);
+ }
+ if (foundedKey == null) {
+ foundedKey = initialKey;
+ }
+ return foundedKey;
+
+ }
+
+ /**
+ * look for a key with a value in the store stack
+ *
+ * @param initialKey
+ * element : ELEMENT_DiagramKind_ElementKind.preferenceKind
+ * Diagram : DIAGRAM_DiagramKind.preferenceKind
+ * Editor: PAPYRUS_EDITOR.preferenceKind
+ * @return the key that returns a value or null if there is no value
+ */
+ protected String findKeyAStoreValue(String initialKey) {
+ String foundedKey = null;
+ if (getStorePreferences().get(initialKey, null) != null) {
+ foundedKey = initialKey;
+ }
+
+ if (foundedKey == null && hasPrefix(initialKey)) {
+ foundedKey = findKeyAStoreValue(getUpperKey(initialKey));
+ }
+ return foundedKey;
+ }
+
+ /**
+ * this method is used to find a key that a got a value:
+ * if the key is an element. The method look for if this key exist. If no value exists, it look for the key for diagram
+ * if the key for diagram do not exist it look for key for papyrus Editor
+ * the structure of Key is:
+ * element : ELEMENT_DiagramKind_ElementKind.preferenceKind
+ * Diagram : DIAGRAM_DiagramKind.preferenceKind
+ * Editor: PAPYRUS_EDITOR.preferenceKind
+ *
+ */
+ protected String findKeyWithADefaultValue(String initialKey) {
+ String foundedKey = null;
+
+ if (getDefaultPreferences().get(initialKey, null) != null) {
+ foundedKey = initialKey;
+ }
+
+ if (foundedKey == null && hasPrefix(initialKey)) {
+ return findKeyWithADefaultValue(getUpperKey(initialKey));
+ } else {
+ foundedKey = initialKey;
+ }
+ return foundedKey;
+
+ }
+
+ /**
+ * get the upper Key from the initial Key
+ * * the structure of Key is:
+ * element : ELEMENT_DiagramKind_ElementKind.preferenceKind
+ * Diagram : DIAGRAM_DiagramKind.preferenceKind
+ * Editor: PAPYRUS_EDITOR.preferenceKind
+ *
+ * @param initialKey
+ * @return the upperKey
+ *
+ */
+ protected String getUpperKey(String initialKey) {
+
+ String out = initialKey.toString();
+ if (initialKey.startsWith(elementLevelPrefix)) {
+ out = initialKey.toString().replaceAll(elementLevelPrefix, instanceEditorLevelPrefix);
+ out = out.substring(0, out.lastIndexOf("_")) + out.substring(out.indexOf("."), out.length());
+ }
+ if (initialKey.startsWith(instanceEditorLevelPrefix)) {
+ // out=initialKey.toString().replaceAll(instanceEditorLevelPrefix, editorLevelPrefix);
+ out = editorLevelPrefix + out.substring(out.indexOf("."), out.length());
+ }
+ return out;
+ }
+
+ protected boolean hasPrefix(String key) {
+ if (key.startsWith(elementLevelPrefix) || key.startsWith(instanceEditorLevelPrefix)) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * get the value from a key
+ *
+ * @param key
+ * @return the value
+ */
+ @Override
+ protected String internalGet(String key) {
+ String newKey = findKeyWithAValue(key);
+ // System.err.println("-->Initial Key "+key+"--> "+ newKey);
+ return Platform.getPreferencesService().get(newKey, null, getPreferenceNodes(true));
+ }
+
+ @Override
+ public boolean getDefaultBoolean(String name) {
+
+ return super.getDefaultBoolean(findKeyWithADefaultValue(name));
+ }
+
+ @Override
+ public double getDefaultDouble(String name) {
+ return super.getDefaultDouble(findKeyWithADefaultValue(name));
+ }
+
+ @Override
+ public float getDefaultFloat(String name) {
+ return super.getDefaultFloat(findKeyWithADefaultValue(name));
+ };
+
+ @Override
+ public int getDefaultInt(String name) {
+ return super.getDefaultInt(findKeyWithADefaultValue(name));
+ }
+
+ @Override
+ public long getDefaultLong(String name) {
+ return super.getDefaultLong(findKeyWithADefaultValue(name));
+ }
+
+ @Override
+ public String getDefaultString(String name) {
+ return super.getDefaultString(findKeyWithADefaultValue(name));
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/PapyrusScopedPreferenceStore.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/PapyrusScopedPreferenceStore.java
new file mode 100644
index 00000000000..f3ec34c88c1
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/PapyrusScopedPreferenceStore.java
@@ -0,0 +1,858 @@
+/*****************************************************************************
+ * Copyright (c) 2010 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Patrick Tessier (CEA LIST) Patrick.tessier@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.preferences;
+
+/***************************************************************************
+ Copyright (c) 2010 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ *
+ * Contributors:
+ * the code is copy from ScopedPreferenceStore but I have open some methods in order to be
+ * available for the overload
+ *
+ * Patrick Tessier (CEA LIST) Patrick.tessier@cea.fr - Initial API and implementation
+ *
+ *
+ *******************************************************************************/
+
+import java.io.IOException;
+
+import org.eclipse.core.commands.common.EventManager;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Plugin;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.core.runtime.preferences.DefaultScope;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences.INodeChangeListener;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences.NodeChangeEvent;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
+import org.eclipse.core.runtime.preferences.IScopeContext;
+import org.eclipse.jface.preference.IPersistentPreferenceStore;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.util.SafeRunnable;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.osgi.service.prefs.BackingStoreException;
+
+/**
+ * The ScopedPreferenceStore is an IPreferenceStore that uses the scopes
+ * provided in org.eclipse.core.runtime.preferences.
+ * <p>
+ * A ScopedPreferenceStore does the lookup of a preference based on it's search scopes and sets the value of the preference based on its store scope.
+ * </p>
+ * <p>
+ * The default scope is always included in the search scopes when searching for preference values.
+ * </p>
+ *
+ * @see org.eclipse.core.runtime.preferences
+ * @since 3.1
+ */
+public class PapyrusScopedPreferenceStore extends EventManager implements IPreferenceStore, IPersistentPreferenceStore {
+
+ /**
+ * The storeContext is the context where values will stored with the
+ * setValue methods. If there are no searchContexts this will be the search
+ * context. (along with the "default" context)
+ */
+ protected IScopeContext storeContext;
+
+ /**
+ * The searchContext is the array of contexts that will be used by the get
+ * methods for searching for values.
+ */
+ protected IScopeContext[] searchContexts;
+
+ /**
+ * A boolean to indicate the property changes should not be propagated.
+ */
+ protected boolean silentRunning = false;
+
+ /**
+ * The listener on the IEclipsePreferences. This is used to forward updates
+ * to the property change listeners on the preference store.
+ */
+ protected IEclipsePreferences.IPreferenceChangeListener preferencesListener;
+
+ /**
+ * The default context is the context where getDefault and setDefault
+ * methods will search. This context is also used in the search.
+ */
+ protected IScopeContext defaultContext = DefaultScope.INSTANCE;
+
+ /**
+ * The nodeQualifer is the string used to look up the node in the contexts.
+ */
+ protected String nodeQualifier;
+
+ /**
+ * The defaultQualifier is the string used to look up the default node.
+ */
+ protected String defaultQualifier;
+
+ /**
+ * Boolean value indicating whether or not this store has changes to be
+ * saved.
+ */
+ private boolean dirty;
+
+ /**
+ * Create a new instance of the receiver. Store the values in context in the
+ * node looked up by qualifier. <strong>NOTE:</strong> Any instance of
+ * ScopedPreferenceStore should call
+ *
+ * @param context
+ * the scope to store to
+ * @param qualifier
+ * the qualifier used to look up the preference node
+ * @param defaultQualifierPath
+ * the qualifier used when looking up the defaults
+ */
+ public PapyrusScopedPreferenceStore(IScopeContext context, String qualifier, String defaultQualifierPath) {
+ this(context, qualifier);
+ this.defaultQualifier = defaultQualifierPath;
+ }
+
+ /**
+ * Create a new instance of the receiver. Store the values in context in the
+ * node looked up by qualifier.
+ *
+ * @param context
+ * the scope to store to
+ * @param qualifier
+ * the qualifer used to look up the preference node
+ */
+ public PapyrusScopedPreferenceStore(IScopeContext context, String qualifier) {
+ storeContext = context;
+ this.nodeQualifier = qualifier;
+ this.defaultQualifier = qualifier;
+
+ ((IEclipsePreferences) getStorePreferences().parent()).addNodeChangeListener(getNodeChangeListener());
+ }
+
+ /**
+ * Return a node change listener that adds a removes the receiver when nodes
+ * change.
+ *
+ * @return INodeChangeListener
+ */
+ private INodeChangeListener getNodeChangeListener() {
+ return new IEclipsePreferences.INodeChangeListener() {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.core.runtime.preferences.IEclipsePreferences.INodeChangeListener#added(org.eclipse.core.runtime.preferences.IEclipsePreferences
+ * .NodeChangeEvent)
+ */
+ public void added(NodeChangeEvent event) {
+ if (nodeQualifier.equals(event.getChild().name()) && isListenerAttached()) {
+ getStorePreferences().addPreferenceChangeListener(preferencesListener);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.core.runtime.preferences.IEclipsePreferences.INodeChangeListener#removed(org.eclipse.core.runtime.preferences.
+ * IEclipsePreferences.NodeChangeEvent)
+ */
+ public void removed(NodeChangeEvent event) {
+ // Do nothing as there are no events from removed node
+ }
+ };
+ }
+
+ /**
+ * Initialize the preferences listener.
+ */
+ private void initializePreferencesListener() {
+ if (preferencesListener == null) {
+ preferencesListener = new IEclipsePreferences.IPreferenceChangeListener() {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener#preferenceChange(org.eclipse.core.runtime.
+ * preferences.IEclipsePreferences.PreferenceChangeEvent)
+ */
+ public void preferenceChange(PreferenceChangeEvent event) {
+
+ if (silentRunning) {
+ return;
+ }
+
+ Object oldValue = event.getOldValue();
+ Object newValue = event.getNewValue();
+ String key = event.getKey();
+ if (newValue == null) {
+ newValue = getDefault(key, oldValue);
+ } else if (oldValue == null) {
+ oldValue = getDefault(key, newValue);
+ }
+ firePropertyChangeEvent(event.getKey(), oldValue, newValue);
+ }
+ };
+ getStorePreferences().addPreferenceChangeListener(preferencesListener);
+ }
+
+ }
+
+ /**
+ * Does its best at determining the default value for the given key. Checks
+ * the given object's type and then looks in the list of defaults to see if
+ * a value exists. If not or if there is a problem converting the value, the
+ * default default value for that type is returned.
+ *
+ * @param key
+ * the key to search
+ * @param obj
+ * the object who default we are looking for
+ * @return Object or <code>null</code>
+ */
+ protected Object getDefault(String key, Object obj) {
+ IEclipsePreferences defaults = getDefaultPreferences();
+ if (obj instanceof String) {
+ return defaults.get(key, STRING_DEFAULT_DEFAULT);
+ } else if (obj instanceof Integer) {
+ return Integer.valueOf(defaults.getInt(key, INT_DEFAULT_DEFAULT));
+ } else if (obj instanceof Double) {
+ return new Double(defaults.getDouble(key, DOUBLE_DEFAULT_DEFAULT));
+ } else if (obj instanceof Float) {
+ return new Float(defaults.getFloat(key, FLOAT_DEFAULT_DEFAULT));
+ } else if (obj instanceof Long) {
+ return Long.valueOf(defaults.getLong(key, LONG_DEFAULT_DEFAULT));
+ } else if (obj instanceof Boolean) {
+ return defaults.getBoolean(key, BOOLEAN_DEFAULT_DEFAULT) ? Boolean.TRUE : Boolean.FALSE;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Return the IEclipsePreferences node associated with this store.
+ *
+ * @return the preference node for this store
+ */
+ protected IEclipsePreferences getStorePreferences() {
+ return storeContext.getNode(nodeQualifier);
+ }
+
+ /**
+ * Return the default IEclipsePreferences for this store.
+ *
+ * @return this store's default preference node
+ */
+ protected IEclipsePreferences getDefaultPreferences() {
+ return defaultContext.getNode(defaultQualifier);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#addPropertyChangeListener(org.eclipse.jface.util.IPropertyChangeListener)
+ */
+ public void addPropertyChangeListener(IPropertyChangeListener listener) {
+ initializePreferencesListener();// Create the preferences listener if it
+ // does not exist
+ addListenerObject(listener);
+ }
+
+ /**
+ * Return the preference path to search preferences on. This is the list of
+ * preference nodes based on the scope contexts for this store. If there are
+ * no search contexts set, then return this store's context.
+ * <p>
+ * Whether or not the default context should be included in the resulting list is specified by the <code>includeDefault</code> parameter.
+ * </p>
+ *
+ * @param includeDefault
+ * <code>true</code> if the default context should be included
+ * and <code>false</code> otherwise
+ * @return IEclipsePreferences[]
+ * @since 3.4 public, was added in 3.1 as private method
+ */
+ public IEclipsePreferences[] getPreferenceNodes(boolean includeDefault) {
+ // if the user didn't specify a search order, then return the scope that
+ // this store was created on. (and optionally the default)
+ if (searchContexts == null) {
+ if (includeDefault) {
+ return new IEclipsePreferences[] { getStorePreferences(), getDefaultPreferences() };
+ }
+ return new IEclipsePreferences[] { getStorePreferences() };
+ }
+ // otherwise the user specified a search order so return the appropriate
+ // nodes based on it
+ int length = searchContexts.length;
+ if (includeDefault) {
+ length++;
+ }
+ IEclipsePreferences[] preferences = new IEclipsePreferences[length];
+ for (int i = 0; i < searchContexts.length; i++) {
+ preferences[i] = searchContexts[i].getNode(nodeQualifier);
+ }
+ if (includeDefault) {
+ preferences[length - 1] = getDefaultPreferences();
+ }
+ return preferences;
+ }
+
+ /**
+ * Set the search contexts to scopes. When searching for a value the seach
+ * will be done in the order of scope contexts and will not search the
+ * storeContext unless it is in this list.
+ * <p>
+ * If the given list is <code>null</code>, then clear this store's search contexts. This means that only this store's scope context and default scope will be used during preference value searching.
+ * </p>
+ * <p>
+ * The defaultContext will be added to the end of this list automatically and <em>MUST NOT</em> be included by the user.
+ * </p>
+ *
+ * @param scopes
+ * a list of scope contexts to use when searching, or <code>null</code>
+ */
+ public void setSearchContexts(IScopeContext[] scopes) {
+ this.searchContexts = scopes;
+ if (scopes == null) {
+ return;
+ }
+
+ // Assert that the default was not included (we automatically add it to
+ // the end)
+ for (int i = 0; i < scopes.length; i++) {
+ if (scopes[i].equals(defaultContext)) {
+ Assert.isTrue(false, WorkbenchMessages.ScopedPreferenceStore_DefaultAddedError);
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#contains(java.lang.String)
+ */
+ public boolean contains(String name) {
+ if (name == null) {
+ return false;
+ }
+ return (Platform.getPreferencesService().get(name, null, getPreferenceNodes(true))) != null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#firePropertyChangeEvent(java.lang.String,
+ * java.lang.Object, java.lang.Object)
+ */
+ public void firePropertyChangeEvent(String name, Object oldValue, Object newValue) {
+ // important: create intermediate array to protect against listeners
+ // being added/removed during the notification
+ final Object[] list = getListeners();
+ if (list.length == 0) {
+ return;
+ }
+ final PropertyChangeEvent event = new PropertyChangeEvent(this, name, oldValue, newValue);
+ for (int i = 0; i < list.length; i++) {
+ final IPropertyChangeListener listener = (IPropertyChangeListener) list[i];
+ SafeRunner.run(new SafeRunnable(JFaceResources.getString("PreferenceStore.changeError")) { //$NON-NLS-1$
+
+ public void run() {
+ listener.propertyChange(event);
+ }
+ });
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#getBoolean(java.lang.String)
+ */
+ public boolean getBoolean(String name) {
+ String value = internalGet(name);
+ return value == null ? BOOLEAN_DEFAULT_DEFAULT : Boolean.valueOf(value).booleanValue();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultBoolean(java.lang.String)
+ */
+ public boolean getDefaultBoolean(String name) {
+ return getDefaultPreferences().getBoolean(name, BOOLEAN_DEFAULT_DEFAULT);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultDouble(java.lang.String)
+ */
+ public double getDefaultDouble(String name) {
+ return getDefaultPreferences().getDouble(name, DOUBLE_DEFAULT_DEFAULT);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultFloat(java.lang.String)
+ */
+ public float getDefaultFloat(String name) {
+ return getDefaultPreferences().getFloat(name, FLOAT_DEFAULT_DEFAULT);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultInt(java.lang.String)
+ */
+ public int getDefaultInt(String name) {
+ return getDefaultPreferences().getInt(name, INT_DEFAULT_DEFAULT);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultLong(java.lang.String)
+ */
+ public long getDefaultLong(String name) {
+ return getDefaultPreferences().getLong(name, LONG_DEFAULT_DEFAULT);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#getDefaultString(java.lang.String)
+ */
+ public String getDefaultString(String name) {
+ return getDefaultPreferences().get(name, STRING_DEFAULT_DEFAULT);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#getDouble(java.lang.String)
+ */
+ public double getDouble(String name) {
+ String value = internalGet(name);
+ if (value == null) {
+ return DOUBLE_DEFAULT_DEFAULT;
+ }
+ try {
+ return Double.parseDouble(value);
+ } catch (NumberFormatException e) {
+ return DOUBLE_DEFAULT_DEFAULT;
+ }
+ }
+
+ /**
+ * Return the string value for the specified key. Look in the nodes which
+ * are specified by this object's list of search scopes. If the value does
+ * not exist then return <code>null</code>.
+ *
+ * @param key
+ * the key to search with
+ * @return String or <code>null</code> if the value does not exist.
+ */
+ protected String internalGet(String key) {
+ return Platform.getPreferencesService().get(key, null, getPreferenceNodes(true));
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#getFloat(java.lang.String)
+ */
+ public float getFloat(String name) {
+ String value = internalGet(name);
+ if (value == null) {
+ return FLOAT_DEFAULT_DEFAULT;
+ }
+ try {
+ return Float.parseFloat(value);
+ } catch (NumberFormatException e) {
+ return FLOAT_DEFAULT_DEFAULT;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#getInt(java.lang.String)
+ */
+ public int getInt(String name) {
+ String value = internalGet(name);
+ if (value == null) {
+ return INT_DEFAULT_DEFAULT;
+ }
+ try {
+ return Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ return INT_DEFAULT_DEFAULT;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#getLong(java.lang.String)
+ */
+ public long getLong(String name) {
+ String value = internalGet(name);
+ if (value == null) {
+ return LONG_DEFAULT_DEFAULT;
+ }
+ try {
+ return Long.parseLong(value);
+ } catch (NumberFormatException e) {
+ return LONG_DEFAULT_DEFAULT;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#getString(java.lang.String)
+ */
+ public String getString(String name) {
+ String value = internalGet(name);
+ return value == null ? STRING_DEFAULT_DEFAULT : value;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#isDefault(java.lang.String)
+ */
+ public boolean isDefault(String name) {
+ if (name == null) {
+ return false;
+ }
+ return (Platform.getPreferencesService().get(name, null, getPreferenceNodes(false))) == null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#needsSaving()
+ */
+ public boolean needsSaving() {
+ return dirty;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#putValue(java.lang.String,
+ * java.lang.String)
+ */
+ public void putValue(String name, String value) {
+ try {
+ // Do not notify listeners
+ silentRunning = true;
+ getStorePreferences().put(name, value);
+ } finally {
+ // Be sure that an exception does not stop property updates
+ silentRunning = false;
+ dirty = true;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#removePropertyChangeListener(org.eclipse.jface.util.IPropertyChangeListener)
+ */
+ public void removePropertyChangeListener(IPropertyChangeListener listener) {
+ removeListenerObject(listener);
+ if (!isListenerAttached()) {
+ disposePreferenceStoreListener();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String,
+ * double)
+ */
+ public void setDefault(String name, double value) {
+ getDefaultPreferences().putDouble(name, value);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String,
+ * float)
+ */
+ public void setDefault(String name, float value) {
+ getDefaultPreferences().putFloat(name, value);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String,
+ * int)
+ */
+ public void setDefault(String name, int value) {
+ getDefaultPreferences().putInt(name, value);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String,
+ * long)
+ */
+ public void setDefault(String name, long value) {
+ getDefaultPreferences().putLong(name, value);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String,
+ * java.lang.String)
+ */
+ public void setDefault(String name, String defaultObject) {
+ getDefaultPreferences().put(name, defaultObject);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#setDefault(java.lang.String,
+ * boolean)
+ */
+ public void setDefault(String name, boolean value) {
+ getDefaultPreferences().putBoolean(name, value);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#setToDefault(java.lang.String)
+ */
+ public void setToDefault(String name) {
+
+ String oldValue = getString(name);
+ String defaultValue = getDefaultString(name);
+ try {
+ silentRunning = true;// Turn off updates from the store
+ // removing a non-existing preference is a no-op so call the Core
+ // API directly
+ getStorePreferences().remove(name);
+ if (!oldValue.equals(defaultValue)) {
+ dirty = true;
+ firePropertyChangeEvent(name, oldValue, defaultValue);
+ }
+
+ } finally {
+ silentRunning = false;// Restart listening to preferences
+ }
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String,
+ * double)
+ */
+ public void setValue(String name, double value) {
+ double oldValue = getDouble(name);
+ if (oldValue == value) {
+ return;
+ }
+ try {
+ silentRunning = true;// Turn off updates from the store
+ if (getDefaultDouble(name) == value) {
+ getStorePreferences().remove(name);
+ } else {
+ getStorePreferences().putDouble(name, value);
+ }
+ dirty = true;
+ firePropertyChangeEvent(name, new Double(oldValue), new Double(value));
+ } finally {
+ silentRunning = false;// Restart listening to preferences
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String,
+ * float)
+ */
+ public void setValue(String name, float value) {
+ float oldValue = getFloat(name);
+ if (oldValue == value) {
+ return;
+ }
+ try {
+ silentRunning = true;// Turn off updates from the store
+ if (getDefaultFloat(name) == value) {
+ getStorePreferences().remove(name);
+ } else {
+ getStorePreferences().putFloat(name, value);
+ }
+ dirty = true;
+ firePropertyChangeEvent(name, new Float(oldValue), new Float(value));
+ } finally {
+ silentRunning = false;// Restart listening to preferences
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String,
+ * int)
+ */
+ public void setValue(String name, int value) {
+ int oldValue = getInt(name);
+ if (oldValue == value) {
+ return;
+ }
+ try {
+ silentRunning = true;// Turn off updates from the store
+ if (getDefaultInt(name) == value) {
+ getStorePreferences().remove(name);
+ } else {
+ getStorePreferences().putInt(name, value);
+ }
+ dirty = true;
+ firePropertyChangeEvent(name, Integer.valueOf(oldValue), Integer.valueOf(value));
+ } finally {
+ silentRunning = false;// Restart listening to preferences
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String,
+ * long)
+ */
+ public void setValue(String name, long value) {
+ long oldValue = getLong(name);
+ if (oldValue == value) {
+ return;
+ }
+ try {
+ silentRunning = true;// Turn off updates from the store
+ if (getDefaultLong(name) == value) {
+ getStorePreferences().remove(name);
+ } else {
+ getStorePreferences().putLong(name, value);
+ }
+ dirty = true;
+ firePropertyChangeEvent(name, Long.valueOf(oldValue), Long.valueOf(value));
+ } finally {
+ silentRunning = false;// Restart listening to preferences
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String,
+ * java.lang.String)
+ */
+ public void setValue(String name, String value) {
+ // Do not turn on silent running here as Strings are propagated
+ if (getDefaultString(name).equals(value)) {
+ getStorePreferences().remove(name);
+ } else {
+ getStorePreferences().put(name, value);
+ }
+ dirty = true;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPreferenceStore#setValue(java.lang.String,
+ * boolean)
+ */
+ public void setValue(String name, boolean value) {
+ boolean oldValue = getBoolean(name);
+ if (oldValue == value) {
+ return;
+ }
+ try {
+ silentRunning = true;// Turn off updates from the store
+ if (getDefaultBoolean(name) == value) {
+ getStorePreferences().remove(name);
+ } else {
+ getStorePreferences().putBoolean(name, value);
+ }
+ dirty = true;
+ firePropertyChangeEvent(name, oldValue ? Boolean.TRUE : Boolean.FALSE, value ? Boolean.TRUE : Boolean.FALSE);
+ } finally {
+ silentRunning = false;// Restart listening to preferences
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.preference.IPersistentPreferenceStore#save()
+ */
+ public void save() throws IOException {
+ try {
+ getStorePreferences().flush();
+ dirty = false;
+ } catch (BackingStoreException e) {
+ throw new IOException(e.getMessage());
+ }
+
+ }
+
+ /**
+ * Dispose the receiver.
+ */
+ private void disposePreferenceStoreListener() {
+
+ IEclipsePreferences root = (IEclipsePreferences) Platform.getPreferencesService().getRootNode().node(Plugin.PLUGIN_PREFERENCE_SCOPE);
+ try {
+ if (!(root.nodeExists(nodeQualifier))) {
+ return;
+ }
+ } catch (BackingStoreException e) {
+ return;// No need to report here as the node won't have the
+ // listener
+ }
+
+ IEclipsePreferences preferences = getStorePreferences();
+ if (preferences == null) {
+ return;
+ }
+ if (preferencesListener != null) {
+ preferences.removePreferenceChangeListener(preferencesListener);
+ preferencesListener = null;
+ }
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/dialog/AbstractApplyValueOnPreferenceKeyDialog.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/dialog/AbstractApplyValueOnPreferenceKeyDialog.java
new file mode 100644
index 00000000000..f21f02085d6
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/dialog/AbstractApplyValueOnPreferenceKeyDialog.java
@@ -0,0 +1,71 @@
+/*****************************************************************************
+ * Copyright (c) 2010 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Patrick Tessier (CEA LIST) Patrick.tessier@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.preferences.dialog;
+
+import java.util.ArrayList;
+
+/**
+ * The Class ApplyValueOnPreferenceKeyDialog display all the preference key and give all selected keys
+ */
+public abstract class AbstractApplyValueOnPreferenceKeyDialog extends AbstractPreferenceKeyDialog {
+
+ /** The checked key. */
+ protected ArrayList<String> checkedKey;
+
+ /**
+ * Instantiates a new apply value on preference key dialog.
+ *
+ * @param keys
+ * the keys
+ */
+ public AbstractApplyValueOnPreferenceKeyDialog(String[] keys) {
+ super(keys);
+ checkedKey = new ArrayList<String>();
+ }
+
+ /**
+ * Gets the key to remove.
+ *
+ * @return the key to remove
+ */
+ public ArrayList<String> getKeyToRemove() {
+ return checkedKey;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.dialogs.Dialog#okPressed()
+ */
+ @Override
+ protected void okPressed() {
+ for (int i = 0; i < keyTable.getItems().length; i++) {
+ if (keyTable.getItems()[i].getChecked()) {
+ checkedKey.add((String) keyTable.getItems()[i].getData());
+ }
+ }
+ super.okPressed();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.dialogs.Dialog#cancelPressed()
+ */
+ @Override
+ protected void cancelPressed() {
+ super.cancelPressed();
+ checkedKey = new ArrayList<String>();
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/dialog/AbstractPreferenceKeyDialog.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/dialog/AbstractPreferenceKeyDialog.java
new file mode 100644
index 00000000000..9265a692051
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/dialog/AbstractPreferenceKeyDialog.java
@@ -0,0 +1,105 @@
+/*****************************************************************************
+ * Copyright (c) 2010 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Patrick Tessier (CEA LIST) Patrick.tessier@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.preferences.dialog;
+
+import java.util.Arrays;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.IContentProvider;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.papyrus.infra.ui.Activator;
+import org.eclipse.papyrus.infra.ui.messages.Messages;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+
+/**
+ * The Class AbstractPreferenceKeyDialog display all preference key that are given in parameters
+ */
+public abstract class AbstractPreferenceKeyDialog extends org.eclipse.jface.dialogs.StatusDialog {
+
+ /** The key table. */
+ protected Table keyTable;
+
+ /** The table viewer. */
+ protected TableViewer tableViewer;
+
+ /** The keys. */
+ protected String[] keys;
+
+ /**
+ * Instantiates a new abstract preference key dialog.
+ *
+ * @param keys
+ * the array of preference jy to display
+ */
+ public AbstractPreferenceKeyDialog(String[] keys) {
+ super(new Shell());
+ this.keys = Arrays.copyOf(keys, keys.length);
+ setStatusLineAboveButtons(true);
+ updateStatus(new Status(IStatus.INFO, Activator.PLUGIN_ID, Messages.AbstractPreferenceKeyDialog_WouldYouLikeOverloadPreferences));
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ Composite composite = (Composite) super.createDialogArea(parent);
+ keyTable = new Table(composite, SWT.CHECK | SWT.BORDER);
+ tableViewer = new TableViewer(keyTable);
+ tableViewer.setLabelProvider(createLabelProvider());
+ tableViewer.setContentProvider(createContentProvider());
+
+ TableColumn column = new TableColumn(keyTable, SWT.NONE);
+ column.setWidth(150);
+ column.setText(Messages.AbstractPreferenceKeyDialog_Pref_Kind);
+
+ column = new TableColumn(keyTable, SWT.NONE);
+ column.setWidth(90);
+ column.setText(Messages.AbstractPreferenceKeyDialog_Level);
+
+ column = new TableColumn(keyTable, SWT.NONE);
+ column.setWidth(200);
+ column.setText(Messages.AbstractPreferenceKeyDialog_Localization);
+ tableViewer.setInput(keys);
+ keyTable.setHeaderVisible(true);
+
+
+ return composite;
+
+ }
+
+ /**
+ *
+ * @return
+ * the label provider for the table viewer
+ */
+ protected abstract IBaseLabelProvider createLabelProvider();
+
+ /**
+ *
+ * @return
+ * the content provider for the table viewer
+ */
+ protected abstract IContentProvider createContentProvider();
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/EditorLifecycleEventListener.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/EditorLifecycleEventListener.java
new file mode 100644
index 00000000000..7264ae39750
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/EditorLifecycleEventListener.java
@@ -0,0 +1,55 @@
+/*****************************************************************************
+ * Copyright (c) 2013, 2015 CEA LIST, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus - bug 469188
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.services;
+
+import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor;
+
+/**
+ * Listens to the Lifecycle of an {@link IMultiDiagramEditor}
+ *
+ * @author Camille Letavernier
+ *
+ */
+public interface EditorLifecycleEventListener {
+
+ /**
+ * The ServicesRegistry is successfully started
+ *
+ * @param editor
+ */
+ public void postInit(IMultiDiagramEditor editor);
+
+ /**
+ * All the editors are constructed, but not yet displayed
+ *
+ * @param editor
+ */
+ public default void preDisplay(IMultiDiagramEditor editor) {
+ // Pass
+ }
+
+ /**
+ * All the editors are displayed
+ *
+ * @param editor
+ */
+ public void postDisplay(IMultiDiagramEditor editor);
+
+ /**
+ * The editor is about to be closed
+ *
+ * @param editor
+ */
+ public void beforeClose(IMultiDiagramEditor editor);
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/EditorLifecycleManager.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/EditorLifecycleManager.java
new file mode 100644
index 00000000000..2866903aa39
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/EditorLifecycleManager.java
@@ -0,0 +1,30 @@
+/*****************************************************************************
+ * Copyright (c) 2013 CEA LIST.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.services;
+
+import org.eclipse.papyrus.infra.core.services.IService;
+
+/**
+ * The LifecycleManager for IMultiDiagramEditor
+ *
+ * It notifies its listeners when the state of the editor changes
+ *
+ * @author Camille Letavernier
+ *
+ */
+public interface EditorLifecycleManager extends IService {
+
+ public void addEditorLifecycleEventsListener(EditorLifecycleEventListener listener);
+
+ public void removeEditorLifecycleEventsListener(EditorLifecycleEventListener listener);
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/Messages.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/Messages.java
new file mode 100644
index 00000000000..58482ab0e2c
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/Messages.java
@@ -0,0 +1,34 @@
+/*****************************************************************************
+ * Copyright (c) 2015 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.ui.services;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Translatable strings.
+ */
+class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.papyrus.infra.core.services.messages"; //$NON-NLS-1$
+ public static String SaveLayoutBeforeClose_0;
+ public static String SaveLayoutBeforeClose_1;
+ public static String SaveLayoutBeforeClose_2;
+
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/ResourceUpdateService.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/ResourceUpdateService.java
new file mode 100644
index 00000000000..423727e534f
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/ResourceUpdateService.java
@@ -0,0 +1,292 @@
+/*****************************************************************************
+ * Copyright (c) 2013, 2014 CEA LIST and others.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (camille.letavernier@cea.fr) - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 437217
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.services;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.concurrent.ConcurrentMap;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceChangeEvent;
+import org.eclipse.core.resources.IResourceChangeListener;
+import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.resources.IResourceDeltaVisitor;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.services.IService;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.ui.Activator;
+import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor;
+import org.eclipse.papyrus.infra.ui.editor.IReloadableEditor;
+import org.eclipse.papyrus.infra.ui.editor.IReloadableEditor.DirtyPolicy;
+import org.eclipse.papyrus.infra.ui.lifecycleevents.DoSaveEvent;
+import org.eclipse.papyrus.infra.ui.lifecycleevents.ILifeCycleEventsProvider;
+import org.eclipse.papyrus.infra.ui.lifecycleevents.ISaveEventListener;
+import org.eclipse.ui.IPartListener;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
+import org.eclipse.ui.progress.UIJob;
+
+import com.google.common.collect.Maps;
+
+/**
+ * A Service to check workspace modifications on current resources
+ *
+ * @author Camille Letavernier
+ *
+ */
+public class ResourceUpdateService implements IService, IPartListener {
+
+ protected ServicesRegistry registry;
+
+ protected ModelSet modelSet;
+
+ static int[] handledTypes = new int[] { IResourceChangeEvent.POST_CHANGE, IResourceChangeEvent.PRE_DELETE, IResourceChangeEvent.PRE_CLOSE };
+
+ protected boolean isSaving;
+
+ protected ConcurrentMap<IMultiDiagramEditor, Job> pendingEditorCloseJobs = Maps.newConcurrentMap();
+
+ private final ISaveEventListener preSaveListener = new ISaveEventListener() {
+
+ @Override
+ public void doSaveAs(DoSaveEvent event) {
+ isSaving = true;
+ }
+
+ @Override
+ public void doSave(DoSaveEvent event) {
+ isSaving = true;
+ }
+ };
+
+ private final ISaveEventListener postSaveListener = new ISaveEventListener() {
+
+ @Override
+ public void doSaveAs(DoSaveEvent event) {
+ isSaving = false;
+ }
+
+ @Override
+ public void doSave(DoSaveEvent event) {
+ isSaving = false;
+ }
+ };
+
+ @Override
+ public void init(ServicesRegistry servicesRegistry) throws ServiceException {
+ this.registry = servicesRegistry;
+ }
+
+ @Override
+ public void startService() throws ServiceException {
+ ResourcesPlugin.getWorkspace().addResourceChangeListener(resourceChangeListener, IResourceChangeEvent.POST_CHANGE);
+ modelSet = registry.getService(ModelSet.class);
+ registry.getService(ILifeCycleEventsProvider.class).addAboutToDoSaveListener(preSaveListener);
+ registry.getService(ILifeCycleEventsProvider.class).addPostDoSaveListener(postSaveListener);
+ }
+
+ @Override
+ public void disposeService() throws ServiceException {
+ ResourcesPlugin.getWorkspace().removeResourceChangeListener(resourceChangeListener);
+ modelSet = null;
+ }
+
+ protected void closeEditor() {
+ closeEditor(Collections.<Resource> emptyList(), false);
+ }
+
+ protected void closeEditor(final Collection<? extends Resource> triggeringResources, final boolean reopen) {
+ try {
+ if (!reopen) {
+ registry.remove(SaveLayoutBeforeClose.class.getName());
+ }
+
+ final IMultiDiagramEditor editor = registry.getService(IMultiDiagramEditor.class);
+ if (editor != null) {
+ final IWorkbenchPartSite site = editor.getSite();
+ UIJob closeEditorJob = new UIJob(site.getShell().getDisplay(), NLS.bind("Reload editor {0}", editor.getTitle())) {
+
+ @Override
+ public IStatus runInUIThread(IProgressMonitor monitor) {
+ // Remove the pending job
+ pendingEditorCloseJobs.remove(editor);
+
+ IStatus result = Status.OK_STATUS;
+ monitor = SubMonitor.convert(monitor, IProgressMonitor.UNKNOWN);
+
+ try {
+ IReloadableEditor.ReloadReason reason = reopen ? IReloadableEditor.ReloadReason.RESOURCES_CHANGED : IReloadableEditor.ReloadReason.RESOURCES_DELETED;
+
+ DirtyPolicy dirtyPolicy = DirtyPolicy.getDefault();
+ if (!reopen && !editor.isDirty()) {
+ // Check whether we're deleting one of our own resources. If so, just close
+ URI principalURI = modelSet.getURIWithoutExtension();
+ for (Resource next : triggeringResources) {
+ if (next.getURI().trimFileExtension().equals(principalURI)) {
+ dirtyPolicy = DirtyPolicy.DO_NOT_SAVE;
+ break;
+ }
+ }
+ }
+
+ try {
+ IReloadableEditor.Adapter.getAdapter(editor).reloadEditor(triggeringResources, reason, dirtyPolicy);
+ } catch (CoreException e) {
+ result = e.getStatus();
+ }
+ } finally {
+ monitor.done();
+ }
+
+ return result;
+ }
+ };
+
+ // We are notified usually of at least three resources (*.di, *.notation, *.uml) that are unloaded, but
+ // there's no need to close and re-open the same editor three times
+ if (pendingEditorCloseJobs.putIfAbsent(editor, closeEditorJob) == null) {
+ // Async execution to avoid lock conflicts on the Workspace (Probably owned by this thread, and not the UI thread)
+ IWorkbenchSiteProgressService progressService = site.getService(IWorkbenchSiteProgressService.class);
+ progressService.schedule(closeEditorJob);
+ }
+ }
+ } catch (ServiceException ex) {
+ // Nothing
+ }
+ }
+
+ protected void handleResourcesRemoved(Collection<Resource> emfResources) {
+ closeEditor(emfResources, false);
+ }
+
+ protected void handleResourceChanged(Collection<Resource> emfResources) {
+ closeEditor(emfResources, true);
+ }
+
+ // Copied from org.eclipse.emf.ecore.presentation.EcoreEditor
+ protected IResourceChangeListener resourceChangeListener = new IResourceChangeListener() {
+
+ @Override
+ public void resourceChanged(IResourceChangeEvent event) {
+ IResourceDelta delta = event.getDelta();
+ try {
+ class ResourceDeltaVisitor implements IResourceDeltaVisitor {
+
+ protected Collection<Resource> changedResources = new ArrayList<Resource>();
+
+ protected Collection<Resource> removedResources = new ArrayList<Resource>();
+
+ @Override
+ public boolean visit(final IResourceDelta delta) {
+ if (delta.getResource().getType() == IResource.FILE) {
+ if (delta.getKind() == IResourceDelta.REMOVED || delta.getKind() == IResourceDelta.CHANGED) {
+ URI resourceURI = URI.createPlatformResourceURI(delta.getFullPath().toString(), true);
+ Resource resource = modelSet.getResource(resourceURI, false);
+ if (resource == null) {
+ // try again, with a pluginURI, see bug 418428
+ URI pluginURI = URI.createPlatformPluginURI(delta.getFullPath().toString(), true);
+ resource = modelSet.getResource(pluginURI, false);
+ }
+ if (resource != null) {
+
+ if (delta.getKind() == IResourceDelta.REMOVED) {
+ removedResources.add(resource);
+ } else {
+ if ((delta.getFlags() & IResourceDelta.MARKERS) != 0) {
+ // Skip markers
+ // DiagnosticDecorator.DiagnosticAdapter.update(resource, markerHelper.getMarkerDiagnostics(resource, (IFile)delta.getResource()));
+ }
+ if ((delta.getFlags() & IResourceDelta.CONTENT) != 0) {
+ // if(!savedResources.remove(resource)) {
+ // changedResources.add(resource);
+ // }
+ if (!isSaving) {
+ changedResources.add(resource);
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ return true;
+ }
+
+ public Collection<Resource> getChangedResources() {
+ return changedResources;
+ }
+
+ public Collection<Resource> getRemovedResources() {
+ return removedResources;
+ }
+ }
+
+ final ResourceDeltaVisitor visitor = new ResourceDeltaVisitor();
+
+ delta.accept(visitor);
+
+ if (!visitor.getRemovedResources().isEmpty()) {
+ handleResourcesRemoved(visitor.getRemovedResources());
+ }
+
+ if (!visitor.getChangedResources().isEmpty()) {
+ handleResourceChanged(visitor.getChangedResources());
+ }
+ } catch (CoreException exception) {
+ Activator.log.error(exception);
+ }
+ }
+ };
+
+ @Override
+ public void partActivated(IWorkbenchPart part) {
+ // Nothing
+ }
+
+ @Override
+ public void partBroughtToTop(IWorkbenchPart part) {
+ // Nothing
+ }
+
+ @Override
+ public void partClosed(IWorkbenchPart part) {
+ // Nothing
+ }
+
+ @Override
+ public void partDeactivated(IWorkbenchPart part) {
+ // Nothing
+ }
+
+ @Override
+ public void partOpened(IWorkbenchPart part) {
+ // Nothing
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/SaveLayoutBeforeClose.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/SaveLayoutBeforeClose.java
new file mode 100644
index 00000000000..0243ca859b1
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/SaveLayoutBeforeClose.java
@@ -0,0 +1,218 @@
+/*****************************************************************************
+ * Copyright (c) 2014, 2015 CEA LIST, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus - bug 434983
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.services;
+
+import java.io.IOException;
+
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialogWithToggle;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.resource.sasheditor.SashModel;
+import org.eclipse.papyrus.infra.core.services.IService;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.ui.Activator;
+import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor;
+import org.eclipse.papyrus.infra.ui.internal.commands.TogglePageLayoutStorageHandler;
+import org.eclipse.papyrus.infra.ui.internal.preferences.EditorPreferences;
+import org.eclipse.papyrus.infra.ui.internal.preferences.YesNo;
+import org.eclipse.papyrus.infra.ui.lifecycleevents.DoSaveEvent;
+import org.eclipse.papyrus.infra.ui.lifecycleevents.ILifeCycleEventsProvider;
+import org.eclipse.papyrus.infra.ui.lifecycleevents.LifeCycleEventsProvider;
+
+/**
+ * This service automatically saves the current SashModel before closing the Papyrus editor
+ *
+ * This is useful, as modifications to the SashModel do not dirty the editor
+ *
+ * The save action is not executed if the editor is dirty when it is closed (To ensure model consistency)
+ *
+ * Bug 430976: [SashEditor] Editor layout is not exactly the same when reopening the model
+ * https://bugs.eclipse.org/bugs/show_bug.cgi?id=430976
+ *
+ * @author Camille Letavernier
+ */
+public class SaveLayoutBeforeClose implements IService {
+
+ private ServicesRegistry registry;
+
+ private EditorLifecycleManager lifecycleManager;
+
+ private EditorLifecycleEventListener lifecycleListener;
+
+ @Override
+ public void init(ServicesRegistry servicesRegistry) throws ServiceException {
+ this.registry = servicesRegistry;
+ }
+
+ @Override
+ public void startService() throws ServiceException {
+ installSaveOnClose();
+ }
+
+ protected void installSaveOnClose() {
+ try {
+ lifecycleManager = registry.getService(EditorLifecycleManager.class);
+ if (lifecycleManager == null) {
+ return;
+ }
+ } catch (ServiceException ex) {
+ return;
+ }
+
+ lifecycleListener = new EditorLifecycleEventListener() {
+
+ @Override
+ public void postInit(IMultiDiagramEditor editor) {
+ // Nothing
+ }
+
+ @Override
+ public void postDisplay(IMultiDiagramEditor editor) {
+ checkSharedLayout(editor);
+ }
+
+ @Override
+ public void beforeClose(IMultiDiagramEditor editor) {
+ saveBeforeClose(editor);
+ }
+ };
+
+ lifecycleManager.addEditorLifecycleEventsListener(lifecycleListener);
+ }
+
+ public void saveBeforeClose(IMultiDiagramEditor editor) {
+ if (editor.isDirty()) {
+ return; // User explicitly quit without saving. Do nothing (And if user wants to save during exit, the sashmodel will be saved anyway)
+ }
+
+ ModelSet modelSet; // Required
+ LifeCycleEventsProvider internalLifecycleEventsProvider = null; // Optional
+
+ try {
+ modelSet = registry.getService(ModelSet.class);
+ } catch (ServiceException ex) {
+ return;
+ }
+
+ try {
+ ILifeCycleEventsProvider eventsProvider = registry.getService(ILifeCycleEventsProvider.class);
+ if (eventsProvider instanceof LifeCycleEventsProvider) {
+ internalLifecycleEventsProvider = (LifeCycleEventsProvider) eventsProvider;
+ }
+ } catch (ServiceException ex) {
+ // Ignore: the service is optional
+ }
+
+ SashModel sashModel = (SashModel) modelSet.getModel(SashModel.MODEL_ID);
+
+ try {
+ // We need to send pre- and post-save events, but we can only do that with the internal LifecycleEventsProvider
+ // The ISaveAndDirtyService can only save the whole model, but we just want to save the sash
+ DoSaveEvent event = new DoSaveEvent(registry, editor, true);
+ if (internalLifecycleEventsProvider != null) {
+ internalLifecycleEventsProvider.fireAboutToDoSaveEvent(event);
+ internalLifecycleEventsProvider.fireDoSaveEvent(event);
+ }
+ sashModel.saveModel();
+ if (internalLifecycleEventsProvider != null) {
+ internalLifecycleEventsProvider.firePostDoSaveEvent(event);
+ }
+ } catch (IOException ex) {
+ Activator.log.error(ex);
+ }
+ }
+
+ private void checkSharedLayout(IMultiDiagramEditor editor) {
+ try {
+ ModelSet modelSet = registry.getService(ModelSet.class);
+ SashModel sashModel = (SashModel) modelSet.getModel(SashModel.MODEL_ID);
+
+ if (sashModel.isLegacyMode()) {
+ // Have we ever created the private sash model file?
+ URI privateURI = sashModel.getPrivateResourceURI();
+ if (!modelSet.getURIConverter().exists(privateURI, null)) {
+ // Prompt the user
+ promptToEnablePrivateStorage(editor);
+ }
+ }
+ } catch (ServiceException ex) {
+ // Shared layout doesn't matter if there's no model-set
+ }
+ }
+
+ private void promptToEnablePrivateStorage(IMultiDiagramEditor editor) {
+ YesNo preference = EditorPreferences.getInstance().getConvertSharedPageLayoutToPrivate();
+
+ if (preference == YesNo.PROMPT) {
+ MessageDialogWithToggle dlg = MessageDialogWithToggle.openYesNoCancelQuestion(editor.getSite().getShell(),
+ Messages.SaveLayoutBeforeClose_0,
+ Messages.SaveLayoutBeforeClose_1,
+ Messages.SaveLayoutBeforeClose_2, false, null, null);
+
+ switch (dlg.getReturnCode()) {
+ case IDialogConstants.YES_ID:
+ preference = YesNo.YES;
+ break;
+ case IDialogConstants.NO_ID:
+ preference = YesNo.NO;
+ break;
+ default:
+ // User cancelled
+ preference = YesNo.PROMPT;
+ break;
+ }
+
+ if (dlg.getToggleState()) {
+ EditorPreferences.getInstance().setConvertSharedPageLayoutToPrivate(preference);
+ }
+ }
+
+ switch (preference) {
+ case YES:
+ // Change the storage to private
+ new TogglePageLayoutStorageHandler().togglePrivatePageLayout(editor);
+
+ // And save the new layout scheme
+ saveBeforeClose(editor);
+ break;
+ case NO:
+ // Just create the empty resource and save it
+ try {
+ ModelSet modelSet = editor.getServicesRegistry().getService(ModelSet.class);
+ SashModel sashModel = (SashModel) modelSet.getModel(SashModel.MODEL_ID);
+ modelSet.createResource(sashModel.getPrivateResourceURI());
+ saveBeforeClose(editor);
+ } catch (ServiceException e) {
+ // Without a model-set, much else is going wrong, so there's no need to deal
+ // with this here
+ }
+ break;
+ default:
+ // User cancelled
+ break;
+ }
+ }
+
+ @Override
+ public void disposeService() throws ServiceException {
+ registry = null;
+ if (lifecycleManager != null) {
+ lifecycleManager.removeEditorLifecycleEventsListener(lifecycleListener);
+ lifecycleListener = null;
+ lifecycleManager = null;
+ }
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/internal/EditorLifecycleManagerImpl.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/internal/EditorLifecycleManagerImpl.java
new file mode 100644
index 00000000000..b37b131962a
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/internal/EditorLifecycleManagerImpl.java
@@ -0,0 +1,128 @@
+/*****************************************************************************
+ * Copyright (c) 2013, 2015 CEA LIST, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus - bug 469188
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.services.internal;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor;
+import org.eclipse.papyrus.infra.ui.services.EditorLifecycleEventListener;
+import org.eclipse.papyrus.infra.ui.services.EditorLifecycleManager;
+
+
+public class EditorLifecycleManagerImpl implements EditorLifecycleManager, InternalEditorLifecycleManager {
+
+ private final Set<EditorLifecycleEventListener> listeners = new HashSet<EditorLifecycleEventListener>();
+
+ @Override
+ public void init(ServicesRegistry servicesRegistry) throws ServiceException {
+ // Nothing
+ }
+
+ @Override
+ public void startService() throws ServiceException {
+ // Nothing
+ }
+
+ @Override
+ public void disposeService() throws ServiceException {
+ listeners.clear();
+ }
+
+ @Override
+ public void addEditorLifecycleEventsListener(EditorLifecycleEventListener listener) {
+ listeners.add(listener);
+ }
+
+ @Override
+ public void removeEditorLifecycleEventsListener(EditorLifecycleEventListener listener) {
+ listeners.remove(listener);
+ }
+
+ @Override
+ public void firePostInit(final IMultiDiagramEditor editor) {
+ for (final EditorLifecycleEventListener listener : listeners) {
+ SafeRunner.run(new ISafeRunnable() {
+
+ @Override
+ public void run() throws Exception {
+ listener.postInit(editor);
+ }
+
+ @Override
+ public void handleException(Throwable exception) {
+ // Already logged by the SafeRunner
+ }
+ });
+ }
+ }
+
+ @Override
+ public void firePreDisplay(final IMultiDiagramEditor editor) {
+ for (final EditorLifecycleEventListener listener : listeners) {
+ SafeRunner.run(new ISafeRunnable() {
+
+ @Override
+ public void run() throws Exception {
+ listener.preDisplay(editor);
+ }
+
+ @Override
+ public void handleException(Throwable exception) {
+ // Already logged by the SafeRunner
+ }
+ });
+ }
+ }
+
+ @Override
+ public void firePostDisplay(final IMultiDiagramEditor editor) {
+ for (final EditorLifecycleEventListener listener : listeners) {
+ SafeRunner.run(new ISafeRunnable() {
+
+ @Override
+ public void run() throws Exception {
+ listener.postDisplay(editor);
+ }
+
+ @Override
+ public void handleException(Throwable exception) {
+ // Already logged by the SafeRunner
+ }
+ });
+ }
+ }
+
+ @Override
+ public void fireBeforeClose(final IMultiDiagramEditor editor) {
+ for (final EditorLifecycleEventListener listener : listeners) {
+ SafeRunner.run(new ISafeRunnable() {
+
+ @Override
+ public void run() throws Exception {
+ listener.beforeClose(editor);
+ }
+
+ @Override
+ public void handleException(Throwable exception) {
+ // Already logged by the SafeRunner
+ }
+ });
+ }
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/internal/InternalEditorLifecycleManager.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/internal/InternalEditorLifecycleManager.java
new file mode 100644
index 00000000000..301557028d9
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/internal/InternalEditorLifecycleManager.java
@@ -0,0 +1,48 @@
+/*****************************************************************************
+ * Copyright (c) 2013, 2015 CEA LIST, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus - bug 469188
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.services.internal;
+
+import org.eclipse.papyrus.infra.core.services.IService;
+import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor;
+
+
+public interface InternalEditorLifecycleManager extends IService {
+
+ /**
+ * Sends the postInit notification for this editor
+ *
+ * @param editor
+ */
+ void firePostInit(IMultiDiagramEditor editor);
+
+ /**
+ * Sets the preDisplay notification for this editor
+ *
+ * @param editor
+ */
+ void firePreDisplay(IMultiDiagramEditor editor);
+
+ /**
+ * Sends the postDisplay notification for this editor
+ *
+ * @param editor
+ */
+ void firePostDisplay(IMultiDiagramEditor editor);
+
+ /**
+ * Sends the beforeClose notification for this Editor
+ *
+ * @param editor
+ */
+ void fireBeforeClose(IMultiDiagramEditor editor);
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/messages.properties b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/messages.properties
new file mode 100644
index 00000000000..a6f77150932
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/messages.properties
@@ -0,0 +1,15 @@
+#
+# Copyright (c) 2015 Christian W. Damus and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Christian W. Damus - Initial API and implementation
+#
+
+SaveLayoutBeforeClose_0=Editor Layout Storage
+SaveLayoutBeforeClose_1=This model stores the editor page layout in the DI resource, which if managed in a source control system will share the layout with others. Convert to local (private) storage of the page layout?
+SaveLayoutBeforeClose_2=Remember my decision
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/AbstractCreateMenuFromCommandCategory.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/AbstractCreateMenuFromCommandCategory.java
new file mode 100644
index 00000000000..82ef8983d95
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/AbstractCreateMenuFromCommandCategory.java
@@ -0,0 +1,135 @@
+/*****************************************************************************
+ * Copyright (c) 2013 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.util;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.Category;
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.IHandler;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.core.expressions.EvaluationResult;
+import org.eclipse.core.expressions.Expression;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jface.action.IContributionManager;
+import org.eclipse.papyrus.infra.ui.Activator;
+import org.eclipse.swt.SWT;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.menus.CommandContributionItem;
+import org.eclipse.ui.menus.CommandContributionItemParameter;
+import org.eclipse.ui.menus.ExtensionContributionFactory;
+import org.eclipse.ui.menus.IContributionRoot;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * Abstract Class to create menu from an Eclipse Command category
+ *
+ * @author VL222926
+ *
+ */
+public abstract class AbstractCreateMenuFromCommandCategory extends ExtensionContributionFactory {
+
+ /** the category of the command contributing to this menu */
+ protected final String commandCateogyId;
+
+ /**
+ *
+ * Constructor.
+ *
+ * @param commandCategoryId
+ * the category of the command contributing to this menu
+ */
+ public AbstractCreateMenuFromCommandCategory(final String commandCategoryId) {
+ this.commandCateogyId = commandCategoryId;
+ }
+
+ /**
+ *
+ * @see org.eclipse.ui.menus.AbstractContributionFactory#createContributionItems(org.eclipse.ui.services.IServiceLocator, org.eclipse.ui.menus.IContributionRoot)
+ *
+ * @param serviceLocator
+ * @param additions
+ */
+ @Override
+ public void createContributionItems(IServiceLocator serviceLocator, IContributionRoot additions) {
+ // test to know if we can create elements if it is possible...
+ Expression visibleWhen = new Expression() {
+
+ @Override
+ public EvaluationResult evaluate(IEvaluationContext context) throws CoreException {
+ return EvaluationResult.TRUE;
+ }
+ };
+ for (final CommandContributionItem item : addCreationItems(serviceLocator, additions, null)) {
+ additions.addContributionItem(item, visibleWhen);
+ }
+ }
+
+ /**
+ *
+ * @param serviceLocator
+ * @param additions
+ * @param parent
+ * @return
+ */
+ protected List<CommandContributionItem> addCreationItems(final IServiceLocator serviceLocator, final IContributionRoot additions, IContributionManager parent) {
+ final ICommandService commandService = PlatformUI.getWorkbench().getService(ICommandService.class);
+ final List<CommandContributionItem> items = new ArrayList<CommandContributionItem>();
+ final Category category = commandService.getCategory(this.commandCateogyId);
+ final Set<Command> commands = new TreeSet<Command>();
+ commands.addAll(Arrays.asList(commandService.getDefinedCommands()));
+ for (Command command : commands) {
+ Category currentCategory = null;
+ try {
+ currentCategory = command.getCategory();
+ } catch (NotDefinedException e) {
+ Activator.log.debug(e.getLocalizedMessage());
+ continue;
+ }
+ if (command.isDefined() && category.equals(currentCategory)) {
+ final IHandler handler = command.getHandler();
+ if (handler instanceof AbstractHandler) {
+
+ // required!?!?! in some case can avoid the message for handler conflicting (ex : Allocate in SysML NatTable Allocation
+ ((AbstractHandler) handler).setEnabled(null);
+ boolean isEnabled = handler.isEnabled();
+ command.setEnabled(null);
+ ((AbstractHandler) handler).setEnabled(null);
+
+ isEnabled = handler.isEnabled();
+ try {
+ if (isEnabled) {
+ CommandContributionItemParameter p = new CommandContributionItemParameter(serviceLocator, "", command.getId(), SWT.PUSH); //$NON-NLS-1$
+ p.label = command.getDescription();
+ p.icon = EclipseCommandUtils.getCommandIcon(command);
+ CommandContributionItem item = new CommandContributionItem(p);
+ items.add(item);
+ }
+ } catch (NotDefinedException e) {
+ Activator.log.debug(e.getLocalizedMessage());
+ }
+ }
+ }
+ }
+ return items;
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/DisplayUtils.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/DisplayUtils.java
new file mode 100644
index 00000000000..0781c1d0ce7
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/DisplayUtils.java
@@ -0,0 +1,47 @@
+/*****************************************************************************
+ * Copyright (c) 2010 CEA LIST.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Remi Schnekenburger (CEA LIST) remi.schnekenburger@cea.fr - Initial API and implementation
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.util;
+
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.ui.Activator;
+
+
+/**
+ * Util class for display in Papyrus (label providers, etc...)
+ *
+ * @deprecated Use the LabelProviderService instead
+ */
+@Deprecated
+public class DisplayUtils {
+
+ /**
+ * Gets the shared label provider.
+ *
+ * @return Get the current {@link ILabelProvider} or <code>null</code> if
+ * not found
+ */
+ public static ILabelProvider getLabelProvider() {
+ try {
+ ServicesRegistry registry = EditorUtils.getServiceRegistry();
+ return registry == null ? null : registry.getService(ILabelProvider.class);
+ } catch (IllegalStateException e) {
+ // Registry can't be found, do nothing.
+ Activator.log.error(e);
+ } catch (ServiceException e) {
+ Activator.log.error(e);
+ }
+ return null;
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/EclipseCommandUtils.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/EclipseCommandUtils.java
new file mode 100644
index 00000000000..d7d462e82ca
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/EclipseCommandUtils.java
@@ -0,0 +1,137 @@
+/*****************************************************************************
+ * Copyright (c) 2013 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.util;
+
+import java.util.Collection;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.eclipse.core.commands.Category;
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.State;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.papyrus.infra.ui.Activator;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.ICommandImageService;
+import org.eclipse.ui.commands.ICommandService;
+
+/**
+ * This class provides useful methods to manipulate Eclipse Command
+ *
+ * @author vl222926
+ *
+ */
+public class EclipseCommandUtils {
+
+ private EclipseCommandUtils() {
+ // to prevent instanciation
+ }
+
+ public static final String TOGGLE_STATE = "org.eclipse.ui.commands.toggleState"; //$NON-NLS-1$
+
+ public static final String RADIO_STATE = "org.eclipse.ui.commands.radioState"; //$NON-NLS-1$
+
+ public static final String DELETE_COMMAND = "org.eclipse.ui.edit.delete"; //$NON-NLS-1$
+
+ /**
+ *
+ * @param categoryId
+ * a category id
+ * @return
+ * all commands defined for this category
+ */
+ public static final Collection<Command> getAllExistingCommandsInCategory(final String categoryId) {
+ final Set<Command> commands = new TreeSet<Command>();
+ final ICommandService commandService = PlatformUI.getWorkbench().getService(ICommandService.class);
+ final Category category = commandService.getCategory(categoryId);
+ for (final Command command : commandService.getDefinedCommands()) {
+ Category currentCategory = null;
+ try {
+ currentCategory = command.getCategory();
+ } catch (NotDefinedException e) {
+ Activator.log.debug(e.getLocalizedMessage());
+ continue;
+ }
+ if (/* command.isDefined() && */category.equals(currentCategory)) {
+ commands.add(command);
+ }
+ }
+ return commands;
+ }
+
+ /**
+ *
+ * @param command
+ * an Eclipse command
+ * @return
+ * the image descriptor associated to this command
+ */
+ public static final ImageDescriptor getCommandIcon(final Command command) {
+ final IWorkbench workbench = PlatformUI.getWorkbench();
+ final ICommandImageService service = workbench.getService(ICommandImageService.class);
+ final ImageDescriptor imageDescriptor = service.getImageDescriptor(command.getId());
+ return imageDescriptor;
+ }
+
+ /**
+ *
+ * @param command
+ * an eclipse command
+ * @param newValue
+ * the new boolean value to set to the state of this command
+ */
+ public static final void updateToggleCommandState(final org.eclipse.core.commands.Command command, final boolean newValue) {
+ if (command != null) {
+ final State state = command.getState(TOGGLE_STATE);
+ if (state != null) {
+ state.setValue(newValue);
+ }
+ }
+ }
+
+ /**
+ *
+ * @param command
+ * an eclipse command
+ * @param newValue
+ * the new value to set to the state of this command
+ */
+ public static final void updateRadioCommandState(final org.eclipse.core.commands.Command command, final Object newValue) {
+ if (command != null) {
+ final State state = command.getState(RADIO_STATE);
+ if (state != null) {
+ state.setValue(newValue);
+ }
+ }
+ }
+
+ /**
+ *
+ * @return
+ * the eclipse command service
+ */
+ public static final ICommandService getCommandService() {
+ IWorkbench wb = PlatformUI.getWorkbench();
+ if (wb != null) {
+ IWorkbenchWindow ww = wb.getActiveWorkbenchWindow();
+ if (ww != null) {
+ return ww.getService(ICommandService.class);
+ }
+ }
+ return null;
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/EditorHelper.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/EditorHelper.java
new file mode 100644
index 00000000000..be7a0d1dbaa
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/EditorHelper.java
@@ -0,0 +1,71 @@
+/*****************************************************************************
+ * Copyright (c) 2012 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vincent Lorenzo (CEA LIST) Vincent.Lorenzo@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.util;
+
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ *
+ * a helper for the Editor
+ *
+ */
+public class EditorHelper {
+
+ private EditorHelper() {
+ // nothing to do
+ }
+
+ /**
+ *
+ * @return
+ * the current editor or <code>null</code> if not found
+ */
+ public static final IEditorPart getCurrentEditor() {
+ final IWorkbench workbench = PlatformUI.getWorkbench();
+ if (workbench != null) {
+ final IWorkbenchWindow activeWorkbench = workbench.getActiveWorkbenchWindow();
+ if (activeWorkbench != null) {
+ final IWorkbenchPage activePage = activeWorkbench.getActivePage();
+ if (activePage != null) {
+ return activePage.getActiveEditor();
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ *
+ * @return
+ * the current active part or <code>null</code> if not found
+ */
+ public static final IWorkbenchPart getActivePart() {
+ final IWorkbench workbench = PlatformUI.getWorkbench();
+ if (workbench != null) {
+ final IWorkbenchWindow activeWorkbench = workbench.getActiveWorkbenchWindow();
+ if (activeWorkbench != null) {
+ final IWorkbenchPage activePage = activeWorkbench.getActivePage();
+ if (activePage != null) {
+ return activePage.getActivePart();
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/EditorUtils.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/EditorUtils.java
new file mode 100644
index 00000000000..eea097e6062
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/EditorUtils.java
@@ -0,0 +1,721 @@
+/*****************************************************************************
+ * Copyright (c) 2008, 2013 CEA LIST and others.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation
+ * <a href="mailto:thomas.szadel@atosorigin.com">Thomas Szadel</a>: Code simplification and NPE
+ * management.
+ * Christian W. Damus (CEA LIST) - API for determining URI of a resource in an editor
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.emf.common.ui.URIEditorInput;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.papyrus.infra.core.editor.BackboneException;
+import org.eclipse.papyrus.infra.core.resource.sasheditor.DiModelUtils;
+import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.ISashWindowsContentProvider;
+import org.eclipse.papyrus.infra.core.sasheditor.di.contentprovider.DiSashModelMngr;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.IPage;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.ISashWindowsContainer;
+import org.eclipse.papyrus.infra.core.sashwindows.di.service.IPageManager;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.services.ServiceNotFoundException;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.core.utils.DiResourceSet;
+import org.eclipse.papyrus.infra.ui.Activator;
+import org.eclipse.papyrus.infra.ui.editor.CoreMultiDiagramEditor;
+import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorReference;
+import org.eclipse.ui.IFileEditorInput;
+import org.eclipse.ui.IURIEditorInput;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * Set of utility methods for the CoreEditor. <br>
+ * WARNING : Some of these methods rely on
+ * PlatformUI.getWorkbench().getActiveWorkbenchWindow()getActivePage() to lookup
+ * for shared objects owned by the main editor. This doesn't work during the
+ * initialization of the main editor because the main editor is not yet
+ * registered in the Eclipse workbench. This can lead to a null or an exception,
+ * and sometime this can lead to getting the shared object of another main
+ * editor !
+ *
+ * @author cedric dumoulin
+ * @author <a href="mailto:thomas.szadel@atosorigin.com">Thomas Szadel</a>
+ */
+// FIXME throws Exception (eg: NotFoundException) instead of null
+public class EditorUtils {
+
+ /**
+ * Gets the opened multi-diagram editors.
+ *
+ * @return The opened {@link IMultiDiagramEditor} or null if an error
+ * occured.
+ */
+ public static IMultiDiagramEditor[] getMultiDiagramEditors() {
+ // Lookup ServiceRegistry
+ IWorkbenchWindow workbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ if (workbenchWindow == null) {
+ return null;
+ }
+ IWorkbenchPage page = workbenchWindow.getActivePage();
+ if (page == null) {
+ return null;
+ }
+ List<IMultiDiagramEditor> list = new ArrayList<IMultiDiagramEditor>();
+ for (IEditorReference editorRef : page.getEditorReferences()) {
+ IEditorPart editorPart = editorRef.getEditor(false);
+ if (editorPart instanceof IMultiDiagramEditor) {
+ list.add((IMultiDiagramEditor) editorPart);
+ }
+ }
+ return list.toArray(new IMultiDiagramEditor[list.size()]);
+ }
+
+ /**
+ * Returns the editors that are related to to given file.<BR>
+ *
+ * @param file
+ * The file (model, di or notation).
+ * @return The associated editors.
+ */
+ public static IMultiDiagramEditor[] getRelatedEditors(IFile file) {
+ // Get the DI file
+ IFile diFile = DiModelUtils.getRelatedDiFile(file);
+ if (diFile == null || !diFile.exists()) {
+ return new IMultiDiagramEditor[0];
+ }
+
+ IMultiDiagramEditor[] openedEditors = EditorUtils.getMultiDiagramEditors();
+ if (openedEditors == null) {
+ return new IMultiDiagramEditor[0];
+ }
+ List<IMultiDiagramEditor> list = new ArrayList<IMultiDiagramEditor>(openedEditors.length);
+
+ for (IMultiDiagramEditor editorPart : openedEditors) {
+ if (editorPart.getEditorInput() instanceof IFileEditorInput && diFile.equals(((IFileEditorInput) editorPart.getEditorInput()).getFile())) {
+ list.add(editorPart);
+ }
+ }
+ return list.toArray(new IMultiDiagramEditor[list.size()]);
+ }
+
+ /**
+ * Create an instance of IPageMngr acting on the provided resource. This
+ * instance is suitable to add, remove, close or open diagrams.
+ *
+ * @param diResource
+ * @return The non transactional implementation of IPageMngr
+ */
+ public static IPageManager getIPageMngr(Resource diResource) {
+ return DiSashModelMngr.createIPageMngr(diResource);
+ }
+
+
+ // //////////////////////////////////////////
+ // The following methods are deprecated. They have been replaced by specific
+ // implementations of ServiceUtils (e.g. ServiceUtilsForHandlers, ServiceUtilsForEObject),
+ // which depend on a specific context (ExecutionEvent, EObject, ...) instead of
+ // the active editor
+ // //////////////////////////////////////////
+
+ /**
+ * Gets the {@link IMultiDiagramEditor} interface of the a Eclipse active
+ * editor, if possible, or null if not possible. <br>
+ * WARNING - This method doesn't work during the initialization of the main
+ * editor. See note in class doc. <br>
+ * This method return null if there is no active editor, or if the editor is
+ * not instance of IMultiDiagramEditor. <br>
+ * This method is designed to be used by ui actions that interact with the
+ * active editor. <br>
+ * This method should not be used during the editor initialization phase. <br>
+ * In any case, a check should be done on the returned value that can be
+ * null. Usage of this method is discouraged. Use {@link #getMultiDiagramEditorChecked()} instead.
+ *
+ *
+ * @return Get the current {@link IMultiDiagramEditor} or null if not found.
+ */
+ public static IMultiDiagramEditor getMultiDiagramEditor() {
+ // Lookup ServiceRegistry
+ IWorkbenchWindow workbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ if (workbenchWindow == null) {
+ return null;
+ }
+ IWorkbenchPage page = workbenchWindow.getActivePage();
+ if (page == null) {
+ return null;
+ }
+ IEditorPart editor = page.getActiveEditor();
+ if (editor instanceof IMultiDiagramEditor) {
+ return (IMultiDiagramEditor) editor;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Lookup the currently active Diagram from the Papyrus editor. Return the
+ * current Diagram or null if none is active. <br>
+ * WARNING - This method doesn't work during the initialization of the main
+ * editor. See note in class doc. <br>
+ * This method return null if the ServicesRegistry can not be found. <br>
+ * TODO This method introduce dependency on GMF. It can be moved to a GMF
+ * plugin.
+ *
+ * @return The active diagram or null if not found.
+ *
+ * @deprecated The core do make suppositions about the type of nested
+ * Editors, GMF stuff should be moved in GMF projects. In many
+ * case, {@link #lookupActiveNestedIEditor()} can be used.
+ */
+ // @Deprecated
+ // public static Diagram lookupEditorActiveDiagram() {
+ // DiagramEditor diagEditor = lookupActiveDiagramEditor();
+ // return diagEditor == null ? null : diagEditor.getDiagram();
+ // }
+
+ /**
+ * Lookup the currently active Diagram from the Papyrus editor. Return the
+ * current Diagram or null if none is active. <br>
+ * WARNING - This method doesn't work during the initialization of the main
+ * editor. See note in class doc. <br>
+ * This method return null if the ServicesRegistry can not be found. <br>
+ * TODO This method introduce dependency on GMF. It can be moved to a GMF
+ * plugin.
+ *
+ * @return the active diagram editor or null if not found.
+ *
+ * @deprecated The core do make suppositions about the type of nested
+ * Editors, GMF stuff should be moved in GMF projects. In many
+ * case, {@link #lookupActiveNestedIEditor()} can be used.
+ */
+ // @Deprecated
+ // public static DiagramEditor lookupActiveDiagramEditor() {
+ // // Get the active page within the sashcontainer
+ // IEditorPart activeEditor = lookupActiveNestedIEditor();
+ // // Check if it is a GMF DiagramEditor
+ // if(activeEditor instanceof DiagramEditor) {
+ // return ((DiagramEditor)activeEditor);
+ // } else {
+ // // Not found
+ // return null;
+ // }
+ //
+ // }
+
+ /**
+ * Lookup the currently active {@link IEditorPart} from the Papyrus editor.
+ * Return the current nested editor part, or null if it can not be found. <br>
+ * WARNING - This method doesn't work during the initialization of the main
+ * editor. See note in class doc. <br>
+ * This method return null if the ServicesRegistry can not be found. <br>
+ * This method is designed to be used by ui actions that interact with the
+ * active editor. <br>
+ * This method should not be used during the editor initialization phase. <br>
+ * In any case, a check should be done on the returned value that can be
+ * null. An alternative is to use
+ * serviceRegistry.getService(ISashWindowsContainer
+ * .class).getActiveEditor(); <br>
+ * It is preferable to retrieve the ServiceRegistry from elsewhere whenever
+ * it is possible. <br>
+ *
+ *
+ * @return
+ * @deprecated Check
+ * modeling/org.eclipse.mdt.papyrus/trunk/doc/DevelopperDocuments
+ * /cookbook/PapyrusCookBook.odt and use one of the replacement:
+ * <ul>
+ * <li>org.eclipse.papyrus.infra.core.utils.ServiceUtils</li>
+ * <li>
+ * org.eclipse.papyrus.uml.diagram.common.util.ServiceUtilsForGMF</li>
+ * <li>
+ * org.eclipse.papyrus.infra.core.utils.ServiceUtilsForActionHandlers (to be used with care !)</li>
+ * </ul>
+ */
+ @Deprecated
+ public static IEditorPart lookupActiveNestedIEditor() {
+ // Get the sashwindow container
+ ISashWindowsContainer container = getSashWindowContainer();
+ // Get the active page within the sashcontainer
+ return container == null ? null : container.getActiveEditor();
+ }
+
+ /**
+ * Lookup the currently active IEditor in the SashSystem. If the currently
+ * eclipse active editor doesn't contains a {@link ISashWindowsContainer},
+ * return null. If the current SashSystem page is not a IEditor, return
+ * null. <br>
+ * WARNING - This method doesn't work during the initialization of the main
+ * editor. See note in class doc. <br>
+ * This method return null if the ServicesRegistry can not be found. <br>
+ * This method is designed to be used by ui actions that interact with the
+ * active editor. <br>
+ * This method should not be used during the editor initialization phase. <br>
+ * In any case, a check should be done on the returned value that can be
+ * null. An alternative is to use
+ * serviceRegistry.getService(ISashWindowsContainer
+ * .class).getActiveSashWindowsPage(); <br>
+ * It is preferable to retrieve the ServiceRegistry from elsewhere whenever
+ * it is possible.
+ *
+ * @return
+ * @deprecated Check
+ * modeling/org.eclipse.mdt.papyrus/trunk/doc/DevelopperDocuments
+ * /cookbook/PapyrusCookBook.odt and use one of the replacement:
+ * <ul>
+ * <li>org.eclipse.papyrus.infra.core.utils.ServiceUtils</li>
+ * <li>
+ * org.eclipse.papyrus.uml.diagram.common.util.ServiceUtilsForGMF</li>
+ * <li>
+ * org.eclipse.papyrus.infra.core.utils.ServiceUtilsForActionHandlers (to be used with care !)</li>
+ * </ul>
+ */
+ @Deprecated
+ public static IPage lookupActiveNestedPage() {
+
+ // Get the sashwindow container
+ ISashWindowsContainer container = getSashWindowContainer();
+ // Get the active page within the sashcontainer
+ return container == null ? null : container.getActiveSashWindowsPage();
+ }
+
+ /**
+ *
+ * @return
+ */
+ private static ISashWindowsContainer getSashWindowContainer() {
+
+ try {
+ return getServiceRegistryChecked().getService(ISashWindowsContainer.class);
+ } catch (ServiceException e) {
+ // The contract says that we return null if not found
+ return null;
+ }
+ }
+
+ /**
+ * Gets the di resource set.
+ *
+ * @return Get the current {@link DiResourceSet} or null if not found.
+ * @deprecated Check
+ * modeling/org.eclipse.mdt.papyrus/trunk/doc/DevelopperDocuments
+ * /cookbook/PapyrusCookBook.odt and use one of the replacement:
+ * <ul>
+ * <li>org.eclipse.papyrus.infra.core.utils.ServiceUtils</li>
+ * <li>
+ * org.eclipse.papyrus.uml.diagram.common.util.ServiceUtilsForGMF</li>
+ * <li>
+ * org.eclipse.papyrus.infra.core.utils.ServiceUtilsForActionHandlers (to be used with care !)</li>
+ * </ul>
+ */
+ @Deprecated
+ public static DiResourceSet getDiResourceSet() {
+ try {
+ ServicesRegistry registry = getServiceRegistry();
+ return registry == null ? null : registry.getService(DiResourceSet.class);
+ } catch (ServiceException e) {
+ Activator.log.error(e);
+ }
+ return null;
+ }
+
+ /**
+ * Gets the {@link TransactionalEditingDomain} of the current active Eclipse
+ * Editor. This method should be used only when it is sure that the active
+ * editor exist, and that you want the EditingDomain of this editor. <br>
+ * This method return null if the TransactionalEditingDomain can not be
+ * found. <br>
+ * This method is designed to be used by ui actions that interact with the
+ * active editor. <br>
+ * This method should not be used during the editor initialization phase. <br>
+ * In any case, a check should be done on the returned value that can be
+ * null. An alternative is to use {@link #getTransactionalEditingDomainChecked()} and to catch the
+ * exception. <br>
+ * It is preferable to use {@link #getTransactionalEditingDomain(ServicesRegistry)} whenever it is
+ * possible. <br>
+ * In GMF EditParts or EditPolicies, the ServiceRegistry can be retrieved
+ * with methods from
+ * org.eclipse.papyrus.uml.diagram.common.util.DiagramCoreServiceUtils <br>
+ * WARNING: This method can return null if there is no Active Editor. This
+ * happen during the editor initialization, especially when there is no
+ * other editor opened.
+ *
+ * @return Get the current {@link TransactionalEditingDomain} or null if not
+ * found
+ * @deprecated Check
+ * modeling/org.eclipse.mdt.papyrus/trunk/doc/DevelopperDocuments
+ * /cookbook/PapyrusCookBook.odt and use one of the replacement:
+ * <ul>
+ * <li>org.eclipse.papyrus.infra.core.utils.ServiceUtils</li>
+ * <li>
+ * org.eclipse.papyrus.uml.diagram.common.util.ServiceUtilsForGMF</li>
+ * <li>
+ * org.eclipse.papyrus.infra.core.utils.ServiceUtilsForActionHandlers (to be used with care !)</li>
+ * </ul>
+ */
+ @Deprecated
+ public static TransactionalEditingDomain getTransactionalEditingDomain() {
+ try {
+ ServicesRegistry registry = getServiceRegistry();
+ return registry == null ? null : registry.getService(TransactionalEditingDomain.class);
+ } catch (IllegalStateException e) {
+ // Registry can't be found, do nothing.
+ } catch (ServiceException e) {
+ Activator.log.error(e);
+ }
+ return null;
+ }
+
+ /**
+ * Gets the {@link TransactionalEditingDomain} of the current active Eclipse
+ * Editor. This method should be used only when it is sure that the active
+ * editor exist, and that you want the EditingDomain of this editor. <br>
+ * This method is designed to be used by ui actions that interact with the
+ * active editor. <br>
+ * This method should not be used during the editor initialization phase. <br>
+ * It is preferable to use {@link #getTransactionalEditingDomain(ServicesRegistry)} whenever it is
+ * possible. <br>
+ * This method throw a {@link ServiceException} if the
+ * TransactionalEditingDomain can not be found. <br>
+ * In GMF EditParts or EditPolicies, the ServiceRegistry can be retrieved
+ * with methods from
+ * org.eclipse.papyrus.uml.diagram.common.util.DiagramCoreServiceUtils
+ *
+ *
+ * WARNING: This method throws an exception when no Active Editor is found.
+ * This happen during the editor initialization, especially when there is no
+ * other editor opened.
+ *
+ * @return Get the current {@link TransactionalEditingDomain}
+ * @throws ServiceException
+ * @throws ServiceNotFoundException
+ * @deprecated Check
+ * modeling/org.eclipse.mdt.papyrus/trunk/doc/DevelopperDocuments
+ * /cookbook/PapyrusCookBook.odt and use one of the replacement:
+ * <ul>
+ * <li>org.eclipse.papyrus.infra.core.utils.ServiceUtils</li>
+ * <li>
+ * org.eclipse.papyrus.uml.diagram.common.util.ServiceUtilsForGMF</li>
+ * <li>
+ * org.eclipse.papyrus.infra.core.utils.ServiceUtilsForActionHandlers (to be used with care !)</li>
+ * </ul>
+ */
+ @Deprecated
+ public static TransactionalEditingDomain getTransactionalEditingDomainChecked() throws ServiceException {
+ try {
+ ServicesRegistry registry = getServiceRegistryChecked();
+ return registry.getService(TransactionalEditingDomain.class);
+ } catch (IllegalStateException e) {
+ throw new ServiceException(e);
+ } catch (Exception e) {
+ throw new ServiceException(e);
+ }
+ }
+
+ /**
+ * Gets the {@link TransactionalEditingDomain} registered in the {@link ServicesRegistry}.
+ *
+ * @param servicesRegistry
+ * @return
+ * @deprecated Check
+ * modeling/org.eclipse.mdt.papyrus/trunk/doc/DevelopperDocuments
+ * /cookbook/PapyrusCookBook.odt and use one of the replacement:
+ * <ul>
+ * <li>org.eclipse.papyrus.infra.core.utils.ServiceUtils</li>
+ * </ul>
+ */
+ @Deprecated
+ public static TransactionalEditingDomain getTransactionalEditingDomain(ServicesRegistry registry) {
+ try {
+ return registry.getService(TransactionalEditingDomain.class);
+ } catch (IllegalStateException e) {
+ // Registry can't be found, do nothing.
+ } catch (ServiceException e) {
+ Activator.log.error(e);
+ }
+ return null;
+ }
+
+ /**
+ * Gets the {@link TransactionalEditingDomain} registered in the {@link ServicesRegistry}.
+ *
+ * @param servicesRegistry
+ * @return
+ * @throws ServiceException
+ * If the TransactionalEditingDomain can not be found.
+ * @deprecated Check
+ * modeling/org.eclipse.mdt.papyrus/trunk/doc/DevelopperDocuments
+ * /cookbook/PapyrusCookBook.odt and use one of the replacement:
+ * <ul>
+ * <li>org.eclipse.papyrus.infra.core.utils.ServiceUtils</li>
+ * </ul>
+ */
+ @Deprecated
+ public static TransactionalEditingDomain getTransactionalEditingDomainChecked(ServicesRegistry registry) throws ServiceException {
+ return registry.getService(TransactionalEditingDomain.class);
+ }
+
+ /**
+ * Get the {@link ServicesRegistry}of the currently active eclipse editor. <br>
+ * WARNING - This method doesn't work during the initialization of the main
+ * editor. See note in class doc. <br>
+ * This method return null if the ServicesRegistry can not be found. <br>
+ * This method is designed to be used by ui actions that interact with the
+ * active editor. <br>
+ * This method should not be used during the editor initialization phase. <br>
+ * In any case, a check should be done on the returned value that can be
+ * null. An alternative is to use {@link #getServiceRegistryChecked()} and
+ * to catch the exception. <br>
+ * It is preferable to retrieve the ServiceRegistry from elsewhere whenever
+ * it is possible. <br>
+ * In GMF EditParts or EditPolicies, the ServiceRegistry can be retrieved
+ * with methods from
+ * org.eclipse.papyrus.uml.diagram.common.util.ServiceUtilsForGMF
+ *
+ * <br>
+ * WARNING: This method can return null if there is no Active Editor. This
+ * happen during the editor initialization, especially when there is no
+ * other editor opened.
+ *
+ * @return The {@link ServicesRegistry} or null if not found.
+ * @deprecated Check
+ * modeling/org.eclipse.mdt.papyrus/trunk/doc/DevelopperDocuments
+ * /cookbook/PapyrusCookBook.odt and use one of the replacement:
+ * <ul>
+ * <li>org.eclipse.papyrus.infra.core.utils.ServiceUtils</li>
+ * <li>
+ * org.eclipse.papyrus.uml.diagram.common.util.ServiceUtilsForGMF</li>
+ * <li>
+ * org.eclipse.papyrus.infra.core.utils.ServiceUtilsForActionHandlers (to be used with care !)</li>
+ * </ul>
+ */
+ @Deprecated
+ static public ServicesRegistry getServiceRegistry() {
+ // Lookup ServiceRegistry
+ IMultiDiagramEditor editor = getMultiDiagramEditor();
+ return editor == null ? null : (ServicesRegistry) editor.getAdapter(ServicesRegistry.class);
+ }
+
+ /**
+ * Get the service registry of the currently active main editor. <br>
+ * WARNING - This method doesn't work during the initialization of the main
+ * editor. See note in class doc.
+ *
+ * @return The {@link ServicesRegistry} or null if not found.
+ * @throws ServiceException
+ * If an error occurs.
+ * @deprecated Check
+ * modeling/org.eclipse.mdt.papyrus/trunk/doc/DevelopperDocuments
+ * /cookbook/PapyrusCookBook.odt and use one of the replacement:
+ * <ul>
+ * <li>org.eclipse.papyrus.infra.core.utils.ServiceUtils</li>
+ * <li>
+ * org.eclipse.papyrus.uml.diagram.common.util.ServiceUtilsForGMF</li>
+ * <li>
+ * org.eclipse.papyrus.infra.core.utils.ServiceUtilsForActionHandlers (to be used with care !)</li>
+ * </ul>
+ */
+ @Deprecated
+ static public ServicesRegistry getServiceRegistryChecked() throws ServiceException {
+ // Lookup ServiceRegistry
+ IMultiDiagramEditor editor = getMultiDiagramEditor();
+ if (editor == null) {
+ throw new ServiceException("Can't get ServiceRegistry"); //$NON-NLS-1$
+ }
+
+ return editor.getAdapter(ServicesRegistry.class);
+ }
+
+ /**
+ * Get the ISashWindowsContentProvider of the active Eclipse Editor, if
+ * possible. <br>
+ * This method return null if the ServiceRegistry can not be found or if an
+ * error occur. <br>
+ * This method is designed to be used by ui actions that interact with the
+ * active editor. <br>
+ * This method should not be used during the editor initialization phase. <br>
+ * In any case, a check should be done on the returned value that can be
+ * null. <br>
+ *
+ * @return the ISashWindowsContentProvider from the main editor or null if
+ * not found.
+ * @deprecated Check
+ * modeling/org.eclipse.mdt.papyrus/trunk/doc/DevelopperDocuments
+ * /cookbook/PapyrusCookBook.odt and use one of the replacement:
+ * <ul>
+ * <li>org.eclipse.papyrus.infra.core.utils.ServiceUtils</li>
+ * <li>
+ * org.eclipse.papyrus.uml.diagram.common.util.ServiceUtilsForGMF</li>
+ * <li>
+ * org.eclipse.papyrus.infra.core.utils.ServiceUtilsForActionHandlers (to be used with care !)</li>
+ * </ul>
+ */
+ @Deprecated
+ static public ISashWindowsContentProvider getISashWindowsContentProvider() {
+
+ try {
+ return getServiceRegistryChecked().getService(ISashWindowsContentProvider.class);
+ } catch (ServiceException e) {
+ // The contract says that we return null if not found
+ return null;
+ }
+ }
+
+ /**
+ * Get the ISashWindowsContentProvider of the active Eclipse Editor, if
+ * possible. <br>
+ * This method return null if the ServiceRegistry can not be found or if an
+ * error occur. <br>
+ * This method is designed to be used by ui actions that interact with the
+ * active editor. <br>
+ * This method should not be used during the editor initialization phase. <br>
+ * In any case, a check should be done on the returned value that can be
+ * null.
+ *
+ * @return the ISashWindowsContentProvider from the main editor or null if
+ * not found.
+ * @deprecated Check
+ * modeling/org.eclipse.mdt.papyrus/trunk/doc/DevelopperDocuments
+ * /cookbook/PapyrusCookBook.odt and use one of the replacement:
+ * <ul>
+ * <li>org.eclipse.papyrus.infra.core.utils.ServiceUtils</li>
+ * <li>
+ * org.eclipse.papyrus.uml.diagram.common.util.ServiceUtilsForGMF</li>
+ * <li>
+ * org.eclipse.papyrus.infra.core.utils.ServiceUtilsForActionHandlers (to be used with care !)</li>
+ * </ul>
+ */
+ @Deprecated
+ public static IPageManager getIPageMngr() {
+
+ try {
+ return getServiceRegistryChecked().getService(IPageManager.class);
+ } catch (ServiceException e) {
+ // The contract says that we return null if not found
+ return null;
+ }
+ }
+
+ /**
+ * Get the Eclipse ActiveEditor.
+ *
+ * @return The active {@link CoreMultiDiagramEditor} or null if not found.
+ * @deprecated Use {@link EditorUtils#getMultiDiagramEditor()}
+ */
+ @Deprecated
+ protected static IEditorPart getWorkbenchActiveEditor() {
+ IMultiDiagramEditor editorPart = getMultiDiagramEditor();
+ if (editorPart instanceof CoreMultiDiagramEditor) {
+ return editorPart;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the {@link IMultiDiagramEditor} interface of the a Eclipse active
+ * editor, if possible, or throw an exception if not possible. <br>
+ * WARNING - This method throw an exception during the initialization of the
+ * main editor. This method throws an exception if there is no active
+ * editor, or if the editor is not instance of IMultiDiagramEditor. <br>
+ * This method is designed to be used by ui actions that interact with the
+ * active editor. <br>
+ *
+ *
+ * @return Get the current {@link IMultiDiagramEditor} or null if not found.
+ * @throws BackboneException
+ * If it is not possible to get an instanceof {@link IMultiDiagramEditor}
+ */
+ public static IMultiDiagramEditor getMultiDiagramEditorChecked() throws BackboneException {
+ IEditorPart editor;
+ try {
+ editor = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor();
+ } catch (NullPointerException e) {
+ // Can't get the active editor
+ throw new BackboneException("Can't get the current Eclipse Active Editor: There is no active editor at this time."); //$NON-NLS-1$
+ }
+
+ if (editor instanceof IMultiDiagramEditor) {
+ return (IMultiDiagramEditor) editor;
+ } else {
+ throw new BackboneException("Can't get an Active Editor instance of IMultiDiagramEditor. (actual type:" + editor.getClass().getName() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ /**
+ * Obtains the URI of the EMF resource identified by the given editor reference.
+ *
+ * @param editorRef
+ * an editor reference
+ *
+ * @return the best-effort URI of the resource that it edits, or {@code null} if it could not be determined,
+ * including the case when the editor input could not be obtained from the reference
+ */
+ public static URI getResourceURI(IEditorReference editorRef) {
+ try {
+ return getResourceURI(editorRef.getEditorInput());
+ } catch (PartInitException e) {
+ Activator.log.error("Could not obtain editor input from editor reference.", e); //$NON-NLS-1$
+ return null;
+ }
+ }
+
+ /**
+ * Obtains the URI of the EMF resource edited by the given {@code editor}.
+ *
+ * @param editor
+ * an open editor
+ *
+ * @return the best-effort URI of the resource that it edits, or {@code null} if it could not be determined,
+ * such as if the editor input could not be obtained from the editor
+ */
+ public static URI getResourceURI(IEditorPart editor) {
+ return getResourceURI(editor.getEditorInput());
+ }
+
+ /**
+ * Obtains the URI of the EMF resource identified by the given editor input.
+ *
+ * @param editorInput
+ * an editor input
+ *
+ * @return the best-effort URI of the resource that it edits, or {@code null} if it could not be determined
+ */
+ public static URI getResourceURI(IEditorInput editorInput) {
+ URI result = null;
+
+ if (editorInput instanceof IFileEditorInput) {
+ result = URI.createPlatformResourceURI(((IFileEditorInput) editorInput).getFile().getFullPath().toString(), true);
+ } else if (editorInput instanceof URIEditorInput) {
+ result = ((URIEditorInput) editorInput).getURI();
+ } else if (editorInput instanceof IURIEditorInput) {
+ result = URI.createURI(((IURIEditorInput) editorInput).getURI().toASCIIString(), true);
+ } else if (editorInput != null) {
+ // desperation
+ Object adapter = editorInput.getAdapter(URI.class);
+ if (adapter instanceof URI) {
+ result = (URI) adapter;
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ICallableWithProgress.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ICallableWithProgress.java
new file mode 100644
index 00000000000..bfcafbe8284
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ICallableWithProgress.java
@@ -0,0 +1,45 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.ui.util;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.concurrent.Callable;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.operation.IRunnableContext;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+
+/**
+ * The {@link Callable} analogue of an {@link IRunnableWithProgress}.
+ */
+public interface ICallableWithProgress<V> {
+ /**
+ * Invokes me in a runnable context with a progress monitor.
+ *
+ * @param monitor
+ * the progress monitor to use to display progress and receive
+ * requests for cancellation
+ * @exception InvocationTargetException
+ * if the run method must propagate a checked exception,
+ * it should wrap it inside an <code>InvocationTargetException</code>; runtime exceptions are automatically
+ * wrapped in an <code>InvocationTargetException</code> by the calling context
+ * @exception InterruptedException
+ * if the operation detects a request to cancel,
+ * using <code>IProgressMonitor.isCanceled()</code>, it should exit by throwing <code>InterruptedException</code>
+ *
+ * @see UIUtil#call(IRunnableContext, ICallableWithProgress)
+ * @see IRunnableContext#run
+ */
+ V call(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException;
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/LocalMemento.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/LocalMemento.java
new file mode 100644
index 00000000000..309542ee425
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/LocalMemento.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2014 CEA and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.infra.ui.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.ui.IMemento;
+
+
+/**
+ * Invocation handler for the dynamic local memento implementation.
+ */
+class LocalMemento implements InvocationHandler {
+
+ private static final Class<?>[] INTERFACES = { IMemento.class };
+
+ private static final Map<Method, Method> delegates = createDelegates();
+
+ private final String type;
+
+ private final String id;
+
+ private final List<IMemento> children = new ArrayList<IMemento>();
+
+ private final Map<String, Object> attributes = new HashMap<String, Object>();
+
+ private String textData;
+
+ LocalMemento(String type, String id) {
+ super();
+
+ this.type = type;
+ this.id = id;
+ }
+
+ static IMemento createMemento(String type, String id) {
+ LocalMemento handler = new LocalMemento(type, id);
+ return (IMemento) Proxy.newProxyInstance(LocalMemento.class.getClassLoader(), INTERFACES, handler);
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ Object result = null;
+
+ Method implementation = delegates.get(method);
+ if (implementation == null) {
+ throw new UnsupportedOperationException("dynamic proxy handler does not understand " + method.getName()); //$NON-NLS-1$
+ } else {
+ result = implementation.invoke(this, args);
+ }
+
+ return result;
+ }
+
+ @API
+ String getType() {
+ return type;
+ }
+
+ @API
+ String getID() {
+ return id;
+ }
+
+ @API
+ IMemento createChild(String type) {
+ return createChild(type, null);
+ }
+
+ @API
+ IMemento createChild(String type, String id) {
+ IMemento result = createMemento(type, id);
+ children.add(result);
+ return result;
+ }
+
+ @API
+ IMemento getChild(String type) {
+ IMemento result = null;
+ for (IMemento next : children) {
+ if (type.equals(next.getType())) {
+ result = next;
+ break;
+ }
+ }
+ return result;
+ }
+
+ @API
+ IMemento[] getChildren() {
+ return children.toArray(new IMemento[children.size()]);
+ }
+
+ @API
+ IMemento[] getChildren(String type) {
+ List<IMemento> result = new ArrayList<IMemento>(children.size());
+ for (IMemento next : children) {
+ if (type.equals(next.getType())) {
+ result.add(next);
+ }
+ }
+ return result.toArray(new IMemento[result.size()]);
+ }
+
+ @API
+ Float getFloat(String key) {
+ return coerce(attributes.get(key), Float.class);
+ }
+
+ private <T> T coerce(Object value, Class<T> type) {
+ Object result;
+
+ if (value == null) {
+ result = value;
+ } else if (type.isInstance(value)) {
+ result = value;
+ } else if (Number.class.isAssignableFrom(type) && (value instanceof Number)) {
+ Number number = (Number) value;
+ if (type == Integer.class) {
+ result = number.intValue();
+ } else if (type == Float.class) {
+ result = number.floatValue();
+ } else {
+ throw new IllegalArgumentException("unsupported numeric type: " + type.getSimpleName()); //$NON-NLS-1$
+ }
+ } else if (Number.class.isAssignableFrom(type) && (value instanceof String)) {
+ String string = (String) value;
+ if (type == Integer.class) {
+ result = Integer.valueOf(string);
+ } else if (type == Float.class) {
+ result = Float.valueOf(string);
+ } else {
+ throw new IllegalArgumentException("unsupported numeric type: " + type.getSimpleName()); //$NON-NLS-1$
+ }
+ } else if (type == Boolean.class) {
+ // We know the value isn't a Boolean, otherwise we would have handled it already
+ if (value instanceof String) {
+ result = Boolean.valueOf((String) value);
+ } else {
+ throw new IllegalArgumentException("unsupported boolean conversion from type: " + ((value == null) ? "null" : value.getClass().getSimpleName())); //$NON-NLS-1$
+ }
+ } else if (type == String.class) {
+ result = String.valueOf(value);
+ } else {
+ throw new IllegalArgumentException("unsupported attribute type: " + type.getSimpleName()); //$NON-NLS-1$
+ }
+
+ return type.cast(result);
+ }
+
+ @API
+ Integer getInteger(String key) {
+ return coerce(attributes.get(key), Integer.class);
+ }
+
+ @API
+ String getString(String key) {
+ return coerce(attributes.get(key), String.class);
+ }
+
+ @API
+ Boolean getBoolean(String key) {
+ return coerce(attributes.get(key), Boolean.class);
+ }
+
+ @API
+ String getTextData() {
+ return textData;
+ }
+
+ @API
+ String[] getAttributeKeys() {
+ return attributes.keySet().toArray(new String[attributes.size()]);
+ }
+
+ @API
+ void putFloat(String key, float value) {
+ attributes.put(key, value);
+ }
+
+ @API
+ void putInteger(String key, int value) {
+ attributes.put(key, value);
+ }
+
+ @API
+ void putString(String key, String value) {
+ attributes.put(key, value);
+ }
+
+ @API
+ void putBoolean(String key, boolean value) {
+ attributes.put(key, value);
+ }
+
+ @API
+ void putTextData(String data) {
+ textData = data;
+ }
+
+ private boolean isLocalMemento(IMemento memento) {
+ return (memento != null) && Proxy.isProxyClass(memento.getClass()) && ((Proxy.getInvocationHandler(memento) instanceof LocalMemento));
+ }
+
+ @API
+ void putMemento(IMemento memento) {
+ if (!isLocalMemento(memento)) {
+ throw new IllegalArgumentException("memento is not a local memento"); //$NON-NLS-1$
+ }
+ children.add(memento);
+ }
+
+ @Override
+ @API(owner = Object.class)
+ public String toString() {
+ StringBuilder result = new StringBuilder();
+
+ append(result, 0);
+
+ return result.toString();
+ }
+
+ private void append(StringBuilder buf, int depth) {
+ // Indent
+ for (int i = 0; i < depth; i++) {
+ buf.append(" "); //$NON-NLS-1$
+ }
+
+ buf.append("LocalMemento(");//$NON-NLS-1$
+ buf.append(type);
+ if (id != null) {
+ buf.append('[').append(id).append(']');
+ }
+ buf.append(") ").append(attributes); //$NON-NLS-1$
+ buf.append('\n');
+
+ final int nextDepth = depth + 1;
+ for (IMemento next : children) {
+ ((LocalMemento) Proxy.getInvocationHandler(next)).append(buf, nextDepth);
+ }
+ }
+
+ private static Map<Method, Method> createDelegates() {
+ Map<Method, Method> result = new HashMap<Method, Method>();
+
+ for (Method implementation : LocalMemento.class.getDeclaredMethods()) {
+ if (implementation.isAnnotationPresent(API.class)) {
+ try {
+ Method api = implementation.getAnnotation(API.class).owner().getMethod(implementation.getName(), implementation.getParameterTypes());
+ result.put(api, implementation);
+ } catch (NoSuchMethodException e) {
+ throw new LinkageError("Incompatible IMemento API change: " + implementation.getName());
+ }
+ }
+ }
+
+ return result;
+ }
+
+ @Target(ElementType.METHOD)
+ @Retention(RetentionPolicy.RUNTIME)
+ private @interface API {
+
+ Class<?> owner() default IMemento.class;
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/PapyrusImageUtils.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/PapyrusImageUtils.java
new file mode 100644
index 00000000000..ee0d9fb314f
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/PapyrusImageUtils.java
@@ -0,0 +1,67 @@
+/*****************************************************************************
+ * Copyright (c) 2010 CEA LIST.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Tristan Faure (ATOS ORIGIN INTEGRATION) tristan.faure@atosorigin.com - Initial API and implementation
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.util;
+
+import java.io.IOException;
+import java.net.URL;
+
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.papyrus.infra.ui.Activator;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * Services to access to Papyrus images
+ *
+ * @author tristan faure
+ *
+ */
+public class PapyrusImageUtils {
+
+ private static final String default_icon_32 = "/icons/papyrus/32x32/Papyrus_32x32_t.gif"; //$NON-NLS-1$
+
+ private static final String default_icon = "/icons/papyrus/Papyrus.gif"; //$NON-NLS-1$
+
+ /**
+ * get the default icon for Papyrus the image does not have to be disposed
+ * as it is registered in an ImageRegistry
+ *
+ * @return the Image
+ */
+ public static Image getDefaultIcon() {
+ return getIcon(default_icon);
+ }
+
+ /**
+ * get the default icon 32x32 for Papyrus the image does not have to be
+ * disposed as it is registered in an ImageRegistry
+ *
+ * @return the Image
+ */
+ public static Image getDefaultIcon32() {
+ return getIcon(default_icon_32);
+ }
+
+ private static Image getIcon(String path) {
+ String key = Activator.PLUGIN_ID + path;
+ Image result = JFaceResources.getImageRegistry().get(key);
+ if (result == null) {
+ URL url = Activator.getDefault().getBundle().getEntry(path);
+ try {
+ result = new Image(Display.getDefault(), url.openStream());
+ JFaceResources.getImageRegistry().put(key, result);
+ } catch (IOException e) {
+ }
+ }
+ return result;
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/SelectionHelper.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/SelectionHelper.java
new file mode 100644
index 00000000000..c642bc534fe
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/SelectionHelper.java
@@ -0,0 +1,119 @@
+/*****************************************************************************
+ * Copyright (c) 2014 CEA LIST and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * CEA LIST - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.ui.util;
+
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.ui.ISelectionService;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * @author VL222926
+ *
+ */
+public class SelectionHelper {
+
+ /**
+ * Constructor.
+ *
+ */
+ private SelectionHelper() {
+ // to avoid instanciation
+ }
+
+ /**
+ *
+ * @return
+ * the selection service or <code>null</code> if not found
+ *
+ */
+ public static final ISelectionService getSelectionService() {
+ IWorkbench wb = PlatformUI.getWorkbench();
+ if (wb != null) {
+ // don't work
+ // ISelectionService s1 = (ISelectionService) wb.getService(ISelectionService.class);
+ IWorkbenchWindow ww = wb.getActiveWorkbenchWindow();
+ if (ww != null) {
+ return (ISelectionService) ww.getService(ISelectionService.class);
+ }
+ }
+ return null;
+ }
+
+ /**
+ *
+ * @return
+ * the current selection or an empty selection. can't be <code>null</code>
+ */
+ public static final ISelection getCurrentSelection() {
+ ISelectionService selectionService = getSelectionService();
+ if (selectionService != null) {
+ ISelection currentSelection = selectionService.getSelection();
+ if (currentSelection != null) {
+ return currentSelection;
+ }
+ }
+ return StructuredSelection.EMPTY;
+ }
+
+ /**
+ *
+ * @param viewId
+ * the id of the view for which we want the selection
+ * @return
+ * the current selection for the view, the returned value can't be <code>null</code>
+ */
+ public static final ISelection getCurrentSelection(String viewId) {
+ ISelectionService selectionService = getSelectionService();
+ if (selectionService != null) {
+ ISelection currentSelection = selectionService.getSelection(viewId);
+ if (currentSelection != null) {
+ return currentSelection;
+ }
+ }
+ return StructuredSelection.EMPTY;
+ }
+
+ /**
+ *
+ * @return
+ * a structured selection.
+ * the returned value can't be <code>null</code>
+ */
+ public static final IStructuredSelection getCurrentStructuredSelection() {
+ ISelection selection = getCurrentSelection();
+ if (selection instanceof IStructuredSelection) {
+ return (IStructuredSelection) selection;
+ }
+ return StructuredSelection.EMPTY;
+ }
+
+ /**
+ *
+ * @param viewId
+ * the id of the view for which we want the selection
+ * @return
+ * the current selection for the view, the returned value can't be <code>null</code>
+ */
+ public static final IStructuredSelection getCurrentStructuredSelection(String viewId) {
+ ISelection selection = getCurrentSelection(viewId);
+ if (selection instanceof IStructuredSelection) {
+ return (IStructuredSelection) selection;
+ }
+ return StructuredSelection.EMPTY;
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ServiceUtilsForActionHandlers.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ServiceUtilsForActionHandlers.java
new file mode 100644
index 00000000000..917a41e8688
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ServiceUtilsForActionHandlers.java
@@ -0,0 +1,149 @@
+/*****************************************************************************
+ * Copyright (c) 2010, 2016 LIFL, CEA LIST, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Cedric Dumoulin (LIFL) cedric.dumoulin@lifl.fr - Initial API and implementation
+ * Christian W. Damus - bug 485220
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.ui.util;
+
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.ISashWindowsContainer;
+import org.eclipse.papyrus.infra.core.sashwindows.di.service.IPageManager;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.services.ServiceNotFoundException;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.core.utils.AbstractServiceUtils;
+import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor;
+import org.eclipse.papyrus.infra.ui.lifecycleevents.ILifeCycleEventsProvider;
+import org.eclipse.ui.IEditorPart;
+
+/**
+ * Set of utility methods for accessing core Services. This class provide
+ * methods to access the Papyrus well known services. This class is designed to
+ * be used from ui Action Handlers or from any code relying on the Eclipse
+ * Active Editor. <br>
+ * All methods from this class rely on the Eclipse Active Editor, which should
+ * be an instance of {@link IMultiDiagramEditor}. If this is not the case,
+ * methods throw an exception {@link ServiceException}.
+ *
+ * @author cedric dumoulin
+ *
+ * @deprecated 0.10: Use org.eclipse.papyrus.infra.emf.utils.ServiceUtilsForHandlers instead
+ */
+@Deprecated
+public class ServiceUtilsForActionHandlers extends AbstractServiceUtils<Void> {
+
+ private ServiceUtilsForActionHandlers() {
+ // Singleton
+ }
+
+ private final static ServiceUtilsForActionHandlers instance = new ServiceUtilsForActionHandlers();
+
+ /**
+ * Get the singleton instance of the class.
+ *
+ * @return
+ */
+ public static final ServiceUtilsForActionHandlers getInstance() {
+ return instance;
+ }
+
+ @Override
+ public ServicesRegistry getServiceRegistry(Void from) throws ServiceException {
+ return getServiceRegistry();
+ }
+
+ /**
+ * Get the service registry from the specified parameter.
+ *
+ * @param from
+ * @return
+ */
+ public ServicesRegistry getServiceRegistry() throws ServiceException {
+ ServicesRegistry serviceRegistry = getContextualServiceRegistry();
+ if (serviceRegistry != null) {
+ return serviceRegistry;
+ }
+
+ // Not found
+ throw new ServiceNotFoundException("Can't get the ServiceRegistry from current Eclipse Active Editor"); //$NON-NLS-1$
+ }
+
+ /**
+ * Gets the {@link TransactionalEditingDomain} registered in the {@link ServicesRegistry}.
+ *
+ * @return
+ * @throws ServiceException
+ * If an error occurs while getting the requested service.
+ */
+ public TransactionalEditingDomain getTransactionalEditingDomain() throws ServiceException {
+ return getServiceRegistry().getService(TransactionalEditingDomain.class);
+ }
+
+ /**
+ * Gets the {@link IPageManager} registered in the {@link ServicesRegistry}.
+ *
+ * @return
+ * @throws ServiceException
+ * If an error occurs while getting the requested service.
+ */
+ public IPageManager getIPageManager() throws ServiceException {
+ return getServiceRegistry().getService(IPageManager.class);
+ }
+
+ /**
+ * Gets the {@link IPageMngr} registered in the {@link ServicesRegistry}.
+ *
+ * @return
+ * @throws ServiceException
+ * If an error occurs while getting the requested service.
+ */
+ public ModelSet getModelSet() throws ServiceException {
+ return getServiceRegistry().getService(ModelSet.class);
+ }
+
+ /**
+ * Gets the {@link ILifeCycleEventsProvider} registered in the {@link ServicesRegistry}.
+ *
+ * @param from
+ * @return
+ * @throws ServiceException
+ * If an error occurs while getting the requested service.
+ */
+ public ILifeCycleEventsProvider getILifeCycleEventsProvider() throws ServiceException {
+ return getServiceRegistry().getService(ILifeCycleEventsProvider.class);
+ }
+
+ /**
+ * Gets the {@link ISashWindowsContainer} registered in the {@link ServicesRegistry}.
+ *
+ * @param from
+ * @return
+ * @throws ServiceException
+ * If an error occurs while getting the requested service.
+ */
+ public ISashWindowsContainer getISashWindowsContainer() throws ServiceException {
+ return getServiceRegistry().getService(ISashWindowsContainer.class);
+ }
+
+ /**
+ * Gets the {@link IEditorPart} of the currently nested active editor.
+ *
+ * @param from
+ * @return
+ * @throws ServiceException
+ * If an error occurs while getting the requested service.
+ */
+ public IEditorPart getNestedActiveIEditorPart() throws ServiceException {
+ return getISashWindowsContainer().getActiveEditor();
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ServiceUtilsForWorkbenchPage.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ServiceUtilsForWorkbenchPage.java
new file mode 100644
index 00000000000..624257964cc
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ServiceUtilsForWorkbenchPage.java
@@ -0,0 +1,63 @@
+/*****************************************************************************
+ * Copyright (c) 2012 CEA LIST.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.util;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.core.utils.AbstractServiceUtils;
+import org.eclipse.ui.IWorkbenchPage;
+
+/**
+ * A ServiceUtils implementation for manipulating the Papyrus services from an IWorkbenchPage
+ *
+ * @author Camille Letavernier
+ *
+ */
+public class ServiceUtilsForWorkbenchPage extends AbstractServiceUtils<IWorkbenchPage> {
+
+ @Override
+ public ServicesRegistry getServiceRegistry(IWorkbenchPage from) throws ServiceException {
+ IAdaptable adaptable = null;
+ if (from instanceof IAdaptable) {
+ adaptable = (IAdaptable) from;
+ } else if (from != null) {
+ // 421392: [Model Explorer] Link with Editor does not work properly
+ // https://bugs.eclipse.org/bugs/show_bug.cgi?id=421392
+
+ // Since Eclipse 4.4, the concrete WorkbenchPage is not IAdaptable anymore.
+ // Try the ActivePart
+ adaptable = from.getActivePart();
+ }
+
+ if (adaptable != null) {
+ ServicesRegistry registry = (ServicesRegistry) adaptable.getAdapter(ServicesRegistry.class);
+ if (registry != null) {
+ return registry;
+ }
+ }
+
+
+ throw new ServiceException("Cannot resolve the ServiceRegistry from the IWorkbenchPage. Page: " + from); //$NON-NLS-1$
+ }
+
+ public static ServiceUtilsForWorkbenchPage getInstance() {
+ return instance;
+ }
+
+ private static ServiceUtilsForWorkbenchPage instance = new ServiceUtilsForWorkbenchPage();
+
+ private ServiceUtilsForWorkbenchPage() {
+ // Singleton
+ }
+
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/TransactionUIHelper.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/TransactionUIHelper.java
new file mode 100644
index 00000000000..825a99386a3
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/TransactionUIHelper.java
@@ -0,0 +1,81 @@
+/*****************************************************************************
+ * Copyright (c) 2014, 2016 CEA LIST, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus - bug 465416
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.util;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.emf.common.util.WrappedException;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+
+
+/**
+ * Helper utilities for working with transactions on the UI thread.
+ */
+public class TransactionUIHelper {
+
+ /**
+ * Create a privileged runnable with progress, which is like a regular {@linkplain TransactionalEditingDomain#createPrivilegedRunnable(Runnable)
+ * privileged runnable} except that it is given a progress monitor for progress reporting.
+ * This enables execution of monitored runnables on the modal-context thread using the transaction borrowed from the UI thread.
+ *
+ * @param domain
+ * an editing domain
+ * @param runnable
+ * a runnable with progress that is to borrow the {@code domain}'s active transaction on the modal context thread
+ * @return the privileged runnable, ready to pass into the progress service or other such API
+ */
+ public static IRunnableWithProgress createPrivilegedRunnableWithProgress(TransactionalEditingDomain domain, final IRunnableWithProgress runnable) {
+ final IProgressMonitor monitorHolder[] = { null };
+
+ final Runnable privileged = domain.createPrivilegedRunnable(new Runnable() {
+
+ @Override
+ public void run() {
+ try {
+ runnable.run(monitorHolder[0]);
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new WrappedException(e);
+ }
+ }
+ });
+
+ return new IRunnableWithProgress() {
+
+ @Override
+ public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+ monitorHolder[0] = monitor;
+
+ try {
+ privileged.run();
+ } catch (OperationCanceledException e) {
+ throw new InterruptedException(e.getLocalizedMessage());
+ } catch (WrappedException e) {
+ Exception unwrapped = e.exception();
+ if (unwrapped instanceof InvocationTargetException) {
+ throw (InvocationTargetException) unwrapped;
+ } else if (unwrapped instanceof InterruptedException) {
+ throw (InterruptedException) unwrapped;
+ } else {
+ throw e;
+ }
+ }
+ }
+ };
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/UIUtil.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/UIUtil.java
new file mode 100644
index 00000000000..1dd62db4ff5
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/UIUtil.java
@@ -0,0 +1,517 @@
+/*
+ * Copyright (c) 2014, 2016 CEA, Christian W. Damus, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ * Christian W. Damus - bug 399859
+ * Christian W. Damus - bug 451557
+ * Christian W. Damus - bug 485220
+ *
+ */
+package org.eclipse.papyrus.infra.ui.util;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+import java.util.concurrent.AbstractExecutorService;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.emf.common.util.AbstractTreeIterator;
+import org.eclipse.emf.common.util.TreeIterator;
+import org.eclipse.jface.operation.IRunnableContext;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.papyrus.infra.tools.util.IExecutorService;
+import org.eclipse.papyrus.infra.tools.util.Iterators2;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IMemento;
+
+import com.google.common.collect.Iterators;
+
+
+/**
+ * Miscellaneous general-purpose UI utilities.
+ */
+public class UIUtil {
+
+ /**
+ * Not instantiable by clients.
+ */
+ private UIUtil() {
+ super();
+ }
+
+ /**
+ * Create an executor that runs tasks asynchronously on the UI thread. If you need synchronous execution, schedule {@link Future}s and {@linkplain Future#get() wait} for them.
+ *
+ * @param display
+ * the display on which thread to execute tasks
+ *
+ * @return the executor
+ */
+ public static IExecutorService createUIExecutor(Display display) {
+ return new DisplayExecutorService(display);
+ }
+
+ /**
+ * Create an executor that runs tasks asynchronously on an observable {@link Realm}. If you need synchronous execution, schedule {@link Future}s and {@linkplain Future#get() wait} for them.
+ *
+ * @param realm
+ * the observable realm on which thread to execute tasks
+ *
+ * @return the executor
+ */
+ public static ExecutorService createObservableExecutor(Realm realm) {
+ return new RealmExecutorService(realm);
+ }
+
+ /**
+ * Creates a local memento that is not persistable and is not based on an XML document. This is useful for capturing the
+ * state of UI elements locally in cases where persistence of the memento is not required.
+ *
+ * @return the memento
+ */
+ public static IMemento createLocalMemento() {
+ return LocalMemento.createMemento("__anonymous__", null); //$NON-NLS-1$
+ }
+
+ /**
+ * Synchronously invokes a {@code callable} on the given {@code display}'s thread.
+ *
+ * @param display
+ * a display
+ * @param callable
+ * a callable to invoke
+ * @return the callable's result (which, because this method is synchronous, will be ready)
+ *
+ * @see #asyncCall(Display, Callable)
+ * @see #createUIExecutor(Display)
+ */
+ public static <V> Future<V> syncCall(Display display, Callable<V> callable) {
+ final FutureTask<V> result = new FutureTask<V>(callable);
+ display.syncExec(result);
+ return result;
+ }
+
+ /**
+ * Synchronously invokes a {@code callable} on the default display thread.
+ *
+ * @param callable
+ * a callable to invoke
+ * @return the callable's result (which, because this method is synchronous, will be ready)
+ *
+ * @see #syncCall(Display, Callable)
+ * @see #asyncCall(Callable)
+ * @see #createUIExecutor(Display)
+ */
+ public static <V> Future<V> syncCall(Callable<V> callable) {
+ return syncCall(Display.getDefault(), callable);
+ }
+
+ /**
+ * Asynchronously invokes a {@code callable} on the given {@code display}'s thread.
+ *
+ * @param display
+ * a display
+ * @param callable
+ * a callable to invoke
+ * @return the callable's result
+ *
+ * @see #syncCall(Display, Callable)
+ * @see #createUIExecutor(Display)
+ */
+ public static <V> Future<V> asyncCall(Display display, Callable<V> callable) {
+ final FutureTask<V> result = new FutureTask<V>(callable);
+ display.asyncExec(result);
+ return result;
+ }
+
+ /**
+ * Asynchronously invokes a {@code callable} on the default display thread.
+ *
+ * @param callable
+ * a callable to invoke
+ * @return the callable's result
+ *
+ * @see #asyncCall(Display, Callable)
+ * @see #syncCall(Callable)
+ * @see #createUIExecutor(Display)
+ */
+ public static <V> Future<V> asyncCall(Callable<V> callable) {
+ return asyncCall(Display.getDefault(), callable);
+ }
+
+ /**
+ * Calls a {@code callable} in the given {@code context}.
+ *
+ * @param fork
+ * {@code true} if the runnable should be run in a separate thread,
+ * and {@code false} to run in the same thread
+ * @param cancelable
+ * {@code true} to enable the cancellation, and {@code false} to make the operation uncancellable
+ * @param runnable
+ * the runnable to run
+ *
+ * @exception InvocationTargetException
+ * wraps any exception or error which occurs
+ * while running the runnable
+ * @exception InterruptedException
+ * propagated by the context if the runnable
+ * acknowledges cancellation by throwing this exception. This should not be thrown
+ * if {@code cancelable} is {@code false}.
+ */
+ public static <V> V call(IRunnableContext context, boolean fork, boolean cancelable, ICallableWithProgress<V> callable) throws InvocationTargetException, InterruptedException {
+ class RunnableWrapper implements IRunnableWithProgress {
+ final ICallableWithProgress<V> delegate;
+
+ V result;
+
+ RunnableWrapper(ICallableWithProgress<V> delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+ result = delegate.call(monitor);
+ }
+ }
+
+ RunnableWrapper wrapper = new RunnableWrapper(callable);
+ context.run(fork, cancelable, wrapper);
+ return wrapper.result;
+ }
+
+ /**
+ * Obtains a simple executor that asynchronously executes at most one task on the default
+ * display thread. While any task is still pending execution on this executor,
+ * all others are silently discarded. This is useful for cases where, for example, UI
+ * refreshes are posted repeatedly from independent events that aren't aware of each other
+ * but where each refresh task would repeat the same work.
+ *
+ * @param display
+ * a display on which thread to execute tasks
+ *
+ * @return the executor
+ *
+ * @see #createAsyncOnceExecutor(Display)
+ */
+ public static Executor createAsyncOnceExecutor() {
+ return createAsyncOnceExecutor(Display.getDefault());
+ }
+
+ /**
+ * Obtains a simple executor that asynchronously executes at most one task on the given {@code display}'s thread. While any task is still pending execution on this executor,
+ * all others are silently discarded. This is useful for cases where, for example, UI
+ * refreshes are posted repeatedly from independent events that aren't aware of each other
+ * but where each refresh task would repeat the same work.
+ *
+ * @param display
+ * a display on which thread to execute tasks
+ *
+ * @return the executor
+ */
+ public static Executor createAsyncOnceExecutor(final Display display) {
+ return new Executor() {
+ private final AtomicBoolean pending = new AtomicBoolean();
+
+ @Override
+ public void execute(final Runnable task) {
+ if (pending.compareAndSet(false, true)) {
+ display.asyncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ pending.set(false);
+ task.run();
+ }
+ });
+ }
+ }
+ };
+ }
+
+ /**
+ * Obtains a tree iterator over all of the controls contained within a given {@code root} control, not including that {@code root}.
+ *
+ * @param root
+ * a control to iterate
+ * @return an unmodifiable iterator over all of its nested controls, which naturally will be empty if the {@code root} is not a {@link Composite}
+ */
+ public static TreeIterator<Control> allChildren(Control root) {
+ return new AbstractTreeIterator<Control>(root, false) {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected Iterator<? extends Control> getChildren(Object object) {
+ return (object instanceof Composite) ? Iterators.forArray(((Composite) object).getChildren()) : Iterators.<Control> emptyIterator();
+ }
+ };
+ }
+
+ /**
+ * Obtains a tree iterator over all of the controls of a particular type contained within a given {@code root} control, not including that {@code root}.
+ *
+ * @param root
+ * a control to iterate
+ * @param type
+ * the type of children to include in the iteration
+ *
+ * @return an unmodifiable iterator over all of its nested controls, which naturally will be empty if the {@code root} is not a {@link Composite}
+ */
+ public static <C extends Control> TreeIterator<C> allChildren(Control root, final Class<C> type) {
+ return Iterators2.filter(allChildren(root), type);
+ }
+
+ //
+ // Nested types
+ //
+
+ private static abstract class UIExecutorService extends AbstractExecutorService implements IExecutorService {
+
+ private final Lock lock = new ReentrantLock();
+
+ private final Condition emptyCond = lock.newCondition();
+
+ private final Queue<RunnableWrapper> pending = new LinkedList<RunnableWrapper>();
+
+ private volatile boolean shutdown;
+
+ UIExecutorService() {
+ super();
+ }
+
+ @Override
+ public void execute(Runnable command) {
+ if (isShutdown()) {
+ throw new RejectedExecutionException("Executor service is shut down"); //$NON-NLS-1$
+ }
+
+ asyncExec(enqueue(command));
+ }
+
+ @Override
+ public <V> V syncCall(Callable<V> callable) throws InterruptedException, ExecutionException {
+ class SyncResult implements Runnable {
+ V result;
+ ExecutionException fail;
+
+ @Override
+ public void run() {
+ try {
+ result = callable.call();
+ } catch (Exception e) {
+ fail = new ExecutionException(e);
+ fail.fillInStackTrace();
+ }
+ }
+ }
+
+ SyncResult result = new SyncResult();
+
+ syncExec(result);
+
+ if (result.fail != null) {
+ throw result.fail;
+ }
+
+ return result.result;
+ }
+
+ abstract void asyncExec(Runnable runnable);
+
+ @Override
+ public List<Runnable> shutdownNow() {
+ List<Runnable> result = new ArrayList<Runnable>();
+
+ shutdown();
+
+ for (Runnable dequeued = dequeue(); dequeued != null; dequeued = dequeue()) {
+ result.add(dequeued);
+ }
+
+ return result;
+ }
+
+ private RunnableWrapper enqueue(Runnable task) {
+ RunnableWrapper result = new RunnableWrapper(task);
+
+ lock.lock();
+ try {
+ boolean wasEmpty = pending.isEmpty();
+ pending.offer(result);
+ if (wasEmpty) {
+ // Now not empty
+ emptyCond.signalAll();
+ }
+ } finally {
+ lock.unlock();
+ }
+
+ return result;
+ }
+
+ private RunnableWrapper dequeue() {
+ RunnableWrapper result = null;
+
+ lock.lock();
+ try {
+ result = pending.poll();
+ if (result == null) {
+ // Now empty
+ emptyCond.signalAll();
+ }
+ } finally {
+ lock.unlock();
+ }
+
+ return result;
+ }
+
+ boolean dequeue(RunnableWrapper task) {
+ boolean result = false;
+
+ lock.lock();
+ try {
+ result = pending.remove(task);
+ if (result && pending.isEmpty()) {
+ // Now empty
+ emptyCond.signalAll();
+ }
+ } finally {
+ lock.unlock();
+ }
+
+ return result;
+ }
+
+ @Override
+ public void shutdown() {
+ shutdown = true;
+ }
+
+ @Override
+ public boolean isTerminated() {
+ lock.lock();
+ try {
+ return isShutdown() && pending.isEmpty();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ @Override
+ public boolean isShutdown() {
+ return shutdown;
+ }
+
+ @Override
+ public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
+ if (timeout < 0L) {
+ throw new IllegalArgumentException("negative timeout"); //$NON-NLS-1$
+ }
+
+ final Date deadline = (timeout == 0L) ? null : new Date(System.currentTimeMillis() + unit.toMillis(timeout));
+ boolean result = false;
+
+ lock.lock();
+ try {
+ boolean stillWaiting = true;
+ for (result = isTerminated(); !result && stillWaiting; result = isTerminated()) {
+ if (deadline == null) {
+ emptyCond.await();
+ } else {
+ stillWaiting = emptyCond.awaitUntil(deadline);
+ }
+ }
+ } finally {
+ lock.unlock();
+ }
+
+ return result;
+ }
+
+ //
+ // Nested types
+ //
+
+ private class RunnableWrapper implements Runnable {
+
+ private final Runnable delegate;
+
+ RunnableWrapper(Runnable delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void run() {
+ // Don't run if I was cancelled by shutdown
+ if (dequeue(this)) {
+ delegate.run();
+ }
+ }
+ }
+ };
+
+ private static class DisplayExecutorService extends UIExecutorService {
+ private final Display display;
+
+ DisplayExecutorService(Display display) {
+ super();
+
+ this.display = display;
+ }
+
+ @Override
+ void asyncExec(Runnable runnable) {
+ display.asyncExec(runnable);
+ }
+
+ @Override
+ public void syncExec(Runnable task) {
+ display.syncExec(task);
+ }
+ }
+
+ private static class RealmExecutorService extends UIExecutorService {
+ private final Realm realm;
+
+ RealmExecutorService(Realm realm) {
+ super();
+
+ this.realm = realm;
+ }
+
+ @Override
+ void asyncExec(Runnable runnable) {
+ realm.asyncExec(runnable);
+ }
+
+ @Override
+ public void syncExec(Runnable task) {
+ realm.exec(task);
+ }
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/WorkbenchPartHelper.java b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/WorkbenchPartHelper.java
new file mode 100644
index 00000000000..c94256dd8f5
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/WorkbenchPartHelper.java
@@ -0,0 +1,71 @@
+/*****************************************************************************
+ * Copyright (c) 2012 CEA LIST.
+ *
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Vincent Lorenzo (CEA LIST) Vincent.Lorenzo@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.util;
+
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ *
+ * a helper for the Eclipse workbench part
+ *
+ */
+public class WorkbenchPartHelper {
+
+ private WorkbenchPartHelper() {
+ // nothing to do
+ }
+
+ /**
+ *
+ * @return
+ * the current IWorkbenchPart or <code>null</code> if not found
+ */
+ public static final IWorkbenchPart getCurrentActiveWorkbenchPart() {
+ final IWorkbench workbench = PlatformUI.getWorkbench();
+ if (workbench != null) {
+ final IWorkbenchWindow activeWorkbench = workbench.getActiveWorkbenchWindow();
+ if (activeWorkbench != null) {
+ final IWorkbenchPage activePage = activeWorkbench.getActivePage();
+ if (activePage != null) {
+ return activePage.getActivePart();
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ *
+ * @return
+ * the current IEditorPart or <code>null</code> if not found
+ */
+ public static final IEditorPart getCurrentActiveEditorPart() {
+ final IWorkbench workbench = PlatformUI.getWorkbench();
+ if (workbench != null) {
+ final IWorkbenchWindow activeWorkbench = workbench.getActiveWorkbenchWindow();
+ if (activeWorkbench != null) {
+ final IWorkbenchPage activePage = activeWorkbench.getActivePage();
+ if (activePage != null) {
+ return activePage.getActiveEditor();
+ }
+ }
+ }
+ return null;
+ }
+}

Back to the top