Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/infra/core/org.eclipse.papyrus.infra.core/schema/model.exsd38
-rw-r--r--plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/AbstractBaseModel.java8
-rw-r--r--plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/EMFLogicalModel.java16
-rw-r--r--plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/ResourceAdapter.java118
-rw-r--r--plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/utils/JobBasedFuture.java335
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/PapyrusROTransactionalEditingDomain.java7
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf/.classpath14
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf/.settings/org.eclipse.jdt.core.prefs6
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf/META-INF/MANIFEST.MF3
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/resource/AnyRootNamespaceContentHandler.java104
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/resource/index/IWorkspaceModelIndexListener.java61
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/resource/index/WorkspaceModelIndex.java864
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/resource/index/WorkspaceModelIndexAdapter.java58
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/resource/index/WorkspaceModelIndexEvent.java76
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/utils/EMFFunctions.java98
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/utils/EMFPredicates.java63
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/util/ICallableWithProgress.java45
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/util/ReferenceCounted.java175
-rw-r--r--plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/util/UIUtil.java152
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/commands/CreateControlResource.java25
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/participants/IControlCommandParticipant.java12
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/participants/IUncontrolCommandParticipant.java17
-rw-r--r--plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/MultipleValueEditor.java12
-rw-r--r--plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/providers/DelegatingLabelProvider.java25
-rw-r--r--plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/providers/DelegatingStyledLabelProvider.java61
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/.classpath7
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/.project28
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/.settings/org.eclipse.jdt.core.prefs291
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/.settings/org.eclipse.jdt.ui.prefs68
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/META-INF/MANIFEST.MF32
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/about.html28
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/build.properties9
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/documentation.pdoc4
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/plugin.properties12
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/plugin.xml11
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/pom.xml14
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/Activator.java118
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/DecoratorModelControlModeParticipant.java142
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/PackageRefactoringContext.java265
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/commands/AbstractDecoratorModelRefactoringCommand.java143
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/commands/ConfirmSaveCommand.java58
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/commands/DecoratorModelRefactoringCommandFactory.java236
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/commands/DirectionConstraint.java32
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/commands/LoadedDecoratorModelRefactoringCommand.java56
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/commands/SaveModelCommand.java148
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/commands/UnloadedDecoratorModelRefactoringCommand.java68
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/messages/Messages.java46
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/messages/messages.properties25
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/AbstractDecoratorModelUpdater.java61
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/AbstractDecoratorModelUpdaterDelegate.java94
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/CrossReferenceUpdater.java123
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/IDecoratorModelUpdaterDelegate.java35
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/IRefactoringStep.java31
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/LoadedDecoratorModelUpdaterDelegate.java49
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/PostControlDecoratorModelUpdater.java104
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/PostUncontrolDecoratorModelUpdater.java115
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/UnloadedDecoratorModelUpdaterDelegate.java52
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/.classpath7
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/.project28
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/.settings/org.eclipse.jdt.core.prefs291
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/.settings/org.eclipse.jdt.ui.prefs68
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/META-INF/MANIFEST.MF35
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/OSGI-INF/l10n/bundle.properties3
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/about.html28
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/build.properties11
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/documentation.pdoc4
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/icons/full/ctool16/dup_resource.pngbin0 -> 595 bytes
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/icons/full/ctool16/externalize.gifbin0 -> 329 bytes
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/icons/full/ctool16/internalize.gifbin0 -> 327 bytes
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/icons/full/ctool16/unload_resource.pngbin0 -> 4355 bytes
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/icons/full/dtool16/load_resource.pngbin0 -> 4218 bytes
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/icons/full/etool16/load_resource.pngbin0 -> 4323 bytes
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/plugin.xml12
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/pom.xml14
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/resources/UMLStereotypeApplicationExternalResource.ctx33
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/resources/UMLStereotypeApplicationExternalResourceEnvironment.xmi27
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/resources/ui/SinglePackageDecoratorModels.xwt12
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/resources/ui/SinglePackageProfile.xwt12
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/internal/properties/constraints/HasExternalizedProfileApplicationsConstraint.java83
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/internal/properties/messages/Messages.java43
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/internal/properties/messages/messages.properties12
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/properties/Activator.java111
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/properties/elements/AppliedProfilesObservableList.java65
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/properties/elements/DecoratorModelsObservableList.java243
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/properties/elements/PackageModelElement.java46
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/properties/elements/PackageModelElementFactory.java48
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/properties/widgets/DecoratorModelPropertyEditor.java340
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/properties/widgets/ProfileApplicationPropertyEditor.java208
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/.classpath7
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/.project28
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/.settings/org.eclipse.jdt.core.prefs291
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/.settings/org.eclipse.jdt.ui.prefs68
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/META-INF/MANIFEST.MF42
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/about.html28
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/build.properties10
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/documentation.pdoc4
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/icons/full/ovr16/profileApps.pngbin0 -> 2993 bytes
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/plugin.properties38
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/plugin.xml273
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/pom.xml14
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/Activator.java111
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/Startup.java32
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/commands/ExternalizeProfilesHandler.java51
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/commands/InternalizeProfilesHandler.java51
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/commands/LoadAvailableDecoratorModelsHandler.java61
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/commands/UnloadDecoratorModelHandler.java273
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/commands/UnloadLoadedDecoratorModelsHandler.java74
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/expressions/PackagePropertyTester.java134
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/messages/Messages.java98
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/messages/messages.properties67
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/preferences/DecoratorModelPreferencePage.java47
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/preferences/ProfileExternalizationUIPreferences.java69
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/preferences/WhenKind.java32
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/providers/AvailableDecoratorModelsSnippet.java169
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/providers/DecoratorModelLabelDecorator.java192
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/providers/DecoratorModelLabelProvider.java185
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/providers/EncapsulatedAdapterFactoryLabelProvider.java65
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/providers/ProfileResourceLabelProvider.java149
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/AbstractManageProfileApplicationsWizard.java168
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/AbstractNewDecoratorModelPage.java205
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/AbstractProfileApplicationSelectionPage.java227
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/AbstractProfileApplicationsPage.java36
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/ConflictingDecoratorModelsPage.java216
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/DecoratorModelSelectionPage.java319
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/DuplicateDecoratorModelPage.java176
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/DuplicateDecoratorModelWizard.java156
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/ExternalizeProfileApplicationsPage.java143
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/ExternalizeProfileApplicationsWizard.java138
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/InternalizeProfileApplicationsPage.java76
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/InternalizeProfileApplicationsWizard.java83
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/LoadDecoratorModelsPage.java120
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/LoadProfileApplicationsWizard.java230
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/UnloadProfileApplicationsWizard.java93
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/ui/providers/DeleteEmptyDecoratorModelsPolicy.java119
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/.classpath7
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/.project28
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/.settings/org.eclipse.jdt.core.prefs291
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/.settings/org.eclipse.jdt.ui.prefs68
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/META-INF/MANIFEST.MF39
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/about.html28
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/build.properties12
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/conception.textile43
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/documentation.pdoc4
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/model/ProfileExternalization.profile.di2
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/model/ProfileExternalization.profile.genmodel46
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/model/ProfileExternalization.profile.notation86
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/model/ProfileExternalization.profile.uml55
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/model/profileExternalization.ecore32
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/plugin.properties14
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/plugin.xml83
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/pom.xml14
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/Activator.java62
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/helper/DecoratorModelUtils.java1201
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/helper/IDeleteEmptyDecoratorModelsPolicy.java33
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/helper/PapyrusProfileApplicationHelper.java61
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/helper/PapyrusStereotypeApplicationHelper.java46
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/commands/CreateDecoratorModelCommand.java130
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/commands/DeleteDecoratorModelCommand.java105
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/commands/ReclaimProfileApplicationsCommand.java44
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/commands/SaveDecoratorModelCommand.java74
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/commands/SeparateProfileApplicationsCommand.java53
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/expressions/FilePropertyTester.java54
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/messages/Messages.java37
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/messages/messages.properties6
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/providers/ExternalizedProfileApplicationDelegate.java222
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/resource/DecoratorModelCopier.java207
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/resource/DecoratorModelIndex.java589
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/resource/DecoratorModelIndexEvent.java42
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/resource/DecoratorModelReadOnlyHandler.java79
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/resource/DecoratorModelResourceSet.java116
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/resource/IDecoratorModelIndexListener.java27
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/resource/index/ProfileIndexHandler.java367
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/model/DecoratorModel.java260
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/model/UMLSnippet.java118
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/ApplyProfiles.java92
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/ProfileExternalizationFactory.java56
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/ProfileExternalizationPackage.java249
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/impl/ApplyProfilesImpl.java274
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/impl/ProfileExternalizationFactoryImpl.java121
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/impl/ProfileExternalizationPackageImpl.java345
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/internal/operations/ApplyProfilesOperations.java88
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/util/ProfileExternalizationAdapterFactory.java148
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/util/ProfileExternalizationSwitch.java136
-rw-r--r--plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/util/ProfileExternalizationValidator.java231
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/commands/MoveProfileApplicationCommand.java7
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/commands/MoveStereotypeApplicationToControlResource.java10
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/helpers/ProfileApplicationHelper.java36
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/participants/StereotypeApplicationRepairParticipant.java167
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/ApplyProfileAction.java27
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/ZombieStereotypesDescriptor.java52
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.profile/META-INF/MANIFEST.MF1
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.profile/src/org/eclipse/papyrus/uml/profile/providers/ProfileApplicationContentProvider.java22
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.profile/src/org/eclipse/papyrus/uml/profile/service/ReapplyProfilesService.java71
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.profile/src/org/eclipse/papyrus/uml/profile/service/ui/RefreshProfileDialog.java22
-rw-r--r--plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/widgets/ProfileApplicationEditor.java51
-rw-r--r--plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/widgets/ProfileApplicationPropertyEditor.java10
-rw-r--r--plugins/uml/tools/org.eclipse.papyrus.uml.tools.utils/src/org/eclipse/papyrus/uml/tools/utils/CustomUMLUtil.java16
-rw-r--r--plugins/uml/tools/org.eclipse.papyrus.uml.tools.utils/src/org/eclipse/papyrus/uml/tools/utils/ProfileUtil.java63
-rw-r--r--plugins/uml/tools/org.eclipse.papyrus.uml.tools/plugin.xml1
-rw-r--r--plugins/uml/tools/org.eclipse.papyrus.uml.tools/schema/profileApplicationDelegates.exsd125
-rw-r--r--plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/commands/ApplyProfileCommand.java56
-rw-r--r--plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/ProfileApplicationObservableList.java31
-rw-r--r--plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/helper/IProfileApplicationDelegate.java135
-rw-r--r--plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/helper/ProfileApplicationDelegateRegistry.java245
204 files changed, 19335 insertions, 188 deletions
diff --git a/plugins/infra/core/org.eclipse.papyrus.infra.core/schema/model.exsd b/plugins/infra/core/org.eclipse.papyrus.infra.core/schema/model.exsd
index 3e924caa53e..d9644724ac7 100644
--- a/plugins/infra/core/org.eclipse.papyrus.infra.core/schema/model.exsd
+++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/schema/model.exsd
@@ -58,9 +58,10 @@ Registered model can be retrieved from the ModelSet.
</documentation>
</annotation>
<complexType>
- <sequence minOccurs="0" maxOccurs="unbounded">
+ <choice minOccurs="0" maxOccurs="unbounded">
<element ref="modelSnippet"/>
- </sequence>
+ <element ref="dependency"/>
+ </choice>
<attribute name="description" type="string">
<annotation>
<documentation>
@@ -150,6 +151,39 @@ The code is executed right after the modelSet is loaded.
</complexType>
</element>
+ <element name="dependency">
+ <complexType>
+ <choice minOccurs="1" maxOccurs="unbounded">
+ <element ref="loadAfter"/>
+ <element ref="unloadBefore"/>
+ </choice>
+ </complexType>
+ </element>
+
+ <element name="loadAfter">
+ <complexType>
+ <attribute name="identifier" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="unloadBefore">
+ <complexType>
+ <attribute name="identifier" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
<annotation>
<appInfo>
<meta.section type="since"/>
diff --git a/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/AbstractBaseModel.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/AbstractBaseModel.java
index b97d551c383..c9b798632be 100644
--- a/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/AbstractBaseModel.java
+++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/AbstractBaseModel.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2010, 2014 CEA LIST and others.
+ * Copyright (c) 2010, 2014 CEA LIST, Christian W. Damus, and others.
*
*
* All rights reserved. This program and the accompanying materials
@@ -11,6 +11,7 @@
* CEA LIST - Initial API and implementation
* Christian W. Damus (CEA) - manage models by URI, not IFile (CDO)
* Christian W. Damus (CEA) - bug 437052
+ * Christian W. Damus - bug 399859
*
*****************************************************************************/
package org.eclipse.papyrus.infra.core.resource;
@@ -269,6 +270,10 @@ public abstract class AbstractBaseModel extends AbstractModel implements IVersio
protected Map<Object, Object> getSaveOptions() {
+ return getDefaultSaveOptions();
+ }
+
+ public static Map<Object, Object> getDefaultSaveOptions() {
Map<Object, Object> saveOptions = new HashMap<Object, Object>();
// default save options.
@@ -288,7 +293,6 @@ public abstract class AbstractBaseModel extends AbstractModel implements IVersio
return saveOptions;
}
-
@Override
public void saveCopy(IPath targetPathWithoutExtension, Map<Object, Object> targetMap) {
// OutputStream targetStream = getOutputStream(targetPath);
diff --git a/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/EMFLogicalModel.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/EMFLogicalModel.java
index 653351be6a5..9ee222ffaca 100644
--- a/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/EMFLogicalModel.java
+++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/EMFLogicalModel.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2013, 2014 CEA LIST and others.
+ * Copyright (c) 2013, 2014 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
@@ -9,17 +9,20 @@
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
* Christian W. Damus (CEA) - bug 437052
+ * Christian W. Damus - bug 399859
*
*****************************************************************************/
package org.eclipse.papyrus.infra.core.resource;
import java.io.IOException;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.Set;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.papyrus.infra.core.Activator;
/**
@@ -33,9 +36,20 @@ public abstract class EMFLogicalModel extends AbstractBaseModel implements IEMFM
protected final Set<Resource> resources = new HashSet<Resource>();
public Set<Resource> getResources() {
+ pruneDeletedResources();
return resources;
}
+ protected void pruneDeletedResources() {
+ ResourceSet rset = getModelManager();
+ for (Iterator<Resource> iter = resources.iterator(); iter.hasNext();) {
+ if (iter.next().getResourceSet() != rset) {
+ // This resource was deleted
+ iter.remove();
+ }
+ }
+ }
+
@Override
protected void configureResource(Resource resourceToConfigure) {
super.configureResource(resourceToConfigure);
diff --git a/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/ResourceAdapter.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/ResourceAdapter.java
index 727a02170d1..862d550115d 100644
--- a/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/ResourceAdapter.java
+++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/resource/ResourceAdapter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 CEA and others.
+ * Copyright (c) 2014 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
@@ -8,10 +8,12 @@
*
* Contributors:
* Christian W. Damus (CEA) - Initial API and implementation
+ * Christian W. Damus - bug 399859
*
*/
package org.eclipse.papyrus.infra.core.resource;
+import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.Notifier;
@@ -21,6 +23,13 @@ import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.transaction.NotificationFilter;
+import org.eclipse.emf.transaction.ResourceSetChangeEvent;
+import org.eclipse.emf.transaction.ResourceSetListener;
+import org.eclipse.emf.transaction.RollbackException;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+
+import com.google.common.collect.ImmutableList;
/**
@@ -38,6 +47,15 @@ public abstract class ResourceAdapter extends AdapterImpl {
// Don't need to track resources as targets (there are multiple)
if (newTarget instanceof ResourceSet) {
super.setTarget(newTarget);
+
+ // Discover existing resources. Iterate the current set; any new additions
+ // will be discovered automatically
+ for (Resource next : ImmutableList.copyOf(((ResourceSet) newTarget).getResources())) {
+ handleResourceAdded(next);
+ if (next.isLoaded()) {
+ handleResourceLoaded(next);
+ }
+ }
}
}
@@ -203,4 +221,102 @@ public abstract class ResourceAdapter extends AdapterImpl {
protected void handleRootRemoved(Resource resource, EObject root) {
// Pass
}
+
+ //
+ // Nested types
+ //
+
+ /**
+ * A variant of the {@link ResourceAdapter} that is attached to a {@link TransactionalEditingDomain} to process batched notifications.
+ */
+ public static class Transactional extends ResourceAdapter implements ResourceSetListener {
+ private final boolean isPrecommit;
+
+ private final NotificationFilter filter = NotificationFilter.NOT_TOUCH.and(createFilter());
+
+ /**
+ * Initializes me as a post-commit resource notification handler.
+ */
+ public Transactional() {
+ this(false);
+ }
+
+ /**
+ * Initializes me as a pre- or post-commit resource notification handler.
+ *
+ * @param isPrecommit
+ * {@code true} to react to pre-commit notifications; {@code false} to react to post-commit notifications
+ */
+ public Transactional(boolean isPrecommit) {
+ this.isPrecommit = isPrecommit;
+ }
+
+ @Override
+ public boolean isAggregatePrecommitListener() {
+ return false;
+ }
+
+ @Override
+ public boolean isPrecommitOnly() {
+ return isPrecommit;
+ }
+
+ @Override
+ public boolean isPostcommitOnly() {
+ return !isPrecommit;
+ }
+
+ /**
+ * Subclasses may override/extend this method to create custom filters, perhaps based on the default filter create by the superclass.
+ * <b>Note</b> that this method is invoked by the superclass constructor, so subclasses must not attempt to access their own state.
+ *
+ * @return my notification filter
+ */
+ protected NotificationFilter createFilter() {
+ return NotificationFilter.createNotifierTypeFilter(ResourceSet.class).or(
+ NotificationFilter.createNotifierTypeFilter(Resource.class));
+ }
+
+ @Override
+ public NotificationFilter getFilter() {
+ return filter;
+ }
+
+ @Override
+ public void resourceSetChanged(ResourceSetChangeEvent event) {
+ handleResourceSetChangeEvent(event);
+ }
+
+ @Override
+ public Command transactionAboutToCommit(ResourceSetChangeEvent event) throws RollbackException {
+ handleResourceSetChangeEvent(event);
+ return null;
+ }
+
+ protected void handleResourceSetChangeEvent(ResourceSetChangeEvent event) {
+ for (Notification next : event.getNotifications()) {
+ notifyChanged(next);
+ }
+ }
+
+ @Override
+ public final void setTarget(Notifier newTarget) {
+ // Don't attach me to anything. I am fed directly by the editing domain
+ }
+
+ @Override
+ public final void unsetTarget(Notifier oldTarget) {
+ // Pass
+ }
+
+ @Override
+ protected final void addAdapter(Notifier notifier) {
+ // Don't attach me to anything. I am fed directly by the editing domain
+ }
+
+ @Override
+ protected final void removeAdapter(Notifier notifier) {
+ // Pass
+ }
+ }
}
diff --git a/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/utils/JobBasedFuture.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/utils/JobBasedFuture.java
new file mode 100644
index 00000000000..f5fb41b133b
--- /dev/null
+++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/utils/JobBasedFuture.java
@@ -0,0 +1,335 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.core.utils;
+
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicReference;
+
+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.OperationCanceledException;
+import org.eclipse.core.runtime.ProgressMonitorWrapper;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.IJobManager;
+import org.eclipse.core.runtime.jobs.ILock;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.papyrus.infra.core.Activator;
+
+import com.google.common.util.concurrent.ExecutionList;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * A Guava {@link ListenableFuture} implemented as an Eclipse {@link Job} to ensure that, in case the UI thread ever has to wait
+ * for the future result, the blockage is reported to the user with opportunity to cancel.
+ * <p>
+ * <b>Note</b> that no scheduling rule must be {@linkplain Job#setRule(ISchedulingRule) set} on instances of this class. Nor must the implementation of the {@link #compute(IProgressMonitor)} method attempt to
+ * {@linkplain IJobManager#beginRule(ISchedulingRule, IProgressMonitor) begin} an ad hoc rule. Doing either will almost certainly cause deadlock or worse.
+ */
+public abstract class JobBasedFuture<V> extends Job implements ListenableFuture<V> {
+ private static final ScheduledThreadPoolExecutor TIMEOUT_EXECUTOR = new ScheduledThreadPoolExecutor(1);
+
+ private final CountDownLatch started = new CountDownLatch(1);
+ private final ILock runningLock = Job.getJobManager().newLock();
+ private final ISchedulingRule rule = new ISchedulingRule() {
+
+ @Override
+ public boolean isConflicting(ISchedulingRule rule) {
+ return rule == this;
+ }
+
+ @Override
+ public boolean contains(ISchedulingRule rule) {
+ return rule == this;
+ }
+ };
+
+ private final AtomicReference<State> state = new AtomicReference<State>(State.RUNNING);
+
+ private volatile Throwable exception;
+ private final ExecutionList executions = new ExecutionList();
+
+ private volatile V value;
+
+ static {
+ TIMEOUT_EXECUTOR.setKeepAliveTime(10, TimeUnit.SECONDS);
+ TIMEOUT_EXECUTOR.allowCoreThreadTimeOut(true);
+ }
+
+ public JobBasedFuture(String name) {
+ super(name);
+
+ setSystem(true);
+ setRule(rule);
+ }
+
+ final boolean transition(State from, State to) {
+ return state.compareAndSet(from, to);
+ }
+
+ final State state() {
+ return state.get();
+ }
+
+ final boolean isInState(State state) {
+ return this.state.get() == state;
+ }
+
+ @Override
+ protected final IStatus run(IProgressMonitor monitor) {
+ IStatus result = Status.OK_STATUS;
+
+ runningLock.acquire();
+ started.countDown();
+
+ try {
+ setValue(compute(monitor));
+ } catch (CoreException e) {
+ result = e.getStatus();
+ fail(e);
+ } catch (ThreadDeath d) {
+ throw d;
+ } catch (Throwable t) {
+ result = new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Uncaught exception in future job", t); //$NON-NLS-1$
+ fail(t);
+ } finally {
+ runningLock.release();
+ }
+
+ return result;
+ }
+
+ protected abstract V compute(IProgressMonitor monitor) throws Exception;
+
+ @Override
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ boolean result = transition(State.RUNNING, State.CANCELLED);
+
+ if (result) {
+ try {
+ cancel();
+ } finally {
+ executions.execute();
+ }
+ }
+
+ return result;
+ }
+
+ boolean fail(Throwable t) {
+ boolean result = transition(State.RUNNING, State.FAILED);
+
+ if (result) {
+ exception = t;
+ executions.execute();
+ }
+
+ return result;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return isInState(State.CANCELLED);
+ }
+
+ @Override
+ public boolean isDone() {
+ return !isInState(State.RUNNING);
+ }
+
+ @Override
+ public V get() throws InterruptedException, ExecutionException {
+ awaitDone(0L);
+
+ return getValue();
+ }
+
+ @Override
+ public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+ if (!awaitDone(unit.toMillis(timeout))) {
+ throw new TimeoutException();
+ }
+
+ return getValue();
+ }
+
+ final boolean awaitDone(long timeoutMillis) throws InterruptedException {
+ // Check for short-circuit in case of running a listener on completion that
+ // then (obviously) tries to get our value
+ boolean result = isDone();
+
+ if (!result) {
+ Job current = Job.getJobManager().currentJob();
+ if ((current == null) || (current.getRule() == null)) {
+ result = uiSafeAwaitDone(timeoutMillis);
+ } else {
+ result = lockBasedAwaitDone(timeoutMillis);
+ }
+ }
+
+ return result;
+ }
+
+ private boolean lockBasedAwaitDone(long timeoutMillis) throws InterruptedException {
+ boolean result = false;
+
+ // Synchronize first on the start of execution of the job. This should never block for very long because the job
+ // will not have a scheduling rule that anyone else can begin
+
+ if (timeoutMillis <= 0L) {
+ started.await();
+ runningLock.acquire();
+
+ try {
+ result = isDone();
+ } finally {
+ runningLock.release();
+ }
+ } else {
+ final long startedWaiting = System.currentTimeMillis();
+ if (started.await(timeoutMillis, TimeUnit.MILLISECONDS)) {
+ long remaining = timeoutMillis - (System.currentTimeMillis() - startedWaiting);
+ if (remaining > 0L) {
+ if (runningLock.acquire(remaining)) {
+ try {
+ result = isDone();
+ } finally {
+ runningLock.release();
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ private boolean uiSafeAwaitDone(long timeoutMillis) throws InterruptedException {
+ boolean result = false;
+
+ // Synchronize first on the start of execution of the job. This should never block for very long because the job
+ // will not have a scheduling rule that anyone else can begin
+
+ if (timeoutMillis <= 0L) {
+ started.await();
+
+ try {
+ Job.getJobManager().beginRule(rule, null);
+ result = isDone();
+ } finally {
+ Job.getJobManager().endRule(rule);
+ }
+ } else {
+ final long startedWaiting = System.currentTimeMillis();
+ if (started.await(timeoutMillis, TimeUnit.MILLISECONDS)) {
+ long remaining = timeoutMillis - (System.currentTimeMillis() - startedWaiting);
+ final IProgressMonitor monitor = new TimeoutMonitor();
+
+ ScheduledFuture<?> timeout = TIMEOUT_EXECUTOR.schedule(new Runnable() {
+
+ @Override
+ public void run() {
+ monitor.setCanceled(true);
+ }
+ }, remaining, TimeUnit.MILLISECONDS);
+
+ try {
+ try {
+ Job.getJobManager().beginRule(rule, monitor);
+ timeout.cancel(false);
+ result = isDone();
+ } finally {
+ Job.getJobManager().endRule(rule);
+ Thread.interrupted(); // clear interrupt state, just in case
+ }
+ } catch (OperationCanceledException e) {
+ // timed out
+ }
+ }
+ }
+
+ return result;
+ }
+
+ final boolean setValue(V value) {
+ boolean result = transition(State.RUNNING, State.DONE);
+
+ if (result) {
+ this.value = value;
+ executions.execute();
+ }
+
+ return result;
+ }
+
+ final V getValue() throws ExecutionException {
+ V result = null;
+
+ final State state = state();
+ switch (state) {
+ case CANCELLED:
+ throw new CancellationException(String.format("Job \"%s\" was cancelled", getName()));
+ case FAILED:
+ throw new ExecutionException(exception);
+ case DONE:
+ result = this.value;
+ break;
+ default:
+ throw new IllegalStateException(state.name());
+ }
+
+ return result;
+ }
+
+ @Override
+ public void addListener(Runnable listener, Executor executor) {
+ executions.add(listener, executor);
+ }
+
+ //
+ // Nested types
+ //
+
+ private enum State {
+ RUNNING, CANCELLED, FAILED, DONE;
+ }
+
+ private static class TimeoutMonitor extends ProgressMonitorWrapper {
+ private Thread thread;
+
+ TimeoutMonitor() {
+ super(new NullProgressMonitor());
+
+ thread = Thread.currentThread();
+ }
+
+ @Override
+ public void setCanceled(boolean b) {
+ boolean wasCanceled = isCanceled();
+ super.setCanceled(b);
+ if (!wasCanceled && b) {
+ thread.interrupt();
+ }
+ }
+ }
+}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/PapyrusROTransactionalEditingDomain.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/PapyrusROTransactionalEditingDomain.java
index 652d2d3371f..159ee2c3364 100644
--- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/PapyrusROTransactionalEditingDomain.java
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf.readonly/src/org/eclipse/papyrus/infra/emf/readonly/PapyrusROTransactionalEditingDomain.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2011, 2014 Atos Origin, CEA, and others.
+ * Copyright (c) 2011, 2014 Atos Origin, CEA, Christian W. Damus, and others.
*
*
* All rights reserved. This program and the accompanying materials
@@ -14,6 +14,7 @@
* Christian W. Damus (CEA) - bug 429826
* Christian W. Damus (CEA) - bug 422257
* Christian W. Damus (CEA) - bug 415639
+ * Christian W. Damus - bug 399859
*
*****************************************************************************/
package org.eclipse.papyrus.infra.emf.readonly;
@@ -109,7 +110,9 @@ public class PapyrusROTransactionalEditingDomain extends TransactionalEditingDom
}
protected void handleCrossResourceContainmentProxy(Notification notification) {
- if (notification.getEventType() == Notification.RESOLVE) {
+ // If it's not an EReference, then it's a feature-map EAttribute from an unknown-schema AnyType
+ // and it won't contain cross-resource containment references (at least, not that we could tell)
+ if ((notification.getEventType() == Notification.RESOLVE) && (notification.getFeature() instanceof EReference)) {
EReference reference = (EReference) notification.getFeature();
if (reference.isContainment()) {
InternalEObject newValue = (InternalEObject) notification.getNewValue();
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/.classpath b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/.classpath
index 2d1a4302f04..ad32c83a788 100644
--- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/.classpath
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/.classpath
@@ -1,7 +1,7 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
- <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
- <classpathentry kind="src" path="src"/>
- <classpathentry kind="output" path="bin"/>
-</classpath>
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/.settings/org.eclipse.jdt.core.prefs b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/.settings/org.eclipse.jdt.core.prefs
index 4759947300a..410244d65a6 100644
--- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/.settings/org.eclipse.jdt.core.prefs
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/.settings/org.eclipse.jdt.core.prefs
@@ -1,10 +1,10 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
-org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.source=1.5
+org.eclipse.jdt.core.compiler.source=1.6
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/META-INF/MANIFEST.MF b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/META-INF/MANIFEST.MF
index 8c7bca4dadc..d259619ae52 100644
--- a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/META-INF/MANIFEST.MF
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/META-INF/MANIFEST.MF
@@ -9,6 +9,7 @@ Export-Package: org.eclipse.papyrus.infra.emf,
org.eclipse.papyrus.infra.emf.providers.strategy,
org.eclipse.papyrus.infra.emf.requests,
org.eclipse.papyrus.infra.emf.resource,
+ org.eclipse.papyrus.infra.emf.resource.index,
org.eclipse.papyrus.infra.emf.utils
Require-Bundle: org.eclipse.ui,
org.eclipse.core.runtime,
@@ -41,5 +42,5 @@ Bundle-Name: EMF Tools
Bundle-Activator: org.eclipse.papyrus.infra.emf.Activator
Bundle-ManifestVersion: 2
Bundle-SymbolicName: org.eclipse.papyrus.infra.emf;singleton:=true
-Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/resource/AnyRootNamespaceContentHandler.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/resource/AnyRootNamespaceContentHandler.java
new file mode 100644
index 00000000000..5d4d7c3ea04
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/resource/AnyRootNamespaceContentHandler.java
@@ -0,0 +1,104 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.emf.resource;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.ContentHandler;
+import org.eclipse.emf.ecore.xmi.XMLResource;
+import org.eclipse.emf.ecore.xmi.impl.RootXMLContentHandlerImpl;
+import org.eclipse.emf.ecore.xml.type.XMLTypeDocumentRoot;
+
+import com.google.common.base.Strings;
+
+/**
+ * A XML content type handler that matches a namespace pattern against any of the namespaces declared in the document's root element.
+ * It therefore does not support the {@link RootXMLContentHandlerImpl#ELEMENT_NAMES} and {@link RootXMLContentHandlerImpl#KIND} configuration attributes.
+ */
+public class AnyRootNamespaceContentHandler extends RootXMLContentHandlerImpl {
+
+ public AnyRootNamespaceContentHandler(Map<String, String> parameters) {
+ super(parameters);
+ }
+
+ public AnyRootNamespaceContentHandler(String contentTypeID, String[] extensions, String namespace) {
+ super(contentTypeID, extensions, null, namespace, null);
+ }
+
+ public AnyRootNamespaceContentHandler(String contentTypeID, String[] extensions, Pattern namespacePattern) {
+ super(contentTypeID, extensions, null, namespacePattern, null);
+ }
+
+ @Override
+ public Map<String, Object> contentDescription(URI uri, InputStream inputStream, Map<?, ?> options, Map<Object, Object> context) throws IOException {
+ Map<String, Object> result;
+ String contentType = contentTypeID;
+
+ try {
+ result = super.contentDescription(uri, inputStream, options, context);
+
+ XMLResource xmlResource = load(uri, inputStream, options, context);
+ EList<EObject> contents = xmlResource.getContents();
+ if (!contents.isEmpty()) {
+ EObject eObject = contents.get(0);
+ if (eObject instanceof XMLTypeDocumentRoot) {
+ String matchedNamespace = null;
+ XMLTypeDocumentRoot documentRoot = (XMLTypeDocumentRoot) eObject;
+ for (String next : documentRoot.getXMLNSPrefixMap().values()) {
+ if (isMatchingNamespace(next)) {
+ matchedNamespace = next;
+ break;
+ }
+ }
+
+ if (matchedNamespace != null) {
+ result.put(VALIDITY_PROPERTY, ContentHandler.Validity.VALID);
+ } else {
+ // If none of the root namespaces matched, then we can be assured
+ // that the resource is not of this content type
+ result.put(VALIDITY_PROPERTY, ContentHandler.Validity.INVALID);
+ }
+
+ if (contentType == null) {
+ contentType = matchedNamespace;
+ }
+ }
+ }
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IOException("Uncaught exception in describing resource content.", e); //$NON-NLS-1$
+ }
+
+ result.put(CONTENT_TYPE_PROPERTY, Strings.nullToEmpty(contentType));
+ return result;
+ }
+
+ //
+ // Nested types
+ //
+
+ public static class Describer extends RootXMLContentHandlerImpl.Describer {
+ @Override
+ protected ContentHandler createContentHandler(Map<String, String> parameters) {
+ return new AnyRootNamespaceContentHandler(parameters);
+ }
+ }
+}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/resource/index/IWorkspaceModelIndexListener.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/resource/index/IWorkspaceModelIndexListener.java
new file mode 100644
index 00000000000..7f76ceb8afb
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/resource/index/IWorkspaceModelIndexListener.java
@@ -0,0 +1,61 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.emf.resource.index;
+
+import java.util.EventListener;
+
+/**
+ * Listener protocol for notifications of {@link WorkspaceModelIndex} events.
+ */
+public interface IWorkspaceModelIndexListener extends EventListener {
+ /**
+ * Notifies me that the index is about to {@linkplain WorkspaceModelIndexEvent#ABOUT_TO_RECALCULATE re-calculate} changes in some project.
+ *
+ * @param event
+ * the event object
+ */
+ void indexAboutToRecalculate(WorkspaceModelIndexEvent event);
+
+ /**
+ * Notifies me that the index has finished {@linkplain WorkspaceModelIndexEvent#RECALCULATED re-calculation} of changes in some project.
+ *
+ * @param event
+ * the event object
+ */
+ void indexRecalculated(WorkspaceModelIndexEvent event);
+
+ /**
+ * Notifies me that the index is about to {@linkplain WorkspaceModelIndexEvent#ABOUT_TO_CALCULATE fully calculate} the index for some project.
+ *
+ * @param event
+ * the event object
+ */
+ void indexAboutToCalculate(WorkspaceModelIndexEvent event);
+
+ /**
+ * Notifies me that the index has finished {@linkplain WorkspaceModelIndexEvent#CALCULATED full calculation} for some project.
+ *
+ * @param event
+ * the event object
+ */
+ void indexCalculated(WorkspaceModelIndexEvent event);
+
+ /**
+ * Notifies me that the index {@linkplain WorkspaceModelIndexEvent#FAILED failed} to (re-)calculate some project.
+ *
+ * @param event
+ * the event object
+ */
+ void indexFailed(WorkspaceModelIndexEvent event);
+}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/resource/index/WorkspaceModelIndex.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/resource/index/WorkspaceModelIndex.java
new file mode 100644
index 00000000000..d0960e3595a
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/resource/index/WorkspaceModelIndex.java
@@ -0,0 +1,864 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.emf.resource.index;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+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.IResourceVisitor;
+import org.eclipse.core.resources.IWorkspace;
+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.Platform;
+import org.eclipse.core.runtime.QualifiedName;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.content.IContentType;
+import org.eclipse.core.runtime.content.IContentTypeManager;
+import org.eclipse.core.runtime.jobs.IJobChangeEvent;
+import org.eclipse.core.runtime.jobs.IJobChangeListener;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.core.runtime.jobs.JobChangeAdapter;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.papyrus.infra.core.utils.JobBasedFuture;
+import org.eclipse.papyrus.infra.emf.Activator;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Queues;
+import com.google.common.collect.SetMultimap;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * A general-purpose index of model resources in the Eclipse workspace.
+ */
+public class WorkspaceModelIndex<T> {
+ private static final int MAX_INDEX_RETRIES = 3;
+
+ private final IndexHandler<? extends T> indexer;
+
+ private final QualifiedName indexKey;
+ private final IContentTypeManager mgr;
+ private final IContentType contentType;
+
+ private final SetMultimap<IProject, IFile> index = HashMultimap.create();
+ private final IResourceChangeListener workspaceListener = new WorkspaceListener();
+
+ private final Map<IProject, AbstractIndexJob> activeJobs = Maps.newHashMap();
+ private final JobWrangler jobWrangler;
+
+ private final CopyOnWriteArrayList<IWorkspaceModelIndexListener> listeners = Lists.newCopyOnWriteArrayList();
+
+ public WorkspaceModelIndex(String name, String contentType, IndexHandler<? extends T> indexer) {
+ this(name, contentType, indexer, 0);
+ }
+
+ public WorkspaceModelIndex(String name, String contentType, IndexHandler<? extends T> indexer, int maxConcurrentJobs) {
+ super();
+
+ this.indexKey = new QualifiedName("org.eclipse.papyrus.modelindex", name); //$NON-NLS-1$
+ this.mgr = Platform.getContentTypeManager();
+ this.contentType = this.mgr.getContentType(contentType);
+ this.indexer = indexer;
+
+ jobWrangler = new JobWrangler(maxConcurrentJobs);
+
+ startIndex();
+ }
+
+ public void dispose() {
+ ResourcesPlugin.getWorkspace().removeResourceChangeListener(workspaceListener);
+ Job.getJobManager().cancel(this);
+
+ synchronized (index) {
+ for (IFile next : index.values()) {
+ try {
+ next.setSessionProperty(indexKey, null);
+ } catch (CoreException e) {
+ // Just continue, best-effort. There's nothing else to do
+ }
+ }
+
+ index.clear();
+ }
+ }
+
+ private void startIndex() {
+ IWorkspace workspace = ResourcesPlugin.getWorkspace();
+ workspace.addResourceChangeListener(workspaceListener, IResourceChangeEvent.POST_CHANGE);
+
+ index(Arrays.asList(workspace.getRoot().getProjects()));
+ }
+
+ void index(Collection<? extends IProject> projects) {
+ List<Job> jobs = Lists.newArrayListWithCapacity(projects.size());
+ for (IProject next : projects) {
+ jobs.add(new IndexProjectJob(next));
+ }
+ schedule(jobs);
+ }
+
+ /**
+ * Obtains an asynchronous future result that is scheduled to run after any pending indexing work has completed.
+ * The {@code function} is <em>not</em> invoked under synchronization on the index; it is passed a copy of the
+ * last consistent state of the index after any pending calculations have completed.
+ *
+ * @param function
+ * the function to schedule. Its input is the complete index map
+ *
+ * @return the future result of the function applied to the index
+ */
+ public <V> ListenableFuture<V> afterIndex(final Function<? super Map<IFile, T>, V> function) {
+ return Futures.transform(getIndex(), function);
+ }
+
+ /**
+ * Obtains an asynchronous future result that is scheduled to run after any pending indexing work has completed.
+ * The {@code callable} is invoked under synchronization on the index, so it must be careful about how it
+ * synchronizes on other objects to avoid deadlocks.
+ *
+ * @param callable
+ * the operation to schedule
+ *
+ * @return the future result of the operation
+ */
+ public <V> ListenableFuture<V> afterIndex(final Callable<V> callable) {
+ ListenableFuture<V> result;
+
+ if (Job.getJobManager().find(this).length == 0) {
+ // Result is available now
+ try {
+ result = Futures.immediateFuture(callable.call());
+ } catch (Exception e) {
+ result = Futures.immediateFailedFuture(e);
+ }
+ } else {
+ JobBasedFuture<V> job = new JobBasedFuture<V>(NLS.bind("Wait for model index \"{0}\"", indexKey.getLocalName())) {
+ {
+ // setSystem(true);
+ }
+
+ @Override
+ protected V compute(IProgressMonitor monitor) throws Exception {
+ V result;
+
+ Job.getJobManager().join(WorkspaceModelIndex.this, monitor);
+ synchronized (index) {
+ result = callable.call();
+ }
+
+ return result;
+ }
+ };
+ job.schedule();
+ result = job;
+ }
+
+ return result;
+ }
+
+ /**
+ * Schedules an operation to run after any pending indexing work has completed.
+ * The {@code runnable} is invoked under synchronization on the index, so it must be careful about how it
+ * synchronizes on other objects to avoid deadlocks.
+ *
+ * @param runnable
+ * the operation to schedule
+ */
+ public void afterIndex(final Runnable runnable) {
+ afterIndex(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ runnable.run();
+ return null;
+ }
+ });
+ }
+
+ /**
+ * Obtains the index when it is ready.
+ *
+ * @return the future value of the index, when it is ready
+ */
+ public ListenableFuture<Map<IFile, T>> getIndex() {
+ return afterIndex(new Callable<Map<IFile, T>>() {
+ @Override
+ public Map<IFile, T> call() {
+ return map();
+ }
+ });
+ }
+
+ /**
+ * @precondition The {@link #index} monitor is held.
+ */
+ private Map<IFile, T> map() {
+ ImmutableMap.Builder<IFile, T> result = ImmutableMap.builder();
+
+ for (IFile next : index.values()) {
+ try {
+ @SuppressWarnings("unchecked")
+ T value = (T) next.getSessionProperty(indexKey);
+ if (value != null) {
+ result.put(next, value);
+ }
+ } catch (CoreException e) {
+ Activator.log.error("Failed to access index data for file " + next.getFullPath(), e); //$NON-NLS-1$
+ }
+ }
+
+ return result.build();
+ }
+
+ void process(IFile file) throws CoreException {
+ IProject project = file.getProject();
+
+ if (match(file)) {
+ add(project, file);
+ } else {
+ remove(project, file);
+ }
+ }
+
+ boolean match(IFile file) {
+ boolean result = false;
+
+ if (file.isAccessible()) {
+ InputStream input = null;
+
+ try {
+ input = file.getContents(true);
+ IContentType[] contentTypes = mgr.findContentTypesFor(input, file.getName());
+ for (int i = 0; (i < contentTypes.length) && !result; i++) {
+ result = contentTypes[i].isKindOf(contentType);
+ }
+ } catch (Exception e) {
+ Activator.log.error("Failed to index file " + file.getFullPath(), e); //$NON-NLS-1$
+ } finally {
+ if (input != null) {
+ try {
+ input.close();
+ } catch (IOException e) {
+ Activator.log.error("Failed to close indexed file " + file.getFullPath(), e); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ void add(IProject project, IFile file) throws CoreException {
+ synchronized (index) {
+ index.put(project, file);
+ file.setSessionProperty(indexKey, indexer.index(file));
+ }
+ }
+
+ void remove(IProject project, IFile file) throws CoreException {
+ synchronized (index) {
+ index.remove(project, file);
+ indexer.unindex(file);
+
+ if (file.exists()) {
+ file.setSessionProperty(indexKey, null);
+ }
+ }
+ }
+
+ void remove(IProject project) throws CoreException {
+ synchronized (index) {
+ if (index.containsKey(project)) {
+ for (IFile next : index.get(project)) {
+ indexer.unindex(next);
+ }
+ index.removeAll(project);
+ }
+ }
+ }
+
+ ReindexProjectJob reindex(IProject project, Iterable<? extends IndexDelta> deltas) {
+ ReindexProjectJob result = null;
+
+ synchronized (activeJobs) {
+ AbstractIndexJob active = activeJobs.get(project);
+
+ if (active != null) {
+ switch (active.kind()) {
+ case REINDEX:
+ @SuppressWarnings("unchecked")
+ ReindexProjectJob reindex = (ReindexProjectJob) active;
+ reindex.addDeltas(deltas);
+ break;
+ case INDEX:
+ @SuppressWarnings("unchecked")
+ IndexProjectJob index = (IndexProjectJob) active;
+ ReindexProjectJob followup = index.getFollowup();
+ if (followup != null) {
+ followup.addDeltas(deltas);
+ } else {
+ followup = new ReindexProjectJob(project, deltas);
+ index.setFollowup(followup);
+ }
+ break;
+ case MASTER:
+ throw new IllegalStateException("Master job is in the active table."); //$NON-NLS-1$
+ }
+ } else {
+ // No active job. We'll need a new one
+ result = new ReindexProjectJob(project, deltas);
+ }
+ }
+
+ return result;
+ }
+
+ IResourceVisitor getWorkspaceVisitor(final IProgressMonitor monitor) {
+ return new IResourceVisitor() {
+
+ @Override
+ public boolean visit(IResource resource) throws CoreException {
+ if (resource.getType() == IResource.FILE) {
+ process((IFile) resource);
+ }
+
+ return !monitor.isCanceled();
+ }
+ };
+ }
+
+ private void schedule(Collection<? extends Job> jobs) {
+ // Synchronize on the active jobs because this potentially alters the wrangler's follow-up job
+ synchronized (activeJobs) {
+ jobWrangler.add(jobs);
+ }
+ }
+
+ public void addListener(IWorkspaceModelIndexListener listener) {
+ listeners.addIfAbsent(listener);
+ }
+
+ public void removeListener(IWorkspaceModelIndexListener listener) {
+ listeners.remove(listener);
+ }
+
+ private void notifyStarting(AbstractIndexJob indexJob) {
+ if (!listeners.isEmpty()) {
+ WorkspaceModelIndexEvent event;
+
+ switch (indexJob.kind()) {
+ case INDEX:
+ event = new WorkspaceModelIndexEvent(this, WorkspaceModelIndexEvent.ABOUT_TO_CALCULATE, indexJob.getProject());
+ for (IWorkspaceModelIndexListener next : listeners) {
+ try {
+ next.indexAboutToCalculate(event);
+ } catch (Exception e) {
+ Activator.log.error("Uncaught exception in index listsner.", e); //$NON-NLS-1$
+ }
+ }
+ break;
+ case REINDEX:
+ event = new WorkspaceModelIndexEvent(this, WorkspaceModelIndexEvent.ABOUT_TO_RECALCULATE, indexJob.getProject());
+ for (IWorkspaceModelIndexListener next : listeners) {
+ try {
+ next.indexAboutToRecalculate(event);
+ } catch (Exception e) {
+ Activator.log.error("Uncaught exception in index listsner.", e); //$NON-NLS-1$
+ }
+ }
+ break;
+ case MASTER:
+ // Pass
+ break;
+ }
+ }
+ }
+
+ private void notifyFinished(AbstractIndexJob indexJob, IStatus status) {
+ if (!listeners.isEmpty()) {
+ WorkspaceModelIndexEvent event;
+
+ if ((status != null) && (status.getSeverity() >= IStatus.ERROR)) {
+ event = new WorkspaceModelIndexEvent(this, WorkspaceModelIndexEvent.FAILED, indexJob.getProject());
+ for (IWorkspaceModelIndexListener next : listeners) {
+ try {
+ next.indexFailed(event);
+ } catch (Exception e) {
+ Activator.log.error("Uncaught exception in index listsner.", e); //$NON-NLS-1$
+ }
+ }
+ } else {
+ switch (indexJob.kind()) {
+ case INDEX:
+ event = new WorkspaceModelIndexEvent(this, WorkspaceModelIndexEvent.CALCULATED, indexJob.getProject());
+ for (IWorkspaceModelIndexListener next : listeners) {
+ try {
+ next.indexCalculated(event);
+ } catch (Exception e) {
+ Activator.log.error("Uncaught exception in index listsner.", e); //$NON-NLS-1$
+ }
+ }
+ break;
+ case REINDEX:
+ event = new WorkspaceModelIndexEvent(this, WorkspaceModelIndexEvent.RECALCULATED, indexJob.getProject());
+ for (IWorkspaceModelIndexListener next : listeners) {
+ try {
+ next.indexRecalculated(event);
+ } catch (Exception e) {
+ Activator.log.error("Uncaught exception in index listsner.", e); //$NON-NLS-1$
+ }
+ }
+ break;
+ case MASTER:
+ // Pass
+ break;
+ }
+ }
+ }
+ }
+
+ //
+ // Nested types
+ //
+
+ /**
+ * Callback interface for the index client to update the index.
+ */
+ public static interface IndexHandler<T> {
+ /**
+ * Updates the index for a file that matches our selection criteria.
+ *
+ * @param file
+ * a file that exists and matches the index selection criteria
+ *
+ * @return the object to store in the index for this {@code file}
+ */
+ T index(IFile file);
+
+ /**
+ * Updates the index for a file that no longer exists or no longer matches our selection criteria.
+ *
+ * @param file
+ * a file that no longer exists or otherwise no longer matches our selection criteria. It is removed from the index
+ */
+ void unindex(IFile file);
+ }
+
+ private enum JobKind {
+ MASTER, INDEX, REINDEX;
+
+ boolean isSystem() {
+ return this != MASTER;
+ }
+ }
+
+ private abstract class AbstractIndexJob extends Job {
+ private final IProject project;
+
+ AbstractIndexJob(String name, IProject project) {
+ super(name);
+
+ this.project = project;
+
+ if (project != null) {
+ setRule(project);
+ synchronized (activeJobs) {
+ if (!activeJobs.containsKey(project)) {
+ activeJobs.put(project, this);
+ }
+ }
+ }
+
+ setSystem(kind().isSystem());
+ }
+
+ @Override
+ public boolean belongsTo(Object family) {
+ return family == WorkspaceModelIndex.this;
+ }
+
+ final IProject getProject() {
+ return project;
+ }
+
+ abstract JobKind kind();
+
+ @Override
+ protected final IStatus run(IProgressMonitor monitor) {
+ IStatus result;
+
+ try {
+ result = doRun(monitor);
+ } finally {
+ synchronized (activeJobs) {
+ AbstractIndexJob followup = getFollowup();
+
+ if (project != null) {
+ if (followup == null) {
+ activeJobs.remove(project);
+ } else {
+ activeJobs.put(project, followup);
+ }
+ }
+
+ if (followup != null) {
+ // Kick off the follow-up job
+ followup.schedule();
+ }
+ }
+ }
+
+ return result;
+ }
+
+ protected abstract IStatus doRun(IProgressMonitor monitor);
+
+ protected AbstractIndexJob getFollowup() {
+ return null;
+ }
+ }
+
+ private class JobWrangler extends AbstractIndexJob {
+ private final Queue<Job> queue = Queues.newArrayDeque();
+ private final Set<Job> pending = Sets.newHashSet();
+ private final Set<IProject> failedProjects = Sets.newHashSet();
+
+ private final Lock pendingLock = new ReentrantLock();
+ private final Condition pendingCheck = pendingLock.newCondition();
+
+ private final int maxPending;
+
+ JobWrangler(int maxConcurrentJobs) {
+ super("Workspace model indexer", null);
+
+ this.maxPending = (maxConcurrentJobs <= 0) ? Integer.MAX_VALUE : maxConcurrentJobs;
+ }
+
+ @Override
+ JobKind kind() {
+ return JobKind.MASTER;
+ }
+
+ void add(Iterable<? extends Job> jobs) {
+ pendingLock.lock();
+
+ try {
+ if (queue.isEmpty() && pending.isEmpty()) {
+ // I am a new job
+ schedule();
+ }
+
+ Iterables.addAll(queue, jobs);
+ pendingCheck.signalAll();
+ } finally {
+ pendingLock.unlock();
+ }
+ }
+
+ @Override
+ protected IStatus doRun(IProgressMonitor monitor) {
+ IJobChangeListener listener = new JobChangeAdapter() {
+ private final Map<IProject, Integer> retries = Maps.newHashMap();
+
+ @Override
+ public void aboutToRun(IJobChangeEvent event) {
+ Job starting = event.getJob();
+
+ if (pending.contains(starting)) {
+ // one of mine is starting
+ @SuppressWarnings("unchecked")
+ AbstractIndexJob indexJob = (AbstractIndexJob) starting;
+ notifyStarting(indexJob);
+ }
+ }
+
+ @Override
+ public void done(IJobChangeEvent event) {
+ pendingLock.lock();
+ try {
+ final Job finished = event.getJob();
+ if (pending.remove(finished)) {
+ // one of mine finished
+ pendingCheck.signalAll();
+
+ @SuppressWarnings("unchecked")
+ AbstractIndexJob indexJob = (AbstractIndexJob) finished;
+ IProject project = indexJob.getProject();
+
+ notifyFinished(indexJob, event.getResult());
+
+ if ((event.getResult() != null) && (event.getResult().getSeverity() >= IStatus.ERROR)) {
+ // Indexing failed to complete. Need to re-build the index
+ if (project != null) {
+ int count = retries.containsKey(project) ? retries.get(project) : 0;
+ if (count++ < MAX_INDEX_RETRIES) {
+ // Only retry up to three times
+ failedProjects.add(project);
+ }
+ retries.put(project, ++count);
+ }
+ }
+ }
+ } finally {
+ pendingLock.unlock();
+ }
+ }
+ };
+
+ getJobManager().addJobChangeListener(listener);
+
+ try {
+ pendingLock.lock();
+
+ try {
+ for (;;) {
+ for (Job next = queue.poll(); next != null; next = queue.poll()) {
+ while (pending.size() >= maxPending) {
+ pendingCheck.awaitUninterruptibly();
+ }
+ pending.add(next);
+ next.schedule();
+ }
+
+ if (pending.isEmpty() && queue.isEmpty()) {
+ if (failedProjects.isEmpty()) {
+ // Done with wrangling jobs, for now
+ break;
+ } else {
+ // Rebuild the index for these projects, from scratch
+ index(failedProjects); // This adds to my queue
+ failedProjects.clear();
+ }
+ } else {
+ // Wait for something new to come into the queue or for the pending set to drain
+ pendingCheck.awaitUninterruptibly();
+ }
+ }
+ } finally {
+ pendingLock.unlock();
+ }
+ } finally {
+ getJobManager().removeJobChangeListener(listener);
+ }
+
+ return Status.OK_STATUS;
+ }
+ }
+
+ private class IndexProjectJob extends AbstractIndexJob {
+ private ReindexProjectJob followup;
+
+ IndexProjectJob(IProject project) {
+ super("Indexing project " + project.getName(), project);
+ }
+
+ @Override
+ JobKind kind() {
+ return JobKind.INDEX;
+ }
+
+ @Override
+ protected IStatus doRun(IProgressMonitor monitor) {
+ IStatus result = Status.OK_STATUS;
+ final IProject project = getProject();
+
+ monitor.beginTask("Indexing models in project " + project.getName(), IProgressMonitor.UNKNOWN);
+
+ try {
+ if (project.isAccessible()) {
+ project.accept(getWorkspaceVisitor(monitor));
+ } else {
+ remove(project);
+ }
+
+ if (monitor.isCanceled()) {
+ result = Status.CANCEL_STATUS;
+ }
+ } catch (CoreException e) {
+ result = e.getStatus();
+ } finally {
+ monitor.done();
+ }
+
+ return result;
+ }
+
+ void setFollowup(ReindexProjectJob followup) {
+ this.followup = followup;
+ }
+
+ @Override
+ protected ReindexProjectJob getFollowup() {
+ return followup;
+ }
+ }
+
+ private class WorkspaceListener implements IResourceChangeListener {
+ @Override
+ public void resourceChanged(IResourceChangeEvent event) {
+ final Multimap<IProject, IndexDelta> deltas = ArrayListMultimap.create();
+
+ try {
+ event.getDelta().accept(new IResourceDeltaVisitor() {
+
+ @Override
+ public boolean visit(IResourceDelta delta) throws CoreException {
+ if (delta.getResource().getType() == IResource.FILE) {
+ IFile file = (IFile) delta.getResource();
+
+ switch (delta.getKind()) {
+ case IResourceDelta.CHANGED:
+ if ((delta.getFlags() & (IResourceDelta.SYNC | IResourceDelta.CONTENT | IResourceDelta.REPLACED)) != 0) {
+ // Re-index in place
+ deltas.put(file.getProject(), new IndexDelta(file, IndexDelta.DeltaKind.REINDEX));
+ }
+ break;
+ case IResourceDelta.REMOVED:
+ deltas.put(file.getProject(), new IndexDelta(file, IndexDelta.DeltaKind.UNINDEX));
+ break;
+ case IResourceDelta.ADDED:
+ deltas.put(file.getProject(), new IndexDelta(file, IndexDelta.DeltaKind.INDEX));
+ break;
+ }
+ }
+ return true;
+ }
+ });
+ } catch (CoreException e) {
+ Activator.log.error("Failed to analyze resource changes for re-indexing.", e); //$NON-NLS-1$
+ }
+
+ if (!deltas.isEmpty()) {
+ List<Job> jobs = Lists.newArrayListWithCapacity(deltas.keySet().size());
+ for (IProject next : deltas.keySet()) {
+ ReindexProjectJob reindex = reindex(next, deltas.get(next));
+ if (reindex != null) {
+ jobs.add(reindex);
+ }
+ }
+ schedule(jobs);
+ }
+ }
+ }
+
+ private static class IndexDelta {
+ private final IFile file;
+
+ private final DeltaKind kind;
+
+ IndexDelta(IFile file, DeltaKind kind) {
+ this.file = file;
+ this.kind = kind;
+ }
+
+ //
+ // Nested types
+ //
+
+ enum DeltaKind {
+ INDEX, REINDEX, UNINDEX
+ }
+ }
+
+ private class ReindexProjectJob extends AbstractIndexJob {
+ private final IProject project;
+ private final ConcurrentLinkedQueue<IndexDelta> deltas;
+
+ ReindexProjectJob(IProject project, Iterable<? extends IndexDelta> deltas) {
+ super("Re-indexing project " + project.getName(), project);
+ this.project = project;
+ this.deltas = Queues.newConcurrentLinkedQueue(deltas);
+ }
+
+ @Override
+ JobKind kind() {
+ return JobKind.REINDEX;
+ }
+
+ void addDeltas(Iterable<? extends IndexDelta> deltas) {
+ Iterables.addAll(this.deltas, deltas);
+ }
+
+ @Override
+ protected IStatus doRun(IProgressMonitor monitor) {
+ IStatus result = Status.OK_STATUS;
+
+ monitor.beginTask("Re-indexing models in project " + project.getName(), IProgressMonitor.UNKNOWN);
+
+ try {
+ for (IndexDelta next = deltas.poll(); next != null; next = deltas.poll()) {
+ if (monitor.isCanceled()) {
+ result = Status.CANCEL_STATUS;
+ break;
+ }
+
+ try {
+ switch (next.kind) {
+ case INDEX:
+ case REINDEX:
+ process(next.file);
+ break;
+ case UNINDEX:
+ remove(project, next.file);
+ break;
+ }
+ } catch (CoreException e) {
+ result = e.getStatus();
+ break;
+ } finally {
+ monitor.worked(1);
+ }
+ }
+ } finally {
+ monitor.done();
+ }
+
+ return result;
+ }
+
+ @Override
+ protected AbstractIndexJob getFollowup() {
+ // If I still have work to do, then I am my own follow-up
+ return deltas.isEmpty() ? null : this;
+ }
+ }
+}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/resource/index/WorkspaceModelIndexAdapter.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/resource/index/WorkspaceModelIndexAdapter.java
new file mode 100644
index 00000000000..5f122ae72ff
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/resource/index/WorkspaceModelIndexAdapter.java
@@ -0,0 +1,58 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.emf.resource.index;
+
+/**
+ * A convenience superclass for selective call-back implementation in {@link WorkspaceModelIndex} listeners.
+ */
+public class WorkspaceModelIndexAdapter implements IWorkspaceModelIndexListener {
+
+ public WorkspaceModelIndexAdapter() {
+ super();
+ }
+
+ @Override
+ public void indexAboutToRecalculate(WorkspaceModelIndexEvent event) {
+ indexAboutToCalculateOrRecalculate(event);
+ }
+
+ @Override
+ public void indexRecalculated(WorkspaceModelIndexEvent event) {
+ indexCalculatedOrRecalculated(event);
+ }
+
+ @Override
+ public void indexAboutToCalculate(WorkspaceModelIndexEvent event) {
+ indexAboutToCalculateOrRecalculate(event);
+ }
+
+ @Override
+ public void indexCalculated(WorkspaceModelIndexEvent event) {
+ indexCalculatedOrRecalculated(event);
+ }
+
+ @Override
+ public void indexFailed(WorkspaceModelIndexEvent event) {
+ // Pass
+ }
+
+ protected void indexAboutToCalculateOrRecalculate(WorkspaceModelIndexEvent event) {
+ // Pass
+ }
+
+ protected void indexCalculatedOrRecalculated(WorkspaceModelIndexEvent event) {
+ // Pass
+ }
+
+}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/resource/index/WorkspaceModelIndexEvent.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/resource/index/WorkspaceModelIndexEvent.java
new file mode 100644
index 00000000000..2bec19dc288
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/resource/index/WorkspaceModelIndexEvent.java
@@ -0,0 +1,76 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.emf.resource.index;
+
+import java.util.EventObject;
+
+import org.eclipse.core.resources.IProject;
+
+/**
+ * Event object notifying {@link IWorkspaceModelIndexListener}s of changes in the index.
+ */
+public class WorkspaceModelIndexEvent extends EventObject {
+
+ /** Event type indicating that the index is about to be re-calculated for some project based on changes in that project. */
+ public static final int ABOUT_TO_RECALCULATE = 0;
+
+ /** Event type indicating that the index has finished re-calculating for some project based on changes in that project. */
+ public static final int RECALCULATED = 1;
+
+ /** Event type indicating that the index is about to be fully calculated for some project. */
+ public static final int ABOUT_TO_CALCULATE = 2;
+
+ /** Event type indicating that the index has finished a full calculation for some project. */
+ public static final int CALCULATED = 3;
+
+ /** Event type indicating that the index (re-)calculation was interrupted or otherwise failed and the index is now out of sync for some project. */
+ public static final int FAILED = 4;
+
+
+ private static final long serialVersionUID = 1L;
+
+ private final int eventType;
+
+ private final IProject project;
+
+ /**
+ * Initializes me.
+ *
+ * @param source
+ * the index that has changed
+ * @param eventType
+ * the kind of change
+ * @param project
+ * the project for which the index changed
+ */
+ public WorkspaceModelIndexEvent(WorkspaceModelIndex<?> source, int eventType, IProject project) {
+ super(source);
+
+ this.eventType = eventType;
+ this.project = project;
+ }
+
+ @Override
+ public WorkspaceModelIndex<?> getSource() {
+ return (WorkspaceModelIndex<?>) super.getSource();
+ }
+
+ public int getEventType() {
+ return eventType;
+ }
+
+ public IProject getProject() {
+ return project;
+ }
+}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/utils/EMFFunctions.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/utils/EMFFunctions.java
new file mode 100644
index 00000000000..20996f1277f
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/utils/EMFFunctions.java
@@ -0,0 +1,98 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.emf.utils;
+
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+
+import com.google.common.base.Function;
+
+/**
+ * Useful Guava {@link Function}s for working with EMF models.
+ */
+public class EMFFunctions {
+
+ private EMFFunctions() {
+ super();
+ }
+
+ /**
+ * Obtains a function that obtains the URI of an EMF object.
+ *
+ * @return an EMF object URI function
+ *
+ * @see EcoreUtil#getURI(EObject)
+ */
+ public static Function<EObject, URI> objectURI() {
+ return new Function<EObject, URI>() {
+ @Override
+ public URI apply(EObject input) {
+ return (input == null) ? null : EcoreUtil.getURI(input);
+ }
+ };
+ }
+
+ /**
+ * Obtains a function that obtains the URI of a resource.
+ *
+ * @return a resource URI function
+ *
+ * @see Resource#getURI()
+ */
+ public static Function<Resource, URI> resourceURI() {
+ return new Function<Resource, URI>() {
+ @Override
+ public URI apply(Resource input) {
+ return (input == null) ? null : input.getURI();
+ }
+ };
+ }
+
+ /**
+ * Obtains a function that trims the fragments of URIs.
+ *
+ * @return a URI fragment trimming function
+ *
+ * @see URI#trimFragment()
+ */
+ public static Function<URI, URI> trimURIFragment() {
+ return new Function<URI, URI>() {
+ @Override
+ public URI apply(URI input) {
+ return (input == null) ? null : input.trimFragment();
+ }
+ };
+ }
+
+ public static Function<EObject, Object> getFeature(final EStructuralFeature feature) {
+ return new Function<EObject, Object>() {
+ @Override
+ public Object apply(EObject input) {
+ return (input == null) ? null : input.eGet(feature);
+ }
+ };
+ }
+
+ public static <T> Function<EObject, T> getFeature(final EStructuralFeature feature, final Class<T> ofType) {
+ return new Function<EObject, T>() {
+ @Override
+ public T apply(EObject input) {
+ return (input == null) ? null : ofType.cast(input.eGet(feature));
+ }
+ };
+ }
+}
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/utils/EMFPredicates.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/utils/EMFPredicates.java
new file mode 100644
index 00000000000..18b7a7937e8
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/utils/EMFPredicates.java
@@ -0,0 +1,63 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.emf.utils;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Useful Guava {@link Predicate}s for working with EMF models.
+ */
+public class EMFPredicates {
+
+ private EMFPredicates() {
+ super();
+ }
+
+ /**
+ * Obtains a predicate testing that an EMF object is not a proxy. It is formulated this
+ * way on the expectation that usually one would want to filter for objects that aren't
+ * proxies. Otherwise, just do {@code Predicates.not(EMFPredicates.notProxy())}.
+ *
+ * @return a predicate that matches EMF objects that are not proxies
+ *
+ * @see EObject#eIsProxy()
+ */
+ public static Predicate<EObject> notProxy() {
+ return new Predicate<EObject>() {
+ @Override
+ public boolean apply(EObject input) {
+ return (input != null) && !input.eIsProxy();
+ }
+ };
+ }
+
+ /**
+ * Obtains a predicate testing that a resource is loaded.
+ *
+ * @return an is-loaded predicate
+ *
+ * @see Resource#isLoaded()
+ */
+ public static Predicate<Resource> isLoaded() {
+ return new Predicate<Resource>() {
+ @Override
+ public boolean apply(Resource input) {
+ return (input != null) && input.isLoaded();
+ }
+ };
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/util/ICallableWithProgress.java b/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/util/ICallableWithProgress.java
new file mode 100644
index 00000000000..2efd39b53ed
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/util/ICallableWithProgress.java
@@ -0,0 +1,45 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.tools.util;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.concurrent.Callable;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.operation.IRunnableContext;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+
+/**
+ * The {@link Callable} analogue of an {@link IRunnableWithProgress}.
+ */
+public interface ICallableWithProgress<V> {
+ /**
+ * Invokes me in a runnable context with a progress monitor.
+ *
+ * @param monitor
+ * the progress monitor to use to display progress and receive
+ * requests for cancellation
+ * @exception InvocationTargetException
+ * if the run method must propagate a checked exception,
+ * it should wrap it inside an <code>InvocationTargetException</code>; runtime exceptions are automatically
+ * wrapped in an <code>InvocationTargetException</code> by the calling context
+ * @exception InterruptedException
+ * if the operation detects a request to cancel,
+ * using <code>IProgressMonitor.isCanceled()</code>, it should exit by throwing <code>InterruptedException</code>
+ *
+ * @see UIUtil#call(IRunnableContext, ICallableWithProgress)
+ * @see IRunnableContext#run
+ */
+ V call(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException;
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/util/ReferenceCounted.java b/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/util/ReferenceCounted.java
new file mode 100644
index 00000000000..6c0444c3086
--- /dev/null
+++ b/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/util/ReferenceCounted.java
@@ -0,0 +1,175 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.tools.util;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * A convenient reference-counting utility with automatic disposal and asynchronous auto-disposal (intended
+ * for use with the UI event-loop executor service). Sub-classes leveraging the self-disposing behaviour of
+ * the self-owning instance must override the {@link #dispose()} method.
+ */
+public class ReferenceCounted<T> {
+ private final T owner;
+ private final AtomicInteger refCount = new AtomicInteger();
+ private Runnable disposeAction;
+ private final ExecutorService autoReleaseExecutor;
+
+ /**
+ * Initializes me with my owner for which I count references.
+ * <p>
+ * I do not support {@link #autoRelease()}.
+ *
+ * @param owner
+ * my owner
+ * @param disposeAction
+ * action to run when the reference count reaches zero to dispose my {@code owner}
+ *
+ * @throws IllegalArgumentException
+ * if the {@code disposeAction} is {@code null} because, really,
+ * why would you need reference counting for an object that doesn't need to be disposed?
+ */
+ public ReferenceCounted(T owner, Runnable disposeAction) {
+ this(owner, null, disposeAction);
+ }
+
+ /**
+ * Initializes me with my owner for which I count references.
+ * <p>
+ * I support {@link #autoRelease()} using the given executor.
+ *
+ * @param owner
+ * my owner
+ * @param autoReleaseExecutor
+ * the executor on which to schedule auto-release invocations
+ * @param disposeAction
+ * action to run when the reference count reaches zero to dispose my {@code owner}
+ *
+ * @throws IllegalArgumentException
+ * if the {@code disposeAction} is {@code null} because, really,
+ * why would you need reference counting for an object that doesn't need to be disposed?
+ */
+ public ReferenceCounted(T owner, ExecutorService autoReleaseExecutor, Runnable disposeAction) {
+ super();
+
+ if (disposeAction == null) {
+ throw new IllegalArgumentException("null disposeAction"); //$NON-NLS-1$
+ }
+
+ this.owner = owner;
+ this.autoReleaseExecutor = autoReleaseExecutor;
+ this.disposeAction = disposeAction;
+ }
+
+ /**
+ * Initializes me as a self-disposing reference-counted instance. This constructor is only suitable
+ * for chaining from subclasses.
+ * <p>
+ * I do not support {@link #autoRelease()}.
+ */
+ protected ReferenceCounted() {
+ this((ExecutorService) null);
+ }
+
+ /**
+ * Initializes me as a self-disposing reference-counted instance. This constructor is only suitable
+ * for chaining from subclasses.
+ * <p>
+ * I support {@link #autoRelease()} using the given executor.
+ *
+ * @param autoReleaseExecutor
+ * the executor on which to schedule auto-release invocations
+ */
+ @SuppressWarnings("unchecked")
+ protected ReferenceCounted(ExecutorService autoReleaseExecutor) {
+ super();
+
+ this.owner = (T) this;
+ this.disposeAction = new SelfDisposeAction();
+ this.autoReleaseExecutor = autoReleaseExecutor;
+ }
+
+ /**
+ * Retains me, incrementing my retain count. The caller must eventually {@link #release()} me (even if via the {@link #autoRelease()} method)
+ * if I am to become disposable.
+ *
+ * @return my owner, for convenience of call chaining
+ */
+ public final T retain() {
+ refCount.incrementAndGet();
+ return owner;
+ }
+
+ /**
+ * Releases me, decrementing my retain count. When my retain count reaches zero, I dispose myself using the
+ * configured dispose-action runnable.
+ */
+ public final void release() {
+ if (refCount.decrementAndGet() <= 0) {
+ if (disposeAction != null) {
+ try {
+ disposeAction.run();
+ } finally {
+ disposeAction = null;
+ }
+ }
+ }
+ }
+
+ /**
+ * Automatically releases me some time in the future, as determined by the auto-release executor with which
+ * I was configured. A particularly convenient executor is one that posts an asynchronous execution on the
+ * display thread, to automatically dispose my owner (or me, as the case may be) when the display thread
+ * returns to the event loop.
+ *
+ * @return my owner, for convenience of call chaining
+ *
+ * @throws IllegalStateException
+ * if I have no auto-release executor
+ */
+ public final T autoRelease() {
+ if (autoReleaseExecutor == null) {
+ throw new IllegalStateException("no auto-release executor available"); //$NON-NLS-1$
+ }
+
+ // Don't submit the dispose action because we could still be retained!
+ autoReleaseExecutor.execute(new Runnable() {
+
+ public void run() {
+ release();
+ }
+ });
+ return owner;
+ }
+
+ /**
+ * For classes that extend the {@code ReferenceCount}, this must be overridden to implement disposal.
+ * The default implementation throws {@link UnsupportedOperationException} to ensure that subclasses
+ * override it.
+ */
+ protected void dispose() {
+ throw new UnsupportedOperationException("dispose is unimplemented"); //$NON-NLS-1$
+ }
+
+ //
+ // Nested types
+ //
+
+ private class SelfDisposeAction implements Runnable {
+ public void run() {
+ dispose();
+ }
+ }
+}
diff --git a/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/util/UIUtil.java b/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/util/UIUtil.java
index a6ea02ed31e..945be4fc150 100644
--- a/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/util/UIUtil.java
+++ b/plugins/infra/org.eclipse.papyrus.infra.tools/src/org/eclipse/papyrus/infra/tools/util/UIUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 CEA and others.
+ * Copyright (c) 2014 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
@@ -8,10 +8,12 @@
*
* Contributors:
* Christian W. Damus (CEA) - Initial API and implementation
+ * Christian W. Damus - bug 399859
*
*/
package org.eclipse.papyrus.infra.tools.util;
+import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
@@ -19,15 +21,21 @@ import java.util.List;
import java.util.Queue;
import java.util.concurrent.AbstractExecutorService;
import java.util.concurrent.Callable;
+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.jface.operation.IRunnableContext;
+import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IMemento;
@@ -53,7 +61,19 @@ public class UIUtil {
* @return the executor
*/
public static ExecutorService createUIExecutor(Display display) {
- return new UIExecutorService(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);
}
/**
@@ -132,11 +152,97 @@ public class UIUtil {
return asyncCall(Display.getDefault(), callable);
}
+ /**
+ * Calls a {@code callable} in the given {@code context}.
+ *
+ * @param fork
+ * {@code true} if the runnable should be run in a separate thread,
+ * and {@code false} to run in the same thread
+ * @param cancelable
+ * {@code true} to enable the cancellation, and {@code false} to make the operation uncancellable
+ * @param runnable
+ * the runnable to run
+ *
+ * @exception InvocationTargetException
+ * wraps any exception or error which occurs
+ * while running the runnable
+ * @exception InterruptedException
+ * propagated by the context if the runnable
+ * acknowledges cancellation by throwing this exception. This should not be thrown
+ * if {@code cancelable} is {@code false}.
+ */
+ public static <V> V call(IRunnableContext context, boolean fork, boolean cancelable, ICallableWithProgress<V> callable) throws InvocationTargetException, InterruptedException {
+ class RunnableWrapper implements IRunnableWithProgress {
+ final ICallableWithProgress<V> delegate;
+
+ V result;
+
+ RunnableWrapper(ICallableWithProgress<V> delegate) {
+ this.delegate = delegate;
+ }
+
+ public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+ result = delegate.call(monitor);
+ }
+ }
+
+ RunnableWrapper wrapper = new RunnableWrapper(callable);
+ context.run(fork, cancelable, wrapper);
+ return wrapper.result;
+ }
+
+ /**
+ * Obtains a simple executor that asynchronously executes at most one task on the default
+ * display thread. While any task is still pending execution on this executor,
+ * all others are silently discarded. This is useful for cases where, for example, UI
+ * refreshes are posted repeatedly from independent events that aren't aware of each other
+ * but where each refresh task would repeat the same work.
+ *
+ * @param display
+ * a display on which thread to execute tasks
+ *
+ * @return the executor
+ *
+ * @see #createAsyncOnceExecutor(Display)
+ */
+ public static Executor createAsyncOnceExecutor() {
+ return createAsyncOnceExecutor(Display.getDefault());
+ }
+
+ /**
+ * Obtains a simple executor that asynchronously executes at most one task on the given {@code display}'s thread. While any task is still pending execution on this executor,
+ * all others are silently discarded. This is useful for cases where, for example, UI
+ * refreshes are posted repeatedly from independent events that aren't aware of each other
+ * but where each refresh task would repeat the same work.
+ *
+ * @param display
+ * a display on which thread to execute tasks
+ *
+ * @return the executor
+ */
+ public static Executor createAsyncOnceExecutor(final Display display) {
+ return new Executor() {
+ private final AtomicBoolean pending = new AtomicBoolean();
+
+ public void execute(final Runnable task) {
+ if (pending.compareAndSet(false, true)) {
+ display.asyncExec(new Runnable() {
+
+ public void run() {
+ pending.set(false);
+ task.run();
+ }
+ });
+ }
+ }
+ };
+ }
+
//
// Nested types
//
- private static class UIExecutorService extends AbstractExecutorService {
+ private static abstract class UIExecutorService extends AbstractExecutorService {
private final Lock lock = new ReentrantLock();
@@ -144,12 +250,10 @@ public class UIUtil {
private final Queue<RunnableWrapper> pending = new LinkedList<RunnableWrapper>();
- private final Display display;
-
private volatile boolean shutdown;
- UIExecutorService(Display display) {
- this.display = display;
+ UIExecutorService() {
+ super();
}
public void execute(Runnable command) {
@@ -157,9 +261,11 @@ public class UIUtil {
throw new RejectedExecutionException("Executor service is shut down"); //$NON-NLS-1$
}
- display.asyncExec(enqueue(command));
+ asyncExec(enqueue(command));
}
+ abstract void asyncExec(Runnable runnable);
+
public List<Runnable> shutdownNow() {
List<Runnable> result = new ArrayList<Runnable>();
@@ -286,4 +392,34 @@ public class UIUtil {
}
}
};
+
+ 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);
+ }
+ }
+
+ 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);
+ }
+ }
}
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/commands/CreateControlResource.java b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/commands/CreateControlResource.java
index e5068461254..e989776a7c0 100644
--- a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/commands/CreateControlResource.java
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/commands/CreateControlResource.java
@@ -1,6 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2013 Atos.
- *
+ * Copyright (c) 2013, 2014 Atos, 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
@@ -9,6 +8,7 @@
*
* Contributors:
* Arthur Daussy (Atos) arthur.daussy@atos.net - Initial API and implementation
+ * Christian W. Damus - bug 399859
*
*****************************************************************************/
package org.eclipse.papyrus.infra.services.controlmode.commands;
@@ -55,7 +55,15 @@ public class CreateControlResource extends AbstractControlResourceCommand {
Resource resource = getResourceSet().getResource(getTargetUri(), false);
boolean resourceInSet = resource != null;
if (resourceInSet) {
- return CommandResult.newErrorCommandResult("The resource is already in the resource set");
+ if (failedToLoadBecauseNonexistent(resource)) {
+ // It doesn't exist, so by re-creating it we may actually help to fix unresolved proxies
+ // (such as from an out-of-date sash model)
+ resource.getResourceSet().getResources().remove(resource);
+ resource = null;
+ resourceInSet = false;
+ } else {
+ return CommandResult.newErrorCommandResult("The resource is already in the resource set");
+ }
}
Resource newResource = getResourceSet().createResource(getTargetUri());
if (newResource == null) {
@@ -70,6 +78,17 @@ public class CreateControlResource extends AbstractControlResourceCommand {
return CommandResult.newOKCommandResult(newResource);
}
+ boolean failedToLoadBecauseNonexistent(Resource resource) {
+ boolean result = false;
+
+ if (resource.getContents().isEmpty() && !resource.getErrors().isEmpty()) {
+ // Does it exist to load it?
+ result = !resource.getResourceSet().getURIConverter().exists(resource.getURI(), null);
+ }
+
+ return result;
+ }
+
@Override
protected IStatus doUndo(IProgressMonitor monitor, IAdaptable info) throws ExecutionException {
IStatus superStatus = super.doUndo(monitor, info);
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/participants/IControlCommandParticipant.java b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/participants/IControlCommandParticipant.java
index b121fdd4830..e9f6e8ede2c 100644
--- a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/participants/IControlCommandParticipant.java
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/participants/IControlCommandParticipant.java
@@ -1,5 +1,6 @@
/*******************************************************************************
- * Copyright (c) 2013 Atos.
+ * Copyright (c) 2013, 2014 Atos, 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
@@ -7,6 +8,8 @@
*
* Contributors:
* Arthur Daussy <a href="mailto:arthur.daussy@atos.net"> - initial API and implementation
+ * Christian W. Damus - bug 399859
+ *
******************************************************************************/
package org.eclipse.papyrus.infra.services.controlmode.participants;
@@ -35,7 +38,8 @@ public interface IControlCommandParticipant extends IControlModeParticipant {
/**
* Ask the participant for command that will be executed before the control command
- * The returned command should not be null (use {@link UnexecutableCommand}
+ * The returned command should be {@code null} if no pre-control command is
+ * required (an {@link UnexecutableCommand} blocks all pre-control execution).
*
* @param request
* @return
@@ -44,7 +48,9 @@ public interface IControlCommandParticipant extends IControlModeParticipant {
/**
* Ask the participant for command that will be executed after the control command
- *
+ * The returned command should be {@code null} if no post-control command is
+ * required (an {@link UnexecutableCommand} blocks all post-control execution).
+ *
* @param request
* @return
*/
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/participants/IUncontrolCommandParticipant.java b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/participants/IUncontrolCommandParticipant.java
index 791f1b014cb..4bfaacadce7 100644
--- a/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/participants/IUncontrolCommandParticipant.java
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.controlmode/src/org/eclipse/papyrus/infra/services/controlmode/participants/IUncontrolCommandParticipant.java
@@ -1,6 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2013 Atos.
- *
+ * Copyright (c) 2013, 2014 Atos, 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
@@ -9,11 +8,13 @@
*
* Contributors:
* Arthur Daussy (Atos) arthur.daussy@atos.net - Initial API and implementation
+ * Christian W. Damus - bug 399859
*
*****************************************************************************/
package org.eclipse.papyrus.infra.services.controlmode.participants;
import org.eclipse.gmf.runtime.common.core.command.ICommand;
+import org.eclipse.gmf.runtime.common.core.command.UnexecutableCommand;
import org.eclipse.papyrus.infra.services.controlmode.ControlModeRequest;
/**
@@ -33,16 +34,20 @@ public interface IUncontrolCommandParticipant extends IControlModeParticipant {
public boolean provideUnControlCommand(ControlModeRequest request);
/**
- * Ask the participant for command that will be executed before the control/uncontrol command
- *
+ * Ask the participant for command that will be executed before the uncontrol command
+ * The returned command should be {@code null} if no pre-uncontrol command is
+ * required (an {@link UnexecutableCommand} blocks all pre-uncontrol execution).
+ *
* @param request
* @return
*/
public ICommand getPreUncontrolCommand(ControlModeRequest request);
/**
- * Ask the participant for command that will be executed after the control/uncontrol command
- *
+ * Ask the participant for command that will be executed after the uncontrol command
+ * The returned command should be {@code null} if no post-uncontrol command is
+ * required (an {@link UnexecutableCommand} blocks all post-uncontrol execution).
+ *
* @param request
* @return
*/
diff --git a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/MultipleValueEditor.java b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/MultipleValueEditor.java
index 0002e105505..1c9ecd9e80d 100644
--- a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/MultipleValueEditor.java
+++ b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/MultipleValueEditor.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2010, 2014 CEA LIST and others.
+ * Copyright (c) 2010, 2014 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
@@ -9,6 +9,7 @@
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
* Christian W. Damus (CEA) - bug 402525
+ * Christian W. Damus - bug 399859
*
*****************************************************************************/
package org.eclipse.papyrus.infra.widgets.editors;
@@ -21,6 +22,7 @@ import org.eclipse.core.databinding.observable.IChangeListener;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
@@ -246,8 +248,10 @@ public class MultipleValueEditor extends AbstractListEditor implements Selection
remove.setEnabled(!readOnly);
up.setEnabled(ordered && !readOnly);
down.setEnabled(ordered && !readOnly);
- edit.setEnabled(this.referenceFactory != null && referenceFactory.canEdit() && !readOnly);
+ if (edit != null) {
+ edit.setEnabled(this.referenceFactory != null && referenceFactory.canEdit() && !readOnly);
+ }
if (modelProperty != null && this.upperBound != MANY) {
if (modelProperty.size() >= this.upperBound) {
@@ -312,7 +316,7 @@ public class MultipleValueEditor extends AbstractListEditor implements Selection
* @param labelProvider
* The label provider for this editor
*/
- public void setLabelProvider(ILabelProvider labelProvider) {
+ public void setLabelProvider(IBaseLabelProvider labelProvider) {
treeViewer.setLabelProvider(labelProvider);
}
@@ -578,7 +582,7 @@ public class MultipleValueEditor extends AbstractListEditor implements Selection
*/
@Override
public void widgetDefaultSelected(SelectionEvent e) {
- if (e.widget == tree && edit.isEnabled()) {
+ if ((e.widget == tree) && (edit != null) && edit.isEnabled()) {
editAction();
}
}
diff --git a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/providers/DelegatingLabelProvider.java b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/providers/DelegatingLabelProvider.java
index 16d174f58c2..cdfdef64464 100644
--- a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/providers/DelegatingLabelProvider.java
+++ b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/providers/DelegatingLabelProvider.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2013 CEA LIST.
+ * Copyright (c) 2013, 2014 CEA LIST, Christian W. Damus, and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,11 +8,15 @@
*
* Contributors:
* CEA LIST - Initial API and implementation
+ * Christian W. Damus - bug 399859
+ *
*****************************************************************************/
package org.eclipse.papyrus.infra.widgets.providers;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.LabelProviderChangedEvent;
import org.eclipse.swt.graphics.Image;
/**
@@ -20,14 +24,17 @@ import org.eclipse.swt.graphics.Image;
* possibility of overriding certain labels.
*/
public class DelegatingLabelProvider
- implements ILabelProvider {
+ extends LabelProvider {
private final ILabelProvider delegate;
+ private ILabelProviderListener forwardingListener;
public DelegatingLabelProvider(ILabelProvider delegate) {
super();
this.delegate = delegate;
+
+ delegate.addListener(getForwardingListener());
}
@Override
@@ -98,7 +105,21 @@ public class DelegatingLabelProvider
*/
@Override
public void dispose() {
+ delegate.removeListener(getForwardingListener());
delegate.dispose();
}
+ private ILabelProviderListener getForwardingListener() {
+ if (forwardingListener == null) {
+ forwardingListener = new ILabelProviderListener() {
+
+ @Override
+ public void labelProviderChanged(LabelProviderChangedEvent event) {
+ fireLabelProviderChanged(new LabelProviderChangedEvent(DelegatingLabelProvider.this, event.getElements()));
+ }
+ };
+ }
+
+ return forwardingListener;
+ }
}
diff --git a/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/providers/DelegatingStyledLabelProvider.java b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/providers/DelegatingStyledLabelProvider.java
new file mode 100644
index 00000000000..b08a0ac5b89
--- /dev/null
+++ b/plugins/infra/widget/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/providers/DelegatingStyledLabelProvider.java
@@ -0,0 +1,61 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.widgets.providers;
+
+import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider.IStyledLabelProvider;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.StyledString;
+
+/**
+ * A styled label provider that delegates to another styled label provider with the option to override certain labels.
+ */
+public class DelegatingStyledLabelProvider extends DelegatingLabelProvider implements IStyledLabelProvider {
+
+ private final IStyledLabelProvider delegate;
+
+ public DelegatingStyledLabelProvider(ILabelProvider delegate) {
+ super(delegate);
+
+ if (!(delegate instanceof IStyledLabelProvider)) {
+ throw new IllegalArgumentException("delegate is not a styled label provider"); //$NON-NLS-1$
+ }
+
+ this.delegate = (IStyledLabelProvider) delegate;
+ }
+
+ @Override
+ public StyledString getStyledText(Object element) {
+ StyledString result = customGetStyledText(element);
+ if (result == null) {
+ result = delegatedGetStyledText(element);
+ }
+ return result;
+ }
+
+ /**
+ * Override in subclasses to return custom styled text to override the delegate.
+ * The default implementation simply returns {@code null}.
+ *
+ * @param element
+ * an element for which to provide styled text
+ * @return the custom styled text, or {@code null} to delegate
+ */
+ protected StyledString customGetStyledText(Object element) {
+ return null;
+ }
+
+ protected final StyledString delegatedGetStyledText(Object element) {
+ return delegate.getStyledText(element);
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/.classpath b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/.classpath
new file mode 100644
index 00000000000..ad32c83a788
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/.project b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/.project
new file mode 100644
index 00000000000..3e210335afd
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.papyrus.uml.decoratormodel.controlmode</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/.settings/org.eclipse.jdt.core.prefs b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000000..94d61f00da6
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,291 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
+org.eclipse.jdt.core.formatter.comment.line_length=260
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=false
+org.eclipse.jdt.core.formatter.join_wrapped_lines=false
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=260
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=5
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/.settings/org.eclipse.jdt.ui.prefs b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 00000000000..954281dbc31
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,68 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=false
+cleanup.always_use_this_for_non_static_field_access=false
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=false
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=false
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=true
+cleanup.organize_imports=false
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=true
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=false
+cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+cleanup.use_this_for_non_static_method_access=false
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_Papyrus
+cleanup_settings_version=2
+eclipse.preferences.version=1
+formatter_profile=_Papyrus
+formatter_settings_version=12
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=java;javax;org;com;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="false" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * Constructor.\n *\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*****************************************************************************\n * Copyright (c) ${year} CEA LIST and others.\n * \n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * which accompanies this distribution, and is available at\n * http\://www.eclipse.org/legal/epl-v10.html\n *\n * Contributors\:\n * CEA LIST - Initial API and implementation\n * \n *****************************************************************************/\n</template><template autoinsert\="true" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * @author ${user}\n *\n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment">/**\n * ${see_to_overridden}\n *\n * ${tags}\n */</template><template autoinsert\="false" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${see_to_target}\n *\n * ${tags}\n */</template><template autoinsert\="true" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/META-INF/MANIFEST.MF b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/META-INF/MANIFEST.MF
new file mode 100644
index 00000000000..bd31b94d679
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/META-INF/MANIFEST.MF
@@ -0,0 +1,32 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-SymbolicName: org.eclipse.papyrus.uml.decoratormodel.controlmode;singleton:=true
+Bundle-Version: 1.1.0.qualifier
+Bundle-ClassPath: .
+Bundle-Activator: org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.Activator
+Bundle-Vendor: %providerName
+Bundle-Localization: plugin
+Require-Bundle: org.eclipse.core.runtime,
+ org.eclipse.emf.ecore;bundle-version="2.10.0";visibility:=reexport,
+ org.eclipse.uml2.types;visibility:=reexport,
+ org.eclipse.papyrus.infra.core.log;bundle-version="1.1.0",
+ org.eclipse.uml2.uml;visibility:=reexport,
+ org.eclipse.uml2.common;visibility:=reexport,
+ org.eclipse.papyrus.infra.core;bundle-version="1.1.0",
+ org.eclipse.papyrus.infra.emf;bundle-version="1.1.0",
+ org.eclipse.papyrus.uml.tools.utils;bundle-version="1.1.0",
+ org.eclipse.papyrus.uml.tools;bundle-version="1.1.0",
+ org.eclipse.emf.transaction;bundle-version="1.4.0",
+ com.google.guava;bundle-version="11.0.0",
+ org.eclipse.gmf.runtime.emf.commands.core;bundle-version="1.7.0",
+ org.eclipse.papyrus.uml.decoratormodel;bundle-version="1.1.0",
+ org.eclipse.papyrus.infra.services.controlmode;bundle-version="1.1.0",
+ org.eclipse.ui;bundle-version="3.107.0",
+ org.eclipse.papyrus.infra.tools;bundle-version="1.1.0"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Bundle-ActivationPolicy: lazy
+Export-Package: org.eclipse.papyrus.uml.decoratormodel.internal.controlmode;x-internal:=true,
+ org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.commands;x-internal:=true,
+ org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.messages;x-internal:=true,
+ org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.updaters;x-internal:=true
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/about.html b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/about.html
new file mode 100644
index 00000000000..d35d5aed64c
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>June 5, 2007</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
+
+</body>
+</html>
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/build.properties b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/build.properties
new file mode 100644
index 00000000000..ec9cbd2972b
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/build.properties
@@ -0,0 +1,9 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ about.html,\
+ documentation.pdoc,\
+ plugin.xml,\
+ plugin.properties
+src.includes = about.html
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/documentation.pdoc b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/documentation.pdoc
new file mode 100644
index 00000000000..9c2acff120a
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/documentation.pdoc
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<doc:Documentation xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:doc="http://www.eclipse.org/papyrus/documentation/plugin/documentation" description="Control-mode participants for management of externalized profile applications.">
+ <referent firstName="Christian" lastName="Damus" eMail="give.a.damus@gmail.com" currentCompany="independent"/>
+</doc:Documentation>
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/plugin.properties b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/plugin.properties
new file mode 100644
index 00000000000..a1a12f40362
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/plugin.properties
@@ -0,0 +1,12 @@
+# Copyright (c) 2014 Christian W. Damus and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Christian W. Damus - Initial API and implementation
+
+pluginName = Papyrus Decorator Models Control Mode Extensions
+providerName = Eclipse Modeling Project
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/plugin.xml b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/plugin.xml
new file mode 100644
index 00000000000..d30b4fae382
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/plugin.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+ <extension
+ point="org.eclipse.papyrus.infra.services.controlmode.participant">
+ <participant
+ class="org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.DecoratorModelControlModeParticipant">
+ </participant>
+ </extension>
+
+</plugin>
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/pom.xml b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/pom.xml
new file mode 100644
index 00000000000..666d54e42e5
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/pom.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project>
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>org.eclipse.papyrus</artifactId>
+ <groupId>org.eclipse.papyrus</groupId>
+ <version>1.1.0-SNAPSHOT</version>
+ <relativePath>../../../../releng/top-pom-main.xml</relativePath>
+ </parent>
+ <artifactId>org.eclipse.papyrus.uml.decoratormodel.controlmode</artifactId>
+ <groupId>org.eclipse.papyrus</groupId>
+ <version>1.1.0-SNAPSHOT</version>
+ <packaging>eclipse-plugin</packaging>
+</project> \ No newline at end of file
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/Activator.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/Activator.java
new file mode 100644
index 00000000000..f5898c8bdc0
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/Activator.java
@@ -0,0 +1,118 @@
+/*****************************************************************************
+ * Copyright (c) 2013, 2014 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:
+ * Remi Schnekenburger (CEA LIST) - Initial API and implementation
+ * Christian W. Damus - bug 399859
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.controlmode;
+
+import java.util.concurrent.ExecutorService;
+
+import org.eclipse.core.runtime.Plugin;
+import org.eclipse.papyrus.infra.core.log.LogHelper;
+import org.eclipse.papyrus.infra.tools.util.UIUtil;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class Activator extends Plugin {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "org.eclipse.papyrus.uml.decoratormodel.controlmode"; //$NON-NLS-1$
+
+ // The shared instance
+ private static Activator plugin;
+
+ /** logger helper */
+ public static LogHelper log;
+
+ private ExecutorService executorService;
+
+ public Activator() {
+ super();
+ }
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+
+ executorService = UIUtil.createUIExecutor(Display.getDefault());
+
+ plugin = this;
+ log = new LogHelper(this);
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ executorService.shutdown();
+ executorService = null;
+
+ plugin = null;
+ log = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static Activator getDefault() {
+ return plugin;
+ }
+
+ public static IWorkbenchWindow getActiveWorkbenchWindow() {
+ IWorkbenchWindow result = null;
+
+ IWorkbench bench = PlatformUI.getWorkbench();
+ if (bench != null) {
+ result = bench.getActiveWorkbenchWindow();
+ if (result == null) {
+ IWorkbenchWindow[] allWindows = bench.getWorkbenchWindows();
+ if (allWindows.length > 0) {
+ result = allWindows[0];
+ }
+ }
+ }
+
+ return result;
+ }
+
+ public ExecutorService getExecutorService() {
+ return executorService;
+ }
+
+ /**
+ * Changes my executor service for asynchronous processing in control-mode refactorings.
+ *
+ * @param executorService
+ * the new executor service. Must not be {@code null}
+ *
+ * @return the formerly installed executor service (please restore it when you have finished with yours)
+ *
+ * @throws IllegalArgumentException
+ * if {@code executorService} is {@code null}
+ */
+ public ExecutorService setExecutorService(ExecutorService executorService) {
+ if (executorService == null) {
+ throw new IllegalArgumentException("null executorService"); //$NON-NLS-1$
+ }
+
+ ExecutorService result = this.executorService;
+ this.executorService = executorService;
+ return result;
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/DecoratorModelControlModeParticipant.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/DecoratorModelControlModeParticipant.java
new file mode 100644
index 00000000000..53a0c916d56
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/DecoratorModelControlModeParticipant.java
@@ -0,0 +1,142 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.controlmode;
+
+import static org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.PackageRefactoringContext.getPackagesBeingControlled;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.gmf.runtime.common.core.command.CompositeCommand;
+import org.eclipse.gmf.runtime.common.core.command.ICommand;
+import org.eclipse.gmf.runtime.common.core.command.UnexecutableCommand;
+import org.eclipse.papyrus.infra.services.controlmode.ControlModeRequest;
+import org.eclipse.papyrus.infra.services.controlmode.participants.IControlCommandParticipant;
+import org.eclipse.papyrus.infra.services.controlmode.participants.IUncontrolCommandParticipant;
+import org.eclipse.papyrus.uml.decoratormodel.helper.DecoratorModelUtils;
+import org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.commands.ConfirmSaveCommand;
+import org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.commands.DecoratorModelRefactoringCommandFactory;
+import org.eclipse.uml2.uml.Package;
+
+/**
+ * Control-mode participant for handling dependent decorator models that apply profiles to the
+ * package(s) being controlled in new resource(s).
+ */
+public class DecoratorModelControlModeParticipant implements IControlCommandParticipant, IUncontrolCommandParticipant {
+ static final String PARTICIPANT_ID = Activator.PLUGIN_ID + ".participant"; //$NON-NLS-1$
+
+ public DecoratorModelControlModeParticipant() {
+ super();
+ }
+
+ @Override
+ public String getID() {
+ return PARTICIPANT_ID;
+ }
+
+ @Override
+ public int getPriority() {
+ // We really want this to be the last participant to run, both in control and uncontrol cases
+ return -100;
+ }
+
+ @Override
+ public boolean provideControlCommand(ControlModeRequest request) {
+ return hasExternalProfileApplications(request, true);
+ }
+
+ @Override
+ public ICommand getPreControlCommand(ControlModeRequest request) {
+ // Refactoring is done as a post-process
+ ICommand result = null;
+
+ if (request.isUIAction() && hasExternalProfileApplications(request, false)) {
+ // Refactoring will require save, so prompt the user
+ result = new ConfirmSaveCommand(Activator.getActiveWorkbenchWindow().getShell());
+ }
+
+ try {
+ result = CompositeCommand.compose(result, DecoratorModelRefactoringCommandFactory.createPreCommand(request));
+ } catch (CoreException e) {
+ Activator.getDefault().getLog().log(e.getStatus());
+ result = new UnexecutableCommand(e.getStatus());
+ }
+
+ return result;
+ }
+
+ @Override
+ public ICommand getPostControlCommand(ControlModeRequest request) {
+ try {
+ return DecoratorModelRefactoringCommandFactory.createPostCommand(request);
+ } catch (CoreException e) {
+ Activator.getDefault().getLog().log(e.getStatus());
+ return new UnexecutableCommand(e.getStatus());
+ }
+ }
+
+ @Override
+ public boolean provideUnControlCommand(ControlModeRequest request) {
+ return hasExternalProfileApplications(request, true);
+ }
+
+ @Override
+ public ICommand getPreUncontrolCommand(ControlModeRequest request) {
+ // Refactoring is done as a post-process
+ ICommand result = null;
+
+ if (request.isUIAction() && hasExternalProfileApplications(request, false)) {
+ // Refactoring will require save, so prompt the user
+ result = new ConfirmSaveCommand(Activator.getActiveWorkbenchWindow().getShell());
+ }
+
+ try {
+ result = CompositeCommand.compose(result, DecoratorModelRefactoringCommandFactory.createPreCommand(request));
+ } catch (CoreException e) {
+ Activator.getDefault().getLog().log(e.getStatus());
+ result = new UnexecutableCommand(e.getStatus());
+ }
+
+ return result;
+ }
+
+ @Override
+ public ICommand getPostUncontrolCommand(ControlModeRequest request) {
+ try {
+ return DecoratorModelRefactoringCommandFactory.createPostCommand(request);
+ } catch (CoreException e) {
+ Activator.getDefault().getLog().log(e.getStatus());
+ return new UnexecutableCommand(e.getStatus());
+ }
+ }
+
+ protected boolean hasExternalProfileApplications(ControlModeRequest request, boolean includeLoaded) {
+ boolean result = false;
+
+ for (Package next : getPackagesBeingControlled(request.getTargetObject())) {
+ try {
+ result = !DecoratorModelUtils.getAllDecoratorModelAppliedProfileDefinitions(next, includeLoaded, true).isEmpty();
+ } catch (CoreException e) {
+ // Assume that some refactoring is needed (the commands may later fail or, hopefully,
+ // find nothing to do)
+ result = true;
+ Activator.getDefault().getLog().log(e.getStatus());
+ }
+
+ if (result) {
+ break;
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/PackageRefactoringContext.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/PackageRefactoringContext.java
new file mode 100644
index 00000000000..2bd604621c9
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/PackageRefactoringContext.java
@@ -0,0 +1,265 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.controlmode;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.emf.transaction.util.TransactionUtil;
+import org.eclipse.papyrus.infra.emf.utils.EMFFunctions;
+import org.eclipse.papyrus.infra.emf.utils.EMFPredicates;
+import org.eclipse.papyrus.infra.services.controlmode.ControlModeRequest;
+import org.eclipse.papyrus.infra.tools.util.ReferenceCounted;
+import org.eclipse.papyrus.uml.decoratormodel.helper.DecoratorModelUtils;
+import org.eclipse.papyrus.uml.decoratormodel.internal.resource.DecoratorModelIndex;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.Profile;
+import org.eclipse.uml2.uml.ProfileApplication;
+import org.eclipse.uml2.uml.UMLPackage;
+
+import com.google.common.base.Functions;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Iterators;
+import com.google.common.collect.MapMaker;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+/**
+ * Contextual information about the control/uncontrol refactoring of a package
+ * that informs the refactoring of dependent decorator models.
+ */
+public class PackageRefactoringContext extends ReferenceCounted<PackageRefactoringContext> {
+ private static Map<Package, PackageRefactoringContext> contexts = new MapMaker().weakKeys().weakValues().makeMap();
+
+ private final Package package_;
+ private final URI oldUserModelURI;
+ private final URI newUserModelURI;
+
+ private final TransactionalEditingDomain domain;
+ private final Set<Package> affectedPackages;
+ private final Set<ProfileApplication> preRefactoringProfileApplications;
+
+ // Map of profile URI to decorator-model URI to applied definition URI
+ private final Map<URI, Map<URI, URI>> allExternalAppliedProfiles;
+ // Just those that are inherited from the parent package
+ private final Map<URI, Map<URI, URI>> inheritedExternalAppliedProfiles;
+
+ private final Set<URI> affectedDecoratorModels;
+ private final Set<URI> affectedLoadedDecoratorModels;
+ private final Set<URI> affectedUnloadedDecoratorModels;
+
+ private Map<Object, Object> data;
+
+ private PackageRefactoringContext(Package package_, URI oldUserModelURI, URI newUserModelURI) {
+ super(Activator.getDefault().getExecutorService());
+
+ this.package_ = package_;
+ this.oldUserModelURI = oldUserModelURI;
+ this.newUserModelURI = newUserModelURI;
+
+ this.domain = TransactionUtil.getEditingDomain(package_);
+ this.affectedPackages = ImmutableSet.copyOf(getPackagesBeingControlled(package_));
+ this.preRefactoringProfileApplications = ImmutableSet.copyOf(package_.getProfileApplications());
+
+ // Find URIs of decorator models attached to these packages and all their ancestors because
+ // all of those profiles are applied to these packages, except for any that are loaded
+ // because their proxies will take care of themselves
+
+ Set<Package> allPackages = Sets.newHashSet(affectedPackages);
+ for (Package next : affectedPackages) {
+ allPackages.addAll(next.allOwningPackages());
+ }
+
+ Set<URI> decorators = Sets.newHashSet();
+ Map<URI, Map<URI, URI>> allExternal = null;
+ Map<URI, Map<URI, URI>> inheritedExternal = null;
+ try {
+ allExternal = DecoratorModelUtils.getAllDecoratorModelAppliedProfileDefinitions(package_);
+ if (package_.getNestingPackage() != null) {
+ inheritedExternal = DecoratorModelUtils.getAllDecoratorModelAppliedProfileDefinitions(package_.getNestingPackage());
+ }
+
+ for (Package next : allPackages) {
+ decorators.addAll(DecoratorModelIndex.getInstance().getDecoratorModelsForPackage(EcoreUtil.getURI(next)));
+ }
+ } catch (CoreException e) {
+ // TODO
+ Activator.getDefault().getLog().log(e.getStatus());
+ allExternal = Collections.emptyMap();
+ }
+
+ this.allExternalAppliedProfiles = (allExternal != null) ? allExternal : Collections.<URI, Map<URI, URI>> emptyMap();
+ this.inheritedExternalAppliedProfiles = (inheritedExternal != null) ? inheritedExternal : Collections.<URI, Map<URI, URI>> emptyMap();
+ this.affectedDecoratorModels = ImmutableSet.copyOf(decorators);
+
+ Set<URI> allLoaded = Sets.newHashSet(Iterables.transform(Iterables.filter(domain.getResourceSet().getResources(), EMFPredicates.isLoaded()), EMFFunctions.resourceURI()));
+ this.affectedLoadedDecoratorModels = ImmutableSet.copyOf(Sets.intersection(decorators, allLoaded));
+ decorators.removeAll(allLoaded);
+ this.affectedUnloadedDecoratorModels = ImmutableSet.copyOf(decorators);
+ }
+
+ static PackageRefactoringContext get(Package package_, ControlModeRequest request) {
+ PackageRefactoringContext result = contexts.get(package_);
+
+ if (result == null) {
+ result = new PackageRefactoringContext(package_, request.getSourceURI(), request.getNewURI());
+ contexts.put(package_, result);
+ }
+
+ return result;
+ }
+
+ static void remove(PackageRefactoringContext context) {
+ if (contexts.get(context.getPackage()) == context) {
+ contexts.remove(context.getPackage());
+ }
+ }
+
+ /**
+ * Obtains the current package refactoring context for the specified {@code request}, if any.
+ * <b>Note</b> that this method {@linkplain ReferenceCounted#retain() retains} the resulting context.
+ *
+ * @param request
+ * a request
+ * @return the retained context, or {@code null} if none
+ */
+ public static PackageRefactoringContext getInstance(ControlModeRequest request) {
+ return (request.getTargetObject() instanceof Package) ? get((Package) request.getTargetObject(), request).retain() : null;
+ }
+
+ @Override
+ protected void dispose() {
+ remove(this);
+ data = null;
+ }
+
+ public TransactionalEditingDomain getEditingDomain() {
+ return domain;
+ }
+
+ public Package getPackage() {
+ return package_;
+ }
+
+ public URI getOldUserModelURI() {
+ return oldUserModelURI;
+ }
+
+ public URI getNewUserModelURI() {
+ return newUserModelURI;
+ }
+
+ public Set<ProfileApplication> getPreRefactoringProfileApplications() {
+ return preRefactoringProfileApplications;
+ }
+
+ public Set<Profile> getPreRefactoringAppliedProfiles() {
+ return ImmutableSet.copyOf(Collections2.transform(getPreRefactoringProfileApplications(), //
+ EMFFunctions.getFeature(UMLPackage.Literals.PROFILE_APPLICATION__APPLIED_PROFILE, Profile.class)));
+ }
+
+ public Set<URI> getPreRefactoringAppliedProfileURIs() {
+ return ImmutableSet.copyOf(Collections2.transform(getPreRefactoringProfileApplications(), //
+ Functions.compose(EMFFunctions.objectURI(), EMFFunctions.getFeature(UMLPackage.Literals.PROFILE_APPLICATION__APPLIED_PROFILE, Profile.class))));
+ }
+
+ public Set<ProfileApplication> getPostRefactoringProfileApplications() {
+ return Sets.difference(Sets.newHashSet(package_.getProfileApplications()), preRefactoringProfileApplications);
+ }
+
+ public Set<Profile> getPostRefactoringAppliedProfiles() {
+ return ImmutableSet.copyOf(Collections2.transform(getPostRefactoringProfileApplications(), //
+ EMFFunctions.getFeature(UMLPackage.Literals.PROFILE_APPLICATION__APPLIED_PROFILE, Profile.class)));
+ }
+
+ public Set<URI> getPostRefactoringAppliedProfileURIs() {
+ return ImmutableSet.copyOf(Collections2.transform(getPostRefactoringProfileApplications(), //
+ Functions.compose(EMFFunctions.objectURI(), EMFFunctions.getFeature(UMLPackage.Literals.PROFILE_APPLICATION__APPLIED_PROFILE, Profile.class))));
+ }
+
+ public Set<Package> getAffectedPackages() {
+ return affectedPackages;
+ }
+
+ public Map<URI, Map<URI, URI>> getAllExternalProfileApplications() {
+ return allExternalAppliedProfiles;
+ }
+
+ public Map<URI, Map<URI, URI>> getInheritedExternalProfileApplications() {
+ return inheritedExternalAppliedProfiles;
+ }
+
+ public Set<URI> getAffectedDecoratorModels() {
+ return affectedDecoratorModels;
+ }
+
+ public Set<URI> getAffectedLoadedDecoratorModels() {
+ return affectedLoadedDecoratorModels;
+ }
+
+ public Set<URI> getAffectedUnloadedDecoratorModels() {
+ return affectedUnloadedDecoratorModels;
+ }
+
+ public Map<URI, URI> getAllExternalProfileApplicationsFor(URI decoratorModelURI) {
+ return getExternalProfileApplicationsFor(decoratorModelURI, getAllExternalProfileApplications());
+ }
+
+ public Map<URI, URI> getInheritedExternalProfileApplicationsFor(URI decoratorModelURI) {
+ return getExternalProfileApplicationsFor(decoratorModelURI, getInheritedExternalProfileApplications());
+ }
+
+ private Map<URI, URI> getExternalProfileApplicationsFor(URI decoratorModelURI, Map<URI, Map<URI, URI>> source) {
+ ImmutableMap.Builder<URI, URI> result = ImmutableMap.builder();
+
+ for (Map.Entry<URI, Map<URI, URI>> next : source.entrySet()) {
+ URI definition = next.getValue().get(decoratorModelURI);
+ if (definition != null) {
+ result.put(next.getKey(), definition);
+ }
+ }
+
+ return result.build();
+ }
+
+ public static Iterable<Package> getPackagesBeingControlled(final EObject object) {
+ return new Iterable<Package>() {
+
+ @Override
+ public Iterator<Package> iterator() {
+ // The "proper contents" includes containment proxies until such time as they are resolved.
+ // So, filter them out
+ Iterator<EObject> properContents = EcoreUtil.getAllProperContents(Collections.singletonList(object), false);
+ return Iterators.filter(Iterators.filter(properContents, Package.class), EMFPredicates.notProxy());
+ }
+ };
+ }
+
+ public Map<Object, Object> getContextData() {
+ if (data == null) {
+ data = Maps.newHashMap();
+ }
+ return data;
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/commands/AbstractDecoratorModelRefactoringCommand.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/commands/AbstractDecoratorModelRefactoringCommand.java
new file mode 100644
index 00000000000..d42cae0b990
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/commands/AbstractDecoratorModelRefactoringCommand.java
@@ -0,0 +1,143 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.commands;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.gmf.runtime.common.core.command.AbstractCommand;
+import org.eclipse.gmf.runtime.common.core.command.CommandResult;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.PackageRefactoringContext;
+import org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.messages.Messages;
+import org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.updaters.IRefactoringStep;
+
+import com.google.common.collect.Lists;
+
+/**
+ * Common implementation of the commands that refactor loaded and unloaded dependent decorator models for the changes
+ * in the URIs of the base elements of stereotype applications and adding/removing profile applications for
+ * stand-along usage of the user-model controlled units.
+ */
+abstract class AbstractDecoratorModelRefactoringCommand extends AbstractCommand {
+
+ private final List<IRefactoringStep> steps = Lists.newArrayListWithExpectedSize(2);
+
+ private final DirectionConstraint direction;
+
+ private final URI decoratorModelURI;
+
+ protected AbstractDecoratorModelRefactoringCommand(PackageRefactoringContext context, URI decoratorModelURI) {
+ this(context, decoratorModelURI, DirectionConstraint.ALL);
+ }
+
+ protected AbstractDecoratorModelRefactoringCommand(PackageRefactoringContext context, URI decoratorModelURI, DirectionConstraint direction) {
+ super(NLS.bind(Messages.AbstractDecoratorModelRefactoringCommand_0, decoratorModelURI), getIFiles(decoratorModelURI));
+
+ this.direction = direction;
+ this.decoratorModelURI = decoratorModelURI;
+ }
+
+ public AbstractDecoratorModelRefactoringCommand addStep(IRefactoringStep step) {
+ steps.add(step);
+ return this;
+ }
+
+ @Override
+ protected CommandResult doExecuteWithResult(IProgressMonitor monitor, IAdaptable info) throws ExecutionException {
+ SubMonitor sub = SubMonitor.convert(monitor, steps.size());
+
+ if (!direction.canRefactor()) {
+ sub.done();
+ } else {
+ ResourceSet rset = getResourceSet();
+ try {
+ Resource resource = getResource(rset, decoratorModelURI);
+ if ((resource != null) && resource.isLoaded()) {
+ boolean changed = false;
+
+ // If the resource is not loaded, something didn't go right in the basic control step
+ for (ListIterator<IRefactoringStep> iter = steps.listIterator(); iter.hasNext();) {
+ changed = iter.next().refactor(resource, sub.newChild(1)) || changed;
+ }
+
+ resourceRefactored(resource, changed);
+ }
+ } finally {
+ disposeResourceSet(rset);
+ sub.done();
+ }
+ }
+
+ return CommandResult.newOKCommandResult();
+ }
+
+ protected abstract ResourceSet getResourceSet();
+
+ protected abstract Resource getResource(ResourceSet resourceSet, URI decoratorModelURI);
+
+ protected abstract void resourceRefactored(Resource resource, boolean changed) throws ExecutionException;
+
+ protected abstract void disposeResourceSet(ResourceSet resourceSet);
+
+ @Override
+ protected CommandResult doUndoWithResult(IProgressMonitor monitor, IAdaptable info) throws ExecutionException {
+ SubMonitor sub = SubMonitor.convert(monitor, steps.size());
+
+ if (!direction.canUnrefactor()) {
+ sub.done();
+ } else {
+ ResourceSet rset = getResourceSet();
+ try {
+ Resource resource = getResource(rset, decoratorModelURI);
+ if ((resource != null) && resource.isLoaded()) {
+ boolean changed = false;
+
+ // If the resource is not loaded, something didn't go right in the basic control step
+ for (ListIterator<IRefactoringStep> iter = steps.listIterator(steps.size()); iter.hasPrevious();) {
+ changed = iter.previous().unrefactor(resource, sub.newChild(1)) || changed;
+ }
+
+ resourceRefactored(resource, changed);
+ }
+ } finally {
+ disposeResourceSet(rset);
+ sub.done();
+ }
+ }
+
+ return CommandResult.newOKCommandResult();
+ }
+
+ @Override
+ protected CommandResult doRedoWithResult(IProgressMonitor monitor, IAdaptable info) throws ExecutionException {
+ return doExecuteWithResult(monitor, info);
+ }
+
+ private static List<IFile> getIFiles(URI decoratorModel) {
+ return Collections.singletonList(ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(decoratorModel.toPlatformString(true))));
+ }
+
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/commands/ConfirmSaveCommand.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/commands/ConfirmSaveCommand.java
new file mode 100644
index 00000000000..196f131e2ca
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/commands/ConfirmSaveCommand.java
@@ -0,0 +1,58 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.commands;
+
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.gmf.runtime.common.core.command.AbstractCommand;
+import org.eclipse.gmf.runtime.common.core.command.CommandResult;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.messages.Messages;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * A command that prompts the user to confirm the need to save and fails with cancel status if the user elects not to proceed.
+ */
+public class ConfirmSaveCommand extends AbstractCommand {
+ private Shell parentShell;
+
+ public ConfirmSaveCommand(Shell parentShell) {
+ super(Messages.ConfirmSaveCommand_0);
+
+ this.parentShell = parentShell;
+ }
+
+ @Override
+ protected CommandResult doExecuteWithResult(IProgressMonitor progressMonitor, IAdaptable info) throws ExecutionException {
+ if (MessageDialog.openQuestion(parentShell, Messages.ConfirmSaveCommand_1, Messages.ConfirmSaveCommand_2)) {
+ return CommandResult.newOKCommandResult();
+ } else {
+ return CommandResult.newCancelledCommandResult();
+ }
+ }
+
+ @Override
+ protected CommandResult doRedoWithResult(IProgressMonitor progressMonitor, IAdaptable info) throws ExecutionException {
+ // User already confirmed execution; that is sufficient
+ return CommandResult.newOKCommandResult();
+ }
+
+ @Override
+ protected CommandResult doUndoWithResult(IProgressMonitor progressMonitor, IAdaptable info) throws ExecutionException {
+ // User already confirmed execution; that is sufficient
+ return CommandResult.newOKCommandResult();
+ }
+
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/commands/DecoratorModelRefactoringCommandFactory.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/commands/DecoratorModelRefactoringCommandFactory.java
new file mode 100644
index 00000000000..62ada47e4c0
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/commands/DecoratorModelRefactoringCommandFactory.java
@@ -0,0 +1,236 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.commands;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.gmf.runtime.common.core.command.ICommand;
+import org.eclipse.gmf.runtime.emf.commands.core.command.CompositeTransactionalCommand;
+import org.eclipse.papyrus.infra.services.controlmode.ControlModeRequest;
+import org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.PackageRefactoringContext;
+import org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.messages.Messages;
+import org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.updaters.AbstractDecoratorModelUpdater;
+import org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.updaters.CrossReferenceUpdater;
+import org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.updaters.LoadedDecoratorModelUpdaterDelegate;
+import org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.updaters.PostControlDecoratorModelUpdater;
+import org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.updaters.PostUncontrolDecoratorModelUpdater;
+import org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.updaters.UnloadedDecoratorModelUpdaterDelegate;
+
+/**
+ * Factory for control-mode participant commands that refactor loaded and unloaded decorator model resources
+ * according to the changing URIs of referenced objects.
+ */
+public class DecoratorModelRefactoringCommandFactory {
+ private DecoratorModelRefactoringCommandFactory() {
+ super();
+ }
+
+ public static ICommand createPreCommand(ControlModeRequest request) throws CoreException {
+ PackageRefactoringContext context = PackageRefactoringContext.getInstance(request);
+ if (context == null) {
+ return null;
+ }
+
+ boolean needsSave = false;
+ CompositeTransactionalCommand result = new CompositeTransactionalCommand(context.getEditingDomain(), Messages.DecoratorModelRefactoringCommandFactory_0);
+
+ // Gather up all the loaded decorator models and create a command for each
+ for (URI decoratorModel : context.getAffectedLoadedDecoratorModels()) {
+ ICommand refactoringCommand = request.isControlRequest() ?
+ createPreControlLoaded(context, decoratorModel) :
+ createPreUncontrolLoaded(context, decoratorModel);
+ if (refactoringCommand != null) {
+ result.add(refactoringCommand);
+ }
+ }
+
+ // Gather up all the unloaded decorator models and create a command for each
+ for (URI decoratorModel : context.getAffectedUnloadedDecoratorModels()) {
+ ICommand refactoringCommand = request.isControlRequest() ?
+ createPreControlUnloaded(context, decoratorModel) :
+ createPreUncontrolUnloaded(context, decoratorModel);
+ if (refactoringCommand != null) {
+ result.add(refactoringCommand);
+ needsSave = true;
+ }
+ }
+
+ if (result.isEmpty()) {
+ // Didn't need any command after all. Fine
+ result = null;
+ } else if (needsSave) {
+ // Must save the model to ensure that the refactoring of unloaded resources is consistent
+ result.add(new SaveModelCommand(context));
+ }
+
+ context.autoRelease();
+
+ return result;
+ }
+
+ private static RefactoringStepStore getStore(PackageRefactoringContext context, URI decoratorModel) {
+ RefactoringStepStore result = (RefactoringStepStore) context.getContextData().get(decoratorModel);
+ if (result == null) {
+ result = new RefactoringStepStore();
+ context.getContextData().put(decoratorModel, result);
+ }
+ return result;
+ }
+
+ static CrossReferenceUpdater getCrossReferenceUpdater(PackageRefactoringContext context, URI decoratorModel) {
+ RefactoringStepStore store = getStore(context, decoratorModel);
+ if (store.crossReferences == null) {
+ store.crossReferences = new CrossReferenceUpdater(context, decoratorModel);
+ }
+ return store.crossReferences;
+ }
+
+ static AbstractDecoratorModelUpdater getProfileApplicationsUpdater(PackageRefactoringContext context, URI decoratorModel) {
+ RefactoringStepStore store = getStore(context, decoratorModel);
+ return store.profileApplications;
+ }
+
+ static void setProfileApplicationsUpdater(PackageRefactoringContext context, URI decoratorModel, AbstractDecoratorModelUpdater updater) {
+ RefactoringStepStore store = getStore(context, decoratorModel);
+ store.profileApplications = updater;
+ }
+
+ static AbstractDecoratorModelRefactoringCommand createPreControlLoaded(PackageRefactoringContext context, URI decoratorModel) {
+ return null;
+ }
+
+ static AbstractDecoratorModelRefactoringCommand createPreControlUnloaded(PackageRefactoringContext context, URI decoratorModel) {
+ // We need to undo an control refactoring *after* doing the base refactoring, which means that
+ // we must be a pre-refactoring participant for that purpose
+ CrossReferenceUpdater crossReferenceUpdater = getCrossReferenceUpdater(context, decoratorModel);
+ AbstractDecoratorModelUpdater profileApplicationUpdater = getProfileApplicationsUpdater(context, decoratorModel);
+ if (profileApplicationUpdater == null) {
+ profileApplicationUpdater = new PostControlDecoratorModelUpdater(new UnloadedDecoratorModelUpdaterDelegate(context.getPackage()), context, decoratorModel);
+ setProfileApplicationsUpdater(context, decoratorModel, profileApplicationUpdater);
+ }
+ // Steps in reverse order relative to the execute/redo direction!
+ return new UnloadedDecoratorModelRefactoringCommand(context, decoratorModel, DirectionConstraint.UNREFACTOR_ONLY).addStep(profileApplicationUpdater).addStep(crossReferenceUpdater);
+ }
+
+ static AbstractDecoratorModelRefactoringCommand createPreUncontrolLoaded(PackageRefactoringContext context, URI decoratorModel) {
+ return null;
+ }
+
+ static AbstractDecoratorModelRefactoringCommand createPreUncontrolUnloaded(PackageRefactoringContext context, URI decoratorModel) {
+ // We need to undo an uncontrol refactoring *after* undoing the base refactoring, which means that
+ // we must actually be a pre-refactoring participant for that purpose
+ CrossReferenceUpdater crossReferenceUpdater = getCrossReferenceUpdater(context, decoratorModel);
+ AbstractDecoratorModelUpdater profileApplicationUpdater = getProfileApplicationsUpdater(context, decoratorModel);
+ if (profileApplicationUpdater == null) {
+ profileApplicationUpdater = new PostUncontrolDecoratorModelUpdater(new UnloadedDecoratorModelUpdaterDelegate(context.getPackage()), context, decoratorModel);
+ setProfileApplicationsUpdater(context, decoratorModel, profileApplicationUpdater);
+ }
+ // Steps in reverse order relative to the execute/redo direction!
+ return new UnloadedDecoratorModelRefactoringCommand(context, decoratorModel, DirectionConstraint.UNREFACTOR_ONLY).addStep(profileApplicationUpdater).addStep(crossReferenceUpdater);
+ }
+
+ public static ICommand createPostCommand(ControlModeRequest request) throws CoreException {
+ PackageRefactoringContext context = PackageRefactoringContext.getInstance(request);
+ if (context == null) {
+ return null;
+ }
+
+ boolean needsSave = false;
+ CompositeTransactionalCommand result = new CompositeTransactionalCommand(context.getEditingDomain(), Messages.DecoratorModelRefactoringCommandFactory_0);
+
+ // Gather up all the loaded decorator models and create a command for each
+ for (URI decoratorModel : context.getAffectedLoadedDecoratorModels()) {
+ ICommand refactoringCommand = request.isControlRequest() ?
+ createPostControlLoaded(context, decoratorModel) :
+ createPostUncontrolLoaded(context, decoratorModel);
+ if (refactoringCommand != null) {
+ result.add(refactoringCommand);
+ }
+ }
+
+ // Gather up all the unloaded decorator models and create a command for each
+ for (URI decoratorModel : context.getAffectedUnloadedDecoratorModels()) {
+ ICommand refactoringCommand = request.isControlRequest() ?
+ createPostControlUnloaded(context, decoratorModel) :
+ createPostUncontrolUnloaded(context, decoratorModel);
+ if (refactoringCommand != null) {
+ result.add(refactoringCommand);
+ needsSave = true;
+ }
+ }
+
+ if (result.isEmpty()) {
+ // Didn't need any command after all. Fine
+ result = null;
+ } else if (needsSave) {
+ // Must save the model to ensure that the refactoring of unloaded resources is consistent
+ result.add(new SaveModelCommand(context));
+ }
+
+ context.autoRelease();
+
+ return result;
+ }
+
+ static AbstractDecoratorModelRefactoringCommand createPostControlLoaded(PackageRefactoringContext context, URI decoratorModel) {
+ AbstractDecoratorModelUpdater profileApplicationUpdater = getProfileApplicationsUpdater(context, decoratorModel);
+ if (profileApplicationUpdater == null) {
+ profileApplicationUpdater = new PostControlDecoratorModelUpdater(new LoadedDecoratorModelUpdaterDelegate(context.getPackage()), context, decoratorModel);
+ setProfileApplicationsUpdater(context, decoratorModel, profileApplicationUpdater);
+ }
+ return new LoadedDecoratorModelRefactoringCommand(context, decoratorModel).addStep(profileApplicationUpdater);
+ }
+
+ static AbstractDecoratorModelRefactoringCommand createPostControlUnloaded(PackageRefactoringContext context, URI decoratorModel) {
+ // We need to execute/redo an control refactoring *after* doing the base refactoring, which means that
+ // we must be a post-refactoring participant for that purpose
+ CrossReferenceUpdater crossReferenceUpdater = getCrossReferenceUpdater(context, decoratorModel);
+ AbstractDecoratorModelUpdater profileApplicationUpdater = getProfileApplicationsUpdater(context, decoratorModel);
+ if (profileApplicationUpdater == null) {
+ profileApplicationUpdater = new PostControlDecoratorModelUpdater(new UnloadedDecoratorModelUpdaterDelegate(context.getPackage()), context, decoratorModel);
+ setProfileApplicationsUpdater(context, decoratorModel, profileApplicationUpdater);
+ }
+ return new UnloadedDecoratorModelRefactoringCommand(context, decoratorModel, DirectionConstraint.REFACTOR_ONLY).addStep(crossReferenceUpdater).addStep(profileApplicationUpdater);
+ }
+
+ static AbstractDecoratorModelRefactoringCommand createPostUncontrolLoaded(PackageRefactoringContext context, URI decoratorModel) {
+ AbstractDecoratorModelUpdater profileApplicationUpdater = getProfileApplicationsUpdater(context, decoratorModel);
+ if (profileApplicationUpdater == null) {
+ profileApplicationUpdater = new PostUncontrolDecoratorModelUpdater(new LoadedDecoratorModelUpdaterDelegate(context.getPackage()), context, decoratorModel);
+ setProfileApplicationsUpdater(context, decoratorModel, profileApplicationUpdater);
+ }
+ return new LoadedDecoratorModelRefactoringCommand(context, decoratorModel).addStep(profileApplicationUpdater);
+ }
+
+ static AbstractDecoratorModelRefactoringCommand createPostUncontrolUnloaded(PackageRefactoringContext context, URI decoratorModel) {
+ // We need to execute/redo an uncontrol refactoring *after* doing the base refactoring, which means that
+ // we must be a post-refactoring participant for that purpose
+ CrossReferenceUpdater crossReferenceUpdater = getCrossReferenceUpdater(context, decoratorModel);
+ AbstractDecoratorModelUpdater profileApplicationUpdater = getProfileApplicationsUpdater(context, decoratorModel);
+ if (profileApplicationUpdater == null) {
+ profileApplicationUpdater = new PostUncontrolDecoratorModelUpdater(new UnloadedDecoratorModelUpdaterDelegate(context.getPackage()), context, decoratorModel);
+ setProfileApplicationsUpdater(context, decoratorModel, profileApplicationUpdater);
+ }
+ return new UnloadedDecoratorModelRefactoringCommand(context, decoratorModel, DirectionConstraint.REFACTOR_ONLY).addStep(crossReferenceUpdater).addStep(profileApplicationUpdater);
+ }
+
+ //
+ // Nested types
+ //
+
+ private static class RefactoringStepStore {
+ CrossReferenceUpdater crossReferences;
+ AbstractDecoratorModelUpdater profileApplications;
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/commands/DirectionConstraint.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/commands/DirectionConstraint.java
new file mode 100644
index 00000000000..3591acd9f71
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/commands/DirectionConstraint.java
@@ -0,0 +1,32 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.commands;
+
+/**
+ * An enumeration of constraints on the direction in which a command will run.
+ * This allows a pair of commands to run, on in the pre position and one in post,
+ * that share refactoring steps such that one runs the forward refactoring in the
+ * post position and the other the reverse refactoring in the pre position.
+ */
+public enum DirectionConstraint {
+ ALL, REFACTOR_ONLY, UNREFACTOR_ONLY;
+
+ public boolean canRefactor() {
+ return this != UNREFACTOR_ONLY;
+ }
+
+ public boolean canUnrefactor() {
+ return this != REFACTOR_ONLY;
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/commands/LoadedDecoratorModelRefactoringCommand.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/commands/LoadedDecoratorModelRefactoringCommand.java
new file mode 100644
index 00000000000..e10319a3144
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/commands/LoadedDecoratorModelRefactoringCommand.java
@@ -0,0 +1,56 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.commands;
+
+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.transaction.TransactionalEditingDomain;
+import org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.PackageRefactoringContext;
+
+/**
+ * Implementation of the commands that refactor <em>unloaded</em> dependent decorator models for the changes
+ * in the URIs of the base elements of stereotype applications.
+ */
+class LoadedDecoratorModelRefactoringCommand extends AbstractDecoratorModelRefactoringCommand {
+
+ private final TransactionalEditingDomain domain;
+
+ protected LoadedDecoratorModelRefactoringCommand(PackageRefactoringContext context, URI decoratorModelURI) {
+ super(context, decoratorModelURI);
+
+ this.domain = context.getEditingDomain();
+ }
+
+ @Override
+ protected ResourceSet getResourceSet() {
+ return domain.getResourceSet();
+ }
+
+ @Override
+ protected Resource getResource(ResourceSet resourceSet, URI decoratorModelURI) {
+ // The resource is expected to be loaded
+ return resourceSet.getResource(decoratorModelURI, false);
+ }
+
+ @Override
+ protected void disposeResourceSet(ResourceSet resourceSet) {
+ // The resource set is shared with the editor, so leave it alone
+ }
+
+ @Override
+ protected void resourceRefactored(Resource resource, boolean changed) {
+ // Don't save a loaded resource; the editor will do that if necessary
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/commands/SaveModelCommand.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/commands/SaveModelCommand.java
new file mode 100644
index 00000000000..7d9adcc4b3b
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/commands/SaveModelCommand.java
@@ -0,0 +1,148 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.commands;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IAdaptable;
+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.gmf.runtime.common.core.command.AbstractCommand;
+import org.eclipse.gmf.runtime.common.core.command.CommandResult;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.papyrus.infra.core.editor.IMultiDiagramEditor;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.emf.utils.ServiceUtilsForResourceSet;
+import org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.Activator;
+import org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.PackageRefactoringContext;
+import org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.messages.Messages;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * A command that asynchronously saves the model editor after completion of the (un)control operation,
+ * if it completes normally.
+ */
+class SaveModelCommand extends AbstractCommand {
+ private final ModelSet modelSet;
+
+ private volatile boolean savePending;
+
+ SaveModelCommand(PackageRefactoringContext context) {
+ super(Messages.SaveModelCommand_0);
+
+ this.modelSet = (ModelSet) context.getEditingDomain().getResourceSet();
+ }
+
+ @Override
+ protected CommandResult doExecuteWithResult(IProgressMonitor progressMonitor, IAdaptable info) throws ExecutionException {
+ if (savePending) {
+ // We are being invoked to roll back the composite operation that failed in some later command,
+ // so cancel the pending async exec
+ savePending = false;
+ return CommandResult.newOKCommandResult();
+ }
+
+ // We now have a save operation pending (asynchronously)
+ savePending = true;
+
+ // Do this asynchronously because we need the current transaction to have finished first,
+ // otherwise the command-stack (and hence the editor) will be marked dirty when it commits.
+ // Moreover, because undo also needs to save and this is the last command in the composite,
+ // it will actually undo first, which would save then save first if synchronous
+ Activator.getDefault().getExecutorService().execute(new Runnable() {
+
+ @Override
+ public void run() {
+ if (!savePending) {
+ // The execute/undo/redo was rolled back, so don't go through with save.
+ return;
+ }
+ savePending = false;
+
+ try {
+ // Prefer to save the editor so that it doesn't spuriously prompt for reloading
+ // resources saved without its knowledge. Of course, there may not be an editor
+ IRunnableWithProgress save = new IRunnableWithProgress() {
+
+ @Override
+ public void run(IProgressMonitor monitor) throws InvocationTargetException {
+ try {
+ IEditorPart editor = findEditor(modelSet);
+ if (editor != null) {
+ save(editor);
+ } else {
+ modelSet.save(monitor);
+ }
+ } catch (IOException e) {
+ throw new InvocationTargetException(e);
+ }
+ }
+ };
+
+ if (Display.getCurrent() != null) {
+ Activator.getActiveWorkbenchWindow().run(false, false, save);
+ } else {
+ save.run(new NullProgressMonitor());
+ }
+ } catch (InvocationTargetException e) {
+ IStatus status = new Status(IStatus.WARNING, Activator.PLUGIN_ID, Messages.SaveModelCommand_1, e.getTargetException());
+ StatusManager.getManager().handle(status, StatusManager.LOG | StatusManager.SHOW);
+ } catch (InterruptedException e) {
+ IStatus status = new Status(IStatus.WARNING, Activator.PLUGIN_ID, Messages.SaveModelCommand_2, e);
+ StatusManager.getManager().handle(status, StatusManager.LOG | StatusManager.SHOW);
+ }
+ }
+ });
+
+ return CommandResult.newOKCommandResult();
+ }
+
+ @Override
+ protected CommandResult doUndoWithResult(IProgressMonitor progressMonitor, IAdaptable info) throws ExecutionException {
+ // On Undo we also need to save changes to ensure consistency
+ return doExecuteWithResult(progressMonitor, info);
+ }
+
+ @Override
+ protected CommandResult doRedoWithResult(IProgressMonitor progressMonitor, IAdaptable info) throws ExecutionException {
+ // On Redo we also need to save changes to ensure consistency
+ return doExecuteWithResult(progressMonitor, info);
+ }
+
+ static IEditorPart findEditor(ModelSet modelSet) {
+ IEditorPart result = null;
+
+ try {
+ IMultiDiagramEditor editor = ServiceUtilsForResourceSet.getInstance().getService(IMultiDiagramEditor.class, modelSet);
+ if (editor instanceof IEditorPart) {
+ result = editor;
+ }
+ } catch (ServiceException e) {
+ // Obviously this isn't our editor if the service registry doesn't have an editor
+ }
+
+ return result;
+ }
+
+ static void save(IEditorPart editor) {
+ editor.getSite().getPage().saveEditor(editor, false);
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/commands/UnloadedDecoratorModelRefactoringCommand.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/commands/UnloadedDecoratorModelRefactoringCommand.java
new file mode 100644
index 00000000000..89f9e9851a9
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/commands/UnloadedDecoratorModelRefactoringCommand.java
@@ -0,0 +1,68 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.commands;
+
+import java.io.IOException;
+
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
+import org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.PackageRefactoringContext;
+import org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.messages.Messages;
+import org.eclipse.papyrus.uml.decoratormodel.internal.resource.DecoratorModelResourceSet;
+import org.eclipse.papyrus.uml.decoratormodel.model.DecoratorModel;
+
+/**
+ * Implementation of the commands that refactor <em>unloaded</em> dependent decorator models for the changes
+ * in the URIs of the base elements of stereotype applications.
+ */
+class UnloadedDecoratorModelRefactoringCommand extends AbstractDecoratorModelRefactoringCommand {
+ protected UnloadedDecoratorModelRefactoringCommand(PackageRefactoringContext context, URI decoratorModelURI) {
+ super(context, decoratorModelURI);
+ }
+
+ protected UnloadedDecoratorModelRefactoringCommand(PackageRefactoringContext context, URI decoratorModelURI, DirectionConstraint direction) {
+ super(context, decoratorModelURI, direction);
+ }
+
+ @Override
+ protected ResourceSet getResourceSet() {
+ return new DecoratorModelResourceSet();
+ }
+
+ @Override
+ protected Resource getResource(ResourceSet resourceSet, URI decoratorModelURI) {
+ // Load the resource in our scratch resource set
+ return resourceSet.getResource(decoratorModelURI, true);
+ }
+
+ @Override
+ protected void disposeResourceSet(ResourceSet resourceSet) {
+ EMFHelper.unload(resourceSet);
+ }
+
+ @Override
+ protected void resourceRefactored(Resource resource, boolean changed) throws ExecutionException {
+ if (changed) {
+ try {
+ resource.save(new DecoratorModel().getSaveOptions());
+ } catch (IOException e) {
+ throw new ExecutionException(Messages.UnloadedDecoratorModelRefactoringCommand_0, e);
+ }
+ }
+ }
+
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/messages/Messages.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/messages/Messages.java
new file mode 100644
index 00000000000..6d9b148064f
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/messages/Messages.java
@@ -0,0 +1,46 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.messages;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Translatable strings presented in the plug-in's UI.
+ */
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.messages.messages"; //$NON-NLS-1$
+
+ public static String AbstractDecoratorModelRefactoringCommand_0;
+ public static String ConfirmSaveCommand_0;
+ public static String ConfirmSaveCommand_1;
+ public static String ConfirmSaveCommand_2;
+ public static String CrossReferenceUpdater_0;
+ public static String DecoratorModelRefactoringCommandFactory_0;
+ public static String PostControlDecoratorModelUpdater_0;
+ public static String PostControlDecoratorModelUpdater_1;
+ public static String PostUncontrolDecoratorModelUpdater_0;
+ public static String PostUncontrolDecoratorModelUpdater_1;
+ public static String SaveModelCommand_0;
+ public static String SaveModelCommand_1;
+ public static String SaveModelCommand_2;
+ public static String UnloadedDecoratorModelRefactoringCommand_0;
+
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/messages/messages.properties b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/messages/messages.properties
new file mode 100644
index 00000000000..3be38781ee8
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/messages/messages.properties
@@ -0,0 +1,25 @@
+# Copyright (c) 2014 Christian W. Damus and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Christian W. Damus - Initial API and implementation
+#
+
+AbstractDecoratorModelRefactoringCommand_0=Refactor profile application {0}
+ConfirmSaveCommand_0=Confirm Model Save
+ConfirmSaveCommand_1=Save Model
+ConfirmSaveCommand_2=This operation requires refactoring of profile applications that are not loaded. The model must be saved in order to ensure consistency of stereotype applications.\n\nProceed?
+CrossReferenceUpdater_0=Updating cross-references in {0}
+DecoratorModelRefactoringCommandFactory_0=Refactor Profile Application Models
+PostControlDecoratorModelUpdater_0=Updating profile applications in {0}
+PostControlDecoratorModelUpdater_1=Removing profile applications from {0}
+PostUncontrolDecoratorModelUpdater_0=Updating profile applications in {0}
+PostUncontrolDecoratorModelUpdater_1=Restoring profile applications in {0}
+SaveModelCommand_0=Save Model
+SaveModelCommand_1=Failed to save model. Refactorings may be applied inconsistently if the model is not saved.
+SaveModelCommand_2=Model save was cancelled. Refactorings may be applied inconsistently if the model is not saved.
+UnloadedDecoratorModelRefactoringCommand_0=Failed to save refactoring changes
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/AbstractDecoratorModelUpdater.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/AbstractDecoratorModelUpdater.java
new file mode 100644
index 00000000000..b2812529aae
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/AbstractDecoratorModelUpdater.java
@@ -0,0 +1,61 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.updaters;
+
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.ProfileApplication;
+
+/**
+ * Common implementation of profile application updaters for loaded and unloaded models.
+ */
+public abstract class AbstractDecoratorModelUpdater implements IRefactoringStep {
+ private final IDecoratorModelUpdaterDelegate delegate;
+
+ public AbstractDecoratorModelUpdater(IDecoratorModelUpdaterDelegate delegate) {
+ super();
+
+ this.delegate = delegate;
+ }
+
+ @Override
+ public abstract boolean refactor(Resource resource, IProgressMonitor monitor) throws ExecutionException;
+
+ @Override
+ public abstract boolean unrefactor(Resource resource, IProgressMonitor monitor) throws ExecutionException;
+
+ Package getDecoratorPackage(Resource resource) {
+ return delegate.getDecoratorPackage(resource);
+ }
+
+ Package createDecoratorPackage(Resource resource) {
+ return delegate.createDecoratorPackage(resource);
+ }
+
+ ProfileApplication getProfileApplication(Package package_, URI appliedProfileURI) {
+ return delegate.getProfileApplication(package_, appliedProfileURI);
+ }
+
+ boolean hasProfileApplication(Package package_, URI appliedProfileURI) {
+ return getProfileApplication(package_, appliedProfileURI) != null;
+ }
+
+ ProfileApplication addProfileApplication(Package package_, URI profileURI, URI appliedDefinitionURI) {
+ return delegate.addProfileApplication(package_, profileURI, appliedDefinitionURI);
+ }
+
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/AbstractDecoratorModelUpdaterDelegate.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/AbstractDecoratorModelUpdaterDelegate.java
new file mode 100644
index 00000000000..25bea67436e
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/AbstractDecoratorModelUpdaterDelegate.java
@@ -0,0 +1,94 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.updaters;
+
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.papyrus.uml.decoratormodel.helper.DecoratorModelUtils;
+import org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ApplyProfiles;
+import org.eclipse.uml2.uml.Dependency;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.Profile;
+import org.eclipse.uml2.uml.ProfileApplication;
+
+import com.google.common.collect.Iterables;
+
+/**
+ * @author damus
+ *
+ */
+abstract class AbstractDecoratorModelUpdaterDelegate implements IDecoratorModelUpdaterDelegate {
+
+ private final Package package_;
+
+ public AbstractDecoratorModelUpdaterDelegate(Package package_) {
+ super();
+
+ this.package_ = package_;
+ }
+
+ protected final Package getControlledPackage() {
+ return package_;
+ }
+
+ @Override
+ public Package getDecoratorPackage(Resource resource) {
+ Package result = null;
+
+ URI packageURI = EcoreUtil.getURI(package_);
+ for (ApplyProfiles next : Iterables.filter(resource.getContents(), ApplyProfiles.class)) {
+ Dependency dep = next.getBase_Dependency();
+ if ((dep != null) && !dep.getClients().isEmpty()) {
+ if (EcoreUtil.getURI(dep.getClients().get(0)).equals(packageURI)) {
+ // that's the one
+ result = Iterables.getFirst(Iterables.filter(dep.getSuppliers(), Package.class), null);
+ if (result != null) {
+ break;
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public Package createDecoratorPackage(Resource resource) {
+ Package result = null;
+
+ Package root = DecoratorModelUtils.getDecoratorModel(resource);
+ if (root != null) {
+ result = DecoratorModelUtils.getDecoratorPackage(root, package_, true);
+ }
+
+ return result;
+ }
+
+ @Override
+ public ProfileApplication getProfileApplication(Package package_, URI appliedProfileURI) {
+ ProfileApplication result = null;
+
+ for (ProfileApplication next : package_.getProfileApplications()) {
+ Profile profile = next.getAppliedProfile();
+ if ((profile != null) && EcoreUtil.getURI(profile).equals(appliedProfileURI)) {
+ result = next;
+ break;
+ }
+ }
+
+ return result;
+ }
+
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/CrossReferenceUpdater.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/CrossReferenceUpdater.java
new file mode 100644
index 00000000000..ba2ab576445
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/CrossReferenceUpdater.java
@@ -0,0 +1,123 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.updaters;
+
+import java.util.Iterator;
+
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.InternalEObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.PackageRefactoringContext;
+import org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.messages.Messages;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+
+/**
+ * Implementation of the commands that refactor <em>unloaded</em> dependent decorator models for the changes
+ * in the URIs of the base elements of stereotype applications.
+ */
+public class CrossReferenceUpdater implements IRefactoringStep {
+
+ final TransactionalEditingDomain domain;
+ URI decoratorModelURI;
+ URI oldUserModelURI;
+ URI newUserModelURI;
+
+ public CrossReferenceUpdater(PackageRefactoringContext context, URI decoratorModelURI) {
+ super();
+
+ this.domain = context.getEditingDomain();
+ this.decoratorModelURI = decoratorModelURI;
+ this.oldUserModelURI = context.getOldUserModelURI();
+ this.newUserModelURI = context.getNewUserModelURI();
+ }
+
+ @Override
+ public boolean refactor(Resource resource, IProgressMonitor monitor) throws ExecutionException {
+ return refactor(resource, oldUserModelURI, newUserModelURI, monitor);
+ }
+
+ @Override
+ public boolean unrefactor(Resource resource, IProgressMonitor monitor) throws ExecutionException {
+ return refactor(resource, newUserModelURI, oldUserModelURI, monitor);
+ }
+
+ protected boolean refactor(Resource resource, URI oldURI, URI newURI, IProgressMonitor monitor) throws ExecutionException {
+ boolean result = false;
+ monitor.beginTask(NLS.bind(Messages.CrossReferenceUpdater_0, decoratorModelURI), IProgressMonitor.UNKNOWN);
+
+ // If the resource is not loaded, something didn't go right in the basic control step
+ Resource newUserModelResource = domain.getResourceSet().getResource(newURI, false);
+ if ((newUserModelResource != null) && newUserModelResource.isLoaded()) {
+ final Predicate<EReference> needsRefactoring = needsRefactoring();
+ for (Iterator<EObject> all = resource.getAllContents(); all.hasNext();) {
+ EObject next = all.next();
+ for (EReference ref : Iterables.filter(next.eClass().getEAllReferences(), needsRefactoring)) {
+ if (next.eIsSet(ref)) {
+ if (ref.isMany()) {
+ for (Object xref : (Iterable<?>) next.eGet(ref)) {
+ EObject eXRef = (EObject) xref;
+ if (eXRef.eIsProxy()) {
+ result = refactor(eXRef, oldURI, newURI, newUserModelResource) || result;
+ }
+ }
+ } else {
+ EObject eXRef = (EObject) next.eGet(ref);
+ if ((eXRef != null) && eXRef.eIsProxy()) {
+ result = refactor(eXRef, oldURI, newURI, newUserModelResource) || result;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ boolean refactor(EObject xref, URI oldURI, URI newURI, Resource newUserModelResource) {
+ boolean result = false;
+
+ InternalEObject proxy = (InternalEObject) xref;
+ URI proxyURI = proxy.eProxyURI();
+ if (proxyURI.trimFragment().equals(oldURI)) {
+ String fragment = proxyURI.fragment();
+ EObject target = newUserModelResource.getEObject(fragment);
+ if (target != null) {
+ // Proxy resolves to the new resource? Good. Rewrite it
+ proxy.eSetProxyURI(newURI.appendFragment(fragment));
+ result = true;
+ }
+ }
+
+ return result;
+ }
+
+ static Predicate<EReference> needsRefactoring() {
+ return new Predicate<EReference>() {
+ @Override
+ public boolean apply(EReference input) {
+ return (input != null) && input.isChangeable() && !input.isDerived() && !input.isContainment() && !input.isContainer();
+ }
+ };
+ }
+
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/IDecoratorModelUpdaterDelegate.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/IDecoratorModelUpdaterDelegate.java
new file mode 100644
index 00000000000..ec51c7b2e61
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/IDecoratorModelUpdaterDelegate.java
@@ -0,0 +1,35 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.updaters;
+
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.ProfileApplication;
+
+/**
+ * @author damus
+ *
+ */
+public interface IDecoratorModelUpdaterDelegate {
+
+ Package getDecoratorPackage(Resource resource);
+
+ Package createDecoratorPackage(Resource resource);
+
+ ProfileApplication getProfileApplication(Package package_, URI appliedProfileURI);
+
+ ProfileApplication addProfileApplication(Package package_, URI profileURI, URI appliedDefinitionURI);
+
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/IRefactoringStep.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/IRefactoringStep.java
new file mode 100644
index 00000000000..7d9366005f7
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/IRefactoringStep.java
@@ -0,0 +1,31 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.updaters;
+
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.emf.ecore.resource.Resource;
+
+
+
+/**
+ * Protocol of a step in a sequence of decorator-model resource refactoring steps.
+ */
+public interface IRefactoringStep {
+
+ boolean refactor(Resource resource, IProgressMonitor monitor) throws ExecutionException;
+
+ boolean unrefactor(Resource resource, IProgressMonitor monitor) throws ExecutionException;
+
+} \ No newline at end of file
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/LoadedDecoratorModelUpdaterDelegate.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/LoadedDecoratorModelUpdaterDelegate.java
new file mode 100644
index 00000000000..c9e373d778e
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/LoadedDecoratorModelUpdaterDelegate.java
@@ -0,0 +1,49 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.updaters;
+
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.Profile;
+import org.eclipse.uml2.uml.ProfileApplication;
+
+/**
+ * @author damus
+ *
+ */
+public class LoadedDecoratorModelUpdaterDelegate extends AbstractDecoratorModelUpdaterDelegate {
+
+ public LoadedDecoratorModelUpdaterDelegate(Package package_) {
+ super(package_);
+ }
+
+ @Override
+ public ProfileApplication addProfileApplication(Package package_, URI profileURI, URI appliedDefinitionURI) {
+ ProfileApplication result = null;
+
+ // Get the corresponding loaded profile application of the controlled package
+ Profile profile = (Profile) EMFHelper.getResourceSet(getControlledPackage()).getEObject(profileURI, true);
+ ProfileApplication toCopy = getControlledPackage().getProfileApplication(profile, true);
+
+ if (toCopy != null) {
+ result = EcoreUtil.copy(toCopy);
+ package_.getProfileApplications().add(result);
+ }
+
+ return result;
+ }
+
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/PostControlDecoratorModelUpdater.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/PostControlDecoratorModelUpdater.java
new file mode 100644
index 00000000000..0851837adcd
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/PostControlDecoratorModelUpdater.java
@@ -0,0 +1,104 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.updaters;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.PackageRefactoringContext;
+import org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.messages.Messages;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.ProfileApplication;
+
+import com.google.common.collect.Sets;
+
+/**
+ * A post-control updater of the profile applications that are stored in a decorator model.
+ *
+ */
+public class PostControlDecoratorModelUpdater extends AbstractDecoratorModelUpdater {
+
+ // Mapping of profile URI to applied definition EPackage URI
+ private final Map<URI, URI> profilesToAdd;
+ private Set<URI> profilesAdded;
+
+ public PostControlDecoratorModelUpdater(IDecoratorModelUpdaterDelegate delegate, PackageRefactoringContext context, URI decoratorModelURI) {
+ super(delegate);
+
+ this.profilesToAdd = context.getAllExternalProfileApplicationsFor(decoratorModelURI);
+ }
+
+ @Override
+ public boolean refactor(Resource resource, IProgressMonitor monitor) throws ExecutionException {
+ boolean result = false;
+
+ monitor.beginTask(NLS.bind(Messages.PostControlDecoratorModelUpdater_0, resource.getURI().lastSegment()), IProgressMonitor.UNKNOWN);
+ if (!profilesToAdd.isEmpty()) {
+ Package evilTwin = getDecoratorPackage(resource);
+ if (evilTwin == null) {
+ evilTwin = createDecoratorPackage(resource);
+ result = true;
+ }
+
+ for (Map.Entry<URI, URI> next : profilesToAdd.entrySet()) {
+ URI profileURI = next.getKey();
+ if (!hasProfileApplication(evilTwin, profileURI)) {
+ addProfileApplication(evilTwin, profileURI, next.getValue());
+ result = true;
+
+ if (profilesAdded == null) {
+ profilesAdded = Sets.newHashSet();
+ }
+ profilesAdded.add(profileURI);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public boolean unrefactor(Resource resource, IProgressMonitor monitor) throws ExecutionException {
+ boolean result = false;
+
+ monitor.beginTask(NLS.bind(Messages.PostControlDecoratorModelUpdater_1, resource.getURI().lastSegment()), IProgressMonitor.UNKNOWN);
+ if (profilesAdded != null) {
+ Package evilTwin = getDecoratorPackage(resource);
+ if (evilTwin != null) {
+ for (URI next : profilesAdded) {
+ ProfileApplication application = getProfileApplication(evilTwin, next);
+ if (application != null) {
+ application.destroy();
+ result = true;
+ }
+ }
+
+ if (evilTwin.getProfileApplications().isEmpty()) {
+ evilTwin.destroy();
+ result = true;
+ }
+ }
+
+ profilesAdded = null;
+ }
+
+ return result;
+ }
+
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/PostUncontrolDecoratorModelUpdater.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/PostUncontrolDecoratorModelUpdater.java
new file mode 100644
index 00000000000..97d7339827e
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/PostUncontrolDecoratorModelUpdater.java
@@ -0,0 +1,115 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.updaters;
+
+import java.util.Map;
+
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.PackageRefactoringContext;
+import org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.messages.Messages;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.ProfileApplication;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+
+/**
+ * A post-uncontrol updater of the profile applications that are stored in a decorator model.
+ */
+public class PostUncontrolDecoratorModelUpdater extends AbstractDecoratorModelUpdater {
+
+ // Mapping of profile URI to applied definition EPackage URI
+ private final Map<URI, URI> profilesToRemove;
+ private Map<URI, URI> profilesRemoved;
+
+ public PostUncontrolDecoratorModelUpdater(IDecoratorModelUpdaterDelegate delegate, PackageRefactoringContext context, URI decoratorModelURI) {
+ super(delegate);
+
+ // Compute the profile applications that we no longer need because they are the same definition that is
+ // inherited from the parent package
+ ImmutableMap.Builder<URI, URI> extraneousProfiles = ImmutableMap.builder();
+ Map<URI, URI> inherited = context.getInheritedExternalProfileApplicationsFor(decoratorModelURI);
+ for (Map.Entry<URI, URI> all : context.getAllExternalProfileApplicationsFor(decoratorModelURI).entrySet()) {
+ if (all.getValue().equals(inherited.get(all.getKey()))) {
+ extraneousProfiles.put(all.getKey(), all.getValue());
+ }
+ }
+ this.profilesToRemove = extraneousProfiles.build();
+ }
+
+ @Override
+ public boolean refactor(Resource resource, IProgressMonitor monitor) throws ExecutionException {
+ boolean result = false;
+
+ monitor.beginTask(NLS.bind(Messages.PostUncontrolDecoratorModelUpdater_0, resource.getURI().lastSegment()), IProgressMonitor.UNKNOWN);
+ if (!profilesToRemove.isEmpty()) {
+ Package evilTwin = getDecoratorPackage(resource);
+ if (evilTwin != null) {
+ for (Map.Entry<URI, URI> next : profilesToRemove.entrySet()) {
+ ProfileApplication application = getProfileApplication(evilTwin, next.getKey());
+ EPackage definition = (application == null) ? null : application.getAppliedDefinition();
+ if ((definition != null) && next.getValue().equals(EcoreUtil.getURI(definition))) {
+ application.destroy();
+ result = true;
+
+ if (profilesRemoved == null) {
+ profilesRemoved = Maps.newHashMap();
+ }
+ profilesRemoved.put(next.getKey(), next.getValue());
+ }
+ }
+
+ if (evilTwin.getProfileApplications().isEmpty()) {
+ // Remove it, too
+ evilTwin.destroy();
+ result = true;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public boolean unrefactor(Resource resource, IProgressMonitor monitor) throws ExecutionException {
+ boolean result = false;
+
+ monitor.beginTask(NLS.bind(Messages.PostUncontrolDecoratorModelUpdater_1, resource.getURI().lastSegment()), IProgressMonitor.UNKNOWN);
+ if (profilesRemoved != null) {
+ Package evilTwin = getDecoratorPackage(resource);
+ if (evilTwin == null) {
+ evilTwin = createDecoratorPackage(resource);
+ result = true;
+ }
+
+ for (Map.Entry<URI, URI> next : profilesRemoved.entrySet()) {
+ if (!hasProfileApplication(evilTwin, next.getKey())) {
+ addProfileApplication(evilTwin, next.getKey(), next.getValue());
+ result = true;
+ }
+ }
+
+ profilesRemoved = null;
+ }
+
+ return result;
+ }
+
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/UnloadedDecoratorModelUpdaterDelegate.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/UnloadedDecoratorModelUpdaterDelegate.java
new file mode 100644
index 00000000000..9a69d2c7312
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.controlmode/src/org/eclipse/papyrus/uml/decoratormodel/internal/controlmode/updaters/UnloadedDecoratorModelUpdaterDelegate.java
@@ -0,0 +1,52 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.controlmode.updaters;
+
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EcoreFactory;
+import org.eclipse.emf.ecore.InternalEObject;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.Profile;
+import org.eclipse.uml2.uml.ProfileApplication;
+import org.eclipse.uml2.uml.UMLFactory;
+import org.eclipse.uml2.uml.util.UMLUtil;
+
+/**
+ * @author damus
+ *
+ */
+public class UnloadedDecoratorModelUpdaterDelegate extends AbstractDecoratorModelUpdaterDelegate {
+
+ public UnloadedDecoratorModelUpdaterDelegate(Package package_) {
+ super(package_);
+ }
+
+ @Override
+ public ProfileApplication addProfileApplication(Package package_, URI profileURI, URI appliedDefinitionURI) {
+ // Create a proxy for the profile
+ Profile profile = UMLFactory.eINSTANCE.createProfile();
+ ((InternalEObject) profile).eSetProxyURI(profileURI);
+ ProfileApplication result = package_.createProfileApplication();
+ result.setAppliedProfile(profile);
+
+ // and a proxy for the Ecore definition
+ EPackage definition = EcoreFactory.eINSTANCE.createEPackage();
+ ((InternalEObject) definition).eSetProxyURI(appliedDefinitionURI);
+ result.createEAnnotation(UMLUtil.UML2_UML_PACKAGE_2_0_NS_URI).getReferences().add(definition);
+
+ return result;
+ }
+
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/.classpath b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/.classpath
new file mode 100644
index 00000000000..64c5e31b7a2
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/.project b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/.project
new file mode 100644
index 00000000000..ff3c7c0fd61
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.papyrus.uml.decoratormodel.properties</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/.settings/org.eclipse.jdt.core.prefs b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000000..c585cc455ae
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,291 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.5
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
+org.eclipse.jdt.core.formatter.comment.line_length=260
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=false
+org.eclipse.jdt.core.formatter.join_wrapped_lines=false
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=260
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=5
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/.settings/org.eclipse.jdt.ui.prefs b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 00000000000..954281dbc31
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,68 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=false
+cleanup.always_use_this_for_non_static_field_access=false
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=false
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=false
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=true
+cleanup.organize_imports=false
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=true
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=false
+cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+cleanup.use_this_for_non_static_method_access=false
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_Papyrus
+cleanup_settings_version=2
+eclipse.preferences.version=1
+formatter_profile=_Papyrus
+formatter_settings_version=12
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=java;javax;org;com;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="false" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * Constructor.\n *\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*****************************************************************************\n * Copyright (c) ${year} CEA LIST and others.\n * \n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * which accompanies this distribution, and is available at\n * http\://www.eclipse.org/legal/epl-v10.html\n *\n * Contributors\:\n * CEA LIST - Initial API and implementation\n * \n *****************************************************************************/\n</template><template autoinsert\="true" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * @author ${user}\n *\n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment">/**\n * ${see_to_overridden}\n *\n * ${tags}\n */</template><template autoinsert\="false" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${see_to_target}\n *\n * ${tags}\n */</template><template autoinsert\="true" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/META-INF/MANIFEST.MF b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/META-INF/MANIFEST.MF
new file mode 100644
index 00000000000..c5182577e79
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/META-INF/MANIFEST.MF
@@ -0,0 +1,35 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %Bundle-Name
+Bundle-SymbolicName: org.eclipse.papyrus.uml.decoratormodel.properties;singleton:=true
+Bundle-Version: 1.1.0.qualifier
+Bundle-Activator: org.eclipse.papyrus.uml.decoratormodel.properties.Activator
+Bundle-Vendor: %Bundle-Vendor
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.eclipse.papyrus.views.properties;bundle-version="1.1.0",
+ org.eclipse.uml2.uml;bundle-version="4.1.0",
+ org.eclipse.papyrus.uml.tools.utils;bundle-version="1.1.0",
+ org.eclipse.papyrus.infra.widgets;bundle-version="1.1.0",
+ org.eclipse.papyrus.uml.properties;bundle-version="1.1.0",
+ org.eclipse.core.databinding.observable;bundle-version="1.4.1",
+ org.eclipse.core.databinding;bundle-version="1.4.1",
+ com.google.guava;bundle-version="11.0.0",
+ org.eclipse.papyrus.views.properties.model;bundle-version="1.1.0",
+ org.eclipse.papyrus.infra.emf;bundle-version="1.1.0",
+ org.eclipse.papyrus.infra.tools;bundle-version="1.1.0",
+ org.eclipse.emf.edit;bundle-version="2.10.0",
+ org.eclipse.emf.transaction;bundle-version="1.8.0",
+ org.eclipse.papyrus.uml.tools;bundle-version="1.1.0",
+ org.eclipse.emf.databinding;bundle-version="1.3.0",
+ org.eclipse.papyrus.infra.core;bundle-version="1.1.0",
+ org.eclipse.papyrus.infra.core.log;bundle-version="1.1.0",
+ org.eclipse.papyrus.uml.decoratormodel;bundle-version="1.1.0",
+ org.eclipse.papyrus.uml.decoratormodel.ui;bundle-version="1.1.0",
+ org.eclipse.papyrus.infra.constraints;bundle-version="1.1.0"
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Bundle-ActivationPolicy: lazy
+Export-Package: org.eclipse.papyrus.uml.decoratormodel.internal.properties.constraints;x-internal:=true,
+ org.eclipse.papyrus.uml.decoratormodel.properties,
+ org.eclipse.papyrus.uml.decoratormodel.properties.elements,
+ org.eclipse.papyrus.uml.decoratormodel.properties.widgets
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/OSGI-INF/l10n/bundle.properties b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/OSGI-INF/l10n/bundle.properties
new file mode 100644
index 00000000000..645c6c42673
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/OSGI-INF/l10n/bundle.properties
@@ -0,0 +1,3 @@
+#Properties file for org.eclipse.papyrus.uml.decoratormodel.properties
+Bundle-Vendor = Eclipse Modeling Project
+Bundle-Name = Papyrus Decorator Model Property Sheets \ No newline at end of file
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/about.html b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/about.html
new file mode 100644
index 00000000000..d35d5aed64c
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>June 5, 2007</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
+
+</body>
+</html>
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/build.properties b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/build.properties
new file mode 100644
index 00000000000..b95c74127cb
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/build.properties
@@ -0,0 +1,11 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml,\
+ resources/,\
+ OSGI-INF/,\
+ icons/,\
+ about.html,\
+ documentation.pdoc
+src.includes = about.html
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/documentation.pdoc b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/documentation.pdoc
new file mode 100644
index 00000000000..53d668be2bb
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/documentation.pdoc
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<doc:Documentation xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:doc="http://www.eclipse.org/papyrus/documentation/plugin/documentation" description="Property sheet customizations for management of separate profile applications.">
+ <referent firstName="Christian" lastName="Damus" eMail="give.a.damus@gmail.com" currentCompany="independent"/>
+</doc:Documentation>
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/icons/full/ctool16/dup_resource.png b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/icons/full/ctool16/dup_resource.png
new file mode 100644
index 00000000000..41efe451edb
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/icons/full/ctool16/dup_resource.png
Binary files differ
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/icons/full/ctool16/externalize.gif b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/icons/full/ctool16/externalize.gif
new file mode 100644
index 00000000000..5a0837d1e47
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/icons/full/ctool16/externalize.gif
Binary files differ
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/icons/full/ctool16/internalize.gif b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/icons/full/ctool16/internalize.gif
new file mode 100644
index 00000000000..d38085ad9c2
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/icons/full/ctool16/internalize.gif
Binary files differ
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/icons/full/ctool16/unload_resource.png b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/icons/full/ctool16/unload_resource.png
new file mode 100644
index 00000000000..9f025e2a8b3
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/icons/full/ctool16/unload_resource.png
Binary files differ
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/icons/full/dtool16/load_resource.png b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/icons/full/dtool16/load_resource.png
new file mode 100644
index 00000000000..905ebeee0a7
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/icons/full/dtool16/load_resource.png
Binary files differ
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/icons/full/etool16/load_resource.png b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/icons/full/etool16/load_resource.png
new file mode 100644
index 00000000000..4fd6673d06d
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/icons/full/etool16/load_resource.png
Binary files differ
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/plugin.xml b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/plugin.xml
new file mode 100644
index 00000000000..c95214422da
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/plugin.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+<extension point="org.eclipse.papyrus.views.properties.environment">
+ <environment environmentModel="resources/UMLStereotypeApplicationExternalResourceEnvironment.xmi">
+ </environment>
+ </extension>
+ <extension point="org.eclipse.papyrus.views.properties.context">
+ <context contextModel="resources/UMLStereotypeApplicationExternalResource.ctx">
+ </context>
+ </extension>
+</plugin>
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/pom.xml b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/pom.xml
new file mode 100644
index 00000000000..855d83f8bff
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/pom.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project>
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>org.eclipse.papyrus</artifactId>
+ <groupId>org.eclipse.papyrus</groupId>
+ <version>1.1.0-SNAPSHOT</version>
+ <relativePath>../../../../releng/top-pom-main.xml</relativePath>
+ </parent>
+ <artifactId>org.eclipse.papyrus.uml.decoratormodel.properties</artifactId>
+ <groupId>org.eclipse.papyrus</groupId>
+ <version>1.1.0-SNAPSHOT</version>
+ <packaging>eclipse-plugin</packaging>
+</project> \ No newline at end of file
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/resources/UMLStereotypeApplicationExternalResource.ctx b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/resources/UMLStereotypeApplicationExternalResource.ctx
new file mode 100644
index 00000000000..bf1638b2dae
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/resources/UMLStereotypeApplicationExternalResource.ctx
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<contexts:Context xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:constraints="http://www.eclipse.org/papyrus/constraints/0.9" xmlns:contexts="http://www.eclipse.org/papyrus/properties/contexts/0.9" name="UMLStereotypeApplicationExternalResource">
+ <dependencies href="ppe:/context/org.eclipse.papyrus.uml.properties/Model/UML/UML.ctx#/"/>
+ <tabs label="Profile" id="profile" category="org.eclipse.papyrus" priority="50">
+ <sections name="SinglePackageProfile" sectionFile="ui/SinglePackageProfile.xwt">
+ <widget href="ui/SinglePackageProfile.xwt#/"/>
+ </sections>
+ </tabs>
+ <tabs label="Applications" id="applications" category="org.eclipse.papyrus" priority="50">
+ <afterTab href="ppe:/context/org.eclipse.papyrus.uml.properties/Model/UML/UML.ctx#//@tabs.1"/>
+ <sections name="SinglePackageDecoratorModels" sectionFile="ui/SinglePackageDecoratorModels.xwt">
+ <widget href="ui/SinglePackageDecoratorModels.xwt#/"/>
+ </sections>
+ </tabs>
+ <views name="SinglePackageProfile" sections="//@tabs.0/@sections.0" automaticContext="true">
+ <constraints xsi:type="constraints:SimpleConstraint" name="isSinglePackage" overrideable="false">
+ <constraintType href="ppe:/environment/org.eclipse.papyrus.uml.properties/Model/Environment.xmi#//@constraintTypes.0"/>
+ <properties xsi:type="constraints:ValueProperty" name="umlClassName" value="Package"/>
+ </constraints>
+ </views>
+ <views name="SinglePackageDecoratorModels" sections="//@tabs.1/@sections.0">
+ <constraints xsi:type="constraints:SimpleConstraint" name="hasExternalizedProfileApplications">
+ <constraintType href="ppe:/environment/org.eclipse.papyrus.uml.decoratormodel.properties/resources/UMLStereotypeApplicationExternalResourceEnvironment.xmi#//@constraintTypes.0"/>
+ </constraints>
+ </views>
+ <dataContexts name="PackageAdditions" label="Package Additions">
+ <elements name="Package">
+ <properties name="profileApplication" label="Profile Applications" type="Reference" description="References the ProfileApplications that indicate which profiles have been applied to the Package."/>
+ <properties name="externalProfileApplication" label="External Profile Applications" type="Reference" description="The models in the workspace that apply profiles to the package, loaded and unloaded."/>
+ </elements>
+ <modelElementFactory href="UMLStereotypeApplicationExternalResourceEnvironment.xmi#//@modelElementFactories.0"/>
+ </dataContexts>
+</contexts:Context>
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/resources/UMLStereotypeApplicationExternalResourceEnvironment.xmi b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/resources/UMLStereotypeApplicationExternalResourceEnvironment.xmi
new file mode 100644
index 00000000000..21eee0ec154
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/resources/UMLStereotypeApplicationExternalResourceEnvironment.xmi
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="ASCII"?>
+<environment:Environment
+ xmi:version="2.0"
+ xmlns:xmi="http://www.omg.org/XMI"
+ xmlns:environment="http://www.eclipse.org/papyrus/properties/environment/0.9">
+ <constraintTypes
+ label="Has Externalized Profile Applications"
+ constraintClass="org.eclipse.papyrus.uml.decoratormodel.internal.properties.constraints.HasExternalizedProfileApplicationsConstraint"/>
+ <modelElementFactories
+ name="Package Factory"
+ factoryClass="org.eclipse.papyrus.uml.decoratormodel.properties.elements.PackageModelElementFactory"/>
+ <propertyEditorTypes
+ label="External Resource Profile Application Editor"
+ widgetClass="ProfileApplicationPropertyEditor"
+ namespace="//@namespaces.0"
+ type="Reference"
+ multiplicity="-1"/>
+ <propertyEditorTypes
+ label="Decorator Model Editor"
+ widgetClass="DecoratorModelPropertyEditor"
+ namespace="//@namespaces.0"
+ type="Reference"
+ multiplicity="-1"/>
+ <namespaces
+ name="umlprofileexternalresource"
+ value="org.eclipse.papyrus.uml.decoratormodel.properties.widgets"/>
+</environment:Environment>
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/resources/ui/SinglePackageDecoratorModels.xwt b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/resources/ui/SinglePackageDecoratorModels.xwt
new file mode 100644
index 00000000000..3f0cc7bfcf3
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/resources/ui/SinglePackageDecoratorModels.xwt
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Composite xmlns="http://www.eclipse.org/xwt/presentation"
+ xmlns:ppel="clr-namespace:org.eclipse.papyrus.views.properties.widgets.layout"
+ xmlns:x="http://www.eclipse.org/xwt" xmlns:ppe="clr-namespace:org.eclipse.papyrus.views.properties.widgets"
+ xmlns:umlprofileexternalresource="clr-namespace:org.eclipse.papyrus.uml.decoratormodel.properties.widgets"
+ xmlns:uml="clr-namespace:org.eclipse.papyrus.uml.properties.widgets">
+ <Composite.layout>
+ <ppel:PropertiesLayout></ppel:PropertiesLayout>
+ </Composite.layout>
+ <umlprofileexternalresource:DecoratorModelPropertyEditor
+ input="{Binding}" property="PackageAdditions:externalProfileApplication"></umlprofileexternalresource:DecoratorModelPropertyEditor>
+</Composite> \ No newline at end of file
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/resources/ui/SinglePackageProfile.xwt b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/resources/ui/SinglePackageProfile.xwt
new file mode 100644
index 00000000000..eb262a0531b
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/resources/ui/SinglePackageProfile.xwt
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Composite xmlns="http://www.eclipse.org/xwt/presentation"
+ xmlns:ppel="clr-namespace:org.eclipse.papyrus.views.properties.widgets.layout"
+ xmlns:x="http://www.eclipse.org/xwt" xmlns:ppe="clr-namespace:org.eclipse.papyrus.views.properties.widgets"
+ xmlns:umlprofileexternalresource="clr-namespace:org.eclipse.papyrus.uml.decoratormodel.properties.widgets"
+ xmlns:uml="clr-namespace:org.eclipse.papyrus.uml.properties.widgets">
+ <Composite.layout>
+ <ppel:PropertiesLayout></ppel:PropertiesLayout>
+ </Composite.layout>
+ <umlprofileexternalresource:ProfileApplicationPropertyEditor
+ input="{Binding}" property="PackageAdditions:profileApplication"></umlprofileexternalresource:ProfileApplicationPropertyEditor>
+</Composite> \ No newline at end of file
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/internal/properties/constraints/HasExternalizedProfileApplicationsConstraint.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/internal/properties/constraints/HasExternalizedProfileApplicationsConstraint.java
new file mode 100644
index 00000000000..3f2e801dc0e
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/internal/properties/constraints/HasExternalizedProfileApplicationsConstraint.java
@@ -0,0 +1,83 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.properties.constraints;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.papyrus.infra.constraints.constraints.AbstractConstraint;
+import org.eclipse.papyrus.infra.constraints.constraints.Constraint;
+import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
+import org.eclipse.papyrus.uml.decoratormodel.helper.DecoratorModelUtils;
+import org.eclipse.papyrus.uml.decoratormodel.internal.resource.DecoratorModelIndex;
+import org.eclipse.papyrus.uml.decoratormodel.properties.Activator;
+import org.eclipse.uml2.uml.Package;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.SetMultimap;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * A properties constraint matching packages that have loaded or unloaded decorator models.
+ */
+public class HasExternalizedProfileApplicationsConstraint extends AbstractConstraint {
+
+ /**
+ * Initializes me.
+ */
+ public HasExternalizedProfileApplicationsConstraint() {
+ super();
+ }
+
+ @Override
+ protected boolean match(Object selection) {
+ boolean result = false;
+
+ EObject object = EMFHelper.getEObject(selection);
+
+ if (object instanceof Package) {
+ Package package_ = (Package) object;
+
+ try {
+ result = !Iterables.isEmpty(DecoratorModelUtils.getDecoratorModelProfileApplications(package_));
+ if (!result) {
+ ListenableFuture<SetMultimap<URI, URI>> appliedProfiles = DecoratorModelIndex.getInstance().getAllAppliedProfilesAsync(EcoreUtil.getURI(package_));
+
+ // Optimistic enablement for responsiveness
+ result = !appliedProfiles.isDone() || !Futures.get(appliedProfiles, CoreException.class).isEmpty();
+ }
+ } catch (CoreException e) {
+ // Oh, well. I guess we won't show this property
+ Activator.getDefault().getLog().log(e.getStatus());
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ protected boolean equivalent(Constraint constraint) {
+ if (this == constraint) {
+ return true;
+ }
+ return constraint instanceof HasExternalizedProfileApplicationsConstraint;
+ }
+
+ @Override
+ public String toString() {
+ return "HasExternalizedProfileApplicationsConstraint"; //$NON-NLS-1$
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/internal/properties/messages/Messages.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/internal/properties/messages/Messages.java
new file mode 100644
index 00000000000..e339c7a5c7e
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/internal/properties/messages/Messages.java
@@ -0,0 +1,43 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.properties.messages;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * @author damus
+ *
+ */
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.papyrus.uml.decoratormodel.internal.properties.messages.messages"; //$NON-NLS-1$
+ public static String DecoratorModelPropertyEditor_0;
+ public static String DecoratorModelPropertyEditor_1;
+ public static String DecoratorModelPropertyEditor_2;
+ public static String DecoratorModelPropertyEditor_3;
+ public static String DecoratorModelPropertyEditor_4;
+ public static String DecoratorModelPropertyEditor_5;
+ public static String DecoratorModelPropertyEditor_6;
+ public static String DecoratorModelPropertyEditor_7;
+ public static String DecoratorModelPropertyEditor_8;
+ public static String ProfileApplicationPropertyEditor_0;
+ public static String ProfileApplicationPropertyEditor_1;
+ public static String ProfileApplicationPropertyEditor_2;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/internal/properties/messages/messages.properties b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/internal/properties/messages/messages.properties
new file mode 100644
index 00000000000..14cafbe6fa0
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/internal/properties/messages/messages.properties
@@ -0,0 +1,12 @@
+DecoratorModelPropertyEditor_0=External Profile Applications:
+DecoratorModelPropertyEditor_1=State
+DecoratorModelPropertyEditor_2=Profile Application
+DecoratorModelPropertyEditor_3=Load the selected profile application(s)
+DecoratorModelPropertyEditor_4=Unload the selected profile application(s)
+DecoratorModelPropertyEditor_5=Duplicate the selected profile application
+DecoratorModelPropertyEditor_6=Failed to unload profile application(s).
+DecoratorModelPropertyEditor_7=Loaded
+DecoratorModelPropertyEditor_8=Unloaded
+ProfileApplicationPropertyEditor_0=Externalize profile application
+ProfileApplicationPropertyEditor_1=Internalize profile application
+ProfileApplicationPropertyEditor_2=({0})
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/properties/Activator.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/properties/Activator.java
new file mode 100644
index 00000000000..87a3875b8f7
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/properties/Activator.java
@@ -0,0 +1,111 @@
+/*****************************************************************************
+ * Copyright (c) 2011, 2014 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:
+ * Remi Schnekenburger (CEA LIST) remi.schnekenburger@cea.fr - Initial API and implementation
+ * Christian W. Damus - bug 399859
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.uml.decoratormodel.properties;
+
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * 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.uml.decoratormodel.properties"; //$NON-NLS-1$
+
+ // The shared instance
+ private static Activator plugin;
+
+ /**
+ * The constructor
+ */
+ public Activator() {
+ }
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ plugin = this;
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ plugin = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static Activator getDefault() {
+ return plugin;
+ }
+
+ /**
+ * Returns the image at the given path from this plugin
+ *
+ * @param path
+ * the path of the image to be displayed
+ * @return The Image at the given location, or null if it couldn't be found
+ */
+ public Image getImage(String path) {
+ return getImage(PLUGIN_ID, path);
+ }
+
+ /**
+ * Returns the image from the given image descriptor
+ *
+ * @param pluginId
+ * The plugin in which the image is located
+ * @param path
+ * The path to the image from the plugin
+ * @return
+ * The Image at the given location, or null if it couldn't be found
+ */
+ public Image getImage(String pluginId, String path) {
+ final ImageRegistry registry = getImageRegistry();
+ String key = pluginId + "/" + path; //$NON-NLS-1$
+ Image image = registry.get(key);
+ if (image == null) {
+ registry.put(key, AbstractUIPlugin.imageDescriptorFromPlugin(pluginId, path));
+ image = registry.get(key);
+ }
+ return image;
+ }
+
+ public static IWorkbenchWindow getActiveWorkbenchWindow() {
+ IWorkbenchWindow result = null;
+
+ IWorkbench bench = PlatformUI.getWorkbench();
+ if (bench != null) {
+ result = bench.getActiveWorkbenchWindow();
+ if (result == null) {
+ IWorkbenchWindow[] allWindows = bench.getWorkbenchWindows();
+ if (allWindows.length > 0) {
+ result = allWindows[0];
+ }
+ }
+ }
+
+ return result;
+ }
+
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/properties/elements/AppliedProfilesObservableList.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/properties/elements/AppliedProfilesObservableList.java
new file mode 100644
index 00000000000..8571d789f61
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/properties/elements/AppliedProfilesObservableList.java
@@ -0,0 +1,65 @@
+/*****************************************************************************
+ * Copyright (c) 2012, 2014 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:
+ * Sebastien Poissonnet (CEA LIST) sebastien.poissonnet@cea.fr
+ * Mickaël ADAM (ALL4TEC) mickael.adam@all4tec.net - bug 435174
+ * Gabriel Pascual (ALL4TEC) - Bug 441511
+ * Christian W. Damus (CEA) - Bug 441227
+ * Christian W. Damus - bug 399859
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.uml.decoratormodel.properties.elements;
+
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.papyrus.infra.core.resource.ResourceAdapter;
+import org.eclipse.papyrus.uml.tools.databinding.ProfileApplicationObservableList;
+import org.eclipse.uml2.uml.Package;
+
+/**
+ * Observable list for applied profiles.
+ */
+public class AppliedProfilesObservableList extends ProfileApplicationObservableList {
+
+ private ResourceAdapter adapter;
+
+ public AppliedProfilesObservableList(Package source, EditingDomain domain) {
+ super(source, domain);
+
+ adapter = createResourceAdapter();
+ domain.getResourceSet().eAdapters().add(adapter);
+ }
+
+ @Override
+ public synchronized void dispose() {
+ if (adapter.getTarget() != null) {
+ adapter.getTarget().eAdapters().remove(adapter);
+ }
+
+ super.dispose();
+ }
+
+ protected final Package getPackage() {
+ return (Package) getObserved();
+ }
+
+ private ResourceAdapter createResourceAdapter() {
+ return new ResourceAdapter() {
+ @Override
+ protected void handleResourceLoaded(Resource resource) {
+ refreshCacheList();
+ }
+
+ @Override
+ protected void handleResourceUnloaded(Resource resource) {
+ refreshCacheList();
+ }
+ };
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/properties/elements/DecoratorModelsObservableList.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/properties/elements/DecoratorModelsObservableList.java
new file mode 100644
index 00000000000..1da88fbfe40
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/properties/elements/DecoratorModelsObservableList.java
@@ -0,0 +1,243 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.properties.elements;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.eclipse.core.databinding.observable.IObserving;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.list.ObservableList;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.common.command.CompoundCommand;
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.transaction.NotificationFilter;
+import org.eclipse.emf.transaction.ResourceSetListener;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.papyrus.infra.core.resource.ResourceAdapter;
+import org.eclipse.papyrus.infra.tools.util.UIUtil;
+import org.eclipse.papyrus.infra.widgets.editors.AbstractEditor;
+import org.eclipse.papyrus.infra.widgets.editors.ICommitListener;
+import org.eclipse.papyrus.uml.decoratormodel.helper.DecoratorModelUtils;
+import org.eclipse.papyrus.uml.decoratormodel.internal.resource.DecoratorModelIndex;
+import org.eclipse.papyrus.uml.decoratormodel.internal.resource.DecoratorModelIndexEvent;
+import org.eclipse.papyrus.uml.decoratormodel.internal.resource.IDecoratorModelIndexListener;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.ProfileApplication;
+import org.eclipse.uml2.uml.UMLPackage;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * The list of a {@link Package}'s decorator models, both loaded and unloaded.
+ */
+public class DecoratorModelsObservableList extends ObservableList implements ICommitListener, IObserving {
+
+ private final AtomicBoolean pendingCalculation = new AtomicBoolean();
+
+ private Package package_;
+
+ private TransactionalEditingDomain domain;
+
+ private final List<Command> commands;
+
+ private final ExecutorService realmExecutor;
+
+ private final ResourceSetListener resourceSetListener;
+
+ private final IDecoratorModelIndexListener indexListener;
+
+ /**
+ * Initializes me in the default realm.
+ *
+ * @param package_
+ * the package for which we track the decorator models
+ * @param domain
+ * the editing domain context in which to execute commands
+ */
+ public DecoratorModelsObservableList(Package package_, TransactionalEditingDomain domain) {
+ this(Realm.getDefault(), package_, domain);
+ }
+
+ /**
+ * Initializes me.
+ *
+ * @param realm
+ * the observable realm that owns me
+ * @param package_
+ * the package for which we track the decorator models
+ * @param domain
+ * the editing domain context in which to execute commands
+ */
+ public DecoratorModelsObservableList(Realm realm, Package package_, TransactionalEditingDomain domain) {
+ super(realm, Lists.newArrayList(), Object.class);
+
+ this.package_ = package_;
+ this.domain = domain;
+
+ this.commands = Lists.newArrayListWithExpectedSize(1);
+
+ this.realmExecutor = UIUtil.createObservableExecutor(realm);
+
+ this.resourceSetListener = new ResourceAdapter.Transactional() {
+ private NotificationFilter packageFilter;
+
+ @Override
+ protected NotificationFilter createFilter() {
+ packageFilter = NotificationFilter.createFeatureFilter(UMLPackage.Literals.PACKAGE__PROFILE_APPLICATION);
+ return super.createFilter().or(packageFilter);
+ }
+
+ @Override
+ public void notifyChanged(Notification msg) {
+ if (packageFilter.matches(msg)) {
+ // Some externalized profiles may no longer be available
+ calculate();
+ } else {
+ // Resource case
+ super.notifyChanged(msg);
+ }
+ }
+
+ @Override
+ protected void handleResourceLoaded(Resource resource) {
+ calculate();
+ }
+
+ @Override
+ protected void handleResourceUnloaded(Resource resource) {
+ calculate();
+ }
+ };
+ domain.addResourceSetListener(resourceSetListener);
+
+ this.indexListener = new IDecoratorModelIndexListener() {
+
+ public void indexChanged(DecoratorModelIndexEvent event) {
+ // Some unloaded decorator models may have changed
+ calculate();
+ }
+ };
+ DecoratorModelIndex.getInstance().addIndexListener(indexListener);
+
+ calculate();
+ }
+
+ public Package getObserved() {
+ return package_;
+ }
+
+ @Override
+ public synchronized void dispose() {
+ try {
+ DecoratorModelIndex.getInstance().removeIndexListener(indexListener);
+ if (domain != null) {
+ domain.removeResourceSetListener(resourceSetListener);
+ }
+ if (!realmExecutor.isShutdown()) {
+ realmExecutor.shutdownNow();
+ }
+ } finally {
+ super.dispose();
+ }
+ }
+
+ public void commit(AbstractEditor editor) {
+ if (!commands.isEmpty()) {
+ if (commands.size() == 1) {
+ domain.getCommandStack().execute(commands.get(0));
+ } else {
+ domain.getCommandStack().execute(new CompoundCommand(commands));
+ }
+ commands.clear();
+ }
+ }
+
+ void calculate() {
+ if (!pendingCalculation.compareAndSet(false, true) || isDisposed()) {
+ return;
+ }
+
+ // First, mark me stale
+ getRealm().exec(new Runnable() {
+
+ public void run() {
+ setStale(true);
+ }
+ });
+
+ // Then asynchronously compute my value
+ ListenableFuture<Set<URI>> decoratorModelURIs = DecoratorModelUtils.getUnloadedDecoratorModelsAsync(package_);
+ Futures.addCallback(decoratorModelURIs, new FutureCallback<Set<URI>>() {
+ public void onSuccess(Set<URI> result) {
+ if (isDisposed() || (domain == null) || (domain.getResourceSet() == null)) {
+ return;
+ }
+
+ try {
+ // compute all the unloaded models
+ Set<Object> newValue = Sets.<Object> newHashSet(result);
+ for (Resource next : domain.getResourceSet().getResources()) {
+ if (next.isLoaded()) {
+ newValue.remove(next.getURI());
+ }
+ }
+
+ // now get the loaded ones
+ for (ProfileApplication next : DecoratorModelUtils.getDecoratorModelProfileApplications(package_)) {
+ newValue.add(next.eResource());
+ }
+
+ List<Object> newList = Lists.newArrayList(newValue);
+ // because the ordering of all these sets is random, we must sort so that the list doesn't
+ // change its ordering randomly each time
+ sort(newList);
+
+ setStale(false);
+ updateWrappedList(newList);
+ } finally {
+ pendingCalculation.set(false);
+ }
+ }
+
+ public void onFailure(Throwable t) {
+ // TODO Auto-generated method stub
+ }
+ }, realmExecutor);
+ }
+
+ void sort(List<?> list) {
+ Collections.sort(list, new Comparator<Object>() {
+ public int compare(Object o1, Object o2) {
+ URI uri1 = getURI(o1);
+ URI uri2 = getURI(o2);
+ return uri1.toString().compareTo(uri2.toString());
+ }
+
+ URI getURI(Object o) {
+ return (o instanceof Resource) ? ((Resource) o).getURI() : (URI) o;
+ }
+ });
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/properties/elements/PackageModelElement.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/properties/elements/PackageModelElement.java
new file mode 100644
index 00000000000..24840e11e5a
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/properties/elements/PackageModelElement.java
@@ -0,0 +1,46 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.properties.elements;
+
+import org.eclipse.core.databinding.observable.IObservable;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.papyrus.uml.properties.modelelement.UMLModelElement;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.UMLPackage;
+
+/**
+ * Properties model element for packages.
+ */
+public class PackageModelElement extends UMLModelElement {
+ static final String DECORATOR_MODEL_PROPERTY = "externalProfileApplication"; //$NON-NLS-1$
+
+ public PackageModelElement(Package source, TransactionalEditingDomain domain) {
+ super(source, domain);
+ }
+
+ protected final Package getPackage() {
+ return (Package) getSource();
+ }
+
+ @Override
+ public IObservable doGetObservable(String propertyPath) {
+ if (propertyPath.equals(UMLPackage.Literals.PACKAGE__PROFILE_APPLICATION.getName())) {
+ return new AppliedProfilesObservableList(getPackage(), domain);
+ } else if (propertyPath.equals(DECORATOR_MODEL_PROPERTY)) {
+ return new DecoratorModelsObservableList(getPackage(), (TransactionalEditingDomain) domain);
+ }
+
+ return super.doGetObservable(propertyPath);
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/properties/elements/PackageModelElementFactory.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/properties/elements/PackageModelElementFactory.java
new file mode 100644
index 00000000000..08c7845d095
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/properties/elements/PackageModelElementFactory.java
@@ -0,0 +1,48 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.properties.elements;
+
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.emf.transaction.util.TransactionUtil;
+import org.eclipse.papyrus.uml.properties.modelelement.UMLModelElement;
+import org.eclipse.papyrus.uml.properties.modelelement.UMLModelElementFactory;
+import org.eclipse.papyrus.uml.tools.utils.UMLUtil;
+import org.eclipse.papyrus.views.properties.contexts.DataContextElement;
+import org.eclipse.uml2.uml.Element;
+import org.eclipse.uml2.uml.Package;
+
+/**
+ * Properties model element factory for profile applications.
+ */
+public class PackageModelElementFactory extends UMLModelElementFactory {
+
+ public PackageModelElementFactory() {
+ super();
+ }
+
+ @Override
+ protected UMLModelElement doCreateFromSource(Object source, DataContextElement context) {
+ Element umlSource = UMLUtil.resolveUMLElement(source);
+ if (umlSource instanceof Package) {
+ return createPackageElement((Package) umlSource, context);
+ }
+
+ return super.doCreateFromSource(source, context);
+ }
+
+ protected UMLModelElement createPackageElement(Package package_, DataContextElement context) {
+ TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(package_);
+ return new PackageModelElement(package_, domain);
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/properties/widgets/DecoratorModelPropertyEditor.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/properties/widgets/DecoratorModelPropertyEditor.java
new file mode 100644
index 00000000000..6d1009ff872
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/properties/widgets/DecoratorModelPropertyEditor.java
@@ -0,0 +1,340 @@
+/*****************************************************************************
+ * Copyright (c) 2011, 2014 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 399859
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.properties.widgets;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.databinding.observable.ChangeEvent;
+import org.eclipse.core.databinding.observable.IChangeListener;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.CellLabelProvider;
+import org.eclipse.jface.viewers.ColumnWeightData;
+import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableLayout;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.ViewerCell;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
+import org.eclipse.papyrus.infra.widgets.editors.AbstractListEditor;
+import org.eclipse.papyrus.uml.decoratormodel.internal.properties.messages.Messages;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.commands.UnloadDecoratorModelHandler;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.providers.DecoratorModelLabelProvider;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.wizards.DuplicateDecoratorModelWizard;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.wizards.LoadProfileApplicationsWizard;
+import org.eclipse.papyrus.uml.decoratormodel.properties.Activator;
+import org.eclipse.papyrus.views.properties.widgets.AbstractPropertyEditor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.statushandlers.StatusManager;
+import org.eclipse.uml2.uml.Package;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+/**
+ * Property sheet editor for the "decorator models" property of a package.
+ */
+public class DecoratorModelPropertyEditor extends AbstractPropertyEditor {
+
+ public DecoratorModelPropertyEditor(Composite parent, int style) {
+ super(new DecoratorModelEditor(parent, style));
+ }
+
+ //
+ // Nested types
+ //
+
+ static class DecoratorModelEditor extends AbstractListEditor implements IChangeListener {
+
+ private TableViewer table;
+
+ private Button loadButton;
+
+ private Button unloadButton;
+
+ private Button duplicateButton;
+
+ private boolean preservingSelection;
+
+ protected DecoratorModelEditor(Composite parent, int style) {
+ super(parent, style, Messages.DecoratorModelPropertyEditor_0);
+ setLayout(new GridLayout(2, false));
+
+ createActionButtons(this);
+
+ table = new TableViewer(this, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.MULTI);
+ GridData gd = new GridData(GridData.FILL_BOTH);
+ gd.minimumHeight = 140;
+ gd.horizontalSpan = 2;
+ table.getTable().setLayoutData(gd);
+ TableLayout tableLayout = new TableLayout(true);
+ table.getTable().setLayout(tableLayout);
+ table.getTable().setHeaderVisible(true);
+ table.getTable().setLinesVisible(true);
+ table.setContentProvider(ArrayContentProvider.getInstance());
+
+ TableViewerColumn stateColumn = new TableViewerColumn(table, SWT.NONE);
+ stateColumn.getColumn().setText(Messages.DecoratorModelPropertyEditor_1);
+ stateColumn.setLabelProvider(new StateCellLabelProvider());
+ tableLayout.addColumnData(new ColumnWeightData(25, 100, true));
+
+ TableViewerColumn resourceColumn = new TableViewerColumn(table, SWT.NONE);
+ resourceColumn.getColumn().setText(Messages.DecoratorModelPropertyEditor_2);
+ resourceColumn.setLabelProvider(new DelegatingStyledCellLabelProvider(new DecoratorModelLabelProvider()));
+ tableLayout.addColumnData(new ColumnWeightData(75, 350, true));
+
+ table.addSelectionChangedListener(new ISelectionChangedListener() {
+
+ public void selectionChanged(SelectionChangedEvent event) {
+ updateButtons();
+ }
+ });
+ table.addDoubleClickListener(new IDoubleClickListener() {
+
+ public void doubleClick(DoubleClickEvent event) {
+ if (loadButton.isEnabled()) {
+ loadDecoratorModels();
+ }
+ }
+ });
+
+ updateButtons();
+ }
+
+ protected void createActionButtons(Composite parent) {
+ Composite buttonsArea = new Composite(parent, SWT.NONE);
+ buttonsArea.setLayoutData(new GridData(SWT.END, SWT.DEFAULT, false, false));
+ buttonsArea.setLayout(new RowLayout());
+
+ loadButton = new Button(buttonsArea, SWT.PUSH);
+ loadButton.setImage(Activator.getDefault().getImage("/icons/full/dtool16/load_resource.png")); //$NON-NLS-1$
+ loadButton.setToolTipText(Messages.DecoratorModelPropertyEditor_3);
+
+ unloadButton = new Button(buttonsArea, SWT.PUSH);
+ unloadButton.setImage(Activator.getDefault().getImage("/icons/full/ctool16/unload_resource.png")); //$NON-NLS-1$
+ unloadButton.setToolTipText(Messages.DecoratorModelPropertyEditor_4);
+
+ duplicateButton = new Button(buttonsArea, SWT.PUSH);
+ duplicateButton.setImage(Activator.getDefault().getImage("/icons/full/ctool16/dup_resource.png")); //$NON-NLS-1$
+ duplicateButton.setToolTipText(Messages.DecoratorModelPropertyEditor_5);
+
+ SelectionListener action = new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ action((Button) e.widget);
+ }
+ };
+
+ loadButton.addSelectionListener(action);
+ unloadButton.addSelectionListener(action);
+ duplicateButton.addSelectionListener(action);
+ }
+
+ protected void action(Button button) {
+ if (button == loadButton) {
+ loadDecoratorModels();
+ } else if (button == unloadButton) {
+ unloadDecoratorModels();
+ } else if (button == duplicateButton) {
+ duplicateDecoratorModel();
+ }
+ updateButtons();
+ }
+
+ @Override
+ protected void doBinding() {
+ super.doBinding();
+
+ table.setInput(modelProperty);
+ modelProperty.addChangeListener(this);
+ }
+
+ public void handleChange(ChangeEvent event) {
+ if (!isDisposed()) {
+ preservingSelection(new Runnable() {
+
+ public void run() {
+ table.refresh();
+ }
+ });
+ }
+ }
+
+ protected Package getPackage() {
+ return (Package) getContextElement();
+ }
+
+ protected void loadDecoratorModels() {
+ Set<URI> resources = ImmutableSet.copyOf(Iterables.filter(((IStructuredSelection) table.getSelection()).toList(), URI.class));
+ if (!Iterables.isEmpty(resources)) {
+ final LoadProfileApplicationsWizard wizard = new LoadProfileApplicationsWizard(false, true);
+ wizard.init(getPackage(), resources);
+
+ preservingSelection(new Runnable() {
+
+ public void run() {
+ if (wizard.isComplete()) {
+ // Just do it
+ wizard.performFinish();
+ } else {
+ new WizardDialog(getShell(), wizard).open();
+ }
+ }
+ });
+ }
+ }
+
+ protected void unloadDecoratorModels() {
+ final Iterable<Resource> resources = Iterables.filter(((IStructuredSelection) table.getSelection()).toList(), Resource.class);
+ if (!Iterables.isEmpty(resources)) {
+ final ResourceSet rset = Iterables.getFirst(resources, null).getResourceSet();
+
+ preservingSelection(new Runnable() {
+
+ public void run() {
+ try {
+ UnloadDecoratorModelHandler.unloadResources(Activator.getActiveWorkbenchWindow(), rset, resources);
+ } catch (ExecutionException e) {
+ Throwable exc = (e.getCause() != null) ? e.getCause() : e;
+ IStatus status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.DecoratorModelPropertyEditor_6, exc);
+ Activator.getDefault().getLog().log(status);
+ StatusManager.getManager().handle(status, StatusManager.SHOW);
+ }
+ }
+ });
+ }
+ }
+
+ protected void duplicateDecoratorModel() {
+ final Object selected = ((IStructuredSelection) table.getSelection()).getFirstElement();
+ if (selected != null) {
+ preservingSelection(new Runnable() {
+
+ public void run() {
+ DuplicateDecoratorModelWizard wizard = new DuplicateDecoratorModelWizard();
+ wizard.init(EMFHelper.getResourceSet(getPackage()), selected);
+ new WizardDialog(getShell(), wizard).open();
+ }
+ });
+ }
+ }
+
+ protected void updateButtons() {
+ List<?> selection = ((IStructuredSelection) table.getSelection()).toList();
+
+ boolean enableLoad = !selection.isEmpty();
+ boolean enableUnload = enableLoad;
+ boolean enableDup = selection.size() == 1;
+
+ if (enableLoad) {
+ for (Object next : selection) {
+ enableLoad = enableLoad && !(next instanceof Resource);
+ enableUnload = enableUnload && (next instanceof Resource);
+ }
+ }
+
+ loadButton.setImage(Activator.getDefault().getImage(enableLoad ? "/icons/full/etool16/load_resource.png" : "/icons/full/dtool16/load_resource.png")); //$NON-NLS-1$ //$NON-NLS-2$
+ loadButton.setEnabled(enableLoad);
+ unloadButton.setEnabled(enableUnload);
+ duplicateButton.setEnabled(enableDup);
+ }
+
+ void preservingSelection(Runnable runnable) {
+ final boolean wasPreservingSelection = preservingSelection;
+ List<Object> selection = null;
+ Set<URI> uris = null;
+
+ if (!preservingSelection) {
+ selection = Lists.newArrayList((Iterator<?>) ((IStructuredSelection) table.getSelection()).iterator());
+ uris = Sets.newHashSet();
+ for (Object next : selection) {
+ if (next instanceof Resource) {
+ next = ((Resource) next).getURI();
+ }
+ if (next instanceof URI) {
+ uris.add((URI) next);
+ }
+ }
+
+ preservingSelection = true;
+ }
+
+ try {
+ runnable.run();
+ } finally {
+ preservingSelection = wasPreservingSelection;
+
+ if (selection != null) {
+ selection.clear();
+ for (Object next : modelProperty) {
+ URI uri = (next instanceof Resource) ? ((Resource) next).getURI() : (next instanceof URI) ? (URI) next : null;
+ if (uris.contains(uri)) {
+ selection.add(next);
+ }
+ }
+ table.setSelection(new StructuredSelection(selection), true);
+ updateButtons();
+ }
+ }
+ }
+
+ @Override
+ public Object getEditableType() {
+ return List.class;
+ }
+
+ @Override
+ public void setReadOnly(boolean readOnly) {
+ // Pass
+ }
+
+ @Override
+ public boolean isReadOnly() {
+ return true;
+ }
+
+ }
+
+ static class StateCellLabelProvider extends CellLabelProvider {
+ @Override
+ public void update(ViewerCell cell) {
+ cell.setText((cell.getElement() instanceof Resource) ? Messages.DecoratorModelPropertyEditor_7 : Messages.DecoratorModelPropertyEditor_8);
+ }
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/properties/widgets/ProfileApplicationPropertyEditor.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/properties/widgets/ProfileApplicationPropertyEditor.java
new file mode 100644
index 00000000000..af66845c7dd
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.properties/src/org/eclipse/papyrus/uml/decoratormodel/properties/widgets/ProfileApplicationPropertyEditor.java
@@ -0,0 +1,208 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.properties.widgets;
+
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.emf.transaction.util.TransactionUtil;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StyledString;
+import org.eclipse.jface.window.SameShellProvider;
+import org.eclipse.jface.window.Window;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.papyrus.uml.decoratormodel.helper.DecoratorModelUtils;
+import org.eclipse.papyrus.uml.decoratormodel.internal.properties.messages.Messages;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.wizards.ExternalizeProfileApplicationsWizard;
+import org.eclipse.papyrus.uml.decoratormodel.properties.Activator;
+import org.eclipse.papyrus.uml.decoratormodel.ui.providers.DeleteEmptyDecoratorModelsPolicy;
+import org.eclipse.papyrus.uml.properties.widgets.ProfileApplicationEditor;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.Profile;
+import org.eclipse.uml2.uml.ProfileApplication;
+
+import com.google.common.base.Function;
+import com.google.common.base.Strings;
+import com.google.common.collect.Iterables;
+
+/**
+ * Specialized property editor for profile applications of a package that enables editing of the selected profile application.
+ */
+public class ProfileApplicationPropertyEditor extends org.eclipse.papyrus.uml.properties.widgets.ProfileApplicationPropertyEditor {
+
+ /**
+ * Constructor.
+ *
+ * @param parent
+ * @param style
+ */
+ public ProfileApplicationPropertyEditor(Composite parent, int style) {
+ super(parent, style);
+ }
+
+ @Override
+ protected ProfileApplicationEditor createProfileApplicationEditor(Composite parent, int style) {
+ return new ExternalizableProfileApplicationEditor(parent, style);
+ }
+
+ //
+ // Nested types
+ //
+
+ static class ExternalizableProfileApplicationEditor extends ProfileApplicationEditor {
+
+ private Button externalizeButton;
+
+ private Button internalizeButton;
+
+ ExternalizableProfileApplicationEditor(Composite parent, int style) {
+ super(parent, style);
+ }
+
+ @Override
+ protected void createListControls() {
+ super.createListControls();
+
+ externalizeButton = createButton(Activator.getDefault().getImage("/icons/full/ctool16/externalize.gif"), Messages.ProfileApplicationPropertyEditor_0); //$NON-NLS-1$
+ internalizeButton = createButton(Activator.getDefault().getImage("/icons/full/ctool16/internalize.gif"), Messages.ProfileApplicationPropertyEditor_1); //$NON-NLS-1$
+ }
+
+ @Override
+ protected ProfileColumnsLabelProvider createProfileColumnsLabelProvider(IBaseLabelProvider labelProvider) {
+ return new ExternalizableProfileColumnsLabelProvider(labelProvider);
+ }
+
+ @Override
+ protected void updateControls() {
+ super.updateControls();
+
+ final Package package_ = getInputPackage();
+ final Iterable<ProfileApplication> profileApplications = getSelectedProfileApplications();
+
+ boolean allInternalized = false;
+ for (ProfileApplication next : profileApplications) {
+ allInternalized = next.getApplyingPackage() == package_;
+ if (!allInternalized) {
+ break;
+ }
+ }
+ externalizeButton.setEnabled(allInternalized);
+
+ boolean allExternalized = false;
+ for (ProfileApplication next : profileApplications) {
+ allExternalized = next.getApplyingPackage() != package_;
+ if (!allExternalized) {
+ break;
+ }
+ }
+ internalizeButton.setEnabled(allExternalized);
+ }
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ super.widgetSelected(e);
+
+ if (e.widget == externalizeButton) {
+ externalizeProfileApplications();
+ } else if (e.widget == internalizeButton) {
+ internalizeProfileApplications();
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ Iterable<ProfileApplication> getSelectedProfileApplications() {
+ final Package package_ = getInputPackage();
+ IStructuredSelection selection = (IStructuredSelection) treeViewer.getSelection();
+ return Iterables.transform(selection.toList(), new Function<Object, ProfileApplication>() {
+ public ProfileApplication apply(Object input) {
+ return package_.getProfileApplication((Profile) input, true);
+ }
+ });
+ }
+
+ Package getInputPackage() {
+ return (Package) getContextElement();
+ }
+
+ void externalizeProfileApplications() {
+ Package package_ = getInputPackage();
+
+ TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(package_);
+ if (domain != null) {
+ ExternalizeProfileApplicationsWizard wizard = new ExternalizeProfileApplicationsWizard();
+ final Iterable<ProfileApplication> profileApplications = getSelectedProfileApplications();
+ wizard.init(package_, profileApplications);
+
+ WizardDialog dlg = new WizardDialog(getShell(), wizard);
+ if (dlg.open() == Window.OK) {
+ commit();
+ updateControls();
+ }
+ }
+ }
+
+ void internalizeProfileApplications() {
+ Package package_ = getInputPackage();
+
+ TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(package_);
+ if (domain != null) {
+ final Iterable<ProfileApplication> profileApplications = getSelectedProfileApplications();
+ domain.getCommandStack().execute(DecoratorModelUtils.createReclaimProfileApplicationsCommand(profileApplications, new DeleteEmptyDecoratorModelsPolicy(new SameShellProvider(internalizeButton))));
+ commit();
+ updateControls();
+ }
+ }
+
+ //
+ // Nested types
+ //
+
+ protected class ExternalizableProfileColumnsLabelProvider extends ProfileColumnsLabelProvider {
+
+ public ExternalizableProfileColumnsLabelProvider(IBaseLabelProvider defaultLabelProvider) {
+ super(defaultLabelProvider);
+ }
+
+ @Override
+ public StyledString getStyledText(Object element) {
+ StyledString result = super.getStyledText(element);
+
+ ProfileApplication application = null;
+ if (element instanceof Profile) {
+ application = getInputPackage().getProfileApplication((Profile) element, true);
+ } else if (element instanceof ProfileApplication) {
+ application = (ProfileApplication) element;
+ }
+
+ if ((application != null) && (application.eResource() != getInputPackage().eResource())) {
+ Package rootPackage = (Package) EcoreUtil.getRootContainer(application);
+ String modelName = rootPackage.getName();
+ if (Strings.isNullOrEmpty(modelName)) {
+ modelName = rootPackage.eResource().getURI().trimFileExtension().lastSegment();
+ }
+ String qualifier = " " + NLS.bind(Messages.ProfileApplicationPropertyEditor_2, modelName); //$NON-NLS-1$
+
+ result.append(qualifier, StyledString.DECORATIONS_STYLER);
+ }
+
+ return result;
+ }
+ }
+ }
+
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/.classpath b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/.classpath
new file mode 100644
index 00000000000..ad32c83a788
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/.project b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/.project
new file mode 100644
index 00000000000..10b0b694c9b
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.papyrus.uml.decoratormodel.ui</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/.settings/org.eclipse.jdt.core.prefs b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000000..94d61f00da6
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,291 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
+org.eclipse.jdt.core.formatter.comment.line_length=260
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=false
+org.eclipse.jdt.core.formatter.join_wrapped_lines=false
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=260
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=5
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/.settings/org.eclipse.jdt.ui.prefs b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 00000000000..954281dbc31
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,68 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=false
+cleanup.always_use_this_for_non_static_field_access=false
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=false
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=false
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=true
+cleanup.organize_imports=false
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=true
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=false
+cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+cleanup.use_this_for_non_static_method_access=false
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_Papyrus
+cleanup_settings_version=2
+eclipse.preferences.version=1
+formatter_profile=_Papyrus
+formatter_settings_version=12
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=java;javax;org;com;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="false" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * Constructor.\n *\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*****************************************************************************\n * Copyright (c) ${year} CEA LIST and others.\n * \n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * which accompanies this distribution, and is available at\n * http\://www.eclipse.org/legal/epl-v10.html\n *\n * Contributors\:\n * CEA LIST - Initial API and implementation\n * \n *****************************************************************************/\n</template><template autoinsert\="true" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * @author ${user}\n *\n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment">/**\n * ${see_to_overridden}\n *\n * ${tags}\n */</template><template autoinsert\="false" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${see_to_target}\n *\n * ${tags}\n */</template><template autoinsert\="true" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/META-INF/MANIFEST.MF b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/META-INF/MANIFEST.MF
new file mode 100644
index 00000000000..55c1d331102
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/META-INF/MANIFEST.MF
@@ -0,0 +1,42 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-SymbolicName: org.eclipse.papyrus.uml.decoratormodel.ui;singleton:=true
+Bundle-Version: 1.1.0.qualifier
+Bundle-ClassPath: .
+Bundle-Activator: org.eclipse.papyrus.uml.decoratormodel.internal.ui.Activator
+Bundle-Vendor: %providerName
+Bundle-Localization: plugin
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.eclipse.emf.ecore;visibility:=reexport,
+ org.eclipse.papyrus.infra.core.log;bundle-version="1.1.0",
+ org.eclipse.uml2.uml;bundle-version="4.1.0";visibility:=reexport,
+ org.eclipse.papyrus.infra.core;bundle-version="1.1.0",
+ org.eclipse.papyrus.uml.tools.utils;bundle-version="1.1.0",
+ org.eclipse.papyrus.uml.tools;bundle-version="1.1.0",
+ org.eclipse.emf.transaction;bundle-version="1.4.0",
+ com.google.guava;bundle-version="11.0.0",
+ org.eclipse.gmf.runtime.emf.commands.core;bundle-version="1.7.0",
+ org.eclipse.papyrus.uml.decoratormodel;bundle-version="1.1.0",
+ org.eclipse.emf.edit.ui;bundle-version="2.10.0",
+ org.eclipse.core.expressions;bundle-version="3.4.600",
+ org.eclipse.papyrus.infra.emf;bundle-version="1.1.0",
+ org.eclipse.papyrus.editor;bundle-version="1.1.0",
+ org.eclipse.ui.ide;bundle-version="3.10.100",
+ org.eclipse.ui.navigator;bundle-version="3.5.500",
+ org.eclipse.papyrus.emf.facet.custom.metamodel;bundle-version="1.1.0";resolution:=optional,
+ org.eclipse.papyrus.infra.tools;bundle-version="1.1.0",
+ org.eclipse.papyrus.infra.onefile;bundle-version="1.1.0",
+ org.eclipse.papyrus.infra.widgets;bundle-version="1.1.0",
+ org.eclipse.papyrus.uml.extensionpoints;bundle-version="1.1.0",
+ org.eclipse.papyrus.uml.profile;bundle-version="1.1.0"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Bundle-ActivationPolicy: lazy
+Export-Package: org.eclipse.papyrus.uml.decoratormodel.internal.ui,
+ org.eclipse.papyrus.uml.decoratormodel.internal.ui.commands;x-friends:="org.eclipse.papyrus.uml.decoratormodel.properties",
+ org.eclipse.papyrus.uml.decoratormodel.internal.ui.expressions;x-internal:=true,
+ org.eclipse.papyrus.uml.decoratormodel.internal.ui.preferences;x-internal:=true,
+ org.eclipse.papyrus.uml.decoratormodel.internal.ui.providers;x-friends:="org.eclipse.papyrus.uml.decoratormodel.properties",
+ org.eclipse.papyrus.uml.decoratormodel.internal.ui.wizards;x-friends:="org.eclipse.papyrus.uml.decoratormodel.properties",
+ org.eclipse.papyrus.uml.decoratormodel.ui.providers
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/about.html b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/about.html
new file mode 100644
index 00000000000..d35d5aed64c
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>June 5, 2007</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
+
+</body>
+</html>
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/build.properties b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/build.properties
new file mode 100644
index 00000000000..169989da1b8
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/build.properties
@@ -0,0 +1,10 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ about.html,\
+ documentation.pdoc,\
+ plugin.xml,\
+ plugin.properties,\
+ icons/
+src.includes = about.html
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/documentation.pdoc b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/documentation.pdoc
new file mode 100644
index 00000000000..4887381972c
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/documentation.pdoc
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<doc:Documentation xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:doc="http://www.eclipse.org/papyrus/documentation/plugin/documentation" description="User interface elements for management of separate profile applications.">
+ <referent firstName="Christian" lastName="Damus" eMail="give.a.damus@gmail.com" currentCompany="independent"/>
+</doc:Documentation>
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/icons/full/ovr16/profileApps.png b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/icons/full/ovr16/profileApps.png
new file mode 100644
index 00000000000..1214d5d30b4
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/icons/full/ovr16/profileApps.png
Binary files differ
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/plugin.properties b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/plugin.properties
new file mode 100644
index 00000000000..b82480134b3
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/plugin.properties
@@ -0,0 +1,38 @@
+# Copyright (c) 2014 Christian W. Damus and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Christian W. Damus - Initial API and implementation
+
+pluginName = Papyrus Decorator Models UI
+providerName = Eclipse Modeling Project
+
+externalize.label = Externalize Profile Applications...
+externalize.tooltip = Move profile applications into a separate model
+internalize.label = Internalize Profile Applications...
+internalize.tooltip = Reintegrate profile applications from a separate model into the main UML model
+unload.pkg.label = Unload Profile Applications
+unload.pkg.tooltip = Unload profile applications provided by the selected model
+load.label = Load Profile Applications...
+load.tooltip = Load external profile applications for the selected package
+unload.cmd.label = Unload Profile Applications...
+unload.cmd.tooltip = Unload profile applications for the selected package
+externalize.description = Move profile applications into separately loadable resources.
+externalize.name = Externalize Profile Applications
+internalize.description = Reintegrate externalized profile applications into the main UML model resource.
+internalize.name = Internalize Profile Applications
+unload.pkg.description = Unload profile applications provided by the selected resource.
+unload.pkg.name = Unload Profile Applications
+load.description = Load externalized profile applications for the selected package.
+load.name = Load Profile Applications
+unload.description = Unload profile applications for the selected package.
+unload.name = Unload Profile Applications
+cnf.filter.description = Filters out models that provide profile applications to Papyrus UML models.
+cnf.filter.name = Profile Applications
+profapps.decorator.label = Profile Applications
+profapps.decorator.description = Indicates workspace resources that are profile applications and packages in Model Explorer for which there are unloaded profile applications available that apply profiles to them.
+profapps.page.name = Profile Applications
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/plugin.xml b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/plugin.xml
new file mode 100644
index 00000000000..ec1279518d5
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/plugin.xml
@@ -0,0 +1,273 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+ <extension
+ point="org.eclipse.ui.menus">
+ <menuContribution
+ allPopups="false"
+ locationURI="popup:org.eclipse.papyrus.uml.modelrepair.refactor?after=additions">
+ <command
+ commandId="org.eclipse.papyrus.uml.decoratormodel.ui.ExternalizeProfiles"
+ label="%externalize.label"
+ style="push"
+ tooltip="%externalize.tooltip">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <count
+ value="1">
+ </count>
+ <iterate operator="and" ifEmpty="false">
+ <adapt
+ type="org.eclipse.emf.ecore.EObject">
+ <instanceof
+ value="org.eclipse.uml2.uml.Package">
+ </instanceof>
+ <test
+ forcePluginActivation="true"
+ property="org.eclipse.papyrus.uml.decoratormodel.ownsProfileApplications">
+ </test>
+ </adapt>
+ </iterate>
+ </and>
+ </visibleWhen>
+ </command>
+ <command
+ commandId="org.eclipse.papyrus.uml.decoratormodel.ui.InternalizeProfiles"
+ label="%internalize.label"
+ style="push"
+ tooltip="%internalize.tooltip">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <count
+ value="1">
+ </count>
+ <iterate operator="and" ifEmpty="false">
+ <adapt
+ type="org.eclipse.emf.ecore.EObject">
+ <instanceof
+ value="org.eclipse.uml2.uml.Package">
+ </instanceof>
+ <test
+ forcePluginActivation="true"
+ property="org.eclipse.papyrus.uml.decoratormodel.hasExternalProfileApplications">
+ </test>
+ </adapt>
+ </iterate>
+ </and>
+ </visibleWhen>
+ </command>
+ </menuContribution>
+ <menuContribution
+ allPopups="false"
+ locationURI="popup:org.eclipse.papyrus.views.modelexplorer.modelexplorer.popup?after=tools">
+ <command
+ commandId="org.eclipse.papyrus.uml.decoratormodel.ui.UnloadProfileApplications"
+ label="%unload.pkg.label"
+ style="push"
+ tooltip="%unload.pkg.tooltip">
+ <visibleWhen
+ checkEnabled="false">
+ <iterate operator="and" ifEmpty="false">
+ <adapt
+ type="org.eclipse.emf.ecore.EObject">
+ <instanceof
+ value="org.eclipse.uml2.uml.Package">
+ </instanceof>
+ <test
+ forcePluginActivation="true"
+ property="org.eclipse.papyrus.uml.decoratormodel.isDecoratorModel">
+ </test>
+ </adapt>
+ </iterate>
+ </visibleWhen>
+ </command>
+ <command
+ commandId="org.eclipse.papyrus.uml.decoratormodel.ui.LoadAvailableDecoratorModels"
+ label="%load.label"
+ style="push"
+ tooltip="%load.tooltip">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <count
+ value="1">
+ </count>
+ <iterate operator="and" ifEmpty="false">
+ <adapt
+ type="org.eclipse.emf.ecore.EObject">
+ <instanceof
+ value="org.eclipse.uml2.uml.Package">
+ </instanceof>
+ <test
+ forcePluginActivation="true"
+ property="org.eclipse.papyrus.uml.decoratormodel.hasUnloadedDecoratorModels"
+ args="recursive,optimistic">
+ </test>
+ </adapt>
+ </iterate>
+ </and>
+ </visibleWhen>
+ </command>
+ <command
+ commandId="org.eclipse.papyrus.uml.decoratormodel.ui.UnloadLoadedDecoratorModels"
+ label="%unload.cmd.label"
+ style="push"
+ tooltip="%unload.cmd.tooltip">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <count
+ value="1">
+ </count>
+ <iterate operator="and" ifEmpty="false">
+ <adapt
+ type="org.eclipse.emf.ecore.EObject">
+ <instanceof
+ value="org.eclipse.uml2.uml.Package">
+ </instanceof>
+ <test
+ forcePluginActivation="true"
+ property="org.eclipse.papyrus.uml.decoratormodel.hasLoadedDecoratorModels"
+ args="recursive">
+ </test>
+ </adapt>
+ </iterate>
+ </and>
+ </visibleWhen>
+ </command>
+ </menuContribution>
+ </extension>
+ <extension
+ point="org.eclipse.ui.commands">
+ <command
+ defaultHandler="org.eclipse.papyrus.uml.decoratormodel.internal.ui.commands.ExternalizeProfilesHandler"
+ description="%externalize.description"
+ id="org.eclipse.papyrus.uml.decoratormodel.ui.ExternalizeProfiles"
+ name="%externalize.name">
+ </command>
+ <command
+ defaultHandler="org.eclipse.papyrus.uml.decoratormodel.internal.ui.commands.InternalizeProfilesHandler"
+ description="%internalize.description"
+ id="org.eclipse.papyrus.uml.decoratormodel.ui.InternalizeProfiles"
+ name="%internalize.name">
+ </command>
+ <command
+ defaultHandler="org.eclipse.papyrus.uml.decoratormodel.internal.ui.commands.UnloadDecoratorModelHandler"
+ description="%unload.pkg.description"
+ id="org.eclipse.papyrus.uml.decoratormodel.ui.UnloadProfileApplications"
+ name="%unload.pkg.name">
+ </command>
+ <command
+ defaultHandler="org.eclipse.papyrus.uml.decoratormodel.internal.ui.commands.LoadAvailableDecoratorModelsHandler"
+ description="%load.description"
+ id="org.eclipse.papyrus.uml.decoratormodel.ui.LoadAvailableDecoratorModels"
+ name="%load.name">
+ </command>
+ <command
+ defaultHandler="org.eclipse.papyrus.uml.decoratormodel.internal.ui.commands.UnloadLoadedDecoratorModelsHandler"
+ description="%unload.description"
+ id="org.eclipse.papyrus.uml.decoratormodel.ui.UnloadLoadedDecoratorModels"
+ name="%unload.name">
+ </command>
+ </extension>
+ <extension
+ point="org.eclipse.core.expressions.propertyTesters">
+ <propertyTester
+ class="org.eclipse.papyrus.uml.decoratormodel.internal.ui.expressions.PackagePropertyTester"
+ id="org.eclipse.papyrus.uml.decoratormodel.package"
+ namespace="org.eclipse.papyrus.uml.decoratormodel"
+ properties="ownsProfileApplications,hasExternalProfileApplications,isDecoratorModel,hasUnloadedDecoratorModels,hasLoadedDecoratorModels"
+ type="org.eclipse.uml2.uml.Package">
+ </propertyTester>
+ </extension>
+ <extension
+ point="org.eclipse.ui.navigator.navigatorContent">
+ <commonFilter
+ activeByDefault="true"
+ description="%cnf.filter.description"
+ id="org.eclipse.papyrus.uml.decoratormodel.ui.DecoratorModelFilter"
+ name="%cnf.filter.name"
+ visibleInUI="true">
+ <filterExpression>
+ <adapt
+ type="org.eclipse.emf.ecore.EObject">
+ <instanceof
+ value="org.eclipse.uml2.uml.Package">
+ </instanceof>
+ <test
+ property="org.eclipse.papyrus.uml.decoratormodel.isDecoratorModel">
+ </test>
+ </adapt>
+ </filterExpression>
+ </commonFilter>
+ </extension>
+ <extension
+ point="org.eclipse.ui.navigator.viewer">
+ <viewerContentBinding
+ viewerId="org.eclipse.papyrus.views.modelexplorer.modelexplorer">
+ <includes>
+ <contentExtension
+ pattern="org.eclipse.papyrus.uml.decoratormodel.ui.*">
+ </contentExtension>
+ </includes>
+ </viewerContentBinding>
+ </extension>
+ <extension
+ point="org.eclipse.ui.startup">
+ <startup
+ class="org.eclipse.papyrus.uml.decoratormodel.internal.ui.Startup"></startup>
+ </extension>
+ <extension
+ point="org.eclipse.ui.decorators">
+ <decorator
+ class="org.eclipse.papyrus.uml.decoratormodel.internal.ui.providers.DecoratorModelLabelDecorator"
+ id="org.eclipse.papyrus.uml.decoratormodel.ui.DecoratorModel"
+ label="%profapps.decorator.label"
+ lightweight="true"
+ state="true">
+ <description>
+ %profapps.decorator.description
+ </description>
+ <enablement>
+ <or>
+ <objectClass
+ name="org.eclipse.emf.ecore.EObject">
+ </objectClass>
+ <objectClass
+ name="org.eclipse.papyrus.emf.facet.custom.metamodel.v0_2_0.internal.treeproxy.EObjectTreeElement">
+ </objectClass>
+ <objectClass
+ name="org.eclipse.core.resources.IFile">
+ </objectClass>
+ <objectClass
+ name="org.eclipse.papyrus.infra.onefile.model.IPapyrusFile">
+ </objectClass>
+ </or>
+ </enablement>
+ </decorator>
+ </extension>
+ <extension
+ point="org.eclipse.papyrus.infra.core.model">
+ <modelSetSnippet
+ classname="org.eclipse.papyrus.uml.decoratormodel.internal.ui.providers.AvailableDecoratorModelsSnippet"
+ description="Interceptor of resource loads that optionally prompts to load available decorator models.">
+ </modelSetSnippet>
+ </extension>
+ <extension
+ point="org.eclipse.core.runtime.preferences">
+ <initializer
+ class="org.eclipse.papyrus.uml.decoratormodel.internal.ui.preferences.ProfileExternalizationUIPreferences">
+ </initializer>
+ </extension>
+ <extension
+ point="org.eclipse.ui.preferencePages">
+ <page
+ category="org.eclipse.papyrus.infra.core.sasheditor.preferences.generalcategory"
+ class="org.eclipse.papyrus.uml.decoratormodel.internal.ui.preferences.DecoratorModelPreferencePage"
+ id="org.eclipse.papyrus.uml.decoratormodel.ui.DecoratorModelPreferences"
+ name="%profapps.page.name">
+ </page>
+ </extension>
+</plugin>
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/pom.xml b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/pom.xml
new file mode 100644
index 00000000000..a2a1d6d5989
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/pom.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project>
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>org.eclipse.papyrus</artifactId>
+ <groupId>org.eclipse.papyrus</groupId>
+ <version>1.1.0-SNAPSHOT</version>
+ <relativePath>../../../../releng/top-pom-main.xml</relativePath>
+ </parent>
+ <artifactId>org.eclipse.papyrus.uml.decoratormodel.ui</artifactId>
+ <groupId>org.eclipse.papyrus</groupId>
+ <version>1.1.0-SNAPSHOT</version>
+ <packaging>eclipse-plugin</packaging>
+</project> \ No newline at end of file
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/Activator.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/Activator.java
new file mode 100644
index 00000000000..df197410272
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/Activator.java
@@ -0,0 +1,111 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.ui;
+
+import java.util.concurrent.ExecutorService;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.papyrus.infra.core.log.LogHelper;
+import org.eclipse.papyrus.infra.tools.util.UIUtil;
+import org.eclipse.papyrus.uml.decoratormodel.internal.resource.DecoratorModelIndex;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * 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.uml.decoratormodel.ui"; //$NON-NLS-1$
+
+ // The shared instance
+ private static Activator plugin;
+
+ private ExecutorService executorService;
+
+ /**
+ * Logging utility.
+ */
+ public static LogHelper log;
+
+ public Activator() {
+ super();
+ }
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+
+ executorService = UIUtil.createUIExecutor(Display.getDefault());
+
+ plugin = this;
+ log = new LogHelper(this);
+
+ // Kick the index
+ DecoratorModelIndex.getInstance();
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ executorService.shutdown();
+ executorService = null;
+
+ plugin = null;
+ log = null;
+
+ super.stop(context);
+ }
+
+ /**
+ * Obtains the static instance.
+ *
+ * @return the static instance
+ */
+ public static Activator getDefault() {
+ return plugin;
+ }
+
+ public ImageDescriptor getIcon(String path) {
+ if (!path.startsWith("icons/")) { //$NON-NLS-1$
+ path = "icons/" + path; //$NON-NLS-1$
+ }
+ return AbstractUIPlugin.imageDescriptorFromPlugin(PLUGIN_ID, path);
+ }
+
+ public ExecutorService getExecutorService() {
+ return executorService;
+ }
+
+ public static IWorkbenchWindow getActiveWorkbenchWindow() {
+ IWorkbenchWindow result = null;
+
+ IWorkbench bench = PlatformUI.getWorkbench();
+ if (bench != null) {
+ result = bench.getActiveWorkbenchWindow();
+ if (result == null) {
+ IWorkbenchWindow[] allWindows = bench.getWorkbenchWindows();
+ if (allWindows.length > 0) {
+ result = allWindows[0];
+ }
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/Startup.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/Startup.java
new file mode 100644
index 00000000000..3e8826b68b0
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/Startup.java
@@ -0,0 +1,32 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.ui;
+
+import org.eclipse.ui.IStartup;
+
+/**
+ * Early start-up hook for the externalized profile applications subsystem.
+ */
+public class Startup implements IStartup {
+
+ public Startup() {
+ super();
+ }
+
+ @Override
+ public void earlyStartup() {
+ // Kick the index
+ Activator.getDefault();
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/commands/ExternalizeProfilesHandler.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/commands/ExternalizeProfilesHandler.java
new file mode 100644
index 00000000000..029aed14f48
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/commands/ExternalizeProfilesHandler.java
@@ -0,0 +1,51 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.ui.commands;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.wizards.ExternalizeProfileApplicationsWizard;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * Command handler for the "Externalize Profile Applications&hellip;" command.
+ */
+public class ExternalizeProfilesHandler extends AbstractHandler {
+
+ public ExternalizeProfilesHandler() {
+ super();
+ }
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ IWorkbench bench = HandlerUtil.getActiveWorkbenchWindowChecked(event).getWorkbench();
+ ISelection selection = HandlerUtil.getActiveMenuSelectionChecked(event);
+
+ if (selection instanceof IStructuredSelection) {
+ ExternalizeProfileApplicationsWizard wizard = new ExternalizeProfileApplicationsWizard();
+ wizard.init(bench, (IStructuredSelection) selection);
+
+ WizardDialog dlg = new WizardDialog(bench.getActiveWorkbenchWindow().getShell(), wizard);
+ dlg.open();
+ }
+
+ return null;
+ }
+
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/commands/InternalizeProfilesHandler.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/commands/InternalizeProfilesHandler.java
new file mode 100644
index 00000000000..2c2ab0175f1
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/commands/InternalizeProfilesHandler.java
@@ -0,0 +1,51 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.ui.commands;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.wizards.InternalizeProfileApplicationsWizard;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * Command handler for the "Internalize Profile Applications&hellip;" command.
+ */
+public class InternalizeProfilesHandler extends AbstractHandler {
+
+ public InternalizeProfilesHandler() {
+ super();
+ }
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ IWorkbench bench = HandlerUtil.getActiveWorkbenchWindowChecked(event).getWorkbench();
+ ISelection selection = HandlerUtil.getActiveMenuSelectionChecked(event);
+
+ if (selection instanceof IStructuredSelection) {
+ InternalizeProfileApplicationsWizard wizard = new InternalizeProfileApplicationsWizard();
+ wizard.init(bench, (IStructuredSelection) selection);
+
+ WizardDialog dlg = new WizardDialog(bench.getActiveWorkbenchWindow().getShell(), wizard);
+ dlg.open();
+ }
+
+ return null;
+ }
+
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/commands/LoadAvailableDecoratorModelsHandler.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/commands/LoadAvailableDecoratorModelsHandler.java
new file mode 100644
index 00000000000..9a0ca979baf
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/commands/LoadAvailableDecoratorModelsHandler.java
@@ -0,0 +1,61 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.ui.commands;
+
+import java.util.Collections;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.wizards.LoadProfileApplicationsWizard;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.uml2.uml.Package;
+
+/**
+ * Command handler for the "Load Available Profile Applications&hellip;" command.
+ */
+public class LoadAvailableDecoratorModelsHandler extends AbstractHandler {
+
+ public LoadAvailableDecoratorModelsHandler() {
+ super();
+ }
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindowChecked(event).getWorkbench().getActiveWorkbenchWindow();
+ ISelection selection = HandlerUtil.getActiveMenuSelectionChecked(event);
+
+ if (selection instanceof IStructuredSelection) {
+ Package package_ = (Package) EMFHelper.getEObject(((IStructuredSelection) selection).getFirstElement());
+ promptToLoadAvailableProfileApplications(window.getShell(), package_, false);
+ }
+
+ return null;
+ }
+
+ public static void promptToLoadAvailableProfileApplications(Shell parentShell, Package package_, final boolean autoPrompt) {
+ LoadProfileApplicationsWizard wizard = new LoadProfileApplicationsWizard(autoPrompt);
+ wizard.init(package_, Collections.<URI> emptySet());
+
+ WizardDialog dlg = new WizardDialog(parentShell, wizard);
+ dlg.open();
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/commands/UnloadDecoratorModelHandler.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/commands/UnloadDecoratorModelHandler.java
new file mode 100644
index 00000000000..a09cc0227c5
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/commands/UnloadDecoratorModelHandler.java
@@ -0,0 +1,273 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.ui.commands;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Set;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.emf.common.command.AbstractCommand;
+import org.eclipse.emf.common.command.AbstractCommand.NonDirtying;
+import org.eclipse.emf.common.command.BasicCommandStack;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
+import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.emf.transaction.util.TransactionUtil;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.papyrus.infra.core.editor.IMultiDiagramEditor;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
+import org.eclipse.papyrus.infra.emf.utils.ServiceUtilsForResourceSet;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.messages.Messages;
+import org.eclipse.papyrus.uml.tools.utils.CustomUMLUtil;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.uml2.uml.Package;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+
+/**
+ * Command handler for the "Unload Profile Applications" command.
+ */
+public class UnloadDecoratorModelHandler extends AbstractHandler {
+
+ public UnloadDecoratorModelHandler() {
+ super();
+ }
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindowChecked(event);
+ ISelection selection = HandlerUtil.getActiveMenuSelectionChecked(event);
+
+ ResourceSet resourceSet = null;
+ final Set<Resource> toUnload = Sets.newHashSet();
+ if (selection instanceof IStructuredSelection) {
+ for (Object next : ((IStructuredSelection) selection).toList()) {
+ EObject eObject = EMFHelper.getEObject(next);
+ if (eObject instanceof Package) {
+ Resource resource = eObject.eResource();
+ toUnload.add(resource);
+ resourceSet = resource.getResourceSet();
+ }
+ }
+ }
+
+ if (resourceSet != null) {
+ unloadResources(window, resourceSet, toUnload);
+ }
+
+ return null;
+ }
+
+ public static void unloadResources(IWorkbenchWindow uiContext, ResourceSet resourceSet, final Iterable<? extends Resource> resources) throws ExecutionException {
+ // Check for resources that need to be saved
+ final SaveHandler save = getSaveHandler(resourceSet);
+ boolean needSave = save.isSaveNeeded(resources);
+ if (needSave) {
+ if (!confirmSave(uiContext.getShell())) {
+ // Bail if user refused to save
+ return;
+ }
+
+ try {
+ uiContext.run(true, false, new IRunnableWithProgress() {
+
+ @Override
+ public void run(IProgressMonitor monitor) throws InvocationTargetException {
+ try {
+ save.save(resources, monitor);
+ } catch (IOException e) {
+ throw new InvocationTargetException(e);
+ }
+ }
+ });
+ } catch (InterruptedException e) {
+ throw new ExecutionException(Messages.UnloadDecoratorModelHandler_0, e);
+ } catch (InvocationTargetException e) {
+ throw new ExecutionException(Messages.UnloadDecoratorModelHandler_1, e.getTargetException());
+ }
+ }
+
+ TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(resourceSet);
+ if (domain != null) {
+ class UnloadCommand extends AbstractCommand implements NonDirtying {
+ UnloadCommand() {
+ super(Messages.UnloadDecoratorModelHandler_2);
+ }
+
+ @Override
+ protected boolean prepare() {
+ return true;
+ }
+
+ @Override
+ public void execute() {
+ for (Resource next : resources) {
+ // Destroy the contents of the resource to effect unapplication of stereotypes
+ CustomUMLUtil.destroyAll(next.getContents());
+
+ next.unload();
+ next.getResourceSet().getResources().remove(next);
+ next.eAdapters().clear();
+ }
+ }
+
+ /**
+ * Unloading resources breaks undo/redo of any previous commands that involved their
+ * contents.
+ *
+ * @return {@code false}, always
+ */
+ @Override
+ public boolean canUndo() {
+ return false;
+ }
+
+ @Override
+ public void redo() {
+ throw new IllegalStateException("command was not undone"); //$NON-NLS-1$
+ }
+ }
+
+ domain.getCommandStack().execute(new UnloadCommand());
+ }
+ }
+
+ static SaveHandler getSaveHandler(ResourceSet resourceSet) {
+ return (resourceSet instanceof ModelSet) ? new ModelSetSaveHandlerImpl((ModelSet) resourceSet) : new SaveHandlerImpl(resourceSet);
+ }
+
+ static boolean confirmSave(Shell parentShell) {
+ return MessageDialog.openConfirm(parentShell, Messages.UnloadDecoratorModelHandler_2, Messages.UnloadDecoratorModelHandler_3);
+ }
+
+ //
+ // Nested types
+ //
+
+ interface SaveHandler {
+ boolean isSaveNeeded(Iterable<? extends Resource> resources);
+
+ void save(Iterable<? extends Resource> resources, IProgressMonitor monitor) throws IOException;
+ }
+
+ static class SaveHandlerImpl implements SaveHandler {
+ private final ResourceSet resourceSet;
+
+ SaveHandlerImpl(ResourceSet resourceSet) {
+ this.resourceSet = resourceSet;
+ }
+
+ @Override
+ public boolean isSaveNeeded(Iterable<? extends Resource> resources) {
+ boolean result = false;
+ boolean trackingModification = true;
+
+ for (Resource next : resources) {
+ if (!next.isTrackingModification()) {
+ // Can't trust this method
+ result = false;
+ trackingModification = false;
+ break;
+ }
+
+ if (next.isModified()) {
+ result = true;
+ break;
+ }
+ }
+
+ if (!result && !trackingModification) {
+ // Check command stack, if any
+ EditingDomain domain = AdapterFactoryEditingDomain.getEditingDomainFor(resourceSet);
+ if ((domain != null) && (domain.getCommandStack() instanceof BasicCommandStack)) {
+ result = ((BasicCommandStack) domain.getCommandStack()).isSaveNeeded();
+ } else {
+ // Asssume that save will be needed
+ result = true;
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public void save(Iterable<? extends Resource> resources, IProgressMonitor monitor) throws IOException {
+ SubMonitor sub = SubMonitor.convert(monitor, Messages.UnloadDecoratorModelHandler_4, Iterables.size(resources));
+
+ for (Resource next : resources) {
+ next.save(null);
+ sub.worked(1);
+ }
+
+ sub.done();
+ }
+ }
+
+ static class ModelSetSaveHandlerImpl implements SaveHandler {
+ private final ModelSet modelSet;
+
+ ModelSetSaveHandlerImpl(ModelSet modelSet) {
+ this.modelSet = modelSet;
+ }
+
+ @Override
+ public boolean isSaveNeeded(Iterable<? extends Resource> resources) {
+ boolean result = false;
+
+ for (Resource next : resources) {
+ if (modelSet.shouldSave(next)) {
+ result = true;
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public void save(Iterable<? extends Resource> resources, IProgressMonitor monitor) throws IOException {
+ // First, try to find the open editor
+ IMultiDiagramEditor editor = null;
+
+ try {
+ editor = ServiceUtilsForResourceSet.getInstance().getService(IMultiDiagramEditor.class, modelSet);
+ } catch (ServiceException e) {
+ // OK, there's no editor. That's fine
+ }
+
+ if (editor != null) {
+ editor.doSave(monitor);
+ } else {
+ // Just save the model set for consistency
+ modelSet.save(monitor);
+ }
+ }
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/commands/UnloadLoadedDecoratorModelsHandler.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/commands/UnloadLoadedDecoratorModelsHandler.java
new file mode 100644
index 00000000000..414907dd4f3
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/commands/UnloadLoadedDecoratorModelsHandler.java
@@ -0,0 +1,74 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.ui.commands;
+
+import java.util.Collections;
+import java.util.Set;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
+import org.eclipse.papyrus.uml.decoratormodel.helper.DecoratorModelUtils;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.messages.Messages;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.wizards.UnloadProfileApplicationsWizard;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.uml2.uml.Package;
+
+import com.google.common.collect.Sets;
+
+/**
+ * Command handler for the "Unload Decorator Models&hellip;" command.
+ */
+public class UnloadLoadedDecoratorModelsHandler extends AbstractHandler {
+
+ public UnloadLoadedDecoratorModelsHandler() {
+ super();
+ }
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindowChecked(event).getWorkbench().getActiveWorkbenchWindow();
+ ISelection selection = HandlerUtil.getActiveMenuSelectionChecked(event);
+
+ if (selection instanceof IStructuredSelection) {
+ Package package_ = (Package) EMFHelper.getEObject(((IStructuredSelection) selection).getFirstElement());
+ Set<URI> loaded = Sets.newHashSet();
+
+ // Collect all loaded profile application resources for loaded sub-units
+ loaded.addAll(DecoratorModelUtils.getLoadedDecoratorModels(package_.eResource()));
+ for (Package subUnit : DecoratorModelUtils.getLoadedSubUnitPackages(package_)) {
+ loaded.addAll(DecoratorModelUtils.getLoadedDecoratorModels(subUnit.eResource()));
+ }
+
+ if (loaded.isEmpty()) {
+ MessageDialog.openWarning(window.getShell(), Messages.UnloadLoadedDecoratorModelsHandler_0, Messages.UnloadLoadedDecoratorModelsHandler_1);
+ } else {
+ UnloadProfileApplicationsWizard wizard = new UnloadProfileApplicationsWizard();
+ wizard.init(package_, Collections.<URI> emptySet());
+
+ WizardDialog dlg = new WizardDialog(window.getShell(), wizard);
+ dlg.open();
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/expressions/PackagePropertyTester.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/expressions/PackagePropertyTester.java
new file mode 100644
index 00000000000..958c0bbe095
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/expressions/PackagePropertyTester.java
@@ -0,0 +1,134 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.ui.expressions;
+
+import java.util.Set;
+import java.util.concurrent.Future;
+
+import org.eclipse.core.expressions.PropertyTester;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
+import org.eclipse.papyrus.uml.decoratormodel.helper.DecoratorModelUtils;
+import org.eclipse.uml2.uml.Package;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.Futures;
+
+/**
+ * Tester for core-expressions properties contributed to the UML {@link Package} type.
+ */
+public class PackagePropertyTester extends PropertyTester {
+ public static final String PROPERTY_OWNS_PROFILE_APPLICATIONS = "ownsProfileApplications"; //$NON-NLS-1$
+
+ public static final String PROPERTY_HAS_EXTERNAL_PROFILE_APPLICATIONS = "hasExternalProfileApplications"; //$NON-NLS-1$
+
+ public static final String PROPERTY_IS_DECORATOR_MODEL = "isDecoratorModel"; //$NON-NLS-1$
+
+ public static final String PROPERTY_HAS_UNLOADED_DECORATOR_MODELS = "hasUnloadedDecoratorModels"; //$NON-NLS-1$
+
+ public static final String PROPERTY_HAS_LOADED_DECORATOR_MODELS = "hasLoadedDecoratorModels"; //$NON-NLS-1$
+
+ public PackagePropertyTester() {
+ super();
+ }
+
+ @Override
+ public boolean test(Object receiver, String property, Object[] args, Object expectedValue) {
+ boolean result = false;
+
+ if (receiver instanceof IStructuredSelection) {
+ receiver = ((IStructuredSelection) receiver).getFirstElement();
+ } else if (receiver instanceof Iterable<?>) {
+ receiver = Iterables.getFirst((Iterable<?>) receiver, null);
+ }
+
+ receiver = EMFHelper.getEObject(receiver);
+ if (receiver instanceof Package) {
+ Package package_ = (Package) receiver;
+
+ if (PROPERTY_OWNS_PROFILE_APPLICATIONS.equals(property)) {
+ result = ownsProfileApplications(package_);
+ } else if (PROPERTY_HAS_EXTERNAL_PROFILE_APPLICATIONS.equals(property)) {
+ result = hasExternalProfileApplications(package_);
+ } else if (PROPERTY_IS_DECORATOR_MODEL.equals(property)) {
+ result = isDecoratorModel(package_);
+ } else if (PROPERTY_HAS_UNLOADED_DECORATOR_MODELS.equals(property)) {
+ result = hasUnloadedDecoratorModels(package_, args);
+ } else if (PROPERTY_HAS_LOADED_DECORATOR_MODELS.equals(property)) {
+ result = hasLoadedDecoratorModels(package_, args);
+ }
+
+ // These are all boolean properties
+ result = expectBoolean(expectedValue) == result;
+ }
+
+ return result;
+ }
+
+ private static boolean expectBoolean(Object expectedValue) {
+ return (expectedValue == null) || ((expectedValue instanceof Boolean) && ((Boolean) expectedValue).booleanValue());
+ }
+
+ static boolean ownsProfileApplications(Package receiver) {
+ return !receiver.getProfileApplications().isEmpty();
+ }
+
+ static boolean hasExternalProfileApplications(Package receiver) {
+ return !Iterables.isEmpty(DecoratorModelUtils.getDecoratorModelProfileApplications(receiver));
+ }
+
+ static boolean isDecoratorModel(Package receiver) {
+ return (receiver.getOwner() == null) && DecoratorModelUtils.hasExternalizationProfile(receiver);
+ }
+
+ static boolean hasUnloadedDecoratorModels(Package receiver, Object[] args) {
+ Set<?> options = Sets.newHashSet(args);
+ boolean recursive = options.contains("recursive"); //$NON-NLS-1$
+ boolean optimistic = options.contains("optimistic"); //$NON-NLS-1$
+
+ return hasUnloadedDecoratorModels(receiver, recursive, optimistic);
+ }
+
+ public static boolean hasUnloadedDecoratorModels(Package receiver, boolean recursive, boolean optimistic) {
+ Future<Boolean> result = DecoratorModelUtils.hasUnloadedDecoratorModelsAsync(receiver, true);
+
+ // Optimistic enablement in case the index is not yet ready. Allow for null result
+ return result.isDone() ? Boolean.TRUE.equals(Futures.getUnchecked(result)) : optimistic;
+ }
+
+ static boolean hasLoadedDecoratorModels(Package receiver, Object[] args) {
+ Set<?> options = Sets.newHashSet(args);
+ boolean recursive = options.contains("recursive"); //$NON-NLS-1$
+
+ return hasLoadedDecoratorModels(receiver, recursive);
+ }
+
+ private static boolean hasLoadedDecoratorModels(Package receiver, boolean recursive) {
+ Resource resource = receiver.eResource();
+ boolean result = !DecoratorModelUtils.getLoadedDecoratorModels(resource).isEmpty();
+
+ if (!result && recursive) {
+ for (Package next : DecoratorModelUtils.getLoadedSubUnitPackages(receiver)) {
+ result = hasLoadedDecoratorModels(next, recursive);
+ if (result) {
+ break;
+ }
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/messages/Messages.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/messages/Messages.java
new file mode 100644
index 00000000000..21a33952bfc
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/messages/Messages.java
@@ -0,0 +1,98 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.ui.messages;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * @author damus
+ *
+ */
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.papyrus.uml.decoratormodel.internal.ui.messages.messages"; //$NON-NLS-1$
+ public static String AbstractNewDecoratorModelPage_0;
+ public static String AbstractNewDecoratorModelPage_1;
+ public static String AbstractNewDecoratorModelPage_2;
+ public static String AbstractNewDecoratorModelPage_3;
+ public static String AbstractNewDecoratorModelPage_4;
+ public static String AbstractNewDecoratorModelPage_5;
+ public static String AbstractNewDecoratorModelPage_6;
+ public static String AbstractNewDecoratorModelPage_7;
+ public static String AbstractNewDecoratorModelPage_8;
+ public static String AbstractProfileApplicationSelectionPage_0;
+ public static String AbstractProfileApplicationSelectionPage_1;
+ public static String AbstractProfileApplicationSelectionPage_2;
+ public static String ConflictingDecoratorModelsPage_0;
+ public static String ConflictingDecoratorModelsPage_1;
+ public static String ConflictingDecoratorModelsPage_2;
+ public static String ConflictingDecoratorModelsPage_3;
+ public static String DecoratorModelPreferencePage_0;
+ public static String DecoratorModelPreferencePage_1;
+ public static String DecoratorModelPreferencePage_2;
+ public static String DecoratorModelPreferencePage_3;
+ public static String DecoratorModelPreferencePage_4;
+ public static String DecoratorModelSelectionPage_0;
+ public static String DecoratorModelSelectionPage_1;
+ public static String DecoratorModelSelectionPage_2;
+ public static String DecoratorModelSelectionPage_3;
+ public static String DecoratorModelSelectionPage_4;
+ public static String DecoratorModelSelectionPage_5;
+ public static String DeleteEmptyDecoratorModelsPolicy_0;
+ public static String DeleteEmptyDecoratorModelsPolicy_1;
+ public static String DeleteEmptyDecoratorModelsPolicy_2;
+ public static String DuplicateDecoratorModelPage_0;
+ public static String DuplicateDecoratorModelPage_1;
+ public static String DuplicateDecoratorModelPage_2;
+ public static String DuplicateDecoratorModelPage_3;
+ public static String DuplicateDecoratorModelPage_4;
+ public static String DuplicateDecoratorModelPage_5;
+ public static String DuplicateDecoratorModelPage_6;
+ public static String DuplicateDecoratorModelPage_7;
+ public static String DuplicateDecoratorModelWizard_0;
+ public static String DuplicateDecoratorModelWizard_1;
+ public static String DuplicateDecoratorModelWizard_2;
+ public static String ExternalizeProfileApplicationsPage_0;
+ public static String ExternalizeProfileApplicationsPage_1;
+ public static String ExternalizeProfileApplicationsPage_2;
+ public static String ExternalizeProfileApplicationsPage_3;
+ public static String ExternalizeProfileApplicationsPage_4;
+ public static String ExternalizeProfileApplicationsPage_5;
+ public static String ExternalizeProfileApplicationsWizard_0;
+ public static String InternalizeProfileApplicationsPage_0;
+ public static String InternalizeProfileApplicationsWizard_0;
+ public static String LoadDecoratorModelsPage_0;
+ public static String LoadProfileApplicationsWizard_0;
+ public static String LoadProfileApplicationsWizard_1;
+ public static String ProfileResourceLabelProvider_0;
+ public static String UnloadDecoratorModelHandler_0;
+ public static String UnloadDecoratorModelHandler_1;
+ public static String UnloadDecoratorModelHandler_2;
+ public static String UnloadDecoratorModelHandler_3;
+ public static String UnloadDecoratorModelHandler_4;
+ public static String UnloadLoadedDecoratorModelsHandler_0;
+ public static String UnloadLoadedDecoratorModelsHandler_1;
+ public static String UnloadProfileApplicationsWizard_0;
+ public static String UnloadProfileApplicationsWizard_1;
+ public static String UnloadProfileApplicationsWizard_2;
+ public static String WhenKind_0;
+ public static String WhenKind_1;
+ public static String WhenKind_2;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/messages/messages.properties b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/messages/messages.properties
new file mode 100644
index 00000000000..e8819bd1fdd
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/messages/messages.properties
@@ -0,0 +1,67 @@
+AbstractNewDecoratorModelPage_0=If creating a new profile application, enter a name for it that indicates its viewpoint or purpose.
+AbstractNewDecoratorModelPage_1=Resource:
+AbstractNewDecoratorModelPage_2=Browse...
+AbstractNewDecoratorModelPage_3=Model name:
+AbstractNewDecoratorModelPage_4=profile application
+AbstractNewDecoratorModelPage_5=Not a valid resource path.
+AbstractNewDecoratorModelPage_6=No such project or folder: {0}
+AbstractNewDecoratorModelPage_7=Decorator model file extension must be "{0}"
+AbstractNewDecoratorModelPage_8=Selected resource is not a profile application.
+AbstractProfileApplicationSelectionPage_0=Profiles:
+AbstractProfileApplicationSelectionPage_1=Select &All
+AbstractProfileApplicationSelectionPage_2=&Deselect All
+ConflictingDecoratorModelsPage_0=Unload Profile Applications
+ConflictingDecoratorModelsPage_1=Unload profile applications that are no longer needed, for conflicts, or to switch perspectives.
+ConflictingDecoratorModelsPage_2=Select &Conflicts
+ConflictingDecoratorModelsPage_3=One or more profile applications must be unloaded because it applies the same profile as will be loaded.
+DecoratorModelPreferencePage_0=Profile Applications
+DecoratorModelPreferencePage_1=Options controlling how to handle externalized profile applications and the models that contain them.
+DecoratorModelPreferencePage_2=Automatically prompt to load available profile applications
+DecoratorModelPreferencePage_3=Prompt to confirm unloading conflicting profile applications
+DecoratorModelPreferencePage_4=Delete empty models when reintegrating profile applications from them
+DecoratorModelSelectionPage_0=Select Profile Applications
+DecoratorModelSelectionPage_1=Profile applications:
+DecoratorModelSelectionPage_2=Select &All
+DecoratorModelSelectionPage_3=&Deselect All
+DecoratorModelSelectionPage_4=Do not show this again
+DecoratorModelSelectionPage_5=There are no profile applications to choose from.
+DeleteEmptyDecoratorModelsPolicy_0=Delete Profile Applications
+DeleteEmptyDecoratorModelsPolicy_1=These resources no longer have any profile applications and therefore do not apply profiles any models. Delete them?
+DeleteEmptyDecoratorModelsPolicy_2=Remember my decision
+DuplicateDecoratorModelPage_0=Duplicate Profile Application
+DuplicateDecoratorModelPage_1=Enter a resource path and name for the new profile application.
+DuplicateDecoratorModelPage_2=Duplicate Profile Application
+DuplicateDecoratorModelPage_3=Select a container and file name for the new profile application.
+DuplicateDecoratorModelPage_4=File "{0}" already exists. Please choose another.
+DuplicateDecoratorModelPage_5={0} copy
+DuplicateDecoratorModelPage_6={0}Copy{1}
+DuplicateDecoratorModelPage_7=Profile application copy
+DuplicateDecoratorModelWizard_0=Duplicate Profile Application
+DuplicateDecoratorModelWizard_1=Duplicating profile application ...
+DuplicateDecoratorModelWizard_2=Failed to save profile application copy
+ExternalizeProfileApplicationsPage_0=Choose Profile Applications to Externalize
+ExternalizeProfileApplicationsPage_1=If creating a new profile application resource, enter a name for it that indicates its viewpoint or purpose.
+ExternalizeProfileApplicationsPage_2=Select Profile Application
+ExternalizeProfileApplicationsPage_3=Select an existing profile application resource or create a new one to contain the profile application(s).
+ExternalizeProfileApplicationsPage_4=Selected resource is not a profile application.
+ExternalizeProfileApplicationsPage_5=Selected resource already applies profile "{0}" to package "{1}".
+ExternalizeProfileApplicationsWizard_0=Externalize Profile Applications
+InternalizeProfileApplicationsPage_0=Choose Profile Applications to Internalize
+InternalizeProfileApplicationsWizard_0=Internalize Profile Applications
+LoadDecoratorModelsPage_0=Profile applications "{0}" and "{1}" apply the same profile to the same package.
+LoadProfileApplicationsWizard_0=Load Profile Applications
+LoadProfileApplicationsWizard_1=Select profile applications to load.
+ProfileResourceLabelProvider_0=<unknown profile>
+UnloadDecoratorModelHandler_0=Profile application resource save cancelled.
+UnloadDecoratorModelHandler_1=Failed to save profile application resource.
+UnloadDecoratorModelHandler_2=Unload Profile Applications
+UnloadDecoratorModelHandler_3=At least one profile application has changes that must be saved before it can be unloaded. OK to save?
+UnloadDecoratorModelHandler_4=Saving model...
+UnloadLoadedDecoratorModelsHandler_0=Unload Profile Applications
+UnloadLoadedDecoratorModelsHandler_1=No externalized profile applications are loaded for the selected package.
+UnloadProfileApplicationsWizard_0=Unload Profile Applications
+UnloadProfileApplicationsWizard_1=Select externalized profile applications to unload.
+UnloadProfileApplicationsWizard_2=Failed to unload profile applications.
+WhenKind_0=Always
+WhenKind_1=Never
+WhenKind_2=Prompt
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/preferences/DecoratorModelPreferencePage.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/preferences/DecoratorModelPreferencePage.java
new file mode 100644
index 00000000000..63b302a4f90
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/preferences/DecoratorModelPreferencePage.java
@@ -0,0 +1,47 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.ui.preferences;
+
+import org.eclipse.jface.preference.BooleanFieldEditor;
+import org.eclipse.jface.preference.FieldEditorPreferencePage;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.Activator;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.messages.Messages;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+
+/**
+ * Preference page UI for decorator model behaviour of the tooling.
+ */
+public class DecoratorModelPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage {
+
+ public DecoratorModelPreferencePage() {
+ super(Messages.DecoratorModelPreferencePage_0, GRID);
+
+ setPreferenceStore(Activator.getDefault().getPreferenceStore());
+ setDescription(Messages.DecoratorModelPreferencePage_1);
+ }
+
+ @Override
+ public void init(IWorkbench workbench) {
+ // Pass
+ }
+
+ @Override
+ protected void createFieldEditors() {
+ addField(new BooleanFieldEditor(ProfileExternalizationUIPreferences.AUTO_PROMPT_TO_LOAD_PROFILE_APPLICATIONS, Messages.DecoratorModelPreferencePage_2, getFieldEditorParent()));
+ addField(new BooleanFieldEditor(ProfileExternalizationUIPreferences.PROMPT_TO_UNLOAD_CONFLICTING_DECORATOR_MODELS, Messages.DecoratorModelPreferencePage_3, getFieldEditorParent()));
+ addField(WhenKind.createFieldEditor(ProfileExternalizationUIPreferences.DELETE_EMPTY_DECORATOR_MODELS, Messages.DecoratorModelPreferencePage_4, getFieldEditorParent()));
+ }
+
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/preferences/ProfileExternalizationUIPreferences.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/preferences/ProfileExternalizationUIPreferences.java
new file mode 100644
index 00000000000..a4c341857f1
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/preferences/ProfileExternalizationUIPreferences.java
@@ -0,0 +1,69 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.ui.preferences;
+
+import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.Activator;
+
+/**
+ * Preferences for the behaviour of the profile externalization tooling UI.
+ */
+public class ProfileExternalizationUIPreferences extends AbstractPreferenceInitializer {
+ static final String AUTO_PROMPT_TO_LOAD_PROFILE_APPLICATIONS = "autoPromptToLoadProfileApplications"; //$NON-NLS-1$
+
+ static final String PROMPT_TO_UNLOAD_CONFLICTING_DECORATOR_MODELS = "promptToUnloadConflicts"; //$NON-NLS-1$
+
+ static final String DELETE_EMPTY_DECORATOR_MODELS = "deleteEmptyDecoratorModels"; //$NON-NLS-1$
+
+
+ public ProfileExternalizationUIPreferences() {
+ super();
+ }
+
+ static IPreferenceStore getStore() {
+ return Activator.getDefault().getPreferenceStore();
+ }
+
+ public static void setAutoPromptToLoadProfileApplications(boolean autoPrompt) {
+ getStore().setValue(AUTO_PROMPT_TO_LOAD_PROFILE_APPLICATIONS, autoPrompt);
+ }
+
+ public static boolean getAutoPromptToLoadProfileApplications() {
+ return getStore().getBoolean(AUTO_PROMPT_TO_LOAD_PROFILE_APPLICATIONS);
+ }
+
+ public static void setPromptToUnloadConflicts(boolean prompt) {
+ getStore().setValue(PROMPT_TO_UNLOAD_CONFLICTING_DECORATOR_MODELS, prompt);
+ }
+
+ public static boolean getPromptToUnloadConflicts() {
+ return getStore().getBoolean(PROMPT_TO_UNLOAD_CONFLICTING_DECORATOR_MODELS);
+ }
+
+ public static void setDeleteEmptyDecoratorModels(WhenKind when) {
+ getStore().setValue(DELETE_EMPTY_DECORATOR_MODELS, when.name());
+ }
+
+ public static WhenKind getDeleteEmptyDecoratorModels() {
+ return WhenKind.valueOf(getStore().getString(DELETE_EMPTY_DECORATOR_MODELS));
+ }
+
+ @Override
+ public void initializeDefaultPreferences() {
+ getStore().setDefault(AUTO_PROMPT_TO_LOAD_PROFILE_APPLICATIONS, true);
+ getStore().setDefault(PROMPT_TO_UNLOAD_CONFLICTING_DECORATOR_MODELS, true);
+ getStore().setDefault(DELETE_EMPTY_DECORATOR_MODELS, WhenKind.PROMPT.name());
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/preferences/WhenKind.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/preferences/WhenKind.java
new file mode 100644
index 00000000000..eedf7103cc8
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/preferences/WhenKind.java
@@ -0,0 +1,32 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.ui.preferences;
+
+import org.eclipse.jface.preference.FieldEditor;
+import org.eclipse.jface.preference.RadioGroupFieldEditor;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.messages.Messages;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * An enumeration of possible settings of "when" type preferences.
+ */
+public enum WhenKind {
+ PROMPT, NEVER, ALWAYS;
+
+ public static FieldEditor createFieldEditor(String preferenceName, String labelText, Composite parent) {
+ return new RadioGroupFieldEditor(preferenceName, labelText, 3, //
+ new String[][] { { Messages.WhenKind_0, ALWAYS.name() }, { Messages.WhenKind_1, NEVER.name() }, { Messages.WhenKind_2, PROMPT.name() } }, //
+ parent);
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/providers/AvailableDecoratorModelsSnippet.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/providers/AvailableDecoratorModelsSnippet.java
new file mode 100644
index 00000000000..29d15e012aa
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/providers/AvailableDecoratorModelsSnippet.java
@@ -0,0 +1,169 @@
+/*****************************************************************************
+ * Copyright (c) 2014 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 399859
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.ui.providers;
+
+import java.util.concurrent.Executor;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.papyrus.infra.core.editor.IMultiDiagramEditor;
+import org.eclipse.papyrus.infra.core.resource.IModelSetSnippet;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.resource.ResourceAdapter;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.emf.utils.ServiceUtilsForEObject;
+import org.eclipse.papyrus.infra.emf.utils.ServiceUtilsForResourceSet;
+import org.eclipse.papyrus.infra.tools.util.UIUtil;
+import org.eclipse.papyrus.uml.decoratormodel.helper.DecoratorModelUtils;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.Activator;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.commands.LoadAvailableDecoratorModelsHandler;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.preferences.ProfileExternalizationUIPreferences;
+import org.eclipse.papyrus.uml.profile.service.ReapplyProfilesService;
+import org.eclipse.papyrus.uml.tools.model.UmlModel;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.UMLPackage;
+
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+
+/**
+ * A {@link ModelSet} snippet that intercepts loading of resources to optionally prompt the user to load available profile applications.
+ */
+public class AvailableDecoratorModelsSnippet extends ResourceAdapter implements IModelSetSnippet {
+ private static final String EDITOR_SERVICE_ID = IMultiDiagramEditor.class.getName();
+
+ private Executor profileRefreshExecutor;
+
+ private ModelSet modelSet;
+
+ public AvailableDecoratorModelsSnippet() {
+ super();
+ }
+
+ @Override
+ public void start(ModelSet modelsManager) {
+ this.modelSet = modelsManager;
+ addAdapter(modelsManager);
+ profileRefreshExecutor = UIUtil.createAsyncOnceExecutor();
+ }
+
+ @Override
+ public void dispose(ModelSet modelsManager) {
+ if (modelsManager == modelSet) {
+ profileRefreshExecutor = null;
+ removeAdapter(modelsManager);
+ modelSet = null;
+ }
+ }
+
+ @Override
+ protected void handleResourceLoaded(Resource resource) {
+ final Package package_ = (Package) EcoreUtil.getObjectByType(resource.getContents(), UMLPackage.Literals.PACKAGE);
+ if (package_ != null) {
+ // Check whether to prompt for loading available decorator models
+ if (isPromptEnabled()) {
+ // Only prompt for resources in this user model
+ Resource root = EcoreUtil.getRootContainer(package_).eResource();
+ if (modelSet.getURIWithoutExtension().equals(root.getURI().trimFileExtension())) {
+ // Schedule a call-back on the UI thread to prompt if there are unloaded profile applications available
+ Futures.addCallback(DecoratorModelUtils.hasUnloadedDecoratorModelsAsync(package_, false), //
+ promptToLoadDecoratorModels(package_), Activator.getDefault().getExecutorService());
+ }
+ }
+
+ // Maybe a decorator model was loaded? Check for profile migration. Note that we don't
+ // need to invoke profile refresh when loading/discovering resources on first opening
+ // the editor because the editor already does that
+ if (DecoratorModelUtils.isDecoratorModel(resource) && (profileRefreshExecutor != null)) {
+ UmlModel uml = (UmlModel) modelSet.getModel(UmlModel.MODEL_ID);
+ final Package rootPackage = (uml == null) ? null : (Package) EcoreUtil.getObjectByType(uml.getResource().getContents(), UMLPackage.Literals.PACKAGE);
+ if (rootPackage != null) {
+ profileRefreshExecutor.execute(new Runnable() {
+
+ @Override
+ public void run() {
+ // Check that the editor wasn't closed in the mean-time
+ if (modelSet != null) {
+ refreshProfiles(rootPackage);
+ }
+ }
+ });
+ }
+ }
+ }
+ }
+
+ boolean isPromptEnabled() {
+ boolean result = false;
+
+ if (ProfileExternalizationUIPreferences.getAutoPromptToLoadProfileApplications()) {
+ // Even so, only prompt if opening in an editor
+ try {
+ ServicesRegistry services = ServiceUtilsForResourceSet.getInstance().getServiceRegistry(modelSet);
+ result = (services != null) && services.isStarted(EDITOR_SERVICE_ID);
+
+ if (result) {
+ // And then only if the editor is not open on a decorator model!
+ UmlModel uml = (UmlModel) modelSet.getModel(UmlModel.MODEL_ID);
+ Resource mainResource = (uml == null) ? null : uml.getResource();
+ result = (mainResource == null) || !DecoratorModelUtils.isDecoratorModel(mainResource);
+ }
+ } catch (ServiceException e) {
+ // That's fine. If there's no editor, then it can't be opening
+ }
+ }
+
+ return result;
+ }
+
+ static boolean isLoadedAndAttached(EObject object) {
+ return !object.eIsProxy() && (object.eResource() != null);
+ }
+
+ private FutureCallback<Boolean> promptToLoadDecoratorModels(final Package package_) {
+ return new FutureCallback<Boolean>() {
+ @Override
+ public void onSuccess(Boolean result) {
+ if (result && isLoadedAndAttached(package_)) {
+ // Still loaded and attached
+ IWorkbenchWindow window = Activator.getActiveWorkbenchWindow();
+ if (window != null) {
+ LoadAvailableDecoratorModelsHandler.promptToLoadAvailableProfileApplications(window.getShell(), package_, true);
+ }
+ }
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ // Don't prompt anything
+ }
+ };
+ }
+
+ protected void refreshProfiles(Package rootPackage) {
+ ReapplyProfilesService reapplyProfiles;
+ try {
+ reapplyProfiles = ServiceUtilsForEObject.getInstance().getService(ReapplyProfilesService.class, rootPackage);
+ } catch (ServiceException ex) {
+ return;
+ }
+
+ reapplyProfiles.checkProfiles();
+ }
+
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/providers/DecoratorModelLabelDecorator.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/providers/DecoratorModelLabelDecorator.java
new file mode 100644
index 00000000000..3b1c91c837f
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/providers/DecoratorModelLabelDecorator.java
@@ -0,0 +1,192 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.ui.providers;
+
+import java.util.Set;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.content.IContentType;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.jface.viewers.BaseLabelProvider;
+import org.eclipse.jface.viewers.IDecoration;
+import org.eclipse.jface.viewers.ILightweightLabelDecorator;
+import org.eclipse.jface.viewers.LabelProviderChangedEvent;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
+import org.eclipse.papyrus.infra.onefile.model.IPapyrusFile;
+import org.eclipse.papyrus.uml.decoratormodel.helper.DecoratorModelUtils;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.Activator;
+import org.eclipse.papyrus.uml.tools.model.UmlModel;
+import org.eclipse.ui.ide.IDE;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.ProfileApplication;
+
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Label decorator for packages to indicate availability of externalized profile applications, decorator models loaded for a package, etc.
+ */
+public class DecoratorModelLabelDecorator extends BaseLabelProvider implements ILightweightLabelDecorator {
+
+ public DecoratorModelLabelDecorator() {
+ super();
+ }
+
+ @Override
+ public void decorate(Object element, IDecoration decoration) {
+ EObject eObject = EMFHelper.getEObject(element);
+
+ if ((eObject instanceof Package) && (eObject.eResource() != null)) {
+ decoratePackage((Package) eObject, decoration);
+ } else if (element instanceof IFile) {
+ decorateFile((IFile) element, decoration);
+ } else if (element instanceof IPapyrusFile) {
+ decorateFile((IPapyrusFile) element, decoration);
+ }
+ }
+
+ private void decorateFile(IFile file, IDecoration decoration) {
+ IContentType type = IDE.getContentType(file);
+ if ((type != null) && type.isKindOf(DecoratorModelUtils.DECORATOR_MODEL_CONTENT_TYPE)) {
+ addOverlay(decoration);
+ }
+ }
+
+ private void decorateFile(IPapyrusFile file, IDecoration decoration) {
+ for (IResource resource : file.getAssociatedResources()) {
+ if (resource.getType() == IResource.FILE) {
+ IContentType type = IDE.getContentType((IFile) resource);
+ if ((type != null) && type.isKindOf(DecoratorModelUtils.DECORATOR_MODEL_CONTENT_TYPE)) {
+ addOverlay(decoration);
+ break;
+ }
+ }
+ }
+ }
+
+ private void addOverlay(IDecoration decoration) {
+ decoration.addOverlay(Activator.getDefault().getIcon("full/ovr16/profileApps.png"), IDecoration.TOP_RIGHT); //$NON-NLS-1$
+ }
+
+ private void decoratePackage(Package package_, IDecoration decoration) {
+ // Root packages only, because the presentation of decorator models to display is recursive over controlled units.
+ // Also exclude any packages that are decorated by the main model if the main model is a decorator model
+ if ((package_.eContainer() == null) && !isUserOpenedDecoratorModel(package_)) {
+ if (!decoratePackageIcon(package_, decoration)) {
+ // Short-circuit the rest of the decoration of this package because we'll be revisiting it
+ return;
+ }
+ }
+
+ decoratePackageText(package_, decoration);
+ }
+
+ /**
+ * Is the given package the root of a model that is decorated by a decorator model opened as the main UML model of the model-set?
+ */
+ private static boolean isUserOpenedDecoratorModel(Package package_) {
+ boolean result = false;
+
+ ResourceSet rset = EMFHelper.getResourceSet(package_);
+ if (rset instanceof ModelSet) {
+ UmlModel uml = (UmlModel) ((ModelSet) rset).getModel(UmlModel.MODEL_ID);
+ if (uml != null) {
+ Resource main = uml.getResource();
+ if (DecoratorModelUtils.isDecoratorModel(main)) {
+ if (DecoratorModelUtils.isDecoratorModelFor(main, package_.eResource())) {
+ result = true;
+ } else {
+ for (Package next : DecoratorModelUtils.getLoadedSubUnitPackages(package_)) {
+ if (DecoratorModelUtils.isDecoratorModelFor(main, next.eResource())) {
+ result = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ private boolean decoratePackageIcon(Package package_, IDecoration decoration) {
+ boolean result = false;
+
+ ListenableFuture<Boolean> hasUnloadedDecoratorModels = DecoratorModelUtils.hasUnloadedDecoratorModelsAsync(package_, true);
+ if (hasUnloadedDecoratorModels.isDone()) {
+ result = true;
+ if (Futures.getUnchecked(hasUnloadedDecoratorModels)) {
+ addOverlay(decoration);
+ }
+ result = true;
+ } else {
+ hasUnloadedDecoratorModels.addListener(postUpdate(package_), Activator.getDefault().getExecutorService());
+ }
+
+ return result;
+ }
+
+ private void decoratePackageText(Package package_, IDecoration decoration) {
+ // Decorate packages with a suffix listing the loaded profile application model names
+ Set<Package> profileApplicationModels = null;
+ for (ProfileApplication profileApplication : DecoratorModelUtils.getDecoratorModelProfileApplications(package_)) {
+ if (profileApplicationModels == null) {
+ profileApplicationModels = Sets.newLinkedHashSet();
+ }
+ profileApplicationModels.add((Package) EcoreUtil.getRootContainer(profileApplication));
+ }
+ if (profileApplicationModels != null) {
+ StringBuilder suffix = new StringBuilder();
+
+ for (Package next : profileApplicationModels) {
+ if (suffix.length() == 0) {
+ suffix.append(" ("); //$NON-NLS-1$
+ } else {
+ suffix.append(", "); //$NON-NLS-1$
+ }
+
+ String modelName = next.getName();
+ if (modelName == null) {
+ modelName = next.eResource().getURI().trimFileExtension().lastSegment();
+ }
+ suffix.append(modelName);
+ }
+
+ if (suffix.length() > 0) {
+ suffix.append(")"); //$NON-NLS-1$
+ }
+
+ if (suffix.length() > 0) {
+ decoration.addSuffix(suffix.toString());
+ }
+ }
+ }
+
+ private Runnable postUpdate(final Object element) {
+ return new Runnable() {
+
+ @Override
+ public void run() {
+ fireLabelProviderChanged(new LabelProviderChangedEvent(DecoratorModelLabelDecorator.this, element));
+ }
+ };
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/providers/DecoratorModelLabelProvider.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/providers/DecoratorModelLabelProvider.java
new file mode 100644
index 00000000000..3944aefdee3
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/providers/DecoratorModelLabelProvider.java
@@ -0,0 +1,185 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.ui.providers;
+
+import java.util.Collections;
+import java.util.Map;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.Path;
+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.ecore.util.EcoreUtil;
+import org.eclipse.jface.viewers.LabelProviderChangedEvent;
+import org.eclipse.jface.viewers.StyledString;
+import org.eclipse.papyrus.infra.widgets.providers.DelegatingStyledLabelProvider;
+import org.eclipse.papyrus.uml.decoratormodel.internal.resource.DecoratorModelIndex;
+import org.eclipse.papyrus.uml.decoratormodel.internal.resource.DecoratorModelIndexEvent;
+import org.eclipse.papyrus.uml.decoratormodel.internal.resource.IDecoratorModelIndexListener;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.Activator;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.model.WorkbenchLabelProvider;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.UMLPackage;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * A label provider for presentation of decorator model {@link IFile}s or {@link Resource}s in the UI.
+ */
+public class DecoratorModelLabelProvider extends DelegatingStyledLabelProvider implements IDecoratorModelIndexListener {
+ private final ResourceSet resourceSet;
+
+ private volatile Map<URI, String> modelNames;
+
+ public DecoratorModelLabelProvider(ResourceSet resourceSet) {
+ super(new WorkbenchLabelProvider());
+
+ this.resourceSet = resourceSet;
+ DecoratorModelIndex.getInstance().addIndexListener(this);
+ }
+
+ public DecoratorModelLabelProvider() {
+ this(null);
+ }
+
+ @Override
+ public void dispose() {
+ DecoratorModelIndex.getInstance().removeIndexListener(this);
+
+ super.dispose();
+ }
+
+ @Override
+ protected Image customGetImage(Object element) {
+ Image result = null;
+
+ if (element instanceof Resource) {
+ element = ((Resource) element).getURI();
+ }
+ if (element instanceof URI) {
+ URI uri = (URI) element;
+ if (uri.isPlatformResource()) {
+ IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(uri.toPlatformString(true)));
+ result = delegatedGetImage(file);
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public StyledString customGetStyledText(Object element) {
+ return (element instanceof IFile) ? getStyledText((IFile) element) //
+ : (element instanceof Resource) ? getStyledText((Resource) element) //
+ : (element instanceof URI) ? getStyledText((URI) element) //
+ : null;
+ }
+
+ protected StyledString getStyledText(Resource resource) {
+ Package model = resource.isLoaded() ? (Package) EcoreUtil.getObjectByType(resource.getContents(), UMLPackage.Literals.PACKAGE) : null;
+
+ String modelName;
+
+ if (model == null) {
+ modelName = getModelNames().get(resource.getURI());
+ } else {
+ modelName = model.getName();
+ }
+
+ return getStyledText(modelName, resource.getURI());
+ }
+
+ protected StyledString getStyledText(String modelName, URI uri) {
+ StyledString result = new StyledString();
+ result.append(modelName);
+
+ String qualifier = uri.isPlatformResource() ? uri.toPlatformString(true) : uri.toString();
+ result.append(" - " + qualifier, StyledString.QUALIFIER_STYLER); //$NON-NLS-1$
+
+ return result;
+ }
+
+ protected StyledString getStyledText(IFile file) {
+ URI uri = URI.createPlatformResourceURI(file.getFullPath().toString(), true);
+
+ return getStyledText(uri);
+ }
+
+ protected StyledString getStyledText(URI uri) {
+ StyledString result;
+
+ // Get the actual current loaded model name if loaded, otherwise from the index
+ Resource resource = (resourceSet != null) ? resourceSet.getResource(uri, false) : null;
+ if (resource != null) {
+ result = getStyledText(resource);
+ } else {
+ String modelName = getModelNames().get(uri);
+ if (modelName == null) {
+ modelName = uri.trimFileExtension().lastSegment();
+ }
+ result = getStyledText(modelName, uri);
+ }
+
+ return result;
+ }
+
+ protected synchronized final Map<URI, String> getModelNames() {
+ if (modelNames == null) {
+ final ListenableFuture<Map<URI, String>> futureModelNames = DecoratorModelIndex.getInstance().getDecoratorModelNamesAsync();
+
+ if (futureModelNames.isDone()) {
+ // Get it now
+ modelNames = Futures.getUnchecked(futureModelNames);
+ } else {
+ futureModelNames.addListener(new Runnable() {
+
+ @Override
+ public void run() {
+ synchronized (DecoratorModelLabelProvider.this) {
+ modelNames = Futures.getUnchecked(futureModelNames);
+ if (modelNames == null) {
+ // Oh, well
+ modelNames = Collections.emptyMap();
+ } else {
+ // Update the labels now
+ updateLabels();
+ }
+ }
+ }
+ }, Activator.getDefault().getExecutorService());
+ }
+
+ if (modelNames == null) {
+ // Placeholder until the future result is ready
+ modelNames = Collections.emptyMap();
+ }
+ }
+
+ return modelNames;
+ }
+
+ @Override
+ public void indexChanged(DecoratorModelIndexEvent event) {
+ modelNames = null;
+ updateLabels();
+ }
+
+ protected void updateLabels() {
+ fireLabelProviderChanged(new LabelProviderChangedEvent(this));
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/providers/EncapsulatedAdapterFactoryLabelProvider.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/providers/EncapsulatedAdapterFactoryLabelProvider.java
new file mode 100644
index 00000000000..5ba483efae2
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/providers/EncapsulatedAdapterFactoryLabelProvider.java
@@ -0,0 +1,65 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.ui.providers;
+
+import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
+import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.uml2.uml.ProfileApplication;
+
+/**
+ * @author damus
+ *
+ */
+public class EncapsulatedAdapterFactoryLabelProvider extends AdapterFactoryLabelProvider {
+ public EncapsulatedAdapterFactoryLabelProvider() {
+ super(new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE));
+ }
+
+ @Override
+ public void dispose() {
+ try {
+ super.dispose();
+ } finally {
+ ((ComposedAdapterFactory) getAdapterFactory()).dispose();
+ }
+ }
+
+ @Override
+ public String getText(Object element) {
+ return super.getText(unwrap(element));
+ }
+
+ @Override
+ public Image getImage(Object element) {
+ return super.getImage(unwrap(element));
+ }
+
+ Object unwrap(Object element) {
+ return element;
+ }
+
+ public static ILabelProvider appliedProfiles() {
+ return new EncapsulatedAdapterFactoryLabelProvider() {
+ @Override
+ Object unwrap(Object element) {
+ if (element instanceof ProfileApplication) {
+ element = ((ProfileApplication) element).getAppliedProfile();
+ }
+ return element;
+ }
+ };
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/providers/ProfileResourceLabelProvider.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/providers/ProfileResourceLabelProvider.java
new file mode 100644
index 00000000000..7edcfcd371c
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/providers/ProfileResourceLabelProvider.java
@@ -0,0 +1,149 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.ui.providers;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPath;
+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.ecore.util.EcoreUtil;
+import org.eclipse.jface.viewers.StyledString;
+import org.eclipse.papyrus.infra.widgets.providers.DelegatingStyledLabelProvider;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.messages.Messages;
+import org.eclipse.papyrus.uml.extensionpoints.Registry;
+import org.eclipse.papyrus.uml.extensionpoints.profile.IRegisteredProfile;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.model.WorkbenchLabelProvider;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.UMLPackage;
+
+/**
+ * A label provider for presentation of decorator model {@link IFile}s or {@link Resource}s in the UI.
+ */
+public class ProfileResourceLabelProvider extends DelegatingStyledLabelProvider {
+ private final ResourceSet resourceSet;
+
+ public ProfileResourceLabelProvider(ResourceSet resourceSet) {
+ super(new WorkbenchLabelProvider());
+
+ this.resourceSet = resourceSet;
+ }
+
+ @Override
+ protected Image customGetImage(Object element) {
+ Image result = null;
+
+ if (element instanceof Resource) {
+ element = ((Resource) element).getURI();
+ }
+ if (element instanceof URI) {
+ URI uri = (URI) element;
+ IRegisteredProfile registered = getRegisteredProfile(uri);
+ if (registered != null) {
+ result = registered.getImage();
+ } else if (uri.isPlatformResource()) {
+ IResource file = !uri.isPlatformResource() ? null : ResourcesPlugin.getWorkspace().getRoot().findMember(uri.toPlatformString(true));
+ result = delegatedGetImage(file);
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public StyledString customGetStyledText(Object element) {
+ return (element instanceof IFile) ? getStyledText((IFile) element) //
+ : (element instanceof Resource) ? getStyledText((Resource) element) //
+ : (element instanceof URI) ? getStyledText((URI) element) //
+ : null;
+ }
+
+ protected StyledString getStyledText(Resource resource) {
+ StyledString result;
+
+ URI uri = resource.getURI();
+ Package model = resource.isLoaded() ? (Package) EcoreUtil.getObjectByType(resource.getContents(), UMLPackage.Literals.PACKAGE) : null;
+ if (model == null) {
+ result = getStyledText(uri);
+ } else if (uri.isPlatformResource()) {
+ result = new StyledString();
+ result.append(model.getName());
+
+ String qualifier = uri.isPlatformResource() ? uri.toPlatformString(true) : uri.toString();
+ result.append(" - " + qualifier, StyledString.QUALIFIER_STYLER); //$NON-NLS-1$
+ } else {
+ result = getStyledText(model.getName(), resource.getURI());
+ }
+
+ return result;
+ }
+
+ protected StyledString getStyledText(String modelName, URI uri) {
+ StyledString result = new StyledString();
+ result.append(modelName);
+
+ String qualifier = uri.isPlatformResource() ? uri.toPlatformString(true) : uri.toString();
+ result.append(" - " + qualifier, StyledString.QUALIFIER_STYLER); //$NON-NLS-1$
+
+ return result;
+ }
+
+ protected StyledString getStyledText(IFile file) {
+ StyledString result = new StyledString();
+
+ IPath path = file.getFullPath().removeFileExtension();
+ result.append(path.lastSegment());
+ result.append(" - " + path.removeLastSegments(1).toString(), StyledString.QUALIFIER_STYLER); //$NON-NLS-1$
+
+ return result;
+ }
+
+ protected IRegisteredProfile getRegisteredProfile(URI uri) {
+ IRegisteredProfile result = null;
+ for (IRegisteredProfile next : Registry.getRegisteredProfiles()) {
+ if (uri.equals(next.getUri())) {
+ result = next;
+ break;
+ }
+ }
+ return result;
+ }
+
+ protected StyledString getStyledText(URI uri) {
+ StyledString result;
+
+ IRegisteredProfile registered = getRegisteredProfile(uri);
+
+ if (registered != null) {
+ result = getStyledText(registered.getName(), uri);
+ } else {
+ Resource resource = (resourceSet == null) ? null : resourceSet.getResource(uri, false);
+ if ((resource != null) && resource.isLoaded()) {
+ result = getStyledText(resource);
+ } else {
+ IResource file = !uri.isPlatformResource() ? null : ResourcesPlugin.getWorkspace().getRoot().findMember(uri.toPlatformString(true));
+ if (file instanceof IFile) {
+ result = getStyledText((IFile) file);
+ } else {
+ result = getStyledText(Messages.ProfileResourceLabelProvider_0, uri);
+ }
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/AbstractManageProfileApplicationsWizard.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/AbstractManageProfileApplicationsWizard.java
new file mode 100644
index 00000000000..0227974cc86
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/AbstractManageProfileApplicationsWizard.java
@@ -0,0 +1,168 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.ui.wizards;
+
+import java.util.Collections;
+import java.util.Set;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.IWizardPage;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.Activator;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWizard;
+import org.eclipse.uml2.uml.Package;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Sets;
+import com.google.common.eventbus.EventBus;
+import com.google.common.eventbus.Subscribe;
+
+/**
+ * @author damus
+ *
+ */
+abstract class AbstractManageProfileApplicationsWizard extends Wizard implements IWorkbenchWizard {
+
+ private final boolean autoPrompt;
+
+ private Package package_;
+
+ private Set<URI> availableResources;
+
+ private IFile[] selectedResources;
+
+ private DecoratorModelSelectionPage mainPage;
+
+ public AbstractManageProfileApplicationsWizard(boolean autoPrompt) {
+ super();
+
+ this.autoPrompt = autoPrompt;
+ }
+
+ @Override
+ public void init(IWorkbench workbench, IStructuredSelection selection) {
+ EObject eObject = EMFHelper.getEObject(selection.getFirstElement());
+ if (eObject instanceof Package) {
+ init((Package) eObject, Collections.<URI> emptyList());
+ }
+ }
+
+ public void init(Package package_, Iterable<URI> initialSelections) {
+ this.package_ = package_;
+ this.availableResources = getAvailableProfileApplicationResources(package_);
+
+ EventBus bus = new EventBus("wizard"); //$NON-NLS-1$
+ bus.register(this);
+ createPages(package_, bus);
+ initPages(package_, ImmutableList.copyOf(initialSelections));
+ }
+
+ protected void createPages(Package package_, EventBus bus) {
+ mainPage = createSelectionPage(bus);
+ mainPage.setIsAutomaticPrompt(isAutoPrompt());
+ configureSelectionPage(mainPage);
+ }
+
+ protected void initPages(Package package_, Iterable<URI> initialSelections) {
+ mainPage.setInput(package_, availableResources);
+ mainPage.select(initialSelections);
+ }
+
+ @Override
+ public void addPages() {
+ addPage(mainPage);
+ }
+
+ @Override
+ public IWizardPage getStartingPage() {
+ IWizardPage result = super.getStartingPage();
+
+ if ((mainPage != null) && mainPage.canFlipToNextPage()) {
+ result = mainPage.getNextPage();
+ }
+
+ return result;
+ }
+
+ protected DecoratorModelSelectionPage createSelectionPage(EventBus bus) {
+ return new DecoratorModelSelectionPage(bus);
+ }
+
+ protected void configureSelectionPage(DecoratorModelSelectionPage page) {
+ // Pass
+ }
+
+ protected boolean isAutoPrompt() {
+ return autoPrompt;
+ }
+
+ abstract Set<URI> getAvailableProfileApplicationResources(Package package_);
+
+ protected IDialogSettings getSection(String sectionName, boolean createIfNecessary) {
+ IDialogSettings settings = Activator.getDefault().getDialogSettings().getSection(getClass().getSimpleName());
+ if ((settings == null) && createIfNecessary) {
+ settings = Activator.getDefault().getDialogSettings().addNewSection(getClass().getSimpleName());
+ }
+
+ IDialogSettings result = (settings == null) ? null : settings.getSection(sectionName);
+ if ((result == null) && createIfNecessary) {
+ result = settings.addNewSection(sectionName);
+ }
+
+ return result;
+ }
+
+ protected IDialogSettings getSection(IDialogSettings settings, String sectionName, boolean createIfNecessary) {
+ IDialogSettings result = settings.getSection(sectionName);
+ if ((result == null) && createIfNecessary) {
+ result = settings.addNewSection(sectionName);
+ }
+
+ return result;
+ }
+
+ @Subscribe
+ public void resourcesSelected(IFile[] resources) {
+ this.selectedResources = resources;
+ }
+
+ public boolean isComplete() {
+ return (mainPage != null) && mainPage.isPageComplete();
+ }
+
+ protected final Package getPackage() {
+ return package_;
+ }
+
+ @Override
+ public boolean performFinish() {
+ final ResourceSet resourceSet = getPackage().eResource().getResourceSet();
+
+ final Set<URI> resourceURIs = Sets.newHashSet();
+ for (IFile next : selectedResources) {
+ resourceURIs.add(URI.createPlatformResourceURI(next.getFullPath().toString(), true));
+ }
+
+ return performFinish(resourceSet, resourceURIs);
+ }
+
+ protected abstract boolean performFinish(ResourceSet resourceSet, Set<URI> resourceURIs);
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/AbstractNewDecoratorModelPage.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/AbstractNewDecoratorModelPage.java
new file mode 100644
index 00000000000..80da8761be7
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/AbstractNewDecoratorModelPage.java
@@ -0,0 +1,205 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.ui.wizards;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.emf.common.ui.dialogs.WorkspaceResourceDialog;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.papyrus.uml.decoratormodel.helper.DecoratorModelUtils;
+import org.eclipse.papyrus.uml.decoratormodel.internal.resource.DecoratorModelIndex;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.Activator;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.messages.Messages;
+import org.eclipse.papyrus.uml.tools.model.UmlModel;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * @author damus
+ *
+ */
+public abstract class AbstractNewDecoratorModelPage<I, P> extends AbstractProfileApplicationSelectionPage<I, P> {
+ private static final String FILE_EXTENSION_SETTING = "fileExtension"; //$NON-NLS-1$
+
+ private Text resourceText;
+
+ private Text modelNameText;
+
+ private String modelName;
+
+ public AbstractNewDecoratorModelPage(String name, String title, ImageDescriptor icon, Class<P> elementType) {
+ super(name, title, icon, elementType);
+
+ setMessage(Messages.AbstractNewDecoratorModelPage_0);
+ }
+
+ @Override
+ protected int getLayoutColumnCount() {
+ return 3;
+ }
+
+ @Override
+ protected void createAdditionalContents(Composite mainArea) {
+ lead(label(mainArea, Messages.AbstractNewDecoratorModelPage_1), 15);
+ resourceText = new Text(mainArea, SWT.SINGLE | SWT.BORDER);
+ lead(fill(resourceText, true, false), 15);
+ resourceText.setText(defaultResource(getInput()));
+ resourceText.addModifyListener(new ModifyListener() {
+
+ @Override
+ public void modifyText(ModifyEvent e) {
+ validatePage();
+ }
+ });
+
+ Button browse = lead(button(mainArea, Messages.AbstractNewDecoratorModelPage_2), 15);
+ browse.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ browseResource();
+ }
+ });
+
+ label(mainArea, Messages.AbstractNewDecoratorModelPage_3);
+ modelNameText = new Text(mainArea, SWT.SINGLE | SWT.BORDER);
+ span(fill(modelNameText, true, false), 2);
+ modelName = defaultModelName(getInput());
+ modelNameText.addModifyListener(new ModifyListener() {
+
+ @Override
+ public void modifyText(ModifyEvent e) {
+ // Don't capture changes while disabled so that we can restore the user's text
+ if (modelNameText.isEnabled()) {
+ modelName = modelNameText.getText();
+ validatePage();
+ }
+ }
+ });
+ }
+
+ public URI getResourceURI() {
+ String resourcePath = resourceText.getText().trim();
+ return (resourcePath.length() > 0) ? URI.createPlatformResourceURI(resourcePath, true) : null;
+ }
+
+ protected String defaultModelName(I input) {
+ return Messages.AbstractNewDecoratorModelPage_4;
+ }
+
+ public String getModelName() {
+ return modelNameText.getText();
+ }
+
+ protected abstract void browseResource();
+
+ protected void browseResource(String title, String message) {
+ IFile file = WorkspaceResourceDialog.openNewFile(getShell(), title, message, new Path(resourceText.getText().trim()), null);
+ if (file != null) {
+ resourceText.setText(file.getFullPath().toString());
+ }
+ }
+
+ @Override
+ protected void validatePage() {
+ setErrorMessage(null);
+
+ URI resourceURI = getResourceURI();
+ if (resourceURI == null) {
+ setPageComplete(false);
+ } else if (!resourceURI.isPlatformResource()) {
+ setErrorMessage(Messages.AbstractNewDecoratorModelPage_5);
+ setPageComplete(false);
+ } else {
+ IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(resourceURI.toPlatformString(true)));
+ IContainer container = file.getParent();
+
+ if (!container.exists()) {
+ setErrorMessage(NLS.bind(Messages.AbstractNewDecoratorModelPage_6, container.getFullPath().toString()));
+ setPageComplete(false);
+ } else if (!UmlModel.UML_FILE_EXTENSION.equals(resourceURI.fileExtension())) {
+ setErrorMessage(NLS.bind(Messages.AbstractNewDecoratorModelPage_7, UmlModel.UML_FILE_EXTENSION));
+ setPageComplete(false);
+ } else {
+ if (file.exists()) {
+ modelNameText.setEnabled(false);
+
+ String message = validateExistingFile(file);
+ if (message != null) {
+ setErrorMessage(message);
+ setPageComplete(false);
+ } else if (!DecoratorModelUtils.isDecoratorModel(getResourceURI())) {
+ setErrorMessage(Messages.AbstractNewDecoratorModelPage_8);
+ setPageComplete(false);
+ } else {
+ try {
+ modelNameText.setText(DecoratorModelIndex.getInstance().getDecoratorModelName(getResourceURI()));
+ } catch (CoreException e) {
+ Activator.getDefault().getLog().log(e.getStatus());
+ StatusManager.getManager().handle(e.getStatus(), StatusManager.SHOW);
+ }
+ super.validatePage();
+ }
+ } else {
+ // Restore the user's input
+ if (!modelNameText.getText().equals(modelName)) {
+ modelNameText.setText(modelName);
+ }
+ modelNameText.setEnabled(true);
+ super.validatePage();
+ }
+ }
+ }
+ }
+
+ protected String validateExistingFile(IFile file) {
+ return null;
+ }
+
+ protected String getFileExtension() {
+ String result = getDialogSettings().get(FILE_EXTENSION_SETTING);
+ if (result == null) {
+ result = "profileapp.uml"; //$NON-NLS-1$
+ }
+ return result;
+ }
+
+ void saveSettings() {
+ URI uri = getResourceURI();
+ if (uri != null) {
+ String fileExtension = uri.fileExtension();
+ uri = uri.trimFileExtension();
+
+ while (uri.fileExtension() != null) {
+ fileExtension = String.format("%s.%s", uri.fileExtension(), fileExtension); //$NON-NLS-1$
+ uri = uri.trimFileExtension();
+ }
+
+ getDialogSettings().put(FILE_EXTENSION_SETTING, fileExtension);
+ }
+ }
+
+ protected abstract String defaultResource(I input);
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/AbstractProfileApplicationSelectionPage.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/AbstractProfileApplicationSelectionPage.java
new file mode 100644
index 00000000000..95ca65ec091
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/AbstractProfileApplicationSelectionPage.java
@@ -0,0 +1,227 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.ui.wizards;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.CheckStateChangedEvent;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.ICheckStateListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.messages.Messages;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Table;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+
+/**
+ * @author damus
+ *
+ */
+abstract class AbstractProfileApplicationSelectionPage<I, P> extends WizardPage {
+
+ private final Class<P> elementType;
+
+ private CheckboxTableViewer profilesTable;
+
+ private I input;
+
+ private List<P> initialSelections;
+
+ public AbstractProfileApplicationSelectionPage(String name, String title, ImageDescriptor icon, Class<P> elementType) {
+ super(name, title, icon);
+
+ this.elementType = elementType;
+ }
+
+ @Override
+ public void createControl(Composite parent) {
+ Composite main = new Composite(parent, SWT.NONE);
+
+ final int layoutCols = getLayoutColumnCount();
+ main.setLayout(new GridLayout(layoutCols, false));
+
+ span(label(main, Messages.AbstractProfileApplicationSelectionPage_0), layoutCols);
+
+ profilesTable = new CheckboxTableViewer(new Table(main, SWT.CHECK | SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER));
+ span(fill(profilesTable.getTable(), true, true), layoutCols);
+ profilesTable.setContentProvider(createProfilesContentProvider());
+ profilesTable.setLabelProvider(createProfilesLabelProvider());
+ profilesTable.setComparator(new ViewerComparator());
+ profilesTable.setInput(getInput());
+ checkInitialSelections(profilesTable, initialSelections);
+
+ profilesTable.addCheckStateListener(new ICheckStateListener() {
+
+ @Override
+ public void checkStateChanged(CheckStateChangedEvent event) {
+ validatePage();
+ }
+ });
+
+ createSelectionButtons(main);
+
+ createAdditionalContents(main);
+
+ setControl(main);
+
+ validatePage();
+ }
+
+ protected void checkInitialSelections(CheckboxTableViewer table, Collection<P> initialSelections) {
+ if (initialSelections != null) {
+ table.setCheckedElements(initialSelections.toArray());
+ }
+ }
+
+ protected int getLayoutColumnCount() {
+ return 2;
+ }
+
+ protected void createAdditionalContents(Composite mainArea) {
+ // Pass
+ }
+
+ public void setInput(I input) {
+ this.input = input;
+
+ if (profilesTable != null) {
+ profilesTable.setInput(input);
+ }
+ }
+
+ public I getInput() {
+ return input;
+ }
+
+ public void select(Iterable<P> profileApplications) {
+ this.initialSelections = ImmutableList.copyOf(profileApplications);
+
+ if (profilesTable != null) {
+ profilesTable.setCheckedElements(this.initialSelections.toArray());
+ }
+ }
+
+ public List<P> getSelectedProfileApplications() {
+ Object[] raw = profilesTable.getCheckedElements();
+ return ImmutableList.copyOf(Iterables.filter(Arrays.asList(raw), elementType));
+ }
+
+ private void createSelectionButtons(Composite parent) {
+ Composite buttons = new Composite(parent, SWT.NONE);
+ span(buttons, getLayoutColumnCount());
+
+ RowLayout layout = new RowLayout();
+ layout.marginLeft = 0;
+ layout.marginTop = 0;
+ layout.marginRight = 0;
+ layout.marginBottom = 0;
+ buttons.setLayout(layout);
+
+ class ButtonHandler extends SelectionAdapter {
+ final boolean select;
+
+ ButtonHandler(boolean select) {
+ this.select = select;
+ }
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ profilesTable.setAllChecked(select);
+ validatePage();
+ }
+ }
+
+ button(buttons, Messages.AbstractProfileApplicationSelectionPage_1).addSelectionListener(new ButtonHandler(true));
+ button(buttons, Messages.AbstractProfileApplicationSelectionPage_2).addSelectionListener(new ButtonHandler(false));
+ }
+
+ protected abstract IStructuredContentProvider createProfilesContentProvider();
+
+ protected abstract IBaseLabelProvider createProfilesLabelProvider();
+
+ protected void validatePage() {
+ if (profilesTable.getCheckedElements().length == 0) {
+ setPageComplete(false);
+ } else {
+ setPageComplete(true);
+ }
+ }
+
+ static GridData gd(Control c) {
+ GridData result = (GridData) c.getLayoutData();
+ if (result == null) {
+ result = new GridData();
+ c.setLayoutData(result);
+ }
+ return result;
+ }
+
+ static Label label(Composite parent, String text) {
+ Label result = new Label(parent, SWT.NONE);
+ result.setText(text);
+ return result;
+ }
+
+ static Button button(Composite parent, String text) {
+ Button result = new Button(parent, SWT.PUSH);
+ result.setText(text);
+ return result;
+ }
+
+ static <C extends Control> C span(C c, int horizontal) {
+ gd(c).horizontalSpan = horizontal;
+ return c;
+ }
+
+ static <C extends Control> C lead(C c, int dlus) {
+ gd(c).verticalIndent = dlus;
+ return c;
+ }
+
+ static <C extends Control> C fill(C c, boolean horizontal, boolean vertical) {
+ GridData gd = gd(c);
+ if (horizontal) {
+ gd.horizontalAlignment = SWT.FILL;
+ gd.grabExcessHorizontalSpace = true;
+ }
+ if (vertical) {
+ gd.verticalAlignment = SWT.FILL;
+ gd.grabExcessVerticalSpace = true;
+ }
+ return c;
+ }
+
+ static <C extends Control> C align(C c, int align) {
+ GridData gd = gd(c);
+ gd.horizontalAlignment = align;
+ return c;
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/AbstractProfileApplicationsPage.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/AbstractProfileApplicationsPage.java
new file mode 100644
index 00000000000..2fa2d29b40e
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/AbstractProfileApplicationsPage.java
@@ -0,0 +1,36 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.ui.wizards;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.providers.EncapsulatedAdapterFactoryLabelProvider;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.ProfileApplication;
+
+/**
+ * @author damus
+ *
+ */
+abstract class AbstractProfileApplicationsPage extends AbstractProfileApplicationSelectionPage<Package, ProfileApplication> {
+
+ public AbstractProfileApplicationsPage(String name, String title, ImageDescriptor icon) {
+ super(name, title, icon, ProfileApplication.class);
+ }
+
+ @Override
+ protected IBaseLabelProvider createProfilesLabelProvider() {
+ return EncapsulatedAdapterFactoryLabelProvider.appliedProfiles();
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/ConflictingDecoratorModelsPage.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/ConflictingDecoratorModelsPage.java
new file mode 100644
index 00000000000..0d6ea55c379
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/ConflictingDecoratorModelsPage.java
@@ -0,0 +1,216 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.ui.wizards;
+
+import static org.eclipse.papyrus.uml.decoratormodel.internal.ui.wizards.AbstractProfileApplicationsPage.button;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.CoreException;
+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.ecore.util.EcoreUtil;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
+import org.eclipse.papyrus.uml.decoratormodel.helper.DecoratorModelUtils;
+import org.eclipse.papyrus.uml.decoratormodel.internal.resource.DecoratorModelIndex;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.Activator;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.messages.Messages;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.preferences.ProfileExternalizationUIPreferences;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.statushandlers.StatusManager;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.Profile;
+
+import com.google.common.collect.Maps;
+import com.google.common.collect.SetMultimap;
+import com.google.common.collect.Sets;
+import com.google.common.eventbus.EventBus;
+import com.google.common.eventbus.Subscribe;
+
+/**
+ * @author damus
+ *
+ */
+public class ConflictingDecoratorModelsPage extends DecoratorModelSelectionPage {
+ private IFile[] resourcesSelectedForLoad;
+ private IFile[] conflicts;
+ private Button selectConflicts;
+
+ /*
+ * Map of (package -> profile -> application resource).
+ */
+ private Map<URI, Map<URI, URI>> loadedExternalApplications;
+
+ public ConflictingDecoratorModelsPage(EventBus bus) {
+ this(bus, null);
+ }
+
+ public ConflictingDecoratorModelsPage(EventBus bus, ImageDescriptor titleImage) {
+ super("unload", Messages.ConflictingDecoratorModelsPage_0, bus, titleImage); //$NON-NLS-1$
+
+ bus.register(this);
+
+ setMessage(Messages.ConflictingDecoratorModelsPage_1);
+ }
+
+ @Override
+ public void setInput(Package package_, Set<URI> input) {
+ super.setInput(package_, input);
+
+ // Compute the external profile applications already loaded
+ loadedExternalApplications = Maps.newHashMap();
+ ResourceSet rset = EMFHelper.getResourceSet(package_);
+ for (URI next : input) {
+ Resource resource = rset.getResource(next, true);
+ for (Map.Entry<Package, Profile> external : DecoratorModelUtils.getDecoratorProfileApplications(resource).entrySet()) {
+ URI packageURI = EcoreUtil.getURI(external.getKey());
+ Map<URI, URI> profiles = loadedExternalApplications.get(packageURI);
+ if (profiles == null) {
+ profiles = Maps.newHashMap();
+ loadedExternalApplications.put(packageURI, profiles);
+ }
+
+ profiles.put(EcoreUtil.getURI(external.getValue()), next);
+ }
+ }
+
+ conflicts = computeConflicts(resourcesSelectedForLoad);
+
+ validatePage();
+ }
+
+ @Override
+ protected void createSpecialSelectionButtons(Composite parent) {
+ selectConflicts = button(parent, Messages.ConflictingDecoratorModelsPage_2);
+ selectConflicts.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ for (IFile next : conflicts) {
+ table.setChecked(next, true);
+ }
+ validatePage();
+ }
+ });
+
+ if (conflicts != null) {
+ selectConflicts.setEnabled(conflicts.length > 0);
+ }
+ }
+
+ @Override
+ protected void storeDontShowThisPreference(boolean dontShowThisAgain) {
+ ProfileExternalizationUIPreferences.setPromptToUnloadConflicts(!dontShowThisAgain);
+ }
+
+ public Set<URI> getResourcesToUnload() {
+ return filesToURIs(getCheckedFiles());
+ }
+
+ @Subscribe
+ public void resourcesSelectedForLoad(IFile[] resources) {
+ this.resourcesSelectedForLoad = resources;
+ this.conflicts = computeConflicts(resources);
+
+ validatePage();
+ }
+
+ static Set<URI> filesToURIs(IFile[] files) {
+ Set<URI> result = Sets.newHashSet();
+ for (IFile next : files) {
+ result.add(URI.createPlatformResourceURI(next.getFullPath().toString(), true));
+ }
+ return result;
+ }
+
+ protected IFile[] computeConflicts(IFile[] resources) {
+ if ((loadedExternalApplications == null) || (resources == null)) {
+ return new IFile[0];
+ }
+
+ Set<URI> result = Sets.newHashSet();
+ Set<URI> uris = filesToURIs(resources);
+
+ // The input resources are loaded. Which of these apply the same profiles
+ // to the same packages as any of ones to be loaded?
+ for (URI next : uris) {
+ try {
+ SetMultimap<URI, URI> profileApplications = DecoratorModelIndex.getInstance().getAppliedProfilesByPackage(next);
+ for (URI packageURI : profileApplications.keySet()) {
+ Map<URI, URI> existingAppliedProfiles = loadedExternalApplications.get(packageURI);
+ if (existingAppliedProfiles != null) {
+ Set<URI> newProfiles = profileApplications.get(packageURI);
+ for (Map.Entry<URI, URI> profileToResource : existingAppliedProfiles.entrySet()) {
+ if (newProfiles.contains(profileToResource.getKey())) {
+ // This is a conflict
+ result.add(profileToResource.getValue());
+ }
+ }
+ }
+ }
+ } catch (CoreException e) {
+ Activator.getDefault().getLog().log(e.getStatus());
+ StatusManager.getManager().handle(e.getStatus(), StatusManager.SHOW);
+ }
+ }
+
+ // Before we have created the UI, automatically select any conflicts if we are showing
+ // this page as an automatic prompt to unload conflicts
+ if (!result.isEmpty() && showDontShowThis() && !ProfileExternalizationUIPreferences.getPromptToUnloadConflicts() && (table == null)) {
+ select(result);
+ }
+
+ IFile[] conflicts = urisToFilesArray(result);
+ if (selectConflicts != null) {
+ selectConflicts.setEnabled(conflicts.length > 0);
+ }
+
+ return conflicts;
+ }
+
+ boolean anyConflictNotSelected() {
+ boolean result = false;
+
+ Set<IFile> checked = Sets.newHashSet(getCheckedFiles());
+ if (conflicts != null) {
+ for (IFile next : conflicts) {
+ if (!checked.contains(next)) {
+ result = true;
+ break;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ void validatePage() {
+ setErrorMessage(null);
+
+ if (anyConflictNotSelected()) {
+ setErrorMessage(Messages.ConflictingDecoratorModelsPage_3);
+ setPageComplete(false);
+ } else {
+ setPageComplete(true);
+ }
+ }
+
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/DecoratorModelSelectionPage.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/DecoratorModelSelectionPage.java
new file mode 100644
index 00000000000..f2383fbf03c
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/DecoratorModelSelectionPage.java
@@ -0,0 +1,319 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.ui.wizards;
+
+import static org.eclipse.papyrus.uml.decoratormodel.internal.ui.wizards.AbstractProfileApplicationsPage.align;
+import static org.eclipse.papyrus.uml.decoratormodel.internal.ui.wizards.AbstractProfileApplicationsPage.button;
+import static org.eclipse.papyrus.uml.decoratormodel.internal.ui.wizards.AbstractProfileApplicationsPage.fill;
+import static org.eclipse.papyrus.uml.decoratormodel.internal.ui.wizards.AbstractProfileApplicationsPage.label;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.CheckStateChangedEvent;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider;
+import org.eclipse.jface.viewers.ICheckStateListener;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.messages.Messages;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.preferences.ProfileExternalizationUIPreferences;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.providers.DecoratorModelLabelProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.uml2.uml.Package;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+import com.google.common.eventbus.EventBus;
+
+/**
+ * @author damus
+ *
+ */
+public class DecoratorModelSelectionPage extends WizardPage {
+ private boolean showDontShowThis;
+
+ protected CheckboxTableViewer table;
+
+ private ResourceSet resourceSet;
+ private Set<URI> input;
+ private Set<IFile> initialSelections;
+
+ private final EventBus bus;
+
+ public DecoratorModelSelectionPage(EventBus bus) {
+ this(bus, null);
+ }
+
+ public DecoratorModelSelectionPage(EventBus bus, ImageDescriptor titleImage) {
+ this("selection", Messages.DecoratorModelSelectionPage_0, bus, titleImage); //$NON-NLS-1$
+ }
+
+ protected DecoratorModelSelectionPage(String name, String title, EventBus bus, ImageDescriptor titleImage) {
+ super(name, title, titleImage);
+
+ this.bus = bus;
+ }
+
+ @Override
+ public void createControl(Composite parent) {
+ Composite main = new Composite(parent, SWT.NONE);
+ main.setLayout(new GridLayout());
+
+ label(main, Messages.DecoratorModelSelectionPage_1);
+ table = new CheckboxTableViewer(new Table(main, SWT.BORDER | SWT.CHECK | SWT.V_SCROLL | SWT.H_SCROLL));
+ fill(table.getTable(), true, true);
+ table.setLabelProvider(new DelegatingStyledCellLabelProvider(new DecoratorModelLabelProvider(resourceSet)));
+ table.setContentProvider(new AvailableResourcesContentProvider());
+ table.setInput(getInput());
+ if (initialSelections != null) {
+ table.setCheckedElements(Iterables.toArray(initialSelections, IFile.class));
+ }
+ table.addCheckStateListener(new ICheckStateListener() {
+
+ @Override
+ public void checkStateChanged(CheckStateChangedEvent event) {
+ validatePage();
+ }
+ });
+
+ createSelectionButtons(main);
+
+ if (showDontShowThis()) {
+ createPreferenceArea(main);
+ }
+
+ setControl(main);
+
+ validatePage();
+ }
+
+ IFile[] getCheckedFiles() {
+ List<?> checked = (table == null) //
+ ? (initialSelections == null) ? Collections.emptyList() : ImmutableList.copyOf(initialSelections) //
+ : Arrays.asList(table.getCheckedElements());
+ return Iterables.toArray(Iterables.filter(checked, IFile.class), IFile.class);
+ }
+
+ protected void createSelectionButtons(Composite parent) {
+ Composite buttons = new Composite(parent, SWT.NONE);
+ align(buttons, SWT.TRAIL);
+
+ RowLayout layout = new RowLayout();
+ layout.marginLeft = 0;
+ layout.marginTop = 0;
+ layout.marginRight = 0;
+ layout.marginBottom = 0;
+ buttons.setLayout(layout);
+
+ createSpecialSelectionButtons(buttons);
+
+ class ButtonHandler extends SelectionAdapter {
+ final boolean select;
+
+ ButtonHandler(boolean select) {
+ this.select = select;
+ }
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ table.setAllChecked(select);
+ validatePage();
+ }
+ }
+
+ button(buttons, Messages.DecoratorModelSelectionPage_2).addSelectionListener(new ButtonHandler(true));
+ button(buttons, Messages.DecoratorModelSelectionPage_3).addSelectionListener(new ButtonHandler(false));
+ }
+
+ protected void createSpecialSelectionButtons(Composite buttons) {
+ // Pass
+ }
+
+ protected void createPreferenceArea(Composite parent) {
+ final boolean[] preference = { false };
+ final Button dontShowThisButton = new Button(parent, SWT.CHECK);
+ dontShowThisButton.setText(Messages.DecoratorModelSelectionPage_4);
+
+ dontShowThisButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ preference[0] = dontShowThisButton.getSelection();
+ }
+ });
+ dontShowThisButton.getShell().addDisposeListener(new DisposeListener() {
+
+ @Override
+ public void widgetDisposed(DisposeEvent e) {
+ storeDontShowThisPreference(preference[0]);
+ }
+ });
+ }
+
+ protected void storeDontShowThisPreference(boolean dontShowThisAgain) {
+ ProfileExternalizationUIPreferences.setAutoPromptToLoadProfileApplications(!dontShowThisAgain);
+ }
+
+ public void setIsAutomaticPrompt(boolean autoPrompt) {
+ showDontShowThis = autoPrompt;
+ }
+
+ protected boolean showDontShowThis() {
+ return showDontShowThis;
+ }
+
+ public void setInput(Package package_, Set<URI> input) {
+ this.input = input;
+
+ if (package_ != null) {
+ resourceSet = EMFHelper.getResourceSet(package_);
+ }
+
+ if (table != null) {
+ table.setInput(input);
+ }
+
+ validatePage();
+ }
+
+ public Set<URI> getInput() {
+ return input;
+ }
+
+ public void select(Iterable<URI> resources) {
+ Set<IFile> files = urisToFiles(resources);
+ if (!files.equals(this.initialSelections)) {
+ this.initialSelections = urisToFiles(resources);
+
+ if (table != null) {
+ table.setCheckedElements(Iterables.toArray(files, IFile.class));
+ }
+
+ bus.post(initialSelections);
+
+ validatePage();
+ }
+ }
+
+ void validatePage() {
+ setErrorMessage(null);
+ IFile[] checked = getCheckedFiles();
+ bus.post(getCheckedFiles());
+
+ if ((input == null) || input.isEmpty()) {
+ setErrorMessage(Messages.DecoratorModelSelectionPage_5);
+ setPageComplete(false);
+ } else if (checked.length == 0) {
+ setPageComplete(false);
+ } else {
+ setPageComplete(true);
+ }
+ }
+
+ static Set<IFile> urisToFiles(Iterable<URI> uris) {
+ Set<IFile> result = Sets.newLinkedHashSet();
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ for (URI next : uris) {
+ if (next.isPlatformResource()) {
+ IFile file = root.getFile(new Path(next.toPlatformString(true)));
+ if ((file != null) && file.exists()) {
+ result.add(file);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ static IFile[] urisToFilesArray(Iterable<URI> uris) {
+ return Iterables.toArray(urisToFiles(uris), IFile.class);
+ }
+
+ //
+ // Nested types
+ //
+
+ static class AvailableResourcesContentProvider implements ITreeContentProvider {
+ private final IFile[] none = {};
+
+ @Override
+ public Object[] getElements(Object inputElement) {
+ IFile[] result = none;
+
+ if (inputElement instanceof Collection<?>) {
+ result = urisToFilesArray(Iterables.filter((Collection<?>) inputElement, URI.class));
+ Arrays.sort(result, new Comparator<IFile>() {
+ @Override
+ public int compare(IFile o1, IFile o2) {
+ return o1.getName().compareTo(o2.getName());
+ }
+ });
+ }
+
+ return result;
+ }
+
+ @Override
+ public void dispose() {
+ // Pass
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ // Pass
+ }
+
+ @Override
+ public Object[] getChildren(Object parentElement) {
+ // There is no tree structure
+ return none;
+ }
+
+ @Override
+ public Object getParent(Object element) {
+ // There is no tree structure
+ return null;
+ }
+
+ @Override
+ public boolean hasChildren(Object element) {
+ // There is no tree structure
+ return false;
+ }
+ }
+
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/DuplicateDecoratorModelPage.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/DuplicateDecoratorModelPage.java
new file mode 100644
index 00000000000..c2790ba67e3
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/DuplicateDecoratorModelPage.java
@@ -0,0 +1,176 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.ui.wizards;
+
+import java.util.Collection;
+import java.util.Set;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.emf.common.util.TreeIterator;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.papyrus.uml.decoratormodel.internal.resource.DecoratorModelIndex;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.Activator;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.messages.Messages;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.providers.ProfileResourceLabelProvider;
+import org.eclipse.ui.statushandlers.StatusManager;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.ProfileApplication;
+import org.eclipse.uml2.uml.UMLPackage;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+
+/**
+ * @author damus
+ *
+ */
+public class DuplicateDecoratorModelPage extends AbstractNewDecoratorModelPage<Object, URI> {
+ private final ResourceSet resourceSet;
+
+ public DuplicateDecoratorModelPage(ResourceSet resourceSet) {
+ super("duplicate", Messages.DuplicateDecoratorModelPage_0, null, URI.class); //$NON-NLS-1$
+
+ this.resourceSet = resourceSet;
+
+ setMessage(Messages.DuplicateDecoratorModelPage_1);
+ }
+
+ @Override
+ protected void checkInitialSelections(CheckboxTableViewer table, Collection<URI> initialSelections) {
+ table.setAllChecked(true);
+ }
+
+ @Override
+ protected void browseResource() {
+ browseResource(Messages.DuplicateDecoratorModelPage_2, Messages.DuplicateDecoratorModelPage_3);
+ }
+
+ @Override
+ protected IBaseLabelProvider createProfilesLabelProvider() {
+ return new DelegatingStyledCellLabelProvider(new ProfileResourceLabelProvider(resourceSet));
+ }
+
+ @Override
+ protected IStructuredContentProvider createProfilesContentProvider() {
+ return new IStructuredContentProvider() {
+
+ @Override
+ public Object[] getElements(Object inputElement) {
+ Set<URI> result = Sets.newLinkedHashSet();
+
+ if (inputElement instanceof Resource) {
+ Resource decoratorModelResource = (Resource) inputElement;
+ for (TreeIterator<EObject> iter = EcoreUtil.getAllContents(getRoot(decoratorModelResource).getNestedPackages()); iter.hasNext();) {
+ EObject next = iter.next();
+ if (next instanceof ProfileApplication) {
+ EObject profile = (EObject) next.eGet(UMLPackage.Literals.PROFILE_APPLICATION__APPLIED_PROFILE, false);
+ if (profile != null) {
+ // Add the URI of the resource containing the applied profile
+ result.add(EcoreUtil.getURI(profile).trimFragment());
+ }
+ iter.prune();
+ } else if (!(next instanceof Package)) {
+ iter.prune();
+ }
+ }
+ } else if (inputElement instanceof URI) {
+ URI decoratorModelURI = (URI) inputElement;
+ try {
+ for (URI next : DecoratorModelIndex.getInstance().getAppliedProfilesByPackage(decoratorModelURI).values()) {
+ // Add the URI of the resource containing the applied profile
+ result.add(next.trimFragment());
+ }
+ } catch (CoreException e) {
+ StatusManager.getManager().handle(e.getStatus(), StatusManager.SHOW | StatusManager.LOG);
+ }
+ }
+
+ return result.toArray();
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ // Pass
+ }
+
+ @Override
+ public void dispose() {
+ // Pass
+ }
+ };
+ }
+
+ Package getRoot(Resource resource) {
+ return Iterables.getFirst(Iterables.filter(resource.getContents(), Package.class), null);
+ }
+
+ @Override
+ protected String validateExistingFile(IFile file) {
+ return NLS.bind(Messages.DuplicateDecoratorModelPage_4, file.getFullPath());
+ }
+
+ @Override
+ protected String defaultModelName(Object input) {
+ String result = null;
+ if (input instanceof Resource) {
+ Resource resource = (Resource) input;
+ result = NLS.bind(Messages.DuplicateDecoratorModelPage_5, getRoot(resource).getName());
+ } else {
+ try {
+ result = NLS.bind(Messages.DuplicateDecoratorModelPage_5, DecoratorModelIndex.getInstance().getDecoratorModelName((URI) input));
+ } catch (CoreException e) {
+ Activator.getDefault().getLog().log(e.getStatus());
+ result = Messages.DuplicateDecoratorModelPage_7;
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ protected String defaultResource(Object input) {
+ URI result;
+
+ if (input instanceof Resource) {
+ Resource resource = (Resource) input;
+ result = resource.getURI();
+ } else {
+ result = (URI) input;
+ }
+
+ String baseName = result.lastSegment();
+ String ext = ""; //$NON-NLS-1$
+ int dot = baseName.indexOf('.');
+
+ if (dot >= 0) {
+ ext = baseName.substring(dot);
+ baseName = baseName.substring(0, dot);
+ }
+
+ result = result.trimSegments(1).appendSegment(NLS.bind(Messages.DuplicateDecoratorModelPage_6, baseName, ext));
+
+ return result.toPlatformString(true);
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/DuplicateDecoratorModelWizard.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/DuplicateDecoratorModelWizard.java
new file mode 100644
index 00000000000..0f4603f749f
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/DuplicateDecoratorModelWizard.java
@@ -0,0 +1,156 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.ui.wizards;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collections;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.jface.dialogs.DialogSettings;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.papyrus.infra.tools.util.ICallableWithProgress;
+import org.eclipse.papyrus.infra.tools.util.UIUtil;
+import org.eclipse.papyrus.uml.decoratormodel.helper.DecoratorModelUtils;
+import org.eclipse.papyrus.uml.decoratormodel.internal.resource.DecoratorModelCopier;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.Activator;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.messages.Messages;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * A wizard for duplication of an existing loaded or unloaded decorator model.
+ */
+public class DuplicateDecoratorModelWizard extends Wizard {
+
+ private ResourceSet resourceSet;
+
+ private Object decoratorModel;
+
+ private DuplicateDecoratorModelPage mainPage;
+
+ public DuplicateDecoratorModelWizard() {
+ super();
+
+ setWindowTitle(Messages.DuplicateDecoratorModelWizard_0);
+ setDialogSettings(DialogSettings.getOrCreateSection(Activator.getDefault().getDialogSettings(), getClass().getSimpleName()));
+ }
+
+ public void init(ResourceSet resourceSet, Object decoratorModel) {
+ this.resourceSet = resourceSet;
+ this.decoratorModel = decoratorModel;
+
+ if (mainPage != null) {
+ mainPage.setInput(decoratorModel);
+ }
+ }
+
+ @Override
+ public void addPages() {
+ mainPage = new DuplicateDecoratorModelPage(resourceSet);
+ addPage(mainPage);
+ mainPage.setInput(decoratorModel);
+ }
+
+ @Override
+ public boolean needsProgressMonitor() {
+ return true;
+ }
+
+ @Override
+ public boolean performFinish() {
+ boolean result = false;
+
+ mainPage.saveSettings();
+
+ final Set<URI> profileURIs = ImmutableSet.copyOf(mainPage.getSelectedProfileApplications());
+ final URI resourceURI = mainPage.getResourceURI();
+ final String modelName = mainPage.getModelName();
+
+ if (!profileURIs.isEmpty() && (resourceURI != null)) {
+ try {
+ result = UIUtil.call(getContainer(), false, false, new ICallableWithProgress<Boolean>() {
+
+ @Override
+ public Boolean call(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+ boolean result = false;
+
+ final ResourceSet resourceSet;
+ final URI decoratorModelURI;
+
+ monitor.beginTask(Messages.DuplicateDecoratorModelWizard_1, IProgressMonitor.UNKNOWN);
+ try {
+ if (decoratorModel instanceof Resource) {
+ Resource unload = (Resource) decoratorModel;
+ resourceSet = unload.getResourceSet();
+ decoratorModelURI = unload.getURI();
+ if (!UnloadProfileApplicationsWizard.unload(resourceSet, Collections.singleton(unload.getURI()))) {
+ // Bail
+ return false;
+ }
+ } else {
+ resourceSet = null;
+ decoratorModelURI = (URI) decoratorModel;
+ }
+
+ try {
+ result = copy(decoratorModelURI, resourceURI, modelName, profileURIs);
+
+ if (result && (resourceSet != null)) {
+ // Switch to the new copy
+ DecoratorModelUtils.loadDecoratorModels(resourceSet, Collections.singleton(resourceURI));
+ }
+ } catch (IOException e) {
+ throw new InvocationTargetException(e);
+ }
+ } finally {
+ monitor.done();
+ }
+
+ return result;
+ }
+ });
+ } catch (InterruptedException e) {
+ // Pass
+ } catch (InvocationTargetException e) {
+ IStatus status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.DuplicateDecoratorModelWizard_2, e.getTargetException());
+ StatusManager.getManager().handle(status, StatusManager.SHOW | StatusManager.LOG);
+ }
+ }
+
+ return result;
+ }
+
+ private boolean copy(URI sourceModel, URI destinationModel, String modelName, Set<URI> profileURIs) throws IOException {
+ boolean result = false;
+
+ DecoratorModelCopier copier = new DecoratorModelCopier(modelName, profileURIs);
+ try {
+ Resource destination = copier.copy(sourceModel, destinationModel);
+ destination.save(null);
+ result = true;
+ } finally {
+ copier.dispose();
+ }
+
+ return result;
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/ExternalizeProfileApplicationsPage.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/ExternalizeProfileApplicationsPage.java
new file mode 100644
index 00000000000..2b60d9feb68
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/ExternalizeProfileApplicationsPage.java
@@ -0,0 +1,143 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.ui.wizards;
+
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.papyrus.uml.decoratormodel.helper.DecoratorModelUtils;
+import org.eclipse.papyrus.uml.decoratormodel.internal.resource.DecoratorModelIndex;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.Activator;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.messages.Messages;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.providers.EncapsulatedAdapterFactoryLabelProvider;
+import org.eclipse.uml2.common.util.UML2Util;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.Profile;
+import org.eclipse.uml2.uml.ProfileApplication;
+
+import com.google.common.collect.Lists;
+
+/**
+ * @author damus
+ *
+ */
+public class ExternalizeProfileApplicationsPage extends AbstractNewDecoratorModelPage<Package, ProfileApplication> {
+ public ExternalizeProfileApplicationsPage() {
+ super("externalize", Messages.ExternalizeProfileApplicationsPage_0, null, ProfileApplication.class); //$NON-NLS-1$
+
+ setMessage(Messages.ExternalizeProfileApplicationsPage_1);
+ }
+
+ @Override
+ protected void browseResource() {
+ browseResource(Messages.ExternalizeProfileApplicationsPage_2, Messages.ExternalizeProfileApplicationsPage_3);
+ }
+
+ @Override
+ protected IBaseLabelProvider createProfilesLabelProvider() {
+ return EncapsulatedAdapterFactoryLabelProvider.appliedProfiles();
+ }
+
+ @Override
+ protected IStructuredContentProvider createProfilesContentProvider() {
+ return new IStructuredContentProvider() {
+
+ @Override
+ public Object[] getElements(Object inputElement) {
+ Object[] result = null;
+
+ if (inputElement instanceof Package) {
+ Package package_ = (Package) inputElement;
+ List<ProfileApplication> profileApplications = Lists.newArrayList();
+
+ for (ProfileApplication next : package_.getProfileApplications()) {
+ Profile profile = next.getAppliedProfile();
+
+ if ((profile != null) && !profile.eIsProxy()) {
+ profileApplications.add(next);
+ }
+ }
+
+ result = profileApplications.toArray();
+ }
+
+ return (result == null) ? new Object[0] : result;
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ // Pass
+ }
+
+ @Override
+ public void dispose() {
+ // Pass
+ }
+ };
+ }
+
+ @Override
+ protected String validateExistingFile(IFile file) {
+ String result = null;
+
+ String conflictingProfile = null;
+ if (!DecoratorModelUtils.isDecoratorModel(getResourceURI())) {
+ result = Messages.ExternalizeProfileApplicationsPage_4;
+ } else if ((conflictingProfile = findProfileApplication(file)) != null) {
+ result = NLS.bind(Messages.ExternalizeProfileApplicationsPage_5, conflictingProfile, getInput().getName());
+ }
+
+ return result;
+ }
+
+ private String findProfileApplication(IFile decoratorModel) {
+ URI decoratorModelURI = URI.createPlatformResourceURI(decoratorModel.getFullPath().toString(), true);
+ String result = null;
+
+ try {
+ Set<URI> applied = DecoratorModelIndex.getInstance().getAppliedProfiles(EcoreUtil.getURI(getInput()), decoratorModelURI);
+ for (ProfileApplication profileApplication : getSelectedProfileApplications()) {
+ if (applied.contains(EcoreUtil.getURI(profileApplication.getAppliedProfile()))) {
+ result = profileApplication.getAppliedProfile().getName();
+ }
+ }
+ } catch (CoreException e) {
+ Activator.getDefault().getLog().log(e.getStatus());
+ }
+
+ return result;
+ }
+
+ @Override
+ protected String defaultResource(Package package_) {
+ String resourceName = (package_ == null) ? "" : UML2Util.getValidJavaIdentifier(package_.getName()); //$NON-NLS-1$
+ if ((resourceName.length() > 0) && Character.isUpperCase(resourceName.charAt(0))) {
+ resourceName = Character.toLowerCase(resourceName.charAt(0)) + resourceName.substring(1);
+ }
+
+ IPath result = new Path(package_.eResource().getURI().toPlatformString(true)).removeLastSegments(1).append(resourceName).addFileExtension(getFileExtension());
+
+ return result.toString();
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/ExternalizeProfileApplicationsWizard.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/ExternalizeProfileApplicationsWizard.java
new file mode 100644
index 00000000000..8e8bd4428e7
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/ExternalizeProfileApplicationsWizard.java
@@ -0,0 +1,138 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.ui.wizards;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.transaction.util.TransactionUtil;
+import org.eclipse.jface.dialogs.DialogSettings;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
+import org.eclipse.papyrus.uml.decoratormodel.helper.DecoratorModelUtils;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.Activator;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.messages.Messages;
+import org.eclipse.ui.ISelectionListener;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkbenchWizard;
+import org.eclipse.ui.views.properties.PropertySheet;
+import org.eclipse.ui.views.properties.PropertyShowInContext;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.ProfileApplication;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * @author damus
+ *
+ */
+public class ExternalizeProfileApplicationsWizard extends Wizard implements IWorkbenchWizard {
+ static final String PROPERTY_SHEET_VIEW_ID = "org.eclipse.ui.views.PropertySheet"; //$NON-NLS-1$
+
+ private IWorkbenchWindow workbenchWindow;
+
+ private Package package_;
+
+ private ExternalizeProfileApplicationsPage mainPage;
+
+ private List<ProfileApplication> initialSelections;
+
+ public ExternalizeProfileApplicationsWizard() {
+ super();
+
+ setWindowTitle(Messages.ExternalizeProfileApplicationsWizard_0);
+ setDialogSettings(DialogSettings.getOrCreateSection(Activator.getDefault().getDialogSettings(), getClass().getSimpleName()));
+ }
+
+ @Override
+ public void init(IWorkbench workbench, IStructuredSelection selection) {
+ workbenchWindow = workbench.getActiveWorkbenchWindow();
+
+ EObject eObject = EMFHelper.getEObject(selection.getFirstElement());
+ if (eObject instanceof Package) {
+ init((Package) eObject, Collections.<ProfileApplication> emptyList());
+ }
+ }
+
+ public void init(Package package_, Iterable<ProfileApplication> initialSelections) {
+ this.package_ = package_;
+ this.initialSelections = ImmutableList.copyOf(initialSelections);
+
+ if (mainPage != null) {
+ mainPage.setInput(package_);
+ mainPage.select(initialSelections);
+ }
+
+ if (workbenchWindow == null) {
+ workbenchWindow = Activator.getActiveWorkbenchWindow();
+ }
+ }
+
+ @Override
+ public void addPages() {
+ mainPage = new ExternalizeProfileApplicationsPage();
+ addPage(mainPage);
+ mainPage.setInput(package_);
+ mainPage.select(initialSelections);
+ }
+
+ @Override
+ public boolean performFinish() {
+ boolean result = false;
+
+ mainPage.saveSettings();
+
+ List<ProfileApplication> profileApplications = mainPage.getSelectedProfileApplications();
+ URI resourceURI = mainPage.getResourceURI();
+ String modelName = mainPage.getModelName();
+
+ if (!profileApplications.isEmpty() && (resourceURI != null)) {
+ Command command = DecoratorModelUtils.createSeparateProfileApplicationsCommand(profileApplications, resourceURI, modelName);
+ TransactionUtil.getEditingDomain(package_).getCommandStack().execute(command);
+
+ result = true;
+
+ refreshPropertySheet();
+ }
+
+ return result;
+ }
+
+ private void refreshPropertySheet() {
+ if (workbenchWindow != null) {
+ // Refresh the Properties view in case it wasn't showing the decorator models tab
+ PropertySheet propertiesView = (PropertySheet) workbenchWindow.getActivePage().findView(PROPERTY_SHEET_VIEW_ID);
+ if (propertiesView != null) {
+ PropertyShowInContext context = (PropertyShowInContext) propertiesView.getShowInContext();
+ if ((context != null) && (context.getSelection() instanceof IStructuredSelection) && (propertiesView.getCurrentPage() instanceof ISelectionListener)) {
+ ISelectionListener page = (ISelectionListener) propertiesView.getCurrentPage();
+ IStructuredSelection selection = (IStructuredSelection) context.getSelection();
+
+ // The Tabbed Property Sheet page ignores the selection if it's the same as before
+ page.selectionChanged(context.getPart(), StructuredSelection.EMPTY);
+
+ // The XWT tab descriptor remembers the previous selection and just returns the cache
+ // of tabs if it gets that same selection instance again, so create a new one for it
+ page.selectionChanged(context.getPart(), new StructuredSelection(selection.toArray()));
+ }
+ }
+ }
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/InternalizeProfileApplicationsPage.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/InternalizeProfileApplicationsPage.java
new file mode 100644
index 00000000000..157a18e454e
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/InternalizeProfileApplicationsPage.java
@@ -0,0 +1,76 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.ui.wizards;
+
+import java.util.List;
+
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.papyrus.uml.decoratormodel.helper.DecoratorModelUtils;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.messages.Messages;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.Profile;
+import org.eclipse.uml2.uml.ProfileApplication;
+
+import com.google.common.collect.Lists;
+
+/**
+ * @author damus
+ *
+ */
+public class InternalizeProfileApplicationsPage extends AbstractProfileApplicationsPage {
+
+ public InternalizeProfileApplicationsPage() {
+ super("internalize", Messages.InternalizeProfileApplicationsPage_0, null); //$NON-NLS-1$
+ }
+
+ @Override
+ protected IStructuredContentProvider createProfilesContentProvider() {
+ return new IStructuredContentProvider() {
+
+ @Override
+ public Object[] getElements(Object inputElement) {
+ Object[] result = null;
+
+ if (inputElement instanceof Package) {
+ Package package_ = (Package) inputElement;
+ List<ProfileApplication> profileApplications = Lists.newArrayList();
+
+ for (ProfileApplication next : DecoratorModelUtils.getDecoratorModelProfileApplications(package_)) {
+ Profile profile = next.getAppliedProfile();
+
+ if ((profile != null) && !profile.eIsProxy()) {
+ profileApplications.add(next);
+ }
+ }
+
+ result = profileApplications.toArray();
+ }
+
+ return (result == null) ? new Object[0] : result;
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ // Pass
+ }
+
+ @Override
+ public void dispose() {
+ // Pass
+ }
+ };
+ }
+
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/InternalizeProfileApplicationsWizard.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/InternalizeProfileApplicationsWizard.java
new file mode 100644
index 00000000000..01a65f04411
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/InternalizeProfileApplicationsWizard.java
@@ -0,0 +1,83 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.ui.wizards;
+
+import java.util.List;
+
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.transaction.util.TransactionUtil;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
+import org.eclipse.papyrus.uml.decoratormodel.helper.DecoratorModelUtils;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.messages.Messages;
+import org.eclipse.papyrus.uml.decoratormodel.ui.providers.DeleteEmptyDecoratorModelsPolicy;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchWizard;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.ProfileApplication;
+
+/**
+ * @author damus
+ *
+ */
+public class InternalizeProfileApplicationsWizard extends Wizard implements IWorkbenchWizard {
+
+ private Package package_;
+
+ private InternalizeProfileApplicationsPage mainPage;
+
+ public InternalizeProfileApplicationsWizard() {
+ super();
+
+ setWindowTitle(Messages.InternalizeProfileApplicationsWizard_0);
+ }
+
+ @Override
+ public void init(IWorkbench workbench, IStructuredSelection selection) {
+ EObject eObject = EMFHelper.getEObject(selection.getFirstElement());
+ if (eObject instanceof Package) {
+ package_ = (Package) eObject;
+
+ if (mainPage != null) {
+ mainPage.setInput(package_);
+ }
+ }
+ }
+
+ @Override
+ public void addPages() {
+ mainPage = new InternalizeProfileApplicationsPage();
+ addPage(mainPage);
+ mainPage.setInput(package_);
+ }
+
+ @Override
+ public boolean performFinish() {
+ boolean result = false;
+
+ List<ProfileApplication> profileApplications = mainPage.getSelectedProfileApplications();
+
+ if (!profileApplications.isEmpty()) {
+ Command command = DecoratorModelUtils.createReclaimProfileApplicationsCommand(profileApplications, new DeleteEmptyDecoratorModelsPolicy(getShell()));
+ TransactionUtil.getEditingDomain(package_).getCommandStack().execute(command);
+
+ result = true;
+ }
+
+ return result;
+ }
+
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/LoadDecoratorModelsPage.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/LoadDecoratorModelsPage.java
new file mode 100644
index 00000000000..7806505efc1
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/LoadDecoratorModelsPage.java
@@ -0,0 +1,120 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.ui.wizards;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.papyrus.uml.decoratormodel.internal.resource.DecoratorModelIndex;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.Activator;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.messages.Messages;
+import org.eclipse.ui.statushandlers.StatusManager;
+import org.eclipse.uml2.uml.Package;
+
+import com.google.common.collect.Maps;
+import com.google.common.collect.SetMultimap;
+import com.google.common.collect.Sets;
+import com.google.common.eventbus.EventBus;
+
+/**
+ * @author damus
+ *
+ */
+public class LoadDecoratorModelsPage extends DecoratorModelSelectionPage {
+
+ /*
+ * Map of (decorator model -> package -> profiles).
+ */
+ private Map<IFile, SetMultimap<URI, URI>> externalApplications;
+
+ public LoadDecoratorModelsPage(EventBus bus) {
+ super(bus);
+ }
+
+ @Override
+ public void setInput(Package package_, Set<URI> input) {
+ super.setInput(package_, input);
+
+ // Compute the external profile applications available
+ externalApplications = Maps.newHashMap();
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ for (URI profileApplicationResource : input) {
+ IFile file = root.getFile(new Path(profileApplicationResource.toPlatformString(true)));
+
+ try {
+ SetMultimap<URI, URI> profileApplications = DecoratorModelIndex.getInstance().getAppliedProfilesByPackage(profileApplicationResource);
+ externalApplications.put(file, profileApplications);
+ } catch (CoreException e) {
+ Activator.getDefault().getLog().log(e.getStatus());
+ StatusManager.getManager().handle(e.getStatus(), StatusManager.SHOW);
+ }
+ }
+ }
+
+ protected String computeConflict() {
+ String result = null;
+
+ IFile[] selected = getCheckedFiles();
+ if (selected.length > 1) {
+ out: for (int i = 0; i < selected.length; i++) {
+ IFile a = selected[i];
+ SetMultimap<URI, URI> applicationsFromA = externalApplications.get(a);
+ for (int j = i + 1; j < selected.length; j++) {
+ IFile b = selected[j];
+ SetMultimap<URI, URI> applicationsFromB = externalApplications.get(b);
+ if (intersect(applicationsFromA, applicationsFromB)) {
+ result = NLS.bind(Messages.LoadDecoratorModelsPage_0, a.getName(), b.getName());
+ break out;
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ static <K, V> boolean intersect(SetMultimap<K, V> a, SetMultimap<K, V> b) {
+ boolean result = false;
+
+ for (K next : a.keySet()) {
+ if (!Sets.intersection(a.get(next), b.get(next)).isEmpty()) {
+ result = true;
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ void validatePage() {
+ setErrorMessage(null);
+
+ String conflict = computeConflict();
+ if (conflict != null) {
+ setErrorMessage(conflict);
+ setPageComplete(false);
+ } else {
+ super.validatePage();
+ }
+ }
+
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/LoadProfileApplicationsWizard.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/LoadProfileApplicationsWizard.java
new file mode 100644
index 00000000000..1bdb368c64d
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/LoadProfileApplicationsWizard.java
@@ -0,0 +1,230 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.ui.wizards;
+
+import java.util.Set;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.jface.dialogs.DialogSettings;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.papyrus.uml.decoratormodel.helper.DecoratorModelUtils;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.messages.Messages;
+import org.eclipse.uml2.uml.Package;
+
+import com.google.common.base.Functions;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+import com.google.common.eventbus.EventBus;
+
+/**
+ * @author damus
+ *
+ */
+public class LoadProfileApplicationsWizard extends AbstractManageProfileApplicationsWizard {
+
+ private static final String SECTION_RESOURCES = "resources"; //$NON-NLS-1$
+ private static final String KEY_AUTO_PROMPT_SELECTIONS = "autoPromptSelections"; //$NON-NLS-1$
+
+ private Set<URI> loadedProfileApplicationResources;
+
+ private ConflictingDecoratorModelsPage conflictsPage;
+
+ private final boolean promptingConflicts;
+
+ public LoadProfileApplicationsWizard(boolean autoPrompt) {
+ this(autoPrompt, false);
+ }
+
+ public LoadProfileApplicationsWizard(boolean autoPrompt, boolean promptingConflicts) {
+ super(autoPrompt);
+
+ this.promptingConflicts = promptingConflicts;
+
+ setWindowTitle(Messages.LoadProfileApplicationsWizard_0);
+ }
+
+ @Override
+ protected DecoratorModelSelectionPage createSelectionPage(EventBus bus) {
+ return new LoadDecoratorModelsPage(bus);
+ }
+
+ @Override
+ protected void configureSelectionPage(DecoratorModelSelectionPage page) {
+ page.setMessage(Messages.LoadProfileApplicationsWizard_1);
+ }
+
+ @Override
+ Set<URI> getAvailableProfileApplicationResources(Package package_) {
+ Set<URI> result = Sets.newHashSet();
+
+ // Collect all available decorator models
+ result.addAll(DecoratorModelUtils.getUnloadedDecoratorModels(package_.eResource()));
+
+ // If we are automatically prompting the user, then do it only for the actual resource being opened
+ if (!isAutoPrompt()) {
+ // Collect available decorator models for loaded sub-units
+ for (Package subUnit : DecoratorModelUtils.getLoadedSubUnitPackages(package_)) {
+ result.addAll(DecoratorModelUtils.getUnloadedDecoratorModels(subUnit.eResource()));
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ protected void createPages(Package package_, EventBus bus) {
+ super.createPages(package_, bus);
+
+ loadedProfileApplicationResources = getLoadedProfileApplicationResources(package_);
+
+ if (needsUnloadConflictsPage()) {
+ // Have potential for conflicts, or at least resources that we can unload
+ conflictsPage = new ConflictingDecoratorModelsPage(bus);
+ conflictsPage.setIsAutomaticPrompt(promptingConflicts);
+ }
+ }
+
+ @Override
+ protected void initPages(Package package_, Iterable<URI> initialSelections) {
+ if (isAutoPrompt() && Iterables.isEmpty(initialSelections)) {
+ // Compute the initial selections
+ initialSelections = getSavedDecoratorsSelection();
+ }
+
+ super.initPages(package_, initialSelections);
+
+ if (conflictsPage != null) {
+ conflictsPage.setInput(package_, loadedProfileApplicationResources);
+ }
+ }
+
+ @Override
+ public void addPages() {
+ super.addPages();
+
+ if (conflictsPage != null) {
+ addPage(conflictsPage);
+ }
+ }
+
+ public boolean needsUnloadConflictsPage() {
+ return (loadedProfileApplicationResources != null) && !loadedProfileApplicationResources.isEmpty();
+ }
+
+ protected Set<URI> getLoadedProfileApplicationResources(Package package_) {
+ Set<Resource> resources = Sets.newHashSet();
+ resources.add(package_.eResource());
+ for (Package next : DecoratorModelUtils.getLoadedSubUnitPackages(package_)) {
+ resources.add(next.eResource());
+ }
+
+ Set<URI> result = Sets.newHashSet();
+
+ for (Resource next : resources) {
+ result.addAll(DecoratorModelUtils.getLoadedDecoratorModels(next));
+ }
+
+ return result;
+ }
+
+ @Override
+ public boolean isComplete() {
+ return super.isComplete() && ((conflictsPage == null) || conflictsPage.isPageComplete());
+ }
+
+ @Override
+ protected boolean performFinish(ResourceSet resourceSet, Set<URI> resourceURIs) {
+ if (conflictsPage != null) {
+ Set<URI> unload = conflictsPage.getResourcesToUnload();
+ if (!unload.isEmpty() && !UnloadProfileApplicationsWizard.unload(resourceSet, unload)) {
+ // Bail
+ return false;
+ }
+ }
+
+ boolean result = DecoratorModelUtils.loadDecoratorModels(resourceSet, resourceURIs);
+
+ if (isAutoPrompt()) {
+ saveDecoratorsSelection(resourceURIs);
+ }
+
+ return result;
+ }
+
+ protected void saveDecoratorsSelection(Set<URI> resourceURIs) {
+ boolean remove = resourceURIs.isEmpty();
+
+ IDialogSettings resourcesSection = getSection(SECTION_RESOURCES, !remove);
+ if (resourcesSection != null) {
+ pruneResourceSections(resourcesSection);
+
+ String resourceURI = getPackage().eResource().getURI().toString();
+
+ IDialogSettings resource = getSection(resourcesSection, resourceURI, !remove);
+ if (resource != null) {
+ if (remove) {
+ resource.put(KEY_AUTO_PROMPT_SELECTIONS, (String[]) null);
+ } else {
+ String[] uris = Iterables.toArray(Iterables.transform(resourceURIs, Functions.toStringFunction()), String.class);
+ resource.put(KEY_AUTO_PROMPT_SELECTIONS, uris);
+ }
+ }
+ }
+ }
+
+ private Set<URI> getSavedDecoratorsSelection() {
+ ImmutableSet.Builder<URI> result = ImmutableSet.builder();
+ IDialogSettings resourcesSection = getSection(SECTION_RESOURCES, false);
+ if (resourcesSection != null) {
+ String resourceURI = getPackage().eResource().getURI().toString();
+ IDialogSettings resource = resourcesSection.getSection(resourceURI);
+ if (resource != null) {
+ String[] uris = resource.getArray(KEY_AUTO_PROMPT_SELECTIONS);
+ if (uris != null) {
+ for (String next : uris) {
+ result.add(URI.createURI(next));
+ }
+ }
+ }
+ }
+
+ return result.build();
+ }
+
+ private void pruneResourceSections(IDialogSettings resourcesSection) {
+ for (IDialogSettings next : resourcesSection.getSections()) {
+ URI uri = URI.createURI(next.getName());
+ boolean exists = false;
+
+ if (uri.isPlatformResource()) {
+ IPath path = new Path(uri.toPlatformString(true));
+ IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(path);
+
+ // If the file's project is closed, assume the file still exists
+ exists = (file != null) && (file.isAccessible() || !file.getProject().isOpen());
+ }
+
+ if (!exists) {
+ ((DialogSettings) resourcesSection).removeSection(next);
+ }
+ }
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/UnloadProfileApplicationsWizard.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/UnloadProfileApplicationsWizard.java
new file mode 100644
index 00000000000..7ac8c273eec
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/internal/ui/wizards/UnloadProfileApplicationsWizard.java
@@ -0,0 +1,93 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.ui.wizards;
+
+import java.util.Set;
+
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.papyrus.uml.decoratormodel.helper.DecoratorModelUtils;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.Activator;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.commands.UnloadDecoratorModelHandler;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.messages.Messages;
+import org.eclipse.ui.statushandlers.StatusManager;
+import org.eclipse.uml2.uml.Package;
+
+import com.google.common.collect.Sets;
+
+/**
+ * @author damus
+ *
+ */
+public class UnloadProfileApplicationsWizard extends AbstractManageProfileApplicationsWizard {
+
+ public UnloadProfileApplicationsWizard() {
+ super(false); // There is no auto-prompt for unload
+
+ setWindowTitle(Messages.UnloadProfileApplicationsWizard_0);
+ }
+
+ @Override
+ protected void configureSelectionPage(DecoratorModelSelectionPage page) {
+ page.setMessage(Messages.UnloadProfileApplicationsWizard_1);
+ }
+
+ @Override
+ Set<URI> getAvailableProfileApplicationResources(Package package_) {
+ Set<URI> result = Sets.newHashSet();
+
+ // Collect all loaded profile application resources for loaded sub-units
+ result.addAll(DecoratorModelUtils.getLoadedDecoratorModels(package_.eResource()));
+ for (Package subUnit : DecoratorModelUtils.getLoadedSubUnitPackages(package_)) {
+ result.addAll(DecoratorModelUtils.getLoadedDecoratorModels(subUnit.eResource()));
+ }
+
+ return result;
+ }
+
+ @Override
+ protected boolean performFinish(final ResourceSet resourceSet, final Set<URI> resourceURIs) {
+ return unload(resourceSet, resourceURIs);
+ }
+
+ static boolean unload(final ResourceSet resourceSet, final Set<URI> resourceURIs) {
+ boolean result = false;
+
+ Set<Resource> toUnload = Sets.newHashSet();
+
+ for (URI uri : resourceURIs) {
+ Resource resource = resourceSet.getResource(uri, false);
+ if ((resource != null) && resource.isLoaded()) {
+ toUnload.add(resource);
+ }
+ }
+
+ if (!toUnload.isEmpty()) {
+ try {
+ UnloadDecoratorModelHandler.unloadResources(Activator.getActiveWorkbenchWindow(), resourceSet, toUnload);
+ result = true;
+ } catch (ExecutionException e) {
+ IStatus status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.UnloadProfileApplicationsWizard_2, e);
+ Activator.getDefault().getLog().log(status);
+ StatusManager.getManager().handle(status, StatusManager.BLOCK);
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/ui/providers/DeleteEmptyDecoratorModelsPolicy.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/ui/providers/DeleteEmptyDecoratorModelsPolicy.java
new file mode 100644
index 00000000000..7d7a53bbba5
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel.ui/src/org/eclipse/papyrus/uml/decoratormodel/ui/providers/DeleteEmptyDecoratorModelsPolicy.java
@@ -0,0 +1,119 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.ui.providers;
+
+import static org.eclipse.papyrus.uml.decoratormodel.internal.ui.preferences.WhenKind.ALWAYS;
+import static org.eclipse.papyrus.uml.decoratormodel.internal.ui.preferences.WhenKind.NEVER;
+
+import java.util.Collection;
+
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.dialogs.MessageDialogWithToggle;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.jface.window.IShellProvider;
+import org.eclipse.jface.window.SameShellProvider;
+import org.eclipse.papyrus.uml.decoratormodel.helper.IDeleteEmptyDecoratorModelsPolicy;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.messages.Messages;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.preferences.ProfileExternalizationUIPreferences;
+import org.eclipse.papyrus.uml.decoratormodel.internal.ui.providers.DecoratorModelLabelProvider;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * UI based policy for deletion of empty decorator models, with the possibility of interactively prompting the user.
+ */
+public class DeleteEmptyDecoratorModelsPolicy implements IDeleteEmptyDecoratorModelsPolicy {
+ private final IShellProvider parentShell;
+
+ public DeleteEmptyDecoratorModelsPolicy(IShellProvider parentShell) {
+ super();
+
+ this.parentShell = parentShell;
+ }
+
+ public DeleteEmptyDecoratorModelsPolicy(Shell parentShell) {
+ this(new SameShellProvider(parentShell));
+ }
+
+ @Override
+ public boolean shouldDeleteDecoratorModels(Collection<? extends Resource> decoratorModels) {
+ boolean result;
+
+ switch (ProfileExternalizationUIPreferences.getDeleteEmptyDecoratorModels()) {
+ case PROMPT:
+ result = promptToDelete(decoratorModels);
+ break;
+ case ALWAYS:
+ result = true;
+ break;
+ case NEVER:
+ default:
+ result = false;
+ break;
+ }
+
+ return result;
+ }
+
+ private boolean promptToDelete(final Collection<? extends Resource> decoratorModels) {
+ MessageDialogWithToggle dlg = new MessageDialogWithToggle(parentShell.getShell(), Messages.DeleteEmptyDecoratorModelsPolicy_0, null, Messages.DeleteEmptyDecoratorModelsPolicy_1,
+ MessageDialog.QUESTION, new String[] { IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL }, 1, Messages.DeleteEmptyDecoratorModelsPolicy_2, false) {
+ @Override
+ protected Control createCustomArea(Composite parent) {
+ Composite custom = new Composite(parent, SWT.NONE);
+ custom.setLayout(new FillLayout());
+ custom.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ TableViewer table = new TableViewer(custom, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
+ table.setContentProvider(ArrayContentProvider.getInstance());
+ table.setLabelProvider(new DelegatingStyledCellLabelProvider(new DecoratorModelLabelProvider()));
+ table.setComparator(new ViewerComparator()); // Label-based sort is fine
+ table.setInput(decoratorModels);
+
+ return custom;
+ }
+ };
+
+ boolean result;
+
+ switch (dlg.open()) {
+ case IDialogConstants.YES_ID:
+ result = true;
+ if (dlg.getToggleState()) {
+ ProfileExternalizationUIPreferences.setDeleteEmptyDecoratorModels(ALWAYS);
+ }
+ break;
+ case IDialogConstants.NO_ID:
+ result = false;
+ if (dlg.getToggleState()) {
+ ProfileExternalizationUIPreferences.setDeleteEmptyDecoratorModels(NEVER);
+ }
+ break;
+ default: // canceled
+ result = false;
+ break;
+ }
+
+ return result;
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/.classpath b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/.classpath
new file mode 100644
index 00000000000..ad32c83a788
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/.project b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/.project
new file mode 100644
index 00000000000..cb1b41de6a3
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.papyrus.uml.decoratormodel</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/.settings/org.eclipse.jdt.core.prefs b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000000..94d61f00da6
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,291 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
+org.eclipse.jdt.core.formatter.comment.line_length=260
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=false
+org.eclipse.jdt.core.formatter.join_wrapped_lines=false
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=260
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=5
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/.settings/org.eclipse.jdt.ui.prefs b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 00000000000..954281dbc31
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,68 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=false
+cleanup.always_use_this_for_non_static_field_access=false
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=false
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=false
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=true
+cleanup.organize_imports=false
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=true
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=false
+cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+cleanup.use_this_for_non_static_method_access=false
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_Papyrus
+cleanup_settings_version=2
+eclipse.preferences.version=1
+formatter_profile=_Papyrus
+formatter_settings_version=12
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=java;javax;org;com;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="false" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * Constructor.\n *\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*****************************************************************************\n * Copyright (c) ${year} CEA LIST and others.\n * \n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * which accompanies this distribution, and is available at\n * http\://www.eclipse.org/legal/epl-v10.html\n *\n * Contributors\:\n * CEA LIST - Initial API and implementation\n * \n *****************************************************************************/\n</template><template autoinsert\="true" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * @author ${user}\n *\n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment">/**\n * ${see_to_overridden}\n *\n * ${tags}\n */</template><template autoinsert\="false" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${see_to_target}\n *\n * ${tags}\n */</template><template autoinsert\="true" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/META-INF/MANIFEST.MF b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/META-INF/MANIFEST.MF
new file mode 100644
index 00000000000..0a20855a793
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/META-INF/MANIFEST.MF
@@ -0,0 +1,39 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-SymbolicName: org.eclipse.papyrus.uml.decoratormodel;singleton:=true
+Bundle-Version: 1.1.0.qualifier
+Bundle-ClassPath: .
+Bundle-Activator: org.eclipse.papyrus.uml.decoratormodel.Activator
+Bundle-Vendor: %providerName
+Bundle-Localization: plugin
+Require-Bundle: org.eclipse.core.runtime,
+ org.eclipse.emf.ecore;bundle-version="2.10.0";visibility:=reexport,
+ org.eclipse.uml2.types;bundle-version="2.0.0";visibility:=reexport,
+ org.eclipse.papyrus.infra.core.log;bundle-version="1.1.0",
+ org.eclipse.uml2.uml;bundle-version="5.1.0";visibility:=reexport,
+ org.eclipse.uml2.common;bundle-version="2.0.0";visibility:=reexport,
+ org.eclipse.papyrus.infra.core;bundle-version="1.1.0",
+ org.eclipse.papyrus.infra.emf;bundle-version="1.1.0",
+ org.eclipse.papyrus.uml.tools.utils;bundle-version="1.1.0",
+ org.eclipse.papyrus.uml.tools;bundle-version="1.1.0",
+ org.eclipse.emf.transaction;bundle-version="1.4.0",
+ com.google.guava;bundle-version="11.0.0",
+ org.eclipse.gmf.runtime.emf.commands.core;bundle-version="1.7.0",
+ org.eclipse.core.expressions;bundle-version="3.4.600",
+ org.eclipse.papyrus.infra.emf.readonly;bundle-version="1.1.0"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Bundle-ActivationPolicy: lazy;exclude:=org.eclipse.papyrus.uml.decoratormodel.internal.expressions
+Export-Package: org.eclipse.papyrus.uml.decoratormodel,
+ org.eclipse.papyrus.uml.decoratormodel.helper,
+ org.eclipse.papyrus.uml.decoratormodel.internal.commands;x-internal:=true,
+ org.eclipse.papyrus.uml.decoratormodel.internal.expressions;x-internal:=true,
+ org.eclipse.papyrus.uml.decoratormodel.internal.messages;x-internal:=true,
+ org.eclipse.papyrus.uml.decoratormodel.internal.providers;x-internal:=true,
+ org.eclipse.papyrus.uml.decoratormodel.internal.resource;x-friends:="org.eclipse.papyrus.uml.decoratormodel.ui,org.eclipse.papyrus.uml.decoratormodel.properties,org.eclipse.papyrus.uml.decoratormodel.controlmode",
+ org.eclipse.papyrus.uml.decoratormodel.internal.resource.index;x-internal:=true,
+ org.eclipse.papyrus.uml.decoratormodel.model,
+ org.eclipse.papyrus.uml.decoratormodel.profileExternalization,
+ org.eclipse.papyrus.uml.decoratormodel.profileExternalization.impl,
+ org.eclipse.papyrus.uml.decoratormodel.profileExternalization.internal.operations;x-internal:=true,
+ org.eclipse.papyrus.uml.decoratormodel.profileExternalization.util
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/about.html b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/about.html
new file mode 100644
index 00000000000..d35d5aed64c
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>June 5, 2007</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
+
+</body>
+</html>
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/build.properties b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/build.properties
new file mode 100644
index 00000000000..aadf93b715a
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/build.properties
@@ -0,0 +1,12 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ about.html,\
+ documentation.pdoc,\
+ plugin.xml,\
+ model/profileExternalization.ecore,\
+ model/ProfileExternalization.profile.uml,\
+ model/ProfileExternalization.profile.genmodel,\
+ plugin.properties
+src.includes = about.html
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/conception.textile b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/conception.textile
new file mode 100644
index 00000000000..d08e0596b42
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/conception.textile
@@ -0,0 +1,43 @@
+
+h1. Conception of the external profile application management module
+
+
+h2. Context
+
+Currently, profile applications are serialized within the same file as the model itself. This feature will enable to serialize profile applications within a dedicated file. This feature will be an option that the user may configure within the Papyrus preferences. If one applies several profiles on a model, each profile application is serialized within its own resource. It has to be possible to switch from one configuration to the other, i.e. either to externalize profile applications or to internalize them.
+Control mode shall be taken into consideration here and should continue to work correctly.
+
+h3. Enable external profile application
+
+The purpose of this task will consist in patching the UML2 component in order this latter can fully support the possibility to apply profiles on UML models by serializing this profile application in a separate file and vice-versa. Papyrus UI has also to be enriched in order to enable the user to configure Papyrus in order to enable or disable this option. The process will be reversible, i.e. profiles would be serializable individually in or out the model resources. In addition, the tool will also support the ability to apply several times the same profile. In case of a profile has been applied several time (values of the stereotype properties would be possibly different in that case), only one profile application is defined as part of the current configuration.
+
+h3. Control mode extension
+
+This task will consist in analyzing the impact of the externalization of profile serialization and update its design in order the control mode can still run correctly in that case. The test set of the control mode will also be extended to cover this new use case.
+
+h2. Thoughts
+
+# currently, the profile application themselves are part of the model (this is a real element in the UML metamodel). the stereotype applications are located in the same resource as the model, at the same level as the model itself. The goal of this module is to separate the stereotype applications from the model resource and to put them in one or several external resources.
+# Several strategies are possible to manage profile applications in external resources. Each profile application can be saved in a separated resource, or all profile applications can have their own resource. This would ease the management of view points on the model (loading or not a given profile would be easy, and so specific domain concepts would be present or not. The sub profiles should also be taken into account: do each sub-profile need its own resource, or the resource is managed by the main profile (example of SysML)
+# The naming of the resource: name of the profile should be present. the name of the UML element on which the profile is applied should be used, in order to be able to have several external resources for the same profile in case of control mode. Should the version of the profile be present also ?
+# integration with the control mode: should one/several new resource be created when splitting the model?
+# integration with rename/copy files
+# integration with copy paste: does the current extension of the copy/paste work with this module?
+# profile migration: when Papyrus detects that a new definition of a profile is available, the migration needs to account for externalized stereotype applications. These must be loaded, converted, and unloaded again if not currently loaded; this is very like the stereotype repair functionality
+# do we really need to be able to store profile applications independently of their applying packages? And multiple applications of the same profile? It should be sufficient to store stereotype applications separately, and perhaps multiple disjoint sets of applications of the same stereotypes from the same profile on the same model elements. What really matters in UML terms is the discovery and loading of a particular set of stereotype applications; the profile application has no value except in determining which stereotypes are applicable in a given scope
+
+h2. Current external mechanism limitations
+
+h3. Stereotype application helper
+
+UML2 module provides a framework for externalization of the stereotype applications, but this mechanism is rather basic. It relies with a singleton helper, referenced in the java system properties. If the externalization is done, it will be done for all components in the installation relying on UML2 metamodel, not only Papyrus models. Moreover, only one Eclipse component can provide a customization. If another component that Papyrus relies on that extension mechanism, only one will work at the same time.
+
+* should be simple to let stereotype application helpers be attached to a resource set
+
+h3. Required extensions
+
+Stereotypes may define required metaclass extensions, which imply that every instance of the extended metaclass in the scope of the profile application must have an application of the stereotype. This is actually enforced by the UML API at run-time; when a profile is applied that has required extensions, the stereotypes are applied to all elements that require them. Also, when an element is attached to the model, all required stereotypes are applied that are not already applied
+
+* the enforcement of required stereotypes is suppressed when loading a model, which means that required stereotype applications can be stored in separate resources and loaded separately
+* a resource containing required stereotype applications may be unloaded. The UML API tolerates required stereotype applications being unapplied in this way
+* for profiles that do not have any required extensions, it is feasible to edit the model without having any stereotype resource loaded. Not so if it has required metaclass extensions, because any attachment/move/reattachment of an element will cause it and all of its contents to have required stereotypes applied. If a stereotype resource is not loaded at the time, then the UML API will think the required stereotypes are unapplied and will try to apply them
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/documentation.pdoc b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/documentation.pdoc
new file mode 100644
index 00000000000..a9948960562
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/documentation.pdoc
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<doc:Documentation xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:doc="http://www.eclipse.org/papyrus/documentation/plugin/documentation" description="Core APIs for management of profile and stereotype applications in external resources">
+ <referent firstName="Christian" lastName="Damus" eMail="give.a.damus@gmail.com" currentCompany="independent"/>
+</doc:Documentation>
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/model/ProfileExternalization.profile.di b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/model/ProfileExternalization.profile.di
new file mode 100644
index 00000000000..bf9abab340f
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/model/ProfileExternalization.profile.di
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI"/>
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/model/ProfileExternalization.profile.genmodel b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/model/ProfileExternalization.profile.genmodel
new file mode 100644
index 00000000000..93e853d2624
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/model/ProfileExternalization.profile.genmodel
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<genmodel:GenModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmlns:genmodel="http://www.eclipse.org/uml2/2.2.0/GenModel"
+ copyrightText="Copyright (c) 2014 Christian W. Damus and others.&#xA;&#xA;All rights reserved. This program and the accompanying materials&#xA;are made available under the terms of the Eclipse Public License v1.0&#xA;which accompanies this distribution, and is available at&#xA;http://www.eclipse.org/legal/epl-v10.html&#xA;&#xA;Contributors:&#xA; Christian W. Damus - Initial API and implementation"
+ modelDirectory="/org.eclipse.papyrus.uml.decoratormodel/src" modelPluginID="org.eclipse.papyrus.uml.decoratormodel"
+ modelName="ProfileExternalization" nonNLSMarkers="true" rootExtendsClass="org.eclipse.emf.ecore.impl.MinimalEObjectImpl$Container"
+ codeFormatting="true" commentFormatting="true" importerID="org.eclipse.uml2.uml.ecore.importer"
+ complianceLevel="6.0" copyrightFields="false" usedGenPackages="../../org.eclipse.emf.ecore/model/Ecore.genmodel#//ecore ../../org.eclipse.uml2.types/model/Types.genmodel#//types ../../org.eclipse.uml2.uml/model/UML.genmodel#//uml"
+ operationReflection="true" importOrganizing="true" cleanup="true" factoryMethods="true"
+ pluralizedGetters="true" cacheAdapterSupport="true" safeStrings="true" invariantPrefix="validate">
+ <genAnnotations source="http://www.eclipse.org/emf/2002/GenModel/importer/org.eclipse.uml2.uml.ecore.importer">
+ <details key="ECORE_TAGGED_VALUES" value="PROCESS"/>
+ <details key="UNION_PROPERTIES" value="PROCESS"/>
+ <details key="UNTYPED_PROPERTIES" value="PROCESS"/>
+ <details key="DUPLICATE_FEATURES" value="PROCESS"/>
+ <details key="SUBSETTING_PROPERTIES" value="PROCESS"/>
+ <details key="VALIDATION_DELEGATES" value="PROCESS"/>
+ <details key="OPPOSITE_ROLE_NAMES" value="PROCESS"/>
+ <details key="COMMENTS" value="PROCESS"/>
+ <details key="DUPLICATE_FEATURE_INHERITANCE" value="PROCESS"/>
+ <details key="DUPLICATE_OPERATIONS" value="PROCESS"/>
+ <details key="PROPERTY_DEFAULT_EXPRESSIONS" value="PROCESS"/>
+ <details key="INVARIANT_CONSTRAINTS" value="PROCESS"/>
+ <details key="REDEFINING_PROPERTIES" value="PROCESS"/>
+ <details key="ANNOTATION_DETAILS" value="PROCESS"/>
+ <details key="NON_API_INVARIANTS" value="PROCESS"/>
+ <details key="DUPLICATE_OPERATION_INHERITANCE" value="PROCESS"/>
+ <details key="REDEFINING_OPERATIONS" value="PROCESS"/>
+ <details key="INVOCATION_DELEGATES" value="PROCESS"/>
+ <details key="DERIVED_FEATURES" value="PROCESS"/>
+ <details key="OPERATION_BODIES" value="PROCESS"/>
+ <details key="CAMEL_CASE_NAMES" value="IGNORE"/>
+ <details key="SUPER_CLASS_ORDER" value="PROCESS"/>
+ </genAnnotations>
+ <foreignModel>ProfileExternalization.profile.uml</foreignModel>
+ <genPackages xsi:type="genmodel:GenPackage" prefix="ProfileExternalization" basePackage="org.eclipse.papyrus.uml.decoratormodel"
+ disposableProviderFactory="true" fileExtensions="profileext" ecorePackage="profileExternalization.ecore#/"
+ operationsPackage="org.eclipse.papyrus.uml.decoratormodel.profileExternalization.internal.operations">
+ <genClasses xsi:type="genmodel:GenClass" ecoreClass="profileExternalization.ecore#//ApplyProfiles">
+ <genFeatures xsi:type="genmodel:GenFeature" notify="false" createChild="false"
+ propertySortChoices="true" ecoreFeature="ecore:EReference profileExternalization.ecore#//ApplyProfiles/base_Dependency"/>
+ <genOperations xsi:type="genmodel:GenOperation" ecoreOperation="profileExternalization.ecore#//ApplyProfiles/getAppliedProfiles"/>
+ <genOperations xsi:type="genmodel:GenOperation" ecoreOperation="profileExternalization.ecore#//ApplyProfiles/getExternalizedAppliedProfilePackages"/>
+ </genClasses>
+ </genPackages>
+</genmodel:GenModel>
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/model/ProfileExternalization.profile.notation b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/model/ProfileExternalization.profile.notation
new file mode 100644
index 00000000000..2c286961aff
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/model/ProfileExternalization.profile.notation
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<notation:Diagram xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmlns:notation="http://www.eclipse.org/gmf/runtime/1.0.2/notation" xmlns:style="http://www.eclipse.org/papyrus/infra/viewpoints/policy/style" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_M2EtsEWjEeSNXJj2G3jVCw" type="PapyrusUMLProfileDiagram" name="stereotypes" measurementUnit="Pixel">
+ <eAnnotations xmi:type="ecore:EAnnotation" xmi:id="_hcw_sEW1EeSNXJj2G3jVCw" source="Stereotype_Annotation">
+ <details xmi:type="ecore:EStringToStringMapEntry" xmi:id="_hcw_sUW1EeSNXJj2G3jVCw" key="StereotypeWithQualifiedNameList" value=""/>
+ <details xmi:type="ecore:EStringToStringMapEntry" xmi:id="_hcw_skW1EeSNXJj2G3jVCw" key="StereotypeList" value="Ecore::EPackage"/>
+ <details xmi:type="ecore:EStringToStringMapEntry" xmi:id="_hcxmwEW1EeSNXJj2G3jVCw" key="Stereotype_Presentation_Kind" value="HorizontalStereo"/>
+ <details xmi:type="ecore:EStringToStringMapEntry" xmi:id="_hcxmwUW1EeSNXJj2G3jVCw" key="PropStereoDisplay" value=""/>
+ <details xmi:type="ecore:EStringToStringMapEntry" xmi:id="_hcxmwkW1EeSNXJj2G3jVCw" key="StereotypePropertyLocation" value="Compartment"/>
+ </eAnnotations>
+ <children xmi:type="notation:Shape" xmi:id="_OOR2wEWjEeSNXJj2G3jVCw" type="1026">
+ <children xmi:type="notation:DecorationNode" xmi:id="_OOX9YEWjEeSNXJj2G3jVCw" type="1034"/>
+ <children xmi:type="notation:BasicCompartment" xmi:id="_OOc14EWjEeSNXJj2G3jVCw" type="1071">
+ <styles xmi:type="notation:TitleStyle" xmi:id="_OOc14UWjEeSNXJj2G3jVCw"/>
+ <styles xmi:type="notation:SortingStyle" xmi:id="_OOc14kWjEeSNXJj2G3jVCw"/>
+ <styles xmi:type="notation:FilteringStyle" xmi:id="_OOc140WjEeSNXJj2G3jVCw"/>
+ <layoutConstraint xmi:type="notation:Bounds" xmi:id="_OOc15EWjEeSNXJj2G3jVCw"/>
+ </children>
+ <children xmi:type="notation:BasicCompartment" xmi:id="_OOdc8EWjEeSNXJj2G3jVCw" type="1019">
+ <children xmi:type="notation:Node" xmi:id="_baY2QEWkEeSNXJj2G3jVCw" type="3020">
+ <element xmi:type="uml:Operation" href="ProfileExternalization.profile.uml#_baC4AEWkEeSNXJj2G3jVCw"/>
+ <layoutConstraint xmi:type="notation:Location" xmi:id="_baY2QUWkEeSNXJj2G3jVCw"/>
+ </children>
+ <children xmi:type="notation:Node" xmi:id="_hadJAEWpEeSNXJj2G3jVCw" type="3020">
+ <element xmi:type="uml:Operation" href="ProfileExternalization.profile.uml#_hab64EWpEeSNXJj2G3jVCw"/>
+ <layoutConstraint xmi:type="notation:Location" xmi:id="_hadwEEWpEeSNXJj2G3jVCw"/>
+ </children>
+ <styles xmi:type="notation:TitleStyle" xmi:id="_OOdc8UWjEeSNXJj2G3jVCw"/>
+ <styles xmi:type="notation:SortingStyle" xmi:id="_OOdc8kWjEeSNXJj2G3jVCw"/>
+ <styles xmi:type="notation:FilteringStyle" xmi:id="_OOdc80WjEeSNXJj2G3jVCw"/>
+ <layoutConstraint xmi:type="notation:Bounds" xmi:id="_OOdc9EWjEeSNXJj2G3jVCw"/>
+ </children>
+ <element xmi:type="uml:Stereotype" href="ProfileExternalization.profile.uml#_ON8fkEWjEeSNXJj2G3jVCw"/>
+ <layoutConstraint xmi:type="notation:Bounds" xmi:id="_OOSd0EWjEeSNXJj2G3jVCw" x="129" y="139"/>
+ </children>
+ <children xmi:type="notation:Shape" xmi:id="_c82kAEWjEeSNXJj2G3jVCw" type="1031">
+ <eAnnotations xmi:type="ecore:EAnnotation" xmi:id="_c84ZMEWjEeSNXJj2G3jVCw" source="Stereotype_Annotation">
+ <details xmi:type="ecore:EStringToStringMapEntry" xmi:id="_c84ZMUWjEeSNXJj2G3jVCw" key="StereotypeWithQualifiedNameList" value=""/>
+ <details xmi:type="ecore:EStringToStringMapEntry" xmi:id="_c84ZMkWjEeSNXJj2G3jVCw" key="StereotypeList" value="StandardProfile::Metaclass"/>
+ <details xmi:type="ecore:EStringToStringMapEntry" xmi:id="_c84ZM0WjEeSNXJj2G3jVCw" key="Stereotype_Presentation_Kind" value="HorizontalStereo"/>
+ <details xmi:type="ecore:EStringToStringMapEntry" xmi:id="_c84ZNEWjEeSNXJj2G3jVCw" key="PropStereoDisplay" value=""/>
+ <details xmi:type="ecore:EStringToStringMapEntry" xmi:id="_c84ZNUWjEeSNXJj2G3jVCw" key="StereotypePropertyLocation" value="Compartment"/>
+ </eAnnotations>
+ <children xmi:type="notation:DecorationNode" xmi:id="_c82kAkWjEeSNXJj2G3jVCw" type="1084"/>
+ <element xmi:type="uml:Class" href="pathmap://UML_METAMODELS/UML.metamodel.uml#Dependency"/>
+ <layoutConstraint xmi:type="notation:Bounds" xmi:id="_c82kA0WjEeSNXJj2G3jVCw" x="549" y="148"/>
+ </children>
+ <children xmi:type="notation:Shape" xmi:id="_hb0CoEWjEeSNXJj2G3jVCw" type="1014">
+ <children xmi:type="notation:DecorationNode" xmi:id="_hb0CokWjEeSNXJj2G3jVCw" type="1015"/>
+ <children xmi:type="notation:DecorationNode" xmi:id="_hb0psEWjEeSNXJj2G3jVCw" type="5063"/>
+ <element xmi:type="uml:Constraint" href="ProfileExternalization.profile.uml#_hbLwgEWjEeSNXJj2G3jVCw"/>
+ <layoutConstraint xmi:type="notation:Bounds" xmi:id="_hb0CoUWjEeSNXJj2G3jVCw" x="177" y="284"/>
+ </children>
+ <children xmi:type="notation:Shape" xmi:id="_7MEUoEWjEeSNXJj2G3jVCw" type="1014">
+ <children xmi:type="notation:DecorationNode" xmi:id="_7ME7sEWjEeSNXJj2G3jVCw" type="1015"/>
+ <children xmi:type="notation:DecorationNode" xmi:id="_7ME7sUWjEeSNXJj2G3jVCw" type="5063"/>
+ <element xmi:type="uml:Constraint" href="ProfileExternalization.profile.uml#_7MDGgEWjEeSNXJj2G3jVCw"/>
+ <layoutConstraint xmi:type="notation:Bounds" xmi:id="_7MEUoUWjEeSNXJj2G3jVCw" x="141" y="369"/>
+ </children>
+ <styles xmi:type="notation:StringValueStyle" xmi:id="_M2EtsUWjEeSNXJj2G3jVCw" name="diagram_compatibility_version" stringValue="1.0.0"/>
+ <styles xmi:type="notation:DiagramStyle" xmi:id="_M2EtskWjEeSNXJj2G3jVCw"/>
+ <styles xmi:type="style:PapyrusViewStyle" xmi:id="_M2Ets0WjEeSNXJj2G3jVCw">
+ <owner xmi:type="uml:Profile" href="ProfileExternalization.profile.uml#_Mzzc0EWjEeSNXJj2G3jVCw"/>
+ </styles>
+ <element xmi:type="uml:Profile" href="ProfileExternalization.profile.uml#_Mzzc0EWjEeSNXJj2G3jVCw"/>
+ <edges xmi:type="notation:Connector" xmi:id="_eLjLwEWjEeSNXJj2G3jVCw" type="1013" source="_OOR2wEWjEeSNXJj2G3jVCw" target="_c82kAEWjEeSNXJj2G3jVCw">
+ <styles xmi:type="notation:FontStyle" xmi:id="_eLjLwUWjEeSNXJj2G3jVCw"/>
+ <element xmi:type="uml:Extension" href="ProfileExternalization.profile.uml#_eLao4EWjEeSNXJj2G3jVCw"/>
+ <bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_eLjLwkWjEeSNXJj2G3jVCw" points="[50, -5, -255, 0]$[291, -17, -14, -12]"/>
+ <sourceAnchor xmi:type="notation:IdentityAnchor" xmi:id="_efEksEWjEeSNXJj2G3jVCw" id="(1.0,0.22522522522522523)"/>
+ <targetAnchor xmi:type="notation:IdentityAnchor" xmi:id="_eL8NUEWjEeSNXJj2G3jVCw" id="(0.0,0.32)"/>
+ </edges>
+ <edges xmi:type="notation:Connector" xmi:id="_iMuiMEWjEeSNXJj2G3jVCw" type="8500" source="_hb0CoEWjEeSNXJj2G3jVCw" target="_OOR2wEWjEeSNXJj2G3jVCw">
+ <styles xmi:type="notation:FontStyle" xmi:id="_iMuiMUWjEeSNXJj2G3jVCw"/>
+ <element xsi:nil="true"/>
+ <bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_iMuiMkWjEeSNXJj2G3jVCw" points="[0, 0, 91, 94]$[-70, -115, 21, -21]"/>
+ <sourceAnchor xmi:type="notation:IdentityAnchor" xmi:id="_iM0BwEWjEeSNXJj2G3jVCw" id="(0.08588957055214724,0.15)"/>
+ <targetAnchor xmi:type="notation:IdentityAnchor" xmi:id="_iM0o0EWjEeSNXJj2G3jVCw" id="(0.24919093851132687,0.918918918918919)"/>
+ </edges>
+ <edges xmi:type="notation:Connector" xmi:id="_7byysEWjEeSNXJj2G3jVCw" type="8500" source="_7MEUoEWjEeSNXJj2G3jVCw" target="_OOR2wEWjEeSNXJj2G3jVCw">
+ <styles xmi:type="notation:FontStyle" xmi:id="_7byysUWjEeSNXJj2G3jVCw"/>
+ <element xsi:nil="true"/>
+ <bendpoints xmi:type="notation:RelativeBendpoints" xmi:id="_7byyskWjEeSNXJj2G3jVCw" points="[0, 0, 93, 126]$[-79, -109, 14, 17]"/>
+ <sourceAnchor xmi:type="notation:IdentityAnchor" xmi:id="_7b1O8EWjEeSNXJj2G3jVCw" id="(0.05396825396825397,0.03333333333333333)"/>
+ <targetAnchor xmi:type="notation:IdentityAnchor" xmi:id="_7b12AEWjEeSNXJj2G3jVCw" id="(0.12631578947368421,0.95)"/>
+ </edges>
+</notation:Diagram>
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/model/ProfileExternalization.profile.uml b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/model/ProfileExternalization.profile.uml
new file mode 100644
index 00000000000..ef644591746
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/model/ProfileExternalization.profile.uml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xmi:XMI xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:Ecore="http://www.eclipse.org/uml2/schemas/Ecore/5" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xsi:schemaLocation="http://www.eclipse.org/uml2/schemas/Ecore/5 pathmap://UML_PROFILES/Ecore.profile.uml#_z1OFcHjqEdy8S4Cr8Rc_NA">
+ <uml:Profile xmi:id="_Mzzc0EWjEeSNXJj2G3jVCw" name="ProfileExternalization" URI="http://www.eclipse.org/Papyrus/2014/profile/profileExternalization" metaclassReference="_c8xEcEWjEeSNXJj2G3jVCw">
+ <elementImport xmi:type="uml:ElementImport" xmi:id="_c8xEcEWjEeSNXJj2G3jVCw" alias="Dependency">
+ <importedElement xmi:type="uml:Class" href="pathmap://UML_METAMODELS/UML.metamodel.uml#Dependency"/>
+ </elementImport>
+ <packagedElement xmi:type="uml:Stereotype" xmi:id="_ON8fkEWjEeSNXJj2G3jVCw" name="ApplyProfiles">
+ <ownedRule xmi:type="uml:Constraint" xmi:id="_hbLwgEWjEeSNXJj2G3jVCw" name="suppliers_are_packages">
+ <specification xmi:type="uml:OpaqueExpression" xmi:id="_47v30EWjEeSNXJj2G3jVCw">
+ <language>OCL</language>
+ <body>base_Dependency.supplier->forAll(oclIsKindOf(uml::Package))</body>
+ </specification>
+ </ownedRule>
+ <ownedRule xmi:type="uml:Constraint" xmi:id="_7MDGgEWjEeSNXJj2G3jVCw" name="clients_are_packages">
+ <specification xmi:type="uml:OpaqueExpression" xmi:id="_CGxc8EWkEeSNXJj2G3jVCw">
+ <language>OCL</language>
+ <body>base_Dependency.client->forAll(oclIsKindOf(uml::Package))</body>
+ </specification>
+ </ownedRule>
+ <ownedAttribute xmi:type="uml:Property" xmi:id="_eLaB0EWjEeSNXJj2G3jVCw" name="base_Dependency" association="_eLao4EWjEeSNXJj2G3jVCw">
+ <type xmi:type="uml:Class" href="pathmap://UML_METAMODELS/UML.metamodel.uml#Dependency"/>
+ </ownedAttribute>
+ <ownedOperation xmi:type="uml:Operation" xmi:id="_baC4AEWkEeSNXJj2G3jVCw" name="getAppliedProfiles">
+ <ownedRule xmi:type="uml:Constraint" xmi:id="_-EjIMEWkEeSNXJj2G3jVCw" name="">
+ <specification xmi:type="uml:OpaqueExpression" xmi:id="_-EjIMUWkEeSNXJj2G3jVCw">
+ <language>OCL</language>
+ <body>base_Dependency.supplier->selectByKind(uml::Package).appliedProfile</body>
+ </specification>
+ </ownedRule>
+ <ownedParameter xmi:type="uml:Parameter" xmi:id="_n4wbcEWkEeSNXJj2G3jVCw" direction="return" effect="read">
+ <type xmi:type="uml:Class" href="pathmap://UML_METAMODELS/UML.metamodel.uml#Profile"/>
+ <lowerValue xmi:type="uml:LiteralInteger" xmi:id="_pjhUIEWkEeSNXJj2G3jVCw"/>
+ <upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_pjh7MEWkEeSNXJj2G3jVCw" value="*"/>
+ </ownedParameter>
+ </ownedOperation>
+ <ownedOperation xmi:type="uml:Operation" xmi:id="_hab64EWpEeSNXJj2G3jVCw" name="getExternalizedAppliedProfilePackages">
+ <ownedParameter xmi:type="uml:Parameter" xmi:id="_pHz2QEWpEeSNXJj2G3jVCw" direction="return" effect="read">
+ <type xmi:type="uml:Class" href="pathmap://UML_METAMODELS/UML.metamodel.uml#Package"/>
+ <lowerValue xmi:type="uml:LiteralInteger" xmi:id="_qF6dQEWpEeSNXJj2G3jVCw"/>
+ <upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_qF7EUEWpEeSNXJj2G3jVCw" value="*"/>
+ </ownedParameter>
+ </ownedOperation>
+ </packagedElement>
+ <packagedElement xmi:type="uml:Extension" xmi:id="_eLao4EWjEeSNXJj2G3jVCw" name="E_ApplyProfiles_Dependency1" memberEnd="_eLao4UWjEeSNXJj2G3jVCw _eLaB0EWjEeSNXJj2G3jVCw">
+ <ownedEnd xmi:type="uml:ExtensionEnd" xmi:id="_eLao4UWjEeSNXJj2G3jVCw" name="extension_ApplyProfiles" type="_ON8fkEWjEeSNXJj2G3jVCw" aggregation="composite" association="_eLao4EWjEeSNXJj2G3jVCw"/>
+ </packagedElement>
+ <profileApplication xmi:type="uml:ProfileApplication" xmi:id="_bkeWoEW1EeSNXJj2G3jVCw">
+ <eAnnotations xmi:type="ecore:EAnnotation" xmi:id="_bkxRkEW1EeSNXJj2G3jVCw" source="http://www.eclipse.org/uml2/2.0.0/UML">
+ <references xmi:type="ecore:EPackage" href="pathmap://UML_PROFILES/Ecore.profile.uml#_z1OFcHjqEdy8S4Cr8Rc_NA"/>
+ </eAnnotations>
+ <appliedProfile xmi:type="uml:Profile" href="pathmap://UML_PROFILES/Ecore.profile.uml#_0"/>
+ </profileApplication>
+ </uml:Profile>
+ <Ecore:EPackage xmi:id="_hcTFoEW1EeSNXJj2G3jVCw" base_Package="_Mzzc0EWjEeSNXJj2G3jVCw" packageName="profileExternalization" nsPrefix="profileext" basePackage="org.eclipse.papyrus.uml.decoratormodel"/>
+</xmi:XMI>
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/model/profileExternalization.ecore b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/model/profileExternalization.ecore
new file mode 100644
index 00000000000..1b80f2a96ac
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/model/profileExternalization.ecore
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="profileExternalization" nsURI="http://www.eclipse.org/Papyrus/2014/profile/profileExternalization"
+ nsPrefix="profileext">
+ <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore">
+ <details key="validationDelegates" value="http://www.eclipse.org/emf/2002/Ecore/OCL"/>
+ </eAnnotations>
+ <eAnnotations source="http://www.eclipse.org/uml2/2.0.0/UML">
+ <details key="originalName" value="ProfileExternalization"/>
+ </eAnnotations>
+ <eClassifiers xsi:type="ecore:EClass" name="ApplyProfiles">
+ <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore">
+ <details key="constraints" value="suppliers_are_packages clients_are_packages"/>
+ </eAnnotations>
+ <eAnnotations source="http://www.eclipse.org/emf/2002/Ecore/OCL">
+ <details key="suppliers_are_packages" value="base_Dependency.supplier->forAll(oclIsKindOf(uml::Package))"/>
+ <details key="clients_are_packages" value="base_Dependency.client->forAll(oclIsKindOf(uml::Package))"/>
+ </eAnnotations>
+ <eAnnotations source="http://www.eclipse.org/emf/2002/GenModel">
+ <details key="documentation" value="base_Dependency.supplier->forAll(oclIsKindOf(uml::Package))&#xA;base_Dependency.client->forAll(oclIsKindOf(uml::Package))"/>
+ </eAnnotations>
+ <eOperations name="getAppliedProfiles" ordered="false" upperBound="-1" eType="ecore:EClass ../../org.eclipse.uml2.uml/model/UML.ecore#//Profile"/>
+ <eOperations name="getExternalizedAppliedProfilePackages" ordered="false" upperBound="-1"
+ eType="ecore:EClass ../../org.eclipse.uml2.uml/model/UML.ecore#//Package"/>
+ <eStructuralFeatures xsi:type="ecore:EReference" name="base_Dependency" ordered="false"
+ lowerBound="1" eType="ecore:EClass ../../org.eclipse.uml2.uml/model/UML.ecore#//Dependency">
+ <eAnnotations source="http://schema.omg.org/spec/MOF/2.0/emof.xml#Property.oppositeRoleName">
+ <details key="body" value="extension_ApplyProfiles"/>
+ </eAnnotations>
+ </eStructuralFeatures>
+ </eClassifiers>
+</ecore:EPackage>
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/plugin.properties b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/plugin.properties
new file mode 100644
index 00000000000..b7baf78fbf7
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/plugin.properties
@@ -0,0 +1,14 @@
+# Copyright (c) 2014 Christian W. Damus and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Christian W. Damus - Initial API and implementation
+
+pluginName = Papyrus Decorator Models Core
+providerName = Eclipse Modeling Project
+
+content-type.name = Papyrus Profile Application
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/plugin.xml b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/plugin.xml
new file mode 100644
index 00000000000..544441f79eb
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/plugin.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+ <extension
+ point="org.eclipse.core.expressions.propertyTesters">
+ <propertyTester
+ class="org.eclipse.papyrus.uml.decoratormodel.internal.expressions.FilePropertyTester"
+ id="org.eclipse.papyrus.uml.decoratormodel.file"
+ namespace="org.eclipse.papyrus.uml.decoratormodel"
+ properties="isDecoratorModel"
+ type="org.eclipse.core.resources.IFile">
+ </propertyTester>
+ </extension>
+ <extension
+ point="org.eclipse.papyrus.infra.core.model">
+ <model
+ classname="org.eclipse.papyrus.uml.decoratormodel.model.DecoratorModel">
+ <dependency>
+ <loadAfter
+ identifier="org.eclipse.papyrus.infra.core.resource.uml.UmlModel">
+ </loadAfter>
+ </dependency>
+ <modelSnippet
+ classname="org.eclipse.papyrus.uml.decoratormodel.model.UMLSnippet"
+ description="UML model listener support for loaded decorator models.">
+ </modelSnippet>
+ </model>
+ </extension>
+ <extension
+ point="org.eclipse.emf.ecore.uri_mapping">
+ <mapping
+ source="pathmap://PAPYRUS_PROFILEEXT/"
+ target="platform:/plugin/org.eclipse.papyrus.uml.decoratormodel/model/">
+ </mapping>
+ </extension>
+
+ <extension point="org.eclipse.emf.ecore.generated_package">
+ <!-- @generated ProfileExternalization.profile -->
+ <package
+ uri="http://www.eclipse.org/Papyrus/2014/profile/profileExternalization"
+ class="org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ProfileExternalizationPackage"
+ genModel="model/ProfileExternalization.profile.genmodel"/>
+ </extension>
+ <extension
+ point="org.eclipse.uml2.uml.generated_package">
+ <profile
+ location="pathmap://PAPYRUS_PROFILEEXT/ProfileExternalization.profile.uml#_Mzzc0EWjEeSNXJj2G3jVCw"
+ uri="http://www.eclipse.org/Papyrus/2014/profile/profileExternalization">
+ </profile>
+ </extension>
+ <extension
+ point="org.eclipse.core.contenttype.contentTypes">
+ <content-type
+ base-type="org.eclipse.uml2.uml"
+ id="org.eclipse.papyrus.uml.decoratormodel.decorator_model"
+ name="%content-type.name"
+ priority="normal">
+ <describer
+ class="org.eclipse.papyrus.infra.emf.resource.AnyRootNamespaceContentHandler$Describer">
+ <parameter
+ name="namespacePattern"
+ value="http://www\.eclipse\.org/Papyrus/2014/profile/profileExternalization" />
+ </describer>
+ </content-type>
+ </extension>
+ <extension
+ point="org.eclipse.papyrus.infra.emf.readonly.readOnlyHandler">
+ <readOnlyHandler
+ id="org.eclipse.papyrus.uml.decoratormodel.DecoratorModel"
+ class="org.eclipse.papyrus.uml.decoratormodel.internal.resource.DecoratorModelReadOnlyHandler"
+ priority="50">
+ <affinity
+ axis="discretion">
+ </affinity>
+ </readOnlyHandler>
+ </extension>
+ <extension
+ point="org.eclipse.papyrus.uml.tools.profileApplicationDelegates">
+ <delegate
+ class="org.eclipse.papyrus.uml.decoratormodel.internal.providers.ExternalizedProfileApplicationDelegate">
+ </delegate>
+ </extension>
+</plugin>
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/pom.xml b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/pom.xml
new file mode 100644
index 00000000000..3c362f5eae1
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/pom.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project>
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>org.eclipse.papyrus</artifactId>
+ <groupId>org.eclipse.papyrus</groupId>
+ <version>1.1.0-SNAPSHOT</version>
+ <relativePath>../../../../releng/top-pom-main.xml</relativePath>
+ </parent>
+ <artifactId>org.eclipse.papyrus.uml.decoratormodel</artifactId>
+ <groupId>org.eclipse.papyrus</groupId>
+ <version>1.1.0-SNAPSHOT</version>
+ <packaging>eclipse-plugin</packaging>
+</project> \ No newline at end of file
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/Activator.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/Activator.java
new file mode 100644
index 00000000000..8eb6aaa4ba0
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/Activator.java
@@ -0,0 +1,62 @@
+/*****************************************************************************
+ * Copyright (c) 2013, 2014 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:
+ * Remi Schnekenburger (CEA LIST) - Initial API and implementation
+ * Christian W. Damus - bug 399859
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel;
+
+import org.eclipse.core.runtime.Plugin;
+import org.eclipse.papyrus.infra.core.log.LogHelper;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class Activator extends Plugin {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "org.eclipse.papyrus.uml.decoratormodel"; //$NON-NLS-1$
+
+ // The shared instance
+ private static Activator plugin;
+
+ /** logger helper */
+ public static LogHelper log;
+
+ public Activator() {
+ super();
+ }
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ plugin = this;
+ log = new LogHelper(this);
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ plugin = null;
+ log = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static Activator getDefault() {
+ return plugin;
+ }
+
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/helper/DecoratorModelUtils.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/helper/DecoratorModelUtils.java
new file mode 100644
index 00000000000..59026a769d2
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/helper/DecoratorModelUtils.java
@@ -0,0 +1,1201 @@
+/*****************************************************************************
+ * Copyright (c) 2013, 2014 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:
+ * Remi Schnekenburger (CEA LIST) - Initial API and implementation
+ * Christian W. Damus - bug 399859
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.uml.decoratormodel.helper;
+
+import java.io.BufferedInputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.content.IContentDescription;
+import org.eclipse.core.runtime.content.IContentType;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.common.command.CompoundCommand;
+import org.eclipse.emf.common.command.UnexecutableCommand;
+import org.eclipse.emf.common.util.TreeIterator;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.resource.ContentHandler;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.resource.URIConverter;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.emf.ecore.util.InternalEList;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.emf.transaction.util.TransactionUtil;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.emf.resource.AnyRootNamespaceContentHandler;
+import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
+import org.eclipse.papyrus.uml.decoratormodel.Activator;
+import org.eclipse.papyrus.uml.decoratormodel.internal.commands.CreateDecoratorModelCommand;
+import org.eclipse.papyrus.uml.decoratormodel.internal.commands.DeleteDecoratorModelCommand;
+import org.eclipse.papyrus.uml.decoratormodel.internal.commands.ReclaimProfileApplicationsCommand;
+import org.eclipse.papyrus.uml.decoratormodel.internal.commands.SaveDecoratorModelCommand;
+import org.eclipse.papyrus.uml.decoratormodel.internal.commands.SeparateProfileApplicationsCommand;
+import org.eclipse.papyrus.uml.decoratormodel.internal.resource.DecoratorModelIndex;
+import org.eclipse.papyrus.uml.decoratormodel.model.DecoratorModel;
+import org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ApplyProfiles;
+import org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ProfileExternalizationPackage;
+import org.eclipse.papyrus.uml.tools.utils.CustomUMLUtil;
+import org.eclipse.uml2.common.util.CacheAdapter;
+import org.eclipse.uml2.common.util.UML2Util;
+import org.eclipse.uml2.uml.Component;
+import org.eclipse.uml2.uml.Dependency;
+import org.eclipse.uml2.uml.DirectedRelationship;
+import org.eclipse.uml2.uml.Element;
+import org.eclipse.uml2.uml.NamedElement;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.Profile;
+import org.eclipse.uml2.uml.ProfileApplication;
+import org.eclipse.uml2.uml.Stereotype;
+import org.eclipse.uml2.uml.UMLFactory;
+import org.eclipse.uml2.uml.UMLPackage;
+import org.eclipse.uml2.uml.util.UMLUtil;
+import org.eclipse.uml2.uml.util.UMLUtil.StereotypeApplicationHelper;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.SetMultimap;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.UncheckedExecutionException;
+
+/**
+ * Utility class for stereotype application management in external resources. Descriptions of individual
+ * methods indicate whether they do or do not access the decorator model index, to assist in determining
+ * appropriate code patterns to ensure liveness of threads etc.
+ */
+public class DecoratorModelUtils {
+
+ public static final URI PROFILE_URI = URI.createURI("pathmap://PAPYRUS_PROFILEEXT/ProfileExternalization.profile.uml#_Mzzc0EWjEeSNXJj2G3jVCw", true); //$NON-NLS-1$
+
+ public static final IContentType DECORATOR_MODEL_CONTENT_TYPE = Platform.getContentTypeManager().getContentType("org.eclipse.papyrus.uml.decoratormodel.decorator_model"); //$NON-NLS-1$
+
+ private static final ContentHandler DECORATOR_MODEL_CONTENT_HANDLER = new AnyRootNamespaceContentHandler(DECORATOR_MODEL_CONTENT_TYPE.getId(), null, ProfileExternalizationPackage.eNS_URI);
+
+ private static final String STEREOTYPE_PREFIX = "ProfileExternalization::"; //$NON-NLS-1$
+
+ public static final String APPLY_PROFILES_QNAME = STEREOTYPE_PREFIX + "ApplyProfiles"; //$NON-NLS-1$
+
+ private static final Object LOADED_RESOURCES_CACHE_KEY = new Object();
+
+ private static final Object UNLOADED_RESOURCE_DECORATORS_CACHE_KEY = new Object();
+
+ private static final Object UNLOADED_PACKAGE_DECORATORS_CACHE_KEY = new Object();
+
+ private static final Object INTRINSIC_PROFILE_APPLICATIONS_CACHE_KEY = new Object();
+
+ public static void externalizeProfileApplication(ProfileApplication profileApplication, Resource decoratorResource) {
+ Resource sourceResource = profileApplication.eResource();
+ ResourceSet resourceSet = (sourceResource == null) ? null : sourceResource.getResourceSet();
+
+ // Ensure existence of the root package for external resource packages.
+ // The Externalization Profile is applied here so that it is not inherited
+ // by the packages in the user model
+ Package decoratorModel = getDecoratorModel(decoratorResource);
+
+ // Ensure existence of the externalizing package
+ Package externalPackage = getDecoratorPackage(decoratorModel, profileApplication.getApplyingPackage(), true);
+
+ // Move the profile application to the externalizing package
+ externalPackage.getProfileApplications().add(profileApplication);
+
+ // Find all of the profile's stereotype applications in the source resource
+ List<EObject> stereotypeApplications = new ArrayList<EObject>();
+ for (EObject next : sourceResource.getContents()) {
+ if (!(next instanceof Element) && isDefinedBy(profileApplication, next)) {
+ stereotypeApplications.add(next);
+ }
+ }
+
+ // Move them
+ StereotypeApplicationHelper stereotypeHelper = StereotypeApplicationHelper.getInstance(resourceSet);
+ for (EObject next : stereotypeApplications) {
+ stereotypeHelper.addToContainmentList(UMLUtil.getBaseElement(next), next);
+ }
+ }
+
+ public static void internalizeProfileApplications(Iterable<? extends ProfileApplication> profileApplications, IDeleteEmptyDecoratorModelsPolicy deletePolicy) {
+ List<Package> emptyDecoratorModels = Lists.newArrayList();
+
+ for (ProfileApplication profileApplication : profileApplications) {
+ Resource sourceResource = profileApplication.eResource();
+ ResourceSet resourceSet = (sourceResource == null) ? null : sourceResource.getResourceSet();
+
+ Package externalPackage = profileApplication.getApplyingPackage();
+ Package applyingPackage = getUserPackage(externalPackage);
+
+ // Find all of the profile's stereotype applications in the source resource
+ List<EObject> stereotypeApplications = new ArrayList<EObject>();
+ for (EObject next : sourceResource.getContents()) {
+ if (!(next instanceof Element) && isDefinedBy(profileApplication, next)) {
+ stereotypeApplications.add(next);
+ }
+ }
+
+ // Move the profile application to the applying package
+ applyingPackage.getProfileApplications().add(profileApplication);
+
+ // Delete the external package if it's no longer needed
+ Package root = externalPackage.getNestingPackage();
+ List<ProfileApplication> remaining = externalPackage.getProfileApplications();
+ if (remaining.isEmpty()) {
+ externalPackage.destroy();
+
+ // And the root, too
+ if ((root != null) && root.getNestedPackages().isEmpty()) {
+ emptyDecoratorModels.add(root);
+ }
+ }
+
+ // Move the stereotype applications
+ StereotypeApplicationHelper stereotypeHelper = StereotypeApplicationHelper.getInstance(resourceSet);
+ for (EObject next : stereotypeApplications) {
+ stereotypeHelper.addToContainmentList(UMLUtil.getBaseElement(next), next);
+ }
+ }
+
+ if (!emptyDecoratorModels.isEmpty() && shouldDelete(emptyDecoratorModels, deletePolicy)) {
+ CustomUMLUtil.destroyAll(emptyDecoratorModels);
+ }
+ }
+
+ private static boolean shouldDelete(Collection<? extends Package> decoratorModels, IDeleteEmptyDecoratorModelsPolicy deletePolicy) {
+ boolean result = (deletePolicy == null);
+
+ if (!result) {
+ // Consult the policy
+ Set<Resource> decoratorModelResources = Sets.newLinkedHashSet();
+ for (Package next : decoratorModels) {
+ decoratorModelResources.add(next.eResource());
+ }
+
+ result = deletePolicy.shouldDeleteDecoratorModels(decoratorModelResources);
+ }
+
+ return result;
+ }
+
+ public static Profile getExternalizationProfile(ResourceSet resourceSet) {
+ return (Profile) resourceSet.getEObject(PROFILE_URI, true);
+ }
+
+ public static Package getDecoratorModel(Resource resource) {
+ Package result = null;
+
+ Profile externalizationProfile = getExternalizationProfile(resource.getResourceSet());
+ for (Package next : Iterables.filter(resource.getContents(), Package.class)) {
+ if (next.isProfileApplied(externalizationProfile)) {
+ result = next;
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ private static boolean isDefinedBy(ProfileApplication profileApplication, EObject stereotypeApplication) {
+ boolean result = false;
+
+ Element baseElement = UMLUtil.getBaseElement(stereotypeApplication);
+ if (baseElement != null) {
+ Stereotype stereotype = UMLUtil.getStereotype(stereotypeApplication);
+ if (stereotype != null) {
+ result = profileApplication.getAppliedDefinition(stereotype) == stereotypeApplication.eClass();
+ }
+ }
+
+ return result;
+ }
+
+ private static boolean isApplyProfiles(Dependency dependency) {
+ boolean result = false;
+
+ CacheAdapter cache = CacheAdapter.getCacheAdapter(dependency);
+ if (cache != null) {
+ for (EStructuralFeature.Setting setting : cache.getNonNavigableInverseReferences(dependency)) {
+ if (setting.getEStructuralFeature() == ProfileExternalizationPackage.Literals.APPLY_PROFILES__BASE_DEPENDENCY) {
+ result = true;
+ break;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Queries the packages in currently loaded decorator models that provide profile applications to a given package.
+ * <p>
+ * This method does <em>not</em> access the decorator model index.
+ *
+ * @param package_
+ * a package
+ * @return its currently loaded decorator-model packages
+ */
+ public static Iterable<Package> getDecoratorPackages(Package package_) {
+ Set<Package> result = null;
+
+ for (ApplyProfiles next : getDecoratorModelDependencies(package_)) {
+ if (result == null) {
+ result = new LinkedHashSet<Package>();
+ }
+ result.addAll(next.getExternalizedAppliedProfilePackages());
+ }
+
+ return (result == null) ? Collections.<Package> emptySet() : result;
+ }
+
+ /**
+ * Queries the currently loaded profile applications of a package that are provided by decorator models.
+ * <p>
+ * This method does <em>not</em> access the decorator model index.
+ *
+ * @param package_
+ * a package
+ * @return its currently loaded decorator-model profile applications
+ */
+ public static Iterable<ProfileApplication> getDecoratorModelProfileApplications(Package package_) {
+ Set<ProfileApplication> result = null;
+
+ for (ApplyProfiles next : getDecoratorModelDependencies(package_)) {
+ if (result == null) {
+ result = new LinkedHashSet<ProfileApplication>();
+ }
+ for (Package externalPackage : next.getExternalizedAppliedProfilePackages()) {
+ result.addAll(externalPackage.getProfileApplications());
+ }
+ }
+
+ return (result == null) ? Collections.<ProfileApplication> emptySet() : result;
+ }
+
+ /**
+ * Queries the package in the user model to which an externalized profile application applies a profile.
+ * <p>
+ * This method does <em>not</em> access the decorator model index.
+ *
+ * @param profileApplication
+ * a profile application
+ * @return the user-model package to which it applies a profile
+ */
+ public static Package getUserModelApplyingPackage(ProfileApplication profileApplication) {
+ Package applying = profileApplication.getApplyingPackage();
+ Package result = applying; // Maybe it's not actually an externalized profile application
+
+ if (applying != null) {
+ for (Dependency next : Iterables.filter(applying.getTargetDirectedRelationships(UMLPackage.Literals.DEPENDENCY), Dependency.class)) {
+ if (isApplyProfiles(next)) {
+ Package clientPackage = Iterables.getFirst(Iterables.filter(next.getClients(), Package.class), null);
+ if (clientPackage != null) {
+ result = clientPackage;
+ break;
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Queries a mapping of the currently loaded profile applications in a decorator model resource.
+ * <p>
+ * This method does <em>not</em> access the decorator model index.
+ *
+ * @param decoratorModel
+ * a decorator model resource
+ *
+ * @return a mapping of user-model package to applied profile as specified by the decorator model
+ */
+ public static Map<Package, Profile> getDecoratorProfileApplications(Resource decoratorModel) {
+ Map<Package, Profile> result = Maps.newHashMap();
+
+ for (ApplyProfiles next : Iterables.filter(decoratorModel.getContents(), ApplyProfiles.class)) {
+ Dependency base = next.getBase_Dependency();
+ if (base != null) {
+ for (Package applying : Iterables.filter(base.getClients(), Package.class)) {
+ for (Profile profile : next.getAppliedProfiles()) {
+ result.put(applying, profile);
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Queries the currently loaded applied profiles of a package from decorator models.
+ * <p>
+ * This method does <em>not</em> access the decorator model index.
+ *
+ * @param package_
+ * a user model package
+ *
+ * @return its applied profiles from currently loaded decorator models
+ */
+ public static Iterable<Profile> getDecoratorModelAppliedProfiles(Package package_) {
+ Set<Profile> result = null;
+
+ for (ApplyProfiles next : getDecoratorModelDependencies(package_)) {
+ if (result == null) {
+ result = new LinkedHashSet<Profile>();
+ }
+ result.addAll(next.getAppliedProfiles());
+ }
+
+ return (result == null) ? Collections.<Profile> emptySet() : result;
+ }
+
+ /**
+ * Queries the mapping of URIs of all applied profiles of a package from decorator models, including those inherited
+ * from ancestor packages, to mappings of URIs of decorator models to URIs of Ecore definitions applied by those decorators.
+ * The second-order map is necessary because multiple decorator models can apply different definitions of the same profile
+ * to the same package.
+ * <p>
+ * This method <em>accesses the decorator model index</em> and is therefore not suitable for use in time-sensitive code because an invocation may block the caller for an indeterminate interval. It is equivalent to invoking
+ * {@code getAllDecoratorModelAppliedProfileDefinitions(package_, true, true)}.
+ *
+ * @param package_
+ * a user model package
+ *
+ * @return the mapping of URIs of all profiles that it applies, loaded and unloaded, to applied Ecore definitions by decorator model
+ *
+ * @throws CoreException
+ * on failure to access the decorator model index
+ *
+ * @see #getAllDecoratorModelAppliedProfileDefinitions(Package, boolean, boolean)
+ */
+ public static Map<URI, Map<URI, URI>> getAllDecoratorModelAppliedProfileDefinitions(Package package_) throws CoreException {
+ return getAllDecoratorModelAppliedProfileDefinitions(package_, true, true);
+ }
+
+ /**
+ * Queries the mapping of URIs of all applied profiles of a package from decorator models, including those inherited
+ * from ancestor packages, to mappings of URIs of decorator models to URIs of Ecore definitions applied by those decorators.
+ * The second-order map is necessary because multiple decorator models can apply different definitions of the same profile
+ * to the same package.
+ * <p>
+ * This method <em>accesses the decorator model index</em> if {@code includeUnloaded} is {@code true} and is therefore not suitable for use in time-sensitive code in that case because an invocation may block the caller for an indeterminate interval.
+ *
+ * @param package_
+ * a user model package
+ * @param includeLoaded
+ * whether to include profile definitions from decorator models that are currently loaded
+ * @param includeUnloaded
+ * whether to include profile definitions from decorator models that are <em>not</em> currently loaded.
+ * Obviously, it is not useful to exclude both loaded and unloaded decorator models, because that guarantees an empty result
+ *
+ * @return the mapping of URIs of all profiles that it applies, loaded and unloaded, to applied Ecore definitions by decorator model
+ *
+ * @throws CoreException
+ * on failure to access the decorator model index in the {@code includeUnloaded} case
+ */
+ public static Map<URI, Map<URI, URI>> getAllDecoratorModelAppliedProfileDefinitions(Package package_, boolean includeLoaded, boolean includeUnloaded) throws CoreException {
+ Map<URI, Map<URI, URI>> result = Maps.newLinkedHashMap();
+
+ for (Package each : Iterables.concat(Collections.singleton(package_), package_.allOwningPackages())) {
+ if (includeLoaded) {
+ Iterable<ProfileApplication> loaded = getDecoratorModelProfileApplications(each);
+ if (!Iterables.isEmpty(loaded)) {
+ for (ProfileApplication next : loaded) {
+ Profile profile = next.getAppliedProfile();
+ EPackage definition = next.getAppliedDefinition();
+ if ((profile != null) && (definition != null)) {
+ URI profileURI = EcoreUtil.getURI(profile);
+ URI decoratorURI = next.eResource().getURI();
+ URI definitionURI = EcoreUtil.getURI(definition);
+
+ Map<URI, URI> definitions = result.get(profileURI);
+ if (definitions == null) {
+ definitions = Maps.newHashMap();
+ result.put(profileURI, definitions);
+ }
+
+ // Only take the first package's loaded definition URI because that is the one
+ // that is actually applied; any higher ones are occluded
+ if (!definitions.containsKey(decoratorURI)) {
+ definitions.put(decoratorURI, definitionURI);
+ }
+ }
+ }
+ }
+ }
+
+ if (includeUnloaded) {
+ Map<URI, Map<URI, URI>> index = DecoratorModelIndex.getInstance().getAllAppliedProfileDefinitions(EcoreUtil.getURI(each));
+ if (!index.isEmpty()) {
+ // Only add profiles from decorator models that aren't currently loaded
+ ResourceSet rset = EMFHelper.getResourceSet(each);
+ if (rset != null) {
+ for (URI profile : index.keySet()) {
+ Map<URI, URI> profileResult = result.get(profile);
+ if (profileResult == null) {
+ profileResult = Maps.newHashMap();
+ result.put(profile, profileResult);
+ }
+ for (Map.Entry<URI, URI> application : index.get(profile).entrySet()) {
+ // Add profile definitions from (profile, decorator) pairs that we do not yet have
+ // and that are not loaded
+ URI decorator = application.getKey();
+ if (!profileResult.containsKey(decorator)) {
+ Resource resource = rset.getResource(decorator, false);
+ if ((resource == null) || !resource.isLoaded()) {
+ profileResult.put(decorator, application.getValue());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ static Iterable<ApplyProfiles> getDecoratorModelDependencies(Package package_) {
+ List<ApplyProfiles> result = null;
+
+ for (Dependency dependency : package_.getClientDependencies()) {
+ for (EStructuralFeature.Setting setting : CacheAdapter.getCacheAdapter(dependency).getNonNavigableInverseReferences(dependency)) {
+ if (setting.getEStructuralFeature() == ProfileExternalizationPackage.Literals.APPLY_PROFILES__BASE_DEPENDENCY) {
+ if (result == null) {
+ result = new ArrayList<ApplyProfiles>();
+ }
+
+ result.add((ApplyProfiles) setting.getEObject());
+ }
+ }
+ }
+
+ return (result == null) ? Collections.<ApplyProfiles> emptyList() : result;
+ }
+
+ public static Package getDecoratorPackage(Package externalizationModel, Package userPackage, boolean createIfNecessary) {
+ Package result = null;
+ for (Package next : externalizationModel.getNestedPackages()) {
+ if (getUserPackage(next) == userPackage) {
+ result = next;
+ break;
+ }
+ }
+ if (result == null) {
+ result = externalizationModel.createNestedPackage(UML2Util.getValidJavaIdentifier(userPackage.getQualifiedName()));
+ Dependency dependency = UMLFactory.eINSTANCE.createDependency();
+ dependency.getClients().add(userPackage);
+ dependency.getSuppliers().add(result);
+ result.getPackagedElements().add(dependency);
+
+ // This stereotype name is unambiguous at this point because the only available profile
+ // is the externalization profile inherited from the root package
+ dependency.applyStereotype(dependency.getApplicableStereotype(APPLY_PROFILES_QNAME));
+ }
+
+ return result;
+ }
+
+ static Package getUserPackage(Package externalPackage) {
+ Package result = null;
+
+ for (DirectedRelationship next : externalPackage.getTargetDirectedRelationships(UMLPackage.Literals.DEPENDENCY)) {
+ for (EStructuralFeature.Setting setting : CacheAdapter.getCacheAdapter(next).getNonNavigableInverseReferences(next)) {
+ if (setting.getEStructuralFeature() == ProfileExternalizationPackage.Literals.APPLY_PROFILES__BASE_DEPENDENCY) {
+ result = Iterables.getFirst(Iterables.filter(next.getSources(), Package.class), null);
+ if (result != null) {
+ break;
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Queries whether a package has the externalization profile applied that is used by decorator models.
+ * <p>
+ * This method does <em>not</em> access the decorator model index.
+ *
+ * @param package_
+ * a package
+ * @return whether it has the externalization profile applied
+ */
+ public static boolean hasExternalizationProfile(Package package_) {
+ boolean result = false;
+
+ for (Profile next : package_.getAppliedProfiles()) {
+ if (PROFILE_URI.equals(EcoreUtil.getURI(next))) {
+ result = true;
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ public static Command createSeparateProfileApplicationsCommand(Iterable<? extends ProfileApplication> profileApplications, URI resourceURI, String modelName) {
+ Command result;
+
+ ProfileApplication any = Iterables.getFirst(profileApplications, null);
+
+ if (any == null) {
+ result = UnexecutableCommand.INSTANCE;
+ } else {
+ TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(any);
+ if (domain == null) {
+ result = UnexecutableCommand.INSTANCE;
+ } else {
+ // First, ensure the existence of the decorator model resource
+ result = new CreateDecoratorModelCommand(domain, resourceURI, modelName);
+ CompoundCommand compound = new CompoundCommand(1, result.getLabel(), result.getDescription());
+ compound.append(result);
+ result = compound;
+
+ // Then put the profile applications in it
+ compound.append(new SeparateProfileApplicationsCommand(domain, profileApplications, resourceURI));
+
+ // And, finally, ensure that the model-set will save the decorator model when the editor is next saved
+ if (domain.getResourceSet() instanceof ModelSet) {
+ compound.append(new SaveDecoratorModelCommand((ModelSet) domain.getResourceSet(), resourceURI));
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Creates a command that reintegrates the specified profile applications into the user model proper. Empty decorator models will always be deleted.
+ *
+ * @param profileApplications
+ * the externalized profile applications to reintegrate
+ *
+ * @return the delete command, or an unexecutable command if the request is invalid for some reason
+ *
+ * @see #createReclaimProfileApplicationsCommand(Iterable, IDeleteEmptyDecoratorModelsPolicy)
+ */
+ public static Command createReclaimProfileApplicationsCommand(Iterable<? extends ProfileApplication> profileApplications) {
+ return createReclaimProfileApplicationsCommand(profileApplications, null);
+ }
+
+ /**
+ * Creates a command that reintegrates the specified profile applications into the user model proper.
+ *
+ * @param profileApplications
+ * the externalized profile applications to reintegrate
+ * @param deletePolicy
+ * an optional policy determining whether any decorator models that are left without profile applications should be deleted. May be {@code null}, in which case empty decorator models will be deleted
+ *
+ * @return the delete command, or an unexecutable command if the request is invalid for some reason
+ */
+ public static Command createReclaimProfileApplicationsCommand(Iterable<? extends ProfileApplication> profileApplications, IDeleteEmptyDecoratorModelsPolicy deletePolicy) {
+ Command result;
+
+ ProfileApplication any = Iterables.getFirst(profileApplications, null);
+
+ if (any == null) {
+ result = UnexecutableCommand.INSTANCE;
+ } else {
+ TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(any);
+ if (domain == null) {
+ result = UnexecutableCommand.INSTANCE;
+ } else {
+ result = new ReclaimProfileApplicationsCommand(domain, profileApplications, deletePolicy);
+ CompoundCommand compound = new CompoundCommand(0, result.getLabel(), result.getDescription());
+ compound.append(result);
+ result = compound;
+
+ // Managing the resources to delete on save only applies to model-sets
+ if (domain.getResourceSet() instanceof ModelSet) {
+ ModelSet modelSet = (ModelSet) domain.getResourceSet();
+ Set<URI> resourcesToDelete = Sets.newHashSet();
+ for (ProfileApplication next : profileApplications) {
+ Resource toDelete = next.eResource();
+ if (resourcesToDelete.add(toDelete.getURI())) {
+ compound.append(new DeleteDecoratorModelCommand(modelSet, toDelete));
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Queries whether a resource is a loaded decorator model resource.
+ * <p>
+ * This method does <em>not</em> access the decorator model index.
+ *
+ * @param resource
+ * a resource
+ *
+ * @return whether it is a loaded decorator model resource
+ */
+ public static boolean isDecoratorModel(Resource resource) {
+ boolean result = false;
+
+ ResourceSet rset = resource.getResourceSet();
+ if (rset != null) {
+ // There must be at least one <<applyProfiles>> dependency in a profile applications resource
+ result = EcoreUtil.getObjectByType(resource.getContents(), ProfileExternalizationPackage.Literals.APPLY_PROFILES) != null;
+ }
+
+ return result;
+ }
+
+ /**
+ * Queries whether a resource is a loaded decorator model for the given user model resource.
+ * <p>
+ * This method does <em>not</em> access the decorator model index.
+ *
+ * @param resource
+ * a resource
+ * @param modelResource
+ * a user model resource
+ *
+ * @return whether the {@code resource} is a loaded decorator model for the user model resource
+ */
+ public static boolean isDecoratorModelFor(Resource resource, Resource modelResource) {
+ boolean result = false;
+
+ ResourceSet rset = resource.getResourceSet();
+ if (rset != null) {
+ for (ApplyProfiles next : Iterables.filter(EcoreUtil.getObjectsByType(resource.getContents(), ProfileExternalizationPackage.Literals.APPLY_PROFILES), ApplyProfiles.class)) {
+ Dependency baseDependency = next.getBase_Dependency();
+ if (baseDependency != null) {
+ for (Iterator<NamedElement> iter = ((InternalEList<NamedElement>) baseDependency.getClients()).basicIterator(); !result && iter.hasNext();) {
+ NamedElement client = iter.next();
+ if (client.eIsProxy()) {
+ URI uri = EcoreUtil.getURI(client).trimFragment();
+ result = uri.equals(modelResource.getURI());
+ } else {
+ result = client.eResource() == modelResource;
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Queries the URIs of user model resources that contain packages for which a decorator model provides applied profiles.
+ * <p>
+ * This method does <em>not</em> access the decorator model index.
+ *
+ * @param decoratorModelResource
+ * a resource in a decorator model
+ *
+ * @return the URIs of resources in user models containing packages to which the decorator model applies profiles
+ */
+ public static Set<URI> getUserModelResources(Resource decoratorModelResource) {
+ Set<URI> result = Sets.newHashSet();
+
+ for (ApplyProfiles next : Iterables.filter(EcoreUtil.getObjectsByType(decoratorModelResource.getContents(), ProfileExternalizationPackage.Literals.APPLY_PROFILES), ApplyProfiles.class)) {
+ Dependency baseDependency = next.getBase_Dependency();
+ if (baseDependency != null) {
+ for (Iterator<NamedElement> iter = ((InternalEList<NamedElement>) baseDependency.getClients()).basicIterator(); iter.hasNext();) {
+ NamedElement client = iter.next();
+ if (client.eIsProxy()) {
+ result.add(EcoreUtil.getURI(client).trimFragment());
+ } else {
+ result.add(client.eResource().getURI());
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Whether the resource indicated by the given URI is a decorator model resource.
+ * <p>
+ * This method does <em>not</em> access the decorator model index.
+ *
+ * @param uri
+ * the URI of some resource, which may or may not exist
+ *
+ * @return whether the resource at the URI exists and is a decorator model
+ */
+ public static boolean isDecoratorModel(URI uri) {
+ boolean result = false;
+
+ if (uri.isPlatformResource()) {
+ // Let the workspace's content-type manager handle it (which can cache the information)
+ IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(uri.toPlatformString(true)));
+
+ try {
+ IContentDescription desc = file.exists() ? file.getContentDescription() : null;
+ result = (desc != null) && (desc.getContentType() != null) && desc.getContentType().isKindOf(DECORATOR_MODEL_CONTENT_TYPE);
+ } catch (CoreException e) {
+ // Couldn't determine content description? Then it cannot be our type
+ Activator.getDefault().getLog().log(e.getStatus());
+ }
+ } else {
+ // Work it out the hard way
+ InputStream input = null;
+
+ try {
+ input = URIConverter.INSTANCE.createInputStream(uri);
+ if (!input.markSupported()) {
+ input = new BufferedInputStream(input);
+ }
+ input.mark(Integer.MAX_VALUE);
+
+ Map<String, ?> desc = DECORATOR_MODEL_CONTENT_HANDLER.contentDescription(uri, input, Maps.newHashMap(), Maps.newHashMap());
+ result = desc.get(ContentHandler.VALIDITY_PROPERTY) == ContentHandler.Validity.VALID;
+ } catch (Exception e) {
+ // Couldn't read the contents? Then it's not what we're looking for
+ } finally {
+ if (input != null) {
+ try {
+ input.close();
+ } catch (Exception e) {
+ Activator.log.error(e);
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Queries the URIs of decorator model resources currently loaded in a user model resource's resource-set that contain
+ * profile applications for packages in that user model resource.
+ * <p>
+ * This method does <em>not</em> access the decorator model index.
+ *
+ * @param modelResource
+ * a resource in an user model
+ *
+ * @return the URIs of resources currently loaded in the same resource set that provide profile applications to packages
+ * in the user model resource
+ */
+ public static Set<URI> getLoadedDecoratorModels(Resource modelResource) {
+ Element root = (Element) EcoreUtil.getObjectByType(modelResource.getContents(), UMLPackage.Literals.ELEMENT);
+ if (root == null) {
+ return Collections.emptySet();
+ }
+
+ CacheAdapter cache = CacheAdapter.getCacheAdapter(root);
+
+ @SuppressWarnings("unchecked")
+ Set<URI> result = (Set<URI>) cache.get(root, LOADED_RESOURCES_CACHE_KEY);
+ if (result == null) {
+ result = Sets.newHashSet();
+ collectLoadedDecoratorModels(modelResource, result);
+ cache.put(root, LOADED_RESOURCES_CACHE_KEY, result);
+ }
+
+ return result;
+ }
+
+ private static void collectLoadedDecoratorModels(Resource modelResource, Set<URI> result) {
+ // We don't do externalization of profile applications in the resources that externalize profile applications
+ if (!isDecoratorModel(modelResource)) {
+ ResourceSet resourceSet = modelResource.getResourceSet();
+ URI modelURI = modelResource.getURI();
+ for (Resource next : resourceSet.getResources()) {
+ URI uri = next.getURI();
+ if (next.isLoaded() && !uri.equals(modelURI) && isDecoratorModelFor(next, modelResource)) {
+ result.add(uri);
+ }
+ }
+ }
+ }
+
+ /**
+ * Queries the URIs of decorator models in the workspace that are not yet loaded that provide profile applications for
+ * packages in the given user model resource. This set excludes and decorator models that have profile applications that
+ * would conflict with natively-applied profiles of packages in the user model resource, as it would not be permitted
+ * to load any of these.
+ * <p>
+ * This method <em>accesses the decorator model index</em> and is therefore not suitable for use in time-sensitive code because an invocation may block the caller for an indeterminate interval. In cases where responsiveness is essential, use the
+ * {@link #getUnloadedDecoratorModelsAsync(Resource)} API, instead.
+ *
+ * @param modelResource
+ * a user model resource
+ * @return the URIs of its currently available unloaded decorator models
+ *
+ * @see #getUnloadedDecoratorModelsAsync(Resource)
+ */
+ public static Set<URI> getUnloadedDecoratorModels(Resource modelResource) {
+ Element root = (Element) EcoreUtil.getObjectByType(modelResource.getContents(), UMLPackage.Literals.ELEMENT);
+ if (root == null) {
+ return Collections.emptySet();
+ }
+
+ CacheAdapter cache = CacheAdapter.getCacheAdapter(root);
+
+ @SuppressWarnings("unchecked")
+ Set<URI> result = (Set<URI>) cache.get(root, UNLOADED_RESOURCE_DECORATORS_CACHE_KEY);
+ if (result == null) {
+ result = Sets.newHashSet();
+ try {
+ collectUnloadedDecoratorModels(DecoratorModelIndex.getInstance().getDecoratorModels(), modelResource, result);
+ } catch (CoreException e) {
+ Activator.log.error("Error in determining unloaded decorator models.", e); //$NON-NLS-1$
+ }
+ cache.put(root, UNLOADED_RESOURCE_DECORATORS_CACHE_KEY, result);
+ }
+
+ return result;
+ }
+
+ /**
+ * Asynchronously queries the URIs of decorator models in the workspace that are not yet loaded that provide profile applications for
+ * packages in the given user model resource. This set excludes and decorator models that have profile applications that
+ * would conflict with natively-applied profiles of packages in the user model resource, as it would not be permitted
+ * to load any of these.
+ *
+ * @param modelResource
+ * a user model resource
+ * @return the future result of the URIs of its currently available unloaded decorator models
+ *
+ * @see #getUnloadedDecoratorModelsAsync(Iterable)
+ * @see #getUnloadedDecoratorModelsAsync(Package)
+ * @see #getUnloadedDecoratorModels(Resource)
+ */
+ public static ListenableFuture<Set<URI>> getUnloadedDecoratorModelsAsync(final Resource modelResource) {
+ return getUnloadedDecoratorModelsAsync(Collections.singleton(modelResource));
+ }
+
+ /**
+ * Asynchronously queries the URIs of decorator models in the workspace that are not yet loaded that provide profile applications for
+ * packages in the given user model resources. This set excludes and decorator models that have profile applications that
+ * would conflict with natively-applied profiles of packages in the user model resources, as it would not be permitted
+ * to load any of these.
+ *
+ * @param modelResources
+ * zero or more user model resources
+ * @return the future result of the URIs of their currently available unloaded decorator models
+ *
+ * @see #getUnloadedDecoratorModelsAsync(Resource)
+ * @see #getUnloadedDecoratorModelsAsync(Package)
+ */
+ public static ListenableFuture<Set<URI>> getUnloadedDecoratorModelsAsync(final Iterable<Resource> modelResources) {
+ if (Iterables.isEmpty(modelResources)) {
+ return Futures.immediateFuture(Collections.<URI> emptySet());
+ }
+
+ ListenableFuture<SetMultimap<URI, URI>> decoratorMap = DecoratorModelIndex.getInstance().getDecoratorModelsAsync();
+ Function<SetMultimap<URI, URI>, Set<URI>> transform = new Function<SetMultimap<URI, URI>, Set<URI>>() {
+ @Override
+ public Set<URI> apply(SetMultimap<URI, URI> input) {
+ Set<URI> result = Sets.newHashSet();
+
+ for (Resource modelResource : modelResources) {
+ Element root = Iterables.isEmpty(modelResources) ? null : (Element) EcoreUtil.getObjectByType(modelResource.getContents(), UMLPackage.Literals.ELEMENT);
+ if (root != null) {
+ CacheAdapter cache = CacheAdapter.getCacheAdapter(root);
+
+ @SuppressWarnings("unchecked")
+ Set<URI> local = (Set<URI>) cache.get(root, UNLOADED_RESOURCE_DECORATORS_CACHE_KEY);
+ if (local == null) {
+ local = Sets.newHashSet();
+ collectUnloadedDecoratorModels(input, modelResource, local);
+ cache.put(root, UNLOADED_RESOURCE_DECORATORS_CACHE_KEY, local);
+ }
+ result.addAll(local);
+ }
+ }
+
+ return result;
+ }
+ };
+
+ return Futures.transform(decoratorMap, transform);
+ }
+
+ /**
+ * Asynchronously queries the URIs of decorator models in the workspace that are not yet loaded that provide profile applications for
+ * the given user model package. This set excludes and decorator models that have profile applications that
+ * would conflict with natively-applied profiles of that package, as it would not be permitted
+ * to load any of these.
+ *
+ * @param package_
+ * a package in a user model
+ * @return the future result of the URIs of its currently available unloaded decorator models
+ *
+ * @see #getUnloadedDecoratorModelsAsync(Resource)
+ * @see #getUnloadedDecoratorModelsAsync(Iterable)
+ */
+ public static ListenableFuture<Set<URI>> getUnloadedDecoratorModelsAsync(final Package package_) {
+ if (package_.eResource() == null) {
+ return Futures.immediateFuture(Collections.<URI> emptySet());
+ }
+
+ CacheAdapter cache = CacheAdapter.getCacheAdapter(package_);
+ @SuppressWarnings("unchecked")
+ Set<URI> cached = (Set<URI>) cache.get(package_, UNLOADED_PACKAGE_DECORATORS_CACHE_KEY);
+ if (cached != null) {
+ return Futures.immediateFuture(cached);
+ }
+
+ ListenableFuture<Set<URI>> decoratorMap = DecoratorModelIndex.getInstance().getDecoratorModelsForPackageAsync(EcoreUtil.getURI(package_));
+ Function<Set<URI>, Set<URI>> transform = new Function<Set<URI>, Set<URI>>() {
+ @Override
+ public Set<URI> apply(Set<URI> input) {
+ Set<URI> result = Sets.newHashSet();
+
+ Resource resource = package_.eResource();
+ if (resource != null) {
+ try {
+ collectUnloadedDecoratorModels(DecoratorModelIndex.getInstance().getDecoratorModels(), resource, result);
+ } catch (CoreException e) {
+ throw new UncheckedExecutionException(e);
+ }
+ }
+
+ // filter for only those unloaded resources that apply profiles to this package
+ result.retainAll(input);
+
+ CacheAdapter cache = CacheAdapter.getCacheAdapter(package_);
+ cache.put(package_, UNLOADED_PACKAGE_DECORATORS_CACHE_KEY, result);
+
+ return result;
+ }
+ };
+
+ return Futures.transform(decoratorMap, transform);
+ }
+
+ /**
+ * Asynchronously queries whether the resource containing the given package (or, optionally, any of its currently loaded
+ * sub-units) has applicable decorator models that are not yet loaded.
+ *
+ * @param package_
+ * a package in a user model
+ * @param recursive
+ * whether to check loaded sub-units recursively
+ * @return the future result of whether the package has available unloaded decorator models
+ *
+ * @see #getUnloadedDecoratorModelsAsync(Resource)
+ */
+ public static ListenableFuture<Boolean> hasUnloadedDecoratorModelsAsync(Package package_, boolean recursive) {
+ Resource modelResource = package_.eResource();
+ if ((modelResource == null) || isDecoratorModel(modelResource)) {
+ return Futures.immediateFuture(Boolean.FALSE);
+ }
+
+ Iterable<Resource> resources = Collections.singleton(modelResource);
+ if (recursive) {
+ resources = Iterables.concat(resources, getLoadedSubUnitPackageResources(package_));
+ }
+
+ return Futures.transform(getUnloadedDecoratorModelsAsync(resources), new Function<Collection<?>, Boolean>() {
+ @Override
+ public Boolean apply(Collection<?> input) {
+ return (input != null) && !input.isEmpty();
+ }
+ });
+ }
+
+ private static void collectUnloadedDecoratorModels(SetMultimap<URI, URI> userModelsToDecoratorModels, Resource modelResource, Set<URI> result) {
+ URI uri = modelResource.getURI();
+ ResourceSet resourceSet = modelResource.getResourceSet();
+
+ // We don't do externalization of profile applications in the resources that externalize profile applications
+ if (uri.isPlatformResource() && !isDecoratorModel(modelResource)) {
+ // Managing the resources to delete on save only applies to model-sets
+ Set<URI> pendingDeletion = (resourceSet instanceof ModelSet) ? ((ModelSet) resourceSet).getResourcesToDeleteOnSave() : Collections.<URI> emptySet();
+
+ try {
+ for (URI indexed : Sets.difference(userModelsToDecoratorModels.get(uri), pendingDeletion)) {
+ Resource indexedResource = resourceSet.getResource(indexed, false);
+ if ((indexedResource == null) || !indexedResource.isLoaded()) {
+ // Don't include resources that have profile applications conflicting with profile applications
+ // owned by the current model
+ if (!hasConflictingProfileApplication(indexed, modelResource)) {
+ result.add(indexed);
+ }
+ }
+ }
+ } catch (CoreException e) {
+ Activator.log.error("Error in determining unloaded decorator models.", e); //$NON-NLS-1$
+ }
+ }
+ }
+
+ private static Collection<ProfileApplication> getIntrinsicProfileApplications(Resource modelResource) {
+ Element root = (Element) EcoreUtil.getObjectByType(modelResource.getContents(), UMLPackage.Literals.ELEMENT);
+ if (root == null) {
+ return Collections.emptyList();
+ }
+
+ CacheAdapter cache = CacheAdapter.getCacheAdapter(root);
+
+ @SuppressWarnings("unchecked")
+ Collection<ProfileApplication> result = (Collection<ProfileApplication>) cache.get(root, INTRINSIC_PROFILE_APPLICATIONS_CACHE_KEY);
+ if (result == null) {
+ result = Lists.newArrayList();
+ for (TreeIterator<EObject> iter = EcoreUtil.getAllProperContents(root, false); iter.hasNext();) {
+ EObject next = iter.next();
+ if (next instanceof ProfileApplication) {
+ result.add((ProfileApplication) next);
+
+ // No profile applications inside a profile application
+ iter.prune();
+ } else if (!((next instanceof Package) || (next instanceof Component))) {
+ // Packages are only in packages or components, and that's where profile applications may be found
+ iter.prune();
+ }
+ }
+ cache.put(root, INTRINSIC_PROFILE_APPLICATIONS_CACHE_KEY, result);
+ }
+
+ return result;
+ }
+
+ private static boolean hasConflictingProfileApplication(URI profileApplicationResourceURI, Resource modelResource) throws CoreException {
+ boolean result = false;
+
+ SetMultimap<URI, URI> indexed = DecoratorModelIndex.getInstance().getAppliedProfilesByPackage(profileApplicationResourceURI);
+
+ for (ProfileApplication profileApplication : getIntrinsicProfileApplications(modelResource)) {
+ if (indexed.containsEntry(EcoreUtil.getURI(profileApplication.getApplyingPackage()), EcoreUtil.getURI(profileApplication.getAppliedProfile()))) {
+ result = true;
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Obtains the currently loaded packages nested to any depth within the given package that are roots of sub-unit resources.
+ * <p>
+ * This method does <em>not</em> access the decorator model index.
+ *
+ * @param package_
+ * a package in an user model
+ *
+ * @return nested packages that are roots of loaded sub-unit resources
+ */
+ public static Iterable<Package> getLoadedSubUnitPackages(Package package_) {
+ List<Package> result = Lists.newArrayListWithExpectedSize(0);
+
+ final Resource topResource = package_.eResource();
+ for (TreeIterator<EObject> iter = EcoreUtil.getAllContents(package_, false); iter.hasNext();) {
+ EObject next = iter.next();
+ if (next instanceof Package) {
+ if (!next.eIsProxy() && (next.eResource() != topResource)) {
+ // It's in a loaded sub-unit
+ result.add((Package) next);
+ }
+ } else if (!(next instanceof Component)) {
+ // No sense in looking into anything that can't contain packages
+ iter.prune();
+ }
+ }
+
+ return result;
+ }
+
+ static Iterable<Resource> getLoadedSubUnitPackageResources(Package package_) {
+ return Iterables.transform(getLoadedSubUnitPackages(package_), getResourceFunction());
+ }
+
+ static Function<EObject, Resource> getResourceFunction() {
+ return new Function<EObject, Resource>() {
+ @Override
+ public Resource apply(EObject input) {
+ return input.eResource();
+ }
+ };
+ }
+
+ /**
+ * Loads the specified decorator models in a given resource set context.
+ * <p>
+ * This method does <em>not</em> access the decorator model index.
+ *
+ * @param resourceSet
+ * the context in which to load the decorator models
+ * @param resourceURIs
+ * URIs of the decorator models to load
+ *
+ * @return whether the decorator models were successfully loaded
+ */
+ public static boolean loadDecoratorModels(final ResourceSet resourceSet, final Iterable<? extends URI> resourceURIs) {
+ boolean result = false;
+
+ Runnable operation = new Runnable() {
+ @Override
+ public void run() {
+ if (resourceSet instanceof ModelSet) {
+ DecoratorModel model = DecoratorModel.getInstance((ModelSet) resourceSet);
+ for (URI next : resourceURIs) {
+ model.loadDecoratorModel(next);
+ }
+ } else {
+ for (URI next : resourceURIs) {
+ resourceSet.getResource(next, true);
+ }
+ }
+ }
+ };
+
+ TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(resourceSet);
+ if (domain != null) {
+ try {
+ domain.runExclusive(operation);
+ result = true;
+ } catch (InterruptedException e) {
+ Activator.log.error(e);
+ }
+ } else {
+ operation.run();
+ }
+
+ return result;
+ }
+
+ /**
+ * Configures a resource set to support profile applications externalized in decorator models.
+ *
+ * @param resourceSet
+ * the resource set to configure
+ */
+ public static void configure(ResourceSet resourceSet) {
+ if (resourceSet == null) {
+ throw new IllegalArgumentException("null resourceSet"); //$NON-NLS-1$
+ }
+
+ UMLUtil.ProfileApplicationHelper.setInstance(resourceSet, new PapyrusProfileApplicationHelper());
+ UMLUtil.StereotypeApplicationHelper.setInstance(resourceSet, new PapyrusStereotypeApplicationHelper());
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/helper/IDeleteEmptyDecoratorModelsPolicy.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/helper/IDeleteEmptyDecoratorModelsPolicy.java
new file mode 100644
index 00000000000..9684e2d5986
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/helper/IDeleteEmptyDecoratorModelsPolicy.java
@@ -0,0 +1,33 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.helper;
+
+import java.util.Collection;
+
+import org.eclipse.emf.ecore.resource.Resource;
+
+/**
+ * A protocol by which the profile-application reintegration command can query the client whether to delete decorator models that have been emptied of
+ * the last of their profile applications.
+ */
+public interface IDeleteEmptyDecoratorModelsPolicy {
+ /**
+ * Queries whether the specified decorator model resources may be deleted now that they contain no more profile applications.
+ *
+ * @param decoratorModels
+ * decorator models to delete
+ * @return whether they should be deleted
+ */
+ boolean shouldDeleteDecoratorModels(Collection<? extends Resource> decoratorModels);
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/helper/PapyrusProfileApplicationHelper.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/helper/PapyrusProfileApplicationHelper.java
new file mode 100644
index 00000000000..cc2eccbc898
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/helper/PapyrusProfileApplicationHelper.java
@@ -0,0 +1,61 @@
+/*****************************************************************************
+ * Copyright (c) 2013, 2014 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:
+ * Remi Schnekenburger (CEA LIST) - Initial API and implementation
+ * Christian W. Damus - bug 399859
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.uml.decoratormodel.helper;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.util.UMLUtil.ProfileApplicationHelper;
+
+import com.google.common.collect.Iterables;
+
+
+/**
+ * Extended profile application helper for Papyrus tool.
+ * <P>
+ * When this helper is activated, profiles are located in external resources
+ * </P>
+ */
+public class PapyrusProfileApplicationHelper extends ProfileApplicationHelper {
+
+ @Override
+ public Iterable<Package> getOtherApplyingPackages(Package package_) {
+ Iterable<Package> result = super.getOtherApplyingPackages(package_);
+ Set<Package> combined = null;
+
+ for (Package parent : Iterables.concat(Collections.singleton(package_), result)) {
+ Iterator<Package> externalized = DecoratorModelUtils.getDecoratorPackages(parent).iterator();
+ if (externalized.hasNext()) {
+ if (combined == null) {
+ combined = new LinkedHashSet<Package>();
+
+ Iterables.addAll(combined, result);
+ }
+
+ while (externalized.hasNext()) {
+ combined.add(externalized.next());
+ }
+ }
+ }
+
+ if (combined != null) {
+ result = combined;
+ }
+
+ return result;
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/helper/PapyrusStereotypeApplicationHelper.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/helper/PapyrusStereotypeApplicationHelper.java
new file mode 100644
index 00000000000..73c14a72675
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/helper/PapyrusStereotypeApplicationHelper.java
@@ -0,0 +1,46 @@
+/*****************************************************************************
+ * Copyright (c) 2013, 2014 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:
+ * Remi Schnekenburger (CEA LIST) - Initial API and implementation
+ * Christian W. Damus - bug 399859
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.uml.decoratormodel.helper;
+
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.papyrus.uml.tools.utils.ProfileUtil;
+import org.eclipse.uml2.uml.Element;
+import org.eclipse.uml2.uml.ProfileApplication;
+import org.eclipse.uml2.uml.util.UMLUtil.StereotypeApplicationHelper;
+
+
+/**
+ * Specific Stereotype Application Helper for Papyrus tool. If it detects the model is not a model handled by Papyrus, it will delegate to the standard Stereotype application helper.
+ */
+public class PapyrusStereotypeApplicationHelper extends StereotypeApplicationHelper {
+
+ @Override
+ protected EList<EObject> getContainmentList(Element element, EClass definition) {
+ // Locate stereotype applications in the same resource as the profile application
+
+ ProfileApplication profileApplication = ProfileUtil.getProfileApplication(element, definition);
+ if (profileApplication != null) {
+ Resource containingResource = profileApplication.eResource();
+ if (containingResource != null) {
+ return containingResource.getContents();
+ }
+ }
+
+ return super.getContainmentList(element, definition);
+ }
+
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/commands/CreateDecoratorModelCommand.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/commands/CreateDecoratorModelCommand.java
new file mode 100644
index 00000000000..5be5f0036fc
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/commands/CreateDecoratorModelCommand.java
@@ -0,0 +1,130 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.commands;
+
+import org.eclipse.emf.common.command.AbstractCommand;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.InternalEObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.uml.decoratormodel.helper.DecoratorModelUtils;
+import org.eclipse.papyrus.uml.decoratormodel.internal.messages.Messages;
+import org.eclipse.papyrus.uml.decoratormodel.model.DecoratorModel;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.Profile;
+import org.eclipse.uml2.uml.UMLFactory;
+import org.eclipse.uml2.uml.UMLPackage;
+
+/**
+ * A command that ensures existence of the decorator model resource into which profile applications will be put by the {@link SeparateProfileApplicationsCommand}. Undoing this command will remove the decorator model resource from
+ * the resource set if it created it.
+ */
+public class CreateDecoratorModelCommand extends AbstractCommand {
+ private final TransactionalEditingDomain domain;
+ private final URI resourceURI;
+ private final String modelName;
+
+ private Resource createdResource;
+ private Package createdDecoratorModel;
+
+ public CreateDecoratorModelCommand(TransactionalEditingDomain domain, URI resourceURI, String modelName) {
+ super(Messages.CreateDecoratorModelCommand_0);
+
+ this.domain = domain;
+ this.resourceURI = resourceURI;
+ this.modelName = modelName;
+ }
+
+ @Override
+ protected boolean prepare() {
+ return (domain != null) && (domain.getResourceSet() != null) && (resourceURI != null);
+ }
+
+ @Override
+ public void execute() {
+ ResourceSet resourceSet = domain.getResourceSet();
+ Resource decoratorModel = resourceSet.getResource(resourceURI, false);
+
+ if (decoratorModel == null) {
+ if (canLoad(resourceSet, resourceURI)) {
+ // Just load it, then, for the next command to find. This is not undoable (nor needs to be)
+ resourceSet.getResource(resourceURI, true);
+ } else {
+ // Create the new decorator model resource
+ if (resourceSet instanceof ModelSet) {
+ DecoratorModel model = DecoratorModel.getInstance((ModelSet) resourceSet);
+ createdResource = model.loadDecoratorModel(resourceURI);
+ } else {
+ // Ensure that we get a UML resource, regardless of the URI
+ createdResource = resourceSet.createResource(resourceURI, UMLPackage.eCONTENT_TYPE);
+ }
+
+ initializeDecoratorModel(createdResource, modelName);
+ }
+ }
+ }
+
+ protected void initializeDecoratorModel(Resource resource, String modelName) {
+ createdDecoratorModel = UMLFactory.eINSTANCE.createPackage();
+ createdDecoratorModel.setName(modelName);
+ resource.getContents().add(createdDecoratorModel);
+
+ // The Externalization Profile is applied here so that it is not inherited by the packages in the user model
+ Profile externalizationProfile = DecoratorModelUtils.getExternalizationProfile(resource.getResourceSet());
+ createdDecoratorModel.applyProfile(externalizationProfile);
+ }
+
+ protected boolean canLoad(ResourceSet resourceSet, URI resourceURI) {
+ boolean result = resourceSet.getURIConverter().exists(resourceURI, null);
+
+ if (result) {
+ // Furthermore, is it a decorator model?
+ result = DecoratorModelUtils.isDecoratorModel(resourceURI);
+ }
+
+ return result;
+ }
+
+ @Override
+ public boolean canUndo() {
+ return true;
+ }
+
+ @Override
+ public void undo() {
+ if (createdResource != null) {
+ // Unload it and remove it
+ createdResource.unload();
+ createdResource.getResourceSet().getResources().remove(createdResource);
+ createdResource.eAdapters().clear();
+ }
+ }
+
+ @Override
+ public void redo() {
+ if (createdResource != null) {
+ ResourceSet resourceSet = domain.getResourceSet();
+ if (resourceSet.getResource(createdResource.getURI(), false) == null) {
+ // Simply put the same resource back
+ resourceSet.getResources().add(createdResource);
+ createdResource.getContents().clear(); // Just in case
+ createdResource.getContents().add(createdDecoratorModel);
+ ((InternalEObject) createdDecoratorModel).eSetProxyURI(null);
+ }
+ }
+ }
+
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/commands/DeleteDecoratorModelCommand.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/commands/DeleteDecoratorModelCommand.java
new file mode 100644
index 00000000000..87a8a0ee367
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/commands/DeleteDecoratorModelCommand.java
@@ -0,0 +1,105 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.commands;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.eclipse.emf.common.command.AbstractCommand;
+import org.eclipse.emf.common.command.AbstractCommand.NonDirtying;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.uml.decoratormodel.internal.messages.Messages;
+
+import com.google.common.collect.Lists;
+
+/**
+ * A command that ensures the next save of the {@link ModelSet} will delete the decorator model
+ * emptied out by some previous {@link ReclaimProfileApplicationsCommand}.
+ */
+public class DeleteDecoratorModelCommand extends AbstractCommand implements NonDirtying {
+ private final ModelSet modelSet;
+ private final Resource resource;
+ private Collection<Resource> deleted;
+
+ public DeleteDecoratorModelCommand(ModelSet modelSet, Resource resource) {
+ super(Messages.DeleteDecoratorModelCommand_0);
+
+ this.modelSet = modelSet;
+ this.resource = resource;
+ }
+
+ @Override
+ protected boolean prepare() {
+ return (resource != null) && resource.isLoaded();
+ }
+
+ @Override
+ public void execute() {
+ if (resource.getContents().isEmpty()) {
+ // there are usually three resources to delete in any Papyrus model
+ deleted = Lists.newArrayListWithExpectedSize(3);
+
+ modelSet.getResourcesToDeleteOnSave().add(resource.getURI());
+ resource.unload();
+ modelSet.getResources().remove(resource);
+ resource.eAdapters().clear();
+ deleted.add(resource);
+
+ // find its siblings
+ URI withoutExtension = resource.getURI().trimFileExtension();
+ for (Iterator<Resource> iter = modelSet.getResources().iterator(); iter.hasNext();) {
+ Resource next = iter.next();
+ if (next.getURI().trimFileExtension().equals(withoutExtension)) {
+ modelSet.getResourcesToDeleteOnSave().add(next.getURI());
+ next.unload();
+ iter.remove();
+ next.eAdapters().clear();
+ deleted.add(next);
+ }
+ }
+ }
+ }
+
+ /**
+ * Because this command only unloads the resource if it's empty, this is undoable simply by re-adding the resource to the resource set.
+ *
+ * @return {@code true}, always
+ */
+ @Override
+ public boolean canUndo() {
+ return true;
+ }
+
+ @Override
+ public void undo() {
+ if (deleted != null) {
+ for (Resource next : deleted) {
+ modelSet.getResourcesToDeleteOnSave().remove(next.getURI());
+ if (modelSet.getResource(next.getURI(), false) == null) {
+ modelSet.getResources().add(next);
+
+ // Don't attempt to load the resource because we'll be putting its contents back as part of the undo!
+ }
+ }
+ }
+ }
+
+ @Override
+ public void redo() {
+ execute();
+ }
+
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/commands/ReclaimProfileApplicationsCommand.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/commands/ReclaimProfileApplicationsCommand.java
new file mode 100644
index 00000000000..1e5cb0af714
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/commands/ReclaimProfileApplicationsCommand.java
@@ -0,0 +1,44 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.commands;
+
+import org.eclipse.emf.transaction.RecordingCommand;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.papyrus.uml.decoratormodel.helper.DecoratorModelUtils;
+import org.eclipse.papyrus.uml.decoratormodel.helper.IDeleteEmptyDecoratorModelsPolicy;
+import org.eclipse.papyrus.uml.decoratormodel.internal.messages.Messages;
+import org.eclipse.uml2.uml.ProfileApplication;
+
+/**
+ * A command that brings one or more profile applications back from a separate resource into the UML model.
+ */
+public class ReclaimProfileApplicationsCommand extends RecordingCommand {
+
+ private final IDeleteEmptyDecoratorModelsPolicy deletePolicy;
+
+ private final Iterable<? extends ProfileApplication> profileApplications;
+
+ public ReclaimProfileApplicationsCommand(TransactionalEditingDomain domain, Iterable<? extends ProfileApplication> profileApplications, IDeleteEmptyDecoratorModelsPolicy deletePolicy) {
+ super(domain, Messages.ReclaimProfileApplicationsCommand_0);
+
+ this.profileApplications = profileApplications;
+ this.deletePolicy = deletePolicy;
+ }
+
+ @Override
+ protected void doExecute() {
+ DecoratorModelUtils.internalizeProfileApplications(profileApplications, deletePolicy);
+ }
+
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/commands/SaveDecoratorModelCommand.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/commands/SaveDecoratorModelCommand.java
new file mode 100644
index 00000000000..7a6b3ddc1c2
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/commands/SaveDecoratorModelCommand.java
@@ -0,0 +1,74 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.commands;
+
+import java.util.Set;
+
+import org.eclipse.emf.common.command.AbstractCommand;
+import org.eclipse.emf.common.command.AbstractCommand.NonDirtying;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.uml.decoratormodel.internal.messages.Messages;
+
+import com.google.common.collect.Sets;
+
+/**
+ * A command that ensures the next save of the {@link ModelSet} will save the decorator model
+ * potentially created (if not already existing) by some previous {@link SeparateProfileApplicationsCommand}.
+ */
+public class SaveDecoratorModelCommand extends AbstractCommand implements NonDirtying {
+ private final ModelSet modelSet;
+ private final URI resourceURIWithoutExtension;
+ private Set<URI> rescued;
+
+ public SaveDecoratorModelCommand(ModelSet modelSet, URI resourceURI) {
+ super(Messages.SaveDecoratorModelCommand_0);
+
+ this.modelSet = modelSet;
+ this.resourceURIWithoutExtension = resourceURI.trimFileExtension();
+ }
+
+ @Override
+ protected boolean prepare() {
+ rescued = Sets.newHashSet();
+ for (URI next : modelSet.getResourcesToDeleteOnSave()) {
+ if (next.trimFileExtension().equals(resourceURIWithoutExtension)) {
+ rescued.add(next);
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean canUndo() {
+ return true;
+ }
+
+ @Override
+ public void execute() {
+ modelSet.getResourcesToDeleteOnSave().removeAll(rescued);
+ }
+
+ @Override
+ public void undo() {
+ modelSet.getResourcesToDeleteOnSave().addAll(rescued);
+ }
+
+ @Override
+ public void redo() {
+ execute();
+ }
+
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/commands/SeparateProfileApplicationsCommand.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/commands/SeparateProfileApplicationsCommand.java
new file mode 100644
index 00000000000..c5b65962148
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/commands/SeparateProfileApplicationsCommand.java
@@ -0,0 +1,53 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.commands;
+
+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.transaction.RecordingCommand;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.papyrus.uml.decoratormodel.helper.DecoratorModelUtils;
+import org.eclipse.papyrus.uml.decoratormodel.internal.messages.Messages;
+import org.eclipse.uml2.uml.ProfileApplication;
+
+/**
+ * A command that factors out one or more profile applications into a separate resource.
+ * This command has a pre-requisite that the decorator model resource must already exist when it executes. This may be
+ * satisfied either by the resource already existing in storage or being created by a previous command in a compound.
+ */
+public class SeparateProfileApplicationsCommand extends RecordingCommand {
+
+ private final ResourceSet resourceSet;
+ private final Iterable<? extends ProfileApplication> profileApplications;
+ private final URI resourceURI;
+
+ public SeparateProfileApplicationsCommand(TransactionalEditingDomain domain, Iterable<? extends ProfileApplication> profileApplications, URI resourceURI) {
+ super(domain, Messages.SeparateProfileApplicationsCommand_0);
+
+ this.resourceSet = domain.getResourceSet();
+ this.profileApplications = profileApplications;
+ this.resourceURI = resourceURI;
+ }
+
+ @Override
+ protected void doExecute() {
+ Resource decoratorModel = resourceSet.getResource(resourceURI, true);
+
+ for (ProfileApplication profileApplication : profileApplications) {
+ DecoratorModelUtils.externalizeProfileApplication(profileApplication, decoratorModel);
+ }
+ }
+
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/expressions/FilePropertyTester.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/expressions/FilePropertyTester.java
new file mode 100644
index 00000000000..ebaba3f98db
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/expressions/FilePropertyTester.java
@@ -0,0 +1,54 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.expressions;
+
+import org.eclipse.core.expressions.PropertyTester;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.papyrus.uml.decoratormodel.helper.DecoratorModelUtils;
+
+/**
+ * A core-expressions property tester for {@link IFile}s.
+ */
+public class FilePropertyTester extends PropertyTester {
+ public static final String PROPERTY_IS_DECORATOR_MODEL = "isDecoratorModel"; //$NON-NLS-1$
+
+ public FilePropertyTester() {
+ super();
+ }
+
+ @Override
+ public boolean test(Object receiver, String property, Object[] args, Object expectedValue) {
+ boolean result = false;
+ if (receiver instanceof IFile) {
+ IFile file = (IFile) receiver;
+
+ if (PROPERTY_IS_DECORATOR_MODEL.equals(property)) {
+ result = expectBoolean(expectedValue) == isDecoratorModel(file);
+ }
+ }
+
+ return result;
+ }
+
+ private static boolean expectBoolean(Object expectedValue) {
+ return (expectedValue == null) || ((expectedValue instanceof Boolean) && ((Boolean) expectedValue).booleanValue());
+ }
+
+ boolean isDecoratorModel(IFile file) {
+ URI uri = URI.createPlatformResourceURI(file.getFullPath().toString(), true);
+ return DecoratorModelUtils.isDecoratorModel(uri);
+ }
+
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/messages/Messages.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/messages/Messages.java
new file mode 100644
index 00000000000..a48cbbd3b59
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/messages/Messages.java
@@ -0,0 +1,37 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.messages;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * @author damus
+ *
+ */
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.papyrus.uml.decoratormodel.internal.messages.messages"; //$NON-NLS-1$
+ public static String CreateDecoratorModelCommand_0;
+ public static String DecoratorModelIndex_0;
+ public static String DeleteDecoratorModelCommand_0;
+ public static String ReclaimProfileApplicationsCommand_0;
+ public static String SaveDecoratorModelCommand_0;
+ public static String SeparateProfileApplicationsCommand_0;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/messages/messages.properties b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/messages/messages.properties
new file mode 100644
index 00000000000..8fa99336bb3
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/messages/messages.properties
@@ -0,0 +1,6 @@
+CreateDecoratorModelCommand_0=Create Profile Application
+DecoratorModelIndex_0=Failed to access profile application index
+DeleteDecoratorModelCommand_0=Delete Profile Application
+ReclaimProfileApplicationsCommand_0=Reclaim Profile Applications
+SaveDecoratorModelCommand_0=Save Profile Application
+SeparateProfileApplicationsCommand_0=Separate Profile Applications
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/providers/ExternalizedProfileApplicationDelegate.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/providers/ExternalizedProfileApplicationDelegate.java
new file mode 100644
index 00000000000..f2f4ae44a3c
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/providers/ExternalizedProfileApplicationDelegate.java
@@ -0,0 +1,222 @@
+/*****************************************************************************
+ * Copyright (c) 2005, 2014 IBM Corporation, Embarcadero Technologies, 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:
+ * IBM - initial API and implementation
+ * Kenn Hussey (Embarcadero Technologies) - 271470
+ * Kenn Hussey - 323181, 348433
+ * Kenn Hussey (CEA) - 327039, 369492, 313951, 163556, 418466, 447901
+ * Christian W. Damus (CEA) - 300957, 431998
+ * Christian W. Damus - 444588, 399859
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.providers;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.eclipse.emf.common.util.ECollections;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.common.util.TreeIterator;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.EStructuralFeature.Setting;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.xmi.XMLResource;
+import org.eclipse.papyrus.uml.decoratormodel.helper.DecoratorModelUtils;
+import org.eclipse.papyrus.uml.tools.helper.IProfileApplicationDelegate;
+import org.eclipse.uml2.uml.Element;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.Profile;
+import org.eclipse.uml2.uml.ProfileApplication;
+import org.eclipse.uml2.uml.Stereotype;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+/**
+ * An implementation of the profile-application delegate protocol for externalized profile applications.
+ */
+public class ExternalizedProfileApplicationDelegate implements IProfileApplicationDelegate {
+
+ private final PrivateUtil util = new PrivateUtil();
+
+ public ExternalizedProfileApplicationDelegate() {
+ super();
+ }
+
+ @Override
+ public boolean appliesTo(Package package_) {
+ return true;
+ }
+
+ @Override
+ public Iterable<ProfileApplication> getProfileApplications(Package package_) {
+ return Iterables.concat(package_.getProfileApplications(), DecoratorModelUtils.getDecoratorModelProfileApplications(package_));
+ }
+
+ @Override
+ public ProfileApplication getProfileApplication(Package package_, Profile profile) {
+ ProfileApplication result = package_.getProfileApplication(profile);
+
+ if (result == null) {
+ for (ProfileApplication next : DecoratorModelUtils.getDecoratorModelProfileApplications(package_)) {
+ if (next.getAppliedProfile() == profile) {
+ result = next;
+ break;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public boolean appliesTo(ProfileApplication profileApplication) {
+ Resource resource = profileApplication.eResource();
+ return (resource != null) && DecoratorModelUtils.isDecoratorModel(resource);
+ }
+
+ @Override
+ public Package getApplyingPackage(ProfileApplication profileApplication) {
+ return DecoratorModelUtils.getUserModelApplyingPackage(profileApplication);
+ }
+
+ @Override
+ public Profile getAppliedProfile(ProfileApplication profileApplication) {
+ return profileApplication.getAppliedProfile();
+ }
+
+ @Override
+ public EList<EObject> reapplyProfile(Package package_, Profile profile) {
+ ProfileApplication existing = getProfileApplication(package_, profile);
+ return (existing == null) ? ECollections.<EObject> emptyEList() // Nothing to do
+ : (existing.getApplyingPackage() == package_) ? package_.applyProfile(profile) // Simple UML case
+ : util.reapplyProfile(package_, existing); // Our extended UML case
+ }
+
+ //
+ // Nested types
+ //
+
+ // extending UML-internal PackageOperations class to access protected API
+ @SuppressWarnings("restriction")
+ private class PrivateUtil extends org.eclipse.uml2.uml.internal.operations.PackageOperations {
+
+ EList<EObject> reapplyProfile(Package package_, ProfileApplication profileApplication) {
+ Profile profile = ExternalizedProfileApplicationDelegate.this.getAppliedProfile(profileApplication);
+ EPackage definition = profile.getDefinition();
+
+ Collection<EObject> originals = Lists.newArrayList();
+ StereotypeApplicationCopier copier = new PrivateStereotypeCopier(profile);
+
+ // First, update the referenced definition of profile applications and copy all stereotype applications that are still applicable
+ for (TreeIterator<EObject> allContents = getAllContents(package_, true, false); allContents.hasNext();) {
+ EObject eObject = allContents.next();
+
+ if (eObject instanceof Element) {
+ Element element = (Element) eObject;
+
+ if (element instanceof Package) {
+ for (ProfileApplication next : ExternalizedProfileApplicationDelegate.this.getProfileApplications((Package) element)) {
+ if (ExternalizedProfileApplicationDelegate.this.getAppliedProfile(next) == profile) {
+ EList<EObject> references = getEAnnotation(profileApplication, UML2_UML_PACKAGE_2_0_NS_URI, true).getReferences();
+
+ if (references.isEmpty()) {
+ references.add(definition);
+ } else {
+ references.set(0, definition);
+ }
+ }
+ }
+ }
+
+ for (EObject stereotypeApplication : element.getStereotypeApplications()) {
+ Stereotype stereotype = getStereotype(stereotypeApplication);
+
+ if ((stereotype != null) && (stereotype.getProfile() == profile)) {
+ if (element.isStereotypeApplicable(stereotype)) {
+ EObject copy = copier.copy(stereotypeApplication);
+ Resource eResource = stereotypeApplication.eResource();
+
+ if (eResource != null) {
+ EList<EObject> contents = eResource.getContents();
+
+ if (eResource == copy.eResource()) {
+ contents.move(contents.indexOf(stereotypeApplication), copy);
+ } else {
+ contents.set(contents.indexOf(stereotypeApplication), copy);
+ }
+ }
+ }
+
+ originals.add(stereotypeApplication);
+ }
+ }
+ }
+ }
+
+ // Copy cross-references within the stereotype application forest that was copied
+ copier.copyReferences();
+
+ // Propagate object IDs of stereotype applications and update all incoming cross-references from objects that were not copied
+ for (EObject key : copier.keySet()) {
+ EObject copy = copier.get(key);
+
+ Resource eResource = key.eResource();
+
+ if (eResource instanceof XMLResource) {
+ XMLResource xmlResource = (XMLResource) eResource;
+ xmlResource.setID(copy, xmlResource.getID(key));
+ }
+
+ for (Setting setting : new ArrayList<EStructuralFeature.Setting>(
+ getNonNavigableInverseReferences(key))) {
+
+ EObject eObject = setting.getEObject();
+
+ if (!copier.containsKey(eObject)) {
+ EStructuralFeature eStructuralFeature = setting.getEStructuralFeature();
+
+ if ((eStructuralFeature != null) && eStructuralFeature.isChangeable()) {
+ if (eStructuralFeature.isMany()) {
+ Object value = eObject.eGet(eStructuralFeature);
+
+ @SuppressWarnings("unchecked")
+ EList<EObject> list = ((EList<EObject>) value);
+ list.set(list.indexOf(key), copy);
+ } else {
+ setting.set(copy);
+ }
+ }
+ }
+ }
+ }
+
+ // Delete all of the original stereotype applications (leaving only the copies)
+ destroyAll(originals);
+
+ // Easy result in the common case of the profile not having any required metaclass extensions
+ return profile.getOwnedExtensions(true).isEmpty() ? ECollections.<EObject> emptyEList() : applyAllRequiredStereotypes(package_);
+ }
+
+ //
+ // Nested types
+ //
+
+ private class PrivateStereotypeCopier extends StereotypeApplicationCopier {
+ private static final long serialVersionUID = 1L;
+
+ PrivateStereotypeCopier(Profile profile) {
+ super(profile);
+ }
+ }
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/resource/DecoratorModelCopier.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/resource/DecoratorModelCopier.java
new file mode 100644
index 00000000000..907287290a1
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/resource/DecoratorModelCopier.java
@@ -0,0 +1,207 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.resource;
+
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EAttribute;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
+import org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ApplyProfiles;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.PackageableElement;
+import org.eclipse.uml2.uml.Profile;
+import org.eclipse.uml2.uml.ProfileApplication;
+import org.eclipse.uml2.uml.UMLPackage;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * A utility for copying decorator models, with optional filtering of which profile applications are copied.
+ */
+public class DecoratorModelCopier {
+
+ private final ResourceSet resourceSet;
+ private final FilteredCopier copier;
+
+ /**
+ * Initializes me with the name of the copy model. All profile applications are copied.
+ *
+ * @param modelName
+ * the name of the new decorator model
+ */
+ public DecoratorModelCopier(String modelName) {
+ this(modelName, null);
+ }
+
+ /**
+ * Initializes me with the name of the copy model and the set of URIs of profiles to include in the copy.
+ *
+ * @param modelName
+ * the name of the new decorator model
+ * @param profileURIs
+ * the URIs of the resources storing profiles which applications are to be copied, or {@code null} to copy all profile applications.
+ *
+ * @throws IllegalArgumentException
+ * if the set of profile URIs is empty, because then the resulting model would be useless
+ */
+ public DecoratorModelCopier(String modelName, Set<URI> profileURIs) {
+ super();
+
+ Preconditions.checkArgument((profileURIs == null) || !profileURIs.isEmpty(), "empty profileURIs set"); //$NON-NLS-1$
+
+ this.resourceSet = new DecoratorModelResourceSet(profileURIs);
+ this.copier = new FilteredCopier(modelName, profileURIs);
+ }
+
+ public void dispose() {
+ copier.clear();
+ EMFHelper.unload(resourceSet);
+ }
+
+ /**
+ * Copies the decorator model indicated by the source URI to the destination URI. It is the caller's responsibility to save the destination resource.
+ *
+ * @param sourceModel
+ * the source model URI
+ * @param destinationModel
+ * the destination model URI
+ *
+ * @return the destination resource, which is new and not yet saved
+ */
+ public Resource copy(URI sourceModel, URI destinationModel) {
+ Resource result = resourceSet.createResource(destinationModel, UMLPackage.eCONTENT_TYPE);
+ Resource source = resourceSet.getResource(sourceModel, true);
+
+ List<EObject> output = result.getContents();
+ for (EObject next : source.getContents()) {
+ if (copier.shouldCopy(next)) {
+ output.add(copier.copy(next));
+ }
+ }
+ copier.copyReferences();
+
+ return result;
+ }
+
+ //
+ // Nested types
+ //
+
+ private static class FilteredCopier extends EcoreUtil.Copier {
+ private static final long serialVersionUID = 1L;
+
+ private final String modelName;
+
+ private final Set<URI> profileURIs;
+
+ FilteredCopier(String modelName, Set<URI> profileURIs) {
+ super(false);
+
+ this.modelName = modelName;
+ this.profileURIs = profileURIs;
+ }
+
+ @Override
+ protected void copyAttribute(EAttribute eAttribute, EObject eObject, EObject copyEObject) {
+ if ((eAttribute == UMLPackage.Literals.NAMED_ELEMENT__NAME) && (eObject.eContainer() == null)) {
+ // Set the name of the target model
+ copyEObject.eSet(eAttribute, modelName);
+ } else {
+ super.copyAttribute(eAttribute, eObject, copyEObject);
+ }
+ }
+
+ @Override
+ protected void copyContainment(EReference eReference, EObject eObject, EObject copyEObject) {
+ if (eObject instanceof Package) {
+ Package package_ = (Package) eObject;
+
+ if (package_.eContainer() == null) {
+ // Root package
+ if (eReference == UMLPackage.Literals.PACKAGE__PACKAGED_ELEMENT) {
+ List<PackageableElement> source = package_.getPackagedElements();
+ List<PackageableElement> target = ((Package) copyEObject).getPackagedElements();
+ for (PackageableElement next : source) {
+ // Don't copy nested packages for which we don't want any of the profile applications
+ if (shouldCopy(next)) {
+ target.add((PackageableElement) copy(next));
+ }
+ }
+ } else {
+ super.copyContainment(eReference, eObject, copyEObject);
+ }
+ } else if (eReference == UMLPackage.Literals.PACKAGE__PROFILE_APPLICATION) {
+ List<ProfileApplication> source = package_.getProfileApplications();
+ List<ProfileApplication> target = ((Package) copyEObject).getProfileApplications();
+ for (ProfileApplication next : source) {
+ // Don't copy applications of profiles that we want to exclude
+ if (shouldCopy(next)) {
+ target.add((ProfileApplication) copy(next));
+ }
+ }
+ } else {
+ super.copyContainment(eReference, eObject, copyEObject);
+ }
+ } else {
+ super.copyContainment(eReference, eObject, copyEObject);
+ }
+ }
+
+ boolean shouldCopy(EObject object) {
+ boolean result = profileURIs == null;
+
+ if (!result) {
+ if (object instanceof Package) {
+ // We copy a package if it's the root model package or we want any of its profile applications
+ result = object.eContainer() == null;
+ if (!result) {
+ for (ProfileApplication next : ((Package) object).getProfileApplications()) {
+ if (shouldCopy(next)) {
+ result = true;
+ break;
+ }
+ }
+ }
+ } else if (object instanceof ProfileApplication) {
+ ProfileApplication profileApplication = (ProfileApplication) object;
+
+ // Always copy the root package's profile applications
+ result = profileApplication.getApplyingPackage().eContainer() == null;
+ if (!result) {
+ // Remember that our resource set doesn't resolve proxies
+ Profile profile = ((ProfileApplication) object).getAppliedProfile();
+ result = profileURIs.contains(EcoreUtil.getURI(profile).trimFragment());
+ }
+ } else if (object instanceof ApplyProfiles) {
+ // Did we copy the dependency to which this stereotype is applied?
+ result = get(((ApplyProfiles) object).getBase_Dependency()) != null;
+ } else if (object.eContainer() == null) {
+ // It's a stereotype application. Copy it if its profile is in our set
+ result = profileURIs.contains(EcoreUtil.getURI(object.eClass()).trimFragment());
+ } else {
+ result = true;
+ }
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/resource/DecoratorModelIndex.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/resource/DecoratorModelIndex.java
new file mode 100644
index 00000000000..057c24a3846
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/resource/DecoratorModelIndex.java
@@ -0,0 +1,589 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.resource;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.papyrus.infra.emf.resource.index.WorkspaceModelIndex;
+import org.eclipse.papyrus.infra.emf.resource.index.WorkspaceModelIndex.IndexHandler;
+import org.eclipse.papyrus.infra.emf.resource.index.WorkspaceModelIndexAdapter;
+import org.eclipse.papyrus.infra.emf.resource.index.WorkspaceModelIndexEvent;
+import org.eclipse.papyrus.uml.decoratormodel.Activator;
+import org.eclipse.papyrus.uml.decoratormodel.helper.DecoratorModelUtils;
+import org.eclipse.papyrus.uml.decoratormodel.internal.messages.Messages;
+import org.eclipse.papyrus.uml.decoratormodel.internal.resource.index.ProfileIndexHandler;
+import org.eclipse.uml2.common.util.CacheAdapter;
+
+import com.google.common.base.Function;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.SetMultimap;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * A workspace-wide index mapping UML model resources to decorator models that apply profiles to them.
+ */
+public class DecoratorModelIndex {
+
+ private static final int MAX_INDEX_JOBS = 5;
+
+ private static final DecoratorModelIndex INSTANCE = new DecoratorModelIndex();
+
+ private final Object sync = new Object();
+ private final SetMultimap<URI, URI> modelToDecorators = HashMultimap.create();
+ private final SetMultimap<URI, URI> decoratorToModels = HashMultimap.create();
+ private final SetMultimap<URI, URI> packageToDecoratorModels = HashMultimap.create();
+
+ private final Map<URI, Map<URI, Map<URI, URI>>> decoratorModelToPackageToProfileApplications = Maps.newHashMap();
+ private final Map<URI, String> decoratorModelNames = Maps.newHashMap();
+
+ private final WorkspaceModelIndex<DecoratorModelIndex> index;
+
+ private final CopyOnWriteArrayList<IDecoratorModelIndexListener> listeners = Lists.newCopyOnWriteArrayList();
+
+ /**
+ * Not instantiable by clients.
+ */
+ private DecoratorModelIndex() {
+ super();
+
+ index = new WorkspaceModelIndex<DecoratorModelIndex>("decoratorModels", DecoratorModelUtils.DECORATOR_MODEL_CONTENT_TYPE.getId(), indexer(), MAX_INDEX_JOBS); //$NON-NLS-1$
+ index.addListener(new WorkspaceModelIndexAdapter() {
+ @Override
+ protected void indexAboutToCalculateOrRecalculate(WorkspaceModelIndexEvent event) {
+ // Clear the CacheAdapter to purge any caches of information derived from this index
+ CacheAdapter.getInstance().clear();
+ }
+
+ @Override
+ protected void indexCalculatedOrRecalculated(WorkspaceModelIndexEvent event) {
+ notifyChanged();
+ }
+ });
+ }
+
+ public void dispose() {
+ index.dispose();
+ modelToDecorators.clear();
+ }
+
+ public static DecoratorModelIndex getInstance() {
+ return INSTANCE;
+ }
+
+ /**
+ * Asynchronously queries the mapping of URIs of user models to URIs of decorator models that apply profiles to them.
+ *
+ * @param modelResourceURI
+ * the URI of a user model resource
+ * @return a future result of the mapping of user model URIs to decorator model URIs
+ */
+ public ListenableFuture<SetMultimap<URI, URI>> getDecoratorModelsAsync() {
+ return afterIndex(getDecoratorModelsCallable());
+ }
+
+ /**
+ * Queries the mapping of URIs of user models to URIs of decorator models that apply profiles to them.
+ *
+ * @return the mapping of user model URIs to decorator model URIs
+ */
+ public SetMultimap<URI, URI> getDecoratorModels() throws CoreException {
+ return sync(afterIndex(getDecoratorModelsCallable()));
+ }
+
+ Callable<SetMultimap<URI, URI>> getDecoratorModelsCallable() {
+ return new SyncCallable<SetMultimap<URI, URI>>() {
+ @Override
+ protected SetMultimap<URI, URI> doCall() {
+ return ImmutableSetMultimap.copyOf(modelToDecorators);
+ }
+ };
+ }
+
+ /**
+ * Asynchronously queries the URIs of decorator models that apply profiles to the specified user model resource.
+ *
+ * @param modelResourceURI
+ * the URI of a user model resource
+ * @return a future result of the URIs of decorator models for the user model resource
+ */
+ public ListenableFuture<Set<URI>> getDecoratorModelsAsync(URI modelResourceURI) {
+ return afterIndex(getDecoratorModelsCallable(modelResourceURI));
+ }
+
+ /**
+ * Queries the URIs of decorator models that apply profiles to the specified user model resource.
+ *
+ * @param modelResourceURI
+ * the URI of a user model resource
+ * @return the URIs of decorator models for the user model resource
+ */
+ public Set<URI> getDecoratorModels(URI modelResourceURI) throws CoreException {
+ return sync(afterIndex(getDecoratorModelsCallable(modelResourceURI)));
+ }
+
+ final <V> V sync(Future<V> future) throws CoreException {
+ try {
+ return future.get();
+ } catch (InterruptedException e) {
+ throw new CoreException(Status.CANCEL_STATUS);
+ } catch (ExecutionException e) {
+ throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.DecoratorModelIndex_0, e));
+ }
+ }
+
+ Callable<Set<URI>> getDecoratorModelsCallable(final URI modelResourceURI) {
+ return new SyncCallable<Set<URI>>() {
+ @Override
+ protected Set<URI> doCall() {
+ return ImmutableSet.copyOf(modelToDecorators.get(modelResourceURI));
+ }
+ };
+ }
+
+ /**
+ * Asynchronously queries the URIs of profiles applied to the specified user model package by the specified decorator model.
+ *
+ * @param packageURI
+ * the URI of a package in a user model
+ * @param decoratorModel
+ * the URI of a decorator model
+ * @return the future result of the URIs of profiles applied to the package by the resource
+ */
+ public ListenableFuture<Set<URI>> getAppliedProfilesAsync(final URI packageURI, URI decoratorModel) {
+ return Futures.transform(getAppliedProfilesByPackageAsync(decoratorModel), new Function<SetMultimap<URI, URI>, Set<URI>>() {
+ @Override
+ public Set<URI> apply(SetMultimap<URI, URI> input) {
+ return input.get(packageURI);
+ }
+ });
+ }
+
+ /**
+ * Queries the URIs of profiles applied to the specified user model package by the specified decorator model.
+ *
+ * @param packageURI
+ * the URI of a package in a user model
+ * @param decoratorModel
+ * the URI of a decorator model
+ * @return the URIs of profiles applied to the package by the resource
+ */
+ public Set<URI> getAppliedProfiles(URI packageURI, URI decoratorModel) throws CoreException {
+ return sync(getAppliedProfilesAsync(packageURI, decoratorModel));
+ }
+
+ /**
+ * Asynchronously queries a mapping of user-model package URIs to URIs of profiles applied to them by the specified decorator model.
+ *
+ * @param decoratorModel
+ * the URI of a decorator model
+ * @return the future result of the URIs of user model packages to profiles applied to them by the resource
+ */
+ public ListenableFuture<SetMultimap<URI, URI>> getAppliedProfilesByPackageAsync(URI decoratorModel) {
+ return afterIndex(getAppliedProfilesByPackageCallable(decoratorModel));
+ }
+
+ /**
+ * Queries a mapping of user-model package URIs to URIs of profiles applied to them by the specified decorator model.
+ *
+ * @param decoratorModel
+ * the URI of a decorator model
+ * @return the URIs of user model packages to profiles applied to them by the resource
+ */
+ public SetMultimap<URI, URI> getAppliedProfilesByPackage(URI decoratorModel) throws CoreException {
+ return sync(afterIndex(getAppliedProfilesByPackageCallable(decoratorModel)));
+ }
+
+ Callable<SetMultimap<URI, URI>> getAppliedProfilesByPackageCallable(final URI decoratorModel) {
+ return new SyncCallable<SetMultimap<URI, URI>>() {
+ @Override
+ protected SetMultimap<URI, URI> doCall() {
+ SetMultimap<URI, URI> result;
+
+ Map<URI, Map<URI, URI>> packageToProfileApplications = decoratorModelToPackageToProfileApplications.get(decoratorModel);
+ if (packageToProfileApplications == null) {
+ result = ImmutableSetMultimap.of();
+ } else {
+ ImmutableSetMultimap.Builder<URI, URI> builder = ImmutableSetMultimap.builder();
+ for (Map.Entry<URI, Map<URI, URI>> next : packageToProfileApplications.entrySet()) {
+ builder.putAll(next.getKey(), next.getValue().keySet());
+ }
+ result = builder.build();
+ }
+
+ return result;
+ }
+ };
+ }
+
+ /**
+ * Asynchronously queries a mapping of all profiles applied externally on a package to the resources that apply those profiles.
+ * The mapping is one-to-many because any number of decorator models can apply the same profile to a package.
+ *
+ * @param package_
+ * the URI of a user-model package
+ * @return the future result of a mapping of the URIs of profiles externally applied on the package to the resources that apply them
+ */
+ public ListenableFuture<SetMultimap<URI, URI>> getAllAppliedProfilesAsync(URI package_) {
+ return afterIndex(getAllAppliedProfilesCallable(package_));
+ }
+
+ /**
+ * Queries a mapping of all profiles applied externally on a package to the resources that apply those profiles.
+ * The mapping is one-to-many because any number of decorator models can apply the same profile to a package.
+ *
+ * @param package_
+ * the URI of a user-model package
+ * @return a mapping of the URIs of profiles externally applied on the package to the resources that apply them
+ */
+ public SetMultimap<URI, URI> getAllAppliedProfiles(URI package_) throws CoreException {
+ return sync(afterIndex(getAllAppliedProfilesCallable(package_)));
+ }
+
+ Callable<SetMultimap<URI, URI>> getAllAppliedProfilesCallable(final URI packageURI) {
+ return new SyncCallable<SetMultimap<URI, URI>>() {
+ @Override
+ protected SetMultimap<URI, URI> doCall() {
+ ImmutableSetMultimap.Builder<URI, URI> result = ImmutableSetMultimap.builder();
+
+ for (URI paResource : modelToDecorators.get(packageURI.trimFragment())) {
+ Map<URI, Map<URI, URI>> packageToProfileApplications = decoratorModelToPackageToProfileApplications.get(paResource);
+ if (packageToProfileApplications != null) {
+ Map<URI, URI> profileApplications = packageToProfileApplications.get(packageURI);
+ if (profileApplications != null) {
+ for (URI profile : profileApplications.keySet()) {
+ result.put(profile, paResource);
+ }
+ }
+ }
+ }
+
+ return result.build();
+ }
+ };
+ }
+
+ /**
+ * Asynchronously queries a mapping of all profiles applied externally on a package to mappings of decorator model resources that apply those profiles
+ * to the Ecore definitions applied by those decorators. That is, (profile&nbsp;==>&nbsp;decorator-model&nbsp;==>&nbsp;ecore-definition).
+ * The mapping is one-to-many because any number of decorator models can apply the same profile to a package.
+ *
+ * @param package_
+ * the URI of a user-model package
+ * @return the future result of a mapping of the URIs of profiles externally applied on the package to the resources that apply them to
+ * the Ecore definitions applied by those resources
+ */
+ public ListenableFuture<Map<URI, Map<URI, URI>>> getAllAppliedProfileDefinitionsAsync(URI package_) {
+ return afterIndex(getAllAppliedProfileDefinitionsCallable(package_));
+ }
+
+ /**
+ * Queries a mapping of all profiles applied externally on a package to mappings of decorator model resources that apply those profiles
+ * to the Ecore definitions applied by those decorators. That is, (profile&nbsp;==>&nbsp;decorator-model&nbsp;==>&nbsp;ecore-definition).
+ * The mapping is one-to-many because any number of decorator models can apply the same profile to a package.
+ *
+ * @param package_
+ * the URI of a user-model package
+ * @return a mapping of the URIs of profiles externally applied on the package to the resources that apply them to
+ * the Ecore definitions applied by those resources
+ */
+ public Map<URI, Map<URI, URI>> getAllAppliedProfileDefinitions(URI package_) throws CoreException {
+ return sync(afterIndex(getAllAppliedProfileDefinitionsCallable(package_)));
+ }
+
+ Callable<Map<URI, Map<URI, URI>>> getAllAppliedProfileDefinitionsCallable(final URI packageURI) {
+ return new SyncCallable<Map<URI, Map<URI, URI>>>() {
+ @Override
+ protected Map<URI, Map<URI, URI>> doCall() {
+ Map<URI, ImmutableMap.Builder<URI, URI>> gather = Maps.newHashMap();
+
+ for (URI paResource : modelToDecorators.get(packageURI.trimFragment())) {
+ Map<URI, Map<URI, URI>> packageToProfileApplications = decoratorModelToPackageToProfileApplications.get(paResource);
+ if (packageToProfileApplications != null) {
+ Map<URI, URI> profileApplications = packageToProfileApplications.get(packageURI);
+ if (profileApplications != null) {
+ for (Map.Entry<URI, URI> next : profileApplications.entrySet()) {
+ URI profile = next.getKey();
+ ImmutableMap.Builder<URI, URI> builder = gather.get(profile);
+ if (builder == null) {
+ builder = ImmutableMap.builder();
+ gather.put(profile, builder);
+ }
+
+ builder.put(paResource, next.getValue());
+ }
+ }
+ }
+ }
+
+ ImmutableMap.Builder<URI, Map<URI, URI>> result = ImmutableMap.builder();
+ for (Map.Entry<URI, ImmutableMap.Builder<URI, URI>> next : gather.entrySet()) {
+ result.put(next.getKey(), next.getValue().build());
+ }
+ return result.build();
+ }
+ };
+ }
+
+ /**
+ * Asynchronously queries the set of URIs of decorator models that apply profiles to the specified package.
+ *
+ * @param package_
+ * the URI of a user-model package
+ * @return the future result of the URIs of all decorator models that apply profiels to it
+ */
+ public ListenableFuture<Set<URI>> getDecoratorModelsForPackageAsync(URI package_) {
+ return afterIndex(getDecoratorModelsForPackageCallable(package_));
+ }
+
+ /**
+ * Queries the set of URIs of decorator models that apply profiles to the specified package.
+ *
+ * @param package_
+ * the URI of a user-model package
+ * @return the URIs of all decorator models that apply profiels to it
+ */
+ public Set<URI> getDecoratorModelsForPackage(URI package_) throws CoreException {
+ return sync(afterIndex(getDecoratorModelsForPackageCallable(package_)));
+ }
+
+ Callable<Set<URI>> getDecoratorModelsForPackageCallable(final URI packageURI) {
+ return new SyncCallable<Set<URI>>() {
+ @Override
+ protected Set<URI> doCall() {
+ return ImmutableSet.copyOf(packageToDecoratorModels.get(packageURI));
+ }
+ };
+ }
+
+ /**
+ * Asynchronously queries a mapping of the user-defined names/identifiers of the profile application externalization models in the workspace.
+ *
+ * @return the future result of the known decorator models' names
+ */
+ public ListenableFuture<Map<URI, String>> getDecoratorModelNamesAsync() {
+ return afterIndex(getDecoratorModelNamesCallable());
+ }
+
+ /**
+ * Queries a mapping of the user-defined names/identifiers of the profile application externalization models in the workspace.
+ *
+ * @return the known decorator models' names
+ */
+ public Map<URI, String> getDecoratorModelNames() throws CoreException {
+ return sync(afterIndex(getDecoratorModelNamesCallable()));
+ }
+
+ Callable<Map<URI, String>> getDecoratorModelNamesCallable() {
+ return new SyncCallable<Map<URI, String>>() {
+ @Override
+ protected Map<URI, String> doCall() {
+ return ImmutableMap.copyOf(decoratorModelNames);
+ }
+ };
+ }
+
+ /**
+ * Asynchronously queries the user-defined names/identifier of a decorator model.
+ *
+ * @param resourceURI
+ * the URI of the decorator model
+ * @return the future result of the decorator model name
+ */
+ public ListenableFuture<String> getDecoratorModelNameAsync(final URI resourceURI) {
+ return Futures.transform(getDecoratorModelNamesAsync(), new Function<Map<URI, String>, String>() {
+ @Override
+ public String apply(Map<URI, String> input) {
+ return input.get(resourceURI);
+ }
+ });
+ }
+
+ /**
+ * Queries the user-defined names/identifier of a decorator model.
+ *
+ * @param resourceURI
+ * the URI of the decorator model
+ * @return the decorator model name
+ */
+ public String getDecoratorModelName(URI resourceURI) throws CoreException {
+ return sync(getDecoratorModelNameAsync(resourceURI));
+ }
+
+ <V> ListenableFuture<V> afterIndex(Callable<V> callable) {
+ return index.afterIndex(callable);
+ }
+
+ private void index(IFile file) {
+ final URI decoratorURI = URI.createPlatformResourceURI(file.getFullPath().toString(), true);
+
+ ProfileIndexHandler handler = new ProfileIndexHandler(decoratorURI);
+
+ InputStream input = null;
+
+ try {
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ factory.setValidating(false);
+ factory.setNamespaceAware(true);
+ SAXParser parser = factory.newSAXParser();
+
+ input = file.getContents();
+
+ parser.parse(input, handler, decoratorURI.toString());
+ } catch (Exception e) {
+ // We intentionally bomb out early with an exception
+ } finally {
+ if (input != null) {
+ try {
+ input.close();
+ } catch (IOException e) {
+ Activator.log.error("Could not close file after indexing.", e); //$NON-NLS-1$
+ }
+ }
+ }
+
+ synchronized (sync) {
+ // first, remove all links to the decorator model
+ for (URI next : decoratorToModels.get(decoratorURI)) {
+ modelToDecorators.remove(next, decoratorURI);
+ }
+
+ // update the forward mapping
+ decoratorToModels.replaceValues(decoratorURI, handler.getReferencedModelURIs());
+
+ // update the reverse mapping
+ for (URI next : handler.getReferencedModelURIs()) {
+ modelToDecorators.put(next, decoratorURI);
+ }
+
+ // remove all package links to the decorator model
+ Map<URI, Map<URI, URI>> packageToProfileApplications = decoratorModelToPackageToProfileApplications.get(decoratorURI);
+ if (packageToProfileApplications != null) {
+ for (URI next : packageToProfileApplications.keySet()) {
+ packageToDecoratorModels.remove(next, decoratorURI);
+ }
+ }
+
+ // update the package links
+ for (URI next : handler.getPackageToProfileApplications().keySet()) {
+ packageToDecoratorModels.put(next, decoratorURI);
+ }
+
+ // and update the package-to-profiles-to-definitions index
+ decoratorModelToPackageToProfileApplications.put(decoratorURI, handler.getPackageToProfileApplications());
+
+ // and the externalization name index
+ decoratorModelNames.put(decoratorURI, handler.getExternalizationName());
+ }
+ }
+
+ private void unindex(IFile file) {
+ final URI decoratorURI = URI.createPlatformResourceURI(file.getFullPath().toString(), true);
+
+ synchronized (sync) {
+ // first, remove all links to the decorator model
+ for (URI next : decoratorToModels.get(decoratorURI)) {
+ modelToDecorators.remove(next, decoratorURI);
+ }
+
+ // remove the forward mapping
+ decoratorToModels.removeAll(decoratorURI);
+
+ // remove from mapping of packages to decorator models
+ Map<URI, Map<URI, URI>> packageToProfileApplications = decoratorModelToPackageToProfileApplications.get(decoratorURI);
+ if (packageToProfileApplications != null) {
+ for (URI next : packageToProfileApplications.keySet()) {
+ packageToDecoratorModels.get(next).remove(decoratorURI);
+ }
+ }
+
+ // remove the package-to-profiles index
+ decoratorModelToPackageToProfileApplications.remove(decoratorURI);
+
+ // and the name index
+ decoratorModelNames.remove(decoratorURI);
+ }
+ }
+
+ private IndexHandler<DecoratorModelIndex> indexer() {
+ return new IndexHandler<DecoratorModelIndex>() {
+ @Override
+ public DecoratorModelIndex index(IFile file) {
+ DecoratorModelIndex.this.index(file);
+ return DecoratorModelIndex.this;
+ }
+
+ @Override
+ public void unindex(IFile file) {
+ DecoratorModelIndex.this.unindex(file);
+ }
+ };
+ }
+
+ public void addIndexListener(IDecoratorModelIndexListener listener) {
+ listeners.addIfAbsent(listener);
+ }
+
+ public void removeIndexListener(IDecoratorModelIndexListener listener) {
+ listeners.remove(listener);
+ }
+
+ protected final void notifyChanged() {
+ if (!listeners.isEmpty()) {
+ DecoratorModelIndexEvent event = new DecoratorModelIndexEvent(this, DecoratorModelIndexEvent.INDEX_CHANGED);
+ for (IDecoratorModelIndexListener next : listeners) {
+ try {
+ next.indexChanged(event);
+ } catch (Exception e) {
+ Activator.log.error("Uncaught exception in decorator model index listener.", e); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+
+ //
+ // Nested types
+ //
+
+ abstract class SyncCallable<V> implements Callable<V> {
+ @Override
+ public final V call() throws Exception {
+ synchronized (sync) {
+ return doCall();
+ }
+ }
+
+ protected abstract V doCall();
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/resource/DecoratorModelIndexEvent.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/resource/DecoratorModelIndexEvent.java
new file mode 100644
index 00000000000..8c911fd8112
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/resource/DecoratorModelIndexEvent.java
@@ -0,0 +1,42 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.resource;
+
+import java.util.EventObject;
+
+/**
+ * Event object notifying of changes to the {@link DecoratorModelIndex}.
+ */
+public class DecoratorModelIndexEvent extends EventObject {
+
+ public static final int INDEX_CHANGED = 0;
+
+ private static final long serialVersionUID = 1L;
+
+ private final int eventType;
+
+ public DecoratorModelIndexEvent(DecoratorModelIndex source, int eventType) {
+ super(source);
+
+ this.eventType = eventType;
+ }
+
+ public final DecoratorModelIndex getIndex() {
+ return (DecoratorModelIndex) getSource();
+ }
+
+ public final int getEventType() {
+ return eventType;
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/resource/DecoratorModelReadOnlyHandler.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/resource/DecoratorModelReadOnlyHandler.java
new file mode 100644
index 00000000000..d0cd231810d
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/resource/DecoratorModelReadOnlyHandler.java
@@ -0,0 +1,79 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.resource;
+
+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.papyrus.infra.core.resource.AbstractReadOnlyHandler;
+import org.eclipse.papyrus.infra.core.resource.IReadOnlyHandler2;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.resource.ReadOnlyAxis;
+import org.eclipse.papyrus.uml.decoratormodel.helper.DecoratorModelUtils;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+
+/**
+ * Read-only handler for profile application resources used by the current model.
+ */
+public class DecoratorModelReadOnlyHandler extends AbstractReadOnlyHandler {
+
+ public DecoratorModelReadOnlyHandler(EditingDomain editingDomain) {
+ super(editingDomain);
+ }
+
+ @Override
+ public Optional<Boolean> anyReadOnly(Set<ReadOnlyAxis> axes, URI[] uris) {
+ // mine is a discretionary read-only policy
+ if (axes.contains(ReadOnlyAxis.DISCRETION)) {
+ EditingDomain domain = getEditingDomain();
+ ResourceSet rset = (domain == null) ? null : domain.getResourceSet();
+ if (rset instanceof ModelSet) {
+ Set<URI> userModels = Sets.newHashSet();
+
+ for (URI next : uris) {
+ Resource resource = rset.getResource(next, false);
+ if ((resource != null) && resource.isLoaded() && DecoratorModelUtils.isDecoratorModel(resource)) {
+ userModels.addAll(DecoratorModelUtils.getUserModelResources(resource));
+ }
+ }
+
+ if (userModels.isEmpty()) {
+ // An empty profile applications resource is not read-only; it's waiting for us to add stuff to it!
+ return Optional.of(false);
+ } else {
+ // This resource's read-only status is the same as the resources for which it provides profile applications
+ IReadOnlyHandler2 manager = ((ModelSet) rset).getReadOnlyHandler();
+ if (manager != null) {
+ return manager.anyReadOnly(ReadOnlyAxis.discretionAxes(), Iterables.toArray(userModels, URI.class));
+ }
+ }
+ }
+ }
+
+ return Optional.absent();
+ }
+
+ @Override
+ public Optional<Boolean> makeWritable(Set<ReadOnlyAxis> axes, URI[] uris) {
+ // I never make anything writable; my job is to make sure that resources don't appear read-only when they shouldn't
+ return Optional.absent();
+ }
+
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/resource/DecoratorModelResourceSet.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/resource/DecoratorModelResourceSet.java
new file mode 100644
index 00000000000..b5b46e67021
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/resource/DecoratorModelResourceSet.java
@@ -0,0 +1,116 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.resource;
+
+import java.util.Set;
+
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EFactory;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.emf.ecore.impl.EPackageRegistryImpl;
+import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
+import org.eclipse.emf.ecore.util.BasicExtendedMetaData;
+import org.eclipse.emf.ecore.util.ExtendedMetaData;
+import org.eclipse.emf.ecore.xmi.XMLResource;
+import org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ProfileExternalizationPackage;
+import org.eclipse.uml2.uml.UMLPackage;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * A minimalist resource set that does not resolve proxies except in some given scope of target resource URIs.
+ */
+public class DecoratorModelResourceSet extends ResourceSetImpl {
+ private final Set<URI> resolutionScope;
+
+ public DecoratorModelResourceSet() {
+ this(null);
+ }
+
+ public DecoratorModelResourceSet(Set<URI> resolutionScope) {
+ super();
+
+ this.resolutionScope = resolutionScope;
+
+ EPackage.Registry registry = new DecoratorModelPackageRegistry();
+ ExtendedMetaData metadata = new BasicExtendedMetaData(registry);
+
+ setPackageRegistry(registry);
+ getLoadOptions().put(XMLResource.OPTION_EXTENDED_META_DATA, metadata);
+
+ getLoadOptions().put(XMLResource.OPTION_DEFER_IDREF_RESOLUTION, true);
+ getLoadOptions().put(XMLResource.OPTION_LAX_FEATURE_PROCESSING, true);
+ getLoadOptions().put(XMLResource.OPTION_RECORD_UNKNOWN_FEATURE, true);
+ getLoadOptions().put(XMLResource.OPTION_USE_PACKAGE_NS_URI_AS_LOCATION, false);
+ }
+
+ @Override
+ public EObject getEObject(URI uri, boolean loadOnDemand) {
+ EObject result = null;
+
+ // Don't resolve any proxies except to metamodels and registered profiles and resources in our scope
+ if (!loadOnDemand || !uri.isPlatformResource() || ((resolutionScope != null) && resolutionScope.contains(uri.trimFragment()))) {
+ result = super.getEObject(uri, loadOnDemand);
+ } else {
+ result = super.getEObject(uri, false);
+ }
+
+ return result;
+ }
+
+ //
+ // Nested types
+ //
+
+
+ private static class DecoratorModelPackageRegistry extends EPackageRegistryImpl {
+ private static final long serialVersionUID = 1L;
+
+ private final Set<EPackage> acceptedPackages = ImmutableSet.of(UMLPackage.eINSTANCE, EcorePackage.eINSTANCE, ProfileExternalizationPackage.eINSTANCE);
+ private final Set<EFactory> acceptedFactories;
+
+ {
+ ImmutableSet.Builder<EFactory> factories = ImmutableSet.builder();
+ for (EPackage next : acceptedPackages) {
+ factories.add(next.getEFactoryInstance());
+ }
+ acceptedFactories = factories.build();
+ }
+
+ DecoratorModelPackageRegistry() {
+ super(EPackage.Registry.INSTANCE);
+ }
+
+ // Don't resolve anything but the UML metamodel and the externalization profile
+ @Override
+ protected EPackage delegatedGetEPackage(String nsURI) {
+ EPackage result = super.delegatedGetEPackage(nsURI);
+ if (!acceptedPackages.contains(result)) {
+ result = null;
+ }
+ return result;
+ }
+
+ @Override
+ protected EFactory delegatedGetEFactory(String nsURI) {
+ EFactory result = super.delegatedGetEFactory(nsURI);
+ if (!acceptedFactories.contains(result)) {
+ result = null;
+ }
+ return result;
+ }
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/resource/IDecoratorModelIndexListener.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/resource/IDecoratorModelIndexListener.java
new file mode 100644
index 00000000000..7589d2e835d
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/resource/IDecoratorModelIndexListener.java
@@ -0,0 +1,27 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.resource;
+
+/**
+ * Protocol for receiving notifications of index change events.
+ */
+public interface IDecoratorModelIndexListener {
+ /**
+ * Notifies me that the index has changed, usually due to changes to workspace resources that are decorator models.
+ *
+ * @param event
+ * the change event
+ */
+ void indexChanged(DecoratorModelIndexEvent event);
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/resource/index/ProfileIndexHandler.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/resource/index/ProfileIndexHandler.java
new file mode 100644
index 00000000000..9aa4106ee01
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/internal/resource/index/ProfileIndexHandler.java
@@ -0,0 +1,367 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.internal.resource.index;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.xmi.XMIResource;
+import org.eclipse.uml2.uml.UMLPackage;
+import org.eclipse.uml2.uml.util.UMLUtil;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Sets;
+
+/**
+ * SAX parsing handler for indexing a profile-application resource. It produces two outputs:
+ * <ul>
+ * <li>{@link #getReferencedModelURIs()}: the set of model resource URIs for which the resource profiles profile applications (without fragments)</li>
+ * <li>{@link #getAppliedProfileURIs()}: a mapping of applying package to applied profile, as object URIs (with fragments)</li>
+ * </ul>
+ */
+public class ProfileIndexHandler extends DefaultHandler {
+ private final URI fileURI;
+ private final Set<URI> referencedModelURIs = Sets.newHashSet();
+ private final Map<URI, Map<URI, URI>> packageToProfileApplications = Maps.newHashMap();
+ private String externalizationName;
+
+ private String umlNamespace;
+ private String umlPrefix;
+ private String xmiType;
+ private String xmiID;
+ private Set<String> packageTypes;
+ private String dependencyType;
+ private String client;
+ private String profileApplication;
+ private String appliedProfile;
+ private String eAnnotations;
+ private String references;
+
+ private UMLElement top;
+ private int ignore;
+
+ private UMLElement currentPackage;
+
+ private Map<String, URI> packageClients = Maps.newHashMap();
+ private URIPair currentProfileApplication;
+ private Multimap<String, URIPair> packageProfileApplications = ArrayListMultimap.create();
+
+ private Await await = new Await();
+
+ /**
+ * Initializes me.
+ *
+ * @param fileURI
+ * the URI of the profile-application file that I am parsing
+ */
+ public ProfileIndexHandler(final URI fileURI) {
+ this.fileURI = fileURI;
+ }
+
+ public URI getFileURI() {
+ return fileURI;
+ }
+
+ public Set<URI> getReferencedModelURIs() {
+ return referencedModelURIs;
+ }
+
+ public Map<URI, Map<URI, URI>> getPackageToProfileApplications() {
+ return packageToProfileApplications;
+ }
+
+ public String getExternalizationName() {
+ return externalizationName;
+ }
+
+ @Override
+ public void startPrefixMapping(String prefix, String uri) throws SAXException {
+ if (uri.startsWith(XMIResource.XMI_NAMESPACE_PREFIX) || uri.startsWith(XMIResource.XMI_2_4_NAMESPACE_PREFIX)) {
+ xmiType = qname(prefix, "type"); //$NON-NLS-1$
+ xmiID = qname(prefix, "id"); //$NON-NLS-1$
+ } else if (EPackage.Registry.INSTANCE.getEPackage(uri) == UMLPackage.eINSTANCE) {
+ umlNamespace = uri;
+ umlPrefix = prefix;
+
+ packageTypes = ImmutableSet.of(umlElement("Package"), umlElement("Model"), umlElement("Profile")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ dependencyType = umlElement("Dependency"); //$NON-NLS-1$
+ client = "client"; //$NON-NLS-1$
+
+ profileApplication = "profileApplication"; //$NON-NLS-1$
+ appliedProfile = "appliedProfile"; //$NON-NLS-1$
+
+ eAnnotations = "eAnnotations"; //$NON-NLS-1$
+ references = "references"; //$NON-NLS-1$
+ }
+ }
+
+ protected final String umlElement(String name) {
+ return qname(umlPrefix, name);
+ }
+
+ protected final String qname(String prefix, String name) {
+ StringBuilder buf = new StringBuilder(prefix.length() + name.length() + 1);
+ return buf.append(prefix).append(':').append(name).toString();
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
+ if (umlNamespace.equals(uri) || (top != null)) {
+ // skip over annotations
+ if (!ignore(qName, attributes)) {
+ push(qName, attributes);
+ handleUMLElement(top, attributes);
+ }
+ }
+ }
+
+ boolean ignore(String qName, Attributes attributes) {
+ boolean result = false;
+
+ if (attributes != null) { // Starting an element
+ result = (ignore > 0) || (eAnnotations.equals(qName) && !UMLUtil.UML2_UML_PACKAGE_2_0_NS_URI.equals(attributes.getValue("source"))); //$NON-NLS-1$
+ if (result) {
+ ignore++;
+ }
+ } else { // Ending an element
+ result = (ignore > 0);
+ if (result) {
+ ignore--;
+ }
+ }
+
+ return result;
+ }
+
+ protected final void push(String qName, Attributes attributes) {
+ top = new UMLElement(qName, attributes);
+ }
+
+ protected final UMLElement pop() {
+ UMLElement result = top;
+ if (top != null) {
+ top = top.parent;
+ }
+ return result;
+ }
+
+ protected void handleUMLElement(UMLElement element, Attributes attributes) throws SAXException {
+ if (element.isPackage() && (element.getHREF() == null)) {
+ // An href is a reference to a package, not a package in our element hierarchy
+ currentPackage = element;
+
+ // if it's the top package, get its name
+ if (currentPackage.parent == null) {
+ externalizationName = attributes.getValue("name"); //$NON-NLS-1$
+ }
+ }
+
+ if (element.isA(dependencyType)) {
+ // It's a dependency. We want its client
+ await.push(client);
+ } else if (element.isRole(profileApplication)) {
+ currentProfileApplication = new URIPair();
+ packageProfileApplications.put(currentPackage.id, currentProfileApplication);
+ await.push(appliedProfile);
+ } else if (element.isA(UMLUtil.UML2_UML_PACKAGE_2_0_NS_URI)) {
+ // It's the applied profile definition annotation
+ await.push(references);
+ } else if (await.isAwaiting(element)) {
+ if (element.isRole(client) && element.isPackage()) {
+ // Got a package dependency client
+ handleDependencyClient(element);
+ } else if (element.isRole(appliedProfile)) {
+ handleAppliedProfile(element);
+ } else if (element.isRole(references)) {
+ handleReferences(element);
+ }
+
+ await.pop();
+ }
+ }
+
+ protected void handleDependencyClient(UMLElement client) {
+ URI href = client.getHREF();
+ if (href != null) {
+ referencedModelURIs.add(href.trimFragment());
+ packageClients.put(currentPackage.id, href);
+ }
+ }
+
+ protected void handleReferences(UMLElement references) {
+ URI href = references.getHREF();
+ if (href != null) {
+ currentProfileApplication.second = href;
+ }
+ }
+
+ protected void handleAppliedProfile(UMLElement appliedProfile) {
+ URI href = appliedProfile.getHREF();
+ if (href != null) {
+ currentProfileApplication.first = href;
+ }
+ }
+
+ protected void summarize() {
+ for (String packageID : packageProfileApplications.keySet()) {
+ URI applyingPackageURI = packageClients.get(packageID);
+ if (applyingPackageURI != null) {
+ Collection<URIPair> profileApplications = packageProfileApplications.get(packageID);
+ if (!profileApplications.isEmpty()) {
+ Map<URI, URI> map = packageToProfileApplications.get(applyingPackageURI);
+ if (map == null) {
+ map = Maps.newHashMap();
+ packageToProfileApplications.put(applyingPackageURI, map);
+ }
+ for (URIPair profileApplication : profileApplications) {
+ map.put(profileApplication.first, profileApplication.second);
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String qName) throws SAXException {
+ if (!ignore(qName, null)) {
+ if (await.stopAt(pop())) {
+ await.pop();
+ }
+
+ if (top != null) {
+ currentPackage = top.nearestPackage();
+ }
+
+ if (top == null) {
+ // We're done with UML content
+ summarize();
+ throw new OperationCanceledException();
+ }
+ }
+ }
+
+ //
+ // Nested types
+ //
+
+ class UMLElement {
+ final UMLElement parent;
+
+ final String role;
+ final String type;
+ final String id;
+ final String href;
+
+ UMLElement(String qName, Attributes attributes) {
+ parent = top;
+
+ String type;
+ if (qName.equals(eAnnotations)) {
+ // "type" of an annotation is its source
+ type = attributes.getValue("source"); //$NON-NLS-1$
+ } else {
+ type = attributes.getValue(xmiType);
+ if (Strings.isNullOrEmpty(type)) {
+ type = qName;
+ }
+ }
+
+ this.role = qName;
+ this.type = type;
+ this.id = attributes.getValue(xmiID);
+ this.href = attributes.getValue("href"); //$NON-NLS-1$
+ }
+
+ boolean isPackage() {
+ return packageTypes.contains(type);
+ }
+
+ boolean isRole(String roleName) {
+ return roleName.equals(role);
+ }
+
+ boolean isA(String xmiType) {
+ return xmiType.equals(type);
+ }
+
+ URI getHREF() {
+ return Strings.isNullOrEmpty(href) ? null : URI.createURI(href).resolve(fileURI);
+ }
+
+ UMLElement nearestPackage() {
+ for (UMLElement next = this; next != null; next = next.parent) {
+ if (next.isPackage()) {
+ return next;
+ }
+ }
+ return null;
+ }
+ }
+
+ class Await {
+ final Await parent = await;
+
+ final String awaiting;
+ final UMLElement limit;
+
+ Await() {
+ this(null);
+ }
+
+ private Await(String awaiting) {
+ this.awaiting = awaiting;
+ this.limit = top;
+ }
+
+ boolean isRoot() {
+ return parent == null;
+ }
+
+ boolean isAwaiting(UMLElement element) {
+ return !isRoot() && element.isRole(awaiting);
+ }
+
+ boolean stopAt(UMLElement element) {
+ return !isRoot() && (limit == element);
+ }
+
+ Await push(String elementName) {
+ Await result = new Await(elementName);
+ await = result;
+ return result;
+ }
+
+ void pop() {
+ if (!isRoot()) {
+ await = parent;
+ }
+ }
+ }
+
+ private static final class URIPair {
+ URI first;
+ URI second;
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/model/DecoratorModel.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/model/DecoratorModel.java
new file mode 100644
index 00000000000..f673d2f0530
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/model/DecoratorModel.java
@@ -0,0 +1,260 @@
+/*****************************************************************************
+ * Copyright (c) 2013, 2014 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:
+ * Remi Schnekenburger (CEA LIST) - Initial API and implementation
+ * Christian W. Damus - bug 399859
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.uml.decoratormodel.model;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IPath;
+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.ecore.util.EcoreUtil;
+import org.eclipse.emf.ecore.xmi.XMIResource;
+import org.eclipse.papyrus.infra.core.resource.AbstractBaseModel;
+import org.eclipse.papyrus.infra.core.resource.AbstractModel;
+import org.eclipse.papyrus.infra.core.resource.IModelSnippet;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.resource.ModelUtils;
+import org.eclipse.papyrus.uml.decoratormodel.Activator;
+import org.eclipse.papyrus.uml.decoratormodel.helper.DecoratorModelUtils;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.UMLPackage;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+/**
+ * A Papyrus Model managing loaded decorator models for the model being edited.
+ */
+public class DecoratorModel extends AbstractModel {
+
+ /** identifier of this IModel */
+ public static final String ID = "org.eclipse.papyrus.uml.decoratormodel.DecoratorModel"; //$NON-NLS-1$
+
+ // URI of an as-yet-empty resource that we are creating to put profile applications into, so that it will
+ // be known to be a decorator model resource
+ private URI creatingDecoratorModelURI;
+
+ @Override
+ public String getIdentifier() {
+ return ID;
+ }
+
+ @Override
+ public void init(ModelSet modelSet) {
+ super.init(modelSet);
+
+ DecoratorModelUtils.configure(modelSet);
+ }
+
+ /*
+ * Overridden to make it visible in this package.
+ */
+ @Override
+ protected ModelSet getModelManager() {
+ return super.getModelManager();
+ }
+
+ @Override
+ public void loadModel(IPath path) {
+ loadModel(getPlatformURI(path));
+ }
+
+ /**
+ * Returns a platform resource URI of the given path
+ *
+ * @param path
+ * the path
+ * @return the uri
+ */
+ protected URI getPlatformURI(IPath path) {
+ return URI.createPlatformResourceURI(path.toString(), true);
+ }
+
+ @Override
+ public void loadModel(URI uri) {
+ List<Resource> resources = getResources();
+ for (Resource resource : resources) {
+ try {
+ if (!resource.isLoaded()) {
+ resource.load(null);
+ }
+ EcoreUtil.resolveAll(resource); // Ensure that models applying the profiles are loaded
+ configureResource(resource);
+ } catch (IOException e) {
+ Activator.log.error(e);
+ }
+ }
+ // call registered snippets
+ snippets.performStart(this);
+ }
+
+ /**
+ * Returns the dynamically computed list of resources that are loaded decorator models.
+ *
+ * @return the loaded decorator models
+ */
+ protected List<Resource> getResources() {
+ List<Resource> result = Lists.newArrayListWithExpectedSize(0);
+
+ for (Resource next : ImmutableList.copyOf(getModelManager().getResources())) {
+ if (isDecoratorModelResource(next)) {
+ URI trimmed = next.getURI().trimFileExtension();
+ if (trimmed.equals(getModelManager().getURIWithoutExtension())) {
+ // This is one of ours
+ result.add(next);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ public boolean isDecoratorModelResource(Resource resource) {
+ return isDecoratorModel(resource) || resource.getURI().equals(creatingDecoratorModelURI);
+ }
+
+ protected void configureResource(Resource resource) {
+ if (resource instanceof XMIResource) {
+ ((XMIResource) resource).getDefaultSaveOptions().putAll(getSaveOptions());
+ ((XMIResource) resource).setEncoding(AbstractBaseModel.ENCODING);
+ }
+ }
+
+ public Map<Object, Object> getSaveOptions() {
+ return AbstractBaseModel.getDefaultSaveOptions();
+ }
+
+ @Override
+ public void saveModel() throws IOException {
+ List<Resource> resources = getResources();
+ for (Resource resource : resources) {
+ if (!getModelManager().getTransactionalEditingDomain().isReadOnly(resource) && !ModelUtils.resourceFailedOnLoad(resource)) {
+ resource.save(getSaveOptions());
+ }
+ }
+ }
+
+ @Override
+ public void unload() {
+ // call registered snippets
+ snippets.performDispose(this);
+ List<Resource> resources = getResources();
+ for (Resource resource : resources) {
+ resource.unload();
+ }
+ }
+
+ @Override
+ public void addModelSnippet(IModelSnippet snippet) {
+ snippets.add(snippet);
+ }
+
+ @Override
+ public Set<URI> getModifiedURIs() {
+ Set<URI> result = Sets.newHashSet();
+
+ for (Resource resource : getResources()) {
+ if (!getModelManager().isTrackingModification() || resource.isModified()) {
+ result.add(resource.getURI());
+ }
+ }
+
+ return result;
+ }
+
+ public Resource loadDecoratorModel(URI uri) {
+ final ResourceSet resourceSet = getModelManager();
+
+ Resource result = resourceSet.getResource(uri, false);
+ if (result == null) {
+ // Use the UML resource implementation to ensure consistent handling of the UML metamodel and profiles
+ creatingDecoratorModelURI = uri;
+ try {
+ result = resourceSet.createResource(uri, UMLPackage.eCONTENT_TYPE);
+ } finally {
+ creatingDecoratorModelURI = null;
+ }
+ }
+
+ if (!result.isLoaded()) {
+ try {
+ result.load(resourceSet.getLoadOptions());
+
+ // Ensure that references to base elements resolve so that the diagrams
+ // and property sheets etc. may all update
+ EcoreUtil.resolveAll(result);
+ } catch (Exception e) {
+ // Fine, we couldn't load it all. Will recover whatever we did manage to load
+ }
+ }
+
+ return result;
+ }
+
+ public static boolean isDecoratorModel(Resource resource) {
+ boolean result = false;
+
+ if (resource.isLoaded()) {
+ Package root = (Package) EcoreUtil.getObjectByType(resource.getContents(), UMLPackage.Literals.PACKAGE);
+ if (root != null) {
+ result = DecoratorModelUtils.hasExternalizationProfile(root);
+ }
+ }
+
+ return result;
+ }
+
+ public static DecoratorModel getInstance(ModelSet modelSet) {
+ return (DecoratorModel) modelSet.getModel(ID);
+ }
+
+ //
+ // No-ops. I am like the AdditionalResourcesModel: I don't manage an aspect of the model being edited, rather, other models
+ //
+
+ @Override
+ public void createModel(IPath fullPath) {
+ // Pass
+ }
+
+ @Override
+ public void createModel(URI uri) {
+ // Pass
+ }
+
+ @Override
+ public void importModel(IPath path) {
+ // Pass
+ }
+
+ @Override
+ public void importModel(URI uri) {
+ // Pass
+ }
+
+ @Override
+ public void changeModelPath(IPath fullPath) {
+ // Pass
+ }
+
+ @Override
+ public void setModelURI(URI uri) {
+ // Pass
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/model/UMLSnippet.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/model/UMLSnippet.java
new file mode 100644
index 00000000000..7ef9e77de1d
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/model/UMLSnippet.java
@@ -0,0 +1,118 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.decoratormodel.model;
+
+import java.util.Set;
+
+import org.eclipse.emf.common.notify.Adapter;
+import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.papyrus.infra.core.listenerservice.ModelListenerManager;
+import org.eclipse.papyrus.infra.core.resource.IModel;
+import org.eclipse.papyrus.infra.core.resource.IModelSnippet;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.resource.ResourceAdapter;
+import org.eclipse.papyrus.uml.decoratormodel.helper.DecoratorModelUtils;
+import org.eclipse.papyrus.uml.tools.model.UmlModel;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+
+/**
+ * A model snippet that ensures propagation of the {@link UmlModel}'s {@link ModelListenerManager} to all
+ * loaded profile-application resources.
+ */
+public class UMLSnippet implements IModelSnippet {
+ private DecoratorModel model;
+ private Adapter resourceAdapter;
+ private ModelListenerManager modelListenerManager;
+
+ public UMLSnippet() {
+ super();
+ }
+
+ @Override
+ public void start(IModel startingModel) {
+ model = (DecoratorModel) startingModel;
+
+ ModelSet modelSet = model.getModelManager();
+ UmlModel uml = (UmlModel) modelSet.getModel(UmlModel.MODEL_ID);
+ if (uml != null) {
+ modelListenerManager = getModelListenerManager(uml);
+ if (modelListenerManager != null) {
+ modelSet.eAdapters().add(getResourceAdapter());
+ }
+ }
+ }
+
+ @Override
+ public void dispose(IModel stoppingModel) {
+ if (stoppingModel == model) {
+ if (modelListenerManager != null) {
+ ModelSet modelSet = ((DecoratorModel) stoppingModel).getModelManager();
+ modelSet.eAdapters().remove(getResourceAdapter());
+ }
+
+ resourceAdapter = null;
+ modelListenerManager = null;
+ model = null;
+ }
+ }
+
+ private ModelListenerManager getModelListenerManager(UmlModel uml) {
+ ModelListenerManager result = null;
+
+ Resource resource = uml.getResource();
+ if (resource != null) {
+ result = Iterables.getFirst(Iterables.filter(resource.eAdapters(), ModelListenerManager.class), null);
+ }
+
+ return result;
+ }
+
+ private Adapter getResourceAdapter() {
+ if (resourceAdapter == null) {
+ resourceAdapter = new ResourceAdapter() {
+ private Set<Resource> managedResources = Sets.newHashSet();
+
+ @Override
+ protected void handleResourceAdded(Resource resource) {
+ if (model.isDecoratorModelResource(resource) || DecoratorModelUtils.isDecoratorModel(resource.getURI())) {
+ managedResources.add(resource);
+ resource.eAdapters().add(modelListenerManager);
+ }
+ }
+
+ @Override
+ protected void handleResourceRemoved(Resource resource) {
+ if (managedResources.remove(resource)) {
+ resource.eAdapters().remove(modelListenerManager);
+ }
+ }
+
+ @Override
+ public void unsetTarget(Notifier oldTarget) {
+ super.unsetTarget(oldTarget);
+
+ if (managedResources.remove(oldTarget)) {
+ // unmanage the resource
+ oldTarget.eAdapters().remove(modelListenerManager);
+ }
+ }
+ };
+ }
+
+ return resourceAdapter;
+ }
+}
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/ApplyProfiles.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/ApplyProfiles.java
new file mode 100644
index 00000000000..5a63e8b4289
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/ApplyProfiles.java
@@ -0,0 +1,92 @@
+/**
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ */
+package org.eclipse.papyrus.uml.decoratormodel.profileExternalization;
+
+import org.eclipse.emf.common.util.EList;
+
+import org.eclipse.emf.ecore.EObject;
+
+import org.eclipse.uml2.uml.Dependency;
+import org.eclipse.uml2.uml.Profile;
+
+/**
+ * <!-- begin-user-doc -->
+ * A representation of the model object '<em><b>Apply Profiles</b></em>'.
+ * <!-- end-user-doc -->
+ *
+ * <!-- begin-model-doc -->
+ * base_Dependency.supplier->forAll(oclIsKindOf(uml::Package))
+ * base_Dependency.client->forAll(oclIsKindOf(uml::Package))
+ * <!-- end-model-doc -->
+ *
+ * <p>
+ * The following features are supported:
+ * <ul>
+ * <li>{@link org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ApplyProfiles#getBase_Dependency <em>Base Dependency</em>}</li>
+ * </ul>
+ * </p>
+ *
+ * @see org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ProfileExternalizationPackage#getApplyProfiles()
+ * @model annotation="http://www.eclipse.org/emf/2002/Ecore constraints='suppliers_are_packages clients_are_packages'"
+ * annotation="http://www.eclipse.org/emf/2002/Ecore/OCL suppliers_are_packages='base_Dependency.supplier->forAll(oclIsKindOf(uml::Package))' clients_are_packages='base_Dependency.client->forAll(oclIsKindOf(uml::Package))'"
+ * @generated
+ */
+public interface ApplyProfiles extends EObject
+{
+ /**
+ * Returns the value of the '<em><b>Base Dependency</b></em>' reference.
+ * <!-- begin-user-doc -->
+ * <p>
+ * If the meaning of the '<em>Base Dependency</em>' reference isn't clear, there really should be more of a description here...
+ * </p>
+ * <!-- end-user-doc -->
+ *
+ * @return the value of the '<em>Base Dependency</em>' reference.
+ * @see #setBase_Dependency(Dependency)
+ * @see org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ProfileExternalizationPackage#getApplyProfiles_Base_Dependency()
+ * @model required="true" ordered="false"
+ * annotation="http://schema.omg.org/spec/MOF/2.0/emof.xml#Property.oppositeRoleName body='extension_ApplyProfiles'"
+ * @generated
+ */
+ Dependency getBase_Dependency();
+
+ /**
+ * Sets the value of the '{@link org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ApplyProfiles#getBase_Dependency <em>Base Dependency</em>}' reference.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @param value
+ * the new value of the '<em>Base Dependency</em>' reference.
+ * @see #getBase_Dependency()
+ * @generated
+ */
+ void setBase_Dependency(Dependency value);
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @model kind="operation" ordered="false"
+ * @generated
+ */
+ EList<Profile> getAppliedProfiles();
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @model kind="operation" ordered="false"
+ * @generated
+ */
+ EList<org.eclipse.uml2.uml.Package> getExternalizedAppliedProfilePackages();
+
+} // ApplyProfiles
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/ProfileExternalizationFactory.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/ProfileExternalizationFactory.java
new file mode 100644
index 00000000000..617ffa15eb7
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/ProfileExternalizationFactory.java
@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ */
+package org.eclipse.papyrus.uml.decoratormodel.profileExternalization;
+
+import org.eclipse.emf.ecore.EFactory;
+
+/**
+ * <!-- begin-user-doc -->
+ * The <b>Factory</b> for the model.
+ * It provides a create method for each non-abstract class of the model.
+ * <!-- end-user-doc -->
+ *
+ * @see org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ProfileExternalizationPackage
+ * @generated
+ */
+public interface ProfileExternalizationFactory extends EFactory
+{
+ /**
+ * The singleton instance of the factory.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ ProfileExternalizationFactory eINSTANCE = org.eclipse.papyrus.uml.decoratormodel.profileExternalization.impl.ProfileExternalizationFactoryImpl.init();
+
+ /**
+ * Returns a new object of class '<em>Apply Profiles</em>'.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @return a new object of class '<em>Apply Profiles</em>'.
+ * @generated
+ */
+ ApplyProfiles createApplyProfiles();
+
+ /**
+ * Returns the package supported by this factory.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @return the package supported by this factory.
+ * @generated
+ */
+ ProfileExternalizationPackage getProfileExternalizationPackage();
+
+} // ProfileExternalizationFactory
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/ProfileExternalizationPackage.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/ProfileExternalizationPackage.java
new file mode 100644
index 00000000000..9c0dfe93a37
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/ProfileExternalizationPackage.java
@@ -0,0 +1,249 @@
+/**
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ */
+package org.eclipse.papyrus.uml.decoratormodel.profileExternalization;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EOperation;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EReference;
+
+/**
+ * <!-- begin-user-doc -->
+ * The <b>Package</b> for the model.
+ * It contains accessors for the meta objects to represent
+ * <ul>
+ * <li>each class,</li>
+ * <li>each feature of each class,</li>
+ * <li>each operation of each class,</li>
+ * <li>each enum,</li>
+ * <li>and each data type</li>
+ * </ul>
+ * <!-- end-user-doc -->
+ *
+ * @see org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ProfileExternalizationFactory
+ * @model kind="package"
+ * annotation="http://www.eclipse.org/emf/2002/Ecore validationDelegates='http://www.eclipse.org/emf/2002/Ecore/OCL'"
+ * annotation="http://www.eclipse.org/uml2/2.0.0/UML originalName='ProfileExternalization'"
+ * @generated
+ */
+public interface ProfileExternalizationPackage extends EPackage
+{
+ /**
+ * The package name.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ String eNAME = "profileExternalization"; //$NON-NLS-1$
+
+ /**
+ * The package namespace URI.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ String eNS_URI = "http://www.eclipse.org/Papyrus/2014/profile/profileExternalization"; //$NON-NLS-1$
+
+ /**
+ * The package namespace name.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ String eNS_PREFIX = "profileext"; //$NON-NLS-1$
+
+ /**
+ * The singleton instance of the package.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ ProfileExternalizationPackage eINSTANCE = org.eclipse.papyrus.uml.decoratormodel.profileExternalization.impl.ProfileExternalizationPackageImpl.init();
+
+ /**
+ * The meta object id for the '{@link org.eclipse.papyrus.uml.decoratormodel.profileExternalization.impl.ApplyProfilesImpl <em>Apply Profiles</em>}' class.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @see org.eclipse.papyrus.uml.decoratormodel.profileExternalization.impl.ApplyProfilesImpl
+ * @see org.eclipse.papyrus.uml.decoratormodel.profileExternalization.impl.ProfileExternalizationPackageImpl#getApplyProfiles()
+ * @generated
+ */
+ int APPLY_PROFILES = 0;
+
+ /**
+ * The feature id for the '<em><b>Base Dependency</b></em>' reference.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ * @ordered
+ */
+ int APPLY_PROFILES__BASE_DEPENDENCY = 0;
+
+ /**
+ * The number of structural features of the '<em>Apply Profiles</em>' class.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ * @ordered
+ */
+ int APPLY_PROFILES_FEATURE_COUNT = 1;
+
+ /**
+ * The operation id for the '<em>Get Applied Profiles</em>' operation.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ * @ordered
+ */
+ int APPLY_PROFILES___GET_APPLIED_PROFILES = 0;
+
+ /**
+ * The operation id for the '<em>Get Externalized Applied Profile Packages</em>' operation.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ * @ordered
+ */
+ int APPLY_PROFILES___GET_EXTERNALIZED_APPLIED_PROFILE_PACKAGES = 1;
+
+ /**
+ * The number of operations of the '<em>Apply Profiles</em>' class.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ * @ordered
+ */
+ int APPLY_PROFILES_OPERATION_COUNT = 2;
+
+
+ /**
+ * Returns the meta object for class '{@link org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ApplyProfiles <em>Apply Profiles</em>}'.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @return the meta object for class '<em>Apply Profiles</em>'.
+ * @see org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ApplyProfiles
+ * @generated
+ */
+ EClass getApplyProfiles();
+
+ /**
+ * Returns the meta object for the reference '{@link org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ApplyProfiles#getBase_Dependency <em>Base Dependency</em>}'.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @return the meta object for the reference '<em>Base Dependency</em>'.
+ * @see org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ApplyProfiles#getBase_Dependency()
+ * @see #getApplyProfiles()
+ * @generated
+ */
+ EReference getApplyProfiles_Base_Dependency();
+
+ /**
+ * Returns the meta object for the '{@link org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ApplyProfiles#getAppliedProfiles() <em>Get Applied Profiles</em>}' operation.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @return the meta object for the '<em>Get Applied Profiles</em>' operation.
+ * @see org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ApplyProfiles#getAppliedProfiles()
+ * @generated
+ */
+ EOperation getApplyProfiles__GetAppliedProfiles();
+
+ /**
+ * Returns the meta object for the '{@link org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ApplyProfiles#getExternalizedAppliedProfilePackages() <em>Get Externalized Applied Profile Packages</em>}' operation.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @return the meta object for the '<em>Get Externalized Applied Profile Packages</em>' operation.
+ * @see org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ApplyProfiles#getExternalizedAppliedProfilePackages()
+ * @generated
+ */
+ EOperation getApplyProfiles__GetExternalizedAppliedProfilePackages();
+
+ /**
+ * Returns the factory that creates the instances of the model.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @return the factory that creates the instances of the model.
+ * @generated
+ */
+ ProfileExternalizationFactory getProfileExternalizationFactory();
+
+ /**
+ * <!-- begin-user-doc -->
+ * Defines literals for the meta objects that represent
+ * <ul>
+ * <li>each class,</li>
+ * <li>each feature of each class,</li>
+ * <li>each operation of each class,</li>
+ * <li>each enum,</li>
+ * <li>and each data type</li>
+ * </ul>
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ interface Literals
+ {
+ /**
+ * The meta object literal for the '{@link org.eclipse.papyrus.uml.decoratormodel.profileExternalization.impl.ApplyProfilesImpl <em>Apply Profiles</em>}' class.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @see org.eclipse.papyrus.uml.decoratormodel.profileExternalization.impl.ApplyProfilesImpl
+ * @see org.eclipse.papyrus.uml.decoratormodel.profileExternalization.impl.ProfileExternalizationPackageImpl#getApplyProfiles()
+ * @generated
+ */
+ EClass APPLY_PROFILES = eINSTANCE.getApplyProfiles();
+
+ /**
+ * The meta object literal for the '<em><b>Base Dependency</b></em>' reference feature.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ EReference APPLY_PROFILES__BASE_DEPENDENCY = eINSTANCE.getApplyProfiles_Base_Dependency();
+
+ /**
+ * The meta object literal for the '<em><b>Get Applied Profiles</b></em>' operation.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ EOperation APPLY_PROFILES___GET_APPLIED_PROFILES = eINSTANCE.getApplyProfiles__GetAppliedProfiles();
+
+ /**
+ * The meta object literal for the '<em><b>Get Externalized Applied Profile Packages</b></em>' operation.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ EOperation APPLY_PROFILES___GET_EXTERNALIZED_APPLIED_PROFILE_PACKAGES = eINSTANCE.getApplyProfiles__GetExternalizedAppliedProfilePackages();
+
+ }
+
+} // ProfileExternalizationPackage
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/impl/ApplyProfilesImpl.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/impl/ApplyProfilesImpl.java
new file mode 100644
index 00000000000..1531744f06a
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/impl/ApplyProfilesImpl.java
@@ -0,0 +1,274 @@
+/**
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ */
+package org.eclipse.papyrus.uml.decoratormodel.profileExternalization.impl;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.InternalEObject;
+import org.eclipse.emf.ecore.impl.ENotificationImpl;
+import org.eclipse.emf.ecore.impl.MinimalEObjectImpl;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ApplyProfiles;
+import org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ProfileExternalizationPackage;
+import org.eclipse.papyrus.uml.decoratormodel.profileExternalization.internal.operations.ApplyProfilesOperations;
+import org.eclipse.uml2.common.util.CacheAdapter;
+import org.eclipse.uml2.uml.Dependency;
+import org.eclipse.uml2.uml.Profile;
+
+/**
+ * <!-- begin-user-doc -->
+ * An implementation of the model object '<em><b>Apply Profiles</b></em>'.
+ * <!-- end-user-doc -->
+ * <p>
+ * The following features are implemented:
+ * <ul>
+ * <li>{@link org.eclipse.papyrus.uml.decoratormodel.profileExternalization.impl.ApplyProfilesImpl#getBase_Dependency <em>Base Dependency</em>}</li>
+ * </ul>
+ * </p>
+ *
+ * @generated
+ */
+public class ApplyProfilesImpl extends MinimalEObjectImpl.Container implements ApplyProfiles
+{
+ /**
+ * The cached value of the '{@link #getBase_Dependency() <em>Base Dependency</em>}' reference.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @see #getBase_Dependency()
+ * @generated
+ * @ordered
+ */
+ protected Dependency base_Dependency;
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ protected ApplyProfilesImpl()
+ {
+ super();
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ @Override
+ protected EClass eStaticClass()
+ {
+ return ProfileExternalizationPackage.Literals.APPLY_PROFILES;
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ @Override
+ public Dependency getBase_Dependency()
+ {
+ if (base_Dependency != null && base_Dependency.eIsProxy())
+ {
+ InternalEObject oldBase_Dependency = (InternalEObject) base_Dependency;
+ base_Dependency = (Dependency) eResolveProxy(oldBase_Dependency);
+ if (base_Dependency != oldBase_Dependency)
+ {
+ if (eNotificationRequired()) {
+ eNotify(new ENotificationImpl(this, Notification.RESOLVE, ProfileExternalizationPackage.APPLY_PROFILES__BASE_DEPENDENCY, oldBase_Dependency, base_Dependency));
+ }
+ }
+ }
+ return base_Dependency;
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ public Dependency basicGetBase_Dependency()
+ {
+ return base_Dependency;
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ @Override
+ public void setBase_Dependency(Dependency newBase_Dependency)
+ {
+ Dependency oldBase_Dependency = base_Dependency;
+ base_Dependency = newBase_Dependency;
+ if (eNotificationRequired()) {
+ eNotify(new ENotificationImpl(this, Notification.SET, ProfileExternalizationPackage.APPLY_PROFILES__BASE_DEPENDENCY, oldBase_Dependency, base_Dependency));
+ }
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ @Override
+ public EList<Profile> getAppliedProfiles()
+ {
+ return ApplyProfilesOperations.getAppliedProfiles(this);
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ @Override
+ public EList<org.eclipse.uml2.uml.Package> getExternalizedAppliedProfilePackages()
+ {
+ return ApplyProfilesOperations.getExternalizedAppliedProfilePackages(this);
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ @Override
+ public Object eGet(int featureID, boolean resolve, boolean coreType)
+ {
+ switch (featureID)
+ {
+ case ProfileExternalizationPackage.APPLY_PROFILES__BASE_DEPENDENCY:
+ if (resolve) {
+ return getBase_Dependency();
+ }
+ return basicGetBase_Dependency();
+ }
+ return super.eGet(featureID, resolve, coreType);
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ @Override
+ public void eSet(int featureID, Object newValue)
+ {
+ switch (featureID)
+ {
+ case ProfileExternalizationPackage.APPLY_PROFILES__BASE_DEPENDENCY:
+ setBase_Dependency((Dependency) newValue);
+ return;
+ }
+ super.eSet(featureID, newValue);
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ @Override
+ public void eUnset(int featureID)
+ {
+ switch (featureID)
+ {
+ case ProfileExternalizationPackage.APPLY_PROFILES__BASE_DEPENDENCY:
+ setBase_Dependency((Dependency) null);
+ return;
+ }
+ super.eUnset(featureID);
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ @Override
+ public boolean eIsSet(int featureID)
+ {
+ switch (featureID)
+ {
+ case ProfileExternalizationPackage.APPLY_PROFILES__BASE_DEPENDENCY:
+ return base_Dependency != null;
+ }
+ return super.eIsSet(featureID);
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ @Override
+ public Object eInvoke(int operationID, EList<?> arguments) throws InvocationTargetException
+ {
+ switch (operationID)
+ {
+ case ProfileExternalizationPackage.APPLY_PROFILES___GET_APPLIED_PROFILES:
+ return getAppliedProfiles();
+ case ProfileExternalizationPackage.APPLY_PROFILES___GET_EXTERNALIZED_APPLIED_PROFILE_PACKAGES:
+ return getExternalizedAppliedProfilePackages();
+ }
+ return super.eInvoke(operationID, arguments);
+ }
+
+ /**
+ * Creates a new instance of the specified Ecore class.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @param eClass
+ * The Ecore class of the instance to create.
+ * @return The new instance.
+ * @generated
+ */
+ protected EObject create(EClass eClass)
+ {
+ return EcoreUtil.create(eClass);
+ }
+
+ /**
+ * Retrieves the cache adapter for this '<em><b>Apply Profiles</b></em>'.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @return The cache adapter for this '<em><b>Apply Profiles</b></em>'.
+ * @generated
+ */
+ protected CacheAdapter getCacheAdapter()
+ {
+ return CacheAdapter.getCacheAdapter(this);
+ }
+
+} // ApplyProfilesImpl
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/impl/ProfileExternalizationFactoryImpl.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/impl/ProfileExternalizationFactoryImpl.java
new file mode 100644
index 00000000000..28798b87f31
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/impl/ProfileExternalizationFactoryImpl.java
@@ -0,0 +1,121 @@
+/**
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ */
+package org.eclipse.papyrus.uml.decoratormodel.profileExternalization.impl;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.impl.EFactoryImpl;
+import org.eclipse.emf.ecore.plugin.EcorePlugin;
+import org.eclipse.papyrus.uml.decoratormodel.profileExternalization.*;
+
+/**
+ * <!-- begin-user-doc -->
+ * An implementation of the model <b>Factory</b>.
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+public class ProfileExternalizationFactoryImpl extends EFactoryImpl implements ProfileExternalizationFactory
+{
+ /**
+ * Creates the default factory implementation.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ public static ProfileExternalizationFactory init()
+ {
+ try
+ {
+ ProfileExternalizationFactory theProfileExternalizationFactory = (ProfileExternalizationFactory) EPackage.Registry.INSTANCE.getEFactory(ProfileExternalizationPackage.eNS_URI);
+ if (theProfileExternalizationFactory != null)
+ {
+ return theProfileExternalizationFactory;
+ }
+ } catch (Exception exception)
+ {
+ EcorePlugin.INSTANCE.log(exception);
+ }
+ return new ProfileExternalizationFactoryImpl();
+ }
+
+ /**
+ * Creates an instance of the factory.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ public ProfileExternalizationFactoryImpl()
+ {
+ super();
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ @Override
+ public EObject create(EClass eClass)
+ {
+ switch (eClass.getClassifierID())
+ {
+ case ProfileExternalizationPackage.APPLY_PROFILES:
+ return createApplyProfiles();
+ default:
+ throw new IllegalArgumentException("The class '" + eClass.getName() + "' is not a valid classifier"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ @Override
+ public ApplyProfiles createApplyProfiles()
+ {
+ ApplyProfilesImpl applyProfiles = new ApplyProfilesImpl();
+ return applyProfiles;
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ @Override
+ public ProfileExternalizationPackage getProfileExternalizationPackage()
+ {
+ return (ProfileExternalizationPackage) getEPackage();
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @deprecated
+ * @generated
+ */
+ @Deprecated
+ public static ProfileExternalizationPackage getPackage()
+ {
+ return ProfileExternalizationPackage.eINSTANCE;
+ }
+
+} // ProfileExternalizationFactoryImpl
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/impl/ProfileExternalizationPackageImpl.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/impl/ProfileExternalizationPackageImpl.java
new file mode 100644
index 00000000000..34b3cee8235
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/impl/ProfileExternalizationPackageImpl.java
@@ -0,0 +1,345 @@
+/**
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ */
+package org.eclipse.papyrus.uml.decoratormodel.profileExternalization.impl;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EOperation;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.EValidator;
+import org.eclipse.emf.ecore.impl.EPackageImpl;
+import org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ApplyProfiles;
+import org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ProfileExternalizationFactory;
+import org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ProfileExternalizationPackage;
+import org.eclipse.papyrus.uml.decoratormodel.profileExternalization.util.ProfileExternalizationValidator;
+import org.eclipse.uml2.uml.UMLPackage;
+
+/**
+ * <!-- begin-user-doc -->
+ * An implementation of the model <b>Package</b>.
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+public class ProfileExternalizationPackageImpl extends EPackageImpl implements ProfileExternalizationPackage
+{
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ private EClass applyProfilesEClass = null;
+
+ /**
+ * Creates an instance of the model <b>Package</b>, registered with {@link org.eclipse.emf.ecore.EPackage.Registry EPackage.Registry} by the package
+ * package URI value.
+ * <p>
+ * Note: the correct way to create the package is via the static factory method {@link #init init()}, which also performs initialization of the package, or returns the registered package, if one already exists. <!-- begin-user-doc --> <!-- end-user-doc -->
+ *
+ * @see org.eclipse.emf.ecore.EPackage.Registry
+ * @see org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ProfileExternalizationPackage#eNS_URI
+ * @see #init()
+ * @generated
+ */
+ private ProfileExternalizationPackageImpl()
+ {
+ super(eNS_URI, ProfileExternalizationFactory.eINSTANCE);
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ private static boolean isInited = false;
+
+ /**
+ * Creates, registers, and initializes the <b>Package</b> for this model, and for any others upon which it depends.
+ *
+ * <p>
+ * This method is used to initialize {@link ProfileExternalizationPackage#eINSTANCE} when that field is accessed. Clients should not invoke it directly. Instead, they should simply access that field to obtain the package. <!-- begin-user-doc --> <!--
+ * end-user-doc -->
+ *
+ * @see #eNS_URI
+ * @see #createPackageContents()
+ * @see #initializePackageContents()
+ * @generated
+ */
+ public static ProfileExternalizationPackage init()
+ {
+ if (isInited) {
+ return (ProfileExternalizationPackage) EPackage.Registry.INSTANCE.getEPackage(ProfileExternalizationPackage.eNS_URI);
+ }
+
+ // Obtain or create and register package
+ ProfileExternalizationPackageImpl theProfileExternalizationPackage = (ProfileExternalizationPackageImpl) (EPackage.Registry.INSTANCE.get(eNS_URI) instanceof ProfileExternalizationPackageImpl ? EPackage.Registry.INSTANCE.get(eNS_URI)
+ : new ProfileExternalizationPackageImpl());
+
+ isInited = true;
+
+ // Initialize simple dependencies
+ UMLPackage.eINSTANCE.eClass();
+
+ // Create package meta-data objects
+ theProfileExternalizationPackage.createPackageContents();
+
+ // Initialize created meta-data
+ theProfileExternalizationPackage.initializePackageContents();
+
+ // Register package validator
+ EValidator.Registry.INSTANCE.put
+ (theProfileExternalizationPackage,
+ new EValidator.Descriptor()
+ {
+ @Override
+ public EValidator getEValidator()
+ {
+ return ProfileExternalizationValidator.INSTANCE;
+ }
+ });
+
+ // Mark meta-data to indicate it can't be changed
+ theProfileExternalizationPackage.freeze();
+
+
+ // Update the registry and return the package
+ EPackage.Registry.INSTANCE.put(ProfileExternalizationPackage.eNS_URI, theProfileExternalizationPackage);
+ return theProfileExternalizationPackage;
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ @Override
+ public EClass getApplyProfiles()
+ {
+ return applyProfilesEClass;
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ @Override
+ public EReference getApplyProfiles_Base_Dependency()
+ {
+ return (EReference) applyProfilesEClass.getEStructuralFeatures().get(0);
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ @Override
+ public EOperation getApplyProfiles__GetAppliedProfiles()
+ {
+ return applyProfilesEClass.getEOperations().get(0);
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ @Override
+ public EOperation getApplyProfiles__GetExternalizedAppliedProfilePackages()
+ {
+ return applyProfilesEClass.getEOperations().get(1);
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ @Override
+ public ProfileExternalizationFactory getProfileExternalizationFactory()
+ {
+ return (ProfileExternalizationFactory) getEFactoryInstance();
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ private boolean isCreated = false;
+
+ /**
+ * Creates the meta-model objects for the package. This method is
+ * guarded to have no affect on any invocation but its first.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ public void createPackageContents()
+ {
+ if (isCreated) {
+ return;
+ }
+ isCreated = true;
+
+ // Create classes and their features
+ applyProfilesEClass = createEClass(APPLY_PROFILES);
+ createEReference(applyProfilesEClass, APPLY_PROFILES__BASE_DEPENDENCY);
+ createEOperation(applyProfilesEClass, APPLY_PROFILES___GET_APPLIED_PROFILES);
+ createEOperation(applyProfilesEClass, APPLY_PROFILES___GET_EXTERNALIZED_APPLIED_PROFILE_PACKAGES);
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ private boolean isInitialized = false;
+
+ /**
+ * Complete the initialization of the package and its meta-model. This
+ * method is guarded to have no affect on any invocation but its first.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ public void initializePackageContents()
+ {
+ if (isInitialized) {
+ return;
+ }
+ isInitialized = true;
+
+ // Initialize package
+ setName(eNAME);
+ setNsPrefix(eNS_PREFIX);
+ setNsURI(eNS_URI);
+
+ // Obtain other dependent packages
+ UMLPackage theUMLPackage = (UMLPackage) EPackage.Registry.INSTANCE.getEPackage(UMLPackage.eNS_URI);
+
+ // Create type parameters
+
+ // Set bounds for type parameters
+
+ // Add supertypes to classes
+
+ // Initialize classes, features, and operations; add parameters
+ initEClass(applyProfilesEClass, ApplyProfiles.class, "ApplyProfiles", !IS_ABSTRACT, !IS_INTERFACE, IS_GENERATED_INSTANCE_CLASS); //$NON-NLS-1$
+ initEReference(getApplyProfiles_Base_Dependency(), theUMLPackage.getDependency(), null,
+ "base_Dependency", null, 1, 1, ApplyProfiles.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_COMPOSITE, IS_RESOLVE_PROXIES, !IS_UNSETTABLE, IS_UNIQUE, !IS_DERIVED, !IS_ORDERED); //$NON-NLS-1$
+
+ initEOperation(getApplyProfiles__GetAppliedProfiles(), theUMLPackage.getProfile(), "getAppliedProfiles", 0, -1, IS_UNIQUE, !IS_ORDERED); //$NON-NLS-1$
+
+ initEOperation(getApplyProfiles__GetExternalizedAppliedProfilePackages(), theUMLPackage.getPackage(), "getExternalizedAppliedProfilePackages", 0, -1, IS_UNIQUE, !IS_ORDERED); //$NON-NLS-1$
+
+ // Create resource
+ createResource(eNS_URI);
+
+ // Create annotations
+ // http://www.eclipse.org/emf/2002/Ecore
+ createEcoreAnnotations();
+ // http://www.eclipse.org/uml2/2.0.0/UML
+ createUMLAnnotations();
+ // http://www.eclipse.org/emf/2002/Ecore/OCL
+ createOCLAnnotations();
+ // http://schema.omg.org/spec/MOF/2.0/emof.xml#Property.oppositeRoleName
+ createEmofAnnotations();
+ }
+
+ /**
+ * Initializes the annotations for <b>http://www.eclipse.org/emf/2002/Ecore</b>.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ protected void createEcoreAnnotations()
+ {
+ String source = "http://www.eclipse.org/emf/2002/Ecore"; //$NON-NLS-1$
+ addAnnotation(this,
+ source,
+ new String[]
+ { "validationDelegates", "http://www.eclipse.org/emf/2002/Ecore/OCL" //$NON-NLS-1$ //$NON-NLS-2$
+ });
+ addAnnotation(applyProfilesEClass,
+ source,
+ new String[]
+ { "constraints", "suppliers_are_packages clients_are_packages" //$NON-NLS-1$ //$NON-NLS-2$
+ });
+ }
+
+ /**
+ * Initializes the annotations for <b>http://www.eclipse.org/uml2/2.0.0/UML</b>.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ protected void createUMLAnnotations()
+ {
+ String source = "http://www.eclipse.org/uml2/2.0.0/UML"; //$NON-NLS-1$
+ addAnnotation(this,
+ source,
+ new String[]
+ { "originalName", "ProfileExternalization" //$NON-NLS-1$ //$NON-NLS-2$
+ });
+ }
+
+ /**
+ * Initializes the annotations for <b>http://www.eclipse.org/emf/2002/Ecore/OCL</b>.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ protected void createOCLAnnotations()
+ {
+ String source = "http://www.eclipse.org/emf/2002/Ecore/OCL"; //$NON-NLS-1$
+ addAnnotation(applyProfilesEClass,
+ source,
+ new String[]
+ { "suppliers_are_packages", "base_Dependency.supplier->forAll(oclIsKindOf(uml::Package))", //$NON-NLS-1$ //$NON-NLS-2$
+ "clients_are_packages", "base_Dependency.client->forAll(oclIsKindOf(uml::Package))" //$NON-NLS-1$ //$NON-NLS-2$
+ });
+ }
+
+ /**
+ * Initializes the annotations for <b>http://schema.omg.org/spec/MOF/2.0/emof.xml#Property.oppositeRoleName</b>.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ protected void createEmofAnnotations()
+ {
+ String source = "http://schema.omg.org/spec/MOF/2.0/emof.xml#Property.oppositeRoleName"; //$NON-NLS-1$
+ addAnnotation(getApplyProfiles_Base_Dependency(),
+ source,
+ new String[]
+ { "body", "extension_ApplyProfiles" //$NON-NLS-1$ //$NON-NLS-2$
+ });
+ }
+
+} // ProfileExternalizationPackageImpl
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/internal/operations/ApplyProfilesOperations.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/internal/operations/ApplyProfilesOperations.java
new file mode 100644
index 00000000000..8fe6e059688
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/internal/operations/ApplyProfilesOperations.java
@@ -0,0 +1,88 @@
+/**
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ */
+package org.eclipse.papyrus.uml.decoratormodel.profileExternalization.internal.operations;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.emf.common.util.BasicEList;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ApplyProfiles;
+import org.eclipse.uml2.uml.Dependency;
+import org.eclipse.uml2.uml.NamedElement;
+import org.eclipse.uml2.uml.Profile;
+
+/**
+ * <!-- begin-user-doc -->
+ * A static utility class that provides operations related to '<em><b>Apply Profiles</b></em>' model objects.
+ * <!-- end-user-doc -->
+ *
+ * <p>
+ * The following operations are supported:
+ * <ul>
+ * <li>{@link org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ApplyProfiles#getAppliedProfiles() <em>Get Applied Profiles</em>}</li>
+ * <li>{@link org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ApplyProfiles#getExternalizedAppliedProfilePackages() <em>Get Externalized Applied Profile Packages</em>}</li>
+ * </ul>
+ * </p>
+ *
+ * @generated
+ */
+public class ApplyProfilesOperations
+{
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ protected ApplyProfilesOperations() {
+ super();
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated NOT
+ */
+ public static EList<Profile> getAppliedProfiles(ApplyProfiles applyProfiles) {
+ Set<Profile> result = new HashSet<Profile>();
+
+ for (org.eclipse.uml2.uml.Package package_ : applyProfiles.getExternalizedAppliedProfilePackages()) {
+ result.addAll(package_.getAppliedProfiles());
+ }
+
+ return new BasicEList.UnmodifiableEList<Profile>(result.size(), result.toArray());
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated NOT
+ */
+ public static EList<org.eclipse.uml2.uml.Package> getExternalizedAppliedProfilePackages(ApplyProfiles applyProfiles) {
+ Set<org.eclipse.uml2.uml.Package> result = new HashSet<org.eclipse.uml2.uml.Package>();
+
+ Dependency base = applyProfiles.getBase_Dependency();
+ if (base != null) {
+ for (NamedElement next : base.getSuppliers()) {
+ if (next instanceof org.eclipse.uml2.uml.Package) {
+ result.add((org.eclipse.uml2.uml.Package) next);
+ }
+ }
+ }
+
+ return new BasicEList.UnmodifiableEList<org.eclipse.uml2.uml.Package>(result.size(), result.toArray());
+ }
+
+} // ApplyProfilesOperations \ No newline at end of file
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/util/ProfileExternalizationAdapterFactory.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/util/ProfileExternalizationAdapterFactory.java
new file mode 100644
index 00000000000..123f70ccfec
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/util/ProfileExternalizationAdapterFactory.java
@@ -0,0 +1,148 @@
+/**
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ */
+package org.eclipse.papyrus.uml.decoratormodel.profileExternalization.util;
+
+import org.eclipse.emf.common.notify.Adapter;
+import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.emf.common.notify.impl.AdapterFactoryImpl;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.papyrus.uml.decoratormodel.profileExternalization.*;
+
+/**
+ * <!-- begin-user-doc -->
+ * The <b>Adapter Factory</b> for the model.
+ * It provides an adapter <code>createXXX</code> method for each class of the model.
+ * <!-- end-user-doc -->
+ *
+ * @see org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ProfileExternalizationPackage
+ * @generated
+ */
+public class ProfileExternalizationAdapterFactory extends AdapterFactoryImpl
+{
+ /**
+ * The cached model package.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ protected static ProfileExternalizationPackage modelPackage;
+
+ /**
+ * Creates an instance of the adapter factory.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ public ProfileExternalizationAdapterFactory()
+ {
+ if (modelPackage == null)
+ {
+ modelPackage = ProfileExternalizationPackage.eINSTANCE;
+ }
+ }
+
+ /**
+ * Returns whether this factory is applicable for the type of the object.
+ * <!-- begin-user-doc -->
+ * This implementation returns <code>true</code> if the object is either the model's package or is an instance object of the model.
+ * <!-- end-user-doc -->
+ *
+ * @return whether this factory is applicable for the type of the object.
+ * @generated
+ */
+ @Override
+ public boolean isFactoryForType(Object object)
+ {
+ if (object == modelPackage)
+ {
+ return true;
+ }
+ if (object instanceof EObject)
+ {
+ return ((EObject) object).eClass().getEPackage() == modelPackage;
+ }
+ return false;
+ }
+
+ /**
+ * The switch that delegates to the <code>createXXX</code> methods.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ protected ProfileExternalizationSwitch<Adapter> modelSwitch =
+ new ProfileExternalizationSwitch<Adapter>()
+ {
+ @Override
+ public Adapter caseApplyProfiles(ApplyProfiles object)
+ {
+ return createApplyProfilesAdapter();
+ }
+
+ @Override
+ public Adapter defaultCase(EObject object)
+ {
+ return createEObjectAdapter();
+ }
+ };
+
+ /**
+ * Creates an adapter for the <code>target</code>.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @param target
+ * the object to adapt.
+ * @return the adapter for the <code>target</code>.
+ * @generated
+ */
+ @Override
+ public Adapter createAdapter(Notifier target)
+ {
+ return modelSwitch.doSwitch((EObject) target);
+ }
+
+
+ /**
+ * Creates a new adapter for an object of class '{@link org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ApplyProfiles <em>Apply Profiles</em>}'.
+ * <!-- begin-user-doc -->
+ * This default implementation returns null so that we can easily ignore cases;
+ * it's useful to ignore a case when inheritance will catch all the cases anyway.
+ * <!-- end-user-doc -->
+ *
+ * @return the new adapter.
+ * @see org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ApplyProfiles
+ * @generated
+ */
+ public Adapter createApplyProfilesAdapter()
+ {
+ return null;
+ }
+
+ /**
+ * Creates a new adapter for the default case.
+ * <!-- begin-user-doc -->
+ * This default implementation returns null.
+ * <!-- end-user-doc -->
+ *
+ * @return the new adapter.
+ * @generated
+ */
+ public Adapter createEObjectAdapter()
+ {
+ return null;
+ }
+
+} // ProfileExternalizationAdapterFactory
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/util/ProfileExternalizationSwitch.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/util/ProfileExternalizationSwitch.java
new file mode 100644
index 00000000000..49bbe45d06e
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/util/ProfileExternalizationSwitch.java
@@ -0,0 +1,136 @@
+/**
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ */
+package org.eclipse.papyrus.uml.decoratormodel.profileExternalization.util;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.util.Switch;
+import org.eclipse.papyrus.uml.decoratormodel.profileExternalization.*;
+
+/**
+ * <!-- begin-user-doc -->
+ * The <b>Switch</b> for the model's inheritance hierarchy.
+ * It supports the call {@link #doSwitch(EObject) doSwitch(object)} to invoke the <code>caseXXX</code> method for each class of the model,
+ * starting with the actual class of the object
+ * and proceeding up the inheritance hierarchy
+ * until a non-null result is returned,
+ * which is the result of the switch.
+ * <!-- end-user-doc -->
+ *
+ * @see org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ProfileExternalizationPackage
+ * @generated
+ */
+public class ProfileExternalizationSwitch<T> extends Switch<T>
+{
+ /**
+ * The cached model package
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ protected static ProfileExternalizationPackage modelPackage;
+
+ /**
+ * Creates an instance of the switch.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ public ProfileExternalizationSwitch()
+ {
+ if (modelPackage == null)
+ {
+ modelPackage = ProfileExternalizationPackage.eINSTANCE;
+ }
+ }
+
+ /**
+ * Checks whether this is a switch for the given package.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @parameter ePackage the package in question.
+ * @return whether this is a switch for the given package.
+ * @generated
+ */
+ @Override
+ protected boolean isSwitchFor(EPackage ePackage)
+ {
+ return ePackage == modelPackage;
+ }
+
+ /**
+ * Calls <code>caseXXX</code> for each class of the model until one returns a non null result; it yields that result.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @return the first non-null result returned by a <code>caseXXX</code> call.
+ * @generated
+ */
+ @Override
+ protected T doSwitch(int classifierID, EObject theEObject)
+ {
+ switch (classifierID)
+ {
+ case ProfileExternalizationPackage.APPLY_PROFILES: {
+ ApplyProfiles applyProfiles = (ApplyProfiles) theEObject;
+ T result = caseApplyProfiles(applyProfiles);
+ if (result == null) {
+ result = defaultCase(theEObject);
+ }
+ return result;
+ }
+ default:
+ return defaultCase(theEObject);
+ }
+ }
+
+ /**
+ * Returns the result of interpreting the object as an instance of '<em>Apply Profiles</em>'.
+ * <!-- begin-user-doc -->
+ * This implementation returns null;
+ * returning a non-null result will terminate the switch.
+ * <!-- end-user-doc -->
+ *
+ * @param object
+ * the target of the switch.
+ * @return the result of interpreting the object as an instance of '<em>Apply Profiles</em>'.
+ * @see #doSwitch(org.eclipse.emf.ecore.EObject) doSwitch(EObject)
+ * @generated
+ */
+ public T caseApplyProfiles(ApplyProfiles object)
+ {
+ return null;
+ }
+
+ /**
+ * Returns the result of interpreting the object as an instance of '<em>EObject</em>'.
+ * <!-- begin-user-doc -->
+ * This implementation returns null;
+ * returning a non-null result will terminate the switch, but this is the last case anyway.
+ * <!-- end-user-doc -->
+ *
+ * @param object
+ * the target of the switch.
+ * @return the result of interpreting the object as an instance of '<em>EObject</em>'.
+ * @see #doSwitch(org.eclipse.emf.ecore.EObject)
+ * @generated
+ */
+ @Override
+ public T defaultCase(EObject object)
+ {
+ return null;
+ }
+
+} // ProfileExternalizationSwitch
diff --git a/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/util/ProfileExternalizationValidator.java b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/util/ProfileExternalizationValidator.java
new file mode 100644
index 00000000000..7ea7a9e80bf
--- /dev/null
+++ b/plugins/uml/decoratormodel/org.eclipse.papyrus.uml.decoratormodel/src/org/eclipse/papyrus/uml/decoratormodel/profileExternalization/util/ProfileExternalizationValidator.java
@@ -0,0 +1,231 @@
+/**
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ */
+package org.eclipse.papyrus.uml.decoratormodel.profileExternalization.util;
+
+import java.util.Map;
+
+import org.eclipse.emf.common.util.Diagnostic;
+import org.eclipse.emf.common.util.DiagnosticChain;
+import org.eclipse.emf.common.util.ResourceLocator;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.util.EObjectValidator;
+import org.eclipse.papyrus.uml.decoratormodel.profileExternalization.*;
+
+/**
+ * <!-- begin-user-doc -->
+ * The <b>Validator</b> for the model.
+ * <!-- end-user-doc -->
+ *
+ * @see org.eclipse.papyrus.uml.decoratormodel.profileExternalization.ProfileExternalizationPackage
+ * @generated
+ */
+public class ProfileExternalizationValidator extends EObjectValidator
+{
+ /**
+ * The cached model package
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ public static final ProfileExternalizationValidator INSTANCE = new ProfileExternalizationValidator();
+
+ /**
+ * A constant for the {@link org.eclipse.emf.common.util.Diagnostic#getSource() source} of diagnostic {@link org.eclipse.emf.common.util.Diagnostic#getCode() codes} from this package.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @see org.eclipse.emf.common.util.Diagnostic#getSource()
+ * @see org.eclipse.emf.common.util.Diagnostic#getCode()
+ * @generated
+ */
+ public static final String DIAGNOSTIC_SOURCE = "org.eclipse.papyrus.uml.decoratormodel.profileExternalization"; //$NON-NLS-1$
+
+ /**
+ * A constant with a fixed name that can be used as the base value for additional hand written constants.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ private static final int GENERATED_DIAGNOSTIC_CODE_COUNT = 0;
+
+ /**
+ * A constant with a fixed name that can be used as the base value for additional hand written constants in a derived class.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ protected static final int DIAGNOSTIC_CODE_COUNT = GENERATED_DIAGNOSTIC_CODE_COUNT;
+
+ /**
+ * Creates an instance of the switch.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ public ProfileExternalizationValidator()
+ {
+ super();
+ }
+
+ /**
+ * Returns the package of this validator switch.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ @Override
+ protected EPackage getEPackage()
+ {
+ return ProfileExternalizationPackage.eINSTANCE;
+ }
+
+ /**
+ * Calls <code>validateXXX</code> for the corresponding classifier of the model.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ @Override
+ protected boolean validate(int classifierID, Object value, DiagnosticChain diagnostics, Map<Object, Object> context)
+ {
+ switch (classifierID)
+ {
+ case ProfileExternalizationPackage.APPLY_PROFILES:
+ return validateApplyProfiles((ApplyProfiles) value, diagnostics, context);
+ default:
+ return true;
+ }
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ public boolean validateApplyProfiles(ApplyProfiles applyProfiles, DiagnosticChain diagnostics, Map<Object, Object> context)
+ {
+ if (!validate_NoCircularContainment(applyProfiles, diagnostics, context)) {
+ return false;
+ }
+ boolean result = validate_EveryMultiplicityConforms(applyProfiles, diagnostics, context);
+ if (result || diagnostics != null) {
+ result &= validate_EveryDataValueConforms(applyProfiles, diagnostics, context);
+ }
+ if (result || diagnostics != null) {
+ result &= validate_EveryReferenceIsContained(applyProfiles, diagnostics, context);
+ }
+ if (result || diagnostics != null) {
+ result &= validate_EveryBidirectionalReferenceIsPaired(applyProfiles, diagnostics, context);
+ }
+ if (result || diagnostics != null) {
+ result &= validate_EveryProxyResolves(applyProfiles, diagnostics, context);
+ }
+ if (result || diagnostics != null) {
+ result &= validate_UniqueID(applyProfiles, diagnostics, context);
+ }
+ if (result || diagnostics != null) {
+ result &= validate_EveryKeyUnique(applyProfiles, diagnostics, context);
+ }
+ if (result || diagnostics != null) {
+ result &= validate_EveryMapEntryUnique(applyProfiles, diagnostics, context);
+ }
+ if (result || diagnostics != null) {
+ result &= validateApplyProfiles_suppliers_are_packages(applyProfiles, diagnostics, context);
+ }
+ if (result || diagnostics != null) {
+ result &= validateApplyProfiles_clients_are_packages(applyProfiles, diagnostics, context);
+ }
+ return result;
+ }
+
+ /**
+ * The cached validation expression for the suppliers_are_packages constraint of '<em>Apply Profiles</em>'.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ protected static final String APPLY_PROFILES__SUPPLIERS_ARE_PACKAGES__EEXPRESSION = "base_Dependency.supplier->forAll(oclIsKindOf(uml::Package))"; //$NON-NLS-1$
+
+ /**
+ * Validates the suppliers_are_packages constraint of '<em>Apply Profiles</em>'.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ public boolean validateApplyProfiles_suppliers_are_packages(ApplyProfiles applyProfiles, DiagnosticChain diagnostics, Map<Object, Object> context)
+ {
+ return validate(ProfileExternalizationPackage.Literals.APPLY_PROFILES,
+ applyProfiles,
+ diagnostics,
+ context, "http://www.eclipse.org/emf/2002/Ecore/OCL", //$NON-NLS-1$
+ "suppliers_are_packages", //$NON-NLS-1$
+ APPLY_PROFILES__SUPPLIERS_ARE_PACKAGES__EEXPRESSION,
+ Diagnostic.ERROR,
+ DIAGNOSTIC_SOURCE,
+ 0);
+ }
+
+ /**
+ * The cached validation expression for the clients_are_packages constraint of '<em>Apply Profiles</em>'.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ protected static final String APPLY_PROFILES__CLIENTS_ARE_PACKAGES__EEXPRESSION = "base_Dependency.client->forAll(oclIsKindOf(uml::Package))"; //$NON-NLS-1$
+
+ /**
+ * Validates the clients_are_packages constraint of '<em>Apply Profiles</em>'.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ public boolean validateApplyProfiles_clients_are_packages(ApplyProfiles applyProfiles, DiagnosticChain diagnostics, Map<Object, Object> context)
+ {
+ return validate(ProfileExternalizationPackage.Literals.APPLY_PROFILES,
+ applyProfiles,
+ diagnostics,
+ context, "http://www.eclipse.org/emf/2002/Ecore/OCL", //$NON-NLS-1$
+ "clients_are_packages", //$NON-NLS-1$
+ APPLY_PROFILES__CLIENTS_ARE_PACKAGES__EEXPRESSION,
+ Diagnostic.ERROR,
+ DIAGNOSTIC_SOURCE,
+ 0);
+ }
+
+ /**
+ * Returns the resource locator that will be used to fetch messages for this validator's diagnostics.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ @Override
+ public ResourceLocator getResourceLocator()
+ {
+ // TODO
+ // Specialize this to return a resource locator for messages specific to this validator.
+ // Ensure that you remove @generated or mark it @generated NOT
+ return super.getResourceLocator();
+ }
+
+} // ProfileExternalizationValidator
diff --git a/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/commands/MoveProfileApplicationCommand.java b/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/commands/MoveProfileApplicationCommand.java
index a5919a61837..f744e9af9fd 100644
--- a/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/commands/MoveProfileApplicationCommand.java
+++ b/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/commands/MoveProfileApplicationCommand.java
@@ -1,6 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2013 Atos.
- *
+ * Copyright (c) 2013, 2014 Atos, 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
@@ -9,6 +8,7 @@
*
* Contributors:
* Arthur Daussy (Atos) arthur.daussy@atos.net - Initial API and implementation
+ * Christian W. Damus - bug 399859
*
*****************************************************************************/
package org.eclipse.papyrus.uml.controlmode.profile.commands;
@@ -44,11 +44,12 @@ public class MoveProfileApplicationCommand extends AbstractControlCommand {
@Override
protected CommandResult doExecuteWithResult(IProgressMonitor monitor, IAdaptable info) throws ExecutionException {
Package packageUncontroled = (Package) getRequest().getTargetObject();
+ Resource sourceResource = packageUncontroled.eContainer().eResource();
Resource targetResource = getRequest().getTargetResource(getRequest().getNewURI().fileExtension());
if (targetResource == null) {
return CommandResult.newErrorCommandResult("Unable to retreive target resource");
}
- ProfileApplicationHelper.nestedRelocateStereotypeApplications(packageUncontroled, targetResource);
+ ProfileApplicationHelper.nestedRelocateStereotypeApplications(packageUncontroled, sourceResource, targetResource);
return CommandResult.newOKCommandResult();
}
} \ No newline at end of file
diff --git a/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/commands/MoveStereotypeApplicationToControlResource.java b/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/commands/MoveStereotypeApplicationToControlResource.java
index ec8a4f0fcd8..d1973f4df83 100644
--- a/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/commands/MoveStereotypeApplicationToControlResource.java
+++ b/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/commands/MoveStereotypeApplicationToControlResource.java
@@ -1,6 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2013 Atos.
- *
+ * Copyright (c) 2013, 2014 Atos, 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
@@ -9,6 +8,7 @@
*
* Contributors:
* Arthur Daussy (Atos) arthur.daussy@atos.net - Initial API and implementation
+ * Christian W. Damus - bug 399859
*
*****************************************************************************/
package org.eclipse.papyrus.uml.controlmode.profile.commands;
@@ -19,7 +19,6 @@ import java.util.Set;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
@@ -27,6 +26,7 @@ import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.gmf.runtime.common.core.command.CommandResult;
import org.eclipse.papyrus.infra.services.controlmode.ControlModeRequest;
import org.eclipse.papyrus.infra.services.controlmode.commands.AbstractControlCommand;
+import org.eclipse.papyrus.uml.controlmode.profile.helpers.ProfileApplicationHelper;
import org.eclipse.papyrus.uml.tools.model.UmlModel;
import org.eclipse.uml2.uml.Element;
@@ -58,13 +58,13 @@ public final class MoveStereotypeApplicationToControlResource extends AbstractCo
}
}
+ Resource sourceResource = elem.eContainer().eResource();
Resource targetResource = getRequest().getTargetResource(UmlModel.UML_FILE_EXTENSION);
if (targetResource == null) {
return createNewControlCommandError("No uml resource created");//
}
for (Element e : elements) {
- EList<EObject> stereotypeApplications = e.getStereotypeApplications();
- targetResource.getContents().addAll(stereotypeApplications);
+ ProfileApplicationHelper.relocateStereotypeApplications(e, sourceResource, targetResource);
}
return CommandResult.newOKCommandResult();
diff --git a/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/helpers/ProfileApplicationHelper.java b/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/helpers/ProfileApplicationHelper.java
index 4d215c1ee5f..6e6242a86ce 100644
--- a/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/helpers/ProfileApplicationHelper.java
+++ b/plugins/uml/org.eclipse.papyrus.uml.controlmode.profile/src/org/eclipse/papyrus/uml/controlmode/profile/helpers/ProfileApplicationHelper.java
@@ -1,6 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2011 Atos Origin.
- *
+ * Copyright (c) 2011, 2014 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
@@ -9,6 +8,7 @@
*
* Contributors:
* Atos Origin - Initial API and implementation
+ * Christian W. Damus - bug 399859
*
*****************************************************************************/
package org.eclipse.papyrus.uml.controlmode.profile.helpers;
@@ -36,7 +36,8 @@ public class ProfileApplicationHelper {
public static final String DUPLICATED_PROFILE = "duplicatedProfile";
/**
- * Duplicate a profile application on a child package.
+ * Duplicate a profile application on a child package if that profile application is
+ * intrinsic to the model (not owned by a different model).
*
* @param _package
* package to duplicate profile application on
@@ -45,7 +46,9 @@ public class ProfileApplicationHelper {
*/
public static void duplicateProfileApplication(Package _package, Profile profile) {
if (profile != null && profile.getDefinition() != null) {
- if (!isSameProfileApplied(_package, profile)) {
+ ProfileApplication toCopy = _package.getProfileApplication(profile, true);
+ // Is it inherited from a parent package and intrinsic to the model?
+ if (_package.allOwningPackages().contains(toCopy.getApplyingPackage())) {
_package.applyProfile(profile);
ProfileApplication profileAppl = _package.getProfileApplication(profile);
if (profileAppl != null) {
@@ -107,34 +110,45 @@ public class ProfileApplicationHelper {
}
/**
- * Relocate stereotype applications for the nested elements of the selection in the controlled resource
+ * Relocate stereotype applications for the nested elements of the selection in the controlled resource.
+ * Stereotype applications are moved to the {@code target} resource only if they are currently in the {@code source} resource, to account for possibly externalized profile applications.
*
* @param pack
* the package for which stereotype application must be relocated
+ * @param source
+ * the source resource
* @param target
* the target controlled resource
*/
- public static void nestedRelocateStereotypeApplications(Package pack, Resource target) {
- relocateStereotypeApplications(pack, target);
+ public static void nestedRelocateStereotypeApplications(Package pack, Resource source, Resource target) {
+ relocateStereotypeApplications(pack, source, target);
for (Iterator<EObject> i = EcoreUtil.getAllProperContents(pack, true); i.hasNext();) {
EObject current = i.next();
if (current instanceof Element) {
- relocateStereotypeApplications((Element) current, target);
+ relocateStereotypeApplications((Element) current, source, target);
}
}
}
/**
- * Relocate stereotype applications for the an element in the controlled resource
+ * Relocate stereotype applications for the an element in the controlled resource.
+ * Stereotype applications are moved to the {@code target} resource only if they are currently in the {@code source} resource, to account for possibly externalized profile applications.
*
* @param element
* the element for which stereotype application must be relocated
+ * @param source
+ * the source resource
* @param target
* the target controlled resource
*/
- public static void relocateStereotypeApplications(Element element, Resource targetResource) {
+ public static void relocateStereotypeApplications(Element element, Resource source, Resource target) {
EList<EObject> stereotypeApplications = element.getStereotypeApplications();
- targetResource.getContents().addAll(stereotypeApplications);
+ EList<EObject> targetList = target.getContents();
+ for (EObject next : stereotypeApplications) {
+ if (next.eResource() == source) {
+ targetList.add(next);
+ }
+ }
}
/**
diff --git a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/participants/StereotypeApplicationRepairParticipant.java b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/participants/StereotypeApplicationRepairParticipant.java
index 80d2bd42644..7e690138567 100644
--- a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/participants/StereotypeApplicationRepairParticipant.java
+++ b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/participants/StereotypeApplicationRepairParticipant.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 CEA and others.
+ * Copyright (c) 2014 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
@@ -8,6 +8,7 @@
*
* Contributors:
* Christian W. Damus (CEA) - Initial API and implementation
+ * Christian W. Damus - bug 399859
*
*/
package org.eclipse.papyrus.uml.modelrepair.internal.participants;
@@ -39,8 +40,10 @@ import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EStructuralFeature.Setting;
import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.util.ECrossReferenceAdapter;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.util.FeatureMap;
import org.eclipse.emf.ecore.xmi.XMLResource;
@@ -50,7 +53,6 @@ import org.eclipse.papyrus.infra.emf.resource.IDependencyReplacementParticipant;
import org.eclipse.papyrus.infra.emf.resource.Replacement;
import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
import org.eclipse.papyrus.uml.modelrepair.Activator;
-import org.eclipse.uml2.common.util.UML2Util;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Namespace;
@@ -218,6 +220,18 @@ public class StereotypeApplicationRepairParticipant extends PackageOperations im
public void migrate(Collection<? extends EObject> stereotypeApplications, IProgressMonitor monitor) {
SubMonitor sub = SubMonitor.convert(monitor, (2 * stereotypeApplications.size()) + 2);
+ // Capture object IDs for later transfer to new stereotype applications
+ final Map<EObject, String> objectIDs = Maps.newHashMap();
+ for (EObject next : stereotypeApplications) {
+ Resource res = next.eResource();
+ if (res instanceof XMLResource) {
+ String id = ((XMLResource) res).getID(next);
+ if (id != null) {
+ objectIDs.put(next, id);
+ }
+ }
+ }
+
for (EObject next : stereotypeApplications) {
EObject newInstance = copier.copy(next);
if ((newInstance != null) && (newInstance != next)) {
@@ -244,26 +258,28 @@ public class StereotypeApplicationRepairParticipant extends PackageOperations im
if (copy != null) {
// Update the ID, if the old ID is known
- Resource res = original.eResource();
- if (res instanceof XMLResource) {
- XMLResource xml = (XMLResource) res;
- String id = xml.getID(original);
- if (id != null) {
- xml.setID(copy, id);
+ String id = objectIDs.get(original);
+ if (id != null) {
+ Resource res = copy.eResource();
+ if (res instanceof XMLResource) {
+ ((XMLResource) res).setID(copy, id);
}
}
// Replace incoming references to the old stereotypes with references to the new stereotypes
for (Setting setting : ImmutableList.copyOf(getNonNavigableInverseReferences(original))) {
- EStructuralFeature ref = setting.getEStructuralFeature();
-
- if ((ref != null) && ref.isChangeable()) {
- if (ref.isMany()) {
- @SuppressWarnings("unchecked")
- EList<EObject> list = ((EList<EObject>) setting.getEObject().eGet(ref));
- list.set(list.indexOf(original), copy);
- } else {
- setting.set(copy);
+ // Don't update cross-references between the old stereotype applications!
+ if (!copier.containsKey(setting.getEObject())) {
+ EStructuralFeature ref = setting.getEStructuralFeature();
+
+ if ((ref != null) && ref.isChangeable()) {
+ if (ref.isMany()) {
+ @SuppressWarnings("unchecked")
+ EList<EObject> list = ((EList<EObject>) setting.getEObject().eGet(ref));
+ list.set(list.indexOf(original), copy);
+ } else {
+ setting.set(copy);
+ }
}
}
}
@@ -273,11 +289,44 @@ public class StereotypeApplicationRepairParticipant extends PackageOperations im
}
sub2.done();
- UML2Util.destroyAll(stereotypeApplications);
+ // Delete all trace of the old stereotype applications
+ for (EObject root : stereotypeApplications) {
+ removeCrossReferences(root);
+
+ for (TreeIterator<EObject> iter = root.eAllContents(); iter.hasNext();) {
+ EObject next = iter.next();
+
+ // The 'mixed' feature-map of an AnyType typically includes EReferences that think they are containments but aren't,
+ // where there are cross-document references (which are represented in the XMI as nested elements)
+ if (next.eIsProxy() || !EcoreUtil.isAncestor(root, next)) {
+ // Don't mess with objects contained elsewhere; they are referenced, not actually contained
+ iter.prune();
+ } else {
+ removeCrossReferences(next);
+ }
+ }
+
+ // And detach it from wherever it may be (if anywhere)
+ EcoreUtil.remove(root);
+ }
+
sub.worked(1);
copier.clear();
}
+
+ private void removeCrossReferences(EObject object) {
+ ECrossReferenceAdapter xrefAdapter = ECrossReferenceAdapter.getCrossReferenceAdapter(object);
+ if (xrefAdapter != null) { // It should not be null because we have the UML CacheAdapter!
+ for (EStructuralFeature.Setting next : ImmutableList.copyOf(xrefAdapter.getInverseReferences(object))) {
+ EReference reference = (EReference) next.getEStructuralFeature();
+
+ if (reference.isChangeable() && !reference.isContainment() && !reference.isContainer() && !reference.isDerived()) {
+ EcoreUtil.remove(next, object);
+ }
+ }
+ }
+ }
}
protected static class StereotypeApplicationRepairCopier extends StereotypeApplicationCopier {
@@ -409,11 +458,25 @@ public class StereotypeApplicationRepairParticipant extends PackageOperations im
if (referenced == null) {
String propertyName = getQualifiedName(UMLUtil.getNamedElement(copyFeature, eObject));
handleException(new IllegalStateException(String.format("Unresolved reference in stereotype property %s: %s", propertyName, ref))); //$NON-NLS-1$
- } else if (!copyFeature.getEType().isInstance(referenced)) {
- String propertyName = getQualifiedName(UMLUtil.getNamedElement(copyFeature, eObject));
- handleException(new IllegalStateException(String.format("Attempt to reference object of type %s in stereotype property %s", UML2EcoreConverter.getOriginalName(referenced.eClass()), propertyName))); //$NON-NLS-1$
} else {
- eAdd(copyEObject, copyFeature, referenced);
+ // Is it an AnyType? If so, perhaps we have already converted it
+ if (referenced instanceof AnyType) {
+ // Look for copy
+ EObject referencedCopy = get(referenced);
+ if (referencedCopy != null) {
+ referenced = referencedCopy;
+ } else {
+ // Create a new proxy for it
+ referenced = createProxy((EReference) copyFeature, (AnyType) referenced);
+ }
+ }
+
+ if (!copyFeature.getEType().isInstance(referenced)) {
+ String propertyName = getQualifiedName(UMLUtil.getNamedElement(copyFeature, eObject));
+ handleException(new IllegalStateException(String.format("Attempt to reference object of type %s in stereotype property %s", UML2EcoreConverter.getOriginalName(referenced.eClass()), propertyName))); //$NON-NLS-1$
+ } else {
+ eAdd(copyEObject, copyFeature, referenced);
+ }
}
}
} else if (copyFeature instanceof EAttribute) {
@@ -462,6 +525,24 @@ public class StereotypeApplicationRepairParticipant extends PackageOperations im
return baseResource.getResourceSet().getEObject(uri, true);
}
+ protected EObject createProxy(EReference reference, AnyType original) {
+ EObject result = original; // As a fall-back, we would just return the original and report a problem
+
+ EClass type = reference.getEReferenceType();
+ if (type.isAbstract()) {
+ // The original should have had type information, then, in the reference
+ type = getTarget(original);
+ }
+
+ if ((type != null) && !type.isAbstract()) {
+ result = EcoreUtil.create(type);
+ Resource resource = original.eResource();
+ ((InternalEObject) result).eSetProxyURI(resource.getURI().appendFragment(resource.getURIFragment(original)));
+ }
+
+ return result;
+ }
+
protected void copyUnrecognizedContentMixed(EAttribute mixed, EObject eObject, EObject copyEObject) {
FeatureMap featureMap = (FeatureMap) eObject.eGet(mixed);
for (FeatureMap.Entry next : featureMap) {
@@ -488,19 +569,29 @@ public class StereotypeApplicationRepairParticipant extends PackageOperations im
} else if (copyFeature instanceof EReference) {
EReference reference = (EReference) copyFeature;
if (!reference.isContainment()) {
- // Get the HREF/IDREF from the element, resolve the referenced object, and set it into the reference
- String refs = getTextContent(anyType);
- if (refs != null) {
- for (String ref : whitespace.split(refs)) {
- EObject referenced = resolveRef(eObject, ref);
- if (referenced == null) {
- String propertyName = getQualifiedName(UMLUtil.getNamedElement(copyFeature, eObject));
- handleException(new IllegalStateException(String.format("Unresolved reference in stereotype property %s: %s", propertyName, ref))); //$NON-NLS-1$
- } else if (!copyFeature.getEType().isInstance(referenced)) {
- String propertyName = getQualifiedName(UMLUtil.getNamedElement(copyFeature, eObject));
- handleException(new IllegalStateException(String.format("Attempt to reference object of type %s in stereotype property %s", UML2EcoreConverter.getOriginalName(referenced.eClass()), propertyName))); //$NON-NLS-1$
- } else {
- eAdd(copyEObject, reference, referenced);
+ if (anyType.eClass() != XMLTypePackage.Literals.ANY_TYPE) {
+ // We got a real proxy, somehow. Just use it
+ if (!copyFeature.getEType().isInstance(anyType)) {
+ String propertyName = getQualifiedName(UMLUtil.getNamedElement(copyFeature, eObject));
+ handleException(new IllegalStateException(String.format("Attempt to reference object of type %s in stereotype property %s", UML2EcoreConverter.getOriginalName(anyType.eClass()), propertyName))); //$NON-NLS-1$
+ } else {
+ eAdd(copyEObject, reference, anyType);
+ }
+ } else {
+ // Get the HREF/IDREF from the element, resolve the referenced object, and set it into the reference
+ String refs = getTextContent(anyType);
+ if (refs != null) {
+ for (String ref : whitespace.split(refs)) {
+ EObject referenced = resolveRef(eObject, ref);
+ if (referenced == null) {
+ String propertyName = getQualifiedName(UMLUtil.getNamedElement(copyFeature, eObject));
+ handleException(new IllegalStateException(String.format("Unresolved reference in stereotype property %s: %s", propertyName, ref))); //$NON-NLS-1$
+ } else if (!copyFeature.getEType().isInstance(referenced)) {
+ String propertyName = getQualifiedName(UMLUtil.getNamedElement(copyFeature, eObject));
+ handleException(new IllegalStateException(String.format("Attempt to reference object of type %s in stereotype property %s", UML2EcoreConverter.getOriginalName(referenced.eClass()), propertyName))); //$NON-NLS-1$
+ } else {
+ eAdd(copyEObject, reference, referenced);
+ }
}
}
}
@@ -653,7 +744,8 @@ public class StereotypeApplicationRepairParticipant extends PackageOperations im
// The base_Xyz extension end is always at most one, so it should be serialized as an IDREF
for (FeatureMap.Entry next : (FeatureMap) anyType.eGet(XMLTypePackage.Literals.ANY_TYPE__ANY_ATTRIBUTE)) {
if (next.getEStructuralFeature().getName().startsWith("base_")) {
- EObject referenced = resolveRef(anyType, String.valueOf(next.getValue()));
+ Object value = next.getValue();
+ EObject referenced = (value instanceof EObject) ? (EObject) value : resolveRef(anyType, String.valueOf(next.getValue()));
if (referenced instanceof Element) {
result = (Element) referenced;
break;
@@ -665,7 +757,8 @@ public class StereotypeApplicationRepairParticipant extends PackageOperations im
if (result == null) {
for (FeatureMap.Entry next : (FeatureMap) anyType.eGet(XMLTypePackage.Literals.ANY_TYPE__MIXED)) {
if ((next.getEStructuralFeature() instanceof EReference) && next.getEStructuralFeature().getName().startsWith("base_")) {
- EObject referenced = resolveRef(anyType, getTextContent((EObject) next.getValue()));
+ EObject value = (EObject) next.getValue();
+ EObject referenced = (value.eClass() != XMLTypePackage.Literals.ANY_TYPE) ? (EObject) value : resolveRef(anyType, getTextContent(value));
if (referenced instanceof Element) {
result = (Element) referenced;
break;
diff --git a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/ApplyProfileAction.java b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/ApplyProfileAction.java
index 82ce8181436..91b7d9a5656 100644
--- a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/ApplyProfileAction.java
+++ b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/ApplyProfileAction.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 CEA and others.
+ * Copyright (c) 2014 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
@@ -8,6 +8,7 @@
*
* Contributors:
* Christian W. Damus (CEA) - Initial API and implementation
+ * Christian W. Damus - bug 399859
*
*/
package org.eclipse.papyrus.uml.modelrepair.internal.stereotypes;
@@ -24,8 +25,11 @@ import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.osgi.util.NLS;
import org.eclipse.papyrus.infra.services.labelprovider.service.LabelProviderService;
import org.eclipse.papyrus.uml.modelrepair.internal.participants.StereotypeApplicationRepairParticipant;
+import org.eclipse.papyrus.uml.tools.helper.IProfileApplicationDelegate;
+import org.eclipse.papyrus.uml.tools.helper.ProfileApplicationDelegateRegistry;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.Profile;
+import org.eclipse.uml2.uml.ProfileApplication;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
@@ -84,7 +88,7 @@ public class ApplyProfileAction extends AbstractRepairAction {
// Apply the profile
StereotypeApplicationRepairParticipant.createStereotypeApplicationMigrator(profile, diagnostics).migrate(stereotypeApplications, sub.newChild(stereotypeApplications.size()));
for (Package next : packages) {
- next.applyProfile(profile);
+ applyProfile(next, profile);
}
result = true;
@@ -94,4 +98,23 @@ public class ApplyProfileAction extends AbstractRepairAction {
return result;
}
+
+ protected ProfileApplication applyProfile(Package package_, Profile profile) {
+ ProfileApplication result;
+
+ IProfileApplicationDelegate delegate = ProfileApplicationDelegateRegistry.INSTANCE.getDelegate(package_);
+
+ // Is this a re-application?
+ ProfileApplication existing = delegate.getProfileApplication(package_, profile);
+ if (existing != null) {
+ delegate = ProfileApplicationDelegateRegistry.INSTANCE.getDelegate(existing);
+ delegate.reapplyProfile(package_, profile);
+ result = existing;
+ } else {
+ package_.applyProfile(profile);
+ result = delegate.getProfileApplication(package_, profile);
+ }
+
+ return result;
+ }
}
diff --git a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/ZombieStereotypesDescriptor.java b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/ZombieStereotypesDescriptor.java
index 73199c701f3..6c30a71318c 100644
--- a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/ZombieStereotypesDescriptor.java
+++ b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/ZombieStereotypesDescriptor.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 CEA and others.
+ * Copyright (c) 2014 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
@@ -8,6 +8,7 @@
*
* Contributors:
* Christian W. Damus (CEA) - Initial API and implementation
+ * Christian W. Damus - bug 399859
*
*/
package org.eclipse.papyrus.uml.modelrepair.internal.stereotypes;
@@ -22,6 +23,7 @@ import java.util.regex.Pattern;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.common.util.DiagnosticChain;
+import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
@@ -35,6 +37,8 @@ import org.eclipse.emf.ecore.util.FeatureMap;
import org.eclipse.emf.ecore.util.FeatureMapUtil;
import org.eclipse.papyrus.infra.services.labelprovider.service.LabelProviderService;
import org.eclipse.papyrus.uml.modelrepair.internal.participants.StereotypesUtil;
+import org.eclipse.papyrus.uml.tools.helper.IProfileApplicationDelegate;
+import org.eclipse.papyrus.uml.tools.helper.ProfileApplicationDelegateRegistry;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Extension;
import org.eclipse.uml2.uml.Package;
@@ -286,11 +290,12 @@ public class ZombieStereotypesDescriptor {
} else {
// Find the profile application
result = null;
- for (Package pkg = base.getNearestPackage(); pkg != null; pkg = (pkg.getOwner() == null) ? null : pkg.getOwner().getNearestPackage()) {
- for (ProfileApplication next : pkg.getProfileApplications()) {
+ out: for (Package pkg = base.getNearestPackage(); pkg != null; pkg = (pkg.getOwner() == null) ? null : pkg.getOwner().getNearestPackage()) {
+ IProfileApplicationDelegate delegate = ProfileApplicationDelegateRegistry.INSTANCE.getDelegate(pkg);
+ for (ProfileApplication next : delegate.getProfileApplications(pkg)) {
if (equal(next.getAppliedDefinition(), schema, root)) {
result = new ProfileContext(schema, next);
- break;
+ break out;
}
}
}
@@ -318,9 +323,23 @@ public class ZombieStereotypesDescriptor {
}
} else if (FeatureMapUtil.isFeatureMap(next)) {
// Handle unknown schema
- for (FeatureMap.Entry entry : (FeatureMap) stereotypeApplication.eGet(next)) {
- if (entry.getEStructuralFeature().getName().startsWith(Extension.METACLASS_ROLE_PREFIX)) {
- Object value = entry.getValue();
+ FeatureMap.Internal fmap = (FeatureMap.Internal) stereotypeApplication.eGet(next);
+ int entryIndex = -1;
+ for (FeatureMap.Entry entry : fmap) {
+ entryIndex++;
+ EStructuralFeature feature = entry.getEStructuralFeature();
+ if (feature.getName().startsWith(Extension.METACLASS_ROLE_PREFIX)) {
+ // In case it's a reference, ensure that we try to resolve it
+ Object value = fmap.get(feature, true);
+ if (value instanceof EList<?>) {
+ // As a member of the 'mixed' feature-map, it is assumed to have multiplicity
+ value = ((EList<?>) value).get(0);
+
+ // The feature-map list doesn't resolve proxies despite that we asked for resolving
+ if (feature instanceof EReference) {
+ value = fmap.resolveProxy(feature, entryIndex, 0, value);
+ }
+ }
if (value instanceof String) {
// Try it as an IDREF
@@ -358,11 +377,26 @@ public class ZombieStereotypesDescriptor {
result = schema1 == schema2;
if (!result && (schema1 != null)) { // Implies that schema2 != null, also
result = Objects.equal(schema1.getNsURI(), schema2.getNsURI());
+
if (!result) {
// Maybe one is a proxy whose URI is the schema-location of the other (being a demand-created package)
URI uri1 = guessURI(schema1);
URI uri2 = guessURI(schema2);
result = Objects.equal(uri1, uri2);
+
+ if (!result) {
+ // One more try: If both URIs match the auto-generated dynamic Ecore definition pattern, then we
+ // can try to normalize and compare them
+ Matcher m = AUTO_NSURI_PATTERN.matcher(uri1.toString());
+ if (m.matches()) {
+ String normalized1 = uri1.toString().substring(0, m.start(1));
+ m.reset(uri2.toString());
+ if (m.matches()) {
+ String normalized2 = uri2.toString().substring(0, m.start(1));
+ result = normalized1.equals(normalized2);
+ }
+ }
+ }
}
}
@@ -412,9 +446,7 @@ public class ZombieStereotypesDescriptor {
}
ProfileContext(EPackage schema, ProfileApplication profileApplication) {
- this.applyingPackage = profileApplication.getApplyingPackage();
- this.schema = schema;
- init();
+ this(profileApplication.getApplyingPackage(), schema);
}
private void init() {
diff --git a/plugins/uml/org.eclipse.papyrus.uml.profile/META-INF/MANIFEST.MF b/plugins/uml/org.eclipse.papyrus.uml.profile/META-INF/MANIFEST.MF
index e236cd836eb..5d05a683864 100644
--- a/plugins/uml/org.eclipse.papyrus.uml.profile/META-INF/MANIFEST.MF
+++ b/plugins/uml/org.eclipse.papyrus.uml.profile/META-INF/MANIFEST.MF
@@ -4,6 +4,7 @@ Export-Package: org.eclipse.papyrus.uml.profile,
org.eclipse.papyrus.uml.profile.definition,
org.eclipse.papyrus.uml.profile.preference,
org.eclipse.papyrus.uml.profile.providers,
+ org.eclipse.papyrus.uml.profile.service,
org.eclipse.papyrus.uml.profile.structure,
org.eclipse.papyrus.uml.profile.tree,
org.eclipse.papyrus.uml.profile.tree.objects,
diff --git a/plugins/uml/org.eclipse.papyrus.uml.profile/src/org/eclipse/papyrus/uml/profile/providers/ProfileApplicationContentProvider.java b/plugins/uml/org.eclipse.papyrus.uml.profile/src/org/eclipse/papyrus/uml/profile/providers/ProfileApplicationContentProvider.java
index 06ae1a7d489..213cdb282fc 100644
--- a/plugins/uml/org.eclipse.papyrus.uml.profile/src/org/eclipse/papyrus/uml/profile/providers/ProfileApplicationContentProvider.java
+++ b/plugins/uml/org.eclipse.papyrus.uml.profile/src/org/eclipse/papyrus/uml/profile/providers/ProfileApplicationContentProvider.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2012 CEA LIST.
+ * Copyright (c) 2012, 2014 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
@@ -9,6 +9,8 @@
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
* Gabriel Pascual (ALL4TEC) gabriel.pascual@all4tec.net - Initial API and implementation
+ * Christian W. Damus - bug 399859
+ *
*****************************************************************************/
package org.eclipse.papyrus.uml.profile.providers;
@@ -17,9 +19,10 @@ import java.util.List;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.papyrus.infra.widgets.providers.AbstractStaticContentProvider;
+import org.eclipse.papyrus.uml.tools.helper.IProfileApplicationDelegate;
+import org.eclipse.papyrus.uml.tools.helper.ProfileApplicationDelegateRegistry;
import org.eclipse.papyrus.uml.tools.utils.ProfileUtil;
import org.eclipse.uml2.uml.Package;
-import org.eclipse.uml2.uml.Profile;
import org.eclipse.uml2.uml.ProfileApplication;
@@ -41,6 +44,8 @@ public class ProfileApplicationContentProvider extends AbstractStaticContentProv
* the root package
*/
public ProfileApplicationContentProvider(Package rootPackage) {
+ super();
+
this.rootPackage = rootPackage;
}
@@ -73,10 +78,9 @@ public class ProfileApplicationContentProvider extends AbstractStaticContentProv
// Parse applied profiles of parent to find dirty ones and get profile application
- List<Profile> appliedProfiles = new LinkedList<Profile>(parentPackage.getAppliedProfiles());
- for (Profile profile : appliedProfiles) {
- if (ProfileUtil.isDirty(parentPackage, profile)) {
- childrenList.add(parentPackage.getProfileApplication(profile));
+ for (ProfileApplication profileApplication : getDelegate(parentPackage).getProfileApplications(parentPackage)) {
+ if ((profileApplication != null) && ProfileUtil.isDirty(parentPackage, profileApplication.getAppliedProfile())) {
+ childrenList.add(profileApplication);
}
}
@@ -89,10 +93,13 @@ public class ProfileApplicationContentProvider extends AbstractStaticContentProv
children = new Object[0];
}
-
return children;
}
+ protected IProfileApplicationDelegate getDelegate(Package package_) {
+ return ProfileApplicationDelegateRegistry.INSTANCE.getDelegate(package_);
+ }
+
/**
* @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang.Object)
*
@@ -121,5 +128,4 @@ public class ProfileApplicationContentProvider extends AbstractStaticContentProv
return getChildren(element).length > 0;
}
-
}
diff --git a/plugins/uml/org.eclipse.papyrus.uml.profile/src/org/eclipse/papyrus/uml/profile/service/ReapplyProfilesService.java b/plugins/uml/org.eclipse.papyrus.uml.profile/src/org/eclipse/papyrus/uml/profile/service/ReapplyProfilesService.java
index 69bd34952b0..a5be822ad2f 100644
--- a/plugins/uml/org.eclipse.papyrus.uml.profile/src/org/eclipse/papyrus/uml/profile/service/ReapplyProfilesService.java
+++ b/plugins/uml/org.eclipse.papyrus.uml.profile/src/org/eclipse/papyrus/uml/profile/service/ReapplyProfilesService.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2013, 2014 CEA LIST and others.
+ * Copyright (c) 2013, 2014 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
@@ -10,6 +10,8 @@
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
* Christian W. Damus (CEA) - bug 434302
* Gabriel Pascual (ALL4TEC) gabriel.pascual@all4tec.net - Bug 435995
+ * Christian W. Damus - bug 399859
+ *
*****************************************************************************/
package org.eclipse.papyrus.uml.profile.service;
@@ -19,8 +21,8 @@ import java.util.Map;
import org.eclipse.emf.common.command.CompoundCommand;
import org.eclipse.emf.ecore.EObject;
-import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.emf.transaction.util.TransactionUtil;
import org.eclipse.papyrus.infra.core.editor.IMultiDiagramEditor;
import org.eclipse.papyrus.infra.core.resource.ModelSet;
import org.eclipse.papyrus.infra.core.resource.NotFoundException;
@@ -29,17 +31,19 @@ import org.eclipse.papyrus.infra.core.services.EditorLifecycleManager;
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.emf.utils.EMFHelper;
import org.eclipse.papyrus.uml.modelrepair.service.IStereotypeRepairService;
import org.eclipse.papyrus.uml.profile.Activator;
import org.eclipse.papyrus.uml.profile.service.ui.RefreshProfileDialog;
import org.eclipse.papyrus.uml.profile.validation.ProfileValidationHelper;
import org.eclipse.papyrus.uml.tools.commands.ApplyProfileCommand;
+import org.eclipse.papyrus.uml.tools.helper.IProfileApplicationDelegate;
+import org.eclipse.papyrus.uml.tools.helper.ProfileApplicationDelegateRegistry;
import org.eclipse.papyrus.uml.tools.model.UmlModel;
import org.eclipse.papyrus.uml.tools.utils.ProfileUtil;
import org.eclipse.swt.widgets.Display;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.Profile;
+import org.eclipse.uml2.uml.ProfileApplication;
/**
* If a local profile is applied on this model, and this profile has been
@@ -58,6 +62,8 @@ public class ReapplyProfilesService implements IService, EditorLifecycleEventLis
private IStereotypeRepairService stereotypeRepairService;
+ private IMultiDiagramEditor editor;
+
/**
* {@inheritDoc}
*/
@@ -83,6 +89,27 @@ public class ReapplyProfilesService implements IService, EditorLifecycleEventLis
}
}
+ public void checkProfiles() {
+ if (editor != null) {
+ checkProfilesAfterRepair(editor);
+ }
+ }
+
+ private void checkProfilesAfterRepair(final IMultiDiagramEditor editor) {
+ if (stereotypeRepairService == null) {
+ // Just check profiles, now
+ checkProfiles(editor);
+ } else {
+ // Ensure that we only kick in the profile migration after any pending repair has completed
+ stereotypeRepairService.getPostRepairExecutor().execute(new Runnable() {
+
+ public void run() {
+ checkProfiles(editor);
+ }
+ });
+ }
+ }
+
protected void checkProfiles(IMultiDiagramEditor editor) {
ModelSet modelSet;
try {
@@ -124,8 +151,9 @@ public class ReapplyProfilesService implements IService, EditorLifecycleEventLis
return false;
}
- for (Profile profile : currentPackage.getAppliedProfiles()) {
- if (ProfileUtil.isDirty(currentPackage, profile)) {
+ IProfileApplicationDelegate delegate = ProfileApplicationDelegateRegistry.INSTANCE.getDelegate(currentPackage);
+ for (ProfileApplication profileApplication : delegate.getProfileApplications(currentPackage)) {
+ if (ProfileUtil.isDirty(currentPackage, delegate.getAppliedProfile(profileApplication))) {
RefreshProfileDialog dialog = new RefreshProfileDialog(editor.getSite().getShell(), this.rootPackage);
dialog.setCallback(getCallback(dialog));
dialog.open();
@@ -147,9 +175,9 @@ public class ReapplyProfilesService implements IService, EditorLifecycleEventLis
public void run() {
Map<Package, Collection<Profile>> profilesToReapply = dialog.getProfilesToReapply();
- EditingDomain domain = EMFHelper.resolveEditingDomain(rootPackage);
+ TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(rootPackage);
- if (domain instanceof TransactionalEditingDomain) {
+ if (domain != null) {
// Create a flat list of profiles, for validation
Collection<Profile> allProfiles = new LinkedList<Profile>();
@@ -161,7 +189,7 @@ public class ReapplyProfilesService implements IService, EditorLifecycleEventLis
if (ProfileValidationHelper.checkApplicableProfiles(Display.getCurrent().getActiveShell(), allProfiles)) {
CompoundCommand command = new CompoundCommand();
for (Map.Entry<Package, Collection<Profile>> profiles : profilesToReapply.entrySet()) {
- command.append(new ApplyProfileCommand(profiles.getKey(), profiles.getValue(), (TransactionalEditingDomain) domain));
+ command.append(new ApplyProfileCommand(profiles.getKey(), profiles.getValue(), domain));
}
domain.getCommandStack().execute(command);
@@ -176,36 +204,27 @@ public class ReapplyProfilesService implements IService, EditorLifecycleEventLis
};
}
- /**
- * {@inheritDoc}
- */
public void disposeService() throws ServiceException {
this.rootPackage = null;
this.stereotypeRepairService = null;
this.servicesRegistry = null;
+ this.editor = null;
}
public void postInit(IMultiDiagramEditor editor) {
- // Nothing
+ if (this.editor == null) {
+ this.editor = editor;
+ }
}
- public void postDisplay(final IMultiDiagramEditor editor) {
- if (stereotypeRepairService == null) {
- // Just check profiles, now
- checkProfiles(editor);
- } else {
- // Ensure that we only kick in the profile migration after any pending repair has completed
- stereotypeRepairService.getPostRepairExecutor().execute(new Runnable() {
-
- public void run() {
- checkProfiles(editor);
- }
- });
- }
+ public void postDisplay(IMultiDiagramEditor editor) {
+ checkProfilesAfterRepair(editor);
}
public void beforeClose(IMultiDiagramEditor editor) {
- // Nothing
+ if (editor == this.editor) {
+ this.editor = null;
+ }
}
}
diff --git a/plugins/uml/org.eclipse.papyrus.uml.profile/src/org/eclipse/papyrus/uml/profile/service/ui/RefreshProfileDialog.java b/plugins/uml/org.eclipse.papyrus.uml.profile/src/org/eclipse/papyrus/uml/profile/service/ui/RefreshProfileDialog.java
index dd864d8b2ab..89a82e0637e 100644
--- a/plugins/uml/org.eclipse.papyrus.uml.profile/src/org/eclipse/papyrus/uml/profile/service/ui/RefreshProfileDialog.java
+++ b/plugins/uml/org.eclipse.papyrus.uml.profile/src/org/eclipse/papyrus/uml/profile/service/ui/RefreshProfileDialog.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2012 CEA LIST.
+ * Copyright (c) 2012, 2014 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
@@ -9,6 +9,8 @@
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
* Gabriel Pascual (ALL4TEC) gabriel.pascual@all4tec.net - Initial API and implementation
+ * Christian W. Damus - bug 399859
+ *
*****************************************************************************/
package org.eclipse.papyrus.uml.profile.service.ui;
@@ -22,6 +24,8 @@ import org.eclipse.jface.viewers.TableLayout;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.papyrus.uml.profile.providers.ProfileApplicationContentProvider;
import org.eclipse.papyrus.uml.profile.providers.ProfileApplicationLabelProvider;
+import org.eclipse.papyrus.uml.tools.helper.IProfileApplicationDelegate;
+import org.eclipse.papyrus.uml.tools.helper.ProfileApplicationDelegateRegistry;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TreeEditor;
import org.eclipse.swt.events.SelectionEvent;
@@ -119,7 +123,7 @@ public class RefreshProfileDialog extends SelectionDialog {
Object currentDataItem = treeItem.getData();
if (currentDataItem instanceof ProfileApplication) {
- final ProfileApplication profileApplication = (ProfileApplication) currentDataItem;
+ ProfileApplication profileApplication = (ProfileApplication) currentDataItem;
Tree tree = treeItem.getParent();
@@ -127,15 +131,18 @@ public class RefreshProfileDialog extends SelectionDialog {
checkbox.setSelection(true);
- getProfilesToReapply((Package) profileApplication.getOwner()).add(profileApplication.getAppliedProfile());
+ IProfileApplicationDelegate delegate = getDelegate(profileApplication);
+ final Package applyingPackage = delegate.getApplyingPackage(profileApplication);
+ final Profile appliedProfile = delegate.getAppliedProfile(profileApplication);
+ getProfilesToReapply(applyingPackage).add(appliedProfile);
checkbox.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent e) {
if (checkbox.getSelection()) {
- getProfilesToReapply((Package) profileApplication.getOwner()).add(profileApplication.getAppliedProfile());
+ getProfilesToReapply(applyingPackage).add(appliedProfile);
} else {
- getProfilesToReapply((Package) profileApplication.getOwner()).remove(profileApplication.getAppliedProfile());
+ getProfilesToReapply(applyingPackage).remove(appliedProfile);
}
}
@@ -158,6 +165,10 @@ public class RefreshProfileDialog extends SelectionDialog {
}
}
+ protected IProfileApplicationDelegate getDelegate(ProfileApplication profileApplication) {
+ return ProfileApplicationDelegateRegistry.INSTANCE.getDelegate(profileApplication);
+ }
+
@Override
protected Composite getDialogArea() {
return (Composite) super.getDialogArea();
@@ -183,5 +194,4 @@ public class RefreshProfileDialog extends SelectionDialog {
public Map<Package, Collection<Profile>> getProfilesToReapply() {
return profilesToReapply;
}
-
}
diff --git a/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/widgets/ProfileApplicationEditor.java b/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/widgets/ProfileApplicationEditor.java
index 84c0e7f3cbe..97470770b1c 100644
--- a/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/widgets/ProfileApplicationEditor.java
+++ b/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/widgets/ProfileApplicationEditor.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2011, 2013 CEA LIST.
+ * Copyright (c) 2011, 2014 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
@@ -9,6 +9,7 @@
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
* Christian W. Damus (CEA) - Refactoring package/profile import/apply UI for CDO
+ * Christian W. Damus - bug 399859
*
*****************************************************************************/
package org.eclipse.papyrus.uml.properties.widgets;
@@ -24,13 +25,16 @@ import java.util.Map;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
-import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ColumnWeightData;
+import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider.IStyledLabelProvider;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StyledCellLabelProvider;
+import org.eclipse.jface.viewers.StyledString;
import org.eclipse.jface.viewers.TableLayout;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.jface.window.Window;
@@ -49,6 +53,7 @@ import org.eclipse.papyrus.uml.tools.profile.definition.Version;
import org.eclipse.papyrus.uml.tools.utils.ProfileUtil;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
@@ -117,16 +122,26 @@ public class ProfileApplicationEditor extends MultipleReferenceEditor {
}
@Override
- public void setLabelProvider(ILabelProvider labelProvider) {
- super.setLabelProvider(new ProfileColumnsLabelProvider(labelProvider));
+ public void setLabelProvider(IBaseLabelProvider labelProvider) {
+ super.setLabelProvider(createProfileColumnsLabelProvider(labelProvider));
}
- protected class ProfileColumnsLabelProvider extends ColumnLabelProvider {
+ protected ProfileColumnsLabelProvider createProfileColumnsLabelProvider(IBaseLabelProvider labelProvider) {
+ return new ProfileColumnsLabelProvider(labelProvider);
+ }
+
+ protected class ProfileColumnsLabelProvider extends StyledCellLabelProvider {
private ILabelProvider defaultLabelProvider;
+ private IStyledLabelProvider styledLabelProvider;
- public ProfileColumnsLabelProvider(ILabelProvider defaultLabelProvider) {
- this.defaultLabelProvider = defaultLabelProvider;
+ public ProfileColumnsLabelProvider(IBaseLabelProvider defaultLabelProvider) {
+ if (defaultLabelProvider instanceof ILabelProvider) {
+ this.defaultLabelProvider = (ILabelProvider) defaultLabelProvider;
+ }
+ if (defaultLabelProvider instanceof IStyledLabelProvider) {
+ this.styledLabelProvider = (IStyledLabelProvider) defaultLabelProvider;
+ }
}
@Override
@@ -158,8 +173,11 @@ public class ProfileApplicationEditor extends MultipleReferenceEditor {
}
public void updateName(ViewerCell cell) {
- cell.setImage(defaultLabelProvider.getImage(cell.getElement()));
- cell.setText(defaultLabelProvider.getText(cell.getElement()));
+ cell.setImage(getImage(cell.getElement()));
+
+ StyledString styledText = getStyledText(cell.getElement());
+ cell.setText(styledText.getString());
+ cell.setStyleRanges(styledText.getStyleRanges());
}
public void updateLocation(ViewerCell cell, Profile profile) {
@@ -185,15 +203,28 @@ public class ProfileApplicationEditor extends MultipleReferenceEditor {
cell.setText(versionText);
}
+
+ public Image getImage(Object element) {
+ return (defaultLabelProvider != null) ? defaultLabelProvider.getImage(element) : null;
+ }
+
+ public StyledString getStyledText(Object element) {
+ return (styledLabelProvider != null) ? styledLabelProvider.getStyledText(element) : new StyledString((defaultLabelProvider != null) ? defaultLabelProvider.getText(element) : ""); //$NON-NLS-1$
+ }
}
@Override
protected void createListControls() {
super.createListControls();
+
up.dispose();
+ up = null;
+
down.dispose();
+ down = null;
+
edit.dispose();
- up = down = edit = null;
+ edit = null;
add.setToolTipText(Messages.ProfileApplicationEditor_ApplyProfile);
addRegisteredProfile = createButton(Activator.getDefault().getImage("/icons/AddReg.gif"), Messages.ProfileApplicationEditor_ApplyRegisteredProfile); //$NON-NLS-1$
diff --git a/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/widgets/ProfileApplicationPropertyEditor.java b/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/widgets/ProfileApplicationPropertyEditor.java
index 19de5a47301..879580fbb9b 100644
--- a/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/widgets/ProfileApplicationPropertyEditor.java
+++ b/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/widgets/ProfileApplicationPropertyEditor.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2011 CEA LIST.
+ * Copyright (c) 2011, 2014 CEA LIST, Christian W. Damus, and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,6 +8,8 @@
*
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
+ * Christian W. Damus - bug 399859
+ *
*****************************************************************************/
package org.eclipse.papyrus.uml.properties.widgets;
@@ -37,10 +39,14 @@ public class ProfileApplicationPropertyEditor extends AbstractPropertyEditor {
* @param style
*/
public ProfileApplicationPropertyEditor(Composite parent, int style) {
- editor = new ProfileApplicationEditor(parent, style);
+ editor = createProfileApplicationEditor(parent, style);
super.setEditor(editor);
}
+ protected ProfileApplicationEditor createProfileApplicationEditor(Composite parent, int style) {
+ return new ProfileApplicationEditor(parent, style);
+ }
+
@Override
public void doBinding() {
diff --git a/plugins/uml/tools/org.eclipse.papyrus.uml.tools.utils/src/org/eclipse/papyrus/uml/tools/utils/CustomUMLUtil.java b/plugins/uml/tools/org.eclipse.papyrus.uml.tools.utils/src/org/eclipse/papyrus/uml/tools/utils/CustomUMLUtil.java
index f60baf1a1a8..5c7684aa8bb 100644
--- a/plugins/uml/tools/org.eclipse.papyrus.uml.tools.utils/src/org/eclipse/papyrus/uml/tools/utils/CustomUMLUtil.java
+++ b/plugins/uml/tools/org.eclipse.papyrus.uml.tools.utils/src/org/eclipse/papyrus/uml/tools/utils/CustomUMLUtil.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2013 CEA LIST.
+ * Copyright (c) 2013, 2014 CEA LIST, Christian W. Damus, and others.
*
*
* All rights reserved. This program and the accompanying materials
@@ -9,10 +9,13 @@
*
* Contributors:
* Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation
+ * Christian W. Damus - bug 399859
*
*****************************************************************************/
package org.eclipse.papyrus.uml.tools.utils;
+import java.util.Collection;
+
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
@@ -23,6 +26,8 @@ import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Extension;
import org.eclipse.uml2.uml.util.UMLUtil;
+import com.google.common.collect.ImmutableList;
+
/**
* Provides methods for stereotypes application outside of a resource
*
@@ -31,6 +36,15 @@ import org.eclipse.uml2.uml.util.UMLUtil;
*/
public class CustomUMLUtil extends UMLUtil {
+ public static void destroy(EObject eObject) {
+ UML2Util.destroy(eObject);
+ }
+
+ public static void destroyAll(Collection<? extends EObject> eObjects) {
+ // Iterate a copy of the list to avoid concurrent modification
+ UML2Util.destroyAll(ImmutableList.copyOf(eObjects));
+ }
+
/**
* The StereotypeApplicationHelper can be overridden to change the default
* location of applied stereotypes.
diff --git a/plugins/uml/tools/org.eclipse.papyrus.uml.tools.utils/src/org/eclipse/papyrus/uml/tools/utils/ProfileUtil.java b/plugins/uml/tools/org.eclipse.papyrus.uml.tools.utils/src/org/eclipse/papyrus/uml/tools/utils/ProfileUtil.java
index 9c4502715e5..dbc33ae288a 100644
--- a/plugins/uml/tools/org.eclipse.papyrus.uml.tools.utils/src/org/eclipse/papyrus/uml/tools/utils/ProfileUtil.java
+++ b/plugins/uml/tools/org.eclipse.papyrus.uml.tools.utils/src/org/eclipse/papyrus/uml/tools/utils/ProfileUtil.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2012, 2013 CEA LIST.
+ * Copyright (c) 2012, 2014 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
@@ -9,6 +9,7 @@
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
* Christian W. Damus (CEA) - Handle dynamic profile applications in CDO
+ * Christian W. Damus - bug 399859
*
*****************************************************************************/
package org.eclipse.papyrus.uml.tools.utils;
@@ -30,8 +31,11 @@ import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
import org.eclipse.uml2.common.util.UML2Util;
import org.eclipse.uml2.uml.Association;
import org.eclipse.uml2.uml.Class;
+import org.eclipse.uml2.uml.Element;
+import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.Profile;
+import org.eclipse.uml2.uml.ProfileApplication;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.Stereotype;
import org.eclipse.uml2.uml.UMLPackage;
@@ -42,7 +46,7 @@ import org.eclipse.uml2.uml.UMLPackage;
* @author Camille Letavernier
*
*/
-public class ProfileUtil {
+public class ProfileUtil extends org.eclipse.uml2.uml.util.UMLUtil {
/**
@@ -73,9 +77,9 @@ public class ProfileUtil {
// ckeck applied profile application definition vs profile definition referenced in file
Profile profileInFile = (Profile) (modelResource.getContents().get(0));
-
- if (_package.getProfileApplication(_profile) != null) {
- EPackage appliedProfileDefinition = _package.getProfileApplication(_profile).getAppliedDefinition();
+ ProfileApplication profileApplication = _package.getProfileApplication(_profile, true);
+ if (profileApplication != null) {
+ EPackage appliedProfileDefinition = profileApplication.getAppliedDefinition();
EPackage fileProfileDefinition = null;
// Check profiles qualified names to ensure the correct profiles are compared
@@ -231,4 +235,53 @@ public class ProfileUtil {
return null;
}
+
+ /**
+ * Finds the profile application, if any, in the context of an {@code element} that supplies the given
+ * stereotype Ecore definition.
+ *
+ * @param element
+ * a model element
+ * @param stereotypeDefinition
+ * the Ecore definition of a stereotype
+ *
+ * @return the providing profile application, or {@code null} if none can be determined
+ */
+ public static ProfileApplication getProfileApplication(Element element, EClass stereotypeDefinition) {
+ ProfileApplication result = null;
+
+ NamedElement umlDefinition = getNamedElement(stereotypeDefinition, element);
+ if (umlDefinition != null) {
+ Profile profile = getContainingProfile(umlDefinition);
+ if (profile != null) {
+ result = getApplicationOf(profile, element);
+ }
+ }
+
+ return result;
+ }
+
+ static Profile getContainingProfile(NamedElement umlDefinition) {
+ Profile result = null;
+
+ for (Package package_ = umlDefinition.getNearestPackage(); package_ != null; package_ = package_.getNestingPackage()) {
+ if (package_ instanceof Profile) {
+ result = (Profile) package_;
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ static ProfileApplication getApplicationOf(Profile profile, Element context) {
+ ProfileApplication result = null;
+
+ Package package_ = context.getNearestPackage();
+ if (package_ != null) {
+ result = package_.getProfileApplication(profile, true);
+ }
+
+ return result;
+ }
}
diff --git a/plugins/uml/tools/org.eclipse.papyrus.uml.tools/plugin.xml b/plugins/uml/tools/org.eclipse.papyrus.uml.tools/plugin.xml
index 39f408d93b2..9bc98abc8ae 100644
--- a/plugins/uml/tools/org.eclipse.papyrus.uml.tools/plugin.xml
+++ b/plugins/uml/tools/org.eclipse.papyrus.uml.tools/plugin.xml
@@ -2,6 +2,7 @@
<?eclipse version="3.4"?>
<plugin>
<extension-point id="importSources" name="Package Import Sources" schema="/schema/importSources.exsd"/>
+ <extension-point id="profileApplicationDelegates" name="Profile Application Delegates" schema="schema/profileApplicationDelegates.exsd"/>
<!-- Register the UML delegating constraint provider -->
<extension
diff --git a/plugins/uml/tools/org.eclipse.papyrus.uml.tools/schema/profileApplicationDelegates.exsd b/plugins/uml/tools/org.eclipse.papyrus.uml.tools/schema/profileApplicationDelegates.exsd
new file mode 100644
index 00000000000..240e80d3505
--- /dev/null
+++ b/plugins/uml/tools/org.eclipse.papyrus.uml.tools/schema/profileApplicationDelegates.exsd
@@ -0,0 +1,125 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.papyrus.uml.tools" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+ <appinfo>
+ <meta.schema plugin="org.eclipse.papyrus.uml.tools" id="profileApplicationDelegates" name="Profile Application Delegates"/>
+ </appinfo>
+ <documentation>
+ Pluggable providers of Papyrus markers for EMF resources.
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <annotation>
+ <appinfo>
+ <meta.element />
+ </appinfo>
+ <documentation>
+ Registry of profile-application delegates.
+ </documentation>
+ </annotation>
+ <complexType>
+ <sequence minOccurs="0" maxOccurs="unbounded">
+ <element ref="delegate"/>
+ </sequence>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appinfo>
+ <meta.attribute translatable="true"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="delegate">
+ <annotation>
+ <documentation>
+ The optional enablement expression is evaluated on a profile application to determine whether the delegate applies to it.
+
+The expression context defines two variables: &lt;tt&gt;selection&lt;/tt&gt; (the default variable) provides the profile application and &lt;tt&gt;resource&lt;/tt&gt; provides the EMF resource that contains it.
+ </documentation>
+ </annotation>
+ <complexType>
+ <attribute name="class" type="string" use="required">
+ <annotation>
+ <documentation>
+ The class implementing the profile-application delegate protocol.
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="java" basedOn=":org.eclipse.papyrus.uml.tools.helper.IProfileApplicationDelegate"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="since"/>
+ </appinfo>
+ <documentation>
+ Papyrus 1.1.0.
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="examples"/>
+ </appinfo>
+ <documentation>
+ [Enter documentation]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="apiinfo"/>
+ </appinfo>
+ <documentation>
+ [Enter API information here.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="implementation"/>
+ </appinfo>
+ <documentation>
+ The &lt;tt&gt;org.eclipse.papyrus.uml.decoratormodel.internal.providers.ExternalizedProfileApplicationDelegate&lt;/tt&gt; class implements the delegate for externally applied profile applications.
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="copyright"/>
+ </appinfo>
+ <documentation>
+ Copyright (c) 2014 Christian W. Damus and others.
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/epl-v10.html
+ </documentation>
+ </annotation>
+
+</schema>
diff --git a/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/commands/ApplyProfileCommand.java b/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/commands/ApplyProfileCommand.java
index 3eda2012dcd..cdeb557d6df 100644
--- a/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/commands/ApplyProfileCommand.java
+++ b/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/commands/ApplyProfileCommand.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2011 CEA LIST.
+ * Copyright (c) 2011, 2014 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
@@ -9,6 +9,8 @@
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
* Gabriel Pascual (ALL4TEC) gabriel.pascual@all4tec.net - Initial API and implementation
+ * Christian W. Damus - bug 399859
+ *
*****************************************************************************/
package org.eclipse.papyrus.uml.tools.commands;
@@ -19,7 +21,10 @@ import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.transaction.RecordingCommand;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.papyrus.uml.tools.helper.IProfileApplicationDelegate;
+import org.eclipse.papyrus.uml.tools.helper.ProfileApplicationDelegateRegistry;
import org.eclipse.papyrus.uml.tools.profile.definition.IPapyrusVersionConstants;
+import org.eclipse.papyrus.uml.tools.utils.CustomUMLUtil;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.Profile;
import org.eclipse.uml2.uml.ProfileApplication;
@@ -108,27 +113,56 @@ public class ApplyProfileCommand extends RecordingCommand {
this(umlPackage, Collections.singletonList(profile), editingDomain, saveProfileApplicationVersion);
}
- /**
- * @see org.eclipse.emf.transaction.RecordingCommand#doExecute()
- *
- */
+ protected final Package getPackage() {
+ return umlPackage;
+ }
+
+ protected final Collection<Profile> getProfiles() {
+ return profiles;
+ }
+
@Override
protected void doExecute() {
- for (Profile profile : profiles) {
- // Apply profile
- umlPackage.applyProfile(profile);
+ Package umlPackage = getPackage();
+ for (Profile profile : getProfiles()) {
+ ProfileApplication profileApplication = applyProfile(umlPackage, profile);
// Save version of applied profile if necessary
if (saveProfileApplicationVersion) {
- ProfileApplication profileApplication = umlPackage.getProfileApplication(profile);
-
// Get version annotation in case it is a Papyrus profile
EAnnotation versionAnnotation = profile.getDefinition().getEAnnotation(IPapyrusVersionConstants.PAPYRUS_EANNOTATION_SOURCE);
if (versionAnnotation != null) {
- profileApplication.getEAnnotations().add(0, EcoreUtil.copy(versionAnnotation));
+ EAnnotation existing = profileApplication.getEAnnotation(IPapyrusVersionConstants.PAPYRUS_EANNOTATION_SOURCE);
+ int index = 0;
+
+ if (existing != null) {
+ // Replace this; don't just add to the existing ones
+ index = profileApplication.getEAnnotations().indexOf(existing);
+ CustomUMLUtil.destroy(existing);
+ }
+
+ profileApplication.getEAnnotations().add(index, EcoreUtil.copy(versionAnnotation));
}
}
}
}
+ protected ProfileApplication applyProfile(Package package_, Profile profile) {
+ ProfileApplication result;
+
+ IProfileApplicationDelegate delegate = ProfileApplicationDelegateRegistry.INSTANCE.getDelegate(package_);
+
+ // Is this a re-application?
+ ProfileApplication existing = delegate.getProfileApplication(package_, profile);
+ if (existing != null) {
+ delegate = ProfileApplicationDelegateRegistry.INSTANCE.getDelegate(existing);
+ delegate.reapplyProfile(package_, profile);
+ result = existing;
+ } else {
+ package_.applyProfile(profile);
+ result = delegate.getProfileApplication(package_, profile);
+ }
+
+ return result;
+ }
}
diff --git a/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/ProfileApplicationObservableList.java b/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/ProfileApplicationObservableList.java
index 649ad39bd21..ce6deff945c 100644
--- a/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/ProfileApplicationObservableList.java
+++ b/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/databinding/ProfileApplicationObservableList.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2011, 2014 CEA LIST and others.
+ * Copyright (c) 2011, 2014 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
@@ -9,10 +9,12 @@
* Contributors:
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
* Christian W. Damus (CEA) - 402525
+ * Christian W. Damus - bug 399859
*
*****************************************************************************/
package org.eclipse.papyrus.uml.tools.databinding;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
@@ -31,8 +33,10 @@ import org.eclipse.papyrus.infra.widgets.editors.AbstractEditor;
import org.eclipse.papyrus.infra.widgets.editors.ICommitListener;
import org.eclipse.papyrus.uml.tools.commands.ApplyProfileCommand;
import org.eclipse.papyrus.uml.tools.commands.UnapplyProfileCommand;
+import org.eclipse.papyrus.uml.tools.helper.ProfileApplicationDelegateRegistry;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.Profile;
+import org.eclipse.uml2.uml.ProfileApplication;
/**
*
@@ -52,8 +56,7 @@ public class ProfileApplicationObservableList extends WritableList implements IC
private AbstractStereotypeListener listener;
/**
- *
- * Constructor.
+ * Initializes me with the default applied profiles provider.
*
* @param umlSource
* The Package on which the profiles are applied or unapplied
@@ -61,9 +64,11 @@ public class ProfileApplicationObservableList extends WritableList implements IC
* The editing domain on which the commands are executed
*/
public ProfileApplicationObservableList(Package umlSource, EditingDomain domain) {
- super(new LinkedList<Object>(umlSource.getAppliedProfiles()), Profile.class);
+ super(getAppliedProfiles(umlSource), Profile.class);
+
this.umlSource = umlSource;
this.domain = domain;
+
commands = new LinkedList<Command>();
listener = new AbstractStereotypeListener(umlSource) {
@@ -194,12 +199,26 @@ public class ProfileApplicationObservableList extends WritableList implements IC
commands.clear();
}
- private void refreshCacheList() {
+ protected final void refreshCacheList() {
wrappedList.clear();
- wrappedList.addAll(umlSource.getAppliedProfiles());
+ wrappedList.addAll(getAppliedProfiles(umlSource));
fireListChange(null);
}
+ static Collection<Profile> getAppliedProfiles(Package package_) {
+ final ProfileApplicationDelegateRegistry reg = ProfileApplicationDelegateRegistry.INSTANCE;
+
+ List<Profile> result = new ArrayList<Profile>();
+ for (ProfileApplication next : reg.getDelegate(package_).getProfileApplications(package_)) {
+ Profile profile = reg.getDelegate(next).getAppliedProfile(next);
+ if (profile != null) {
+ result.add(profile);
+ }
+ }
+
+ return result;
+ }
+
/**
* {@inheritDoc}
*/
diff --git a/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/helper/IProfileApplicationDelegate.java b/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/helper/IProfileApplicationDelegate.java
new file mode 100644
index 00000000000..07a983b0c27
--- /dev/null
+++ b/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/helper/IProfileApplicationDelegate.java
@@ -0,0 +1,135 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.tools.helper;
+
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.Profile;
+import org.eclipse.uml2.uml.ProfileApplication;
+
+/**
+ * Protocol for a delegate that assists any UI elements dealing with profile applications in the manipulation of those profile applications.
+ * Many UI components may just want to use the {@linkplain Default default implementation}.
+ *
+ * @see Default
+ */
+public interface IProfileApplicationDelegate {
+ /**
+ * Queries whether I am applicable to (support introspection/manipulation of) profile applications of the given package.
+ *
+ * @param package_
+ * a package
+ * @return whether I am the delegate that should be used to introspect/manipulate profile applications of the given package
+ */
+ boolean appliesTo(Package package_);
+
+ /**
+ * Queries the profile applications of a package to manage in the UI.
+ *
+ * @param package_
+ * a package presented in the UI
+ * @return its profile applications
+ */
+ Iterable<ProfileApplication> getProfileApplications(Package package_);
+
+ /**
+ * Queries the existing application, if any, of the given {@code profile} directly to a package (not an inherited profile application).
+ *
+ * @param package_
+ * a package
+ * @param profile
+ * a profile that may or may not be directly applied
+ *
+ * @return the application of the {@code profile} specifically to the given package, or {@code null} if either the package does not have the profile applied or the profile application is inherited
+ */
+ ProfileApplication getProfileApplication(Package package_, Profile profile);
+
+ /**
+ * Queries whether I am applicable to (support introspection/manipulation of) a given profile application.
+ *
+ * @param profileApplication
+ * a profile application
+ * @return whether I am the delegate that should be used to introspect/manipulate the profile application
+ */
+ boolean appliesTo(ProfileApplication profileApplication);
+
+ /**
+ * Queries the package that applies a profile via the specific application.
+ *
+ * @param profileApplication
+ * a profile application
+ * @return that package to which it applies a profile
+ */
+ Package getApplyingPackage(ProfileApplication profileApplication);
+
+ /**
+ * Queries the profile applied by the specified application.
+ *
+ * @param profileApplication
+ * a profile application
+ * @return the profile that it applies
+ */
+ Profile getAppliedProfile(ProfileApplication profileApplication);
+
+ /**
+ * Re-applies the specified {@code profile} to a package.
+ *
+ * @param package_
+ * the package to which to re-apply the {@code profile}. The profile must already be applied
+ * @param profile
+ * the profile to re-apply
+ *
+ * @return any new stereotype applications created as a consequence of required metaclass extensions
+ */
+ EList<EObject> reapplyProfile(Package package_, Profile profile);
+
+ //
+ // Nested types
+ //
+
+ /**
+ * A simple implementation of the profile-application delegate protocol that just provides the UML standard
+ * properties of a profile application.
+ */
+ class Default implements IProfileApplicationDelegate {
+ public boolean appliesTo(Package package_) {
+ return true;
+ }
+
+ public Iterable<ProfileApplication> getProfileApplications(Package package_) {
+ return package_.getProfileApplications();
+ }
+
+ public ProfileApplication getProfileApplication(Package package_, Profile profile) {
+ return package_.getProfileApplication(profile);
+ }
+
+ public boolean appliesTo(ProfileApplication profileApplication) {
+ return true;
+ }
+
+ public Package getApplyingPackage(ProfileApplication profileApplication) {
+ return profileApplication.getApplyingPackage();
+ }
+
+ public Profile getAppliedProfile(ProfileApplication profileApplication) {
+ return profileApplication.getAppliedProfile();
+ }
+
+ public EList<EObject> reapplyProfile(Package package_, Profile profile) {
+ return package_.applyProfile(profile);
+ }
+ }
+}
diff --git a/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/helper/ProfileApplicationDelegateRegistry.java b/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/helper/ProfileApplicationDelegateRegistry.java
new file mode 100644
index 00000000000..7603d8cf68d
--- /dev/null
+++ b/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/helper/ProfileApplicationDelegateRegistry.java
@@ -0,0 +1,245 @@
+/*****************************************************************************
+ * Copyright (c) 2014 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.uml.tools.helper;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.plugin.RegistryReader;
+import org.eclipse.papyrus.uml.tools.Activator;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.Profile;
+import org.eclipse.uml2.uml.ProfileApplication;
+
+/**
+ * A registry of {@link IProfileApplicationDelegate} plugged in on my extension point.
+ */
+public class ProfileApplicationDelegateRegistry {
+
+ private static final String EXT_POINT = "profileApplicationDelegates"; //$NON-NLS-1$
+
+ private static final IProfileApplicationDelegate NULL_DELEGATE = new IProfileApplicationDelegate.Default() {
+ @Override
+ public boolean appliesTo(ProfileApplication profileApplication) {
+ return false;
+ }
+ };
+
+ public static final ProfileApplicationDelegateRegistry INSTANCE = new ProfileApplicationDelegateRegistry();
+
+ private final List<IProfileApplicationDelegate> delegates = new java.util.ArrayList<IProfileApplicationDelegate>(2);
+
+ private boolean needPrune;
+
+ private ProfileApplicationDelegateRegistry() {
+ super();
+
+ new MyRegistryReader().readRegistry();
+
+ // And the default delegate to backstop the plug-ins
+ delegates.add(new IProfileApplicationDelegate.Default());
+ }
+
+ /**
+ * Prune out any null providers (failed to initialize) and replace
+ * descriptors that have been instantiated by their instances, to avoid
+ * delegation.
+ */
+ private void prune() {
+ if (needPrune) {
+ needPrune = false;
+ for (ListIterator<IProfileApplicationDelegate> iter = delegates.listIterator(); iter.hasNext();) {
+
+ IProfileApplicationDelegate next = iter.next();
+ if (next == NULL_DELEGATE) {
+ iter.remove();
+ } else if (next instanceof MyRegistryReader.Descriptor) {
+ MyRegistryReader.Descriptor desc = (MyRegistryReader.Descriptor) next;
+ if (desc.instance != null) {
+ iter.set(desc.instance);
+ }
+ }
+ }
+ }
+ }
+
+ public IProfileApplicationDelegate getDelegate(Package package_) {
+ IProfileApplicationDelegate result = NULL_DELEGATE;
+
+ synchronized (delegates) {
+ prune();
+
+ for (IProfileApplicationDelegate next : delegates) {
+ if (next.appliesTo(package_)) {
+ result = next;
+ break;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ public IProfileApplicationDelegate getDelegate(ProfileApplication profileApplication) {
+ IProfileApplicationDelegate result = NULL_DELEGATE;
+
+ synchronized (delegates) {
+ prune();
+
+ for (IProfileApplicationDelegate next : delegates) {
+ if (next.appliesTo(profileApplication)) {
+ result = next;
+ break;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ private void removeProvider(String className) {
+ synchronized (delegates) {
+ for (Iterator<IProfileApplicationDelegate> iter = delegates.iterator(); iter.hasNext();) {
+
+ IProfileApplicationDelegate next = iter.next();
+ if (next instanceof MyRegistryReader.Descriptor) {
+ MyRegistryReader.Descriptor desc = (MyRegistryReader.Descriptor) next;
+ if (className.equals(desc.getClassName())) {
+ iter.remove();
+ break;
+ }
+ } else if (className.equals(next.getClass().getName())) {
+ iter.remove();
+ break;
+ }
+ }
+ }
+ }
+
+ //
+ // Nested types
+ //
+
+ private class MyRegistryReader extends RegistryReader {
+
+ private static final String A_CLASS = "class"; //$NON-NLS-1$
+
+ private static final String E_DELEGATE = "delegate"; //$NON-NLS-1$
+
+ private Descriptor currentDescriptor;
+
+ MyRegistryReader() {
+ super(Platform.getExtensionRegistry(), Activator.PLUGIN_ID, EXT_POINT);
+ }
+
+ @Override
+ protected boolean readElement(IConfigurationElement element, boolean add) {
+ return add ? handleAdd(element) : handleRemove(element);
+ }
+
+ private boolean handleAdd(IConfigurationElement element) {
+ boolean result = false;
+
+ if (E_DELEGATE.equals(element.getName())) {
+ if (element.getAttribute(A_CLASS) == null) {
+ logMissingAttribute(element, A_CLASS);
+ } else {
+ currentDescriptor = new Descriptor(element, A_CLASS);
+ delegates.add(currentDescriptor);
+ }
+
+ result = true;
+ }
+
+ return result;
+ }
+
+ private boolean handleRemove(IConfigurationElement element) {
+ boolean result = true;
+
+ if (E_DELEGATE.equals(element.getName())) {
+ String className = element.getAttribute(A_CLASS);
+ if (className == null) {
+ logMissingAttribute(element, A_CLASS);
+ result = false;
+ } else {
+ removeProvider(className);
+ }
+ }
+
+ return result;
+ }
+
+ private class Descriptor extends PluginClassDescriptor implements IProfileApplicationDelegate {
+
+ private IProfileApplicationDelegate instance;
+
+ Descriptor(IConfigurationElement element, String attributeName) {
+ super(element, attributeName);
+ }
+
+ String getClassName() {
+ return element.getAttribute(attributeName);
+ }
+
+ IProfileApplicationDelegate getInstance() {
+ if (instance == null) {
+ try {
+ instance = (IProfileApplicationDelegate) createInstance();
+ } catch (Exception e) {
+ Activator.log.error("Failed to instantiate profile-application delegate extension.", e);
+ instance = NULL_DELEGATE;
+ }
+
+ needPrune = true;
+ }
+
+ return instance;
+ }
+
+ public boolean appliesTo(Package package_) {
+ return getInstance().appliesTo(package_);
+ }
+
+ public boolean appliesTo(ProfileApplication profileApplication) {
+ return getInstance().appliesTo(profileApplication);
+ }
+
+ public Iterable<ProfileApplication> getProfileApplications(Package package_) {
+ return getInstance().getProfileApplications(package_);
+ }
+
+ public ProfileApplication getProfileApplication(Package package_, Profile profile) {
+ return getInstance().getProfileApplication(package_, profile);
+ }
+
+ public Package getApplyingPackage(ProfileApplication profileApplication) {
+ return getInstance().getApplyingPackage(profileApplication);
+ }
+
+ public Profile getAppliedProfile(ProfileApplication profileApplication) {
+ return getInstance().getAppliedProfile(profileApplication);
+ }
+
+ public EList<EObject> reapplyProfile(Package package_, Profile profile) {
+ return getInstance().reapplyProfile(package_, profile);
+ }
+ }
+ }
+}

Back to the top