Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian W. Damus2016-02-11 02:48:20 +0000
committerGerrit Code Review @ Eclipse.org2016-02-12 15:31:41 +0000
commitecd4928b327f5561364c5068c9ff5f1668e92d13 (patch)
tree7c34f46cf82a1d65ac753fa92c2a5d55371b8dba /plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra
parent751a204d74e15eb2db6b41c937691fc56dcc1252 (diff)
downloadorg.eclipse.papyrus-ecd4928b327f5561364c5068c9ff5f1668e92d13.tar.gz
org.eclipse.papyrus-ecd4928b327f5561364c5068c9ff5f1668e92d13.tar.xz
org.eclipse.papyrus-ecd4928b327f5561364c5068c9ff5f1668e92d13.zip
Bug 485220: [Architecture] Provide a more modular architecture
https://bugs.eclipse.org/bugs/show_bug.cgi?id=485220 Factor UI dependencies out of the UML Element Types bundle. This includes moving some advices that interact with the user into a new org.eclipse.papyrus.uml.service.types.ui bundle. Pull up the PasteCommandService and IPasteCommandProvider API into the Infra Diagram layer where the extension point is defined. Deprecate the old API in the UML layer. Introduce a service for participation of languages in CSS styling: * styling reset actions in the Reset Style command * access to semantic model classes and properties to make available to CSS Factor PapyrusObservableValue and cohorts out of the UML Tools bundle into the Infra Layer for more general reuse and to relieve the Diagram Infrastructure layer of UML dependencies. The old API remains as deprecated. Remove the Infra Diagram Layer dependency on UML Layer for property testers governing deletion in the diagram. Includes introduction of a new IGraphicalDeletionHelper OSGi service for delegation of the determination of whether an element can be deleted from the diagram and replacement of the XML expression properties * org.eclipse.papyrus.uml.diagram.common.isSemanticDeletion * org.eclipse.papyrus.uml.diagram.common.isReadOnly by * org.eclipse.papyrus.infra.gmfdiag.common.isSemanticDeletion * org.eclipse.papyrus.infra.gmfdiag.common.canDelete (where the latter is the negation of the property that it supersedes) Extract UML dependencies from the Diagram Outline and CSS Editor bundles. Remove unused MDTUtil APIs that referenced a UML-specific annotation. Move the Diagram Infrastructure CSS Palette bundle into the UML layer because it serves to provide extensions on the Palette Service, which is an overtly UML-specific capability. All client APIs for the Properties View are moved from org.eclipse.papyrus.views.properties bundle to a new org.eclipse.papyrus.infra.properties.ui bundle. This includes renaming of: * extension points * label-provider contexts * XWT namespaces Add an "all UI tests" suite. Define a componentized hierarchical build layout of the main plug-ins Change-Id: I43f8f3644857a18b69715f5a2f1da9b1cf286d67
Diffstat (limited to 'plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra')
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/Activator.java99
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/command/AbstractCommandHandler.java189
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/command/AbstractPapyrusHandler.java217
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/contentoutline/ContentOutlineRegistry.java263
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/contentoutline/IPapyrusContentOutlinePage.java34
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/contentoutline/NestedEditorDelegatedOutlinePage.java1098
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/AbstractStringValueConverter.java86
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/ConvertedValueContainer.java75
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/EMFStringValueConverter.java373
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/IStringValueConverter.java36
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/MultiConvertedValueContainer.java39
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/StringValueConverterStatus.java60
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/dnd/PapyrusTransfer.java105
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/ContentProviderServiceFactory.java68
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/CoreMultiDiagramEditor.java1244
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/DiSashModelManagerServiceFactory.java114
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/DiSashModelMngrServiceFactory.java101
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/IMultiDiagramEditor.java93
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/IPapyrusPageInput.java35
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/IReloadableEditor.java409
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/MultiDiagramEditorSelectionContext.java291
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/MultiDiagramPropertySheetPage.java178
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/PageIconRegistryServiceFactory.java71
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/PageMngrServiceFactory.java83
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/PapyrusPageInput.java62
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/CompositeReloadContext.java86
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/DelegatingReloadContext.java74
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EMFSelectionContext.java52
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EMFTreeViewerContext.java52
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EditorReloadAdapter.java36
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EditorReloadEvent.java188
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IDisposableReloadContext.java23
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IEditorReloadListener.java44
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IInternalEMFSelectionContext.java109
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IReloadContextProvider.java38
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/SelectionContext.java81
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/TreeViewerContext.java64
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/AbstractGetEditorIconQuery.java74
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IEditorFactory.java57
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IEditorIconFactory.java64
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IEditorIconFactoryExtended.java30
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IPageIconsRegistry.java40
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IPageIconsRegistryExtended.java32
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/PageIconsRegistry.java118
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/PageModelFactoryRegistry.java165
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/anytype/AnyTypeEditorFactory.java135
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/commands/ICreationCondition.java36
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/commands/IModelCreationCommand.java31
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/commands/PerspectiveContextDependence.java51
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/AbstractEditorFactory.java109
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorDescriptor.java168
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorDescriptorExtensionFactory.java99
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorFactoryProxy.java137
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorIconFactory.java152
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorNotFoundException.java53
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/IPluggableEditorFactory.java39
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/MultiDiagramException.java53
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/PluggableEditorFactoryReader.java143
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/commands/PageLayoutStorageState.java164
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/commands/SashLayoutCommandFactory.java226
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/commands/TogglePageLayoutStorageHandler.java78
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/EditorPreferencePage.java52
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/EditorPreferences.java88
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/Messages.java37
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/YesNo.java21
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/messages.properties18
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/DoSaveEvent.java66
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/IEditorInputChangedListener.java40
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/ILifeCycleEventsProvider.java57
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/ISaveAndDirtyService.java56
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/ISaveEventListener.java27
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/LifeCycleEventsProvider.java291
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/LifeCycleEventsProviderServiceFactory.java79
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/SaveAndDirtyService.java550
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/AbstractCommonCommandHandler.java98
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/AbstractEMFParametricOnSelectedElementsAction.java61
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/AbstractParametricOnSelectedElementsAction.java115
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/NameNormalization.java24
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/NameNormalizationCommand.java124
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/NamePropertyTester.java41
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/messages/Messages.java48
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/messages/messages.properties10
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/ActionBarContributorDescriptor.java72
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/ActionBarContributorExtensionFactory.java72
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/ActionBarContributorRegistry.java176
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/CoreComposedActionBarContributor.java122
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/IActionBarContributorFactory.java25
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/AbstractPapyrusPreferencePage.java237
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/AbstractPapyrusPreferenceStore.java300
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/AbstractPreferenceGroup.java161
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/IPapyrusPreferencePage.java28
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/PapyrusScopedPreferenceStore.java858
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/VisiblePageSingleton.java67
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/dialog/AbstractApplyValueOnPreferenceKeyDialog.java71
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/dialog/AbstractPreferenceKeyDialog.java105
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/providers/CompositePapyrusContentProvider.java109
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/providers/CompositeSemanticContentProviderFactory.java63
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/providers/DelegatingPapyrusContentProvider.java170
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/providers/ISemanticContentProviderFactory.java59
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/EditorLifecycleEventListener.java55
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/EditorLifecycleManager.java30
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/Messages.java34
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/ResourceUpdateService.java292
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/SaveLayoutBeforeClose.java218
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/internal/EditorLifecycleManagerImpl.java128
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/internal/InternalEditorLifecycleManager.java48
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/messages.properties15
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/AbstractCreateMenuFromCommandCategory.java135
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/DisplayUtils.java47
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/EclipseCommandUtils.java137
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/EditorHelper.java71
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/EditorUtils.java721
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ICallableWithProgress.java50
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/LocalMemento.java285
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/PapyrusImageUtils.java67
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/SelectionHelper.java119
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ServiceUtilsForActionHandlers.java149
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ServiceUtilsForHandlers.java122
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ServiceUtilsForIEvaluationContext.java113
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ServiceUtilsForSelection.java61
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ServiceUtilsForWorkbenchPage.java63
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/TransactionUIHelper.java81
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/UIUtil.java706
-rw-r--r--plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/WorkbenchPartHelper.java71
124 files changed, 16940 insertions, 0 deletions
diff --git a/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/Activator.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/Activator.java
new file mode 100644
index 00000000000..a744cf9db8d
--- /dev/null
+++ b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/Activator.java
@@ -0,0 +1,99 @@
+/*****************************************************************************
+ * 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
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * 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
+ */
+public class Activator extends AbstractUIPlugin {
+
+ /**
+ * The plug-in ID
+ */
+ public static final String PLUGIN_ID = "org.eclipse.papyrus.infra.ui"; //$NON-NLS-1$
+
+ // The shared instance
+ private static Activator plugin;
+
+ /**
+ * The plug-in's logger
+ */
+ public static LogHelper log;
+
+ private ServiceRegistration<IExecutorServiceFactory> executorFactoryReg;
+ private ServiceRegistration<IContextualServiceRegistryTracker> serviceRegistryTrackerReg;
+
+ /**
+ * The constructor
+ */
+ public Activator() {
+ }
+
+ @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);
+ }
+
+ @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);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static Activator getDefault() {
+ return plugin;
+ }
+
+}
diff --git a/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/command/AbstractCommandHandler.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/command/AbstractCommandHandler.java
new file mode 100644
index 00000000000..9145151e8a0
--- /dev/null
+++ b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/command/AbstractCommandHandler.java
@@ -0,0 +1,189 @@
+/*****************************************************************************
+ * Copyright (c) 2010, 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:
+ * Patrick Tessier (CEA LIST) Patrick.tessier@cea.fr - Initial API and implementation
+ * Vincent Lorenzo (CEA-LIST) vincent.lorenzo@cea.fr
+ * Christian W. Damus (CEA) - Refactoring package/profile import/apply UI for CDO
+ * Christian W. Damus - bug 485220
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.command;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
+import org.eclipse.papyrus.infra.ui.Activator;
+import org.eclipse.papyrus.infra.ui.util.ServiceUtilsForHandlers;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * <pre>
+ *
+ * This abstract command handler manages:
+ * - current selection in order to build a list of the selected {@link EObject}
+ * - execute the command (returned by children) in Papyrus {@link TransactionalEditingDomain}
+ * - calculate the command enablement and visibility regarding the command executability
+ * (the command is now shown in menu if not executable).
+ *
+ * </pre>
+ */
+public abstract class AbstractCommandHandler extends AbstractPapyrusHandler {
+
+ private List<?> selection = Collections.EMPTY_LIST;
+
+ /**
+ * Returns the command to execute (to be implemented
+ * in children implementing this class)
+ *
+ * @param context
+ * the command evaluation context
+ *
+ * @return the command to execute
+ */
+ protected abstract Command getCommand(IEvaluationContext context);
+
+ protected Command getCommand(ExecutionEvent event) {
+ Command result = null;
+
+ Object context = event.getApplicationContext();
+ if (context instanceof IEvaluationContext) {
+ result = getCommand((IEvaluationContext) context);
+ } else {
+ throw new IllegalArgumentException("No evaluation context in execution event: " + event); //$NON-NLS-1$
+ }
+
+ return result;
+ }
+
+ protected List<?> getSelection() {
+ return selection;
+ }
+
+ /**
+ * <pre>
+ * Get the selected element, the first selected element if several are selected or null
+ * if no selection or the selection is not an {@link EObject}.
+ *
+ * @return selected {@link EObject} or null
+ * </pre>
+ *
+ */
+ protected EObject getSelectedElement() {
+ EObject eObject = null;
+
+ // Get current selection
+ List<?> selection = getSelection();
+
+ // Treat non-null selected object (try to adapt and return EObject)
+ if (!selection.isEmpty()) {
+
+ // Get first element if the selection is an IStructuredSelection
+ Object first = selection.get(0);
+
+ EObject businessObject = EMFHelper.getEObject(first);
+ if (businessObject != null) {
+ eObject = businessObject;
+ }
+ }
+
+ return eObject;
+ }
+
+ /**
+ * <pre>
+ * Parse current selection and extract the list of {@link EObject} from
+ * this selection.
+ *
+ * This also tries to adapt selected element into {@link EObject}
+ * (for example to get the {@link EObject} from a selection in the ModelExplorer).
+ *
+ * @return a list of currently selected {@link EObject}
+ * </pre>
+ *
+ */
+ protected List<EObject> getSelectedElements() {
+
+ List<EObject> selectedEObjects = new ArrayList<EObject>();
+
+ // Get current selection
+ Collection<?> selection = getSelection();
+
+ // Treat non-null selected object (try to adapt and return EObject)
+ if (!selection.isEmpty()) {
+
+ // Parse current selection
+ for (Object current : selection) {
+ // Adapt current selection to EObject
+ EObject selectedEObject = EMFHelper.getEObject(current);
+ if (selectedEObject != null) {
+ // we avoid to add null element in the list!
+ selectedEObjects.add(selectedEObject);
+ }
+ }
+ }
+
+ return selectedEObjects;
+ }
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ try {
+ ISelection selection = HandlerUtil.getCurrentSelection(event);
+ this.selection = (selection instanceof IStructuredSelection) ? ((IStructuredSelection) selection).toList() : Collections.EMPTY_LIST;
+
+ ServiceUtilsForHandlers.getInstance().getTransactionalEditingDomain(event).getCommandStack().execute(getCommand(event));
+ } catch (ServiceException e) {
+ Activator.log.error("Unexpected error while executing command.", e); //$NON-NLS-1$
+ } finally {
+ // clear the selection
+ this.selection = Collections.EMPTY_LIST;
+ }
+
+ return null;
+ }
+
+ protected boolean computeEnabled(IEvaluationContext context) {
+ boolean result = false;
+
+ Command command = getCommand(context);
+ if (command != null) {
+ result = command.canExecute();
+ command.dispose();
+ }
+
+ return result;
+ }
+
+ @Override
+ public void setEnabled(Object evaluationContext) {
+ if (evaluationContext instanceof IEvaluationContext) {
+ IEvaluationContext context = (IEvaluationContext) evaluationContext;
+
+ Object selection = ((IEvaluationContext) evaluationContext).getDefaultVariable();
+ if (selection instanceof Collection<?>) {
+ this.selection = (selection instanceof List<?>) ? (List<?>) selection : new java.util.ArrayList<Object>((Collection<?>) selection);
+ setBaseEnabled(computeEnabled(context));
+ this.selection = Collections.EMPTY_LIST;
+ }
+ }
+ super.setEnabled(evaluationContext);
+ }
+}
diff --git a/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/command/AbstractPapyrusHandler.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/command/AbstractPapyrusHandler.java
new file mode 100644
index 00000000000..d77ab4240be
--- /dev/null
+++ b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/command/AbstractPapyrusHandler.java
@@ -0,0 +1,217 @@
+/*****************************************************************************
+ * 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
+ * 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
+ * Christian W. Damus - bug 485220
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.command;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.TreeSelection;
+import org.eclipse.papyrus.infra.core.sashwindows.di.service.IPageManager;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
+import org.eclipse.papyrus.infra.ui.util.ServiceUtilsForHandlers;
+import org.eclipse.papyrus.infra.ui.util.ServiceUtilsForIEvaluationContext;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * This provides facilities to get the TransactionEditingDomain and the PageManager from
+ * the current Papyrus editor or view context.
+ */
+public abstract class AbstractPapyrusHandler extends AbstractHandler {
+
+ /**
+ * Obtains the transactional editing domain associated with the Papyrus Editor or View
+ * that is the context of the specified {@code execution}.
+ *
+ * @param execution
+ * an execution event
+ *
+ * @return the editing domain, or {@code null} if there is none (such as when the Papyrus Editor is closing)
+ */
+ protected TransactionalEditingDomain getEditingDomain(ExecutionEvent execution) {
+ TransactionalEditingDomain result = null;
+
+ try {
+ result = ServiceUtilsForHandlers.getInstance().getTransactionalEditingDomain(execution);
+ } catch (ServiceException e) {
+ // The wrong kind of editor/view is active or the Papyrus Editor is shutting down.
+ // These are both normal conditions
+ }
+
+ return result;
+ }
+
+ /**
+ * Obtains the transactional editing domain associated with the Papyrus Editor or View
+ * that has the specified evaluation {@code context}.
+ *
+ * @param context
+ * an evaluation context for a command's enablement or other computation
+ *
+ * @return the editing domain, or {@code null} if there is none (such as when the Papyrus Editor is closing)
+ */
+ protected TransactionalEditingDomain getEditingDomain(IEvaluationContext context) {
+ TransactionalEditingDomain result = null;
+
+ try {
+ result = ServiceUtilsForIEvaluationContext.getInstance().getTransactionalEditingDomain(context);
+ } catch (ServiceException e) {
+ // The wrong kind of editor/view is active or the Papyrus Editor is shutting down.
+ // These are both normal conditions
+ }
+
+ return result;
+ }
+
+ /**
+ * Obtains the page manager associated with the Papyrus Editor or View
+ * that is the context of the specified {@code execution}.
+ *
+ * @param execution
+ * an execution event
+ *
+ * @return the page manager, or {@code null} if there is none (such as when the Papyrus Editor is closing)
+ */
+ protected IPageManager getPageManager(ExecutionEvent execution) {
+ IPageManager result = null;
+
+ try {
+ result = ServiceUtilsForHandlers.getInstance().getIPageManager(execution);
+ } catch (ServiceException e) {
+ // The wrong kind of editor/view is active or the Papyrus Editor is shutting down.
+ // These are both normal conditions
+ }
+
+ return result;
+ }
+
+ /**
+ * Obtains the page manager associated with the Papyrus Editor or View
+ * that has the specified evaluation {@code context}.
+ *
+ * @param context
+ * an evaluation context for a command's enablement or other computation
+ *
+ * @return the page manager, or {@code null} if there is none (such as when the Papyrus Editor is closing)
+ */
+ protected IPageManager getPageManager(IEvaluationContext context) {
+ IPageManager result = null;
+
+ try {
+ result = ServiceUtilsForIEvaluationContext.getInstance().getIPageManager(context);
+ } catch (ServiceException e) {
+ // The wrong kind of editor/view is active or the Papyrus Editor is shutting down.
+ // These are both normal conditions
+ }
+
+ return result;
+ }
+
+ /**
+ * Adapt the specified object to the requested type, if possible.
+ * Return null if the object can't be adapted.
+ *
+ * @param object
+ * @param expectedClassType
+ * @return The adapted object, or null.
+ */
+ @SuppressWarnings("unchecked")
+ private <T> T adapt(Object object, Class<T> expectedClassType) {
+
+
+ EObject eobject = EMFHelper.getEObject(object);
+
+ if (eobject != null && expectedClassType.isInstance(eobject)) {
+ return (T) eobject;
+ }
+
+
+
+ // Try global mechanism
+ {
+ T ele = Platform.getAdapterManager().getAdapter(object, expectedClassType);
+ if (ele != null) {
+ return ele;
+ }
+ // Try as EObject if the expectedClasType is sub-type of EObject.
+ if (EObject.class.isAssignableFrom(expectedClassType)) {
+ // to EObject
+ eobject = Platform.getAdapterManager().getAdapter(object, EObject.class);
+
+ if (eobject != null && expectedClassType.isInstance(eobject)) {
+
+ return (T) eobject;
+ }
+ }
+ }
+ // Can't be adapted
+ return null;
+
+ }
+
+ /**
+ * Filter the list, and only retain objects that can be adapted to the specified type
+ *
+ * @param objects
+ * @param class1
+ * @return
+ */
+ private <T> List<T> getAllElementAdaptedToType(List<Object> list, Class<T> expectedClassType) {
+
+ List<T> res = new ArrayList<T>();
+
+ for (Object cur : list) {
+
+ T adapted = adapt(cur, expectedClassType);
+ if (adapted != null) {
+ res.add(adapted);
+ }
+ }
+ return res;
+ }
+
+ /**
+ * Get all selected element of the specified type.
+ *
+ * @param expectedType
+ * @return
+ * @throws ExecutionException
+ */
+ @SuppressWarnings("unchecked")
+ protected <T> List<T> getCurrentSelectionAdaptedToType(ExecutionEvent event, Class<T> expectedType) throws ExecutionException {
+
+ // Get selection from the workbench
+ ISelection selection = HandlerUtil.getCurrentSelectionChecked(event);
+
+ // Get the selected objects according to the type of the selected
+ if (selection instanceof IStructuredSelection) {
+ IStructuredSelection structuredSelection = (IStructuredSelection) selection;
+ return getAllElementAdaptedToType(structuredSelection.toList(), expectedType);
+ } else if (selection instanceof TreeSelection) {
+ TreeSelection treeSelection = (TreeSelection) selection;
+ return getAllElementAdaptedToType(treeSelection.toList(), expectedType);
+
+ }
+ return null;
+ }
+}
diff --git a/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/contentoutline/ContentOutlineRegistry.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/contentoutline/IPapyrusContentOutlinePage.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/contentoutline/IPapyrusContentOutlinePage.java
new file mode 100644
index 00000000000..8ce4fd3985f
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/contentoutline/NestedEditorDelegatedOutlinePage.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/contentoutline/NestedEditorDelegatedOutlinePage.java
new file mode 100644
index 00000000000..833f0ef89fb
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/AbstractStringValueConverter.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/AbstractStringValueConverter.java
new file mode 100644
index 00000000000..02e1f24f92c
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/ConvertedValueContainer.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/ConvertedValueContainer.java
new file mode 100644
index 00000000000..657091fb03c
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/EMFStringValueConverter.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/EMFStringValueConverter.java
new file mode 100644
index 00000000000..2847e7180fa
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/IStringValueConverter.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/IStringValueConverter.java
new file mode 100644
index 00000000000..5ce086d2dd7
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/MultiConvertedValueContainer.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/MultiConvertedValueContainer.java
new file mode 100644
index 00000000000..4324d0191fa
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/StringValueConverterStatus.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/converter/StringValueConverterStatus.java
new file mode 100644
index 00000000000..979bc06460c
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/dnd/PapyrusTransfer.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/ContentProviderServiceFactory.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/ContentProviderServiceFactory.java
new file mode 100644
index 00000000000..49557e36432
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/CoreMultiDiagramEditor.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/CoreMultiDiagramEditor.java
new file mode 100644
index 00000000000..bbfb16f40a6
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/DiSashModelManagerServiceFactory.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/DiSashModelMngrServiceFactory.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/IMultiDiagramEditor.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/IMultiDiagramEditor.java
new file mode 100644
index 00000000000..4193c25cf3e
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/IPapyrusPageInput.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/IPapyrusPageInput.java
new file mode 100644
index 00000000000..50594efbec8
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/IReloadableEditor.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/MultiDiagramEditorSelectionContext.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/MultiDiagramPropertySheetPage.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/PageIconRegistryServiceFactory.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/PageIconRegistryServiceFactory.java
new file mode 100644
index 00000000000..c35a776b83a
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/PageMngrServiceFactory.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/PapyrusPageInput.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/PapyrusPageInput.java
new file mode 100644
index 00000000000..84d317fc793
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/CompositeReloadContext.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/DelegatingReloadContext.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EMFSelectionContext.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EMFTreeViewerContext.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EditorReloadAdapter.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/EditorReloadEvent.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IDisposableReloadContext.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IEditorReloadListener.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IInternalEMFSelectionContext.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/IReloadContextProvider.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/SelectionContext.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editor/reload/TreeViewerContext.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/AbstractGetEditorIconQuery.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/AbstractGetEditorIconQuery.java
new file mode 100644
index 00000000000..9c02a4bf35d
--- /dev/null
+++ b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/AbstractGetEditorIconQuery.java
@@ -0,0 +1,74 @@
+/*****************************************************************************
+ * Copyright (c) 2011 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.editorsfactory;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.emf.utils.ServiceUtilsForEObject;
+import org.eclipse.papyrus.infra.ui.editorsfactory.IPageIconsRegistry;
+import org.eclipse.papyrus.infra.ui.editorsfactory.IPageIconsRegistryExtended;
+import org.eclipse.papyrus.infra.ui.editorsfactory.PageIconsRegistry;
+
+/**
+ *
+ * An abstract class to get the iconRegistery
+ *
+ */
+public abstract class AbstractGetEditorIconQuery {// we don't need to implements IJavaModelQuery here
+
+ /**
+ * the icon registry
+ */
+ private static IPageIconsRegistry editorRegistry;
+
+ /**
+ * Get the EditorRegistry used to create editor instances. This default
+ * implementation return the singleton eINSTANCE. This method can be
+ * subclassed to return another registry.
+ *
+ * @return the singleton eINSTANCE of editor registry
+ */
+ protected IPageIconsRegistryExtended getEditorRegistry(EObject context) {
+ try {
+ return (IPageIconsRegistryExtended) ServiceUtilsForEObject.getInstance().getService(IPageIconsRegistry.class, context);
+ } catch (Exception ex) {
+ // Skip
+ }
+ if (editorRegistry == null) {
+ editorRegistry = createEditorRegistry(context);
+ }
+ if (!(editorRegistry instanceof IPageIconsRegistryExtended)) {
+ throw new RuntimeException("The editor registry do not implement IPageIconsRegistryExtended");////$NON-NLS-1$
+ }
+ return (IPageIconsRegistryExtended) editorRegistry;
+ }
+
+ /**
+ * Return the EditorRegistry for nested editor descriptors. Subclass should
+ * implements this method in order to return the registry associated to the
+ * extension point namespace.
+ *
+ * @return the EditorRegistry for nested editor descriptors
+ */
+ protected IPageIconsRegistry createEditorRegistry(EObject context) {
+ try {
+ return ServiceUtilsForEObject.getInstance().getService(IPageIconsRegistry.class, context);
+ } catch (ServiceException e) {
+ // Not found, return an empty one which return null for each
+ // request.
+ return new PageIconsRegistry();
+ }
+ }
+}
diff --git a/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IEditorFactory.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IEditorFactory.java
new file mode 100644
index 00000000000..a107a8e53ff
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IEditorIconFactory.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IEditorIconFactory.java
new file mode 100644
index 00000000000..16ea36ce42b
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IEditorIconFactoryExtended.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IEditorIconFactoryExtended.java
new file mode 100644
index 00000000000..52faed51ce4
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IPageIconsRegistry.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IPageIconsRegistry.java
new file mode 100644
index 00000000000..4063f28288c
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IPageIconsRegistryExtended.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/IPageIconsRegistryExtended.java
new file mode 100644
index 00000000000..a11b5f5e7ff
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/PageIconsRegistry.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/PageModelFactoryRegistry.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/anytype/AnyTypeEditorFactory.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/editorsfactory/anytype/AnyTypeEditorFactory.java
new file mode 100644
index 00000000000..137c3c533ef
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/commands/ICreationCondition.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/commands/ICreationCondition.java
new file mode 100644
index 00000000000..035cfbfda70
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/commands/IModelCreationCommand.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/commands/IModelCreationCommand.java
new file mode 100644
index 00000000000..8b7f371b28e
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/commands/PerspectiveContextDependence.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/commands/PerspectiveContextDependence.java
new file mode 100644
index 00000000000..0c8b0a9d9fe
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/AbstractEditorFactory.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/AbstractEditorFactory.java
new file mode 100644
index 00000000000..89ace2da204
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorDescriptor.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorDescriptor.java
new file mode 100644
index 00000000000..d7aa6d558eb
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorDescriptorExtensionFactory.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorFactoryProxy.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorFactoryProxy.java
new file mode 100644
index 00000000000..8a80509bda2
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorIconFactory.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorIconFactory.java
new file mode 100644
index 00000000000..94038633af4
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorNotFoundException.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/EditorNotFoundException.java
new file mode 100644
index 00000000000..f0e189ae4e1
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/IPluggableEditorFactory.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/IPluggableEditorFactory.java
new file mode 100644
index 00000000000..87f1cde5d2b
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/MultiDiagramException.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/MultiDiagramException.java
new file mode 100644
index 00000000000..fd6a89ff037
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/extension/diagrameditor/PluggableEditorFactoryReader.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/commands/PageLayoutStorageState.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/commands/SashLayoutCommandFactory.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/commands/TogglePageLayoutStorageHandler.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/EditorPreferencePage.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/EditorPreferences.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/Messages.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/YesNo.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/internal/preferences/messages.properties b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/DoSaveEvent.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/DoSaveEvent.java
new file mode 100644
index 00000000000..51e34e85d83
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/IEditorInputChangedListener.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/IEditorInputChangedListener.java
new file mode 100644
index 00000000000..64835143e55
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/ILifeCycleEventsProvider.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/ILifeCycleEventsProvider.java
new file mode 100644
index 00000000000..31f2afae670
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/ISaveAndDirtyService.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/ISaveAndDirtyService.java
new file mode 100644
index 00000000000..a93b164ea0d
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/ISaveEventListener.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/ISaveEventListener.java
new file mode 100644
index 00000000000..03d6aaa6a02
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/LifeCycleEventsProvider.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/LifeCycleEventsProvider.java
new file mode 100644
index 00000000000..3fb4e594271
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/LifeCycleEventsProviderServiceFactory.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/LifeCycleEventsProviderServiceFactory.java
new file mode 100644
index 00000000000..b9126079262
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/lifecycleevents/SaveAndDirtyService.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/AbstractCommonCommandHandler.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/AbstractCommonCommandHandler.java
new file mode 100644
index 00000000000..deb6799a923
--- /dev/null
+++ b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/AbstractCommonCommandHandler.java
@@ -0,0 +1,98 @@
+/*****************************************************************************
+ * Copyright (c) 2015 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:
+ * Francois Le Fevre (CEA LIST) francois.le-fevre@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.menu;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.ui.util.ServiceUtilsForHandlers;
+import org.eclipse.ui.ISources;
+
+/**
+ * This abstract command handler: - calculates the current selection -
+ * calculates the visibility and enablement based on command executability -
+ * executes the command in Papyrus command stack
+ *
+ */
+public abstract class AbstractCommonCommandHandler extends AbstractHandler {
+
+ /**
+ * Iterate over current selection and build a list of the {@link EObject} contained in the selection.
+ *
+ * @return the currently selected {@link EObject}
+ */
+ protected abstract List<EObject> getSelectedElements();
+
+ /**
+ *
+ * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+ *
+ * @param event
+ * @return null
+ * @throws ExecutionException
+ */
+ @Override
+ public abstract Object execute(ExecutionEvent event) throws ExecutionException;
+
+ protected TransactionalEditingDomain getEditingDomain(ExecutionEvent event) {
+ try {
+ return ServiceUtilsForHandlers.getInstance().getTransactionalEditingDomain(event);
+ } catch (ServiceException ex) {
+ return null;
+ }
+ }
+
+ @Override
+ public void setEnabled(Object evaluationContext) {
+ if (evaluationContext instanceof IEvaluationContext) {
+ Object selection = ((IEvaluationContext) evaluationContext).getVariable(ISources.ACTIVE_CURRENT_SELECTION_NAME);
+ if (selection instanceof Collection<?>) {
+ this.selection = (selection instanceof List<?>) ? (List<?>) selection : new java.util.ArrayList<Object>((Collection<?>) selection);
+ } else if (selection instanceof IStructuredSelection) {
+ this.selection = ((IStructuredSelection) selection).toList();
+ }
+ setBaseEnabled(computeEnabled());
+ this.selection = Collections.EMPTY_LIST;
+ }
+ super.setEnabled(evaluationContext);
+ }
+
+ protected boolean computeEnabled() {
+ List<EObject> elts = getSelectedElements();
+ return !(elts.size() == 0);
+ }
+
+ protected List<?> getSelection() {
+ return selection;
+ }
+
+ protected List<?> selection = Collections.EMPTY_LIST;
+
+ /**
+ *
+ * @return true if the command can be executed
+ */
+ public boolean isVisible() {
+ return isEnabled();
+ }
+}
diff --git a/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/AbstractEMFParametricOnSelectedElementsAction.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/AbstractEMFParametricOnSelectedElementsAction.java
new file mode 100644
index 00000000000..001b9b50bc4
--- /dev/null
+++ b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/AbstractEMFParametricOnSelectedElementsAction.java
@@ -0,0 +1,61 @@
+/*****************************************************************************
+ * Copyright (c) 2015 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:
+ * Francois Le Fevre (CEA LIST) francois.le-fevre@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.menu;
+
+import java.util.List;
+
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.common.command.UnexecutableCommand;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.papyrus.infra.ui.menu.AbstractParametricOnSelectedElementsAction;
+
+
+public abstract class AbstractEMFParametricOnSelectedElementsAction extends AbstractParametricOnSelectedElementsAction {
+
+ /**
+ *
+ * Constructor.
+ *
+ * @param parameter
+ * parameter for the action
+ * @param selectedEditPart
+ * the selectedEditPart for the action
+ */
+ public AbstractEMFParametricOnSelectedElementsAction(String parameter, List<EObject> selectedEditPart) {
+ super(parameter, selectedEditPart);
+ }
+
+ /**
+ * Returns the command for this action
+ *
+ * @return
+ * the command for this action
+ */
+ public Command getCommand() {
+ if (isEnabled()) {
+ Command cmd = getBuildedCommand();
+ if (cmd != null && cmd.canExecute()) {
+ return cmd;
+ }
+ }
+ return UnexecutableCommand.INSTANCE;
+ }
+
+ /**
+ *
+ * @return
+ * the command for this action
+ */
+ protected abstract Command getBuildedCommand();
+}
diff --git a/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/AbstractParametricOnSelectedElementsAction.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/AbstractParametricOnSelectedElementsAction.java
new file mode 100644
index 00000000000..5aa80a0b054
--- /dev/null
+++ b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/AbstractParametricOnSelectedElementsAction.java
@@ -0,0 +1,115 @@
+/*****************************************************************************
+ * Copyright (c) 2015 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:
+ * Francois Le Fevre (CEA LIST) francois.le-fevre@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.menu;
+
+import java.util.List;
+
+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.ui.Activator;
+import org.eclipse.papyrus.infra.ui.util.ServiceUtilsForActionHandlers;
+
+
+public abstract class AbstractParametricOnSelectedElementsAction {
+
+ /**
+ * parameter for the action
+ */
+ protected String parameter;
+
+ /**
+ * selected EditPart
+ */
+ private List<EObject> selection;
+
+ /**
+ *
+ * Constructor.
+ *
+ * @param parameter
+ * parameter for the action
+ * @param selectedEditPart
+ * the selectedEditPart for the action
+ */
+ public AbstractParametricOnSelectedElementsAction(String parameter, List<EObject> selectedEditPart) {
+ this.parameter = parameter;
+ this.selection = selectedEditPart;
+ }
+
+ /**
+ * Returns the selected Editparts for this action
+ *
+ * @return
+ * {@link #selection}
+ */
+ protected List<EObject> getSelection() {
+ return selection;
+ }
+
+ /**
+ * Test if the command can be build
+ *
+ * @return
+ * <code>true</code> if the command can be build
+ */
+ public boolean isEnabled() {
+ return true;
+ //return !selection.isEmpty();
+ }
+
+ /**
+ * Gets the parameter.
+ *
+ * @return the parameter
+ */
+ public String getParameter() {
+ return parameter;
+ }
+
+
+ /**
+ * Sets the parameter.
+ *
+ * @param parameter
+ * the new parameter
+ */
+ public void setParameter(String parameter) {
+ this.parameter = parameter;
+ }
+
+ /**
+ * executes the action
+ */
+ public void doRun(IProgressMonitor progressMonitor) {
+ // may be implemented by inherited class
+ };
+
+
+ /**
+ * Returns the {@link TransactionalEditingDomain}
+ *
+ * @return the {@link TransactionalEditingDomain} or <code>null</code> if it can not be found
+ */
+ protected TransactionalEditingDomain getEditingDomain() {
+ TransactionalEditingDomain editingDomain = null;
+ try {
+ editingDomain = ServiceUtilsForActionHandlers.getInstance().getTransactionalEditingDomain();
+ } catch (ServiceException e) {
+ Activator.log.error(e);
+ }
+ return editingDomain;
+ }
+}
diff --git a/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/NameNormalization.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/NameNormalization.java
new file mode 100644
index 00000000000..44d3711682d
--- /dev/null
+++ b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/NameNormalization.java
@@ -0,0 +1,24 @@
+/*****************************************************************************
+ * Copyright (c) 2015 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.menu;
+
+/**
+ * @author flefevre
+ *
+ */
+public interface NameNormalization {
+
+ public String normalizeName(String name, String parameter);
+
+}
diff --git a/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/NameNormalizationCommand.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/NameNormalizationCommand.java
new file mode 100644
index 00000000000..563cb346a83
--- /dev/null
+++ b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/NameNormalizationCommand.java
@@ -0,0 +1,124 @@
+/*****************************************************************************
+ * Copyright (c) 2015 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:
+ * Francois Le Fevre (CEA LIST) francois.le-fevre@cea.fr - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.menu;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.transaction.RecordingCommand;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+
+/**
+ * this command is used to create a link "satisfyBy" between requirement and namedElement
+ *
+ */
+public abstract class NameNormalizationCommand extends RecordingCommand implements NameNormalization{
+ protected EObject source;
+ protected String parameter;
+
+ private final String BLANK= new String("");//$NON-NLS-1$
+ private final String SPACE= new String(" ");//$NON-NLS-1$
+ private final String MULTISPACE= new String(" +");//$NON-NLS-1$
+ private final String UNDERSCORE= new String("_");//$NON-NLS-1$
+ private final String MULTIUNDERSCORE= new String("_+");//$NON-NLS-1$
+
+ public static final String NAME_ACTION="name quick formatting action";//$NON-NLS-1$
+
+ public static final String DEFAULT_ACTION="default";//$NON-NLS-1$
+ public static final String UPPERCASE_ACTION="uppercase";//$NON-NLS-1$
+ public static final String LOWERCASE_ACTION="lowercase";//$NON-NLS-1$
+ public static final String SWITCHSPACE2UNDERSCORE_ACTION="switchSpace2Underscore";//$NON-NLS-1$
+ public static final String CAPITALIZEFIRSTLETTER_ACTION="capitalizeFirstLetter";//$NON-NLS-1$
+ public static final String REMOVESPACE_ACTION="removeSpace";//$NON-NLS-1$
+
+ public NameNormalizationCommand(TransactionalEditingDomain domain, EObject source, String normalization){
+ super(domain,NAME_ACTION+": "+normalization);
+ this.source=source;
+ this.parameter=normalization;
+ }
+
+ public String normalizeName(String name, String parameter){
+ String newName = new String(name);
+ switch (parameter) {
+ case UPPERCASE_ACTION:
+ newName = getUpperCaseName(name);
+ break;
+ case LOWERCASE_ACTION:
+ newName = getLowerCaseName(name);
+ break;
+ case SWITCHSPACE2UNDERSCORE_ACTION:
+ newName = switchSpace2UnderscoreName(name);
+ break;
+ case REMOVESPACE_ACTION:
+ newName = removeSpaceName(name);
+ break;
+ case CAPITALIZEFIRSTLETTER_ACTION:
+ newName = capitalizeName(name);
+ break;
+
+ default:
+ newName = new String(name);
+ break;
+ }
+ return newName;
+ }
+
+ private String capitalizeName(String name) {
+ String[] ns = name.split(" ");
+ StringBuffer finalName=new StringBuffer();
+ for(String n : ns){
+ finalName.append(n.substring(0, 1).toUpperCase()+n.substring(1,n.length())+" ");
+ }
+ return finalName.toString().trim();
+ }
+
+ private String removeSpaceName(String name) {
+ StringBuffer finalName=new StringBuffer();
+ int spacePos = name.indexOf(SPACE);
+ if(spacePos>0){
+ finalName.append(name.replace(SPACE, BLANK));
+ }
+ else{
+ finalName.append(name.replaceAll("(.)([A-Z])", "$1 $2"));//$NON-NLS-1$
+ }
+
+ return finalName.toString().trim();
+ }
+
+ private String getUpperCaseName(String name){
+ return name.toUpperCase().trim();
+ }
+
+ private String getLowerCaseName(String name){
+ return name.toLowerCase().trim();
+ }
+
+ private String switchSpace2UnderscoreName(String name){
+ StringBuffer finalName=new StringBuffer();
+ int underscorePos = name.indexOf(UNDERSCORE);
+ int spacePos = name.indexOf(SPACE);
+ if(underscorePos>0 && spacePos>0 && underscorePos<spacePos){
+ finalName.append(name.replace(UNDERSCORE, BLANK));
+ }
+ else if(underscorePos>0 && spacePos>0 && underscorePos>spacePos){
+ finalName.append(name.replace(SPACE, UNDERSCORE));
+ }
+ else if(underscorePos<0 && spacePos>0 ){
+ finalName.append(name.replace(SPACE, UNDERSCORE));
+ }
+ else if(underscorePos>0 && spacePos<0){
+ finalName.append(name.replace(UNDERSCORE, SPACE));
+ }
+
+ return finalName.toString().trim().replaceAll(MULTISPACE, SPACE).replaceAll(MULTIUNDERSCORE, UNDERSCORE);
+ }
+} \ No newline at end of file
diff --git a/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/NamePropertyTester.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/NamePropertyTester.java
new file mode 100644
index 00000000000..70287ddb3a3
--- /dev/null
+++ b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/menu/NamePropertyTester.java
@@ -0,0 +1,41 @@
+/*****************************************************************************
+ * Copyright (c) 2011 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:
+ * Francois Le Fevre (CEA LIST) francois.le-fevre@cea.fr - Initial API and implementation
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.menu;
+
+import org.eclipse.core.expressions.PropertyTester;
+import org.eclipse.jface.viewers.IStructuredSelection;
+
+public abstract class NamePropertyTester extends PropertyTester {
+ /**
+ * property associated with the parameter linked to the command in the plugin.xml
+ */
+ public static final String PARAMETER_ID = new String("org.eclipse.papyrus.infra.ui.menu.quickformatcommandParameter"); //$NON-NLS-1$
+ /**
+ * property to test if a diagram has the required edit policy
+ */
+ public static final String IS_NAME_CHANGEABLE = "isNameChangeable"; //$NON-NLS-1$
+
+
+ /**
+ *
+ * {@inheritDoc}
+ */
+ public boolean test(Object receiver, String property, Object[] args, Object expectedValue) {
+ if (IS_NAME_CHANGEABLE.equals(property) && receiver instanceof IStructuredSelection) {
+ boolean answer = isNameChangeable((IStructuredSelection) receiver);
+ return new Boolean(answer).equals(expectedValue);
+ }
+ return false;
+ }
+
+ protected abstract boolean isNameChangeable(IStructuredSelection selection);
+}
diff --git a/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/messages/Messages.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/messages/messages.properties b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/ActionBarContributorDescriptor.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/ActionBarContributorDescriptor.java
new file mode 100644
index 00000000000..3af4448ed36
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/ActionBarContributorExtensionFactory.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/ActionBarContributorExtensionFactory.java
new file mode 100644
index 00000000000..da949ab92ae
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/ActionBarContributorRegistry.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/ActionBarContributorRegistry.java
new file mode 100644
index 00000000000..347e1e0d5c7
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/CoreComposedActionBarContributor.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/CoreComposedActionBarContributor.java
new file mode 100644
index 00000000000..2e8459fe5cf
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/IActionBarContributorFactory.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/multidiagram/actionbarcontributor/IActionBarContributorFactory.java
new file mode 100644
index 00000000000..e296d88deab
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/AbstractPapyrusPreferencePage.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/AbstractPapyrusPreferencePage.java
new file mode 100644
index 00000000000..13426ddc474
--- /dev/null
+++ b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/AbstractPapyrusPreferencePage.java
@@ -0,0 +1,237 @@
+/****************************************************************************
+ * Copyright (c) 2008, 2016 Atos Origin, 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:
+ * Thibault Landre (Atos Origin) - Initial API and implementation
+ * Christian W. Damus - bug 485220
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.preferences;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ProjectScope;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.IWorkbenchPropertyPage;
+import org.eclipse.ui.preferences.ScopedPreferenceStore;
+
+/**
+ * An abstract implementation of a Preference page.
+ *
+ * This preference page allows clients to define preference page in the preference of Eclipse, and
+ * in the properties of a project in the workspace.
+ * <p>
+ * Clients must implement :
+ * <ul>
+ * <li>{@link #getBundleId()} method in order to define the preference scope (Project or Instance) of the preference page.</li>
+ * <li>{@link #createPageContents(Composite)} method to populate the preference page with the different {@link AbstractPreferenceGroup}s. </br>
+ * Each group added has to be declared through the {@link #addPreferenceGroup(AbstractPreferenceGroup)}</code> method</li>
+ * </ul>
+ * </p>
+ */
+public abstract class AbstractPapyrusPreferencePage extends PreferencePage implements IWorkbenchPreferencePage, IWorkbenchPropertyPage, IPapyrusPreferencePage {
+
+ private IProject project;
+
+ private Set<AbstractPreferenceGroup> groupSet;
+
+ private String key;
+
+ /**
+ * @see org.eclipse.ui.IWorkbenchPropertyPage#getElement()
+ */
+ @Override
+ public IAdaptable getElement() {
+ return project;
+ }
+
+ protected void setPreferenceKey(String aKey) {
+ this.key = aKey;
+ }
+
+ protected String getPreferenceKey() {
+ return this.key;
+ }
+
+ /**
+ * @see org.eclipse.ui.IWorkbenchPropertyPage#setElement(org.eclipse.core.runtime.IAdaptable)
+ */
+ @Override
+ public void setElement(IAdaptable element) {
+ project = (IProject) element.getAdapter(IResource.class);
+ }
+
+ /**
+ * @see org.eclipse.jface.preference.PreferencePage#doGetPreferenceStore()
+ */
+ @Override
+ protected IPreferenceStore doGetPreferenceStore() {
+ IPreferenceStore store;
+ if (project != null) {
+ store = new ScopedPreferenceStore(new ProjectScope(project), getBundleId());
+ } else {
+ store = new ScopedPreferenceStore(InstanceScope.INSTANCE, getBundleId());
+ }
+ return store;
+ }
+
+ /**
+ * Initializes this preference page for the given workbench.
+ *
+ * @param workbench
+ * the workbench
+ *
+ * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench)
+ *
+ */
+ @Override
+ public void init(IWorkbench workbench) {
+ // Do nothing
+ }
+
+ /**
+ * Create the Papyrus preference page and inits the different fields editor contained in the
+ * page.
+ * <p>
+ * This method shouldn't be overriden by sub-classes
+ * </p>
+ * {@inheritDoc}
+ */
+ @Override
+ protected Control createContents(Composite parent) {
+ // Create the container composite
+ Composite container = new Composite(parent, SWT.NONE);
+ GridLayout containerLayout = new GridLayout();
+ container.setLayout(containerLayout);
+
+ createPageContents(container);
+
+ initGroup();
+
+ return container;
+ }
+
+ /**
+ * Populate the preference page with the different field editor.
+ * <p>
+ * Each field added has to be declared through the <code>addEditorFields(FieldEditor fe)</code> method
+ * </p>
+ *
+ * @param parent
+ * the parent composite
+ */
+ protected abstract void createPageContents(Composite parent);
+
+ /**
+ * Add the given field editor to the page.
+ */
+ protected void addPreferenceGroup(AbstractPreferenceGroup fe) {
+ if (groupSet == null) {
+ groupSet = new HashSet<>();
+ }
+ groupSet.add(fe);
+ }
+
+ @Override
+ public boolean performOk() {
+ VisiblePageSingleton.getInstance().store();
+ return super.performOk();
+ }
+
+ /**
+ * Stores the values of the fields contained in this page into the preference store.
+ */
+ protected void storePreferences() {
+ if (groupSet != null) {
+ for (AbstractPreferenceGroup gs : groupSet) {
+ gs.storePreferences();
+ }
+ }
+ }
+
+ /**
+ * Store all preferences
+ */
+ @Override
+ public void storeAllPreferences() {
+ storePreferences();
+
+ }
+
+ @Override
+ protected void performDefaults() {
+ loadDefaultPreferences();
+ super.performDefaults();
+ }
+
+ /**
+ * Load the default preferences of the fields contained in this page
+ */
+ private void loadDefaultPreferences() {
+ if (groupSet != null) {
+ for (AbstractPreferenceGroup gs : groupSet) {
+ gs.loadDefault();
+ }
+ }
+
+ }
+
+ /**
+ * Init groups contained in this page.
+ */
+ private void initGroup() {
+ if (groupSet != null) {
+ for (AbstractPreferenceGroup gs : groupSet) {
+ gs.setPreferenceStore(getPreferenceStore());
+ gs.load();
+ }
+ }
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+ if (groupSet != null) {
+ for (AbstractPreferenceGroup gs : groupSet) {
+ gs.dispose();
+ }
+ }
+
+
+ }
+
+ @Override
+ public void setVisible(boolean visible) {
+ if (visible == true) {
+ VisiblePageSingleton.getInstance().setVisiblePage(this);
+ initGroup();
+ }
+ super.setVisible(visible);
+
+ }
+
+ /**
+ * The bundle ID used to defined the preference store
+ *
+ * @return String
+ */
+ protected abstract String getBundleId();
+
+}
diff --git a/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/AbstractPapyrusPreferenceStore.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/AbstractPapyrusPreferenceStore.java
new file mode 100644
index 00000000000..922fd74b9c3
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/AbstractPreferenceGroup.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/AbstractPreferenceGroup.java
new file mode 100644
index 00000000000..b90d098e54b
--- /dev/null
+++ b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/AbstractPreferenceGroup.java
@@ -0,0 +1,161 @@
+/*****************************************************************************
+ * Copyright (c) 2009, 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:
+ * Patrick Tessier (CEA LIST) Patrick.tessier@cea.fr
+ * Thibault Landre (Atos Origin)
+ * Christian W. Damus - bug 485220
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.preferences;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.jface.dialogs.DialogPage;
+import org.eclipse.jface.preference.FieldEditor;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * The Class AbstractPreferenceGroup.
+ */
+public abstract class AbstractPreferenceGroup extends Composite {
+
+ /** The key to find preference */
+ private String key;
+
+ /**
+ * The fieldsEditor : a set that will contain all editor in the composite. It is in charge of
+ * loading / storing / setting the preference store / loading default of all its contained field
+ * editor
+ */
+ private Set<FieldEditor> fieldsEditor;
+
+ /**
+ * Gets the dialog page.
+ *
+ * @return the dialogPage
+ */
+ protected DialogPage getDialogPage() {
+ return dialogPage;
+ }
+
+ /** The dialog page. */
+ protected DialogPage dialogPage;
+
+ /**
+ * Gets the title.
+ *
+ * @return the title
+ */
+ public String getKey() {
+ return key;
+ }
+
+ /**
+ * Sets the title.
+ *
+ * @param title
+ * the title to set
+ */
+ protected void setKey(String title) {
+ this.key = title;
+ }
+
+ /**
+ * Instantiates a new abstract group.
+ *
+ * @param parent
+ * the parent of the composite
+ * @param String
+ * the title of the page
+ * @param dialogPage
+ * to set the page in field editor
+ */
+ public AbstractPreferenceGroup(Composite parent, String key, DialogPage dialogPage) {
+ super(parent, SWT.None);
+ this.key = key;
+ this.dialogPage = dialogPage;
+ this.setLayout(new GridLayout());
+ fieldsEditor = new HashSet<FieldEditor>();
+ }
+
+ /**
+ * Gets an encapsulated composite. This composite is used to contain a FieldEditor and to allow
+ * developers to work with a FieldEditor like Composite element.
+ *
+ * @param parent
+ * the parent
+ *
+ * @return the encapsulated compo
+ */
+ protected final Composite getEncapsulatedComposite(Composite parent) {
+ Composite compo = new Composite(parent, SWT.NONE);
+ compo.setLayout(new GridLayout());
+ return compo;
+ }
+
+ /**
+ * Register field editor. It will add the fieldEditor to a map that will be used to
+ * store/load/loadDefault/set the PreferenceStore of contained fieldEditor
+ *
+ * @param fieldEditor
+ * the fieldEditor to add.
+ */
+ protected void addFieldEditor(FieldEditor fieldEditor) {
+ fieldsEditor.add(fieldEditor);
+ }
+
+ /**
+ * Load preferences of all registered fieldEditors.
+ *
+ * @see org.eclipse.papyrus.infra.AbstractPreferenceGroup.preferences.ui.AbstractGroup#addFieldEditor(FieldEditor)
+ */
+ public void load() {
+ for (FieldEditor fe : fieldsEditor) {
+ fe.load();
+ }
+ }
+
+ /**
+ * Set the preference store of all registered fieldEditors.
+ *
+ * @see org.eclipse.papyrus.infra.AbstractPreferenceGroup.preferences.ui.AbstractGroup#addFieldEditor(FieldEditor)
+ */
+ public final void setPreferenceStore(IPreferenceStore store) {
+ for (FieldEditor fe : fieldsEditor) {
+ fe.setPreferenceStore(store);
+ }
+ }
+
+ /**
+ * Load default preferences of all registered fieldEditors.
+ *
+ * @see org.eclipse.papyrus.infra.AbstractPreferenceGroup.preferences.ui.AbstractGroup#addFieldEditor(FieldEditor)
+ */
+ public final void loadDefault() {
+ for (FieldEditor fe : fieldsEditor) {
+ fe.loadDefault();
+ }
+ }
+
+ /**
+ * Store preferences of the registered fieldEditors.
+ *
+ * @see org.eclipse.papyrus.infra.AbstractPreferenceGroup.preferences.ui.AbstractGroup#addFieldEditor(FieldEditor)
+ */
+ public final void storePreferences() {
+ for (FieldEditor fe : fieldsEditor) {
+ fe.store();
+ }
+ }
+
+}
diff --git a/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/IPapyrusPreferencePage.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/IPapyrusPreferencePage.java
new file mode 100644
index 00000000000..4a82d671fef
--- /dev/null
+++ b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/IPapyrusPreferencePage.java
@@ -0,0 +1,28 @@
+/*****************************************************************************
+ * Copyright (c) 2010, 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:
+ * CEA LIST - Initial API and implementation
+ * Christian W. Damus - bug 485220
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.ui.preferences;
+
+import org.eclipse.jface.preference.IPreferencePage;
+
+/**
+ * Specialized protocol for preference pages participating in the {@link VisiblePageSingleton}
+ * mechanism.
+ */
+public interface IPapyrusPreferencePage extends IPreferencePage {
+ /**
+ * Requests the page to store all of its preferences in the preference store.
+ */
+ void storeAllPreferences();
+}
diff --git a/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/PapyrusScopedPreferenceStore.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/VisiblePageSingleton.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/VisiblePageSingleton.java
new file mode 100644
index 00000000000..7fafd1364aa
--- /dev/null
+++ b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/VisiblePageSingleton.java
@@ -0,0 +1,67 @@
+/*****************************************************************************
+ * Copyright (c) 2010, 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:
+ * Patrick Tessier (CEA LIST) Patrick.tessier@cea.fr - Initial API and implementation
+ * Christian W. Damus - bug 485220
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.preferences;
+
+import org.eclipse.jface.preference.IPreferencePage;
+
+/**
+ * This singleton has bee created to manage the button ok and apply of preference page.
+ * In the case of button ok pressed, the behavior of eclipse try of apply in the first preference page found.
+ * Here each page has a specific behavior. So to store the preference, the active page is called
+ *
+ */
+public class VisiblePageSingleton {
+
+ private static VisiblePageSingleton instance;
+
+ private IPreferencePage page;
+
+ /**
+ *
+ * @return the instance of the {@link VisiblePageSingleton}
+ */
+ public static VisiblePageSingleton getInstance() {
+ if (instance == null) {
+ instance = new VisiblePageSingleton();
+ }
+ return instance;
+ }
+
+ /**
+ * set the visible page
+ *
+ * @param page
+ * a {@link IPreferencePage} --> {@link DiagramPreferencePage} or {@link AbstractPapyrusPreferencePage}
+ */
+ public void setVisiblePage(IPreferencePage page) {
+ this.page = page;
+ }
+
+ /**
+ *
+ * @return the Visible Page
+ */
+ public IPreferencePage getVisiblePage() {
+ return this.page;
+ }
+
+ /**
+ * call the visisble page in order to store preferences
+ */
+ public void store() {
+ if (this.page instanceof IPapyrusPreferencePage) {
+ ((IPapyrusPreferencePage) (this.page)).storeAllPreferences();
+ }
+ }
+}
diff --git a/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/dialog/AbstractApplyValueOnPreferenceKeyDialog.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/dialog/AbstractApplyValueOnPreferenceKeyDialog.java
new file mode 100644
index 00000000000..3b4a3791000
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/dialog/AbstractPreferenceKeyDialog.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/preferences/dialog/AbstractPreferenceKeyDialog.java
new file mode 100644
index 00000000000..14b07d5d618
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/providers/CompositePapyrusContentProvider.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/providers/CompositePapyrusContentProvider.java
new file mode 100644
index 00000000000..b667228dde5
--- /dev/null
+++ b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/providers/CompositePapyrusContentProvider.java
@@ -0,0 +1,109 @@
+/*****************************************************************************
+ * Copyright (c) 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.providers;
+
+import java.util.Objects;
+import java.util.stream.Stream;
+
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.papyrus.infra.widgets.providers.IAdaptableContentProvider;
+import org.eclipse.papyrus.infra.widgets.providers.IHierarchicContentProvider;
+import org.eclipse.papyrus.infra.widgets.providers.IStaticContentProvider;
+
+import com.google.common.collect.Iterables;
+
+/**
+ * A content provider that synthesizes content from multiple other providers.
+ */
+public class CompositePapyrusContentProvider implements IAdaptableContentProvider, IHierarchicContentProvider, IStaticContentProvider {
+
+ private final ITreeContentProvider[] delegates;
+
+ public CompositePapyrusContentProvider(ITreeContentProvider... delegates) {
+ super();
+
+ this.delegates = new ITreeContentProvider[delegates.length];
+ for (int i = 0; i < delegates.length; i++) {
+ // Wrap it or not, as needed
+ this.delegates[i] = DelegatingPapyrusContentProvider.wrap(delegates[i]);
+ }
+ }
+
+ public CompositePapyrusContentProvider(Iterable<? extends ITreeContentProvider> delegates) {
+ this(Iterables.toArray(delegates, ITreeContentProvider.class));
+ }
+
+ @Override
+ public Object[] getElements(Object inputElement) {
+ return Stream.of(delegates)
+ .flatMap(d -> Stream.of(d.getElements(inputElement)))
+ .toArray();
+ }
+
+ @Override
+ public void dispose() {
+ Stream.of(delegates).forEach(ITreeContentProvider::dispose);
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ Stream.of(delegates).forEach(d -> d.inputChanged(viewer, oldInput, newInput));
+ }
+
+ @Override
+ public Object[] getChildren(Object parentElement) {
+ return Stream.of(delegates)
+ .flatMap(d -> Stream.of(d.getChildren(parentElement)))
+ .toArray();
+ }
+
+ @Override
+ public Object getParent(Object element) {
+ return Stream.of(delegates)
+ .map(d -> d.getParent(element))
+ .filter(Objects::nonNull)
+ .findAny().orElse(null);
+ }
+
+ @Override
+ public boolean hasChildren(Object element) {
+ return Stream.of(delegates)
+ .anyMatch(d -> d.hasChildren(element));
+ }
+
+ @Override
+ public Object getAdaptedValue(Object containerElement) {
+ return Stream.of(delegates)
+ .map(IAdaptableContentProvider.class::cast)
+ .map(d -> d.getAdaptedValue(containerElement))
+ .filter(Objects::nonNull)
+ .findAny().orElse(containerElement);
+ }
+
+ @Override
+ public boolean isValidValue(Object element) {
+ return Stream.of(delegates)
+ .map(IHierarchicContentProvider.class::cast)
+ .anyMatch(d -> d.isValidValue(element));
+ }
+
+ @Override
+ public Object[] getElements() {
+ return Stream.of(delegates)
+ .map(IStaticContentProvider.class::cast)
+ .flatMap(d -> Stream.of(d.getElements()))
+ .toArray();
+ }
+
+}
diff --git a/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/providers/CompositeSemanticContentProviderFactory.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/providers/CompositeSemanticContentProviderFactory.java
new file mode 100644
index 00000000000..71616365e59
--- /dev/null
+++ b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/providers/CompositeSemanticContentProviderFactory.java
@@ -0,0 +1,63 @@
+/*****************************************************************************
+ * Copyright (c) 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.providers;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+
+/**
+ * Default implementation of a composite content-provider factory.
+ */
+class CompositeSemanticContentProviderFactory implements ISemanticContentProviderFactory {
+ private final List<ISemanticContentProviderFactory> factories;
+
+ CompositeSemanticContentProviderFactory(ISemanticContentProviderFactory first, ISemanticContentProviderFactory second) {
+ super();
+
+ factories = Arrays.asList(first, second);
+ }
+
+ private CompositeSemanticContentProviderFactory(CompositeSemanticContentProviderFactory composite, ISemanticContentProviderFactory other) {
+ super();
+
+ if (other instanceof CompositeSemanticContentProviderFactory) {
+ List<ISemanticContentProviderFactory> otherFactories = ((CompositeSemanticContentProviderFactory) other).factories;
+ factories = new ArrayList<>(composite.factories.size() + otherFactories.size());
+ factories.addAll(composite.factories);
+ factories.addAll(otherFactories);
+ } else {
+ factories = new ArrayList<>(composite.factories.size() + 1);
+ factories.addAll(composite.factories);
+ factories.add(other);
+ }
+ }
+
+ @Override
+ public ITreeContentProvider createSemanticContentProvider(ResourceSet resourceSet) {
+ return DelegatingPapyrusContentProvider.compose(factories.stream()
+ .map(f -> f.createSemanticContentProvider(resourceSet))
+ .collect(Collectors.toList()));
+ }
+
+ @Override
+ public ISemanticContentProviderFactory compose(ISemanticContentProviderFactory other) {
+ return new CompositeSemanticContentProviderFactory(this, other);
+ }
+
+}
diff --git a/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/providers/DelegatingPapyrusContentProvider.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/providers/DelegatingPapyrusContentProvider.java
new file mode 100644
index 00000000000..de1ddcce51f
--- /dev/null
+++ b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/providers/DelegatingPapyrusContentProvider.java
@@ -0,0 +1,170 @@
+/*****************************************************************************
+ * Copyright (c) 2012, 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 (CEA) - bug 410346
+ * Christian W. Damus - bug 485220
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.providers;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.papyrus.infra.tools.util.TypeUtils;
+import org.eclipse.papyrus.infra.widgets.providers.IAdaptableContentProvider;
+import org.eclipse.papyrus.infra.widgets.providers.IHierarchicContentProvider;
+import org.eclipse.papyrus.infra.widgets.providers.IStaticContentProvider;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+/**
+ * A content-provider implementing the complete set of Papyrus-specific content-provider APIs that
+ * delegates those APIs to another provider according to its actual capabilities.
+ */
+public class DelegatingPapyrusContentProvider implements IAdaptableContentProvider, IHierarchicContentProvider, IStaticContentProvider {
+
+ private static final Object[] NONE = {};
+
+ private final ITreeContentProvider treeDelegate;
+ private final IAdaptableContentProvider adaptableDelegate;
+ private final IHierarchicContentProvider hierarchicDelegate;
+ private final IStaticContentProvider staticDelegate;
+
+ public DelegatingPapyrusContentProvider(ITreeContentProvider delegate) {
+ super();
+
+ treeDelegate = delegate;
+ adaptableDelegate = TypeUtils.as(delegate, IAdaptableContentProvider.class);
+ hierarchicDelegate = TypeUtils.as(delegate, IHierarchicContentProvider.class);
+ staticDelegate = TypeUtils.as(delegate, IStaticContentProvider.class);
+ }
+
+ /**
+ * Obtains a content-provider based on the given {@code provider} that implements all of the
+ * the Papyrus-specific extension protocols.
+ *
+ * @param provider
+ * a tree-content provider
+ * @return a complete provider, which may be a delegating provider or may be the original
+ * {@code provider} if it is already complete
+ */
+ public static ITreeContentProvider wrap(ITreeContentProvider provider) {
+ return ((provider instanceof IAdaptableContentProvider) && (provider instanceof IHierarchicContentProvider) && (provider instanceof IStaticContentProvider))
+ ? provider
+ : new DelegatingPapyrusContentProvider(provider);
+ }
+
+ /**
+ * Obtains a content-provider based on the given providers that implements all of the
+ * the Papyrus-specific extension protocols.
+ *
+ * @param first,&nbsp;second,&nbsp;rest
+ * two or more tree-content providers
+ * @return a complete provider based on the given providers
+ */
+ public static ITreeContentProvider compose(ITreeContentProvider first, ITreeContentProvider second, ITreeContentProvider... rest) {
+ return compose(Lists.asList(first, second, rest));
+ }
+
+ /**
+ * Obtains a content-provider based on the given {@code providers} that implements all of the
+ * the Papyrus-specific extension protocols.
+ *
+ * @param providers
+ * zero or more tree-content providers
+ * @return a complete provider based on the given {@code providers}
+ */
+ public static ITreeContentProvider compose(Iterable<? extends ITreeContentProvider> providers) {
+ ITreeContentProvider result;
+
+ // Obtain optimal result in case of a single provider
+ if (providers instanceof Collection<?>) {
+ Collection<? extends ITreeContentProvider> collection = (Collection<? extends ITreeContentProvider>) providers;
+ switch (collection.size()) {
+ case 0:
+ result = new CompositePapyrusContentProvider();
+ break;
+ case 1:
+ result = wrap(Iterables.getOnlyElement(collection));
+ break;
+ default:
+ result = new CompositePapyrusContentProvider(providers);
+ break;
+ }
+ } else {
+ Iterator<? extends ITreeContentProvider> iter = providers.iterator();
+ if (!iter.hasNext()) {
+ result = new CompositePapyrusContentProvider();
+ } else {
+ ITreeContentProvider provider = iter.next();
+ if (iter.hasNext()) {
+ result = new CompositePapyrusContentProvider(providers);
+ } else {
+ result = wrap(provider);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public Object[] getElements(Object inputElement) {
+ return treeDelegate.getElements(inputElement);
+ }
+
+ @Override
+ public void dispose() {
+ treeDelegate.dispose();
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ treeDelegate.inputChanged(viewer, oldInput, newInput);
+ }
+
+ @Override
+ public Object[] getChildren(Object parentElement) {
+ return treeDelegate.getChildren(parentElement);
+ }
+
+ @Override
+ public Object getParent(Object element) {
+ return treeDelegate.getParent(element);
+ }
+
+ @Override
+ public boolean hasChildren(Object element) {
+ return treeDelegate.hasChildren(element);
+ }
+
+ @Override
+ public Object getAdaptedValue(Object containerElement) {
+ return (adaptableDelegate == null)
+ ? containerElement
+ : adaptableDelegate.getAdaptedValue(containerElement);
+ }
+
+ @Override
+ public boolean isValidValue(Object element) {
+ return (hierarchicDelegate == null) || hierarchicDelegate.isValidValue(element);
+ }
+
+ @Override
+ public Object[] getElements() {
+ return (staticDelegate == null)
+ ? NONE
+ : staticDelegate.getElements();
+ }
+
+}
diff --git a/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/providers/ISemanticContentProviderFactory.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/providers/ISemanticContentProviderFactory.java
new file mode 100644
index 00000000000..05eecf9f087
--- /dev/null
+++ b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/providers/ISemanticContentProviderFactory.java
@@ -0,0 +1,59 @@
+/*****************************************************************************
+ * Copyright (c) 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.providers;
+
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.papyrus.infra.core.resource.IModel;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+
+/**
+ * <p>
+ * A protocol for creation of semantic model content providers on EMF resource sets.
+ * </p>
+ * <p>
+ * It is expected that {@link IModel}s representing semantic model content in the
+ * {@link ModelSet} provide adapters of this interface type for the purpose of obtaining
+ * suitable content-providers for presentation of the model content to the user.
+ * Because there there are potentially multiple such {@code IModel}s that have
+ * semantic content, it is possible that multiple content-providers will have to be
+ * combined via the {@link #compose(ISemanticContentProviderFactory)} API.
+ * </p>
+ *
+ * @see IModel
+ * @see #compose(ISemanticContentProviderFactory)
+ */
+@FunctionalInterface
+public interface ISemanticContentProviderFactory {
+ /**
+ * Creates a semantic model content provider on the given {@code ResourceSet}.
+ *
+ * @param resourceSet
+ * a resource set
+ *
+ * @return the semantic model content provider
+ */
+ ITreeContentProvider createSemanticContentProvider(ResourceSet resourceSet);
+
+ /**
+ * Obtains a factory that composes my provider with an{@code other} factory's provider.
+ *
+ * @param other
+ * another semantic content-provider factory
+ * @return the composed factory, which generally creates composed content providers
+ */
+ default ISemanticContentProviderFactory compose(ISemanticContentProviderFactory other) {
+ return new CompositeSemanticContentProviderFactory(this, other);
+ }
+}
diff --git a/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/EditorLifecycleEventListener.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/EditorLifecycleEventListener.java
new file mode 100644
index 00000000000..fb55dabd681
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/EditorLifecycleManager.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/EditorLifecycleManager.java
new file mode 100644
index 00000000000..d018ab385d1
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/Messages.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/Messages.java
new file mode 100644
index 00000000000..0b8d66d2056
--- /dev/null
+++ b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/Messages.java
@@ -0,0 +1,34 @@
+/*****************************************************************************
+ * 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.services;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Translatable strings.
+ */
+class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.papyrus.infra.ui.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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/ResourceUpdateService.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/ResourceUpdateService.java
new file mode 100644
index 00000000000..c83e251e17c
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/SaveLayoutBeforeClose.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/SaveLayoutBeforeClose.java
new file mode 100644
index 00000000000..5b84eadb2cb
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/internal/EditorLifecycleManagerImpl.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/internal/EditorLifecycleManagerImpl.java
new file mode 100644
index 00000000000..99a102093f5
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/internal/InternalEditorLifecycleManager.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/internal/InternalEditorLifecycleManager.java
new file mode 100644
index 00000000000..97420afd721
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/services/messages.properties b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/AbstractCreateMenuFromCommandCategory.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/AbstractCreateMenuFromCommandCategory.java
new file mode 100644
index 00000000000..c392791147e
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/DisplayUtils.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/DisplayUtils.java
new file mode 100644
index 00000000000..27bc70bb5bc
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/EclipseCommandUtils.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/EclipseCommandUtils.java
new file mode 100644
index 00000000000..ace809b60a5
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/EditorHelper.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/EditorHelper.java
new file mode 100644
index 00000000000..01802f176fa
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/EditorUtils.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/EditorUtils.java
new file mode 100644
index 00000000000..6918f42b92d
--- /dev/null
+++ b/plugins/infra/ui/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.ui.util.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.ui.util.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.ui.util.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.ui.util.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.ui.util.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.ui.util.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.ui.util.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.ui.util.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.ui.util.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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ICallableWithProgress.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ICallableWithProgress.java
new file mode 100644
index 00000000000..08d3f1d857b
--- /dev/null
+++ b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ICallableWithProgress.java
@@ -0,0 +1,50 @@
+/*****************************************************************************
+ * Copyright (c) 2014, 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.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;
+import org.eclipse.papyrus.infra.tools.util.IProgressCallable;
+
+/**
+ * The {@link Callable} analogue of an {@link IRunnableWithProgress}.
+ *
+ * @deprecated Use the {@link IProgressCallable} API, instead.
+ */
+@Deprecated
+public interface ICallableWithProgress<V> extends IProgressCallable<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
+ */
+ @Override
+ V call(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException;
+}
diff --git a/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/LocalMemento.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/PapyrusImageUtils.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/SelectionHelper.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/SelectionHelper.java
new file mode 100644
index 00000000000..5132a841f4c
--- /dev/null
+++ b/plugins/infra/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ServiceUtilsForActionHandlers.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ServiceUtilsForHandlers.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ServiceUtilsForHandlers.java
new file mode 100644
index 00000000000..aec185cc30e
--- /dev/null
+++ b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ServiceUtilsForHandlers.java
@@ -0,0 +1,122 @@
+/*****************************************************************************
+ * Copyright (c) 2012, 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 485220
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.util;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.papyrus.infra.core.sasheditor.editor.ISashWindowsContainer;
+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.ui.IEditorPart;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartSite;
+
+/**
+ * ServicesUtils based on the Handler's ExecutionEvent
+ *
+ * It first tests the current selection, then the IWorkbenchPart on which the handler is executed.
+ * The IWorkbenchPart is expected to be adaptable to a ServiceRegistry.
+ *
+ * @author Camille Letavernier
+ *
+ * @see ServiceUtilsForSelection
+ */
+public class ServiceUtilsForHandlers extends AbstractServiceUtils<ExecutionEvent> {
+
+ private ServiceUtilsForHandlers() {
+ // Singleton
+ }
+
+ /**
+ * 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(ExecutionEvent from) throws ServiceException {
+ return getService(ISashWindowsContainer.class, from).getActiveEditor();
+ }
+
+ @Override
+ public ServicesRegistry getServiceRegistry(ExecutionEvent from) throws ServiceException {
+
+ if (from == null) {
+ return getContextualServiceRegistry();
+ }
+
+ Object context = from.getApplicationContext();
+
+ if (context instanceof IEvaluationContext) {
+ IEvaluationContext evaluationContext = (IEvaluationContext) context;
+
+ // Search for the IWorkbenchPartSite from which the ExecutionEvent is sent (May be different that the Active one)
+ Object workbenchPartSite = evaluationContext.getVariable("org.eclipse.ui.IWorkbenchPartSite");
+ if (workbenchPartSite instanceof IWorkbenchPartSite) {
+ IWorkbenchPartSite site = (IWorkbenchPartSite) workbenchPartSite;
+ Object registry = site.getAdapter(ServicesRegistry.class);
+ if (registry != null && registry instanceof ServicesRegistry) {
+ return (ServicesRegistry) registry;
+ }
+
+ // Search for the IWorkbenchPart from which the ExecutionEvent is sent (May be different that the Active one)
+ IWorkbenchPart workbenchPart = site.getPart();
+ registry = workbenchPart.getAdapter(ServicesRegistry.class);
+ if (registry != null && registry instanceof ServicesRegistry) {
+ return (ServicesRegistry) registry;
+ }
+ }
+
+ Object selection = evaluationContext.getVariable(ISources.ACTIVE_CURRENT_SELECTION_NAME);
+
+ ServicesRegistry registry;
+
+ // Try to resolve the ServicesRegistry from the current selection
+ if (selection instanceof ISelection && !((ISelection) selection).isEmpty()) {
+ try {
+ registry = ServiceUtilsForSelection.getInstance().getServiceRegistry((ISelection) selection);
+ if (registry != null) {
+ return registry;
+ }
+ } catch (ServiceException ex) {
+ // Ignore and try another ServiceUtils
+ }
+ }
+
+ // We couldn't retrieve the ServiceRegistry from the current selection.
+
+ // Try to adapt the active part to the ServicesRegistry
+ IWorkbenchPart part = (IWorkbenchPart) evaluationContext.getVariable(ISources.ACTIVE_PART_NAME);
+ registry = (part).getAdapter(ServicesRegistry.class);
+ if (registry != null) {
+ return registry;
+ }
+ }
+
+ throw new ServiceNotFoundException("The ServiceRegistry cannot be resolved"); //$NON-NLS-1$
+ }
+
+
+
+ public static ServiceUtilsForHandlers getInstance() {
+ return instance;
+ }
+
+ private static final ServiceUtilsForHandlers instance = new ServiceUtilsForHandlers();
+}
diff --git a/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ServiceUtilsForIEvaluationContext.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ServiceUtilsForIEvaluationContext.java
new file mode 100644
index 00000000000..015a5e5076e
--- /dev/null
+++ b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ServiceUtilsForIEvaluationContext.java
@@ -0,0 +1,113 @@
+/*****************************************************************************
+ * Copyright (c) 2012, 2016 Cedric Dumoulin, 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 - Initial API and implementation
+ * Christian W. Damus - bug 485220
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.infra.ui.util;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.expressions.IEvaluationContext;
+import org.eclipse.jface.viewers.ISelection;
+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.ui.ISources;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartSite;
+
+/**
+ * ServicesUtils based on the Handler's IEvaluationContext.
+ * This class can be used for both the {@link AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)} and the {@link AbstractHandler#setEnabled(Object)} methods.
+ *
+ *
+ * @author Cedric Dumoulin
+ *
+ */
+public class ServiceUtilsForIEvaluationContext extends AbstractServiceUtils<IEvaluationContext> {
+
+ private ServiceUtilsForIEvaluationContext() {
+ // Singleton
+ }
+
+ /**
+ *
+ * @see org.eclipse.papyrus.infra.core.utils.AbstractServiceUtils#getServiceRegistry(java.lang.Object)
+ *
+ * @param from
+ * @return
+ * @throws ServiceException
+ */
+ @Override
+ public ServicesRegistry getServiceRegistry(IEvaluationContext from) throws ServiceException {
+
+ if (from == null) {
+ return getContextualServiceRegistry();
+ }
+
+ IEvaluationContext evaluationContext = from;
+
+ // Search for the IWorkbenchPartSite from which the ExecutionEvent is sent (May be different that the Active one)
+ Object workbenchPartSite = evaluationContext.getVariable("org.eclipse.ui.IWorkbenchPartSite");
+ if (workbenchPartSite instanceof IWorkbenchPartSite) {
+ IWorkbenchPartSite site = (IWorkbenchPartSite) workbenchPartSite;
+ Object registry = site.getAdapter(ServicesRegistry.class);
+ if (registry != null && registry instanceof ServicesRegistry) {
+ return (ServicesRegistry) registry;
+ }
+
+ // Search for the IWorkbenchPart from which the ExecutionEvent is sent (May be different that the Active one)
+ IWorkbenchPart workbenchPart = site.getPart();
+ registry = workbenchPart.getAdapter(ServicesRegistry.class);
+ if (registry != null && registry instanceof ServicesRegistry) {
+ return (ServicesRegistry) registry;
+ }
+ }
+
+ Object selection = evaluationContext.getVariable(ISources.ACTIVE_CURRENT_SELECTION_NAME);
+
+ ServicesRegistry registry;
+
+ // Try to resolve the ServicesRegistry from the current selection
+ if (selection instanceof ISelection && !((ISelection) selection).isEmpty()) {
+ try {
+ registry = ServiceUtilsForSelection.getInstance().getServiceRegistry((ISelection) selection);
+ if (registry != null) {
+ return registry;
+ }
+ } catch (ServiceException ex) {
+ // Ignore and try another ServiceUtils
+ }
+ }
+
+ // We couldn't retrieve the ServiceRegistry from the current selection.
+
+ // Try to adapt the active part to the ServicesRegistry
+ Object _part = evaluationContext.getVariable(ISources.ACTIVE_PART_NAME);
+ if (_part instanceof IWorkbenchPart) {
+ IWorkbenchPart part = (IWorkbenchPart) _part;
+ registry = (part).getAdapter(ServicesRegistry.class);
+ if (registry != null) {
+ return registry;
+ }
+ }
+
+
+ // nothing found
+ throw new ServiceNotFoundException("The ServiceRegistry cannot be resolved"); //$NON-NLS-1$
+ }
+
+ public static ServiceUtilsForIEvaluationContext getInstance() {
+ return instance;
+ }
+
+ private static final ServiceUtilsForIEvaluationContext instance = new ServiceUtilsForIEvaluationContext();
+}
diff --git a/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ServiceUtilsForSelection.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ServiceUtilsForSelection.java
new file mode 100644
index 00000000000..f3a799d303a
--- /dev/null
+++ b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ServiceUtilsForSelection.java
@@ -0,0 +1,61 @@
+/*****************************************************************************
+ * 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 java.util.Iterator;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+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.papyrus.infra.emf.utils.EMFHelper;
+import org.eclipse.papyrus.infra.emf.utils.ServiceUtilsForEObject;
+
+/**
+ * ServiceUtils based on an ISelection.
+ *
+ * Expects an IStructuredSelection containing at least one EObject (It then relies on ServiceUtilsForEObject to retrieve the ServicesRegistry)
+ *
+ * @author Camille Letavernier
+ */
+public class ServiceUtilsForSelection extends AbstractServiceUtils<ISelection> {
+
+ private ServiceUtilsForSelection() {
+ // Singleton
+ }
+
+ private static ServiceUtilsForSelection instance = new ServiceUtilsForSelection();
+
+ public static ServiceUtilsForSelection getInstance() {
+ return instance;
+ }
+
+ @Override
+ public ServicesRegistry getServiceRegistry(ISelection from) throws ServiceException {
+ if (from instanceof IStructuredSelection) {
+ IStructuredSelection selection = (IStructuredSelection) from;
+ Iterator<?> selectionIterator = selection.iterator();
+ while (selectionIterator.hasNext()) {
+ Object selectedElement = selectionIterator.next();
+ EObject selectedEObject = EMFHelper.getEObject(selectedElement);
+ if (selectedEObject != null) {
+ return ServiceUtilsForEObject.getInstance().getServiceRegistry(selectedEObject);
+ }
+ }
+ }
+
+ throw new ServiceException("Cannot retrieve the ServiceRegistry"); //$NON-NLS-1$
+ }
+
+}
diff --git a/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/ServiceUtilsForWorkbenchPage.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/TransactionUIHelper.java b/plugins/infra/ui/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/ui/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/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/UIUtil.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/UIUtil.java
new file mode 100644
index 00000000000..343bcdeba56
--- /dev/null
+++ b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/UIUtil.java
@@ -0,0 +1,706 @@
+/*
+ * 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.CompletableFuture;
+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.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
+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.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.core.utils.IServiceRegistryProvider;
+import org.eclipse.papyrus.infra.core.utils.ServiceUtils;
+import org.eclipse.papyrus.infra.tools.util.IExecutorService;
+import org.eclipse.papyrus.infra.tools.util.IProgressCallable;
+import org.eclipse.papyrus.infra.tools.util.IProgressRunnable;
+import org.eclipse.papyrus.infra.tools.util.Iterators2;
+import org.eclipse.papyrus.infra.ui.editor.IMultiDiagramEditor;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.progress.IProgressService;
+import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
+
+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}.
+ *
+ * @deprecated Use the {@link #call(IRunnableContext, boolean, boolean, IProgressCallable)} or
+ * {@link IExecutorService#submit(IProgressCallable)} API, instead.
+ */
+ @Deprecated
+ public static <V> V call(IRunnableContext context, boolean fork, boolean cancelable, ICallableWithProgress<V> callable) throws InvocationTargetException, InterruptedException {
+ return call(context, fork, cancelable, (IProgressCallable<V>) 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, IProgressCallable<V> callable) throws InvocationTargetException, InterruptedException {
+ class RunnableWrapper implements IRunnableWithProgress {
+ final IProgressCallable<V> delegate;
+
+ V result;
+
+ RunnableWrapper(IProgressCallable<V> delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+ try {
+ result = delegate.call(monitor);
+ } catch (OperationCanceledException e) {
+ throw new InterruptedException(e.getMessage());
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new InvocationTargetException(e);
+ }
+ }
+ }
+
+ 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;
+ }
+
+ @Override
+ public Future<?> submit(IProgressRunnable task) {
+ return submit(new IProgressCallable<Void>() {
+ @Override
+ public Void call(IProgressMonitor monitor) {
+ task.run(monitor);
+ return null;
+ }
+ });
+ }
+
+ @Override
+ public void syncExec(IProgressRunnable task) throws InterruptedException, ExecutionException {
+ syncCall(new IProgressCallable<Void>() {
+ @Override
+ public Void call(IProgressMonitor monitor) {
+ task.run(monitor);
+ return null;
+ }
+ });
+ }
+
+ IProgressService getProgressService(IProgressCallable<?> callable) {
+ IProgressService result;
+
+ try {
+ ServicesRegistry registry = (callable instanceof IServiceRegistryProvider)
+ ? ((IServiceRegistryProvider) callable).getServiceRegistry()
+ : null;
+ IMultiDiagramEditor editor = ServiceUtils.getInstance().getService(
+ IMultiDiagramEditor.class, registry);
+ result = editor.getEditorSite().getService(IWorkbenchSiteProgressService.class);
+ } catch (ServiceException e) {
+ // Fine, there's no editor
+ result = PlatformUI.getWorkbench().getProgressService();
+ }
+
+ 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);
+ }
+
+ @Override
+ public <V> Future<V> submit(IProgressCallable<V> callable) {
+ IProgressService service = getProgressService(callable);
+ IWorkbenchSiteProgressService wbService = (service instanceof IWorkbenchSiteProgressService) ? (IWorkbenchSiteProgressService) service : null;
+
+ FutureProgress<V> result = new FutureProgress<>(callable, wbService);
+
+ try {
+ service.run(true, true, result);
+ } catch (Exception e) {
+ // This shouldn't happen when running asynchronously
+ result.completeExceptionally(e);
+ }
+
+ return result;
+ }
+
+ @Override
+ public <V> V syncCall(IProgressCallable<V> callable) throws InterruptedException, ExecutionException {
+ IProgressService service = getProgressService(callable);
+ IWorkbenchSiteProgressService wbService = (service instanceof IWorkbenchSiteProgressService) ? (IWorkbenchSiteProgressService) service : null;
+
+ FutureProgress<V> result = new FutureProgress<>(callable, wbService);
+
+ try {
+ service.busyCursorWhile(result);
+ } catch (Exception e) {
+ result.completeExceptionally(e);
+ }
+
+ return result.get(); // It really should be completed, by now
+ }
+ }
+
+ 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);
+ }
+
+ @Override
+ public <V> Future<V> submit(IProgressCallable<V> callable) {
+ // No place to report progress in this case
+ FutureTask<V> result = new FutureTask<V>(() -> callable.call(new NullProgressMonitor()));
+ asyncExec(result);
+ return result;
+ }
+
+ @Override
+ public <V> V syncCall(IProgressCallable<V> callable) throws InterruptedException, ExecutionException {
+ // No place to report progress in this case
+ FutureTask<V> result = new FutureTask<V>(() -> callable.call(new NullProgressMonitor()));
+ syncExec(result);
+ return result.get(); // It really should be completed, by now
+ }
+ }
+
+ private static class FutureProgress<V> extends CompletableFuture<V> implements IRunnableWithProgress {
+ private final IProgressCallable<V> delegate;
+ private final IWorkbenchSiteProgressService service;
+
+ private volatile IProgressMonitor monitor;
+
+ FutureProgress(IProgressCallable<V> delegate, IWorkbenchSiteProgressService service) {
+ super();
+
+ this.delegate = delegate;
+ this.service = service;
+ }
+
+ @Override
+ public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+ try {
+ this.monitor = monitor;
+
+ if (service != null) {
+ service.incrementBusy();
+ }
+
+ try {
+ complete(delegate.call(monitor));
+ } finally {
+ this.monitor = null;
+
+ if (service != null) {
+ service.decrementBusy();
+ }
+ }
+ } catch (OperationCanceledException e) {
+ throw new InterruptedException(e.getMessage());
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new InvocationTargetException(e);
+ }
+ }
+
+ @Override
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ IProgressMonitor monitor = this.monitor;
+ if (monitor != null) {
+ monitor.setCanceled(true);
+ }
+
+ return super.cancel(mayInterruptIfRunning);
+ }
+
+ }
+}
diff --git a/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/WorkbenchPartHelper.java b/plugins/infra/ui/org.eclipse.papyrus.infra.ui/src/org/eclipse/papyrus/infra/ui/util/WorkbenchPartHelper.java
new file mode 100644
index 00000000000..4ecdc94d48f
--- /dev/null
+++ b/plugins/infra/ui/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