Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui')
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/action/ConcernComboContributionItem.java398
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/action/DeleteFromDiagramContributionItem.java137
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/action/FindElementAction.java81
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/action/LaunchBehaviorContributionItem.java194
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/action/RevealFindLabelDialog.java56
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/action/SetStyleToWorkspaceImageContributionItem.java152
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/color/ColorManager.java83
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/decorators/AbstractSiriusDecorator.java265
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AbstractCachedSVGFigure.java218
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AbstractGeoShapePolygonFigure.java91
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AbstractTransparentEllipse.java68
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AbstractTransparentImage.java83
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AbstractTransparentNode.java53
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AbstractTransparentRectangle.java67
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/ActionTriggerImageFigure.java192
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AirDefaultSizeNodeFigure.java240
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AirNoteFigure.java96
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AirStyleDefaultSizeNodeFigure.java59
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AlphaDropShadowBorder.java127
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/BundledImageFigure.java396
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/DBorderedNodeFigure.java46
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/FigureQuery.java88
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/FoldingToggleAwareClippingStrategy.java41
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/FoldingToggleImageFigure.java120
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/GaugeCompositeFigure.java188
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/GaugeSectionFigure.java193
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/GradientHelper.java145
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/GradientRoundedRectangle.java164
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/IRoundedCorner.java33
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/ITransparentFigure.java55
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/IWorkspaceImageFigure.java47
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/InvisibleResizableCompartmentFigure.java49
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/LozengeFigure.java116
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/MouseAwareImageFigure.java218
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/ODesignEllipseFigure.java78
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/OneLineMarginBorder.java170
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/ParallelogramFigure.java59
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/PolygoneAndPolylineDecoraction.java160
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/SVGFigure.java326
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/SVGWorkspaceImageFigure.java273
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/SiriusWrapLabel.java1774
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/StyledFigure.java22
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/ViewGradientFigureDesc.java39
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/ViewNodeContainerFigureDesc.java28
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/ViewNodeContainerParallelogram.java67
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/ViewNodeContainerRectangleFigureDesc.java80
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/WorkspaceImageFigure.java209
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/anchor/AirSlidableImageAnchor.java330
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/anchor/AnchorProvider.java49
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/anchor/ZoomDependantAnchor.java29
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/locator/DBorderItemLocator.java804
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/locator/NorthNameLocator.java148
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/AbstractSiriusLayoutDataManager.java828
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/GraphicalHelper.java205
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ILayoutDataManagerProvider.java41
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/LayoutConstants.java44
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/LayoutDataHelper.java122
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/LayoutDataKey.java27
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/LayoutExtender.java178
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/LayoutUtils.java614
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/PinHelper.java204
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/SiriusLayoutDataManager.java86
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/SiriusLayoutDataManagerForSemanticElementsFactory.java46
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractEdgeDecorateSemanticElementOrdering.java92
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractEdgeViewOrdering.java142
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractNodeDecorateSemanticElementOrdering.java80
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractNodeViewOrdering.java114
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractSemanticTreeOrdering.java159
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractTreeViewOrdering.java506
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractViewEdgeOrdering.java93
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractViewNodeOrdering.java81
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractViewOrdering.java84
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/GridView.java255
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/GridViewOrdering.java52
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/SimpleCompositeEdgeViewOrdering.java118
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/SimpleCompositeViewOrdering.java117
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/SimpleViewOrdering.java43
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/ViewOrdering.java34
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/ViewOrderingHint.java155
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/ViewOrderingProvider.java44
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/provider/AbstractLayoutProvider.java547
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/provider/CompoundLayoutProvider.java96
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/provider/DefaultLayoutProvider.java217
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/provider/ExtendableLayoutProvider.java48
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/provider/GridLayoutProvider.java555
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/provider/InlineEdgeLayoutProvider.java940
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/provider/LayoutProvider.java62
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/provider/LineLayoutProvider.java302
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/policy/CompoundEditPolicy.java250
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/properties/AbstractPropertySection.java370
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/properties/MiscPropertySection.java130
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/properties/MiscPropertySource.java179
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/properties/filter/AbstractPropertyFilter.java87
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/properties/filter/MiscPropertyFilter.java31
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/util/EditPartTools.java83
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/util/GMFNotationHelper.java431
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/ActivateBehaviorToolsCommand.java63
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/ActivateFiltersCommand.java145
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/ActivateRulesCommand.java61
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/ChangeLayerActivationCommand.java115
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/DeactivateBehaviorToolsCommand.java63
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/DeactivateFiltersCommand.java68
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/DeactivateRulesCommand.java61
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/EdgeRoutingStyleChangedCommand.java57
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/FindElementCommand.java48
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/InitializeHiddenElementsCommand.java60
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/SemanticChangedCommand.java56
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/SetCurrentConcernCommand.java107
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/SetDefaultConcernCommand.java68
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/dialogs/ColorPalettePopup.java385
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/dialogs/DiagramElementsSelectionDialog.java893
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/dialogs/DiagramElementsSelectionDialogPatternMatcher.java94
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/dialogs/ExtendedFeatureEditorDialog.java535
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/dialogs/SelectDiagramElementBackgroundImageDialog.java145
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/dialogs/WorkspaceImagePathSelector.java122
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/dialogs/WorkspacePathValidator.java67
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/dnd/DragAndDropWrapper.java66
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/edit/command/CommandFactory.java151
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/edit/command/RecordingCommandsExecutor.java55
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/figure/DiagramSemanticElementLockedNotificationFigure.java313
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/figure/ICollapseMode.java56
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/figure/NotificationFigure.java267
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/figure/TransparentFigureGraphicsModifier.java61
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/figure/locator/FeedbackDBorderItemLocator.java66
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/find/BasicFindLabelEngine.java159
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/AdvancedSiriusLayoutDataManager.java51
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/ArrangeAllWithAutoSize.java365
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/AutoSizeAndRegionAwareGraphLayout.java600
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/DiagramLayoutCustomization.java184
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/EdgeLayoutDataKey.java23
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/IsPinnedPredicate.java103
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/LayoutDataHelperImpl.java327
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/LayoutUtil.java48
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/NodeLayoutDataKey.java23
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/PinnedElementsHandler.java910
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/data/extension/LayoutDataManagerDescriptor.java105
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/data/extension/LayoutDataManagerRegistry.java161
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/data/extension/LayoutDataManagerRegistryListener.java151
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/diagram/DEdgeLayoutDataKey.java53
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/diagram/DNodeLayoutDataKey.java87
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/diagram/SiriusLayoutDataManagerForDDiagram.java150
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/ordering/OrderedTreeOrdering.java185
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/ordering/OrderedTreeViewOrderingProvider.java96
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/ordering/ViewOrderingProviderRegistry.java123
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/AbstractCompositeLayoutProvider.java480
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/AbstractProviderDescriptor.java135
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/AdjustedGridLayout.java56
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/ArrangeAllOnlyLayoutProvider.java40
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/ArrangeSelectionLayoutProvider.java249
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/BorderItemAwareLayoutProvider.java1553
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/CompositeDownTopLayoutProvider.java51
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/CompositeDownTopProvider.java73
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/CompositeLeftRightLayoutProvider.java77
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/CompositeLeftRightProvider.java79
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/CompositeTopDownLayoutProvider.java51
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/CompositeTopDownProvider.java82
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/LayoutProviderDescriptor.java55
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/LayoutService.java106
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/OrderedTreeLayoutProvider.java124
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/PinnedElementsLayoutProvider.java217
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/semantic/AbstractSemanticLayoutDataKey.java102
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/semantic/SemanticEdgeLayoutDataKey.java45
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/semantic/SemanticNodeLayoutDataKey.java46
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/semantic/SiriusLayoutDataManagerForSemanticElements.java173
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/BehaviorsPropertySection.java133
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/CompositeEObjectPropertySource.java83
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/DiagramColorAndFontPropertySection.java139
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/DiagramConnectionAppearancePropertySection.java316
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/DiagramShapeColorAndFontPropertySection.java445
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/DocumentationPropertySection.java297
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/ExtendedPropertySource.java422
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/ExtensionSemanticPropertiesSection.java182
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/FiltersPropertySection.java485
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/ResetStylePropertiesToDefaultValuesSelectionAdapter.java122
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/SemanticAndExtensionPropertySection.java60
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/SemanticPropertySection.java234
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/StylePropertySection.java285
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/ValidationPropertySection.java121
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/filter/ExtendedPropertyFilter.java52
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/filter/SemanticExtensionPropertyFilter.java37
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/filter/SemanticPropertyFilter.java49
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/filter/StylePropertyFilter.java33
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/routers/BracketConnectionRouter.java91
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/routers/DBranchRouter.java204
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/routers/DForestRouter.java336
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/routers/DTreeRouter.java563
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/routers/SiriusBendpointConnectionRouter.java88
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/util/EditPartQuery.java236
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/outlineview/DiagramOutlineWithBookPages.java204
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/filters/FiltersActivationAdapter.java107
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/filters/FiltersCellModifier.java130
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/filters/FiltersContentProvider.java120
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/filters/FiltersLabelProvider.java107
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/filters/FiltersTableViewer.java99
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/layers/LayersActivationAdapter.java107
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/layers/LayersCellModifier.java172
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/layers/LayersContentProvider.java164
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/layers/LayersEventsListener.java67
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/layers/LayersLabelProvider.java178
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/layers/LayersTableViewer.java106
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/outline/OutlineComparator.java85
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/outline/OutlineContentProvider.java329
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/outline/OutlineContentResourceSetListener.java326
-rw-r--r--plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/outline/OutlineLabelProvider.java187
204 files changed, 37543 insertions, 0 deletions
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/action/ConcernComboContributionItem.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/action/ConcernComboContributionItem.java
new file mode 100644
index 0000000000..2b38224bef
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/action/ConcernComboContributionItem.java
@@ -0,0 +1,398 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.action;
+
+import java.util.Iterator;
+
+import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.emf.transaction.NotificationFilter;
+import org.eclipse.emf.transaction.ResourceSetChangeEvent;
+import org.eclipse.emf.transaction.ResourceSetListener;
+import org.eclipse.emf.transaction.ResourceSetListenerImpl;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.emf.transaction.util.TransactionUtil;
+import org.eclipse.jface.action.ContributionItem;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+import org.eclipse.ui.IPartListener;
+import org.eclipse.ui.IPartService;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.PlatformUI;
+
+import org.eclipse.sirius.common.tools.api.util.StringUtil;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.description.concern.ConcernDescription;
+import org.eclipse.sirius.diagram.tools.api.editor.DDiagramEditor;
+import org.eclipse.sirius.diagram.ui.tools.internal.commands.SetCurrentConcernCommand;
+import org.eclipse.sirius.diagram.ui.tools.internal.commands.SetDefaultConcernCommand;
+
+/**
+ * A ControlContribution that uses a {@link org.eclipse.swt.widgets.Combo} as
+ * its control.
+ *
+ * @author ymortier
+ */
+public class ConcernComboContributionItem extends ContributionItem {
+
+ /**
+ * ID for concern contribution.
+ */
+ public static final String CONCERN_CONTRIBUTION_ID = "ConcernContribution";
+
+ private boolean forceSetText;
+
+ private Combo combo;
+
+ private final String[] initStrings;
+
+ private ToolItem toolitem;
+
+ private DDiagram diagram;
+
+ private final IPartService service;
+
+ private IPartListener partListener;
+
+ private TransactionalEditingDomain domain;
+
+ private ResourceSetListener listener;
+
+ /**
+ * Constructor for ComboToolItem.
+ *
+ * @param partService
+ * used to add a PartListener
+ * @param initString
+ * the initial string displayed in the combo
+ */
+ public ConcernComboContributionItem(final IPartService partService, final String initString) {
+ this(partService, new String[] { initString });
+ }
+
+ /**
+ * Constructor for ComboToolItem.
+ *
+ * @param partService
+ * used to add a PartListener
+ * @param initStrings
+ * the initial string displayed in the combo
+ */
+ public ConcernComboContributionItem(final IPartService partService, final String[] initStrings) {
+ super(CONCERN_CONTRIBUTION_ID);
+ this.initStrings = initStrings;
+ service = partService;
+ partListener = new IPartListener() {
+ public void partActivated(final IWorkbenchPart part) {
+
+ if (part instanceof DDiagramEditor) {
+ DDiagramEditor editor = (DDiagramEditor) part;
+ DDiagram editorDiagram = (DDiagram) editor.getRepresentation();
+ domain = (TransactionalEditingDomain) editor.getAdapter(EditingDomain.class);
+ setDiagram(editorDiagram);
+ }
+ }
+
+ public void partBroughtToTop(final IWorkbenchPart p) {
+ }
+
+ public void partClosed(final IWorkbenchPart p) {
+ }
+
+ public void partDeactivated(final IWorkbenchPart p) {
+ }
+
+ public void partOpened(final IWorkbenchPart p) {
+ }
+ };
+ partService.addPartListener(partListener);
+ }
+
+ /**
+ * Get the current diagram.
+ *
+ * @return current diagram
+ */
+ public DDiagram getDiagram() {
+ return diagram;
+ }
+
+ private void diagramChanged() {
+ if (Display.getCurrent() == null) {
+ PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ refresh(false);
+ }
+ });
+ } else {
+ refresh(false);
+ }
+ }
+
+ private String[] getPickableConcerns() {
+ if (getDiagram() != null && getDiagram().getDescription() != null && getDiagram().getDescription().getConcerns() != null) {
+ final String[] data = new String[getDiagram().getDescription().getConcerns().getOwnedConcernDescriptions().size()];
+ for (int i = 0; i < getDiagram().getDescription().getConcerns().getOwnedConcernDescriptions().size(); i++) {
+ final ConcernDescription desc = getDiagram().getDescription().getConcerns().getOwnedConcernDescriptions().get(i);
+ data[i] = desc.getName();
+ }
+ return data;
+
+ } else {
+ return new String[0];
+ }
+ }
+
+ private void refresh(final boolean repopulateCombo) {
+ if (combo == null || combo.isDisposed()) {
+ return;
+ }
+ // $TODO GTK workaround
+ try {
+ if (diagram == null || domain == null) {
+ combo.setEnabled(false);
+ combo.setText(StringUtil.EMPTY_STRING);
+ } else {
+ if (repopulateCombo) {
+ combo.setItems(getPickableConcerns());
+ }
+
+ String currentConcern = StringUtil.EMPTY_STRING;
+ if (getDiagram().getCurrentConcern() != null) {
+ currentConcern = getDiagram().getCurrentConcern().getName();
+ }
+ final int index = combo.indexOf(currentConcern);
+ if (index == -1 || forceSetText) {
+ combo.setText(currentConcern);
+ } else {
+ combo.select(index);
+ }
+ combo.setEnabled(true);
+ }
+ } catch (final SWTException exception) {
+ if (!"gtk".equals(SWT.getPlatform())) {
+ throw exception;
+ }
+ }
+ }
+
+ /**
+ * Computes the width required by control.
+ *
+ * @param control
+ * The control to compute width
+ * @return int The width required
+ */
+ protected int computeWidth(final Control control) {
+ return control.computeSize(100, 20, true).x;
+ }
+
+ /**
+ * Creates and returns the control for this contribution item under the
+ * given parent composite.
+ *
+ * @param parent
+ * the parent composite
+ * @return the new control
+ */
+ protected Control createControl(final Composite parent) {
+ combo = new Combo(parent, SWT.DROP_DOWN);
+ combo.addSelectionListener(new SelectionListener() {
+ public void widgetSelected(final SelectionEvent e) {
+ handleWidgetSelected(e);
+ }
+
+ public void widgetDefaultSelected(final SelectionEvent e) {
+ handleWidgetDefaultSelected(e);
+ }
+ });
+ combo.addFocusListener(new FocusListener() {
+ public void focusGained(final FocusEvent e) {
+ // do nothing
+ }
+
+ public void focusLost(final FocusEvent e) {
+ refresh(false);
+ }
+ });
+
+ // Initialize width of combo
+ combo.setItems(initStrings);
+ toolitem.setWidth(computeWidth(combo));
+ combo.setToolTipText("Current concern");
+ refresh(true);
+ return combo;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.action.ContributionItem#dispose()
+ */
+ @Override
+ public void dispose() {
+ if (partListener == null) {
+ return;
+ }
+ service.removePartListener(partListener);
+ removeSemanticListener();
+ diagram = null;
+ combo = null;
+ partListener = null;
+ domain = null;
+ }
+
+ /**
+ * The control item implementation of this <code>IContributionItem</code>
+ * method calls the <code>createControl</code> framework method. Subclasses
+ * must implement <code>createControl</code> rather than overriding this
+ * method.
+ *
+ * @param parent
+ * The parent of the control to fill
+ */
+ @Override
+ public final void fill(final Composite parent) {
+ createControl(parent);
+ }
+
+ /**
+ * The control item implementation of this <code>IContributionItem</code>
+ * method throws an exception since controls cannot be added to menus.
+ *
+ * @param parent
+ * The menu
+ * @param index
+ * Menu index
+ */
+ @Override
+ public final void fill(final Menu parent, final int index) {
+ }
+
+ /**
+ * The control item implementation of this <code>IContributionItem</code>
+ * method calls the <code>createControl</code> framework method to create a
+ * control under the given parent, and then creates a new tool item to hold
+ * it. Subclasses must implement <code>createControl</code> rather than
+ * overriding this method.
+ *
+ * @param parent
+ * The ToolBar to add the new control to
+ * @param index
+ * Index
+ */
+ @Override
+ public void fill(final ToolBar parent, final int index) {
+ toolitem = new ToolItem(parent, SWT.SEPARATOR, index);
+ final Control control = createControl(parent);
+ toolitem.setControl(control);
+ }
+
+ /**
+ * Sets the DDiagram.
+ *
+ * @param dia
+ * The diagram
+ */
+ public void setDiagram(final DDiagram dia) {
+ if (diagram == dia) {
+ return;
+ }
+
+ if (domain == null) {
+ domain = TransactionUtil.getEditingDomain(dia);
+ }
+
+ diagram = dia;
+ removeSemanticListener();
+ addSemanticListener();
+ refresh(true);
+ }
+
+ private void addSemanticListener() {
+ listener = new ResourceSetListenerImpl() {
+
+ @Override
+ public NotificationFilter getFilter() {
+ return NotificationFilter.NOT_TOUCH.and(NotificationFilter.createNotifierFilter(diagram));
+ }
+
+ @Override
+ public boolean isPostcommitOnly() {
+ return true;
+ }
+
+ @Override
+ public void resourceSetChanged(ResourceSetChangeEvent event) {
+ diagramChanged();
+ }
+ };
+ domain.addResourceSetListener(listener);
+ }
+
+ private void removeSemanticListener() {
+ if (domain != null) {
+ domain.removeResourceSetListener(listener);
+ }
+ }
+
+ /**
+ * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(SelectionEvent)
+ */
+ private void handleWidgetDefaultSelected(final SelectionEvent event) {
+ if (diagram != null) {
+ if (combo.getSelectionIndex() >= 0) {
+ setCurrentConcern(combo.getItem(combo.getSelectionIndex()));
+ } else {
+ setCurrentConcern(combo.getText());
+ }
+ }
+ refresh(false);
+ }
+
+ private void setCurrentConcern(final String item) {
+ boolean foundConcern = false;
+ if (item != null) {
+ if (getDiagram() != null && getDiagram().getDescription() != null && getDiagram().getDescription().getConcerns() != null) {
+ final Iterator<ConcernDescription> it = getDiagram().getDescription().getConcerns().getOwnedConcernDescriptions().iterator();
+ while (it.hasNext()) {
+ final ConcernDescription desc = it.next();
+ if (desc.getName().equals(item)) {
+ foundConcern = true;
+ domain.getCommandStack().execute(new SetCurrentConcernCommand(domain, diagram, desc));
+ }
+ }
+ }
+ }
+ if (!foundConcern) {
+ domain.getCommandStack().execute(new SetDefaultConcernCommand(domain, diagram));
+ }
+ }
+
+ /**
+ * @see org.eclipse.swt.events.SelectionListener#widgetSelected(SelectionEvent)
+ */
+ private void handleWidgetSelected(final SelectionEvent event) {
+ forceSetText = true;
+ handleWidgetDefaultSelected(event);
+ forceSetText = false;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/action/DeleteFromDiagramContributionItem.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/action/DeleteFromDiagramContributionItem.java
new file mode 100644
index 0000000000..6ae3939531
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/action/DeleteFromDiagramContributionItem.java
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2011 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.action;
+
+import org.eclipse.gef.EditPart;
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.IPartListener;
+import org.eclipse.ui.IPartService;
+import org.eclipse.ui.ISelectionListener;
+import org.eclipse.ui.IWorkbenchPart;
+
+import org.eclipse.sirius.diagram.tools.internal.actions.delete.DeleteFromDiagramAction;
+import org.eclipse.sirius.diagram.tools.internal.graphical.edit.part.DDiagramRootEditPart;
+
+/**
+ * A ControlContribution that uses a {@link org.eclipse.swt.widgets.Button} as
+ * its control.
+ *
+ * @author cnotot
+ */
+public class DeleteFromDiagramContributionItem extends ActionContributionItem {
+
+ private final IPartService service;
+
+ private IPartListener partListener;
+
+ private IWorkbenchPart representationPart;
+
+ private final ISelectionListener editPartSelectionListener = new ISelectionListener() {
+ public void selectionChanged(final IWorkbenchPart part, final ISelection selection) {
+ // if selection is not in this item parent part => do nothing
+ if (representationPart != null && !representationPart.equals(part)) {
+ return;
+ }
+ getAction().setEnabled(shouldBeEnabled(selection));
+ update();
+ }
+ };
+
+ /**
+ * Default Constructor for ComboToolItem.
+ *
+ * @param action
+ * contributed action
+ */
+ public DeleteFromDiagramContributionItem(final IAction action) {
+ super(action);
+ service = null;
+ }
+
+ /**
+ * Constructor for ComboToolItem.
+ *
+ * @param action
+ * contributed action
+ * @param partService
+ * used to add a PartListener and a SelectionListener
+ */
+ public DeleteFromDiagramContributionItem(final IAction action, final IPartService partService) {
+ super(action);
+ service = partService;
+ partListener = new IPartListener() {
+ public void partActivated(final IWorkbenchPart part) {
+ final EditPart editPArt = (EditPart) part.getAdapter(EditPart.class);
+ if (editPArt instanceof DDiagramRootEditPart) {
+ part.getSite().getPage().addSelectionListener(editPartSelectionListener);
+ }
+
+ }
+
+ public void partBroughtToTop(final IWorkbenchPart p) {
+ }
+
+ public void partClosed(final IWorkbenchPart p) {
+ }
+
+ public void partDeactivated(final IWorkbenchPart p) {
+ p.getSite().getPage().removeSelectionListener(editPartSelectionListener);
+ }
+
+ public void partOpened(final IWorkbenchPart p) {
+ }
+ };
+ partService.addPartListener(partListener);
+ IWorkbenchPart part = partService.getActivePart();
+ if (part != null) {
+ ISelectionProvider selectionProvider = part.getSite().getSelectionProvider();
+ if (selectionProvider != null) {
+ getAction().setEnabled(shouldBeEnabled(selectionProvider.getSelection()));
+ update();
+ }
+ }
+ }
+
+ public void setItemPart(IWorkbenchPart itemPart) {
+ this.representationPart = itemPart;
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.action.ContributionItem#dispose()
+ */
+ @Override
+ public void dispose() {
+ if (partListener != null && service != null) {
+ service.removePartListener(partListener);
+ }
+ partListener = null;
+ representationPart = null;
+ super.dispose();
+ }
+
+ private boolean shouldBeEnabled(final ISelection selection) {
+ if (selection instanceof IStructuredSelection) {
+ final IAction action = getAction();
+ if (action instanceof DeleteFromDiagramAction) {
+ final DeleteFromDiagramAction deleteAction = (DeleteFromDiagramAction) action;
+ return deleteAction.shouldBeEnabled(selection);
+ }
+ }
+ return false;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/action/FindElementAction.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/action/FindElementAction.java
new file mode 100644
index 0000000000..940bc4ef3a
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/action/FindElementAction.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.action;
+
+import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditor;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.ui.IObjectActionDelegate;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+import org.eclipse.sirius.common.ui.tools.api.find.AbstractFindLabelDialog;
+import org.eclipse.sirius.diagram.ui.tools.internal.find.BasicFindLabelEngine;
+
+/**
+ * A find element Eclipse action.
+ *
+ * @author glefur
+ */
+public class FindElementAction implements IObjectActionDelegate {
+ /**
+ * The action ID.
+ */
+ public static final String ID = "org.eclipse.sirius.transversal.find.ui.binding.FindElementAction";
+
+ private DiagramEditor currentPart;
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.IObjectActionDelegate#setActivePart(org.eclipse.jface.action.IAction,
+ * org.eclipse.ui.IWorkbenchPart)
+ */
+ public void setActivePart(final IAction action, final IWorkbenchPart targetPart) {
+ if (targetPart instanceof DiagramEditor) {
+ currentPart = (DiagramEditor) targetPart;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction)
+ */
+ public void run(final IAction action) {
+ if (currentPart != null) {
+ final AbstractFindLabelDialog dialog = new RevealFindLabelDialog(currentPart.getSite().getShell(), new BasicFindLabelEngine(currentPart), currentPart);
+ dialog.open();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.IActionDelegate#selectionChanged(org.eclipse.jface.action.IAction,
+ * org.eclipse.jface.viewers.ISelection)
+ */
+ public void selectionChanged(final IAction action, final ISelection selection) {
+ final IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ if (window != null) {
+ final IWorkbenchPage page = window.getActivePage();
+ if (page != null) {
+ final IWorkbenchPart targetPart = page.getActivePart();
+ if (targetPart instanceof DiagramEditor) {
+ currentPart = (DiagramEditor) targetPart;
+ }
+ }
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/action/LaunchBehaviorContributionItem.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/action/LaunchBehaviorContributionItem.java
new file mode 100644
index 0000000000..46389016f4
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/action/LaunchBehaviorContributionItem.java
@@ -0,0 +1,194 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.action;
+
+import java.util.Iterator;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.Request;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.render.editparts.RenderedDiagramRootEditPart;
+import org.eclipse.jface.action.ContributionItem;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+import org.eclipse.ui.IPartListener;
+import org.eclipse.ui.IPartService;
+import org.eclipse.ui.IWorkbenchPart;
+
+import org.eclipse.sirius.diagram.ImagesPath;
+import org.eclipse.sirius.diagram.internal.edit.parts.DDiagramEditPart;
+import org.eclipse.sirius.diagram.part.SiriusDiagramEditorPlugin;
+import org.eclipse.sirius.diagram.tools.api.requests.RequestConstants;
+
+/**
+ * Add a button to launch all behaviors.
+ *
+ * @author ymortier
+ */
+public class LaunchBehaviorContributionItem extends ContributionItem {
+
+ /**
+ * ID for concern contribution.
+ */
+ public static final String CONCERN_CONTRIBUTION_ID = "ConcernContributionBehavior";
+
+ private final IPartService service;
+
+ private IPartListener partListener;
+
+ private EditPart viewPointEditPart;
+
+ private Button button;
+
+ private ToolItem toolitem;
+
+ /**
+ * Constructor for ComboToolItem.
+ *
+ * @param partService
+ * used to add a PartListener
+ */
+ public LaunchBehaviorContributionItem(final IPartService partService) {
+ super(CONCERN_CONTRIBUTION_ID);
+ service = partService;
+ Assert.isNotNull(partService);
+ partListener = new IPartListener() {
+ public void partActivated(final IWorkbenchPart part) {
+ final EditPart editPArt = (EditPart) part.getAdapter(EditPart.class);
+ if (editPArt instanceof RenderedDiagramRootEditPart) {
+ final RenderedDiagramRootEditPart root = (RenderedDiagramRootEditPart) editPArt;
+ final Iterator<?> iterChildren = root.getChildren().iterator();
+ while (iterChildren.hasNext()) {
+ final Object child = iterChildren.next();
+ if (child instanceof DDiagramEditPart) {
+ viewPointEditPart = (GraphicalEditPart) child;
+ }
+ }
+ }
+
+ }
+
+ public void partBroughtToTop(final IWorkbenchPart p) {
+ }
+
+ public void partClosed(final IWorkbenchPart p) {
+ }
+
+ public void partDeactivated(final IWorkbenchPart p) {
+ }
+
+ public void partOpened(final IWorkbenchPart p) {
+ }
+ };
+ partService.addPartListener(partListener);
+ }
+
+ /**
+ * Creates and returns the control for this contribution item under the
+ * given parent composite.
+ *
+ * @param parent
+ * the parent composite
+ * @return the new control
+ */
+ protected Control createControl(final Composite parent) {
+ button = new Button(parent, SWT.PUSH);
+ button.setText("Launch Behavior");
+ button.setSize(30, 20);
+ button.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ final Request request = new Request(RequestConstants.REQ_LAUNCH_RULE_TOOL);
+ viewPointEditPart.performRequest(request);
+ }
+ });
+ final Image image = SiriusDiagramEditorPlugin.getInstance().getImage(SiriusDiagramEditorPlugin.findImageDescriptor(ImagesPath.GO_IMG));
+ button.setImage(image);
+ button.setSize(image.getBounds().width + button.getBorderWidth(), image.getBounds().height + button.getBorderWidth());
+ return button;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.action.ContributionItem#dispose()
+ */
+ @Override
+ public void dispose() {
+ if (partListener == null) {
+ return;
+ }
+ if (button != null && !button.isDisposed()) {
+ button.dispose();
+ }
+ if (service != null) {
+ service.removePartListener(this.partListener);
+ }
+ button = null;
+ partListener = null;
+ }
+
+ /**
+ * The control item implementation of this <code>IContributionItem</code>
+ * method calls the <code>createControl</code> framework method. Subclasses
+ * must implement <code>createControl</code> rather than overriding this
+ * method.
+ *
+ * @param parent
+ * The parent of the control to fill
+ */
+ @Override
+ public final void fill(final Composite parent) {
+ createControl(parent);
+ }
+
+ /**
+ * The control item implementation of this <code>IContributionItem</code>
+ * method throws an exception since controls cannot be added to menus.
+ *
+ * @param parent
+ * The menu
+ * @param index
+ * Menu index
+ */
+ @Override
+ public final void fill(final Menu parent, final int index) {
+ Assert.isTrue(false, "Can't add a control to a menu"); //$NON-NLS-1$
+ }
+
+ /**
+ * The control item implementation of this <code>IContributionItem</code>
+ * method calls the <code>createControl</code> framework method to create a
+ * control under the given parent, and then creates a new tool item to hold
+ * it. Subclasses must implement <code>createControl</code> rather than
+ * overriding this method.
+ *
+ * @param parent
+ * The ToolBar to add the new control to
+ * @param index
+ * Index
+ */
+ @Override
+ public void fill(final ToolBar parent, final int index) {
+ toolitem = new ToolItem(parent, SWT.SEPARATOR, index);
+ final Control control = createControl(parent);
+ toolitem.setControl(control);
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/action/RevealFindLabelDialog.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/action/RevealFindLabelDialog.java
new file mode 100644
index 0000000000..6752f09e3a
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/action/RevealFindLabelDialog.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.action;
+
+import org.eclipse.gef.EditPart;
+import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditor;
+import org.eclipse.swt.widgets.Shell;
+
+import org.eclipse.sirius.common.tools.api.find.AbstractFindLabelEngine;
+import org.eclipse.sirius.common.ui.tools.api.find.AbstractFindLabelDialog;
+
+/**
+ * An implementation of the AbstractFindLabelDialog that use the "reveal" method
+ * when the "next" button is used.
+ *
+ * @author glefur
+ */
+public class RevealFindLabelDialog extends AbstractFindLabelDialog {
+ private final DiagramEditor editor;
+
+ /**
+ * Constructor.
+ *
+ * @param parentShell
+ * the parent shell
+ * @param engine
+ * the find label engine
+ * @param currentEditor
+ * the current editor
+ */
+ public RevealFindLabelDialog(final Shell parentShell, final AbstractFindLabelEngine engine, final DiagramEditor currentEditor) {
+ super(parentShell, engine);
+ this.editor = currentEditor;
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.common.ui.tools.api.find.AbstractFindLabelDialog#selectElement(java.lang.Object)
+ */
+ @Override
+ protected void selectElement(final Object selection) {
+ editor.getDiagramGraphicalViewer().select((EditPart) selection);
+ editor.getDiagramGraphicalViewer().reveal((EditPart) selection);
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/action/SetStyleToWorkspaceImageContributionItem.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/action/SetStyleToWorkspaceImageContributionItem.java
new file mode 100644
index 0000000000..904fa000e0
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/action/SetStyleToWorkspaceImageContributionItem.java
@@ -0,0 +1,152 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2011 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.action;
+
+import java.util.Iterator;
+
+import org.eclipse.gef.EditPart;
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.IPartListener;
+import org.eclipse.ui.IPartService;
+import org.eclipse.ui.ISelectionListener;
+import org.eclipse.ui.IWorkbenchPart;
+
+import org.eclipse.sirius.diagram.edit.api.part.IAbstractDiagramNodeEditPart;
+import org.eclipse.sirius.diagram.tools.internal.graphical.edit.part.DDiagramRootEditPart;
+
+/**
+ * A ControlContribution that uses a {@link org.eclipse.swt.widgets.Button} as
+ * its control.
+ *
+ * @author Maxime Porhel (mporhel)
+ */
+public class SetStyleToWorkspaceImageContributionItem extends ActionContributionItem {
+
+ private final IPartService service;
+
+ private IPartListener partListener;
+
+ private IWorkbenchPart representationPart;
+
+ private final ISelectionListener editPartSelectionListener = new ISelectionListener() {
+ public void selectionChanged(final IWorkbenchPart part, final ISelection selection) {
+ if (representationPart != null && !representationPart.equals(part)) {
+ return;
+ }
+ getAction().setEnabled(shouldBeEnabled(selection));
+ update();
+ }
+ };
+
+ /**
+ * Default Constructor for ComboToolItem.
+ *
+ * @param action
+ * contributed action
+ */
+ public SetStyleToWorkspaceImageContributionItem(final IAction action) {
+ super(action);
+ service = null;
+ }
+
+ /**
+ * Constructor for ComboToolItem.
+ *
+ * @param action
+ * contributed action
+ * @param partService
+ * used to add a PartListener and a SelectionListener
+ * @param part
+ * this contribution item workbench part.
+ */
+ public SetStyleToWorkspaceImageContributionItem(final IAction action, final IPartService partService, IWorkbenchPart part) {
+ super(action);
+ representationPart = part;
+ service = partService;
+ partListener = new IPartListener() {
+ public void partActivated(final IWorkbenchPart part) {
+ final EditPart editPArt = (EditPart) part.getAdapter(EditPart.class);
+ if (editPArt instanceof DDiagramRootEditPart) {
+ part.getSite().getPage().addSelectionListener(editPartSelectionListener);
+ }
+
+ }
+
+ public void partBroughtToTop(final IWorkbenchPart p) {
+ }
+
+ public void partClosed(final IWorkbenchPart p) {
+ }
+
+ public void partDeactivated(final IWorkbenchPart p) {
+ p.getSite().getPage().removeSelectionListener(editPartSelectionListener);
+ }
+
+ public void partOpened(final IWorkbenchPart p) {
+ }
+ };
+ partService.addPartListener(partListener);
+ IWorkbenchPart activePart = partService.getActivePart();
+ if (activePart != null) {
+ ISelectionProvider selectionProvider = activePart.getSite().getSelectionProvider();
+ if (selectionProvider != null) {
+ getAction().setEnabled(shouldBeEnabled(selectionProvider.getSelection()));
+ update();
+ }
+ }
+ }
+
+ /**
+ * Constructor for ComboToolItem.
+ *
+ * @param action
+ * contributed action
+ * @param partService
+ * used to add a PartListener and a SelectionListener
+ */
+ public SetStyleToWorkspaceImageContributionItem(final IAction action, final IPartService partService) {
+ this(action, partService, null);
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.action.ContributionItem#dispose()
+ */
+ @Override
+ public void dispose() {
+ if (partListener != null && service != null) {
+ service.removePartListener(partListener);
+ }
+ partListener = null;
+ representationPart = null;
+ super.dispose();
+ }
+
+ private boolean shouldBeEnabled(final ISelection selection) {
+ if (selection instanceof IStructuredSelection) {
+ boolean result = true;
+ final Iterator it = ((IStructuredSelection) selection).iterator();
+ while (it.hasNext()) {
+ if (!(it.next() instanceof IAbstractDiagramNodeEditPart)) {
+ result = false;
+ }
+ }
+ return result;
+ }
+ return false;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/color/ColorManager.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/color/ColorManager.java
new file mode 100644
index 0000000000..a9fe3cebaa
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/color/ColorManager.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2011 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.color;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.draw2d.ColorConstants;
+import org.eclipse.draw2d.FigureUtilities;
+import org.eclipse.swt.graphics.Color;
+
+import org.eclipse.sirius.RGBValues;
+import org.eclipse.sirius.ui.tools.api.color.VisualBindingManager;
+
+/**
+ * Manage the color in complement to {@link VisualBindingManager} with use of
+ * draw2d API to compute some colors.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ *
+ */
+public class ColorManager {
+
+ private static ColorManager defaultInstance;
+
+ private Map<String, Color> lighterColorCache;
+
+ /**
+ * Constructor.
+ */
+ protected ColorManager() {
+ lighterColorCache = new HashMap<String, Color>();
+ }
+
+ /**
+ * Return the singleton instance.
+ *
+ * @return a default instance
+ */
+ public static ColorManager getDefault() {
+ if (defaultInstance == null) {
+ defaultInstance = new ColorManager();
+ }
+ return defaultInstance;
+ }
+
+ /**
+ * Get a lighter color from the colorToLight.
+ *
+ * @param colorToLight
+ * the color to light
+ * @return A color get from the cache
+ */
+ public Color getLighterColor(final RGBValues colorToLight) {
+ final String key = getKey(colorToLight);
+ if (!lighterColorCache.containsKey(key)) {
+ Color newLighterColor = FigureUtilities.mixColors(VisualBindingManager.getDefault().getColorFromRGBValues(colorToLight), ColorConstants.white, 0.4);
+ lighterColorCache.put(key, newLighterColor);
+ }
+ return lighterColorCache.get(key);
+ }
+
+ private String getKey(RGBValues color) {
+ StringBuilder sb = new StringBuilder("Color");
+ if (color != null) {
+ sb.append("_r:");
+ sb.append(color.getRed());
+ sb.append("_g:");
+ sb.append(color.getGreen());
+ sb.append("_b:");
+ sb.append(color.getBlue());
+ }
+ return sb.toString();
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/decorators/AbstractSiriusDecorator.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/decorators/AbstractSiriusDecorator.java
new file mode 100644
index 0000000000..58e415f3bc
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/decorators/AbstractSiriusDecorator.java
@@ -0,0 +1,265 @@
+/*******************************************************************************
+ * Copyright (c) 2011 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.decorators;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.GraphicalEditPart;
+import org.eclipse.gef.editparts.AbstractConnectionEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.services.decorator.AbstractDecorator;
+import org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecoration;
+import org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecoratorTarget;
+import org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecoratorTarget.Direction;
+import org.eclipse.gmf.runtime.draw2d.ui.mapmode.MapModeUtil;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.swt.graphics.Image;
+
+import org.eclipse.sirius.diagram.edit.api.part.AbstractDiagramListEditPart;
+import org.eclipse.sirius.diagram.edit.api.part.AbstractDiagramNameEditPart;
+import org.eclipse.sirius.diagram.edit.api.part.IDiagramElementEditPart;
+import org.eclipse.sirius.diagram.internal.edit.parts.DNodeListEditPart;
+import org.eclipse.sirius.diagram.internal.edit.parts.DNodeListElementEditPart;
+import org.eclipse.sirius.diagram.internal.edit.parts.DNodeListNameEditPart;
+import org.eclipse.sirius.diagram.internal.edit.parts.DNodeNameEditPart;
+
+/**
+ * Abstract Sirius decorator.
+ *
+ * @author mchauvin
+ */
+public abstract class AbstractSiriusDecorator extends AbstractDecorator {
+ /**
+ * The margin to use during decoration.
+ */
+ protected static final int MARGIN = -1;
+
+ /** the decorations being displayed */
+ private List<IDecoration> decorations = Collections.<IDecoration> emptyList();
+
+ /**
+ * Create a decorator.
+ *
+ * @param decoratorTarget
+ * target to decorate.
+ */
+ public AbstractSiriusDecorator(final IDecoratorTarget decoratorTarget) {
+ super(decoratorTarget);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecorator#activate()
+ */
+ public void activate() {
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecorator#refresh()
+ */
+ public void refresh() {
+ removeDecorations();
+ final View view = (View) getDecoratorTarget().getAdapter(View.class);
+ if (view != null && (shouldConsiderDetachedViews() || view.eResource() != null)) {
+ final EditPart editPart = (EditPart) getDecoratorTarget().getAdapter(EditPart.class);
+ if (!shouldBeDecorated(editPart)) {
+ return;
+ }
+ // Get margin
+ int margin = MARGIN;
+ if (editPart instanceof org.eclipse.gef.GraphicalEditPart) {
+ margin = MapModeUtil.getMapMode(((org.eclipse.gef.GraphicalEditPart) editPart).getFigure()).DPtoLP(margin);
+ }
+
+ Image decorationImage = getDecorationImage(editPart);
+ if (null != decorationImage) {
+ if (editPart instanceof AbstractConnectionEditPart) {
+ addDecoration(getDecoratorTarget().addConnectionDecoration(decorationImage, 50, false));
+ } else {
+ addDecoration(getDecoratorTarget().addShapeDecoration(decorationImage, getDirection(editPart), margin, false));
+ }
+ }
+ }
+ }
+
+ /**
+ * Indicates whether this decorator should consider detached {@link View}s
+ * (i.e. {@link View}s which eResource() is null).
+ *
+ * @return true if this decorator should consider detached {@link View}s,
+ * false otherwise.
+ */
+ protected boolean shouldConsiderDetachedViews() {
+ return false;
+ }
+
+ /**
+ * Specific refresh for an edit. Override if you need to do specific things.
+ *
+ * @param editPart
+ * edit part
+ */
+ protected void refresh(final EditPart editPart) {
+ /* do nothing */
+ }
+
+ /**
+ * Get the position of the decorator according to edit part.
+ *
+ * @param editPart
+ * the edit part
+ * @return a Direction
+ */
+ protected abstract Direction getDirection(final EditPart editPart);
+
+ /**
+ * Check if the edit part respect conditions to be decorate.
+ *
+ * @param editPart
+ * the editPart to check
+ * @return true if the editPart respect conditions to be decorate, false
+ * otherwise
+ */
+ protected boolean shouldBeDecorated(final EditPart editPart) {
+ boolean shouldBeDecorated = true;
+ if (editPart == null || editPart.getParent() == null || editPart.getRoot() == null || editPart.getViewer() == null) {
+ shouldBeDecorated = false;
+ } else if (editPart instanceof AbstractDiagramNameEditPart && !(editPart instanceof DNodeListElementEditPart)) {
+ /* Check that the editPart is not a name dEditPart */
+ shouldBeDecorated = false;
+ } else if (editPart instanceof org.eclipse.gef.GraphicalEditPart) {
+ /* Check if the size of the figure is sufficient */
+ shouldBeDecorated = figureIsBigEnoughToBeDecorated(editPart);
+ }
+ return shouldBeDecorated;
+ }
+
+ private boolean figureIsBigEnoughToBeDecorated(final EditPart editPart) {
+ final IFigure figure = ((org.eclipse.gef.GraphicalEditPart) editPart).getFigure();
+
+ final Dimension size = figure.getSize();
+
+ if (size.width < 10 && size.width > 0 && size.height < 10 && size.height > 0) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Get the decoration image.<br>
+ *
+ * @param editPart
+ * the edit part to get the decoration image from
+ * @return <code>null</code> if no image found.
+ */
+ protected abstract Image getDecorationImage(EditPart editPart);
+
+ private void removeDecorations() {
+ for (final IDecoration decoration : decorations) {
+ if (decoration instanceof IFigure && ((IFigure) decoration).getParent() != null) {
+ ((IFigure) decoration).getParent().remove((IFigure) decoration);
+ }
+
+ final GraphicalEditPart ownerEditPart = (GraphicalEditPart) getDecoratorTarget().getAdapter(GraphicalEditPart.class);
+ if (ownerEditPart != null && ownerEditPart.getRoot() != null && ownerEditPart.getViewer() != null) {
+ ownerEditPart.getViewer().getVisualPartMap().remove(decoration);
+ }
+ }
+ decorations = new ArrayList<IDecoration>();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.services.decorator.AbstractDecorator#deactivate()
+ */
+ @Override
+ public void deactivate() {
+ removeDecorations();
+ }
+
+ /**
+ * Get the IDecorations of this DescribedDecorator.
+ *
+ * @return Returns the decorations.
+ */
+ public List<IDecoration> getDecorations() {
+ return decorations;
+ }
+
+ /**
+ * Add an IDecoration to this DescribedDecorator.
+ *
+ * @param decoration
+ * IDecoration to add.
+ */
+ public void addDecoration(final IDecoration decoration) {
+ decorations.add(decoration);
+ }
+
+ /**
+ * Get the underlying semantic element for given edit part.
+ *
+ * @param editPart
+ * to decorate
+ * @return <code>null</code> if not found.
+ */
+ protected EObject getUnderlyingSemanticElement(EditPart editPart) {
+ EObject result = null;
+ // Precondition:
+ if (null == editPart) {
+ return result;
+ }
+ if (editPart instanceof IDiagramElementEditPart) {
+ result = ((IDiagramElementEditPart) editPart).resolveTargetSemanticElement();
+ }
+ return result;
+ }
+
+ /**
+ * Indicates if the given editPart should contain decorations according to
+ * its type. For example, {@link DNodeListNameEditPart}s should not be
+ * decorated.
+ *
+ * @param editPart
+ * the edit part to inspect
+ * @return true if the given editPart should contain decorations, false
+ * otherwise
+ */
+ public boolean isDecorableEditPart(IDiagramElementEditPart editPart) {
+ boolean result = true;
+ if (editPart instanceof DNodeNameEditPart) {
+ EditPart parentEditPart = editPart.getParent();
+ if (!(parentEditPart instanceof DNodeListEditPart) && !(parentEditPart instanceof AbstractDiagramListEditPart)) {
+ result = false;
+ }
+ } else if (editPart instanceof DNodeListNameEditPart) {
+ result = false;
+ } else if (editPart instanceof DNodeListElementEditPart) {
+ // We only decorate DNodeListElementEditParts if the semantic
+ // element is different from parent editpart
+ EditPart parentEditPart = editPart.getParent();
+ if (parentEditPart.getModel() instanceof View && editPart.getModel() instanceof View) {
+ result = !(((View) parentEditPart.getModel()).getElement().equals(((View) editPart.getModel()).getElement()));
+ }
+ }
+ return result;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AbstractCachedSVGFigure.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AbstractCachedSVGFigure.java
new file mode 100644
index 0000000000..37ddc88a6e
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AbstractCachedSVGFigure.java
@@ -0,0 +1,218 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import java.awt.image.BufferedImage;
+import java.util.Collection;
+import java.util.Map;
+
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.XYLayout;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+import org.w3c.dom.Document;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.MapMaker;
+
+import org.eclipse.sirius.common.tools.api.util.StringUtil;
+import org.eclipse.sirius.diagram.part.SiriusDiagramEditorPlugin;
+import org.eclipse.sirius.diagram.ui.tools.internal.figure.TransparentFigureGraphicsModifier;
+
+/**
+ * A {@link AbstractCachedSVGFigure} is a {@link SVGFigure} corresponding to a
+ * svg image. {@link Image} are store in a map with soft values.
+ *
+ * @author mporhel
+ */
+public abstract class AbstractCachedSVGFigure extends SVGFigure implements StyledFigure, ITransparentFigure {
+
+ /**
+ * Key separator.
+ */
+ protected static final String SEPARATOR = "|";
+
+ /**
+ * Soft cache to store svg.
+ */
+ private static final Map<String, Image> SVG_IMG_CACHE = new MapMaker().softValues().makeMap();
+
+ private static final String IMAGE_DIR = "images/"; //$NON-NLS-1$
+
+ private static final String IMAGE_EXT = ".svg"; //$NON-NLS-1$
+
+ private static final String IMAGE_NOT_FOUND = "NotFound"; //$NON-NLS-1$
+
+ private int viewpointAlpha = DEFAULT_ALPHA;
+
+ private boolean transparent;
+
+ /**
+ * Build a new {@link AbstractCachedSVGFigure} from an Image instance.
+ *
+ */
+ public AbstractCachedSVGFigure() {
+ this.setLayoutManager(new XYLayout());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getSiriusAlpha() {
+ return viewpointAlpha;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isTransparent() {
+ return transparent;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setSiriusAlpha(int alpha) {
+ this.viewpointAlpha = alpha;
+
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setTransparent(boolean transparent) {
+ this.transparent = transparent;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.figure.lite.svg.SVGFigure#paintFigure(org.eclipse.draw2d.Graphics)
+ */
+ @Override
+ protected void paintFigure(Graphics graphics) {
+ TransparentFigureGraphicsModifier modifier = new TransparentFigureGraphicsModifier(this, graphics);
+ modifier.pushState();
+
+ Rectangle r = getClientArea();
+ Image image = getCachedImage(getKey() + getContextKey(graphics), r, graphics);
+ // Draw the image
+ if (image != null) {
+ graphics.drawImage(image, r.x, r.y);
+ }
+ modifier.popState();
+ }
+
+ private String getContextKey(Graphics graphics) {
+ // CHECKSTYLE:OFF
+ int aaText = SWT.DEFAULT;
+ try {
+ aaText = graphics.getTextAntialias();
+ } catch (Exception e) {
+ // not supported
+ }
+ // CHECKSTYLE:ON
+
+ StringBuilder result = new StringBuilder();
+ result.append(aaText);
+ result.append(SEPARATOR);
+ Rectangle r = getClientArea();
+ result.append(getSpecifyCanvasWidth() ? r.width : -1);
+ result.append(SEPARATOR);
+ result.append(getSpecifyCanvasHeight() ? r.height : -1);
+
+ return result.toString();
+ }
+
+ /**
+ * Get the image cached or create new one and cache it.
+ *
+ * @param key
+ * the key
+ * @param clientArea
+ * the client area
+ * @param graphics
+ * the graphical context
+ * @return an image store in a cache
+ */
+ protected Image getCachedImage(final String key, Rectangle clientArea, Graphics graphics) {
+
+ if (!SVG_IMG_CACHE.containsKey(key)) {
+
+ /* Create the image if it does not exist */
+ Document document = getDocument();
+ if (document == null) {
+ return null;
+ }
+
+ getTranscoder().setCanvasSize(getSpecifyCanvasWidth() ? clientArea.width : -1, getSpecifyCanvasHeight() ? clientArea.height : -1);
+ updateRenderingHints(graphics);
+ BufferedImage awtImage = getTranscoder().getBufferedImage();
+ if (awtImage != null) {
+ SVG_IMG_CACHE.put(key, toSWT(Display.getCurrent(), awtImage));
+ }
+ }
+ // Get the image from the cache
+ return SVG_IMG_CACHE.get(key);
+ }
+
+ /**
+ * Compute a key for this figure. This key is used to store in cache the
+ * corresponding {@link org.eclipse.swt.graphics.Image}.
+ *
+ * The key must begin by the document key.
+ *
+ * @return The key corresponding to this BundleImageFigure.
+ */
+ protected abstract String getKey();
+
+ /**
+ * The uri of the image to display when the file has not been found.
+ *
+ * @return The uri of the image to display when the file has not been found.
+ */
+ protected static String getImageNotFoundURI() {
+ final String path = new StringBuffer(IMAGE_DIR).append(IMAGE_NOT_FOUND).append(IMAGE_EXT).toString();
+ String pluginId = SiriusDiagramEditorPlugin.getInstance().getBundle().getSymbolicName();
+ return "platform:/plugin/" + pluginId + "/" + path;
+ }
+
+ /**
+ * Remove all entries whose key begins with the given key. Remove from the
+ * document map, the entries with the given keys to force to re-read the
+ * file.
+ *
+ * @param documentKey
+ * the document key.
+ * @return true of something was removed.
+ */
+ protected static boolean doRemoveFromCache(final String documentKey) {
+ if (!StringUtil.isEmpty(documentKey)) {
+ boolean remove = false;
+ Collection<String> keyToRemove = Lists.newArrayList();
+ for (String key : SVG_IMG_CACHE.keySet()) {
+ if (key.startsWith(documentKey)) {
+ keyToRemove.add(key);
+ }
+ }
+
+ for (String toRemove : keyToRemove) {
+ SVG_IMG_CACHE.remove(toRemove);
+ remove = true;
+ }
+ boolean removedFromDocumentsMap = documentsMap.remove(documentKey) != null;
+ return remove || removedFromDocumentsMap;
+ }
+ return false;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AbstractGeoShapePolygonFigure.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AbstractGeoShapePolygonFigure.java
new file mode 100644
index 0000000000..eda8c735d0
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AbstractGeoShapePolygonFigure.java
@@ -0,0 +1,91 @@
+/******************************************************************************
+ * Copyright (c) 2003, 2004, 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Mariot Chauvin <mariot.chauvin@obeo.fr> - Checkstylized
+ ****************************************************************************/
+
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.geometry.PointList;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gmf.runtime.draw2d.ui.figures.IPolygonAnchorableFigure;
+import org.eclipse.gmf.runtime.gef.ui.figures.DefaultSizeNodeFigure;
+
+/**
+ * Base class for polygons in the Geometric shapes palette.
+ *
+ * author jschofie
+ *
+ * @author mchauvin
+ */
+public abstract class AbstractGeoShapePolygonFigure extends DefaultSizeNodeFigure implements IPolygonAnchorableFigure {
+
+ /**
+ * Constructor.
+ *
+ * @param width
+ * figure width
+ * @param height
+ * figure height
+ * @param spacing
+ * figure spacing
+ */
+ public AbstractGeoShapePolygonFigure(final int width, final int height, final int spacing) {
+ super(width, height);
+ setOpaque(true);
+ }
+
+ /**
+ * This method is used to compute the shapes polygon points. This is
+ * currently based on the shapes bounding box.
+ *
+ * Subclasses must return their list of points based on the object size.
+ *
+ * @param rect
+ * the rectangle that the shape will fit in
+ * @return the point list
+ */
+ protected abstract PointList calculatePoints(Rectangle rect);
+
+ /**
+ * Get the content pane.
+ *
+ * @return the content pane
+ */
+ public IFigure getContentPane() {
+ return (IFigure) getChildren().get(0);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.gef.ui.figures.NodeFigure#paintFigure(org.eclipse.draw2d.Graphics)
+ */
+ @Override
+ protected void paintFigure(final Graphics g) {
+ g.setBackgroundColor(getBackgroundColor());
+ g.setForegroundColor(getForegroundColor());
+ g.setLineWidth(getLineWidth());
+
+ final PointList points = calculatePoints(new Rectangle(getBounds()));
+ g.fillPolygon(points);
+ g.drawPolygon(points);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.draw2d.ui.figures.IPolygonAnchorableFigure#getPolygonPoints()
+ */
+ public PointList getPolygonPoints() {
+ return calculatePoints(new Rectangle(getBounds()));
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AbstractTransparentEllipse.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AbstractTransparentEllipse.java
new file mode 100644
index 0000000000..0362b4c461
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AbstractTransparentEllipse.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import org.eclipse.draw2d.Ellipse;
+import org.eclipse.draw2d.Graphics;
+
+import org.eclipse.sirius.diagram.ui.tools.internal.figure.TransparentFigureGraphicsModifier;
+
+/**
+ * An abstract ellipse figure to handle transparency.
+ *
+ * @mporhel
+ */
+public abstract class AbstractTransparentEllipse extends Ellipse implements StyledFigure, ITransparentFigure {
+
+ private int viewpointAlpha = DEFAULT_ALPHA;
+
+ private boolean transparent;
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void fillShape(Graphics graphics) {
+ TransparentFigureGraphicsModifier modifier = new TransparentFigureGraphicsModifier(this, graphics);
+ modifier.pushState();
+ super.fillShape(graphics);
+ modifier.popState();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getSiriusAlpha() {
+ return viewpointAlpha;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isTransparent() {
+ return transparent;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setSiriusAlpha(int alpha) {
+ this.viewpointAlpha = alpha;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setTransparent(boolean transparent) {
+ this.transparent = transparent;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AbstractTransparentImage.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AbstractTransparentImage.java
new file mode 100644
index 0000000000..c85be12799
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AbstractTransparentImage.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.ImageFigure;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.swt.graphics.Image;
+
+import org.eclipse.sirius.diagram.ui.tools.internal.figure.TransparentFigureGraphicsModifier;
+
+/**
+ * An abstract image figure to handle transparency.
+ *
+ * @author mporhel
+ */
+public abstract class AbstractTransparentImage extends ImageFigure implements StyledFigure, ITransparentFigure {
+
+ private int viewpointAlpha = DEFAULT_ALPHA;
+
+ private boolean transparent;
+
+ /**
+ * Create a new {@link AbstractTransparentImage}.
+ *
+ * @param flyWeightImage
+ * an image instance.
+ */
+ public AbstractTransparentImage(final Image flyWeightImage) {
+ super(flyWeightImage);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void paintFigure(Graphics graphics) {
+ if (getImage() != null) {
+ TransparentFigureGraphicsModifier modifier = new TransparentFigureGraphicsModifier(this, graphics);
+ modifier.pushState();
+ graphics.drawImage(getImage(), new Rectangle(getImage().getBounds()), getBounds());
+ modifier.popState();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getSiriusAlpha() {
+ return viewpointAlpha;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isTransparent() {
+ return transparent;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setSiriusAlpha(int alpha) {
+ this.viewpointAlpha = alpha;
+
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setTransparent(boolean transparent) {
+ this.transparent = transparent;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AbstractTransparentNode.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AbstractTransparentNode.java
new file mode 100644
index 0000000000..30f3aa74ff
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AbstractTransparentNode.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import org.eclipse.gmf.runtime.gef.ui.figures.NodeFigure;
+
+/**
+ * An abstract node figure to handle transparency.
+ */
+public abstract class AbstractTransparentNode extends NodeFigure implements ITransparentFigure {
+
+ private int viewpointAlpha = DEFAULT_ALPHA;
+
+ private boolean transparent;
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getSiriusAlpha() {
+ return viewpointAlpha;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isTransparent() {
+ return transparent;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setSiriusAlpha(int alpha) {
+ this.viewpointAlpha = alpha;
+
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setTransparent(boolean transparent) {
+ this.transparent = transparent;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AbstractTransparentRectangle.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AbstractTransparentRectangle.java
new file mode 100644
index 0000000000..2d2df2b401
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AbstractTransparentRectangle.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.RectangleFigure;
+
+import org.eclipse.sirius.diagram.ui.tools.internal.figure.TransparentFigureGraphicsModifier;
+
+/**
+ * An abstract rectangle figure to handle transparency.
+ */
+public abstract class AbstractTransparentRectangle extends RectangleFigure implements StyledFigure, ITransparentFigure {
+
+ private int viewpointAlpha = DEFAULT_ALPHA;
+
+ private boolean transparent;
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void fillShape(Graphics graphics) {
+ TransparentFigureGraphicsModifier modifier = new TransparentFigureGraphicsModifier(this, graphics);
+ modifier.pushState();
+ super.fillShape(graphics);
+ modifier.popState();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getSiriusAlpha() {
+ return viewpointAlpha;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isTransparent() {
+ return transparent;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setSiriusAlpha(int alpha) {
+ this.viewpointAlpha = alpha;
+
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setTransparent(boolean transparent) {
+ this.transparent = transparent;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/ActionTriggerImageFigure.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/ActionTriggerImageFigure.java
new file mode 100644
index 0000000000..37d88bc783
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/ActionTriggerImageFigure.java
@@ -0,0 +1,192 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.draw2d.MouseEvent;
+import org.eclipse.draw2d.MouseListener;
+import org.eclipse.swt.graphics.Image;
+
+import org.eclipse.sirius.common.ui.tools.api.util.ISimpleAction;
+
+/**
+ * A figure that triggers actions when the user clicks on the image.
+ *
+ *
+ * @author ymortier
+ */
+public class ActionTriggerImageFigure extends MouseAwareImageFigure {
+
+ /** The image that is shown when the user clicks on the figure. */
+ protected Image clickedImage;
+
+ /**
+ * Actions to triggers when the image is clicked (type of
+ * {@link ISimpleAction}.
+ */
+ private List actions;
+
+ /**
+ * the action trigger mandatory to simulate click
+ */
+ private ActionTrigger actionTrigger;
+
+ /**
+ * Create a new {@link ActionTriggerImageFigure}.
+ */
+ public ActionTriggerImageFigure() {
+ super();
+ this.init();
+ }
+
+ /**
+ * Create a new {@link ActionTriggerImageFigure}.
+ *
+ * @param imageWOFocus
+ * the image that is shown when the mouse is not on the figure.
+ * @param imageWFocus
+ * the image that is shown when the mouse is on the figure.
+ */
+ public ActionTriggerImageFigure(final Image imageWOFocus, final Image imageWFocus) {
+ super(imageWOFocus, imageWFocus);
+ this.init();
+ }
+
+ /**
+ * Create a new {@link ActionTriggerImageFigure}.
+ *
+ * @param imageWOFocus
+ * the image that is shown when the mouse is not on the figure.
+ */
+ public ActionTriggerImageFigure(final Image imageWOFocus) {
+ super(imageWOFocus);
+ this.init();
+ }
+
+ /**
+ * Initialize the figure.
+ */
+ private void init() {
+ this.actions = new LinkedList();
+ this.actionTrigger = new ActionTrigger();
+ this.addMouseListener(this.actionTrigger);
+ }
+
+ /**
+ * This class has the responsability to trigger actions when the figure is
+ * clicked.
+ *
+ * @author ymortier
+ */
+ private class ActionTrigger implements MouseListener {
+
+ /**
+ * @see MouseListener#mouseDoubleClicked(MouseEvent)
+ */
+ public void mouseDoubleClicked(final MouseEvent me) {
+ // do nothing.
+ }
+
+ /**
+ * @see MouseListener#mousePressed(MouseEvent)
+ */
+ public void mousePressed(final MouseEvent me) {
+ if (clickedImage != null) {
+ ActionTriggerImageFigure.this.setImage(clickedImage);
+ }
+ trigger();
+ me.consume();
+ }
+
+ /**
+ * @see MouseListener#mouseReleased(MouseEvent)
+ */
+ public void mouseReleased(final MouseEvent me) {
+ if (getImage() == clickedImage) {
+ setImage(imageWFocus);
+ }
+ }
+
+ }
+
+ /**
+ * Trigger all actions.
+ */
+ public void trigger() {
+ final Iterator iterActions = this.iterActions();
+ while (iterActions.hasNext()) {
+ final ISimpleAction action = (ISimpleAction) iterActions.next();
+ action.executeAction();
+ }
+ }
+
+ /**
+ * Add an action.
+ *
+ * @param simpleAction
+ * the action to add.
+ */
+ public void addAction(final ISimpleAction simpleAction) {
+ this.actions.add(simpleAction);
+ }
+
+ /**
+ * Add an action at the specified index.
+ *
+ * @param simpleAction
+ * the action to add.
+ * @param index
+ * index at which the specified element is to be inserted
+ */
+ public void addAction(final ISimpleAction simpleAction, final int index) {
+ this.actions.add(index, simpleAction);
+ }
+
+ /**
+ * Remove all actions.
+ */
+ public void clearActions() {
+ this.actions.clear();
+ }
+
+ /**
+ * Remove an action.
+ *
+ * @param simpleAction
+ * the action to remove.
+ */
+ public void removeAction(final ISimpleAction simpleAction) {
+ this.actions.remove(simpleAction);
+ }
+
+ /**
+ * Return an iterator that iterates on actions.
+ *
+ * @return an iterator that iterates on actions.
+ */
+ public Iterator iterActions() {
+ return this.actions.iterator();
+ }
+
+ /**
+ * Define the image that is shown when the user clicks on the figure.
+ *
+ * @param clickedImage
+ * the image that is shown when the user clicks on the figure.
+ */
+ public void setClickedImage(final Image clickedImage) {
+ this.clickedImage = clickedImage;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AirDefaultSizeNodeFigure.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AirDefaultSizeNodeFigure.java
new file mode 100644
index 0000000000..e77cb21ab3
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AirDefaultSizeNodeFigure.java
@@ -0,0 +1,240 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import org.eclipse.draw2d.ConnectionAnchor;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Insets;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.PrecisionPoint;
+import org.eclipse.gef.editparts.ZoomManager;
+import org.eclipse.gmf.runtime.draw2d.ui.figures.BaseSlidableAnchor;
+import org.eclipse.gmf.runtime.gef.ui.figures.DefaultSizeNodeFigure;
+
+import org.eclipse.sirius.diagram.ui.tools.api.figure.anchor.AnchorProvider;
+import org.eclipse.sirius.diagram.ui.tools.api.figure.anchor.ZoomDependantAnchor;
+
+/**
+ * The air default size node figure to add custom anchor.
+ *
+ * @author ymortier
+ */
+public class AirDefaultSizeNodeFigure extends DefaultSizeNodeFigure {
+
+ /** The zoom manager. */
+ protected ZoomManager zoomManager;
+
+ /** The anchor provider. */
+ private AnchorProvider anchorProvider;
+
+ /** The slidable anchor area. */
+ private double slidableAnchorArea = -1.0; // disabled by default, so that we
+ // use the value from super.
+
+ /**
+ * Create a new {@link AirDefaultSizeNodeFigure}.
+ *
+ * @param defSize
+ * the size.
+ * @param anchorProvider
+ * the anchor provider.
+ */
+ public AirDefaultSizeNodeFigure(final Dimension defSize, final AnchorProvider anchorProvider) {
+ super(defSize);
+ this.anchorProvider = anchorProvider;
+ }
+
+ /**
+ * Create a new {@link AirDefaultSizeNodeFigure}.
+ *
+ * @param width
+ * the width.
+ * @param height
+ * the height.
+ * @param anchorProvider
+ * the anchor provider.
+ */
+ public AirDefaultSizeNodeFigure(final int width, final int height, final AnchorProvider anchorProvider) {
+ super(width, height);
+ this.anchorProvider = anchorProvider;
+ }
+
+ /**
+ * Create an anchor with the provider given as parameter.
+ *
+ * @param provider
+ * the provider
+ * @param p
+ * the precision point
+ * @return the created anchor
+ */
+ public ConnectionAnchor createAnchor(final AnchorProvider provider, final PrecisionPoint p) {
+ final ConnectionAnchor anchor = provider.createAnchor(this, p);
+ setZoomManagerToAnchor(anchor);
+ return anchor;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.gef.ui.figures.NodeFigure#createAnchor(org.eclipse.draw2d.geometry.PrecisionPoint)
+ */
+ @Override
+ protected ConnectionAnchor createAnchor(final PrecisionPoint p) {
+ if (this.anchorProvider != null) {
+ final ConnectionAnchor anchor = this.anchorProvider.createAnchor(this, p);
+ setZoomManagerToAnchor(anchor);
+ return anchor;
+ }
+ return super.createAnchor(p);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.gef.ui.figures.NodeFigure#createConnectionAnchor(org.eclipse.draw2d.geometry.Point)
+ */
+ @Override
+ protected ConnectionAnchor createConnectionAnchor(final Point p) {
+ return super.createConnectionAnchor(p);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.gef.ui.figures.NodeFigure#createDefaultAnchor()
+ */
+ @Override
+ protected ConnectionAnchor createDefaultAnchor() {
+ if (this.anchorProvider != null) {
+ final ConnectionAnchor anchor = this.anchorProvider.createDefaultAnchor(this);
+ setZoomManagerToAnchor(anchor);
+ return anchor;
+ }
+ return super.createDefaultAnchor();
+ }
+
+ private void setZoomManagerToAnchor(final ConnectionAnchor anchor) {
+ if (anchor instanceof ZoomDependantAnchor) {
+ ((ZoomDependantAnchor) anchor).setZoomManager(zoomManager);
+ }
+ }
+
+ /**
+ * No insets. {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.Figure#getInsets()
+ */
+ @Override
+ public Insets getInsets() {
+ return new Insets(0);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.Figure#getMinimumSize(int, int)
+ */
+ @Override
+ public Dimension getMinimumSize(final int hint, final int hint2) {
+ return new Dimension(10, 10); // the minimun size.
+ }
+
+ /**
+ * Overridden to allow user control using
+ * {@link #setSlidableAnchorArea(double)}.
+ * <p>
+ * {@inheritDoc}
+ */
+ @Override
+ public double getSlidableAnchorArea() {
+ if (this.slidableAnchorArea >= 0) {
+ return this.slidableAnchorArea;
+ } else {
+ return super.getSlidableAnchorArea();
+ }
+ }
+
+ /**
+ * Specifies how large the area of the figure's bounds where SlidableAnchor
+ * will be created. The value must be below 1.0. A negative value means
+ * "use the default from the superclass".
+ *
+ * @param value
+ * the percentage of area of the figure's bounds where
+ * SlidableAnchor will be created.
+ */
+ public void setSlidableAnchorArea(double value) {
+ if (value > 1.0) {
+ this.slidableAnchorArea = 1.0;
+ } else {
+ this.slidableAnchorArea = value;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.Figure#getMaximumSize()
+ */
+ @Override
+ public Dimension getMaximumSize() {
+ return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
+ }
+
+ /**
+ * Return the {@link AnchorProvider} of the figure.
+ *
+ * @return the {@link AnchorProvider} of the figure.
+ */
+ public AnchorProvider getAnchorProvider() {
+ return anchorProvider;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.gef.ui.figures.NodeFigure#getConnectionAnchor(java.lang.String)
+ */
+ @Override
+ public ConnectionAnchor getConnectionAnchor(final String terminal) {
+ ConnectionAnchor connectAnchor = (ConnectionAnchor) getConnectionAnchors().get(terminal == null ? szAnchor : terminal);
+ if (connectAnchor == null) {
+ if (szAnchor.equals(terminal)) {
+ // get a new one - this figure doesn't support static anchors
+ connectAnchor = createDefaultAnchor();
+ } else {
+ connectAnchor = createAnchor(BaseSlidableAnchor.parseTerminalString(terminal));
+ }
+ getConnectionAnchors().put(terminal == null ? szAnchor : terminal, connectAnchor);
+ }
+
+ return connectAnchor;
+ }
+
+ /**
+ * Set the zoom manager.
+ *
+ * @param manager
+ * the zoom manager
+ */
+ public void setZoomManager(final ZoomManager manager) {
+ if (zoomManager != manager) {
+ zoomManager = manager;
+ for (ConnectionAnchor anchor : (Iterable<ConnectionAnchor>) this.getConnectionAnchors().values()) {
+ if (anchor instanceof ZoomDependantAnchor) {
+ ((ZoomDependantAnchor) anchor).setZoomManager(manager);
+ }
+ }
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AirNoteFigure.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AirNoteFigure.java
new file mode 100644
index 0000000000..2996e5b8ef
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AirNoteFigure.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.geometry.Insets;
+import org.eclipse.gmf.runtime.diagram.ui.figures.NoteFigure;
+
+import org.eclipse.sirius.diagram.ui.tools.internal.figure.TransparentFigureGraphicsModifier;
+
+/**
+ * Specific Figure to handle documentation notes.
+ *
+ * @author cbrun
+ *
+ */
+public class AirNoteFigure extends NoteFigure implements StyledFigure, ITransparentFigure {
+
+ private int viewpointAlpha = DEFAULT_ALPHA;
+
+ private boolean transparent;
+
+ /**
+ * Create a new note with specicic values.
+ *
+ * @param width
+ * <code>int</code> value that is the default width in logical
+ * units
+ * @param height
+ * <code>int</code> value that is the default height in logical
+ * units
+ * @param insets
+ * <code>Insets</code> that is the empty margin inside the note
+ * figure in logical units
+ */
+ public AirNoteFigure(final int width, final int height, final Insets insets) {
+ super(width, height, insets);
+ }
+
+ /**
+ * Create a new note figure with default values.
+ */
+ public AirNoteFigure() {
+ super(100, 50, new Insets(5, 5, 5, 5));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void paintFigure(Graphics g) {
+ TransparentFigureGraphicsModifier modifier = new TransparentFigureGraphicsModifier(this, g);
+ modifier.pushState();
+ super.paintFigure(g);
+ modifier.popState();
+
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getSiriusAlpha() {
+ return viewpointAlpha;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isTransparent() {
+ return transparent;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setSiriusAlpha(int alpha) {
+ this.viewpointAlpha = alpha;
+
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setTransparent(boolean transparent) {
+ this.transparent = transparent;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AirStyleDefaultSizeNodeFigure.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AirStyleDefaultSizeNodeFigure.java
new file mode 100644
index 0000000000..f89ab3c7e4
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AirStyleDefaultSizeNodeFigure.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2011 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gmf.runtime.gef.ui.figures.DefaultSizeNodeFigure;
+
+/**
+ * The sefault size node for styles.
+ *
+ * @author ymortier
+ */
+public class AirStyleDefaultSizeNodeFigure extends DefaultSizeNodeFigure {
+
+ /**
+ * Constructor.
+ *
+ * @param defSize
+ * the default size.
+ */
+ public AirStyleDefaultSizeNodeFigure(final Dimension defSize) {
+ super(defSize);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param width
+ * the initial width to initialize the default size with
+ * @param height
+ * the initial height to initialize the default size with
+ */
+ public AirStyleDefaultSizeNodeFigure(final int width, final int height) {
+ super(width, height);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.Figure#setBounds(org.eclipse.draw2d.geometry.Rectangle)
+ */
+ @Override
+ public void setBounds(final Rectangle rect) {
+ if (getParent() != null) {
+ super.setBounds(getParent().getBounds());
+ } else {
+ super.setBounds(rect);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AlphaDropShadowBorder.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AlphaDropShadowBorder.java
new file mode 100644
index 0000000000..ca30221ef8
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/AlphaDropShadowBorder.java
@@ -0,0 +1,127 @@
+/***********************************************************************
+ * Copyright (c) 2008 Anyware Technologies
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Simon Bernard (Anyware Technologies) - initial API and implementation
+ * Cedric Brun (Obeo) - changes to consider the included shape and not the wrapping one.
+ *
+ * $Id: AlphaDropShadowBorder.java,v 1.1 2008/08/12 13:24:50 jlescot Exp $
+ **********************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import org.eclipse.draw2d.AbstractBackground;
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.geometry.Insets;
+import org.eclipse.draw2d.geometry.PointList;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gmf.runtime.diagram.ui.figures.DiagramColorConstants;
+import org.eclipse.gmf.runtime.draw2d.ui.figures.DropShadowBorder;
+import org.eclipse.gmf.runtime.draw2d.ui.figures.IPolygonAnchorableFigure;
+import org.eclipse.gmf.runtime.draw2d.ui.mapmode.MapModeUtil;
+import org.eclipse.swt.graphics.Color;
+
+/**
+ * A border using a shadow<br>
+ * creation : 17 mai. 08
+ *
+ * @author <a href="mailto:simon.bernard@anyware-tech.com">Simon Bernard</a>
+ * CHECKSTYLE:OFF
+ */
+public class AlphaDropShadowBorder extends AbstractBackground implements DropShadowBorder {
+
+ private static final int DEFAULT_SHIFT_VALUE = 1;
+
+ private static final Color SHADOW_COLOR = DiagramColorConstants.diagramDarkGray;
+
+ private static final int DEFAULT_TRANSPARENCY = 65;
+
+ private boolean shouldDrawShadow = true;
+
+ private int shift = DEFAULT_SHIFT_VALUE;
+
+ private IFigure shape;
+
+ /**
+ *
+ * @param shape
+ */
+ public AlphaDropShadowBorder(IFigure shape) {
+ super();
+ this.shape = shape;
+ }
+
+ public void setShouldDrawDropShadow(boolean drawDropShadow) {
+ shouldDrawShadow = drawDropShadow;
+ }
+
+ public boolean shouldDrawDropShadow() {
+ return shouldDrawShadow;
+ }
+
+ /**
+ * Method for determining the inset the border will take up on the shape.
+ *
+ * @param figure
+ * Figure that will be inset from the border
+ * @return Insets the Insets for the border on the given figure.
+ */
+ @Override
+ public Insets getInsets(IFigure figure) {
+ Insets insetsNew = new Insets();
+ insetsNew.top = 0;
+ insetsNew.left = 0;
+ insetsNew.bottom = MapModeUtil.getMapMode(figure).DPtoLP(shift * 2);
+ insetsNew.right = MapModeUtil.getMapMode(figure).DPtoLP(shift * 2);
+ return insetsNew;
+ }
+
+ public Insets getTransparentInsets(IFigure figure) {
+ Insets insetsNew = new Insets();
+ insetsNew.top = 0;
+ insetsNew.left = 0;
+ insetsNew.bottom = MapModeUtil.getMapMode(figure).DPtoLP(shift * 2);
+ insetsNew.right = MapModeUtil.getMapMode(figure).DPtoLP(shift * 2);
+ return insetsNew;
+ }
+
+ @Override
+ public void paintBackground(IFigure figure, Graphics graphics, Insets insets) {
+ if (shouldDrawDropShadow()) {
+ int ORIGINALALPHA = graphics.getAlpha();
+ graphics.pushState();
+ graphics.setBackgroundColor(SHADOW_COLOR);
+ graphics.setAlpha(DEFAULT_TRANSPARENCY);
+ if (shape instanceof IRoundedCorner) {
+ int cWidth = ((IRoundedCorner) shape).getCornerWidth();
+ int cHeight = ((IRoundedCorner) shape).getCornerWidth();
+ Rectangle bounds = figure.getBounds().getCopy();
+ bounds.translate(shift, shift);
+ graphics.fillRoundRectangle(bounds, cWidth, cHeight);
+ bounds.translate(shift, shift);
+ graphics.fillRoundRectangle(bounds, cWidth, cHeight);
+
+ } else if (shape instanceof IPolygonAnchorableFigure) {
+ PointList polygonPoints = ((IPolygonAnchorableFigure) shape).getPolygonPoints();
+ polygonPoints.translate(shift, shift);
+ graphics.fillPolygon(polygonPoints);
+ polygonPoints.translate(shift, shift);
+ graphics.fillPolygon(polygonPoints);
+ } else {
+ Rectangle bounds = figure.getBounds().getCopy();
+ bounds.translate(shift, shift);
+ graphics.fillRoundRectangle(bounds, 0, 0);
+ bounds.translate(shift, shift);
+ graphics.fillRoundRectangle(bounds, 0, 0);
+ }
+ graphics.setAlpha(ORIGINALALPHA);
+ graphics.popState();
+
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/BundledImageFigure.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/BundledImageFigure.java
new file mode 100644
index 0000000000..3ead512cb4
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/BundledImageFigure.java
@@ -0,0 +1,396 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.XYLayout;
+import org.eclipse.swt.graphics.Color;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import org.eclipse.sirius.common.tools.api.util.StringUtil;
+import org.eclipse.sirius.BundledImage;
+import org.eclipse.sirius.RGBValues;
+import org.eclipse.sirius.diagram.part.SiriusDiagramEditorPlugin;
+import org.eclipse.sirius.diagram.ui.tools.api.color.ColorManager;
+
+/**
+ * A {@link BundledImageFigure} is a Figure corresponding to an Image defined in
+ * a plugin.
+ *
+ * @author cbrun
+ */
+public class BundledImageFigure extends AbstractCachedSVGFigure {
+
+ /**
+ * The stroke tag in the SVG file.
+ */
+ private static final String SVG_STROKE = "stroke";
+ /**
+ * The fill tag in the SVG file.
+ */
+ private static final String SVG_FILL = "fill";
+
+ /**
+ * The stop-color tag in the SVG file.
+ */
+ private static final String SVG_STOP_COLOR = "stop-color";
+
+ /**
+ * The name of the style attribute in the SVG file.
+ */
+ private static final String SVG_STYLE_ATTRIBUTE_NAME = "style";
+
+ /**
+ * The id of the lighter stop color of the gradient in the SVG file.
+ */
+ private static final String SVG_STOP_LIGHTER_ID = "stop1";
+
+ /**
+ * The id of the main stop color of the gradient in the SVG file.
+ */
+ private static final String SVG_STOP_MAIN_ID = "stop2";
+
+ /**
+ * The id of the gradient element in the SVG file.
+ */
+ private static final String SVG_GRADIENT_ELEMENT_ID = "elementWithGradient";
+
+ /**
+ * The id of the shadow element in the SVG file.
+ */
+ private static final String SVG_SHADOW_ELEMENT_ID = "shadow";
+
+ private static final String IMAGE_DIR = "images/"; //$NON-NLS-1$
+
+ private static final String IMAGE_EXT = ".svg"; //$NON-NLS-1$
+
+ /**
+ * * The actual shapeName use to draw the SVG figure
+ */
+ private String shapeName;
+
+ /**
+ * The actual border color use to draw the SVG figure
+ */
+ private String mainBorderColor;
+
+ /**
+ * The actual lighter border color use to draw the shadow of SVG figure
+ */
+ private String lighterBorderColor;
+
+ /**
+ * The actual lighter gradient color use to draw the SVG figure
+ */
+ private String lighterGradientColor;
+
+ /**
+ * The actual main gradient color use to draw the SVG figure
+ */
+ private String mainGradientColor;
+
+ /**
+ * Build a new {@link BundledImageFigure} from an Image instance.
+ *
+ */
+ public BundledImageFigure() {
+ this.setLayoutManager(new XYLayout());
+ }
+
+ /**
+ * Create the {@link BundledImageFigure} from a {@link BundledImage}
+ * instance.
+ *
+ * @param bundle
+ * {@link BundledImage} specification.
+ * @return new Figure.
+ */
+ public static IFigure createImageFigure(final BundledImage bundle) {
+ final BundledImageFigure fig = new BundledImageFigure();
+ fig.refreshFigure(bundle);
+ return fig;
+ }
+
+ /**
+ * @param bundle
+ */
+ private boolean updateShape(BundledImage bundledImage) {
+ boolean updated = false;
+ if (bundledImage != null && bundledImage.getShape() != null) {
+ String newShapeName = bundledImage.getShape().getName();
+ if (!StringUtil.isEmpty(newShapeName) && !newShapeName.equals(getShapeName())) {
+ this.setURI(getImageFileURI(newShapeName), false);
+ this.setShapeName(newShapeName);
+ updated = true;
+ }
+ }
+ return updated;
+ }
+
+ /**
+ * @param bundledImage
+ * @param force
+ * If the color must be force to refresh (in case of shape update
+ * for sample)
+ */
+ private boolean updateColors(BundledImage bundledImage, boolean force) {
+ boolean updated = updateColorFields(bundledImage);
+ updated = updateDocumentColors(force || updated);
+ return updated;
+ }
+
+ private boolean updateColorFields(BundledImage bundledImage) {
+ // Compute colors
+ RGBValues color = bundledImage.getColor();
+ Color newLighterColor = ColorManager.getDefault().getLighterColor(color);
+
+ RGBValues borderColor = bundledImage.getBorderColor();
+ Color newBorderLighterColor = ColorManager.getDefault().getLighterColor(borderColor);
+
+ // Get Hexa values
+ String hexaColor = getRGBValuesColorToHexa(color);
+ String hexaLighterColor = getColorToHexa(newLighterColor);
+ String hexaBorderColor = getRGBValuesColorToHexa(borderColor);
+ String hexaLighterBorderColor = getColorToHexa(newBorderLighterColor);
+
+ boolean updated = false;
+
+ if (hexaColor != null && (!hexaColor.equals(this.getMainGradientColor()))) {
+ this.setMainGradientColor(hexaColor);
+ updated = true;
+ }
+
+ if (hexaLighterColor != null && (!hexaLighterColor.equals(this.getLighterGradientColor()))) {
+ this.setLighterGradientColor(hexaLighterColor);
+ updated = true;
+ }
+
+ if (hexaBorderColor != null && (!hexaBorderColor.equals(this.getMainBorderColor()))) {
+ this.setMainBorderColor(hexaBorderColor);
+ updated = true;
+ }
+
+ if (hexaLighterBorderColor != null && (!hexaLighterBorderColor.equals(this.getLighterBorderColor()))) {
+ this.setLighterBorderColor(hexaLighterBorderColor);
+ updated = true;
+ }
+
+ return updated;
+ }
+
+ private boolean updateDocumentColors(boolean needsUpdate) {
+ boolean updated = false;
+ if (needsUpdate) {
+ setURI(getURI(), false);
+ Document document = this.getDocument();
+ if (document != null && needsUpdate) {
+ /* Update the border color (if exists). */
+ Element gradientStep1 = document.getElementById(BundledImageFigure.SVG_STOP_LIGHTER_ID);
+ if (gradientStep1 != null) {
+ String gradientStep1Style = gradientStep1.getAttribute(BundledImageFigure.SVG_STYLE_ATTRIBUTE_NAME);
+ gradientStep1.setAttribute(BundledImageFigure.SVG_STYLE_ATTRIBUTE_NAME, getNewStyle(gradientStep1Style, BundledImageFigure.SVG_STOP_COLOR, getLighterGradientColor()));
+ updated = true;
+ }
+
+ /* Update the main gradient color (if exists). */
+ Element gradientStep2 = document.getElementById(BundledImageFigure.SVG_STOP_MAIN_ID);
+ if (gradientStep2 != null) {
+ String gradientStep2Style = gradientStep2.getAttribute(BundledImageFigure.SVG_STYLE_ATTRIBUTE_NAME);
+ gradientStep2.setAttribute(BundledImageFigure.SVG_STYLE_ATTRIBUTE_NAME, getNewStyle(gradientStep2Style, BundledImageFigure.SVG_STOP_COLOR, getMainGradientColor()));
+ updated = true;
+ }
+
+ /* Update the shadow border (if exists). */
+ Element shadow = document.getElementById(SVG_SHADOW_ELEMENT_ID);
+ if (shadow != null) {
+ String shadowStyle = shadow.getAttribute(BundledImageFigure.SVG_STYLE_ATTRIBUTE_NAME);
+ shadow.setAttribute(BundledImageFigure.SVG_STYLE_ATTRIBUTE_NAME, getNewStyle(shadowStyle, SVG_FILL, getLighterBorderColor()));
+ updated = true;
+ }
+
+ /* Update the border color (if exists). */
+ Element elementWithGradient = document.getElementById(BundledImageFigure.SVG_GRADIENT_ELEMENT_ID);
+ if (elementWithGradient != null) {
+ String elementWithGradientStyle = elementWithGradient.getAttribute(BundledImageFigure.SVG_STYLE_ATTRIBUTE_NAME);
+ elementWithGradient.setAttribute(BundledImageFigure.SVG_STYLE_ATTRIBUTE_NAME, getNewStyle(elementWithGradientStyle, BundledImageFigure.SVG_STROKE, getMainBorderColor()));
+ updated = true;
+ }
+ }
+ }
+ return updated;
+ }
+
+ /**
+ * @param shapeName
+ * @return
+ */
+ private static String getImageFileURI(String shapeName) {
+ final String path = new StringBuffer(IMAGE_DIR).append(shapeName).append(IMAGE_EXT).toString();
+ String pluginId = SiriusDiagramEditorPlugin.getInstance().getBundle().getSymbolicName();
+ return "platform:/plugin/" + pluginId + "/" + path;
+ }
+
+ /**
+ * @param color
+ * The color to transform in hexa value
+ * @return The hexa representation of the color.
+ */
+ private static String getRGBValuesColorToHexa(final RGBValues color) {
+ String blankDigit = "0";
+ StringBuffer colorInHexa = new StringBuffer();
+ String hexaColor = Integer.toHexString(color.getRed());
+ if (hexaColor.length() == 1) {
+ colorInHexa.append(blankDigit);
+ }
+ colorInHexa.append(hexaColor);
+ hexaColor = Integer.toHexString(color.getGreen());
+ if (hexaColor.length() == 1) {
+ colorInHexa.append(blankDigit);
+ }
+ colorInHexa.append(hexaColor);
+ hexaColor = Integer.toHexString(color.getBlue());
+ if (hexaColor.length() == 1) {
+ colorInHexa.append(blankDigit);
+ }
+ colorInHexa.append(hexaColor);
+ return colorInHexa.toString();
+ }
+
+ /**
+ * @param color
+ * The color to transform in hexa value
+ * @return The hexa representation of the color.
+ */
+ private String getColorToHexa(Color color) {
+ String blankDigit = "0";
+ StringBuffer colorInHexa = new StringBuffer();
+ String hexaColor = Integer.toHexString(color.getRed());
+ if (hexaColor.length() == 1) {
+ colorInHexa.append(blankDigit);
+ }
+ colorInHexa.append(hexaColor);
+ hexaColor = Integer.toHexString(color.getGreen());
+ if (hexaColor.length() == 1) {
+ colorInHexa.append(blankDigit);
+ }
+ colorInHexa.append(hexaColor);
+ hexaColor = Integer.toHexString(color.getBlue());
+ if (hexaColor.length() == 1) {
+ colorInHexa.append(blankDigit);
+ }
+ colorInHexa.append(hexaColor);
+ return colorInHexa.toString();
+ }
+
+ private static String getNewStyle(String actualStyle, String colorAttribute, String newColor) {
+ int indexOfColorAttribute = actualStyle.indexOf(colorAttribute);
+ String newStyle = actualStyle.substring(0, indexOfColorAttribute + colorAttribute.length() + 2);
+ newStyle = newStyle.concat(newColor);
+ newStyle = newStyle.concat(actualStyle.substring(actualStyle.indexOf(";", indexOfColorAttribute), actualStyle.length()));
+ return newStyle;
+ }
+
+ /**
+ * refresh the figure.
+ *
+ * @param bundledImage
+ * the image associated to the figure
+ */
+ public void refreshFigure(final BundledImage bundledImage) {
+ if (bundledImage != null) {
+ boolean updated = this.updateShape(bundledImage);
+ updated = this.updateColors(bundledImage, updated) || updated;
+ if (updated) {
+ this.contentChanged();
+ }
+ } else {
+ this.setURI(null);
+ }
+ }
+
+ protected String getShapeName() {
+ return shapeName;
+ }
+
+ protected void setShapeName(String shapeName) {
+ this.shapeName = shapeName;
+ }
+
+ protected String getMainBorderColor() {
+ return mainBorderColor;
+ }
+
+ protected void setMainBorderColor(String mainBorderColor) {
+ this.mainBorderColor = mainBorderColor;
+ }
+
+ protected String getLighterBorderColor() {
+ return lighterBorderColor;
+ }
+
+ protected void setLighterBorderColor(String lighterBorderColor) {
+ this.lighterBorderColor = lighterBorderColor;
+ }
+
+ protected String getLighterGradientColor() {
+ return lighterGradientColor;
+ }
+
+ protected void setLighterGradientColor(String lighterGradientColor) {
+ this.lighterGradientColor = lighterGradientColor;
+ }
+
+ protected String getMainGradientColor() {
+ return mainGradientColor;
+ }
+
+ protected void setMainGradientColor(String mainGradientColor) {
+ this.mainGradientColor = mainGradientColor;
+ }
+
+ /**
+ * Compute a key for this BundleImageFigure. This key is used to store in
+ * cache the corresponding {@link org.eclipse.swt.graphics.Image}.
+ *
+ * {@inheritDoc}
+ *
+ * @return The key corresponding to this BundleImageFigure.
+ */
+ protected String getKey() {
+ StringBuffer result = new StringBuffer();
+ result.append(getDocumentKey());
+ result.append(SEPARATOR);
+ result.append(getSiriusAlpha());
+ result.append(SEPARATOR);
+ return result.toString();
+ }
+
+ /**
+ * Compute a key for this BundleImageFigure. This key is used to store in
+ * cache the corresponding {@link org.eclipse.swt.graphics.Image}.
+ *
+ * {@inheritDoc}
+ *
+ * @return The key corresponding to this BundleImageFigure.
+ */
+ protected String getDocumentKey() {
+ StringBuffer result = new StringBuffer();
+ result.append(super.getDocumentKey());
+ result.append(SEPARATOR);
+ result.append(shapeName);
+ result.append(SEPARATOR);
+ result.append(mainBorderColor);
+ result.append(SEPARATOR);
+ result.append(mainGradientColor);
+ return result.toString();
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/DBorderedNodeFigure.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/DBorderedNodeFigure.java
new file mode 100644
index 0000000000..7b0b796acc
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/DBorderedNodeFigure.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.gmf.runtime.diagram.ui.figures.BorderedNodeFigure;
+
+/**
+ * This figure overrides {@link BorderedNodeFigure} in order to force layout
+ * because of an issue where resizing a node will not relocate its bordered
+ * nodes.
+ *
+ * @author smonnier
+ *
+ */
+public class DBorderedNodeFigure extends BorderedNodeFigure {
+
+ /**
+ * Creates a new DBorderedNodeFigure figure.
+ *
+ * @param mainFigure
+ * the figure to use with this figure
+ */
+ public DBorderedNodeFigure(IFigure mainFigure) {
+ super(mainFigure);
+ }
+
+ /**
+ * This method has been overridden to avoid comparing bounds of this and
+ * getMainFigure(). {@inheritDoc}
+ */
+ @Override
+ protected void layout() {
+ getMainFigure().setBounds(this.getBounds().getCopy());
+ getBorderItemContainer().invalidateTree();
+ erase();
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/FigureQuery.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/FigureQuery.java
new file mode 100644
index 0000000000..5d8f275ce2
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/FigureQuery.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2011 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.Label;
+import org.eclipse.gmf.runtime.draw2d.ui.figures.WrapLabel;
+
+import com.google.common.collect.Iterables;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.common.tools.api.util.Options;
+
+/**
+ * A class aggregating all the queries (read-only!) having a {@link IFigure} as
+ * starting point.
+ *
+ * @author lredor
+ *
+ */
+public class FigureQuery {
+
+ private IFigure figure;
+
+ /**
+ * Create a new query.
+ *
+ * @param figure
+ * the element to query.
+ */
+ public FigureQuery(IFigure figure) {
+ this.figure = figure;
+ }
+
+ /**
+ * Return the label figure of this figure. Search in all chidren the first
+ * figure of kind {@link Label}, {@link WrapLabel} or
+ * {@link SiriusWrapLabel}.
+ *
+ * @return the first label figure or null if any
+ */
+ public Option<IFigure> getLabelFigure() {
+ Option<IFigure> result = Options.newNone();
+ if (figure instanceof SiriusWrapLabel || figure instanceof WrapLabel || figure instanceof Label) {
+ result = Options.newSome(figure);
+ } else {
+ for (IFigure childFigure : Iterables.filter(figure.getChildren(), IFigure.class)) {
+ Option<IFigure> temp = new FigureQuery(childFigure).getLabelFigure();
+ if (temp.some()) {
+ result = temp;
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Return the label of the first label figure of this figure. Search in all
+ * chidren the first figure of kind {@link Label}, {@link WrapLabel} or
+ * {@link SiriusWrapLabel}.
+ *
+ * @return the label of the first label figure or null if any
+ */
+ public Option<String> getText() {
+ Option<String> result = Options.newNone();
+ Option<IFigure> labelFigure = getLabelFigure();
+ if (labelFigure.some()) {
+ if (labelFigure.get() instanceof SiriusWrapLabel) {
+ result = Options.newSome(((SiriusWrapLabel) labelFigure.get()).getText());
+ }
+ if (labelFigure.get() instanceof WrapLabel) {
+ result = Options.newSome(((WrapLabel) labelFigure.get()).getText());
+ } else if (labelFigure.get() instanceof Label) {
+ result = Options.newSome(((Label) labelFigure.get()).getText());
+ }
+ }
+ return result;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/FoldingToggleAwareClippingStrategy.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/FoldingToggleAwareClippingStrategy.java
new file mode 100644
index 0000000000..c9291ac60e
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/FoldingToggleAwareClippingStrategy.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2012 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import org.eclipse.draw2d.IClippingStrategy;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.geometry.Rectangle;
+
+/**
+ * A clipping strategy to avoid (0,0) sized clip area for
+ * {@link FoldingToggleImageFigure} and allow repaint after user style
+ * customization. For other figures type, it keep the
+ * {@link org.eclipse.draw2d.Figure#paintChildren(org.eclipse.draw2d.Graphics)}
+ * behavior.
+ *
+ * @author mporhel
+ */
+public class FoldingToggleAwareClippingStrategy implements IClippingStrategy {
+
+ /**
+ * {@inheritDoc}
+ */
+ public Rectangle[] getClip(IFigure childFigure) {
+ if (childFigure != null) {
+ Rectangle bounds = childFigure.getBounds().getCopy();
+ if (childFigure instanceof FoldingToggleImageFigure) {
+ bounds.setSize(FoldingToggleImageFigure.FOLD_ICON_HEIGHT, FoldingToggleImageFigure.FOLD_ICON_WIDTH);
+ }
+ return new Rectangle[] { bounds };
+ }
+ return null;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/FoldingToggleImageFigure.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/FoldingToggleImageFigure.java
new file mode 100644
index 0000000000..05596d14d0
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/FoldingToggleImageFigure.java
@@ -0,0 +1,120 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.swt.graphics.Image;
+
+import com.google.common.base.Preconditions;
+
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.EdgeTarget;
+import org.eclipse.sirius.diagram.business.internal.query.EdgeTargetQuery;
+import org.eclipse.sirius.diagram.edit.api.part.IAbstractDiagramNodeEditPart;
+import org.eclipse.sirius.diagram.part.SiriusDiagramEditorPlugin;
+import org.eclipse.sirius.diagram.tools.internal.commands.ToggleFoldingStateCommand;
+
+/**
+ * A figure which displays and controls the folding state of an element.
+ *
+ * @author pcdavid
+ */
+public class FoldingToggleImageFigure extends ActionTriggerImageFigure {
+
+ /**
+ * Width of the images used for the folding toggle.
+ */
+ protected static final int FOLD_ICON_WIDTH = 9;
+
+ /**
+ * Height of the images used for the folding toggle.
+ */
+ protected static final int FOLD_ICON_HEIGHT = FOLD_ICON_WIDTH;
+
+ private static final Image MINUS_IMAGE = SiriusDiagramEditorPlugin.getInstance().getImage(SiriusDiagramEditorPlugin.getBundledImageDescriptor("/icons/collapse.gif"));
+
+ private static final Image PLUS_IMAGE = SiriusDiagramEditorPlugin.getInstance().getImage(SiriusDiagramEditorPlugin.getBundledImageDescriptor("/icons/expand.gif"));
+
+ private final IAbstractDiagramNodeEditPart part;
+
+ /**
+ * Constructor.
+ *
+ * @param part
+ * the element whose folding state to display and control.
+ */
+ public FoldingToggleImageFigure(IAbstractDiagramNodeEditPart part) {
+ this.part = Preconditions.checkNotNull(part);
+ setSize(new Dimension(FOLD_ICON_WIDTH, FOLD_ICON_HEIGHT));
+ show(null);
+ DDiagramElement element = part.resolveDiagramElement();
+ if (element instanceof EdgeTarget) {
+ updateImage();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void paint(Graphics graphics) {
+ updateImage();
+ super.paint(graphics);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void trigger() {
+ DDiagramElement element = part.resolveDiagramElement();
+ if (element instanceof EdgeTarget) {
+ TransactionalEditingDomain domain = part.getEditingDomain();
+ domain.getCommandStack().execute(new ToggleFoldingStateCommand(domain, part));
+ updateImage();
+ }
+ }
+
+ private void updateImage() {
+ if (part.isActive()) {
+ DDiagramElement element = part.resolveDiagramElement();
+ if (element instanceof EdgeTarget) {
+ EdgeTargetQuery query = new EdgeTargetQuery((EdgeTarget) element);
+ if (!query.isFoldingPoint()) {
+ show(null);
+ } else {
+ switch (query.getFoldingState()) {
+ case FOLDED:
+ show(PLUS_IMAGE);
+ break;
+ case UNFOLDED:
+ case MIXED:
+ default:
+ show(MINUS_IMAGE);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ private void show(Image img) {
+ setImageWOFocus(img);
+ setImageWFocus(img);
+ if (img == null) {
+ setSize(0, 0);
+ } else {
+ setSize(FOLD_ICON_WIDTH, FOLD_ICON_HEIGHT);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/GaugeCompositeFigure.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/GaugeCompositeFigure.java
new file mode 100644
index 0000000000..8320716bc9
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/GaugeCompositeFigure.java
@@ -0,0 +1,188 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.RandomAccess;
+
+import org.eclipse.draw2d.XYLayout;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gmf.runtime.draw2d.ui.figures.RectangularDropShadowLineBorder;
+
+import org.eclipse.sirius.AlignmentKind;
+
+/**
+ * Figures that paints many gauges.
+ *
+ * @author ymortier
+ */
+public class GaugeCompositeFigure extends AbstractTransparentNode implements StyledFigure {
+ private List<GaugeSectionFigure> gauges;
+
+ private AlignmentKind alignment = AlignmentKind.HORIZONTAL_LITERAL;
+
+ /**
+ * Create a new {@link GaugeCompositeFigure}.
+ */
+ public GaugeCompositeFigure() {
+ this.setLayoutManager(new XYLayout());
+ this.gauges = new ArrayList<GaugeSectionFigure>();
+ this.setBorder(new RectangularDropShadowLineBorder());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.Figure#setBounds(org.eclipse.draw2d.geometry.Rectangle)
+ */
+ @Override
+ public void setBounds(final Rectangle rect) {
+ super.setBounds(rect);
+ this.computeChildrenBounds(rect);
+ }
+
+ /**
+ * Set a new alignment.
+ *
+ * @param alignment
+ * new alignment.
+ * @since 2.0
+ */
+ public void setAlignment(final AlignmentKind alignment) {
+ this.alignment = alignment;
+ }
+
+ /**
+ * Returns the gauge.
+ *
+ * @return the gauge.
+ */
+ public List<GaugeSectionFigure> getGauges() {
+ return Collections.unmodifiableList(gauges);
+ }
+
+ /**
+ * Returns the gauge at the specified index.
+ *
+ * @param index
+ * index of the gauge to return.
+ * @return the gauge at the specified index.
+ */
+ public GaugeSectionFigure getGaugeAt(final int index) {
+ return this.gauges.get(index);
+ }
+
+ /**
+ * Adds a gauge.
+ */
+ public void addGauge() {
+ final GaugeSectionFigure gauge = GaugeSectionFigure.createDefaultSection();
+ this.add(gauge, 0);
+ this.gauges.add(gauge);
+ this.computeChildrenBounds(this.getBounds());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.Figure#useLocalCoordinates()
+ */
+ @Override
+ protected boolean useLocalCoordinates() {
+ return true;
+ }
+
+ private void computeChildrenBounds(final Rectangle rect) {
+ final int borderInsetsH = (getBorder() == null || getBorder().getInsets(this) == null) ? 0 : getBorder().getInsets(this).left + getBorder().getInsets(this).right;
+ final int borderInsetsV = (getBorder() == null || getBorder().getInsets(this) == null) ? 0 : getBorder().getInsets(this).top + getBorder().getInsets(this).bottom;
+
+ Dimension childDimension = null;
+
+ int sideSize = -1;
+ int vSideSize = -1;
+
+ int nbGauges = this.gauges.size();
+ if (nbGauges == 0) {
+ nbGauges = 1;
+ }
+
+ switch (this.alignment) {
+ case VERTICAL_LITERAL:
+ childDimension = new Dimension(rect.width - borderInsetsH, (rect.height - borderInsetsV) / nbGauges);
+ break;
+ case HORIZONTAL_LITERAL:
+ childDimension = new Dimension((rect.width - borderInsetsH) / nbGauges, rect.height - borderInsetsV);
+ break;
+ case SQUARE_LITERAL:
+ default:
+ // ... square ...
+ sideSize = (int) Math.ceil(Math.sqrt(nbGauges));
+ // adjust v size
+ vSideSize = sideSize;
+ if (nbGauges != (sideSize * sideSize) && nbGauges % sideSize == 0) {
+ vSideSize--;
+ }
+ sideSize = sideSize <= 0 ? 1 : sideSize;
+ vSideSize = vSideSize <= 0 ? 1 : vSideSize;
+ childDimension = new Dimension((rect.width - borderInsetsH) / sideSize, (rect.height - borderInsetsV) / vSideSize);
+ break;
+ }
+
+ List sections = this.getGauges();
+ if (!(sections instanceof RandomAccess)) {
+ // Convert sections to an ArrayList to improve performance.
+ sections = new ArrayList(this.getGauges());
+ }
+ for (int i = 0; i < sections.size(); i++) {
+ final GaugeSectionFigure figure = (GaugeSectionFigure) sections.get(i);
+ Point p = null;
+ switch (this.alignment) {
+ case VERTICAL_LITERAL:
+ p = new Point(0, childDimension.height * i);
+ break;
+ case HORIZONTAL_LITERAL:
+ p = new Point(childDimension.width * i, 0);
+ break;
+ case SQUARE_LITERAL:
+ default:
+ p = new Point(childDimension.width * (i % sideSize), childDimension.height * (Math.floor((double) i / sideSize) % vSideSize));
+ break;
+ }
+ figure.setBounds(new Rectangle(p, childDimension));
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setTransparent(boolean transparent) {
+ super.setTransparent(transparent);
+ for (GaugeSectionFigure section : gauges) {
+ section.setTransparent(transparent);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setSiriusAlpha(int alpha) {
+ super.setSiriusAlpha(alpha);
+ for (GaugeSectionFigure section : gauges) {
+ section.setSiriusAlpha(alpha);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/GaugeSectionFigure.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/GaugeSectionFigure.java
new file mode 100644
index 0000000000..3c5184b2ff
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/GaugeSectionFigure.java
@@ -0,0 +1,193 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import org.eclipse.draw2d.ColorConstants;
+import org.eclipse.draw2d.FlowLayout;
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.LineBorder;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.draw2d.text.FlowPage;
+import org.eclipse.draw2d.text.TextFlow;
+
+import org.eclipse.sirius.common.tools.api.util.StringUtil;
+import org.eclipse.sirius.diagram.ui.tools.internal.figure.TransparentFigureGraphicsModifier;
+
+/**
+ * Figure of a section of a quadriptyque.
+ *
+ * @author ymortier
+ */
+public class GaugeSectionFigure extends AbstractTransparentNode {
+
+ /** The minimal value. */
+ private int min;
+
+ /** The maximal value. */
+ private int max;
+
+ /** The value. */
+ private int value;
+
+ private final TextFlow textFlow = new TextFlow(StringUtil.EMPTY_STRING);
+
+ /**
+ * Creates a new <code>QuadriptyqueSectionFigure</code>.
+ *
+ * @param min
+ * the minimal value.
+ * @param max
+ * the maximal value.
+ * @param value
+ * the value.
+ */
+ public GaugeSectionFigure(final int min, final int max, final int value) {
+ this.setLayoutManager(new FlowLayout());
+ final FlowPage flowPage = new FlowPage();
+ flowPage.add(textFlow);
+ this.add(flowPage);
+ this.textFlow.setForegroundColor(ColorConstants.white);
+ this.min = min;
+ this.max = max;
+ this.value = value;
+ this.setBorder(new LineBorder());
+ }
+
+ /**
+ * Returns the minimal value.
+ *
+ * @return the minimal value.
+ */
+ public int getMin() {
+ return min;
+ }
+
+ /**
+ * Sets the minimal value.
+ *
+ * @param min
+ * the minimal value.
+ */
+ public void setMin(final int min) {
+ this.min = min;
+ }
+
+ /**
+ * Returns the maximal value.
+ *
+ * @return the maximal value.
+ */
+ public int getMax() {
+ return max;
+ }
+
+ /**
+ * Sets the maximal value.
+ *
+ * @param max
+ * the maximal value.
+ */
+ public void setMax(final int max) {
+ this.max = max;
+ }
+
+ /**
+ * Returns the value.
+ *
+ * @return the value.
+ */
+ public int getValue() {
+ return value;
+ }
+
+ /**
+ * Sets the value.
+ *
+ * @param value
+ * the value.
+ */
+ public void setValue(final int value) {
+ this.value = value;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.Figure#useLocalCoordinates()
+ */
+ @Override
+ protected boolean useLocalCoordinates() {
+ return true;
+ }
+
+ /**
+ * Set the section label.
+ *
+ * @param label
+ * new label value.
+ */
+ public void setLabel(final String label) {
+ this.textFlow.setText(label);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.gef.ui.figures.NodeFigure#paintFigure(org.eclipse.draw2d.Graphics)
+ */
+ @Override
+ protected void paintFigure(final Graphics graphics) {
+ TransparentFigureGraphicsModifier modifier = new TransparentFigureGraphicsModifier(this, graphics);
+ modifier.pushState();
+
+ super.paintFigure(graphics);
+ final Rectangle bounds = new Rectangle(this.getBounds());
+ final int divisor = max < min ? 1 : max - min;
+ final int val = this.value > max ? max - min : this.value - min;
+ final int y;
+ if (divisor == 0) {
+ y = val == 0 ? 0 : bounds.height;
+ } else {
+ y = (int) (bounds.height * ((double) val / divisor));
+ }
+
+ graphics.setLineWidth(0);
+ graphics.setBackgroundColor(this.getBackgroundColor());
+ graphics.setForegroundColor(this.getBackgroundColor());
+ graphics.fillRectangle(+bounds.x, bounds.y, bounds.width, bounds.height - y);
+ graphics.setForegroundColor(this.getForegroundColor());
+ graphics.setBackgroundColor(this.getForegroundColor());
+ graphics.fillRectangle(bounds.x, bounds.y + bounds.height - y, bounds.width, y);
+
+ modifier.popState();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.Figure#paintBorder(org.eclipse.draw2d.Graphics)
+ */
+ @Override
+ protected void paintBorder(final Graphics graphics) {
+ graphics.setBackgroundColor(ColorConstants.white);
+ graphics.setForegroundColor(ColorConstants.white);
+ super.paintBorder(graphics);
+ }
+
+ /**
+ * Create the default section.
+ *
+ * @return a default section.
+ */
+ public static GaugeSectionFigure createDefaultSection() {
+ return new GaugeSectionFigure(1, 10, 5);
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/GradientHelper.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/GradientHelper.java
new file mode 100644
index 0000000000..92bff60d90
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/GradientHelper.java
@@ -0,0 +1,145 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2012 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.SWTGraphics;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Pattern;
+
+import org.eclipse.sirius.BackgroundStyle;
+import org.eclipse.sirius.diagram.tools.internal.figure.util.GraphicsUtilities;
+import org.eclipse.sirius.ui.tools.api.color.VisualBindingManager;
+
+/**
+ * Helper for the creation of gradient from ViewGradientFigureDesc.
+ *
+ * @author mporhel
+ *
+ */
+public final class GradientHelper {
+
+ private GradientHelper() {
+
+ }
+
+ /**
+ * Set the gradation of colors.
+ *
+ * @param graphics
+ * the graphics
+ * @param figure
+ * the figure
+ */
+ public static void setColorsGradation(final Graphics graphics, final ViewGradientFigureDesc figure) {
+
+ final Rectangle zoomedBounds = GraphicsUtilities.zoomFillRectangle(graphics, figure.getBounds());
+ if (zoomedBounds != null) {
+ final Pattern pattern = GradientHelper.getGradientPattern(figure.getBackgroundStyle().getValue(), zoomedBounds, figure.getBackgroundColor(), figure.getGradientColor());
+ SWTGraphics swtGraphics = GraphicsUtilities.getSWTGraphics(graphics);
+ if (swtGraphics != null) {
+ swtGraphics.setBackgroundPattern(pattern);
+ }
+ }
+
+ }
+
+ /**
+ * Returns the pattern corresponding to the wanted gradient.
+ *
+ * @param backgroundStyle
+ * the backgroud style
+ * @param bounds
+ * the bounds
+ * @param backgroundColor
+ * the bachground color
+ * @param gradientColor
+ * the gradient color
+ * @return the wanted pattern
+ */
+ public static Pattern getGradientPattern(final int backgroundStyle, final Rectangle bounds, final Color backgroundColor, final Color gradientColor) {
+ final Pattern pattern;
+ switch (backgroundStyle) {
+ case BackgroundStyle.GRADIENT_TOP_TO_BOTTOM:
+ pattern = GradientHelper.getGradientTopToBottom(bounds, backgroundColor, gradientColor);
+ break;
+ case BackgroundStyle.LIQUID:
+ pattern = GradientHelper.getGradientDiag(bounds, backgroundColor, gradientColor);
+ break;
+ case BackgroundStyle.GRADIENT_LEFT_TO_RIGHT:
+ default:
+ pattern = GradientHelper.getGradientLeftToRight(bounds, backgroundColor, gradientColor);
+ break;
+ }
+ return pattern;
+ }
+
+ /**
+ * Returns the pattern corresponding to the LeftToRight gradient.
+ *
+ * @param bounds
+ * the bounds
+ * @param backgroundColor
+ * the background color
+ * @param gradientColor
+ * teh gradient color
+ * @return the correesponding pattern.
+ */
+ public static Pattern getGradientLeftToRight(final Rectangle bounds, final Color backgroundColor, final Color gradientColor) {
+ return VisualBindingManager.getDefault().getPatternFromValue(bounds.x, bounds.y, bounds.x + bounds.width, bounds.y, backgroundColor, gradientColor);
+ }
+
+ /**
+ * Returns the pattern corresponding to the diagonal gradient.
+ *
+ * @param bounds
+ * the bounds
+ * @param backgroundColor
+ * the background color
+ * @param gradientColor
+ * the gradient color
+ * @return a diagonal pattern
+ */
+ public static Pattern getGradientDiag(final Rectangle bounds, final Color backgroundColor, final Color gradientColor) {
+ // size of the square use to compute gradient
+ int x = bounds.x;
+ int y = bounds.y;
+ int i = (bounds.width + bounds.height) / 2;
+
+ int gradientZoneWidth = Math.max(bounds.width, i);
+ if (gradientZoneWidth != bounds.width) {
+ x = bounds.x - (i - bounds.width) / 2;
+ }
+
+ int gradientZoneHeight = Math.max(bounds.height, i);
+ if (gradientZoneHeight != bounds.height) {
+ y = bounds.y - (i - bounds.height) / 2;
+ }
+ return VisualBindingManager.getDefault().getPatternFromValue(x, y, x + gradientZoneWidth, y + gradientZoneHeight, backgroundColor, gradientColor);
+ }
+
+ /**
+ * Returns the pattern corresponding to the TopToBottom gradient.
+ *
+ * @param bounds
+ * the bounds
+ * @param backgroundColor
+ * the background color
+ * @param gradientColor
+ * the gradient color
+ * @return the correesponding pattern.
+ */
+ public static Pattern getGradientTopToBottom(final Rectangle bounds, final Color backgroundColor, final Color gradientColor) {
+ return VisualBindingManager.getDefault().getPatternFromValue(bounds.x, bounds.y, bounds.x, bounds.y + bounds.height, backgroundColor, gradientColor);
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/GradientRoundedRectangle.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/GradientRoundedRectangle.java
new file mode 100644
index 0000000000..a9c496e843
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/GradientRoundedRectangle.java
@@ -0,0 +1,164 @@
+/*******************************************************************************
+ * Copyright (c) 2013 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.MarginBorder;
+import org.eclipse.draw2d.RoundedRectangle;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.gmf.runtime.draw2d.ui.mapmode.MapModeUtil;
+import org.eclipse.swt.graphics.Color;
+
+import org.eclipse.sirius.BackgroundStyle;
+import org.eclipse.sirius.diagram.tools.api.graphical.edit.styles.IContainerLabelOffsets;
+
+/**
+ * Basic implementation of RoundedRectangle shape with gradient and label
+ * capabilities.
+ *
+ * @author mporhel
+ */
+public class GradientRoundedRectangle extends RoundedRectangle implements ViewNodeContainerFigureDesc, ViewGradientFigureDesc, IRoundedCorner {
+
+ private SiriusWrapLabel fLabelFigure;
+
+ private Color gradientColor;
+
+ private BackgroundStyle backgroundStyle;
+
+ private boolean myUseLocalCoordinates;
+
+ /**
+ * Create a new {@link GradientRoundedRectangle}.
+ *
+ * @param dimension
+ * dimension of the corner (with radius, height radius)
+ * @param backgroundStyle
+ * style of the wanted gradient
+ *
+ */
+ public GradientRoundedRectangle(final Dimension dimension, final BackgroundStyle backgroundStyle) {
+ this.backgroundStyle = backgroundStyle;
+ this.setCornerDimensions(new Dimension(MapModeUtil.getMapMode().DPtoLP(dimension.width), MapModeUtil.getMapMode().DPtoLP(dimension.height)));
+ createBorder();
+ createContents();
+ }
+
+ /**
+ * Create a new {@link GradientRoundedRectangle}.
+ */
+ public GradientRoundedRectangle() {
+ this(new Dimension(8, 8), BackgroundStyle.GRADIENT_LEFT_TO_RIGHT_LITERAL);
+ }
+
+ /**
+ * Sets the gradient color.
+ *
+ * @param color
+ * The gradient color
+ */
+ public void setGradientColor(final Color color) {
+ this.gradientColor = color;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see ViewGradientFigureDesc#getGradientColor()
+ */
+ public Color getGradientColor() {
+ return this.gradientColor;
+ }
+
+ /**
+ * Create the content of the figure.
+ */
+ protected void createContents() {
+ fLabelFigure = new SiriusWrapLabel();
+ fLabelFigure.setText(" ");
+ fLabelFigure.setTextWrap(true);
+ this.add(fLabelFigure);
+ }
+
+ /**
+ * Create the border.
+ */
+ protected void createBorder() {
+ this.setBorder(new MarginBorder(IContainerLabelOffsets.LABEL_OFFSET, 0, 0, 0));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @was-generated
+ * @see org.eclipse.draw2d.Figure#useLocalCoordinates()
+ */
+ @Override
+ protected boolean useLocalCoordinates() {
+ return myUseLocalCoordinates;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @was-generated
+ * @param useLocalCoordinates
+ */
+ protected void setUseLocalCoordinates(final boolean useLocalCoordinates) {
+ myUseLocalCoordinates = useLocalCoordinates;
+ }
+
+ /**
+ * Return the label figure.
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.figure.ViewNodeContainerFigureDesc#getLabelFigure()
+ * @return the label figure.
+ */
+ public SiriusWrapLabel getLabelFigure() {
+ return fLabelFigure;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void fillShape(Graphics graphics) {
+ if (getGradientColor() != null) {
+ GradientHelper.setColorsGradation(graphics, this);
+ } else {
+ graphics.setBackgroundColor(getBackgroundColor());
+ }
+ super.fillShape(graphics);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see ViewGradientFigureDesc#getBackgroundStyle()
+ */
+ public BackgroundStyle getBackgroundStyle() {
+ return backgroundStyle;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getCornerHeight() {
+ return this.corner.height;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getCornerWidth() {
+ return this.corner.width;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/IRoundedCorner.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/IRoundedCorner.java
new file mode 100644
index 0000000000..bb77b49796
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/IRoundedCorner.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+/**
+ * Interface for figures having rounded corners.
+ *
+ * @author cedric
+ *
+ */
+public interface IRoundedCorner {
+ /**
+ * return the corner width.
+ *
+ * @return the corner width
+ */
+ int getCornerWidth();
+
+ /**
+ * return the corner height.
+ *
+ * @return the corner height
+ */
+ int getCornerHeight();
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/ITransparentFigure.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/ITransparentFigure.java
new file mode 100644
index 0000000000..cd2b689560
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/ITransparentFigure.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+/**
+ * Interface for transparent figures.
+ *
+ * @author mporhel
+ */
+public interface ITransparentFigure {
+
+ /**
+ * Default alpha value.
+ */
+ int DEFAULT_ALPHA = 100;
+
+ /**
+ * Return true if figure is in transparent mode.
+ *
+ * @return true if figure is in transparent mode.
+ */
+ boolean isTransparent();
+
+ /**
+ * Enable/disable the tranparent mode of the figure.
+ *
+ * @param transparent
+ * the wanted mode.
+ */
+ void setTransparent(boolean transparent);
+
+ /**
+ * Get the alpha value.
+ *
+ * @return the alpha value.
+ */
+ int getSiriusAlpha();
+
+ /**
+ * Set the alpha to the given value. Values may range from 0 to 255. A value
+ * of 0 is completely transparent.
+ *
+ * @param alpha
+ * an alpha value (0-255)
+ */
+ void setSiriusAlpha(int alpha);
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/IWorkspaceImageFigure.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/IWorkspaceImageFigure.java
new file mode 100644
index 0000000000..2f92418648
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/IWorkspaceImageFigure.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2011 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import org.eclipse.draw2d.IFigure;
+
+import org.eclipse.sirius.ContainerStyle;
+import org.eclipse.sirius.WorkspaceImage;
+
+/**
+ * Interface for worskpace image figures.
+ *
+ * @author mporhel
+ */
+public interface IWorkspaceImageFigure extends IFigure {
+
+ /**
+ * Refreshes the figure.
+ *
+ * @param containerStyle
+ * the style of the container
+ */
+ void refreshFigure(final ContainerStyle containerStyle);
+
+ /**
+ * refresh the figure.
+ *
+ * @param workspaceImage
+ * the image associated to the figure
+ */
+ void refreshFigure(final WorkspaceImage workspaceImage);
+
+ /**
+ * Get the image aspect ratio.
+ *
+ * @return the image aspect ratio
+ */
+ double getImageAspectRatio();
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/InvisibleResizableCompartmentFigure.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/InvisibleResizableCompartmentFigure.java
new file mode 100644
index 0000000000..00616374be
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/InvisibleResizableCompartmentFigure.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.gmf.runtime.diagram.ui.figures.ShapeCompartmentFigure;
+import org.eclipse.gmf.runtime.draw2d.ui.mapmode.IMapMode;
+
+/**
+ * A compartment figure not drawing the borders..
+ *
+ * @author cbrun
+ *
+ */
+public class InvisibleResizableCompartmentFigure extends ShapeCompartmentFigure {
+
+ /**
+ * Create a new compartment figure without borders.
+ *
+ * @param title
+ * compartment title.
+ * @param mode
+ * mapping mode.
+ */
+ public InvisibleResizableCompartmentFigure(final String title, final IMapMode mode) {
+ super(title, mode);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.Figure#paintBorder(org.eclipse.draw2d.Graphics)
+ */
+ @Override
+ protected void paintBorder(final Graphics graphics) {
+ /*
+ * we don't want to draw the borders.
+ */
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/LozengeFigure.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/LozengeFigure.java
new file mode 100644
index 0000000000..2b473638bd
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/LozengeFigure.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.Shape;
+import org.eclipse.draw2d.geometry.PointList;
+import org.eclipse.draw2d.geometry.Rectangle;
+
+import org.eclipse.sirius.diagram.ui.tools.internal.figure.TransparentFigureGraphicsModifier;
+
+/**
+ * Specific Figure to handle lozenge style.
+ *
+ * @author mporhel
+ *
+ */
+public class LozengeFigure extends Shape implements StyledFigure, ITransparentFigure {
+
+ private int viewpointAlpha = DEFAULT_ALPHA;
+
+ private boolean transparent;
+
+ /**
+ * Create a new lozenge figure with default values.
+ */
+ public LozengeFigure() {
+ }
+
+ /**
+ * Outlines the lozenge.
+ *
+ * @param graphics
+ * <code>Graphics</code> object that allows to fill the surface
+ */
+ @Override
+ protected void outlineShape(final Graphics graphics) {
+ final PointList pointList = getPointList();
+ graphics.drawPolygon(pointList);
+ }
+
+ /**
+ * Fills the Lozenge.
+ *
+ * @see org.eclipse.draw2d.Shape#fillShape(org.eclipse.draw2d.Graphics)
+ * @param graphics
+ * <code>Graphics</code> object that allows to draw to the
+ * surface
+ */
+ @Override
+ protected void fillShape(final Graphics graphics) {
+ TransparentFigureGraphicsModifier modifier = new TransparentFigureGraphicsModifier(this, graphics);
+ modifier.pushState();
+ graphics.fillPolygon(getPointList());
+ modifier.popState();
+ }
+
+ /**
+ * Computes the polygon points of the lozenge.
+ *
+ * @return PointList list of the points
+ */
+ protected PointList getPointList() {
+ final Rectangle r = new Rectangle();
+ final PointList pointList = new PointList();
+
+ r.x = bounds.x + getLineWidth() / 2;
+ r.y = bounds.y + getLineWidth() / 2;
+ r.width = bounds.width - getLineWidth();
+ r.height = bounds.height - getLineWidth();
+ pointList.removeAllPoints();
+ pointList.addPoint(r.x + r.width / 2, r.y);
+ pointList.addPoint(r.x + r.width, r.y + r.height / 2);
+ pointList.addPoint(r.x + r.width / 2, r.y + r.height);
+ pointList.addPoint(r.x, r.y + r.height / 2);
+
+ return pointList;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getSiriusAlpha() {
+ return viewpointAlpha;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isTransparent() {
+ return transparent;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setSiriusAlpha(int alpha) {
+ this.viewpointAlpha = alpha;
+
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setTransparent(boolean transparent) {
+ this.transparent = transparent;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/MouseAwareImageFigure.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/MouseAwareImageFigure.java
new file mode 100644
index 0000000000..9cb014fcca
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/MouseAwareImageFigure.java
@@ -0,0 +1,218 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.ImageFigure;
+import org.eclipse.draw2d.MouseEvent;
+import org.eclipse.draw2d.MouseMotionListener;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * A figure that shows an image that change on mouseExited and mouseEntered
+ * events. Note that it is the client's responsibility to dispose the given
+ * images. The image is resized to fit the client area size.
+ *
+ *
+ * @author ymortier
+ */
+public class MouseAwareImageFigure extends ImageFigure {
+
+ /** Left Top corner. */
+ private static final Point LEFT_TOP_CORNER = new Point(0, 0);
+
+ /** the image that is shown when the mouse is not on the figure. */
+ protected Image imageWOFocus;
+
+ /** the image that is shown when the mouse is on the figure. */
+ protected Image imageWFocus;
+
+ /** the size. */
+ private Dimension size;
+
+ /**
+ * Create a new {@link MouseAwareImageFigure}.
+ */
+ public MouseAwareImageFigure() {
+ super();
+ init();
+ }
+
+ /**
+ * Create a {@link MouseAwareImageFigure} with the specified image that is
+ * shwon when the mouse is not on the figure.
+ *
+ * @param imageWOFocus
+ * the image that is shown when the mouse is not on the image.
+ */
+ public MouseAwareImageFigure(final Image imageWOFocus) {
+ super(imageWOFocus);
+ this.imageWOFocus = imageWOFocus;
+ init();
+ }
+
+ /**
+ * Create a {@link MouseAwareImageFigure} with the specified images.
+ *
+ * @param imageWOFocus
+ * the image that is shown when the mouse is not on the image.
+ * @param imageWFocus
+ * the image that is shown when the mouse is on the image.
+ */
+ public MouseAwareImageFigure(final Image imageWOFocus, final Image imageWFocus) {
+ super(imageWOFocus);
+ this.imageWOFocus = imageWOFocus;
+ this.imageWFocus = imageWFocus;
+ init();
+ }
+
+ /**
+ * Initialize the figure.
+ */
+ private void init() {
+ this.size = new Dimension();
+ this.addMouseMotionListener(new ToggleImage());
+ }
+
+ /**
+ * Define the image that is shown when the mouse is on the figure.
+ *
+ * @param imageWFocus
+ * the image that is shown when the mouse is on the figure.
+ */
+ public void setImageWFocus(final Image imageWFocus) {
+ this.imageWFocus = imageWFocus;
+ }
+
+ /**
+ * Return the image that is shown when the mouse is on the figure.
+ *
+ * @return the image that is shown when the mouse is on the figure.
+ */
+ public Image getImageWFocus() {
+ return imageWFocus;
+ }
+
+ /**
+ * Define the image that is shown when the mouse is not on the figure.
+ *
+ * @param imageWOFocus
+ * the image that is shown when the mouse is not on the figure.
+ */
+ public void setImageWOFocus(final Image imageWOFocus) {
+ this.setImage(imageWOFocus);
+ this.imageWOFocus = imageWOFocus;
+ }
+
+ /**
+ * Return the image that is shown when the mouse is not on the figure.
+ *
+ * @return the image that is shown when the mouse is not on the figure.
+ */
+ public Image getImageWOFocus() {
+ return imageWOFocus;
+ }
+
+ /**
+ * This class toggle the image that is shown when the mouse entered or
+ * exited the figure.
+ *
+ * @author ymortier
+ */
+ private class ToggleImage implements MouseMotionListener {
+
+ /**
+ * @see MouseMotionListener#mouseDragged(MouseEvent)
+ */
+ public void mouseDragged(final MouseEvent me) {
+ // do nothing.
+ }
+
+ /**
+ * @see MouseMotionListener#mouseEntered(MouseEvent)
+ */
+ public void mouseEntered(final MouseEvent me) {
+ if (imageWFocus != null) {
+ MouseAwareImageFigure.this.setImage(imageWFocus);
+ }
+ }
+
+ /**
+ * @see MouseMotionListener#mouseExited(MouseEvent)
+ */
+ public void mouseExited(final MouseEvent me) {
+ MouseAwareImageFigure.this.setImage(imageWOFocus);
+ }
+
+ /**
+ * @see MouseMotionListener#mouseHover(MouseEvent)
+ */
+ public void mouseHover(final MouseEvent me) {
+ // do nothing.
+ }
+
+ /**
+ * @see MouseMotionListener#mouseMoved(MouseEvent)
+ */
+ public void mouseMoved(final MouseEvent me) {
+ // do nothing.
+ }
+
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.ImageFigure#paintFigure(org.eclipse.draw2d.Graphics)
+ */
+ @Override
+ protected void paintFigure(final Graphics graphics) {
+ // super.paintFigure(graphics);
+ graphics.drawImage(this.getImage(), new Rectangle(LEFT_TOP_CORNER, super.getPreferredSize(0, 0)), new Rectangle(this.getLocation(), this.getSize()));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.Figure#setSize(int, int)
+ */
+ @Override
+ public void setSize(final int w, final int h) {
+ this.size.width = w;
+ this.size.height = h;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.Figure#getBounds()
+ */
+ @Override
+ public Rectangle getBounds() {
+ final Rectangle realBounds = new Rectangle(super.getBounds());
+ realBounds.setSize(this.size);
+ return realBounds;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.ImageFigure#getPreferredSize(int, int)
+ */
+ @Override
+ public Dimension getPreferredSize(final int hint, final int hint2) {
+ return this.size;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/ODesignEllipseFigure.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/ODesignEllipseFigure.java
new file mode 100644
index 0000000000..443c8ade1c
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/ODesignEllipseFigure.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.geometry.Rectangle;
+
+import org.eclipse.sirius.diagram.ui.tools.internal.figure.TransparentFigureGraphicsModifier;
+
+/**
+ * Specific Figure to handle ellipse style.
+ *
+ * @author mporhel
+ *
+ */
+public class ODesignEllipseFigure extends AbstractTransparentEllipse {
+
+ /**
+ * Outlines the Ellipse.
+ *
+ * @Override
+ * @see org.eclipse.draw2d.Ellipse#outlineShape(org.eclipse.draw2d.Graphics)
+ * @param graphics
+ * <code>Graphics</code> object that allows to draw to the
+ * surface
+ */
+ @Override
+ protected void outlineShape(final Graphics graphics) {
+ final Rectangle r = Rectangle.SINGLETON;
+ r.setBounds(getDrawBounds());
+ r.width--;
+ r.height--;
+ r.shrink((lineWidth - 1) / 2, (lineWidth - 1) / 2);
+ graphics.drawOval(r);
+ }
+
+ /**
+ * Fills the Ellipse.
+ *
+ * @Override
+ * @see org.eclipse.draw2d.Ellipse#fillShape(org.eclipse.draw2d.Graphics)
+ * @param graphics
+ * <code>Graphics</code> object that allows to draw to the
+ * surface
+ */
+ @Override
+ protected void fillShape(final Graphics graphics) {
+ TransparentFigureGraphicsModifier modifier = new TransparentFigureGraphicsModifier(this, graphics);
+ modifier.pushState();
+ graphics.fillOval(getDrawBounds());
+ modifier.popState();
+ }
+
+ /**
+ * Computes the rectangle containing the Ellipse.
+ *
+ * @Override
+ * @see org.eclipse.draw2d.Ellipse#fillShape(org.eclipse.draw2d.Graphics)
+ * @return a rectangle which can contains the ellipse and its border
+ */
+ protected Rectangle getDrawBounds() {
+ final Rectangle r = new Rectangle(super.getBounds());
+ r.x = bounds.x + getLineWidth() / 2;
+ r.y = bounds.y + getLineWidth() / 2;
+ r.width = bounds.width - getLineWidth();
+ r.height = bounds.height - getLineWidth();
+ return r;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/OneLineMarginBorder.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/OneLineMarginBorder.java
new file mode 100644
index 0000000000..d1ec721aca
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/OneLineMarginBorder.java
@@ -0,0 +1,170 @@
+/*******************************************************************************
+ * Copyright (c) 2013 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.PositionConstants;
+import org.eclipse.draw2d.geometry.Insets;
+import org.eclipse.gmf.runtime.draw2d.ui.figures.OneLineBorder;
+import org.eclipse.gmf.runtime.draw2d.ui.mapmode.MapModeUtil;
+
+/**
+ * Specific {@link OneLineBorder} with dash capabilities, two more supported
+ * positions ({@link PositionConstants#MIDDLE} and
+ * {@link PositionConstants#CENTER}) and margin capabilities.
+ *
+ * @author mporhel
+ */
+public class OneLineMarginBorder extends OneLineBorder {
+
+ private int[] dash;
+
+ private Insets margin = new Insets();
+
+ /**
+ * Constructor.
+ *
+ * @param position
+ * The position to set.
+ */
+ public OneLineMarginBorder(int position) {
+ super();
+ setPosition(position);
+ }
+
+ /**
+ * Paints the border based on the inputs given.
+ *
+ * @param figure
+ * <code>IFigure</code> for which this is the border.
+ * @param graphics
+ * <code>Graphics</code> handle for drawing the border.
+ * @param insets
+ * Space to be taken up by this border.
+ */
+ @Override
+ public void paint(IFigure figure, Graphics graphics, Insets insets) {
+ graphics.setLineDash(dash);
+
+ super.paint(figure, graphics, insets);
+
+ int one = MapModeUtil.getMapMode(figure).DPtoLP(1);
+ int widthInDP = getWidth() / one;
+ int halfWidthInLP = MapModeUtil.getMapMode(figure).DPtoLP(widthInDP / 2);
+
+ switch (getPosition()) {
+ case PositionConstants.MIDDLE:
+ tempRect.y += halfWidthInLP;
+ tempRect.height -= getWidth();
+ graphics.drawLine(tempRect.getTop(), tempRect.getBottom());
+ break;
+ case PositionConstants.CENTER:
+ tempRect.x += halfWidthInLP;
+ tempRect.width -= getWidth();
+ graphics.drawLine(tempRect.getLeft(), tempRect.getRight());
+ break;
+ default:
+ break;
+ }
+ }
+
+ @Override
+ public Insets getInsets(IFigure figure) {
+ Insets borderInsets;
+
+ switch (getPosition()) {
+ case PositionConstants.TOP:
+ borderInsets = new Insets(getWidth(), 0, 0, 0);
+ break;
+ case PositionConstants.LEFT:
+ borderInsets = new Insets(0, getWidth(), 0, 0);
+ break;
+ case PositionConstants.BOTTOM:
+ borderInsets = new Insets(0, 0, getWidth(), 0);
+ break;
+ case PositionConstants.RIGHT:
+ borderInsets = new Insets(0, 0, 0, getWidth());
+ break;
+ case PositionConstants.MIDDLE:
+ borderInsets = new Insets(getWidth() / 2, 0, getWidth() / 2, 0);
+ break;
+ case PositionConstants.CENTER:
+ borderInsets = new Insets(0, getWidth() / 2, 0, getWidth() / 2);
+ break;
+ default:
+ borderInsets = IFigure.NO_INSETS;
+ break;
+ }
+
+ Insets globalInsets = new Insets();
+ globalInsets.add(borderInsets);
+ globalInsets.add(margin);
+
+ return globalInsets;
+ }
+
+ /**
+ * Sets the dash pattern when the custom line style ( is in use.
+ *
+ * @param dashPattern
+ * the pixel pattern
+ */
+ public void setLineDash(int[] dashPattern) {
+ int[] copy = null;
+ if (dashPattern != null) {
+ copy = new int[dashPattern.length];
+ System.arraycopy(dashPattern, 0, copy, 0, dashPattern.length);
+ }
+ this.dash = copy;
+ }
+
+ /**
+ * Set the extra padding to add to the border width.
+ *
+ * @param insets
+ * The blank padding Insets for the border
+ */
+ public void setMargin(Insets insets) {
+ if (margin != null) {
+ margin = insets;
+ } else {
+ margin = new Insets();
+ }
+ }
+
+ /**
+ * Set the extra padding to add to the border width.
+ *
+ * @param t
+ * Top padding
+ * @param l
+ * Left padding
+ * @param b
+ * Bottom padding
+ * @param r
+ * Right padding
+ */
+ public void setMargin(int t, int l, int b, int r) {
+ setMargin(new Insets(t, l, b, r));
+ }
+
+ /**
+ * Set the extra padding to add to the border width.
+ *
+ * @param allsides
+ * Padding size for all sides of the border.
+ * @since 2.0
+ */
+ public void setMargin(int allsides) {
+ setMargin(new Insets(allsides));
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/ParallelogramFigure.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/ParallelogramFigure.java
new file mode 100644
index 0000000000..7ab17389c1
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/ParallelogramFigure.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2008 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.PointList;
+import org.eclipse.draw2d.geometry.Rectangle;
+
+/**
+ * A parallelogram figure.
+ *
+ * @author cbrun
+ *
+ * This Figure represents a Parallelogram Figure
+ */
+public class ParallelogramFigure extends AbstractGeoShapePolygonFigure {
+
+ /** the offset. */
+ protected static final int JITTER = 20;
+
+ /**
+ * Constructor - Creates a Parallelogram with a given Default size.
+ */
+ public ParallelogramFigure() {
+ super(10, 10, 2);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.figure.AbstractGeoShapePolygonFigure#calculatePoints(org.eclipse.draw2d.geometry.Rectangle)
+ */
+ @Override
+ protected PointList calculatePoints(final Rectangle rect) {
+
+ final PointList points = new PointList();
+ final Point p1 = new Point(rect.x + JITTER, rect.y);
+ final Point p2 = new Point(rect.x + rect.width - 1, rect.y);
+
+ final Point p3 = new Point(rect.x + rect.width - JITTER, rect.y + rect.height - 1);
+ final Point p4 = new Point(rect.x, rect.y + rect.height - 1);
+
+ points.addPoint(p1);
+ points.addPoint(p2);
+ points.addPoint(p3);
+ points.addPoint(p4);
+ points.addPoint(p1);
+
+ return points;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/PolygoneAndPolylineDecoraction.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/PolygoneAndPolylineDecoraction.java
new file mode 100644
index 0000000000..9d5d43e42b
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/PolygoneAndPolylineDecoraction.java
@@ -0,0 +1,160 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.PolygonDecoration;
+import org.eclipse.draw2d.PolylineDecoration;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.PointList;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.swt.graphics.Color;
+
+/**
+ * A rotatable, polygon shaped with arrow decoration.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ *
+ */
+public class PolygoneAndPolylineDecoraction extends PolygonDecoration {
+
+ /** A triangle template. */
+ public static final PointList TRIANGLE_TIP = new PointList();
+
+ static {
+ TRIANGLE_TIP.addPoint(-3, 1);
+ TRIANGLE_TIP.addPoint(-2, 0);
+ TRIANGLE_TIP.addPoint(-3, -1);
+ }
+
+ PolylineDecoration polylineDecoration = new PolylineDecoration();
+
+ /**
+ * Constructs a PolygoneAndPolylineDecoraction.
+ */
+ public PolygoneAndPolylineDecoraction() {
+ super();
+ polylineDecoration.setTemplate(TRIANGLE_TIP);
+ }
+
+ /**
+ * Sets the PolylineDecoration's point template. This template is an outline
+ * of the PolylineDecoration's region. (The default value is TRIANGLE_TIP
+ * which is a triangle whose tip is pointing to the right).
+ *
+ * @param pl
+ * the template
+ */
+ public void setPolylineTemplate(PointList pl) {
+ polylineDecoration.setTemplate(pl);
+
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.Polygon#outlineShape(org.eclipse.draw2d.Graphics)
+ */
+ @Override
+ protected void outlineShape(Graphics g) {
+ super.outlineShape(g);
+ g.drawPolyline(polylineDecoration.getPoints());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.Polyline#getBounds()
+ */
+ @Override
+ public Rectangle getBounds() {
+ if (bounds == null) {
+ if (polylineDecoration != null) {
+ bounds = getPoints().getBounds().getUnion(polylineDecoration.getPoints().getBounds()).getExpanded(lineWidth / 2, lineWidth / 2);
+ } else {
+ // In case of constructor the first geBounds is called before
+ // the polylineDecoration creation.
+ bounds = super.getBounds();
+ }
+ }
+ return bounds;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.PolygonDecoration#setRotation(double)
+ */
+ @Override
+ public void setRotation(double angle) {
+ super.setRotation(angle);
+ polylineDecoration.setRotation(angle);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.PolygonDecoration#setScale(double, double)
+ */
+ @Override
+ public void setScale(double x, double y) {
+ super.setScale(x, y);
+ if (polylineDecoration != null) {
+ // The polylineDecoration can be null (at least during the
+ // constructor)
+ polylineDecoration.setScale(x, y);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.Figure#setBackgroundColor(org.eclipse.swt.graphics.Color)
+ */
+ @Override
+ public void setBackgroundColor(Color bg) {
+ super.setBackgroundColor(bg);
+ polylineDecoration.setBackgroundColor(bg);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.Figure#setForegroundColor(org.eclipse.swt.graphics.Color)
+ */
+ @Override
+ public void setForegroundColor(Color fg) {
+ super.setForegroundColor(fg);
+ polylineDecoration.setForegroundColor(fg);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.Polyline#setLineWidth(int)
+ */
+ @Override
+ public void setLineWidth(int w) {
+ super.setLineWidth(w);
+ polylineDecoration.setLineWidth(w);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.PolygonDecoration#setLocation(org.eclipse.draw2d.geometry.Point)
+ */
+ @Override
+ public void setLocation(Point p) {
+ super.setLocation(p);
+ polylineDecoration.setLocation(p);
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/SVGFigure.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/SVGFigure.java
new file mode 100644
index 0000000000..846c38e57c
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/SVGFigure.java
@@ -0,0 +1,326 @@
+/**
+ * Copyright (c) 2008 Borland Software Corporation
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Dmitry Stadnik - initial API and implementation
+ * Obeo - Adaptations.
+ */
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import java.awt.RenderingHints;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.WritableRaster;
+import java.io.IOException;
+import java.util.WeakHashMap;
+
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+
+import org.apache.batik.bridge.BridgeContext;
+import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
+import org.apache.batik.util.XMLResourceDescriptor;
+import org.eclipse.draw2d.Figure;
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Device;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.PaletteData;
+import org.eclipse.swt.widgets.Display;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import org.eclipse.sirius.diagram.part.SiriusDiagramEditorPlugin;
+import org.eclipse.sirius.diagram.tools.internal.figure.svg.InferringNamespaceContext;
+import org.eclipse.sirius.diagram.tools.internal.figure.svg.SVGUtils;
+import org.eclipse.sirius.diagram.tools.internal.figure.svg.SimpleImageTranscoder;
+
+//CHECKSTYLE:OFF
+public class SVGFigure extends Figure {
+
+ private String uri;
+
+ private boolean failedToLoadDocument, specifyCanvasWidth = true, specifyCanvasHeight = true;
+
+ private SimpleImageTranscoder transcoder;
+
+ protected static WeakHashMap<String, Document> documentsMap = new WeakHashMap<String, Document>();
+
+ public final String getURI() {
+ return uri;
+ }
+
+ public final void setURI(String uri) {
+ setURI(uri, true);
+ }
+
+ public void setURI(String uri, boolean loadOnDemand) {
+ this.uri = uri;
+ transcoder = null;
+ failedToLoadDocument = false;
+ if (loadOnDemand) {
+ loadDocument();
+ }
+ }
+
+ private void loadDocument() {
+ transcoder = null;
+ failedToLoadDocument = true;
+ if (uri == null) {
+ return;
+ }
+ String parser = XMLResourceDescriptor.getXMLParserClassName();
+ SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory(parser);
+ try {
+ String documentKey = getDocumentKey();
+ Document document;
+ if (documentsMap.containsKey(documentKey))
+ document = documentsMap.get(documentKey);
+ else {
+ document = factory.createDocument(uri);
+ documentsMap.put(documentKey, document);
+ }
+ transcoder = new SimpleImageTranscoder(document);
+ failedToLoadDocument = false;
+ } catch (IOException e) {
+ SiriusDiagramEditorPlugin.getInstance().logError("Error loading SVG file", e);
+ }
+ }
+
+ protected final Document getDocument() {
+ if (failedToLoadDocument) {
+ return null;
+ }
+ if (transcoder == null) {
+ loadDocument();
+ }
+ return transcoder == null ? null : transcoder.getDocument();
+ }
+
+ /**
+ * The key used to store the document.
+ *
+ * @return the key.
+ */
+ protected String getDocumentKey() {
+ return uri;
+ }
+
+ /**
+ * Returns true if document was loaded without errors; tries to load
+ * document if needed.
+ */
+ public final boolean checkContentAvailable() {
+ return getDocument() != null;
+ }
+
+ private XPath getXPath() {
+ XPath xpath = XPathFactory.newInstance().newXPath();
+ xpath.setNamespaceContext(new InferringNamespaceContext(getDocument().getDocumentElement()));
+ return xpath;
+ }
+
+ /**
+ * Executes XPath query over the SVG document.
+ */
+ protected final NodeList getNodes(String query) {
+ Document document = getDocument();
+ if (document != null) {
+ try {
+ return (NodeList) getXPath().evaluate(query, document, XPathConstants.NODESET);
+ } catch (XPathExpressionException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Reads color value from the document.
+ */
+ protected Color getColor(Element element, String attributeName) {
+ if (getDocument() == null || getDocument() != element.getOwnerDocument()) {
+ return null;
+ }
+ Color color = null;
+ // Make sure that CSSEngine is available.
+ BridgeContext ctx = transcoder.initCSSEngine();
+ try {
+ color = SVGUtils.toSWTColor(element, attributeName);
+ } finally {
+ if (ctx != null) {
+ ctx.dispose();
+ }
+ }
+ return color;
+ }
+
+ @Override
+ protected void paintFigure(Graphics graphics) {
+ super.paintFigure(graphics);
+ Document document = getDocument();
+ if (document == null) {
+ return;
+ }
+ Image image = null;
+ try {
+ Rectangle r = getClientArea();
+ transcoder.setCanvasSize(specifyCanvasWidth ? r.width : -1, specifyCanvasHeight ? r.height : -1);
+ updateRenderingHints(graphics);
+ BufferedImage awtImage = transcoder.getBufferedImage();
+ if (awtImage != null) {
+ image = toSWT(Display.getCurrent(), awtImage);
+ graphics.drawImage(image, r.x, r.y);
+ }
+ } finally {
+ if (image != null) {
+ image.dispose();
+ }
+ }
+ }
+
+ protected void updateRenderingHints(Graphics graphics) {
+ {
+ int aa = SWT.DEFAULT;
+ try {
+ aa = graphics.getAntialias();
+ } catch (Exception e) {
+ // not supported
+ }
+ Object aaHint;
+ if (aa == SWT.ON) {
+ aaHint = RenderingHints.VALUE_ANTIALIAS_ON;
+ } else if (aa == SWT.OFF) {
+ aaHint = RenderingHints.VALUE_ANTIALIAS_OFF;
+ } else {
+ aaHint = RenderingHints.VALUE_ANTIALIAS_DEFAULT;
+ }
+ if (transcoder.getRenderingHints().get(RenderingHints.KEY_ANTIALIASING) != aaHint) {
+ transcoder.getRenderingHints().put(RenderingHints.KEY_ANTIALIASING, aaHint);
+ transcoder.contentChanged();
+ }
+ }
+ {
+ int aa = SWT.DEFAULT;
+ try {
+ aa = graphics.getTextAntialias();
+ } catch (Exception e) {
+ // not supported
+ }
+ Object aaHint;
+ if (aa == SWT.ON) {
+ aaHint = RenderingHints.VALUE_TEXT_ANTIALIAS_ON;
+ } else if (aa == SWT.OFF) {
+ aaHint = RenderingHints.VALUE_TEXT_ANTIALIAS_OFF;
+ } else {
+ aaHint = RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT;
+ }
+ if (transcoder.getRenderingHints().get(RenderingHints.KEY_TEXT_ANTIALIASING) != aaHint) {
+ transcoder.getRenderingHints().put(RenderingHints.KEY_TEXT_ANTIALIASING, aaHint);
+ transcoder.contentChanged();
+ }
+ }
+ }
+
+ /**
+ * Converts an AWT based buffered image into an SWT <code>Image</code>. This
+ * will always return an <code>Image</code> that has 24 bit depth regardless
+ * of the type of AWT buffered image that is passed into the method.
+ *
+ * @param awtImage
+ * the {@link java.awt.image.BufferedImage} to be converted to an
+ * <code>Image</code>
+ * @return an <code>Image</code> that represents the same image data as the
+ * AWT <code>BufferedImage</code> type.
+ */
+ protected static org.eclipse.swt.graphics.Image toSWT(Device device, BufferedImage awtImage) {
+ // We can force bitdepth to be 24 bit because BufferedImage getRGB
+ // allows us to always retrieve 24 bit data regardless of source color
+ // depth.
+ PaletteData palette = new PaletteData(0xFF0000, 0xFF00, 0xFF);
+ ImageData swtImageData = new ImageData(awtImage.getWidth(), awtImage.getHeight(), 24, palette);
+ // Ensure scansize is aligned on 32 bit.
+ int scansize = (((awtImage.getWidth() * 3) + 3) * 4) / 4;
+ WritableRaster alphaRaster = awtImage.getAlphaRaster();
+ byte[] alphaBytes = new byte[awtImage.getWidth()];
+ for (int y = 0; y < awtImage.getHeight(); y++) {
+ int[] buff = awtImage.getRGB(0, y, awtImage.getWidth(), 1, null, 0, scansize);
+ swtImageData.setPixels(0, y, awtImage.getWidth(), buff, 0);
+ if (alphaRaster != null) {
+ int[] alpha = alphaRaster.getPixels(0, y, awtImage.getWidth(), 1, (int[]) null);
+ for (int i = 0; i < awtImage.getWidth(); i++) {
+ alphaBytes[i] = (byte) alpha[i];
+ }
+ swtImageData.setAlphas(0, y, awtImage.getWidth(), alphaBytes, 0);
+ }
+ }
+ return new org.eclipse.swt.graphics.Image(device, swtImageData);
+ }
+
+ public final Rectangle2D getAreaOfInterest() {
+ getDocument();
+ return transcoder == null ? null : transcoder.getCanvasAreaOfInterest();
+ }
+
+ public void setAreaOfInterest(Rectangle2D value) {
+ getDocument();
+ if (transcoder != null) {
+ transcoder.setCanvasAreaOfInterest(value);
+ }
+ repaint();
+ }
+
+ public final boolean isSpecifyCanvasWidth() {
+ return specifyCanvasWidth;
+ }
+
+ public void setSpecifyCanvasWidth(boolean specifyCanvasWidth) {
+ this.specifyCanvasWidth = specifyCanvasWidth;
+ contentChanged();
+ }
+
+ public final boolean isSpecifyCanvasHeight() {
+ return specifyCanvasHeight;
+ }
+
+ public void setSpecifyCanvasHeight(boolean specifyCanvasHeight) {
+ this.specifyCanvasHeight = specifyCanvasHeight;
+ contentChanged();
+ }
+
+ /**
+ * Should be called when SVG document has been changed. It will be
+ * re-rendered and figure will be repainted.
+ */
+ public void contentChanged() {
+ getDocument();
+ if (transcoder != null) {
+ transcoder.contentChanged();
+ }
+ repaint();
+ }
+
+ protected SimpleImageTranscoder getTranscoder() {
+ return transcoder;
+ }
+
+ protected boolean getSpecifyCanvasWidth() {
+ return specifyCanvasWidth;
+ }
+
+ protected boolean getSpecifyCanvasHeight() {
+ return specifyCanvasHeight;
+ }
+ // CHECKSTYLE:ON
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/SVGWorkspaceImageFigure.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/SVGWorkspaceImageFigure.java
new file mode 100644
index 0000000000..3cf30b9e99
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/SVGWorkspaceImageFigure.java
@@ -0,0 +1,273 @@
+/*******************************************************************************
+ * Copyright (c) 2011 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import java.io.File;
+
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.draw2d.XYLayout;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.swt.graphics.Image;
+
+import org.eclipse.sirius.common.tools.api.resource.FileProvider;
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.common.tools.api.util.Options;
+import org.eclipse.sirius.ContainerStyle;
+import org.eclipse.sirius.FlatContainerStyle;
+import org.eclipse.sirius.WorkspaceImage;
+
+/**
+ * The {@link SVGWorkspaceImageFigure} is useful to load svg images using a
+ * cache. The image can be in the workspace, or if it's not found in the
+ * workspace it will be looked up in the plug-ins.
+ *
+ * @author mporhel
+ *
+ */
+public class SVGWorkspaceImageFigure extends AbstractCachedSVGFigure implements IWorkspaceImageFigure {
+
+ private double imageAspectRatio = 1.0;
+
+ private boolean keepAspectRatio = true;
+
+ /**
+ * Create a new {@link SVGWorkspaceImageFigure}.
+ */
+ public SVGWorkspaceImageFigure() { // final Image flyWeightImage) {
+ this.setLayoutManager(new XYLayout());
+ minSize = new Dimension(0, 0);
+ }
+
+ /**
+ * Create the {@link SVGWorkspaceImageFigure} from a {@link WorkspaceImage}
+ * instance.
+ *
+ * @param image
+ * {@link SVGWorkspaceImageFigure} specification.
+ * @return new Figure.
+ */
+ public static SVGWorkspaceImageFigure createImageFigure(final WorkspaceImage image) {
+ SVGWorkspaceImageFigure fig = new SVGWorkspaceImageFigure();
+ fig.refreshFigure(image);
+ return fig;
+ }
+
+ /**
+ * Create the {@link SVGWorkspaceImageFigure} from a {@link ContainerStyle}
+ * instance.
+ *
+ * @param containerStyle
+ * {@link ContainerStyle} specification.
+ * @return new Figure.
+ */
+ public static SVGWorkspaceImageFigure createImageFigure(final ContainerStyle containerStyle) {
+ if (containerStyle instanceof FlatContainerStyle) {
+ FlatContainerStyle style = (FlatContainerStyle) containerStyle;
+ SVGWorkspaceImageFigure fig = new SVGWorkspaceImageFigure();
+ fig.refreshFigure(style);
+ return fig;
+ }
+ // TODO handle other styles..
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.Figure#setSize(int, int)
+ */
+ @Override
+ public void setSize(final int w, final int h) {
+ if (keepAspectRatio) {
+ final int newHeight = (int) (w / imageAspectRatio);
+ super.setSize(w, newHeight);
+ } else {
+ super.setSize(w, h);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.Figure#setMaximumSize(org.eclipse.draw2d.geometry.Dimension)
+ */
+ @Override
+ public void setMaximumSize(final Dimension d) {
+ super.setMaximumSize(this.getSize());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.Figure#setMinimumSize(org.eclipse.draw2d.geometry.Dimension)
+ */
+ @Override
+ public void setMinimumSize(final Dimension d) {
+ super.setMinimumSize(this.getSize());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.Figure#setPreferredSize(org.eclipse.draw2d.geometry.Dimension)
+ */
+ @Override
+ public void setPreferredSize(final Dimension size) {
+ super.setPreferredSize(this.getSize());
+ }
+
+ /**
+ * Get the image aspect ratio.
+ *
+ * @return the image aspect ratio
+ */
+ public double getImageAspectRatio() {
+ return imageAspectRatio;
+ }
+
+ /**
+ * Refreshes the figure.
+ *
+ * @param containerStyle
+ * the style of the container
+ */
+ public void refreshFigure(final ContainerStyle containerStyle) {
+ if (containerStyle instanceof FlatContainerStyle) {
+ final FlatContainerStyle style = (FlatContainerStyle) containerStyle;
+ boolean updated = this.updateImageURI(style.getBackgroundStyle().getName());
+ if (updated) {
+ this.contentChanged();
+ }
+ } else if (containerStyle instanceof WorkspaceImage) {
+ refreshFigure((WorkspaceImage) containerStyle);
+ } else {
+ this.setURI(null);
+ }
+ }
+
+ /**
+ * refresh the figure.
+ *
+ * @param workspaceImage
+ * the image associated to the figure
+ */
+ public void refreshFigure(final WorkspaceImage workspaceImage) {
+ if (workspaceImage != null) {
+ boolean updated = this.updateImageURI(workspaceImage.getWorkspacePath());
+ if (updated) {
+ this.contentChanged();
+ int canvasHeight = getTranscoder().getCanvasHeight();
+ int canvasWidth = getTranscoder().getCanvasWidth();
+
+ if (canvasHeight == -1 || canvasWidth == -1) {
+ int width = getTranscoder().getBufferedImage().getWidth();
+ int height = getTranscoder().getBufferedImage().getHeight();
+ imageAspectRatio = (double) width / (double) height;
+ } else {
+ imageAspectRatio = (double) canvasWidth / (double) canvasHeight;
+ }
+ }
+ } else {
+ this.setURI(null);
+ }
+ }
+
+ private boolean updateImageURI(String workspacePath) {
+ if (workspacePath != null) {
+ Option<String> existingImageUri = getImageUri(workspacePath, false);
+ if (existingImageUri.some()) {
+ setURI(existingImageUri.get());
+ } else {
+ setURI(getImageNotFoundURI());
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Return an optional uri as used in the document key to read svg files.
+ *
+ * @param workspacePath
+ * the workspace path of the file.
+ * @param force
+ * true to avoid to check that the file exists and is readble.
+ * @return an optional system uri.
+ */
+ private static Option<String> getImageUri(String workspacePath, boolean force) {
+ final File imageFile = FileProvider.getDefault().getFile(new Path(workspacePath));
+ if (imageFile != null && (force || imageFile.exists() && imageFile.canRead())) {
+ return Options.newSome(imageFile.toURI().toString());
+ }
+ Option<String> nonExistingFile = Options.newNone();
+ if (force) {
+ // Deleted file : retrieve the key.
+ nonExistingFile = Options.newSome(ResourcesPlugin.getWorkspace().getRoot().getLocationURI().toString() + workspacePath);
+ }
+
+ return nonExistingFile;
+ }
+
+ /**
+ * Compute a key for this {@link SVGWorkspaceImageFigure}. This key is used
+ * to store in cache the corresponding
+ * {@link org.eclipse.swt.graphics.Image}.
+ *
+ * {@inheritDoc}
+ *
+ * @return The key corresponding to this SVGWorkspaceImageFigure.
+ */
+ protected String getKey() {
+ StringBuffer result = new StringBuffer();
+ result.append(getDocumentKey());
+ result.append(SEPARATOR);
+ result.append(getSiriusAlpha());
+ result.append(SEPARATOR);
+ return result.toString();
+ }
+
+ /**
+ * Get an {@link Image} instance. The image will be stored in a cache.
+ *
+ * @param path
+ * the path is a "/project/file" path, if it's not found in the
+ * workspace, the class will look for the file in the plug-ins.
+ * @return an image instance given the path.
+ */
+ public static Image flyWeightImage(String path) {
+ SVGWorkspaceImageFigure fig = new SVGWorkspaceImageFigure();
+ fig.updateImageURI(path);
+ fig.contentChanged();
+ return fig.getCachedImage(fig.getKey(), new Rectangle(0, 0, -1, -1), null);
+ }
+
+ /**
+ * Remove all entries whose key begins with the given key. Remove from the
+ * document map, the entries with the given keys to force to re-read the
+ * file.
+ *
+ * @param workspacePath
+ * the modified or deleted image file path.
+ * @return an option with the document uri used as key for the svg file if a
+ * corresponding element was removed.
+ */
+ public static Option<String> removeFromCache(String workspacePath) {
+ Option<String> imageUri = getImageUri(workspacePath, true);
+ if (imageUri.some()) {
+ if (doRemoveFromCache(imageUri.get())) {
+ return imageUri;
+ }
+ }
+ return Options.newNone();
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/SiriusWrapLabel.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/SiriusWrapLabel.java
new file mode 100644
index 0000000000..fe3bcc44dc
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/SiriusWrapLabel.java
@@ -0,0 +1,1774 @@
+/******************************************************************************
+ * Copyright (c) 2002, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Obeo - Duplication to keep the same behavior as GMF 2.0.1
+ ****************************************************************************/
+//CHECKSTYLE:OFF
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import org.eclipse.draw2d.ColorConstants;
+import org.eclipse.draw2d.Figure;
+import org.eclipse.draw2d.FigureUtilities;
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.LayoutManager;
+import org.eclipse.draw2d.PositionConstants;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Insets;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gmf.runtime.draw2d.ui.internal.mapmode.IMapModeHolder;
+import org.eclipse.gmf.runtime.draw2d.ui.mapmode.IMapMode;
+import org.eclipse.gmf.runtime.draw2d.ui.mapmode.MapModeUtil;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontMetrics;
+import org.eclipse.swt.graphics.Image;
+
+import com.ibm.icu.text.BreakIterator;
+import com.ibm.icu.util.StringTokenizer;
+
+/**
+ * An extended label that has the following extra features:
+ *
+ * 1- It is capable of showing selection and focus feedback (primary or
+ * secondary) 2- It is capable of optionally underlining the label's text 3- It
+ * is capable of wrapping the label's text at a given width with a given
+ * alignment 4- It is capable of supporting multiple label icons (temporary
+ * feature)
+ *
+ * This class was originally deriving off Draw2d's <code>Label</code> class but
+ * with the introduction of the auto-wrapping feature, a copy had to be made
+ * overriding was not straightforward. Hopefully, this extended version can be
+ * pushed to opensource
+ *
+ * <p>
+ * Code taken from Eclipse reference bugzilla #98820
+ *
+ * <p>
+ * Since GMF 2.1, there is a lot of refactoring and regresion (See
+ * https://bugs.eclipse.org/bugs/show_bug.cgi?id=274859). So to keep
+ * compatibility we duplicate the class
+ * org.eclipse.gmf.runtime.draw2d.ui.figures.WrapLabel into SiriusWrapLabel
+ * to keep the same behavior as GMF 2.0.1 There is only a little change in
+ * paintText figure (see javadoc for more details).
+ *
+ * @author melaasar
+ */
+@SuppressWarnings({ "rawtypes", "unchecked", "restriction" })
+public class SiriusWrapLabel extends Figure implements PositionConstants {
+
+ private static final String _ellipse = "..."; //$NON-NLS-1$
+
+ private static final Dimension EMPTY_DIMENSION = new Dimension(0, 0);
+
+ private static final Map mapModeConstantsMap = new WeakHashMap();
+
+ private static class MapModeConstants {
+
+ private static final int MAX_IMAGE_INFO = 12;
+
+ public final WeakReference mapModeRef;
+
+ public final int nDPtoLP_3;
+
+ public final int nDPtoLP_2;
+
+ public final int nDPtoLP_0;
+
+ public final Dimension dimension_nDPtoLP_0;
+
+ public final WeakHashMap fontToEllipseTextSize = new WeakHashMap();
+
+ public final SingleIconInfo[] singleIconInfos = new SingleIconInfo[MAX_IMAGE_INFO];
+
+ public MapModeConstants(IMapMode mapMode) {
+ this.mapModeRef = new WeakReference(mapMode);
+ nDPtoLP_2 = mapMode.DPtoLP(2);
+ nDPtoLP_3 = mapMode.DPtoLP(3);
+ nDPtoLP_0 = mapMode.DPtoLP(0);
+ dimension_nDPtoLP_0 = new Dimension(nDPtoLP_0, nDPtoLP_0);
+ }
+
+ public Dimension getEllipseTextSize(Font f) {
+ Dimension d = (Dimension) fontToEllipseTextSize.get(f);
+ if (d == null) {
+ IMapMode mapMode = (IMapMode) mapModeRef.get();
+ d = FigureUtilities.getTextExtents(_ellipse, f);
+ d.height = FigureUtilities.getFontMetrics(f).getHeight();
+ d = new Dimension(mapMode.DPtoLP(d.width), mapMode.DPtoLP(d.height));
+ fontToEllipseTextSize.put(f, d);
+ }
+ return d;
+ }
+
+ public SingleIconInfo getSingleIconInfo(Image image) {
+ if (image == null) {
+ return SingleIconInfo.NULL_INFO;
+ }
+ SingleIconInfo info;
+ for (int i = 0; i < MAX_IMAGE_INFO; ++i) {
+ info = singleIconInfos[i];
+ if (info == null) {
+ info = new SingleIconInfo(image);
+ singleIconInfos[i] = info;
+ return info;
+ }
+ if (info.icon == image) {
+ return info;
+ }
+ }
+ int index = SingleIconInfo.count % MAX_IMAGE_INFO;
+ info = new SingleIconInfo(image);
+ singleIconInfos[index] = info;
+ return info;
+ }
+ }
+
+ // reserve 1 bit
+ private static int FLAG_SELECTED = MAX_FLAG << 1;
+
+ private static int FLAG_HASFOCUS = MAX_FLAG << 2;
+
+ private static int FLAG_UNDERLINED = MAX_FLAG << 3;
+
+ private static int FLAG_STRIKEDTHROUGH = MAX_FLAG << 4;
+
+ private static int FLAG_WRAP = MAX_FLAG << 5;
+
+ // reserve 3 bits
+ private static int FLAG_TEXT_ALIGN = MAX_FLAG << 6;
+
+ private static int FLAG_WRAP_ALIGN = MAX_FLAG << 9;
+
+ private static int FLAG_ICON_ALIGN = MAX_FLAG << 12;
+
+ private static int FLAG_LABEL_ALIGN = MAX_FLAG << 15;
+
+ private static int FLAG_TEXT_PLACEMENT = MAX_FLAG << 18;
+
+ private MapModeConstants mapModeConstants;
+
+ /** the original label's text */
+ private String text;
+
+ /** the label's text used in painting after applying required styles */
+ private String subStringText;
+
+ /** the size of text */
+ private Dimension textSize;
+
+ private Dimension ellipseTextSize;
+
+ /** the location of text */
+ private Point textLocation;
+
+ /** the cached hint used to calculate text size */
+ private int cachedPrefSizeHint_width;
+
+ private int cachedPrefSizeHint_height;
+
+ /** the icon location */
+ private Point iconLocation;
+
+ private static abstract class IconInfo {
+ /**
+ * Gets the icon at the index location.
+ *
+ * @param i
+ * the index to retrieve the icon of
+ * @return <code>Image</code> that corresponds to the given index.
+ */
+ public abstract Image getIcon(int i);
+
+ /**
+ * Gets the icon size of the icon at the given index.
+ *
+ * @param i
+ * @return the <code>Dimension</code> that is the size of the icon at
+ * the given index.
+ */
+ public abstract Dimension getIconSize(IMapMode mapMode, int i);
+
+ /**
+ * @return the number of icons
+ */
+ public abstract int getNumberofIcons();
+
+ /**
+ * @return the <code>Dimension</code> that is the total size of all the
+ * icons.
+ */
+ public abstract Dimension getTotalIconSize(IMapMode mapMode);
+
+ public abstract void invalidate();
+
+ /**
+ * Sets the icon at the index location.
+ *
+ * @param icon
+ * @param i
+ */
+ public abstract void setIcon(Image icon, int i);
+
+ /**
+ *
+ */
+ public abstract int getMaxIcons();
+
+ }
+
+ private static class SingleIconInfo extends IconInfo {
+
+ static int count;
+
+ public static final SingleIconInfo NULL_INFO = new SingleIconInfo() {
+ public int getNumberofIcons() {
+ return 0;
+ }
+ };
+
+ final Image icon;
+
+ /** total icon size */
+ private Dimension totalIconSize;
+
+ private SingleIconInfo() {
+ icon = null;// don't increment count, used only for NULL_INFO
+ }
+
+ public SingleIconInfo(Image icon) {
+ this.icon = icon;
+ ++count;
+ }
+
+ public final int getMaxIcons() {
+ return 1;
+ }
+
+ public Image getIcon(int i) {
+ if (i == 0) {
+ return icon;
+ } else if (i > 0) {
+ return null;
+ }
+ throw new IndexOutOfBoundsException();
+ }
+
+ public void setIcon(Image img, int i) {
+ throw new UnsupportedOperationException();
+ }
+
+ public Dimension getIconSize(IMapMode mapMode, int i) {
+ if (i == 0) {
+ return getTotalIconSize(mapMode);
+ }
+
+ throw new IndexOutOfBoundsException();
+ }
+
+ public int getNumberofIcons() {
+ return 1;
+ }
+
+ public Dimension getTotalIconSize(IMapMode mapMode) {
+ if (totalIconSize != null)
+ return totalIconSize;
+
+ if (icon != null && !icon.isDisposed()) {
+ org.eclipse.swt.graphics.Rectangle imgBounds = icon.getBounds();
+ totalIconSize = new Dimension(mapMode.DPtoLP(imgBounds.width), mapMode.DPtoLP(imgBounds.height));
+ } else {
+ totalIconSize = EMPTY_DIMENSION;
+ }
+
+ return totalIconSize;
+ }
+
+ public void invalidate() {
+ totalIconSize = null;
+ }
+
+ }
+
+ private static class MultiIconInfo extends IconInfo {
+
+ /** the label icons */
+ private ArrayList icons = new ArrayList(2);
+
+ /** total icon size */
+ private Dimension totalIconSize;
+
+ public MultiIconInfo() {
+ super();
+ }
+
+ public int getMaxIcons() {
+ return -1;
+ }
+
+ /**
+ * Gets the icon at the index location.
+ *
+ * @param i
+ * the index to retrieve the icon of
+ * @return <code>Image</code> that corresponds to the given index.
+ */
+ public Image getIcon(int i) {
+ if (i >= icons.size())
+ return null;
+
+ return (Image) icons.get(i);
+ }
+
+ /**
+ * Sets the icon at the index location.
+ *
+ * @param icon
+ * @param i
+ */
+ public void setIcon(Image icon, int i) {
+ int size = icons.size();
+ if (i >= size) {
+ for (int j = size; j < i; j++)
+ icons.add(null);
+ icons.add(icon);
+ icons.trimToSize();
+ } else
+ icons.set(i, icon);
+ }
+
+ /**
+ * Gets the icon size of the icon at the given index.
+ *
+ * @param i
+ * @return the <code>Dimension</code> that is the size of the icon at
+ * the given index.
+ */
+ public Dimension getIconSize(IMapMode mapMode, int i) {
+ Image img = getIcon(i);
+ if (img != null && !img.isDisposed()) {
+ org.eclipse.swt.graphics.Rectangle imgBounds = img.getBounds();
+ return new Dimension(mapMode.DPtoLP(imgBounds.width), mapMode.DPtoLP(imgBounds.height));
+ }
+ return EMPTY_DIMENSION;
+ }
+
+ /**
+ * @return the number of icons
+ */
+ public int getNumberofIcons() {
+ return icons.size();
+ }
+
+ /**
+ * @return the <code>Dimension</code> that is the total size of all the
+ * icons.
+ */
+ public Dimension getTotalIconSize(IMapMode mapMode) {
+ if (totalIconSize != null)
+ return totalIconSize;
+ int iconNum = getNumberofIcons();
+ if (iconNum == 0) {
+ return totalIconSize = EMPTY_DIMENSION;
+ }
+
+ totalIconSize = new Dimension();
+ for (int i = 0; i < iconNum; i++) {
+ Dimension iconSize = getIconSize(mapMode, i);
+ totalIconSize.width += iconSize.width;
+ if (iconSize.height > totalIconSize.height)
+ totalIconSize.height = iconSize.height;
+ }
+
+ return totalIconSize;
+ }
+
+ /**
+ *
+ */
+ public void invalidate() {
+ totalIconSize = null;
+ }
+ }
+
+ private IconInfo iconInfo;
+
+ /** the cached hint used to calculate text size */
+ private int cachedTextSizeHint_width;
+
+ private int cachedTextSizeHint_height;
+
+ /**
+ * Construct an empty Label.
+ *
+ * @since 2.0
+ */
+ public SiriusWrapLabel() {
+ text = "";//$NON-NLS-1$
+ // set defaults
+ setAlignmentFlags(CENTER, FLAG_TEXT_ALIGN);
+ setAlignmentFlags(CENTER, FLAG_ICON_ALIGN);
+ setAlignmentFlags(CENTER, FLAG_LABEL_ALIGN);
+ setAlignmentFlags(LEFT, FLAG_WRAP_ALIGN);
+ setPlacementFlags(EAST, FLAG_TEXT_PLACEMENT);
+ }
+
+ /**
+ * Construct a Label with passed String as its text.
+ *
+ * @param s
+ * the label text
+ * @since 2.0
+ */
+ public SiriusWrapLabel(String s) {
+ if (s != null) {
+ text = s;
+ } else {
+ text = "";//$NON-NLS-1$
+ }
+ // setBorder(new LineBorderEx(ColorConstants.red,3));
+ }
+
+ /**
+ * Construct a Label with passed Image as its icon.
+ *
+ * @param i
+ * the label image
+ * @since 2.0
+ */
+ public SiriusWrapLabel(Image i) {
+ text = "";//$NON-NLS-1$
+ iconInfo = new SingleIconInfo(i);
+ }
+
+ /**
+ * Construct a Label with passed String as text and passed Image as its
+ * icon.
+ *
+ * @param s
+ * the label text
+ * @param i
+ * the label image
+ * @since 2.0
+ */
+ public SiriusWrapLabel(String s, Image i) {
+ if (s != null) {
+ text = s;
+ } else {
+ text = "";//$NON-NLS-1$
+ }
+ iconInfo = new SingleIconInfo(i);
+ }
+
+ /**
+ * @return <code>IMapMode</code> used by this figure. <code>IMapMode</code>
+ * that allows for the coordinate mapping from device to logical
+ * units.
+ */
+ private IMapMode getFigureMapMode() {
+ return (IMapMode) getMapModeConstants().mapModeRef.get();
+ }
+
+ private MapModeConstants getMapModeConstants() {
+ if (mapModeConstants == null) {
+ IMapMode mapMode = MapModeUtil.getMapMode(this);
+ while (mapMode instanceof IMapModeHolder) {
+ mapMode = ((IMapModeHolder) mapMode).getMapMode();
+ }
+ mapModeConstants = (MapModeConstants) mapModeConstantsMap.get(mapMode);
+ if (mapModeConstants == null) {
+ mapModeConstants = new MapModeConstants(mapMode);
+ mapModeConstantsMap.put(mapMode, mapModeConstants);
+ }
+ }
+ return mapModeConstants;
+ }
+
+ private void alignOnHeight(Point loc, Dimension size, int alignment) {
+ switch (alignment) {
+ case TOP:
+ loc.y = getInsets().top;
+ break;
+ case BOTTOM:
+ loc.y = bounds.height - size.height - getInsets().bottom;
+ break;
+ default:
+ loc.y = (bounds.height - size.height) / 2;
+ }
+ }
+
+ private void alignOnWidth(Point loc, Dimension size, int alignment) {
+ switch (alignment) {
+ case LEFT:
+ loc.x = getInsets().left;
+ break;
+ case RIGHT:
+ loc.x = bounds.width - size.width - getInsets().right;
+ break;
+ default:
+ loc.x = (bounds.width - size.width) / 2;
+ }
+ }
+
+ private void calculateAlignment(Dimension iconSize, int textPlacement) {
+ switch (textPlacement) {
+ case EAST:
+ case WEST:
+ alignOnHeight(textLocation, getTextSize(), getTextAlignment());
+ alignOnHeight(getIconLocation(), iconSize, getIconAlignment());
+ break;
+ case NORTH:
+ case SOUTH:
+ alignOnWidth(textLocation, getSubStringTextSize(), getTextAlignment());
+ alignOnWidth(getIconLocation(), iconSize, getIconAlignment());
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Calculates the size of the Label using the passed Dimension as the size
+ * of the Label's text.
+ *
+ * @param txtSize
+ * the precalculated size of the label's text
+ * @return the label's size
+ * @since 2.0
+ */
+ protected Dimension calculateLabelSize(Dimension txtSize) {
+ Dimension iconSize = getTotalIconSize();
+ boolean isEmpty = (iconSize.width == 0 && iconSize.height == 0);
+ int len = getText().length();
+ if (len == 0 && isEmpty) {
+ return new Dimension(txtSize.width, txtSize.height);
+ }
+ int gap = (len == 0 || isEmpty) ? 0 : getIconTextGap();
+ int placement = getTextPlacement();
+ if (placement == WEST || placement == EAST) {
+ return new Dimension(iconSize.width + gap + txtSize.width, Math.max(iconSize.height, txtSize.height));
+ } else {
+ return new Dimension(Math.max(iconSize.width, txtSize.width), iconSize.height + gap + txtSize.height);
+ }
+ }
+
+ private void calculateLocations() {
+ textLocation = new Point();
+ iconLocation = new Point();
+ Dimension iconSize = getTotalIconSize();
+ int textPlacement = getTextPlacement();
+ calculatePlacement(iconSize, textPlacement);
+ calculateAlignment(iconSize, textPlacement);
+ Rectangle r = getBounds();
+ Dimension ps = getPreferredSize(r.width, r.height);
+ int w = (r.width - ps.width) + (getTextSize().width - getSubStringTextSize().width);
+ int h = r.height - ps.height;
+ if (w == 0 && h == 0) {
+ return;
+ }
+
+ Dimension offset = new Dimension(w, h);
+ switch (getLabelAlignment()) {
+ case LEFT:
+ offset.scale(0.0f);
+ break;
+ case RIGHT:
+ offset.scale(1.0f);
+ break;
+ case TOP:
+ offset.height = 0;
+ offset.scale(0.5f);
+ break;
+ case BOTTOM:
+ offset.height = offset.height * 2;
+ offset.scale(0.5f);
+ break;
+ case CENTER:
+ default:
+ offset.scale(0.5f);
+ break;
+ }
+
+ switch (textPlacement) {
+ case EAST:
+ case WEST:
+ offset.height = 0;
+ break;
+ case NORTH:
+ case SOUTH:
+ offset.width = 0;
+ break;
+ default:
+ break;
+ }
+
+ textLocation.translate(offset);
+ iconLocation.translate(offset);
+ }
+
+ private void calculatePlacement(Dimension iconSize, int textPlacement) {
+ int gap = (getText().length() == 0 || (iconSize.width == 0 && iconSize.height == 0)) ? 0 : getIconTextGap();
+ Insets insets = getInsets();
+ switch (textPlacement) {
+ case EAST:
+ iconLocation.x = insets.left;
+ textLocation.x = iconSize.width + gap + insets.left;
+ break;
+ case WEST:
+ textLocation.x = insets.left;
+ iconLocation.x = getSubStringTextSize().width + gap + insets.left;
+ break;
+ case NORTH:
+ textLocation.y = insets.top;
+ iconLocation.y = getTextSize().height + gap + insets.top;
+ break;
+ case SOUTH:
+ textLocation.y = iconSize.height + gap + insets.top;
+ iconLocation.y = insets.top;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Calculates the size of the Label's text size. The text size calculated
+ * takes into consideration if the Label's text is currently truncated. If
+ * text size without considering current truncation is desired, use
+ * {@link #calculateTextSize(int, int)}.
+ *
+ * @return the size of the label's text, taking into account truncation
+ * @since 2.0
+ */
+ protected Dimension calculateSubStringTextSize() {
+ Font f = getFont();
+ return getTextExtents(getSubStringText(), f, getFigureMapMode().DPtoLP(FigureUtilities.getFontMetrics(f).getHeight()));
+ }
+
+ /**
+ * Calculates and returns the size of the Label's text. Note that this
+ * Dimension is calculated using the Label's full text, regardless of
+ * whether or not its text is currently truncated. If text size considering
+ * current truncation is desired, use {@link #calculateSubStringTextSize()}.
+ *
+ * @param wHint
+ * a width hint
+ * @param hHint
+ * a height hint
+ * @return the size of the label's text, ignoring truncation
+ * @since 2.0
+ */
+ protected Dimension calculateTextSize(int wHint, int hHint) {
+ Font f = getFont();
+ return getTextExtents(getWrappedText(wHint, hHint), f, getFigureMapMode().DPtoLP(FigureUtilities.getFontMetrics(f).getHeight()));
+ }
+
+ private void clearLocations() {
+ iconLocation = textLocation = null;
+ }
+
+ /**
+ * Returns the Label's icon.
+ *
+ * @return the label icon
+ * @since 2.0
+ */
+ public Image getIcon() {
+ return getIcon(0);
+ }
+
+ /**
+ * Gets the label's icon at the given index
+ *
+ * @param index
+ * The icon index
+ * @return the <code>Image</code> that is the icon for the given index.
+ */
+ public Image getIcon(int index) {
+ if (iconInfo == null)
+ return null;
+ return iconInfo.getIcon(index);
+ }
+
+ /**
+ * Determines if there is any icons by checking if icon size is zeros.
+ *
+ * @return true if icons are present, false otherwise
+ */
+ protected boolean hasIcons() {
+ return (getNumberofIcons() > 0);
+ }
+
+ /**
+ * Returns the current alignment of the Label's icon. The default is
+ * {@link PositionConstants#CENTER}.
+ *
+ * @return the icon alignment
+ * @since 2.0
+ */
+ public int getIconAlignment() {
+ return getAlignment(FLAG_ICON_ALIGN);
+ }
+
+ /**
+ * Returns the bounds of the Label's icon.
+ *
+ * @return the icon's bounds
+ * @since 2.0
+ */
+ public Rectangle getIconBounds() {
+ return new Rectangle(getBounds().getLocation().translate(getIconLocation()), getTotalIconSize());
+ }
+
+ /**
+ * Returns the location of the Label's icon relative to the Label.
+ *
+ * @return the icon's location
+ * @since 2.0
+ */
+ protected Point getIconLocation() {
+ if (iconLocation == null)
+ calculateLocations();
+ return iconLocation;
+ }
+
+ /**
+ * Returns the gap in pixels between the Label's icon and its text.
+ *
+ * @return the gap
+ * @since 2.0
+ */
+ public int getIconTextGap() {
+ return getMapModeConstants().nDPtoLP_3;
+ }
+
+ /**
+ * @see IFigure#getMinimumSize(int, int)
+ */
+ public Dimension getMinimumSize(int w, int h) {
+ if (minSize != null)
+ return minSize;
+ minSize = new Dimension();
+ LayoutManager layoutManager = getLayoutManager();
+ if (layoutManager != null)
+ minSize.setSize(layoutManager.getMinimumSize(this, w, h));
+ Font f = getFont();
+ Dimension d = getEllipseTextSize().getIntersected(getTextExtents(getText(), f, getFigureMapMode().DPtoLP(FigureUtilities.getFontMetrics(f).getHeight())));
+
+ Dimension labelSize = calculateLabelSize(d);
+ Insets insets = getInsets();
+ labelSize.expand(insets.getWidth(), insets.getHeight());
+ minSize.union(labelSize);
+ return minSize;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.draw2d.IFigure#getPreferredSize(int, int)
+ */
+ public Dimension getPreferredSize(int wHint, int hHint) {
+ if (prefSize == null || wHint != cachedPrefSizeHint_width || hHint != cachedPrefSizeHint_height) {
+ prefSize = calculateLabelSize(getTextSize(wHint, hHint));
+ Insets insets = getInsets();
+ prefSize.expand(insets.getWidth(), insets.getHeight());
+ LayoutManager layoutManager = getLayoutManager();
+ if (layoutManager != null) {
+ prefSize.union(layoutManager.getPreferredSize(this, wHint, hHint));
+ }
+ prefSize.union(getMinimumSize(wHint, hHint));
+ cachedPrefSizeHint_width = wHint;
+ cachedPrefSizeHint_height = hHint;
+ }
+ return prefSize;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.draw2d.IFigure#getMaximumSize()
+ */
+ public Dimension getMaximumSize() {
+ // this assumes that getPreferredSize(wHint, hHint) is called before
+ return prefSize;
+ }
+
+ /**
+ * Calculates the amount of the Label's current text will fit in the Label,
+ * including an elipsis "..." if truncation is required.
+ *
+ * @return the substring
+ * @since 2.0
+ */
+ public String getSubStringText() {
+ if (subStringText != null)
+ return subStringText;
+
+ String theText = getText();
+ int textLen = theText.length();
+ if (textLen == 0) {
+ return subStringText = "";//$NON-NLS-1$;;
+ }
+ Dimension size = getSize();
+ Dimension shrink = getPreferredSize(size.width, size.height).getDifference(size);
+ Dimension effectiveSize = getTextSize().getExpanded(-shrink.width, -shrink.height);
+
+ if (effectiveSize.height == 0) {
+ return subStringText = "";//$NON-NLS-1$;
+ }
+
+ Font f = getFont();
+ FontMetrics metrics = FigureUtilities.getFontMetrics(f);
+ IMapMode mm = getFigureMapMode();
+ int fontHeight = mm.DPtoLP(metrics.getHeight());
+ int charAverageWidth = mm.DPtoLP(metrics.getAverageCharWidth());
+ int maxLines = (int) (effectiveSize.height / (double) fontHeight);
+ if (maxLines == 0) {
+ return subStringText = "";//$NON-NLS-1$
+ }
+
+ StringBuffer accumlatedText = new StringBuffer();
+ StringBuffer remainingText = new StringBuffer(theText);
+
+ int effectiveSizeWidth = effectiveSize.width;
+ int widthHint = Math.max(effectiveSizeWidth - getEllipseTextSize().width, 0);
+ int i = 0, j = 0;
+ while (remainingText.length() > 0 && j++ < maxLines) {
+ i = getLineWrapPosition(remainingText.toString(), f, effectiveSizeWidth, fontHeight);
+
+ if (accumlatedText.length() > 0)
+ accumlatedText.append('\n');
+
+ if (i == 0 || (remainingText.length() > i && j == maxLines)) {
+ i = getLargestSubstringConfinedTo(remainingText.toString(), f, widthHint, fontHeight, charAverageWidth);
+ accumlatedText.append(remainingText.substring(0, i));
+ accumlatedText.append(getEllipse());
+ } else
+ accumlatedText.append(remainingText.substring(0, i));
+ remainingText.delete(0, i);
+ }
+ return subStringText = accumlatedText.toString();
+ }
+
+ /**
+ * Creates an equivalent text to that of the label's but with "\n"(s)
+ * inserted at the wrapping positions. This method assumes unlimited
+ * bounding box and is used by <code>calculateTextSize()</code> to calculate
+ * the perfect size of the text with wrapping
+ *
+ * @return the wrapped text
+ */
+ private String getWrappedText(int wHint, int hHint) {
+ String theText = getText();
+ if (wHint == -1 || theText.length() == 0 || !isTextWrapped())
+ return theText;
+
+ Dimension iconSize = getTotalIconSize();
+ if (!(iconSize.width == 0 && iconSize.height == 0)) {
+ switch (getTextPlacement()) {
+ case EAST:
+ case WEST:
+ wHint -= iconSize.width + getIconTextGap();
+ break;
+ case NORTH:
+ case SOUTH:
+ if (hHint != -1)
+ hHint -= iconSize.height + getIconTextGap();
+ break;
+ default:
+ break;
+ }
+ }
+
+ if ((hHint == 0) || (wHint == 0)) {
+ return "";//$NON-NLS-1$;
+ }
+
+ Font f = getFont();
+ int fontHeight = getFigureMapMode().DPtoLP(FigureUtilities.getFontMetrics(f).getHeight());
+ int maxLines = Integer.MAX_VALUE;
+ if (hHint != -1) {
+ maxLines = (int) (hHint / (double) fontHeight);
+ if (maxLines == 0) {
+ return "";//$NON-NLS-1$;;
+ }
+ }
+
+ StringBuffer accumlatedText = new StringBuffer();
+ StringBuffer remainingText = new StringBuffer(theText);
+ int i = 0, j = 0;
+
+ while (remainingText.length() > 0 && j++ < maxLines) {
+ if ((i = getLineWrapPosition(remainingText.toString(), f, wHint, fontHeight)) == 0)
+ break;
+
+ if (accumlatedText.length() > 0)
+ accumlatedText.append('\n');
+ accumlatedText.append(remainingText.substring(0, i));
+ remainingText.delete(0, i);
+ }
+ return accumlatedText.toString();
+ }
+
+ /**
+ * Returns the size of the Label's current text. If the text is currently
+ * truncated, the truncated text with its ellipsis is used to calculate the
+ * size.
+ *
+ * @return the size of this label's text, taking into account truncation
+ * @since 2.0
+ */
+ protected Dimension getSubStringTextSize() {
+ return calculateSubStringTextSize();
+ }
+
+ /**
+ * Returns the size of the String constant "..." the ellipse based on the
+ * currently used Map mode size.
+ *
+ * @return the size of ellipse text
+ *
+ */
+ private Dimension getEllipseTextSize() {
+ if (ellipseTextSize == null) {
+ ellipseTextSize = getMapModeConstants().getEllipseTextSize(getFont());
+ }
+ return ellipseTextSize;
+ }
+
+ /**
+ * Returns the text of the label. Note that this is the complete text of the
+ * label, regardless of whether it is currently being truncated. Call
+ * {@link #getSubStringText()}to return the label's current text contents
+ * with truncation considered.
+ *
+ * @return the complete text of this label
+ * @since 2.0
+ */
+ public String getText() {
+ return text;
+ }
+
+ /**
+ * Returns the current alignment of the Label's text. The default text
+ * alignment is {@link PositionConstants#CENTER}.
+ *
+ * @return the text alignment
+ */
+ public int getTextAlignment() {
+ return getAlignment(FLAG_TEXT_ALIGN);
+ }
+
+ /**
+ * Returns the current alignment of the entire Label. The default label
+ * alignment is {@link PositionConstants#LEFT}.
+ *
+ * @return the label alignment
+ */
+ private int getLabelAlignment() {
+ return getAlignment(FLAG_LABEL_ALIGN);
+ }
+
+ /**
+ * Returns the bounds of the label's text. Note that the bounds are
+ * calculated using the label's complete text regardless of whether the
+ * label's text is currently truncated.
+ *
+ * @return the bounds of this label's complete text
+ * @since 2.0
+ */
+ public Rectangle getTextBounds() {
+ return new Rectangle(getBounds().getLocation().translate(getTextLocation()), getTextSize());
+ }
+
+ /**
+ * Returns the location of the label's text relative to the label.
+ *
+ * @return the text location
+ * @since 2.0
+ */
+ protected Point getTextLocation() {
+ if (textLocation != null)
+ return textLocation;
+ calculateLocations();
+ return textLocation;
+ }
+
+ /**
+ * Returns the current placement of the label's text relative to its icon.
+ * The default text placement is {@link PositionConstants#EAST}.
+ *
+ * @return the text placement
+ * @since 2.0
+ */
+ public int getTextPlacement() {
+ return getPlacement(FLAG_TEXT_PLACEMENT);
+ }
+
+ /**
+ * Returns the size of the label's complete text. Note that the text used to
+ * make this calculation is the label's full text, regardless of whether the
+ * label's text is currently being truncated and is displaying an ellipsis.
+ * If the size considering current truncation is desired, call
+ * {@link #getSubStringTextSize()}.
+ *
+ * @param wHint
+ * a width hint
+ * @param hHint
+ * a height hint
+ * @return the size of this label's complete text
+ * @since 2.0
+ */
+ protected Dimension getTextSize(int wHint, int hHint) {
+ if (textSize == null || wHint != cachedTextSizeHint_width || hHint != cachedTextSizeHint_height) {
+ textSize = calculateTextSize(wHint, hHint);
+ cachedTextSizeHint_width = wHint;
+ cachedTextSizeHint_height = hHint;
+ }
+ return textSize;
+ }
+
+ /**
+ * Gets the text size given the current size as a width hint
+ */
+ private final Dimension getTextSize() {
+ Rectangle r = getBounds();
+ return getTextSize(r.width, r.height);
+ }
+
+ /**
+ * @see IFigure#invalidate()
+ */
+ public void invalidate() {
+ prefSize = null;
+ minSize = null;
+ clearLocations();
+ ellipseTextSize = null;
+ textSize = null;
+ subStringText = null;
+ if (iconInfo != null)
+ iconInfo.invalidate();
+ super.invalidate();
+ }
+
+ /**
+ * Returns <code>true</code> if the label's text is currently truncated and
+ * is displaying an ellipsis, <code>false</code> otherwise.
+ *
+ * @return <code>true</code> if the label's text is truncated
+ * @since 2.0
+ */
+ public boolean isTextTruncated() {
+ return !getSubStringTextSize().equals(getTextSize());
+ }
+
+ /**
+ * @see org.eclipse.draw2d.Figure#paintFigure(org.eclipse.draw2d.Graphics)
+ */
+ public void paintFigure(Graphics graphics) {
+ if (isSelected()) {
+ graphics.pushState();
+ graphics.setBackgroundColor(ColorConstants.menuBackgroundSelected);
+ graphics.fillRectangle(getSelectionRectangle());
+ graphics.popState();
+ graphics.setForegroundColor(ColorConstants.white);
+ }
+ if (hasFocus()) {
+ graphics.pushState();
+ graphics.setXORMode(true);
+ graphics.setForegroundColor(ColorConstants.menuBackgroundSelected);
+ graphics.setBackgroundColor(ColorConstants.white);
+ graphics.drawFocus(getSelectionRectangle().resize(-1, -1));
+ graphics.popState();
+ }
+ if (isOpaque())
+ super.paintFigure(graphics);
+ Rectangle figBounds = getBounds();
+
+ graphics.translate(figBounds.x, figBounds.y);
+ if (hasIcons())
+ paintIcons(graphics);
+
+ String subString = getSubStringText();
+ if (subString.length() > 0) {
+ if (!isEnabled()) {
+ graphics.translate(1, 1);
+ graphics.setForegroundColor(ColorConstants.buttonLightest);
+ paintText(graphics, subString);
+ graphics.translate(-1, -1);
+ graphics.setForegroundColor(ColorConstants.buttonDarker);
+ } else {
+ paintText(graphics, subString);
+ }
+ }
+ graphics.translate(-figBounds.x, -figBounds.y);
+ }
+
+ /**
+ * Paints the text and optionally underlines it. <BR>
+ * The offset added to avoid truncating at the top make a truncating at the
+ * bottom so to avoid the bottom truncating problem we remove this fix.
+ *
+ * @param graphics
+ * The graphics context
+ * @param subString
+ * The string to draw
+ */
+ private void paintText(Graphics graphics, String subString) {
+ StringTokenizer tokenizer = new StringTokenizer(subString, "\n"); //$NON-NLS-1$
+ Font f = getFont();
+ FontMetrics fontMetrics = FigureUtilities.getFontMetrics(f);
+ int fontHeight = getFigureMapMode().DPtoLP(fontMetrics.getHeight());
+ int fontHeightHalf = fontHeight / 2;
+ int textWidth = getTextExtents(subString, f, fontHeight).width;
+ Point p = getTextLocation();
+ int y = p.y;
+ int x = p.x;
+ final int wrapAlignment = getTextWrapAlignment();
+ boolean isUnderlined = isTextUnderlined();
+ boolean isStrikedThrough = isTextStrikedThrough();
+ Rectangle clipRect = new Rectangle();
+ graphics.getClip(clipRect);
+ int clipRectTopRight_x = clipRect.getTopRight().x;
+ // If the font's leading area is 0 then we need to add an offset to
+ // avoid truncating at the top (e.g. Korean fonts)
+ // if (0 == fontMetrics.getLeading()) {
+ // y += getMapModeConstants().nDPtoLP_2; // 2 is the leading area for
+ // default English
+ // }
+
+ while (tokenizer.hasMoreTokens()) {
+ x = p.x;
+ String token = tokenizer.nextToken();
+ int tokenWidth = getTextExtents(token, f, fontHeight).width;
+
+ switch (wrapAlignment) {
+ case CENTER:
+ x += (textWidth - tokenWidth) / 2;
+ break;
+ case RIGHT:
+ x += textWidth - tokenWidth;
+ break;
+ default:
+ break;
+ }
+
+ // increase the clipping rectangle by a small amount to account for
+ // font overhang
+ // from italic / irregular characters etc.
+
+ if (tokenWidth + x <= clipRectTopRight_x) {
+ Rectangle newClipRect = new Rectangle(clipRect);
+ newClipRect.width += (tokenWidth / token.length()) / 2;
+ graphics.setClip(newClipRect);
+ }
+
+ graphics.drawText(token, x, y);
+ graphics.setClip(clipRect);
+
+ y += fontHeight;
+
+ if (isUnderlined)
+ graphics.drawLine(x, y - 1, x + tokenWidth, y - 1);
+ if (isStrikedThrough)
+ graphics.drawLine(x, y - fontHeightHalf + 1, x + tokenWidth, y - fontHeightHalf + 1);
+ }
+ }
+
+ /**
+ * Paints the icon(s)
+ *
+ * @param graphics
+ * The graphics context
+ */
+ private void paintIcons(Graphics graphics) {
+ Point p = Point.SINGLETON;
+ p.setLocation(getIconLocation());
+
+ int num = getNumberofIcons();
+ for (int i = 0; i < num; i++) {
+ Image icon = getIcon(i);
+ if (icon != null) {
+ graphics.drawImage(icon, p);
+ p.x += getIconSize(i).width;
+ }
+ }
+ }
+
+ /**
+ * Sets the label's icon to the passed image.
+ *
+ * @param image
+ * the new label image
+ * @since 2.0
+ */
+ public void setIcon(Image image) {
+ setIcon(image, 0);
+ }
+
+ /**
+ * Sets the label's icon at given index
+ *
+ * @param image
+ * The icon image or null to remove the icon
+ * @param index
+ * The icon index
+ */
+ public void setIcon(Image image, int index) {
+ if (iconInfo == null) {
+ if (index == 0) {
+ iconInfo = getMapModeConstants().getSingleIconInfo(image);
+ } else {
+ iconInfo = new MultiIconInfo();
+ iconInfo.setIcon(image, index);
+ }
+ revalidate();
+ repaint();// Call repaint, in case the image dimensions are the
+ // same.
+ } else if (iconInfo.getIcon(index) != image) {
+ if (iconInfo.getMaxIcons() == 1) {
+ if (index == 0) {
+ iconInfo = getMapModeConstants().getSingleIconInfo(image);
+ revalidate();
+ repaint();// Call repaint, in case the image dimensions are
+ // the same.
+ return;
+ }
+ IconInfo oldIconInfo = iconInfo;
+ iconInfo = new MultiIconInfo();
+ iconInfo.setIcon(oldIconInfo.getIcon(0), 0);
+ }
+ iconInfo.setIcon(image, index);
+ revalidate();
+ repaint();// Call repaint, in case the image dimensions are the
+ // same.
+ }
+ }
+
+ /**
+ * Sets the icon alignment relative to the .abel's alignment to the passed
+ * value. The default is {@link PositionConstants#CENTER}. Other possible
+ * values are {@link PositionConstants#TOP},
+ * {@link PositionConstants#BOTTOM},{@link PositionConstants#LEFT}and
+ * {@link PositionConstants#RIGHT}.
+ *
+ * @param align
+ * the icon alignment
+ * @since 2.0
+ */
+ public void setIconAlignment(int align) {
+ if (getIconAlignment() == align)
+ return;
+ setAlignmentFlags(align, FLAG_ICON_ALIGN);
+ clearLocations();
+ repaint();
+ }
+
+ /**
+ * getIconSize
+ *
+ * @param index
+ * of icon to retrieve size of.
+ * @return Dimension representing the icon size.
+ */
+ protected Dimension getIconSize(int index) {
+ if (iconInfo == null)
+ return EMPTY_DIMENSION;
+ return iconInfo.getIconSize(getFigureMapMode(), index);
+ }
+
+ /**
+ * getIconNumber
+ *
+ * @return int number of icons in the wrap label
+ */
+ protected int getNumberofIcons() {
+ if (iconInfo == null)
+ return 0;
+ return iconInfo.getNumberofIcons();
+ }
+
+ /**
+ * getTotalIconSize Calculates the total union of icon sizes
+ *
+ * @return Dimension that is the union of icon sizes
+ */
+ protected Dimension getTotalIconSize() {
+ if (iconInfo == null)
+ return EMPTY_DIMENSION;
+ return iconInfo.getTotalIconSize(getFigureMapMode());
+ }
+
+ /**
+ * Sets the Label's alignment to the passed value. The default is
+ * {@link PositionConstants#CENTER}. Other possible values are
+ * {@link PositionConstants#TOP},{@link PositionConstants#BOTTOM},
+ * {@link PositionConstants#LEFT}and {@link PositionConstants#RIGHT}.
+ *
+ * @param align
+ * label alignment
+ */
+ public void setLabelAlignment(int align) {
+ if (getLabelAlignment() == align)
+ return;
+ setAlignmentFlags(align, FLAG_LABEL_ALIGN);
+ clearLocations();
+ repaint();
+ }
+
+ /**
+ * Return the ellipse string.
+ *
+ * @return the <code>String</code> that represents the fact that the text
+ * has been truncated and that more text is available but hidden.
+ * Usually this is represented by "...".
+ */
+ protected String getEllipse() {
+ return _ellipse;
+ }
+
+ /**
+ * Sets the label's text.
+ *
+ * @param s
+ * the new label text
+ * @since 2.0
+ */
+ public void setText(String s) {
+ // "text" will never be null.
+ if (s == null)
+ s = "";//$NON-NLS-1$
+ if (text.equals(s))
+ return;
+ text = s;
+ revalidate();
+ repaint(); // If the new text does not cause a new size, we still need
+ // to paint.
+ }
+
+ /**
+ * Sets the text alignment of the Label relative to the label alignment. The
+ * default is {@link PositionConstants#CENTER}. Other possible values are
+ * {@link PositionConstants#TOP},{@link PositionConstants#BOTTOM},
+ * {@link PositionConstants#LEFT}and {@link PositionConstants#RIGHT}.
+ *
+ * @param align
+ * the text alignment
+ * @since 2.0
+ */
+ public void setTextAlignment(int align) {
+ if (getTextAlignment() == align)
+ return;
+ setAlignmentFlags(align, FLAG_TEXT_ALIGN);
+ clearLocations();
+ repaint();
+ }
+
+ /**
+ * Sets the text placement of the label relative to its icon. The default is
+ * {@link PositionConstants#EAST}. Other possible values are
+ * {@link PositionConstants#NORTH},{@link PositionConstants#SOUTH}and
+ * {@link PositionConstants#WEST}.
+ *
+ * @param where
+ * the text placement
+ * @since 2.0
+ */
+ public void setTextPlacement(int where) {
+ if (getTextPlacement() == where)
+ return;
+ setPlacementFlags(where, FLAG_TEXT_PLACEMENT);
+ revalidate();
+ repaint();
+ }
+
+ /**
+ * Sets whether the label text should be underlined
+ *
+ * @param b
+ * Wether the label text should be underlined
+ */
+ public void setTextUnderline(boolean b) {
+ if (isTextUnderlined() == b)
+ return;
+ setFlag(FLAG_UNDERLINED, b);
+ repaint();
+ }
+
+ /**
+ * @return whether the label text is underlined
+ */
+ public boolean isTextUnderlined() {
+ return (flags & FLAG_UNDERLINED) != 0;
+ }
+
+ /**
+ * Sets whether the label text should be striked-through
+ *
+ * @param b
+ * Wether the label text should be stricked-through
+ */
+ public void setTextStrikeThrough(boolean b) {
+ if (isTextStrikedThrough() == b)
+ return;
+ setFlag(FLAG_STRIKEDTHROUGH, b);
+ repaint();
+ }
+
+ /**
+ * @return wether the label text is stricked-through
+ */
+ public boolean isTextStrikedThrough() {
+ return (flags & FLAG_STRIKEDTHROUGH) != 0;
+ }
+
+ /**
+ * Sets whether the label text should wrap
+ *
+ * @param b
+ * whether the label text should wrap
+ */
+ public void setTextWrap(boolean b) {
+ if (isTextWrapped() == b)
+ return;
+ setFlag(FLAG_WRAP, b);
+ revalidate();
+ repaint();
+ }
+
+ /**
+ * @return wether the label text wrap is on
+ */
+ public boolean isTextWrapped() {
+ return (flags & FLAG_WRAP) != 0;
+ }
+
+ /**
+ * Sets the wrapping width of the label text. This is only valid if text
+ * wrapping is turned on
+ *
+ * @param i
+ * The label text wrapping width
+ */
+ public void setTextWrapWidth(int i) {
+ /*
+ * if (this.wrapWidth == i) return; this.wrapWidth = i; revalidate();
+ * repaint();
+ */
+ }
+
+ /**
+ * Sets the wrapping width of the label text. This is only valid if text
+ * wrapping is turned on
+ *
+ * @param i
+ * The label text wrapping width
+ */
+ public void setTextWrapAlignment(int i) {
+ if (getTextWrapAlignment() == i)
+ return;
+
+ setAlignmentFlags(i, FLAG_WRAP_ALIGN);
+ repaint();
+ }
+
+ /**
+ * @return the label text wrapping width
+ */
+ public int getTextWrapAlignment() {
+ return getAlignment(FLAG_WRAP_ALIGN);
+ }
+
+ /**
+ * setPlacementFlags
+ *
+ * @param align
+ * @param flagOffset
+ */
+ private void setPlacementFlags(int align, int flagOffset) {
+ flags &= ~(0x7 * flagOffset);
+ switch (align) {
+ case EAST:
+ flags |= 0x1 * flagOffset;
+ break;
+ case WEST:
+ flags |= 0x2 * flagOffset;
+ break;
+ case NORTH:
+ flags |= 0x3 * flagOffset;
+ break;
+ case SOUTH:
+ flags |= 0x4 * flagOffset;
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * getPlacement
+ *
+ * @param flagOffset
+ * @return PositionConstant representing the placement
+ */
+ private int getPlacement(int flagOffset) {
+ int wrapValue = flags & (0x7 * flagOffset);
+ if (wrapValue == 0x1 * flagOffset)
+ return EAST;
+ else if (wrapValue == 0x2 * flagOffset)
+ return WEST;
+ else if (wrapValue == 0x3 * flagOffset)
+ return NORTH;
+ else if (wrapValue == 0x4 * flagOffset)
+ return SOUTH;
+
+ return EAST;
+ }
+
+ /**
+ * setAlignmentFlags
+ *
+ * @param align
+ * @param flagOffset
+ */
+ private void setAlignmentFlags(int align, int flagOffset) {
+ flags &= ~(0x7 * flagOffset);
+ switch (align) {
+ case CENTER:
+ flags |= 0x1 * flagOffset;
+ break;
+ case TOP:
+ flags |= 0x2 * flagOffset;
+ break;
+ case LEFT:
+ flags |= 0x3 * flagOffset;
+ break;
+ case RIGHT:
+ flags |= 0x4 * flagOffset;
+ break;
+ case BOTTOM:
+ flags |= 0x5 * flagOffset;
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Retrieves the alignment value from the flags member.
+ *
+ * @param flagOffset
+ * that is the bitwise value representing the offset.
+ * @return PositionConstant representing the alignment
+ */
+ private int getAlignment(int flagOffset) {
+ int wrapValue = flags & (0x7 * flagOffset);
+ if (wrapValue == 0x1 * flagOffset)
+ return CENTER;
+ else if (wrapValue == 0x2 * flagOffset)
+ return TOP;
+ else if (wrapValue == 0x3 * flagOffset)
+ return LEFT;
+ else if (wrapValue == 0x4 * flagOffset)
+ return RIGHT;
+ else if (wrapValue == 0x5 * flagOffset)
+ return BOTTOM;
+
+ return CENTER;
+ }
+
+ /**
+ * Sets the selection state of this label
+ *
+ * @param b
+ * true will cause the label to appear selected
+ */
+ public void setSelected(boolean b) {
+ if (isSelected() == b)
+ return;
+ setFlag(FLAG_SELECTED, b);
+ repaint();
+ }
+
+ /**
+ * @return the selection state of this label
+ */
+ public boolean isSelected() {
+ return (flags & FLAG_SELECTED) != 0;
+ }
+
+ /**
+ * Sets the focus state of this label
+ *
+ * @param b
+ * true will cause a focus rectangle to be drawn around the text
+ * of the Label
+ */
+ public void setFocus(boolean b) {
+ if (hasFocus() == b)
+ return;
+ setFlag(FLAG_HASFOCUS, b);
+ repaint();
+ }
+
+ /**
+ * @return the focus state of this label
+ */
+ public boolean hasFocus() {
+ return (flags & FLAG_HASFOCUS) != 0;
+ }
+
+ /**
+ * Returns the bounds of the text selection
+ *
+ * @return The bounds of the text selection
+ */
+ private Rectangle getSelectionRectangle() {
+ Rectangle figBounds = getTextBounds();
+ int expansion = getMapModeConstants().nDPtoLP_2;
+ figBounds.resize(expansion, expansion);
+ translateToParent(figBounds);
+ figBounds.intersect(getBounds());
+ return figBounds;
+ }
+
+ /**
+ * returns the position of last character within the supplied text that will
+ * fit within the supplied width.
+ *
+ * @param s
+ * a text string
+ * @param f
+ * font used to draw the text string
+ * @param w
+ * width in pixles.
+ * @param fontHeight
+ * int <b>mapped already to logical units</b>.
+ */
+ private int getLineWrapPosition(String s, Font f, int w, int fontHeight) {
+ if (getTextExtents(s, f, fontHeight).width <= w) {
+ return s.length();
+ }
+ // create an iterator for line breaking positions
+ BreakIterator iter = BreakIterator.getLineInstance();
+ iter.setText(s);
+ int start = iter.first();
+ int end = iter.next();
+
+ // if the first line segment does not fit in the width,
+ // determine the position within it where we need to cut
+ if (getTextExtents(s.substring(start, end), f, fontHeight).width > w) {
+ iter = BreakIterator.getCharacterInstance();
+ iter.setText(s);
+ start = iter.first();
+ }
+
+ // keep iterating as long as width permits
+ do
+ end = iter.next();
+ while (end != BreakIterator.DONE && getTextExtents(s.substring(start, end), f, fontHeight).width <= w);
+ return (end == BreakIterator.DONE) ? iter.last() : iter.previous();
+ }
+
+ /**
+ * Returns the largest substring of <i>s </i> in Font <i>f </i> that can be
+ * confined to the number of pixels in <i>availableWidth <i>.
+ *
+ * @param s
+ * the original string
+ * @param f
+ * the font
+ * @param w
+ * the available width
+ * @param fontHeight
+ * int <b>mapped already to logical units</b>.
+ * @param charAverageWidth
+ * int <b>mapped already to logical units</b>.
+ * @return the largest substring that fits in the given width
+ * @since 2.0
+ */
+ private int getLargestSubstringConfinedTo(String s, Font f, int w, int fontHeight, int charAverageWidth) {
+ float avg = charAverageWidth;
+ int min = 0;
+ int max = s.length() + 1;
+
+ // The size of the current guess
+ int guess = 0, guessSize = 0;
+ while ((max - min) > 1) {
+ // Pick a new guess size
+ // New guess is the last guess plus the missing width in pixels
+ // divided by the average character size in pixels
+ guess = guess + (int) ((w - guessSize) / avg);
+
+ if (guess >= max)
+ guess = max - 1;
+ if (guess <= min)
+ guess = min + 1;
+
+ // Measure the current guess
+ guessSize = getTextExtents(s.substring(0, guess), f, fontHeight).width;
+
+ if (guessSize < w)
+ // We did not use the available width
+ min = guess;
+ else
+ // We exceeded the available width
+ max = guess;
+ }
+ return min;
+ }
+
+ /**
+ * Gets the tex extent scaled to the mapping mode
+ */
+ private Dimension getTextExtents(String s, Font f, int fontHeight) {
+ if (s.length() == 0) {
+ return getMapModeConstants().dimension_nDPtoLP_0;
+ } else {
+ // height should be set using the font height and the number of
+ // lines in the string
+ Dimension d = FigureUtilities.getTextExtents(s, f);
+ IMapMode mapMode = getFigureMapMode();
+ d.width = mapMode.DPtoLP(d.width);
+ d.height = fontHeight * new StringTokenizer(s, "\n").countTokens();//$NON-NLS-1$
+ return d;
+ }
+ }
+
+ /**
+ * Returns the current alignment of the entire Label. The default label
+ * alignment is {@link PositionConstants#LEFT}.
+ *
+ * @return the label alignment
+ */
+ public int getLabelAlignment2() {
+ return getLabelAlignment();
+ }
+
+ // CHECKSTYLE:ON
+
+ /**
+ * {@inheritDoc}
+ *
+ * Return false when this label part is not visible. (some edge
+ * labels intercepts the selection when they are hidden or empty and non
+ * visible)
+ */
+ @Override
+ public boolean containsPoint(int x, int y) {
+ if (isVisible()) {
+ return super.containsPoint(x, y);
+ }
+ return false;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/StyledFigure.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/StyledFigure.java
new file mode 100644
index 0000000000..868e8ebd3a
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/StyledFigure.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import org.eclipse.draw2d.IFigure;
+
+/**
+ * The figure showing the style.
+ *
+ * @author ymortier
+ */
+public interface StyledFigure extends IFigure {
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/ViewGradientFigureDesc.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/ViewGradientFigureDesc.java
new file mode 100644
index 0000000000..9209dee4a7
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/ViewGradientFigureDesc.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.swt.graphics.Color;
+
+import org.eclipse.sirius.BackgroundStyle;
+
+/**
+ * Common interface which add support of gradient for container and list figure
+ * descriptors.
+ *
+ * @author mporhel
+ */
+public interface ViewGradientFigureDesc extends IFigure {
+ /**
+ * Get the gradient color.
+ *
+ * @return the gradient color.
+ */
+ Color getGradientColor();
+
+ /**
+ * Get the background style.
+ *
+ * @return the background style.
+ */
+ BackgroundStyle getBackgroundStyle();
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/ViewNodeContainerFigureDesc.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/ViewNodeContainerFigureDesc.java
new file mode 100644
index 0000000000..d7b5f51fd3
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/ViewNodeContainerFigureDesc.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import org.eclipse.draw2d.IFigure;
+
+/**
+ * We changed the generated class to an Interface in order to easily switch from
+ * an implementation to another during the edit part creation.
+ *
+ * @author cbrun
+ */
+public interface ViewNodeContainerFigureDesc extends IFigure {
+ /**
+ * Get the figure label.
+ *
+ * @return the figure label.
+ */
+ SiriusWrapLabel getLabelFigure();
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/ViewNodeContainerParallelogram.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/ViewNodeContainerParallelogram.java
new file mode 100644
index 0000000000..a20d447ed5
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/ViewNodeContainerParallelogram.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2011 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import org.eclipse.draw2d.MarginBorder;
+
+import org.eclipse.sirius.diagram.tools.api.graphical.edit.styles.IContainerLabelOffsets;
+
+/**
+ * Figure for the parallelogram shape.
+ *
+ * @author cbrun
+ *
+ */
+public class ViewNodeContainerParallelogram extends ParallelogramFigure implements ViewNodeContainerFigureDesc {
+
+ private SiriusWrapLabel fContainerLabelFigure;
+
+ private boolean myUseLocalCoordinates;
+
+ /**
+ * Constructor.
+ */
+ public ViewNodeContainerParallelogram() {
+ // setLayoutManager(new XYLayout());
+ createContents();
+ this.setBorder(new MarginBorder(IContainerLabelOffsets.LABEL_OFFSET, 0, 0, 0));
+ }
+
+ private void createContents() {
+ fContainerLabelFigure = new SiriusWrapLabel();
+ fContainerLabelFigure.setText(" ");
+ fContainerLabelFigure.setTextWrap(true);
+ this.add(fContainerLabelFigure);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.Figure#useLocalCoordinates()
+ */
+ @Override
+ protected boolean useLocalCoordinates() {
+ return myUseLocalCoordinates;
+ }
+
+ protected void setUseLocalCoordinates(final boolean useLocalCoordinates) {
+ myUseLocalCoordinates = useLocalCoordinates;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.figure.ViewNodeContainerFigureDesc#getLabelFigure()
+ */
+ public SiriusWrapLabel getLabelFigure() {
+ return fContainerLabelFigure;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/ViewNodeContainerRectangleFigureDesc.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/ViewNodeContainerRectangleFigureDesc.java
new file mode 100644
index 0000000000..d42ac3184c
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/ViewNodeContainerRectangleFigureDesc.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import org.eclipse.draw2d.MarginBorder;
+import org.eclipse.draw2d.RectangleFigure;
+
+import org.eclipse.sirius.diagram.tools.api.graphical.edit.styles.IContainerLabelOffsets;
+
+/**
+ * Basic implementation of {@link ViewNodeContainerFigureDesc} with a rectangle
+ * shape.
+ *
+ * @author cbrun
+ *
+ */
+public class ViewNodeContainerRectangleFigureDesc extends RectangleFigure implements ViewNodeContainerFigureDesc {
+
+ private SiriusWrapLabel fContainerLabelFigure;
+
+ /**
+ * @was-generated
+ */
+ private boolean myUseLocalCoordinates;
+
+ /**
+ * Create a new {@link ViewNodeContainerFigureDesc}.
+ */
+ public ViewNodeContainerRectangleFigureDesc() {
+ this.setFill(false);
+ createContents();
+ this.setBorder(new MarginBorder(IContainerLabelOffsets.LABEL_OFFSET, 0, 0, 0));
+ }
+
+ private void createContents() {
+ fContainerLabelFigure = new SiriusWrapLabel();
+ fContainerLabelFigure.setText(" ");
+ fContainerLabelFigure.setTextWrap(true);
+ this.add(fContainerLabelFigure);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @was-generated
+ * @see org.eclipse.draw2d.Figure#useLocalCoordinates()
+ */
+ @Override
+ protected boolean useLocalCoordinates() {
+ return myUseLocalCoordinates;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @was-generated
+ * @param useLocalCoordinates
+ */
+ protected void setUseLocalCoordinates(final boolean useLocalCoordinates) {
+ myUseLocalCoordinates = useLocalCoordinates;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @was-generated
+ * @see org.eclipse.sirius.diagram.ui.tools.api.figure.ViewNodeContainerFigureDesc#getLabelFigure()
+ */
+ public SiriusWrapLabel getLabelFigure() {
+ return fContainerLabelFigure;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/WorkspaceImageFigure.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/WorkspaceImageFigure.java
new file mode 100644
index 0000000000..aaa012aade
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/WorkspaceImageFigure.java
@@ -0,0 +1,209 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure;
+
+import java.io.File;
+import java.net.MalformedURLException;
+
+import org.eclipse.core.runtime.Path;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.Image;
+
+import org.eclipse.sirius.common.tools.api.resource.FileProvider;
+import org.eclipse.sirius.ContainerStyle;
+import org.eclipse.sirius.WorkspaceImage;
+import org.eclipse.sirius.diagram.part.SiriusDiagramEditorPlugin;
+import org.eclipse.sirius.diagram.tools.internal.image.ImagesPath;
+
+/**
+ * The {@link WorkspaceImageFigure} is useful to load images using a cache. The
+ * image can be in the workspace, or if it's not found in the workspace it will
+ * be looked up in the plug-ins.
+ *
+ * @author cbrun
+ *
+ */
+public class WorkspaceImageFigure extends AbstractTransparentImage implements IWorkspaceImageFigure {
+
+ private double imageAspectRatio = 1.0;
+
+ private boolean keepAspectRatio = true;
+
+ /**
+ * Create a new {@link WorkspaceImageFigure}.
+ *
+ * @param flyWeightImage
+ * an image instance.
+ */
+ public WorkspaceImageFigure(final Image flyWeightImage) {
+ super(flyWeightImage);
+ imageAspectRatio = (double) flyWeightImage.getBounds().width / flyWeightImage.getBounds().height;
+ minSize = new Dimension(0, 0);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.Figure#setSize(int, int)
+ */
+ @Override
+ public void setSize(final int w, final int h) {
+ if (keepAspectRatio) {
+ final int newHeight = (int) (w / imageAspectRatio);
+ super.setSize(w, newHeight);
+ } else {
+ super.setSize(w, h);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.Figure#setMaximumSize(org.eclipse.draw2d.geometry.Dimension)
+ */
+ @Override
+ public void setMaximumSize(final Dimension d) {
+ super.setMaximumSize(this.getSize());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.Figure#setMinimumSize(org.eclipse.draw2d.geometry.Dimension)
+ */
+ @Override
+ public void setMinimumSize(final Dimension d) {
+ super.setMinimumSize(this.getSize());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.Figure#setPreferredSize(org.eclipse.draw2d.geometry.Dimension)
+ */
+ @Override
+ public void setPreferredSize(final Dimension size) {
+ super.setPreferredSize(this.getSize());
+ }
+
+ /**
+ * Get an {@link Image} instance. The image will be stored in a cache.
+ *
+ * @param path
+ * the path is a "/project/file" path, if it's not found in the
+ * workspace, the class will look for the file in the plug-ins.
+ * @return an image instance given the path.
+ * @deprecated
+ */
+ @Deprecated
+ public static Image flyWeightImage(final String path) {
+ if (path != null) {
+ final File imageFile = FileProvider.getDefault().getFile(new Path(path));
+ ImageDescriptor desc = null;
+ if (imageFile != null && imageFile.exists() && imageFile.canRead()) {
+ try {
+ desc = SiriusDiagramEditorPlugin.findImageDescriptor(imageFile.toURI().toURL());
+ } catch (MalformedURLException e) {
+ // do nothing
+ }
+ }
+ return WorkspaceImageFigure.flyWeightImage(desc);
+ }
+ return WorkspaceImageFigure.getImageNotFound();
+ }
+
+ /**
+ * Get an {@link Image} instance. The image will be stored in a cache.
+ *
+ * @param desc
+ * the image descriptor
+ * @return an image instance given the image descriptor.
+ * @deprecated
+ */
+ @Deprecated
+ public static Image flyWeightImage(final ImageDescriptor desc) {
+ if (desc != null) {
+ return SiriusDiagramEditorPlugin.getInstance().getImage(desc);
+ } else {
+ return WorkspaceImageFigure.getImageNotFound();
+ }
+ }
+
+ private static Image getImageNotFound() {
+ return SiriusDiagramEditorPlugin.getInstance().getImage(SiriusDiagramEditorPlugin.findImageWithDimensionDescriptor(ImagesPath.IMAGE_NOT_FOUND));
+ }
+
+ /**
+ * Create an {@link WorkspaceImageFigure} instance from an image path.
+ *
+ * @param path
+ * the path is a "/project/file" path, if it's not found in the
+ * workspace, the class will look for the file in the plug-ins.
+ * @return an image instance given the path.
+ */
+ @Deprecated
+ public static WorkspaceImageFigure createImageFigure(final String path) {
+ final WorkspaceImageFigure fig = new WorkspaceImageFigure(WorkspaceImageFigure.flyWeightImage(path));
+ return fig;
+ }
+
+ /**
+ * Create an {@link WorkspaceImageFigure} instance from a workspace image.
+ *
+ * @param wksImage
+ * : an instance of {@link WorkspaceImage}.
+ * @return the image figure built using the {@link WorkspaceImage} object.
+ */
+ @Deprecated
+ public static WorkspaceImageFigure createImageFigure(final WorkspaceImage wksImage) {
+ final String path = wksImage.getWorkspacePath();
+ return WorkspaceImageFigure.createImageFigure(path);
+
+ }
+
+ /**
+ * Get the image aspect ratio.
+ *
+ * @return the image aspect ratio
+ */
+ public double getImageAspectRatio() {
+ return imageAspectRatio;
+ }
+
+ /**
+ * Refresh the figure.
+ *
+ * @param bundledImage
+ * the image associated to the figure
+ */
+ public void refreshFigure(final WorkspaceImage bundledImage) {
+ final String path = bundledImage.getWorkspacePath();
+ final Image image = WorkspaceImageFigure.flyWeightImage(path);
+ if (!image.equals(this.getImage())) {
+ this.setImage(WorkspaceImageFigure.flyWeightImage(path));
+ this.repaint();
+ }
+ }
+
+ /**
+ * Refresh the figure.
+ *
+ * @param containerStyle
+ * the style of the container
+ */
+ public void refreshFigure(final ContainerStyle containerStyle) {
+ if (containerStyle instanceof WorkspaceImage) {
+ WorkspaceImage workspaceImage = (WorkspaceImage) containerStyle;
+ refreshFigure(workspaceImage);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/anchor/AirSlidableImageAnchor.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/anchor/AirSlidableImageAnchor.java
new file mode 100644
index 0000000000..23e1002801
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/anchor/AirSlidableImageAnchor.java
@@ -0,0 +1,330 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure.anchor;
+
+import java.util.Iterator;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.ImageFigure;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.PointList;
+import org.eclipse.draw2d.geometry.PrecisionPoint;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gmf.runtime.draw2d.ui.geometry.LineSeg;
+import org.eclipse.gmf.runtime.draw2d.ui.geometry.PointListUtilities;
+import org.eclipse.gmf.runtime.gef.ui.figures.SlidableAnchor;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+
+/**
+ * The {@link org.eclipse.gmf.runtime.gef.ui.figures.SlidableImageAnchor} for
+ * air. This anchor takes the client area into account.
+ *
+ * @author ymortier
+ */
+public class AirSlidableImageAnchor extends SlidableAnchor {
+
+ private ImageAnchorLocation imageAnchorLocation;
+
+ private ImageFigure imageFig;
+
+ /**
+ * Create a new {@link AirSlidableImageAnchor}.
+ */
+ public AirSlidableImageAnchor() {
+ super();
+ }
+
+ /**
+ * Create a new {@link AirSlidableImageAnchor}.
+ *
+ * @param f
+ * the container figure.
+ * @param imageFig
+ * the image figure.
+ * @param p
+ * the position.
+ */
+ public AirSlidableImageAnchor(final IFigure f, final ImageFigure imageFig, final PrecisionPoint p) {
+ super(f, p);
+ this.imageFig = imageFig;
+ }
+
+ /**
+ * Create a new {@link AirSlidableImageAnchor}.
+ *
+ * @param container
+ * the container figure.
+ * @param imageFig
+ * the image figure.
+ */
+ public AirSlidableImageAnchor(final IFigure container, final ImageFigure imageFig) {
+ super(container);
+ this.imageFig = imageFig;
+ }
+
+ /**
+ * Create a new {@link AirSlidableImageAnchor}.
+ *
+ * @param f
+ * the container figure.
+ */
+ public AirSlidableImageAnchor(final IFigure f) {
+ super(f);
+ }
+
+ /**
+ * Return the image.
+ *
+ * @return the image.
+ * @see org.eclipse.gmf.runtime.gef.ui.figures.SlidableImageAnchor#getImage()
+ */
+ protected Image getImage() {
+ final ImageFigure imageFigure = getImageFigure();
+ if (imageFigure != null) {
+ return imageFigure.getImage();
+ }
+ return null;
+ }
+
+ /**
+ * Return the image figure.
+ *
+ * @return the image figure.
+ */
+ protected ImageFigure getImageFigure() {
+ ImageFigure ret = imageFig;
+ if (ret == null) {
+ final IFigure root = this.getOwner().getParent() == null ? this.getOwner() : this.getOwner().getParent();
+ ret = AirSlidableImageAnchor.getImageFigure(root);
+ }
+ return ret;
+ }
+
+ /**
+ * Returns the first {@link ImageFigure}.
+ *
+ * @param root
+ * the root figure.
+ * @return the first {@link ImageFigure}.
+ */
+ private static ImageFigure getImageFigure(final IFigure root) {
+ ImageFigure ret = null;
+ if (root instanceof ImageFigure) {
+ ret = (ImageFigure) root;
+ }
+ final Iterator iterChilren = root.getChildren().iterator();
+ while (iterChilren.hasNext() && ret == null) {
+ final IFigure next = (IFigure) iterChilren.next();
+ ret = AirSlidableImageAnchor.getImageFigure(next);
+ }
+ return ret;
+ }
+
+ private final class ImageAnchorLocation {
+
+ private ImageData imgData;
+
+ private ImageData transMaskData;
+
+ private ImageAnchorLocation(final Image img) {
+ imgData = img.getImageData();
+ transMaskData = imgData.getTransparencyMask();
+ }
+
+ /**
+ * @return Returns the imgData.
+ */
+ protected ImageData getImageData() {
+ return imgData;
+ }
+
+ /**
+ * @return Returns the transMaskData.
+ */
+ protected ImageData getTransparencyMaskData() {
+ return transMaskData;
+ }
+
+ /**
+ * isTransparentAt Accessor to determine if the image is transparent at
+ * a given point.
+ *
+ * @param x
+ * int location into the image
+ * @param y
+ * int location into the image
+ * @param checkAdjacent
+ * check adjacent pixels for transparency as well.
+ * @return boolean true if transparent, false otherwise.
+ */
+ protected boolean isTransparentAt(final int x, final int y, final boolean checkAdjacent) {
+ // boundary checking
+ if (x < 0 || x >= getImageData().width || y < 0 || y >= getImageData().height) {
+ return true;
+ }
+
+ // check for alpha channel
+ int transValue = 255;
+ // check for transparency mask
+ if (getTransparencyMaskData() != null) {
+ transValue = getTransparencyMaskData().getPixel(x, y) == 0 ? 0 : 255;
+ }
+
+ if (transValue != 0) {
+ if (getImageData().alphaData != null) {
+ transValue = getImageData().getAlpha(x, y);
+ }
+ }
+
+ // use a tolerance
+ boolean trans = false;
+ if (transValue < 10) {
+ trans = true;
+
+ if (checkAdjacent) {
+ trans = trans && isTransparentAt(x + 1, y, false);
+ trans = trans && isTransparentAt(x + 1, y + 1, false);
+ trans = trans && isTransparentAt(x + 1, y - 1, false);
+ trans = trans && isTransparentAt(x - 1, y + 1, false);
+ trans = trans && isTransparentAt(x - 1, y, false);
+ trans = trans && isTransparentAt(x - 1, y - 1, false);
+ trans = trans && isTransparentAt(x, y + 1, false);
+ trans = trans && isTransparentAt(x, y - 1, false);
+ }
+ }
+
+ return trans;
+ }
+
+ /**
+ * getLocation Delegation function used by the ConnectionAnchor
+ * getLocation
+ *
+ * @param start
+ * the <code>Point</code> that is the beginning of a line
+ * segment used to calculate the anchor location inside the
+ * image.
+ * @param edge
+ * the <code>Point</code> that is the end of a line segment
+ * used to calculate the anchor location inside the image.
+ * @param isDefaultAnchor
+ * - true if location for the default anchor should be
+ * calculated
+ * @return Point representing the location inside the image to anchor
+ * to.
+ */
+ private Point getLocation(final Point start, final Point edge, final Rectangle containerRect, final boolean isDefaultAnchor) {
+
+ final Point top = containerRect.getTopLeft();
+ getOwner().getParent().translateToRelative(top);
+
+ Point ptIntersect = null;
+ final Rectangle imageBounds = getOwner().getBounds();
+ final Dimension dim = edge.getDifference(top);
+ final Point edgeImg = new Point(Math.max(0, Math.min(dim.width, imageBounds.width - 1)), Math.max(0, Math.min(dim.height, imageBounds.height - 1)));
+ final Dimension startDim = start.getDifference(top);
+ final Point startImg = new Point(Math.max(0, Math.min(startDim.width, imageBounds.width - 1)), Math.max(0, Math.min(startDim.height, imageBounds.height - 1)));
+ ptIntersect = calculateIntersection(startImg, edgeImg);
+ if (ptIntersect == null) {
+ return null;
+ }
+ return ptIntersect.getTranslated(top.x, top.y);
+ }
+
+ /**
+ * calculateIntersection Utility method to calculate the intersection
+ * point of a given point at an angle into the image to find the first
+ * opaque pixel.
+ *
+ * @param start
+ * Point that is in the center of the Image.
+ * @param edge
+ * Point that is on the edge of the Image.
+ * @return Point that is the intersection with the first opaque pixel.
+ */
+ private Point calculateIntersection(final Point start, final Point edge) {
+ final Point opaque = new Point(edge);
+
+ final LineSeg line = new LineSeg(start, edge);
+ long distance = Math.round(line.length());
+ final Rectangle imageBounds = getOwner().getBounds();
+ // otherwise calculate value
+ while (opaque.x >= 0 && opaque.x < imageBounds.width && opaque.y >= 0 && opaque.y < imageBounds.height) {
+ // convert x and y to client area.
+ final int imageWidth = getImageData().width;
+ final int imageHeight = getImageData().height;
+ final int x = (int) (opaque.x * (double) imageWidth / imageBounds.width);
+ final int y = (int) (opaque.y * (double) imageHeight / imageBounds.height);
+ if (!isTransparentAt(x, y, true)) {
+ return opaque;
+ }
+
+ line.pointOn(distance, LineSeg.KeyPoint.ORIGIN, opaque);
+ distance--;
+ }
+
+ // default is to fall through and return the chopbox point
+ return null;
+ }
+ }
+
+ /**
+ * Returns bounds of the figure.
+ *
+ * @return the owner figure
+ */
+ protected IFigure getContainer() {
+ return getOwner();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.draw2d.ui.figures.BaseSlidableAnchor#getLocation(org.eclipse.draw2d.geometry.Point,
+ * org.eclipse.draw2d.geometry.Point)
+ */
+ @Override
+ protected Point getLocation(final Point ownReference, final Point foreignReference) {
+ final Image image = getImage();
+ if (image == null) {
+ return super.getLocation(ownReference, foreignReference);
+ }
+ Rectangle bounds = getOwner().getBounds();
+ final ImageFigure imageFigure = getImageFigure();
+ if (imageFigure != null) {
+ bounds = imageFigure.getBounds();
+ }
+ final Rectangle ownerRect = new Rectangle(bounds);
+ getOwner().translateToAbsolute(ownerRect);
+ final PointList intersections = getIntersectionPoints(ownReference, foreignReference);
+ Point loc = null;
+ if (intersections != null && intersections.size() != 0) {
+ final Point ptRef = PointListUtilities.pickFarestPoint(intersections, foreignReference);
+ final Point ptEdge = PointListUtilities.pickClosestPoint(intersections, foreignReference);
+ final ImageAnchorLocation imgAnchorLocation = getImageAnchorLocation();
+ loc = imgAnchorLocation.getLocation(ptRef, ptEdge, ownerRect, isDefaultAnchor());
+ if (loc != null) {
+ loc = normalizeToStraightlineTolerance(foreignReference, loc, 3);
+ }
+ }
+ return loc;
+ }
+
+ private ImageAnchorLocation getImageAnchorLocation() {
+ if (this.imageAnchorLocation == null) {
+ final Image image = getImage();
+ this.imageAnchorLocation = new ImageAnchorLocation(image);
+ }
+ return imageAnchorLocation;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/anchor/AnchorProvider.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/anchor/AnchorProvider.java
new file mode 100644
index 0000000000..798dce4a39
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/anchor/AnchorProvider.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure.anchor;
+
+import org.eclipse.draw2d.ConnectionAnchor;
+import org.eclipse.draw2d.geometry.PrecisionPoint;
+
+import org.eclipse.sirius.diagram.ui.tools.api.figure.AirDefaultSizeNodeFigure;
+
+/**
+ * The anchor provider.
+ *
+ * @author ymortier
+ */
+public interface AnchorProvider {
+
+ /**
+ * Create and return an anchor.
+ *
+ * @param figure
+ * the figure that owns the anchor.
+ *
+ * @return the anchor.
+ */
+ ConnectionAnchor createDefaultAnchor(AirDefaultSizeNodeFigure figure);
+
+ /**
+ * Creates an anchor at the specified point (from the ratio of the
+ * reference's coordinates and bounds of the figure.
+ *
+ * @param figure
+ * the figure that owns the anchor.
+ *
+ * @param p
+ * relative reference for the <Code>SlidableAnchor</Code>
+ * @return a <code>ConnetionAnchor</code> for this figure with relative
+ * reference at p
+ */
+ ConnectionAnchor createAnchor(AirDefaultSizeNodeFigure figure, PrecisionPoint p);
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/anchor/ZoomDependantAnchor.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/anchor/ZoomDependantAnchor.java
new file mode 100644
index 0000000000..925a89e709
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/anchor/ZoomDependantAnchor.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure.anchor;
+
+import org.eclipse.gef.editparts.ZoomManager;
+
+/**
+ * Anchor should implement if they need to know the zoom level for location
+ * computation.
+ *
+ * @author mchauvin
+ */
+public interface ZoomDependantAnchor {
+ /**
+ * Set the zoom manager.
+ *
+ * @param manager
+ * the zoom manager.
+ */
+ void setZoomManager(ZoomManager manager);
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/locator/DBorderItemLocator.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/locator/DBorderItemLocator.java
new file mode 100644
index 0000000000..a970f58a28
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/locator/DBorderItemLocator.java
@@ -0,0 +1,804 @@
+/******************************************************************************
+ * Copyright (c) 2005, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Obeo - adaptation for designer
+ * Laurent Redor (Obeo) <laurent.redor@obeo.fr> - Trac #1735 : Port stability
+ ****************************************************************************/
+
+package org.eclipse.sirius.diagram.ui.tools.api.figure.locator;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.Layer;
+import org.eclipse.draw2d.PositionConstants;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gmf.runtime.diagram.ui.figures.BorderItemLocator;
+
+import com.google.common.collect.Lists;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.common.tools.api.util.Options;
+
+/**
+ * A specific
+ * {@link org.eclipse.gmf.runtime.draw2d.ui.figures.IBorderItemLocator} for
+ * Designer.
+ *
+ * @author ymortier
+ */
+public class DBorderItemLocator extends BorderItemLocator {
+
+ /**
+ * The number of sides. Used to avoid infinite loop exception in there is
+ * too many borderNode relative to the size of the container.
+ */
+ private static final int NB_SIDES = 4;
+
+ /** The left top offset. */
+ private Dimension leftTopOffset;
+
+ /** The right bottom offset. */
+ private Dimension rightBottomOffset;
+
+ /**
+ * Indicates whether the position of the border item has already been
+ * calculated. Uses to determine the conflicts with other border items
+ * locations.
+ */
+ private boolean located;
+
+ /**
+ * Indicates if the border item has moved. This determines if the
+ * computation of the position (relocate method) stems from a shift of the
+ * port itself or something else (a resizing of its container, for example).
+ *
+ */
+ private boolean borderItemHasMoved;
+
+ /**
+ * This list of figures is set during the build of the command in
+ * {@link org.eclipse.sirius.diagram.graphical.edit.policies.SpecificBorderItemSelectionEditPolicy}
+ * to be able to know the figures to ignore when draw2d will launch the
+ * redraw.
+ */
+ private List<IFigure> figuresToIgnoreDuringNextRelocate = Lists.newArrayList();
+
+ /**
+ * Create an {@link DBorderItemLocator} with the specified parentFigure.
+ *
+ * @param parentFigure
+ * the parent figure.
+ */
+ public DBorderItemLocator(final IFigure parentFigure) {
+ super(parentFigure);
+ }
+
+ /**
+ * Create a {@link DBorderItemLocator} with the specified item, parentFigure
+ * and constraint.
+ *
+ * @param borderItem
+ * the border item.
+ * @param parentFigure
+ * the parent figure.
+ * @param constraint
+ * the constraint.
+ */
+ public DBorderItemLocator(final IFigure borderItem, final IFigure parentFigure, final Rectangle constraint) {
+ super(borderItem, parentFigure, constraint);
+ }
+
+ /**
+ * Create a {@link DBorderItemLocator} with the specified item and
+ * preferredSide.
+ *
+ * @param parentFigure
+ * the parent figure.
+ * @param preferredSide
+ * the preferred side.
+ */
+ public DBorderItemLocator(final IFigure parentFigure, final int preferredSide) {
+ super(parentFigure, preferredSide);
+ }
+
+ /**
+ * Define the right bottom offset.
+ *
+ * @param rightBottomOffset
+ * the right bottom offset.
+ */
+ public void setRightBottomOffset(final Dimension rightBottomOffset) {
+ this.rightBottomOffset = rightBottomOffset;
+ }
+
+ /**
+ * Return the right bottom offset.
+ *
+ * @return the right bottom offset.
+ */
+ public Dimension getRightBottomOffset() {
+ if (this.rightBottomOffset != null) {
+ return rightBottomOffset;
+ }
+ return getBorderItemOffset();
+ }
+
+ /**
+ * Define the left top offset.
+ *
+ * @param leftTopOffset
+ * the left top offset.
+ */
+ public void setLeftTopOffset(final Dimension leftTopOffset) {
+ this.leftTopOffset = leftTopOffset;
+ }
+
+ /**
+ * Return the left top offset.
+ *
+ * @return the left top offset.
+ */
+ public Dimension getLeftTopOffset() {
+ if (this.leftTopOffset != null) {
+ return leftTopOffset;
+ }
+ return getBorderItemOffset();
+ }
+
+ /**
+ * Get the preferred location. If none has been previously set, use the
+ * preferred side to take an initial guess.
+ *
+ * @param borderItem
+ * the border item
+ * @return point
+ */
+ @Override
+ protected Point getPreferredLocation(final IFigure borderItem) {
+ final Point constraintLocation = getConstraint().getLocation();
+ final Point ptAbsoluteLocation = this.getAbsoluteToBorder(constraintLocation);
+ return ptAbsoluteLocation;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.figures.BorderItemLocator#relocate(org.eclipse.draw2d.IFigure)
+ */
+ @Override
+ public void relocate(final IFigure borderItem) {
+ Rectangle parentBounds = getParentFigure().getBounds().getCopy();
+ // If the relocate is called before that the figure have been
+ // "initialized", it is by-passed.
+ if (!(parentBounds.x == 0 && parentBounds.y == 0 && parentBounds.width <= 0 && parentBounds.height <= 0)) {
+ final Dimension size = getSize(borderItem);
+ final Rectangle rectSuggested = new Rectangle(getPreferredLocation(borderItem), size);
+ // If the border item has moved, we change the preferred side,
+ // otherwise we let the current side enabled
+ if (borderItemHasMoved) {
+ final int closestSide = DBorderItemLocator.findClosestSideOfParent(rectSuggested, getParentBorder());
+ setPreferredSideOfParent(closestSide);
+ setCurrentSideOfParent(closestSide);
+ borderItemHasMoved = false;
+ } else {
+ // We use the notion if figuresToIgnoreDuringNextRelocate only
+ // if bordered node is moved.
+ figuresToIgnoreDuringNextRelocate.clear();
+ }
+ final Point ptNewLocation = locateOnBorder(rectSuggested.getLocation(), getCurrentSideOfParent(), 0, borderItem, figuresToIgnoreDuringNextRelocate);
+ borderItem.setLocation(ptNewLocation);
+ figuresToIgnoreDuringNextRelocate.clear();
+ borderItem.setSize(size);
+ this.located = true;
+ }
+ }
+
+ @Override
+ protected Point locateOnBorder(Point suggestedLocation, int suggestedSide, int circuitCount, IFigure borderItem) {
+ List<IFigure> figuresToIgnore = Lists.newArrayList();
+ figuresToIgnore.add(borderItem);
+ return locateOnBorder(suggestedLocation, suggestedSide, circuitCount, borderItem, figuresToIgnore);
+ }
+
+ /**
+ * The preferred side takes precedence. Search prior on the suggestedSide
+ * then on the following side in the anticlockwise. This is behavior similar
+ * to that of GMF. We could envisage a more intelligent behavior that avoids
+ * passing over other borderedNodes even if it meant a move to the following
+ * side.
+ *
+ * @param suggestedLocation
+ * the suggested location
+ * @param suggestedSide
+ * the suggested side
+ * @param circuitCount
+ * recursion count to avoid an infinite loop
+ * @param borderItem
+ * the border item.
+ * @param portsFiguresToIgnore
+ * the ports figures to ignore
+ * @return point
+ */
+ protected Point locateOnBorder(final Point suggestedLocation, final int suggestedSide, final int circuitCount, final IFigure borderItem, final Collection<IFigure> portsFiguresToIgnore) {
+ Point recommendedLocation = locateOnParent(suggestedLocation, suggestedSide, borderItem);
+
+ if (circuitCount < NB_SIDES && conflicts(recommendedLocation, borderItem, portsFiguresToIgnore).some()) {
+ if (suggestedSide == PositionConstants.WEST) {
+ recommendedLocation = locateOnWestBorder(recommendedLocation, circuitCount, borderItem, portsFiguresToIgnore);
+ } else if (suggestedSide == PositionConstants.SOUTH) {
+ recommendedLocation = locateOnSouthBorder(recommendedLocation, circuitCount, borderItem, portsFiguresToIgnore);
+ } else if (suggestedSide == PositionConstants.EAST) {
+ recommendedLocation = locateOnEastBorder(recommendedLocation, circuitCount, borderItem, portsFiguresToIgnore);
+ } else { // NORTH
+ recommendedLocation = locateOnNorthBorder(recommendedLocation, circuitCount, borderItem, portsFiguresToIgnore);
+ }
+ }
+ return recommendedLocation;
+ }
+
+ /**
+ * Locate the recommendedLocation on the south border :
+ * <UL>
+ * <LI>Search alternately to the left and to the right until find an
+ * available space</LI>
+ * <LI>And finally if there is no space on this border search on the east
+ * border.</LI>
+ * </UL>
+ *
+ * @param recommendedLocation
+ * The desired location
+ * @param circuitCount
+ * recursion count to avoid an infinite loop
+ * @param borderItem
+ * the figure representing the border item.
+ * @param portsFiguresToIgnore
+ * the ports figures to ignore
+ * @return the location where the border item can be put
+ */
+ protected Point locateOnSouthBorder(final Point recommendedLocation, final int circuitCount, final IFigure borderItem, final Collection<IFigure> portsFiguresToIgnore) {
+ final Dimension borderItemSize = getSize(borderItem);
+ Point resultLocation = null;
+ final Point rightTestPoint = new Point(recommendedLocation);
+ final Point leftTestPoint = new Point(recommendedLocation);
+ boolean isStillFreeSpaceToTheRight = true;
+ boolean isStillFreeSpaceToTheLeft = true;
+ int rightVerticalGap = 0;
+ int leftVerticalGap = 0;
+ // The recommendedLocationForEast is set when we detected that there is
+ // not free space on right of south side.
+ Point recommendedLocationForEast = recommendedLocation;
+ while (resultLocation == null && (isStillFreeSpaceToTheRight || isStillFreeSpaceToTheLeft)) {
+ if (isStillFreeSpaceToTheRight) {
+ // Move to the right on the south side
+ rightTestPoint.x += rightVerticalGap;
+ Option<Rectangle> optionalConflictingRectangle = conflicts(rightTestPoint, borderItem, portsFiguresToIgnore);
+ if (optionalConflictingRectangle.some()) {
+ rightVerticalGap = (optionalConflictingRectangle.get().x + optionalConflictingRectangle.get().width + 1) - rightTestPoint.x;
+ if (rightTestPoint.x + rightVerticalGap + borderItemSize.width > getParentBorder().getBottomRight().x) {
+ isStillFreeSpaceToTheRight = false;
+ if (circuitCount == NB_SIDES - 1) {
+ // There is no space on either side (so use the last
+ // conflicting position)
+ resultLocation = optionalConflictingRectangle.get().getTopLeft();
+ } else {
+ recommendedLocationForEast = new Point(rightTestPoint.x + rightVerticalGap, optionalConflictingRectangle.get().y - borderItemSize.height - 1);
+ }
+ }
+ } else {
+ resultLocation = rightTestPoint;
+ }
+ }
+ if (isStillFreeSpaceToTheLeft && resultLocation == null) {
+ // Move to the left on the south side
+ leftTestPoint.x -= leftVerticalGap;
+ Option<Rectangle> optionalConflictingRectangle = conflicts(leftTestPoint, borderItem, portsFiguresToIgnore);
+ if (optionalConflictingRectangle.some()) {
+ leftVerticalGap = leftTestPoint.x - (optionalConflictingRectangle.get().x - borderItemSize.width - 1);
+ if (leftTestPoint.x - leftVerticalGap < getParentBorder().getTopLeft().x) {
+ isStillFreeSpaceToTheLeft = false;
+ }
+ } else {
+ resultLocation = leftTestPoint;
+ }
+ }
+ }
+ if (resultLocation == null) {
+ // south is full, try east.
+ resultLocation = locateOnBorder(recommendedLocationForEast, PositionConstants.EAST, circuitCount + 1, borderItem, portsFiguresToIgnore);
+ }
+ return resultLocation;
+ }
+
+ /**
+ * Locate the recommendedLocation on the north border :
+ * <UL>
+ * <LI>Search alternately to the left and to the right until find an
+ * available space</LI>
+ * <LI>And finally if there is no space on this border search on the west
+ * border.</LI>
+ * </UL>
+ *
+ * @param recommendedLocation
+ * The desired location
+ * @param circuitCount
+ * recursion count to avoid an infinite loop
+ * @param borderItem
+ * the figure representing the border item.
+ * @param portsFiguresToIgnore
+ * the ports figures to ignore
+ * @return the location where the border item can be put
+ */
+ protected Point locateOnNorthBorder(final Point recommendedLocation, final int circuitCount, final IFigure borderItem, final Collection<IFigure> portsFiguresToIgnore) {
+ final Dimension borderItemSize = getSize(borderItem);
+ Point resultLocation = null;
+ final Point rightTestPoint = new Point(recommendedLocation);
+ final Point leftTestPoint = new Point(recommendedLocation);
+ boolean isStillFreeSpaceToTheRight = true;
+ boolean isStillFreeSpaceToTheLeft = true;
+ int rightVerticalGap = 0;
+ int leftVerticalGap = 0;
+ // The recommendedLocationForWest is set when we detected that there is
+ // not free space on left of north side.
+ Point recommendedLocationForWest = recommendedLocation;
+ while (resultLocation == null && (isStillFreeSpaceToTheRight || isStillFreeSpaceToTheLeft)) {
+ if (isStillFreeSpaceToTheRight) {
+ // Move to the right on the north side
+ rightTestPoint.x += rightVerticalGap;
+ Option<Rectangle> optionalConflictingRectangle = conflicts(rightTestPoint, borderItem, portsFiguresToIgnore);
+ if (optionalConflictingRectangle.some()) {
+ rightVerticalGap = (optionalConflictingRectangle.get().x + optionalConflictingRectangle.get().width + 1) - rightTestPoint.x;
+ if (rightTestPoint.x + rightVerticalGap + borderItemSize.width > getParentBorder().getBottomRight().x) {
+ isStillFreeSpaceToTheRight = false;
+ }
+ } else {
+ resultLocation = rightTestPoint;
+ }
+ }
+ if (isStillFreeSpaceToTheLeft && resultLocation == null) {
+ // Move to the left on the north side
+ leftTestPoint.x -= leftVerticalGap;
+ Option<Rectangle> optionalConflictingRectangle = conflicts(leftTestPoint, borderItem, portsFiguresToIgnore);
+ if (optionalConflictingRectangle.some()) {
+ leftVerticalGap = leftTestPoint.x - (optionalConflictingRectangle.get().x - borderItemSize.width - 1);
+ if (leftTestPoint.x - leftVerticalGap < getParentBorder().getTopLeft().x) {
+ isStillFreeSpaceToTheLeft = false;
+ if (circuitCount == NB_SIDES - 1) {
+ // There is no space on either side (so use the last
+ // conflicting position)
+ resultLocation = optionalConflictingRectangle.get().getTopLeft();
+ } else {
+ recommendedLocationForWest = new Point(leftTestPoint.x - leftVerticalGap, optionalConflictingRectangle.get().y + optionalConflictingRectangle.get().height + 1);
+ }
+ }
+ } else {
+ resultLocation = leftTestPoint;
+ }
+ }
+ }
+ if (resultLocation == null) {
+ // North is full, try west.
+ resultLocation = locateOnBorder(recommendedLocationForWest, PositionConstants.WEST, circuitCount + 1, borderItem, portsFiguresToIgnore);
+ }
+ return resultLocation;
+ }
+
+ /**
+ * Locate the recommendedLocation on the west border :
+ * <UL>
+ * <LI>Search alternately upward and downward until find an available space</LI>
+ * <LI>And finally if there is no space on this border search on the south
+ * border.</LI>
+ * </UL>
+ *
+ * @param recommendedLocation
+ * The desired location
+ * @param circuitCount
+ * recursion count to avoid an infinite loop
+ * @param borderItem
+ * the figure representing the border item.
+ * @param portsFiguresToIgnore
+ * the ports figures to ignore
+ * @return the location where the border item can be put
+ */
+ protected Point locateOnWestBorder(final Point recommendedLocation, final int circuitCount, final IFigure borderItem, final Collection<IFigure> portsFiguresToIgnore) {
+ final Dimension borderItemSize = getSize(borderItem);
+ Point resultLocation = null;
+ final Point belowTestPoint = new Point(recommendedLocation);
+ final Point aboveTestPoint = new Point(recommendedLocation);
+ boolean isStillFreeSpaceAbove = true;
+ boolean isStillFreeSpaceBelow = true;
+ int belowVerticalGap = 0;
+ int aboveVerticalGap = 0;
+ // The recommendedLocationForSouth is set when we detected that there is
+ // not free space on bottom of west side.
+ Point recommendedLocationForSouth = recommendedLocation;
+ while (resultLocation == null && (isStillFreeSpaceAbove || isStillFreeSpaceBelow)) {
+ if (isStillFreeSpaceBelow) {
+ // Move down on the west side
+ belowTestPoint.y += belowVerticalGap;
+ Option<Rectangle> optionalConflictingRectangle = conflicts(belowTestPoint, borderItem, portsFiguresToIgnore);
+ if (optionalConflictingRectangle.some()) {
+ belowVerticalGap = optionalConflictingRectangle.get().y + optionalConflictingRectangle.get().height - belowTestPoint.y + 1;
+ if (belowTestPoint.y + belowVerticalGap + borderItemSize.height > getParentBorder().getBottomLeft().y) {
+ isStillFreeSpaceBelow = false;
+ if (circuitCount == NB_SIDES - 1) {
+ // There is no space on either side (so use the last
+ // conflicting position)
+ resultLocation = optionalConflictingRectangle.get().getTopLeft();
+ } else {
+ recommendedLocationForSouth = new Point(belowTestPoint.x + optionalConflictingRectangle.get().width + 1, belowTestPoint.y + belowVerticalGap);
+ }
+ }
+ } else {
+ resultLocation = belowTestPoint;
+ }
+ }
+ if (isStillFreeSpaceAbove && resultLocation == null) {
+ // Move up on the west side
+ aboveTestPoint.y -= aboveVerticalGap;
+ Option<Rectangle> optionalConflictingRectangle = conflicts(aboveTestPoint, borderItem, portsFiguresToIgnore);
+ if (optionalConflictingRectangle.some()) {
+ aboveVerticalGap = aboveTestPoint.y - (optionalConflictingRectangle.get().y - borderItemSize.height - 1);
+ if (aboveTestPoint.y - aboveVerticalGap < getParentBorder().getTopRight().y) {
+ isStillFreeSpaceAbove = false;
+ }
+ } else {
+ resultLocation = aboveTestPoint;
+ }
+ }
+ }
+ if (resultLocation == null) {
+ // west is full, try south.
+ resultLocation = locateOnBorder(recommendedLocationForSouth, PositionConstants.SOUTH, circuitCount + 1, borderItem, portsFiguresToIgnore);
+ }
+ return resultLocation;
+ }
+
+ /**
+ * Locate the recommendedLocation on the east border :
+ * <UL>
+ * <LI>Search alternately upward and downward until find an available space</LI>
+ * <LI>And finally if there is no space on this border search on the north
+ * border.</LI>
+ * </UL>
+ *
+ * @param recommendedLocation
+ * The desired location
+ * @param circuitCount
+ * recursion count to avoid an infinite loop
+ * @param borderItem
+ * the figure representing the border item.
+ * @param portsFiguresToIgnore
+ * the ports figures to ignore
+ * @return the location where the border item can be put
+ */
+ protected Point locateOnEastBorder(final Point recommendedLocation, final int circuitCount, final IFigure borderItem, final Collection<IFigure> portsFiguresToIgnore) {
+ final Dimension borderItemSize = getSize(borderItem);
+ Point resultLocation = null;
+ final Point belowTestPoint = new Point(recommendedLocation);
+ final Point aboveTestPoint = new Point(recommendedLocation);
+ boolean isStillFreeSpaceAbove = true;
+ boolean isStillFreeSpaceBelow = true;
+ int belowVerticalGap = 0;
+ int aboveVerticalGap = 0;
+ // The recommendedLocationForNorth is set when we detected that there is
+ // not free space on top of east side.
+ Point recommendedLocationForNorth = recommendedLocation;
+ while (resultLocation == null && (isStillFreeSpaceAbove || isStillFreeSpaceBelow)) {
+ if (isStillFreeSpaceBelow) {
+ // Move down on the east side
+ belowTestPoint.y += belowVerticalGap;
+ Option<Rectangle> optionalConflictingRectangle = conflicts(belowTestPoint, borderItem, portsFiguresToIgnore);
+ if (optionalConflictingRectangle.some()) {
+ belowVerticalGap = optionalConflictingRectangle.get().y + optionalConflictingRectangle.get().height - belowTestPoint.y + 1;
+ if (belowTestPoint.y + belowVerticalGap + borderItemSize.height > getParentBorder().getBottomLeft().y) {
+ isStillFreeSpaceBelow = false;
+ }
+ } else {
+ resultLocation = belowTestPoint;
+ }
+ }
+ if (isStillFreeSpaceAbove && resultLocation == null) {
+ // Move up on the east side
+ aboveTestPoint.y -= aboveVerticalGap;
+ Option<Rectangle> optionalConflictingRectangle = conflicts(aboveTestPoint, borderItem, portsFiguresToIgnore);
+ if (optionalConflictingRectangle.some()) {
+ aboveVerticalGap = aboveTestPoint.y - (optionalConflictingRectangle.get().y - borderItemSize.height - 1);
+ if (aboveTestPoint.y - aboveVerticalGap < getParentBorder().getTopRight().y) {
+ isStillFreeSpaceAbove = false;
+ if (circuitCount == NB_SIDES - 1) {
+ // There is no space on either side (so use the last
+ // conflicting position)
+ resultLocation = optionalConflictingRectangle.get().getTopLeft();
+ } else {
+ recommendedLocationForNorth = new Point(optionalConflictingRectangle.get().x - borderItemSize.width - 1, aboveTestPoint.y - aboveVerticalGap);
+ }
+ }
+ } else {
+ resultLocation = aboveTestPoint;
+ }
+ }
+ }
+ if (resultLocation == null) {
+ // East is full, try north.
+ resultLocation = locateOnBorder(recommendedLocationForNorth, PositionConstants.NORTH, circuitCount + 1, borderItem, portsFiguresToIgnore);
+ }
+ return resultLocation;
+ }
+
+ /**
+ * Ensure the suggested location actually lies on the parent boundary. The
+ * side takes precedence.
+ *
+ * @param suggestedLocation
+ * suggested location
+ * @param suggestedSide
+ * suggested side
+ * @param borderItem
+ * the border item.
+ * @return point the location point
+ */
+ protected Point locateOnParent(final Point suggestedLocation, final int suggestedSide, final IFigure borderItem) {
+ final Rectangle bounds = getParentBorder();
+ final int parentFigureWidth = bounds.width;
+ final int parentFigureHeight = bounds.height;
+ final int parentFigureX = bounds.x;
+ final int parentFigureY = bounds.y;
+ final Dimension borderItemSize = getSize(borderItem);
+ int newX = suggestedLocation.x;
+ int newY = suggestedLocation.y;
+ final int westX = parentFigureX - borderItemSize.width + getBorderItemOffset().width;
+ final int eastX = parentFigureX + parentFigureWidth - getBorderItemOffset().width;
+ final int southY = parentFigureY + parentFigureHeight - getBorderItemOffset().height;
+ final int northY = parentFigureY - borderItemSize.height + getBorderItemOffset().height;
+ if (suggestedSide == PositionConstants.WEST) {
+ if (suggestedLocation.x != westX) {
+ newX = westX;
+ }
+ if (suggestedLocation.y < bounds.getTopLeft().y) {
+ newY = northY + borderItemSize.height;
+ } else if (suggestedLocation.y > bounds.getBottomLeft().y - borderItemSize.height) {
+ newY = southY - borderItemSize.height;
+ }
+ } else if (suggestedSide == PositionConstants.EAST) {
+ if (suggestedLocation.x != eastX) {
+ newX = eastX;
+ }
+ if (suggestedLocation.y < bounds.getTopLeft().y) {
+ newY = northY + borderItemSize.height;
+ } else if (suggestedLocation.y > bounds.getBottomLeft().y - borderItemSize.height) {
+ newY = southY - borderItemSize.height;
+ }
+ } else if (suggestedSide == PositionConstants.SOUTH) {
+ if (suggestedLocation.y != southY) {
+ newY = southY;
+ }
+ if (borderItemSize.width > bounds.width) {
+ // The border item width is larger than the parent item. In that
+ // case, we will center the border item on the south side of the
+ // parent.
+ newX = parentFigureX - (borderItemSize.width - bounds.width) / 2;
+ } else if (suggestedLocation.x < bounds.getBottomLeft().x) {
+ newX = westX + borderItemSize.width;
+ } else if (suggestedLocation.x > bounds.getBottomRight().x - borderItemSize.width) {
+ newX = eastX - borderItemSize.width;
+ }
+ } else { // NORTH
+ if (suggestedLocation.y != northY) {
+ newY = northY;
+ }
+ if (borderItemSize.width > bounds.width) {
+ // The border item width is larger than the parent item. In that
+ // case, we will center the border item on the north side of the
+ // parent.
+ newX = parentFigureX - (borderItemSize.width - bounds.width) / 2;
+ } else if (suggestedLocation.x < bounds.getBottomLeft().x) {
+ newX = westX + borderItemSize.width;
+ } else if (suggestedLocation.x > bounds.getBottomRight().x - borderItemSize.width) {
+ newX = eastX - borderItemSize.width;
+ }
+ }
+ return new Point(newX, newY);
+ }
+
+ /**
+ * Determine if the the given point conflicts with the position of an
+ * existing borderItemFigure.
+ *
+ * @param recommendedLocation
+ * The desired location
+ * @param targetBorderItem
+ * the border node for which we detect conflicts.
+ * @param portsFiguresToIgnore
+ * the ports figures to ignore
+ * @return the optional Rectangle of the border item that is in conflict
+ * with the given bordered node (a none option)
+ */
+ protected Option<Rectangle> conflicts(final Point recommendedLocation, final IFigure targetBorderItem, final Collection<IFigure> portsFiguresToIgnore) {
+ final Rectangle recommendedRect = new Rectangle(recommendedLocation, getSize(targetBorderItem));
+ final List borderItems = targetBorderItem.getParent().getChildren();
+ final ListIterator iterator = borderItems.listIterator();
+ while (iterator.hasNext()) {
+ final IFigure borderItem = (IFigure) iterator.next();
+ if (!portsFiguresToIgnore.contains(borderItem)) {
+ boolean takeIntoAccount = true;
+ // We consider the brothers that :
+ // * have a parent without layoutManager and are directly in a
+ // Layer (this case
+ // corresponds to feedback of collapsed bordered nodes that are
+ // expanded during drop)
+ // * have a parent with a layoutManager and that contains a
+ // constraint of type DBorderItemLocator that is located.
+ if (borderItem.getParent().getLayoutManager() == null) {
+ if (!(borderItem.getParent() instanceof Layer)) {
+ takeIntoAccount = false;
+ }
+ } else if (borderItem.getParent().getLayoutManager().getConstraint(borderItem) instanceof DBorderItemLocator) {
+ final DBorderItemLocator airBorderItemLocator = (DBorderItemLocator) borderItem.getParent().getLayoutManager().getConstraint(borderItem);
+ takeIntoAccount = airBorderItemLocator.located;
+ }
+ if (borderItem.isVisible() && takeIntoAccount) {
+ final Rectangle rect = new Rectangle(borderItem.getBounds());
+ if (!(portsFiguresToIgnore.contains(borderItem)) && borderItem != targetBorderItem && rect.intersects(recommendedRect)) {
+ return Options.newSome(rect);
+ }
+ }
+ }
+ }
+ return Options.newNone();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.figures.BorderItemLocator#setConstraint(org.eclipse.draw2d.geometry.Rectangle)
+ */
+ @Override
+ public void setConstraint(final Rectangle theConstraint) {
+ if (!theConstraint.equals(getConstraint())) {
+ borderItemHasMoved = true;
+ }
+ super.setConstraint(theConstraint);
+ }
+
+ /**
+ * Provides a copy of the current {@link BorderItemLocator} constraint.
+ *
+ * @return a copy of the constraint rectangle.
+ */
+ public Rectangle getCurrentConstraint() {
+ return super.getConstraint().getCopy();
+ }
+
+ /**
+ * Find the closest side when x,y is inside parent.
+ *
+ * @param proposedLocation
+ * the proposed location
+ * @param parentBorder
+ * the parent border
+ * @return draw constant
+ */
+ public static int findClosestSideOfParent(final Rectangle proposedLocation, final Rectangle parentBorder) {
+ // Rectangle parentBorder = getParentBorder();
+ final Point parentCenter = parentBorder.getCenter();
+ final Point childCenter = proposedLocation.getCenter();
+
+ int position;
+
+ if (childCenter.x < parentCenter.x) {
+ // West, North or South.
+ if (childCenter.y < parentCenter.y) {
+ // west or north
+ // closer to west or north?
+ final Point parentTopLeft = parentBorder.getTopLeft();
+ if (childCenter.y < parentTopLeft.y) {
+ position = PositionConstants.NORTH;
+ } else if ((childCenter.x - parentTopLeft.x) <= (childCenter.y - parentTopLeft.y)) {
+ position = PositionConstants.WEST;
+ } else {
+ position = PositionConstants.NORTH;
+ }
+ } else { // west or south
+ final Point parentBottomLeft = parentBorder.getBottomLeft();
+ if (childCenter.y > parentBottomLeft.y) {
+ position = PositionConstants.SOUTH;
+ } else if ((childCenter.x - parentBottomLeft.x) <= (parentBottomLeft.y - childCenter.y)) {
+ position = PositionConstants.WEST;
+ } else {
+ position = PositionConstants.SOUTH;
+ }
+ }
+ } else {
+ // EAST, NORTH or SOUTH
+ if (childCenter.y < parentCenter.y) {
+ // north or east
+ final Point parentTopRight = parentBorder.getTopRight();
+ if (childCenter.y < parentTopRight.y) {
+ position = PositionConstants.NORTH;
+ } else if ((parentTopRight.x - childCenter.x) <= (childCenter.y - parentTopRight.y)) {
+ position = PositionConstants.EAST;
+ } else {
+ position = PositionConstants.NORTH;
+ }
+ } else { // south or east.
+ final Point parentBottomRight = parentBorder.getBottomRight();
+ if (childCenter.y > parentBottomRight.y) {
+ position = PositionConstants.SOUTH;
+ } else if ((parentBottomRight.x - childCenter.x) <= (parentBottomRight.y - childCenter.y)) {
+ position = PositionConstants.EAST;
+ } else {
+ position = PositionConstants.SOUTH;
+ }
+ }
+ }
+ return position;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.figures.BorderItemLocator#getValidLocation(org.eclipse.draw2d.geometry.Rectangle,
+ * org.eclipse.draw2d.IFigure)
+ */
+ @Override
+ public Rectangle getValidLocation(final Rectangle proposedLocation, final IFigure borderItem) {
+ final Rectangle realLocation = new Rectangle(proposedLocation);
+ final int side = DBorderItemLocator.findClosestSideOfParent(proposedLocation, getParentBorder());
+ final Point newTopLeft = locateOnBorder(realLocation.getTopLeft(), side, 0, borderItem);
+ realLocation.setLocation(newTopLeft);
+ return realLocation;
+ }
+
+ /**
+ * Lets consider this border item as not fixed.
+ */
+ public void unfix() {
+ located = false;
+ }
+
+ /**
+ * Get valid location.
+ *
+ * @param proposedLocation
+ * a proposed location and optionally size
+ * @param borderItem
+ * the border item in question
+ * @param figuresToIgnore
+ * list of figures to ignore during conflict detection. This list
+ * must contain at least the <code>borderItem</code>.
+ * @return a rectangle containing the valid location
+ */
+ public Rectangle getValidLocation(Rectangle proposedLocation, IFigure borderItem, Collection<IFigure> figuresToIgnore) {
+ final Rectangle realLocation = new Rectangle(proposedLocation);
+ final int side = DBorderItemLocator.findClosestSideOfParent(proposedLocation, getParentBorder());
+ final Point newTopLeft = locateOnBorder(realLocation.getTopLeft(), side, 0, borderItem, figuresToIgnore);
+ realLocation.setLocation(newTopLeft);
+ return realLocation;
+ }
+
+ /**
+ * This method must be used only when commands are build to move a bordered
+ * node (for example in
+ * {@link org.eclipse.sirius.diagram.graphical.edit.policies.SpecificBorderItemSelectionEditPolicy}
+ * ) after calling {@link #getValidLocation(Rectangle, IFigure, Collection)}
+ * .
+ *
+ * @param figuresToIgnore
+ * The list of figures to ignore.
+ */
+ public void setFiguresToIgnoresDuringNextRelocate(List<IFigure> figuresToIgnore) {
+ this.figuresToIgnoreDuringNextRelocate = figuresToIgnore;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/locator/NorthNameLocator.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/locator/NorthNameLocator.java
new file mode 100644
index 0000000000..116125bbda
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/figure/locator/NorthNameLocator.java
@@ -0,0 +1,148 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.figure.locator;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.PositionConstants;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gmf.runtime.diagram.ui.figures.LayoutHelper;
+import org.eclipse.gmf.runtime.draw2d.ui.figures.IBorderItemLocator;
+import org.eclipse.gmf.runtime.gef.ui.figures.NodeFigure;
+
+/**
+ * This locator locate the item in the north of the bordered figure.
+ *
+ * @author ymortier
+ */
+public class NorthNameLocator implements IBorderItemLocator {
+
+ /** Constraints. */
+ private Rectangle constraint;
+
+ /** the figure around which this border item appears */
+ private final IFigure parentFigure;
+
+ /** The offset between the bordered figure and the border item. */
+ private int offset = 10;
+
+ /**
+ * Create a new <code>LilelineNameLocator</code>.
+ *
+ * @param parentFigure
+ * the parent figure.
+ */
+ public NorthNameLocator(final IFigure parentFigure) {
+ this.parentFigure = parentFigure;
+ }
+
+ /**
+ * Create a new <code>LilelineNameLocator</code>.
+ *
+ * @param parentFigure
+ * the parent figure.
+ * @param offset
+ * The offset between the bordered figure and the border item.
+ */
+ public NorthNameLocator(final IFigure parentFigure, final int offset) {
+ this.parentFigure = parentFigure;
+ this.offset = offset;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.draw2d.ui.figures.IBorderItemLocator#getCurrentSideOfParent()
+ */
+ public int getCurrentSideOfParent() {
+ return PositionConstants.NORTH;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.draw2d.ui.figures.IBorderItemLocator#getValidLocation(org.eclipse.draw2d.geometry.Rectangle,
+ * org.eclipse.draw2d.IFigure)
+ */
+ public Rectangle getValidLocation(final Rectangle proposedLocation, final IFigure borderItem) {
+ final Rectangle realLocation = new Rectangle(proposedLocation);
+ final int x = (getParentBorder().x + (getParentBorder().width / 2)) - (getSize(borderItem).width / 2);
+ final int y = getParentBorder().y - getSize(borderItem).height - this.offset;
+ realLocation.setLocation(new Point(x, y));
+ realLocation.setSize(getSize(borderItem));
+ return realLocation;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.draw2d.ui.figures.IBorderItemLocator#setConstraint(org.eclipse.draw2d.geometry.Rectangle)
+ */
+ public void setConstraint(final Rectangle constraint) {
+ this.constraint = constraint;
+ getParentFigure().revalidate();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.Locator#relocate(org.eclipse.draw2d.IFigure)
+ */
+ public void relocate(final IFigure target) {
+ final Rectangle proposed = new Rectangle(this.constraint);
+ this.getParentFigure().translateToAbsolute(proposed);
+ this.constraint = this.getValidLocation(proposed, target);
+ target.setSize(this.getSize(target));
+ target.setLocation(this.constraint.getLocation());
+ }
+
+ /**
+ * Return the parentFigure.
+ *
+ * @return the parentFigure.
+ */
+ public IFigure getParentFigure() {
+ return this.parentFigure;
+ }
+
+ /**
+ * Utility to calculate the parent bounds with consideration for the handle
+ * bounds inset.
+ *
+ * @return <code>Rectangle</code> that is the bounds of the parent.
+ */
+ protected Rectangle getParentBorder() {
+ Rectangle bounds = new Rectangle(getParentFigure().getBounds());
+ if (getParentFigure() instanceof NodeFigure) {
+ bounds = new Rectangle(((NodeFigure) getParentFigure()).getHandleBounds());
+ }
+ return bounds;
+ }
+
+ /**
+ * Gets the size of the border item figure.
+ *
+ * @param borderItem
+ * the border item figure to get the size
+ * @return the size of the border item figure.
+ */
+ protected final Dimension getSize(final IFigure borderItem) {
+ Dimension size = LayoutHelper.UNDEFINED.getSize();
+ if (this.constraint != null) {
+ size = this.constraint.getSize();
+ }
+ if (LayoutHelper.UNDEFINED.getSize().equals(size)) {
+ size = borderItem.getPreferredSize();
+ }
+ return size;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/AbstractSiriusLayoutDataManager.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/AbstractSiriusLayoutDataManager.java
new file mode 100644
index 0000000000..a89f742470
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/AbstractSiriusLayoutDataManager.java
@@ -0,0 +1,828 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2012 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.eclipse.draw2d.PositionConstants;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gef.ConnectionEditPart;
+import org.eclipse.gef.EditPartViewer;
+import org.eclipse.gef.GraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.notation.Bendpoints;
+import org.eclipse.gmf.runtime.notation.Bounds;
+import org.eclipse.gmf.runtime.notation.Diagram;
+import org.eclipse.gmf.runtime.notation.Edge;
+import org.eclipse.gmf.runtime.notation.IdentityAnchor;
+import org.eclipse.gmf.runtime.notation.JumpLinkStatus;
+import org.eclipse.gmf.runtime.notation.JumpLinkType;
+import org.eclipse.gmf.runtime.notation.Location;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.NotationFactory;
+import org.eclipse.gmf.runtime.notation.NotationPackage;
+import org.eclipse.gmf.runtime.notation.RelativeBendpoints;
+import org.eclipse.gmf.runtime.notation.Routing;
+import org.eclipse.gmf.runtime.notation.RoutingStyle;
+import org.eclipse.gmf.runtime.notation.Smoothness;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.gmf.runtime.notation.datatype.RelativeBendpoint;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+import org.eclipse.sirius.common.tools.api.util.StringUtil;
+import org.eclipse.sirius.AbstractDNode;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DEdge;
+import org.eclipse.sirius.DNode;
+import org.eclipse.sirius.DNodeContainer;
+import org.eclipse.sirius.DNodeList;
+import org.eclipse.sirius.DNodeListElement;
+import org.eclipse.sirius.DSemanticDecorator;
+import org.eclipse.sirius.EdgeTarget;
+import org.eclipse.sirius.business.api.query.DDiagramElementQuery;
+import org.eclipse.sirius.diagram.business.api.query.NodeQuery;
+import org.eclipse.sirius.diagram.business.api.view.SiriusGMFHelper;
+import org.eclipse.sirius.diagram.edit.api.part.AbstractDiagramBorderNodeEditPart;
+import org.eclipse.sirius.diagram.internal.refresh.GMFHelper;
+import org.eclipse.sirius.diagram.internal.refresh.borderednode.CanonicalDBorderItemLocator;
+import org.eclipse.sirius.diagram.layoutdata.AbstractLayoutData;
+import org.eclipse.sirius.diagram.layoutdata.EdgeLayoutData;
+import org.eclipse.sirius.diagram.layoutdata.LayoutdataFactory;
+import org.eclipse.sirius.diagram.layoutdata.LayoutdataPackage;
+import org.eclipse.sirius.diagram.layoutdata.NodeLayoutData;
+import org.eclipse.sirius.diagram.layoutdata.Point;
+import org.eclipse.sirius.diagram.part.SiriusDiagramEditorPlugin;
+import org.eclipse.sirius.diagram.tools.api.draw2d.ui.figures.FigureUtilities;
+import org.eclipse.sirius.diagram.tools.api.graphical.edit.styles.IBorderItemOffsets;
+
+/**
+ * An abstract implementation for {@link SiriusLayoutDataManager}. <BR>
+ * Provide a method to store a layout from a graphicalEditPart and iterates on
+ * it's children.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ *
+ */
+public abstract class AbstractSiriusLayoutDataManager implements SiriusLayoutDataManager {
+
+ private static final Class<?>[] CLASS_EXCEPTIONS = new Class[] { DNodeListElement.class };
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.layout.SiriusLayoutDataManager#storeLayoutData(org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart)
+ */
+ public void storeLayoutData(final IGraphicalEditPart rootEditPart) {
+ final Collection<LayoutDataKey> discoveredKeys = Sets.newHashSet();
+ final EObject semanticElement = rootEditPart.resolveSemanticElement();
+ final View toStoreView = (View) rootEditPart.getModel();
+ if (toStoreView instanceof Edge && semanticElement instanceof DEdge) {
+ addEdgeLayoutData(null, (DEdge) semanticElement, rootEditPart.getRoot().getViewer());
+ } else if (toStoreView instanceof Diagram && semanticElement instanceof DDiagram) {
+ addChildLayout((DDiagram) semanticElement, rootEditPart, discoveredKeys);
+ } else if (toStoreView instanceof Node) {
+ if (semanticElement instanceof DDiagramElement && semanticElement instanceof DSemanticDecorator) {
+ addChildLayout(null, (DSemanticDecorator) semanticElement, (Node) toStoreView, rootEditPart, discoveredKeys);
+ }
+ }
+ discoveredKeys.clear();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.layout.SiriusLayoutDataManager#applyLayout(org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart,
+ * org.eclipse.gef.EditPartViewer)
+ */
+ public void applyLayout(final IGraphicalEditPart rootEditPart) {
+ final EObject semanticElement = rootEditPart.resolveSemanticElement();
+ final View toStoreView = (View) rootEditPart.getModel();
+ if (toStoreView instanceof Edge) {
+ // TODOLRE : Manage the edge as root ?
+ } else if (toStoreView instanceof Diagram && semanticElement instanceof DDiagram) {
+ applyLayout((DDiagram) semanticElement, (Diagram) toStoreView, rootEditPart.getRoot().getViewer());
+ } else if (toStoreView instanceof Node) {
+ if (semanticElement instanceof DDiagramElement && semanticElement instanceof DSemanticDecorator) {
+ applyLayout((DSemanticDecorator) semanticElement, (Node) toStoreView, rootEditPart.getRoot().getViewer(), null);
+ }
+ }
+ }
+
+ /**
+ * @param semanticDecorator
+ * @param toStoreView
+ * @param editPartViewer
+ * The viewer responsible for the current editparts lifecycle.
+ */
+ private void applyLayout(final DDiagram diagram, final Diagram toStoreView, final EditPartViewer editPartViewer) {
+ // We don't apply layout on diagram but only on its node children (the
+ // edge is applied during source node).
+ for (final AbstractDNode node : Iterables.filter(diagram.getOwnedDiagramElements(), AbstractDNode.class)) {
+ final Node gmfNode = SiriusGMFHelper.getGmfNode(node);
+ if (gmfNode != null) {
+ applyLayout(node, gmfNode, editPartViewer, null);
+ }
+ }
+ }
+
+ /**
+ * @param sourceNode
+ * @param editPartViewer
+ */
+ private void applyLayoutToOutgoingEdge(final EdgeTarget sourceNode, final EditPartViewer editPartViewer) {
+ for (final DEdge edge : sourceNode.getOutgoingEdges()) {
+ final Edge gmfEdge = SiriusGMFHelper.getGmfEdge(edge);
+ if (gmfEdge != null) {
+ applyLayout(edge, gmfEdge, editPartViewer);
+ }
+ }
+ }
+
+ /**
+ * @param edge
+ * @param gmfEdge
+ * @param editPartViewer
+ */
+ private void applyLayout(final DEdge edge, final Edge gmfEdge, final EditPartViewer editPartViewer) {
+ final EdgeLayoutData layoutData = (EdgeLayoutData) getLayoutData(createKey(edge));
+ if (layoutData != null) {
+
+ final Bendpoints bendpoints = convertPointsToGMFBendpoint(layoutData);
+ gmfEdge.setBendpoints(bendpoints);
+
+ if (layoutData.getSourceTerminal() != null) {
+ if (gmfEdge.getSourceAnchor() == null) {
+ gmfEdge.setSourceAnchor(NotationFactory.eINSTANCE.createIdentityAnchor());
+ }
+ if (gmfEdge.getSourceAnchor() instanceof IdentityAnchor) {
+ ((IdentityAnchor) gmfEdge.getSourceAnchor()).setId(layoutData.getSourceTerminal());
+ }
+ } else if (gmfEdge.getSourceAnchor() instanceof IdentityAnchor) {
+ gmfEdge.setSourceAnchor(null);
+ }
+ if (layoutData.getTargetTerminal() != null) {
+ if (gmfEdge.getTargetAnchor() == null) {
+ gmfEdge.setTargetAnchor(NotationFactory.eINSTANCE.createIdentityAnchor());
+ }
+ if (gmfEdge.getTargetAnchor() instanceof IdentityAnchor) {
+ ((IdentityAnchor) gmfEdge.getTargetAnchor()).setId(layoutData.getTargetTerminal());
+ }
+ } else if (gmfEdge.getTargetAnchor() instanceof IdentityAnchor) {
+ gmfEdge.setTargetAnchor(null);
+ }
+ final RoutingStyle routingStyle = (RoutingStyle) gmfEdge.getStyle(NotationPackage.eINSTANCE.getRoutingStyle());
+ if (routingStyle != null) {
+ routingStyle.setRouting(Routing.get(layoutData.getRouting()));
+ routingStyle.setJumpLinkStatus(JumpLinkStatus.get(layoutData.getJumpLinkStatus()));
+ routingStyle.setJumpLinkType(JumpLinkType.get(layoutData.getJumpLinkType()));
+ routingStyle.setJumpLinksReverse(layoutData.isReverseJumpLink());
+ routingStyle.setSmoothness(Smoothness.get(layoutData.getSmoothness()));
+ }
+
+ applyLabelLayout(gmfEdge, layoutData);
+ }
+ }
+
+ private void applyLabelLayout(final View gmfView, final AbstractLayoutData parentLayoutData) {
+ if (parentLayoutData != null) {
+ final Node labelNode = SiriusGMFHelper.getLabelNode(gmfView);
+ if (parentLayoutData.getLabel() != null && labelNode != null) {
+ if (!parentLayoutData.getLabel().eIsSet(LayoutdataPackage.eINSTANCE.getNodeLayoutData_Width())
+ && !parentLayoutData.getLabel().eIsSet(LayoutdataPackage.eINSTANCE.getNodeLayoutData_Height())) {
+ Location location = NotationFactory.eINSTANCE.createLocation();
+ location.setX(parentLayoutData.getLabel().getLocation().getX());
+ location.setY(parentLayoutData.getLabel().getLocation().getY());
+ labelNode.setLayoutConstraint(location);
+ } else {
+ Bounds bounds = NotationFactory.eINSTANCE.createBounds();
+ bounds.setX(parentLayoutData.getLabel().getLocation().getX());
+ bounds.setY(parentLayoutData.getLabel().getLocation().getY());
+ bounds.setWidth(parentLayoutData.getLabel().getWidth());
+ bounds.setHeight(parentLayoutData.getLabel().getHeight());
+ labelNode.setLayoutConstraint(bounds);
+ }
+ }
+ }
+ }
+
+ /**
+ * @param edgeLayoutData
+ * The layout data of the edge
+ * @return
+ */
+ private Bendpoints convertPointsToGMFBendpoint(final EdgeLayoutData edgeLayoutData) {
+ final RelativeBendpoints result = NotationFactory.eINSTANCE.createRelativeBendpoints();
+
+ final List<RelativeBendpoint> relativeBendpoints = new LinkedList<RelativeBendpoint>();
+
+ final Point source = edgeLayoutData.getSourceRefPoint();
+ final Point target = edgeLayoutData.getTargetRefPoint();
+
+ /* source and target may be null if edit part was not created */
+ if (source != null && target != null) {
+ final org.eclipse.draw2d.geometry.Point sourceRefPoint = new org.eclipse.draw2d.geometry.Point(source.getX(), source.getY());
+ final org.eclipse.draw2d.geometry.Point targetRefPoint = new org.eclipse.draw2d.geometry.Point(target.getX(), target.getY());
+
+ for (final Point point : edgeLayoutData.getPointList()) {
+ final org.eclipse.draw2d.geometry.Point tempPoint = new org.eclipse.draw2d.geometry.Point(point.getX(), point.getY());
+ final Dimension s = tempPoint.getDifference(sourceRefPoint);
+ final Dimension t = tempPoint.getDifference(targetRefPoint);
+ relativeBendpoints.add(new RelativeBendpoint(s.width, s.height, t.width, t.height));
+ }
+ }
+ result.setPoints(relativeBendpoints);
+
+ return result;
+ }
+
+ /**
+ * Search a layout corresponding to the semantic decorator and applies it to
+ * the node. Then it applies to it's children and outgoing edges.
+ *
+ * @param semanticDecorator
+ * The semantic decorator to search the corresponding layout
+ * @param toRestoreView
+ * Node on which to apply the layout
+ * @param editPartViewer
+ * The viewer responsible for the current editparts lifecycle.
+ * @parentLayoutData the layout of the parent of <code>toRestoreView<code>
+ */
+ private void applyLayout(final DSemanticDecorator semanticDecorator, final Node toRestoreView, final EditPartViewer editPartViewer, final NodeLayoutData parentLayoutData) {
+ LayoutDataKey key = createKey(semanticDecorator);
+ NodeLayoutData layoutData = (NodeLayoutData) getLayoutData(key);
+
+ // If a direct child have the same layout data and key than its parents,
+ // look in the parent layout data 's children for a child layout data
+ // with the expected id.
+ if (parentLayoutData != null && parentLayoutData == layoutData && !StringUtil.isEmpty(key.getId())) {
+ layoutData = null;
+ for (NodeLayoutData childLayoutData : parentLayoutData.getChildren()) {
+ // if many children layout with same id, a choice will not be
+ // possible;
+ if (key.getId().equals(childLayoutData.getId())) {
+ if (layoutData == null) {
+ layoutData = childLayoutData;
+ } else {
+ layoutData = null;
+ break;
+ }
+ }
+ }
+ }
+
+ if (layoutData != null) {
+ final Bounds bounds = NotationFactory.eINSTANCE.createBounds();
+ final IGraphicalEditPart graphicalEditPart = (IGraphicalEditPart) editPartViewer.getEditPartRegistry().get(toRestoreView);
+ Point locationToApply;
+ boolean isCollapsed = false;
+ if (graphicalEditPart instanceof AbstractDiagramBorderNodeEditPart) {
+ // Specific treatment for border node
+ // Compute absolute location
+ locationToApply = LayoutDataHelper.INSTANCE.getAbsoluteLocation(layoutData);
+ // Compute the best location according to other existing
+ // bordered nodes.
+ Node parentNode = (Node) toRestoreView.eContainer();
+ CanonicalDBorderItemLocator locator = new CanonicalDBorderItemLocator(parentNode, PositionConstants.NSEW);
+ if (semanticDecorator instanceof DDiagramElement) {
+ if (new DDiagramElementQuery((DDiagramElement) semanticDecorator).isIndirectlyCollapsed()) {
+ isCollapsed = true;
+ locator.setBorderItemOffset(IBorderItemOffsets.COLLAPSE_FILTER_OFFSET);
+ } else {
+ locator.setBorderItemOffset(IBorderItemOffsets.DEFAULT_OFFSET);
+ }
+ } else {
+ locator.setBorderItemOffset(IBorderItemOffsets.DEFAULT_OFFSET);
+ }
+ final Rectangle rect = new Rectangle(locationToApply.getX(), locationToApply.getY(), layoutData.getWidth(), layoutData.getHeight());
+ final org.eclipse.draw2d.geometry.Point realLocation = locator.getValidLocation(rect, toRestoreView, Lists.newArrayList(toRestoreView));
+ // Compute the new relative position to the parent
+ final org.eclipse.draw2d.geometry.Point parentAbsoluteLocation = ((IGraphicalEditPart) graphicalEditPart.getParent()).getFigure().getBounds().getTopLeft().getCopy();
+ FigureUtilities.translateToAbsoluteByIgnoringScrollbar(((IGraphicalEditPart) graphicalEditPart.getParent()).getFigure(), parentAbsoluteLocation);
+ locationToApply.setX(realLocation.x);
+ locationToApply.setY(realLocation.y);
+ locationToApply = LayoutDataHelper.INSTANCE.getTranslated(locationToApply, parentAbsoluteLocation.negate());
+ } else {
+ locationToApply = LayoutDataHelper.INSTANCE.getRelativeLocation(layoutData, graphicalEditPart);
+
+ // Apply the location to the figure to, to correctly compute
+ // the relative location of the children
+ graphicalEditPart.getFigure().setLocation(new org.eclipse.draw2d.geometry.Point(locationToApply.getX(), locationToApply.getY()));
+ }
+ bounds.setX(locationToApply.getX());
+ bounds.setY(locationToApply.getY());
+ if (isCollapsed) {
+ Dimension dim = new NodeQuery(toRestoreView).getCollapsedSize();
+ bounds.setHeight(dim.height);
+ bounds.setWidth(dim.width);
+ } else {
+ bounds.setHeight(layoutData.getHeight());
+ bounds.setWidth(layoutData.getWidth());
+ }
+ toRestoreView.setLayoutConstraint(bounds);
+ }
+ if (semanticDecorator instanceof DNode) {
+ applyLayoutToNodeChildren((DNode) semanticDecorator, editPartViewer, layoutData);
+ } else if (semanticDecorator instanceof DNodeContainer) {
+ applyLayoutToNodeContainerChildren((DNodeContainer) semanticDecorator, editPartViewer, layoutData);
+ } else if (semanticDecorator instanceof DNodeList) {
+ applyLayoutToNodeListChildren((DNodeList) semanticDecorator, editPartViewer, layoutData);
+ } else {
+ logWarnMessage(semanticDecorator);
+ }
+ // Deal with the outgoing edges
+ if (semanticDecorator instanceof EdgeTarget) {
+ applyLayoutToOutgoingEdge((EdgeTarget) semanticDecorator, editPartViewer);
+ }
+ }
+
+ private void logWarnMessage(final DSemanticDecorator semanticDecorator) {
+ final Class<?> clazz = semanticDecorator.getClass();
+
+ boolean logWarn = true;
+ for (final Class<?> exceptionClass : CLASS_EXCEPTIONS) {
+ if (exceptionClass.isAssignableFrom(clazz)) {
+ logWarn = false;
+ break;
+ }
+ }
+
+ if (logWarn) {
+ SiriusDiagramEditorPlugin.getInstance().logWarning("This kind of diagram element (" + semanticDecorator.getClass().getName() + ") is not yet managed by the LayoutDataManager.");
+ }
+ }
+
+ /**
+ * Try to apply a layout to the children of the {@link DNode}.
+ *
+ * @param parentNode
+ * The parent containing children to apply layout on.
+ * @param editPartViewer
+ * The viewer responsible for the current editparts lifecycle.
+ */
+ private void applyLayoutToNodeChildren(final DNode parentNode, final EditPartViewer editPartViewer, final NodeLayoutData layoutData) {
+ // Restore Bordered nodes
+ applyLayoutForBorderedNodes(parentNode.getOwnedBorderedNodes(), editPartViewer, layoutData);
+ // Restore label
+ final Node gmfNode = SiriusGMFHelper.getGmfNode(parentNode);
+ applyLabelLayout(gmfNode, layoutData);
+ }
+
+ /**
+ * Try to apply a layout to the children of the {@link DNodeContainer}.
+ *
+ * @param container
+ * The parent containing children to apply layout on.
+ * @param editPartViewer
+ * The viewer responsible for the current editparts lifecycle.
+ */
+ private void applyLayoutToNodeContainerChildren(final DNodeContainer container, final EditPartViewer editPartViewer, final NodeLayoutData layoutData) {
+ // Restore children
+ for (final DDiagramElement child : container.getOwnedDiagramElements()) {
+ if (child instanceof AbstractDNode) {
+ // Search the GMF node corresponding to the child
+ final Node gmfNode = SiriusGMFHelper.getGmfNode(child);
+ if (gmfNode != null) {
+ applyLayout(child, gmfNode, editPartViewer, layoutData);
+ }
+ }
+ }
+ // Restore Bordered nodes
+ applyLayoutForBorderedNodes(container.getOwnedBorderedNodes(), editPartViewer, layoutData);
+ // Restore label
+ final Node gmfNode = SiriusGMFHelper.getGmfNode(container);
+ applyLabelLayout(gmfNode, layoutData);
+ }
+
+ /**
+ * Try to apply the layout to the bordered nodes.
+ *
+ * @param borderedNodes
+ * The list of bordered nodes to deals with
+ * @param editPartViewer
+ * The viewer responsible for the current editparts lifecycle.
+ * @param parentLayoutData
+ * The layoutData of the parent of the borderedNodes
+ */
+ private void applyLayoutForBorderedNodes(EList<DNode> borderedNodes, EditPartViewer editPartViewer, NodeLayoutData parentLayoutData) {
+ HashMap<Node, NodeLayoutData> nodesWithLayoutDataToApply = Maps.newHashMap();
+ HashMap<Node, DSemanticDecorator> nodesWithCoresspondingDSemanticDecorator = Maps.newHashMap();
+ // Search each bordered nodes that have layoutData to apply
+ for (final DNode child : borderedNodes) {
+ // Search the GMF node corresponding to the child
+ final Node gmfNode = SiriusGMFHelper.getGmfNode(child);
+ if (gmfNode != null) {
+ LayoutDataKey key = createKey(child);
+ NodeLayoutData layoutData = (NodeLayoutData) getLayoutData(key);
+
+ // If a direct child have the same layout data and key than its
+ // parents, look in the parent layout data 's children for a
+ // child layout data with the expected id.
+ if (parentLayoutData != null && parentLayoutData == layoutData && !StringUtil.isEmpty(key.getId())) {
+ layoutData = null;
+ for (NodeLayoutData childLayoutData : parentLayoutData.getChildren()) {
+ // if many children layout with same id, a choice will
+ // not be possible
+ if (key.getId().equals(childLayoutData.getId())) {
+ if (layoutData == null) {
+ layoutData = childLayoutData;
+ } else {
+ layoutData = null;
+ break;
+ }
+ }
+ }
+ }
+ if (layoutData != null) {
+ nodesWithLayoutDataToApply.put(gmfNode, layoutData);
+ nodesWithCoresspondingDSemanticDecorator.put(gmfNode, child);
+ }
+ }
+ }
+ // Iterate over each bordered nodes which have layout data to apply to
+ Set<Node> toIgnore = nodesWithLayoutDataToApply.keySet();
+ for (Entry<Node, NodeLayoutData> entry : nodesWithLayoutDataToApply.entrySet()) {
+ Node node = entry.getKey();
+ applyLayoutForBorderedNode(nodesWithCoresspondingDSemanticDecorator.get(node), node, editPartViewer, entry.getValue(), toIgnore);
+ }
+ }
+
+ /**
+ * Try to apply the layout to a bordered node.
+ *
+ * @param semanticDecorator
+ * The semantic decorator associated with this Node
+ * @param toRestoreView
+ * Node on which to apply the layout
+ * @param editPartViewer
+ * The viewer responsible for the current editparts lifecycle.
+ * @param layoutData
+ * the layout to apply on <code>toRestoreView<code>
+ * @param portsNodesToIgnore
+ * The list of bordered nodes to ignore in the conflict detection
+ */
+ private void applyLayoutForBorderedNode(final DSemanticDecorator semanticDecorator, final Node toRestoreView, final EditPartViewer editPartViewer, final NodeLayoutData layoutData,
+ final Set<Node> portsNodesToIgnore) {
+ final Bounds bounds = NotationFactory.eINSTANCE.createBounds();
+ Point locationToApply;
+ boolean isCollapsed = false;
+ if (!(toRestoreView.eContainer() instanceof Node)) {
+ return;
+ }
+ Node parentNode = (Node) toRestoreView.eContainer();
+
+ Object parentGraphicalEditPart = editPartViewer.getEditPartRegistry().get(parentNode);
+ NodeQuery nodeQuery = new NodeQuery(toRestoreView);
+
+ if (nodeQuery.isBorderedNode() && parentGraphicalEditPart instanceof IGraphicalEditPart) {
+ // Specific treatment for border node
+ // Compute absolute location
+ locationToApply = LayoutDataHelper.INSTANCE.getAbsoluteLocation(layoutData);
+ // Compute the best location according to other existing
+ // bordered nodes.
+
+ CanonicalDBorderItemLocator locator = new CanonicalDBorderItemLocator(parentNode, PositionConstants.NSEW);
+ if (semanticDecorator instanceof DDiagramElement) {
+ if (new DDiagramElementQuery((DDiagramElement) semanticDecorator).isIndirectlyCollapsed()) {
+ isCollapsed = true;
+ locator.setBorderItemOffset(IBorderItemOffsets.COLLAPSE_FILTER_OFFSET);
+ } else {
+ locator.setBorderItemOffset(IBorderItemOffsets.DEFAULT_OFFSET);
+ }
+ } else {
+ locator.setBorderItemOffset(IBorderItemOffsets.DEFAULT_OFFSET);
+ }
+
+ // CanonicalDBorderItemLocator works with absolute GMF parent
+ // location so we need to translate BorderedNode absolute location
+ // from Draw2D to GMF.
+
+ Point delta = getGMFDraw2DDelta(parentNode, (IGraphicalEditPart) parentGraphicalEditPart);
+ final Rectangle rect = new Rectangle(locationToApply.getX() - delta.getX(), locationToApply.getY() - delta.getY(), layoutData.getWidth(), layoutData.getHeight());
+
+ final org.eclipse.draw2d.geometry.Point realLocation = locator.getValidLocation(rect, toRestoreView, portsNodesToIgnore);
+
+ // Compute the new relative position to the parent
+ final org.eclipse.draw2d.geometry.Point parentAbsoluteLocation = GMFHelper.getAbsoluteBounds(parentNode).getTopLeft();
+ locationToApply.setX(realLocation.x);
+ locationToApply.setY(realLocation.y);
+ locationToApply = LayoutDataHelper.INSTANCE.getTranslated(locationToApply, parentAbsoluteLocation.negate());
+
+ } else {
+ Object graphicalEditPart = editPartViewer.getEditPartRegistry().get(toRestoreView);
+ if (graphicalEditPart instanceof IGraphicalEditPart) {
+ locationToApply = LayoutDataHelper.INSTANCE.getRelativeLocation(layoutData, (IGraphicalEditPart) graphicalEditPart);
+ // Apply the location to the figure to, to correctly compute
+ // the relative location of the children
+ ((GraphicalEditPart) graphicalEditPart).getFigure().setLocation(new org.eclipse.draw2d.geometry.Point(locationToApply.getX(), locationToApply.getY()));
+ } else {
+ locationToApply = LayoutdataFactory.eINSTANCE.createPoint();
+ }
+ }
+ bounds.setX(locationToApply.getX());
+ bounds.setY(locationToApply.getY());
+ if (isCollapsed) {
+ Dimension dim = new NodeQuery(toRestoreView).getCollapsedSize();
+ bounds.setHeight(dim.height);
+ bounds.setWidth(dim.width);
+ } else {
+ bounds.setHeight(layoutData.getHeight());
+ bounds.setWidth(layoutData.getWidth());
+ }
+
+ toRestoreView.setLayoutConstraint(bounds);
+
+ if (semanticDecorator instanceof DNode) {
+ applyLayoutToNodeChildren((DNode) semanticDecorator, editPartViewer, layoutData);
+ } else if (semanticDecorator instanceof DNodeContainer) {
+ applyLayoutToNodeContainerChildren((DNodeContainer) semanticDecorator, editPartViewer, layoutData);
+ } else if (semanticDecorator instanceof DNodeList) {
+ applyLayoutToNodeListChildren((DNodeList) semanticDecorator, editPartViewer, layoutData);
+ } else {
+ logWarnMessage(semanticDecorator);
+ }
+ if (semanticDecorator instanceof EdgeTarget) {
+ applyLayoutToOutgoingEdge((EdgeTarget) semanticDecorator, editPartViewer);
+ }
+ }
+
+ private Point getGMFDraw2DDelta(Node parentNode, IGraphicalEditPart parentEditPart) {
+
+ Point delta = LayoutdataFactory.eINSTANCE.createPoint();
+
+ org.eclipse.draw2d.geometry.Point parentDraw2DAbsoluteLocation = parentEditPart.getFigure().getBounds().getTopLeft().getCopy();
+ FigureUtilities.translateToAbsoluteByIgnoringScrollbar(parentEditPart.getFigure(), parentDraw2DAbsoluteLocation);
+
+ org.eclipse.draw2d.geometry.Point parentGMFAbsoluteLocation = GMFHelper.getAbsoluteLocation(parentNode);
+ delta.setX(parentDraw2DAbsoluteLocation.x - parentGMFAbsoluteLocation.x);
+ delta.setY(parentDraw2DAbsoluteLocation.y - parentGMFAbsoluteLocation.y);
+
+ return delta;
+ }
+
+ /**
+ * Try to apply a layout to the children of the {@link DNodeList}.
+ *
+ * @param nodeList
+ * The parent containing children to apply layout on.
+ * @param editPartViewer
+ * The viewer responsible for the current editparts lifecycle.
+ */
+ private void applyLayoutToNodeListChildren(final DNodeList nodeList, final EditPartViewer editPartViewer, final NodeLayoutData layoutData) {
+ // Restore Bordered nodes
+ applyLayoutForBorderedNodes(nodeList.getOwnedBorderedNodes(), editPartViewer, layoutData);
+
+ // Restore label
+ final Node gmfNode = SiriusGMFHelper.getGmfNode(nodeList);
+ applyLabelLayout(gmfNode, layoutData);
+ }
+
+ /**
+ * Add the layout for the children of a node.
+ *
+ * @param parentNode
+ * The parent of the children
+ * @param parentLayoutData
+ * The corresponding layoutData
+ * @param parentEditPart
+ * The editPart corresponding to the parent LayoutData
+ * @param gmfView
+ * GMF view
+ * @param discoveredKeys
+ * The {@link LayoutDataKey} discovered during the current store
+ * action.
+ */
+ protected void addNodeChildren(final DNode parentNode, final NodeLayoutData parentLayoutData, final IGraphicalEditPart parentEditPart, final View gmfView, Collection<LayoutDataKey> discoveredKeys) {
+ for (final DNode child : parentNode.getOwnedBorderedNodes()) {
+ checkDataAndAddChildLayout(parentLayoutData, child, parentEditPart, discoveredKeys);
+ }
+ // Add the label layout data (if exists).
+ addLabelLayoutData(parentLayoutData, gmfView);
+ }
+
+ /**
+ * Add a layout (if we have enough information : GMF view and editPart).
+ *
+ * @param parentLayoutData
+ * The parent layout data
+ * @param child
+ * The child from which we want to add a new layout
+ * @param parentSavedEditPart
+ * The previous saved editPart (corresponds to parentLayoutData)
+ * @param discoveredKeys
+ * The {@link LayoutDataKey} discovered during the current store
+ * action.
+ */
+ protected void checkDataAndAddChildLayout(final NodeLayoutData parentLayoutData, final AbstractDNode child, final IGraphicalEditPart parentSavedEditPart, Collection<LayoutDataKey> discoveredKeys) {
+ // Search the GMF node corresponding to the child
+ final Node gmfNode = SiriusGMFHelper.getGmfNode(child);
+ if (gmfNode != null) {
+ final IGraphicalEditPart editPart = (IGraphicalEditPart) parentSavedEditPart.getRoot().getViewer().getEditPartRegistry().get(gmfNode);
+ if (editPart != null) {
+ addChildLayout(parentLayoutData, child, gmfNode, editPart, discoveredKeys);
+ }
+ }
+ }
+
+ /**
+ * Add children of the node.
+ *
+ * @param container
+ * The parent of the children
+ * @param parentLayoutData
+ * The corresponding layoutData
+ * @param parentEditPart
+ * The editPart corresponding to the parent LayoutData
+ * @param discoveredKeys
+ * The {@link LayoutDataKey} discovered during the current store
+ * action.
+ */
+ protected void addNodeContainerChildren(final DNodeContainer container, final NodeLayoutData parentLayoutData, final IGraphicalEditPart parentEditPart, Collection<LayoutDataKey> discoveredKeys) {
+ for (final DDiagramElement child : container.getOwnedDiagramElements()) {
+ if (child instanceof AbstractDNode) {
+ checkDataAndAddChildLayout(parentLayoutData, (AbstractDNode) child, parentEditPart, discoveredKeys);
+ }
+ }
+ for (final DNode child : container.getOwnedBorderedNodes()) {
+ checkDataAndAddChildLayout(parentLayoutData, child, parentEditPart, discoveredKeys);
+ }
+ }
+
+ /**
+ * Add children of the node.
+ *
+ * @param nodeList
+ * The parent of the children
+ * @param parentLayoutData
+ * The corresponding layoutData
+ * @param parentEditPart
+ * The editPart corresponding to the parent LayoutData
+ * @param discoveredKeys
+ * The {@link LayoutDataKey} discovered during the current store
+ * action.
+ */
+ protected void addNodeListChildren(final DNodeList nodeList, final NodeLayoutData parentLayoutData, final IGraphicalEditPart parentEditPart, Collection<LayoutDataKey> discoveredKeys) {
+ for (final DNode child : nodeList.getOwnedBorderedNodes()) {
+ checkDataAndAddChildLayout(parentLayoutData, child, parentEditPart, discoveredKeys);
+ }
+ }
+
+ /**
+ * Add the child layout of the diagram.
+ *
+ * @param diagram
+ * the diagram
+ * @param editPart
+ * The viewer responsible for the current editparts lifecycle
+ */
+ private void addChildLayout(final DDiagram diagram, final IGraphicalEditPart diagramEditPart, final Collection<LayoutDataKey> discoveredKeys) {
+
+ for (final AbstractDNode child : Iterables.filter(diagram.getOwnedDiagramElements(), AbstractDNode.class)) {
+ // Search the GMF node corresponding to the child
+ final Node gmfNode = SiriusGMFHelper.getGmfNode(child);
+ if (gmfNode != null) {
+ final IGraphicalEditPart editPart = (IGraphicalEditPart) diagramEditPart.getRoot().getViewer().getEditPartRegistry().get(gmfNode);
+ if (editPart != null) {
+ addChildLayout(null, child, gmfNode, editPart, discoveredKeys);
+ }
+ }
+ }
+ }
+
+ /**
+ * Add a layout.
+ *
+ * @param parentLayoutData
+ * The parent layout data
+ * @param child
+ * The child from which we want to add a new layout
+ * @param gmfNode
+ * The corresponding GMF node.
+ * @param editPart
+ * The editPart corresponding to the new layout
+ */
+ private void addChildLayout(final NodeLayoutData parentLayoutData, final DSemanticDecorator child, final Node gmfNode, final IGraphicalEditPart editPart,
+ final Collection<LayoutDataKey> discoveredKeys) {
+ final NodeLayoutData childLayoutData = LayoutDataHelper.INSTANCE.createNodeLayoutData(gmfNode, editPart, parentLayoutData);
+ if (parentLayoutData != null) {
+ parentLayoutData.getChildren().add(childLayoutData);
+ }
+
+ LayoutDataKey childKey = createKey(child);
+ childLayoutData.setId(childKey.getId());
+
+ // If the current node have the same key than than one of the previously
+ // inspected node, the previously computed data might be replaced. It
+ // could so replaced one of the initially selected parts.
+ if (!discoveredKeys.contains(childKey)) {
+ addLayoutData(childKey, childLayoutData);
+ discoveredKeys.add(childKey);
+ } else if (parentLayoutData == null) {
+ // In this case, the same key is used for a root layout data and for
+ // an other view (child or border of an other view), the root data
+ // should be stored.
+ addLayoutData(childKey, childLayoutData);
+ }
+
+ if (child instanceof DNode) {
+ addNodeChildren((DNode) child, childLayoutData, editPart, gmfNode, discoveredKeys);
+ } else if (child instanceof DNodeContainer) {
+ addNodeContainerChildren((DNodeContainer) child, childLayoutData, editPart, discoveredKeys);
+ } else if (child instanceof DNodeList) {
+ addNodeListChildren((DNodeList) child, childLayoutData, editPart, discoveredKeys);
+ } else {
+ logWarnMessage(child);
+ }
+ if (child instanceof EdgeTarget) {
+ addOutgoingEdge(childLayoutData, (EdgeTarget) child, editPart.getRoot().getViewer());
+ }
+ }
+
+ /**
+ * Add outgoing edge of the edgeTarget.
+ *
+ * @param parentLayoutData
+ * The parent layout data
+ * @param sourceOfEdge
+ * The DDiagramElement that is the source of the edge
+ * @param editPartViewer
+ * The viewer responsible for the current editparts lifecycle.
+ */
+ protected void addOutgoingEdge(final NodeLayoutData parentLayoutData, final EdgeTarget sourceOfEdge, final EditPartViewer editPartViewer) {
+ for (final DEdge outgoingEdge : sourceOfEdge.getOutgoingEdges()) {
+ addEdgeLayoutData(parentLayoutData, outgoingEdge, editPartViewer);
+ }
+ }
+
+ /**
+ * Add edge layout data.
+ *
+ * @param parentLayoutData
+ * The parent layout data
+ * @param edge
+ * The DEdge
+ * @param editPartViewer
+ * The viewer responsible for the current editparts lifecycle.
+ */
+ protected void addEdgeLayoutData(final NodeLayoutData parentLayoutData, final DEdge edge, final EditPartViewer editPartViewer) {
+ // Search the GMF edge corresponding to the child
+ final Edge gmfEdge = SiriusGMFHelper.getGmfEdge(edge);
+ if (gmfEdge != null) {
+ final EdgeLayoutData edgeLayoutData = LayoutDataHelper.INSTANCE.createEdgeLayoutData(gmfEdge, (ConnectionEditPart) editPartViewer.getEditPartRegistry().get(gmfEdge));
+ if (parentLayoutData != null) {
+ parentLayoutData.getOutgoingEdges().add(edgeLayoutData);
+ }
+
+ LayoutDataKey edgeKey = createKey(edge);
+ edgeLayoutData.setId(edgeKey.getId());
+
+ // Add the edge layout data.
+ addLayoutData(edgeKey, edgeLayoutData);
+ // Add the label layout data (if exists).
+ addLabelLayoutData(edgeLayoutData, gmfEdge);
+ }
+ }
+
+ /**
+ * Add the layout data of the label of the edge. This layout data sets the
+ * <code>edgeLabelLayoutData</code> of the {@link EdgeLayoutData}. It's not
+ * added to the layout data with a key in the manager.
+ *
+ * @param parentLayoutData
+ * The edge layout data
+ * @param element
+ * The DEdge
+ * @param gmfElement
+ * The edge corresponding view
+ */
+ private void addLabelLayoutData(final AbstractLayoutData parentLayoutData, final View gmfElement) {
+ final Node labelNode = SiriusGMFHelper.getLabelNode(gmfElement);
+ if (labelNode != null && parentLayoutData != null) {
+ final NodeLayoutData labelLayoutData = LayoutDataHelper.INSTANCE.createLabelLayoutData(labelNode);
+ if (labelNode.getElement() instanceof DSemanticDecorator) {
+ labelLayoutData.setId(createKey((DSemanticDecorator) labelNode.getElement()).getId());
+ }
+ parentLayoutData.setLabel(labelLayoutData);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/GraphicalHelper.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/GraphicalHelper.java
new file mode 100644
index 0000000000..6c96f74251
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/GraphicalHelper.java
@@ -0,0 +1,205 @@
+/*******************************************************************************
+ * Copyright (c) 2011 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout;
+
+import org.eclipse.draw2d.FigureCanvas;
+import org.eclipse.draw2d.FreeformViewport;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramRootEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+
+import com.google.common.base.Preconditions;
+
+import org.eclipse.sirius.diagram.tools.api.draw2d.ui.figures.FigureUtilities;
+
+/**
+ * Utility class to collect helper methods which deal with GraphicalOrdering but
+ * which are not part of its API.
+ *
+ * @author nlepine
+ */
+public final class GraphicalHelper {
+ private GraphicalHelper() {
+ // Prevent instantiation.
+ }
+
+ /**
+ * Get the zoom factor.
+ *
+ * @param part
+ * the current part
+ * @return the zoom factor
+ */
+ public static double getZoom(IGraphicalEditPart part) {
+ Preconditions.checkNotNull(part);
+ double scale = 1.0;
+ if (part.getRoot() instanceof DiagramRootEditPart) {
+ DiagramRootEditPart rootEditPart = (DiagramRootEditPart) part.getRoot();
+ scale = rootEditPart.getZoomManager().getZoom();
+ }
+ return scale;
+ }
+
+ /**
+ * Applied zoom on relative point.
+ *
+ * @param part
+ * the current part
+ * @param relativePoint
+ * relative point
+ */
+ public static void appliedZoomOnRelativePoint(IGraphicalEditPart part, Point relativePoint) {
+ double zoom = getZoom(part);
+ relativePoint.setLocation((int) (relativePoint.x / zoom), (int) (relativePoint.y / zoom));
+ }
+
+ /**
+ * Set the zoom factor.
+ *
+ * @param part
+ * the current part
+ * @param scale
+ * the zoom factor
+ */
+ public static void setZoom(IGraphicalEditPart part, double scale) {
+ Preconditions.checkNotNull(part);
+ if (part.getRoot() instanceof DiagramRootEditPart) {
+ DiagramRootEditPart rootEditPart = (DiagramRootEditPart) part.getRoot();
+ rootEditPart.getZoomManager().setZoom(scale);
+ }
+ }
+
+ /**
+ * Returns the difference between the logical origin (0, 0) and the top-left
+ * point actually visible. This corresponds to how much the scrollbars
+ * "shift" the diagram.
+ *
+ * @param part
+ * an edit part on the view
+ * @return the scroll size
+ */
+ public static Point getScrollSize(IGraphicalEditPart part) {
+ Preconditions.checkNotNull(part);
+ FreeformViewport viewport = FigureUtilities.getFreeformViewport(part.getFigure());
+ if (viewport != null) {
+ return viewport.getViewLocation();
+ } else {
+ return new Point(0, 0);
+ }
+ }
+
+ /**
+ * .
+ *
+ * @param part
+ * an edit part on the view
+ * @param scrollPosition
+ * the scroll size
+ */
+ public static void setScrollSize(IGraphicalEditPart part, Point scrollPosition) {
+ Preconditions.checkNotNull(part);
+ // FreeformViewport viewport =
+ // FigureUtilities.getFreeformViewport(part.getFigure());
+ // if (viewport != null) {
+ // viewport.setLocation(scrollPosition);
+ // }
+ if (part.getViewer().getControl() instanceof FigureCanvas) {
+ // UIThreadRunnable.syncExec(new VoidResult() {
+ // public void run() {
+ ((FigureCanvas) part.getViewer().getControl()).scrollTo(scrollPosition.x, scrollPosition.y);
+ // }
+ // });
+ }
+ }
+
+ /**
+ * Converts a point from screen coordinates to logical coordinates.
+ *
+ * @param point
+ * the point to convert.
+ * @param part
+ * a part from the diagram.
+ */
+ public static void screen2logical(Point point, IGraphicalEditPart part) {
+ point.translate(GraphicalHelper.getScrollSize(part));
+ point.performScale(1.0d / GraphicalHelper.getZoom(part));
+ }
+
+ /**
+ * Converts a rectangle from screen coordinates to logical coordinates.
+ *
+ * @param rect
+ * the rectangle to convert.
+ * @param part
+ * a part from the diagram.
+ */
+ public static void screen2logical(Rectangle rect, IGraphicalEditPart part) {
+ rect.translate(GraphicalHelper.getScrollSize(part));
+ rect.performScale(1.0d / GraphicalHelper.getZoom(part));
+ }
+
+ /**
+ * Converts a dimension from screen coordinates to logical coordinates.
+ * Dimensions have no defined position, so only the current zoom level is
+ * take into account, not the scroll state.
+ *
+ * @param dim
+ * the dimension to convert.
+ * @param part
+ * a part from the diagram.
+ */
+ public static void screen2logical(Dimension dim, IGraphicalEditPart part) {
+ dim.performScale(1.0d / GraphicalHelper.getZoom(part));
+ }
+
+ /**
+ * Converts a point from logical coordinates to screen coordinates.
+ *
+ * @param point
+ * the point to convert.
+ * @param part
+ * a part from the diagram.
+ */
+ public static void logical2screen(Point point, IGraphicalEditPart part) {
+ point.performScale(GraphicalHelper.getZoom(part));
+ point.translate(GraphicalHelper.getScrollSize(part).negate());
+ }
+
+ /**
+ * Converts a rectangle from logical coordinates to screen coordinates.
+ *
+ * @param rect
+ * the rectangle to convert.
+ * @param part
+ * a part from the diagram.
+ */
+ public static void logical2screen(Rectangle rect, IGraphicalEditPart part) {
+ rect.performScale(GraphicalHelper.getZoom(part));
+ rect.translate(GraphicalHelper.getScrollSize(part).negate());
+ }
+
+ /**
+ * Converts a dimension from logical coordinates to screen coordinates.
+ * Dimensions have no defined position, so only the current zoom level is
+ * take into account, not the scroll state.
+ *
+ * @param dim
+ * the dimension to convert.
+ * @param part
+ * a part from the diagram.
+ */
+ public static void logical2Screen(Dimension dim, IGraphicalEditPart part) {
+ dim.performScale(GraphicalHelper.getZoom(part));
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ILayoutDataManagerProvider.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ILayoutDataManagerProvider.java
new file mode 100644
index 0000000000..74038efd14
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ILayoutDataManagerProvider.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2011 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout;
+
+import org.eclipse.sirius.DDiagram;
+
+/**
+ * Interface used be the extension point
+ * <code>org.eclipse.sirius.diagram.layoutDataManager</code> to implements to
+ * override the default behavior of Copy/Paste layout actions.
+ *
+ * @author <a href="mailto:maxime.porhel@obeo.fr">Maxime Porhel</a>
+ */
+public interface ILayoutDataManagerProvider {
+
+ /**
+ * Returns <code>true</code> if this provider provides a specific layout
+ * data manager for the given diagram.
+ *
+ * @param diagram
+ * the current diagram.
+ * @return <code>true</code> if this provider provides a specific layout
+ * data manager for the given diagram.
+ */
+ boolean provides(DDiagram diagram);
+
+ /**
+ * Provides its specific layout data manager. It will be called once.
+ *
+ * @return the extension of the refresh mechanism.
+ */
+ SiriusLayoutDataManager getLayoutDataManager();
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/LayoutConstants.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/LayoutConstants.java
new file mode 100644
index 0000000000..0315138b85
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/LayoutConstants.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2011 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout;
+
+/**
+ * This interface is used to keep track of the different constants available in
+ * the layout plug-in.
+ *
+ * @author cbrun
+ */
+public interface LayoutConstants {
+ /**
+ * The lowest priority.
+ */
+ int LOWEST_PRIORITY = 20;
+
+ /**
+ * A low priority.
+ */
+ int LOW_PRIORITY = 10;
+
+ /**
+ * A normal priority.
+ */
+ int NORMAL_PRIORITY = 5;
+
+ /**
+ * A high priority.
+ */
+ int HIGH_PRIORITY = 1;
+
+ /**
+ * The highest priority.
+ */
+ int HIGHEST_PRIORITY = 0;
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/LayoutDataHelper.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/LayoutDataHelper.java
new file mode 100644
index 0000000000..c8344dfe47
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/LayoutDataHelper.java
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout;
+
+import java.util.Map;
+
+import org.eclipse.gef.ConnectionEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.notation.Edge;
+import org.eclipse.gmf.runtime.notation.Node;
+
+import org.eclipse.sirius.diagram.layoutdata.AbstractLayoutData;
+import org.eclipse.sirius.diagram.layoutdata.EdgeLayoutData;
+import org.eclipse.sirius.diagram.layoutdata.NodeLayoutData;
+import org.eclipse.sirius.diagram.layoutdata.Point;
+import org.eclipse.sirius.diagram.ui.tools.internal.layout.LayoutDataHelperImpl;
+
+/**
+ * Helper to manage the layout data.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ */
+public interface LayoutDataHelper {
+ /**
+ * The singleton instance of the LayoutDataHelper.
+ */
+ LayoutDataHelper INSTANCE = new LayoutDataHelperImpl();
+
+ /**
+ * Create a node layoutData.
+ *
+ * @param gmfNode
+ * The corresponding GMF view
+ * @param editPart
+ * The corresponding editPart
+ * @param parentLayoutData
+ * The parent layout data
+ * @return a new NodeLayoutData
+ */
+ NodeLayoutData createNodeLayoutData(Node gmfNode, IGraphicalEditPart editPart, NodeLayoutData parentLayoutData);
+
+ /**
+ * Create an edge layoutData with the information of edge.
+ *
+ * @param gmfEdge
+ * The corresponding GMF view
+ * @param connectionEditPart
+ * The corresponding edit part
+ * @return a new NodeLayoutData
+ */
+ EdgeLayoutData createEdgeLayoutData(Edge gmfEdge, ConnectionEditPart connectionEditPart);
+
+ /**
+ * Create a label edge layoutData with the location of the label (the width
+ * and height of this {@link NodeLayoutData} are not set).
+ *
+ * @param labelNode
+ * the corresponding GMF view.
+ * @return a new NodeLayoutData
+ */
+ NodeLayoutData createLabelLayoutData(Node labelNode);
+
+ /**
+ * Compute the absolute location of the <code>nodeLayoutData</code>.<BR>
+ * Add recursively the location of its parent.
+ *
+ * @param nodeLayoutData
+ * The concern nodeLayoutData
+ * @return The absolute location
+ */
+ Point getAbsoluteLocation(NodeLayoutData nodeLayoutData);
+
+ /**
+ * Compute the relative location of the <code>nodeLayoutData</code> to the
+ * figure of the edit part.<BR>
+ *
+ * @param layoutData
+ * The concern nodeLayoutData
+ * @param editPart
+ * The corresponding edit part
+ * @return The relative location
+ */
+ Point getRelativeLocation(NodeLayoutData layoutData, IGraphicalEditPart editPart);
+
+ /**
+ * Creates a new Point which is translated by the values of the provided
+ * Point.
+ *
+ * @param originalPoint
+ * The point to translate.
+ * @param pt
+ * Point which provides the translation amounts.
+ * @return A new Point
+ */
+ Point getTranslated(Point originalPoint, org.eclipse.draw2d.geometry.Point pt);
+
+ /**
+ * Filter collection to get only root layout data.
+ *
+ * @param collection
+ * Collection to filter.
+ * @return Filtered collection.
+ */
+ Map<? extends LayoutDataKey, ? extends AbstractLayoutData> getRootLayoutData(Map<? extends LayoutDataKey, ? extends AbstractLayoutData> collection);
+
+ /**
+ * Create key from node layout data.
+ *
+ * @param layoutData
+ * Layout data.
+ * @return Created key.
+ */
+ LayoutDataKey createKey(AbstractLayoutData layoutData);
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/LayoutDataKey.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/LayoutDataKey.java
new file mode 100644
index 0000000000..bc56d6f610
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/LayoutDataKey.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout;
+
+/**
+ * Interface for all kind of key use to store layoutData (
+ * {@link org.eclipse.sirius.diagram.layoutdata.AbstractLayoutData}.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ */
+public interface LayoutDataKey {
+
+ /**
+ * Get the ID of this key.
+ *
+ * @return The ID of this key.
+ */
+ String getId();
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/LayoutExtender.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/LayoutExtender.java
new file mode 100644
index 0000000000..1487f48623
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/LayoutExtender.java
@@ -0,0 +1,178 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout;
+
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.draw2d.graph.Node;
+import org.eclipse.gef.ConnectionEditPart;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IBorderItemEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.ListItemEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeEditPart;
+
+import com.google.common.collect.Iterables;
+
+import org.eclipse.sirius.diagram.ui.tools.api.layout.provider.ExtendableLayoutProvider;
+
+/**
+ * Class providing extended service for {@link ExtendableLayoutProvider}s
+ * implementing the {@link ExtendableLayoutProvider} contract.
+ *
+ * @author cbrun
+ *
+ */
+public class LayoutExtender {
+
+ private final Map<IGraphicalEditPart, Rectangle> updatedLocations = new WeakHashMap<IGraphicalEditPart, Rectangle>();
+
+ private final ExtendableLayoutProvider layouter;
+
+ /**
+ * Create a new extender.
+ *
+ * @param layouter
+ * the layouter to extend.
+ */
+ public LayoutExtender(final ExtendableLayoutProvider layouter) {
+ this.layouter = layouter;
+ }
+
+ /**
+ * return all the updated bounds for each edit parts.
+ *
+ * @return all the updated bounds for each edit parts.
+ */
+ public Map<IGraphicalEditPart, Rectangle> getUpdatedBounds() {
+ return updatedLocations;
+ }
+
+ /**
+ * Notify the extender that edit parts layout is starting.
+ */
+ public void startLayouting() {
+ this.updatedLocations.clear();
+
+ }
+
+ /**
+ * Filter the relevant connections.
+ *
+ * @param editPartToNodeDict
+ * dict of edit parts.
+ * @param list
+ * list to filter.
+ * @return filtered list of connections.
+ */
+ public List getRelevantConnections(final Hashtable editPartToNodeDict, final List list) {
+ final Iterator iterConnections = list.iterator();
+ final boolean shouldHandleListItems = layouter.handleConnectableListItems();
+ while (iterConnections.hasNext()) {
+ final Object next = iterConnections.next();
+ if (next instanceof ConnectionEditPart) {
+ final ConnectionEditPart poly = (ConnectionEditPart) next;
+ EditPart from = poly.getSource();
+ EditPart to = poly.getTarget();
+ if (from instanceof IBorderItemEditPart) {
+ from = from.getParent();
+ } else if (shouldHandleListItems && from instanceof ListItemEditPart) {
+ from = getFirstAnscestorinNodesMap(from, editPartToNodeDict);
+ }
+ if (to instanceof IBorderItemEditPart) {
+ to = to.getParent();
+ } else if (shouldHandleListItems && to instanceof ListItemEditPart) {
+ to = getFirstAnscestorinNodesMap(to, editPartToNodeDict);
+ }
+ if (from == null || to == null) {
+ iterConnections.remove();
+ }
+ }
+ }
+ return list;
+ }
+
+ /**
+ * Called to keep track of every location change.
+ *
+ * @param nodes
+ * nodes to change.
+ * @param diff
+ * diff with the original location.
+ */
+ public void keepLocationChanges(final List nodes, final Point diff) {
+ for (Node node : Iterables.filter(nodes, Node.class)) {
+ if (node.data instanceof ShapeEditPart) {
+ final IGraphicalEditPart gep = (IGraphicalEditPart) node.data;
+ final Rectangle intrinsicBounds = gep.getFigure().getBounds();
+ final Rectangle nodeExt = layouter.provideNodeMetrics(node);
+ final Rectangle newBounds = new Rectangle(nodeExt.x + diff.x, nodeExt.y + diff.y, intrinsicBounds.width, intrinsicBounds.height);
+ updatedLocations.put(gep, newBounds);
+ }
+ }
+ }
+
+ /**
+ * Filter edges for layouting.
+ *
+ * @param selectedObjects
+ * objects to layout.
+ * @param editPartToNodeDict
+ * dict of editparts to nodes.
+ * @return the filtered list of elements to layout.
+ */
+ public List filterEdges(final List selectedObjects, final Map editPartToNodeDict) {
+ final List tmp = new LinkedList(selectedObjects);
+ final Iterator iterConnections = tmp.iterator();
+ final boolean shouldHandleListItems = layouter.handleConnectableListItems();
+ while (iterConnections.hasNext()) {
+ final Object next = iterConnections.next();
+ if (next instanceof ConnectionEditPart) {
+ final ConnectionEditPart poly = (ConnectionEditPart) next;
+ EditPart from = poly.getSource();
+ EditPart to = poly.getTarget();
+ if (from instanceof IBorderItemEditPart) {
+ from = from.getParent();
+ } else if (shouldHandleListItems && from instanceof ListItemEditPart) {
+ from = getFirstAnscestorinNodesMap(from, editPartToNodeDict);
+ }
+ if (to instanceof IBorderItemEditPart) {
+ to = to.getParent();
+ } else if (shouldHandleListItems && to instanceof ListItemEditPart) {
+ to = getFirstAnscestorinNodesMap(to, editPartToNodeDict);
+ }
+ if (from == null || to == null) {
+ iterConnections.remove();
+ }
+ }
+ }
+ return tmp;
+ }
+
+ private EditPart getFirstAnscestorinNodesMap(final EditPart editPart, final Map editPartToNodeDict) {
+ EditPart ancestor = editPart;
+ while (ancestor != null) {
+ if (editPartToNodeDict.get(ancestor) != null) {
+ return ancestor;
+ }
+ ancestor = ancestor.getParent();
+ }
+ return null;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/LayoutUtils.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/LayoutUtils.java
new file mode 100644
index 0000000000..50f8f3522d
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/LayoutUtils.java
@@ -0,0 +1,614 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.draw2d.Figure;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.gmf.runtime.common.core.util.Proxy;
+import org.eclipse.gmf.runtime.diagram.core.preferences.PreferencesHint;
+import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewRequest;
+import org.eclipse.gmf.runtime.draw2d.ui.figures.IBorderItemLocator;
+import org.eclipse.gmf.runtime.notation.Anchor;
+import org.eclipse.gmf.runtime.notation.Bendpoints;
+import org.eclipse.gmf.runtime.notation.Bounds;
+import org.eclipse.gmf.runtime.notation.Diagram;
+import org.eclipse.gmf.runtime.notation.Edge;
+import org.eclipse.gmf.runtime.notation.LayoutConstraint;
+import org.eclipse.gmf.runtime.notation.Location;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.NotationPackage;
+import org.eclipse.gmf.runtime.notation.RoutingStyle;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DDiagramElementContainer;
+import org.eclipse.sirius.DNode;
+import org.eclipse.sirius.DNodeContainer;
+import org.eclipse.sirius.DRepresentation;
+import org.eclipse.sirius.DSemanticDecorator;
+import org.eclipse.sirius.DSemanticDiagram;
+import org.eclipse.sirius.DStylizable;
+import org.eclipse.sirius.business.api.dialect.DialectManager;
+import org.eclipse.sirius.business.api.session.CustomDataConstants;
+import org.eclipse.sirius.business.api.session.SessionManager;
+import org.eclipse.sirius.diagram.business.api.query.ViewQuery;
+import org.eclipse.sirius.diagram.business.internal.query.DNodeQuery;
+import org.eclipse.sirius.diagram.internal.edit.parts.DNodeContainerViewNodeContainerCompartment2EditPart;
+import org.eclipse.sirius.diagram.internal.edit.parts.DNodeContainerViewNodeContainerCompartmentEditPart;
+import org.eclipse.sirius.diagram.tools.api.graphical.edit.styles.BorderItemLocatorProvider;
+import org.eclipse.sirius.diagram.tools.api.graphical.edit.styles.IStyleConfigurationRegistry;
+import org.eclipse.sirius.diagram.tools.api.graphical.edit.styles.StyleConfiguration;
+import org.eclipse.sirius.diagram.tools.api.part.DiagramEditPartService;
+import org.eclipse.sirius.diagram.tools.internal.graphical.edit.DiagramCreationUtil;
+import org.eclipse.sirius.diagram.ui.tools.internal.layout.LayoutUtil;
+
+/**
+ * Useful operations.
+ *
+ * @author ymortier
+ */
+public final class LayoutUtils {
+
+ /**
+ * Default width.
+ */
+ public static final int DEFAULT_WIDTH = 10;
+
+ /**
+ * Scale factor for width and height from diagram node size to draw2d
+ * bounds.
+ */
+ public static final int SCALE = 10;
+
+ /**
+ * The default container dimension.
+ */
+ public static final Dimension DEFAULT_CONTAINER_DIMENSION = new Dimension(150, 70);
+
+ private static final int TOP_MARGIN = 50;
+
+ private static final int LEFT_MARGIN = 50;
+
+ private static Map<IFigure, List<IFigure>> dummys = new HashMap<IFigure, List<IFigure>>();
+
+ private static Map<IFigure, Integer> dummysStack = new HashMap<IFigure, Integer>();
+
+ /**
+ * Avoid instantiation.
+ */
+ private LayoutUtils() {
+
+ }
+
+ /**
+ * Return a valid location for the specified border item view.
+ *
+ * @param borderView
+ * the border item view.
+ * @param proposedLocation
+ * the proposed location.
+ * @param proposedDimension
+ * the proposed dimension.
+ * @param owner
+ * the owner.
+ * @param borderItemContainer
+ * the container figure.
+ * @param mainFigure
+ * the figure that contains border items.
+ * @return a valid location for the specified border item view.
+ */
+ public static Rectangle getValidLocation(final DDiagramElement borderView, final Point proposedLocation, final Dimension proposedDimension, final DDiagramElement owner,
+ final IFigure borderItemContainer, final IFigure mainFigure) {
+ if (mainFigure.getBounds().getSize().height == 0 && mainFigure.getBounds().getSize().width == 0 && owner instanceof DNode) {
+ final Dimension defaultDimension = new DNodeQuery((DNode) owner).getDefaultDimension();
+ mainFigure.getBounds().height = defaultDimension.height;
+ mainFigure.getBounds().width = defaultDimension.width;
+ } else if (mainFigure.getBounds().getSize().height == 0 && mainFigure.getBounds().getSize().width == 0 && owner instanceof DDiagramElementContainer) {
+ final Dimension defaultDimension = DEFAULT_CONTAINER_DIMENSION;
+ mainFigure.getBounds().height = defaultDimension.height;
+ mainFigure.getBounds().width = defaultDimension.width;
+ }
+ final StyleConfiguration styleConfiguration = IStyleConfigurationRegistry.INSTANCE.getStyleConfiguration(owner.getDiagramElementMapping(), ((DStylizable) owner).getStyle());
+ final BorderItemLocatorProvider locatorProvider = styleConfiguration.getBorderItemLocatorProvider();
+ final IFigure dummyFigure = new Figure();
+ final IBorderItemLocator locator = locatorProvider.getBorderItemLocator(mainFigure, owner, borderView);
+ final Rectangle constraint = new Rectangle(proposedLocation, proposedDimension);
+ locator.setConstraint(constraint);
+ dummyFigure.setVisible(true);
+ borderItemContainer.add(dummyFigure);
+ final Rectangle rect = new Rectangle(constraint);
+ rect.translate(mainFigure.getBounds().getLocation().x, mainFigure.getBounds().getLocation().y);
+ mainFigure.translateToAbsolute(rect);
+ dummyFigure.setBounds(rect);
+ final Rectangle realLocation = locator.getValidLocation(rect, dummyFigure);
+ final Point parentOrigin = mainFigure.getBounds().getTopLeft();
+ final Dimension d = realLocation.getTopLeft().getDifference(parentOrigin);
+ final Point location = new Point(d.width, d.height);
+ realLocation.setLocation(location);
+
+ // dummy
+ final List<IFigure> dummysList = dummys.get(borderItemContainer);
+ if (dummysList != null) {
+ dummysList.add(dummyFigure);
+ }
+
+ locator.relocate(dummyFigure);
+ realLocation.setLocation(dummyFigure.getBounds().getLocation());
+ realLocation.setSize(proposedDimension);
+
+ return new Rectangle(realLocation).getTranslated(-parentOrigin.x, -parentOrigin.y);
+
+ }
+
+ /**
+ * Indicates that the figure will receive dummy figures.
+ *
+ * @param figure
+ * the figure.
+ */
+ public static void prepareFigureForDummyAdds(final IFigure figure) {
+ if (!dummys.containsKey(figure)) {
+ dummys.put(figure, new LinkedList<IFigure>());
+ } else {
+ Integer currentValue = dummysStack.get(figure);
+ if (currentValue == null) {
+ currentValue = Integer.valueOf(0);
+ }
+ currentValue = Integer.valueOf(currentValue.intValue() + 1);
+ dummysStack.put(figure, currentValue);
+ }
+ }
+
+ /**
+ * Remove all children that has been added since the last call of
+ * {@link #prepareFigureForDummyAdds(IFigure)} for the specified figure.
+ *
+ * @param figure
+ * the figure.
+ */
+ public static void releaseDummys(final IFigure figure) {
+ if (dummysStack.containsKey(figure)) {
+ Integer currentValue = dummysStack.get(figure);
+ currentValue = Integer.valueOf(currentValue.intValue() - 1);
+ if (currentValue.intValue() == 0) {
+ dummysStack.remove(figure);
+ } else {
+ dummysStack.put(figure, currentValue);
+ }
+ } else {
+ Collection<IFigure> dummysChildren = dummys.get(figure);
+ if (dummysChildren == null) {
+ dummysChildren = Collections.emptyList();
+ }
+ final Iterator<IFigure> iterRemove = dummysChildren.iterator();
+ while (iterRemove.hasNext()) {
+ final IFigure next = iterRemove.next();
+ figure.remove(next);
+ }
+ dummys.remove(figure);
+ }
+ }
+
+ /**
+ * Return the default dimension according to the specified descriptor.
+ *
+ * @param viewDescriptor
+ * the descriptor.
+ * @return the default dimension according to the specified descriptor.
+ */
+ public static Dimension getDefaultDimension(final CreateViewRequest.ViewDescriptor viewDescriptor) {
+ Dimension result = new Dimension(-1, -1);
+ final IAdaptable adapt = viewDescriptor.getElementAdapter();
+ if (adapt instanceof Proxy) {
+ final Object element = ((Proxy) adapt).getRealObject();
+ if (element instanceof DNode) {
+ result = new DNodeQuery((DNode) element).getDefaultDimension();
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Initializes the layout of the diagram of <code>target</code> with the
+ * layout of the the diagram <code>source</code>.
+ *
+ * @param source
+ * the source diagram.
+ * @param target
+ * the target diagram.
+ */
+ public static void initializeDiagramLayout(final Diagram source, final DRepresentation target) {
+ //
+ // Do refresh
+ DialectManager.INSTANCE.refresh(target, new NullProgressMonitor());
+
+ final Shell shell = new Shell();
+ //
+ // Initializes diagram.
+ final DiagramEditPart diagramEditPart = LayoutUtils.createDiagramEditPart(target, shell);
+ final Diagram gmfTarget;
+ if (diagramEditPart == null) {
+ gmfTarget = null;
+ } else {
+ gmfTarget = diagramEditPart.getDiagramView();
+ }
+ //
+ // dispose ui resources.
+ if (diagramEditPart != null) {
+ diagramEditPart.deactivate();
+ }
+
+ Display.getCurrent().asyncExec(new Runnable() {
+ public void run() {
+ shell.dispose();
+ }
+ });
+ //
+ // Maps a real semantic element with only one view.
+ final Map<EObject, List<View>> realSemanticToView = new HashMap<EObject, List<View>>();
+ //
+ // initializes view bounds
+ if (gmfTarget != null) {
+ final List<View> sourceCandidates = new LinkedList<View>();
+ LayoutUtils.computeSourceCandidates(source, sourceCandidates);
+ sourceCandidates.addAll(source.getEdges());
+ LayoutUtils.initializeBounds(source, gmfTarget, realSemanticToView, sourceCandidates);
+ for (final Edge edge : (Iterable<Edge>) gmfTarget.getEdges()) {
+ LayoutUtils.initializeBounds(source, edge, realSemanticToView, sourceCandidates);
+ }
+ LayoutUtils.optimizeLayout(gmfTarget);
+ LayoutUtils.moveToUpperLeftCorner(gmfTarget);
+ }
+ }
+
+ private static void moveToUpperLeftCorner(final View gmfTarget) {
+ final Dimension minDistanceToUpperLeftCorner = new Dimension(-1, -1);
+ for (final View view : (Iterable<View>) gmfTarget.getChildren()) {
+ if (view instanceof Node) {
+ final Node node = (Node) view;
+ if (node.getLayoutConstraint() instanceof Location) {
+ final Location location = (Location) node.getLayoutConstraint();
+ minDistanceToUpperLeftCorner.width = minDistanceToUpperLeftCorner.width < 0 || location.getX() < minDistanceToUpperLeftCorner.width ? location.getX()
+ : minDistanceToUpperLeftCorner.width;
+ minDistanceToUpperLeftCorner.height = minDistanceToUpperLeftCorner.height < 0 || location.getY() < minDistanceToUpperLeftCorner.height ? location.getY()
+ : minDistanceToUpperLeftCorner.height;
+ }
+ }
+ }
+ final Dimension delta = new Dimension(0, 0);
+ if (minDistanceToUpperLeftCorner.width > LEFT_MARGIN) {
+ delta.width = minDistanceToUpperLeftCorner.width - LEFT_MARGIN;
+ }
+ if (minDistanceToUpperLeftCorner.height > TOP_MARGIN) {
+ delta.height = minDistanceToUpperLeftCorner.height - TOP_MARGIN;
+ }
+
+ if (delta.height > 0 || delta.width > 0) {
+ for (final View view : (Iterable<View>) gmfTarget.getChildren()) {
+ if (view instanceof Node) {
+ final Node node = (Node) view;
+ if (node.getLayoutConstraint() instanceof Location) {
+ final Location location = (Location) node.getLayoutConstraint();
+ location.setX(location.getX() - delta.width);
+ location.setY(location.getY() - delta.height);
+ }
+ }
+ }
+ }
+
+ }
+
+ private static void computeSourceCandidates(final View source, final List<View> candidates) {
+ final EObject gmfPOVSemanticElement = ViewUtil.resolveSemanticElement(source);
+ if (gmfPOVSemanticElement instanceof DSemanticDecorator && gmfPOVSemanticElement instanceof DDiagramElement) {
+ candidates.add(source);
+ }
+ for (final View child : (Iterable<View>) source.getChildren()) {
+ LayoutUtils.computeSourceCandidates(child, candidates);
+ }
+ }
+
+ private static void initializeBounds(final Diagram source, final View target, final Map<EObject, List<View>> realSemanticToView, final List<View> sourceCandidates) {
+ final EObject gmfPOVSemanticElement = ViewUtil.resolveSemanticElement(target);
+ if (gmfPOVSemanticElement instanceof DDiagramElement && gmfPOVSemanticElement instanceof DSemanticDecorator) {
+ final View sourceView = LayoutUtils.findSourceView(target, realSemanticToView, sourceCandidates);
+ if (sourceView != null) {
+ LayoutUtils.copyConstraints(sourceView, target);
+ }
+ }
+ for (final View child : (Iterable<View>) target.getChildren()) {
+ LayoutUtils.initializeBounds(source, child, realSemanticToView, sourceCandidates);
+ }
+ }
+
+ /**
+ * Copy constraints of source view and affect them to target view.
+ *
+ * @param sourceView
+ * the source view
+ * @param targetView
+ * the target view
+ */
+ public static void copyConstraints(final View sourceView, final View targetView) {
+ if (sourceView instanceof Node && targetView instanceof Node) {
+ final Node nodeSource = (Node) sourceView;
+ final Node nodeTarget = (Node) targetView;
+ final LayoutConstraint sourceConstraint = nodeSource.getLayoutConstraint();
+ if (sourceConstraint != null) {
+ nodeTarget.setLayoutConstraint((LayoutConstraint) EcoreUtil.copy(sourceConstraint));
+ }
+ } else if (sourceView instanceof Edge && targetView instanceof Edge) {
+ final Edge edgeSource = (Edge) sourceView;
+ final Edge edgeTarget = (Edge) targetView;
+ if (edgeSource.getBendpoints() != null) {
+ edgeTarget.setBendpoints((Bendpoints) EcoreUtil.copy(edgeSource.getBendpoints()));
+ }
+ if (edgeSource.getSourceAnchor() != null) {
+ edgeTarget.setSourceAnchor((Anchor) EcoreUtil.copy(edgeSource.getSourceAnchor()));
+ }
+ if (edgeSource.getTargetAnchor() != null) {
+ edgeTarget.setTargetAnchor((Anchor) EcoreUtil.copy(edgeSource.getTargetAnchor()));
+ }
+ final RoutingStyle rstyle = (RoutingStyle) edgeSource.getStyle(NotationPackage.eINSTANCE.getRoutingStyle());
+ if (rstyle != null) {
+ edgeTarget.getStyles().add(EcoreUtil.copy(rstyle));
+ }
+ }
+ }
+
+ private static View findSourceView(final View target, final Map<EObject, List<View>> realSemanticToView, final List<View> sourceCandidates) {
+ View result = null;
+ final EObject gmfPOVSemanticElement = ViewUtil.resolveSemanticElement(target);
+ if (gmfPOVSemanticElement instanceof DDiagramElement && gmfPOVSemanticElement instanceof DSemanticDecorator) {
+ final EObject targetRealSemanticElement = ((DSemanticDecorator) gmfPOVSemanticElement).getTarget();
+ List<View> views = realSemanticToView.get(targetRealSemanticElement);
+ if (views == null) {
+ views = new ArrayList<View>(1);
+ }
+ // Search if one a the view is similar with target
+ for (final View sourceView : views) {
+ if (LayoutUtils.areSimilars(sourceView, target)) {
+ result = sourceView;
+ break;
+ }
+ }
+ // If any, search in the sourceCandidates
+ if (result == null) {
+ for (final View candidate : sourceCandidates) {
+ if (LayoutUtils.areSimilars(candidate, target)) {
+ result = candidate;
+ break;
+ }
+ }
+ if (result != null) {
+ sourceCandidates.remove(result);
+ views.add(result);
+ realSemanticToView.put(targetRealSemanticElement, views);
+ }
+ }
+
+ // if (result == null &&
+ // !realSemanticToView.containsKey(targetRealSemanticElement)) {
+ // for (final View candidate : sourceCandidates) {
+ // if (areSimilars(candidate, target)) {
+ // result = candidate;
+ // break;
+ // }
+ // }
+ // if (result != null) {
+ // sourceCandidates.remove(result);
+ // views.add(result);
+ // realSemanticToView.put(targetRealSemanticElement, views);
+ // }
+ // }
+ }
+ return result;
+ }
+
+ private static DiagramEditPart createDiagramEditPart(final DRepresentation designerDiagram, final Shell shell) {
+ if (designerDiagram instanceof DSemanticDiagram) {
+ final DSemanticDiagram diag = (DSemanticDiagram) designerDiagram;
+
+ final DiagramCreationUtil util = new DiagramCreationUtil(diag);
+ if (!util.findAssociatedGMFDiagram()) {
+ util.createNewGMFDiagram();
+ SessionManager.INSTANCE.getSession(diag.getTarget()).getServices().putCustomData(CustomDataConstants.GMF_DIAGRAMS, diag, util.getAssociatedGMFDiagram());
+ }
+
+ final Diagram gmfDiag = util.getAssociatedGMFDiagram();
+
+ if (gmfDiag != null) {
+ final DiagramEditPartService tool = new DiagramEditPartService();
+ final DiagramEditPart diagramEditPart = tool.createDiagramEditPart(gmfDiag, shell, new PreferencesHint("DView"));
+ diagramEditPart.refresh();
+
+ // performs an arrange all for canonical views.
+ LayoutUtil.arrange(diagramEditPart);
+
+ // validate to have all nodes in the right position
+ // flush the viewer to have all connections and ports
+ return diagramEditPart;
+ }
+ }
+ return null;
+ }
+
+ private static boolean areSimilars(final View source, final View target) {
+ boolean result = false;
+ // Check if the view type is the same
+ if (source != null && target != null && source.eClass() == target.eClass()) {
+ // Check if the representation is the same
+ final EObject representationSource = ViewUtil.resolveSemanticElement(source);
+ final EObject representationTarget = ViewUtil.resolveSemanticElement(target);
+
+ if (representationSource != null && representationTarget != null && representationSource.eClass() == representationTarget.eClass()) {
+ // Check if the semantic target is the same
+ if (representationSource instanceof DSemanticDecorator && representationTarget instanceof DSemanticDecorator) {
+ final EObject semSource = ((DSemanticDecorator) representationSource).getTarget();
+ final EObject semTarget = ((DSemanticDecorator) representationTarget).getTarget();
+
+ if (semSource != null && semSource == semTarget) {
+ // Check if the source and the target is
+ boolean sourceIsLabel = false;
+ boolean targetIsLabel = false;
+ try {
+ sourceIsLabel = new ViewQuery(source).isForNameEditPart();
+ } catch (final NumberFormatException e) {
+ // do nothing
+ }
+ try {
+ targetIsLabel = new ViewQuery(target).isForNameEditPart();
+ } catch (final NumberFormatException e) {
+ // do nothing
+ }
+ // Test if the source and the target is the same type
+ // (label or not)
+ result = sourceIsLabel == targetIsLabel;
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Optimize the layout of the view.
+ *
+ * @param view
+ * the view to optimize.
+ */
+ private static void optimizeLayout(final View view) {
+ for (final Object object : view.getChildren()) {
+ if (object instanceof View) {
+ LayoutUtils.optimizeLayout((View) object);
+ }
+ }
+ final EObject gmfPOVSemanticElement = ViewUtil.resolveSemanticElement(view);
+ if (gmfPOVSemanticElement instanceof DNodeContainer) {
+ LayoutUtils.optimizeContainerLayout(view);
+ }
+ }
+
+ /**
+ * Optimize the layout of this container.
+ *
+ * @param view
+ * the container to optimize.
+ */
+ private static void optimizeContainerLayout(final View view) {
+
+ final Bounds containerBounds;
+ if (view instanceof Node && ((Node) view).getLayoutConstraint() instanceof Bounds) {
+ containerBounds = (Bounds) ((Node) view).getLayoutConstraint();
+ } else {
+ containerBounds = null;
+ }
+
+ if (containerBounds != null) {
+
+ //
+ // Gets the size of the container
+ final Dimension minSize = new Dimension(-1, -1);
+ //
+ // Gets the compartment.
+ View compartment = null;
+ for (final Object object : view.getChildren()) {
+ if (object instanceof View) {
+ final View child = (View) object;
+ final int id;
+ try {
+ id = Integer.parseInt(child.getType());
+ if (id == DNodeContainerViewNodeContainerCompartment2EditPart.VISUAL_ID || id == DNodeContainerViewNodeContainerCompartmentEditPart.VISUAL_ID) {
+ compartment = child;
+ }
+ } catch (final NumberFormatException nfe) {
+ // silent.
+ }
+ }
+ }
+
+ if (compartment != null) {
+ LayoutUtils.moveToUpperLeftCorner(compartment);
+ for (final Object object : compartment.getChildren()) {
+ if (object instanceof Node) {
+ final Node child = (Node) object;
+ if (child.getLayoutConstraint() instanceof Bounds) {
+ final Bounds bounds = (Bounds) child.getLayoutConstraint();
+ final int height = bounds.getY() + bounds.getHeight() + TOP_MARGIN;
+ final int width = bounds.getWidth() + bounds.getX() + LEFT_MARGIN;
+ minSize.width = minSize.width < 0 || width > minSize.width ? width : minSize.width;
+ minSize.height = minSize.height < 0 || height > minSize.height ? height : minSize.height;
+ }
+ }
+ }
+ }
+
+ final Dimension delta = new Dimension(0, 0);
+
+ int height = containerBounds.getHeight();
+ if (height != -1 && minSize.height > height) {
+ delta.height = minSize.height - height;
+ containerBounds.setHeight(minSize.height);
+ }
+ int width = containerBounds.getWidth();
+ if (width != -1 && minSize.width > width) {
+ delta.width = minSize.width - width;
+ containerBounds.setWidth(minSize.width);
+ }
+
+ if (delta.width > 0 || delta.height > 0) {
+ final View containerView = ViewUtil.getContainerView(view);
+ if (containerView != null) {
+ for (final Object object : containerView.getChildren()) {
+ if (object instanceof Node) {
+ final Node child = (Node) object;
+ LayoutUtils.moveChild(containerBounds, delta, child);
+ }
+ }
+ }
+ }
+
+ }
+
+ }
+
+ private static void moveChild(final Bounds containerBounds, final Dimension delta, final Node child) {
+ if (child.getLayoutConstraint() instanceof Location) {
+ final Location location = (Location) child.getLayoutConstraint();
+ if (location.getX() > containerBounds.getX() && delta.width > 0) {
+ location.setX(location.getX() + delta.width);
+ }
+ if (location.getY() > containerBounds.getY() && delta.height > 0) {
+ location.setY(location.getY() + delta.height);
+ }
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/PinHelper.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/PinHelper.java
new file mode 100644
index 0000000000..a507a0a605
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/PinHelper.java
@@ -0,0 +1,204 @@
+/*******************************************************************************
+ * Copyright (c) 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.emf.ecore.EObject;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+
+import org.eclipse.sirius.AbstractDNode;
+import org.eclipse.sirius.ArrangeConstraint;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DDiagramElementContainer;
+import org.eclipse.sirius.DEdge;
+import org.eclipse.sirius.business.api.diagramtype.DiagramTypeDescriptorRegistry;
+import org.eclipse.sirius.business.api.diagramtype.IDiagramTypeDescriptor;
+import org.eclipse.sirius.business.internal.query.DDiagramElementContainerExperimentalQuery;
+import org.eclipse.sirius.diagram.edit.api.part.IDiagramElementEditPart;
+
+/**
+ * Helper class to test and manipulate the "pinned" status of
+ * {@link DDiagramElement}.
+ *
+ * @author pcdavid
+ *
+ * @since 4.0
+ */
+public final class PinHelper {
+
+ /**
+ * Set of {@link ArrangeConstraint} to specify pinned
+ * {@link DDiagramElement}.
+ */
+ public static final Collection<ArrangeConstraint> PINNED_CONSTRAINTS = new ArrayList<ArrangeConstraint>();
+
+ static {
+ PINNED_CONSTRAINTS.add(ArrangeConstraint.KEEP_LOCATION);
+ PINNED_CONSTRAINTS.add(ArrangeConstraint.KEEP_SIZE);
+ PINNED_CONSTRAINTS.add(ArrangeConstraint.KEEP_RATIO);
+ }
+
+ /**
+ * Get the pinned status of the {@link DDiagramElement} associated to this
+ * {@link IDiagramElementEditPart} <code>self</code>.
+ *
+ * @param self
+ * the edit part from which to test the pinned status of the
+ * associated {@link DDiagramElement}.
+ *
+ * @return <code>true</code> if the associated {@link DDiagramElement} is
+ * pinned, false else.
+ *
+ * @see {@link PinHelper#isPinned(DDiagramElement)}
+ */
+ public boolean isPinned(final IDiagramElementEditPart self) {
+ boolean isPinned = false;
+ EObject diagramElement = self.resolveDiagramElement();
+ if (diagramElement instanceof DDiagramElement) {
+ DDiagramElement dDiagramElement = (DDiagramElement) diagramElement;
+ isPinned = isPinned(dDiagramElement);
+ }
+ return isPinned;
+ }
+
+ /**
+ * Get the pinned status of the {@link DDiagramElement}
+ * <code>dDiagramElement</code>. The pinned status is defined by having the
+ * following {@link ArrangeConstraint} through
+ * {@link AbstractDNode#getArrangeConstraints()} or
+ * {@link DEdge#getArrangeConstraints()} :
+ *
+ * <ol>
+ * <li>
+ * {@link ArrangeConstraint#KEEP_LOCATION}</li>
+ * <li>
+ * {@link ArrangeConstraint#KEEP_SIZE}</li>
+ * <li>
+ * {@link ArrangeConstraint#KEEP_RATIO}</li>
+ * </ol>
+ *
+ * @param dDiagramElement
+ * the {@link DDiagramElement} from which to test the pinned
+ * status.
+ *
+ * @return <code>true</code> if the associated {@link DDiagramElement} is
+ * pinned, false else.
+ */
+ public boolean isPinned(final DDiagramElement dDiagramElement) {
+ boolean isPinned = false;
+ List<ArrangeConstraint> constraints = getArrangeConstraints(dDiagramElement);
+ isPinned = constraints != null && constraints.containsAll(PINNED_CONSTRAINTS);
+ return isPinned;
+ }
+
+ /**
+ * Mark a {@link DDiagramElement} as pinned if possible (depending on its
+ * actual type : {@link AbstractDNode} or {@link DEdge}).
+ *
+ * @param dDiagramElement
+ * the {@link DDiagramElement} to pin
+ *
+ * @return <code>true</code> if <code>dDiagramElement</code> has been
+ * pinned, <code>false</code> if it could not
+ */
+ public boolean markAsPinned(DDiagramElement dDiagramElement) {
+ boolean pinned = false;
+ List<ArrangeConstraint> constraints = getArrangeConstraints(dDiagramElement);
+ if (constraints != null) {
+ constraints.addAll(PINNED_CONSTRAINTS);
+ pinned = true;
+ }
+ return pinned;
+ }
+
+ /**
+ * Mark a {@link DDiagramElement} as un-pinned if possible (depending on its
+ * actual type : {@link AbstractDNode} or {@link DEdge}).
+ *
+ * @param dDiagramElement
+ * the {@link DDiagramElement} to un-pin
+ *
+ * @return <code>true</code> if the <code>dDiagramElement</code> was
+ * un-pinned, <code>false</code> if it could not
+ */
+ public boolean markAsUnpinned(DDiagramElement dDiagramElement) {
+ boolean pinned = false;
+ List<ArrangeConstraint> constraints = getArrangeConstraints(dDiagramElement);
+ if (constraints != null) {
+ constraints.removeAll(PINNED_CONSTRAINTS);
+ pinned = true;
+ }
+ return pinned;
+ }
+
+ private List<ArrangeConstraint> getArrangeConstraints(final EObject diagramElement) {
+ List<ArrangeConstraint> constraints = null;
+ if (diagramElement instanceof AbstractDNode) {
+ final AbstractDNode node = (AbstractDNode) diagramElement;
+ constraints = node.getArrangeConstraints();
+ } else if (diagramElement instanceof DEdge) {
+ final DEdge edge = (DEdge) diagramElement;
+ constraints = edge.getArrangeConstraints();
+ }
+ return constraints;
+ }
+
+ /**
+ * Indicates if the given ddiagram is allowing pin/unpin.
+ *
+ * @param diagram
+ * the diagram to inspect
+ * @return true if the given ddiagram is allowing layouting mode, false
+ * otherwise
+ */
+ public static Predicate<DDiagramElement> allowsPinUnpin(DDiagram diagram) {
+ // default return value is true for non-Region element (for basic
+ // DDiagram that are not handled
+ // by any DiagramDescriptionProvider).
+ Predicate<DDiagramElement> result = new Predicate<DDiagramElement>() {
+ public boolean apply(DDiagramElement dde) {
+ if (dde instanceof DDiagramElementContainer) {
+ DDiagramElementContainerExperimentalQuery query = new DDiagramElementContainerExperimentalQuery((DDiagramElementContainer) dde);
+ return !query.isRegion();
+ }
+ return true;
+ }
+ };
+
+ // If an aird has been opened from the Package Explorer View, then
+ // we return false as no diagram is associated to this editor
+ if (diagram == null || diagram.getDescription() == null) {
+ return Predicates.alwaysFalse();
+ }
+
+ // If diagram is not null, we search for a possible
+ // DiagramDescriptionProvider handling this type of diagram
+ for (final IDiagramTypeDescriptor diagramTypeDescriptor : DiagramTypeDescriptorRegistry.getInstance().getAllDiagramTypeDescriptors()) {
+ if (diagramTypeDescriptor.getDiagramDescriptionProvider().handles(diagram.getDescription().eClass().getEPackage())) {
+ // This DiagramDescriptionProvider may forbid pin/unpin actions.
+ Predicate<DDiagramElement> allowsPinUnpin = diagramTypeDescriptor.getDiagramDescriptionProvider().allowsPinUnpin();
+ if (allowsPinUnpin != null) {
+ result = allowsPinUnpin;
+ break;
+ }
+ }
+ }
+
+ return result;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/SiriusLayoutDataManager.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/SiriusLayoutDataManager.java
new file mode 100644
index 0000000000..a9b646f855
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/SiriusLayoutDataManager.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout;
+
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+
+import org.eclipse.sirius.DSemanticDecorator;
+import org.eclipse.sirius.diagram.layoutdata.AbstractLayoutData;
+
+/**
+ * An interface for all the SiriusLayoutDataManager for mapping key (
+ * {@link LayoutDataKey}) and layoutData ({@link AbstractLayoutData}).
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ *
+ */
+public interface SiriusLayoutDataManager {
+
+ /**
+ * Get the layout data corresponding to the key.
+ *
+ * @param key
+ * The key
+ * @return the layout data corresponding to the key or null if not found.
+ */
+ AbstractLayoutData getLayoutData(final LayoutDataKey key);
+
+ /**
+ * Add a layout data according to the key.
+ *
+ * @param key
+ * The key
+ * @param layoutData
+ * The layout data
+ */
+ void addLayoutData(final LayoutDataKey key, final AbstractLayoutData layoutData);
+
+ /**
+ * Create a key corresponding to the semanticDecorator and available for
+ * this manager.
+ *
+ * @param semanticDecorator
+ * the semantic decorator
+ * @return a new key corresponding to the semanticDecorator and available
+ * for this manager.
+ */
+ LayoutDataKey createKey(final DSemanticDecorator semanticDecorator);
+
+ /**
+ * Store the layout data for this edit part and all it's children.
+ *
+ * @param rootEditPart
+ * the root of the editParts to store.
+ */
+ void storeLayoutData(IGraphicalEditPart rootEditPart);
+
+ /**
+ * Apply the current layout data to the rootEditPart.
+ *
+ * @param rootEditPart
+ * the root edit from which we would try to apply the current
+ * stored layout
+ */
+ void applyLayout(IGraphicalEditPart rootEditPart);
+
+ /**
+ * Check if the manager contains data.
+ *
+ * @return true if the manager contains data, false otherwise.
+ */
+ boolean containsData();
+
+ /**
+ * Remove all the stored layout data.
+ */
+ void clearLayoutData();
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/SiriusLayoutDataManagerForSemanticElementsFactory.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/SiriusLayoutDataManagerForSemanticElementsFactory.java
new file mode 100644
index 0000000000..2694c90b44
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/SiriusLayoutDataManagerForSemanticElementsFactory.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout;
+
+import org.eclipse.sirius.diagram.ui.tools.internal.layout.semantic.SiriusLayoutDataManagerForSemanticElements;
+
+/**
+ * A factory to give access to a {@link SiriusLayoutDataManager} managed by
+ * semantic elements.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ *
+ */
+public class SiriusLayoutDataManagerForSemanticElementsFactory {
+ private static final SiriusLayoutDataManagerForSemanticElementsFactory INSTANCE = new SiriusLayoutDataManagerForSemanticElementsFactory();
+
+ private static final SiriusLayoutDataManagerForSemanticElements VIEWPOINT_LAYOUT_DATA_MANAGER = new SiriusLayoutDataManagerForSemanticElements();
+
+ /**
+ * gives access to the singleton instance of
+ * <code>SiriusLayoutDataManagerForSemanticElementsFactory</code>.
+ *
+ * @return the singleton instance
+ */
+ public static SiriusLayoutDataManagerForSemanticElementsFactory getInstance() {
+ return INSTANCE;
+ }
+
+ /**
+ * Get the {@link SiriusLayoutDataManager}.
+ *
+ * @return an instance of
+ * {@link SiriusLayoutDataManagerForSemanticElements}
+ */
+ public SiriusLayoutDataManager getSiriusLayoutDataManager() {
+ return VIEWPOINT_LAYOUT_DATA_MANAGER;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractEdgeDecorateSemanticElementOrdering.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractEdgeDecorateSemanticElementOrdering.java
new file mode 100644
index 0000000000..1b20a55a80
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractEdgeDecorateSemanticElementOrdering.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout.ordering;
+
+import org.eclipse.emf.ecore.EObject;
+
+import org.eclipse.sirius.DEdge;
+import org.eclipse.sirius.DSemanticDecorator;
+
+/**
+ * This class orders a list of {@link DSemanticDecorator}s that represent an
+ * edge.
+ *
+ * @author ymortier
+ */
+public abstract class AbstractEdgeDecorateSemanticElementOrdering extends AbstractViewEdgeOrdering {
+
+ /**
+ * Return the semantic element that is the source or the target of the edges
+ * to sort.
+ *
+ * @return the semantic element that is the source or the target of the
+ * edges to sort.
+ */
+ public EObject getSemanticElementConnector() {
+ return ((DSemanticDecorator) this.getEdgeTargetConnector()).getTarget();
+ }
+
+ /**
+ * Compare two {@link EObject}s. The return value depends on the relation
+ * order of <code>eObject1</code> and <code>eObject2</code>. It returns a
+ * positive number if <code>eObject1</code> is greater than
+ * <code>eObject2</code>, a negative number if <code>eObject1</code> is
+ * lesser that <code>eObject2</code> or <code>0</code> if
+ * <code>eObject1</code> equals <code>eObject2</code>.
+ *
+ * @param eObject1
+ * the first element to compare.
+ * @param eObject2
+ * the second element to compare.
+ * @return a positive number if <code>eObject1</code> is greater than
+ * <code>eObject2</code>, a negative number if <code>eObject1</code>
+ * is lesser that <code>eObject2</code> or <code>0</code> if
+ * <code>eObject1</code> equals <code>eObject2</code>.
+ */
+ public abstract int compare(EObject eObject1, EObject eObject2);
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.AbstractViewEdgeOrdering#compare(org.eclipse.sirius.DEdge,
+ * org.eclipse.sirius.DEdge)
+ */
+ @Override
+ public int compare(final DEdge vp1, final DEdge vp2) {
+ final DSemanticDecorator dc1 = vp1;
+ final DSemanticDecorator dc2 = vp2;
+ return compare(dc1.getTarget(), dc2.getTarget());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.AbstractViewEdgeOrdering#isAbleToManageViewEdge(org.eclipse.sirius.DEdge)
+ */
+ @Override
+ public final boolean isAbleToManageViewEdge(final DEdge viewEdge) {
+ return isAbleToManageSemanticElement(viewEdge.getTarget());
+ }
+
+ /**
+ * Return <code>true</code> if this
+ * {@link org.eclipse.sirius.diagram.business.api.layout.ordering.ViewOrdering}
+ * is able to manage the specified semantic element.
+ *
+ * @param semanticElement
+ * the semantic element to check.
+ * @return <code>true</code> if this
+ * {@link org.eclipse.sirius.diagram.business.api.layout.ordering.ViewOrdering}
+ * is able to manage the specified semantic element.
+ */
+ public abstract boolean isAbleToManageSemanticElement(EObject semanticElement);
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractEdgeViewOrdering.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractEdgeViewOrdering.java
new file mode 100644
index 0000000000..d29e4ee988
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractEdgeViewOrdering.java
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout.ordering;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import org.eclipse.gmf.runtime.notation.Edge;
+import org.eclipse.gmf.runtime.notation.View;
+
+/**
+ * This class is able to sort a list of {@link Edge}s.
+ *
+ * @author ymortier
+ */
+public abstract class AbstractEdgeViewOrdering extends AbstractViewOrdering {
+
+ /**
+ * The {@link View} that is the source or the target of edges to sort.
+ */
+ private View connector;
+
+ /**
+ * Return The {@link View} that is the source or the target of edges to
+ * sort.
+ *
+ * @return The {@link View} that is the source or the target of edges to
+ * sort.
+ */
+ public View getConnector() {
+ return this.connector;
+ }
+
+ /**
+ * Set The {@link View} that is the source or the target of edges to sort.
+ *
+ * @param connector
+ * The {@link View} that is the source or the target of edges to
+ * sort.
+ */
+ public void setConnector(final View connector) {
+ this.connector = connector;
+ this.isSorted = false;
+ }
+
+ /**
+ * Compare two {@link Edge}s. It returns a positive number if
+ * <code>edge1</code> is greater than <code>edge2</code>, a negative number
+ * if <code>edge1</code> is lesser than <code>edge2</code> or <code>0</code>
+ * if <code>edge1</code> equals <code>edge2</code>.
+ *
+ *
+ * @param edge1
+ * the first edge.
+ * @param edge2
+ * the second edge.
+ * @return a positive number if <code>node1</code> is greater than
+ * <code>node2</code>, a negative number if <code>node1</code> is
+ * lesser than <code>node2</code> or <code>0</code> if
+ * <code>node1</code> equals <code>node2</code>.
+ */
+ public abstract int compare(Edge edge1, Edge edge2);
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.AbstractViewOrdering#sortViews(java.util.List)
+ */
+ @Override
+ protected List<View> sortViews(final List<View> views) {
+ Collections.sort(views, new EdgeComparator());
+ return views;
+ }
+
+ /**
+ * The comparator of {@link Edge}s.
+ *
+ * @author ymortier
+ */
+ private class EdgeComparator implements Comparator<View> {
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.util.Comparator#compare(T, T)
+ */
+ public int compare(final View view0, final View view1) {
+
+ final Edge edge0 = (Edge) view0;
+ final Edge edge1 = (Edge) view1;
+
+ int comparison;
+ if (AbstractEdgeViewOrdering.this.isAbleToManageEdge(edge0)) {
+ if (AbstractEdgeViewOrdering.this.isAbleToManageEdge(edge1)) {
+ comparison = AbstractEdgeViewOrdering.this.compare(edge0, edge1);
+ } else {
+ comparison = 1;
+ }
+ } else {
+ if (AbstractEdgeViewOrdering.this.isAbleToManageEdge(edge1)) {
+ comparison = 1;
+ } else {
+ comparison = 0;
+ }
+ }
+ return comparison;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.GridViewOrdering#isAbleToManageView(org.eclipse.gmf.runtime.notation.View)
+ */
+ public final boolean isAbleToManageView(final View view) {
+ if (view instanceof Edge) {
+ return isAbleToManageEdge((Edge) view);
+ }
+ return false;
+ }
+
+ /**
+ * Return <code>true</code> if this {@link ViewOrdering} is able to manage
+ * the specified {@link Edge}.
+ *
+ * @param edge
+ * the edge to check.
+ * @return <code>true</code> if this {@link ViewOrdering} is able to manage
+ * the specified {@link Edge}.
+ */
+ public abstract boolean isAbleToManageEdge(Edge edge);
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractNodeDecorateSemanticElementOrdering.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractNodeDecorateSemanticElementOrdering.java
new file mode 100644
index 0000000000..511c3bbb46
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractNodeDecorateSemanticElementOrdering.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout.ordering;
+
+import org.eclipse.emf.ecore.EObject;
+
+import org.eclipse.sirius.AbstractDNode;
+import org.eclipse.sirius.DSemanticDecorator;
+
+/**
+ * This class orders a list of {@link DSemanticDecorator}s that represent a
+ * node.
+ *
+ * @author ymortier
+ */
+public abstract class AbstractNodeDecorateSemanticElementOrdering extends AbstractViewNodeOrdering {
+
+ /**
+ * Compare two {@link EObject}s. The return value depends on the relation
+ * order of <code>eObject1</code> and <code>eObject2</code>. It returns a
+ * positive number if <code>eObject1</code> is greater than
+ * <code>eObject2</code>, a negative number if <code>eObject1</code> is
+ * lesser that <code>eObject2</code> or <code>0</code> if
+ * <code>eObject1</code> equals <code>eObject2</code>.
+ *
+ * @param eObject1
+ * the first element to compare.
+ * @param eObject2
+ * the second element to compare.
+ * @return a positive number if <code>eObject1</code> is greater than
+ * <code>eObject2</code>, a negative number if <code>eObject1</code>
+ * is lesser that <code>eObject2</code> or <code>0</code> if
+ * <code>eObject1</code> equals <code>eObject2</code>.
+ */
+ public abstract int compare(EObject eObject1, EObject eObject2);
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.AbstractViewNodeOrdering#compare(org.eclipse.sirius.AbstractDNode,
+ * org.eclipse.sirius.AbstractDNode)
+ */
+ @Override
+ public int compare(final AbstractDNode vp1, final AbstractDNode vp2) {
+ final DSemanticDecorator dc1 = vp1;
+ final DSemanticDecorator dc2 = vp2;
+ return compare(dc1.getTarget(), dc2.getTarget());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.AbstractViewNodeOrdering#isAbleToManageAbstractViewNode(org.eclipse.sirius.AbstractDNode)
+ */
+ @Override
+ public final boolean isAbleToManageAbstractViewNode(final AbstractDNode node) {
+ return isAbleToManageSemanticElement(node.getTarget());
+ }
+
+ /**
+ * Return <code>true</code> if this
+ * {@link org.eclipse.sirius.diagram.business.api.layout.ordering.ViewOrdering}
+ * is able to manage the specified semantic element.
+ *
+ * @param semanticElement
+ * the semantic element to check.
+ * @return <code>true</code> if this
+ * {@link org.eclipse.sirius.diagram.business.api.layout.ordering.ViewOrdering}
+ * is able to manage the specified semantic element.
+ */
+ public abstract boolean isAbleToManageSemanticElement(EObject semanticElement);
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractNodeViewOrdering.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractNodeViewOrdering.java
new file mode 100644
index 0000000000..3609dfd0ea
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractNodeViewOrdering.java
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout.ordering;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.View;
+
+/**
+ * This class is able to sort a list of {@link Node}.
+ *
+ * @author ymortier
+ */
+public abstract class AbstractNodeViewOrdering extends AbstractViewOrdering {
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.AbstractViewOrdering#sortViews(java.util.List)
+ */
+ @Override
+ protected final List<View> sortViews(final List<View> views) {
+ Collections.sort(views, new NodeComparator());
+ return views;
+ }
+
+ /**
+ * Compare two {@link Node}s. It returns a positive number if
+ * <code>node1</code> is greater than <code>node2</code>, a negative number
+ * if <code>node1</code> is lesser than <code>node2</code> or <code>0</code>
+ * if <code>node1</code> equals <code>node2</code>.
+ *
+ *
+ * @param node1
+ * the first node.
+ * @param node2
+ * the second node.
+ * @return a positive number if <code>node1</code> is greater than
+ * <code>node2</code>, a negative number if <code>node1</code> is
+ * lesser than <code>node2</code> or <code>0</code> if
+ * <code>node1</code> equals <code>node2</code>.
+ */
+ public abstract int compare(Node node1, Node node2);
+
+ /**
+ * The comparator of {@link Node}s.
+ *
+ * @author ymortier
+ */
+ private class NodeComparator implements Comparator<View> {
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.util.Comparator#compare(T, T)
+ */
+ public int compare(final View view0, final View view1) {
+ int result;
+
+ final Node node0 = (Node) view0;
+ final Node node1 = (Node) view1;
+
+ if (AbstractNodeViewOrdering.this.isAbleToManageNode(node0)) {
+ if (!AbstractNodeViewOrdering.this.isAbleToManageNode(node1)) {
+ result = -1;
+ } else {
+ result = AbstractNodeViewOrdering.this.compare(node0, node1);
+ }
+ } else {
+ if (AbstractNodeViewOrdering.this.isAbleToManageNode(node1)) {
+ result = 1;
+ } else {
+ result = 0;
+ }
+ }
+ return result;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.GridViewOrdering#isAbleToManageView(org.eclipse.gmf.runtime.notation.View)
+ */
+ public final boolean isAbleToManageView(final View view) {
+ if (view instanceof Node) {
+ return isAbleToManageNode((Node) view);
+ }
+ return false;
+ }
+
+ /**
+ * Return <code>true</code> if this {@link ViewOrdering} is able to manage
+ * the specified {@link Node}.
+ *
+ * @param node
+ * the node to check.
+ * @return <code>true</code> if this {@link ViewOrdering} is able to manage
+ * the specified {@link Node}.
+ */
+ public abstract boolean isAbleToManageNode(Node node);
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractSemanticTreeOrdering.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractSemanticTreeOrdering.java
new file mode 100644
index 0000000000..3cc48bd31e
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractSemanticTreeOrdering.java
@@ -0,0 +1,159 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout.ordering;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.View;
+
+import org.eclipse.sirius.DSemanticDecorator;
+
+/**
+ * Tree ordering to order semantic elements.
+ *
+ * @author ymortier
+ */
+public abstract class AbstractSemanticTreeOrdering extends AbstractTreeViewOrdering {
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.AbstractTreeViewOrdering#getChildren(org.eclipse.gmf.runtime.notation.View,
+ * java.util.List)
+ */
+ @Override
+ public List getChildren(final View parent, final List views) {
+ // FIXME YMO doesn't work fine if there are many views that have the
+ // same target.
+ final List semantics = new ArrayList(views.size());
+ //
+ // Gets the parent semantic element.
+ final EObject semanticParent = this.resolveSemanticElement(parent);
+ if (semanticParent == null) {
+ return Collections.EMPTY_LIST;
+ }
+ //
+ // Keep a trace semantic -> view.
+ final Map semanticToView = new HashMap();
+ final Iterator iterViews = views.iterator();
+ //
+ // Find all semantic elements.
+ while (iterViews.hasNext()) {
+ final View currentView = (View) iterViews.next();
+ // Only Nodes are able to compose a tree.
+ if (currentView instanceof Node) {
+ final EObject semanticElement = this.resolveSemanticElement(currentView);
+ if (semanticElement != null) {
+ semantics.add(semanticElement);
+ semanticToView.put(semanticElement, currentView);
+ }
+ }
+ }
+ //
+ // Gets children.
+ final List semanticChildren = this.getSemanticChildren(semanticParent, semantics);
+ final List viewRoots = new ArrayList(semanticChildren.size());
+ //
+ // Gets view roots.
+ final Iterator iterSemanticRoots = semanticChildren.iterator();
+ while (iterSemanticRoots.hasNext()) {
+ viewRoots.add(semanticToView.get(iterSemanticRoots.next()));
+ }
+ return viewRoots;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.AbstractTreeViewOrdering#getRoots(java.util.List)
+ */
+ @Override
+ public List getRoots(final List views) {
+ // FIXME YMO doesn't work fine if there are many views that have the
+ // same target.
+ final List semantics = new ArrayList(views.size());
+ //
+ // Keep a trace semantic -> view.
+ final Map semanticToView = new HashMap();
+ final Iterator iterViews = views.iterator();
+ //
+ // Find all semantic elements.
+ while (iterViews.hasNext()) {
+ final View currentView = (View) iterViews.next();
+ // Only Nodes are able to compose a tree.
+ if (currentView instanceof Node) {
+ final EObject semanticElement = this.resolveSemanticElement(currentView);
+ if (semanticElement != null) {
+ semantics.add(semanticElement);
+ semanticToView.put(semanticElement, currentView);
+ }
+ }
+ }
+ //
+ // Gets roots.
+ final List semanticRoots = this.getSemanticRoots(semantics);
+ final List viewRoots = new ArrayList(semanticRoots.size());
+ //
+ // Gets view roots.
+ final Iterator iterSemanticRoots = semanticRoots.iterator();
+ while (iterSemanticRoots.hasNext()) {
+ viewRoots.add(semanticToView.get(iterSemanticRoots.next()));
+ }
+ return viewRoots;
+ }
+
+ /**
+ * Return the semantic elements that are the roots of the tree.
+ *
+ * @param eObjects
+ * the semantic elements that are on the diagram.
+ * @return the semantic elements that are the roots of the tree.
+ */
+ public abstract List getSemanticRoots(List eObjects);
+
+ /**
+ * Return the semantic elements that are the children of
+ * <code>semanticParent</code>.
+ *
+ * @param semanticParent
+ * the semantic parent.
+ * @param candidates
+ * all semantic candidates.
+ * @return the semantic elements that are the children of
+ * <code>semanticParent</code>.
+ */
+ public abstract List getSemanticChildren(EObject semanticParent, List candidates);
+
+ /**
+ * Resolves the real semantic element of the specified GMF view.
+ *
+ * @param gmfView
+ * the GMF view.
+ * @return the real semantic element of the specified GMF view.
+ */
+ protected EObject resolveSemanticElement(final View gmfView) {
+ EObject semanticElement = null;
+ final EObject semanticView = ViewUtil.resolveSemanticElement(gmfView);
+ if (semanticView instanceof DSemanticDecorator) {
+ semanticElement = ((DSemanticDecorator) semanticView).getTarget();
+ }
+ return semanticElement;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractTreeViewOrdering.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractTreeViewOrdering.java
new file mode 100644
index 0000000000..b86ada72fc
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractTreeViewOrdering.java
@@ -0,0 +1,506 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout.ordering;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.draw2d.PositionConstants;
+import org.eclipse.gmf.runtime.notation.Location;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.View;
+
+/**
+ * An abstract Tree like view ordering.
+ *
+ * @author ymortier
+ */
+public abstract class AbstractTreeViewOrdering implements ViewOrdering {
+
+ /** The views to sort. */
+ private List<View> views;
+
+ /** The resulted grid view. */
+ private GridView gridView;
+
+ /** Indicates that this instance is aware of user interaction. */
+ private boolean userAwareCapable;
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.ViewOrdering#getSortedViews()
+ */
+ public List<View> getSortedViews() {
+ return views;
+ }
+
+ /**
+ * <code>true</code> if this instance is aware of user interaction.
+ *
+ * @param userAwareCapable
+ * <code>true</code> if this instance is aware of user
+ * interaction.
+ */
+ public void setUserAwareCapable(final boolean userAwareCapable) {
+ this.userAwareCapable = userAwareCapable;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.GridViewOrdering#getSortedViewsAsGrid()
+ */
+ public GridView getSortedViewsAsGrid() {
+ if (this.gridView == null) {
+ buildTree();
+ }
+ return this.gridView;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.GridViewOrdering#isAbleToManageView(org.eclipse.gmf.runtime.notation.View)
+ */
+ public boolean isAbleToManageView(final View view) {
+ return view instanceof Node;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.GridViewOrdering#setViews(java.util.Collection)
+ */
+ public <T extends View> void setViews(final Collection<T> views) {
+ this.views = Collections.<View> unmodifiableList(new ArrayList<T>(views));
+ this.gridView = null;
+ }
+
+ /**
+ * Return the views that are the roots of trees to display.
+ *
+ * @param views
+ * the views.
+ * @return the views that are the roots of trees to display.
+ */
+ public abstract List<View> getRoots(List<View> views);
+
+ /**
+ * Returns all children of the parent view.
+ *
+ * @param parent
+ * the parent view.
+ * @param views
+ * the candidates.
+ * @return all children of the parent view.
+ */
+ public abstract List<View> getChildren(View parent, List<View> views);
+
+ /**
+ * Build the tree.
+ */
+ private void buildTree() {
+
+ List<View> roots = this.getRoots(this.views);
+ final UserAwareCapableOrdering userAwareCapableOrdering = new UserAwareCapableOrdering();
+ userAwareCapableOrdering.setViews(roots);
+ roots = new ArrayList<View>(userAwareCapableOrdering.getSortedViews());
+
+ final AirTree dummyRoot = new AirTree(null);
+
+ final Iterator<View> iterRoots = roots.iterator();
+ while (iterRoots.hasNext()) {
+ final View view = iterRoots.next();
+ final AirTree airTree = new AirTree(view);
+ airTree.setParent(dummyRoot);
+ }
+
+ final List<AirTree> currentViews = new ArrayList<AirTree>(dummyRoot.getChildren());
+ while (!currentViews.isEmpty()) {
+ final AirTree airTree = currentViews.get(0);
+ List<View> childrenView = this.getChildren(airTree.getView(), this.views);
+ if (userAwareCapable) {
+ final UserAwareCapableOrdering ordering = new UserAwareCapableOrdering();
+ ordering.setViews(childrenView);
+ childrenView = ordering.getSortedViews();
+ }
+ final Iterator<View> iterChildrenView = childrenView.iterator();
+ while (iterChildrenView.hasNext()) {
+ final View currentChild = iterChildrenView.next();
+ final AirTree childAirTree = new AirTree(currentChild);
+ childAirTree.setParent(airTree);
+ currentViews.add(childAirTree);
+ }
+ currentViews.remove(airTree);
+ }
+ final ExtendedGrid extendedGrid = getExtendedGrid(dummyRoot);
+ final View[][] gridViews = (View[][]) extendedGrid.toArray(new View[extendedGrid.getNbColumns()][extendedGrid.getNbLines()]);
+ this.gridView = GridView.create(gridViews);
+ clear();
+ }
+
+ /**
+ * Clears all the informations calculated for getting the views.
+ */
+ // Defined to avoid Memory leaks when referencing disposed Views
+ protected void clear() {
+
+ }
+
+ /**
+ * @param dummyRoot
+ */
+ private ExtendedGrid getExtendedGrid(final AirTree dummyRoot) {
+ final ExtendedGrid extendedGrid = new ExtendedGrid();
+
+ List<AirTree> currentNodes = dummyRoot.getChildren();
+ //
+ // index of the current line.
+ int lineIndex = 0;
+ while (!currentNodes.isEmpty()) {
+ //
+ // the next line.
+ final List<AirTree> next = new LinkedList<AirTree>();
+ //
+ // appends a line to the grid.
+ extendedGrid.appendLine();
+ // index of the node in the line.
+ int nodeIndexInLine = 0;
+ // iterate over the line.
+ for (final AirTree node : currentNodes) {
+
+ // the parent.
+ final AirTree parent = node.getParent();
+ //
+ // index of the child into the parent's children list.
+ final int childIndex = parent.getChildren().indexOf(node);
+
+ final int childrenNumber = parent.getChildren().size();
+ if (childIndex == 0) {
+ //
+ // compute the number of columns to add.
+ int nbColumnsToAdd = childrenNumber - (childrenNumber % 2);
+ if (lineIndex > 0) {
+ int parentColumnIndex = getParentColumnIndex(extendedGrid, parent, lineIndex);
+ extendedGrid.insertColumn(parentColumnIndex);
+ extendedGrid.insertColumn(parentColumnIndex);
+
+ for (int i = 0; i < nbColumnsToAdd; i++) {
+ parentColumnIndex = getParentColumnIndex(extendedGrid, parent, lineIndex);
+ if (i % 2 == 0) {
+ extendedGrid.insertColumn(parentColumnIndex);
+ } else {
+ extendedGrid.insertColumn(parentColumnIndex + 1);
+ }
+ }
+ extendedGrid.insertColumn(parentColumnIndex + 1);
+ extendedGrid.insertColumn(parentColumnIndex + 1);
+
+ parentColumnIndex = getParentColumnIndex(extendedGrid, parent, lineIndex);
+ extendedGrid.setData(node.getView(), getColumnIndex(parentColumnIndex, childrenNumber, childIndex), lineIndex);
+ } else {
+ nbColumnsToAdd = childrenNumber;
+ for (int i = 0; i < nbColumnsToAdd; i++) {
+ extendedGrid.appendColumn();
+ }
+ extendedGrid.setData(node.getView(), 0, lineIndex);
+ }
+ } else {
+ int columnIndex;
+ if (lineIndex == 0) {
+ columnIndex = childIndex;
+ } else {
+ final int parentIndex = getParentColumnIndex(extendedGrid, parent, lineIndex);
+ columnIndex = getColumnIndex(parentIndex, childrenNumber, childIndex);
+ if (childrenNumber % 2 == 0 && (childrenNumber / 2) <= childIndex) {
+ columnIndex += 1;
+ }
+ }
+ extendedGrid.setData(node.getView(), columnIndex, lineIndex);
+ }
+
+ //
+ // append children for the next line.
+ next.addAll(node.getChildren());
+ // next node.
+ nodeIndexInLine++;
+ }
+ currentNodes = next;
+ lineIndex++;
+ }
+ // reduceGrid(extendedGrid, dummyRoot);
+ return extendedGrid;
+ }
+
+ private int getColumnIndex(final int parentColumnIndex, final int childrenNumber, final int childIndex) {
+ return parentColumnIndex - (int) Math.floor((double) childrenNumber / 2) + childIndex;
+ }
+
+ private int getParentColumnIndex(final ExtendedGrid extendedGrid, final AirTree parent, final int lineIndex) {
+ return extendedGrid.indexOf(parent.getView(), lineIndex - 1);
+ }
+
+ /**
+ * The tree.
+ *
+ * @author ymortier
+ */
+ private static class AirTree {
+
+ /** The children of this view. */
+ private List<AirTree> children = new LinkedList<AirTree>();
+
+ /** The current View. */
+ private View view;
+
+ /** The parent. */
+ private AirTree parent;
+
+ /**
+ * Create a new {@link AirTree}.
+ *
+ * @param view
+ * the view of the node.
+ */
+ public AirTree(final View view) {
+ this.view = view;
+ }
+
+ /**
+ * Return the view.
+ *
+ * @return the view.
+ */
+ public View getView() {
+ return view;
+ }
+
+ /**
+ * Return the children.
+ *
+ * @return the children.
+ */
+ public List<AirTree> getChildren() {
+ return children;
+ }
+
+ /**
+ * Return the parent of this element.
+ *
+ * @return the parent of this element.
+ */
+ public AirTree getParent() {
+ return parent;
+ }
+
+ /**
+ * Set the parent of this element.
+ *
+ * @param parent
+ * the parent of this element.
+ */
+ public void setParent(final AirTree parent) {
+ this.parent = parent;
+ parent.children.add(this);
+ }
+ }
+
+ private static class UserAwareCapableOrdering extends AbstractNodeViewOrdering {
+
+ /** The orientation. */
+ private int orientation = PositionConstants.HORIZONTAL;
+
+ /**
+ * Default constructor.
+ */
+ public UserAwareCapableOrdering() {
+ // empty.
+ }
+
+ /**
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.AbstractNodeViewOrdering#compare(org.eclipse.gmf.runtime.notation.Node,
+ * org.eclipse.gmf.runtime.notation.Node)
+ */
+ @Override
+ public int compare(final Node node1, final Node node2) {
+ final Location loc1 = (Location) node1.getLayoutConstraint();
+ final Location loc2 = (Location) node2.getLayoutConstraint();
+
+ if (this.orientation == PositionConstants.HORIZONTAL) {
+ return loc1.getX() - loc2.getX();
+ } else {
+ return loc1.getY() - loc2.getY();
+ }
+ }
+
+ /**
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.AbstractNodeViewOrdering#isAbleToManageNode(org.eclipse.gmf.runtime.notation.Node)
+ */
+ @Override
+ public boolean isAbleToManageNode(final Node node) {
+ return node.getLayoutConstraint() instanceof Location;
+ }
+
+ }
+
+ /**
+ * A super grid.
+ *
+ * @author ymortier
+ */
+ private static class ExtendedGrid {
+
+ /** the grid. */
+ private List<List<Object>> grid;
+
+ /** the number of columns. */
+ private int nbColumns;
+
+ /** The number of lines. */
+ private int nbLines;
+
+ /**
+ * Creates an empty grid.
+ */
+ public ExtendedGrid() {
+ this.grid = new ArrayList<List<Object>>();
+ this.nbColumns = 0;
+ this.nbLines = 0;
+ }
+
+ /**
+ * Append a column.
+ */
+ public void appendColumn() {
+ final ArrayList<Object> column = new ArrayList<Object>(nbLines);
+ for (int i = 0; i < nbLines; i++) {
+ column.add(null);
+ }
+ grid.add(column);
+ nbColumns++;
+ }
+
+ /**
+ * Insert the column before the column at the specified index.
+ *
+ * @param index
+ * an index.
+ */
+ public void insertColumn(final int index) {
+ if (index >= this.nbColumns) {
+ this.appendColumn();
+ } else {
+ final ArrayList<Object> column = new ArrayList<Object>(nbLines);
+ for (int i = 0; i < nbLines; i++) {
+ column.add(null);
+ }
+ grid.add(index, column);
+ nbColumns++;
+ }
+
+ }
+
+ /**
+ * Appends a line.
+ */
+ public void appendLine() {
+ final Iterator<List<Object>> iterColumns = this.grid.iterator();
+ while (iterColumns.hasNext()) {
+ final List<Object> column = iterColumns.next();
+ column.add(null);
+ }
+ nbLines++;
+ }
+
+ /**
+ * Set the data at the specified index.
+ *
+ * @param data
+ * the data
+ * @param columnIndex
+ * the column index.
+ * @param lineIndex
+ * the line index.
+ */
+ public void setData(final Object data, final int columnIndex, final int lineIndex) {
+ if (columnIndex >= nbColumns || columnIndex < 0) {
+ throw new IllegalArgumentException();
+ }
+ if (lineIndex >= nbLines || lineIndex < 0) {
+ throw new IllegalArgumentException();
+ }
+ final List<Object> column = grid.get(columnIndex);
+ column.set(lineIndex, data);
+ }
+
+ /**
+ * Return the number of columns.
+ *
+ * @return the number of columns.
+ */
+ public int getNbColumns() {
+ return nbColumns;
+ }
+
+ /**
+ * Return the number of lines.
+ *
+ * @return the number of lines.
+ */
+ public int getNbLines() {
+ return nbLines;
+ }
+
+ /**
+ * Return the column index of the specified data for the specified line.
+ *
+ * @param data
+ * the data.
+ * @param lineIndex
+ * the line.
+ * @return the column index of the specified data for the specified line
+ * or -1 if the data is not in the line.
+ */
+ public int indexOf(final Object data, final int lineIndex) {
+ int result = -1;
+ for (int i = 0; i < this.grid.size() && result < 0; i++) {
+ final List<Object> currentColumn = this.grid.get(i);
+ if (currentColumn.get(lineIndex) != null && currentColumn.get(lineIndex).equals(data)) {
+ result = i;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * TODO
+ *
+ * @param array
+ * @return
+ */
+ public Object[][] toArray(final Object[][] array) {
+ for (int i = 0; i < nbColumns; i++) {
+ final List<Object> column = grid.get(i);
+ for (int j = 0; j < nbLines; j++) {
+ array[i][j] = column.get(j);
+ }
+ }
+ return array;
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractViewEdgeOrdering.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractViewEdgeOrdering.java
new file mode 100644
index 0000000000..0af1a609d8
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractViewEdgeOrdering.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout.ordering;
+
+import org.eclipse.gmf.runtime.notation.Edge;
+
+import org.eclipse.sirius.DEdge;
+import org.eclipse.sirius.EdgeTarget;
+
+/**
+ * This class orders a list of {@link DEdge}s.
+ *
+ * @author ymortier
+ */
+public abstract class AbstractViewEdgeOrdering extends AbstractEdgeViewOrdering {
+
+ /**
+ * Return the {@link EdgeTarget} that is the source or the target of
+ * {@link DEdge}s to sort.
+ *
+ * @return the {@link EdgeTarget} that is the source or the target of
+ * {@link DEdge}s to sort.
+ */
+ public EdgeTarget getEdgeTargetConnector() {
+ return (EdgeTarget) this.getConnector().getElement();
+ }
+
+ /**
+ * Compare two {@link DEdge}s. The return value depends on the relation
+ * order of <code>vp1</code> and <code>vp2</code>. It returns a positive
+ * number if <code>vp1</code> is greater than <code>vp2</code>, a negative
+ * number if <code>vp1</code> is lesser that <code>vp2</code> or
+ * <code>0</code> if <code>vp1</code> equals <code>vp2</code>.
+ *
+ * @param vp1
+ * the first element to compare.
+ * @param vp2
+ * the second element to compare.
+ * @return a positive number if <code>vp1</code> is greater than
+ * <code>vp2</code>, a negative number if <code>vp1</code> is lesser
+ * that <code>vp2</code> or <code>0</code> if <code>vp1</code>
+ * equals <code>vp2</code>.
+ */
+ public abstract int compare(DEdge vp1, DEdge vp2);
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.AbstractEdgeViewOrdering#compare(org.eclipse.gmf.runtime.notation.Edge,
+ * org.eclipse.gmf.runtime.notation.Edge)
+ */
+ @Override
+ public int compare(final Edge edge1, final Edge edge2) {
+ final DEdge viewEdge1 = (DEdge) edge1.getElement();
+ final DEdge viewEdge2 = (DEdge) edge2.getElement();
+ return AbstractViewEdgeOrdering.this.compare(viewEdge1, viewEdge2);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.AbstractEdgeViewOrdering#isAbleToManageEdge(org.eclipse.gmf.runtime.notation.Edge)
+ */
+ @Override
+ public final boolean isAbleToManageEdge(final Edge edge) {
+ if (edge.getElement() instanceof DEdge) {
+ return this.isAbleToManageViewEdge((DEdge) edge.getElement());
+ }
+ return false;
+ }
+
+ /**
+ * Return <code>true</code> if this
+ * {@link org.eclipse.sirius.diagram.business.api.layout.ordering.ViewOrdering}
+ * is able to manage the specified {@link DEdge}.
+ *
+ * @param viewEdge
+ * the view edge to check.
+ * @return <code>true</code> if this
+ * {@link org.eclipse.sirius.diagram.business.api.layout.ordering.ViewOrdering}
+ * is able to manage the specified {@link DEdge}.
+ */
+ public abstract boolean isAbleToManageViewEdge(DEdge viewEdge);
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractViewNodeOrdering.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractViewNodeOrdering.java
new file mode 100644
index 0000000000..7fb8263ed3
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractViewNodeOrdering.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout.ordering;
+
+import org.eclipse.gmf.runtime.notation.Node;
+
+import org.eclipse.sirius.AbstractDNode;
+
+/**
+ * This class orders a list of {@link AbstractDNode}s.
+ *
+ *
+ * @author ymortier
+ */
+public abstract class AbstractViewNodeOrdering extends AbstractNodeViewOrdering {
+
+ /**
+ * Compare two {@link AbstractDNode}s. The return value depends on the
+ * relation order of <code>vp1</code> and <code>vp2</code>. It returns a
+ * positive number if <code>vp1</code> is greater than <code>vp2</code>, a
+ * negative number if <code>vp1</code> is lesser that <code>vp2</code> or
+ * <code>0</code> if <code>vp1</code> equals <code>vp2</code>.
+ *
+ * @param vp1
+ * the first element to compare.
+ * @param vp2
+ * the second element to compare.
+ * @return a positive number if <code>vp1</code> is greater than
+ * <code>vp2</code>, a negative number if <code>vp1</code> is lesser
+ * that <code>vp2</code> or <code>0</code> if <code>vp1</code>
+ * equals <code>vp2</code>.
+ */
+ public abstract int compare(AbstractDNode vp1, AbstractDNode vp2);
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.AbstractNodeViewOrdering#compare(org.eclipse.gmf.runtime.notation.Node,
+ * org.eclipse.gmf.runtime.notation.Node)
+ */
+ @Override
+ public final int compare(final Node node1, final Node node2) {
+ final AbstractDNode viewNode1 = (AbstractDNode) node1.getElement();
+ final AbstractDNode viewNode2 = (AbstractDNode) node2.getElement();
+ return compare(viewNode1, viewNode2);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.AbstractNodeViewOrdering#isAbleToManageNode(org.eclipse.gmf.runtime.notation.Node)
+ */
+ @Override
+ public final boolean isAbleToManageNode(final Node node) {
+ if (node.getElement() instanceof AbstractDNode) {
+ return isAbleToManageAbstractViewNode((AbstractDNode) node.getElement());
+ }
+ return false;
+ }
+
+ /**
+ * Return <code>true</code> if this
+ * {@link org.eclipse.sirius.diagram.business.api.layout.ordering.ViewOrdering}
+ * is able to manage the specified node.
+ *
+ * @param node
+ * the node to check.
+ * @return <code>true</code> if this
+ * {@link org.eclipse.sirius.diagram.business.api.layout.ordering.ViewOrdering}
+ * is able to manage the specified node.
+ */
+ public abstract boolean isAbleToManageAbstractViewNode(AbstractDNode node);
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractViewOrdering.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractViewOrdering.java
new file mode 100644
index 0000000000..037d9e0f96
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/AbstractViewOrdering.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout.ordering;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.gmf.runtime.notation.View;
+
+/**
+ * A simple partially implementation of {@link ViewOrdering}.
+ *
+ * @author ymortier
+ */
+public abstract class AbstractViewOrdering implements ViewOrdering {
+
+ /** The sorted views. */
+ protected List<View> sortedViews;
+
+ /**
+ * <code>true</code> if the views are sorted, <code>false</code> otherwise.
+ */
+ protected boolean isSorted;
+
+ /**
+ * Set the list of views to sort.
+ *
+ * @param views
+ * the list of views to sort.
+ * @param <T>
+ * class which extends {@link View}
+ */
+ public <T extends View> void setViews(final Collection<T> views) {
+ this.sortedViews = new ArrayList<View>(views);
+ this.isSorted = false;
+ }
+
+ /**
+ * The result is not modifiable. All attempts to modify the result will
+ * throw an {@link UnsupportedOperationException}.
+ *
+ * @return the sorted views.
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.ViewOrdering#getSortedViews()
+ */
+ public List<View> getSortedViews() {
+ if (!isSorted) {
+ this.sortedViews = this.sortViews(this.sortedViews);
+ isSorted = true;
+ }
+ return this.sortedViews;
+ }
+
+ /**
+ * Sorts the views.
+ *
+ * @param views
+ * the list of views to sort, this parameter can be modified by
+ * the implementation.
+ * @return the list of sorted views.
+ */
+ protected abstract List<View> sortViews(List<View> views);
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.GridViewOrdering#getSortedViewsAsGrid()
+ */
+ public GridView getSortedViewsAsGrid() {
+ final List<View> list = this.getSortedViews();
+ final View[][] views = new View[1][];
+ views[0] = list.toArray(new View[list.size()]);
+ final GridView gridView = GridView.create(views);
+ return gridView;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/GridView.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/GridView.java
new file mode 100644
index 0000000000..990ad8a226
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/GridView.java
@@ -0,0 +1,255 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout.ordering;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.gmf.runtime.notation.View;
+
+/**
+ * Represents a grid of views.
+ *
+ * @author ymortier
+ */
+public final class GridView {
+
+ /** All columns. */
+ private List<Column> columns;
+
+ /**
+ * Call the method {@link #create(View[][])} to create an instance.
+ */
+ private GridView() {
+ // empty.
+ }
+
+ /**
+ * Create a new instance of {@link GridView}.
+ *
+ * @param views
+ * the grid.
+ * @return the new instance.
+ */
+ public static GridView create(final View[][] views) {
+ final GridView gridView = new GridView();
+ int maxLength = -1;
+ for (View[] view : views) {
+ if (view.length > maxLength) {
+ maxLength = view.length;
+ }
+ }
+ //
+ // copy the array.
+ final View[][] copyView = new View[views.length][];
+ System.arraycopy(views, 0, copyView, 0, views.length);
+ //
+ // equilibrate the array.
+ for (int i = 0; i < views.length; i++) {
+ copyView[i] = new View[maxLength];
+ System.arraycopy(views[i], 0, copyView[i], 0, views[i].length);
+ }
+ //
+ // Create columns
+ gridView.columns = new ArrayList<Column>(copyView.length);
+ for (int i = 0; i < views.length; i++) {
+ final Column column = gridView.new Column(views[i], i);
+ gridView.columns.add(column);
+ }
+ gridView.columns = Collections.unmodifiableList(gridView.columns);
+ return gridView;
+ }
+
+ /**
+ * Return the number of columns of the grid.
+ *
+ * @return the number of columns of the grid.
+ */
+ public int getColumnsCount() {
+ return this.columns.size();
+ }
+
+ /**
+ * Return the number of lines.
+ *
+ * @return the number of lines.
+ */
+ public int getLinesCount() {
+ return getColumnsCount() > 0 ? this.getColumnAt(0).getViewsCount() : 0;
+ }
+
+ /**
+ * Return the {@link Column} that is at the specified index.
+ *
+ * @param index
+ * the index of the column.
+ * @return the {@link Column} that is at the specified index.
+ * @throws IndexOutOfBoundsException
+ * if the index is out ouf bounds.
+ */
+ public Column getColumnAt(final int index) throws IndexOutOfBoundsException {
+ return this.columns.get(index);
+ }
+
+ /**
+ * Return the view at the specified index.
+ *
+ * @param columnIndex
+ * the index of the column.
+ * @param lineIndex
+ * the index of the line.
+ * @return the view at the specified index.
+ * @throws IndexOutOfBoundsException
+ * if the <code>columnIndex</code> or <code>lineIndex</code> is
+ * out of bounds of the grid.
+ */
+ public View getViewAt(final int columnIndex, final int lineIndex) throws IndexOutOfBoundsException {
+ return this.getColumnAt(columnIndex).getViewAt(lineIndex);
+ }
+
+ /**
+ * Return an {@link Iterator} that iterates all columns of the grid. Each
+ * elements is a {@link Column} that represents the column.
+ *
+ * @return an {@link Iterator} that iterates all columns of the grid. Each
+ * elements is a {@link Column} that represents the column.
+ */
+ public Iterator<Column> iteratorColumns() {
+ return this.columns.iterator();
+ }
+
+ /**
+ * Represents a column of the grid.
+ *
+ * @author ymortier
+ */
+ public class Column {
+
+ /** The views of the column. */
+ private List<View> views;
+
+ /** The index of the column. */
+ private int index;
+
+ /**
+ * Create a new {@link Column}.
+ *
+ * @param views
+ * the views of the column.
+ * @throws IllegalArgumentException
+ * if <code>index</code> is lesser than <code>0</code>.
+ */
+ Column(final View[] views, final int index) throws IllegalArgumentException {
+ this.views = new ArrayList<View>(Arrays.asList(views));
+ this.views = Collections.unmodifiableList(this.views);
+ this.index = index;
+ }
+
+ /**
+ * Return the left sibling of the specified view.
+ *
+ * @param view
+ * a view of this column.
+ * @return the left sibling of the specified view or <code>null</code>
+ * if the specified view has no left sibling.
+ * @throws IllegalArgumentException
+ * if the view is not in the column.
+ */
+ public View getLeftSibling(final View view) throws IllegalArgumentException {
+ if (!this.views.contains(view)) {
+ throw new IllegalArgumentException("The view is not in the column");
+ }
+ if (this.index == 0) {
+ return null;
+ }
+ return GridView.this.getViewAt(this.index - 1, this.views.indexOf(view));
+ }
+
+ /**
+ * Return the right sibling of the specified view.
+ *
+ * @param view
+ * a view of this column.
+ * @return the left sibling of the specified view or <code>null</code>
+ * if the specified view has no right sibling.
+ * @throws IllegalArgumentException
+ * if the view is not in the column.
+ */
+ public View getRightSibling(final View view) throws IllegalArgumentException {
+ if (!this.views.contains(view)) {
+ throw new IllegalArgumentException("The view is not in the column");
+ }
+ if (this.index + 1 == GridView.this.getColumnsCount()) {
+ return null;
+ }
+ return GridView.this.getViewAt(this.index + 1, this.views.indexOf(view));
+ }
+
+ /**
+ * Return the view that is at the specified index.
+ *
+ * @param viewIndex
+ * the index of the view.
+ * @return the view that is at the specified index.
+ * @throws IndexOutOfBoundsException
+ * if <code>index</code> is out of bounds.
+ */
+ public View getViewAt(final int viewIndex) throws IndexOutOfBoundsException {
+ return this.views.get(viewIndex);
+ }
+
+ /**
+ * Return the index of the specified view or -1 if the view is not in
+ * this column.
+ *
+ * @param view
+ * the view.
+ * @return the index of the specified view or -1 if the view is not in
+ * this column.
+ */
+ public int indexOf(final View view) {
+ return this.views.indexOf(view);
+ }
+
+ /**
+ * Return the number of views that are in the column.
+ *
+ * @return the number of views that are in the column.
+ */
+ public int getViewsCount() {
+ return this.views.size();
+ }
+
+ /**
+ * Return the left sibling column.
+ *
+ * @return the left sibling column.
+ */
+ public Column getLeftSibling() {
+ if (this.index != 0) {
+ return GridView.this.columns.get(index - 1);
+ }
+ return null;
+ }
+
+ /**
+ * Returns the index of the column.
+ *
+ * @return the index of the column.
+ */
+ public int getIndex() {
+ return index;
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/GridViewOrdering.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/GridViewOrdering.java
new file mode 100644
index 0000000000..e341bceac6
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/GridViewOrdering.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout.ordering;
+
+import java.util.Collection;
+
+import org.eclipse.gmf.runtime.notation.View;
+
+/**
+ * An ordering that is able to order views into a grid.
+ *
+ * @author ymortier
+ */
+public interface GridViewOrdering {
+
+ /**
+ * Returns the views sorted by this ordering.
+ *
+ * @return the views sorted by this ordering.
+ */
+ GridView getSortedViewsAsGrid();
+
+ /**
+ * Returns <code>true</code> if this {@link ViewOrdering} is able to manage
+ * the specified {@link View}.
+ *
+ * @param view
+ * the view to check.
+ * @return <code>true</code> if this {@link ViewOrdering} is able to manage
+ * the specified {@link View}.
+ */
+ boolean isAbleToManageView(View view);
+
+ /**
+ * Set the list of views to sort.
+ *
+ * @param views
+ * the list of views to sort.
+ * @param <T>
+ * class which extends View
+ */
+ <T extends View> void setViews(Collection<T> views);
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/SimpleCompositeEdgeViewOrdering.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/SimpleCompositeEdgeViewOrdering.java
new file mode 100644
index 0000000000..fe4f663959
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/SimpleCompositeEdgeViewOrdering.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout.ordering;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.gmf.runtime.notation.Edge;
+import org.eclipse.gmf.runtime.notation.View;
+
+/**
+ * A simple composite of {@link AbstractEdgeViewOrdering}s.
+ *
+ * @author ymortier
+ */
+public class SimpleCompositeEdgeViewOrdering extends AbstractEdgeViewOrdering {
+
+ /** The orderings. */
+ private List<AbstractEdgeViewOrdering> edgeViewOrderings = new LinkedList<AbstractEdgeViewOrdering>();
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.AbstractEdgeViewOrdering#setConnector(org.eclipse.gmf.runtime.notation.View)
+ */
+ @Override
+ public void setConnector(final View connector) {
+ super.setConnector(connector);
+ final Iterator<AbstractEdgeViewOrdering> iterEdgeViewOrderings = this.edgeViewOrderings.iterator();
+ while (iterEdgeViewOrderings.hasNext()) {
+ final AbstractEdgeViewOrdering current = iterEdgeViewOrderings.next();
+ current.setConnector(connector);
+ }
+ }
+
+ /**
+ * Add a new {@link AbstractEdgeViewOrdering}.
+ *
+ * @param edgeViewOrdering
+ * the {@link AbstractEdgeViewOrdering} to add.
+ */
+ public void addEdgeViewOrdering(final AbstractEdgeViewOrdering edgeViewOrdering) {
+ this.edgeViewOrderings.add(edgeViewOrdering);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.AbstractEdgeViewOrdering#compare(org.eclipse.gmf.runtime.notation.Edge,
+ * org.eclipse.gmf.runtime.notation.Edge)
+ */
+ @Override
+ public int compare(final Edge edge1, final Edge edge2) {
+ final AbstractEdgeViewOrdering viewOrdering1 = this.getViewOrderingFor(edge1);
+ final AbstractEdgeViewOrdering viewOrdering2 = this.getViewOrderingFor(edge2);
+
+ int comparison;
+
+ if (viewOrdering1 == null) {
+ if (viewOrdering2 == null) {
+ comparison = 0;
+ } else {
+ comparison = 1;
+ }
+ } else if (viewOrdering2 == null) {
+ comparison = -1;
+ } else {
+ if (viewOrdering1 == viewOrdering2) {
+ comparison = viewOrdering1.compare(edge1, edge2);
+ } else {
+ comparison = viewOrdering1.hashCode() - viewOrdering2.hashCode();
+ }
+ }
+ return comparison;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.AbstractEdgeViewOrdering#isAbleToManageEdge(org.eclipse.gmf.runtime.notation.Edge)
+ */
+ @Override
+ public boolean isAbleToManageEdge(final Edge edge) {
+ return this.getViewOrderingFor(edge) != null;
+ }
+
+ /**
+ * Return the first {@link ViewOrdering} that is able to manage the
+ * specified view or <code>null</code> if no {@link ViewOrdering} is
+ * availble for the view.
+ *
+ * @param view
+ * the view to manage.
+ * @return the first {@link ViewOrdering} that is able to manage the
+ * specified view or <code>null</code> if no {@link ViewOrdering} is
+ * availble for the view.
+ */
+ protected AbstractEdgeViewOrdering getViewOrderingFor(final Edge view) {
+ final Iterator<AbstractEdgeViewOrdering> iterViewOrderings = this.edgeViewOrderings.iterator();
+ while (iterViewOrderings.hasNext()) {
+ final AbstractEdgeViewOrdering currentViewOrdering = iterViewOrderings.next();
+ if (currentViewOrdering.isAbleToManageView(view)) {
+ return currentViewOrdering;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/SimpleCompositeViewOrdering.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/SimpleCompositeViewOrdering.java
new file mode 100644
index 0000000000..80d8934d6f
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/SimpleCompositeViewOrdering.java
@@ -0,0 +1,117 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout.ordering;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.gmf.runtime.notation.View;
+
+/**
+ * A simple composite view ordering.
+ *
+ * @author ymortier
+ */
+public class SimpleCompositeViewOrdering extends AbstractViewOrdering {
+
+ /** All view orderings. */
+ private List<ViewOrdering> viewOrderings = new LinkedList<ViewOrdering>();
+
+ /**
+ * Adds a new {@link ViewOrdering}.
+ *
+ * @param viewOrdering
+ * the {@link ViewOrdering} to add.
+ */
+ public void addViewOrdering(final ViewOrdering viewOrdering) {
+ this.viewOrderings.add(viewOrdering);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.AbstractViewOrdering#sortViews(java.util.List)
+ */
+ @Override
+ protected List<View> sortViews(final List<View> views) {
+ //
+ // First populate a map :
+ // - ViewOrdering -> List of views to sort.
+ final Iterator<View> iterAllViews = views.iterator();
+ final Map<ViewOrdering, List<View>> viewOrderingsToViews = new HashMap<ViewOrdering, List<View>>();
+ final List<View> nullViewOrdering = new LinkedList<View>();
+ while (iterAllViews.hasNext()) {
+ final View currentView = iterAllViews.next();
+ final ViewOrdering viewOrdering = this.getViewOrderingFor(currentView);
+ if (viewOrdering == null) {
+ nullViewOrdering.add(currentView);
+ } else {
+ List<View> currentViews = viewOrderingsToViews.get(viewOrdering);
+ if (currentViews == null) {
+ currentViews = new LinkedList<View>();
+ viewOrderingsToViews.put(viewOrdering, currentViews);
+ }
+ currentViews.add(currentView);
+ }
+ }
+ //
+ // Second, sort all views.
+ final List<View> sortedViews = new LinkedList<View>();
+ final Iterator<ViewOrdering> iterViewOrderings = this.viewOrderings.listIterator();
+ while (iterViewOrderings.hasNext()) {
+ final ViewOrdering currentViewOrdering = iterViewOrderings.next();
+ final List<View> correspondingViews = viewOrderingsToViews.get(currentViewOrdering);
+ if (correspondingViews != null) {
+ currentViewOrdering.setViews(correspondingViews);
+ sortedViews.addAll(currentViewOrdering.getSortedViews());
+ }
+ }
+ //
+ // Third, Append all views that have no ViewOrdering
+ sortedViews.addAll(nullViewOrdering);
+ return sortedViews;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.GridViewOrdering#isAbleToManageView(org.eclipse.gmf.runtime.notation.View)
+ */
+ public boolean isAbleToManageView(final View view) {
+ return getViewOrderingFor(view) != null;
+ }
+
+ /**
+ * Return the first {@link ViewOrdering} that is able to manage the
+ * specified view or <code>null</code> if no {@link ViewOrdering} is
+ * available for the view.
+ *
+ * @param view
+ * the view to manage.
+ * @return the first {@link ViewOrdering} that is able to manage the
+ * specified view or <code>null</code> if no {@link ViewOrdering} is
+ * available for the view.
+ */
+ protected ViewOrdering getViewOrderingFor(final View view) {
+ final Iterator<ViewOrdering> iterViewOrderings = this.viewOrderings.listIterator();
+ while (iterViewOrderings.hasNext()) {
+ final ViewOrdering currentViewOrdering = iterViewOrderings.next();
+ if (currentViewOrdering.isAbleToManageView(view)) {
+ return currentViewOrdering;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/SimpleViewOrdering.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/SimpleViewOrdering.java
new file mode 100644
index 0000000000..0ce1d57996
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/SimpleViewOrdering.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout.ordering;
+
+import java.util.List;
+
+import org.eclipse.gmf.runtime.notation.View;
+
+/**
+ * Doesn't sort the list.
+ *
+ * @author ymortier
+ */
+public class SimpleViewOrdering extends AbstractViewOrdering {
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.AbstractViewOrdering#sortViews(java.util.List)
+ */
+ @Override
+ protected List<View> sortViews(final List<View> views) {
+ return views;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.GridViewOrdering#isAbleToManageView(org.eclipse.gmf.runtime.notation.View)
+ */
+ public boolean isAbleToManageView(final View view) {
+ return true;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/ViewOrdering.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/ViewOrdering.java
new file mode 100644
index 0000000000..194f06cf21
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/ViewOrdering.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout.ordering;
+
+import java.util.List;
+
+import org.eclipse.gmf.runtime.notation.View;
+
+/**
+ * Represents a type that is able to order views.
+ *
+ * @author ymortier
+ */
+public interface ViewOrdering extends GridViewOrdering {
+
+ /**
+ * Return the views ordered by this {@link ViewOrdering}. The resulted list
+ * might not be modified by the caller. An unmodifiable list will throws an
+ * {@link UnsupportedOperationException} if the caller attempts to modify
+ * the list.
+ *
+ * @return the views ordered by this {@link ViewOrdering}.
+ */
+ List<View> getSortedViews();
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/ViewOrderingHint.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/ViewOrderingHint.java
new file mode 100644
index 0000000000..659694719c
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/ViewOrderingHint.java
@@ -0,0 +1,155 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout.ordering;
+
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import org.eclipse.gmf.runtime.notation.View;
+
+/**
+ * A singleton that provides {@link ViewOrdering}.
+ *
+ * @author ymortier
+ */
+public final class ViewOrderingHint {
+
+ /** The shared instance. */
+ private static ViewOrderingHint instance = new ViewOrderingHint();
+
+ /** All view ordering. */
+ private Map<View, ViewOrdering> viewOrderingsStock;
+
+ /** All edge view ordering. */
+ private Map<View, AbstractEdgeViewOrdering> edgeViewOrderingsStock;
+
+ /**
+ * Avoid instantiation from external.
+ */
+ private ViewOrderingHint() {
+ this.viewOrderingsStock = new WeakHashMap<View, ViewOrdering>();
+ this.edgeViewOrderingsStock = new WeakHashMap<View, AbstractEdgeViewOrdering>();
+ }
+
+ /**
+ * Return the shared instance.
+ *
+ * @return the shared instance.
+ */
+ public static ViewOrderingHint getInstance() {
+ return instance;
+ }
+
+ /**
+ * Put a new {@link ViewOrdering}.
+ *
+ * @param view
+ * the container.
+ * @param viewOrdering
+ * the view ordering.
+ */
+ public void putViewOrdering(final View view, final ViewOrdering viewOrdering) {
+ final ViewOrdering oldOrdering = this.viewOrderingsStock.get(view);
+ if (oldOrdering == null) {
+ this.viewOrderingsStock.put(view, viewOrdering);
+ } else if (oldOrdering instanceof SimpleCompositeViewOrdering) {
+ final SimpleCompositeViewOrdering compositeViewOrdering = (SimpleCompositeViewOrdering) oldOrdering;
+ compositeViewOrdering.addViewOrdering(viewOrdering);
+ } else if (oldOrdering != viewOrdering) {
+ final SimpleCompositeViewOrdering compositeViewOrdering = new SimpleCompositeViewOrdering();
+ compositeViewOrdering.addViewOrdering(oldOrdering);
+ compositeViewOrdering.addViewOrdering(viewOrdering);
+ this.viewOrderingsStock.put(view, compositeViewOrdering);
+ }
+ }
+
+ /**
+ * Put a new {@link AbstractEdgeViewOrdering}.
+ *
+ * @param view
+ * the container.
+ * @param edgeViewOrdering
+ * the view ordering.
+ */
+ public void putEdgeViewOrdering(final View view, final AbstractEdgeViewOrdering edgeViewOrdering) {
+ final ViewOrdering oldOrdering = this.edgeViewOrderingsStock.get(view);
+ if (oldOrdering == null) {
+ this.edgeViewOrderingsStock.put(view, edgeViewOrdering);
+ } else if (oldOrdering instanceof SimpleCompositeEdgeViewOrdering) {
+ final SimpleCompositeEdgeViewOrdering compositeViewOrdering = (SimpleCompositeEdgeViewOrdering) oldOrdering;
+ compositeViewOrdering.addEdgeViewOrdering(edgeViewOrdering);
+ } else if (oldOrdering instanceof AbstractEdgeViewOrdering) {
+ final SimpleCompositeEdgeViewOrdering compositeViewOrdering = new SimpleCompositeEdgeViewOrdering();
+ compositeViewOrdering.addEdgeViewOrdering((AbstractEdgeViewOrdering) oldOrdering);
+ compositeViewOrdering.addEdgeViewOrdering(edgeViewOrdering);
+ this.edgeViewOrderingsStock.put(view, compositeViewOrdering);
+ }
+ }
+
+ /**
+ * Return the view ordering to use by the specified container edit part.
+ *
+ * @param view
+ * the edit part.
+ * @return the view ordering to use by the specified container edit part.
+ */
+ public ViewOrdering consumeViewOrdering(final View view) {
+ final ViewOrdering result = this.viewOrderingsStock.get(view);
+ this.viewOrderingsStock.remove(view);
+ return result;
+ }
+
+ /**
+ * Return the edge view ordering to use by the specified container edit
+ * part.
+ *
+ * @param view
+ * the edit part.
+ * @return the edge view ordering to use by the specified container edit
+ * part.
+ */
+ public AbstractEdgeViewOrdering consumeEdgeViewOrdering(final View view) {
+ final AbstractEdgeViewOrdering result = this.edgeViewOrderingsStock.get(view);
+ this.edgeViewOrderingsStock.remove(view);
+ return result;
+ }
+
+ /**
+ * Removes all registered Hints for the given {@link View}.
+ *
+ * @param view
+ * the {@link View} to remove all registered Hints from
+ */
+ public void removeAllHints(View view) {
+ removeHints(view);
+ }
+
+ /**
+ * Removes all registered Hints for the given View and all its children.
+ *
+ * @param view
+ * the view to remove the registered Hints from
+ */
+ private void removeHints(View view) {
+ if (this.viewOrderingsStock.get(view) != null) {
+ this.viewOrderingsStock.remove(view);
+ }
+ if (this.edgeViewOrderingsStock.get(view) != null) {
+ this.edgeViewOrderingsStock.remove(view);
+ }
+ for (Object child : view.getChildren()) {
+ if (child instanceof View) {
+ removeHints((View) child);
+ }
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/ViewOrderingProvider.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/ViewOrderingProvider.java
new file mode 100644
index 0000000000..e25f57c756
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/ordering/ViewOrderingProvider.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout.ordering;
+
+import org.eclipse.sirius.description.DiagramElementMapping;
+
+/**
+ * Represents an object that provides {@link ViewOrdering}.
+ *
+ * @author ymortier
+ */
+public interface ViewOrderingProvider {
+
+ /**
+ * Return <code>true</code> if this provider provides {@link ViewOrdering}s.
+ * for the specified mapping.
+ *
+ * @param mapping
+ * the mapping.
+ * @return <code>true</code> if this provider provides {@link ViewOrdering}
+ * s. for the specified mapping.
+ */
+ boolean provides(DiagramElementMapping mapping);
+
+ /**
+ * Return the {@link ViewOrdering} to use for the specified
+ * {@link DiagramElementMapping}.
+ *
+ * @param mapping
+ * the mapping.
+ * @return the {@link ViewOrdering} to use for the specified
+ * {@link DiagramElementMapping}.
+ */
+ ViewOrdering getViewOrdering(DiagramElementMapping mapping);
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/provider/AbstractLayoutProvider.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/provider/AbstractLayoutProvider.java
new file mode 100644
index 0000000000..f056ba4902
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/provider/AbstractLayoutProvider.java
@@ -0,0 +1,547 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2011 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout.provider;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.PositionConstants;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.GraphicalEditPart;
+import org.eclipse.gef.Request;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.commands.CompoundCommand;
+import org.eclipse.gef.commands.UnexecutableCommand;
+import org.eclipse.gef.requests.ChangeBoundsRequest;
+import org.eclipse.gmf.runtime.common.core.service.IOperation;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.services.layout.AbstractLayoutEditPartProvider;
+import org.eclipse.gmf.runtime.notation.View;
+
+import com.google.common.collect.Iterables;
+
+import org.eclipse.sirius.common.tools.DslCommonPlugin;
+import org.eclipse.sirius.common.tools.api.profiler.ProfilerTask;
+import org.eclipse.sirius.common.ui.SiriusTransPlugin;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.PinHelper;
+import org.eclipse.sirius.diagram.ui.tools.internal.layout.provider.LayoutService;
+
+/**
+ * An abstract layout provider.
+ *
+ * @author ymortier
+ */
+public abstract class AbstractLayoutProvider extends AbstractLayoutEditPartProvider {
+
+ /**
+ * Modeler Category.
+ */
+ public static final String GENERIC_MODELER_CAT = "Generic Modeler";
+
+ /**
+ * Arrange all.
+ */
+ public static final ProfilerTask ARRANGE_ALL = new ProfilerTask(GENERIC_MODELER_CAT, "Arrange All");
+
+ /** Map all views with a its associated {@link ChangeBoundsRequest}. */
+ protected Map<View, List<Request>> viewsToChangeBoundsRequest;
+
+ /**
+ * Create a new {@link AbstractLayoutProvider}.
+ *
+ */
+ public AbstractLayoutProvider() {
+ this.viewsToChangeBoundsRequest = new HashMap<View, List<Request>>();
+ }
+
+ /**
+ * Set the map that maps all views with a its associated
+ * {@link ChangeBoundsRequest}.
+ *
+ * @param viewsToChangeBoundsRequest
+ * Map all views with a its associated
+ * {@link ChangeBoundsRequest}.
+ */
+ public void setViewsToChangeBoundsRequest(final Map<View, List<Request>> viewsToChangeBoundsRequest) {
+ this.viewsToChangeBoundsRequest = viewsToChangeBoundsRequest;
+ }
+
+ /**
+ * Return the map that maps all views with a its associated
+ * {@link ChangeBoundsRequest}.
+ *
+ * @return the map that maps all views with a its associated
+ * {@link ChangeBoundsRequest}.
+ */
+ public Map<View, List<Request>> getViewsToChangeBoundsRequest() {
+ return viewsToChangeBoundsRequest;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.services.layout.AbstractLayoutEditPartProvider#layoutEditParts(org.eclipse.gef.GraphicalEditPart,
+ * org.eclipse.core.runtime.IAdaptable)
+ */
+ @Override
+ public final Command layoutEditParts(final GraphicalEditPart containerEditPart, final IAdaptable layoutHint) {
+ DslCommonPlugin.PROFILER.startWork(ARRANGE_ALL);
+
+ this.getViewsToChangeBoundsRequest().clear();
+
+ /*
+ * If we are asked to layout a whole diagram, check if a specific
+ * provider has been registered for it (through the
+ * org.eclipse.sirius.common.ui.airLayoutProvider extension point), and use
+ * that provider if there is.
+ */
+ if (containerEditPart instanceof DiagramEditPart) {
+ final DiagramEditPart diagramEditPart = (DiagramEditPart) containerEditPart;
+ final LayoutProvider diagramLayoutProvider = getDiagramLayoutProvider(diagramEditPart, layoutHint);
+ if (diagramLayoutProvider != null) {
+ final Command command = getCommandFromDiagramLayoutProvider(diagramLayoutProvider, diagramEditPart, layoutHint);
+ command.setLabel("Arrange all");
+ DslCommonPlugin.PROFILER.stopWork(ARRANGE_ALL);
+ return command;
+ }
+ }
+
+ final Command command = buildCommand(containerEditPart, layoutHint);
+ command.setLabel("Arrange all");
+ this.getViewsToChangeBoundsRequest().clear();
+ AbstractLayoutProvider.resetWrappedCommand(command);
+ DslCommonPlugin.PROFILER.stopWork(ARRANGE_ALL);
+ return command;
+ }
+
+ /**
+ * Get the the diagram layout provider if there is one.
+ *
+ * @param diagramEditPart
+ * the diagram edit part
+ * @param layoutHint
+ * the layout hint
+ * @return the diagram layout provider if there is one, <code>null</code>
+ * otherwise
+ */
+ private LayoutProvider getDiagramLayoutProvider(final DiagramEditPart diagramEditPart, final IAdaptable layoutHint) {
+ final LayoutProvider candidate = LayoutService.getProvider(diagramEditPart);
+ if (candidate != null && candidate.isDiagramLayoutProvider()) {
+ return candidate;
+ } else {
+ return null;
+ }
+ }
+
+ private Command getCommandFromDiagramLayoutProvider(final LayoutProvider diagramLayoutProvider, final DiagramEditPart diagramEditPart, final IAdaptable layoutHint) {
+ Command command = null;
+ final AbstractLayoutEditPartProvider layoutProvider = diagramLayoutProvider.getLayoutNodeProvider(diagramEditPart);
+ try {
+ final Method method = layoutProvider.getClass().getMethod("layoutEditParts", new Class[] { GraphicalEditPart.class, IAdaptable.class });
+ Assert.isNotNull(method);
+ /* this code seems to avoid an infinite loop */
+ if (method.getDeclaringClass() != AbstractLayoutProvider.class) {
+ command = layoutProvider.layoutEditParts(diagramEditPart, layoutHint);
+ }
+ } catch (final SecurityException e) {
+ SiriusTransPlugin.getPlugin().error("Layout Error", e);
+ } catch (final NoSuchMethodException e) {
+ SiriusTransPlugin.getPlugin().error("Layout Error", e);
+ }
+ if (command == null) {
+ final List<?> children = diagramEditPart.getChildren();
+ command = layoutProvider.layoutEditParts(children, layoutHint);
+ }
+ return command;
+ }
+
+ /**
+ * Build the command which performs the layout of all the edit parts in the
+ * specified container.
+ * <p>
+ * The resulting command is a compound command built recursively by calling
+ * {@link #layoutEditParts(List, IAdaptable)} on all the descendants of the
+ * specified container and then on the container itself.
+ *
+ * @param containerEditPart
+ * the container to layout.
+ * @param layoutHint
+ * the hint to use.
+ * @return a command to execute to perform the layout of the container and
+ * all its descendants.
+ */
+ private Command buildCommand(final GraphicalEditPart containerEditPart, final IAdaptable layoutHint) {
+ final CompoundCommand cc = new CompoundCommand();
+ // Depth-first recursion.
+ for (final IGraphicalEditPart graphicalEditPart : Iterables.filter(containerEditPart.getChildren(), IGraphicalEditPart.class)) {
+ final Command command = buildCommand(graphicalEditPart, layoutHint);
+ if (command.canExecute()) {
+ cc.add(command);
+ }
+ }
+ // Base case: layout the container's direct children.
+ final Command command = this.layoutEditParts(containerEditPart.getChildren(), layoutHint);
+ if (command.canExecute()) {
+ cc.add(command);
+ }
+ return cc;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.common.core.service.IProvider#provides(org.eclipse.gmf.runtime.common.core.service.IOperation)
+ */
+ public boolean provides(final IOperation operation) {
+ return false;
+ }
+
+ /**
+ * Search a request for the specified edit part and of the specified type.
+ *
+ * @param editPart
+ * the edit part.
+ * @param requestType
+ * the type of the request.
+ * @return the found request.
+ */
+ protected Request findRequest(final IGraphicalEditPart editPart, final Object requestType) {
+ if (editPart != null) {
+ return findRequest(editPart.getNotationView(), requestType);
+ }
+ return null;
+ }
+
+ /**
+ * Search a request for the specified view and of the specified type.
+ *
+ * @param notationView
+ * the view.
+ * @param requestType
+ * the type of the request.
+ * @return the found request.
+ */
+ protected Request findRequest(final View notationView, final Object requestType) {
+ final List<Request> requests = this.getViewsToChangeBoundsRequest().get(notationView);
+ Request result = null;
+ if (requests != null) {
+ final Iterator<Request> iterRequests = requests.iterator();
+ while (iterRequests.hasNext() && result == null) {
+ final Request currentRequest = iterRequests.next();
+ if (currentRequest.getType() != null && currentRequest.getType().equals(requestType)) {
+ result = currentRequest;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Create a command with the specified request.
+ *
+ * @param request
+ * the request.
+ * @param editPart
+ * the edit part.
+ * @return an executable command.
+ */
+ protected Command buildCommandWrapper(final Request request, final EditPart editPart) {
+ if (editPart instanceof IGraphicalEditPart) {
+ List<Request> requests = this.getViewsToChangeBoundsRequest().get(((IGraphicalEditPart) editPart).getNotationView());
+ if (requests == null) {
+ requests = new LinkedList<Request>();
+ this.getViewsToChangeBoundsRequest().put(((IGraphicalEditPart) editPart).getNotationView(), requests);
+ }
+ requests.add(request);
+ }
+ return new CommandWrapper(request, editPart);
+ }
+
+ /**
+ * Tests whether an edit part should be considered as pinned (fixed size and
+ * location) during the layout.
+ *
+ * @param part
+ * the edit part.
+ * @return <code>true</code> if the edit part should be considered as
+ * pinned.
+ */
+ protected boolean isPinned(final IGraphicalEditPart part) {
+ boolean isPinned = false;
+ if (part.resolveSemanticElement() instanceof DDiagramElement) {
+ DDiagramElement dDiagramElement = (DDiagramElement) part.resolveSemanticElement();
+ isPinned = new PinHelper().isPinned(dDiagramElement);
+ }
+ return isPinned;
+ }
+
+ /**
+ * Wraps a GMF Command.
+ *
+ * @author ymortier
+ */
+ protected static class CommandWrapper extends Command {
+
+ /** The wrapped command. */
+ private Command executedCommand;
+
+ /** The request. */
+ private final Request request;
+
+ /** The edit part. */
+ private final EditPart editPart;
+
+ /**
+ * Create a new Command wrapper.
+ *
+ * @param request
+ * the request.
+ * @param editPart
+ * the edit part.
+ */
+ public CommandWrapper(final Request request, final EditPart editPart) {
+ this.request = request;
+ this.editPart = editPart;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gef.commands.Command#execute()
+ */
+ @Override
+ public void execute() {
+ final Command cmd = this.getWrappedCommand();
+ cmd.execute();
+ executedCommand = cmd;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gef.commands.Command#canExecute()
+ */
+ @Override
+ public boolean canExecute() {
+ return this.getWrappedCommand().canExecute();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gef.commands.Command#canUndo()
+ */
+ @Override
+ public boolean canUndo() {
+ return this.getWrappedCommand().canUndo();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gef.commands.Command#undo()
+ */
+ @Override
+ public void undo() {
+ this.getWrappedCommand().undo();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gef.commands.Command#redo()
+ */
+ @Override
+ public void redo() {
+ this.getWrappedCommand().redo();
+ }
+
+ private Command getWrappedCommand() {
+ final Command result;
+ if (executedCommand == null) {
+ final Command cmd = editPart.getCommand(request);
+ if (cmd == null) {
+ result = UnexecutableCommand.INSTANCE;
+ } else {
+ result = cmd;
+ }
+ } else {
+ result = executedCommand;
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getLabel() {
+ return getWrappedCommand().getLabel();
+ }
+
+ /**
+ * Returns the request that is causing the command.
+ *
+ * @return the request
+ */
+ public Request getRequest() {
+ return request;
+ }
+
+ /**
+ * Return the associated edit part.
+ *
+ * @return the editPart
+ */
+ public EditPart getEditPart() {
+ return editPart;
+ }
+ }
+
+ /**
+ * Return the relative bounds of the specified edit part.
+ *
+ * @param graphicalEditPart
+ * the edit part.
+ * @return the bounds of the specified edit part.
+ */
+ protected Rectangle getBounds(final IGraphicalEditPart graphicalEditPart) {
+ Object existingRequest = this.findRequest(graphicalEditPart, org.eclipse.gef.RequestConstants.REQ_RESIZE);
+ final Rectangle figureBounds = new Rectangle(graphicalEditPart.getFigure().getBounds());
+ if (existingRequest instanceof ChangeBoundsRequest) {
+ final ChangeBoundsRequest changeBoundsRequest = (ChangeBoundsRequest) existingRequest;
+ if (changeBoundsRequest.getSizeDelta() != null) {
+ adjustBounds(figureBounds, changeBoundsRequest);
+ }
+ }
+ existingRequest = this.findRequest(graphicalEditPart, org.eclipse.gef.RequestConstants.REQ_MOVE);
+ if (existingRequest instanceof ChangeBoundsRequest) {
+ final ChangeBoundsRequest changeBoundsRequest = (ChangeBoundsRequest) existingRequest;
+ if (changeBoundsRequest.getMoveDelta() != null) {
+ figureBounds.x += changeBoundsRequest.getMoveDelta().x;
+ figureBounds.y += changeBoundsRequest.getMoveDelta().y;
+ }
+ }
+ return figureBounds;
+ }
+
+ private void adjustBounds(final Rectangle figureBounds, final ChangeBoundsRequest changeBoundsRequest) {
+ switch (changeBoundsRequest.getResizeDirection()) {
+ case PositionConstants.NORTH:
+ figureBounds.height += changeBoundsRequest.getSizeDelta().height;
+ figureBounds.y -= changeBoundsRequest.getSizeDelta().height;
+ break;
+ case PositionConstants.SOUTH:
+ figureBounds.height += changeBoundsRequest.getSizeDelta().height;
+ break;
+ case PositionConstants.EAST:
+ figureBounds.width += changeBoundsRequest.getSizeDelta().width;
+ break;
+ case PositionConstants.WEST:
+ figureBounds.width += changeBoundsRequest.getSizeDelta().width;
+ figureBounds.x -= changeBoundsRequest.getSizeDelta().width;
+ break;
+ case PositionConstants.NORTH_EAST:
+ figureBounds.height += changeBoundsRequest.getSizeDelta().height;
+ figureBounds.y -= changeBoundsRequest.getSizeDelta().height;
+ figureBounds.width += changeBoundsRequest.getSizeDelta().width;
+ break;
+ case PositionConstants.NORTH_WEST:
+ figureBounds.height += changeBoundsRequest.getSizeDelta().height;
+ figureBounds.y -= changeBoundsRequest.getSizeDelta().height;
+ figureBounds.width += changeBoundsRequest.getSizeDelta().width;
+ figureBounds.x -= changeBoundsRequest.getSizeDelta().width;
+ break;
+ case PositionConstants.SOUTH_WEST:
+ figureBounds.height += changeBoundsRequest.getSizeDelta().height;
+ figureBounds.width += changeBoundsRequest.getSizeDelta().width;
+ figureBounds.x -= changeBoundsRequest.getSizeDelta().width;
+ break;
+ default:
+ figureBounds.height += changeBoundsRequest.getSizeDelta().height;
+ figureBounds.width += changeBoundsRequest.getSizeDelta().width;
+ }
+ }
+
+ /**
+ * Return the first figure of type <code>type</code> that is the figure
+ * <code>searchRoot</code> or a child of <code>searchRoot</code>.
+ *
+ * @param searchRoot
+ * the root figure to start the search.
+ * @param type
+ * the type of the figure to return.
+ * @return Return the first figure of type <code>type</code> that is the
+ * figure <code>searchRoot</code> or a child of
+ * <code>searchRoot</code>.
+ */
+ protected IFigure findChild(final IFigure searchRoot, final Class<?> type) {
+ IFigure result = null;
+ if (type.isInstance(searchRoot)) {
+ result = searchRoot;
+ }
+ final Iterator<?> iterChildren = searchRoot.getChildren().iterator();
+ while (iterChildren.hasNext() && result == null) {
+ final IFigure child = (IFigure) iterChildren.next();
+ result = findChild(child, type);
+ }
+ return result;
+ }
+
+ /**
+ * Return all edit parts contained in root + root.
+ *
+ * @param root
+ * the root edit part
+ * @return all edit parts contained in root + root.
+ */
+ @SuppressWarnings("unchecked")
+ public List<EditPart> getAllEditParts(final EditPart root) {
+ final Set<EditPart> editParts = new HashSet<EditPart>();
+ editParts.add(root);
+ if (root instanceof GraphicalEditPart) {
+ editParts.addAll(((GraphicalEditPart) root).getSourceConnections());
+ editParts.addAll(((GraphicalEditPart) root).getTargetConnections());
+ }
+ final Iterator<EditPart> iterChildren = root.getChildren().iterator();
+ while (iterChildren.hasNext()) {
+ final EditPart next = iterChildren.next();
+ editParts.addAll(getAllEditParts(next));
+ }
+ return new ArrayList<EditPart>(editParts);
+ }
+
+ private static void resetWrappedCommand(final Command command) {
+ if (command instanceof CommandWrapper) {
+ ((CommandWrapper) command).executedCommand = null;
+ } else if (command instanceof CompoundCommand) {
+ final Object[] children = ((CompoundCommand) command).getChildren();
+ for (Object element : children) {
+ if (element instanceof Command) {
+ AbstractLayoutProvider.resetWrappedCommand((Command) element);
+ }
+ }
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/provider/CompoundLayoutProvider.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/provider/CompoundLayoutProvider.java
new file mode 100644
index 0000000000..74e08b3916
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/provider/CompoundLayoutProvider.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2011 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout.provider;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.commands.CompoundCommand;
+import org.eclipse.gmf.runtime.common.core.service.IOperation;
+import org.eclipse.gmf.runtime.diagram.ui.services.layout.AbstractLayoutEditPartProvider;
+
+/**
+ * A compound layout provider.
+ *
+ * @author ymortier
+ */
+public class CompoundLayoutProvider extends AbstractLayoutProvider {
+
+ /** the list of delegated providers. */
+ private final List<AbstractLayoutEditPartProvider> delegatedProviders = new LinkedList<AbstractLayoutEditPartProvider>();
+
+ /** The list of providers that provides for the next operation. */
+ private final List<AbstractLayoutEditPartProvider> realDelegatedProviders = new LinkedList<AbstractLayoutEditPartProvider>();
+
+ /**
+ * Adds a provider.
+ *
+ * @param provider
+ * the provider to add.
+ */
+ public void addProvider(final AbstractLayoutEditPartProvider provider) {
+ this.delegatedProviders.add(provider);
+ this.realDelegatedProviders.add(provider);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.services.layout.AbstractLayoutEditPartProvider#layoutEditParts(java.util.List,
+ * org.eclipse.core.runtime.IAdaptable)
+ */
+ @Override
+ public Command layoutEditParts(final List selectedObjects, final IAdaptable layoutHint) {
+ final CompoundCommand cc = new CompoundCommand();
+ final ArrayList<AbstractLayoutEditPartProvider> inverse = new ArrayList<AbstractLayoutEditPartProvider>(this.realDelegatedProviders);
+ final Iterator<AbstractLayoutEditPartProvider> iterRealDelegatedProviders = inverse.listIterator();
+ while (iterRealDelegatedProviders.hasNext()) {
+ final AbstractLayoutEditPartProvider provider = iterRealDelegatedProviders.next();
+ if (provider instanceof AbstractLayoutProvider) {
+ ((AbstractLayoutProvider) provider).setViewsToChangeBoundsRequest(this.getViewsToChangeBoundsRequest());
+ }
+ final Command command = provider.layoutEditParts(new ArrayList(selectedObjects), layoutHint);
+ if (command != null && command.canExecute()) {
+ cc.add(command);
+ }
+ if (provider instanceof AbstractLayoutProvider) {
+ this.getViewsToChangeBoundsRequest().putAll(((AbstractLayoutProvider) provider).getViewsToChangeBoundsRequest());
+ }
+ }
+ this.getViewsToChangeBoundsRequest().clear();
+ return cc;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.provider.AbstractLayoutProvider#provides(org.eclipse.gmf.runtime.common.core.service.IOperation)
+ */
+ @Override
+ public boolean provides(final IOperation operation) {
+ boolean result = false;
+ this.realDelegatedProviders.clear();
+ final Iterator<AbstractLayoutEditPartProvider> iterDelegatedProviders = this.delegatedProviders.listIterator();
+ while (iterDelegatedProviders.hasNext()) {
+ final AbstractLayoutEditPartProvider currentProvider = iterDelegatedProviders.next();
+ if (currentProvider.provides(operation)) {
+ result = true;
+ this.realDelegatedProviders.add(currentProvider);
+ }
+ }
+ return result;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/provider/DefaultLayoutProvider.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/provider/DefaultLayoutProvider.java
new file mode 100644
index 0000000000..f1fe125832
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/provider/DefaultLayoutProvider.java
@@ -0,0 +1,217 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout.provider;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.commands.CompoundCommand;
+import org.eclipse.gmf.runtime.common.core.service.IOperation;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.services.layout.AbstractLayoutEditPartProvider;
+import org.eclipse.gmf.runtime.diagram.ui.services.layout.ILayoutNodeOperation;
+import org.eclipse.gmf.runtime.diagram.ui.services.layout.LayoutType;
+import org.eclipse.gmf.runtime.notation.View;
+
+import org.eclipse.sirius.common.tools.DslCommonPlugin;
+import org.eclipse.sirius.diagram.ui.tools.internal.layout.provider.LayoutService;
+
+/**
+ * Default layout provider. It delegates the operation using the
+ * {@link LayoutService}.
+ *
+ * @author ymortier
+ */
+public class DefaultLayoutProvider extends AbstractLayoutProvider {
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.provider.AbstractLayoutProvider#provides(org.eclipse.gmf.runtime.common.core.service.IOperation)
+ */
+ @Override
+ public boolean provides(final IOperation operation) {
+ if (operation instanceof ILayoutNodeOperation) {
+ final ILayoutNodeOperation layoutNodeOperation = (ILayoutNodeOperation) operation;
+ final IAdaptable layoutHint = layoutNodeOperation.getLayoutHint();
+ final String layoutType = (String) layoutHint.getAdapter(String.class);
+ if (LayoutType.DEFAULT.equals(layoutType)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.services.layout.AbstractLayoutEditPartProvider#layoutEditParts(java.util.List,
+ * org.eclipse.core.runtime.IAdaptable)
+ */
+ @Override
+ public Command layoutEditParts(final List selectedObjects, final IAdaptable layoutHint) {
+ DslCommonPlugin.PROFILER.startWork(ARRANGE_ALL);
+ final CompoundCommand cc = new CompoundCommand();
+ final Map<EditPart, List<EditPart>> allLayouts = this.split(selectedObjects);
+ final Iterator<Entry<EditPart, List<EditPart>>> iterEntries = allLayouts.entrySet().iterator();
+ while (iterEntries.hasNext()) {
+ final Entry<EditPart, List<EditPart>> currentEntry = iterEntries.next();
+ final IGraphicalEditPart container = (IGraphicalEditPart) currentEntry.getKey();
+ final List<EditPart> children = currentEntry.getValue();
+ if (container instanceof DiagramEditPart) {
+ // addConnection.
+ final DiagramEditPart diagramEditPart = (DiagramEditPart) container;
+ children.addAll(diagramEditPart.getConnections());
+ }
+ final LayoutProvider airLayoutProvider = LayoutService.getProvider(container);
+ if (airLayoutProvider != null) {
+ final AbstractLayoutEditPartProvider gmfLayoutProvider = airLayoutProvider.getLayoutNodeProvider(container);
+ if (gmfLayoutProvider != null) {
+ if (gmfLayoutProvider instanceof AbstractLayoutProvider) {
+ ((AbstractLayoutProvider) gmfLayoutProvider).setViewsToChangeBoundsRequest(this.getViewsToChangeBoundsRequest());
+ }
+ cc.add(gmfLayoutProvider.layoutEditParts(children, layoutHint));
+ if (gmfLayoutProvider instanceof AbstractLayoutProvider) {
+ this.getViewsToChangeBoundsRequest().putAll(((AbstractLayoutProvider) gmfLayoutProvider).getViewsToChangeBoundsRequest());
+ // ((AbstractAirLayoutProvider)
+ // gmfLayoutProvider).getViewsToChangeBoundsRequest().clear();
+ }
+ }
+ }
+ }
+ // this.getViewsToChangeBoundsRequest().clear();
+ DslCommonPlugin.PROFILER.stopWork(ARRANGE_ALL);
+ return cc;
+ }
+
+ /**
+ * Split all edit parts according to their container. Returns a map
+ * (container -> children to layout).
+ *
+ * @param editParts
+ * the
+ * @return a map (container -> children to layout).
+ */
+ protected Map<EditPart, List<EditPart>> split(final List<EditPart> editParts) {
+ final Map<EditPart, List<EditPart>> result = new HashMap<EditPart, List<EditPart>>();
+ final Iterator<EditPart> iterEditParts = editParts.listIterator();
+ while (iterEditParts.hasNext()) {
+ final Object next = iterEditParts.next();
+ if (next instanceof ConnectionEditPart) {
+ final ConnectionEditPart connectionEditPart = (ConnectionEditPart) next;
+ final EditPart container = this.getDiagramEditPart(connectionEditPart);
+ DefaultLayoutProvider.addToMap(result, container, connectionEditPart);
+ } else if (next instanceof IGraphicalEditPart) {
+ final IGraphicalEditPart graphicalEditPart = (IGraphicalEditPart) next;
+ final EditPart container = graphicalEditPart.getParent();
+ DefaultLayoutProvider.addToMap(result, container, graphicalEditPart);
+ } else {
+ iterEditParts.remove();
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Add the object <code>value</code> to the list of objects that is in the
+ * map <code>map</code> for the key <code>key</code>.
+ *
+ * @param map
+ * the map.
+ * @param key
+ * the key.
+ * @param value
+ * the value to add.
+ * @since 2.0
+ */
+ protected static void addToMap(final Map<EditPart, List<EditPart>> map, final EditPart key, final EditPart value) {
+ List<EditPart> values = map.get(key);
+ if (values == null) {
+ values = new LinkedList<EditPart>();
+ map.put(key, values);
+ }
+ values.add(value);
+ }
+
+ /**
+ * Remove all elements that are not an instance of the specified type from
+ * the List <code>list</code>.
+ *
+ * @param list
+ * the list to filter.
+ * @param type
+ * the type to get.
+ */
+ protected static void retainType(final List<?> list, final Class<?> type) {
+ final Iterator<?> iterElements = list.iterator();
+ while (iterElements.hasNext()) {
+ if (!type.isInstance(iterElements.next())) {
+ iterElements.remove();
+ }
+ }
+ }
+
+ /**
+ * Return the diagram edit part of the specified edit part or
+ * <code>null</code> if the diagram edit part can not be retrieved.
+ *
+ * @param editPart
+ * an edit part.
+ * @return the diagram edit part of the specified edit part or
+ * <code>null</code> if the diagram edit part can not be retrieved.
+ */
+ protected DiagramEditPart getDiagramEditPart(final EditPart editPart) {
+ EditPart current = editPart;
+ while (current != null) {
+ if (current instanceof DiagramEditPart) {
+ return (DiagramEditPart) current;
+ }
+ if (current instanceof ConnectionEditPart) {
+ current = ((ConnectionEditPart) current).getSource();
+ } else {
+ current = current.getParent();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return all GMF views of the specified {@link EditPart}s. The key of the
+ * map is a view and the value is the associated {@link EditPart}.
+ *
+ * @param editParts
+ * the edit parts.
+ * @return all GMF views of the specified {@link EditPart}s.
+ * @param <T>
+ * a class which implements {@link EditPart}
+ */
+ protected <T extends EditPart> Map<View, T> getViews(final List<T> editParts) {
+ final Map<View, T> result = new HashMap<View, T>();
+ final Iterator<T> iterEditParts = editParts.iterator();
+ while (iterEditParts.hasNext()) {
+ final T next = iterEditParts.next();
+ if (next.getModel() instanceof View) {
+ result.put((View) next.getModel(), next);
+ }
+ }
+ return result;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/provider/ExtendableLayoutProvider.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/provider/ExtendableLayoutProvider.java
new file mode 100644
index 0000000000..dbcb2f96f4
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/provider/ExtendableLayoutProvider.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout.provider;
+
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.draw2d.graph.Node;
+
+import org.eclipse.sirius.diagram.ui.tools.api.layout.LayoutExtender;
+
+/**
+ * This interface is the lowest common denominator a layout provider needs to
+ * respect to be able to leverage the layout extensions.
+ *
+ * @author cbrun
+ *
+ */
+public interface ExtendableLayoutProvider {
+ /**
+ * return true if the layout handle connectable list items.
+ *
+ * @return true if the layout handle connectable list items.
+ */
+ boolean handleConnectableListItems();
+
+ /**
+ * should return the node metric.
+ *
+ * @param node
+ * a node.
+ * @return the node metric
+ */
+ Rectangle provideNodeMetrics(final Node node);
+
+ /**
+ * return the layout extender used.
+ *
+ * @return the layout extender used.
+ */
+ LayoutExtender getExtender();
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/provider/GridLayoutProvider.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/provider/GridLayoutProvider.java
new file mode 100644
index 0000000000..b2f731b039
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/provider/GridLayoutProvider.java
@@ -0,0 +1,555 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout.provider;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.draw2d.PositionConstants;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Insets;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.draw2d.graph.Node;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.commands.CompoundCommand;
+import org.eclipse.gef.editparts.ZoomManager;
+import org.eclipse.gef.requests.ChangeBoundsRequest;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramRootEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IBorderItemEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeEditPart;
+import org.eclipse.gmf.runtime.notation.View;
+
+import org.eclipse.sirius.diagram.ui.tools.api.layout.LayoutExtender;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.ordering.GridView;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.ordering.GridView.Column;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.ordering.GridViewOrdering;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.ordering.SimpleViewOrdering;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.ordering.ViewOrderingHint;
+
+/**
+ * A layout provider that arranges views according to the specified
+ * {@link GridViewOrdering}.
+ *
+ * @author ymortier
+ */
+public class GridLayoutProvider extends DefaultLayoutProvider implements ExtendableLayoutProvider {
+
+ /** Each case of the grid has the same dimension. */
+ public static final int SAME_DIMENSION = 1;
+
+ /** Each case dimension is computed by line or column. */
+ public static final int DIMENSION_BY_LINE_OR_COLUMN = 2;
+
+ /** Each case has its owned dimension. */
+ public static final int FREE_DIMENSION = 3;
+
+ /** Cache location to improve performances. */
+ private Map<Point, Point> locationsCache = new HashMap<Point, Point>();
+
+ /** The mode of the column size. */
+ private int columnSizeMode = GridLayoutProvider.SAME_DIMENSION;
+
+ /**
+ * The mode of the line size.
+ */
+ private int lineSizeMode = GridLayoutProvider.SAME_DIMENSION;
+
+ /** The padding. */
+ private Insets padding = new Insets(30, 30, 30, 30);
+
+ /**
+ * Maps each column with its max width.
+ * <ul>
+ * <li>Key : Integer, index of the column.</li>
+ * <li>Value : Integer, the max width.</li>
+ * </ul>
+ */
+ private Map<Integer, Integer> maxWidths = new HashMap<Integer, Integer>();
+
+ /**
+ * Maps each line with its max height.
+ * <ul>
+ * <li>Key : Integer, index of the line.</li>
+ * <li>Value : Integer, the max height.</li>
+ * </ul>
+ */
+ private Map<Integer, Integer> maxHeights = new HashMap<Integer, Integer>();
+
+ private final LayoutExtender extender = new LayoutExtender(this);
+
+ /**
+ * Return the padding.
+ *
+ * @return the padding.
+ */
+ public Insets getPadding() {
+ return padding;
+ }
+
+ /**
+ * Returns the column size computing style. The style can be
+ * <ul>
+ * <li>{@link #SAME_DIMENSION}</li>
+ * <li>{@link #DIMENSION_BY_LINE_OR_COLUMN}</li>
+ * <li>{@link #FREE_DIMENSION}</li>
+ * </ul>
+ *
+ * @return the column size computing style.
+ */
+ public int getColumnSizeMode() {
+ return columnSizeMode;
+ }
+
+ /**
+ * Sets the column size computing style. The style can be
+ * <ul>
+ * <li>{@link #SAME_DIMENSION}</li>
+ * <li>{@link #DIMENSION_BY_LINE_OR_COLUMN}</li>
+ * <li>{@link #FREE_DIMENSION}</li>
+ * </ul>
+ *
+ * @param columnSizeMode
+ * the column size computing style.
+ */
+ public void setColumnSizeMode(final int columnSizeMode) {
+ if (columnSizeMode < GridLayoutProvider.SAME_DIMENSION || columnSizeMode > GridLayoutProvider.FREE_DIMENSION) {
+ throw new IllegalArgumentException("Unknown mode : " + columnSizeMode);
+ }
+ this.columnSizeMode = columnSizeMode;
+ }
+
+ /**
+ * Returns the line size computing style. The style can be
+ * <ul>
+ * <li>{@link #SAME_DIMENSION}</li>
+ * <li>{@link #DIMENSION_BY_LINE_OR_COLUMN}</li>
+ * <li>{@link #FREE_DIMENSION}</li>
+ * </ul>
+ *
+ * @return the line size computing style.
+ */
+ public int getLineSizeMode() {
+ return lineSizeMode;
+ }
+
+ /**
+ * Sets the line size computing style. The style can be
+ * <ul>
+ * <li>{@link #SAME_DIMENSION}</li>
+ * <li>{@link #DIMENSION_BY_LINE_OR_COLUMN}</li>
+ * <li>{@link #FREE_DIMENSION}</li>
+ * </ul>
+ *
+ * @param lineSizeMode
+ * the line size computing style.
+ */
+ public void setLineSizeMode(final int lineSizeMode) {
+ if (lineSizeMode < GridLayoutProvider.SAME_DIMENSION || lineSizeMode > GridLayoutProvider.FREE_DIMENSION) {
+ throw new IllegalArgumentException("Unknown mode : " + lineSizeMode);
+ }
+ this.lineSizeMode = lineSizeMode;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.provider.DefaultLayoutProvider#layoutEditParts(java.util.List,
+ * org.eclipse.core.runtime.IAdaptable)
+ */
+ @Override
+ public Command layoutEditParts(@SuppressWarnings("rawtypes")
+ final List selectedObjects, final IAdaptable layoutHint) {
+ extender.startLayouting();
+ this.maxHeights.clear();
+ this.maxWidths.clear();
+ this.locationsCache.clear();
+ final Iterator<?> iterEditParts = selectedObjects.iterator();
+ final List<View> views = new ArrayList<View>(selectedObjects.size());
+ final Map<View, IGraphicalEditPart> viewsToEditPartMap = new HashMap<View, IGraphicalEditPart>();
+ while (iterEditParts.hasNext()) {
+ final Object next = iterEditParts.next();
+ if (next instanceof ShapeEditPart && !(next instanceof IBorderItemEditPart)) {
+ final ShapeEditPart shapeEditPart = (ShapeEditPart) next;
+ final View view = shapeEditPart.getNotationView();
+ viewsToEditPartMap.put(view, shapeEditPart);
+ views.add(view);
+ } else {
+ iterEditParts.remove();
+ }
+ }
+ GridViewOrdering viewOrdering = ViewOrderingHint.getInstance().consumeViewOrdering(getContainerEditPart(selectedObjects).getNotationView());
+ if (viewOrdering == null) {
+ viewOrdering = new SimpleViewOrdering();
+ }
+ viewOrdering.setViews(views);
+ final GridView gridView = viewOrdering.getSortedViewsAsGrid();
+
+ final Command command = this.buildGrid(gridView, viewsToEditPartMap);
+ //
+ // Layout the container.
+ final Command layoutContainer = this.getLayoutContainerCommand(getContainerEditPart(selectedObjects), gridView);
+
+ this.maxHeights.clear();
+ this.maxWidths.clear();
+ this.locationsCache.clear();
+
+ final CompoundCommand cc = new CompoundCommand();
+ cc.add(command);
+ if (layoutContainer != null && layoutContainer.canExecute()) {
+ cc.add(layoutContainer);
+ }
+ return cc;
+ }
+
+ /**
+ * Return the command that layout the container of this grid.
+ *
+ * @param gridView
+ * the grid.
+ * @return the command that layout the container of this grid.
+ */
+ private Command getLayoutContainerCommand(final IGraphicalEditPart containerEditPart, final GridView gridView) {
+ final Dimension containerMinDimension = getLayoutDimensions(gridView);
+ final Dimension expand = new Dimension(0, 0);
+
+ final Dimension containerBounds = this.getBounds(containerEditPart).getSize();
+ if (containerBounds.width < containerMinDimension.width) {
+ expand.width = containerMinDimension.width - containerBounds.width;
+ }
+ if (containerBounds.height < containerMinDimension.height) {
+ expand.height = containerMinDimension.height - containerBounds.height;
+ }
+
+ if (expand.width > 0 || expand.height > 0) {
+ final Object existingRequest = this.viewsToChangeBoundsRequest.get(containerEditPart.getNotationView());
+ if (existingRequest == null) {
+ final ChangeBoundsRequest cbr = new ChangeBoundsRequest(org.eclipse.gef.RequestConstants.REQ_RESIZE);
+ cbr.setResizeDirection(PositionConstants.SOUTH_EAST);
+ cbr.setSizeDelta(expand);
+ final Command command = this.buildCommandWrapper(cbr, containerEditPart);
+ return command;
+ } else if (existingRequest instanceof ChangeBoundsRequest) {
+ final ChangeBoundsRequest cbr = (ChangeBoundsRequest) existingRequest;
+ cbr.setResizeDirection(PositionConstants.SOUTH_EAST);
+ cbr.setSizeDelta(expand);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Creates the command that arranges all views in a grid format.
+ *
+ * @param gridView
+ * the grid.
+ * @param viewsToEditPart
+ * map each view to its edit part.
+ * @return the command that arranges all views in a grid format.
+ */
+ protected Command buildGrid(final GridView gridView, final Map<View, IGraphicalEditPart> viewsToEditPart) {
+ final CompoundCommand cc = new CompoundCommand();
+ if (this.getColumnSizeMode() != GridLayoutProvider.FREE_DIMENSION || this.getLineSizeMode() != GridLayoutProvider.FREE_DIMENSION) {
+ // init size.
+ final Iterator<Column> iterColumns = gridView.iteratorColumns();
+ while (iterColumns.hasNext()) {
+ final Column currentColumn = iterColumns.next();
+ final Integer columnIndex = Integer.valueOf(currentColumn.getIndex());
+ this.maxWidths.put(columnIndex, Integer.valueOf(-1));
+ for (int i = 0; i < currentColumn.getViewsCount(); i++) {
+ final Integer lineIndex = Integer.valueOf(i);
+ final View view = currentColumn.getViewAt(i);
+ Dimension size = new Dimension(0, 0);
+ if (view != null) {
+ final IGraphicalEditPart editPart = viewsToEditPart.get(view);
+ size = getBounds(editPart).getSize();
+ }
+ if (maxHeights.get(lineIndex) == null) {
+ maxHeights.put(lineIndex, Integer.valueOf(-1));
+ }
+ if (size.width > maxWidths.get(columnIndex).intValue()) {
+ maxWidths.put(columnIndex, Integer.valueOf(size.width));
+ }
+ if (size.height > maxHeights.get(lineIndex).intValue()) {
+ maxHeights.put(lineIndex, Integer.valueOf(size.height));
+ }
+
+ }
+ }
+ }
+ //
+ // Create command
+ final Iterator<Column> iterColumns = gridView.iteratorColumns();
+ while (iterColumns.hasNext()) {
+ final Column currentColumn = iterColumns.next();
+ for (int i = 0; i < currentColumn.getViewsCount(); i++) {
+ final Point caseLocation = getLocation(currentColumn.getIndex(), i, gridView, viewsToEditPart);
+ if (currentColumn.getViewAt(i) != null) {
+ final IGraphicalEditPart editPart = viewsToEditPart.get(currentColumn.getViewAt(i));
+ final Point newLocation = new Point(caseLocation.x + getPadding().left, caseLocation.y + getPadding().top);
+ final Command command = createChangeBoundsCommand(editPart, newLocation);
+ if (command != null && command.canExecute()) {
+ cc.add(command);
+ }
+ }
+ }
+ }
+
+ return cc;
+ }
+
+ /**
+ * Create the command that changes the bounds of the specified edit part.
+ *
+ * @param editPart
+ * the specified edit part
+ *
+ * @param newPosition
+ * the new position of the figure.
+ * @return the command that changes the bounds of the specified edit part.
+ */
+ protected Command createChangeBoundsCommand(final IGraphicalEditPart editPart, final Point newPosition) {
+ Command result = null;
+ final Object existingRequest = this.findRequest(editPart, org.eclipse.gef.RequestConstants.REQ_MOVE);
+ ChangeBoundsRequest request = null;
+ double scale = 1.0;
+ if (editPart.getRoot() instanceof DiagramRootEditPart) {
+ final ZoomManager zoomManager = ((DiagramRootEditPart) editPart.getRoot()).getZoomManager();
+ scale = zoomManager.getZoom();
+ }
+ if (existingRequest instanceof ChangeBoundsRequest) {
+ request = (ChangeBoundsRequest) existingRequest;
+ } else if (existingRequest == null) {
+ request = new ChangeBoundsRequest();
+ request.setEditParts(editPart);
+ result = this.buildCommandWrapper(request, editPart);
+ // this.getViewsToChangeBoundsRequest().put(editPart.getNotationView(),
+ // request);
+ }
+ if (newPosition != null) {
+ final Rectangle intrinsicBounds = editPart.getFigure().getBounds();
+ final Dimension delta = newPosition.getDifference(intrinsicBounds.getLocation());
+ delta.width *= scale;
+ delta.height *= scale;
+ if ((delta.width != 0 || delta.height != 0) && request != null) {
+ request.setMoveDelta(new Point(delta.width, delta.height));
+ request.setLocation(newPosition);
+ request.setType(org.eclipse.gef.RequestConstants.REQ_MOVE);
+ result = this.buildCommandWrapper(request, editPart);
+ // String nameToDisplay = editPart.getModel().toString();
+ // if (editPart.getModel() instanceof
+ // org.eclipse.gmf.runtime.notation.Node) {
+ // org.eclipse.gmf.runtime.notation.Node n =
+ // (org.eclipse.gmf.runtime.notation.Node) editPart.getModel();
+ // nameToDisplay = n.getElement().toString();
+ // }
+ // System.out.println("newPosition:" + newPosition +
+ // ", figureBounds: " + intrinsicBounds + " --> " +
+ // nameToDisplay);
+ extender.getUpdatedBounds().put(editPart, new Rectangle(newPosition, intrinsicBounds.getSize()));
+ } else {
+ // no move, return null.
+ return null;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Return the max dimension.
+ *
+ * @return the max dimension.
+ */
+ private Dimension getDiagramMaxDimension() {
+ int maxHeight = -1;
+ final int maxWidth = -1;
+ final Iterator<Integer> iterHeights = this.maxHeights.values().iterator();
+ while (iterHeights.hasNext()) {
+ final Integer currentValue = iterHeights.next();
+ if (currentValue.intValue() > maxHeight) {
+ maxHeight = currentValue.intValue();
+ }
+ }
+ final Iterator<Integer> iterWidths = this.maxWidths.values().iterator();
+ while (iterWidths.hasNext()) {
+ final Integer currentValue = iterWidths.next();
+ if (currentValue.intValue() > maxWidth) {
+ maxHeight = currentValue.intValue();
+ }
+ }
+ return new Dimension(maxWidth, maxHeight);
+ }
+
+ private Dimension getLayoutDimensions(final GridView gridView) {
+ final Dimension result = new Dimension();
+ switch (this.getLineSizeMode()) {
+ case FREE_DIMENSION:
+ case DIMENSION_BY_LINE_OR_COLUMN:
+ final Iterator<Integer> iterHeights = this.maxHeights.values().iterator();
+ while (iterHeights.hasNext()) {
+ final Integer currentValue = iterHeights.next();
+ result.height += currentValue.intValue();
+ result.height += getPadding().top;
+ result.height += getPadding().bottom;
+ }
+ break;
+ case SAME_DIMENSION:
+ result.height = getDiagramMaxDimension().height + (getPadding().top + getPadding().bottom) * gridView.getLinesCount();
+ break;
+ default:
+ break;
+ }
+
+ switch (this.getColumnSizeMode()) {
+ case FREE_DIMENSION:
+ case DIMENSION_BY_LINE_OR_COLUMN:
+ final Iterator<Integer> iterWidths = this.maxWidths.values().iterator();
+ while (iterWidths.hasNext()) {
+ final Integer currentValue = iterWidths.next();
+ result.width += currentValue.intValue();
+ result.width += getPadding().left;
+ result.width += getPadding().top;
+ }
+ break;
+ case SAME_DIMENSION:
+ result.width = getDiagramMaxDimension().width + (getPadding().left + getPadding().right) * gridView.getColumnsCount();
+ break;
+ default:
+ break;
+ }
+ return result;
+ }
+
+ // FIXME do a real implementation.
+ /**
+ * Get the the first parent editPart of selected objects.
+ *
+ * @param selectedObjects
+ * the list of selected object
+ * @return an {@link EditPart} instance
+ */
+ protected IGraphicalEditPart getContainerEditPart(final List<?> selectedObjects) {
+ if (selectedObjects != null && !selectedObjects.isEmpty()) {
+ return (IGraphicalEditPart) ((EditPart) selectedObjects.iterator().next()).getParent();
+ }
+ return null;
+ }
+
+ /**
+ * Return the location of the case (x, y).
+ *
+ * @param x
+ * the x coordinate.
+ * @param y
+ * the y coordinate.
+ * @param gridView
+ * the grid.
+ * @param viewsToEditParts
+ * maps each view with ots corresponding edit part.
+ * @return the location of the case
+ */
+ public Point getLocation(final int x, final int y, final GridView gridView, final Map<View, IGraphicalEditPart> viewsToEditParts) {
+ final Point point = new Point(x, y);
+ final Point cachedLocation = this.locationsCache.get(point);
+ if (cachedLocation != null) {
+ return cachedLocation;
+ }
+ final Point location = new Point();
+ if (x == 0 && y == 0) {
+ location.x = 0;
+ location.y = 0;
+ } else {
+ if (x == 0) {
+ location.x = 0;
+ } else {
+ final Point left = getLocation(x - 1, y, gridView, viewsToEditParts);
+ final View leftView = gridView.getViewAt(x - 1, y);
+ Dimension size = new Dimension(0, 0);
+ if (leftView != null) {
+ final IGraphicalEditPart leftEditPart = viewsToEditParts.get(leftView);
+ size = this.getBounds(leftEditPart).getSize();
+ }
+ switch (this.getColumnSizeMode()) {
+ case FREE_DIMENSION:
+ location.x = left.x + size.width + getPadding().left + getPadding().right;
+ break;
+ case SAME_DIMENSION:
+ location.x = left.x + getDiagramMaxDimension().width + getPadding().left + getPadding().right;
+ break;
+ case DIMENSION_BY_LINE_OR_COLUMN:
+ location.x = left.x + this.maxWidths.get(Integer.valueOf(x - 1)).intValue() + getPadding().right + getPadding().left;
+ break;
+ default:
+ break;
+ }
+ }
+ if (y == 0) {
+ location.y = 0;
+ } else {
+ final Point top = getLocation(x, y - 1, gridView, viewsToEditParts);
+ final View topView = gridView.getViewAt(x, y - 1);
+ Dimension size = new Dimension(0, 0);
+ if (topView != null) {
+ final IGraphicalEditPart topEditPart = viewsToEditParts.get(topView);
+ size = this.getBounds(topEditPart).getSize();
+ }
+ switch (this.getLineSizeMode()) {
+ case FREE_DIMENSION:
+ location.y = top.y + size.height + getPadding().top + getPadding().bottom;
+ break;
+ case SAME_DIMENSION:
+ location.y = top.y + getDiagramMaxDimension().height + getPadding().top + getPadding().bottom;
+ break;
+ case DIMENSION_BY_LINE_OR_COLUMN:
+ location.y = top.y + this.maxHeights.get(Integer.valueOf(y - 1)).intValue() + getPadding().top + getPadding().bottom;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ this.locationsCache.put(point, location);
+ return location;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.layout.provider.ExtendableLayoutProvider#getExtender()
+ */
+ public LayoutExtender getExtender() {
+ return extender;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.layout.provider.ExtendableLayoutProvider#handleConnectableListItems()
+ */
+ public boolean handleConnectableListItems() {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.layout.provider.ExtendableLayoutProvider#provideNodeMetrics(org.eclipse.draw2d.graph.Node)
+ */
+ public Rectangle provideNodeMetrics(Node node) {
+ return null;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/provider/InlineEdgeLayoutProvider.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/provider/InlineEdgeLayoutProvider.java
new file mode 100644
index 0000000000..520ab5545d
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/provider/InlineEdgeLayoutProvider.java
@@ -0,0 +1,940 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2012 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout.provider;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.draw2d.FreeformViewport;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.PositionConstants;
+import org.eclipse.draw2d.geometry.Insets;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.PointList;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.commands.CompoundCommand;
+import org.eclipse.gef.editparts.ZoomManager;
+import org.eclipse.gmf.runtime.common.core.service.IOperation;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramRootEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.requests.RequestConstants;
+import org.eclipse.gmf.runtime.diagram.ui.requests.SetAllBendpointRequest;
+import org.eclipse.gmf.runtime.notation.View;
+
+import com.google.common.collect.Iterables;
+
+import org.eclipse.sirius.diagram.ui.tools.api.layout.ordering.AbstractEdgeViewOrdering;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.ordering.ViewOrderingHint;
+
+/**
+ * <p>
+ * This provider layouts edge "inline" along nodes. The client can choose the
+ * side of the node to use ({@link PositionConstants}), and the start position
+ * of the line.
+ * <p>
+ * <p>
+ * Here are the possible sides that can be used :
+ * <ul>
+ * <li>{@link PositionConstants#NORTH} : the top of the node.</li>
+ * <li>{@link PositionConstants#WEST} : the left of the node.</li>
+ * <li>{@link PositionConstants#EAST} : the right of the node.</li>
+ * <li>{@link PositionConstants#SOUTH} : the bottom of the node.</li>
+ *
+ * TODOYMO implements
+ * <li>{@link PositionConstants#NSEW} : all sides of the node.</li>
+ * <li>{@link PositionConstants#SOUTH_EAST},
+ * {@link PositionConstants#SOUTH_WEST}, {@link PositionConstants#NORTH_EAST},
+ * {@link PositionConstants#NORTH_WEST} : the combination of the two positions.</li>
+ * END TODOYMO
+ * <li>any other combination : compute the better side according to the source
+ * and target nodes.</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Here are the possible start positions :
+ * <ul>
+ * <li>{@link PositionConstants#TOP}</li>
+ * <li>{@link PositionConstants#BOTTOM}</li>
+ * <li>{@link PositionConstants#RIGHT}</li>
+ * <li>{@link PositionConstants#LEFT}</li>
+ * <li>{@link PositionConstants#CENTER} (horizontal)</li>
+ * <li>{@link PositionConstants#MIDDLE} (vertical)</li>
+ * </ul>
+ * </p>
+ * <p>
+ * The two values <code>changeNodeHeight</code> and
+ * <code>changeNodeWitdth</code> indicate if this layout provider can change the
+ * dimension of nodes.
+ * </p>
+ *
+ * FIXME to terminate.
+ *
+ * @author ymortier
+ */
+public class InlineEdgeLayoutProvider extends DefaultLayoutProvider {
+ /** The default padding. */
+ private static final Insets DEFAULT_PADDING = new Insets(30, 30, 10, 30);
+
+ /**
+ * Map each Connection with its {@link MoveEdgeDescriptor} instance.
+ */
+ protected Map connectionsToMoveEdgeDescriptor = new HashMap();
+
+ /** The side to use. */
+ private int side;
+
+ /** The position of the first edge. */
+ private int start;
+
+ /** <code>true</code> if the height of nodes can be changed. */
+ private boolean changeNodeHeight;
+
+ /** <code>true</code> if the width of nodes can be changed. */
+ private boolean changeNodeWidth;
+
+ /** The padding. */
+ private Insets paddings = InlineEdgeLayoutProvider.DEFAULT_PADDING;
+
+ /**
+ * The alignment ({@link PositionConstants#HORIZONTAL} or
+ * {@link PositionConstants#VERTICAL} or {@link PositionConstants#NONE}).
+ * Default is {@link PositionConstants#NONE}
+ */
+ private int alignment = PositionConstants.NONE;
+
+ /**
+ * Set the side to use.
+ *
+ * @param side
+ * the side to use.
+ */
+ public void setSide(final int side) {
+ this.side = side;
+ }
+
+ /**
+ * Return the side to use.
+ *
+ * @return the side to use.
+ */
+ public int getSide() {
+ return side;
+ }
+
+ /**
+ * Set the start position.
+ *
+ * @param start
+ * the start position.
+ */
+ public void setStart(final int start) {
+ this.start = start;
+ }
+
+ /**
+ * Return the start position.
+ *
+ * @return the start position.
+ */
+ public int getStart() {
+ return start;
+ }
+
+ /**
+ * <code>true</code> if the height of nodes can be changed.
+ *
+ * @param changeNodeHeight
+ * <code>true</code> if the height of nodes can be changed.
+ */
+ public void setChangeNodeHeight(final boolean changeNodeHeight) {
+ this.changeNodeHeight = changeNodeHeight;
+ }
+
+ /**
+ * <code>true</code> if the width of nodes can be changed.
+ *
+ * @param changeNodeWidth
+ * <code>true</code> if the width of nodes can be changed.
+ */
+ public void setChangeNodeWidth(final boolean changeNodeWidth) {
+ this.changeNodeWidth = changeNodeWidth;
+ }
+
+ /**
+ * Return <code>true</code> if the height of nodes can be changed.
+ *
+ * @return <code>true</code> if the height of nodes can be changed.
+ */
+ public boolean isChangeNodeHeight() {
+ return changeNodeHeight;
+ }
+
+ /**
+ * Return <code>true</code> if the width of nodes can be changed.
+ *
+ * @return <code>true</code> if the width of nodes can be changed.
+ */
+ public boolean isChangeNodeWidth() {
+ return changeNodeWidth;
+ }
+
+ /**
+ * Set the paddings.
+ *
+ * @param paddings
+ * the paddings.
+ */
+ public void setPaddings(final Insets paddings) {
+ if (paddings != null) {
+ this.paddings = paddings;
+ } else {
+ this.paddings = InlineEdgeLayoutProvider.DEFAULT_PADDING;
+ }
+ }
+
+ /**
+ * Return the paddings.
+ *
+ * @return the paddings.
+ */
+ public Insets getPaddings() {
+ return paddings;
+ }
+
+ /**
+ * Return the alignment.
+ *
+ * @return the alignment.
+ */
+ public int getAlignment() {
+ return alignment;
+ }
+
+ /**
+ * Set the alignment. Possible alignments are :
+ * <ul>
+ * <li> {@link PositionConstants#HORIZONTAL} : start.x = end.x</li>
+ * <li> {@link PositionConstants#VERTICAL} : start.y = end.y</li>
+ * <li> {@link PositionConstants#NONE}</li>
+ * </ul>
+ *
+ * @param alignment
+ * the alignment.
+ */
+ public void setAlignment(final int alignment) {
+ this.alignment = alignment;
+ switch (this.alignment) {
+ case PositionConstants.VERTICAL:
+ case PositionConstants.HORIZONTAL:
+ case PositionConstants.NONE:
+ break;
+ default:
+ this.alignment = PositionConstants.NONE;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.provider.DefaultLayoutProvider#layoutEditParts(java.util.List,
+ * org.eclipse.core.runtime.IAdaptable)
+ */
+ @Override
+ public Command layoutEditParts(@SuppressWarnings("rawtypes")
+ final List selectedObjects, final IAdaptable layoutHint) {
+ final CompoundCommand cc = new CompoundCommand();
+
+ this.connectionsToMoveEdgeDescriptor.clear();
+
+ @SuppressWarnings("unchecked")
+ final Map<EditPart, List<EditPart>> containerToChildren = this.split(selectedObjects);
+ final Iterator<Entry<EditPart, List<EditPart>>> iterLayouts = containerToChildren.entrySet().iterator();
+ while (iterLayouts.hasNext()) {
+ final Entry<EditPart, List<EditPart>> currentLayout = iterLayouts.next();
+ final IGraphicalEditPart container = (IGraphicalEditPart) currentLayout.getKey();
+ final List<EditPart> children = currentLayout.getValue();
+ DefaultLayoutProvider.retainType(children, ConnectionEditPart.class);
+ final AbstractEdgeViewOrdering viewOrdering = ViewOrderingHint.getInstance().consumeEdgeViewOrdering(container.getNotationView());
+ final Command command = this.createChangeBoundsCommand(children, viewOrdering);
+ if (command != null && command.canExecute()) {
+ cc.add(command);
+ }
+ }
+ return cc;
+ }
+
+ /**
+ * Create the command that changes the bounds of the specified connections.
+ *
+ * @param connections
+ * the connections to layout (instances of
+ * {@link ConnectionEditPart}).
+ * @param viewOrdering
+ * the view ordering.
+ * @return the command that changes the bounds of the specified connections.
+ */
+ protected Command createChangeBoundsCommand(final List connections, final AbstractEdgeViewOrdering viewOrdering) {
+ final CompoundCommand cc = new CompoundCommand();
+
+ final Iterator<EditPart> iterNodes = this.getNodesEditPart(connections).iterator();
+
+ while (iterNodes.hasNext()) {
+ final IGraphicalEditPart currentEditPart = (IGraphicalEditPart) iterNodes.next();
+ final List<ConnectionEditPart> connectionsToInit = new ArrayList<ConnectionEditPart>(currentEditPart.getSourceConnections().size() + currentEditPart.getTargetConnections().size());
+ connectionsToInit.addAll(currentEditPart.getSourceConnections());
+ connectionsToInit.addAll(currentEditPart.getTargetConnections());
+ DefaultLayoutProvider.retainType(connections, ConnectionEditPart.class);
+ this.initEdgesStep(currentEditPart, viewOrdering, connectionsToInit);
+ }
+ //
+ // Manage alignement !
+ this.align(viewOrdering);
+ //
+ // Create commands.
+ final Iterator iterDescriptors = this.connectionsToMoveEdgeDescriptor.values().iterator();
+ while (iterDescriptors.hasNext()) {
+ final MoveEdgeDescriptor currentDescriptor = (MoveEdgeDescriptor) iterDescriptors.next();
+ final Command command = this.createChangeEdgeBoundsCommand(currentDescriptor);
+ if (command != null && command.canExecute()) {
+ cc.add(command);
+ }
+ }
+
+ return cc;
+ }
+
+ /**
+ * Return all edit parts that are a source or a target of one connection of
+ * <code>connections</code>.
+ *
+ * @param connections
+ * the connections.
+ * @return all edit parts that are a source or a target of one connection of
+ * <code>connections</code>.
+ */
+ protected Set<EditPart> getNodesEditPart(final List<ConnectionEditPart> connections) {
+ final Set<EditPart> result = new HashSet<EditPart>();
+ final Iterator<ConnectionEditPart> iterConnections = connections.iterator();
+ while (iterConnections.hasNext()) {
+ final ConnectionEditPart connectionEditPart = iterConnections.next();
+ if (connectionEditPart.getSource() instanceof IGraphicalEditPart) {
+ result.add(connectionEditPart.getSource());
+ }
+ if (connectionEditPart.getTarget() instanceof IGraphicalEditPart) {
+ result.add(connectionEditPart.getTarget());
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Init the {@link MoveEdgeDescriptor} of the specified connector.
+ *
+ * @param connector
+ * the edit part that is the source or the target of connections
+ * to init.
+ * @param ordering
+ * the ordering.
+ * @param connections
+ * the connections to layout for this connector (instances of
+ * {@link ConnectionEditPart}).
+ */
+ protected void initEdgesStep(final IGraphicalEditPart connector, final AbstractEdgeViewOrdering ordering, final List<ConnectionEditPart> connections) {
+ final Map<View, ConnectionEditPart> viewsToConnections = this.getViews(connections);
+ ordering.setConnector(connector.getNotationView());
+ ordering.setViews(viewsToConnections.keySet());
+ final Iterator<View> iterViews = ordering.getSortedViews().iterator();
+ int step = 0;
+ while (iterViews.hasNext()) {
+ final View currentView = iterViews.next();
+ final ConnectionEditPart currentConnection = viewsToConnections.get(currentView);
+
+ MoveEdgeDescriptor moveEdgeDescriptor = (MoveEdgeDescriptor) this.connectionsToMoveEdgeDescriptor.get(currentConnection);
+ if (moveEdgeDescriptor == null) {
+ // The connection has no MoveEdgeDescriptor.
+ // Let's create one.
+ moveEdgeDescriptor = new MoveEdgeDescriptor(currentConnection);
+ this.connectionsToMoveEdgeDescriptor.put(currentConnection, moveEdgeDescriptor);
+ }
+
+ if (connector.getSourceConnections().contains(currentConnection)) {
+ // source
+ moveEdgeDescriptor.setSourceStep(step);
+ } else {
+ // target
+ moveEdgeDescriptor.setTargetStep(step);
+ }
+ step++;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.provider.DefaultLayoutProvider#provides(org.eclipse.gmf.runtime.common.core.service.IOperation)
+ */
+ @Override
+ public boolean provides(final IOperation operation) {
+ return false;
+ }
+
+ /**
+ * Create the command that changes the bounds of the specified edge.
+ *
+ * @param moveEdgeDescriptor
+ * the instance that describes how to move the edge.
+ * @return the created command
+ */
+ protected Command createChangeEdgeBoundsCommand(final MoveEdgeDescriptor moveEdgeDescriptor) {
+ // the connection edit part.
+ final ConnectionEditPart connectionEditPart = moveEdgeDescriptor.getConnectionEditPart();
+
+ final Point sourcePoint = moveEdgeDescriptor.getSourceLocation(true);
+ final Point targetPoint = moveEdgeDescriptor.getTargetLocation(true);
+
+ final PointList points = new PointList(2);
+ points.addPoint(sourcePoint);
+ points.addPoint(targetPoint);
+
+ final Point ref1 = new Point(0, 0);
+ final Point ref2 = new Point(0, 0);
+
+ final FreeformViewport viewport = this.getFreeformViewport(moveEdgeDescriptor.connectionEditPart.getConnectionFigure().getSourceAnchor().getOwner());
+ final Point delta = viewport.getViewLocation();
+
+ // the zoom.
+ double scale = 1.0;
+ if (moveEdgeDescriptor.getConnectionEditPart().getRoot() instanceof DiagramRootEditPart) {
+ final ZoomManager zoomManager = ((DiagramRootEditPart) moveEdgeDescriptor.getConnectionEditPart().getRoot()).getZoomManager();
+ scale = zoomManager.getZoom();
+ }
+
+ if (moveEdgeDescriptor.getConnectionEditPart().getSource() instanceof IGraphicalEditPart) {
+ final IGraphicalEditPart graphicalEditPart = (IGraphicalEditPart) moveEdgeDescriptor.getConnectionEditPart().getSource();
+ ref1.y = this.getBounds(graphicalEditPart).getSize().height / 2;
+ }
+ if (moveEdgeDescriptor.getConnectionEditPart().getTarget() instanceof IGraphicalEditPart) {
+ final IGraphicalEditPart graphicalEditPart = (IGraphicalEditPart) moveEdgeDescriptor.getConnectionEditPart().getTarget();
+ ref2.y = this.getBounds(graphicalEditPart).getSize().height / 2;
+ }
+
+ final Point source = connectionEditPart.getConnectionFigure().getSourceAnchor().getReferencePoint().getTranslated(delta);
+ source.x = (int) ((double) source.x * (double) 1 / scale);
+ source.y = (int) ((double) source.y * (double) 1 / scale);
+
+ final Point target = connectionEditPart.getConnectionFigure().getTargetAnchor().getReferencePoint().getTranslated(delta);
+ target.x = (int) ((double) target.x * (double) 1 / scale);
+ target.y = (int) ((double) target.y * (double) 1 / scale);
+
+ final SetAllBendpointRequest setAllBendpointRequest = new SetAllBendpointRequest(RequestConstants.REQ_SET_ALL_BENDPOINT, points, source, target);
+
+ final Command command = this.buildCommandWrapper(setAllBendpointRequest, connectionEditPart);
+ if (command != null && command.canExecute()) {
+ // this.getViewsToChangeBoundsRequest().put(connectionEditPart.getNotationView(),
+ // bendpointRequest);
+ }
+ return command;
+ }
+
+ /**
+ * Returns the {@link FreeformViewport} that owned this figure.
+ *
+ * @return the {@link FreeformViewport} that owned this figure.
+ */
+ private FreeformViewport getFreeformViewport(final IFigure figure) {
+ IFigure current = figure;
+ while (!(current instanceof FreeformViewport) && current != null) {
+ current = current.getParent();
+ }
+ return (FreeformViewport) current;
+ }
+
+ /**
+ * Create and return a command that resize connectors.
+ *
+ * @return and return a command that resize connectors.
+ */
+ protected Command createResizeConnectorsCommand() {
+ final CompoundCommand cc = new CompoundCommand();
+ return cc;
+ }
+
+ /**
+ * Describe how an edge should be located.
+ *
+ * @author ymortier
+ */
+ protected class MoveEdgeDescriptor {
+
+ /** The edge to move. */
+ private ConnectionEditPart connectionEditPart;
+
+ /** The source step. */
+ private int sourceStep;
+
+ /** The target step. */
+ private int targetStep;
+
+ /**
+ * Create a new {@link MoveEdgeDescriptor}.
+ *
+ * @param connectionEditPart
+ * the connection.
+ */
+ public MoveEdgeDescriptor(final ConnectionEditPart connectionEditPart) {
+ this.connectionEditPart = connectionEditPart;
+ }
+
+ /**
+ * Return the source step.
+ *
+ * @return the source step.
+ */
+ public int getSourceStep() {
+ return sourceStep;
+ }
+
+ /**
+ * Return the target step.
+ *
+ * @return the target step.
+ */
+ public int getTargetStep() {
+ return targetStep;
+ }
+
+ /**
+ * Define the source step.
+ *
+ * @param sourceStep
+ * the source step.
+ */
+ public void setSourceStep(final int sourceStep) {
+ this.sourceStep = sourceStep;
+ }
+
+ /**
+ * Define the target step.
+ *
+ * @param targetStep
+ * the target step.
+ */
+ public void setTargetStep(final int targetStep) {
+ this.targetStep = targetStep;
+ }
+
+ /**
+ * Return the connection edit part.
+ *
+ * @return the connection edit part.
+ */
+ public ConnectionEditPart getConnectionEditPart() {
+ return connectionEditPart;
+ }
+
+ /**
+ * Return the location of the source of this edge according to its
+ * <code>sourceStep</code>.
+ *
+ * @param relative
+ * if <code>true</code> then the returned location is
+ * relative to the source figure, the location is an absolute
+ * location otherwise.
+ * @return the location of the source of this edge according to its
+ * <code>sourceStep</code>.
+ */
+ public Point getSourceLocation(final boolean relative) {
+ final int pos = InlineEdgeLayoutProvider.this.computePos(this.sourceStep);
+ final Rectangle sourceBounds = getBounds((IGraphicalEditPart) connectionEditPart.getSource());
+ final Point sourceLocation = InlineEdgeLayoutProvider.this.computePrimaryPoint(pos, sourceBounds);
+ if (!relative) {
+ sourceLocation.translate(sourceBounds.getLocation());
+ }
+ return sourceLocation;
+ }
+
+ /**
+ * Return the location of the target of this edge according to its
+ * <code>targetStep</code>.
+ *
+ * @param relative
+ * if <code>true</code> then the returned location is
+ * relative to the target figure, the location is an absolute
+ * location otherwise.
+ * @return the location of the target of this edge according to its
+ * <code>sourceStep</code>.
+ */
+ public Point getTargetLocation(final boolean relative) {
+ final int pos = InlineEdgeLayoutProvider.this.computePos(this.targetStep);
+ final Rectangle targetBounds = getBounds((IGraphicalEditPart) connectionEditPart.getTarget());
+ final Point targetLocation = InlineEdgeLayoutProvider.this.computePrimaryPoint(pos, targetBounds);
+ if (!relative) {
+ targetLocation.translate(targetBounds.getLocation());
+ }
+ return targetLocation;
+ }
+
+ /**
+ * Approximate the new <code>sourceStep</code> assuming the
+ * <code>desiredLocation</code>.
+ *
+ * @param desiredLocation
+ * the desired source location.
+ * @param relative
+ * <code>true</code> if <code>desiredLocation</code> is
+ * relative to the source figure.
+ */
+ public void approximateSourceStep(final Point desiredLocation, final boolean relative) {
+ final Rectangle sourceBounds = getBounds((IGraphicalEditPart) connectionEditPart.getSource());
+ final Point location = desiredLocation.getCopy();
+ if (!relative) {
+ location.x = location.x - sourceBounds.x;
+ location.y = location.y - sourceBounds.y;
+ }
+ final int pos = posFromPrimaryPoint(location, sourceBounds);
+ this.sourceStep = stepFromPos(pos);
+ }
+
+ /**
+ * Approximate the new <code>targetStep</code> assuming the
+ * <code>desiredLocation</code>.
+ *
+ * @param desiredLocation
+ * the desired target location.
+ * @param relative
+ * <code>true</code> if <code>desiredLocation</code> is
+ * relative to the target figure.
+ */
+ public void approximateTargetStep(final Point desiredLocation, final boolean relative) {
+ final Rectangle targetBounds = getBounds((IGraphicalEditPart) connectionEditPart.getTarget());
+ final Point location = desiredLocation.getCopy();
+ if (!relative) {
+ location.x = location.x - targetBounds.x;
+ location.y = location.y - targetBounds.y;
+ }
+ final int pos = posFromPrimaryPoint(location, targetBounds);
+ this.targetStep = stepFromPos(pos);
+ }
+
+ }
+
+ private int computePos(final int current) {
+
+ int result = current;
+
+ switch (this.side) {
+ case PositionConstants.EAST:
+ case PositionConstants.WEST:
+ case PositionConstants.EAST_WEST:
+ result = this.getPaddings().top + (this.getPaddings().top + this.getPaddings().bottom) * current;
+ break;
+ case PositionConstants.NORTH:
+ case PositionConstants.SOUTH:
+ case PositionConstants.NORTH_SOUTH:
+ result = this.getPaddings().left + (this.getPaddings().left + this.getPaddings().right) * current;
+ break;
+ default:
+ break;
+ }
+ return result;
+ }
+
+ private int stepFromPos(final int pos) {
+
+ int result = pos;
+
+ switch (this.side) {
+ case PositionConstants.EAST:
+ case PositionConstants.WEST:
+ case PositionConstants.EAST_WEST:
+ result = (int) ((pos - this.getPaddings().top) / ((double) this.getPaddings().top + this.getPaddings().bottom));
+ break;
+ case PositionConstants.NORTH:
+ case PositionConstants.SOUTH:
+ case PositionConstants.NORTH_SOUTH:
+ result = (int) ((pos - this.getPaddings().left) / ((double) this.getPaddings().left + this.getPaddings().right));
+ break;
+ default:
+ break;
+ }
+ return result;
+ }
+
+ private Point computePrimaryPoint(final int pos, final Rectangle connectorBounds) {
+ final Point result = new Point();
+ switch (this.getSide()) {
+ case PositionConstants.EAST:
+ result.x = 0;
+ switch (this.getStart()) {
+ case PositionConstants.BOTTOM:
+ result.y = connectorBounds.height - pos;
+ break;
+ case PositionConstants.MIDDLE:
+ result.y = connectorBounds.height / 2 + pos;
+ break;
+ default:
+ result.y = pos;
+ }
+ break;
+ case PositionConstants.WEST:
+ case PositionConstants.EAST_WEST:
+ result.x = connectorBounds.width;
+ switch (this.getStart()) {
+ case PositionConstants.BOTTOM:
+ result.y = connectorBounds.height - pos;
+ break;
+ case PositionConstants.MIDDLE:
+ result.y = connectorBounds.height / 2 + pos;
+ break;
+ default:
+ result.y = pos;
+ break;
+ }
+ break;
+ case PositionConstants.NORTH:
+ result.y = 0;
+ switch (this.getStart()) {
+ case PositionConstants.RIGHT:
+ result.x = connectorBounds.width - pos;
+ break;
+ case PositionConstants.CENTER:
+ result.x = connectorBounds.width / 2 + pos;
+ break;
+ default:
+ break;
+ }
+ break;
+ case PositionConstants.SOUTH:
+ case PositionConstants.NORTH_SOUTH:
+ result.y = connectorBounds.height;
+ switch (this.getStart()) {
+ case PositionConstants.RIGHT:
+ result.x = connectorBounds.width - pos;
+ break;
+ case PositionConstants.CENTER:
+ result.x = connectorBounds.width / 2 + pos;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ return result;
+ }
+
+ private int posFromPrimaryPoint(final Point pt, final Rectangle connectorBounds) {
+
+ int result = 0;
+
+ switch (this.getSide()) {
+ case PositionConstants.EAST:
+ case PositionConstants.WEST:
+ case PositionConstants.EAST_WEST:
+ switch (this.getStart()) {
+ case PositionConstants.BOTTOM:
+ result = connectorBounds.height - pt.y;
+ break;
+ case PositionConstants.MIDDLE:
+ result = pt.y - connectorBounds.height / 2;
+ break;
+ default:
+ result = pt.y;
+ break;
+ }
+ break;
+ case PositionConstants.NORTH:
+ case PositionConstants.SOUTH:
+ case PositionConstants.NORTH_SOUTH:
+ switch (this.getStart()) {
+ case PositionConstants.RIGHT:
+ result = connectorBounds.width - pt.x;
+ break;
+ case PositionConstants.CENTER:
+ result = pt.x - connectorBounds.width / 2;
+ break;
+ default:
+ result = pt.x;
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ return result;
+ }
+
+ /**
+ * Align the edge according to the specified <code>alignment</code> value.
+ *
+ * @param viewOrdering
+ * the edge view ordering
+ */
+ protected void align(final AbstractEdgeViewOrdering viewOrdering) {
+ switch (this.getAlignment()) {
+ case PositionConstants.HORIZONTAL:
+ this.horizontalAlign(viewOrdering);
+ break;
+ case PositionConstants.VERTICAL:
+ this.verticalAlign(viewOrdering);
+ break;
+ default:
+ // do nothing.
+ }
+ }
+
+ // start.y = end.y
+ private void verticalAlign(final AbstractEdgeViewOrdering viewOrdering) {
+ final Map connectorsToStepRearrangeMin = this.initConnectorsToStepRearrangeMin();
+ boolean again = true;
+ while (again) {
+ again = false;
+ final Iterator iterMoveDescriptors = this.connectionsToMoveEdgeDescriptor.values().iterator();
+ while (iterMoveDescriptors.hasNext()) {
+ final MoveEdgeDescriptor currentDescriptor = (MoveEdgeDescriptor) iterMoveDescriptors.next();
+ final Point sourcePoint = currentDescriptor.getSourceLocation(false);
+ final Point targetPoint = currentDescriptor.getTargetLocation(false);
+ if (sourcePoint.y < targetPoint.y - 29 || sourcePoint.y > targetPoint.y + 29) {
+ if (sourcePoint.y < targetPoint.y) {
+ sourcePoint.y = targetPoint.y;
+ currentDescriptor.approximateSourceStep(sourcePoint, false);
+ final IGraphicalEditPart connector = (IGraphicalEditPart) currentDescriptor.getConnectionEditPart().getSource();
+ final int connectorStart = ((Integer) connectorsToStepRearrangeMin.get(connector.getNotationView())).intValue();
+ final int result = this.rearrangeConnector(connector, connectorStart, viewOrdering);
+ connectorsToStepRearrangeMin.put(connector.getNotationView(), Integer.valueOf(result));
+ if (result != connectorStart) {
+ again = true;
+ }
+ } else {
+ targetPoint.y = sourcePoint.y;
+ currentDescriptor.approximateTargetStep(targetPoint, false);
+ final IGraphicalEditPart connector = (IGraphicalEditPart) currentDescriptor.getConnectionEditPart().getTarget();
+ final int connectorStart = ((Integer) connectorsToStepRearrangeMin.get(connector.getNotationView())).intValue();
+ final int result = this.rearrangeConnector(connector, connectorStart, viewOrdering);
+ connectorsToStepRearrangeMin.put(connector.getNotationView(), Integer.valueOf(result));
+ if (result != connectorStart) {
+ again = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // start.y = end.y
+ private void horizontalAlign(final AbstractEdgeViewOrdering viewOrdering) {
+ boolean again = true;
+ while (again) {
+ final Iterator iterMoveDescriptors = this.connectionsToMoveEdgeDescriptor.values().iterator();
+ while (iterMoveDescriptors.hasNext()) {
+ final MoveEdgeDescriptor currentDescriptor = (MoveEdgeDescriptor) iterMoveDescriptors.next();
+ final Point sourcePoint = currentDescriptor.getSourceLocation(false);
+ final Point targetPoint = currentDescriptor.getTargetLocation(false);
+ if (sourcePoint.x < targetPoint.x - 10 || sourcePoint.x > targetPoint.x + 10) {
+ if (sourcePoint.x < targetPoint.x) {
+ sourcePoint.x = targetPoint.x;
+ currentDescriptor.approximateSourceStep(sourcePoint, false);
+ again = true;
+ } else {
+ targetPoint.x = sourcePoint.x;
+ currentDescriptor.approximateTargetStep(targetPoint, false);
+ again = true;
+ }
+
+ }
+ }
+ }
+ }
+
+ private Map initConnectorsToStepRearrangeMin() {
+ final Map result = new HashMap();
+ final Iterator iterDescriptors = this.connectionsToMoveEdgeDescriptor.values().iterator();
+ while (iterDescriptors.hasNext()) {
+ final MoveEdgeDescriptor currentDescriptor = (MoveEdgeDescriptor) iterDescriptors.next();
+ final ConnectionEditPart connectionEditPart = currentDescriptor.getConnectionEditPart();
+ if (connectionEditPart.getSource() instanceof IGraphicalEditPart) {
+ final View sourceConnector = ((IGraphicalEditPart) connectionEditPart.getSource()).getNotationView();
+ if (!result.containsKey(sourceConnector)) {
+ result.put(sourceConnector, Integer.valueOf(0));
+ }
+ }
+ if (connectionEditPart.getTarget() instanceof IGraphicalEditPart) {
+ final View targetConnector = ((IGraphicalEditPart) connectionEditPart.getTarget()).getNotationView();
+ if (!result.containsKey(targetConnector)) {
+ result.put(targetConnector, Integer.valueOf(0));
+ }
+ }
+ }
+ return result;
+ }
+
+ private int rearrangeConnector(final IGraphicalEditPart connector, final int connectorStart, final AbstractEdgeViewOrdering viewOrdering) {
+ int result = connectorStart;
+ final List<EditPart> connections = new ArrayList<EditPart>(connector.getSourceConnections().size() + connector.getTargetConnections().size());
+ Iterables.addAll(connections, Iterables.filter(connector.getSourceConnections(), EditPart.class));
+ Iterables.addAll(connections, Iterables.filter(connector.getTargetConnections(), EditPart.class));
+
+ final Map<View, EditPart> views = this.getViews(connections);
+ viewOrdering.setConnector(connector.getNotationView());
+ viewOrdering.setViews(views.keySet());
+
+ final List<View> sortedViews = viewOrdering.getSortedViews();
+
+ final Iterator<View> iterViews = sortedViews.iterator();
+ int current = 0;
+ while (iterViews.hasNext()) {
+ final View currentView = iterViews.next();
+ final ConnectionEditPart connectionEditPart = (ConnectionEditPart) views.get(currentView);
+ final MoveEdgeDescriptor descriptor = (MoveEdgeDescriptor) this.connectionsToMoveEdgeDescriptor.get(connectionEditPart);
+ final boolean source = connectionEditPart.getSource().equals(connector);
+ if (source) {
+ // source
+ int step = descriptor.getSourceStep();
+ if (step < current) {
+ step = current;
+ }
+ if (step > current) {
+ if (result == connectorStart) {
+ result = step + 1;
+ }
+ current = step;
+ }
+ descriptor.setSourceStep(step);
+ } else {
+ // target
+ int step = descriptor.getTargetStep();
+ if (step < current) {
+ step = current;
+ }
+ if (step > current) {
+ if (result == connectorStart) {
+ result = step + 1;
+ }
+ current = step;
+ }
+ descriptor.setTargetStep(step);
+ }
+ current++;
+ }
+ return result;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/provider/LayoutProvider.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/provider/LayoutProvider.java
new file mode 100644
index 0000000000..570a5eb44b
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/provider/LayoutProvider.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout.provider;
+
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.services.layout.AbstractLayoutEditPartProvider;
+
+/**
+ * A class that provides
+ * {@link org.eclipse.gmf.runtime.diagram.ui.services.layout.AbstractLayoutNodeProvider}
+ * for a specific container.
+ *
+ * @author ymortier
+ */
+public interface LayoutProvider {
+ /**
+ * Simple flag to easily switch between the old/new behaviors during
+ * development.
+ */
+ boolean ENABLE_BORDERED_NODES_ARRANGE_ALL = true;
+
+ /**
+ * Return <code>true</code> if this provider provides a
+ * {@link AbstractLayoutEditPartProvider} for the specified container. A
+ * diagram layout provider should return <code>true</code> if container is
+ * an instance of
+ * {@link org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart}.
+ *
+ * @param container
+ * the container.
+ * @return <code>true</code> if this provider provides a
+ * {@link AbstractLayoutEditPartProvider} for the specified
+ * container.
+ */
+ boolean provides(IGraphicalEditPart container);
+
+ /**
+ * Return the {@link AbstractLayoutEditPartProvider} to use with the
+ * container.
+ *
+ * @param container
+ * the container.
+ * @return the {@link AbstractLayoutEditPartProvider} to use with the
+ * container.
+ */
+ AbstractLayoutEditPartProvider getLayoutNodeProvider(IGraphicalEditPart container);
+
+ /**
+ * Check if this provider is a diagram provider.
+ *
+ * @return <code>true</code> if this provider is a diagram provider.
+ */
+ boolean isDiagramLayoutProvider();
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/provider/LineLayoutProvider.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/provider/LineLayoutProvider.java
new file mode 100644
index 0000000000..20e1976e22
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/layout/provider/LineLayoutProvider.java
@@ -0,0 +1,302 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.layout.provider;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.draw2d.PositionConstants;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Insets;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.commands.CompoundCommand;
+import org.eclipse.gef.editparts.ZoomManager;
+import org.eclipse.gef.requests.ChangeBoundsRequest;
+import org.eclipse.gmf.runtime.common.core.service.IOperation;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.CompartmentEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramRootEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IBorderItemEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.services.layout.ILayoutNodeOperation;
+import org.eclipse.gmf.runtime.diagram.ui.services.layout.LayoutType;
+import org.eclipse.gmf.runtime.notation.View;
+
+import org.eclipse.sirius.diagram.ui.tools.api.layout.ordering.SimpleViewOrdering;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.ordering.ViewOrdering;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.ordering.ViewOrderingHint;
+
+/**
+ * Layout edit parts in line according to the {@link ViewOrdering} to use.
+ *
+ * @author ymortier
+ */
+public class LineLayoutProvider extends AbstractLayoutProvider {
+
+ /** The default padding. */
+ private static final Insets DEFAULT_PADDING = new Insets(30, 30, 30, 30);
+
+ /**
+ * <code>true</code> if the line is horizontal, <code>false</code> if the
+ * line is vertical.
+ */
+ private boolean horizontal = true;
+
+ /**
+ * <code>true</code> if the line is horizontal, <code>false</code> if the
+ * line is vertical.
+ *
+ * @param horizontal
+ * <code>true</code> if the line is horizontal,
+ * <code>false</code> if the line is vertical.
+ */
+ public void setHorizontal(final boolean horizontal) {
+ this.horizontal = horizontal;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.services.layout.AbstractLayoutEditPartProvider#layoutEditParts(java.util.List,
+ * org.eclipse.core.runtime.IAdaptable)
+ */
+ @Override
+ public Command layoutEditParts(final List selectedObjects, final IAdaptable layoutHint) {
+ final Iterator<?> iterEditParts = selectedObjects.iterator();
+ final List<View> views = new ArrayList<View>(selectedObjects.size());
+ final Map<View, ShapeEditPart> viewsToEditPartMap = new HashMap<View, ShapeEditPart>();
+ while (iterEditParts.hasNext()) {
+ final Object next = iterEditParts.next();
+ if (next instanceof ShapeEditPart && !(next instanceof IBorderItemEditPart)) {
+ final ShapeEditPart shapeEditPart = (ShapeEditPart) next;
+ final View view = shapeEditPart.getNotationView();
+ viewsToEditPartMap.put(view, shapeEditPart);
+ views.add(view);
+ } else {
+ iterEditParts.remove();
+ }
+ }
+ ViewOrdering viewOrdering = ViewOrderingHint.getInstance().consumeViewOrdering(getContainerEditPart(selectedObjects).getNotationView());
+ if (viewOrdering == null) {
+ // use a simple view ordering ... too bad.
+ viewOrdering = new SimpleViewOrdering();
+ }
+
+ viewOrdering.setViews(views);
+ final List<View> sortedViews = viewOrdering.getSortedViews();
+ final List<ShapeEditPart> sortedEditParts = new ArrayList<ShapeEditPart>(sortedViews.size());
+ final Iterator<View> iterSortedViews = sortedViews.listIterator();
+ while (iterSortedViews.hasNext()) {
+ final View currentView = iterSortedViews.next();
+ final ShapeEditPart currentEditPart = viewsToEditPartMap.get(currentView);
+ sortedEditParts.add(currentEditPart);
+ }
+ return createNodeChangeBoundCommands(sortedEditParts);
+ }
+
+ /**
+ * Create the change bounds commands.
+ *
+ * @param sortedNodes
+ * the nodes to move.
+ * @return the change bounds command.
+ */
+ protected Command createNodeChangeBoundCommands(final List<ShapeEditPart> sortedNodes) {
+ final CompoundCommand result = new CompoundCommand();
+ final Iterator<ShapeEditPart> iterEditParts = sortedNodes.iterator();
+ int currentX = 0;
+ while (iterEditParts.hasNext()) {
+ final ShapeEditPart shapeEditPart = iterEditParts.next();
+ if (!(shapeEditPart instanceof IBorderItemEditPart)) {
+
+ final View view = shapeEditPart.getNotationView();
+ // the zoom.
+ double scale = 1.0;
+ if (shapeEditPart.getRoot() instanceof DiagramRootEditPart) {
+ final ZoomManager zoomManager = ((DiagramRootEditPart) shapeEditPart.getRoot()).getZoomManager();
+ scale = zoomManager.getZoom();
+ }
+ //
+ // Compute request data.
+ final Point ptOldLocation = shapeEditPart.getFigure().getBounds().getLocation();
+ // shapeEditPart.getFigure().translateToAbsolute(ptOldLocation);
+ final int locationX = horizontal ? currentX + this.getPadding().left : this.getPadding().left;
+ final int locationY = horizontal ? this.getPadding().top : currentX + this.getPadding().top;
+ final Point ptLocation = new Point(locationX, locationY);
+ final Dimension delta = ptLocation.getDifference(ptOldLocation);
+
+ final Object existingRequest = this.findRequest(view, org.eclipse.gef.RequestConstants.REQ_MOVE);
+ int step = 0;
+ if (existingRequest == null) {
+ final ChangeBoundsRequest request = new ChangeBoundsRequest(org.eclipse.gef.RequestConstants.REQ_MOVE);
+ request.setEditParts(shapeEditPart);
+ request.setMoveDelta(new Point(delta.width * scale, delta.height * scale));
+ request.setLocation(new Point(ptLocation.x * scale, ptLocation.y * scale));
+ step = this.horizontal ? getBounds(shapeEditPart).width : getBounds(shapeEditPart).height;
+
+ final Command cmd = this.buildCommandWrapper(request, shapeEditPart);
+ if (cmd != null && cmd.canExecute()) {
+ result.add(cmd);
+ // this.getViewsToChangeBoundsRequest().put(view,
+ // request);
+ }
+ } else if (existingRequest instanceof ChangeBoundsRequest) {
+ final ChangeBoundsRequest changeBoundsRequest = (ChangeBoundsRequest) existingRequest;
+ changeBoundsRequest.setMoveDelta(new Point(delta.width * scale, delta.height * scale));
+ changeBoundsRequest.setLocation(new Point(ptLocation.x * scale, ptLocation.y * scale));
+
+ step = this.horizontal ? getBounds(shapeEditPart).width : getBounds(shapeEditPart).height;
+ }
+ currentX += horizontal ? step + getPadding().right + getPadding().left : step + this.getPadding().bottom + this.getPadding().top;
+
+ // check the size of the container.
+ EditPart container = shapeEditPart.getParent();
+ while (container instanceof CompartmentEditPart) {
+ container = container.getParent();
+ }
+ if (container instanceof ShapeEditPart) {
+ final ShapeEditPart containerEditPart = (ShapeEditPart) container;
+
+ // The minimum witdh
+ final int minWidth = this.horizontal ? ((getPadding().left + getPadding().right) * sortedNodes.size()) + (getNodeMaxWidth(sortedNodes) * sortedNodes.size()) : getPadding().left
+ + getNodeMaxWidth(sortedNodes) + getPadding().right;
+ // The minimum height
+ final int minHeight = this.horizontal ? getPadding().top + this.getNodeMaxHeight(sortedNodes) + this.getPadding().bottom : ((getPadding().top + getPadding().bottom) * sortedNodes
+ .size()) + (this.getNodeMaxHeight(sortedNodes) * sortedNodes.size());
+
+ final Dimension minDimension = new Dimension(minWidth, minHeight);
+
+ final Dimension difference = minDimension.getDifference(containerEditPart.getFigure().getBounds().getSize());
+ if (difference.width > 0 || difference.height > 0) {
+ final Object existingContainerRequest = this.findRequest(containerEditPart, org.eclipse.gef.RequestConstants.REQ_RESIZE); // ;this.getViewsToChangeBoundsRequest().get(containerEditPart.getNotationView());
+ createChangeBoundsCommand(result, existingContainerRequest, containerEditPart, difference, scale);
+ }
+
+ }
+
+ }
+ }
+ return result;
+ }
+
+ private void createChangeBoundsCommand(final CompoundCommand compoundCommand, final Object existingContainerRequest, final ShapeEditPart containerEditPart, final Dimension difference,
+ final double scale) {
+
+ if (existingContainerRequest == null) {
+ final ChangeBoundsRequest changeBoundsRequest = new ChangeBoundsRequest();
+ changeBoundsRequest.setEditParts(containerEditPart);
+ changeBoundsRequest.setResizeDirection(PositionConstants.SOUTH_EAST);
+ changeBoundsRequest.setSizeDelta(new Dimension((int) (difference.width * scale), (int) (difference.height * scale)));
+ changeBoundsRequest.setLocation(new Point(0, 0));
+ changeBoundsRequest.setType(org.eclipse.gef.RequestConstants.REQ_RESIZE);
+ final Command cmd = this.buildCommandWrapper(changeBoundsRequest, containerEditPart);
+ if (cmd.canExecute()) {
+ compoundCommand.add(cmd);
+ // this.getViewsToChangeBoundsRequest().put(containerEditPart.getNotationView(),
+ // changeBoundsRequest);
+ }
+ } else if (existingContainerRequest instanceof ChangeBoundsRequest) {
+ final ChangeBoundsRequest changeBoundsRequest = (ChangeBoundsRequest) existingContainerRequest;
+ changeBoundsRequest.setResizeDirection(PositionConstants.SOUTH_EAST);
+ changeBoundsRequest.setSizeDelta(new Dimension((int) (difference.width * scale), (int) (difference.height * scale)));
+ }
+ }
+
+ /**
+ * Return the maximum width of all nodes (instances of {@link ShapeEditPart}
+ * ) that are in the specified list.
+ *
+ * @param nodes
+ * the nodes.
+ * @return the maximum width of all nodes that are in the specified list.
+ */
+ protected int getNodeMaxWidth(final List<ShapeEditPart> nodes) {
+ int max = -1;
+ for (final ShapeEditPart shapeEditPart : nodes) {
+ final Object existingRequest = this.getViewsToChangeBoundsRequest().get(shapeEditPart.getNotationView());
+ int width = shapeEditPart.getFigure().getBounds().width;
+ if (existingRequest instanceof ChangeBoundsRequest) {
+ width = width + ((ChangeBoundsRequest) existingRequest).getSizeDelta().width;
+ }
+ if (width > max) {
+ max = width;
+ }
+ }
+ return max;
+ }
+
+ /**
+ * Return the maximum height of all nodes (instances of
+ * {@link ShapeEditPart}) that are in the specified list.
+ *
+ * @param nodes
+ * the nodes.
+ * @return the maximum width of all nodes that are in the specified list.
+ */
+ protected int getNodeMaxHeight(final List<ShapeEditPart> nodes) {
+ int max = -1;
+ for (final ShapeEditPart shapeEditPart : nodes) {
+ final int height = this.getBounds(shapeEditPart).height;
+ if (height > max) {
+ max = height;
+ }
+ }
+ return max;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.provider.AbstractLayoutProvider#provides(org.eclipse.gmf.runtime.common.core.service.IOperation)
+ */
+ @Override
+ public boolean provides(final IOperation operation) {
+ final View cview = getContainer(operation);
+ if (cview == null) {
+ return false;
+ }
+ final IAdaptable layoutHint = ((ILayoutNodeOperation) operation).getLayoutHint();
+ final String layoutType = (String) layoutHint.getAdapter(String.class);
+ return LayoutType.DEFAULT.equals(layoutType);
+ }
+
+ /**
+ * Return the padding to use.
+ *
+ * @return the padding to use.
+ */
+ public Insets getPadding() {
+ return DEFAULT_PADDING;
+ }
+
+ // FIXME do a real implementation.
+ /**
+ * Get the container edit part of an object list. Currently the function
+ * takes only the first object of the list
+ *
+ * @param selectedObjects
+ * the selected object
+ * @return the container edit part
+ */
+ protected IGraphicalEditPart getContainerEditPart(final List<EditPart> selectedObjects) {
+ if (selectedObjects != null && !selectedObjects.isEmpty()) {
+ return (IGraphicalEditPart) (selectedObjects.iterator().next()).getParent();
+ }
+ return null;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/policy/CompoundEditPolicy.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/policy/CompoundEditPolicy.java
new file mode 100644
index 0000000000..015029bdd5
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/policy/CompoundEditPolicy.java
@@ -0,0 +1,250 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.policy;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.EditPolicy;
+import org.eclipse.gef.Request;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.commands.CompoundCommand;
+
+/**
+ * This edit policy is composed of many edit policies.
+ *
+ * @author ymortier
+ */
+public class CompoundEditPolicy implements EditPolicy {
+
+ /** The delegated edit policies. */
+ private List<EditPolicy> delegatedEditPolicies = new LinkedList<EditPolicy>();
+
+ /** The host. */
+ private EditPart host;
+
+ /**
+ * if <code>true</code> then null command are added to the resulted compound
+ * command (so the command is unexecutable).
+ */
+ private boolean allowNullCommand;
+
+ /**
+ * <code>true</code> if the resulted command can contain null value.
+ *
+ * @param allowNullCommand
+ * <code>true</code> if the resulted command can contain null
+ * value.
+ */
+ public void setAllowNullCommand(final boolean allowNullCommand) {
+ this.allowNullCommand = allowNullCommand;
+ }
+
+ /**
+ * Returns <code>true</code> if the resulted command can contain null value.
+ *
+ * @return <code>true</code> if the resulted command can contain null value.
+ */
+ public boolean isAllowNullCommand() {
+ return allowNullCommand;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gef.EditPolicy#activate()
+ */
+ public void activate() {
+ final Iterator<EditPolicy> iterEditPolicies = this.delegatedEditPolicies.iterator();
+ while (iterEditPolicies.hasNext()) {
+ iterEditPolicies.next().activate();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gef.EditPolicy#deactivate()
+ */
+ public void deactivate() {
+ final Iterator<EditPolicy> iterEditPolicies = this.delegatedEditPolicies.iterator();
+ while (iterEditPolicies.hasNext()) {
+ iterEditPolicies.next().deactivate();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gef.EditPolicy#eraseSourceFeedback(org.eclipse.gef.Request)
+ */
+ public void eraseSourceFeedback(final Request request) {
+ final Iterator<EditPolicy> iterEditPolicies = this.delegatedEditPolicies.iterator();
+ while (iterEditPolicies.hasNext()) {
+ iterEditPolicies.next().eraseSourceFeedback(request);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gef.EditPolicy#eraseTargetFeedback(org.eclipse.gef.Request)
+ */
+ public void eraseTargetFeedback(final Request request) {
+ final Iterator<EditPolicy> iterEditPolicies = this.delegatedEditPolicies.iterator();
+ while (iterEditPolicies.hasNext()) {
+ iterEditPolicies.next().eraseTargetFeedback(request);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gef.EditPolicy#getCommand(org.eclipse.gef.Request)
+ */
+ public Command getCommand(final Request request) {
+ CompoundCommand ret = null;
+ final Iterator<EditPolicy> iterEditPolicies = this.delegatedEditPolicies.listIterator();
+ while (iterEditPolicies.hasNext()) {
+ final EditPolicy editPolicy = iterEditPolicies.next();
+ final Command command = editPolicy.getCommand(request);
+ if (command != null || isAllowNullCommand()) {
+ if (ret == null) {
+ ret = new CompoundCommand();
+ }
+ ret.add(command);
+ }
+ }
+ /*
+ * If there are only null commands in the result, we should return null.
+ */
+ boolean containsOnlyNullCommands = true;
+ if (ret != null) {
+ for (final Object c : ret.getCommands()) {
+ if (c != null) {
+ containsOnlyNullCommands = false;
+ break;
+ }
+ }
+ }
+ return containsOnlyNullCommands ? null : ret;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gef.EditPolicy#getHost()
+ */
+ public EditPart getHost() {
+ return this.host;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gef.EditPolicy#getTargetEditPart(org.eclipse.gef.Request)
+ */
+ public EditPart getTargetEditPart(final Request request) {
+ EditPart res = null;
+ final Iterator<EditPolicy> iterEditPolicies = this.delegatedEditPolicies.iterator();
+ while (iterEditPolicies.hasNext() && res == null) {
+ final EditPolicy next = iterEditPolicies.next();
+ res = next.getTargetEditPart(request);
+ }
+ return res;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gef.EditPolicy#setHost(org.eclipse.gef.EditPart)
+ */
+ public void setHost(final EditPart editpart) {
+ this.host = editpart;
+ final Iterator<EditPolicy> iterEditPolicies = this.delegatedEditPolicies.iterator();
+ while (iterEditPolicies.hasNext()) {
+ iterEditPolicies.next().setHost(editpart);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gef.EditPolicy#showSourceFeedback(org.eclipse.gef.Request)
+ */
+ public void showSourceFeedback(final Request request) {
+ final Iterator<EditPolicy> iterEditPolicies = this.delegatedEditPolicies.iterator();
+ while (iterEditPolicies.hasNext()) {
+ iterEditPolicies.next().showSourceFeedback(request);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gef.EditPolicy#showTargetFeedback(org.eclipse.gef.Request)
+ */
+ public void showTargetFeedback(final Request request) {
+ final Iterator<EditPolicy> iterEditPolicies = this.delegatedEditPolicies.iterator();
+ while (iterEditPolicies.hasNext()) {
+ iterEditPolicies.next().showTargetFeedback(request);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gef.EditPolicy#understandsRequest(org.eclipse.gef.Request)
+ */
+ public boolean understandsRequest(final Request request) {
+ boolean res = false;
+ final Iterator<EditPolicy> iterEditPolicies = this.delegatedEditPolicies.iterator();
+ while (iterEditPolicies.hasNext() && !res) {
+ res = iterEditPolicies.next().understandsRequest(request);
+ }
+ return res;
+ }
+
+ /**
+ * Adds an edit policy.
+ *
+ * @param editPolicy
+ * the edit policy to add.
+ */
+ public void addEditPolicy(final EditPolicy editPolicy) {
+ if (editPolicy == null) {
+ throw new IllegalArgumentException("the edit policy is null");
+ }
+ this.delegatedEditPolicies.add(editPolicy);
+ }
+
+ /**
+ * Removes an edit policy.
+ *
+ * @param policy
+ * the policy to remove.
+ */
+ public void removeEditPolicy(final EditPolicy policy) {
+ this.delegatedEditPolicies.remove(policy);
+ }
+
+ /**
+ * Return all edit policies.
+ *
+ * @return all edit policies.
+ */
+ public List<EditPolicy> getEditPolicies() {
+ return this.delegatedEditPolicies;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/properties/AbstractPropertySection.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/properties/AbstractPropertySection.java
new file mode 100644
index 0000000000..b86b64a11b
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/properties/AbstractPropertySection.java
@@ -0,0 +1,370 @@
+/******************************************************************************
+ * Copyright (c) 2003, 2009 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Obeo - adaptation
+ ****************************************************************************/
+
+package org.eclipse.sirius.diagram.ui.tools.api.properties;
+
+import org.eclipse.core.commands.operations.OperationHistoryFactory;
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.emf.edit.domain.IEditingDomainProvider;
+import org.eclipse.emf.transaction.NotificationFilter;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.gmf.runtime.diagram.ui.properties.sections.AbstractModelerPropertySection;
+import org.eclipse.gmf.runtime.emf.ui.properties.sections.UndoableModelPropertySheetEntry;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CLabel;
+import org.eclipse.swt.layout.FormAttachment;
+import org.eclipse.swt.layout.FormData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.views.properties.IPropertyDescriptor;
+import org.eclipse.ui.views.properties.IPropertySheetEntry;
+import org.eclipse.ui.views.properties.IPropertySource;
+import org.eclipse.ui.views.properties.IPropertySourceProvider;
+import org.eclipse.ui.views.properties.PropertySheetPage;
+import org.eclipse.ui.views.properties.PropertySheetSorter;
+import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;
+
+/**
+ * An abstract property section that sorts the viewer by the order returned by
+ * {@link IPropertySource#getPropertyDescriptors()}.
+ *
+ * @author ymortier
+ */
+public abstract class AbstractPropertySection extends AbstractModelerPropertySection {
+
+ /**
+ * the property sheet page for this section.
+ */
+ protected PropertySheetPage page;
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.properties.sections.AdvancedPropertySection#createControls(org.eclipse.swt.widgets.Composite,
+ * org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage)
+ */
+ @Override
+ public void createControls(final Composite parent, final TabbedPropertySheetPage aTabbedPropertySheetPage) {
+ super.createControls(parent, aTabbedPropertySheetPage);
+ final Composite composite = getWidgetFactory().createFlatFormComposite(parent);
+ FormData data = null;
+
+ final String tableLabelStr = getTableLabel();
+ CLabel tableLabel = null;
+ if (tableLabelStr != null && tableLabelStr.length() > 0) {
+ tableLabel = getWidgetFactory().createCLabel(composite, tableLabelStr);
+ data = new FormData();
+ data.left = new FormAttachment(0, 0);
+ data.top = new FormAttachment(0, 0);
+ tableLabel.setLayoutData(data);
+ }
+
+ //
+ // remove the other page.
+ page = new SortedPropertySheetPage();
+ final UndoableModelPropertySheetEntry root = new UndoableModelPropertySheetEntry(OperationHistoryFactory.getOperationHistory());
+
+ root.setPropertySourceProvider(getPropertySourceProvider());
+ page.setRootEntry(root);
+
+ page.createControl(composite);
+ data = new FormData();
+ data.left = new FormAttachment(0, 0);
+ data.right = new FormAttachment(100, 0);
+ if (tableLabel == null) {
+ data.top = new FormAttachment(0, 0);
+ } else {
+ data.top = new FormAttachment(tableLabel, 0, SWT.BOTTOM);
+ }
+ data.bottom = new FormAttachment(100, 0);
+ data.height = 100;
+ data.width = 100;
+ page.getControl().setLayoutData(data);
+
+ setActionBars(aTabbedPropertySheetPage.getSite().getActionBars());
+ ((SortedPropertySheetPage) page).setSorter(new AirPropertySorter());
+ }
+
+ private class AirPropertySorter extends PropertySheetSorter {
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.views.properties.PropertySheetSorter#compare(org.eclipse.ui.views.properties.IPropertySheetEntry,
+ * org.eclipse.ui.views.properties.IPropertySheetEntry)
+ */
+ @Override
+ public int compare(final IPropertySheetEntry entryA, final IPropertySheetEntry entryB) {
+ return super.compare(entryA, entryB);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.views.properties.PropertySheetSorter#compareCategories(java.lang.String,
+ * java.lang.String)
+ */
+ @Override
+ public int compareCategories(final String categoryA, final String categoryB) {
+ int result = Integer.MIN_VALUE;
+ IPropertySource propertySource = null;
+ //
+ // Gets the propertySource.
+ if (getPropertySourceProvider() != null && getSelectedObject() != null) {
+ propertySource = getPropertySourceProvider().getPropertySource(getSelectedObject());
+ }
+ if (propertySource == null) {
+ result = super.compareCategories(categoryA, categoryB);
+ }
+ //
+ // Special cases.
+ if (categoryA == null) {
+ result = categoryB == null ? 0 : 1;
+ }
+ if (categoryB == null) {
+ result = categoryA == null ? 0 : -1;
+ }
+ if (categoryA != null && categoryA.equals(categoryB)) {
+ result = 0;
+ }
+ //
+ // general cases.
+ if (propertySource != null) {
+ final IPropertyDescriptor[] descriptors = propertySource.getPropertyDescriptors();
+ for (int i = 0; i < descriptors.length && result == Integer.MIN_VALUE; i++) {
+ if (descriptors[i].getCategory() != null && descriptors[i].getCategory().equals(categoryA)) {
+ result = -1;
+ } else if (descriptors[i].getCategory() != null && descriptors[i].getCategory().equals(categoryB)) {
+ result = 1;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.views.properties.PropertySheetSorter#sort(org.eclipse.ui.views.properties.IPropertySheetEntry[])
+ */
+ @Override
+ public void sort(final IPropertySheetEntry[] entries) {
+ super.sort(entries);
+ }
+
+ }
+
+ /**
+ * Sets and prepares the actionBars for this section.
+ *
+ * @param actionBars
+ * the action bars for this page
+ * @see org.eclipse.gmf.runtime.common.ui.properties.TabbedPropertySheetPage#setActionBars(org.eclipse.ui.IActionBars)
+ */
+ public void setActionBars(final IActionBars actionBars) {
+
+ actionBars.getMenuManager().removeAll();
+ actionBars.getToolBarManager().removeAll();
+ actionBars.getStatusLineManager().removeAll();
+
+ page.makeContributions(actionBars.getMenuManager(), actionBars.getToolBarManager(), actionBars.getStatusLineManager());
+
+ actionBars.getToolBarManager().update(true);
+
+ }
+
+ /**
+ * Returns the PropertySource provider. The default implementation returns
+ * static adapter factory for the properties services. If the extending
+ * class needs to use a different provider then this method has to be
+ * overwriten.
+ *
+ * @return The PropertySource provider
+ */
+ protected IPropertySourceProvider getPropertySourceProvider() {
+ return propertiesProvider;
+ }
+
+ /**
+ * Returns the label for the table. The default implementation returns null,
+ * that is, there is no label.
+ *
+ * @return The label for the table
+ */
+ protected String getTableLabel() {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.properties.sections.AbstractModelerPropertySection#setInput(org.eclipse.ui.IWorkbenchPart,
+ * org.eclipse.jface.viewers.ISelection)
+ */
+ @Override
+ public void setInput(final IWorkbenchPart part, final ISelection selection) {
+ final IEditingDomainProvider provider = (IEditingDomainProvider) part.getAdapter(IEditingDomainProvider.class);
+ if (provider != null) {
+ final EditingDomain theEditingDomain = provider.getEditingDomain();
+ if (theEditingDomain instanceof TransactionalEditingDomain) {
+ setEditingDomain((TransactionalEditingDomain) theEditingDomain);
+ }
+ }
+
+ // Set the eObject for the section, too. The workbench part may not
+ // adapt to IEditingDomainProvider, in which case the selected EObject
+ // will be used to derive the editing domain.
+ if (!selection.isEmpty() && selection instanceof IStructuredSelection) {
+ final Object firstElement = ((IStructuredSelection) selection).getFirstElement();
+
+ if (firstElement != null) {
+ final EObject adapted = unwrap(firstElement);
+
+ if (adapted != null) {
+ setEObject(adapted);
+ }
+ }
+ }
+
+ try {
+ page.selectionChanged(part, selection);
+ // CHECKSTYLE:OFF
+ } catch (RuntimeException e) {
+ // CHECKSTYLE:ON
+ // can occur if the page references semantic element that have been
+ // deleted on CDO
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.properties.sections.AbstractModelerPropertySection#dispose()
+ */
+ @Override
+ public void dispose() {
+ super.dispose();
+
+ if (page != null) {
+ page.dispose();
+ page = null;
+ }
+
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.views.properties.tabbed.AbstractPropertySection#refresh()
+ */
+ @Override
+ public void refresh() {
+ try {
+ page.refresh();
+ // CHECKSTYLE:OFF
+ } catch (RuntimeException e) {
+ // CHECKSTYLE:ON
+ // can occur if the page references semantic element that have been
+ // deleted on CDO
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.views.properties.tabbed.AbstractPropertySection#shouldUseExtraSpace()
+ */
+ @Override
+ public boolean shouldUseExtraSpace() {
+ return true;
+ }
+
+ /**
+ * Update if nessesary, upon receiving the model event.
+ *
+ * @see #aboutToBeShown()
+ * @see #aboutToBeHidden()
+ * @param notification
+ * - even notification
+ * @param element
+ * - element that has changed
+ */
+ @Override
+ public void update(final Notification notification, final EObject element) {
+ if (!isDisposed()) {
+ postUpdateRequest(new Runnable() {
+
+ public void run() {
+ if (!isDisposed() && !isNotifierDeleted(notification)) {
+ refresh();
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.properties.sections.AbstractModelerPropertySection#getFilter()
+ */
+ @Override
+ public NotificationFilter getFilter() {
+ return NotificationFilter.createEventTypeFilter(Notification.SET).or(NotificationFilter.createEventTypeFilter(Notification.UNSET))
+ .or(NotificationFilter.createEventTypeFilter(Notification.ADD)).or(NotificationFilter.createEventTypeFilter(Notification.ADD_MANY))
+ .or(NotificationFilter.createEventTypeFilter(Notification.REMOVE)).or(NotificationFilter.createEventTypeFilter(Notification.REMOVE_MANY))
+ .and(NotificationFilter.createNotifierTypeFilter(EObject.class));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.properties.sections.AbstractModelerPropertySection#addToEObjectList(java.lang.Object)
+ */
+ @Override
+ protected boolean addToEObjectList(final Object object) {
+ /* not implemented */
+ return true;
+ }
+
+ /**
+ * Returns the selected object.
+ *
+ * @return the selected objet.
+ */
+ public abstract Object getSelectedObject();
+
+ /**
+ * A property sheet page that allows to change the sorter of the table
+ * viewer.
+ *
+ * @author ymortier
+ */
+ private static class SortedPropertySheetPage extends PropertySheetPage {
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.views.properties.PropertySheetPage#setSorter(org.eclipse.ui.views.properties.PropertySheetSorter)
+ */
+ @Override
+ public void setSorter(final PropertySheetSorter sorter) {
+ super.setSorter(sorter);
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/properties/MiscPropertySection.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/properties/MiscPropertySection.java
new file mode 100644
index 0000000000..a2c102edd5
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/properties/MiscPropertySection.java
@@ -0,0 +1,130 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.properties;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.eclipse.gef.EditPart;
+import org.eclipse.gmf.runtime.diagram.ui.properties.sections.AdvancedPropertySection;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.views.properties.IPropertyDescriptor;
+import org.eclipse.ui.views.properties.IPropertySource;
+import org.eclipse.ui.views.properties.IPropertySourceProvider;
+import org.eclipse.ui.views.properties.PropertyDescriptor;
+
+import org.eclipse.sirius.common.tools.api.util.StringUtil;
+import org.eclipse.sirius.diagram.tools.internal.properties.DefaultPropertySource;
+
+/**
+ * This property section provides debug informations.
+ *
+ * @author ymortier
+ */
+public class MiscPropertySection extends AdvancedPropertySection implements IPropertySourceProvider {
+
+ /**
+ * Returns the property source of the specified object.
+ *
+ * @param object
+ * the object.
+ * @return the property source of the specified object.
+ */
+ public IPropertySource getPropertySource(final Object object) {
+
+ IPropertySource propSrc = null;
+
+ if (object instanceof IPropertySource) {
+ propSrc = (IPropertySource) object;
+ } else if (object instanceof EditPart) {
+ propSrc = new MiscPropertySource(object);
+ } else if (object instanceof Collection<?>) {
+ final Collection<?> collection = (Collection<?>) object;
+ final IPropertyDescriptor[] propertyDescriptors = new PropertyDescriptor[collection.size()];
+ final Iterator<?> iterCollection = collection.iterator();
+ int i = 0;
+ while (iterCollection.hasNext()) {
+ final Object next = iterCollection.next();
+ propertyDescriptors[i] = new PropertyDescriptor(next, i + StringUtil.EMPTY_STRING);
+ i++;
+ }
+ propSrc = new DefaultPropertySource(propertyDescriptors);
+
+ } else if (object instanceof Object[]) {
+ final Object[] collection = (Object[]) object;
+ final IPropertyDescriptor[] propertyDescriptors = new PropertyDescriptor[collection.length];
+ for (int i = 0; i < collection.length; i++) {
+ Object next = collection[i];
+ if (next == null) {
+ next = "null object";
+ }
+ propertyDescriptors[i] = new PropertyDescriptor(next, i + "");
+ }
+ propSrc = new DefaultPropertySource(propertyDescriptors);
+ } else if (object != null) {
+ propSrc = new MiscPropertySource(object);
+ }
+ return propSrc;
+ }
+
+ /**
+ * Returns the provider.
+ *
+ * @return the provider.
+ */
+ @Override
+ protected IPropertySourceProvider getPropertySourceProvider() {
+ return this;
+ }
+
+ /**
+ * Modify/unwrap selection.
+ *
+ * @param selected
+ * the current selected object
+ * @return the unwrapped object
+ */
+ protected Object transformSelection(final Object selected) {
+
+ if (selected instanceof EditPart) {
+ return selected;
+
+ }
+ return selected;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.properties.sections.AdvancedPropertySection#setInput(org.eclipse.ui.IWorkbenchPart,
+ * org.eclipse.jface.viewers.ISelection)
+ */
+ @Override
+ public void setInput(final IWorkbenchPart part, final ISelection selection) {
+ if (selection.isEmpty() || !(selection instanceof StructuredSelection)) {
+ super.setInput(part, selection);
+ return;
+ }
+ final StructuredSelection structuredSelection = (StructuredSelection) selection;
+ final ArrayList<Object> transformedSelection = new ArrayList<Object>(structuredSelection.size());
+ final Iterator<?> it = structuredSelection.iterator();
+ while (it.hasNext()) {
+ final Object r = transformSelection(it.next());
+ if (r != null) {
+ transformedSelection.add(r);
+ }
+ }
+ super.setInput(part, new StructuredSelection(transformedSelection));
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/properties/MiscPropertySource.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/properties/MiscPropertySource.java
new file mode 100644
index 0000000000..344f5e7502
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/properties/MiscPropertySource.java
@@ -0,0 +1,179 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.properties;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.ui.views.properties.IPropertyDescriptor;
+import org.eclipse.ui.views.properties.IPropertySource;
+import org.eclipse.ui.views.properties.PropertyDescriptor;
+
+import org.eclipse.sirius.common.ui.SiriusTransPlugin;
+
+/**
+ * This property source uses the reflection Java API to display debug
+ * informations.
+ *
+ * @author ymortier
+ */
+public class MiscPropertySource implements IPropertySource {
+
+ /** The selected object. */
+ private Object selectedObject;
+
+ /**
+ * Create a new {@link MiscPropertySource}.
+ *
+ * @param selectedObject
+ * the edit part to analyse.
+ */
+ public MiscPropertySource(final Object selectedObject) {
+ this.selectedObject = selectedObject;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.views.properties.IPropertySource#getEditableValue()
+ */
+ public Object getEditableValue() {
+ return this.selectedObject;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.views.properties.IPropertySource#getPropertyDescriptors()
+ */
+ public IPropertyDescriptor[] getPropertyDescriptors() {
+ final List<Field> allFields = new LinkedList<Field>();
+ Field[] fields = this.selectedObject.getClass().getDeclaredFields();
+ allFields.addAll(Arrays.asList(fields));
+ Class<?> currentClass = this.selectedObject.getClass().getSuperclass();
+ while (currentClass != Object.class) {
+ fields = currentClass.getDeclaredFields();
+ allFields.addAll(Arrays.asList(fields));
+ currentClass = currentClass.getSuperclass();
+ }
+ final PropertyDescriptor[] propertyDescriptors = new ReflectPropertyDescriptor[allFields.size()];
+ final String categName = this.selectedObject.getClass().getName().substring(this.selectedObject.getClass().getName().lastIndexOf('.') + 1);
+ final Iterator<Field> iterFields = allFields.iterator();
+ int i = 0;
+ while (iterFields.hasNext()) {
+ final Field currentField = iterFields.next();
+ if (!Modifier.isStatic(currentField.getModifiers())) {
+ final ReflectPropertyDescriptor reflectPropertyDescriptor = new ReflectPropertyDescriptor(currentField, currentField.getName(), categName);
+ propertyDescriptors[i++] = reflectPropertyDescriptor;
+ }
+ }
+ final int realSize = i;
+ final IPropertyDescriptor[] descriptors = new ReflectPropertyDescriptor[realSize];
+ System.arraycopy(propertyDescriptors, 0, descriptors, 0, realSize);
+ return descriptors;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.views.properties.IPropertySource#getPropertyValue(java.lang.Object)
+ */
+ public Object getPropertyValue(final Object id) {
+
+ Object value = null;
+ if (id instanceof Field) {
+ final Field field = (Field) id;
+ final boolean oldAccessible = field.isAccessible();
+ try {
+ field.setAccessible(true);
+ try {
+ value = field.get(this.selectedObject);
+ } catch (final IllegalArgumentException e) {
+ SiriusTransPlugin.getPlugin().error("Error while getting property value", e);
+ } catch (final IllegalAccessException e) {
+ SiriusTransPlugin.getPlugin().error("Error while getting property value", e);
+ }
+ } finally {
+ field.setAccessible(oldAccessible);
+ }
+ }
+ return value;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.views.properties.IPropertySource#isPropertySet(java.lang.Object)
+ */
+ public boolean isPropertySet(final Object id) {
+ // does nothing
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.views.properties.IPropertySource#resetPropertyValue(java.lang.Object)
+ */
+ public void resetPropertyValue(final Object id) {
+ // does nothing.
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.views.properties.IPropertySource#setPropertyValue(java.lang.Object,
+ * java.lang.Object)
+ */
+ public void setPropertyValue(final Object id, final Object value) {
+ // does nothing.
+ }
+
+ /**
+ * The reflect property descriptor. Use Reflect Java API to retrieves meta
+ * informations.
+ *
+ * @author ymortier
+ */
+ private static class ReflectPropertyDescriptor extends PropertyDescriptor {
+
+ /** The name of the category. */
+ private String category;
+
+ /**
+ * Create a new descriptor.
+ *
+ * @param id
+ * the id of the property.
+ * @param displayName
+ * the name to display.
+ * @param category
+ * the name of the category.
+ */
+ public ReflectPropertyDescriptor(final Object id, final String displayName, final String category) {
+ super(id, displayName);
+ this.category = category;
+ }
+
+ /**
+ * @see org.eclipse.ui.views.properties.PropertyDescriptor#getCategory()
+ */
+ @Override
+ public String getCategory() {
+ return category;
+ }
+
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/properties/filter/AbstractPropertyFilter.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/properties/filter/AbstractPropertyFilter.java
new file mode 100644
index 0000000000..fcfc065e93
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/properties/filter/AbstractPropertyFilter.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.properties.filter;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.jface.viewers.IFilter;
+
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DSemanticDecorator;
+
+/**
+ * The base filter for property. The job of this filter is to initialize the
+ * <code>notationView</code>, the <code>viewPointElement</code> and the
+ * <code>semanticElements</code> attributes. The method
+ * {@link AbstractPropertyFilter#select(Object)} returns always
+ * <code>true</code>.
+ *
+ * @author ymortier
+ */
+public abstract class AbstractPropertyFilter implements IFilter {
+
+ /** The edit part. */
+ protected EditPart editPart;
+
+ /** The GMF model element. */
+ protected View notationView;
+
+ /** The viewpoint model element. */
+ protected EObject viewPointElement;
+
+ /** The semantic model elements. */
+ protected List<EObject> semanticElements;
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.IFilter#select(java.lang.Object)
+ */
+ public boolean select(final Object toTest) {
+ this.notationView = null;
+ this.viewPointElement = null;
+ this.semanticElements = Collections.emptyList();
+ if (toTest instanceof EditPart) {
+ this.editPart = (EditPart) toTest;
+ if (editPart.getModel() instanceof View) {
+ this.notationView = (View) editPart.getModel();
+ }
+ } else if (toTest instanceof View) {
+ this.notationView = (View) toTest;
+ } else if (toTest instanceof DDiagramElement) {
+ this.viewPointElement = (DDiagramElement) toTest;
+ }
+ if (viewPointElement == null && notationView != null) {
+ if (notationView.getElement() != null) {
+ this.viewPointElement = notationView.getElement();
+ }
+ }
+ if (viewPointElement instanceof DSemanticDecorator) {
+ final DSemanticDecorator decorateSemanticElement = (DSemanticDecorator) viewPointElement;
+ // avoid doubles.
+ final Set<EObject> tmpSemanticElements = new HashSet<EObject>();
+ if (viewPointElement instanceof DDiagramElement) {
+ tmpSemanticElements.addAll(((DDiagramElement) viewPointElement).getSemanticElements());
+ }
+ tmpSemanticElements.add(decorateSemanticElement.getTarget());
+ this.semanticElements = new ArrayList<EObject>(tmpSemanticElements);
+ }
+ return true;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/properties/filter/MiscPropertyFilter.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/properties/filter/MiscPropertyFilter.java
new file mode 100644
index 0000000000..3c3f298dc9
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/properties/filter/MiscPropertyFilter.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.properties.filter;
+
+/**
+ * Filters the Misc property section. The section should appears only if the
+ * input selection is an edit part.
+ *
+ * @author ymortier
+ */
+public class MiscPropertyFilter extends AbstractPropertyFilter {
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.properties.filter.AbstractPropertyFilter#select(java.lang.Object)
+ */
+ @Override
+ public boolean select(final Object toTest) {
+ return super.select(toTest) && this.editPart != null;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/util/EditPartTools.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/util/EditPartTools.java
new file mode 100644
index 0000000000..a606f9bc01
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/util/EditPartTools.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2008 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.util;
+
+import java.util.Iterator;
+
+import org.eclipse.gef.EditPart;
+
+/**
+ * Tools for edit part.
+ *
+ * @author ymortier
+ */
+public final class EditPartTools {
+
+ /**
+ * Avoid instantiation.
+ */
+ private EditPartTools() {
+ }
+
+ /**
+ * Returns the first edit part that is an instance of the class
+ * <code>editPartType</code>.
+ *
+ * @param root
+ * the root edit part.
+ * @param editPartType
+ * the type of the edit part.
+ * @return the first edit part that is an instance of the class
+ * <code>editPartType</code>.
+ */
+ public static EditPart getEditPartOfType(final EditPart root, final Class<?> editPartType) {
+ if (root == null || editPartType == null) {
+ throw new IllegalArgumentException("root or editPartType is null");
+ }
+ EditPart result = null;
+ if (editPartType.isInstance(root)) {
+ result = root;
+ }
+ if (result == null) {
+ @SuppressWarnings("unchecked")
+ final Iterator<EditPart> iterChildren = root.getChildren().iterator();
+ while (iterChildren.hasNext() && result == null) {
+ result = EditPartTools.getEditPartOfType(iterChildren.next(), editPartType);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns an ancestor of the given edit part.
+ *
+ * @param <T>
+ * the type of the ancestor to return.
+ * @param aChild
+ * a child edit part.
+ * @param type
+ * the type of the ancestor to return.
+ * @return the found edit part.
+ */
+ public static <T extends EditPart> T getParentOfType(final EditPart aChild, final Class<T> type) {
+ T result = null;
+ EditPart current = aChild;
+ while (result == null && current != null) {
+ if (type.isInstance(current)) {
+ result = type.cast(current);
+ } else {
+ current = current.getParent();
+ }
+ }
+ return result;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/util/GMFNotationHelper.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/util/GMFNotationHelper.java
new file mode 100644
index 0000000000..151b71c5c1
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/api/util/GMFNotationHelper.java
@@ -0,0 +1,431 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.api.util;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.gmf.runtime.diagram.core.preferences.PreferencesHint;
+import org.eclipse.gmf.runtime.diagram.core.services.ViewService;
+import org.eclipse.gmf.runtime.diagram.core.util.ViewType;
+import org.eclipse.gmf.runtime.diagram.ui.preferences.IPreferenceConstants;
+import org.eclipse.gmf.runtime.draw2d.ui.figures.FigureUtilities;
+import org.eclipse.gmf.runtime.notation.Bounds;
+import org.eclipse.gmf.runtime.notation.Diagram;
+import org.eclipse.gmf.runtime.notation.Edge;
+import org.eclipse.gmf.runtime.notation.LayoutConstraint;
+import org.eclipse.gmf.runtime.notation.Location;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.NotationFactory;
+import org.eclipse.gmf.runtime.notation.ShapeStyle;
+import org.eclipse.gmf.runtime.notation.Size;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.PreferenceConverter;
+import org.eclipse.swt.graphics.RGB;
+
+import org.eclipse.sirius.common.ui.SiriusTransPlugin;
+
+/**
+ * Utility class to work with the GMF Annotation model.
+ *
+ * @author cbrun
+ *
+ */
+public final class GMFNotationHelper {
+ /*
+ * This is an utility class, should not be initialized!
+ */
+ private GMFNotationHelper() {
+
+ }
+
+ /**
+ * Return the X position of GMF {@link Node}.
+ *
+ * @param gmfView
+ * the GMF {@link Node}.
+ * @return the X position of the node
+ */
+ public static int getX(final Node gmfView) {
+ if (gmfView.getLayoutConstraint() instanceof Bounds) {
+ final Bounds nodeBounds = (Bounds) gmfView.getLayoutConstraint();
+ return nodeBounds.getX();
+ }
+ return 0;
+ }
+
+ /**
+ * Return the Y position of GMF {@link Node}.
+ *
+ * @param gmfView
+ * the GMF {@link Node}.
+ * @return the Y position of the node
+ */
+ public static int getY(final Node gmfView) {
+ if (gmfView.getLayoutConstraint() instanceof Bounds) {
+ final Bounds nodeBounds = (Bounds) gmfView.getLayoutConstraint();
+ return nodeBounds.getY();
+ }
+ return 0;
+ }
+
+ /**
+ * Return the width of GMF {@link Node}.
+ *
+ * @param gmfView
+ * the GMF {@link Node}.
+ * @return the width of the node
+ */
+ public static int getWidth(final Node gmfView) {
+ if (gmfView.getLayoutConstraint() instanceof Bounds) {
+ final Bounds nodeBounds = (Bounds) gmfView.getLayoutConstraint();
+ return nodeBounds.getWidth();
+ }
+ return 0;
+ }
+
+ /**
+ * Return the height of GMF {@link Node}.
+ *
+ * @param gmfView
+ * the GMF {@link Node}.
+ * @return the height of the node
+ */
+ public static int getHeight(final Node gmfView) {
+ if (gmfView.getLayoutConstraint() instanceof Bounds) {
+ final Bounds nodeBounds = (Bounds) gmfView.getLayoutConstraint();
+ return nodeBounds.getHeight();
+ }
+ return 0;
+ }
+
+ /**
+ * Return the text of a note.
+ *
+ * @param note
+ * a GMF Note.
+ * @return the text of the note.
+ */
+ public static String getNoteDescription(final Node note) {
+ final Iterator it = note.getStyles().iterator();
+ while (it.hasNext()) {
+ final Object obj = it.next();
+ if (obj instanceof ShapeStyle) {
+ return ((ShapeStyle) obj).getDescription();
+ }
+ }
+ return "";
+ }
+
+ /**
+ * return a list of nodes corresponding to notes.
+ *
+ * @param gmfDiagram
+ * any GMF Diagram
+ * @return a list of nodes corresponding to notes.
+ */
+ public static Collection<Node> getNotes(final Diagram gmfDiagram) {
+ final Collection<Node> result = new ArrayList<Node>();
+ final Iterator<EObject> it = gmfDiagram.eAllContents();
+ while (it.hasNext()) {
+ final EObject obj = it.next();
+ if (obj instanceof Node && GMFNotationHelper.isNote((Node) obj)) {
+ result.add((Node) obj);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Usefull to get all the note attachments of a GMF diagram.
+ *
+ * @param gmfDiagram
+ * any GMF diagram.
+ * @return a list of {@link Edge} which are the note attachments.
+ */
+ public static Collection<Edge> getNotesAttachments(final Diagram gmfDiagram) {
+ final Collection<Edge> result = new ArrayList<Edge>();
+ final Iterator<EObject> it = gmfDiagram.eAllContents();
+ while (it.hasNext()) {
+ final EObject obj = it.next();
+ if (obj instanceof Edge && GMFNotationHelper.isNoteAttachment((Edge) obj)) {
+ result.add((Edge) obj);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Tell whether an Edge is a note attachment or not.
+ *
+ * @param obj
+ * any GMF Edge.
+ * @return true if the edge is a note attachment.
+ */
+ public static boolean isNoteAttachment(final Edge obj) {
+ return ViewType.NOTEATTACHMENT.equals(obj.getType());
+ }
+
+ /**
+ * tell whether a node is a note or not.
+ *
+ * @param node
+ * any node.
+ * @return true if the node is a Note
+ */
+ public static boolean isNote(final Node node) {
+ return ViewType.NOTE.equals(node.getType());
+ }
+
+ /**
+ * Browse the resource content of the given element and retrieve GMF
+ * {@link Diagram} corresponding to this element if available.
+ *
+ * @param eObject
+ * any eObject of the Resource containing the diagrams.
+ * @return the first GMF Diagram targeting the eObject, null if not found.
+ */
+ public static Diagram findGMFDiagram(final EObject eObject) {
+ final Iterator<EObject> it = eObject.eResource().getAllContents();
+ while (it.hasNext()) {
+ final Object obj = it.next();
+ if (obj instanceof Diagram) {
+ if (((Diagram) obj).getElement() == eObject) {
+ return (Diagram) obj;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return the list of all the GMF diagrams contained in the resource.
+ *
+ * @param resource
+ * the resource
+ * @return the list of GMF diagram contained in the resource.
+ */
+ public static Collection<Diagram> getGMFDiagrams(final Resource resource) {
+ final Collection<Diagram> result = new ArrayList<Diagram>();
+ final Iterator<EObject> it = resource.getAllContents();
+ while (it.hasNext()) {
+ final EObject obj = it.next();
+ if (obj instanceof Diagram) {
+ result.add((Diagram) obj);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Create a new Note and attach it on the diagram.
+ *
+ * @param container
+ * the container diagram.
+ * @param noteText
+ * the content of the note.
+ * @return the newly created note.
+ */
+ public static Node createNote(final Diagram container, final String noteText) {
+
+ final Node note = ViewService.createNode(container, ViewType.NOTE, PreferencesHint.USE_DEFAULTS);
+ final Iterator it = note.getStyles().iterator();
+ while (it.hasNext()) {
+ final Object cur = it.next();
+ if (cur instanceof ShapeStyle) {
+ ((ShapeStyle) cur).setDescription(noteText);
+ }
+ }
+ return note;
+
+ }
+
+ /**
+ * Create a new Note and attach it on the diagram.
+ *
+ * @param container
+ * the container diagram.
+ * @param noteText
+ * the content of the note.
+ * @param preferencesStore
+ * the preferencesStore of the Calling plugin.
+ * @return the newly created note.
+ */
+ public static Node createNote(final Diagram container, final String noteText, final IPreferenceStore preferencesStore) {
+ final Node note = GMFNotationHelper.createNote(container, noteText);
+
+ try {
+ // In Eclipse 3.5 createNote returns a Shape that does not have the
+ // generic color.
+ Class<?> shapeClass = Class.forName("org.eclipse.gmf.runtime.notation.Shape");
+
+ Method methodSetDescription = shapeClass.getMethod("setDescription", String.class);
+ methodSetDescription.invoke(note, noteText);
+
+ Method methodSetFillColor = shapeClass.getMethod("setFillColor", int.class);
+ RGB fillRGB = PreferenceConverter.getColor(preferencesStore, IPreferenceConstants.PREF_NOTE_FILL_COLOR);
+ methodSetFillColor.invoke(note, FigureUtilities.RGBToInteger(fillRGB).intValue());
+
+ Method methodSetLineColor = shapeClass.getMethod("setLineColor", int.class);
+ RGB lineRGB = PreferenceConverter.getColor(preferencesStore, IPreferenceConstants.PREF_NOTE_LINE_COLOR);
+ methodSetLineColor.invoke(note, FigureUtilities.RGBToInteger(lineRGB).intValue());
+
+ } catch (final ClassNotFoundException cnfe) {
+ // We are not in Eclipse 3.3 : Do nothing else
+ } catch (SecurityException e) {
+ SiriusTransPlugin.getPlugin().error("SecurityException while accessing Shape class", e);
+ } catch (NoSuchMethodException e) {
+ SiriusTransPlugin.getPlugin().error("NoSuchMethodException while accessing Shape class", e);
+ } catch (IllegalArgumentException e) {
+ SiriusTransPlugin.getPlugin().error("IllegalArgumentException while accessing Shape class", e);
+ } catch (IllegalAccessException e) {
+ SiriusTransPlugin.getPlugin().error("IllegalAccessException while accessing Shape class", e);
+ } catch (InvocationTargetException e) {
+ SiriusTransPlugin.getPlugin().error("InvocationTargetException while accessing Shape class", e);
+ }
+ return note;
+
+ }
+
+ /**
+ * Create a LayoutPosition instance from a set of integer values.
+ *
+ * @param x
+ * x position.
+ * @param y
+ * y position .
+ * @param width
+ * layout width.
+ * @param height
+ * layout height.
+ * @return the newly created {@link LayoutConstraint}.
+ */
+ public static LayoutConstraint createLayoutPosition(final BigInteger x, final BigInteger y, final BigInteger width, final BigInteger height) {
+ final Bounds layout = NotationFactory.eINSTANCE.createBounds();
+ layout.setX(x.intValue());
+ layout.setY(y.intValue());
+ layout.setWidth(width.intValue());
+ layout.setHeight(height.intValue());
+ return layout;
+ }
+
+ /**
+ * Browse the given diagram to find a GMF Node targeting the given element.
+ *
+ * @param diagram
+ * a GMF Diagram.
+ * @param modelElement
+ * any element.
+ * @return a Node targeting the model element if found, null otherwise.
+ */
+ public static Node findGMFNode(final Diagram diagram, final EObject modelElement) {
+ final Iterator<EObject> it = diagram.eAllContents();
+ while (it.hasNext()) {
+ final EObject cur = it.next();
+ if (cur instanceof Node) {
+ if (((Node) cur).getElement() == modelElement) {
+ return (Node) cur;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Create a new note attachment and append it on the diagram.
+ *
+ * @param note
+ * : the note .
+ * @param target
+ * : the GMF node to attach to.
+ */
+ public static void createNoteAttachment(final Node note, final Node target) {
+ ViewService.createEdge(note, target, ViewType.NOTEATTACHMENT, PreferencesHint.USE_DEFAULTS);
+ }
+
+ /**
+ * Computes and returns the absolute location of the specified {@link Node}.
+ * Returns (0,0) if the node is <code>null</code>.
+ *
+ * @param node
+ * the node.
+ * @return the absolute location of the specified {@link Node}.
+ */
+ public static Point getAbsoluteLocation(final Node node) {
+ final Point location = new Point(0, 0);
+ EObject current = node;
+ //
+ // Iterates over all parents.
+ while (current instanceof Node) {
+ if (((Node) current).getLayoutConstraint() instanceof Location) {
+ final Location nodeLocation = (Location) ((Node) current).getLayoutConstraint();
+ location.x += nodeLocation.getX();
+ location.y += nodeLocation.getY();
+ }
+ current = current.eContainer();
+ }
+ return location;
+ }
+
+ /**
+ * Get a copy.
+ *
+ * @param bounds
+ * Bounds to copy
+ *
+ * @return the copy
+ */
+ public static Bounds getCopy(Bounds bounds) {
+ Bounds copy = NotationFactory.eINSTANCE.createBounds();
+ copy.setX(bounds.getX());
+ copy.setY(bounds.getY());
+ copy.setWidth(bounds.getWidth());
+ copy.setHeight(bounds.getHeight());
+ return copy;
+ }
+
+ /**
+ * Get a copy.
+ *
+ * @param location
+ * Location to copy
+ *
+ * @return the copy
+ */
+ public static Location getCopy(Location location) {
+ Location copy = NotationFactory.eINSTANCE.createLocation();
+ copy.setX(location.getX());
+ copy.setY(location.getY());
+ return copy;
+ }
+
+ /**
+ * Get a copy.
+ *
+ * @param size
+ * Size to copy
+ *
+ * @return the copy
+ */
+ public static Size getCopy(Size size) {
+ Size copy = NotationFactory.eINSTANCE.createSize();
+ copy.setWidth(size.getWidth());
+ copy.setHeight(size.getHeight());
+ return copy;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/ActivateBehaviorToolsCommand.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/ActivateBehaviorToolsCommand.java
new file mode 100644
index 0000000000..7483907184
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/ActivateBehaviorToolsCommand.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.commands;
+
+import java.util.Collection;
+
+import org.eclipse.emf.transaction.RecordingCommand;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.business.api.helper.concern.ConcernService;
+import org.eclipse.sirius.description.tool.BehaviorTool;
+
+/**
+ * Specific command to update activated behaviors.
+ *
+ * @author mporhel
+ */
+public final class ActivateBehaviorToolsCommand extends RecordingCommand {
+
+ private final Collection<BehaviorTool> newElements;
+
+ private final DDiagram diagram;
+
+ /**
+ * Constructor.
+ *
+ * @param domain
+ * the editing domain.
+ * @param newElements
+ * elements to add
+ * @param dDiagram
+ * the current diagram.
+ */
+ public ActivateBehaviorToolsCommand(TransactionalEditingDomain domain, DDiagram dDiagram, Collection<BehaviorTool> newElements) {
+ super(domain, "Activate behavior tools");
+ this.diagram = dDiagram;
+ this.newElements = newElements;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doExecute() {
+ if (diagram == null || newElements == null) {
+ return;
+ }
+
+ for (BehaviorTool tool : newElements) {
+ diagram.getActivateBehaviors().add(tool);
+ }
+ ConcernService.resetCurrentConcern(diagram);
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/ActivateFiltersCommand.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/ActivateFiltersCommand.java
new file mode 100644
index 0000000000..4058d4ba1e
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/ActivateFiltersCommand.java
@@ -0,0 +1,145 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.commands;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.transaction.RecordingCommand;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+
+import org.eclipse.sirius.common.tools.api.listener.NotificationUtil;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DSemanticDiagram;
+import org.eclipse.sirius.SiriusFactory;
+import org.eclipse.sirius.business.api.helper.concern.ConcernService;
+import org.eclipse.sirius.description.concern.ConcernDescription;
+import org.eclipse.sirius.description.filter.CompositeFilterDescription;
+import org.eclipse.sirius.description.filter.Filter;
+import org.eclipse.sirius.description.filter.FilterDescription;
+import org.eclipse.sirius.description.filter.VariableFilter;
+import org.eclipse.sirius.diagram.tools.internal.filter.FilterTools;
+
+/**
+ * Specific command to update activated filters.
+ *
+ * @author mporhel
+ */
+public final class ActivateFiltersCommand extends RecordingCommand {
+
+ private final Collection<FilterDescription> newElements;
+
+ private final DDiagram diagram;
+
+ /**
+ * Constructor.
+ *
+ * @param domain
+ * the editing domain.
+ * @param diagram
+ * the current diagram.
+ * @param newElements
+ * elements to activate
+ */
+ public ActivateFiltersCommand(TransactionalEditingDomain domain, DDiagram diagram, Collection<FilterDescription> newElements) {
+ super(domain, "Activate filters");
+ this.newElements = newElements;
+ this.diagram = diagram;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doExecute() {
+ if (diagram == null || newElements == null) {
+ return;
+ }
+
+ initFilterVariablesHistory();
+
+ doActivateFilters();
+
+ if (newElements.size() > 0) {
+ NotificationUtil.sendNotification(diagram, org.eclipse.sirius.common.tools.api.listener.Notification.Kind.START, org.eclipse.sirius.common.tools.api.listener.Notification.VISIBILITY_UPDATE);
+ }
+ }
+
+ private void doActivateFilters() {
+ boolean containsVariableFilters = false;
+ final List<FilterDescription> newActivatedFilters = new ArrayList<FilterDescription>();
+ final List<FilterDescription> previousActivatedFilters = new ArrayList<FilterDescription>(diagram.getActivatedFilters());
+
+ ConcernDescription oldConcern = getAndResetConcern();
+
+ try {
+ for (FilterDescription filterDesc : newElements) {
+ if (filterDesc instanceof CompositeFilterDescription && diagram instanceof DSemanticDiagram) {
+ containsVariableFilters = containsVariableFilters | handleVariableInit((CompositeFilterDescription) filterDesc, (DSemanticDiagram) diagram);
+ }
+ /*
+ * In all the cases, if we've got a filter, then enable it..
+ */
+ newActivatedFilters.add(filterDesc);
+ }
+ // need to remove previous filters to handle creation of
+ // new graphical elements on variable filters activation.
+ if (containsVariableFilters && previousActivatedFilters.size() > 0) {
+ diagram.getActivatedFilters().clear();
+ }
+ diagram.getActivatedFilters().addAll(newActivatedFilters);
+ // reactivation of previous activated filters.
+ if (containsVariableFilters && previousActivatedFilters.size() > 0) {
+ diagram.getActivatedFilters().addAll(previousActivatedFilters);
+ }
+ } catch (final InterruptedException e) {
+ ConcernService.setCurrentConcern(diagram, oldConcern);
+ }
+ }
+
+ private ConcernDescription getAndResetConcern() {
+ ConcernDescription oldConcern = null;
+ if (newElements.size() > 0 && diagram.getCurrentConcern() != null) {
+ oldConcern = diagram.getCurrentConcern();
+ ConcernService.resetCurrentConcern(diagram);
+ }
+ return oldConcern;
+ }
+
+ private void initFilterVariablesHistory() {
+ if (diagram.getFilterVariableHistory() == null) {
+ diagram.setFilterVariableHistory(SiriusFactory.eINSTANCE.createFilterVariableHistory());
+ }
+ }
+
+ private boolean handleVariableInit(final CompositeFilterDescription composite, final DSemanticDiagram vp) throws InterruptedException {
+ boolean containsVariableFilters = false;
+ final Iterator<Filter> it = composite.getFilters().iterator();
+ while (it.hasNext()) {
+ final Filter objFilter = it.next();
+ /*
+ * If we have a variable filter we need to open the dialog and set
+ * the different variables..
+ */
+ if (objFilter instanceof VariableFilter) {
+ final VariableFilter filter = (VariableFilter) objFilter;
+ final Map<String, EObject> variables = FilterTools.askForFilterValues(vp, filter);
+ filter.setFilterContext(variables);
+ containsVariableFilters = true;
+ }
+ }
+ return containsVariableFilters;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/ActivateRulesCommand.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/ActivateRulesCommand.java
new file mode 100644
index 0000000000..48701ce255
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/ActivateRulesCommand.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.commands;
+
+import java.util.Collection;
+
+import org.eclipse.emf.transaction.RecordingCommand;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.description.validation.ValidationRule;
+
+/**
+ * Specific command to update activated rules.
+ *
+ * @author mporhel
+ */
+public final class ActivateRulesCommand extends RecordingCommand {
+
+ private final Collection<ValidationRule> newElements;
+
+ private final DDiagram diagram;
+
+ /**
+ * Constructor.
+ *
+ * @param domain
+ * the editing domain.
+ * @param diagram
+ * the current diagram.
+ * @param newElements
+ * elements to activate
+ */
+ public ActivateRulesCommand(TransactionalEditingDomain domain, DDiagram diagram, Collection<ValidationRule> newElements) {
+ super(domain, "Activate validation rules");
+ this.newElements = newElements;
+ this.diagram = diagram;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doExecute() {
+ if (diagram == null || newElements == null) {
+ return;
+ }
+
+ for (ValidationRule rule : newElements) {
+ diagram.getActivatedRules().add(rule);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/ChangeLayerActivationCommand.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/ChangeLayerActivationCommand.java
new file mode 100644
index 0000000000..c59403864a
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/ChangeLayerActivationCommand.java
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.commands;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.emf.transaction.RecordingCommand;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.emf.transaction.util.TransactionUtil;
+
+import org.eclipse.sirius.common.tools.api.listener.Notification;
+import org.eclipse.sirius.common.tools.api.listener.NotificationUtil;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.business.api.dialect.command.RefreshRepresentationsCommand;
+import org.eclipse.sirius.business.api.query.IdentifiedElementQuery;
+import org.eclipse.sirius.business.internal.metamodel.helper.LayerHelper;
+import org.eclipse.sirius.description.Layer;
+
+/**
+ * Specific command to change layer activation.
+ *
+ * @author mporhel
+ */
+public final class ChangeLayerActivationCommand extends RecordingCommand {
+
+ private DDiagram dDiagram;
+
+ private Layer layer;
+
+ private IProgressMonitor monitor;
+
+ /**
+ * Default Constructor.
+ *
+ * @param domain
+ * the editing domain.
+ * @param dDiagram
+ * the {@link DDiagram} for which change the activated layers
+ * @param layer
+ * the {@link Layer} concerned by this change
+ * @deprecated use
+ * {@link ChangeLayerActivationCommand#ChangeLayerActivationCommand(TransactionalEditingDomain, DDiagram, Layer, IProgressMonitor)}
+ * instead
+ */
+ public ChangeLayerActivationCommand(TransactionalEditingDomain domain, DDiagram dDiagram, Layer layer) {
+ this(domain, dDiagram, layer, new NullProgressMonitor());
+ }
+
+ /**
+ * Default Constructor.
+ *
+ * @param domain
+ * the editing domain.
+ * @param dDiagram
+ * the {@link DDiagram} for which change the activated layers
+ * @param layer
+ * the {@link Layer} concerned by this change
+ * @param monitor
+ * a {@link IProgressMonitor} to show progression of layer
+ * activation changes
+ */
+ public ChangeLayerActivationCommand(TransactionalEditingDomain domain, DDiagram dDiagram, Layer layer, IProgressMonitor monitor) {
+ super(domain, dDiagram.getActivatedLayers().contains(layer) ? "Hide" : "Show" + " \"" + new IdentifiedElementQuery(layer).getLabel() + "\" layer");
+ this.dDiagram = dDiagram;
+ this.layer = layer;
+ this.monitor = monitor;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doExecute() {
+ try {
+ monitor.beginTask("Apply layer modifications...", 3);
+ boolean launchRefresh = !LayerHelper.containsOnlyTools(layer) || layer.getCustomization() != null;
+ if (!launchRefresh) {
+ NotificationUtil.sendNotification(dDiagram, Notification.Kind.START, Notification.VISIBILITY);
+ }
+ monitor.worked(1);
+ if (dDiagram.getActivatedLayers().contains(layer)) {
+ dDiagram.getActivatedLayers().remove(layer);
+ } else {
+ dDiagram.getActivatedLayers().add(layer);
+ }
+ monitor.worked(1);
+
+ if (launchRefresh) {
+ new RefreshRepresentationsCommand(TransactionUtil.getEditingDomain(dDiagram), new SubProgressMonitor(monitor, 1), dDiagram).execute();
+ } else {
+ NotificationUtil.sendNotification(dDiagram, Notification.Kind.STOP, Notification.VISIBILITY);
+ }
+ monitor.worked(1);
+ } finally {
+ monitor.done();
+ }
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+ dDiagram = null;
+ layer = null;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/DeactivateBehaviorToolsCommand.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/DeactivateBehaviorToolsCommand.java
new file mode 100644
index 0000000000..35eac07b1a
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/DeactivateBehaviorToolsCommand.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.commands;
+
+import java.util.Collection;
+
+import org.eclipse.emf.transaction.RecordingCommand;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.business.api.helper.concern.ConcernService;
+import org.eclipse.sirius.description.tool.BehaviorTool;
+
+/**
+ * Specific command to update activated behaviors.
+ *
+ * @author mporhel
+ */
+public final class DeactivateBehaviorToolsCommand extends RecordingCommand {
+
+ private final Collection<BehaviorTool> oldElements;
+
+ private final DDiagram diagram;
+
+ /**
+ * Constructor.
+ *
+ * @param domain
+ * the editing domain.
+ * @param oldElements
+ * elements to remove
+ * @param dDiagram
+ * the current diagram.
+ */
+ public DeactivateBehaviorToolsCommand(TransactionalEditingDomain domain, DDiagram dDiagram, Collection<BehaviorTool> oldElements) {
+ super(domain, "Deactivate behavior tools");
+ this.diagram = dDiagram;
+ this.oldElements = oldElements;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doExecute() {
+ if (diagram == null || oldElements == null) {
+ return;
+ }
+
+ for (BehaviorTool tool : oldElements) {
+ diagram.getActivateBehaviors().remove(tool);
+ }
+ ConcernService.resetCurrentConcern(diagram);
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/DeactivateFiltersCommand.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/DeactivateFiltersCommand.java
new file mode 100644
index 0000000000..ab1afa02da
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/DeactivateFiltersCommand.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.commands;
+
+import java.util.Collection;
+
+import org.eclipse.emf.transaction.RecordingCommand;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+
+import org.eclipse.sirius.common.tools.api.listener.NotificationUtil;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.business.api.helper.concern.ConcernService;
+import org.eclipse.sirius.description.filter.FilterDescription;
+
+/**
+ * Specific command to update activated filters.
+ *
+ * @author mporhel
+ */
+public final class DeactivateFiltersCommand extends RecordingCommand {
+
+ private final Collection<FilterDescription> oldElements;
+
+ private final DDiagram diagram;
+
+ /**
+ * Constructor.
+ *
+ * @param domain
+ * the editing domain.
+ * @param diagram
+ * the current diagram.
+ * @param oldElements
+ * elements to deactivate
+ */
+ public DeactivateFiltersCommand(TransactionalEditingDomain domain, DDiagram diagram, Collection<FilterDescription> oldElements) {
+ super(domain, "Deactivate filters");
+ this.oldElements = oldElements;
+ this.diagram = diagram;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doExecute() {
+ if (diagram == null || oldElements == null) {
+ return;
+ }
+
+ for (FilterDescription filter : oldElements) {
+ diagram.getActivatedFilters().remove(filter);
+ }
+
+ if (oldElements.size() > 0) {
+ ConcernService.resetCurrentConcern(diagram);
+ NotificationUtil.sendNotification(diagram, org.eclipse.sirius.common.tools.api.listener.Notification.Kind.START, org.eclipse.sirius.common.tools.api.listener.Notification.VISIBILITY_UPDATE);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/DeactivateRulesCommand.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/DeactivateRulesCommand.java
new file mode 100644
index 0000000000..06d7f6116e
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/DeactivateRulesCommand.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.commands;
+
+import java.util.Collection;
+
+import org.eclipse.emf.transaction.RecordingCommand;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.description.validation.ValidationRule;
+
+/**
+ * Specific command to update activated rules.
+ *
+ * @author mporhel
+ */
+public final class DeactivateRulesCommand extends RecordingCommand {
+
+ private final Collection<ValidationRule> oldElements;
+
+ private final DDiagram diagram;
+
+ /**
+ * Constructor.
+ *
+ * @param domain
+ * the editing domain.
+ * @param diagram
+ * the current diagram.
+ * @param oldElements
+ * elements to deactivate
+ */
+ public DeactivateRulesCommand(TransactionalEditingDomain domain, DDiagram diagram, Collection<ValidationRule> oldElements) {
+ super(domain, "Dectivate validation rules");
+ this.oldElements = oldElements;
+ this.diagram = diagram;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doExecute() {
+ if (diagram == null || oldElements == null) {
+ return;
+ }
+
+ for (ValidationRule rule : oldElements) {
+ diagram.getActivatedRules().remove(rule);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/EdgeRoutingStyleChangedCommand.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/EdgeRoutingStyleChangedCommand.java
new file mode 100644
index 0000000000..9a493cad82
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/EdgeRoutingStyleChangedCommand.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.commands;
+
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.transaction.RecordingCommand;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+
+import org.eclipse.sirius.diagram.edit.api.part.IDiagramEdgeEditPart;
+
+/**
+ * Specific command to update the routing style of an edge edit part.
+ *
+ * @author mporhel
+ */
+public final class EdgeRoutingStyleChangedCommand extends RecordingCommand {
+
+ private final IDiagramEdgeEditPart editpart;
+
+ private final Notification msg;
+
+ /**
+ * Constructor.
+ *
+ * @param domain
+ * the editing domain.
+ * @param msg
+ * the notification
+ * @param editpart
+ * the edge edit part to update.
+ */
+ public EdgeRoutingStyleChangedCommand(TransactionalEditingDomain domain, IDiagramEdgeEditPart editpart, Notification msg) {
+ super(domain, "Change routing style");
+ this.editpart = editpart;
+ this.msg = msg;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doExecute() {
+ if (editpart == null || msg == null) {
+ return;
+ }
+
+ editpart.routingStyleChanged(msg);
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/FindElementCommand.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/FindElementCommand.java
new file mode 100644
index 0000000000..d49c3ecd3c
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/FindElementCommand.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2011 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.commands;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.ui.IObjectActionDelegate;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+import org.eclipse.sirius.diagram.ui.tools.api.action.FindElementAction;
+
+/**
+ * A command to find an element.
+ *
+ * @author mchauvin
+ */
+public class FindElementCommand extends AbstractHandler {
+
+ private IObjectActionDelegate action;
+
+ /**
+ * Construct a new instance.
+ */
+ public FindElementCommand() {
+ action = new FindElementAction();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+ */
+ public Object execute(final ExecutionEvent event) throws ExecutionException {
+ action.selectionChanged(null, HandlerUtil.getCurrentSelection(event));
+ action.run(null);
+ return null;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/InitializeHiddenElementsCommand.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/InitializeHiddenElementsCommand.java
new file mode 100644
index 0000000000..d645af1ac6
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/InitializeHiddenElementsCommand.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.commands;
+
+import java.util.List;
+
+import org.eclipse.emf.transaction.RecordingCommand;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DDiagramElement;
+
+/**
+ * Specific command to add hidden elements to transient reference
+ * hiddenElements.
+ *
+ * @author mporhel
+ */
+public final class InitializeHiddenElementsCommand extends RecordingCommand {
+
+ private final DDiagram dDiagram;
+
+ private final List<DDiagramElement> hiddenElements;
+
+ /**
+ * Constructor.
+ *
+ * @param domain
+ * the editing domain.
+ * @param hiddenElements
+ * the hiddens elements
+ * @param dDiagram
+ * the DDiagram to update.
+ */
+ public InitializeHiddenElementsCommand(TransactionalEditingDomain domain, DDiagram dDiagram, List<DDiagramElement> hiddenElements) {
+ super(domain, "Initialize hidden elements");
+ this.dDiagram = dDiagram;
+ this.hiddenElements = hiddenElements;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doExecute() {
+ if (dDiagram == null || hiddenElements == null || hiddenElements.isEmpty()) {
+ return;
+ }
+
+ dDiagram.getHiddenElements().addAll(hiddenElements);
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/SemanticChangedCommand.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/SemanticChangedCommand.java
new file mode 100644
index 0000000000..2d883f047b
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/SemanticChangedCommand.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.commands;
+
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.transaction.RecordingCommand;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+
+import org.eclipse.sirius.diagram.edit.api.part.IDiagramElementEditPart;
+import org.eclipse.sirius.diagram.edit.internal.part.DiagramElementEditPartOperation;
+
+/**
+ * Specific command to update the edit part when semantic changed.
+ *
+ * @author mporhel
+ */
+public final class SemanticChangedCommand extends RecordingCommand {
+
+ private final IDiagramElementEditPart part;
+
+ private final Notification msg;
+
+ /**
+ * Constructor.
+ *
+ * @param domain
+ * the editing domain.
+ * @param msg
+ * the notification
+ * @param editpart
+ * the diagram element edit part to update.
+ */
+ public SemanticChangedCommand(TransactionalEditingDomain domain, IDiagramElementEditPart editpart, Notification msg) {
+ super(domain, "Semantic changed");
+ this.part = editpart;
+ this.msg = msg;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doExecute() {
+ if (part != null && msg != null) {
+ DiagramElementEditPartOperation.semanticChanged(part, msg);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/SetCurrentConcernCommand.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/SetCurrentConcernCommand.java
new file mode 100644
index 0000000000..aee79db5bb
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/SetCurrentConcernCommand.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.commands;
+
+import java.util.Iterator;
+import java.util.Map;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.transaction.RecordingCommand;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+
+import org.eclipse.sirius.common.tools.api.listener.NotificationUtil;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DSemanticDiagram;
+import org.eclipse.sirius.SiriusFactory;
+import org.eclipse.sirius.business.api.helper.concern.ConcernService;
+import org.eclipse.sirius.description.concern.ConcernDescription;
+import org.eclipse.sirius.description.filter.CompositeFilterDescription;
+import org.eclipse.sirius.description.filter.FilterDescription;
+import org.eclipse.sirius.description.filter.VariableFilter;
+import org.eclipse.sirius.diagram.tools.internal.filter.FilterTools;
+
+/**
+ * Specific command to set the current concern.
+ *
+ * @author mporhel
+ */
+public class SetCurrentConcernCommand extends RecordingCommand {
+
+ private final ConcernDescription desc;
+
+ private final DDiagram diagram;
+
+ /**
+ * Constructor.
+ *
+ * @param domain
+ * the editing domain
+ * @param diagram
+ * the current diagram
+ * @param desc
+ * the requested concern description
+ */
+ public SetCurrentConcernCommand(final TransactionalEditingDomain domain, DDiagram diagram, final ConcernDescription desc) {
+ super(domain, "Set current concern");
+ this.diagram = diagram;
+ this.desc = desc;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean canUndo() {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doExecute() {
+ if (diagram == null || desc == null) {
+ return;
+ }
+
+ NotificationUtil.sendNotification(diagram, org.eclipse.sirius.common.tools.api.listener.Notification.Kind.START, org.eclipse.sirius.common.tools.api.listener.Notification.VISIBILITY_UPDATE);
+
+ final ConcernDescription previousConcern = diagram.getCurrentConcern();
+ if (diagram.getFilterVariableHistory() == null) {
+ diagram.setFilterVariableHistory(SiriusFactory.eINSTANCE.createFilterVariableHistory());
+ }
+ try {
+ final Iterator<FilterDescription> itFilter = desc.getFilters().iterator();
+ while (itFilter.hasNext()) {
+ final FilterDescription fil = itFilter.next();
+ if (fil instanceof CompositeFilterDescription) {
+ final Iterator<?> it2 = ((CompositeFilterDescription) fil).getFilters().iterator();
+ while (it2.hasNext()) {
+ final Object objFilter = it2.next();
+ /*
+ * If we have a variable filter we need to open the
+ * dialog and set the different variables..
+ */
+ if (objFilter instanceof VariableFilter && diagram instanceof DSemanticDiagram) {
+ final VariableFilter filter = (VariableFilter) objFilter;
+ Map<String, EObject> variables;
+ variables = FilterTools.askForFilterValues((DSemanticDiagram) diagram, filter);
+ filter.setFilterContext(variables);
+ }
+ }
+ }
+ }
+ ConcernService.setCurrentConcern(diagram, desc);
+ } catch (final InterruptedException e) {
+ ConcernService.setCurrentConcern(diagram, previousConcern);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/SetDefaultConcernCommand.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/SetDefaultConcernCommand.java
new file mode 100644
index 0000000000..053182ea83
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/commands/SetDefaultConcernCommand.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.commands;
+
+import org.eclipse.emf.transaction.RecordingCommand;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+
+import org.eclipse.sirius.common.tools.api.listener.NotificationUtil;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.business.api.helper.concern.ConcernService;
+
+/**
+ * Specific command to set current concern to default.
+ *
+ * @author mporhel
+ */
+public final class SetDefaultConcernCommand extends RecordingCommand {
+
+ private final DDiagram diag;
+
+ /**
+ * Constructor.
+ *
+ * @param domain
+ * the editing domain.
+ * @param diagram
+ * the current diagram.
+ */
+ public SetDefaultConcernCommand(TransactionalEditingDomain domain, DDiagram diagram) {
+ super(domain, "Set current concern to default");
+ this.diag = diagram;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doExecute() {
+ if (diag == null) {
+ return;
+ }
+
+ if (diag.getDescription() != null && diag.getDescription().getDefaultConcern() != null) {
+ ConcernService.setCurrentConcern(diag, diag.getDescription().getDefaultConcern());
+ } else {
+ ConcernService.setCurrentConcern(diag, null);
+ }
+
+ NotificationUtil.sendNotification(diag, org.eclipse.sirius.common.tools.api.listener.Notification.Kind.START, org.eclipse.sirius.common.tools.api.listener.Notification.VISIBILITY_UPDATE);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean canUndo() {
+ /* we should not be able to undo this */
+ return false;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/dialogs/ColorPalettePopup.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/dialogs/ColorPalettePopup.java
new file mode 100644
index 0000000000..742a37126d
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/dialogs/ColorPalettePopup.java
@@ -0,0 +1,385 @@
+/******************************************************************************
+ * Copyright (c) 2005, 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ ****************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.dialogs;
+
+import java.util.HashMap;
+import java.util.Iterator;
+
+import org.eclipse.gmf.runtime.common.ui.util.WindowUtil;
+import org.eclipse.gmf.runtime.diagram.ui.properties.internal.l10n.DiagramUIPropertiesMessages;
+import org.eclipse.gmf.runtime.draw2d.ui.figures.FigureUtilities;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Device;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.PaletteData;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.ColorDialog;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * Copy of gmf code.
+ */
+public class ColorPalettePopup {
+
+ /** variable to store previous color */
+ private int previousColor;
+
+ private Button customColorButton;
+
+ private HashMap buttonMap = new HashMap();
+
+ /**
+ * A descirptor for an inventory color
+ */
+ private static class InventoryColorDescriptor extends ImageDescriptor {
+
+ /** the default preference color */
+ private static final RGB OUTLINE_COLOR = new RGB(192, 192, 192);
+
+ private RGB rgb;
+
+ public InventoryColorDescriptor(RGB colorValue) {
+ this.rgb = colorValue;
+
+ }
+
+ /**
+ * @see org.eclipse.jface.resource.ImageDescriptor#getImageData()
+ */
+ @Override
+ public ImageData getImageData() {
+ ImageData data = new ImageData(ICON_SIZE.x, ICON_SIZE.y, 1, new PaletteData(new RGB[] { rgb, OUTLINE_COLOR }));
+
+ for (int i = 0; i < ICON_SIZE.y; i++) {
+ data.setPixel(0, i, 1);
+ }
+ for (int i = 0; i < ICON_SIZE.y; i++) {
+ data.setPixel(ICON_SIZE.x - 1, i, 1);
+ }
+ for (int i = 0; i < ICON_SIZE.x; i++) {
+ data.setPixel(i, 0, 1);
+ }
+ for (int i = 0; i < ICON_SIZE.x; i++) {
+ data.setPixel(i, ICON_SIZE.y - 1, 1);
+ }
+ return data;
+ }
+
+ /**
+ * Creates and returns a new SWT image for this image descriptor. The
+ * returned image must be explicitly disposed using the image's dispose
+ * call. The image will not be automatically garbage collected. In the
+ * even of an error, a default image is returned if
+ * <code>returnMissingImageOnError</code> is true, otherwise
+ * <code>null</code> is returned.
+ * <p>
+ * Note: Even if <code>returnMissingImageOnError</code> is true, it is
+ * still possible for this method to return <code>null</code> in extreme
+ * cases, for example if SWT runs out of image handles.
+ * </p>
+ *
+ * @return a new image or <code>null</code> if the image could not be
+ * created
+ *
+ */
+ // CHECKSTYLE:OFF
+ @Override
+ public Image createImage() {
+
+ Device device = Display.getCurrent();
+ ImageData data = getImageData();
+ if (data == null) {
+ data = DEFAULT_IMAGE_DATA;
+ }
+
+ /*
+ * Try to create the supplied image. If there is an SWT Exception
+ * try and create the default image if that was requested. Return
+ * null if this fails.
+ */
+
+ try {
+ if (data.transparentPixel >= 0) {
+ ImageData maskData = data.getTransparencyMask();
+ return new Image(device, data, maskData);
+ }
+ return new Image(device, data);
+ } catch (SWTException exception) {
+
+ try {
+ return new Image(device, DEFAULT_IMAGE_DATA);
+ } catch (SWTException nextException) {
+ return null;
+ }
+
+ }
+ }
+ }
+
+ /** inventory colors. */
+ private static final InventoryColorDescriptor WHITE = new InventoryColorDescriptor(new RGB(255, 255, 255));
+
+ private static final InventoryColorDescriptor BLACK = new InventoryColorDescriptor(new RGB(0, 0, 0));
+
+ private static final InventoryColorDescriptor LIGHT_GRAY = new InventoryColorDescriptor(new RGB(192, 192, 192));
+
+ private static final InventoryColorDescriptor GRAY = new InventoryColorDescriptor(new RGB(128, 128, 128));
+
+ private static final InventoryColorDescriptor RED = new InventoryColorDescriptor(new RGB(227, 164, 156));
+
+ private static final InventoryColorDescriptor GREEN = new InventoryColorDescriptor(new RGB(166, 193, 152));
+
+ private static final InventoryColorDescriptor BLUE = new InventoryColorDescriptor(new RGB(152, 168, 191));
+
+ private static final InventoryColorDescriptor YELLOW = new InventoryColorDescriptor(new RGB(225, 225, 135));
+
+ private static final InventoryColorDescriptor PURPLE = new InventoryColorDescriptor(new RGB(184, 151, 192));
+
+ private static final InventoryColorDescriptor TEAL = new InventoryColorDescriptor(new RGB(155, 199, 204));
+
+ private static final InventoryColorDescriptor PINK = new InventoryColorDescriptor(new RGB(228, 179, 229));
+
+ private static final InventoryColorDescriptor ORANGE = new InventoryColorDescriptor(new RGB(237, 201, 122));
+
+ /** the inventory color list key: anRGB, value: anImage */
+ private static final HashMap imageColorMap = new HashMap();
+
+ private static final String CUSTOM_COLOR_STRING = DiagramUIPropertiesMessages.ColorPalettePopup_custom;
+
+ /** default color icon width. */
+ public static final Point ICON_SIZE = new Point(20, 20);
+
+ // CHECKSTYLE:ON
+
+ static {
+
+ // inventory colors
+ imageColorMap.put(WHITE.rgb, WHITE.createImage());
+ imageColorMap.put(BLACK.rgb, BLACK.createImage());
+ imageColorMap.put(LIGHT_GRAY.rgb, LIGHT_GRAY.createImage());
+ imageColorMap.put(GRAY.rgb, GRAY.createImage());
+ imageColorMap.put(RED.rgb, RED.createImage());
+ imageColorMap.put(GREEN.rgb, GREEN.createImage());
+ imageColorMap.put(BLUE.rgb, BLUE.createImage());
+ imageColorMap.put(YELLOW.rgb, YELLOW.createImage());
+ imageColorMap.put(PURPLE.rgb, PURPLE.createImage());
+ imageColorMap.put(TEAL.rgb, TEAL.createImage());
+ imageColorMap.put(PINK.rgb, PINK.createImage());
+ imageColorMap.put(ORANGE.rgb, ORANGE.createImage());
+ }
+
+ private Shell shell;
+
+ private RGB selectedColor;
+
+ /**
+ * The default color to be used if the user presses the default button.
+ */
+ private boolean useDefaultColor;
+
+ /**
+ * Creates a color palette popup above the specified shell.
+ *
+ * @param parent
+ * a Shell control which will be the parent of the new instance
+ * (cannot be null)
+ * @param preferenceId
+ * the preference id
+ * @param rowHeight
+ * the row height
+ * @deprecated Use the other constructor. This one does not retrieve the
+ * default value from the correct preference store.
+ */
+ @Deprecated
+ public ColorPalettePopup(Shell parent, String preferenceId, int rowHeight) {
+ this(parent, rowHeight);
+ }
+
+ /**
+ * Creates a PopupList above the specified shell.
+ *
+ * @param parent
+ * a widget which will be the parent of the new instance (cannot
+ * be null)
+ * @param rowHeight
+ * the row height
+ */
+ public ColorPalettePopup(Shell parent, int rowHeight) {
+ shell = new Shell(parent, ColorPalettePopup.checkStyle(SWT.NONE));
+ GridLayout layout = new GridLayout(4, true);
+ layout.horizontalSpacing = 0;
+ layout.marginWidth = 0;
+ layout.marginHeight = 0;
+ layout.verticalSpacing = 0;
+ shell.setLayout(layout);
+
+ // CHECKSTYLE:OFF
+ for (Iterator e = imageColorMap.keySet().iterator(); e.hasNext();) {
+ // CHECKSTYLE:ON
+ Button button = new Button(shell, SWT.PUSH);
+ GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+ data.heightHint = rowHeight;
+ data.widthHint = rowHeight;
+ button.setLayoutData(data);
+
+ final RGB rgb = (RGB) e.next();
+ final Image image = (Image) imageColorMap.get(rgb);
+ button.setImage(image);
+ button.addSelectionListener(new SelectionAdapter() {
+
+ @Override
+ public void widgetSelected(SelectionEvent e1) {
+ selectedColor = rgb;
+ shell.dispose();
+ }
+ });
+ buttonMap.put(rgb, button);
+ }
+ // Button defaultButton = new Button(shell, SWT.PUSH);
+ // defaultButton.setText(DEAFULT_COLOR_STRING);
+ // GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+ // data.horizontalSpan = 4;
+ // data.heightHint = rowHeight;
+ // defaultButton.setLayoutData(data);
+ //
+ // defaultButton.addSelectionListener(new SelectionAdapter() {
+ //
+ // public void widgetSelected(SelectionEvent event) {
+ // useDefaultColor = true;
+ // shell.dispose();
+ // }
+ // });
+
+ Button moreColors = new Button(shell, SWT.PUSH);
+ moreColors.setText(CUSTOM_COLOR_STRING);
+ GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+ data.horizontalSpan = 4;
+ data.heightHint = rowHeight;
+ moreColors.setLayoutData(data);
+
+ moreColors.addSelectionListener(new SelectionAdapter() {
+
+ @Override
+ public void widgetSelected(SelectionEvent event) {
+
+ ColorDialog dialog = new ColorDialog(Display.getCurrent().getActiveShell());
+ dialog.setRGB(FigureUtilities.integerToRGB(getPreviousColor()));
+ WindowUtil.centerDialog(dialog.getParent(), Display.getCurrent().getActiveShell());
+ dialog.open();
+ selectedColor = dialog.getRGB();
+ shell.dispose();
+
+ }
+ });
+ // close dialog if user selects outside of the shell
+ shell.addListener(SWT.Deactivate, new Listener() {
+
+ public void handleEvent(Event e) {
+ shell.setVisible(false);
+ }
+ });
+ customColorButton = moreColors;
+
+ }
+
+ /**
+ * @param style
+ * @return
+ */
+ private static int checkStyle(int style) {
+ int mask = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
+ return style & mask;
+ }
+
+ /**
+ * Launches the Popup List, waits for an item to be selected and then closes
+ * PopupList.
+ *
+ * @param location
+ * the initial size and location of the PopupList; the dialog
+ * will be positioned so that it does not run off the screen and
+ * the largest number of items are visible
+ *
+ * @return the text of the selected item or null if no item is selected
+ */
+ public RGB open(Point location) {
+
+ Point listSize = shell.computeSize(SWT.DEFAULT, SWT.DEFAULT, false);
+ shell.setBounds(location.x, location.y, listSize.x, listSize.y);
+
+ shell.open();
+ shell.setFocus();
+ Display display = shell.getDisplay();
+ Button prevButton = (Button) buttonMap.get(FigureUtilities.integerToRGB(getPreviousColor()));
+ if (prevButton != null) {
+ shell.setDefaultButton(prevButton);
+ } else {
+ shell.setDefaultButton(customColorButton);
+ }
+ while (!shell.isDisposed() && shell.isVisible()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ return getSelectedColor();
+ }
+
+ /**
+ * Gets the color the user selected. Could be null as the user may have
+ * cancelled the gesture or they may have selected the default color button.
+ * See {@link #useDefaultColor()}.
+ *
+ * @return the selected color or null
+ */
+ public RGB getSelectedColor() {
+ return selectedColor;
+ }
+
+ /**
+ * Returns true if the user selected to use the default color.
+ *
+ * @return true if the default color is to be used; false otherwise
+ */
+ public boolean useDefaultColor() {
+ return useDefaultColor;
+ }
+
+ /**
+ * Returns the previous color.
+ *
+ * @return the previous color.
+ */
+ public int getPreviousColor() {
+ return previousColor;
+ }
+
+ /**
+ * Sets the previous color.
+ *
+ * @param previousColor
+ * the previous color.
+ */
+ public void setPreviousColor(int previousColor) {
+ this.previousColor = previousColor;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/dialogs/DiagramElementsSelectionDialog.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/dialogs/DiagramElementsSelectionDialog.java
new file mode 100644
index 0000000000..6102f9b1ff
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/dialogs/DiagramElementsSelectionDialog.java
@@ -0,0 +1,893 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.dialogs;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.ecore.provider.EcoreItemProviderAdapterFactory;
+import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
+import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory;
+import org.eclipse.emf.edit.provider.resource.ResourceItemProviderAdapterFactory;
+import org.eclipse.jface.viewers.CheckStateChangedEvent;
+import org.eclipse.jface.viewers.ICheckStateListener;
+import org.eclipse.jface.viewers.ICheckStateProvider;
+import org.eclipse.jface.viewers.IColorProvider;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.jface.window.Window;
+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.events.SelectionListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.dialogs.CheckedTreeSelectionDialog;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Iterators;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.common.tools.api.util.Options;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.diagram.ImagesPath;
+import org.eclipse.sirius.diagram.part.SiriusDiagramEditorPlugin;
+import org.eclipse.sirius.diagram.tools.internal.providers.FilteredTreeContentProvider;
+import org.eclipse.sirius.diagram.ui.tools.internal.views.providers.outline.OutlineLabelProvider;
+import org.eclipse.sirius.provider.SiriusItemProviderAdapterFactory;
+import org.eclipse.sirius.ui.business.api.provider.AbstractDDiagramElementLabelItemProvider;
+import org.eclipse.sirius.ui.tools.api.color.VisualBindingManager;
+
+/**
+ * A dialog box which allows the user to edit a boolean property/flag of a
+ * sub-set of the elements in a diagram. The dialog presents all the elements in
+ * the diagram and indicates their state (selected or not). The user can edit
+ * this state individually for each element. When the operation is validated by
+ * the user (by closing the dialog with the OK button) the specified editing
+ * operations are applied to the elements whose state has been changed (i.e.
+ * they have been selected or deselected).
+ * <p>
+ * What the notion of "selected" means can be customized through 3
+ * programmer-specified functions:
+ * <ul>
+ * <li>a predicate to detect whether an element is selected or not (e.g.
+ * "the element is hidden")</li>
+ * <li>an action to apply to an element to make it selected (e.g.
+ * "set the element as hidden")</li>
+ * <li>an action to apply to an element to make it deselected (e.g.
+ * "set the element as not-hidden/reveal the element")</li>
+ * </ul>
+ *
+ * @author pcdavid
+ */
+public class DiagramElementsSelectionDialog {
+
+ private static final Function<Object, Void> DO_NOTHING = new Function<Object, Void>() {
+ public Void apply(Object from) {
+ return null;
+ };
+ };
+
+ /**
+ * The internal dialog used by this dialog.
+ */
+ protected CustomTreeSelectionDialog dialog;
+
+ /**
+ * The diagram associated to this dialog.
+ */
+ protected DDiagram diagram;
+
+ /**
+ * The filtering mode currently associated to the tree viewer. Can be :
+ * <ul>
+ * <li>All elements</li>
+ * <li>Only checked elements</li>
+ * <li>Only unchecked elements</li>
+ * </ul>
+ */
+ protected FilteringMode mode = FilteringMode.SHOW_ALL;
+
+ private final String title;
+
+ private final String message;
+
+ private Predicate<Object> isSelected = Predicates.alwaysTrue();
+
+ // Grayed elements will not be selectable.
+ private Predicate<Object> isGrayed = Predicates.alwaysFalse();
+
+ private Function<Object, Void> selectedAction = DO_NOTHING;
+
+ private Function<Object, Void> deselectedAction = DO_NOTHING;
+
+ private FilteredTreeContentProvider contentProvider;
+
+ /**
+ * A customized version of CheckedTreeSelectionDialog with a combo to filter
+ * the view to show all elements/only checked elements/only unchecked
+ * elements.
+ *
+ * @author pcdavid
+ */
+ protected final class CustomTreeSelectionDialog extends CheckedTreeSelectionDialog {
+
+ /**
+ * A String used to identify the Text allowing user to type regular
+ * expression (can be used for testing).
+ */
+ public static final String REGEXP_TOOL_TIP = "Expression that will be used to filer elements by name (for example 'abc', 'a?c', '*c'...)";
+
+ /**
+ * The title of the Group allowing user to type Regular Expressions and
+ * filter the selection.
+ */
+ private static final String REGEXP_TITLE = "Filter elements by name";
+
+ /**
+ * The String explaining to user how to use regular expressions.
+ */
+ private static final String REGEXP_EXPLANATIONS = "? = any character, * = any String";
+
+ /**
+ * A matcher used to determine if a given DDiagramElement is matching
+ * the regular expression typed by user. It's updated each time the user
+ * modify the regular expression.
+ */
+ protected DiagramElementsSelectionDialogPatternMatcher patternMatcher;
+
+ /**
+ * Collection of elements currently checked by user.
+ */
+ private final Set<Object> checkedElements = Sets.newHashSet();
+
+ private CustomTreeSelectionDialog(Shell parent, ILabelProvider labelProvider, ITreeContentProvider contentProvider) {
+ super(parent, labelProvider, contentProvider);
+ patternMatcher = new DiagramElementsSelectionDialogPatternMatcher("");
+ }
+
+ @Override
+ public void setInitialSelections(Object[] selectedElements) {
+ setInitialElementSelections(Lists.newArrayList(selectedElements));
+ }
+
+ @Override
+ public void setInitialElementSelections(List selectedElements) {
+ List<Object> filteredSeletection = Lists.newArrayList(Iterables.filter(selectedElements, Predicates.not(isGrayed)));
+ checkedElements.addAll(filteredSeletection);
+ super.setInitialElementSelections(filteredSeletection);
+ }
+
+ /**
+ * Returns the elements currently checked by user.
+ *
+ * @return the elements currently checked by user
+ */
+ public Set<Object> getCheckedElements() {
+ return checkedElements;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.dialogs.Dialog#createContents(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ protected Control createContents(Composite parent) {
+ Control result = super.createContents(parent);
+ getTreeViewer().setCheckStateProvider(new ICheckStateProvider() {
+
+ public boolean isGrayed(Object element) {
+ return isGrayed.apply(element);
+ }
+
+ public boolean isChecked(Object element) {
+ return checkedElements.contains(element);
+ }
+ });
+ getTreeViewer().addCheckStateListener(new ICheckStateListener() {
+ public void checkStateChanged(CheckStateChangedEvent event) {
+ if (!isGrayed.apply(event.getElement())) {
+ if (event.getChecked()) {
+ checkedElements.add(event.getElement());
+ } else {
+ checkedElements.remove(event.getElement());
+ }
+ }
+ }
+ });
+ return result;
+ }
+
+ /**
+ * This method has been overridden to be able to insert selection
+ * buttons between the top label and the tree viewer.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ protected Label createMessageArea(Composite composite) {
+ Label createMessageArea = super.createMessageArea(composite);
+
+ createSelectionButtonsAfterMessageArea(composite);
+
+ // creating a text zone to allow user to type regular expressions
+ createRegexpTypeZone(composite);
+ return createMessageArea;
+ }
+
+ /**
+ * This method has been overridden to remove the selection buttons that
+ * are generically created after the tree viewer. This method should not
+ * return a null value. Otherwise, in case of empty list we will have a
+ * NPE.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ protected Composite createSelectionButtons(Composite composite) {
+ Composite buttonComposite = new Composite(composite, SWT.RIGHT) {
+ /**
+ * This method has been overridden to have an "empty" size for
+ * this composite. {@inheritDoc}
+ *
+ * @see org.eclipse.swt.widgets.Composite#computeSize(int, int,
+ * boolean)
+ */
+ @Override
+ public Point computeSize(int wHint, int hHint, boolean b) {
+ return super.computeSize(0, 0, b);
+ }
+ };
+ buttonComposite.setVisible(false);
+ return buttonComposite;
+ }
+
+ /**
+ * Creates selection buttons.
+ *
+ * @param composite
+ * the parent composite
+ * @return the selection buttons composite
+ */
+ protected Composite createSelectionButtonsAfterMessageArea(Composite composite) {
+ Composite buttonComposite = new Composite(composite, SWT.RIGHT);
+ GridLayout layout = new GridLayout();
+ layout.numColumns = 7;
+ layout.makeColumnsEqualWidth = false;
+ buttonComposite.setLayout(layout);
+ buttonComposite.setFont(composite.getFont());
+
+ GridData data = new GridData(GridData.HORIZONTAL_ALIGN_END | GridData.GRAB_HORIZONTAL);
+ data.grabExcessHorizontalSpace = true;
+ composite.setData(data);
+
+ new Label(buttonComposite, SWT.LEAD).setText("Show");
+ final Combo choices = new Combo(buttonComposite, SWT.READ_ONLY);
+ choices.add(FilteringMode.SHOW_ALL.getName());
+ choices.add(FilteringMode.SHOW_ONLY_CHECKED_ELEMENTS.getName());
+ choices.add(FilteringMode.SHOW_ONLY_UNCHECKED_ELEMENTS.getName());
+ choices.select(0);
+ choices.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ switch (choices.getSelectionIndex()) {
+ case 0:
+ updateFilteringMode(FilteringMode.SHOW_ALL);
+ break;
+ case 1:
+ updateFilteringMode(FilteringMode.SHOW_ONLY_CHECKED_ELEMENTS);
+ break;
+ case 2:
+ updateFilteringMode(FilteringMode.SHOW_ONLY_UNCHECKED_ELEMENTS);
+ break;
+ default:
+ throw new RuntimeException();
+ }
+ }
+ });
+ data = new GridData(GridData.HORIZONTAL_ALIGN_END | GridData.GRAB_HORIZONTAL);
+ data.grabExcessHorizontalSpace = true;
+ data.horizontalSpan = 2;
+ choices.setLayoutData(data);
+
+ data = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL);
+ data.grabExcessHorizontalSpace = true;
+ addButton(buttonComposite, "Check All", SiriusDiagramEditorPlugin.getInstance().getBundledImage(ImagesPath.CHECK_ALL_ICON), new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ checkAll();
+ if (choices.getSelectionIndex() == 1) {
+ updateFilteringMode(FilteringMode.SHOW_ONLY_CHECKED_ELEMENTS);
+ } else if (choices.getSelectionIndex() == 2) {
+ updateFilteringMode(FilteringMode.SHOW_ONLY_UNCHECKED_ELEMENTS);
+ }
+ }
+ }).setLayoutData(data);
+
+ addButton(buttonComposite, "Uncheck All", SiriusDiagramEditorPlugin.getInstance().getBundledImage(ImagesPath.UNCHECK_ALL_ICON), new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ uncheckAll();
+ if (choices.getSelectionIndex() == 1) {
+ updateFilteringMode(FilteringMode.SHOW_ONLY_CHECKED_ELEMENTS);
+ } else if (choices.getSelectionIndex() == 2) {
+ updateFilteringMode(FilteringMode.SHOW_ONLY_UNCHECKED_ELEMENTS);
+ }
+ }
+ }).setLayoutData(data);
+
+ addButton(buttonComposite, "Expand All", SiriusDiagramEditorPlugin.getInstance().getBundledImage(ImagesPath.EXPAND_ALL_ICON), new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ expandAll();
+ }
+ }).setLayoutData(data);
+
+ addButton(buttonComposite, "Collapse All", SiriusDiagramEditorPlugin.getInstance().getBundledImage(ImagesPath.COLLAPSE_ALL_ICON), new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ collapseAll();
+ }
+ }).setLayoutData(data);
+
+ return buttonComposite;
+ }
+
+ /**
+ * Creates a zone in which user will be able to type a Regular
+ * Expression to filter the shown elements.
+ *
+ * @param composite
+ * the parent composite
+ */
+ private void createRegexpTypeZone(Composite composite) {
+ // Step 1 : create Group
+ Group expregGroup = new Group(composite, SWT.NONE);
+ expregGroup.setText(REGEXP_TITLE);
+ GridLayout expregLayout = new GridLayout();
+ expregGroup.setLayout(expregLayout);
+ expregGroup.setFont(composite.getFont());
+ expregGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ // Step 2 : create explanations zone
+ final Label explanationsLabel = new Label(expregGroup, SWT.NONE);
+ explanationsLabel.setText(REGEXP_EXPLANATIONS);
+
+ // Step 3 : create the text zone in which user will type the expreg
+ final Text regularExpressionText = new Text(expregGroup, SWT.BORDER);
+ regularExpressionText.setToolTipText(REGEXP_TOOL_TIP);
+ regularExpressionText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ // Step 4 : add modify listener to this textZone
+ regularExpressionText.addModifyListener(new ModifyListener() {
+
+ public void modifyText(ModifyEvent e) {
+ String typedRegex = ((Text) e.getSource()).getText();
+ // Each time the regular expression is modified, the
+ // patternMatcher is updated
+ setPatternMatcher(new DiagramElementsSelectionDialogPatternMatcher(typedRegex));
+ updateFilteringMode(mode);
+ }
+ });
+ }
+
+ /**
+ * Sets the matcher used to determine if a given DDiagramElement is
+ * matching the regular expression typed by user.
+ *
+ * @param patternMatcher
+ * the patternMatcher to set
+ */
+ public void setPatternMatcher(DiagramElementsSelectionDialogPatternMatcher patternMatcher) {
+ this.patternMatcher = patternMatcher;
+ }
+
+ private Button addButton(Composite parent, String toolTipText, Image image, SelectionListener action) {
+ Button button = new Button(parent, SWT.PUSH);
+ button.setToolTipText(toolTipText);
+ button.setImage(image);
+ button.addSelectionListener(action);
+ return button;
+ }
+
+ private void checkAll() {
+ Object root = getTreeViewer().getInput();
+ setRecursiveState(root, true);
+ }
+
+ private void uncheckAll() {
+ Object root = getTreeViewer().getInput();
+ setRecursiveState(root, false);
+ }
+
+ private void setRecursiveState(Object element, boolean state) {
+ getTreeViewer().setChecked(element, state);
+ if (!isGrayed.apply(element)) {
+ if (state) {
+ checkedElements.add(element);
+ } else {
+ checkedElements.remove(element);
+ }
+ }
+ for (Object child : contentProvider.getChildren(element)) {
+ setRecursiveState(child, state);
+ }
+ }
+
+ private void expandAll() {
+ getTreeViewer().expandAll();
+ }
+
+ private void collapseAll() {
+ getTreeViewer().collapseAll();
+ }
+
+ /**
+ * Updates the treeViewer after a change in the filteringMode or the
+ * typed regular expression.
+ *
+ * @param filteringMode
+ * the new filtering mode
+ */
+ public void updateFilteringMode(FilteringMode filteringMode) {
+ mode = filteringMode;
+ this.refresh();
+ // We expand the tree so that all elements matching the regular
+ // expression (i.e. all visible leafs) are correctly shown
+ getTreeViewer().expandAll();
+ getTreeViewer().setAllChecked(false);
+ for (Object element : checkedElements) {
+ getTreeViewer().setChecked(element, true);
+ }
+ }
+
+ /**
+ * Indicates if the given element is checked <b>AND</b> is matching the
+ * currently typed regular expression.
+ *
+ * @param element
+ * the element to test
+ * @return true if the given element is checked <b>AND</b> is matching
+ * the currently typed regular expression, false otherwise.
+ */
+ public boolean isMatchingExpregOrHasMatchingExpregDescendantsCheckedMode(Object element) {
+ Predicate<Object> isCheckedElementPredicate = Predicates.in(checkedElements);
+ Predicate<Object> isMatchinExpregPredicate = getRegexpMatchPredicate();
+ return isOrHasDescendant(element, Predicates.and(isCheckedElementPredicate, isMatchinExpregPredicate));
+ }
+
+ /**
+ * Indicates if the given element is unchecked <b>AND</b> is matching
+ * the currently typed regular expression.
+ *
+ * @param element
+ * the element to test
+ * @return true if the given element is unchecked <b>AND</b> is matching
+ * the currently typed regular expression, false otherwise.
+ */
+ public boolean isMatchingExpregOrHasMatchingExpregDescendantsUncheckedMode(Object element) {
+ Predicate<Object> isUncheckedElementPredicate = Predicates.not(Predicates.in(checkedElements));
+ Predicate<Object> isMatchinExpregPredicate = getRegexpMatchPredicate();
+ return isOrHasDescendant(element, Predicates.and(isUncheckedElementPredicate, isMatchinExpregPredicate));
+ }
+
+ /**
+ * Indicates if the given element is matching the currently typed
+ * regular expression.
+ *
+ * @param element
+ * the element to test
+ * @return true if the given element is matching the currently typed
+ * regular expression, false otherwise.
+ */
+ public boolean isMatchingExpregOrHasMatchingExpregDescendantsAllMode(Object element) {
+ return isOrHasDescendant(element, getRegexpMatchPredicate());
+ }
+
+ /**
+ * Indicates if the given element or at least one of its children checks
+ * the given predicate.
+ *
+ * @param element
+ * the element to check
+ * @param pred
+ * the predicate to sue
+ * @return true if the given element or at least one of its children
+ * checks the given predicate, false otherwise
+ */
+ public boolean isOrHasDescendant(Object element, final Predicate<Object> pred) {
+ boolean matches = pred.apply(element);
+ if (matches) {
+ return true;
+ } else {
+ return Iterables.any(Arrays.asList(contentProvider.getChildren(element)), new Predicate<Object>() {
+ public boolean apply(Object input) {
+ return isOrHasDescendant(input, pred);
+ }
+ });
+ }
+ }
+
+ /**
+ * Refreshes this dialog's viewer.
+ */
+ public void refresh() {
+ getTreeViewer().refresh();
+ }
+
+ /**
+ * Returns a Predicate indicating if an object is matching the Regular
+ * Expression currently typed by user.
+ *
+ * @return a Predicate indicating if an object is matching the Regular
+ * Expression currently typed by user
+ */
+ public Predicate<Object> getRegexpMatchPredicate() {
+ return patternMatcher.getMatchPredicate();
+ }
+ }
+
+ /**
+ * Represents the various kinds of filtering supported by the tree viewer.
+ *
+ * @author pcdavid
+ */
+ protected enum FilteringMode {
+ /**
+ * Filtering mode in which all elements are considered.
+ */
+ SHOW_ALL("all elements"),
+ /**
+ * Filtering mode in which only checked elements are considered.
+ */
+ SHOW_ONLY_CHECKED_ELEMENTS("only checked elements"),
+ /**
+ * Filtering mode in which only unchecked elements are considered.
+ */
+ SHOW_ONLY_UNCHECKED_ELEMENTS("only unchecked elements");
+
+ private final String name;
+
+ private FilteringMode(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param title
+ * the title of the dialog window.
+ * @param message
+ * the message for the dialog.
+ */
+ public DiagramElementsSelectionDialog(String title, String message) {
+ this.title = title;
+ this.message = message;
+ }
+
+ /**
+ * Sets the predicate to use to detect which elements of the diagram are
+ * selected, in the sense of the criterion to be edited.
+ *
+ * @param isSelectedPredicate
+ * the predicate to used to detect selected elements of the
+ * diagram.
+ */
+ public void setSelectionPredicate(Predicate<Object> isSelectedPredicate) {
+ this.isSelected = isSelectedPredicate;
+ }
+
+ /**
+ * Sets the predicate to use to detect which elements of the diagram are
+ * selected, in the sense of the criterion to be edited.
+ *
+ * @param isGrayedPredicate
+ * the predicate to used to detect selected elements of the
+ * diagram.
+ */
+ public void setGrayedPredicate(Predicate<Object> isGrayedPredicate) {
+ this.isGrayed = isGrayedPredicate != null ? isGrayedPredicate : Predicates.alwaysFalse();
+ }
+
+ /**
+ * @param parent
+ * @return
+ */
+ private Set<Object> getAllChildren(Object parent) {
+ Set<Object> result = new HashSet<Object>();
+ Object[] children = contentProvider.getChildren(parent);
+ for (Object element : children) {
+ result.add(element);
+ result.addAll(getAllChildren(element));
+ }
+ return result;
+ }
+
+ /**
+ * Sets the operation to be applied on elements which are newly selected by
+ * the user.
+ *
+ * @param selectedAction
+ * the operation to apply to newly selected elements.
+ */
+ public void setSelectedAction(Function<Object, Void> selectedAction) {
+ this.selectedAction = selectedAction;
+ }
+
+ /**
+ * Sets the operation to be applied on elements which are deselected by the
+ * user.
+ *
+ * @param deselectedAction
+ * the operation to apply to deselected elements.
+ */
+ public void setDeselectedAction(Function<Object, Void> deselectedAction) {
+ this.deselectedAction = deselectedAction;
+ }
+
+ /**
+ * Asks the end-user for a list of elements to select/de-select, and applies
+ * the corresponding changes.
+ *
+ * @param parent
+ * the shell to use to interact with the user, if required.
+ * @param ddiagram
+ * the diagram whose elements to edit.
+ * @param includeNodeLabel
+ * include node label (if there are on border) in the tree
+ * content
+ * @return <code>true</code> if the operation was correctly executed,
+ * <code>false</code> if it was canceled by the user.
+ */
+ public boolean open(Shell parent, DDiagram ddiagram, boolean includeNodeLabel) {
+ boolean result = false;
+ diagram = ddiagram;
+
+ initContentProvider(includeNodeLabel);
+
+ Set<Object> allSelectedElements = Collections.unmodifiableSet(getAllSelectedElements());
+ Option<Set<Object>> response = askUserForNewSelection(parent, allSelectedElements);
+ if (response.some()) {
+ Set<Object> selectedAfter = response.get();
+ applyRequestedChanges(allSelectedElements, selectedAfter);
+ assert selectedAfter.equals(allSelectedElements);
+ result = true;
+ }
+ diagram = null;
+ dialog = null;
+ contentProvider = null;
+ return result;
+ }
+
+ /**
+ * Init the content provider.
+ *
+ * @param includeNodeLabel
+ * include node label (if there are on border) in the tree
+ * content
+ */
+ protected void initContentProvider(boolean includeNodeLabel) {
+ AdapterFactory adapterFactory = getAdapterFactory();
+ Predicate<Object> predicate = Predicates.instanceOf(DDiagramElement.class);
+ if (includeNodeLabel) {
+ predicate = Predicates.or(predicate, Predicates.instanceOf(AbstractDDiagramElementLabelItemProvider.class));
+ }
+ contentProvider = new FilteredTreeContentProvider(adapterFactory, predicate);
+ }
+
+ /**
+ * Return all selected elements of the diagram that are display in the tree.
+ *
+ * @return All selected elements of the diagram that are display in the
+ * tree.
+ */
+ protected Set<Object> getAllSelectedElements() {
+ Set<Object> treeElements = getAllChildren(diagram);
+ return Sets.newHashSet(Iterators.filter(treeElements.iterator(), Predicates.and(isSelected, Predicates.not(isGrayed))));
+ }
+
+ /**
+ * Asks the user to edit the set of elements which should be selected/match
+ * the criterion being edited.
+ *
+ * @param parent
+ * the parent shell to use if user interaction requires opening
+ * new windows.
+ * @param initialSelection
+ * the set of elements to display as checked on dialog opening.
+ * @return the new set of all the elements in the diagram which were
+ * selected by the user, or <code>Options.newNone()</code> if the
+ * user canceled the operation.
+ */
+ protected Option<Set<Object>> askUserForNewSelection(Shell parent, Set<Object> initialSelection) {
+ setupDialog(parent, initialSelection);
+ int result = dialog.open();
+ if (result == Window.OK) {
+ Set<Object> selectedAfter = getElementsSelectedAfter();
+ return Options.newSome(selectedAfter);
+ } else {
+ return Options.newNone();
+ }
+ }
+
+ /**
+ * Create an configure a selection dialog which allows the user to select a
+ * sub-set of the elements in the diagram.
+ *
+ * @param parent
+ * the parent shell.
+ * @param initialSelection
+ * the set of elements to display as checked on dialog opening.
+ */
+ protected void setupDialog(Shell parent, Set<Object> initialSelection) {
+ dialog = new CustomTreeSelectionDialog(parent, new SelectionDialogLabelProvider(), contentProvider);
+ dialog.setTitle(title);
+
+ String msg = message;
+ if (!Predicates.alwaysFalse().equals(isGrayed)) {
+ StringBuilder sb = new StringBuilder(message);
+ sb.append("\n");
+ sb.append("The wizard will have no effect on grayed elements.");
+ msg = sb.toString();
+ }
+ dialog.setMessage(msg);
+ dialog.setInput(diagram);
+ dialog.addFilter(new ModeFilter());
+ dialog.setInitialElementSelections(Lists.newArrayList(initialSelection));
+ }
+
+ /**
+ * Returns the elements selected when the dialog is about to close.
+ *
+ * @return the elements selected when the dialog is about to close
+ */
+ protected Set<Object> getElementsSelectedAfter() {
+ Set<Object> selectedElements = Sets.newHashSet();
+ for (Object obj : dialog.checkedElements) {
+ if (obj instanceof DDiagramElement) {
+ selectedElements.add(obj);
+ } else if (obj instanceof AbstractDDiagramElementLabelItemProvider) {
+ selectedElements.add(obj);
+ }
+ }
+ return selectedElements;
+ }
+
+ /**
+ * Updates the status of the elements according to the user request.
+ *
+ * @param selectedBefore
+ * all (and only) the elements in the diagram which were actually
+ * pinned before the action.
+ * @param selectedAfter
+ * all (and only) the elements in the diagram which should be
+ * pinned as requested by the user.
+ */
+ protected void applyRequestedChanges(Set<Object> selectedBefore, Set<Object> selectedAfter) {
+ for (Object dde : Sets.difference(selectedBefore, selectedAfter)) {
+ deselectedAction.apply(dde);
+ }
+ for (Object dde : Sets.difference(selectedAfter, selectedBefore)) {
+ selectedAction.apply(dde);
+ }
+ }
+
+ /**
+ * Returns the adapter factory used by this viewer.
+ *
+ * @return The adapter factory used by this viewer.
+ */
+ private AdapterFactory getAdapterFactory() {
+ List<AdapterFactory> factories = new ArrayList<AdapterFactory>();
+ factories.add(new SiriusItemProviderAdapterFactory());
+ factories.add(new ResourceItemProviderAdapterFactory());
+ factories.add(new EcoreItemProviderAdapterFactory());
+ factories.add(new ReflectiveItemProviderAdapterFactory());
+ return new ComposedAdapterFactory(factories);
+ }
+
+ private class ModeFilter extends ViewerFilter {
+
+ @Override
+ public boolean select(Viewer viewer, Object parentElement, Object element) {
+ boolean show = true;
+ // Step 1: only showing check/unchecked element if required
+ switch (mode) {
+ case SHOW_ALL:
+ show = dialog.isMatchingExpregOrHasMatchingExpregDescendantsAllMode(element);
+ break;
+ case SHOW_ONLY_CHECKED_ELEMENTS:
+ show = dialog.isMatchingExpregOrHasMatchingExpregDescendantsCheckedMode(element);
+ break;
+ case SHOW_ONLY_UNCHECKED_ELEMENTS:
+ show = dialog.isMatchingExpregOrHasMatchingExpregDescendantsUncheckedMode(element);
+ break;
+ default:
+ show = true;
+ break;
+ }
+
+ // Step 2: only showing elements which target has not been
+ // deleted
+ boolean isNonDangling = true;
+ if (show) {
+ DDiagramElement underlyingDDiagramElement = null;
+ if (element instanceof DDiagramElement) {
+ underlyingDDiagramElement = (DDiagramElement) element;
+ } else if (element instanceof AbstractDDiagramElementLabelItemProvider && ((AbstractDDiagramElementLabelItemProvider) element).getDiagramElementTarget().some()) {
+ underlyingDDiagramElement = ((AbstractDDiagramElementLabelItemProvider) element).getDiagramElementTarget().get();
+ }
+
+ if (underlyingDDiagramElement != null && underlyingDDiagramElement.eResource() != null) {
+ isNonDangling = underlyingDDiagramElement.getTarget() != null && underlyingDDiagramElement.getTarget().eResource() != null;
+ } else {
+ isNonDangling = false;
+ }
+ }
+ return show && isNonDangling;
+ }
+ }
+
+ private class SelectionDialogLabelProvider extends OutlineLabelProvider implements IColorProvider {
+
+ /**
+ * {@inheritDoc}
+ */
+ public Color getForeground(final Object element) {
+
+ Color foreground = null;
+ if (isGrayed.apply(element)) {
+ foreground = VisualBindingManager.getDefault().getColorFromName("light_gray"); //$NON-NLS-1$
+ }
+ return foreground;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Color getBackground(Object element) {
+ return null;
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/dialogs/DiagramElementsSelectionDialogPatternMatcher.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/dialogs/DiagramElementsSelectionDialogPatternMatcher.java
new file mode 100644
index 0000000000..d384a28368
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/dialogs/DiagramElementsSelectionDialogPatternMatcher.java
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.dialogs;
+
+import org.eclipse.gmf.runtime.common.core.util.StringMatcher;
+
+import com.google.common.base.Predicate;
+
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.ui.business.api.provider.AbstractDDiagramElementLabelItemProvider;
+
+/**
+ * <p>
+ * A {@link StringMatcher} used to detect elements that match a regular
+ * expression.
+ * </p>
+ *
+ * This Matcher creates a MatchPredicate, that can be used to determine if a
+ * given Object matches a regular expression.
+ *
+ * @author <a href="mailto:alex.lagarde@obeo.fr">Alex Lagarde</a>
+ */
+public class DiagramElementsSelectionDialogPatternMatcher {
+
+ private Predicate<Object> matchPredicate;
+
+ private StringMatcher stringMatcher;
+
+ /**
+ * Creates a new PatternMatcher.
+ *
+ *
+ * @param expreg
+ * the regular expression (for example '?a?' or 'abc' or '*c') ;
+ * <code>null</code> or empty regular expression will be replaced
+ * by '*'
+ *
+ */
+ public DiagramElementsSelectionDialogPatternMatcher(String expreg) {
+ String computedExpreg = expreg;
+ if (expreg == null) {
+ computedExpreg = "";
+ }
+ // If the regular expression ends with a space, we have to use the exact
+ // value of the given expreg
+ if (computedExpreg.endsWith(" ")) {
+ computedExpreg = computedExpreg.substring(0, computedExpreg.lastIndexOf(' '));
+ } else {
+ // Otherwise, we add a star to make 'XYZ' recognized by the 'X'
+ // expreg (as in quick outline for example)
+ computedExpreg = computedExpreg + "*";
+ }
+ this.stringMatcher = new StringMatcher(computedExpreg, true, false);
+
+ }
+
+ /**
+ * Creates a {@link Predicate} that can be applied on any Object. This
+ * predicates will return true if the tested element is a
+ * {@link DDiagramElement} and that its name is matching the regular
+ * expression used to construct this Matcher.
+ *
+ * @return a {@link Predicate} that can be applied on any Object to
+ * determine if whether it's matching the regular expression used to
+ * construct this Matcher
+ */
+ public Predicate<Object> getMatchPredicate() {
+ if (matchPredicate == null) {
+ matchPredicate = new Predicate<Object>() {
+
+ public boolean apply(Object input) {
+ String elementName = null;
+ if (input instanceof DDiagramElement) {
+ DDiagramElement element = (DDiagramElement) input;
+ elementName = element.getName();
+ } else if (input instanceof AbstractDDiagramElementLabelItemProvider) {
+ AbstractDDiagramElementLabelItemProvider element = (AbstractDDiagramElementLabelItemProvider) input;
+ elementName = element.getText(element.getTarget());
+ }
+ return elementName != null && stringMatcher.match(elementName);
+ }
+ };
+ }
+ return matchPredicate;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/dialogs/ExtendedFeatureEditorDialog.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/dialogs/ExtendedFeatureEditorDialog.java
new file mode 100644
index 0000000000..eaae9367d8
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/dialogs/ExtendedFeatureEditorDialog.java
@@ -0,0 +1,535 @@
+/**
+ * <copyright>
+ *
+ * Copyright (c) 2002-2008 IBM Corporation 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
+ * Obeo - Adapt for extension
+ *
+ * </copyright>
+ *
+ * $Id: FeatureEditorDialog.java,v 1.11 2007/03/23 17:36:45 marcelop Exp $
+ */
+
+package org.eclipse.sirius.diagram.ui.tools.internal.dialogs;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.common.notify.impl.AdapterFactoryImpl;
+import org.eclipse.emf.common.util.BasicEList;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
+import org.eclipse.emf.edit.provider.IItemLabelProvider;
+import org.eclipse.emf.edit.provider.ItemProvider;
+import org.eclipse.emf.edit.ui.EMFEditUIPlugin;
+import org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider;
+import org.eclipse.emf.edit.ui.provider.ExtendedImageRegistry;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IContentProvider;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.Text;
+
+import org.eclipse.sirius.common.tools.api.util.StringUtil;
+import org.eclipse.sirius.SiriusPlugin;
+import org.eclipse.sirius.diagram.part.SiriusDiagramEditorPlugin;
+import org.eclipse.sirius.ecore.extender.business.api.accessor.ExtensionFeatureDescription;
+import org.eclipse.sirius.ecore.extender.business.api.accessor.ModelAccessor;
+
+/**
+ * Dialog to edit an extended reference.
+ *
+ * @author ymortier
+ */
+public class ExtendedFeatureEditorDialog extends Dialog {
+
+ /** the list of choosen elements. */
+ protected EList<EObject> result;
+
+ /** The list of choices. */
+ private List<EObject> choices;
+
+ /** The current values of the reference. */
+ private List<EObject> referenceValues;
+
+ /** The reference to edit. */
+ private ExtensionFeatureDescription extReference;
+
+ private boolean multiLine;
+
+ private ItemProvider values;
+
+ private IContentProvider contentProvider;
+
+ private ILabelProvider labelProvider;
+
+ /**
+ * Creates a new <code>ExtendedFeatureEditorDialog</code>. see
+ * {@link org.eclipse.emf.edit.ui.celleditor.FeatureEditorDialog}.
+ *
+ * @param parent
+ * the parent.
+ * @param choices
+ * the choices.
+ * @param referenceValues
+ * the reference values.
+ * @param extReference
+ * the ext reference.
+ */
+ public ExtendedFeatureEditorDialog(final Shell parent, final List<EObject> choices, final List<EObject> referenceValues, final ExtensionFeatureDescription extReference) {
+ super(parent);
+ this.choices = choices;
+ this.referenceValues = referenceValues;
+ this.extReference = extReference;
+ final List<AdapterFactory> adapterFactories = Collections.emptyList();
+ final AdapterFactory adapterFactory = new ComposedAdapterFactory(adapterFactories);
+ values = new ItemProvider(adapterFactory, this.referenceValues);
+ contentProvider = new AdapterFactoryContentProvider(adapterFactory);
+ this.choices.removeAll(this.referenceValues);
+ this.labelProvider = new LabelProvider() {
+ @Override
+ public String getText(final Object element) {
+ if (element instanceof EObject) {
+ final ModelAccessor accessor = SiriusPlugin.getDefault().getModelAccessorRegistry().getModelAccessor((EObject) element);
+ return accessor.getQualifiedName((EObject) element, true);
+ }
+ return String.valueOf(element);
+ }
+
+ @Override
+ public Image getImage(final Object element) {
+ ImageDescriptor descriptor = null;
+ if (element instanceof EObject) {
+ final EObject target = (EObject) element;
+ final IItemLabelProvider myLabelProvider = (IItemLabelProvider) SiriusDiagramEditorPlugin.getInstance().getItemProvidersAdapterFactory().adapt(target, IItemLabelProvider.class);
+ descriptor = ExtendedImageRegistry.getInstance().getImageDescriptor(myLabelProvider.getImage(target));
+
+ }
+ if (descriptor == null) {
+ descriptor = ImageDescriptor.getMissingImageDescriptor();
+ }
+ return SiriusDiagramEditorPlugin.getInstance().getImage(descriptor);
+ }
+
+ };
+
+ }
+
+ /**
+ * Creates the dialog.
+ *
+ * This code is cut/paste from the
+ * {@link org.eclipse.emf.edit.ui.celleditor.FeatureEditorDialog} class.
+ *
+ * @param parent
+ * the parent.
+ * @return the control.
+ */
+ @Override
+ protected Control createDialogArea(final Composite parent) {
+ final Composite contents = (Composite) super.createDialogArea(parent);
+
+ final GridLayout contentsGridLayout = (GridLayout) contents.getLayout();
+ contentsGridLayout.numColumns = 3;
+
+ final GridData contentsGridData = (GridData) contents.getLayoutData();
+ contentsGridData.horizontalAlignment = SWT.FILL;
+ contentsGridData.verticalAlignment = SWT.FILL;
+
+ final Composite choiceComposite = createChoiceComposite(contents);
+
+ final Table choiceTable = this.choices == null ? null : new Table(choiceComposite, SWT.MULTI | SWT.BORDER);
+ if (choiceTable != null) {
+ final GridData choiceTableGridData = new GridData();
+ choiceTableGridData.widthHint = Display.getCurrent().getBounds().width / 5;
+ choiceTableGridData.heightHint = Display.getCurrent().getBounds().height / 3;
+ choiceTableGridData.verticalAlignment = SWT.FILL;
+ choiceTableGridData.horizontalAlignment = SWT.FILL;
+ choiceTableGridData.grabExcessHorizontalSpace = true;
+ choiceTableGridData.grabExcessVerticalSpace = true;
+ choiceTable.setLayoutData(choiceTableGridData);
+ }
+
+ final TableViewer choiceTableViewer = this.choices == null ? null : new TableViewer(choiceTable);
+ if (choiceTableViewer != null) {
+ choiceTableViewer.setContentProvider(new AdapterFactoryContentProvider(new AdapterFactoryImpl()));
+ choiceTableViewer.setLabelProvider(labelProvider);
+ choiceTableViewer.setInput(new ItemProvider(this.choices));
+ }
+
+ // We use multi even for a single line because we want to respond to the
+ // enter key.
+ //
+
+ int style = multiLine ? SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL : SWT.MULTI;
+ style = style | SWT.BORDER;
+
+ final Text choiceText = createChoiceText(choiceComposite, style);
+
+ final Composite controlButtons = createControlButtonsArea(contents);
+
+ new Label(controlButtons, SWT.NONE);
+
+ final Button addButton = createAddButton(controlButtons);
+
+ final Button removeButton = createRemoveButton(controlButtons);
+
+ final Label spaceLabel = new Label(controlButtons, SWT.NONE);
+ final GridData spaceLabelGridData = new GridData();
+ spaceLabelGridData.verticalSpan = 2;
+ spaceLabel.setLayoutData(spaceLabelGridData);
+
+ final Button upButton = createUpButton(controlButtons);
+
+ final Button downButton = createDownButton(controlButtons);
+
+ final Composite featureComposite = createFeatureComposite(contents);
+
+ final Table featureTable = new Table(featureComposite, SWT.MULTI | SWT.BORDER);
+ final GridData featureTableGridData = new GridData();
+ featureTableGridData.widthHint = Display.getCurrent().getBounds().width / 5;
+ featureTableGridData.heightHint = Display.getCurrent().getBounds().height / 3;
+ featureTableGridData.verticalAlignment = SWT.FILL;
+ featureTableGridData.horizontalAlignment = SWT.FILL;
+ featureTableGridData.grabExcessHorizontalSpace = true;
+ featureTableGridData.grabExcessVerticalSpace = true;
+ featureTable.setLayoutData(featureTableGridData);
+
+ final TableViewer featureTableViewer = new TableViewer(featureTable);
+ featureTableViewer.setContentProvider(contentProvider);
+ featureTableViewer.setLabelProvider(labelProvider);
+ featureTableViewer.setInput(values);
+ if (!values.getChildren().isEmpty()) {
+ featureTableViewer.setSelection(new StructuredSelection(values.getChildren().get(0)));
+ }
+ setTableViewerListener(choiceTableViewer, featureTableViewer, addButton, removeButton);
+
+ setUpButtonListener(upButton, featureTableViewer);
+ setDownButtonListener(downButton, featureTableViewer);
+
+ setAddButtonListener(addButton, choiceTableViewer, featureTableViewer, choiceText);
+ setRemoveButtonListener(removeButton, choiceTableViewer, featureTableViewer, choiceText);
+
+ return contents;
+ }
+
+ private Text createChoiceText(final Composite parent, final int style) {
+ final Text choiceText = this.choices == null ? new Text(parent, style) : null;
+ if (choiceText != null) {
+ final GridData choiceTextGridData = new GridData();
+ choiceTextGridData.widthHint = Display.getCurrent().getBounds().width / 5;
+ choiceTextGridData.verticalAlignment = SWT.BEGINNING;
+ choiceTextGridData.horizontalAlignment = SWT.FILL;
+ choiceTextGridData.grabExcessHorizontalSpace = true;
+ if (multiLine) {
+ choiceTextGridData.verticalAlignment = SWT.FILL;
+ choiceTextGridData.grabExcessVerticalSpace = true;
+ }
+ choiceText.setLayoutData(choiceTextGridData);
+ }
+
+ if (choiceText != null) {
+ choiceText.addKeyListener(new KeyAdapter() {
+ @Override
+ public void keyPressed(final KeyEvent event) {
+ if (!multiLine && (event.character == '\r' || event.character == '\n')) {
+
+ // Object value =
+ // EcoreUtil.createFromString((EDataType)
+ // eClassifier, choiceText.getText());
+ // values.getChildren().add(value);
+ // choiceText.setText(StringUtil.EMPTY_STRING);
+ // featureTableViewer.setSelection(new
+ // StructuredSelection(value));
+ // event.doit = false;
+
+ } else if (event.character == '\33') {
+ choiceText.setText(StringUtil.EMPTY_STRING);
+ event.doit = false;
+ }
+ }
+ });
+ }
+ return choiceText;
+ }
+
+ private Composite createChoiceComposite(final Composite contents) {
+ final Composite choiceComposite = new Composite(contents, SWT.NONE);
+
+ final GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
+ data.horizontalAlignment = SWT.END;
+ choiceComposite.setLayoutData(data);
+
+ final GridLayout layout = new GridLayout();
+ data.horizontalAlignment = SWT.FILL;
+ layout.marginHeight = 0;
+ layout.marginWidth = 0;
+ layout.numColumns = 1;
+ choiceComposite.setLayout(layout);
+
+ final Label choiceLabel = new Label(choiceComposite, SWT.NONE);
+ choiceLabel.setText(this.choices == null ? EMFEditUIPlugin.INSTANCE.getString("_UI_Value_label") : EMFEditUIPlugin.INSTANCE.getString("_UI_Choices_label"));
+ final GridData choiceLabelGridData = new GridData();
+ choiceLabelGridData.verticalAlignment = SWT.FILL;
+ choiceLabelGridData.horizontalAlignment = SWT.FILL;
+ choiceLabel.setLayoutData(choiceLabelGridData);
+
+ return choiceComposite;
+ }
+
+ private Composite createFeatureComposite(final Composite contents) {
+ final Composite featureComposite = new Composite(contents, SWT.NONE);
+
+ final GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
+ data.horizontalAlignment = SWT.END;
+ featureComposite.setLayoutData(data);
+
+ final GridLayout layout = new GridLayout();
+ data.horizontalAlignment = SWT.FILL;
+ layout.marginHeight = 0;
+ layout.marginWidth = 0;
+ layout.numColumns = 1;
+ featureComposite.setLayout(layout);
+
+ final Label featureLabel = new Label(featureComposite, SWT.NONE);
+ featureLabel.setText(this.extReference.getName());
+ final GridData featureLabelGridData = new GridData();
+ featureLabelGridData.horizontalSpan = 2;
+ featureLabelGridData.horizontalAlignment = SWT.FILL;
+ featureLabelGridData.verticalAlignment = SWT.FILL;
+ featureLabel.setLayoutData(featureLabelGridData);
+
+ return featureComposite;
+ }
+
+ private Composite createControlButtonsArea(final Composite parent) {
+ final Composite controlButtons = new Composite(parent, SWT.NONE);
+ final GridData controlButtonsGridData = new GridData();
+ controlButtonsGridData.verticalAlignment = SWT.FILL;
+ controlButtonsGridData.horizontalAlignment = SWT.FILL;
+ controlButtons.setLayoutData(controlButtonsGridData);
+
+ final GridLayout controlsButtonGridLayout = new GridLayout();
+ controlButtons.setLayout(controlsButtonGridLayout);
+ return controlButtons;
+ }
+
+ private Button createAddButton(final Composite controlButtons) {
+ final Button addButton = new Button(controlButtons, SWT.PUSH);
+ addButton.setText(EMFEditUIPlugin.INSTANCE.getString("_UI_Add_label"));
+ final GridData addButtonGridData = new GridData();
+ addButtonGridData.verticalAlignment = SWT.FILL;
+ addButtonGridData.horizontalAlignment = SWT.FILL;
+ addButton.setLayoutData(addButtonGridData);
+ return addButton;
+ }
+
+ private Button createRemoveButton(final Composite controlButtons) {
+ final Button removeButton = new Button(controlButtons, SWT.PUSH);
+ removeButton.setText(EMFEditUIPlugin.INSTANCE.getString("_UI_Remove_label"));
+ final GridData removeButtonGridData = new GridData();
+ removeButtonGridData.verticalAlignment = SWT.FILL;
+ removeButtonGridData.horizontalAlignment = SWT.FILL;
+ removeButton.setLayoutData(removeButtonGridData);
+ return removeButton;
+ }
+
+ private Button createUpButton(final Composite controlButtons) {
+ final Button upButton = new Button(controlButtons, SWT.PUSH);
+ upButton.setText(EMFEditUIPlugin.INSTANCE.getString("_UI_Up_label"));
+ final GridData upButtonGridData = new GridData();
+ upButtonGridData.verticalAlignment = SWT.FILL;
+ upButtonGridData.horizontalAlignment = SWT.FILL;
+ upButton.setLayoutData(upButtonGridData);
+ return upButton;
+ }
+
+ private Button createDownButton(final Composite controlButtons) {
+ final Button downButton = new Button(controlButtons, SWT.PUSH);
+ downButton.setText(EMFEditUIPlugin.INSTANCE.getString("_UI_Down_label"));
+ final GridData downButtonGridData = new GridData();
+ downButtonGridData.verticalAlignment = SWT.FILL;
+ downButtonGridData.horizontalAlignment = SWT.FILL;
+ downButton.setLayoutData(downButtonGridData);
+ return downButton;
+ }
+
+ private void setUpButtonListener(final Button upButton, final TableViewer featureTableViewer) {
+ upButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(final SelectionEvent event) {
+ final IStructuredSelection selection = (IStructuredSelection) featureTableViewer.getSelection();
+ int minIndex = 0;
+ final Iterator<?> i = selection.iterator();
+ while (i.hasNext()) {
+ final Object value = i.next();
+ final int index = values.getChildren().indexOf(value);
+ values.getChildren().move(Math.max(index - 1, minIndex++), value);
+ }
+ }
+ });
+ }
+
+ private void setDownButtonListener(final Button downButton, final TableViewer featureTableViewer) {
+ downButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(final SelectionEvent event) {
+ final IStructuredSelection selection = (IStructuredSelection) featureTableViewer.getSelection();
+ int maxIndex = values.getChildren().size() - selection.size();
+ final Iterator<?> i = selection.iterator();
+ while (i.hasNext()) {
+ final Object value = i.next();
+ final int index = values.getChildren().indexOf(value);
+ values.getChildren().move(Math.min(index + 1, maxIndex++), value);
+ }
+ }
+ });
+ }
+
+ private void setAddButtonListener(final Button addButton, final TableViewer choiceTableViewer, final TableViewer featureTableViewer, final Text choiceText) {
+ addButton.addSelectionListener(new SelectionAdapter() {
+ // event is null when choiceTableViewer is double clicked
+ @Override
+ public void widgetSelected(final SelectionEvent event) {
+ if (choiceTableViewer != null) {
+ final IStructuredSelection selection = (IStructuredSelection) choiceTableViewer.getSelection();
+ final Iterator<?> i = selection.iterator();
+ while (i.hasNext()) {
+ final Object value = i.next();
+ if (!values.getChildren().contains(value)) {
+ values.getChildren().add(value);
+ choiceTableViewer.remove(value);
+ }
+ }
+ featureTableViewer.setSelection(selection);
+ } else if (choiceText != null) {
+
+ // Object value = EcoreUtil.createFromString((EDataType)
+ // eClassifier, choiceText.getText());
+ // values.getChildren().add(value);
+ // choiceText.setText(StringUtil.EMPTY_STRING);
+ // featureTableViewer.setSelection(new
+ // StructuredSelection(value));
+
+ // Ignore
+
+ }
+ }
+ });
+ }
+
+ private void setRemoveButtonListener(final Button removeButton, final TableViewer choiceTableViewer, final TableViewer featureTableViewer, final Text choiceText) {
+ removeButton.addSelectionListener(new SelectionAdapter() {
+ // event is null when featureTableViewer is double clicked
+ @Override
+ public void widgetSelected(final SelectionEvent event) {
+ final IStructuredSelection selection = (IStructuredSelection) featureTableViewer.getSelection();
+ Object firstValue = null;
+ final Iterator<?> i = selection.iterator();
+ while (i.hasNext()) {
+ final Object value = i.next();
+ if (firstValue == null) {
+ firstValue = value;
+ }
+ values.getChildren().remove(value);
+ choiceTableViewer.add(value);
+ }
+
+ if (!values.getChildren().isEmpty()) {
+ featureTableViewer.setSelection(new StructuredSelection(values.getChildren().get(0)));
+ }
+
+ if (choiceTableViewer != null) {
+ choiceTableViewer.setSelection(selection);
+ } else if (choiceText != null) {
+ if (firstValue != null) {
+ // String value = EcoreUtil.convertToString((EDataType)
+ // eClassifier, firstValue);
+ // choiceText.setText(value);
+ }
+ }
+ }
+ });
+ }
+
+ private void setTableViewerListener(final TableViewer choiceTableViewer, final TableViewer featureTableViewer, final Button addButton, final Button removeButton) {
+ if (choiceTableViewer != null) {
+ choiceTableViewer.addDoubleClickListener(new IDoubleClickListener() {
+ public void doubleClick(final DoubleClickEvent event) {
+ if (addButton.isEnabled()) {
+ addButton.notifyListeners(SWT.Selection, null);
+ }
+ }
+ });
+
+ featureTableViewer.addDoubleClickListener(new IDoubleClickListener() {
+ public void doubleClick(final DoubleClickEvent event) {
+ if (removeButton.isEnabled()) {
+ removeButton.notifyListeners(SWT.Selection, null);
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.dialogs.Dialog#okPressed()
+ */
+ @Override
+ protected void okPressed() {
+ result = new BasicEList(values.getChildren());
+ super.okPressed();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.dialogs.Dialog#close()
+ */
+ @Override
+ public boolean close() {
+ contentProvider.dispose();
+ return super.close();
+ }
+
+ /**
+ * Returns the selected references.
+ *
+ * @return the selected references.
+ */
+ public EList<EObject> getResult() {
+ return result;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/dialogs/SelectDiagramElementBackgroundImageDialog.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/dialogs/SelectDiagramElementBackgroundImageDialog.java
new file mode 100644
index 0000000000..5df774906f
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/dialogs/SelectDiagramElementBackgroundImageDialog.java
@@ -0,0 +1,145 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.dialogs;
+
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.UpdateValueStrategy;
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.emf.databinding.EMFProperties;
+import org.eclipse.jface.databinding.swt.ISWTObservableValue;
+import org.eclipse.jface.databinding.swt.WidgetProperties;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.fieldassist.ControlDecoration;
+import org.eclipse.jface.fieldassist.FieldDecoration;
+import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+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.Shell;
+import org.eclipse.swt.widgets.Text;
+
+import org.eclipse.sirius.BasicLabelStyle;
+import org.eclipse.sirius.SiriusFactory;
+import org.eclipse.sirius.SiriusPackage;
+import org.eclipse.sirius.WorkspaceImage;
+
+/**
+ * Dialog to select an image from workspace.
+ *
+ * @author fmorel
+ */
+public class SelectDiagramElementBackgroundImageDialog extends Dialog {
+
+ private static final String DIALOG_TITLE = "Select background image from workspace";
+
+ private WorkspaceImage workspaceImageForWorkspace;
+
+ private Label workspacePathLabel;
+
+ private Text workspacePathText;
+
+ private Button browseButton;
+
+ /**
+ * Creates an instance of the copy to image dialog.
+ *
+ * @param shell
+ * the parent shell
+ * @param basicLabelStyle
+ * {@link BasicLabelStyle}
+ */
+ public SelectDiagramElementBackgroundImageDialog(Shell shell, BasicLabelStyle basicLabelStyle) {
+ super(shell);
+ this.workspaceImageForWorkspace = SiriusFactory.eINSTANCE.createWorkspaceImage();
+ if (basicLabelStyle instanceof WorkspaceImage) {
+ WorkspaceImage workspaceImage = (WorkspaceImage) basicLabelStyle;
+ workspaceImageForWorkspace.setWorkspacePath(workspaceImage.getWorkspacePath());
+ }
+ }
+
+ /**
+ * Creates and returns the contents of the upper part of this dialog (above
+ * the button bar). {@inheritDoc}
+ *
+ * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ protected Control createDialogArea(final Composite parent) {
+ Composite mainComposite = (Composite) super.createDialogArea(parent);
+
+ GridLayout gridLayout = new GridLayout();
+ gridLayout.numColumns = 1;
+ gridLayout.marginHeight = 5;
+ gridLayout.marginWidth = 5;
+ mainComposite.setLayout(gridLayout);
+ mainComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true));
+
+ createFromWorkspaceComposite(mainComposite);
+ return mainComposite;
+ }
+
+ private void createFromWorkspaceComposite(Composite mainComposite) {
+ Composite fromWorkspaceComposite = new Composite(mainComposite, SWT.NONE);
+
+ GridLayout gridLayout = new GridLayout();
+ gridLayout.numColumns = 3;
+ gridLayout.marginHeight = 0;
+ gridLayout.marginWidth = 0;
+ fromWorkspaceComposite.setLayout(gridLayout);
+ fromWorkspaceComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true));
+
+ workspacePathLabel = new Label(fromWorkspaceComposite, SWT.NONE);
+ workspacePathLabel.setText("Path:");
+
+ workspacePathText = new Text(fromWorkspaceComposite, SWT.FLAT | SWT.BORDER);
+ workspacePathText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ ControlDecoration controlDecoration = new ControlDecoration(workspacePathText, SWT.LEFT | SWT.TOP);
+ FieldDecoration fieldDecoration = FieldDecorationRegistry.getDefault().getFieldDecoration(FieldDecorationRegistry.DEC_ERROR);
+ controlDecoration.setImage(fieldDecoration.getImage());
+
+ ISWTObservableValue workspacePathTextObservable = WidgetProperties.text(SWT.Modify).observe(workspacePathText);
+ IObservableValue workspaceImageObservable = EMFProperties.value(SiriusPackage.Literals.WORKSPACE_IMAGE__WORKSPACE_PATH).observe(workspaceImageForWorkspace);
+ DataBindingContext ctx = new DataBindingContext();
+ WorkspacePathValidator workspacePathValidator = new WorkspacePathValidator(controlDecoration);
+ ctx.bindValue(workspacePathTextObservable, workspaceImageObservable, new UpdateValueStrategy().setAfterConvertValidator(workspacePathValidator), null);
+
+ browseButton = new Button(fromWorkspaceComposite, SWT.NONE);
+ browseButton.setText("Browse");
+ browseButton.addSelectionListener(new WorkspaceImagePathSelector(workspacePathText));
+ }
+
+ /**
+ * Configures the shell in preparation for opening this window in it.
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell)
+ */
+ @Override
+ protected void configureShell(final Shell shell) {
+ super.configureShell(shell);
+ shell.setText(DIALOG_TITLE);
+ shell.setMinimumSize(500, 100);
+ setShellStyle(getShellStyle() | SWT.RESIZE | SWT.MAX);
+ }
+
+ /**
+ * return the image path.
+ *
+ * @return The image path
+ */
+ public String getImagePath() {
+ return workspaceImageForWorkspace.getWorkspacePath();
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/dialogs/WorkspaceImagePathSelector.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/dialogs/WorkspaceImagePathSelector.java
new file mode 100644
index 0000000000..8f2b588e8a
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/dialogs/WorkspaceImagePathSelector.java
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * Copyright (c) 2012 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.dialogs;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.gmf.runtime.diagram.ui.image.ImageFileFormat;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PlatformUI;
+
+import com.google.common.collect.Lists;
+
+import org.eclipse.sirius.common.ui.tools.api.resource.WorkspaceResourceDialogWithFilter;
+
+/**
+ * A {@link SelectionAdapter} to select a image path in the workspace.
+ *
+ * @author <a href="mailto:esteban.dugueperoux@obeo.fr">Esteban Dugueperoux</a>
+ */
+public class WorkspaceImagePathSelector extends SelectionAdapter {
+
+ /** All supported image file extensions. */
+ private static final List<String> IMAGE_FILE_EXTENSIONS = new ArrayList<String>();
+
+ static {
+ for (ImageFileFormat imageFileFormat : ImageFileFormat.VALUES) {
+ IMAGE_FILE_EXTENSIONS.add(imageFileFormat.getName().toLowerCase());
+ }
+ }
+
+ private Text workspacePathText;
+
+ /**
+ * Default constructor.
+ *
+ * @param workspacePathText
+ * the {@link Text} field displaying the selected path
+ */
+ public WorkspaceImagePathSelector(Text workspacePathText) {
+ this.workspacePathText = workspacePathText;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void widgetSelected(SelectionEvent e) {
+ List<ViewerFilter> filters = Lists.newArrayList();
+ if (IMAGE_FILE_EXTENSIONS != null) {
+ filters.add(new FileExtensionFilter(IMAGE_FILE_EXTENSIONS));
+ }
+ IFile[] selectedResources = WorkspaceResourceDialogWithFilter.openFileSelection(PlatformUI.getWorkbench().getDisplay().getActiveShell(), "Background image", "Select the image file:", false,
+ null, filters);
+ if (selectedResources != null && selectedResources.length == 1) {
+ workspacePathText.setText(((IFile) selectedResources[0]).getFullPath().makeRelative().toString());
+ }
+ }
+
+ /**
+ * A filter based on file extension.
+ *
+ * @author lredor
+ */
+ private static class FileExtensionFilter extends ViewerFilter {
+ /**
+ * The list of extensions for which we want to keep file.
+ */
+ private List<String> extensions;
+
+ public FileExtensionFilter(List<String> extensions) {
+ this.extensions = extensions;
+ }
+
+ @Override
+ public boolean select(Viewer viewer, Object parentElement, Object element) {
+ boolean isValid = true;
+ if (element instanceof IFile) {
+ // In the case of a file, we'll check if its extension is one of
+ // the expected
+ IFile file = (IFile) element;
+ isValid = extensions.contains(file.getFileExtension().toLowerCase());
+ } else if (element instanceof IContainer) {
+ // In the case of a container, we'll probe its content to see if
+ // it contains a valid file
+ isValid = false;
+ IContainer container = (IContainer) element;
+ if (!container.isDerived()) {
+ try {
+ final IResource[] members = ((IContainer) container).members();
+ for (IResource member : members) {
+ isValid = select(viewer, parentElement, member);
+ if (isValid) {
+ // we found a valid resource in this folder, it
+ // is useless to probe any further
+ break;
+ }
+ }
+ } catch (final CoreException e) {
+ // This shouldn't happen
+ }
+ }
+ }
+ return isValid;
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/dialogs/WorkspacePathValidator.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/dialogs/WorkspacePathValidator.java
new file mode 100644
index 0000000000..cb847a408c
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/dialogs/WorkspacePathValidator.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2012 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.dialogs;
+
+import java.io.File;
+
+import org.eclipse.core.databinding.validation.IValidator;
+import org.eclipse.core.databinding.validation.ValidationStatus;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.fieldassist.ControlDecoration;
+
+import org.eclipse.sirius.common.tools.api.resource.FileProvider;
+
+/**
+ * A {@link IValidator} to validate the workspace path entered in the text
+ * field.
+ *
+ * @author <a href="mailto:esteban.dugueperoux@obeo.fr">Esteban Dugueperoux</a>
+ */
+public class WorkspacePathValidator implements IValidator {
+
+ private ControlDecoration controlDecoration;
+
+ /**
+ * Default constructor.
+ *
+ * @param controlDecoration
+ * the {@link ControlDecoration}
+ */
+ public WorkspacePathValidator(ControlDecoration controlDecoration) {
+ this.controlDecoration = controlDecoration;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public IStatus validate(Object value) {
+ IStatus status = Status.OK_STATUS;
+ if (value instanceof String && controlDecoration.getControl().isEnabled()) {
+ String text = (String) value;
+ if (text.trim().length() > 0) {
+ IPath path = new Path(text);
+ File file = FileProvider.getDefault().getFile(path);
+ if (file == null || !file.exists()) {
+ controlDecoration.show();
+ controlDecoration.setDescriptionText("The specified path does not correspond to an image in the workspace or in the runtime");
+ status = ValidationStatus.error("NonExistingImageResource");
+ }
+ }
+ }
+ if (status.isOK()) {
+ controlDecoration.hide();
+ }
+ return status;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/dnd/DragAndDropWrapper.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/dnd/DragAndDropWrapper.java
new file mode 100644
index 0000000000..c7544d9905
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/dnd/DragAndDropWrapper.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2011 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.dnd;
+
+import org.eclipse.draw2d.Figure;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.gef.editparts.AbstractGraphicalEditPart;
+
+/**
+ * This class is a wrapper of an Object useful to manage drag and drop.
+ *
+ * @author Mariot Chauvin (mchauvin)
+ */
+public class DragAndDropWrapper extends AbstractGraphicalEditPart {
+
+ private static final IFigure FIGURE = new Figure();
+
+ private Object wrappedObject;
+
+ /**
+ * Constructor.
+ *
+ * @param eObj
+ * the wrapped object
+ */
+ public DragAndDropWrapper(final Object eObj) {
+ wrappedObject = eObj;
+ }
+
+ /**
+ * Get the wrapped Object.
+ *
+ * @return the wrapped object
+ */
+ public Object getObject() {
+ return this.wrappedObject;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#createFigure()
+ */
+ @Override
+ protected IFigure createFigure() {
+ return FIGURE;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gef.editparts.AbstractEditPart#createEditPolicies()
+ */
+ @Override
+ protected void createEditPolicies() {
+ // do nothing
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/edit/command/CommandFactory.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/edit/command/CommandFactory.java
new file mode 100644
index 0000000000..ec77797bb7
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/edit/command/CommandFactory.java
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.edit.command;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.emf.transaction.RecordingCommand;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.gmf.runtime.common.core.command.CommandResult;
+import org.eclipse.gmf.runtime.common.core.command.ICommand;
+import org.eclipse.gmf.runtime.emf.commands.core.command.AbstractTransactionalCommand;
+
+import org.eclipse.sirius.diagram.business.internal.operation.AbstractModelChangeOperation;
+
+/**
+ * Helper class to convert an {@link AbstractModelChangeOperation}s into either
+ * a plain EMF Transaction {@link RecordingCommand} or a GMF-compatible
+ * {@link ICommand}.
+ *
+ * @author pcdavid
+ */
+public final class CommandFactory {
+ private CommandFactory() {
+ // Prevent instantiation.
+ }
+
+ /**
+ * Converts these operations into an EMF Transaction recording command.
+ *
+ * @param ted
+ * the editing domain in which to command will execute.
+ * @param operations
+ * the array of operation to convert.
+ *
+ * @param <T>
+ * the return type of the operation.
+ * @return a recording command which will execute this operation.
+ */
+ public static <T> RecordingCommand createRecordingCommand(TransactionalEditingDomain ted, final Collection<AbstractModelChangeOperation<T>> operations) {
+ String name = operations.isEmpty() ? "Do nothing" : operations.iterator().next().getName();
+ return new RecordingCommandsExecutor<T>(ted, name, operations);
+ }
+
+ /**
+ * Converts this operation into an EMF Transaction recording command.
+ *
+ * @param ted
+ * the editing domain in which to command will execute.
+ * @param operation
+ * the operation to convert.
+ *
+ * @param <T>
+ * the return type of the operation.
+ * @return a recording command which will execute this operation.
+ */
+ public static <T> RecordingCommand createRecordingCommand(TransactionalEditingDomain ted, final AbstractModelChangeOperation<T> operation) {
+ return CommandFactory.createRecordingCommand(ted, Collections.singleton(operation));
+ }
+
+ /**
+ * Converts these operations into an EMF Transaction recording command.
+ *
+ * @param ted
+ * the editing domain in which to command will execute.
+ * @param operations
+ * the array of operation to convert.
+ *
+ * @param <T>
+ * the return type of the operation.
+ * @return a recording command which will execute this operation.
+ */
+ public static <T> RecordingCommand createRecordingCommand(TransactionalEditingDomain ted, final AbstractModelChangeOperation<T>... operations) {
+ return CommandFactory.createRecordingCommand(ted, Arrays.asList(operations));
+ }
+
+ /**
+ * Converts these operations into a GMF-compatible ICommand.
+ *
+ * @param ted
+ * the editing domain in which to command will execute.
+ * @param operations
+ * the operations to convert.
+ *
+ * @param <T>
+ * the return types of the operations.
+ * @return a GMF-compatible command which will execute this operation.
+ */
+ public static <T> ICommand createICommand(TransactionalEditingDomain ted, final Collection<AbstractModelChangeOperation<T>> operations) {
+ String name = operations.isEmpty() ? "Do nothing" : operations.iterator().next().getName();
+ return new AbstractTransactionalCommand(ted, name, null) {
+ @Override
+ protected CommandResult doExecuteWithResult(IProgressMonitor monitor, IAdaptable info) throws ExecutionException {
+ List<T> results = new ArrayList<T>();
+ for (AbstractModelChangeOperation<T> operation : operations) {
+ T value = operation.execute();
+ if (value != null) {
+ results.add(value);
+ }
+ }
+ return CommandResult.newOKCommandResult(results.size() == 1 ? results.get(0) : results);
+ }
+ };
+ }
+
+ /**
+ * Converts this operation into a GMF-compatible ICommand.
+ *
+ * @param ted
+ * the editing domain in which to command will execute.
+ * @param operation
+ * the operation to convert.
+ *
+ * @param <T>
+ * the return type of the operation.
+ * @return a GMF-compatible command which will execute this operation.
+ */
+ public static <T> ICommand createICommand(TransactionalEditingDomain ted, final AbstractModelChangeOperation<T> operation) {
+ return CommandFactory.createICommand(ted, Collections.singleton(operation));
+ }
+
+ /**
+ * Converts these operations into a GMF-compatible ICommand.
+ *
+ * @param ted
+ * the editing domain in which to command will execute.
+ * @param operations
+ * the operations to convert.
+ *
+ * @param <T>
+ * the return types of the operations.
+ * @return a GMF-compatible command which will execute this operation.
+ */
+ public static <T> ICommand createICommand(TransactionalEditingDomain ted, final AbstractModelChangeOperation<T>... operations) {
+ return CommandFactory.createICommand(ted, Arrays.asList(operations));
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/edit/command/RecordingCommandsExecutor.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/edit/command/RecordingCommandsExecutor.java
new file mode 100644
index 0000000000..0bc5d0247d
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/edit/command/RecordingCommandsExecutor.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.edit.command;
+
+import java.util.Collection;
+
+import org.eclipse.emf.transaction.RecordingCommand;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+
+import org.eclipse.sirius.diagram.business.internal.operation.AbstractModelChangeOperation;
+
+/**
+ * A Recording Command used in CommandFactory to execute a collection of
+ * AbstractModelChangeOperation<T>.
+ *
+ * @author smonnier
+ */
+public class RecordingCommandsExecutor<T> extends RecordingCommand {
+
+ private Collection<AbstractModelChangeOperation<T>> operations;
+
+ /**
+ * Constructor.
+ *
+ * @param domain
+ * my domain
+ * @param label
+ * my user-friendly label
+ * @param operations
+ * the array of operation to convert.
+ */
+ public RecordingCommandsExecutor(TransactionalEditingDomain domain, String label, Collection<AbstractModelChangeOperation<T>> operations) {
+ super(domain, label);
+ this.operations = operations;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doExecute() {
+ for (AbstractModelChangeOperation<T> operation : operations) {
+ operation.execute();
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/figure/DiagramSemanticElementLockedNotificationFigure.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/figure/DiagramSemanticElementLockedNotificationFigure.java
new file mode 100644
index 0000000000..2fd9237a25
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/figure/DiagramSemanticElementLockedNotificationFigure.java
@@ -0,0 +1,313 @@
+/*******************************************************************************
+ * Copyright (c) 2011 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.figure;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.List;
+
+import org.eclipse.draw2d.Ellipse;
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.Label;
+import org.eclipse.draw2d.LayeredPane;
+import org.eclipse.draw2d.Viewport;
+import org.eclipse.draw2d.geometry.Insets;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gef.LayerConstants;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramRootEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.l10n.DiagramColorRegistry;
+import org.eclipse.gmf.runtime.draw2d.ui.internal.figures.TransparentBorder;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.RGB;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+import org.eclipse.sirius.diagram.part.SiriusDiagramEditorPlugin;
+import org.eclipse.sirius.provider.SiriusEditPlugin;
+import org.eclipse.sirius.ecore.extender.business.api.permission.LockStatus;
+
+/**
+ * A figure to display a lock notification for the semantic element represented
+ * by a diagram.
+ *
+ * @author <a href="mailto:steve.monnier@obeo.fr">Steve Monnier</a>
+ */
+public class DiagramSemanticElementLockedNotificationFigure extends Ellipse {
+
+ /**
+ * Border color of the notification figure when locked by me.
+ */
+ public static final RGB BORDER_COLOR_LOCKED_BY_ME = new RGB(50, 205, 50);
+
+ /**
+ * Border color of the notification figure when locked by other.
+ */
+ public static final RGB BORDER_COLOR_LOCKED_BY_OTHER = new RGB(255, 0, 0);
+
+ private static final int DEFAULT_WIDTH = 25;
+
+ private static final int DEFAULT_HEIGHT = 25;
+
+ /** The PERMISSION_GRANTED_TO_CURRENT_USER_EXCLUSIVELY icon descriptor. */
+ private static final ImageDescriptor LOCK_BY_ME_IMAGE_DESCRIPTOR = SiriusEditPlugin.Implementation
+ .getBundledImageDescriptor("icons/full/decorator/permission_granted_to_current_user_exclusively.gif");
+
+ /** The PERMISSION_GRANTED_TO_CURRENT_USER_EXCLUSIVELY icon descriptor. */
+ private static final ImageDescriptor LOCK_BY_OTHER_IMAGE_DESCRIPTOR = SiriusEditPlugin.Implementation.getBundledImageDescriptor("icons/full/decorator/permission_denied.gif");
+
+ /**
+ * The transparency of this shape in percent. Must be in [0, 100] range.
+ */
+ private int transparency = 20;
+
+ private PropertyChangeListener propListener;
+
+ private Viewport viewport;
+
+ private DiagramRootEditPart rootEditPart;
+
+ /**
+ * Create a new instance.
+ *
+ * @param rootEditPart
+ * the editor root edit part
+ * @param message
+ * the message to display in the notification
+ * @param lockStatus
+ * the {@link LockStatus} to display in the notification
+ * @param height
+ * notification figure height
+ * @param width
+ * notification figure width
+ */
+ public DiagramSemanticElementLockedNotificationFigure(DiagramRootEditPart rootEditPart, String message, LockStatus lockStatus, int height, int width) {
+ Image lockStatusImage;
+ Label label;
+
+ this.rootEditPart = rootEditPart;
+ this.viewport = (Viewport) rootEditPart.getFigure();
+ this.setSize(width, height);
+ this.setLineWidth(3);
+ updateLocation();
+
+ if (LockStatus.LOCKED_BY_ME.equals(lockStatus)) {
+ this.setForegroundColor(DiagramColorRegistry.getInstance().getColor(BORDER_COLOR_LOCKED_BY_ME));
+ lockStatusImage = SiriusDiagramEditorPlugin.getInstance().getImage(LOCK_BY_ME_IMAGE_DESCRIPTOR);
+ label = new Label(message, lockStatusImage);
+ } else if (LockStatus.LOCKED_BY_OTHER.equals(lockStatus)) {
+ this.setForegroundColor(DiagramColorRegistry.getInstance().getColor(BORDER_COLOR_LOCKED_BY_OTHER));
+ lockStatusImage = SiriusDiagramEditorPlugin.getInstance().getImage(LOCK_BY_OTHER_IMAGE_DESCRIPTOR);
+ label = new Label(message, lockStatusImage);
+ } else {
+ label = new Label(message);
+ }
+ label.setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+ this.add(label);
+
+ propListener = new PropertyChangeListener() {
+ public void propertyChange(PropertyChangeEvent evt) {
+ updateLocation();
+ }
+ };
+
+ }
+
+ /**
+ * Create a new instance.
+ *
+ * @param rootEditPart
+ * the editor root edit part
+ * @param message
+ * the message to display in the notification
+ * @param lockStatus
+ * the {@link LockStatus} to display in the notification
+ */
+ public DiagramSemanticElementLockedNotificationFigure(DiagramRootEditPart rootEditPart, String message, LockStatus lockStatus) {
+ this(rootEditPart, message, lockStatus, DEFAULT_HEIGHT, DEFAULT_WIDTH);
+ }
+
+ private void updateLocation() {
+ Point viewLocation = viewport.getViewLocation().getCopy();
+
+ viewLocation.performScale(1.0d / rootEditPart.getZoomManager().getZoom());
+
+ this.setLocation(new Point(viewLocation.x, viewLocation.y));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addNotify() {
+ super.addNotify();
+ viewport.addPropertyChangeListener(Viewport.PROPERTY_VIEW_LOCATION, propListener);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void removeNotify() {
+ super.removeNotify();
+ viewport.removePropertyChangeListener(Viewport.PROPERTY_VIEW_LOCATION, propListener);
+ viewport = null;
+ }
+
+ /**
+ * Override to use local coordinates. .{@inheritDoc}
+ */
+ protected boolean useLocalCoordinates() {
+ return true;
+ }
+
+ /**
+ * Create a new notification figure and display it to the diagram.
+ *
+ * @param rootEditPart
+ * the diagram root edit part
+ * @param message
+ * the message
+ * @param lockStatus
+ * the {@link LockStatus} to display in the notification
+ */
+ public static void createNotification(DiagramRootEditPart rootEditPart, String message, LockStatus lockStatus) {
+ final LayeredPane pane = (LayeredPane) rootEditPart.getLayer(LayerConstants.PRINTABLE_LAYERS);
+
+ final IFigure notificationFigure = new DiagramSemanticElementLockedNotificationFigure(rootEditPart, message, lockStatus);
+ removeNotification(rootEditPart);
+ pane.add(notificationFigure);
+ }
+
+ /**
+ * Create a new notification figure and display it to the diagram.
+ *
+ * @param rootEditPart
+ * the diagram root edit part
+ * @param message
+ * the message
+ * @param lockStatus
+ * the {@link LockStatus} to display in the notification
+ * @param height
+ * notification figure height
+ * @param width
+ * notification figure width
+ */
+ public static void createNotification(DiagramRootEditPart rootEditPart, String message, LockStatus lockStatus, int height, int width) {
+ final LayeredPane pane = (LayeredPane) rootEditPart.getLayer(LayerConstants.PRINTABLE_LAYERS);
+
+ final IFigure notificationFigure = new DiagramSemanticElementLockedNotificationFigure(rootEditPart, message, lockStatus, height, width);
+ removeNotification(rootEditPart);
+ pane.add(notificationFigure);
+ }
+
+ /**
+ * Create a new notification figure and display it to the diagram.
+ *
+ * @param rootEditPart
+ * the diagram root edit part
+ * @param lockStatus
+ * the {@link LockStatus} to display in the notification
+ */
+ public static void createNotification(DiagramRootEditPart rootEditPart, LockStatus lockStatus) {
+ final LayeredPane pane = (LayeredPane) rootEditPart.getLayer(LayerConstants.PRINTABLE_LAYERS);
+
+ final IFigure notificationFigure = new DiagramSemanticElementLockedNotificationFigure(rootEditPart, "", lockStatus);
+ removeNotification(rootEditPart);
+ pane.add(notificationFigure);
+ }
+
+ /**
+ * Removes the notification figure from the diagram.
+ *
+ * @param rootEditPart
+ * the diagram root edit part
+ */
+ public static void removeNotification(DiagramRootEditPart rootEditPart) {
+ final LayeredPane pane = (LayeredPane) rootEditPart.getLayer(LayerConstants.PRINTABLE_LAYERS);
+ List<IFigure> figuresToRemove = Lists.newArrayList();
+ // Collects notification figures that needs to be removed
+ for (DiagramSemanticElementLockedNotificationFigure diagramSemanticElementLockedNotificationFigure : Iterables.filter(pane.getChildren(), DiagramSemanticElementLockedNotificationFigure.class)) {
+ figuresToRemove.add(diagramSemanticElementLockedNotificationFigure);
+ }
+ // Removes these notation figures from Layer
+ for (IFigure iFigure : figuresToRemove) {
+ pane.remove(iFigure);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.Shape#paintFigure(org.eclipse.draw2d.Graphics)
+ */
+ public void paintFigure(Graphics g) {
+ applyTransparency(g);
+ super.paintFigure(g);
+ g.setAlpha(255);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gef.handles.HandleBounds#getHandleBounds()
+ */
+ public Rectangle getHandleBounds() {
+ Insets insets = new Insets(0, 0, 0, 0);
+ if (getBorder() instanceof TransparentBorder) {
+ insets = ((TransparentBorder) getBorder()).getTransparentInsets(this);
+ }
+
+ // Ignore the insets when placing the handles
+ return new Rectangle(getBounds().x + insets.left, getBounds().y + insets.top, getBounds().width - (insets.right + insets.left), getBounds().height - (insets.bottom + insets.top));
+ }
+
+ /**
+ * Returns transparency value (belongs to [0, 100] interval).
+ *
+ * @return transparency
+ * @since 1.2
+ */
+ public int getTransparency() {
+ return transparency;
+ }
+
+ /**
+ * Sets the transparency if the given parameter is in [0, 100] range.
+ *
+ * @param transparency
+ * The transparency to set
+ * @since 1.2
+ */
+ public void setTransparency(int transparency) {
+ if (transparency != this.transparency && transparency >= 0 && transparency <= 100) {
+ this.transparency = transparency;
+ repaint();
+ }
+ }
+
+ /**
+ * Converts transparency value from percent range [0, 100] to alpha range
+ * [0, 255] and applies converted value. 0% corresponds to alpha 255 and
+ * 100% corresponds to alpha 0.
+ *
+ * @param g
+ * The Graphics used to paint
+ * @since 1.2
+ */
+ protected void applyTransparency(Graphics g) {
+ g.setAlpha(255 - transparency * 255 / 100);
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/figure/ICollapseMode.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/figure/ICollapseMode.java
new file mode 100644
index 0000000000..3be901bc01
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/figure/ICollapseMode.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.figure;
+
+import org.eclipse.draw2d.geometry.Dimension;
+
+/**
+ * Constants for collapsed nodes.
+ *
+ * @author mporhel
+ */
+public interface ICollapseMode {
+
+ /**
+ * Indicates the current collapse mode.
+ *
+ * - true : border nodes are collapsed (height, weight = 0, no available
+ * selection)
+ *
+ * - false : border nodes are minimized and transparents (selection and move
+ * are enabled)
+ *
+ * This flag is only there to ease the switch between the two behavior, as
+ * the client was not sure which mode was best.
+ */
+ boolean DEFAULT = false;
+
+ /**
+ * Offset for default collapsed nodes (in default mode).
+ */
+ Dimension COLLAPSE_DEFAULT_OFFSET = new Dimension(0, 0);
+
+ /**
+ * Offset for collapsed nodes (in minimized mode).
+ */
+ Dimension COLLAPSE_MINIMIZED_OFFSET = new Dimension(2, 2);
+
+ /**
+ * dimension for collapsed nodes (in default mode).
+ */
+ Dimension COLLAPSED_DIMENSION = new Dimension(0, 0);
+
+ /**
+ * dimension for collapsed nodes (in minimized mode).
+ */
+ // we decrease the minimized_dimension of collapsed nodes in minimized mode
+ Dimension MINIMIZED_DIMENSION = new Dimension(1, 1);
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/figure/NotificationFigure.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/figure/NotificationFigure.java
new file mode 100644
index 0000000000..c9c17ac541
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/figure/NotificationFigure.java
@@ -0,0 +1,267 @@
+/*******************************************************************************
+ * Copyright (c) 2011 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.figure;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import org.eclipse.draw2d.ColorConstants;
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.Label;
+import org.eclipse.draw2d.LayeredPane;
+import org.eclipse.draw2d.MouseEvent;
+import org.eclipse.draw2d.MouseListener;
+import org.eclipse.draw2d.RectangleFigure;
+import org.eclipse.draw2d.Shape;
+import org.eclipse.draw2d.Viewport;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Insets;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gef.LayerConstants;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramRootEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.l10n.DiagramColorRegistry;
+import org.eclipse.gmf.runtime.draw2d.ui.internal.figures.TransparentBorder;
+
+/**
+ * A figure to display a notification.
+ *
+ * @author mchauvin
+ * @provisional
+ */
+public class NotificationFigure extends RectangleFigure {
+
+ private static final int WARNING_COLOR_VALUE = 13369343;
+
+ private static final int WIDTH = 400;
+
+ private static final int HEIGHT = 30;
+
+ private static final int TEXT_OFFSET = 5;
+
+ /**
+ * The transparency of this shape in percent. Must be in [0, 100] range.
+ */
+ private int transparency = 20;
+
+ private PropertyChangeListener propListener;
+
+ private Viewport viewport;
+
+ private DiagramRootEditPart rootEditPart;
+
+ /**
+ * Create a new instance.
+ *
+ * @param rootEditPart
+ * the editor root edit part
+ * @param message
+ * the message to display in the notification
+ */
+ public NotificationFigure(DiagramRootEditPart rootEditPart, String message) {
+
+ this.rootEditPart = rootEditPart;
+ this.viewport = (Viewport) rootEditPart.getFigure();
+
+ this.setSize(WIDTH, HEIGHT);
+ this.setBackgroundColor(DiagramColorRegistry.getInstance().getColor(Integer.valueOf(WARNING_COLOR_VALUE)));
+
+ updateLocation();
+
+ Cross cross = new Cross();
+ int crossSize = cross.getSize().width;
+ cross.setLocation(new Point(WIDTH - crossSize - 3, 3));
+ this.add(cross);
+ cross.initialize();
+
+ Label label = new Label(message);
+ label.setSize(WIDTH - TEXT_OFFSET - crossSize, HEIGHT - TEXT_OFFSET);
+ this.add(label);
+
+ propListener = new PropertyChangeListener() {
+ public void propertyChange(PropertyChangeEvent evt) {
+ updateLocation();
+ }
+ };
+ }
+
+ private void updateLocation() {
+ Point viewLocation = viewport.getViewLocation().getCopy();
+ Dimension viewSize = viewport.getSize().getCopy();
+ /* we divide by 2 to center the notification figure */
+
+ // Workaround, as the size of the figure follows zoom, we apply twice
+ // the zoom on figure offset to balance
+ double notationFigureOffset = ((double) (viewSize.width - WIDTH) / 2d) / (rootEditPart.getZoomManager().getZoom() * rootEditPart.getZoomManager().getZoom());
+
+ viewLocation.performScale(1.0d / rootEditPart.getZoomManager().getZoom());
+
+ this.setLocation(new Point(viewLocation.x + notationFigureOffset, viewLocation.y));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addNotify() {
+ super.addNotify();
+ viewport.addPropertyChangeListener(Viewport.PROPERTY_VIEW_LOCATION, propListener);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void removeNotify() {
+ super.removeNotify();
+ viewport.removePropertyChangeListener(Viewport.PROPERTY_VIEW_LOCATION, propListener);
+ viewport = null;
+ }
+
+ /**
+ * Override to use local coordinates. .{@inheritDoc}
+ */
+ protected boolean useLocalCoordinates() {
+ return true;
+ }
+
+ /**
+ * Create a new notification figure and display it to the diagram.
+ *
+ * @param rootEditPart
+ * the diagram root edit part
+ * @param message
+ * the message
+ */
+ public static void createNotification(DiagramRootEditPart rootEditPart, String message) {
+ final LayeredPane pane = (LayeredPane) rootEditPart.getLayer(LayerConstants.PRINTABLE_LAYERS);
+
+ final IFigure nf = new NotificationFigure(rootEditPart, message);
+ pane.add(nf);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.Shape#paintFigure(org.eclipse.draw2d.Graphics)
+ */
+ public void paintFigure(Graphics g) {
+ applyTransparency(g);
+ super.paintFigure(g);
+ g.setAlpha(255);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gef.handles.HandleBounds#getHandleBounds()
+ */
+ public Rectangle getHandleBounds() {
+ Insets insets = new Insets(0, 0, 0, 0);
+ if (getBorder() instanceof TransparentBorder) {
+ insets = ((TransparentBorder) getBorder()).getTransparentInsets(this);
+ }
+
+ // Ignore the insets when placing the handles
+ return new Rectangle(getBounds().x + insets.left, getBounds().y + insets.top, getBounds().width - (insets.right + insets.left), getBounds().height - (insets.bottom + insets.top));
+ }
+
+ /**
+ * Returns transparency value (belongs to [0, 100] interval).
+ *
+ * @return transparency
+ * @since 1.2
+ */
+ public int getTransparency() {
+ return transparency;
+ }
+
+ /**
+ * Sets the transparency if the given parameter is in [0, 100] range.
+ *
+ * @param transparency
+ * The transparency to set
+ * @since 1.2
+ */
+ public void setTransparency(int transparency) {
+ if (transparency != this.transparency && transparency >= 0 && transparency <= 100) {
+ this.transparency = transparency;
+ repaint();
+ }
+ }
+
+ /**
+ * Converts transparency value from percent range [0, 100] to alpha range
+ * [0, 255] and applies converted value. 0% corresponds to alpha 255 and
+ * 100% corresponds to alpha 0.
+ *
+ * @param g
+ * The Graphics used to paint
+ * @since 1.2
+ */
+ protected void applyTransparency(Graphics g) {
+ g.setAlpha(255 - transparency * 255 / 100);
+ }
+
+ /**
+ * A cross figure to close the notation figure.
+ *
+ * @author mchauvin
+ */
+ private static class Cross extends Shape {
+
+ public Cross() {
+ this.setSize(10, 10);
+ }
+
+ /**
+ * Override to use local coordinates. .{@inheritDoc}
+ */
+ protected boolean useLocalCoordinates() {
+ return true;
+ }
+
+ @Override
+ protected void fillShape(Graphics graphics) {
+ graphics.pushState();
+ int x = getBounds().x;
+ int y = getBounds().y;
+ int[] shape = new int[] { x, y, x + 2, y, x + 4, y + 2, x + 5, y + 2, x + 7, y, x + 9, y, x + 9, y + 2, x + 7, y + 4, x + 7, y + 5, x + 9, y + 7, x + 9, y + 9, x + 7, y + 9, x + 5, y + 7,
+ x + 4, y + 7, x + 2, y + 9, x, y + 9, x, y + 7, x + 2, y + 5, x + 2, y + 4, x, y + 2, };
+ graphics.setBackgroundColor(ColorConstants.red);
+ graphics.fillPolygon(shape);
+ graphics.setForegroundColor(ColorConstants.black);
+ graphics.drawPolygon(shape);
+ graphics.popState();
+ }
+
+ @Override
+ protected void outlineShape(Graphics arg0) {
+
+ }
+
+ /**
+ * Initialize this figure. It should be done <b>after</b> adding this
+ * figure to its notation parent figure.
+ */
+ public void initialize() {
+ this.addMouseListener(new MouseListener.Stub() {
+ @Override
+ public void mousePressed(MouseEvent me) {
+ getParent().getParent().remove(getParent());
+ }
+ });
+ }
+
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/figure/TransparentFigureGraphicsModifier.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/figure/TransparentFigureGraphicsModifier.java
new file mode 100644
index 0000000000..67f80afd26
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/figure/TransparentFigureGraphicsModifier.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.figure;
+
+import org.eclipse.draw2d.Graphics;
+
+import org.eclipse.sirius.diagram.ui.tools.api.figure.ITransparentFigure;
+
+/**
+ * Specific handler to configure {@link Graphics} regarding the current
+ * {@link ITransparentFigure}.
+ *
+ * @author mporhel
+ */
+public class TransparentFigureGraphicsModifier {
+
+ private ITransparentFigure figure;
+
+ private Graphics graphics;
+
+ /**
+ * Constructor.
+ *
+ * @param figure
+ * the current figure.
+ * @param graphics
+ * the current graphics
+ */
+ public TransparentFigureGraphicsModifier(ITransparentFigure figure, Graphics graphics) {
+ this.figure = figure;
+ this.graphics = graphics;
+ }
+
+ /**
+ * Pushes the current state of the current graphics onto a stack. Enable
+ * transparency if figure's transparent mode is enabled.
+ */
+ public void pushState() {
+ if (graphics != null && figure != null && figure.isTransparent()) {
+ graphics.pushState();
+ graphics.setAlpha(figure.getSiriusAlpha());
+ }
+ }
+
+ /**
+ * Pops the previous state of the graphics off the stack.
+ */
+ public void popState() {
+ if (graphics != null && figure != null && figure.isTransparent()) {
+ graphics.popState();
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/figure/locator/FeedbackDBorderItemLocator.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/figure/locator/FeedbackDBorderItemLocator.java
new file mode 100644
index 0000000000..bd734b9137
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/figure/locator/FeedbackDBorderItemLocator.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2013 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.figure.locator;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gmf.runtime.diagram.ui.figures.BorderedNodeFigure;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.common.tools.api.util.Options;
+import org.eclipse.sirius.diagram.ui.tools.api.figure.locator.DBorderItemLocator;
+
+/**
+ * A specific bordered item locator for feedback when moving a border node.
+ *
+ * @author fbarbin
+ */
+public class FeedbackDBorderItemLocator extends DBorderItemLocator {
+
+ /**
+ * Default constructor.
+ *
+ * @param parentFigure
+ * the feedback target figure.
+ */
+ public FeedbackDBorderItemLocator(IFigure parentFigure) {
+ super(parentFigure);
+ }
+
+ @Override
+ protected Option<Rectangle> conflicts(Point recommendedLocation, IFigure targetBorderItem, Collection<IFigure> portsFiguresToIgnore) {
+ final Rectangle recommendedRect = new Rectangle(recommendedLocation, getSize(targetBorderItem));
+ IFigure parentFigure = getParentFigure();
+ if (parentFigure instanceof BorderedNodeFigure) {
+ parentFigure = ((BorderedNodeFigure) parentFigure).getBorderItemContainer();
+ }
+ final List borderItems = parentFigure.getChildren();
+ final ListIterator iterator = borderItems.listIterator();
+ while (iterator.hasNext()) {
+ final IFigure borderItem = (IFigure) iterator.next();
+ if (!portsFiguresToIgnore.contains(borderItem)) {
+ if (borderItem.isVisible()) {
+ final Rectangle rect = new Rectangle(borderItem.getBounds());
+ if (!(portsFiguresToIgnore.contains(borderItem)) && borderItem != targetBorderItem && rect.intersects(recommendedRect)) {
+ return Options.newSome(rect);
+ }
+ }
+ }
+ }
+ return Options.newNone();
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/find/BasicFindLabelEngine.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/find/BasicFindLabelEngine.java
new file mode 100644
index 0000000000..e05c49da2a
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/find/BasicFindLabelEngine.java
@@ -0,0 +1,159 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.find;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.editparts.AbstractGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.ITextAwareEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditor;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Lists;
+
+import org.eclipse.sirius.common.tools.api.find.AbstractFindLabelEngine;
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.diagram.ui.tools.api.figure.AirStyleDefaultSizeNodeFigure;
+import org.eclipse.sirius.diagram.ui.tools.api.figure.FigureQuery;
+
+/**
+ * A basic implementation of the AbstractFindLabelEngine. This engine simple
+ * search for labels starting with the search criterion
+ *
+ * @author glefur
+ */
+public class BasicFindLabelEngine extends AbstractFindLabelEngine {
+ /**
+ * A predicate to identify edit parts which are label and which can thus be
+ * matched with text.
+ */
+ private static final Predicate<EditPart> IS_LABEL_EDIT_PART = new Predicate<EditPart>() {
+ public boolean apply(final EditPart part) {
+ final boolean result;
+ if (part instanceof AbstractGraphicalEditPart && part instanceof ITextAwareEditPart) {
+ result = true;
+ } else if (part instanceof IGraphicalEditPart && ((IGraphicalEditPart) part).getFigure() instanceof AirStyleDefaultSizeNodeFigure) {
+ result = true;
+ } else {
+ result = false;
+ }
+ return result;
+ }
+ };
+
+ /**
+ * All diagrams label.
+ */
+ protected List allDiagramLabels;
+
+ /**
+ * The editor where the search is performed.
+ */
+ protected DiagramEditor editor;
+
+ /**
+ * This constructor will initialize the engine with all labels contained
+ * within <tt>currentEditor</tt>.
+ *
+ * @param currentEditor
+ * The editor on which the search is performed.
+ */
+ public BasicFindLabelEngine(final DiagramEditor currentEditor) {
+ super();
+ this.editor = currentEditor;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.common.tools.api.find.AbstractFindLabelEngine#filterLabels(java.lang.String)
+ */
+ @Override
+ protected List filterLabels(final String search) {
+ final List<EditPart> result = Lists.newArrayList();
+ for (Object obj : allLabels()) {
+ final AbstractGraphicalEditPart label = (AbstractGraphicalEditPart) obj;
+ if (matches(label, search)) {
+ result.add(label);
+ }
+ }
+ return result;
+ }
+
+ private boolean matches(final AbstractGraphicalEditPart label, final String search) {
+ return matches(getText(label), search);
+ }
+
+ private boolean matches(final String text, final String search) {
+ return text.indexOf(search) != -1;
+ }
+
+ /**
+ * Returns the text associated to a label edit part and which is used for
+ * textual search.
+ */
+ private String getText(final AbstractGraphicalEditPart label) {
+ final IFigure figure = label.getFigure();
+ final String text = getText(figure);
+ return text != null ? text : "";
+ }
+
+ private String getText(final IFigure figure) {
+ Option<String> result = new FigureQuery(figure).getText();
+ if (result.some()) {
+ return result.get();
+ }
+ return null;
+ }
+
+ private List allLabels() {
+ if (allDiagramLabels == null) {
+ findAllDiagramLabels();
+ }
+ return allDiagramLabels;
+ }
+
+ /**
+ * Finds all the edit parts in the editor which represent labels, and are
+ * thus candidates for text matching.
+ */
+ private void findAllDiagramLabels() {
+ allDiagramLabels = Lists.newArrayList();
+ allDiagramLabels.addAll(Collections2.filter((Collection<? extends EditPart>) findAllEditParts(), IS_LABEL_EDIT_PART));
+ }
+
+ private Collection<? extends EditPart> findAllEditParts() {
+ final DiagramEditPart diagram = editor.getDiagramEditPart();
+ final Collection<? extends EditPart> roots = Lists.newArrayList(diagram);
+ roots.addAll(diagram.getConnections());
+ final Collection<? extends EditPart> editParts = Lists.newArrayList();
+ for (EditPart root : roots) {
+ addAllContainedEditParts(root, editParts);
+ }
+ return editParts;
+ }
+
+ /**
+ * Add an edit part and all its descendants into the specified collection.
+ */
+ private void addAllContainedEditParts(final EditPart ep, final Collection coll) {
+ coll.add(ep);
+ for (Object child : ep.getChildren()) {
+ addAllContainedEditParts((EditPart) child, coll);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/AdvancedSiriusLayoutDataManager.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/AdvancedSiriusLayoutDataManager.java
new file mode 100644
index 0000000000..e66c2b3614
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/AdvancedSiriusLayoutDataManager.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout;
+
+import java.util.Map;
+
+import org.eclipse.sirius.diagram.layoutdata.EdgeLayoutData;
+import org.eclipse.sirius.diagram.layoutdata.NodeLayoutData;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.LayoutDataKey;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.SiriusLayoutDataManager;
+
+/**
+ * Interface to manage
+ * {@link org.eclipse.sirius.diagram.ui.tools.api.layout.SiriusLayoutDataManager}
+ * .
+ *
+ * @author dlecan
+ */
+public interface AdvancedSiriusLayoutDataManager extends SiriusLayoutDataManager {
+
+ /**
+ * Get only root node layout data, that is to say only the layout data
+ * without parent.
+ *
+ * @return Map.
+ */
+ Map<? extends LayoutDataKey, ? extends NodeLayoutData> getRootNodeLayoutData();
+
+ /**
+ * Get node layout data.
+ *
+ * @return Map.
+ */
+ Map<? extends NodeLayoutDataKey, NodeLayoutData> getNodeLayoutData();
+
+ /**
+ * Get edge layout data.
+ *
+ * @return Map.
+ */
+ Map<? extends EdgeLayoutDataKey, EdgeLayoutData> getEdgeLayoutData();
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/ArrangeAllWithAutoSize.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/ArrangeAllWithAutoSize.java
new file mode 100644
index 0000000000..0ddbfdda37
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/ArrangeAllWithAutoSize.java
@@ -0,0 +1,365 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Set;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.draw2d.graph.Node;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.Request;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.commands.CompoundCommand;
+import org.eclipse.gef.editparts.AbstractGraphicalEditPart;
+import org.eclipse.gef.requests.ChangeBoundsRequest;
+import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.requests.RequestConstants;
+import org.eclipse.gmf.runtime.draw2d.ui.internal.graph.VirtualNode;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DDiagramElementContainer;
+import org.eclipse.sirius.DNodeContainer;
+import org.eclipse.sirius.business.internal.query.DDiagramElementContainerExperimentalQuery;
+import org.eclipse.sirius.business.internal.query.DNodeContainerExperimentalQuery;
+import org.eclipse.sirius.diagram.edit.api.part.AbstractDiagramBorderNodeEditPart;
+import org.eclipse.sirius.diagram.edit.api.part.AbstractDiagramElementContainerEditPart;
+import org.eclipse.sirius.diagram.edit.api.part.AbstractDiagramNameEditPart;
+import org.eclipse.sirius.diagram.edit.api.part.IDiagramContainerEditPart;
+import org.eclipse.sirius.diagram.edit.api.part.IDiagramElementEditPart;
+import org.eclipse.sirius.diagram.edit.api.part.IDiagramListEditPart;
+import org.eclipse.sirius.diagram.internal.edit.parts.DDiagramEditPart;
+import org.eclipse.sirius.diagram.internal.edit.parts.SquareEditPart;
+import org.eclipse.sirius.diagram.internal.operation.RegionContainerUpdateLayoutOperation;
+import org.eclipse.sirius.diagram.part.SiriusDiagramEditorPlugin;
+import org.eclipse.sirius.diagram.tools.internal.preferences.SiriusDiagramPreferencesKeys;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.PinHelper;
+import org.eclipse.sirius.diagram.ui.tools.internal.edit.command.CommandFactory;
+import org.eclipse.sirius.diagram.ui.tools.internal.layout.provider.AbstractCompositeLayoutProvider;
+
+/**
+ * This class capture all the needed changes to make to the arrange all behavior
+ * so that auto-size is automatically applied on containers.
+ *
+ * @author cbrun
+ */
+public class ArrangeAllWithAutoSize {
+ /**
+ * Return true if this part should be autosized.
+ *
+ * @param part
+ * The concern part
+ * @return Return true if this part should be auto-size
+ */
+ public static boolean shouldBeAutosized(final IGraphicalEditPart part) {
+ boolean enabled = ArrangeAllWithAutoSize.isEnabled() && (ArrangeAllWithAutoSize.isContainer(part) || ArrangeAllWithAutoSize.isList(part)) && !ArrangeAllWithAutoSize.isPinned(part);
+ if (enabled && ArrangeAllWithAutoSize.isRegion(part)) {
+ EditPart regionContainerCompartment = part.getParent();
+ if (regionContainerCompartment != null) {
+ EditPart regionContainer = regionContainerCompartment.getParent();
+ enabled = regionContainer instanceof IGraphicalEditPart && !ArrangeAllWithAutoSize.isPinned((IGraphicalEditPart) regionContainer);
+ }
+ }
+ return enabled;
+ }
+
+ private static boolean isPinned(final IGraphicalEditPart part) {
+ if (part instanceof IDiagramElementEditPart) {
+ IDiagramElementEditPart diagramElementEditPart = (IDiagramElementEditPart) part;
+ DDiagramElement dDiagramElement = diagramElementEditPart.resolveDiagramElement();
+ return new PinHelper().isPinned(dDiagramElement);
+ }
+ return false;
+ }
+
+ private static boolean isContainer(final IGraphicalEditPart part) {
+ return part instanceof IDiagramContainerEditPart;
+ }
+
+ private static boolean isList(final IGraphicalEditPart part) {
+ return part instanceof IDiagramListEditPart;
+ }
+
+ /**
+ * return true if the auto-size on arrange all feature is enabled in the
+ * preferences.
+ *
+ * @return true if the auto-size on arrange all feature is enabled in the
+ * preferences.
+ */
+ public static boolean isEnabled() {
+ return SiriusDiagramEditorPlugin.getInstance().getPluginPreferences().getBoolean(SiriusDiagramPreferencesKeys.PREF_AUTOSIZE_ON_ARRANGE.name());
+ }
+
+ /**
+ * Prepare the auto-size support for an incoming arrange all. This
+ * preparation involve activating specific behavior on edit parts figures so
+ * that they are able, later on, to provide their 'incoming size after
+ * auto-size has been applied' so that the layout can leverage this
+ * information.
+ *
+ * @param unmodifiableIterator
+ * list iterator of edit parts.
+ */
+ public void prepareForArrangeAll(final Iterator<AbstractDiagramElementContainerEditPart> unmodifiableIterator) {
+ final Set<IFigure> parentFiguresToValidateToGetAutosizeDimensions = Sets.newLinkedHashSet();
+ while (unmodifiableIterator.hasNext()) {
+ final AbstractDiagramElementContainerEditPart ep = unmodifiableIterator.next();
+ if (ArrangeAllWithAutoSize.shouldBeAutosized(ep)) {
+ ep.forceFigureAutosize();
+ if (ep.getParent() instanceof AbstractGraphicalEditPart) {
+ parentFiguresToValidateToGetAutosizeDimensions.add(((AbstractGraphicalEditPart) ep.getParent()).getFigure());
+ }
+ }
+ }
+ for (final IFigure parentFig : parentFiguresToValidateToGetAutosizeDimensions) {
+ parentFig.validate();
+ }
+ }
+
+ /**
+ * Return the dimension this edit part is going to take after application of
+ * the auto-size behavior.
+ *
+ * @param ep
+ * any edit part part of the initialization process.
+ * @return the dimension this edit part is going to take after application
+ * of the auto-size behavior.
+ */
+ public Dimension getSizeToConsiderDuringArrangeAll(final IGraphicalEditPart ep) {
+ final Dimension size;
+ if (ArrangeAllWithAutoSize.shouldBeAutosized(ep) && ep instanceof AbstractDiagramElementContainerEditPart) {
+ size = ((AbstractDiagramElementContainerEditPart) ep).getAutosizedDimensions().getSize();
+ } else {
+ size = ep.getFigure().getBounds().getSize();
+ }
+ return size;
+ }
+
+ // CHECKSTYLE:OFF
+ /**
+ * Create the "Arrange All" sub-commands considering setting all the
+ * containers as auto-sized.
+ *
+ * @param globalDiff
+ * current diff.
+ * @param vi
+ * iterator of views
+ * @param cc
+ * command to update.
+ * @param provider
+ * a layouter responsible to provide the node metrics.
+ * @param minxX
+ * the X coordinate of the reference point.
+ * @param minxY
+ * the Y coordinate of the reference point.
+ */
+ public void createSubCommands(Point globalDiff, ListIterator vi, final CompoundCommand cc, final AbstractCompositeLayoutProvider provider, final int minX, final int minY) {
+ List<Node> nodes = Lists.newArrayList(vi);
+ vi = nodes.listIterator();
+ // Now set the position of the icons. This causes the
+ // arc connection points to be recalculated
+ while (vi.hasNext()) {
+ final Node node = (Node) vi.next();
+
+ if (node.data instanceof ShapeEditPart) {
+ createSubCommands(globalDiff, cc, provider, minX, minY, nodes, node);
+ }
+ }
+ }
+
+ private void createSubCommands(Point globalDiff, final CompoundCommand cc, final AbstractCompositeLayoutProvider provider, final int minX, final int minY, List<Node> nodes, final Node node) {
+ Point diffP = diff(minX, minY, nodes, provider, node);
+ diffP.x = Math.max(diffP.x, globalDiff.x);
+ diffP.y = Math.max(diffP.y, globalDiff.y);
+ if (diffP.x > -node.getPadding().left) {
+ diffP.x = -node.getPadding().left;
+ }
+ if (diffP.y > -node.getPadding().bottom) {
+ diffP.y = -node.getPadding().bottom;
+ }
+
+ Rectangle nodeExt = provider.translateToGraph(provider.provideNodeMetrics(node));
+
+ createSubCommands(cc, node, diffP, nodeExt);
+ }
+
+ private void createSubCommands(final CompoundCommand cc, final Node node, Point diff, final Rectangle nodeExt) {
+ if (node.getParent() instanceof VirtualNode) {
+ if (nodeExt.x > node.getPadding().left) {
+ nodeExt.x -= node.getPadding().left;
+ }
+ if (nodeExt.y > node.getPadding().top) {
+ nodeExt.y -= node.getPadding().top;
+ }
+ }
+
+ final Point pt = new Point();
+ if (nodeExt.x + diff.x > 0) {
+ pt.x = nodeExt.x + diff.x;
+ } else {
+ pt.x = nodeExt.x;
+ }
+ if (nodeExt.y + diff.y > 0) {
+ pt.y = nodeExt.y + diff.y;
+ } else {
+ pt.y = nodeExt.y;
+ }
+ final Point ptLocation = new Point(pt.x, pt.y);
+ final IGraphicalEditPart gep = (IGraphicalEditPart) node.data;
+ final Point ptOldLocation = gep.getFigure().getBounds().getLocation();
+
+ gep.getFigure().translateToAbsolute(ptOldLocation);
+ gep.getFigure().translateToAbsolute(ptLocation);
+
+ if (gep.getParent() instanceof DDiagramEditPart) {
+ if (node.x == node.getPadding().left) {
+ ptLocation.x -= node.getPadding().left;
+ }
+ if (node.y == node.getPadding().bottom) {
+ ptLocation.y -= node.getPadding().bottom;
+ }
+ }
+
+ final Dimension delta = ptLocation.getDifference(ptOldLocation);
+ final ChangeBoundsRequest request = new ChangeBoundsRequest(org.eclipse.gef.RequestConstants.REQ_MOVE);
+
+ final boolean isRegion = isRegion(gep);
+ if (isRegion) {
+ final Dimension size = nodeExt.getSize().getCopy();
+ final Dimension oldSize = gep.getFigure().getBounds().getSize();
+
+ gep.getFigure().translateToAbsolute(oldSize);
+ gep.getFigure().translateToAbsolute(size);
+ final Dimension deltaSize = size.getDifference(oldSize);
+
+ request.setType(org.eclipse.gef.RequestConstants.REQ_RESIZE);
+ request.setConstrainedResize(true);
+ request.setSizeDelta(deltaSize);
+ }
+
+ if (!(delta.height == 0 && delta.width == 0) || isRegion && !(request.getSizeDelta().height == 0 && request.getSizeDelta().width == 0)) {
+ request.setEditParts(gep);
+ request.setMoveDelta(new Point(delta.width, delta.height));
+ request.setLocation(ptLocation);
+
+ if (ArrangeAllWithAutoSize.shouldBeAutosized(gep)) {
+ final CompoundCommand cmd = new CompoundCommand();
+ cmd.add(gep.getCommand(request));
+ cmd.add(gep.getCommand(new Request(RequestConstants.REQ_AUTOSIZE)));
+ cc.add(cmd);
+ } else {
+ final Command cmd = gep.getCommand(request);
+ if (cmd != null && cmd.canExecute()) {
+ cc.add(cmd);
+ }
+ }
+ }
+
+ if (isRegionContainer(gep)) {
+ cc.add(new ICommandProxy(CommandFactory.createICommand(gep.getEditingDomain(), new RegionContainerUpdateLayoutOperation((org.eclipse.gmf.runtime.notation.Node) gep.getModel()))));
+ }
+
+ }
+
+ private static boolean isRegion(IGraphicalEditPart gep) {
+ if (gep instanceof AbstractDiagramElementContainerEditPart) {
+ DDiagramElement resolveDiagramElement = ((AbstractDiagramElementContainerEditPart) gep).resolveDiagramElement();
+ if (resolveDiagramElement instanceof DDiagramElementContainer) {
+ return new DDiagramElementContainerExperimentalQuery((DDiagramElementContainer) resolveDiagramElement).isRegion();
+ }
+ }
+ return false;
+ }
+
+ private static boolean isRegionContainer(IGraphicalEditPart gep) {
+ if (gep instanceof IDiagramContainerEditPart) {
+ DDiagramElement resolveDiagramElement = ((IDiagramContainerEditPart) gep).resolveDiagramElement();
+ if (resolveDiagramElement instanceof DNodeContainer) {
+ return new DNodeContainerExperimentalQuery((DNodeContainer) resolveDiagramElement).isRegionContainer();
+ }
+ }
+ return false;
+ }
+
+ private Point diff(final int minX, final int minY, List<Node> nodes, AbstractCompositeLayoutProvider provider, Node firstNode) {
+ Point ptLayoutMin = new Point(-1, -1);
+ for (Node node : nodes) {
+ // ignore ghost node
+ if (node.data != null) {
+ Rectangle nodeExt = provider.provideNodeMetrics(node);
+ nodeExt = ArrangeAllWithAutoSize.extendBoundingBoxWithBorderedNodes(node, nodeExt);
+ if (ptLayoutMin.x == -1) {
+ ptLayoutMin.x = nodeExt.x;
+ ptLayoutMin.y = nodeExt.y;
+ } else {
+ ptLayoutMin.x = Math.min(ptLayoutMin.x, nodeExt.x);
+ ptLayoutMin.y = Math.min(ptLayoutMin.y, nodeExt.y);
+ }
+ }
+
+ }
+ if (ptLayoutMin.x == firstNode.x) {
+ return provider.translateFromGraph(new Rectangle(0, 0, 0, 0)).getLocation();
+ }
+ return provider.translateFromGraph(new Rectangle(minX - ptLayoutMin.x, minY - ptLayoutMin.y, 0, 0)).getLocation();
+ // return new Point(minX - ptLayoutMin.x, minY - ptLayoutMin.y);
+ }
+
+ static Rectangle extendBoundingBoxWithBorderedNodes(Node node, Rectangle box) {
+ Rectangle extendedBox = box.getCopy();
+ if (node.data instanceof IGraphicalEditPart) {
+ IGraphicalEditPart gep = (IGraphicalEditPart) node.data;
+ /*
+ * 'delta' is how much the bordered node's parent has moved from its
+ * original position. For the bordered nodes, we can only get their
+ * original position (through the figure), but we assume they are
+ * moved along with their parent of the same delta.
+ */
+ Dimension delta = box.getLocation().getDifference(gep.getFigure().getBounds().getLocation());
+ for (AbstractDiagramBorderNodeEditPart borderedNode : Iterables.filter(gep.getChildren(), AbstractDiagramBorderNodeEditPart.class)) {
+ Rectangle translate = borderedNode.getFigure().getBounds().getCopy().translate(delta.width, delta.height);
+ extendedBox.union(translate);
+ }
+ Rectangle extendedBoxName = new Rectangle();
+ for (AbstractDiagramNameEditPart nameNode : Iterables.filter(gep.getChildren(), AbstractDiagramNameEditPart.class)) {
+ Rectangle translate = nameNode.getFigure().getBounds().getCopy();
+ extendedBoxName.union(new Dimension(0, translate.height));
+ }
+ for (SquareEditPart nameNode : Iterables.filter(gep.getChildren(), SquareEditPart.class)) {
+ Dimension translate = gep.getFigure().getMinimumSize().getCopy();
+ extendedBoxName.union(new Dimension(0, translate.height));
+ }
+
+ if (extendedBoxName.height > extendedBox.y) {
+ extendedBox.translate(extendedBoxName.width, extendedBoxName.height);
+ }
+ }
+ if (extendedBox.x < node.getPadding().left) {
+ extendedBox.x = node.getPadding().left;
+ }
+ if (extendedBox.y < node.getPadding().bottom) {
+ extendedBox.y = node.getPadding().bottom;
+ }
+ return extendedBox;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/AutoSizeAndRegionAwareGraphLayout.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/AutoSizeAndRegionAwareGraphLayout.java
new file mode 100644
index 0000000000..84d9582709
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/AutoSizeAndRegionAwareGraphLayout.java
@@ -0,0 +1,600 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2011 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.LayoutManager;
+import org.eclipse.draw2d.PositionConstants;
+import org.eclipse.draw2d.XYLayout;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Insets;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.draw2d.graph.DirectedGraph;
+import org.eclipse.draw2d.graph.DirectedGraphLayout;
+import org.eclipse.draw2d.graph.Edge;
+import org.eclipse.draw2d.graph.EdgeList;
+import org.eclipse.draw2d.graph.Node;
+import org.eclipse.draw2d.graph.NodeList;
+import org.eclipse.draw2d.graph.Subgraph;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.draw2d.ui.internal.graph.AdvancedSubGraph;
+import org.eclipse.gmf.runtime.draw2d.ui.internal.graph.CompositeDirectedGraphLayout;
+import org.eclipse.gmf.runtime.draw2d.ui.internal.graph.VirtualNode;
+
+import com.google.common.collect.Iterables;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.common.tools.api.util.Options;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DDiagramElementContainer;
+import org.eclipse.sirius.DNodeContainer;
+import org.eclipse.sirius.business.internal.query.DDiagramElementContainerExperimentalQuery;
+import org.eclipse.sirius.business.internal.query.DNodeContainerExperimentalQuery;
+import org.eclipse.sirius.diagram.edit.api.part.IAbstractDiagramNodeEditPart;
+import org.eclipse.sirius.diagram.edit.api.part.IDiagramContainerEditPart;
+import org.eclipse.sirius.diagram.edit.api.part.IDiagramNameEditPart;
+import org.eclipse.sirius.diagram.internal.edit.parts.AbstractDNodeContainerCompartmentEditPart;
+
+/**
+ * Customized version of the standard CompositeDirectedGraphLayout to improve
+ * auto-size handling. The original class does not support extensibility, so its
+ * whole code has been copied here and adapted, from the version in GMF 1.0.101.
+ * <p>
+ * Changes from original:
+ * <ul>
+ * <li>Backport of the fix in version 1.4 of the fils in CVS (
+ * <code>http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.gmf/plugins/org.eclipse.gmf.runtime.draw2d.ui/src/org/eclipse/gmf/runtime/draw2d/ui/internal/graph/CompositeDirectedGraphLayout.java?revision=1.4&root=Modeling_Project&view=markup</code>
+ * )</li>
+ * <LI>Add a graph direction variable as in GMF 1.3.0 to manage correctly the
+ * leftRight layout of CompositeLayout</LI>
+ * <LI>Change the insets used in recursiveHandleVirtualNode to get the computed
+ * Insets of our CompositeLayout</LI>
+ * </ul>
+ *
+ * @author pcdavid
+ */
+// CHECKSTYLE:OFF
+@SuppressWarnings("restriction")
+public class AutoSizeAndRegionAwareGraphLayout extends CompositeDirectedGraphLayout {
+
+ private int specificGraphDirection = PositionConstants.SOUTH;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.draw2d.graph.DirectedGraphLayout#visit(org.eclipse.draw2d
+ * .graph.DirectedGraph)
+ */
+ @Override
+ public void visit(DirectedGraph graph) {
+ specificGraphDirection = graph.getDirection();
+ layoutNodes(graph.nodes, false);
+ }
+
+ private void layoutNodes(NodeList nodes, boolean virtualPass) {
+ EdgeList edges = new EdgeList();
+ for (Iterator iter = nodes.iterator(); iter.hasNext();) {
+ Node element = (Node) iter.next();
+ if (element instanceof Subgraph && !(element instanceof VirtualNode)) {
+ layoutNodes(((Subgraph) element).members, virtualPass);
+ }
+ for (Iterator edgesIter = element.outgoing.iterator(); edgesIter.hasNext();) {
+ Edge edge = (Edge) edgesIter.next();
+ if (nodes.contains(edge.target)) {
+ edges.add(edge);
+ }
+ }
+ }
+ if (!virtualPass) {
+ VirtualNodesToNodes virtualNodesNodes = new VirtualNodesToNodes();
+ createVirtualNodes(nodes, edges, virtualNodesNodes);
+ NodeList vituralNodes = virtualNodesNodes.getVirtualNodes();
+ int size = vituralNodes.size();
+ if (size > 0) {
+ edges = virtualNodesNodes.getEdges();
+ for (Iterator iter = vituralNodes.iterator(); iter.hasNext();) {
+ Subgraph virtualNode = (Subgraph) iter.next();
+ layoutNodes(virtualNode.members, true);
+ }
+ adjustVirtualNodesWidthAndHeight(vituralNodes);
+ }
+ }
+
+ Map nodeToOutGoing = new HashMap();
+ Map nodeToIncomingGoing = new HashMap();
+ removeDisconnectedEdges(nodes, nodeToOutGoing, nodeToIncomingGoing);
+ if (nodes.size() > 0) {
+ Node parent = getParent(nodes.getNode(0));
+ DirectedGraph g = new DirectedGraph();
+ g.setDirection(specificGraphDirection);
+ g.nodes = nodes;
+ g.edges = edges;
+
+ final boolean concernRegions = (parent == null && areRegions(nodes)) || (parent != null && getRegionContainer(parent).some());
+ /*
+ * Handle regions : deactivate the default behavior where all nodes
+ * of a same row have the same vertical bounds
+ */
+ if (!concernRegions) {
+ DirectedGraphLayout layout = new DirectedGraphLayout();
+ layout.visit(g);
+ }
+
+ /*
+ * <handle_bordered_nodes>
+ *
+ * Translate all the elements at this level of the appropriate
+ * offsets to consider their bordered nodes. Otherwise elements are
+ * put too close to their parent's border, and the bordered nodes
+ * cause the appearance of scrollbars.
+ */
+ Dimension offsets = getOffsets(nodes);
+ for (int j = 0; j < nodes.size(); j++) {
+ Node n = nodes.getNode(j);
+ n.x += offsets.width;
+ n.y += offsets.height;
+ }
+
+ /*
+ * Handle regions : deactivate the default behavior where all nodes
+ * of a same row have the same vertical bounds
+ */
+ if (concernRegions) {
+ adjustRegionsLayout(nodes, parent);
+ }
+
+ if (parent instanceof AdvancedSubGraph) {
+ adjustAutoSizeNodeWidthAndHeight((AdvancedSubGraph) parent);
+ }
+ }
+
+ restoreDisconnectedEdges(nodeToOutGoing, nodeToIncomingGoing);
+ }
+
+ private void adjustRegionsLayout(NodeList nodes, Node parent) {
+ if (nodes.isEmpty())
+ return;
+
+ DNodeContainer regionContainer = getRegionContainer(nodes, parent);
+ if (regionContainer != null) {
+ DNodeContainerExperimentalQuery query = new DNodeContainerExperimentalQuery(regionContainer);
+ if (query.isVerticalStackContainer()) {
+ adjustRegionLayout(nodes, parent, true);
+ } else if (query.isHorizontaltackContainer()) {
+ adjustRegionLayout(nodes, parent, false);
+ }
+ }
+ }
+
+ /*
+ * @param vertical : vertical if true, horizontal if false.
+ */
+ private void adjustRegionLayout(NodeList nodes, Node parent, boolean vertical) {
+ int commonWidth = 0;
+ int commonHeight = 0;
+ for (int j = 0; j < nodes.size(); j++) {
+ Node n = nodes.getNode(j);
+ commonWidth = Math.max(commonWidth, n.width);
+ commonHeight = Math.max(commonHeight, n.height);
+ }
+
+ // Start regions after parent label.
+ int y = getLabelHeight(parent);
+ int x = 0;
+
+ for (int j = 0; j < nodes.size(); j++) {
+ Node n = nodes.getNode(j);
+ n.x = x;
+ n.y = y;
+
+ if (vertical) {
+ n.width = commonWidth;
+ y += n.height;
+ } else {
+ x += n.width;
+ n.height = commonHeight;
+ }
+ }
+ }
+
+ private DNodeContainer getRegionContainer(NodeList nodes, Node parent) {
+ DNodeContainer rc = null;
+ if (parent != null) {
+ rc = getRegionContainer(parent).get();
+ } else {
+ Option<DDiagramElementContainer> region = getRegion(nodes.getNode(0));
+ rc = region.some() ? (DNodeContainer) region.get().eContainer() : null;
+ }
+
+ return rc;
+ }
+
+ private int getLabelHeight(Node parent) {
+ if (parent != null && parent.data instanceof AbstractDNodeContainerCompartmentEditPart) {
+ AbstractDNodeContainerCompartmentEditPart comp = (AbstractDNodeContainerCompartmentEditPart) parent.data;
+ EditPart containerEditPart = comp.getParent();
+ IDiagramNameEditPart nameEditPart = Iterables.getFirst(Iterables.filter(containerEditPart.getChildren(), IDiagramNameEditPart.class), null);
+ if (nameEditPart != null && nameEditPart.getFigure() != null) {
+ return nameEditPart.getFigure().getBounds().height;
+ }
+ }
+ return 0;
+ }
+
+ /* no parent detect regions */
+ private boolean areRegions(NodeList nodes) {
+ boolean areRegions = false;
+ for (int j = 0; j < nodes.size(); j++) {
+ Node n = nodes.getNode(j);
+ areRegions = areRegions || getRegion(n).some();
+ }
+ return areRegions;
+ }
+
+ private Option<DNodeContainer> getRegionContainer(Node node) {
+ DNodeContainer dnc = null;
+ if (node != null && (node.data instanceof IDiagramContainerEditPart || node.data instanceof AbstractDNodeContainerCompartmentEditPart)) {
+ EObject element = ((IGraphicalEditPart) node.data).resolveSemanticElement();
+ if (element instanceof DNodeContainer) {
+ dnc = (DNodeContainer) element;
+ }
+ }
+
+ if (dnc != null && new DNodeContainerExperimentalQuery(dnc).isRegionContainer()) {
+ return Options.newSome(dnc);
+ }
+ return Options.newNone();
+ }
+
+ private Option<DDiagramElementContainer> getRegion(Node node) {
+ if (node.data instanceof IAbstractDiagramNodeEditPart) {
+ DDiagramElement element = ((IAbstractDiagramNodeEditPart) node.data).resolveDiagramElement();
+ if (element instanceof DDiagramElementContainer && new DDiagramElementContainerExperimentalQuery((DDiagramElementContainer) element).isRegion()) {
+ return Options.newSome((DDiagramElementContainer) element);
+ }
+ }
+ return Options.newNone();
+ }
+
+ /**
+ * Computes how much the specified nodes should be moved to make enough room
+ * for the parent container to contain them
+ * <em>with their bordered nodes</em>.
+ */
+ private Dimension getOffsets(NodeList nodes) {
+ Node node = nodes.getNode(0);
+ int left = node.x, top = node.y;
+ Rectangle bbox = ArrangeAllWithAutoSize.extendBoundingBoxWithBorderedNodes(node, new Rectangle(node.x, node.y, node.width, node.height));
+ int leftBorder = bbox.x, topBorder = bbox.y;
+ for (int i = 1; i < nodes.size(); i++) {
+ node = nodes.getNode(i);
+ left = Math.min(left, node.x);
+ top = Math.min(top, node.y);
+ bbox = ArrangeAllWithAutoSize.extendBoundingBoxWithBorderedNodes(node, new Rectangle(node.x, node.y, node.width, node.height));
+ leftBorder = Math.min(leftBorder, bbox.x);
+ topBorder = Math.min(topBorder, bbox.y);
+ }
+ Point diff = new Point();
+ if (node.getParent() != null) {
+ diff = new Point(node.getParent().x - node.x, node.getParent().y - node.y);
+ }
+ if (diff.x < 0 && diff.y < 0) {
+ return new Dimension(Math.max(0, left - leftBorder), Math.max(0, top - topBorder));
+ }
+ return new Dimension(Math.max(0, Math.abs(left - leftBorder)), Math.max(0, Math.abs(top - topBorder)));
+ }
+
+ private void restoreDisconnectedEdges(Map nodeToOutGoing, Map nodeToIncomingGoing) {
+ restoreEdges(nodeToOutGoing.entrySet(), true);
+ restoreEdges(nodeToIncomingGoing.entrySet(), false);
+ }
+
+ private void removeDisconnectedEdges(NodeList nodes, Map nodeToOutGoing, Map nodeToIncomingGoing) {
+ for (Iterator iter = nodes.iterator(); iter.hasNext();) {
+ Node element = (Node) iter.next();
+ pushExtraEdges(nodes, nodeToOutGoing, element, element.outgoing, false);
+ pushExtraEdges(nodes, nodeToIncomingGoing, element, element.incoming, true);
+ }
+ }
+
+ private void createVirtualNodes(NodeList nodes, EdgeList edges, VirtualNodesToNodes virtualNodesNodes) {
+ Set handledEdges = new HashSet();
+ recursiveHandleVirtualNode(nodes, edges, virtualNodesNodes, handledEdges, new HashSet(nodes));
+ }
+
+ private void recursiveHandleVirtualNode(NodeList nodes, EdgeList edges, VirtualNodesToNodes virtualNodesNodes, Set handledEdges, Set nodesSnapeShot) {
+ for (Iterator edgeIter = edges.iterator(); edgeIter.hasNext();) {
+ Edge element = (Edge) edgeIter.next();
+ if (handledEdges.contains(element)) {
+ continue;
+ }
+ handledEdges.add(element);
+ if (!nodesSnapeShot.contains(element.source) || !nodesSnapeShot.contains(element.target)) {
+ continue;
+ }
+ Node source = element.source;
+ Node target = element.target;
+ boolean sourceHandled = true;
+ boolean targetHandled = true;
+ Subgraph sg = virtualNodesNodes.getVirtualContainer(source);
+ Subgraph sg1 = virtualNodesNodes.getVirtualContainer(target);
+ if (sg == null) {
+ sourceHandled = false;
+ sg = sg1;
+ }
+ if (sg1 == null) {
+ targetHandled = false;
+ }
+ if (sourceHandled == false && targetHandled == false) {
+ sg = new VirtualNode(null, source.getParent());
+ sg.setPadding(new Insets(source.getPadding()));
+ if (source.getParent() == null) {
+ nodes.add(sg);
+ }
+ }
+ if (!sourceHandled) {
+ addNode(sg, source, nodes);
+ virtualNodesNodes.addNode(sg, source);
+ }
+ if (!targetHandled) {
+ addNode(sg, target, nodes);
+ virtualNodesNodes.addNode(sg, target);
+ }
+ // order is important; so we should start handling the outgoing and
+ // the incoming
+ // edges only after the source and target had been handled
+ if (!sourceHandled) {
+ recursiveHandleVirtualNode(nodes, source.outgoing, virtualNodesNodes, handledEdges, nodesSnapeShot);
+ recursiveHandleVirtualNode(nodes, source.incoming, virtualNodesNodes, handledEdges, nodesSnapeShot);
+ }
+ if (!targetHandled) {
+ recursiveHandleVirtualNode(nodes, target.outgoing, virtualNodesNodes, handledEdges, nodesSnapeShot);
+ recursiveHandleVirtualNode(nodes, target.incoming, virtualNodesNodes, handledEdges, nodesSnapeShot);
+ }
+ }
+ }
+
+ private void pushExtraEdges(NodeList nodes, Map nodeToIncomingGoing, Node element, List list, boolean sourceCheck) {
+ List edges = new ArrayList();
+ for (Iterator iterator = list.iterator(); iterator.hasNext();) {
+ Edge edge = (Edge) iterator.next();
+ Node nodeToCheck = sourceCheck ? edge.source : edge.target;
+ if (!nodes.contains(nodeToCheck)) {
+ edges.add(edge);
+ iterator.remove();
+ Node sourceNode = null;
+ Node targetNode = null;
+ sourceNode = getParent(edge.source);
+ targetNode = getParent(edge.target);
+ sourceNode = (!sourceCheck || sourceNode != null) ? sourceNode : edge.source;
+ targetNode = (sourceCheck || targetNode != null) ? targetNode : edge.target;
+ if (!sourceCheck && sourceNode != null && targetNode != null && sourceNode != targetNode && (edge.source != sourceNode || edge.target != targetNode)) {
+ Edge virtualEdge = new Edge(sourceNode, targetNode, edge.getDelta(), edge.weight);
+ virtualEdge.setPadding(edge.getPadding());
+ }
+ }
+ }
+ if (!edges.isEmpty()) {
+ nodeToIncomingGoing.put(element, edges);
+ }
+ }
+
+ private Node getParent(Node node) {
+ Node parent = node.getParent();
+ if (parent instanceof VirtualNode) {
+ parent = parent.getParent();
+ }
+ return parent;
+ }
+
+ private void restoreEdges(Set entries, boolean outgoing) {
+ for (Iterator iter = entries.iterator(); iter.hasNext();) {
+ Map.Entry entry = (Map.Entry) iter.next();
+ Node node = (Node) entry.getKey();
+ List edgesList = (List) entry.getValue();
+ for (Iterator iterator = edgesList.iterator(); iterator.hasNext();) {
+ Edge edgeToRestore = (Edge) iterator.next();
+ if (outgoing) {
+ node.outgoing.add(edgeToRestore);
+ } else {
+ node.incoming.add(edgeToRestore);
+ }
+ }
+
+ }
+ }
+
+ private void adjustVirtualNodesWidthAndHeight(NodeList vituralNodes) {
+ for (Iterator iter = vituralNodes.iterator(); iter.hasNext();) {
+ Subgraph subGraph = (Subgraph) iter.next();
+ adjustVirtualNodeWidthAndHeight(subGraph);
+ }
+
+ }
+
+ private void adjustVirtualNodeWidthAndHeight(Subgraph subGraph) {
+ NodeList nodes = subGraph.members;
+ if (nodes.isEmpty()) {
+ return;
+ }
+ int size = nodes.size();
+ Node node = nodes.getNode(0);
+ int top = node.y, left = node.x, bottom = top + node.height, right = left + node.width;
+ for (int index = 1; index < size; index++) {
+ node = (Node) nodes.get(index);
+ if (top > node.y) {
+ top = node.y;
+ }
+ if (bottom < (node.y + node.height)) {
+ bottom = node.y + node.height;
+ }
+ if (left > node.x) {
+ left = node.x;
+ }
+ if (right < (node.x + node.width)) {
+ right = node.x + node.width;
+ }
+ }
+ subGraph.width = right - left;
+ subGraph.height = bottom - top;
+ }
+
+ private void adjustAutoSizeNodeWidthAndHeight(AdvancedSubGraph subGraph) {
+ if (!subGraph.isAutoSize()) {
+ return;
+ }
+
+ NodeList nodes = subGraph.members;
+ if (nodes.isEmpty()) {
+ return;
+ }
+ int size = nodes.size();
+ Node node = nodes.getNode(0);
+ int top = node.y, left = node.x, bottom = top + node.height, right = left + node.width;
+ Node topNode, leftNode;
+ topNode = leftNode = node;
+ for (int index = 1; index < size; index++) {
+ node = (Node) nodes.get(index);
+ if (top > node.y) {
+ top = node.y;
+ topNode = node;
+ }
+ if (bottom < (node.y + node.height)) {
+ bottom = node.y + node.height;
+ }
+ if (left > node.x) {
+ left = node.x;
+ leftNode = node;
+ }
+ if (right < (node.x + node.width)) {
+ right = node.x + node.width;
+ }
+ }
+ int xDiff = 0;
+ int yDiff = 0;
+ if (subGraph.isHasBufferedZone()) {
+ xDiff = leftNode.x;
+ yDiff = topNode.y;
+ }
+ subGraph.width = right - left + xDiff;
+ subGraph.height = bottom - top + yDiff;
+
+ /*
+ * <auto-size_fix>
+ *
+ * This algorithm comes from
+ * org.eclipse.gmf.runtime.diagram.ui.layout.FreeFormLayoutEx
+ * .layout(IFigure parent).
+ */
+ if (subGraph.data instanceof IGraphicalEditPart) {
+ IGraphicalEditPart gep = (IGraphicalEditPart) subGraph.data;
+ IFigure f = gep.getFigure();
+
+ LayoutManager lm = f.getParent().getLayoutManager();
+ Point offset;
+ if (lm instanceof XYLayout) {
+ offset = ((XYLayout) lm).getOrigin(f.getParent());
+ } else {
+ offset = new Point();
+ }
+
+ Rectangle bounds = f.getBounds().getCopy();
+
+ if (bounds.width == -1 || bounds.height == -1) {
+ Dimension _preferredSize = f.getPreferredSize(bounds.width, bounds.height);
+ bounds = bounds.getCopy();
+ if (bounds.width == -1) {
+ bounds.width = _preferredSize.width;
+ }
+ if (bounds.height == -1) {
+ bounds.height = _preferredSize.height;
+ }
+ }
+ Dimension min = f.getMinimumSize();
+ Dimension max = f.getMaximumSize();
+
+ if (min.width > bounds.width) {
+ bounds.width = min.width;
+ } else if (max.width < bounds.width) {
+ bounds.width = max.width;
+ }
+
+ if (min.height > bounds.height) {
+ bounds.height = min.height;
+ } else if (max.height < bounds.height) {
+ bounds.height = max.height;
+ }
+ bounds = bounds.getTranslated(offset);
+
+ subGraph.width = Math.max(subGraph.width, bounds.width);
+ subGraph.height = Math.max(subGraph.height, bounds.height);
+ }
+ /*
+ * </auto-size_fix>
+ */
+ }
+
+ private void addNode(Subgraph parent, Node node, NodeList nodes) {
+ if (node.getParent() != null) {
+ node.getParent().members.remove(node);
+ }
+ node.setParent(parent);
+ parent.addMember(node);
+ nodes.remove(node);
+ }
+
+ @SuppressWarnings("serial")
+ private static class VirtualNodesToNodes extends HashMap {
+ Set virtualNodes = new HashSet();
+
+ public void addNode(Subgraph sg, Node node) {
+ virtualNodes.add(sg);
+ put(node, sg);
+ }
+
+ public EdgeList getEdges() {
+ EdgeList edges = new EdgeList();
+ for (Iterator iter = virtualNodes.iterator(); iter.hasNext();) {
+ Node element = (Node) iter.next();
+ for (Iterator iterator = element.outgoing.iterator(); iterator.hasNext();) {
+ Edge edge = (Edge) iterator.next();
+ if (virtualNodes.contains(edge.target)) {
+ edges.add(edge);
+ }
+
+ }
+ }
+ return edges;
+ }
+
+ public Subgraph getVirtualContainer(Node node) {
+ return (Subgraph) get(node);
+ }
+
+ public NodeList getVirtualNodes() {
+ NodeList nodeList = new NodeList();
+ nodeList.addAll(virtualNodes);
+ return nodeList;
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/DiagramLayoutCustomization.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/DiagramLayoutCustomization.java
new file mode 100644
index 0000000000..630fd3d89d
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/DiagramLayoutCustomization.java
@@ -0,0 +1,184 @@
+/*******************************************************************************
+ * Copyright (c) 2011 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout;
+
+import java.util.Collection;
+
+import org.eclipse.draw2d.geometry.Insets;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gef.GraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.AbstractBorderedShapeEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.CompartmentEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.notation.View;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Iterables;
+
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.description.CompositeLayout;
+import org.eclipse.sirius.description.DiagramDescription;
+import org.eclipse.sirius.description.Layout;
+import org.eclipse.sirius.diagram.edit.api.part.AbstractDiagramBorderNodeEditPart;
+import org.eclipse.sirius.diagram.edit.api.part.AbstractDiagramElementContainerEditPart;
+
+/**
+ * Class capturing the diagram layout customization made in a viewpoint
+ * specification model.
+ *
+ * @author cbrun
+ *
+ */
+public class DiagramLayoutCustomization {
+ /**
+ * This constant represent the distance from the side of a border node to
+ * the first bendpoint when the router is a border item "aware" one.
+ */
+ private static final int BORDER_NODE_ROUTING_SPACE = 10;
+
+ private int padding = 30;
+
+ /**
+ * Create a new Diagram Customization.
+ */
+ public DiagramLayoutCustomization() {
+
+ }
+
+ /**
+ * Return the Insets that one should use as a padding for the node.
+ *
+ * @param ep
+ * any editpart.
+ * @return the Insets that one should use as a padding for the node.
+ */
+ public Insets getNodePadding(final GraphicalEditPart ep) {
+ /*
+ * This method has been redirected to allow redefinition of the node
+ * padding (which is final in the super class).
+ */
+ Insets inSetPadding = new Insets(this.padding);
+ if (ep instanceof CompartmentEditPart || ep instanceof AbstractDiagramElementContainerEditPart && ((AbstractDiagramElementContainerEditPart) ep).isRegion()) {
+ // No padding for regions.
+ inSetPadding = new Insets(0);
+ } else if (ep instanceof AbstractBorderedShapeEditPart) {
+ // check if the direct parent is added already to the graph
+
+ int maxWidth = -1;
+ int maxHeight = -1;
+ for (final AbstractDiagramBorderNodeEditPart borderNode : Iterables.filter(ep.getChildren(), AbstractDiagramBorderNodeEditPart.class)) {
+ int figTopMargin = borderNode.getFigure().getBounds().width / 4;
+ int figLeftMargin = borderNode.getFigure().getBounds().height / 4;
+ /*
+ * If we've got connections then we should add a bit more
+ * padding to avoid the first bendpoints of the connection as
+ * the router starts with an horizontal or vertical straight
+ * line when being from a port.
+ */
+ final int nbConnections = borderNode.getSourceConnections().size() + ep.getTargetConnections().size();
+ if (nbConnections > 0) {
+ figLeftMargin += figLeftMargin + BORDER_NODE_ROUTING_SPACE;
+ figTopMargin += figTopMargin + BORDER_NODE_ROUTING_SPACE;
+ }
+ if (figTopMargin > maxWidth) {
+ maxWidth = figTopMargin;
+ }
+ if (figLeftMargin > maxHeight) {
+ maxHeight = figLeftMargin;
+ }
+ }
+ inSetPadding = new Insets(Math.max(inSetPadding.top, maxWidth), Math.max(inSetPadding.left, maxHeight), Math.max(inSetPadding.bottom, maxWidth), Math.max(inSetPadding.right, maxHeight));
+ }
+ return inSetPadding;
+
+ }
+
+ /**
+ * Initialize the diagram customization padding looking for specific
+ * settings in the given objects.
+ *
+ * @param selectedObjects
+ * collection of {@link IGraphicalEditPart}
+ */
+ public void initializePaddingWithEditParts(final Collection selectedObjects) {
+ padding = findPaddingFromSelection(selectedObjects);
+ }
+
+ /**
+ * Initialize the diagram customization padding looking for specific
+ * settings in the given views.
+ *
+ * @param views
+ * collection {@link View}
+ */
+ public void initializePaddingWithViews(final Collection<View> views) {
+ padding = findPaddingFromViews(views);
+ }
+
+ private int findPaddingFromViews(final Collection<View> views) {
+ int foundPadding = 30;
+ for (final View obj : views) {
+ foundPadding = getPadding(obj);
+ if (foundPadding != 30)
+ break;
+ }
+ return foundPadding;
+ }
+
+ private int findPaddingFromSelection(final Collection selectedObjects) {
+ int foundPadding = 30;
+ Collection<IGraphicalEditPart> filteredSelection = Collections2.filter(selectedObjects, Predicates.instanceOf(GraphicalEditPart.class));
+ for (final IGraphicalEditPart obj : filteredSelection) {
+ foundPadding = getEditPartPadding(obj);
+ if (foundPadding != 30)
+ break;
+ }
+ return foundPadding;
+ }
+
+ private int getEditPartPadding(final IGraphicalEditPart container) {
+ return getPadding(container.getNotationView());
+ }
+
+ private int getPadding(final View gmfView) {
+ final Layout foundLayout = DiagramLayoutCustomization.findLayoutSettings(gmfView);
+ if (foundLayout instanceof CompositeLayout) {
+ return ((CompositeLayout) foundLayout).getPadding();
+ }
+ return 30;
+ }
+
+ /**
+ * return the layout setting associated with a given {@link View}.
+ *
+ * @param view
+ * any GMF View.
+ * @return the layout setting associated with a given {@link View}. Null if
+ * there is no such setting.
+ */
+ public static Layout findLayoutSettings(final View view) {
+ Layout foundLayout = null;
+ if (view.getDiagram() != null) {
+ final EObject modelElement = view.getDiagram().getElement();
+ if (modelElement instanceof DDiagram) {
+ final DDiagram vp = (DDiagram) modelElement;
+ final DiagramDescription desc = vp.getDescription();
+ if (desc != null) {
+ foundLayout = desc.getLayout();
+ }
+ return foundLayout;
+ }
+ }
+ return foundLayout;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/EdgeLayoutDataKey.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/EdgeLayoutDataKey.java
new file mode 100644
index 0000000000..20695e7bef
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/EdgeLayoutDataKey.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout;
+
+import org.eclipse.sirius.diagram.ui.tools.api.layout.LayoutDataKey;
+
+/**
+ * Interface for all kind of key use to store EdgelayoutData.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ *
+ */
+public interface EdgeLayoutDataKey extends LayoutDataKey {
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/IsPinnedPredicate.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/IsPinnedPredicate.java
new file mode 100644
index 0000000000..943232a4c1
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/IsPinnedPredicate.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout;
+
+import java.util.ArrayList;
+
+import org.eclipse.gef.ConnectionEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.NoteEditPart;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.diagram.edit.api.part.IDiagramElementEditPart;
+import org.eclipse.sirius.diagram.part.SiriusDiagramEditorPlugin;
+import org.eclipse.sirius.diagram.tools.api.preferences.SiriusDiagramPreferencesKeys;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.PinHelper;
+
+/**
+ * A predicate to identify pinned/fixed edit-parts.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ */
+public class IsPinnedPredicate implements Predicate<IGraphicalEditPart> {
+
+ ArrayList<IDiagramElementEditPart> elementsToKeepFixed;
+
+ /**
+ * Default constructor.
+ *
+ * @param elementsToKeepFixed
+ * IDiagramElementEditPart which are not actually pinned but have
+ * to stay fixed.
+ */
+ protected IsPinnedPredicate(ArrayList<IDiagramElementEditPart> elementsToKeepFixed) {
+ this.elementsToKeepFixed = elementsToKeepFixed;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see com.google.common.base.Predicate#apply(java.lang.Object)
+ */
+ public boolean apply(final IGraphicalEditPart part) {
+ boolean result = false;
+ if (part instanceof NoteEditPart) {
+ result = applyNote((NoteEditPart) part);
+ } else {
+ result = isPinnedOrKeepFixed(part);
+ }
+ return result;
+ }
+
+ /**
+ * Applies this predicate to the given note.
+ *
+ * @param part
+ * the NoteEditPart that the predicate should act on
+ * @return the value of this predicate when applied to the input
+ * {@code part}
+ */
+ private boolean applyNote(final NoteEditPart part) {
+ boolean result = false;
+ boolean connectedToPinnedElement = false;
+ for (ConnectionEditPart sourceConn : Iterables.filter(part.getSourceConnections(), ConnectionEditPart.class)) {
+ if (sourceConn.getTarget() instanceof IGraphicalEditPart) {
+ connectedToPinnedElement = connectedToPinnedElement || isPinnedOrKeepFixed((IGraphicalEditPart) sourceConn.getTarget());
+ }
+ }
+ for (ConnectionEditPart targetConn : Iterables.filter(part.getTargetConnections(), ConnectionEditPart.class)) {
+ if (targetConn.getSource() instanceof IGraphicalEditPart) {
+ connectedToPinnedElement = connectedToPinnedElement || isPinnedOrKeepFixed((IGraphicalEditPart) targetConn.getSource());
+ }
+ }
+ if (connectedToPinnedElement) {
+ result = true;
+ } else {
+ if (!SiriusDiagramEditorPlugin.getInstance().getPluginPreferences().getBoolean(SiriusDiagramPreferencesKeys.PREF_MOVE_NOTES_DURING_LATOUT.name())) {
+ result = true;
+ }
+ }
+ return result;
+ }
+
+ private boolean isPinnedOrKeepFixed(IGraphicalEditPart part) {
+ boolean isPinnedOrKeepFixed = false;
+ if (part.resolveSemanticElement() instanceof DDiagramElement) {
+ DDiagramElement dDiagramElement = (DDiagramElement) part.resolveSemanticElement();
+ isPinnedOrKeepFixed = new PinHelper().isPinned(dDiagramElement) || (elementsToKeepFixed != null && elementsToKeepFixed.contains(part));
+ }
+ return isPinnedOrKeepFixed;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/LayoutDataHelperImpl.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/LayoutDataHelperImpl.java
new file mode 100644
index 0000000000..f13182c78a
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/LayoutDataHelperImpl.java
@@ -0,0 +1,327 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout;
+
+import java.util.Map;
+
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.PointList;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gef.ConnectionEditPart;
+import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.draw2d.ui.figures.PolylineConnectionEx;
+import org.eclipse.gmf.runtime.notation.Bounds;
+import org.eclipse.gmf.runtime.notation.ConnectorStyle;
+import org.eclipse.gmf.runtime.notation.Edge;
+import org.eclipse.gmf.runtime.notation.IdentityAnchor;
+import org.eclipse.gmf.runtime.notation.LayoutConstraint;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.NotationPackage;
+import org.eclipse.gmf.runtime.notation.Size;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Maps;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.business.api.query.DDiagramElementQuery;
+import org.eclipse.sirius.diagram.business.api.query.NodeQuery;
+import org.eclipse.sirius.diagram.layoutdata.AbstractLayoutData;
+import org.eclipse.sirius.diagram.layoutdata.EdgeLayoutData;
+import org.eclipse.sirius.diagram.layoutdata.LayoutdataFactory;
+import org.eclipse.sirius.diagram.layoutdata.NodeLayoutData;
+import org.eclipse.sirius.diagram.layoutdata.Point;
+import org.eclipse.sirius.diagram.tools.api.draw2d.ui.figures.FigureUtilities;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.LayoutDataHelper;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.LayoutDataKey;
+import org.eclipse.sirius.diagram.ui.tools.internal.layout.semantic.SemanticEdgeLayoutDataKey;
+import org.eclipse.sirius.diagram.ui.tools.internal.layout.semantic.SemanticNodeLayoutDataKey;
+
+/**
+ * Helper to manage the layout data.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ */
+public class LayoutDataHelperImpl implements LayoutDataHelper {
+
+ private static final Predicate<EObject> ROOT_PREDICATE = new Predicate<EObject>() {
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean apply(final EObject input) {
+ return input.eContainer() == null;
+ }
+ };
+
+ /**
+ * Creates the default LayoutDataHelper implementation.
+ */
+ public LayoutDataHelperImpl() {
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.layout.LayoutDataHelper#createNodeLayoutData(org.eclipse.gmf.runtime.notation.Node,
+ * org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart,
+ * org.eclipse.sirius.diagram.layoutdata.NodeLayoutData)
+ */
+ public NodeLayoutData createNodeLayoutData(final Node node, final IGraphicalEditPart editPart, final NodeLayoutData parentLayoutData) {
+ final NodeLayoutData result = LayoutdataFactory.eINSTANCE.createNodeLayoutData();
+
+ Dimension primarySize = new Dimension(0, 0);
+ // Compute the relative location from the parent layout data
+ // 1-Get the relative location
+ final org.eclipse.draw2d.geometry.Point relativeLocation = editPart.getFigure().getBounds().getLocation().getCopy();
+
+ // 2-Transform to absolute location
+ FigureUtilities.translateToAbsoluteByIgnoringScrollbar(editPart.getFigure(), relativeLocation);
+
+ boolean isCollapsed = false;
+ if (new DDiagramElementQuery((DDiagramElement) node.getElement()).isIndirectlyCollapsed()) {
+ isCollapsed = true;
+ }
+ if (isCollapsed) {
+ LayoutConstraint layoutConstraint = node.getLayoutConstraint();
+ if (layoutConstraint instanceof Bounds) {
+ NodeQuery nodeQuery = new NodeQuery(node);
+ Option<Bounds> option = nodeQuery.getExtendedBounds();
+ if (option.some()) {
+ Bounds unCollapseBounds = option.get();
+ int deltaX = ((Bounds) layoutConstraint).getX() - unCollapseBounds.getX();
+ int deltaY = ((Bounds) layoutConstraint).getY() - unCollapseBounds.getY();
+
+ relativeLocation.setLocation(relativeLocation.x - deltaX, relativeLocation.y - deltaY);
+ primarySize = new Dimension(unCollapseBounds.getWidth(), unCollapseBounds.getHeight());
+ }
+ }
+ } else {
+ final Integer width = (Integer) ViewUtil.getStructuralFeatureValue(node, NotationPackage.eINSTANCE.getSize_Width());
+ final Integer height = (Integer) ViewUtil.getStructuralFeatureValue(node, NotationPackage.eINSTANCE.getSize_Height());
+ primarySize = new Dimension(width.intValue(), height.intValue());
+ if (width.intValue() == -1 || height.intValue() == -1) {
+ primarySize = editPart.getFigure().getSize().getCopy();
+ }
+ }
+
+ // 3-Remove the parent absolute location
+ if (parentLayoutData != null) {
+ final Point parentAbsoluteLocation = LayoutDataHelper.INSTANCE.getAbsoluteLocation(parentLayoutData);
+ relativeLocation.translate(-parentAbsoluteLocation.getX(), -parentAbsoluteLocation.getY());
+ }
+
+ result.setHeight(primarySize.height);
+ result.setWidth(primarySize.width);
+ final Point location = LayoutdataFactory.eINSTANCE.createPoint();
+ location.setX(relativeLocation.x);
+ location.setY(relativeLocation.y);
+ result.setLocation(location);
+
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.layout.LayoutDataHelper#createEdgeLayoutData(org.eclipse.gmf.runtime.notation.Edge)
+ */
+ public EdgeLayoutData createEdgeLayoutData(final Edge gmfEdge, final ConnectionEditPart connectionEditPart) {
+ final EdgeLayoutData result = LayoutdataFactory.eINSTANCE.createEdgeLayoutData();
+ final ConnectorStyle connectorStyle = (ConnectorStyle) gmfEdge.getStyle(NotationPackage.eINSTANCE.getConnectorStyle());
+ if (connectorStyle != null) {
+ result.setRouting(connectorStyle.getRouting().getValue());
+ result.setJumpLinkStatus(connectorStyle.getJumpLinkStatus().getValue());
+ result.setJumpLinkType(connectorStyle.getJumpLinkType().getValue());
+ result.setReverseJumpLink(connectorStyle.isJumpLinksReverse());
+ result.setSmoothness(connectorStyle.getSmoothness().getValue());
+ }
+ if (connectionEditPart != null) {
+ final PolylineConnectionEx polylineConnectionEx = (PolylineConnectionEx) connectionEditPart.getFigure();
+ polylineConnectionEx.getConnectionRouter().route(polylineConnectionEx);
+ final org.eclipse.draw2d.geometry.Point originialSourceRefPoint = polylineConnectionEx.getSourceAnchor().getReferencePoint().getCopy();
+ polylineConnectionEx.translateToRelative(originialSourceRefPoint);
+ result.setSourceRefPoint(createPoint(originialSourceRefPoint));
+
+ final org.eclipse.draw2d.geometry.Point originialTargetRefPoint = polylineConnectionEx.getTargetAnchor().getReferencePoint().getCopy();
+ polylineConnectionEx.translateToRelative(originialTargetRefPoint);
+ result.setTargetRefPoint(createPoint(originialTargetRefPoint));
+
+ initPointList(result.getPointList(), polylineConnectionEx.getPoints().getCopy());
+ }
+ if (gmfEdge.getSourceAnchor() instanceof IdentityAnchor) {
+ result.setSourceTerminal(((IdentityAnchor) gmfEdge.getSourceAnchor()).getId());
+ }
+ if (gmfEdge.getTargetAnchor() instanceof IdentityAnchor) {
+ result.setTargetTerminal(((IdentityAnchor) gmfEdge.getTargetAnchor()).getId());
+ }
+
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.layout.LayoutDataHelper#createLabelLayoutData(org.eclipse.gmf.runtime.notation.Node)
+ */
+ public NodeLayoutData createLabelLayoutData(final Node labelNode) {
+ final NodeLayoutData result = LayoutdataFactory.eINSTANCE.createNodeLayoutData();
+
+ if (labelNode.getLayoutConstraint() instanceof Size) {
+ final Integer width = (Integer) ViewUtil.getStructuralFeatureValue(labelNode, NotationPackage.eINSTANCE.getSize_Width());
+ final Integer height = (Integer) ViewUtil.getStructuralFeatureValue(labelNode, NotationPackage.eINSTANCE.getSize_Height());
+
+ result.setWidth(width);
+ result.setHeight(height);
+ }
+
+ final Integer x = (Integer) ViewUtil.getStructuralFeatureValue(labelNode, NotationPackage.eINSTANCE.getLocation_X());
+ final Integer y = (Integer) ViewUtil.getStructuralFeatureValue(labelNode, NotationPackage.eINSTANCE.getLocation_Y());
+
+ final Point location = LayoutdataFactory.eINSTANCE.createPoint();
+ location.setX(x);
+ location.setY(y);
+
+ result.setLocation(location);
+
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.layout.LayoutDataHelper#getAbsoluteLocation(org.eclipse.sirius.diagram.layoutdata.NodeLayoutData)
+ */
+ public Point getAbsoluteLocation(final NodeLayoutData nodeLayoutData) {
+ Point result = getCopy(nodeLayoutData.getLocation());
+ if (nodeLayoutData.eContainer() instanceof NodeLayoutData) {
+ result = getTranslated(result, getAbsoluteLocation((NodeLayoutData) nodeLayoutData.eContainer()));
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.layout.LayoutDataHelper#getRelativeLocation(org.eclipse.sirius.diagram.layoutdata.NodeLayoutData,
+ * org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart)
+ */
+ public Point getRelativeLocation(final NodeLayoutData layoutData, final IGraphicalEditPart editPart) {
+ final Point result = getAbsoluteLocation(layoutData);
+ final org.eclipse.draw2d.geometry.Point p = new org.eclipse.draw2d.geometry.Point(result.getX(), result.getY());
+ FigureUtilities.translateToRelativeByIgnoringScrollbar(editPart.getFigure(), p);
+ result.setX(p.x);
+ result.setY(p.y);
+
+ return result;
+ }
+
+ /**
+ * Create a new point from a draw2d point.
+ *
+ * @param draw2dPoint
+ * The original point
+ * @return A new point
+ */
+ private Point createPoint(final org.eclipse.draw2d.geometry.Point draw2dPoint) {
+ final Point newPoint = LayoutdataFactory.eINSTANCE.createPoint();
+ newPoint.setX(draw2dPoint.x);
+ newPoint.setY(draw2dPoint.y);
+ return newPoint;
+ }
+
+ /**
+ * Initialize a list of {@link Point} from a {@link PointList}.
+ *
+ * @param pointsList
+ * the list to initialize
+ * @param draw2dPointsList
+ * the original points of the line
+ */
+ private void initPointList(final EList<Point> pointList, final PointList draw2dPointsList) {
+ for (int i = 0; i < draw2dPointsList.size(); i++) {
+ pointList.add(createPoint(draw2dPointsList.getPoint(i)));
+ }
+
+ }
+
+ /**
+ * Return a copy of this Point.
+ *
+ * @param point
+ * the point to copy
+ * @return a copy of this Point
+ */
+ private Point getCopy(final Point point) {
+ final Point copy = LayoutdataFactory.eINSTANCE.createPoint();
+ copy.setX(point.getX());
+ copy.setY(point.getY());
+ return copy;
+ }
+
+ /**
+ * Creates a new Point which is translated by the values of the provided
+ * Point.
+ *
+ * @param originalPoint
+ * The point to translate.
+ * @param pt
+ * Point which provides the translation amounts.
+ * @return A new Point
+ */
+ protected Point getTranslated(final Point originalPoint, final Point pt) {
+ final Point translatedPoint = LayoutdataFactory.eINSTANCE.createPoint();
+ translatedPoint.setX(originalPoint.getX() + pt.getX());
+ translatedPoint.setY(originalPoint.getY() + pt.getY());
+ return translatedPoint;
+ }
+
+ /**
+ * Creates a new Point which is translated by the values of the provided
+ * Point.
+ *
+ * @param originalPoint
+ * The point to translate.
+ * @param pt
+ * Point which provides the translation amounts.
+ * @return A new Point
+ */
+ public Point getTranslated(final Point originalPoint, final org.eclipse.draw2d.geometry.Point pt) {
+ final Point translatedPoint = LayoutdataFactory.eINSTANCE.createPoint();
+ translatedPoint.setX(originalPoint.getX() + pt.x);
+ translatedPoint.setY(originalPoint.getY() + pt.y);
+ return translatedPoint;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<? extends LayoutDataKey, ? extends AbstractLayoutData> getRootLayoutData(final Map<? extends LayoutDataKey, ? extends AbstractLayoutData> collection) {
+ return Maps.filterValues(collection, ROOT_PREDICATE);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public LayoutDataKey createKey(final AbstractLayoutData layoutData) {
+ LayoutDataKey result;
+ if (layoutData instanceof NodeLayoutData) {
+ result = new SemanticNodeLayoutDataKey(layoutData.getId());
+ } else if (layoutData instanceof EdgeLayoutData) {
+ result = new SemanticEdgeLayoutDataKey(layoutData.getId());
+ } else {
+ throw new IllegalArgumentException("Layoutdata of type " + layoutData.getClass() + " is unknown");
+ }
+ return result;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/LayoutUtil.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/LayoutUtil.java
new file mode 100644
index 0000000000..90d112c6f5
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/LayoutUtil.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.gmf.runtime.diagram.ui.actions.ActionIds;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.requests.ArrangeRequest;
+
+/**
+ * Some utility methods for layout.
+ *
+ * @author mchauvin
+ */
+public final class LayoutUtil {
+
+ /**
+ * Avoid instantiation.
+ */
+ private LayoutUtil() {
+
+ }
+
+ /**
+ * Launch an arrange all on the diagram.
+ *
+ * @param diagramEditPart
+ * diagramEditPart;
+ */
+ public static void arrange(final DiagramEditPart diagramEditPart) {
+ final ArrangeRequest arrangeRequest = new ArrangeRequest(ActionIds.ACTION_ARRANGE_ALL);
+ final List<Object> partsToArrange = new ArrayList<Object>(1);
+ partsToArrange.add(diagramEditPart);
+ arrangeRequest.setPartsToArrange(partsToArrange);
+ diagramEditPart.performRequest(arrangeRequest);
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/NodeLayoutDataKey.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/NodeLayoutDataKey.java
new file mode 100644
index 0000000000..9e5d9bd424
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/NodeLayoutDataKey.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout;
+
+import org.eclipse.sirius.diagram.ui.tools.api.layout.LayoutDataKey;
+
+/**
+ * Interface for all kind of key use to store
+ * {@link org.eclipse.sirius.diagram.layoutdata.NodeLayoutData}.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ */
+public interface NodeLayoutDataKey extends LayoutDataKey {
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/PinnedElementsHandler.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/PinnedElementsHandler.java
new file mode 100644
index 0000000000..5315419469
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/PinnedElementsHandler.java
@@ -0,0 +1,910 @@
+/*******************************************************************************
+ * Copyright (c) 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout;
+
+import static org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecoratorTarget.Direction.EAST;
+import static org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecoratorTarget.Direction.NORTH;
+import static org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecoratorTarget.Direction.NORTH_EAST;
+import static org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecoratorTarget.Direction.NORTH_WEST;
+import static org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecoratorTarget.Direction.SOUTH;
+import static org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecoratorTarget.Direction.SOUTH_EAST;
+import static org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecoratorTarget.Direction.SOUTH_WEST;
+import static org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecoratorTarget.Direction.WEST;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.SortedSet;
+
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Insets;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.services.decorator.IDecoratorTarget.Direction;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+import org.eclipse.sirius.diagram.edit.api.part.IDiagramElementEditPart;
+
+/**
+ * Fixes the layout of a particular level as done by a base layout provider to
+ * take pinned elements into account.
+ * <p>
+ * The general algorithm is:
+ * <ol>
+ * <li>move all the pinned elements back to their original positions;</li>
+ * <li>pack the elements by removing horizontal and vertical gaps the first step
+ * may have created;</li>
+ * <li>resolve potential overlaps between pinned elements and unpinned elements
+ * by moving unpinned elements aside.</li>
+ * </ol>
+ *
+ * @author pcdavid
+ */
+public class PinnedElementsHandler {
+ /**
+ * A flag to enable additional but potentially costly asserts and/or debug
+ * messages.
+ */
+ private static final boolean DEBUG = false;
+
+ /**
+ * Constant to indicate that padding information should be included in
+ * bounds/bounding-box computation.
+ */
+ private static final boolean INCLUDE_PADDING = true;
+
+ /**
+ * Constant to indicate that padding information should be not included in
+ * bounds/bounding-box computation.
+ */
+ private static final boolean EXCLUDE_PADDING = false;
+
+ /**
+ * The gap width to leave in between parts in addition to their padding
+ * during the packing phase. If gaps are too small, there is not enough room
+ * left to route the edges between parts, which can cause them to take a
+ * longer route. Set to twice the default gap.
+ */
+ private static final int MINIMAL_GAP_WIDTH = 60;
+
+ /**
+ * A predicate to identify pinned/fixed edit-parts.
+ */
+ private final Predicate<IGraphicalEditPart> isPinned;
+
+ /**
+ * Compares points in left-to-right, top-to-bottom ("reading") order.
+ */
+ private final Comparator<Point> pointComparator = new Comparator<Point>() {
+ public int compare(final Point p1, final Point p2) {
+ if (p1.y != p2.y) {
+ return p1.y - p2.y;
+ } else {
+ return p1.x - p2.x;
+ }
+ }
+ };
+
+ /**
+ * A comparator used to order edit parts from top-left to bottom-right. Used
+ * to produce a more regular and predictable result.
+ */
+ private final Comparator<IGraphicalEditPart> positionComparator = new Comparator<IGraphicalEditPart>() {
+ public int compare(final IGraphicalEditPart igep1, final IGraphicalEditPart igep2) {
+ return pointComparator.compare(getCurrentPosition(igep1), getCurrentPosition(igep2));
+ }
+ };
+
+ /**
+ * A comparator to sort edit-parts from left to right (taking their top-left
+ * point as reference).
+ */
+ private final Comparator<IGraphicalEditPart> leftToRightComparator = new Comparator<IGraphicalEditPart>() {
+ public int compare(final IGraphicalEditPart p1, final IGraphicalEditPart p2) {
+ return getCurrentPosition(p1).x - getCurrentPosition(p2).x;
+ }
+ };
+
+ /**
+ * A comparator to sort edit-parts from top to bottom (taking their top-left
+ * point as reference).
+ */
+ private final Comparator<IGraphicalEditPart> topToBottomComparator = new Comparator<IGraphicalEditPart>() {
+ public int compare(final IGraphicalEditPart p1, final IGraphicalEditPart p2) {
+ return getCurrentPosition(p1).y - getCurrentPosition(p2).y;
+ }
+ };
+
+ /**
+ * All the edit parts to consider for the layout, ordered by their position.
+ */
+ private final SortedSet<IGraphicalEditPart> allEditParts = Sets.newTreeSet(positionComparator);
+
+ /**
+ * All the pinned edit parts. A subset of <code>allEditParts</code>.
+ */
+ private final SortedSet<IGraphicalEditPart> fixedEditParts = Sets.newTreeSet(positionComparator);
+
+ /**
+ * The initial bounds of the edit parts, as computed by previous layout
+ * providers but not yet applied.
+ */
+ private final Map<IGraphicalEditPart, Rectangle> initialBounds;
+
+ /**
+ * The currently computed bounds of the edit parts. Stored separately so
+ * they can be easily reset.
+ */
+ private final Map<IGraphicalEditPart, Rectangle> currentBounds = Maps.newHashMap();
+
+ /**
+ * Provides access to additional layout constraints and preferences
+ * specified in the VSM.
+ */
+ private final DiagramLayoutCustomization layoutCustomization;
+
+ /**
+ * IDiagramElementEditPart which are not actually pinned but have to stay
+ * fixed.
+ */
+ private ArrayList<IDiagramElementEditPart> elementsToKeepFixed;
+
+ /**
+ * Creates a new resolver.
+ *
+ * @param parts
+ * all the edit parts to consider.
+ * @param initialBounds
+ * the initial locations of the edit parts, as computed by
+ * previous layout providers but not yet applied.
+ * @param elementsToKeepFixed
+ * IDiagramElementEditPart which are not actually pinned but have
+ * to stay fixed
+ */
+ public PinnedElementsHandler(final Collection<IGraphicalEditPart> parts, final Map<IGraphicalEditPart, Rectangle> initialBounds, ArrayList<IDiagramElementEditPart> elementsToKeepFixed) {
+ this.initialBounds = Collections.unmodifiableMap(getAllInitialPositions(parts, initialBounds));
+ this.elementsToKeepFixed = elementsToKeepFixed;
+ this.allEditParts.addAll(parts);
+ this.isPinned = new IsPinnedPredicate(this.elementsToKeepFixed);
+ this.fixedEditParts.addAll(Collections2.filter(parts, isPinned));
+ this.layoutCustomization = new DiagramLayoutCustomization();
+ this.layoutCustomization.initializePaddingWithEditParts(Lists.newArrayList(parts));
+ }
+
+ private Map<IGraphicalEditPart, Rectangle> getAllInitialPositions(final Collection<IGraphicalEditPart> parts, final Map<IGraphicalEditPart, Rectangle> explicitBounds) {
+ final Map<IGraphicalEditPart, Rectangle> result = Maps.newHashMap(explicitBounds);
+ for (IGraphicalEditPart part : parts) {
+ if (!result.containsKey(part)) {
+ final Rectangle bounds = part.getFigure().getBounds().getCopy();
+ result.put(part, bounds);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Computes the new locations of all the parts to move to handle pinned
+ * elements properly.
+ *
+ * @return for each part which needs to move, the new position it should be
+ * moved to.
+ */
+ public Map<IGraphicalEditPart, Point> computeSolution() {
+ resetPinnedElements();
+ removeGaps();
+ resolveOverlaps();
+ return getSolution();
+ }
+
+ private boolean hasRemainingSolvableOverlaps() {
+ for (IGraphicalEditPart part : fixedEditParts) {
+ if (!Collections2.filter(findOverlappingParts(part), Predicates.not(isPinned)).isEmpty()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Move all the pinned parts back to their original positions. We can not
+ * tell the original layout algorithm to simply ignore them (too many
+ * side-effects) or consider them as obstacles, so we must cleanup after it.
+ */
+ private void resetPinnedElements() {
+ for (IGraphicalEditPart part : fixedEditParts) {
+ // Access currentBounds directly: #setCurrentPosition() refuses to
+ // move pinned parts.
+ currentBounds.put(part, part.getFigure().getBounds().getCopy());
+ }
+ }
+
+ /**
+ * Pack the layout to avoid vertical and horizontal gaps left by the pinned
+ * parts after they are moved back to their original positions. Only the
+ * gaps which take the whole height/width of the diagram and are wide enough
+ * are taken into account ("wide enough" meaning beyond the configurable
+ * padding associated to the diagram elements).
+ */
+ private void removeGaps() {
+ if (fixedEditParts.isEmpty()) {
+ /*
+ * The packing algorithms are potentially costly if there are many
+ * elements. If there are no pinned elements, the basic layout
+ * algorithms should not have created any substantial gaps, so don't
+ * try to find gaps which very probably do not exist.
+ */
+ return;
+ }
+ packHorizontally();
+ packVertically();
+ }
+
+ /**
+ * Finds all the packable vertical gaps with no edit-parts and moves the
+ * parts beyond them to the left to reduce the gap to the minimum while
+ * still respecting the parts' padding.
+ */
+ private void packHorizontally() {
+ final int[] hRange = getHorizontalRange(allEditParts, EXCLUDE_PADDING);
+ final List<IGraphicalEditPart> movableParts = Lists.newArrayList(Collections2.filter(allEditParts, Predicates.not(isPinned)));
+ Collections.sort(movableParts, leftToRightComparator);
+ for (int i = 0; i < movableParts.size(); i++) {
+ /*
+ * Split the movable parts into two groups (left and right) on index
+ * i. If there is a sufficiently large gap between the two groups,
+ * move the elements of the right group to the left.
+ */
+ final Set<IGraphicalEditPart> leftSide = Sets.newHashSet(movableParts.subList(0, i));
+ final Rectangle leftBox;
+ final Insets leftPadding;
+ if (i == 0) {
+ // Artificial box corresponding to the left margin of the figure
+ // along which to pack.
+ leftBox = new Rectangle(hRange[0] - 1, 0, 1, 1);
+ leftPadding = new Insets(0, 0, 0, 0);
+ } else {
+ leftBox = getBoundingBox(leftSide, EXCLUDE_PADDING);
+ leftPadding = getPadding(leftSide);
+ }
+
+ final Set<IGraphicalEditPart> rightSide = Sets.newHashSet(movableParts.subList(i, movableParts.size()));
+ final Rectangle rightBox = getBoundingBox(rightSide, EXCLUDE_PADDING);
+ final Insets rightPadding = getPadding(rightSide);
+
+ final int currentGapWidth = rightBox.getLeft().x - leftBox.getRight().x;
+ final int minGapWidth = Math.max(MINIMAL_GAP_WIDTH, Math.max(leftPadding.right, rightPadding.left));
+ if (i == 0 && isHorizontalOriginFree(allEditParts, hRange[0])) {
+ // We can move the rightSide elements to the free space
+ translate(rightSide, new Dimension(-currentGapWidth, 0));
+ } else if (currentGapWidth > minGapWidth) {
+ translate(rightSide, new Dimension(-(currentGapWidth - minGapWidth), 0));
+ }
+ }
+ }
+
+ /**
+ * Check if the some parts of the diagram are already to the x origin
+ * position.
+ *
+ * @param parts
+ * List of parts to check
+ * @param xOrigin
+ * The x coordinate to consider as the origin
+ * @return true if the x origin is free
+ */
+ private boolean isHorizontalOriginFree(SortedSet<IGraphicalEditPart> parts, int xOrigin) {
+ boolean result = true;
+ for (IGraphicalEditPart part : parts) {
+ final Rectangle bounds = getCurrentBounds(part, false);
+ result = result && bounds.x != xOrigin;
+ }
+ return result;
+ }
+
+ /**
+ * Check if the some parts of the diagram are already to the y origin
+ * position.
+ *
+ * @param parts
+ * List of parts to check
+ * @param yOrigin
+ * The y coordinate to consider as the origin
+ * @return true if the x origin is free
+ */
+ private boolean isVerticalOriginFree(SortedSet<IGraphicalEditPart> parts, int yOrigin) {
+ boolean result = true;
+ for (IGraphicalEditPart part : parts) {
+ final Rectangle bounds = getCurrentBounds(part, false);
+ result = result && bounds.y != yOrigin;
+ }
+ return result;
+ }
+
+ /**
+ * Compute the horizontal position range for the given <code>parts</code>.
+ *
+ * @param parts
+ * The list of parts to consider
+ * @param includePadding
+ * true if we must include padding, false otherwise
+ * @return the horizontal range
+ */
+ private int[] getHorizontalRange(final Collection<IGraphicalEditPart> parts, final boolean includePadding) {
+ int minPadding = getSmallestHorizontalMargin(parts);
+ int min = minPadding;
+ int max = Integer.MIN_VALUE;
+ for (IGraphicalEditPart part : parts) {
+ final Rectangle bounds = getCurrentBounds(part, includePadding);
+ min = Math.min(min, bounds.getLeft().x);
+ max = Math.max(max, bounds.getRight().x);
+ }
+ // The minimum can not be less than the minPadding
+ min = Math.max(min, minPadding);
+ return new int[] { min, max };
+ }
+
+ /**
+ * Get the smallest margin to the left of the container for the given
+ * <code>parts</code>.
+ *
+ * @param parts
+ * The list of parts to consider
+ * @return the smallest margin to the left of the container
+ */
+ private int getSmallestHorizontalMargin(final Collection<IGraphicalEditPart> parts) {
+ int min = Integer.MAX_VALUE;
+ for (IGraphicalEditPart part : parts) {
+ if (part.getParent() instanceof DiagramEditPart) {
+ // We don't consider padding in diagram
+ min = 0;
+ } else {
+ min = Math.min(min, layoutCustomization.getNodePadding(part).left);
+ }
+ }
+ return min;
+ }
+
+ /**
+ * Finds all the packable horizontal gaps with no edit-parts and moves the
+ * parts beyond them to the top to reduce the gap to the minimum while still
+ * respecting the parts' padding.
+ */
+ private void packVertically() {
+ final int[] vRange = getVerticalRange(allEditParts, EXCLUDE_PADDING);
+ final List<IGraphicalEditPart> movableParts = Lists.newArrayList(Collections2.filter(allEditParts, Predicates.not(isPinned)));
+ Collections.sort(movableParts, topToBottomComparator);
+ for (int i = 0; i < movableParts.size(); i++) {
+ /*
+ * Split the movable parts into two groups (top and bottom) on index
+ * i. If there is a sufficiently large gap between the two groups,
+ * move the elements of the bottom group to the top.
+ */
+ final Set<IGraphicalEditPart> topSide = Sets.newHashSet(movableParts.subList(0, i));
+ final Rectangle topBox;
+ final Insets topPadding;
+ if (i == 0) {
+ // Artificial box corresponding to the top margin of the figure
+ // along which to pack.
+ topBox = new Rectangle(0, vRange[0] - 1, 1, 1);
+ topPadding = new Insets(0, 0, 0, 0);
+ } else {
+ topBox = getBoundingBox(topSide, EXCLUDE_PADDING);
+ topPadding = getPadding(topSide);
+ }
+
+ final Set<IGraphicalEditPart> bottomSide = Sets.newHashSet(movableParts.subList(i, movableParts.size()));
+ final Rectangle bottomBox = getBoundingBox(bottomSide, EXCLUDE_PADDING);
+ final Insets bottomPadding = getPadding(bottomSide);
+
+ final int currentGapWidth = bottomBox.getTop().y - topBox.getBottom().y;
+ final int minGapWidth = Math.max(MINIMAL_GAP_WIDTH, Math.max(topPadding.bottom, bottomPadding.top));
+ if (i == 0 && isVerticalOriginFree(allEditParts, vRange[0])) {
+ // We can move the bottomSide elements to the free space
+ translate(bottomSide, new Dimension(0, -currentGapWidth));
+ } else if (currentGapWidth > minGapWidth) {
+ translate(bottomSide, new Dimension(0, -(currentGapWidth - minGapWidth)));
+ }
+ }
+ }
+
+ /**
+ * Compute the vertical position range for the given <code>parts</code>.
+ *
+ * @param parts
+ * The list of parts to consider
+ * @param includePadding
+ * true if we must include padding, false otherwise
+ * @return the vertical range
+ */
+ private int[] getVerticalRange(final Collection<IGraphicalEditPart> parts, final boolean includePadding) {
+ int minPadding = getSmallestVerticalMargin(parts);
+ int min = minPadding;
+ int max = Integer.MIN_VALUE;
+ for (IGraphicalEditPart part : parts) {
+ final Rectangle bounds = getCurrentBounds(part, includePadding);
+ min = Math.min(min, bounds.getTop().y);
+ max = Math.max(max, bounds.getBottom().y);
+ }
+ // The minimum can not be less than the minPadding
+ min = Math.max(min, minPadding);
+ return new int[] { min, max };
+ }
+
+ /**
+ * Get the smallest margin to the top of the container for the given
+ * <code>parts</code>.
+ *
+ * @param parts
+ * The list of parts to consider
+ * @return the smallest margin to the top of the container
+ */
+ private int getSmallestVerticalMargin(final Collection<IGraphicalEditPart> parts) {
+ int min = Integer.MAX_VALUE;
+ for (IGraphicalEditPart part : parts) {
+ if (part.getParent() instanceof DiagramEditPart) {
+ // We don't consider padding in diagram
+ min = 0;
+ } else {
+ min = Math.min(min, layoutCustomization.getNodePadding(part).top);
+ }
+ }
+ return min;
+ }
+
+ /**
+ * Resolve all the overlaps between pinned parts and movable parts.
+ */
+ private void resolveOverlaps() {
+ for (IGraphicalEditPart part : fixedEditParts) {
+ resolveOverlaps(part);
+ }
+ assert !hasRemainingSolvableOverlaps() : "solvable but unsolved overlaps remain";
+ }
+
+ /**
+ * Resolve all the overlaps concerning the given fixed edit part. This
+ * method may also resolve overlaps concerning other fixed parts in the
+ * process, but will at least resolve all the (solvable) ones concerning the
+ * specified part. After successful execution of this method, the only parts
+ * overlapping <code>fixedPart</code>, if any, are also fixed parts, and
+ * thus are unsolvable overlaps.
+ *
+ * @param fixedPart
+ * the fixed edit part to consider.
+ */
+ private void resolveOverlaps(final IGraphicalEditPart fixedPart) {
+ final Set<IGraphicalEditPart> solvableOverlaps = Sets.filter(findOverlappingParts(fixedPart), Predicates.not(isPinned));
+ final Map<Direction, SortedSet<IGraphicalEditPart>> groupedOverlaps = groupByDirection(fixedPart, solvableOverlaps);
+ for (Entry<Direction, SortedSet<IGraphicalEditPart>> group : groupedOverlaps.entrySet()) {
+ // For a same group, we kept the movedPositions to allow a complete
+ // rollback to move again several parts in same time
+ Map<IGraphicalEditPart, Point> previousMovedPositionsBefore = Maps.newHashMap();
+ for (IGraphicalEditPart part : group.getValue()) {
+ assert overlaps(fixedPart, part);
+ previousMovedPositionsBefore = moveAside(Collections.singleton(part), Collections.singleton(fixedPart), group.getKey(), previousMovedPositionsBefore);
+ assert !overlaps(fixedPart, part);
+ }
+ }
+ assert Collections2.filter(findOverlappingParts(fixedPart), Predicates.not(isPinned)).isEmpty() : "solvable but unsolved overlaps remain";
+ }
+
+ /**
+ * Move the specified movable parts in the specified direction enough to
+ * avoid overlaps with all the specified fixed parts while not creating any
+ * new overlap with other fixed parts. All the movable parts are translated
+ * of the same amount, as a group. More movable parts than the ones
+ * specified explicitly may be move along as they are "pushed" aside to make
+ * enough room.
+ *
+ * @param parts
+ * the parts to move.
+ * @param fixedParts
+ * the fixed parts to avoid.
+ * @param dir
+ * the general direction in which to move the movable parts.
+ * @param previousMovedPositionsOfSameDir
+ * the list of original position of each edit parts that have
+ * previously moved in this direction
+ * @return The positions done during this step (and previous steps) to
+ * eventually used it to restore the previous position.
+ */
+ private Map<IGraphicalEditPart, Point> moveAside(final Set<IGraphicalEditPart> parts, final Set<IGraphicalEditPart> fixedParts, final Direction dir,
+ Map<IGraphicalEditPart, Point> previousMovedPositionsOfSameDir) {
+ /*
+ * First try to move just enough to avoid the explicitly specified
+ * obstacles.
+ */
+ addSavePositions(parts, previousMovedPositionsOfSameDir);
+ tryMove(parts, fixedParts, dir);
+ final Set<IGraphicalEditPart> overlaps = findOverlappingParts(parts);
+ if (!overlaps.isEmpty()) {
+ /*
+ * We created new overlaps. Try a more aggressive change, taking
+ * more parts into consideration and/or moving further.
+ */
+ Set<IGraphicalEditPart> newMovables = parts;
+ Set<IGraphicalEditPart> newFixed = fixedParts;
+
+ final Set<IGraphicalEditPart> movableOverlaps = Sets.newHashSet(Collections2.filter(overlaps, Predicates.not(isPinned)));
+ if (!movableOverlaps.isEmpty()) {
+ /*
+ * If we created new overlaps with movable parts, simply re-try
+ * with an extended set of movable parts including the ones we
+ * need to push along.
+ */
+ newMovables = Sets.union(parts, movableOverlaps);
+ }
+
+ final Set<IGraphicalEditPart> fixedOverlaps = Sets.newHashSet(Collections2.filter(overlaps, isPinned));
+ if (!fixedOverlaps.isEmpty()) {
+ /*
+ * If we created new overlaps with other fixed parts, re-try
+ * with an extended set of fixed obstacles to avoid.
+ */
+ newFixed = Sets.union(fixedParts, fixedOverlaps);
+ }
+
+ /*
+ * Retry with the new, extended sets of parts to consider.
+ */
+ assert newMovables.size() > parts.size() || newFixed.size() > fixedParts.size();
+ moveParts(newMovables, previousMovedPositionsOfSameDir);
+ moveAside(newMovables, newFixed, dir, previousMovedPositionsOfSameDir);
+ }
+ /*
+ * Check that the specified movable parts no longer overlap with the
+ * specified fixed parts.
+ */
+ assert Sets.intersection(Sets.filter(findOverlappingParts(fixedParts), Predicates.not(isPinned)), parts).isEmpty();
+ return previousMovedPositionsOfSameDir;
+ }
+
+ private Map<IGraphicalEditPart, Point> addSavePositions(final Set<IGraphicalEditPart> parts, Map<IGraphicalEditPart, Point> positionsBefore) {
+ for (IGraphicalEditPart part : parts) {
+ positionsBefore.put(part, getCurrentPosition(part));
+ }
+ return positionsBefore;
+ }
+
+ /**
+ * Translate all the given <code>parts</code> of the same amount in the
+ * specified <code>direction</code> as far as required to avoid overlaps
+ * with the specified <code>fixedParts</code>. The move may create new
+ * overlaps with parts other than those in <code>fixedParts</code>.
+ */
+ private void tryMove(final Set<IGraphicalEditPart> parts, final Set<IGraphicalEditPart> fixedParts, final Direction direction) {
+ assert !Sets.intersection(Sets.filter(findOverlappingParts(fixedParts), Predicates.not(isPinned)), parts).isEmpty();
+ final Rectangle movablesBox = getBoundingBox(parts, EXCLUDE_PADDING);
+ final Insets movablesPadding = getPadding(parts);
+ final Rectangle fixedBox = getBoundingBox(fixedParts, EXCLUDE_PADDING);
+ final Insets fixedPadding = getPadding(fixedParts);
+ final Dimension move = computeMoveVector(movablesBox, movablesPadding, fixedBox, fixedPadding, direction);
+ for (IGraphicalEditPart part : parts) {
+ translate(part, move);
+ }
+ assert Sets.intersection(Sets.filter(findOverlappingParts(fixedParts), Predicates.not(isPinned)), parts).isEmpty();
+ }
+
+ /**
+ * Computes the global padding of a set of edit parts.
+ */
+ private Insets getPadding(final Set<IGraphicalEditPart> parts) {
+ final Rectangle smallBox = getBoundingBox(parts, EXCLUDE_PADDING);
+ final Rectangle bigBox = getBoundingBox(parts, INCLUDE_PADDING);
+ final int top = verticalDistance(bigBox.getTop(), smallBox.getTop());
+ final int left = horizontalDistance(bigBox.getLeft(), smallBox.getLeft());
+ final int bottom = verticalDistance(bigBox.getBottom(), smallBox.getBottom());
+ final int right = horizontalDistance(bigBox.getRight(), smallBox.getRight());
+ return new Insets(top, left, bottom, right);
+ }
+
+ private void translate(final Set<IGraphicalEditPart> parts, final Dimension move) {
+ for (IGraphicalEditPart part : parts) {
+ translate(part, move);
+ }
+ }
+
+ private void translate(final IGraphicalEditPart part, final Dimension move) {
+ setCurrentPosition(part, getCurrentPosition(part).getTranslated(move));
+ }
+
+ /**
+ * Computes a move vector suitable to translate <code>movable</code> in the
+ * specified <code>direction</code> until it no longer overlaps with
+ * <code>fixed</code>. Assumes the two rectangles specified overlap when
+ * taking their padding into account.
+ */
+ private Dimension computeMoveVector(final Rectangle movable, final Insets movablePadding, final Rectangle fixed, final Insets fixedPadding, final Direction direction) {
+ final Dimension move;
+ if (direction == NORTH) {
+ move = computeNorthMoveVector(movable, movablePadding, fixed, fixedPadding);
+ } else if (direction == SOUTH) {
+ move = computeSouthMoveVector(movable, movablePadding, fixed, fixedPadding);
+ } else if (direction == EAST) {
+ move = computeEastMoveVector(movable, movablePadding, fixed, fixedPadding);
+ } else if (direction == WEST) {
+ move = computeWestMoveVector(movable, movablePadding, fixed, fixedPadding);
+ } else if (direction == NORTH_EAST) {
+ move = computeMoveVector(movable, movablePadding, fixed, fixedPadding, NORTH).expand(computeMoveVector(movable, movablePadding, fixed, fixedPadding, EAST));
+ } else if (direction == NORTH_WEST) {
+ move = computeMoveVector(movable, movablePadding, fixed, fixedPadding, NORTH).expand(computeMoveVector(movable, movablePadding, fixed, fixedPadding, WEST));
+ } else if (direction == SOUTH_EAST) {
+ move = computeMoveVector(movable, movablePadding, fixed, fixedPadding, SOUTH).expand(computeMoveVector(movable, movablePadding, fixed, fixedPadding, EAST));
+ } else if (direction == SOUTH_WEST) {
+ move = computeMoveVector(movable, movablePadding, fixed, fixedPadding, SOUTH).expand(computeMoveVector(movable, movablePadding, fixed, fixedPadding, WEST));
+ } else {
+ move = null;
+ assert false : "Unknown direction";
+ }
+ return move;
+ }
+
+ private Dimension computeWestMoveVector(final Rectangle movable, final Insets movablePadding, final Rectangle fixed, final Insets fixedPadding) {
+ final Dimension move;
+ if (movable.intersects(fixed)) {
+ final int padding = Math.max(movablePadding.right, fixedPadding.left);
+ move = new Dimension(-(padding + horizontalDistance(fixed.getLeft(), movable.getRight())), 0);
+ } else {
+ final int dx1 = horizontalDistance(fixed.getExpanded(fixedPadding).getLeft(), movable.getRight());
+ final int dx2 = horizontalDistance(fixed.getLeft(), movable.getExpanded(movablePadding).getRight());
+ move = new Dimension(-Math.max(dx1, dx2), 0);
+ }
+ return move;
+ }
+
+ private Dimension computeEastMoveVector(final Rectangle movable, final Insets movablePadding, final Rectangle fixed, final Insets fixedPadding) {
+ final Dimension move;
+ if (movable.intersects(fixed)) {
+ final int padding = Math.max(movablePadding.left, fixedPadding.right);
+ move = new Dimension(padding + horizontalDistance(fixed.getRight(), movable.getLeft()), 0);
+ } else {
+ final int dx1 = horizontalDistance(fixed.getExpanded(fixedPadding).getRight(), movable.getLeft());
+ final int dx2 = horizontalDistance(fixed.getRight(), movable.getExpanded(movablePadding).getLeft());
+ move = new Dimension(Math.max(dx1, dx2), 0);
+ }
+ return move;
+ }
+
+ private Dimension computeSouthMoveVector(final Rectangle movable, final Insets movablePadding, final Rectangle fixed, final Insets fixedPadding) {
+ final Dimension move;
+ if (movable.intersects(fixed)) {
+ final int padding = Math.max(movablePadding.top, fixedPadding.bottom);
+ move = new Dimension(0, padding + verticalDistance(fixed.getBottom(), movable.getTop()));
+ } else {
+ final int dy1 = verticalDistance(fixed.getExpanded(fixedPadding).getBottom(), movable.getTop());
+ final int dy2 = verticalDistance(fixed.getBottom(), movable.getExpanded(movablePadding).getTop());
+ move = new Dimension(0, Math.max(dy1, dy2));
+ }
+ return move;
+ }
+
+ private Dimension computeNorthMoveVector(final Rectangle movable, final Insets movablePadding, final Rectangle fixed, final Insets fixedPadding) {
+ final Dimension move;
+ if (movable.intersects(fixed)) {
+ final int padding = Math.max(movablePadding.bottom, fixedPadding.top);
+ move = new Dimension(0, -(padding + verticalDistance(fixed.getTop(), movable.getBottom())));
+ } else {
+ final int dy1 = verticalDistance(fixed.getExpanded(fixedPadding).getTop(), movable.getBottom());
+ final int dy2 = verticalDistance(fixed.getTop(), movable.getExpanded(movablePadding).getBottom());
+ move = new Dimension(0, -Math.max(dy1, dy2));
+ }
+ return move;
+ }
+
+ private int verticalDistance(final Point p1, final Point p2) {
+ return Math.abs(p1.y - p2.y);
+ }
+
+ private int horizontalDistance(final Point p1, final Point p2) {
+ return Math.abs(p1.x - p2.x);
+ }
+
+ private Map<Direction, SortedSet<IGraphicalEditPart>> groupByDirection(final IGraphicalEditPart origin, final Set<IGraphicalEditPart> parts) {
+ final Map<Direction, SortedSet<IGraphicalEditPart>> result = Maps.newHashMap();
+ for (IGraphicalEditPart part : parts) {
+ final Direction dir = getDirection(origin, part);
+ if (!result.containsKey(dir)) {
+ result.put(dir, Sets.newTreeSet(positionComparator));
+ }
+ result.get(dir).add(part);
+ }
+ return result;
+ }
+
+ private Direction getDirection(final IGraphicalEditPart sourcePart, final IGraphicalEditPart destPart) {
+ final Point source = getCurrentBounds(sourcePart, EXCLUDE_PADDING).getCenter();
+ final Point dest = getCurrentBounds(destPart, EXCLUDE_PADDING).getCenter();
+ final int dx = dest.x - source.x;
+ final int dy = dest.y - source.y;
+ final Direction result;
+ if (dx < 0) {
+ if (dy < 0) {
+ result = NORTH_WEST;
+ } else if (dy == 0) {
+ result = WEST;
+ } else {
+ result = SOUTH_WEST;
+ }
+ } else if (dx > 0) {
+ if (dy < 0) {
+ result = NORTH_EAST;
+ } else if (dy == 0) {
+ result = EAST;
+ } else {
+ result = SOUTH_EAST;
+ }
+ } else {
+ if (dy < 0) {
+ result = NORTH;
+ } else if (dy == 0) {
+ // Default to SOUTH if the parts have the same center
+ result = EAST;
+ } else {
+ result = SOUTH;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns all the parts which overlap with any of the specified parts. Does
+ * not consider internal overlap between the specified elements themselves.
+ */
+ private Set<IGraphicalEditPart> findOverlappingParts(final Set<IGraphicalEditPart> parts) {
+ final Set<IGraphicalEditPart> result = Sets.newHashSet();
+ for (IGraphicalEditPart part : parts) {
+ result.addAll(findOverlappingParts(part));
+ }
+ result.removeAll(parts);
+ return result;
+ }
+
+ private Set<IGraphicalEditPart> findOverlappingParts(final IGraphicalEditPart part) {
+ final Set<IGraphicalEditPart> result = Sets.newHashSet();
+ for (IGraphicalEditPart candidate : allEditParts) {
+ if (overlaps(candidate, part)) {
+ result.add(candidate);
+ }
+ }
+ return result;
+ }
+
+ private boolean overlaps(final IGraphicalEditPart part1, final IGraphicalEditPart part2) {
+ if (part1 == part2) {
+ return false;
+ } else {
+ return getCurrentBounds(part1, EXCLUDE_PADDING).intersects(getCurrentBounds(part2, INCLUDE_PADDING))
+ || getCurrentBounds(part1, INCLUDE_PADDING).intersects(getCurrentBounds(part2, EXCLUDE_PADDING));
+ }
+ }
+
+ private Rectangle getBoundingBox(final Set<IGraphicalEditPart> parts, final boolean includePadding) {
+ Rectangle box = null;
+ for (IGraphicalEditPart part : parts) {
+ if (box == null) {
+ box = getCurrentBounds(part, includePadding);
+ } else {
+ box = box.getUnion(getCurrentBounds(part, includePadding));
+ }
+ }
+ return box;
+ }
+
+ private Point getInitialPosition(final IGraphicalEditPart part) {
+ return getInitialBounds(part).getTopLeft();
+ }
+
+ private Rectangle getInitialBounds(final IGraphicalEditPart part) {
+ return initialBounds.get(part);
+ }
+
+ private Map<IGraphicalEditPart, Point> getSolution() {
+ final Map<IGraphicalEditPart, Point> result = Maps.newHashMap();
+ for (IGraphicalEditPart part : currentBounds.keySet()) {
+ result.put(part, currentBounds.get(part).getTopLeft());
+ }
+ return result;
+ }
+
+ private Point getCurrentPosition(final IGraphicalEditPart part) {
+ return getCurrentBounds(part, EXCLUDE_PADDING).getTopLeft();
+ }
+
+ private Rectangle getCurrentBounds(final IGraphicalEditPart part, final boolean includePadding) {
+ final Rectangle bounds;
+ if (currentBounds.containsKey(part)) {
+ bounds = currentBounds.get(part);
+ } else {
+ bounds = getInitialBounds(part);
+ }
+ if (includePadding == INCLUDE_PADDING) {
+ final Insets padding = layoutCustomization.getNodePadding(part);
+ return bounds.getExpanded(padding);
+ } else {
+ return bounds;
+ }
+ }
+
+ private void setCurrentPosition(final IGraphicalEditPart part, final Point position) {
+ Preconditions.checkArgument(!isPinned.apply(part), "Pinned elements can not move");
+ if (position.equals(getInitialPosition(part))) {
+ currentBounds.remove(part);
+ } else {
+ final Rectangle oldBounds = getCurrentBounds(part, EXCLUDE_PADDING);
+ final Rectangle newBounds = new Rectangle(position.x, position.y, oldBounds.width, oldBounds.height);
+ currentBounds.put(part, newBounds);
+ }
+ }
+
+ /**
+ * Move all the specified parts to the new positions specified in the map.
+ */
+ private void moveParts(Set<IGraphicalEditPart> partToReset, final Map<IGraphicalEditPart, Point> positions) {
+ for (IGraphicalEditPart editPart : partToReset) {
+ // If the editPart has not been moved in the same direction, its
+ // initial position can not be found.
+ if (positions.get(editPart) != null) {
+ setCurrentPosition(editPart, positions.get(editPart));
+ positions.remove(editPart);
+ }
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private void printInitialState() {
+ debugMessage("===============================================================================");
+ debugMessage("Initial state (before #resolveOverlaps()");
+ debugMessage("----------------------------------------");
+ for (IGraphicalEditPart part : allEditParts) {
+ debugMessage("- " + part.getClass().getSimpleName() + " (semantic: " + part.resolveSemanticElement() + ")");
+ debugMessage(" Pinned: " + isPinned.apply(part));
+ debugMessage(" Intrinsic bounds (main figure): " + part.getFigure().getBounds());
+ debugMessage(" Initial bounds (after previous layout pass): " + getInitialBounds(part));
+ }
+ debugMessage("");
+ }
+
+ @SuppressWarnings("unused")
+ private void printResolvedState() {
+ debugMessage("Solution (only moved elements)");
+ debugMessage("------------------------------");
+ for (IGraphicalEditPart part : currentBounds.keySet()) {
+ debugMessage("- " + part.getClass().getSimpleName() + " (semantic: " + part.resolveSemanticElement() + ")");
+ debugMessage(" Pinned: " + isPinned.apply(part));
+ debugMessage(" Intrinsic bounds (main figure): " + part.getFigure().getBounds());
+ debugMessage(" Initial bounds (after previous layout pass): " + getInitialBounds(part));
+ debugMessage(" Computed bounds (after resolution): " + getCurrentPosition(part));
+ }
+ debugMessage("");
+ }
+
+ private void debugMessage(final String msg) {
+ if (DEBUG) {
+ // CHECKSTYLE:OFF
+ System.out.println("DEBUG: " + msg);
+ // CHECKSTYLE:ON
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/data/extension/LayoutDataManagerDescriptor.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/data/extension/LayoutDataManagerDescriptor.java
new file mode 100644
index 0000000000..49d2084442
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/data/extension/LayoutDataManagerDescriptor.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright (c) 2011 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout.data.extension;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+
+import org.eclipse.sirius.common.ui.SiriusTransPlugin;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.ILayoutDataManagerProvider;
+
+/**
+ * Describes a extension as contributed to the
+ * {@link LayoutDataManagerRegistryListener#LAYOUT_DATA_MANAGER_PROVIDER_EXTENSION_POINT}
+ * extension point.
+ *
+ * @author mporhel
+ *
+ */
+public class LayoutDataManagerDescriptor {
+
+ /**
+ * Name of the attribute corresponding to the contributed class's path.
+ */
+ public static final String LAYOUT_DATA_MANAGER_PROVIDER_CLASS_NAME = "class";
+
+ /**
+ * Name of the attribute corresponding to the contributed id.
+ */
+ public static final String LAYOUT_DATA_MANAGER_PROVIDER_ID = "icon";
+
+ /**
+ * Configuration element of this descriptor .
+ */
+ private final IConfigurationElement element;
+
+ /**
+ * The path of the contributed class.
+ */
+ private String extensionClassName;
+
+ /**
+ * The {@link ILayoutDataManagerProvider} described by this descriptor.
+ */
+ private ILayoutDataManagerProvider extension;
+
+ private String id;
+
+ /**
+ * Instantiates a descriptor with all information.
+ *
+ * @param configuration
+ * Configuration element from which to create this descriptor.
+ */
+ public LayoutDataManagerDescriptor(IConfigurationElement configuration) {
+ element = configuration;
+ extensionClassName = configuration.getAttribute(LAYOUT_DATA_MANAGER_PROVIDER_CLASS_NAME);
+ }
+
+ /**
+ * Creates an instance of this descriptor's
+ * {@link ILayoutDataManagerProvider} .
+ *
+ * @return A new instance of this descriptor's
+ * {@link ILayoutDataManagerProvider}.
+ */
+ public ILayoutDataManagerProvider getLayoutDataManagerProvider() {
+ if (extension == null) {
+ try {
+ extension = (ILayoutDataManagerProvider) element.createExecutableExtension(LAYOUT_DATA_MANAGER_PROVIDER_CLASS_NAME);
+ } catch (CoreException e) {
+ SiriusTransPlugin.INSTANCE.error(e.getMessage(), e);
+ }
+ }
+ return extension;
+ }
+
+ /**
+ * Return the id of the current tab extension.
+ *
+ * @return the id of the current tab extension.
+ */
+ public String getId() {
+ if (id == null) {
+ id = element.getAttribute(LAYOUT_DATA_MANAGER_PROVIDER_ID);
+ }
+ return id;
+ }
+
+ /**
+ * Returns the fully qualified name of the contributed class.
+ *
+ * @return the fully qualified name of the contributed class
+ */
+ public String getExtensionClassName() {
+ return extensionClassName;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/data/extension/LayoutDataManagerRegistry.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/data/extension/LayoutDataManagerRegistry.java
new file mode 100644
index 0000000000..1d2495f380
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/data/extension/LayoutDataManagerRegistry.java
@@ -0,0 +1,161 @@
+/*******************************************************************************
+ * Copyright (c) 2011 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout.data.extension;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+import org.eclipse.sirius.common.tools.api.util.StringUtil;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.ILayoutDataManagerProvider;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.SiriusLayoutDataManager;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.SiriusLayoutDataManagerForSemanticElementsFactory;
+
+/**
+ * Registry containing all layout data manager providers that have been parsed
+ * from the
+ * {@link LayoutDataManagerRegistryListener#LAYOUT_DATA_MANAGER_PROVIDER_EXTENSION_POINT}
+ * extension point.
+ *
+ * @author mporhel
+ *
+ */
+public final class LayoutDataManagerRegistry {
+ /**
+ * The registered {@link LayoutDataManagerDescriptor}s.
+ */
+ private static final Map<LayoutDataManagerDescriptor, SiriusLayoutDataManager> EXTENSIONS = Maps.newLinkedHashMap();
+
+ /**
+ * Utility classes don't need a default constructor.
+ */
+ private LayoutDataManagerRegistry() {
+
+ }
+
+ /**
+ * Adds an extension to the registry, with the given behavior.
+ *
+ * @param extension
+ * The extension that is to be added to the registry
+ */
+ public static void addExtension(LayoutDataManagerDescriptor extension) {
+ EXTENSIONS.put(extension, null);
+ }
+
+ /**
+ * Removes all extensions from the registry. This will be called at plugin
+ * stopping.
+ */
+ public static void clearRegistry() {
+ EXTENSIONS.clear();
+ }
+
+ /**
+ * Returns a copy of the registered extensions list.
+ *
+ * @return A copy of the registered extensions list.
+ */
+ public static Collection<LayoutDataManagerDescriptor> getRegisteredExtensions() {
+ return Lists.newArrayList(EXTENSIONS.keySet());
+ }
+
+ /**
+ * Removes a phantom from the registry.
+ *
+ * @param extensionClassName
+ * Qualified class name of the sync element which corresponding
+ * phantom is to be removed from the registry.
+ */
+ public static void removeExtension(String extensionClassName) {
+ for (LayoutDataManagerDescriptor extension : getRegisteredExtensions()) {
+ if (extension.getExtensionClassName().equals(extensionClassName)) {
+ EXTENSIONS.remove(extension);
+ }
+ }
+ }
+
+ /**
+ * Get the extension with the given id.
+ *
+ * @param id
+ * the requested id.
+ *
+ * @return the layout data manager descriptor with the requested id if it
+ * exists.
+ */
+ public static LayoutDataManagerDescriptor getRegisteredExtension(String id) {
+ for (LayoutDataManagerDescriptor desc : EXTENSIONS.keySet()) {
+ if (!StringUtil.isEmpty(desc.getId()) && desc.getId().equals(id)) {
+ return desc;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get the {@link SiriusLayoutDataManager} found applicable for the given
+ * {@link DDiagram}.
+ *
+ * The default manager (based on semantic elements) will always be the last
+ * returned manager.
+ *
+ * @param diagram
+ * the diagram which needs a layout data ma,ager.
+ *
+ * @return a list of {@link SiriusLayoutDataManager} instances.
+ */
+ public static List<SiriusLayoutDataManager> getSiriusLayoutDataManagers(DDiagram diagram) {
+ List<SiriusLayoutDataManager> applicableManagers = Lists.newArrayList();
+ for (LayoutDataManagerDescriptor descriptor : getRegisteredExtensions()) {
+ ILayoutDataManagerProvider provider = descriptor.getLayoutDataManagerProvider();
+ if (provider != null && provider.provides(diagram)) {
+ SiriusLayoutDataManager layoutDataManager = EXTENSIONS.get(descriptor);
+ if (layoutDataManager == null) {
+ layoutDataManager = provider.getLayoutDataManager();
+ EXTENSIONS.put(descriptor, layoutDataManager);
+ }
+ applicableManagers.add(layoutDataManager);
+ }
+ }
+ applicableManagers.add(SiriusLayoutDataManagerForSemanticElementsFactory.getInstance().getSiriusLayoutDataManager());
+ return applicableManagers;
+ }
+
+ /**
+ * Get all known {@link SiriusLayoutDataManager} .
+ *
+ * The default manager (based on semantic elements) will always be the last
+ * returned manager.
+ *
+ * @return a list of {@link SiriusLayoutDataManager} instances.
+ */
+ public static List<SiriusLayoutDataManager> getAllSiriusLayoutDataManagers() {
+ List<SiriusLayoutDataManager> applicableManagers = Lists.newArrayList();
+ for (LayoutDataManagerDescriptor descriptor : getRegisteredExtensions()) {
+ ILayoutDataManagerProvider provider = descriptor.getLayoutDataManagerProvider();
+ if (provider != null) {
+ SiriusLayoutDataManager layoutDataManager = EXTENSIONS.get(descriptor);
+ if (layoutDataManager == null) {
+ layoutDataManager = provider.getLayoutDataManager();
+ EXTENSIONS.put(descriptor, layoutDataManager);
+ }
+ applicableManagers.add(layoutDataManager);
+ }
+ }
+ applicableManagers.add(SiriusLayoutDataManagerForSemanticElementsFactory.getInstance().getSiriusLayoutDataManager());
+ return applicableManagers;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/data/extension/LayoutDataManagerRegistryListener.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/data/extension/LayoutDataManagerRegistryListener.java
new file mode 100644
index 0000000000..d29c4ea3e0
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/data/extension/LayoutDataManagerRegistryListener.java
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * Copyright (c) 2011 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout.data.extension;
+
+import java.util.Set;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionDelta;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.IRegistryChangeEvent;
+import org.eclipse.core.runtime.IRegistryChangeListener;
+import org.eclipse.core.runtime.Platform;
+
+import com.google.common.collect.Sets;
+
+/**
+ * This listener will allow us to be aware of contribution changes against the
+ * {@link LayoutDataManagerRegistryListener#LAYOUT_DATA_MANAGER_PROVIDER_EXTENSION_POINT}
+ * extension point.
+ *
+ * @author mporhel
+ *
+ */
+public class LayoutDataManagerRegistryListener implements IRegistryChangeListener {
+
+ /** Name of the extension point to parse for extensions. */
+ public static final String LAYOUT_DATA_MANAGER_PROVIDER_EXTENSION_POINT = "org.eclipse.sirius.diagram.layoutDataManager"; //$NON-NLS-1$
+
+ /** Name of the extension point's "Layout Data Manager Extension" tag. */
+ private static final String LAYOUT_DATA_MANAGER_PROVIDER_EXTENSION = "layoutDataManagerProvider"; //$NON-NLS-1$
+
+ /**
+ * initialize this listener.
+ */
+ public void init() {
+ final IExtensionRegistry registry = Platform.getExtensionRegistry();
+ registry.addRegistryChangeListener(this, LayoutDataManagerRegistryListener.LAYOUT_DATA_MANAGER_PROVIDER_EXTENSION_POINT);
+ this.parseInitialContributions();
+ }
+
+ /**
+ * Dispose this listener.
+ */
+ public void dispose() {
+ final IExtensionRegistry registry = Platform.getExtensionRegistry();
+ registry.removeRegistryChangeListener(this);
+ LayoutDataManagerRegistry.clearRegistry();
+ }
+
+ /**
+ * Parses a single extension contribution.
+ *
+ * @param extension
+ * Parses the given extension and adds its contribution to the
+ * registry.
+ */
+ private void parseExtension(IExtension extension) {
+ final IConfigurationElement[] configElements = extension.getConfigurationElements();
+ for (IConfigurationElement elem : configElements) {
+ if (LAYOUT_DATA_MANAGER_PROVIDER_EXTENSION.equals(elem.getName())) {
+
+ try {
+ LayoutDataManagerRegistry.addExtension(new LayoutDataManagerDescriptor(elem));
+ } catch (IllegalArgumentException e) {
+ // Do nothing
+ }
+ }
+ }
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.core.runtime.IRegistryEventListener#added(org.eclipse.core.runtime.IExtensionPoint[])
+ */
+ public void added(IExtensionPoint[] extensionPoints) {
+ for (IExtensionPoint extensionPoint : extensionPoints) {
+ for (IExtension extension : extensionPoint.getExtensions()) {
+ parseExtension(extension);
+ }
+ }
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.core.runtime.IRegistryChangeListener#registryChanged(org.eclipse.core.runtime.IRegistryChangeEvent)
+ */
+ public void registryChanged(IRegistryChangeEvent event) {
+ Set<IExtension> addedExtensions = Sets.newLinkedHashSet();
+ for (IExtensionDelta extensionDelta : event.getExtensionDeltas()) {
+ addedExtensions.add(extensionDelta.getExtension());
+ }
+ added(addedExtensions.toArray(new IExtension[addedExtensions.size()]));
+ }
+
+ /**
+ * Behavior when the given extensions are added.
+ *
+ * @param extensions
+ * the added extensions
+ */
+ public void added(IExtension[] extensions) {
+ for (IExtension extension : extensions) {
+ parseExtension(extension);
+ }
+ }
+
+ /**
+ * Though this listener reacts to the extension point changes, there could
+ * have been contributions before it's been registered. This will parse
+ * these initial contributions.
+ */
+ private void parseInitialContributions() {
+ final IExtensionRegistry registry = Platform.getExtensionRegistry();
+
+ for (IExtension extension : registry.getExtensionPoint(LAYOUT_DATA_MANAGER_PROVIDER_EXTENSION_POINT).getExtensions()) {
+ parseExtension(extension);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.core.runtime.IRegistryEventListener#removed(org.eclipse.core.runtime.IExtension[])
+ */
+ public void removed(IExtension[] extensions) {
+ for (IExtension extension : extensions) {
+ final IConfigurationElement[] configElements = extension.getConfigurationElements();
+ for (IConfigurationElement elem : configElements) {
+ if (LAYOUT_DATA_MANAGER_PROVIDER_EXTENSION_POINT.equals(elem.getName())) {
+ final String extensionClassName = elem.getAttribute(LayoutDataManagerDescriptor.LAYOUT_DATA_MANAGER_PROVIDER_CLASS_NAME);
+ LayoutDataManagerRegistry.removeExtension(extensionClassName);
+ }
+ }
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/diagram/DEdgeLayoutDataKey.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/diagram/DEdgeLayoutDataKey.java
new file mode 100644
index 0000000000..e156b4e0ff
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/diagram/DEdgeLayoutDataKey.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout.diagram;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+
+import org.eclipse.sirius.DEdge;
+import org.eclipse.sirius.diagram.ui.tools.internal.layout.EdgeLayoutDataKey;
+
+/**
+ * Kind of key use to store the layout data corresponding to an {@link DEdge}.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ *
+ */
+public class DEdgeLayoutDataKey implements EdgeLayoutDataKey {
+ /**
+ * The target of this EdgeLayoutData
+ */
+ private DEdge target;
+
+ /**
+ * Default constructor.
+ *
+ * @param key
+ * The key
+ */
+ public DEdgeLayoutDataKey(final DEdge key) {
+ this.target = key;
+ }
+
+ protected EObject getTarget() {
+ return target;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.layout.LayoutDataKey#getId()
+ */
+ public String getId() {
+ return EcoreUtil.getURI(getTarget()).fragment();
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/diagram/DNodeLayoutDataKey.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/diagram/DNodeLayoutDataKey.java
new file mode 100644
index 0000000000..41db4edf8d
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/diagram/DNodeLayoutDataKey.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout.diagram;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+
+import org.eclipse.sirius.AbstractDNode;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.diagram.ui.tools.internal.layout.NodeLayoutDataKey;
+
+/**
+ * Kind of key use to store the layout data corresponding to an
+ * {@link AbstractDNode} or a {@link DDiagram}.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ *
+ */
+public class DNodeLayoutDataKey implements NodeLayoutDataKey {
+ /**
+ * The target of this LayoutData (can only be a DDiagram or an
+ * AbstractDNode).
+ */
+ private EObject target;
+
+ /**
+ * Default constructor.
+ *
+ * @param target
+ * The target of the
+ */
+ public DNodeLayoutDataKey(final EObject target) {
+ if (!(target instanceof AbstractDNode || target instanceof DDiagram)) {
+ throw new IllegalArgumentException("The key uses to store this layout data can only be an AbstractDNode or a DDiagram.");
+ }
+ this.target = target;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj instanceof DNodeLayoutDataKey) {
+ return this.getTarget().equals(((DNodeLayoutDataKey) obj).getTarget());
+ } else {
+ return super.equals(obj);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return super.hashCode();
+ }
+
+ protected EObject getTarget() {
+ return target;
+ }
+
+ protected void setTarget(final EObject target) {
+ this.target = target;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.layout.LayoutDataKey#getId()
+ */
+ public String getId() {
+ return EcoreUtil.getURI(getTarget()).fragment();
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/diagram/SiriusLayoutDataManagerForDDiagram.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/diagram/SiriusLayoutDataManagerForDDiagram.java
new file mode 100644
index 0000000000..04ee8de72f
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/diagram/SiriusLayoutDataManagerForDDiagram.java
@@ -0,0 +1,150 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout.diagram;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+
+import org.eclipse.sirius.DSemanticDecorator;
+import org.eclipse.sirius.diagram.layoutdata.AbstractLayoutData;
+import org.eclipse.sirius.diagram.layoutdata.EdgeLayoutData;
+import org.eclipse.sirius.diagram.layoutdata.NodeLayoutData;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.LayoutDataKey;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.SiriusLayoutDataManager;
+
+/**
+ * SiriusLayoutDataManager drives by the DDiagram (DNode, DEdge, ...). Use
+ * for drag'n'drop and creation process.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ *
+ */
+public class SiriusLayoutDataManagerForDDiagram implements SiriusLayoutDataManager {
+ Map<DNodeLayoutDataKey, NodeLayoutData> nodeLayoutDataMap = new HashMap<DNodeLayoutDataKey, NodeLayoutData>();
+
+ Map<DEdgeLayoutDataKey, EdgeLayoutData> edgeLayoutDataMap = new HashMap<DEdgeLayoutDataKey, EdgeLayoutData>();
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.layout.SiriusLayoutDataManager#addLayoutData(org.eclipse.sirius.diagram.ui.tools.api.layout.LayoutDataKey,
+ * org.eclipse.sirius.diagram.layoutdata.AbstractLayoutData)
+ */
+ public void addLayoutData(final LayoutDataKey key, final AbstractLayoutData layoutData) {
+ if (!checkKeyType(key)) {
+ // Kind of key not manage
+ return;
+ }
+ if (key instanceof DNodeLayoutDataKey) {
+ if (layoutData instanceof NodeLayoutData) {
+ nodeLayoutDataMap.put((DNodeLayoutDataKey) key, (NodeLayoutData) layoutData);
+ } else {
+ // Bad type of layoutData for this key
+ }
+ } else if (key instanceof DEdgeLayoutDataKey) {
+ if (layoutData instanceof EdgeLayoutData) {
+ edgeLayoutDataMap.put((DEdgeLayoutDataKey) key, (EdgeLayoutData) layoutData);
+ } else {
+ // Bad type of layoutData for this key
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.layout.SiriusLayoutDataManager#getLayoutData(org.eclipse.sirius.diagram.ui.tools.api.layout.LayoutDataKey)
+ */
+ public AbstractLayoutData getLayoutData(final LayoutDataKey key) {
+ AbstractLayoutData result = null;
+ if (checkKeyType(key)) {
+ if (key instanceof DNodeLayoutDataKey) {
+ result = nodeLayoutDataMap.get(key);
+ } else if (key instanceof DEdgeLayoutDataKey) {
+ result = edgeLayoutDataMap.get(key);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Check if the key is manage by this manager.
+ *
+ * @param key
+ * the key to check
+ * @return
+ */
+ private boolean checkKeyType(final LayoutDataKey key) {
+ return key instanceof DNodeLayoutDataKey || key instanceof DEdgeLayoutDataKey;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.layout.SiriusLayoutDataManager#applyLayout(org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart)
+ */
+ public void applyLayout(final IGraphicalEditPart rootEditPart) {
+ // TODO Auto-generated method stub
+
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.layout.SiriusLayoutDataManager#clearLayoutData()
+ */
+ public void clearLayoutData() {
+ // TODO Auto-generated method stub
+
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.layout.SiriusLayoutDataManager#containsData()
+ */
+ public boolean containsData() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.layout.SiriusLayoutDataManager#createKey(org.eclipse.sirius.DSemanticDecorator)
+ */
+ public LayoutDataKey createKey(final DSemanticDecorator semanticDecorator) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.layout.SiriusLayoutDataManager#getInstance()
+ */
+ public SiriusLayoutDataManager getInstance() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.layout.SiriusLayoutDataManager#storeLayoutData(org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart)
+ */
+ public void storeLayoutData(final IGraphicalEditPart rootEditPart) {
+ // TODO Auto-generated method stub
+
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/ordering/OrderedTreeOrdering.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/ordering/OrderedTreeOrdering.java
new file mode 100644
index 0000000000..b3fe0e7b7c
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/ordering/OrderedTreeOrdering.java
@@ -0,0 +1,185 @@
+/*******************************************************************************
+ * Copyright (c) 2008 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout.ordering;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.View;
+
+import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter;
+import org.eclipse.sirius.common.tools.api.util.StringUtil;
+import org.eclipse.sirius.DSemanticDecorator;
+import org.eclipse.sirius.SiriusPlugin;
+import org.eclipse.sirius.business.api.logger.RuntimeLoggerInterpreter;
+import org.eclipse.sirius.business.api.logger.RuntimeLoggerManager;
+import org.eclipse.sirius.description.AbstractNodeMapping;
+import org.eclipse.sirius.description.DescriptionPackage;
+import org.eclipse.sirius.description.OrderedTreeLayout;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.ordering.AbstractTreeViewOrdering;
+import org.eclipse.sirius.tools.api.interpreter.InterpreterUtil;
+import org.eclipse.sirius.ecore.extender.business.api.accessor.ModelAccessor;
+
+/**
+ * Ordering for an ordered tree.
+ *
+ * @author mchauvin
+ */
+public class OrderedTreeOrdering extends AbstractTreeViewOrdering {
+
+ private Collection<String> domainClasses;
+
+ private OrderedTreeLayout layout;
+
+ private Map<View, List<Node>> map;
+
+ /**
+ * Default constructor.
+ *
+ * @param layout
+ * the ordered tree layout
+ */
+ public OrderedTreeOrdering(final OrderedTreeLayout layout) {
+ this.layout = layout;
+ this.domainClasses = getDomainClasses();
+ map = new WeakHashMap<View, List<Node>>();
+ }
+
+ private Collection<String> getDomainClasses() {
+ final Collection<String> classes = new ArrayList<String>();
+ for (AbstractNodeMapping mapping : layout.getNodeMapping()) {
+ if (!StringUtil.isEmpty(mapping.getDomainClass())) {
+ classes.add(mapping.getDomainClass());
+ }
+ }
+ return classes;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.common.ui.business.api.layout.AbstractTreeViewOrdering#getRoots(java.util.List)
+ */
+ @Override
+ public List<View> getRoots(final List<View> views) {
+ final List<View> result = new LinkedList<View>(views);
+ final Iterator<View> iterViews = views.iterator();
+ while (iterViews.hasNext()) {
+ final View currentView = iterViews.next();
+ map.put(currentView, computeChildren(currentView, views));
+ for (Node node : map.get(currentView)) {
+ result.remove(node);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.common.ui.business.api.layout.AbstractTreeViewOrdering#clear()
+ */
+ @Override
+ protected void clear() {
+ this.map.clear();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.common.ui.business.api.layout.AbstractTreeViewOrdering#getChildren(org.eclipse.gmf.runtime.notation.View,
+ * java.util.List)
+ */
+ @Override
+ public List<View> getChildren(final View parent, final List<View> views) {
+ if (map.containsKey(parent)) {
+ return (List) map.get(parent);
+ }
+ return Collections.<View> emptyList();
+ }
+
+ /**
+ * Returns all children of the parent view.
+ *
+ * @param parent
+ * the parent view.
+ * @param views
+ * the candidates.
+ * @return all children of the parent view.
+ */
+ public List<Node> computeChildren(final View parent, final List<View> views) {
+
+ final List<Node> result = new LinkedList<Node>();
+
+ if (parent.getElement() instanceof DSemanticDecorator) {
+ final EObject element = ((DSemanticDecorator) parent.getElement()).getTarget();
+ if (element != null && element.eResource() != null) {
+ // The element could be null in case of diagram that is not in
+ // refreshAuto mode and that have a semantic element deleted.
+ final ModelAccessor accesor = SiriusPlugin.getDefault().getModelAccessorRegistry().getModelAccessor(element);
+
+ if (accesor != null && isInstanceOfOneDomainClass(element, accesor)) {
+
+ final IInterpreter interpreter = InterpreterUtil.getInterpreter(element);
+ final RuntimeLoggerInterpreter safeInterpreter = RuntimeLoggerManager.INSTANCE.decorate(interpreter);
+
+ final Collection<EObject> acceleoResult = safeInterpreter.evaluateCollection(element, layout, DescriptionPackage.eINSTANCE.getOrderedTreeLayout_ChildrenExpression());
+ final List<EObject> children = new ArrayList<EObject>(acceleoResult);
+ result.addAll(getChildrenNode(views, children));
+
+ }
+ }
+ }
+
+ return result;
+ }
+
+ private List<Node> getChildrenNode(final List<View> views, final List<EObject> children) {
+ final List<Node> childrenNodes = new LinkedList<Node>();
+ final Iterator<EObject> iterChildren = children.iterator();
+ while (iterChildren.hasNext()) {
+ final EObject child = iterChildren.next();
+ final Iterator<View> iterViews = views.iterator();
+ while (iterViews.hasNext()) {
+ final View view = iterViews.next();
+ if (view instanceof Node && view.getElement() instanceof DSemanticDecorator) {
+ final EObject currentSemantic = ((DSemanticDecorator) view.getElement()).getTarget();
+ if (currentSemantic.equals(child)) {
+ childrenNodes.add((Node) view);
+ break;
+ }
+ }
+ }
+ }
+ return childrenNodes;
+ }
+
+ private boolean isInstanceOfOneDomainClass(final EObject element, final ModelAccessor accessor) {
+ boolean isInstance = false;
+ final Iterator<String> it = domainClasses.iterator();
+ while (it.hasNext() && !isInstance) {
+ isInstance = accessor.eInstanceOf(element, it.next());
+ }
+
+ return isInstance;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/ordering/OrderedTreeViewOrderingProvider.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/ordering/OrderedTreeViewOrderingProvider.java
new file mode 100644
index 0000000000..8a86c485f9
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/ordering/OrderedTreeViewOrderingProvider.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2008 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout.ordering;
+
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import org.eclipse.sirius.business.api.helper.SiriusUtil;
+import org.eclipse.sirius.description.AbstractNodeMapping;
+import org.eclipse.sirius.description.DiagramDescription;
+import org.eclipse.sirius.description.DiagramElementMapping;
+import org.eclipse.sirius.description.Layout;
+import org.eclipse.sirius.description.OrderedTreeLayout;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.ordering.ViewOrdering;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.ordering.ViewOrderingProvider;
+
+/**
+ * A tree ordered view ordering {@link ViewOrdering} provider.
+ *
+ * @author mchauvin
+ */
+public class OrderedTreeViewOrderingProvider implements ViewOrderingProvider {
+
+ /** the ordering. */
+
+ private Map<OrderedTreeLayout, OrderedTreeOrdering> orderings = new WeakHashMap<OrderedTreeLayout, OrderedTreeOrdering>();
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.ViewOrderingProvider#getViewOrdering(org.eclipse.sirius.description.DiagramElementMapping)
+ */
+ public ViewOrdering getViewOrdering(final DiagramElementMapping mapping) {
+
+ if (mapping instanceof AbstractNodeMapping) {
+ final AbstractNodeMapping nodeMapping = (AbstractNodeMapping) mapping;
+ final DiagramDescription desc = SiriusUtil.findDiagramDescription(nodeMapping);
+ final Layout layout = desc.getLayout();
+ if (layout instanceof OrderedTreeLayout) {
+ if (((OrderedTreeLayout) layout).getNodeMapping().contains(mapping)) {
+ return getOrdering((OrderedTreeLayout) layout);
+ }
+ }
+ }
+ return null;
+ /*
+ * if (provides(mapping)) return getOrdering((NodeMapping)mapping);
+ * return null;
+ */
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.ordering.ViewOrderingProvider#provides(org.eclipse.sirius.description.DiagramElementMapping)
+ */
+ public boolean provides(final DiagramElementMapping mapping) {
+ if (mapping instanceof AbstractNodeMapping) {
+
+ final AbstractNodeMapping nodeMapping = (AbstractNodeMapping) mapping;
+ final DiagramDescription desc = SiriusUtil.findDiagramDescription(nodeMapping);
+ final Layout layout = desc.getLayout();
+ if (layout instanceof OrderedTreeLayout) {
+ if (((OrderedTreeLayout) layout).getNodeMapping().contains(mapping)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Return the ordering.
+ *
+ * @return the ordering.
+ */
+ private OrderedTreeOrdering getOrdering(final OrderedTreeLayout layout) {
+
+ if (orderings.containsKey(layout)) {
+ return orderings.get(layout);
+ }
+
+ final OrderedTreeOrdering ordering = new OrderedTreeOrdering(layout);
+ ordering.setUserAwareCapable(true);
+ orderings.put(layout, ordering);
+ return ordering;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/ordering/ViewOrderingProviderRegistry.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/ordering/ViewOrderingProviderRegistry.java
new file mode 100644
index 0000000000..ba0024b568
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/ordering/ViewOrderingProviderRegistry.java
@@ -0,0 +1,123 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout.ordering;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.emf.common.EMFPlugin;
+
+import org.eclipse.sirius.description.DiagramElementMapping;
+import org.eclipse.sirius.diagram.part.SiriusDiagramEditorPlugin;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.ordering.ViewOrderingProvider;
+
+/**
+ * This class registers all {@link ViewOrderingProvider}s.
+ *
+ * @author ymortier
+ */
+public final class ViewOrderingProviderRegistry {
+
+ /** The shared instance. */
+ private static ViewOrderingProviderRegistry instance = new ViewOrderingProviderRegistry();
+
+ /** Name of the extension point to parse for style configuration providers. */
+ private static final String VIEW_ORDERING_PROVIDER_EXTENSION_POINT = "org.eclipse.sirius.diagram.viewOrderingProvider"; //$NON-NLS-1$
+
+ /** Externalized here to avoid too many distinct usages. */
+ private static final String TAG_ENGINE = "viewOrderingProvider";
+
+ /** The providers. */
+ private Collection<ViewOrderingProvider> viewOrderingProviders;
+
+ /**
+ * Avoid instantiation from outside.
+ */
+ private ViewOrderingProviderRegistry() {
+ this.parseExtensionMetadata();
+ }
+
+ /**
+ * This will parse the currently running platform for extensions and store
+ * all the match engines that can be found.
+ */
+ private void parseExtensionMetadata() {
+ if (EMFPlugin.IS_ECLIPSE_RUNNING) {
+ this.viewOrderingProviders = new LinkedList<ViewOrderingProvider>();
+ final IExtension[] extensions = Platform.getExtensionRegistry().getExtensionPoint(VIEW_ORDERING_PROVIDER_EXTENSION_POINT).getExtensions();
+ for (IExtension extension : extensions) {
+ final IConfigurationElement[] configElements = extension.getConfigurationElements();
+ for (IConfigurationElement configElement : configElements) {
+ if (configElement.getName().equals(TAG_ENGINE)) {
+ try {
+ final ViewOrderingProvider viewOrderingProvider = (ViewOrderingProvider) configElement.createExecutableExtension("providerClass");
+ this.viewOrderingProviders.add(viewOrderingProvider);
+ } catch (final CoreException e) {
+ SiriusDiagramEditorPlugin.getInstance().logError("Impossible to load the view ordering provider : " + configElement.getName(), e);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Return the shared instance.
+ *
+ * @return the shared instance.
+ */
+ public static ViewOrderingProviderRegistry getInstance() {
+ return instance;
+ }
+
+ /**
+ * Return all providers.
+ *
+ * @return all providers.
+ */
+ public Collection<ViewOrderingProvider> getAllProviders() {
+ return this.viewOrderingProviders;
+ }
+
+ /**
+ * Return the {@link ViewOrderingProvider} to use for the specified mapping.
+ * Return <code>null</code> if no {@link ViewOrderingProvider} is available
+ * for the specified mapping.
+ *
+ * @param mapping
+ * the mapping.
+ * @return the {@link ViewOrderingProvider} to use for the specified
+ * mapping.
+ */
+ public ViewOrderingProvider getProvider(final DiagramElementMapping mapping) {
+ final Iterator<ViewOrderingProvider> iterProviders = this.getAllProviders().iterator();
+ while (iterProviders.hasNext()) {
+ final ViewOrderingProvider currentProvider = iterProviders.next();
+ // try {
+ if (currentProvider.provides(mapping)) {
+ return currentProvider;
+ }
+ // } catch (final RuntimeException e) {
+ // SiriusDiagramEditorPlugin.getInstance().logWarning(
+ // "The view ordering provider " +
+ // currentProvider.getClass().getName()
+ // + " has been removed from the ViewOrderingProviderRegistry since
+ // it threw an Exception in its provides method.", e);
+ // }
+ }
+ return null;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/AbstractCompositeLayoutProvider.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/AbstractCompositeLayoutProvider.java
new file mode 100644
index 0000000000..83ac0105bc
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/AbstractCompositeLayoutProvider.java
@@ -0,0 +1,480 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout.provider;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Insets;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.PointList;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.draw2d.graph.DirectedGraph;
+import org.eclipse.draw2d.graph.DirectedGraphLayout;
+import org.eclipse.draw2d.graph.Edge;
+import org.eclipse.draw2d.graph.EdgeList;
+import org.eclipse.draw2d.graph.Node;
+import org.eclipse.draw2d.graph.NodeList;
+import org.eclipse.draw2d.graph.Subgraph;
+import org.eclipse.gef.ConnectionEditPart;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.commands.CompoundCommand;
+import org.eclipse.gmf.runtime.common.core.service.IOperation;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.CompartmentEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.GroupEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IBorderItemEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeCompartmentEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.providers.internal.CompositeLayoutProvider;
+import org.eclipse.gmf.runtime.draw2d.ui.internal.graph.AdvancedSubGraph;
+import org.eclipse.gmf.runtime.draw2d.ui.mapmode.MapModeUtil;
+import org.eclipse.gmf.runtime.notation.LayoutConstraint;
+import org.eclipse.gmf.runtime.notation.Size;
+import org.eclipse.gmf.runtime.notation.View;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Iterators;
+import com.google.common.collect.Lists;
+
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.diagram.edit.api.part.AbstractDiagramElementContainerEditPart;
+import org.eclipse.sirius.diagram.edit.api.part.IDiagramElementEditPart;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.LayoutExtender;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.PinHelper;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.provider.ExtendableLayoutProvider;
+import org.eclipse.sirius.diagram.ui.tools.internal.layout.ArrangeAllWithAutoSize;
+import org.eclipse.sirius.diagram.ui.tools.internal.layout.AutoSizeAndRegionAwareGraphLayout;
+import org.eclipse.sirius.diagram.ui.tools.internal.layout.DiagramLayoutCustomization;
+
+/**
+ * Abstract base class to factor out the common code between
+ * {@link CompositeLeftRightLayoutProvider},
+ * {@link CompositeDownTopLayoutProvider} and
+ * {@link CompositeTopDownLayoutProvider}.
+ *
+ * @author pcdavid
+ */
+@SuppressWarnings("restriction")
+public abstract class AbstractCompositeLayoutProvider extends CompositeLayoutProvider implements ExtendableLayoutProvider {
+
+ private final LayoutExtender extender = new LayoutExtender(this);
+
+ private final DiagramLayoutCustomization padder = new DiagramLayoutCustomization();
+
+ private final ArrangeAllWithAutoSize autoSize = new ArrangeAllWithAutoSize();
+
+ private Predicate<Object> validateAllElementInArrayListAreIDiagramElementEditPart = new Predicate<Object>() {
+
+ public boolean apply(Object input) {
+ return input instanceof IDiagramElementEditPart;
+ }
+ };
+
+ private ArrayList<IDiagramElementEditPart> elementsToKeepFixed = Lists.newArrayList();
+
+ /**
+ * {@inheritDoc}
+ *
+ * Made public to be available from ArrangeAllWithAutoSize.
+ */
+ @Override
+ public abstract Rectangle translateToGraph(final Rectangle r);
+
+ /**
+ * {@inheritDoc}
+ *
+ * Made public to be available from ArrangeAllWithAutoSize.
+ */
+ @Override
+ public abstract Rectangle translateFromGraph(final Rectangle rect);
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean provides(final IOperation operation) {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean handleConnectableListItems() {
+ return shouldHandleConnectableListItems();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Rectangle provideNodeMetrics(final Node node) {
+ return getNodeMetrics(node);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public LayoutExtender getExtender() {
+ return extender;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Command layoutEditParts(final List selectedObjects, final IAdaptable layoutHint) {
+ padder.initializePaddingWithEditParts(selectedObjects);
+ extender.startLayouting();
+
+ // Clear the list of elements to keep fixed.
+ elementsToKeepFixed.clear();
+ // Finds if there are unpinned diagram elements to keep fixed stored in
+ // the LayoutHint as a Collection
+ if (layoutHint.getAdapter(Collection.class) instanceof ArrayList<?>
+ && Iterables.all((ArrayList<?>) layoutHint.getAdapter(Collection.class), validateAllElementInArrayListAreIDiagramElementEditPart)) {
+ elementsToKeepFixed = new ArrayList<IDiagramElementEditPart>((ArrayList<IDiagramElementEditPart>) layoutHint.getAdapter(Collection.class));
+ }
+ // return super.layoutEditParts(selectedObjects, layoutHint);
+ Command result = super.layoutEditParts(selectedObjects, layoutHint);
+
+ // Clear the list of elements to keep fixed (to avoid memory leak)
+ elementsToKeepFixed.clear();
+
+ return result;
+
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected DirectedGraphLayout createGraphLayout() {
+ return new AutoSizeAndRegionAwareGraphLayout();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("rawtypes")
+ @Override
+ protected List getRelevantConnections(final Hashtable editPartToNodeDict) {
+ /*
+ * We're wrapping the original hashtable with this forwarding one not
+ * failling when called with a null get because we've got cases where
+ * editparts are linked through connections not having source/target
+ * (for instance during folding).
+ */
+ @SuppressWarnings("serial")
+ final List list = super.getRelevantConnections(new Hashtable() {
+
+ @Override
+ public synchronized Object get(Object key) {
+ if (key != null) {
+ return editPartToNodeDict.get(key);
+ }
+ return null;
+ }
+
+ @Override
+ public synchronized Enumeration keys() {
+ return editPartToNodeDict.keys();
+ }
+
+ });
+ return extender.getRelevantConnections(editPartToNodeDict, list);
+ }
+
+ // CHECKSTYLE:OFF
+
+ /*
+ * The code in the methods below is copy/pasted and slightly adapted from
+ * GMF, as it could not be overridden cleanly.
+ */
+
+ @Override
+ protected Command update_diagram(org.eclipse.gef.GraphicalEditPart diagramEP, DirectedGraph g, boolean isLayoutForSelected) {
+ /*
+ * We define the layout default margin at 0 otherwise consecutive calls
+ * to the ArrangeAll actions will always move the nodes in containers.
+ */
+
+ CompoundCommand cc = new CompoundCommand(""); //$NON-NLS-1$
+
+ final Point diff = getLayoutPositionDelta(g, isLayoutForSelected);
+ layoutDefaultMargin = MapModeUtil.getMapMode(diagramEP.getFigure()).DPtoLP(25);
+
+ Command cmd = createNodeChangeBoundCommands(g, diff);
+ if (cmd != null) {
+ cc.add(cmd);
+ }
+
+ cmd = createEdgesChangeBoundsCommands(g, diff);
+ if (cmd != null) {
+ cc.add(cmd);
+ }
+
+ return cc;
+ }
+
+ /**
+ * Only used if ENABLE_PARTIAL_OVERLAP_FIX is true. This is an almost
+ * verbatim copy of the version in the parent class, except for the use of
+ * the custom getNodeMetricsConsideringBorderedNodes.
+ */
+ private Point getLayoutPositionDelta(DirectedGraph g, boolean isLayoutForSelected) {
+ // If laying out selected objects, use diff variables to
+ // position objects at topleft corner of enclosing rectangle.
+ if (isLayoutForSelected) {
+ ListIterator vi;
+ vi = g.nodes.listIterator();
+ Point ptLayoutMin = new Point(-1, -1);
+ while (vi.hasNext()) {
+ Node node = (Node) vi.next();
+ // ignore ghost node
+ if (node.data != null) {
+ Rectangle nodeExt = getNodeMetricsConsideringBorderedNodes(node);
+ if (ptLayoutMin.x == -1) {
+ ptLayoutMin.x = nodeExt.x;
+ ptLayoutMin.y = nodeExt.y;
+ } else {
+ ptLayoutMin.x = Math.min(ptLayoutMin.x, nodeExt.x);
+ ptLayoutMin.y = Math.min(ptLayoutMin.y, nodeExt.y);
+ }
+ }
+ }
+
+ return new Point(this.minX - ptLayoutMin.x, this.minY - ptLayoutMin.y);
+ }
+
+ return new Point(layoutDefaultMargin, layoutDefaultMargin);
+ }
+
+ private Rectangle getNodeMetricsConsideringBorderedNodes(Node node) {
+ Rectangle result = getNodeMetrics(node);
+ if (node instanceof Subgraph && node.data instanceof IGraphicalEditPart) {
+ Subgraph subGraph = (Subgraph) node;
+ NodeList children = subGraph.members;
+ for (int i = 0; i < children.size(); i++) {
+ Node child = children.getNode(i);
+ if (child instanceof IBorderItemEditPart) {
+ result.union(getNodeMetrics(child));
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.providers.internal.DefaultProvider#build_edges(java.util.List,
+ * java.util.Map)
+ * @deprecated
+ */
+ @Override
+ protected EdgeList build_edges(final List selectedObjects, final Map editPartToNodeDict) {
+ return buildEdges(selectedObjects, editPartToNodeDict);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.providers.internal.DefaultProvider#build_edges(java.util.List,
+ * java.util.Map)
+ */
+ @Override
+ protected EdgeList buildEdges(final List selectedObjects, final Map editPartToNodeDict) {
+ return super.buildEdges(extender.filterEdges(selectedObjects, editPartToNodeDict), editPartToNodeDict);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.gmf.runtime.diagram.ui.providers.internal.DefaultProvider
+ * #build_nodes(java.util.List, java.util.Map,
+ * org.eclipse.draw2d.graph.Subgraph)
+ *
+ * @deprecated
+ */
+ @Override
+ @Deprecated
+ protected NodeList build_nodes(List selectedObjects, Map editPartToNodeDict, Subgraph rootGraph) {
+ return buildNodes(selectedObjects, editPartToNodeDict, rootGraph);
+ }
+
+ @Override
+ protected NodeList buildNodes(List selectedObjects, Map editPartToNodeDict, Subgraph rootGraph) {
+ ListIterator li = selectedObjects.listIterator();
+ // <added for auto-size>
+ autoSize.prepareForArrangeAll(Iterators.filter(li, AbstractDiagramElementContainerEditPart.class));
+ // </added for auto-size>
+
+ NodeList nodes = new NodeList();
+ li = selectedObjects.listIterator();
+ while (li.hasNext()) {
+ IGraphicalEditPart gep = (IGraphicalEditPart) li.next();
+ boolean hasChildren = hasChildren(gep);
+ if (!(gep instanceof IBorderItemEditPart) && (gep instanceof ShapeEditPart || gep instanceof ShapeCompartmentEditPart)) {
+ GraphicalEditPart ep = (GraphicalEditPart) gep;
+ Point position = ep.getFigure().getBounds().getLocation();
+ if (minX == -1) {
+ minX = position.x;
+ minY = position.y;
+ } else {
+ minX = Math.min(minX, position.x);
+ minY = Math.min(minY, position.y);
+ }
+ Node n = null;
+ if (hasChildren && !(gep instanceof GroupEditPart)) {
+ AdvancedSubGraph subGraph = null;
+ if (rootGraph != null) {
+ subGraph = new AdvancedSubGraph(ep, rootGraph);
+ } else {
+ subGraph = new AdvancedSubGraph(ep);
+ }
+ subGraph.setAutoSize(isAutoSizeOn(subGraph, ep));
+ if (gep instanceof CompartmentEditPart) {
+ subGraph.setHasBufferedZone(true);
+ }
+ subGraph.setDirection(getLayoutDirection(ep));
+ n = subGraph;
+ } else {
+ if (rootGraph != null) {
+ n = new Node(ep, rootGraph);
+ } else {
+ n = new Node(ep);
+ }
+ }
+ adjustNodePadding(n, editPartToNodeDict);
+ // <modified for auto-size>
+ Dimension size = autoSize.getSizeToConsiderDuringArrangeAll(ep);
+ // </modified for auto-size>
+ setNodeMetrics(n, new Rectangle(position.x, position.y, size.width, size.height));
+ editPartToNodeDict.put(ep, n);
+ nodes.add(n);
+ if (hasChildren && !(gep instanceof GroupEditPart)) {
+ buildNodes(gep.getChildren(), editPartToNodeDict, (Subgraph) n);
+ }
+ }
+ }
+ return nodes;
+ }
+
+ private boolean isAutoSizeOn(AdvancedSubGraph subGraph, IGraphicalEditPart gEP) {
+ if (gEP instanceof CompartmentEditPart && subGraph.getParent() instanceof AdvancedSubGraph) {
+ if (((AdvancedSubGraph) subGraph.getParent()).isAutoSize()) {
+ return true;
+ }
+ } else {
+ View notationView = gEP.getNotationView();
+ if (notationView != null && notationView instanceof org.eclipse.gmf.runtime.notation.Node) {
+ org.eclipse.gmf.runtime.notation.Node node = (org.eclipse.gmf.runtime.notation.Node) notationView;
+ LayoutConstraint contraint = node.getLayoutConstraint();
+ if (contraint instanceof Size) {
+ Size size = (Size) contraint;
+ if (size.getHeight() != -1 && size.getWidth() != -1) {
+ return ArrangeAllWithAutoSize.isEnabled();
+ }
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ protected void createSubCommands(Point diff, ListIterator vi, CompoundCommand cc) {
+ final List nodes = Lists.newArrayList(vi);
+ if (ArrangeAllWithAutoSize.isEnabled()) {
+ autoSize.createSubCommands(diff, nodes.listIterator(), cc, this, minX, minY);
+ } else {
+ // No auto-size : region will not be moved.
+ super.createSubCommands(diff, nodes.listIterator(), cc);
+ }
+ extender.keepLocationChanges(nodes, diff);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void adjustNodePadding(final Node node, final Map editPartToNodeDict) {
+ // <modification>
+ final GraphicalEditPart ep = (GraphicalEditPart) node.data;
+ final Insets padding = padder.getNodePadding(ep);
+ // </modification>
+ // check if the direct parent is added already to the graph
+ final GraphicalEditPart parent = (GraphicalEditPart) ep.getParent();
+ if (parent != null && node.getParent() != null && editPartToNodeDict.get(parent) != node.getParent()) {
+ // now the direct parent is not added to the graph so, we had
+ // to adjust the padding of the node to consider the parent
+ final IFigure thisFigure = parent.getFigure();
+ final IFigure parentFigure = ((GraphicalEditPart) node.getParent().data).getFigure();
+ final Point parentLocation = parentFigure.getBounds().getLocation();
+ final Point nodeLocation = thisFigure.getBounds().getLocation();
+ thisFigure.translateToAbsolute(nodeLocation);
+ parentFigure.translateToAbsolute(parentLocation);
+ final Dimension delta = nodeLocation.getDifference(parentLocation);
+ final Rectangle rect = translateToGraph(new Rectangle(delta.width, delta.height, 0, 0));
+ padding.top += rect.y;
+ padding.left += rect.x;
+ }
+ node.setPadding(padding);
+ }
+
+ /**
+ * Method override to avoid move of edges that have considered as fixed.
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.providers.internal.CompositeLayoutProvider#routeThrough(org.eclipse.draw2d.graph.Edge,
+ * org.eclipse.gef.ConnectionEditPart, org.eclipse.draw2d.graph.Node,
+ * org.eclipse.draw2d.graph.Node,
+ * org.eclipse.draw2d.geometry.PointList,
+ * org.eclipse.draw2d.geometry.Point)
+ */
+ @Override
+ protected Command routeThrough(Edge edge, ConnectionEditPart connectEP, Node source, Node target, PointList points, Point diff) {
+ if (connectEP instanceof IGraphicalEditPart && isPinned((IGraphicalEditPart) connectEP) || (elementsToKeepFixed != null && elementsToKeepFixed.contains(connectEP))) {
+ return null;
+ }
+ return super.routeThrough(edge, connectEP, source, target, points, diff);
+ }
+
+ /**
+ * Tests whether an edit part should be considered as pinned (fixed size and
+ * location) during the layout.
+ *
+ * @param part
+ * the edit part.
+ * @return <code>true</code> if the edit part should be considered as
+ * pinned.
+ */
+ protected boolean isPinned(final IGraphicalEditPart part) {
+ boolean isPinned = false;
+ if (part.resolveSemanticElement() instanceof DDiagramElement) {
+ DDiagramElement dDiagramElement = (DDiagramElement) part.resolveSemanticElement();
+ isPinned = new PinHelper().isPinned(dDiagramElement);
+ }
+ return isPinned;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/AbstractProviderDescriptor.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/AbstractProviderDescriptor.java
new file mode 100644
index 0000000000..cf5a82367f
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/AbstractProviderDescriptor.java
@@ -0,0 +1,135 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout.provider;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+
+import org.eclipse.sirius.diagram.ui.tools.api.layout.LayoutConstants;
+
+/**
+ * A basic descriptor.
+ *
+ * @author ymortier
+ */
+public abstract class AbstractProviderDescriptor implements Comparable<AbstractProviderDescriptor> {
+
+ /** Configuration element of this descriptor. */
+ protected final IConfigurationElement element;
+
+ /** The priority of this provider. */
+ private int priority = LayoutConstants.NORMAL_PRIORITY;
+
+ /** The name of the provider. */
+ private String providerClassName;
+
+ /**
+ * Create a new {@link AbstractProviderDescriptor}.
+ *
+ * @param element
+ * the configuration element.
+ */
+ public AbstractProviderDescriptor(final IConfigurationElement element) {
+ this.element = element;
+ this.priority = getPriorityValue(getAttribute("priority", "low")); //$NON-NLS-1$//$NON-NLS-2$
+ this.providerClassName = getAttribute("providerClass", null); //$NON-NLS-1$
+ }
+
+ /**
+ * Return the provider class name.
+ *
+ * @return the provider class name.
+ */
+ public String getProviderClassName() {
+ return providerClassName;
+ }
+
+ /**
+ * Returns the value of the attribute <code>name</code> of this descriptor's
+ * configuration element. if the attribute hasn't been set, we'll return
+ * <code>defaultValue</code> instead.
+ *
+ * @param name
+ * Name of the attribute we seek the value of.
+ * @param defaultValue
+ * Value to return if the attribute hasn't been set.
+ * @return The value of the attribute <code>name</code>,
+ * <code>defaultValue</code> if it hasn't been set.
+ */
+ private String getAttribute(final String name, final String defaultValue) {
+ final String value = element.getAttribute(name);
+ if (value != null) {
+ return value;
+ }
+ if (defaultValue != null) {
+ return defaultValue;
+ }
+ throw new IllegalArgumentException("The " + name + " attribute is missing"); //$NON-NLS-1$
+ }
+
+ /**
+ * Return the priority of this provider.
+ *
+ * @return the priority of this provider.
+ */
+ public int getPriority() {
+ return priority;
+ }
+
+ /**
+ * Returns the value of the priority described by the given {@link String}.<br/>
+ * Returned values according to <code>priorityString</code> value :
+ * <ul>
+ * <li>&quot;lowest&quot; =&gt;
+ * {@value org.eclipse.sirius.ecore.extender.business.api.accessor.ExtenderConstants#PRIORITY_LOWEST}
+ * </li>
+ * <li>&quot;low&quot; =&gt;
+ * {@value org.eclipse.sirius.ecore.extender.business.api.accessor.ExtenderConstants#PRIORITY_LOW}
+ * </li>
+ * <li>&quot;high&quot; =&gt;
+ * {@value org.eclipse.sirius.ecore.extender.business.api.accessor.ExtenderConstants#PRIORITY_HIGH}
+ * </li>
+ * <li>&quot;highest&quot; =&gt;
+ * {@value org.eclipse.sirius.ecore.extender.business.api.accessor.ExtenderConstants#PRIORITY_HIGHEST}
+ * </li>
+ * <li>anything else =&gt;
+ * {@value org.eclipse.sirius.ecore.extender.business.api.accessor.ExtenderConstants#PRIORITY_NORMAL}
+ * </li>
+ * </ul>
+ *
+ * @param priorityString
+ * {@link String} value of the priority we seek.
+ * @return <code>int</code> corresponding to the given priority
+ * {@link String}.
+ */
+ private int getPriorityValue(final String priorityString) {
+ int priorityValue = LayoutConstants.NORMAL_PRIORITY;
+ if ("lowest".equals(priorityString)) { //$NON-NLS-1$
+ priorityValue = LayoutConstants.LOWEST_PRIORITY;
+ } else if ("low".equals(priorityString)) { //$NON-NLS-1$
+ priorityValue = LayoutConstants.LOW_PRIORITY;
+ } else if ("high".equals(priorityString)) { //$NON-NLS-1$
+ priorityValue = LayoutConstants.HIGH_PRIORITY;
+ } else if ("highest".equals(priorityString)) { //$NON-NLS-1$
+ priorityValue = LayoutConstants.HIGHEST_PRIORITY;
+ }
+ return priorityValue;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int compareTo(final AbstractProviderDescriptor other) {
+ final int nombre1 = other.getPriority();
+ final int nombre2 = priority;
+ return nombre2 - nombre1;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/AdjustedGridLayout.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/AdjustedGridLayout.java
new file mode 100644
index 0000000000..fdb5b31f1d
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/AdjustedGridLayout.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout.provider;
+
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.gef.Request;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.commands.CompoundCommand;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.requests.RequestConstants;
+
+import org.eclipse.sirius.diagram.ui.tools.api.layout.provider.GridLayoutProvider;
+import org.eclipse.sirius.diagram.ui.tools.internal.layout.ArrangeAllWithAutoSize;
+
+/**
+ * Specialization of the {@link GridLayoutProvider} to handle the specific
+ * layout adjustements made on the arrange all.
+ *
+ * @author cbrun
+ *
+ */
+public class AdjustedGridLayout extends GridLayoutProvider {
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Command createChangeBoundsCommand(final IGraphicalEditPart editPart, final Point newPosition) {
+ Command result = null;
+ final Command settingBounds = super.createChangeBoundsCommand(editPart, newPosition);
+ if (ArrangeAllWithAutoSize.isEnabled() && ArrangeAllWithAutoSize.shouldBeAutosized(editPart)) {
+ final Command autoSizeCmd = editPart.getCommand(new Request(RequestConstants.REQ_AUTOSIZE));
+ if (settingBounds != null) {
+ final CompoundCommand cpd = new CompoundCommand();
+ cpd.add(settingBounds);
+ cpd.add(autoSizeCmd);
+ result = cpd;
+
+ } else {
+ result = autoSizeCmd;
+ }
+
+ } else {
+ result = settingBounds;
+ }
+ return result;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/ArrangeAllOnlyLayoutProvider.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/ArrangeAllOnlyLayoutProvider.java
new file mode 100644
index 0000000000..7c3dd39950
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/ArrangeAllOnlyLayoutProvider.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout.provider;
+
+import org.eclipse.sirius.diagram.ui.tools.api.layout.provider.AbstractLayoutProvider;
+
+/**
+ * {@link ArrangeSelectionLayoutProvider} that <b>only accepts ArrangeAll
+ * actions</b> (and does nothing if the current Action is an Arrange Selection
+ * Action).
+ * <p>
+ * Layout provider that add a list of diagram elements to keep fixed in the
+ * LayoutHint, during arrange selection action. This information will be used
+ * later in the PinnedElementHandler and PinnedElementLayoutProvider. It is
+ * executed before the generic arrange operation.
+ * </p>
+ *
+ * @author <a href="mailto:alex.lagarde@obeo.fr">Alex Lagarde</a>
+ */
+public class ArrangeAllOnlyLayoutProvider extends ArrangeSelectionLayoutProvider {
+
+ /**
+ * Creates a new ArrangeAllOnlyLayoutProvider.
+ *
+ * @param clp
+ * The layout provider to call after finding diagram element to
+ * keep fixed on arrange all
+ */
+ public ArrangeAllOnlyLayoutProvider(AbstractLayoutProvider clp) {
+ super(clp);
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/ArrangeSelectionLayoutProvider.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/ArrangeSelectionLayoutProvider.java
new file mode 100644
index 0000000000..8b4925d5c7
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/ArrangeSelectionLayoutProvider.java
@@ -0,0 +1,249 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout.provider;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.commands.CompoundCommand;
+import org.eclipse.gef.commands.UnexecutableCommand;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeNodeEditPart;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+import org.eclipse.sirius.diagram.edit.api.part.IDiagramElementEditPart;
+import org.eclipse.sirius.diagram.internal.edit.parts.DEdgeEditPart;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.PinHelper;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.provider.AbstractLayoutProvider;
+
+/**
+ * Layout provider that add a list of diagram elements to keep fixed in the
+ * LayoutHint, during arrange selection action. This information will be used
+ * later in the PinnedElementHandler and PinnedElementLayoutProvider. It is
+ * executed before the generic arrange operation.
+ *
+ * @author smonnier
+ *
+ */
+public class ArrangeSelectionLayoutProvider extends AbstractLayoutProvider {
+
+ /**
+ * The initial layout provider that arrange the nodes (launch before the
+ * arrange of bordered nodes and before updating the list of diagram element
+ * to keep fixed on arrange).
+ */
+ private AbstractLayoutProvider initialLayoutProvider;
+
+ /**
+ * List of ShapeNodeEditPart not selected on the current diagram.
+ */
+ private ArrayList<ShapeNodeEditPart> notSelectedShapeNodeEditPart;
+
+ /**
+ * List of IDiagramElementEditPart not selected and unpinned on the current
+ * diagram.
+ */
+ private ArrayList<IDiagramElementEditPart> notSelectedShapeNodeEditPartAndUnpinned;
+
+ /**
+ * Predicate to check if an EditPart is not selected
+ */
+ private Predicate<EditPart> editPartIsNotSelected = new Predicate<EditPart>() {
+
+ public boolean apply(EditPart input) {
+ return input.getSelected() == EditPart.SELECTED_NONE;
+ }
+ };
+
+ /**
+ * Predicate to check if a IDiagramElementEditPart is unpinned
+ */
+ private Predicate<IDiagramElementEditPart> diagramElementEditPartIsUnpinned = new Predicate<IDiagramElementEditPart>() {
+
+ public boolean apply(IDiagramElementEditPart input) {
+ return !new PinHelper().isPinned(input);
+ }
+ };
+
+ /**
+ * The default constructor.
+ *
+ * @param clp
+ * The layout provider to call after finding diagram element to
+ * keep fixed on arrange all.
+ */
+ public ArrangeSelectionLayoutProvider(AbstractLayoutProvider clp) {
+ initialLayoutProvider = clp;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * This method is overridden to have the arrange selection acting as an
+ * arrange all where non selected elements are pinned.
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.services.layout.AbstractLayoutEditPartProvider#layoutEditParts(java.util.List,
+ * org.eclipse.core.runtime.IAdaptable)
+ */
+ @Override
+ public Command layoutEditParts(List selectedObjects, IAdaptable layoutHint) {
+ if (selectedObjects.isEmpty()) {
+ return UnexecutableCommand.INSTANCE;
+ }
+
+ IAdaptable updatedLayoutHint = layoutHint;
+
+ CompoundCommand result = new CompoundCommand();
+
+ boolean arrangeIsArrangeSelection = false;
+ if (selectedObjects instanceof LinkedList<?>) {
+ LinkedList<?> selectedObjectsLinkedList = (LinkedList<?>) selectedObjects;
+ if (selectedObjectsLinkedList.get(0) instanceof IGraphicalEditPart) {
+ IGraphicalEditPart igep = (IGraphicalEditPart) selectedObjectsLinkedList.get(0);
+ List topLevelEditParts = Lists.newArrayList(Iterables.filter(igep.getParent().getChildren(), ShapeNodeEditPart.class));
+ arrangeIsArrangeSelection = validateArrangeIsArrangeSelection(selectedObjectsLinkedList, topLevelEditParts);
+ if (arrangeIsArrangeSelection) {
+ // Find out unselected diagram element on container (same
+ // parent) that are unpinned
+ notSelectedShapeNodeEditPart = Lists.newArrayList(Iterables.filter(topLevelEditParts, editPartIsNotSelected));
+ notSelectedShapeNodeEditPart.removeAll(selectedObjectsLinkedList);
+ notSelectedShapeNodeEditPartAndUnpinned = Lists.newArrayList(Iterables.filter(Iterables.filter(notSelectedShapeNodeEditPart, IDiagramElementEditPart.class),
+ diagramElementEditPartIsUnpinned));
+ // Add all children of not selected editPart in the unpinned
+ // list (indeed this avoid a move of children
+ // and
+ // LayoutStabilityOnManualRefreshTest.testLayoutStabilityOnOneViewCreatedDuringManualRefreshWithoutPinnedElement
+ // and
+ // LayoutStabilityOnManualRefreshTest.testLayoutStabilityOnOneViewCreatedDuringManualRefreshWithPinnedElement.
+ addChildrenToNotSelectedUnpinnedList(notSelectedShapeNodeEditPart);
+ // Add all edges that connect two unpinned elements in the
+ // unpinned list
+ if (igep.getRoot().getChildren().size() == 1 && igep.getRoot().getChildren().get(0) instanceof DiagramEditPart) {
+ addEdgesToNotSelectedUnpinnedList((DiagramEditPart) igep.getRoot().getChildren().get(0));
+ }
+
+ // Update Layout Hint to find later the list of unselected
+ // diagram element on diagram that are unpinned as elements
+ // to keep fixed in PinnedElementsHandler
+ final IAdaptable originalHint = layoutHint;
+ updatedLayoutHint = new IAdaptable() {
+ public Object getAdapter(@SuppressWarnings("rawtypes")
+ Class adapter) {
+ if (Collection.class.equals(adapter)) {
+ return notSelectedShapeNodeEditPartAndUnpinned;
+ } else {
+ return originalHint.getAdapter(adapter);
+ }
+ }
+ };
+ // add all top level edit parts to have the arrange
+ // selection acting as an arrange all where non selected
+ // elements are pinned
+ selectedObjectsLinkedList.clear();
+ selectedObjectsLinkedList.addAll(topLevelEditParts);
+ }
+ }
+ }
+
+ result.add(lauchPrimaryArrangeAll(selectedObjects, updatedLayoutHint));
+
+ return result;
+ }
+
+ /**
+ * Add, if needed, children that are also unpinned.
+ *
+ * @param notSelectedParent
+ * list of parents which are not selected for which you want to
+ * browse the children to possibly add to the unpinned list
+ */
+ private void addChildrenToNotSelectedUnpinnedList(ArrayList<? extends EditPart> notSelectedParent) {
+ for (EditPart editPart : notSelectedParent) {
+ ArrayList<EditPart> notSelectedChildrenShapeNodeEditPart = Lists.newArrayList(Iterables.filter(editPart.getChildren(), editPartIsNotSelected));
+ if (!notSelectedChildrenShapeNodeEditPart.isEmpty()) {
+ notSelectedShapeNodeEditPartAndUnpinned.addAll(Lists.newArrayList(Iterables.filter(
+ Iterables.filter(Iterables.filter(notSelectedChildrenShapeNodeEditPart, ShapeNodeEditPart.class), IDiagramElementEditPart.class), diagramElementEditPartIsUnpinned)));
+ addChildrenToNotSelectedUnpinnedList(notSelectedChildrenShapeNodeEditPart);
+ }
+ }
+ }
+
+ /**
+ * Adds all the edges that connect two pinned nodes (or considered as such)
+ * in the list of <code>notSelectedShapeNodeEditPartAndUnpinned</code>. This
+ * list of edges is used in {@link AbstractCompositeLayoutProvider} to avoid
+ * the call of method routeThrough.
+ */
+ private void addEdgesToNotSelectedUnpinnedList(DiagramEditPart diagramEditPart) {
+ for (Object connection : diagramEditPart.getConnections()) {
+ if (connection instanceof DEdgeEditPart) {
+ final DEdgeEditPart dEdgeEditPart = (DEdgeEditPart) connection;
+ if (isPinnedOrConsiderAs(dEdgeEditPart.getSource(), notSelectedShapeNodeEditPartAndUnpinned)
+ && isPinnedOrConsiderAs(dEdgeEditPart.getTarget(), notSelectedShapeNodeEditPartAndUnpinned)) {
+ notSelectedShapeNodeEditPartAndUnpinned.add(dEdgeEditPart);
+ }
+ }
+ }
+ }
+
+ /**
+ * Tests whether an edit part is pinned or should be considered as pinned
+ * (fixed size and location) during the layout.
+ *
+ * @param editPart
+ * the edit part.
+ * @param editPartsConsiderAsPinned
+ * list of editParts that have to be consider as pinned
+ * @return <code>true</code> if the edit part is pinned or should be
+ * considered as pinned.
+ */
+ protected boolean isPinnedOrConsiderAs(EditPart editPart, List<IDiagramElementEditPart> editPartsConsiderAsPinned) {
+ return editPart instanceof IGraphicalEditPart && (isPinned((IGraphicalEditPart) editPart) || editPartsConsiderAsPinned.contains(editPart));
+ }
+
+ /**
+ * Validate if the Arrange action is an Arrange Selection action.
+ *
+ * @param selectedObjects
+ * List of selected element
+ * @param diagramTopElements
+ * @return
+ */
+ private boolean validateArrangeIsArrangeSelection(LinkedList<?> selectedObjects, List diagramTopElements) {
+ // We validate that we do not have the same element as the top diagram
+ // elements.
+ boolean result = selectedObjects.size() != diagramTopElements.size() || !selectedObjects.containsAll(diagramTopElements);
+ return result;
+ }
+
+ /**
+ * Launches the primary arrange all that arrange all nodes.
+ *
+ * @param selectedObjects
+ * the objects to arrange.
+ * @param layoutHint
+ * the layout hint.
+ * @return the arrange command.
+ */
+ protected Command lauchPrimaryArrangeAll(final List selectedObjects, final IAdaptable layoutHint) {
+ return initialLayoutProvider.layoutEditParts(selectedObjects, layoutHint);
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/BorderItemAwareLayoutProvider.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/BorderItemAwareLayoutProvider.java
new file mode 100644
index 0000000000..df8d9101ba
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/BorderItemAwareLayoutProvider.java
@@ -0,0 +1,1553 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout.provider;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.draw2d.Connection;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.PositionConstants;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Ray;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.emf.transaction.util.TransactionUtil;
+import org.eclipse.gef.ConnectionEditPart;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.EditPartViewer;
+import org.eclipse.gef.GraphicalEditPart;
+import org.eclipse.gef.Request;
+import org.eclipse.gef.RequestConstants;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.commands.CompoundCommand;
+import org.eclipse.gef.commands.UnexecutableCommand;
+import org.eclipse.gef.editparts.ZoomManager;
+import org.eclipse.gef.requests.ChangeBoundsRequest;
+import org.eclipse.gmf.runtime.common.core.service.IOperation;
+import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil;
+import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy;
+import org.eclipse.gmf.runtime.diagram.ui.commands.SetBoundsCommand;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramRootEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IBorderItemEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IBorderedShapeEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeCompartmentEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.figures.BorderedNodeFigure;
+import org.eclipse.gmf.runtime.diagram.ui.internal.commands.SetConnectionBendpointsCommand;
+import org.eclipse.gmf.runtime.diagram.ui.services.layout.ILayoutNode;
+import org.eclipse.gmf.runtime.diagram.ui.services.layout.ILayoutNodeOperation;
+import org.eclipse.gmf.runtime.draw2d.ui.figures.IBorderItemLocator;
+import org.eclipse.gmf.runtime.emf.core.util.EObjectAdapter;
+import org.eclipse.gmf.runtime.gef.ui.figures.DefaultSizeNodeFigure;
+import org.eclipse.gmf.runtime.notation.Bounds;
+import org.eclipse.gmf.runtime.notation.Edge;
+import org.eclipse.gmf.runtime.notation.LayoutConstraint;
+import org.eclipse.gmf.runtime.notation.Location;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.gmf.runtime.notation.Size;
+import org.eclipse.gmf.runtime.notation.View;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DNodeContainer;
+import org.eclipse.sirius.DSemanticDecorator;
+import org.eclipse.sirius.business.internal.query.DNodeContainerExperimentalQuery;
+import org.eclipse.sirius.diagram.edit.api.part.AbstractDiagramBorderNodeEditPart;
+import org.eclipse.sirius.diagram.edit.api.part.AbstractDiagramNameEditPart;
+import org.eclipse.sirius.diagram.edit.api.part.IDDiagramEditPart;
+import org.eclipse.sirius.diagram.edit.api.part.IDiagramContainerEditPart;
+import org.eclipse.sirius.diagram.edit.api.part.IDiagramElementEditPart;
+import org.eclipse.sirius.diagram.internal.edit.parts.AbstractDNodeContainerCompartmentEditPart;
+import org.eclipse.sirius.diagram.internal.edit.parts.DEdgeEditPart;
+import org.eclipse.sirius.diagram.internal.operation.RegionContainerUpdateLayoutOperation;
+import org.eclipse.sirius.diagram.tools.internal.graphical.edit.policies.ChangeBoundRequestRecorder;
+import org.eclipse.sirius.diagram.tools.internal.part.SiriusDiagramGraphicalViewer;
+import org.eclipse.sirius.diagram.ui.tools.api.figure.locator.DBorderItemLocator;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.PinHelper;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.provider.AbstractLayoutProvider;
+import org.eclipse.sirius.diagram.ui.tools.internal.edit.command.CommandFactory;
+import org.eclipse.sirius.diagram.ui.tools.internal.layout.ArrangeAllWithAutoSize;
+
+/**
+ * Layout provider that arranges all border items after another layout provider
+ * (<code>initialLayoutProvider</code>) that arranges all the nodes (with
+ * ChangeBoundsCommand).
+ *
+ * The layout is made with several iterations. During each iterations, we store
+ * the port center location of this iteration and the previous one. We compare
+ * the current location with the two previous iteration to know if the port has
+ * been moved. If no port is moved, we stop the arrange process.
+ *
+ * @author ymortier
+ * @author lredor
+ */
+public class BorderItemAwareLayoutProvider extends AbstractLayoutProvider {
+
+ /**
+ * Class to store the data of the previous iteration of the layout.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ *
+ */
+ private static class BorderItemLayoutData {
+ /**
+ * The center location of the border item at the previous iteration.
+ */
+ Point previousCenterLocation;
+
+ /**
+ * The center location of the border item two iterations ago.
+ */
+ Point previousPreviousCenterLocation;
+
+ /**
+ * True if the border item is considered has moved, false otherwise.
+ */
+ boolean isMoved;
+
+ protected Point getPreviousPreviousCenterLocation() {
+ return previousPreviousCenterLocation;
+ }
+
+ protected void setPreviousPreviousCenterLocation(Point previousPreviousCenterLocation) {
+ this.previousPreviousCenterLocation = previousPreviousCenterLocation;
+ }
+
+ protected Point getPreviousCenterLocation() {
+ return previousCenterLocation;
+ }
+
+ protected void setPreviousCenterLocation(Point newCenterLocation) {
+ setPreviousPreviousCenterLocation(getPreviousCenterLocation());
+ this.previousCenterLocation = newCenterLocation;
+ }
+
+ protected boolean isMoved() {
+ return isMoved;
+ }
+
+ protected void setMoved(boolean moved) {
+ this.isMoved = moved;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ String result = "";
+ if (isMoved) {
+ result += "Border item has been moved since previous layout.";
+ } else {
+ result += "Border item has not been moved since previous layout.";
+ }
+ result += " " + getPreviousCenterLocation();
+ return result;
+ }
+ }
+
+ /**
+ * Class that store data about the element that is on the other side of the
+ * border node.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ */
+ private static class BorderItemOppositeElementData {
+ /**
+ * The center of the opposite element.
+ */
+ Point center;
+
+ /**
+ * The location of this element on its container if it's a border node
+ * (PositionConstants). Otherwise, this field equals
+ * PositionConstants.NONE
+ */
+ int side;
+
+ public BorderItemOppositeElementData(Point centerPoint) {
+ this(centerPoint, PositionConstants.NONE);
+ }
+
+ public BorderItemOppositeElementData(Point centerPoint, int side) {
+ center = centerPoint;
+ this.side = side;
+ }
+ }
+
+ /**
+ * An abstract comparator for all comparators managed by the opposite
+ * element of the bordered nodes.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ */
+ private abstract class AbstractCoordinateComparator implements Comparator<IBorderItemEditPart> {
+
+ /**
+ * Gives an OppositeElementData for each border item.
+ */
+ Map<IBorderItemEditPart, BorderItemOppositeElementData> oppositeElementsDataByEditPart;
+
+ /**
+ * Default constructor.
+ *
+ * @param oppositeElementsDataByEditPart
+ */
+ public AbstractCoordinateComparator(final Map<IBorderItemEditPart, BorderItemOppositeElementData> oppositeElementsDataByEditPart) {
+ this.oppositeElementsDataByEditPart = oppositeElementsDataByEditPart;
+ }
+ }
+
+ /**
+ * A comparator for border item on the east side of its parent.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ */
+ private class EastCoordinateComparator extends AbstractCoordinateComparator {
+ /**
+ * Default constructor.
+ *
+ * @param vectorsByEditPart
+ */
+ public EastCoordinateComparator(final Map<IBorderItemEditPart, BorderItemOppositeElementData> oppositeElementsDataByEditPart) {
+ super(oppositeElementsDataByEditPart);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
+ */
+ public int compare(final IBorderItemEditPart o1, final IBorderItemEditPart o2) {
+ int result = 0;
+ final BorderItemOppositeElementData p1 = oppositeElementsDataByEditPart.get(o1);
+ final BorderItemOppositeElementData p2 = oppositeElementsDataByEditPart.get(o2);
+
+ if (p1.center.y == p2.center.y) {
+ if (p1.side == PositionConstants.NORTH) {
+ result = p1.center.x < p2.center.x ? 1 : -1;
+ } else {
+ result = p1.center.x > p2.center.x ? 1 : -1;
+ }
+ } else {
+ result = p1.center.y > p2.center.y ? 1 : -1;
+ }
+ return result;
+ }
+ }
+
+ /**
+ * A comparator for border item on the south side of its parent.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ */
+ private class SouthCoordinateComparator extends AbstractCoordinateComparator {
+ /**
+ * Default constructor.
+ *
+ * @param vectorsByEditPart
+ */
+ public SouthCoordinateComparator(final Map<IBorderItemEditPart, BorderItemOppositeElementData> targetPointsByEditPart) {
+ super(targetPointsByEditPart);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
+ */
+ public int compare(final IBorderItemEditPart o1, final IBorderItemEditPart o2) {
+ int result = 0;
+ final BorderItemOppositeElementData p1 = oppositeElementsDataByEditPart.get(o1);
+ final BorderItemOppositeElementData p2 = oppositeElementsDataByEditPart.get(o2);
+
+ if (p1.center.x == p2.center.x) {
+ if (p1.side == PositionConstants.WEST) {
+ result = p1.center.y < p2.center.y ? 1 : -1;
+ } else {
+ result = p1.center.y > p2.center.y ? 1 : -1;
+ }
+ } else {
+ result = p1.center.x > p2.center.x ? 1 : -1;
+ }
+ return result;
+ }
+ }
+
+ /**
+ * A comparator for border item on the west side of its parent.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ */
+ private class WestCoordinateComparator extends AbstractCoordinateComparator {
+ /**
+ * Default constructor.
+ *
+ * @param vectorsByEditPart
+ */
+ public WestCoordinateComparator(final Map<IBorderItemEditPart, BorderItemOppositeElementData> targetPointsByEditPart) {
+ super(targetPointsByEditPart);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
+ */
+ public int compare(final IBorderItemEditPart o1, final IBorderItemEditPart o2) {
+ int result = 0;
+ final BorderItemOppositeElementData p1 = oppositeElementsDataByEditPart.get(o1);
+ final BorderItemOppositeElementData p2 = oppositeElementsDataByEditPart.get(o2);
+
+ if (p1.center.y == p2.center.y) {
+ if (p1.side == PositionConstants.NORTH) {
+ result = p1.center.x > p2.center.x ? 1 : -1;
+ } else {
+ result = p1.center.x < p2.center.x ? 1 : -1;
+ }
+ } else {
+ result = p1.center.y > p2.center.y ? 1 : -1;
+ }
+ return result;
+ }
+ }
+
+ /**
+ * A comparator for border item on the north side of its parent.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ */
+ private class NorthCoordinateComparator extends AbstractCoordinateComparator {
+ /**
+ * Default constructor.
+ *
+ * @param vectorsByEditPart
+ */
+ public NorthCoordinateComparator(final Map<IBorderItemEditPart, BorderItemOppositeElementData> targetPointsByEditPart) {
+ super(targetPointsByEditPart);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
+ */
+ public int compare(final IBorderItemEditPart o1, final IBorderItemEditPart o2) {
+ int result = 0;
+ final BorderItemOppositeElementData p1 = oppositeElementsDataByEditPart.get(o1);
+ final BorderItemOppositeElementData p2 = oppositeElementsDataByEditPart.get(o2);
+
+ if (p1.center.x == p2.center.x) {
+ if (p1.side == PositionConstants.WEST) {
+ result = p1.center.y > p2.center.y ? 1 : -1;
+ } else {
+ result = p1.center.y < p2.center.y ? 1 : -1;
+ }
+ } else {
+ result = p1.center.x > p2.center.x ? 1 : -1;
+ }
+ return result;
+ }
+ }
+
+ /**
+ * The margin of the bordered nodes :
+ * <UL>
+ * <LI>half on the right and half on the left</LI>
+ * <LI>or half on the top and half on the bottom.</LI>
+ * </UL>
+ */
+ public static final int MARGIN = 16;
+
+ private static final int MAX_ITERATIONS = 10;
+
+ /**
+ * The initial layout provider that arrange the nodes (launch before the
+ * arrange of bordered nodes).
+ */
+ AbstractLayoutProvider initialLayoutProvider;
+
+ /**
+ * Tell if the normal arrange process will be called before the border item
+ * arrange.
+ */
+ boolean launchNormalArrange;
+
+ /**
+ * Stores the location of each border edit part compute during the previous
+ * iteration.
+ */
+ Map<IBorderItemEditPart, BorderItemLayoutData> previousIterationDatasbyEditPart = new HashMap<IBorderItemEditPart, BorderItemLayoutData>();
+
+ private Predicate<Object> validateAllElementInArrayListAreIDiagramElementEditPart = new Predicate<Object>() {
+
+ public boolean apply(Object input) {
+ return input instanceof IDiagramElementEditPart;
+ }
+ };
+
+ /**
+ * The default constructor.
+ *
+ * @param clp
+ * The layout provider to call before calling the layout of the
+ * border items.
+ */
+ public BorderItemAwareLayoutProvider(final AbstractLayoutProvider clp) {
+ initialLayoutProvider = clp;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.services.layout.AbstractLayoutEditPartProvider#layoutEditParts(java.util.List,
+ * org.eclipse.core.runtime.IAdaptable)
+ */
+ @Override
+ public Command layoutEditParts(final List selectedObjects, final IAdaptable layoutHint) {
+ return layoutEditParts(selectedObjects, layoutHint, true);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.business.api.layout.provider.AbstractLayoutProvider#provides(org.eclipse.gmf.runtime.common.core.service.IOperation)
+ */
+ @Override
+ public boolean provides(final IOperation operation) {
+ boolean result = true;
+ if (operation instanceof ILayoutNodeOperation) {
+ final ILayoutNodeOperation layoutNodeOperation = (ILayoutNodeOperation) operation;
+ for (ILayoutNode layoutNode : (Iterable<ILayoutNode>) layoutNodeOperation.getLayoutNodes()) {
+ final Node node = layoutNode.getNode();
+ final EObject semanticElement = ViewUtil.resolveSemanticElement(node);
+ if (semanticElement instanceof DDiagramElement) {
+ final DDiagram diagram = ((DDiagramElement) semanticElement).getParentDiagram();
+ if (diagram.getDescription().getLayout() != null) {
+ result = false;
+ }
+ } else if (!(semanticElement instanceof DSemanticDecorator)) {
+ result = false;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Layout this list of selected objects, using the specified layout hint.
+ * The selected objects all reside within the same parent container. Other
+ * elements that are part of the container but not specified in the list of
+ * objects, are ignored.
+ *
+ * @param selectedObjects
+ * <code>List</code> of <code>EditPart</code> objects that are to
+ * be layed out.
+ * @param layoutHint
+ * <code>IAdaptable</code> hint to the provider to determine the
+ * layout kind.
+ * @param normalArrangeMustBeCalled
+ * Tell if the normal arrange process must be called before the
+ * border item arrange
+ * @return <code>Command</code> that when executed will layout the edit
+ * parts in the container
+ */
+ public Command layoutEditParts(final List selectedObjects, final IAdaptable layoutHint, final boolean normalArrangeMustBeCalled) {
+ this.launchNormalArrange = normalArrangeMustBeCalled;
+
+ if (selectedObjects.isEmpty()) {
+ return UnexecutableCommand.INSTANCE;
+ }
+
+ CompoundCommand result = new CompoundCommand();
+
+ if (launchNormalArrange) {
+ // Create a request recorder to record all ChangeBounds requests by
+ // editparts.
+ final EditPartViewer root = ((EditPart) selectedObjects.get(0)).getViewer();
+ if (root instanceof SiriusDiagramGraphicalViewer) {
+ final ChangeBoundRequestRecorder recorder = ((SiriusDiagramGraphicalViewer) root).getChangeBoundRequestRecorder();
+ recorder.startRecording();
+ result.add(lauchPrimaryArrangeAll(selectedObjects, layoutHint));
+ recorder.stopRecording();
+ registerChangeBoundsCommand(recorder);
+ recorder.dispose();
+ }
+ }
+
+ // Finds if there are unpinned diagram elements to keep fixed stored in
+ // the LayoutHint as a Collection
+ ArrayList<IDiagramElementEditPart> elementsToKeepFixed = Lists.newArrayList();
+ if (layoutHint.getAdapter(Collection.class) instanceof ArrayList<?>
+ && Iterables.all((ArrayList<?>) layoutHint.getAdapter(Collection.class), validateAllElementInArrayListAreIDiagramElementEditPart)) {
+ elementsToKeepFixed = (ArrayList<IDiagramElementEditPart>) layoutHint.getAdapter(Collection.class);
+ }
+
+ // Create the specific command to layout the border items.
+ final Command layoutBorderItems = layoutBorderItems(selectedObjects, 1, elementsToKeepFixed);
+ if (layoutBorderItems != null && layoutBorderItems.canExecute()) {
+ result.add(layoutBorderItems);
+ }
+
+ resetBoundsOfPinnedElements(selectedObjects, result, elementsToKeepFixed);
+ this.getViewsToChangeBoundsRequest().clear();
+ if (result.size() == 0) {
+ result = null; // removeCommandsForPinnedElements(result);
+ }
+ return result;
+ }
+
+ /**
+ * Launches the primary arrange all that arrange all nodes.
+ *
+ * @param selectedObjects
+ * the objects to arrange.
+ * @param layoutHint
+ * the layout hint.
+ * @return the arrange command.
+ */
+ protected Command lauchPrimaryArrangeAll(final List selectedObjects, final IAdaptable layoutHint) {
+ return initialLayoutProvider.layoutEditParts(selectedObjects, layoutHint);
+ }
+
+ /**
+ * Register all the change bounds command recording during the initial
+ * layout (layout without moving ports).
+ *
+ * @param recorder
+ * The request recorder
+ */
+ protected void registerChangeBoundsCommand(final ChangeBoundRequestRecorder recorder) {
+ for (Entry<EditPart, ChangeBoundsRequest> entry : recorder.getAllRequests().entries()) {
+ final EditPart editPart = entry.getKey();
+ if (editPart instanceof IGraphicalEditPart) {
+ ChangeBoundsRequest cbr = entry.getValue();
+ final List<EditPart> editParts = cbr.getEditParts();
+ if (editParts != null) {
+ for (EditPart ep : editParts) {
+ final View v = ((IGraphicalEditPart) ep).getNotationView();
+ List<Request> requests = this.getViewsToChangeBoundsRequest().get(v);
+ if (requests == null) {
+ requests = new LinkedList<Request>();
+ this.getViewsToChangeBoundsRequest().put(v, requests);
+ }
+ requests.add(cbr);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Reset the size and location of the pinned elements to there values they
+ * have before the arrange process.
+ *
+ * @param selectedObjects
+ * The selected elements
+ * @param compoundCommand
+ * Contains all the commands to execute at the end of the layout.
+ * @param elementsToKeepFixed
+ * IDiagramElementEditPart which are not actually pinned but have
+ * to stay fixed
+ */
+ private void resetBoundsOfPinnedElements(final List selectedObjects, final CompoundCommand compoundCommand, ArrayList<IDiagramElementEditPart> elementsToKeepFixed) {
+ final String commandName = "Set Bounds";
+ for (IGraphicalEditPart graphicalEditPart : Iterables.filter(selectedObjects, IGraphicalEditPart.class)) {
+ EObject semanticElement = graphicalEditPart.resolveSemanticElement();
+ if (semanticElement instanceof DDiagramElement) {
+ DDiagramElement dDiagramElement = (DDiagramElement) semanticElement;
+ if (new PinHelper().isPinned(dDiagramElement) || (elementsToKeepFixed != null && elementsToKeepFixed.contains(graphicalEditPart))) {
+ final TransactionalEditingDomain editingDomain = TransactionUtil.getEditingDomain(semanticElement);
+ View notationView = graphicalEditPart.getNotationView();
+ if (notationView instanceof Node) {
+ final Node node = (Node) notationView;
+ resetBounds(compoundCommand, commandName, node, editingDomain);
+ }
+
+ //Keep the GMF model consistent for pinned RegionContainer and Regions
+ if (graphicalEditPart instanceof IDiagramContainerEditPart && dDiagramElement instanceof DNodeContainer
+ && new DNodeContainerExperimentalQuery((DNodeContainer) dDiagramElement).isRegionContainer()) {
+ AbstractDNodeContainerCompartmentEditPart comp = Iterables.getFirst(Iterables.filter(graphicalEditPart.getChildren(), AbstractDNodeContainerCompartmentEditPart.class), null);
+ if (comp != null && comp.getNotationView() != null) {
+ for (Node region : Iterables.filter(comp.getChildren(), Node.class)) {
+ resetBounds(compoundCommand, commandName, region, editingDomain);
+ }
+ }
+ compoundCommand.add(new ICommandProxy(CommandFactory.createICommand(graphicalEditPart.getEditingDomain(),
+ new RegionContainerUpdateLayoutOperation((Node) graphicalEditPart.getModel()))));
+ }
+ }
+ }
+ }
+ }
+
+ private void resetBounds(final CompoundCommand compoundCommand, final String commandName, Node node, TransactionalEditingDomain editingDomain) {
+ final EObjectAdapter objectAdapter = new EObjectAdapter(node);
+
+ final LayoutConstraint layoutConstraint = node.getLayoutConstraint();
+ if (layoutConstraint instanceof Bounds) {
+ final Bounds bounds = (Bounds) layoutConstraint;
+ final SetBoundsCommand setBoundsCommand = new SetBoundsCommand(editingDomain, commandName, objectAdapter,
+ new Rectangle(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight()));
+ compoundCommand.add(new ICommandProxy(setBoundsCommand));
+ } else if (layoutConstraint instanceof Location) {
+ final Location location = (Location) layoutConstraint;
+ final SetBoundsCommand setBoundsCommand = new SetBoundsCommand(editingDomain, commandName, objectAdapter, new Point(location.getX(), location.getY()));
+ compoundCommand.add(new ICommandProxy(setBoundsCommand));
+ } else if (layoutConstraint instanceof Size) {
+ final Size size = (Size) layoutConstraint;
+ final SetBoundsCommand setBoundsCommand = new SetBoundsCommand(editingDomain, commandName, objectAdapter, new Dimension(size.getWidth(), size.getHeight()));
+ compoundCommand.add(new ICommandProxy(setBoundsCommand));
+ }
+ }
+
+ /**
+ * Method getBendpointsChangedCommand Different signature method that allows
+ * a command to constructed for changing the bendpoints without requiring
+ * the original Request.
+ *
+ * @param connection
+ * Connection to generate the bendpoints changed command from
+ * @param edge
+ * notation element that the command will operate on.
+ * @param editingDomain
+ * the concern editing domain
+ * @return Command SetBendpointsCommand that contains the point changes for
+ * the connection.
+ */
+ protected Command getBendpointsChangedCommand(Connection connection, Edge edge, TransactionalEditingDomain editingDomain) {
+ Point ptRef1 = connection.getSourceAnchor().getReferencePoint();
+ connection.translateToRelative(ptRef1);
+
+ Point ptRef2 = connection.getTargetAnchor().getReferencePoint();
+ connection.translateToRelative(ptRef2);
+
+ SetConnectionBendpointsCommand sbbCommand = new SetConnectionBendpointsCommand(editingDomain);
+ sbbCommand.setEdgeAdapter(new EObjectAdapter(edge));
+ sbbCommand.setNewPointList(connection.getPoints(), ptRef1, ptRef2);
+
+ return new ICommandProxy(sbbCommand);
+ }
+
+ /**
+ * Layout all the border items of the selected elements.
+ *
+ * @param selectedObjects
+ * The selected elements
+ * @param elementsToKeepFixed
+ * @param launchNormalArrange
+ * Tell if the normal arrange process will be called before the
+ * border item arrange
+ * @param elementsToKeepFixed
+ * IDiagramElementEditPart which are not actually pinned but have
+ * to stay fixed
+ * @return The command to execute to layout the border items.
+ */
+ private Command layoutBorderItems(final List<?> selectedObjects, final int nbIterations, ArrayList<IDiagramElementEditPart> elementsToKeepFixed) {
+ CompoundCommand cc = new CompoundCommand();
+ for (Object object : selectedObjects) {
+ if (object instanceof GraphicalEditPart) {
+ final Command layoutBorderItems = layoutBorderItems((GraphicalEditPart) object, elementsToKeepFixed);
+ if (layoutBorderItems != null && layoutBorderItems.canExecute()) {
+ cc.add(layoutBorderItems);
+ }
+ }
+ }
+ if (hasBeenMovedBorderItemsDuringLastIteration() && nbIterations < MAX_ITERATIONS) {
+ // Remove all the request not called (because we compute again best
+ // locations)
+ removeRequestsOfThisCommand(cc);
+ // We try to optimize the border items location with the previous
+ // compute locations (record in
+ cc = (CompoundCommand) layoutBorderItems(selectedObjects, nbIterations + 1, elementsToKeepFixed);
+ }
+ clearBorderItemLocations();
+ return cc;
+ }
+
+ /**
+ * Remove the request corresponding to this command of the map that maps all
+ * views with a its associated {@link ChangeBoundsRequest}.
+ *
+ * @param cc
+ * The compoundCommand that is not executed and for which we
+ * wan't to remove the corresponding request.
+ */
+ private void removeRequestsOfThisCommand(CompoundCommand cc) {
+ for (Object childCommand : cc.getCommands()) {
+ if (childCommand instanceof CompoundCommand) {
+ removeRequestsOfThisCommand((CompoundCommand) childCommand);
+ } else if (childCommand instanceof CommandWrapper) {
+ CommandWrapper wrap = (CommandWrapper) childCommand;
+ if (wrap.getEditPart() instanceof IGraphicalEditPart) {
+ List<Request> requests = getViewsToChangeBoundsRequest().get(((IGraphicalEditPart) wrap.getEditPart()).getNotationView());
+ if (requests != null) {
+ requests.remove(wrap.getRequest());
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * @return true if almost one of the border items has been moved during the
+ * last iteration, false otherwise.
+ */
+ private boolean hasBeenMovedBorderItemsDuringLastIteration() {
+ for (IBorderItemEditPart borderItemEditPart : previousIterationDatasbyEditPart.keySet()) {
+ if (previousIterationDatasbyEditPart.get(borderItemEditPart).isMoved()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Clear the data of border items of the previous iterations.
+ */
+ private void clearBorderItemLocations() {
+ previousIterationDatasbyEditPart.clear();
+ }
+
+ /**
+ * Layout all the border items of this graphicalEditPart.
+ *
+ * @param graphicalEditPart
+ * The current element to deal with launchNormalArrange
+ * @param elementsToKeepFixed
+ * @param launchNormalArrange
+ * Tell if the normal arrange process will be called before the
+ * border item arrange
+ * @param elementsToKeepFixed
+ * IDiagramElementEditPart which are not actually pinned but have
+ * to stay fixed
+ * @return The command to execute to layout the border items of this
+ * graphical edit part.
+ */
+ private Command layoutBorderItems(final GraphicalEditPart graphicalEditPart, ArrayList<IDiagramElementEditPart> elementsToKeepFixed) {
+ final CompoundCommand result = new CompoundCommand();
+ if (graphicalEditPart instanceof IBorderedShapeEditPart) {
+ final IBorderedShapeEditPart borderedEditPart = (IBorderedShapeEditPart) graphicalEditPart;
+ if (borderedEditPart.getBorderedFigure() != null && !borderedEditPart.getBorderedFigure().getBorderItemContainer().getChildren().isEmpty()) {
+ final Command layoutBorderItems = layoutBorderItems(borderedEditPart, elementsToKeepFixed);
+ if (layoutBorderItems != null && layoutBorderItems.canExecute()) {
+ result.add(layoutBorderItems);
+ }
+ }
+
+ }
+ for (Object editPart : graphicalEditPart.getChildren()) {
+ if (editPart instanceof GraphicalEditPart) {
+ final Command layoutBorderItems = layoutBorderItems((GraphicalEditPart) editPart, elementsToKeepFixed);
+ if (layoutBorderItems != null && layoutBorderItems.canExecute()) {
+ result.add(layoutBorderItems);
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Layout all the border items of this borderedShapeEditPart.
+ *
+ * @param borderedShapeEditPart
+ * The current element to deal with
+ * @param launchNormalArrange
+ * Tell if the normal arrange process will be called before the
+ * border item arrange
+ * @param elementsToKeepFixed
+ * IDiagramElementEditPart which are not actually pinned but have
+ * to stay fixed
+ * @return The command to execute to layout the border items of this
+ * graphical edit part.
+ */
+ private Command layoutBorderItems(final IBorderedShapeEditPart borderedShapeEditPart, ArrayList<IDiagramElementEditPart> elementsToKeepFixed) {
+ CompoundCommand resCommand = null;
+ if (borderedShapeEditPart instanceof IGraphicalEditPart) {
+
+ IGraphicalEditPart castedEditPart = (IGraphicalEditPart) borderedShapeEditPart;
+ if (borderedShapeEditPart.getMainFigure() != null) {
+ resCommand = new CompoundCommand();
+
+ // Get the zoom level
+ double scale = 1.0;
+ if (castedEditPart.getRoot() instanceof DiagramRootEditPart) {
+ final ZoomManager zoomManager = ((DiagramRootEditPart) castedEditPart.getRoot()).getZoomManager();
+ scale = zoomManager.getZoom();
+ }
+
+ // Get the bounds of the container after arrange all (the
+ // container of the border node).
+ final Rectangle containerBoundsAfterArrangeAll = getBounds(castedEditPart, scale);
+ final Point containerCenterAfterArrangeAll = containerBoundsAfterArrangeAll.getCenter();
+
+ // Use the center of the opposite element to determine the ray
+ // (this ray is then use to determine the side on which to put
+ // the border node)
+ final Map<IBorderItemEditPart, Ray> headings = new HashMap<IBorderItemEditPart, Ray>();
+ for (Object child : castedEditPart.getChildren()) {
+ if (child instanceof IBorderItemEditPart) {
+ if (!isPinned((IBorderItemEditPart) child) && !(elementsToKeepFixed != null && elementsToKeepFixed.contains(child))) {
+ computeHeading((IBorderItemEditPart) child, containerCenterAfterArrangeAll, scale, headings);
+ }
+ }
+ }
+
+ final Point topLeft = containerBoundsAfterArrangeAll.getTopLeft();
+ // Make some trigonometry calculations to know which ports must
+ // be on top, bottom, right, left border of their container.
+ final double absoluteCos = Math.abs(BorderItemAwareLayoutProvider.cos(new Ray(Math.abs(containerCenterAfterArrangeAll.x - topLeft.x), Math.abs(containerCenterAfterArrangeAll.y
+ - topLeft.y))));
+ final double absoluteSin = Math.abs(BorderItemAwareLayoutProvider.sin(new Ray(Math.abs(containerCenterAfterArrangeAll.x - topLeft.x), Math.abs(containerCenterAfterArrangeAll.y
+ - topLeft.y))));
+
+ final List<IBorderItemEditPart> tops = getNorthBorderItems(headings, absoluteCos, scale, containerCenterAfterArrangeAll);
+ final List<IBorderItemEditPart> bottoms = getSouthBorderItems(headings, absoluteCos, scale, containerCenterAfterArrangeAll);
+ final List<IBorderItemEditPart> rights = getEastBorderItems(headings, absoluteSin, scale, containerCenterAfterArrangeAll);
+ final List<IBorderItemEditPart> lefts = getWestBorderItems(headings, absoluteSin, scale, containerCenterAfterArrangeAll);
+
+ unfixLocator(tops);
+ unfixLocator(bottoms);
+ unfixLocator(rights);
+ unfixLocator(lefts);
+
+ final Command topCommand = layoutItems(tops, containerBoundsAfterArrangeAll, PositionConstants.NORTH, scale);
+ if (topCommand != null && topCommand.canExecute()) {
+ resCommand.add(topCommand);
+ }
+ final Command bottomCommand = layoutItems(bottoms, containerBoundsAfterArrangeAll, PositionConstants.SOUTH, scale);
+ if (bottomCommand != null && bottomCommand.canExecute()) {
+ resCommand.add(bottomCommand);
+ }
+ final Command rightCommand = layoutItems(rights, containerBoundsAfterArrangeAll, PositionConstants.EAST, scale);
+ if (rightCommand != null && rightCommand.canExecute()) {
+ resCommand.add(rightCommand);
+ }
+ final Command leftCommand = layoutItems(lefts, containerBoundsAfterArrangeAll, PositionConstants.WEST, scale);
+ if (leftCommand != null && leftCommand.canExecute()) {
+ resCommand.add(leftCommand);
+ }
+ for (IBorderItemEditPart topBorderItemEditPart : tops) {
+ if (topBorderItemEditPart.getSourceConnections().size() > 0) {
+ final Object connection = topBorderItemEditPart.getSourceConnections().get(0);
+ if (connection instanceof DEdgeEditPart) {
+ final DEdgeEditPart viewEdgeEditPart = (DEdgeEditPart) connection;
+ viewEdgeEditPart.getPrimaryShape().refreshLine();
+ }
+ } else if (topBorderItemEditPart.getTargetConnections().size() > 0) {
+ final Object connection = topBorderItemEditPart.getTargetConnections().get(0);
+ if (connection instanceof DEdgeEditPart) {
+ final DEdgeEditPart viewEdgeEditPart = (DEdgeEditPart) connection;
+ viewEdgeEditPart.refresh();
+ }
+ }
+ }
+ }
+ }
+ return resCommand;
+ }
+
+ private void computeHeading(IBorderItemEditPart borderItemEditPart, Point containerCenterAfterArrangeAll, double scale, Map<IBorderItemEditPart, Ray> headings) {
+ final Ray heading = getHeading(borderItemEditPart, containerCenterAfterArrangeAll, scale);
+ if (heading != null) {
+ headings.put(borderItemEditPart, heading);
+ }
+ }
+
+ /**
+ * Layout all the border items on the location (N, S, E or W).
+ *
+ * @param items
+ * A list of border items to layout
+ * @param containerBounds
+ * The bounds of the container after arrange all
+ * @param position
+ * The position of items on its container. Possible values can be
+ * found in {@link PositionConstants} and include NORTH, SOUTH,
+ * EAST and WEST.
+ * @param zoomScale
+ * The scale of the diagram
+ * @return Command A command to layout all items.
+ */
+ protected Command layoutItems(final List<IBorderItemEditPart> items, final Rectangle containerBounds, final int position, final double zoomScale) {
+
+ final CompoundCommand res = new CompoundCommand();
+
+ final boolean width = position == PositionConstants.NORTH || position == PositionConstants.SOUTH;
+
+ final int availableSpace = width ? containerBounds.width : containerBounds.height;
+
+ final int between = (int) ((availableSpace - getSize(items, width, zoomScale) - MARGIN) / (float) items.size());
+
+ int current = MARGIN / 2;
+
+ for (IBorderItemEditPart borderItemEditPart : items) {
+ final ChangeBoundsRequest request = new ChangeBoundsRequest(RequestConstants.REQ_MOVE);
+ Point newLocation;
+ switch (position) {
+ case PositionConstants.NORTH:
+ newLocation = new Point(current, 0);
+ break;
+ case PositionConstants.SOUTH:
+ newLocation = new Point(current, containerBounds.height);
+ break;
+ case PositionConstants.EAST:
+ newLocation = new Point(containerBounds.width, current);
+ break;
+ case PositionConstants.WEST:
+ newLocation = new Point(0, current);
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid items position.");
+ }
+
+ newLocation = newLocation.getTranslated(containerBounds.getTopLeft());
+ // Store the location compute for this border item during this
+ // iteration
+ addBorderItemData(borderItemEditPart, newLocation);
+
+ request.setEditParts(borderItemEditPart);
+ request.setLocation(newLocation);
+ final Rectangle boundsBorderItem = getBounds(borderItemEditPart, zoomScale);
+ final Dimension difference = newLocation.getDifference(boundsBorderItem.getTopLeft());
+ request.setMoveDelta(new Point(difference.width, difference.height));
+ final Command command = this.buildCommandWrapper(request, borderItemEditPart);
+
+ res.add(command);
+
+ current += between + (int) ((width ? boundsBorderItem.width : boundsBorderItem.height) * zoomScale);
+
+ }
+ return res;
+ }
+
+ /**
+ * Store the location compute for this border item during this iteration.
+ *
+ * @param borderItemEditPart
+ * The concerned border item
+ * @param newLocation
+ * The new location computed during the last iteration
+ */
+ private void addBorderItemData(IBorderItemEditPart borderItemEditPart, Point newLocation) {
+ BorderItemLayoutData data = previousIterationDatasbyEditPart.get(borderItemEditPart);
+ if (data == null) {
+ data = new BorderItemLayoutData();
+ data.setMoved(true);
+ data.setPreviousCenterLocation(newLocation);
+ } else {
+ boolean alreadyUsedLocation = data.getPreviousCenterLocation().equals(newLocation);
+ if (!alreadyUsedLocation) {
+ alreadyUsedLocation = data.getPreviousPreviousCenterLocation() != null && data.getPreviousPreviousCenterLocation().equals(newLocation);
+ }
+ data.setPreviousCenterLocation(newLocation);
+ if (alreadyUsedLocation) {
+ data.setMoved(false);
+ } else {
+ data.setMoved(true);
+ }
+ }
+ previousIterationDatasbyEditPart.put(borderItemEditPart, data);
+ }
+
+ /**
+ * Consider all the border item locators with free location (ie the location
+ * of the border item will be recomputed).
+ *
+ * @param editParts
+ * The border items to reset
+ */
+ private void unfixLocator(final List<IBorderItemEditPart> editParts) {
+ for (IBorderItemEditPart borderItemEditPart : editParts) {
+ final IBorderItemLocator borderItemLocator = borderItemEditPart.getBorderItemLocator();
+ if (borderItemLocator instanceof DBorderItemLocator) {
+ ((DBorderItemLocator) borderItemLocator).unfix();
+ }
+ }
+ }
+
+ private int getSize(final List<IBorderItemEditPart> tops, final boolean width, final double zoomScale) {
+ int size = 0;
+
+ for (IBorderItemEditPart editPart : tops) {
+ int editPartSize = (int) (((GraphicalEditPart) editPart).getFigure().getBounds().width * zoomScale);
+ if (!width) {
+ editPartSize = (int) (((GraphicalEditPart) editPart).getFigure().getBounds().height * zoomScale);
+ }
+ size += editPartSize;
+ }
+ return size;
+ }
+
+ /**
+ * Compute the cosinus of a vector.
+ *
+ * @param ray
+ * The vector
+ * @return The cosinus value of the vector
+ */
+ private static double cos(final Ray ray) {
+ return ray.x / Math.sqrt(Math.pow(ray.x, 2) + Math.pow(ray.y, 2));
+ }
+
+ /**
+ * Compute the sinus of a vector.
+ *
+ * @param ray
+ * The vector
+ * @return The sinus value of the vector
+ */
+ private static double sin(final Ray ray) {
+ return ray.y / Math.sqrt(Math.pow(ray.x, 2) + Math.pow(ray.y, 2));
+ }
+
+ /**
+ *
+ * @param parts
+ * @param scale
+ * @return
+ */
+ private Map<IBorderItemEditPart, BorderItemOppositeElementData> getOppositeElementsData(List<IBorderItemEditPart> parts, double scale) {
+ final Map<IBorderItemEditPart, BorderItemOppositeElementData> targetPoints = new HashMap<IBorderItemEditPart, BorderItemOppositeElementData>();
+ for (IBorderItemEditPart borderItemEditPart : parts) {
+ final BorderItemOppositeElementData oppositeElementData = getOppositeElementData(borderItemEditPart, scale);
+ if (oppositeElementData != null) {
+ targetPoints.put(borderItemEditPart, oppositeElementData);
+ }
+ }
+ return targetPoints;
+ }
+
+ /**
+ * Returns the list of border items to be at the North position. This border
+ * items are sorted. To sort this element we compute again the rays with a
+ * new distant point to be more precise on the order.
+ *
+ * @param headings
+ * List of vector by border items
+ * @param containerAbsoluteCos
+ * The absolute cos of the container
+ * @param containerCenter
+ * the center of the container of the border items
+ * @return the list of border items to be at the North position.
+ */
+ private List<IBorderItemEditPart> getNorthBorderItems(final Map<IBorderItemEditPart, Ray> headings, final double containerAbsoluteCos, double scale, final Point containerCenter) {
+
+ final List<IBorderItemEditPart> parts = new LinkedList<IBorderItemEditPart>();
+
+ for (Map.Entry<IBorderItemEditPart, Ray> entry : headings.entrySet()) {
+ final Ray ray = entry.getValue();
+ if (ray.y != 0) {
+
+ final double cos = BorderItemAwareLayoutProvider.cos(ray);
+
+ if (Math.abs(cos) < containerAbsoluteCos && ray.y < 0) {
+ parts.add(entry.getKey());
+ }
+ }
+ }
+
+ final Map<IBorderItemEditPart, BorderItemOppositeElementData> oppositeElementsDataByEditPart = getOppositeElementsData(parts, scale);
+ Collections.sort(parts, new NorthCoordinateComparator(oppositeElementsDataByEditPart));
+
+ return parts;
+
+ }
+
+ /**
+ * Returns the list of border items to be at the South position.
+ *
+ * @param headings
+ * List of vector by border items
+ * @param containerAbsoluteCos
+ * The absolute cos of the container
+ * @return the list of border items to be at the South position.
+ */
+ private List<IBorderItemEditPart> getSouthBorderItems(final Map<IBorderItemEditPart, Ray> headings, final double absoluteCos, double scale, final Point containerCenter) {
+
+ final List<IBorderItemEditPart> parts = new LinkedList<IBorderItemEditPart>();
+
+ for (Map.Entry<IBorderItemEditPart, Ray> entry : headings.entrySet()) {
+ final Ray ray = entry.getValue();
+ if (ray.y != 0) {
+ final double cos = BorderItemAwareLayoutProvider.cos(ray);
+
+ if (Math.abs(cos) < absoluteCos && ray.y > 0) {
+ parts.add(entry.getKey());
+ }
+ }
+ }
+
+ final Map<IBorderItemEditPart, BorderItemOppositeElementData> oppositeElementsDataByEditPart = getOppositeElementsData(parts, scale);
+ Collections.sort(parts, new SouthCoordinateComparator(oppositeElementsDataByEditPart));
+
+ return parts;
+ }
+
+ /**
+ * Returns the list of border items to be at the East position.
+ *
+ * @param headings
+ * List of vector by border items
+ * @param containerAbsoluteSin
+ * The absolute sinus of the container
+ * @return the list of border items to be at the East position.
+ */
+ private List<IBorderItemEditPart> getEastBorderItems(final Map<IBorderItemEditPart, Ray> headings, final double containerAbsoluteSin, double scale, final Point containerCenter) {
+
+ final List<IBorderItemEditPart> parts = new LinkedList<IBorderItemEditPart>();
+
+ for (Map.Entry<IBorderItemEditPart, Ray> entry : headings.entrySet()) {
+ final Ray ray = entry.getValue();
+
+ if (ray.x != 0) {
+ final double sin = BorderItemAwareLayoutProvider.sin(ray);
+
+ if (Math.abs(sin) < containerAbsoluteSin && ray.x > 0) {
+ parts.add(entry.getKey());
+ }
+ }
+
+ }
+
+ final Map<IBorderItemEditPart, BorderItemOppositeElementData> targetPoints = getOppositeElementsData(parts, scale);
+ Collections.sort(parts, new EastCoordinateComparator(targetPoints));
+
+ return parts;
+ }
+
+ /**
+ * Returns the list of border items to be at the West position.
+ *
+ * @param headings
+ * List of vector by border items
+ * @param containerAbsoluteSin
+ * The absolute sinus of the container
+ * @return the list of border items to be at the West position.
+ */
+ private List<IBorderItemEditPart> getWestBorderItems(final Map<IBorderItemEditPart, Ray> headings, final double containerAbsoluteSin, double scale, final Point containerCenter) {
+
+ final List<IBorderItemEditPart> parts = new LinkedList<IBorderItemEditPart>();
+
+ for (Map.Entry<IBorderItemEditPart, Ray> entry : headings.entrySet()) {
+ final Ray ray = entry.getValue();
+ if (ray.x != 0) {
+ final double sin = BorderItemAwareLayoutProvider.sin(ray);
+
+ if (Math.abs(sin) < containerAbsoluteSin && ray.x < 0) {
+ parts.add(entry.getKey());
+ }
+ }
+ }
+
+ final Map<IBorderItemEditPart, BorderItemOppositeElementData> oppositeElementsDataByEditPart = getOppositeElementsData(parts, scale);
+ Collections.sort(parts, new WestCoordinateComparator(oppositeElementsDataByEditPart));
+
+ return parts;
+ }
+
+ /**
+ * Get heading (vector, angle, ...) between the center of the edit part and
+ * the center of the edit part at the other side of the edge. Return null if
+ * :
+ * <UL>
+ * <LI>there is no edge that is come from or go back to
+ * <code>editPart</code></LI>
+ * <LI>there is many edges that is come from or go back to
+ * <code>editPart</code>
+ * <LI>
+ *
+ * @param editPart
+ * The editPart of the current border item
+ * @param containerCenterAfterArrange
+ * The center of the border item parent after arrangeAll
+ * @param scale
+ * The scale of the current diagram
+ * @param launchNormalArrange
+ * Tell if the normal arrange process will be called before the
+ * border item arrange
+ * @return A vector representing the edge
+ */
+ private Ray getHeading(final IBorderItemEditPart editPart, final Point containerCenterAfterArrange, final double scale) {
+ final Point targetPoint = getTargetPoint(editPart, scale);
+ if (targetPoint != null) {
+ return new Ray(containerCenterAfterArrange, targetPoint);
+ }
+ return null;
+ }
+
+ /**
+ * @param editPart
+ * @param scale
+ * @param targetPoint
+ * @return
+ */
+ private Point getTargetPoint(final IBorderItemEditPart editPart, final double scale) {
+ Point targetPoint = null;
+ final GraphicalEditPart target = getTarget(editPart);
+
+ if (target != null && editPart != target && !isAncestor(editPart, target) && !isAncestor(target, editPart)) {
+ if (previousIterationDatasbyEditPart.get(target) != null) {
+ targetPoint = previousIterationDatasbyEditPart.get(target).getPreviousCenterLocation();
+ } else {
+ targetPoint = getBounds((IGraphicalEditPart) target, scale).getCenter();
+ }
+ }
+ return targetPoint;
+ }
+
+ private BorderItemOppositeElementData getOppositeElementData(final IBorderItemEditPart editPart, final double scale) {
+ BorderItemOppositeElementData oppositeElementData = null;
+ final GraphicalEditPart target = getTarget(editPart);
+
+ if (target != null && editPart != target && !isAncestor(editPart, target) && !isAncestor(target, editPart)) {
+ Point targetPoint;
+ if (previousIterationDatasbyEditPart.get(target) != null) {
+ targetPoint = previousIterationDatasbyEditPart.get(target).getPreviousCenterLocation();
+ } else {
+ targetPoint = getBounds((IGraphicalEditPart) target, scale).getCenter();
+ }
+ if (target instanceof IBorderItemEditPart) {
+ oppositeElementData = new BorderItemOppositeElementData(targetPoint, DBorderItemLocator.findClosestSideOfParent(new Rectangle(targetPoint, new Dimension(1, 1)),
+ getBounds((IGraphicalEditPart) target.getParent(), scale)));
+ } else {
+ oppositeElementData = new BorderItemOppositeElementData(targetPoint);
+ }
+ }
+ return oppositeElementData;
+ }
+
+ /**
+ * Return the edit part that is at the other side of the edge. Return null
+ * if :
+ * <UL>
+ * <LI>there is no edge that is come from or go back to
+ * <code>editPart</code></LI>
+ * <LI>there is many edges that is come from or go back to
+ * <code>editPart</code>
+ * <LI>
+ *
+ * @param editPart
+ * A border edit part that is on an extremity of an edge.
+ * @return the opposite graphical edit part
+ */
+ private GraphicalEditPart getTarget(final IBorderItemEditPart editPart) {
+ GraphicalEditPart target = null;
+ if (editPart.getSourceConnections().size() == 1 && editPart.getTargetConnections().isEmpty()) {
+ target = (GraphicalEditPart) ((ConnectionEditPart) editPart.getSourceConnections().get(0)).getTarget();
+ } else if (editPart.getSourceConnections().isEmpty() && editPart.getTargetConnections().size() == 1) {
+ target = (GraphicalEditPart) ((ConnectionEditPart) editPart.getTargetConnections().get(0)).getSource();
+ }
+ return target;
+ }
+
+ /**
+ * Check if <code>childCandidate</code> is contained in
+ * <code>parentCandidate</code>.
+ *
+ * @param childCandidate
+ * The child candidate
+ * @param parentCandidate
+ * The parent candidate
+ * @return true if parentCandidate contains the childCandidate.
+ */
+ private boolean isAncestor(final EditPart childCandidate, final EditPart parentCandidate) {
+ EditPart currentParent = childCandidate.getParent();
+ while (currentParent != null) {
+ if (currentParent == parentCandidate) {
+ return true;
+ }
+ currentParent = currentParent.getParent();
+ }
+ return false;
+ }
+
+ /**
+ * Get the absolute bounds that this edit part will have after the execution
+ * of arrangeAll.<BR>
+ * The return bounds take into account the scale, ie if the real bounds is
+ * {100, 200} the return bounds is {50, 100}.
+ *
+ * @param graphicalEditPart
+ * The edit part to deal with
+ * @param scale
+ * The current scale of the diagram
+ * @return The bounds after arrangeAll
+ */
+ protected Rectangle getBounds(final IGraphicalEditPart graphicalEditPart, final double scale) {
+ return getBounds(graphicalEditPart, scale, null);
+ }
+
+ /**
+ * Get the absolute bounds that this edit part will have after the execution
+ * of arrangeAll.<BR>
+ * The return bounds take into account the scale, ie if the real bounds is
+ * {100, 200} the return bounds is {50, 100}.
+ *
+ * @param graphicalEditPart
+ * The edit part to deal with
+ * @param scale
+ * The current scale of the diagram
+ * @param parentMoveDelta
+ * The parent move delta if it is know, null otherwise
+ * @return The bounds after arrangeAll
+ */
+ protected Rectangle getBounds(final IGraphicalEditPart graphicalEditPart, final double scale, final Dimension parentMoveDelta) {
+ return getBounds(graphicalEditPart, scale, parentMoveDelta, true, true);
+ }
+
+ /**
+ * Get the absolute bounds that this edit part will have after the execution
+ * of arrangeAll.<BR>
+ * The return bounds take into account the scale, ie if the real bounds is
+ * {100, 200} the return bounds is {50, 100}.
+ *
+ * @param graphicalEditPart
+ * The edit part to deal with
+ * @param scale
+ * The current scale of the diagram
+ * @param parentMoveDelta
+ * The parent move delta if it is know, null otherwise
+ * @param processX
+ * A boolean value used to validate if calculating width is
+ * needed
+ * @param processY
+ * A boolean value used to validate if calculating height is
+ * needed
+ * @return The bounds after arrangeAll
+ */
+ protected Rectangle getBounds(final IGraphicalEditPart graphicalEditPart, final double scale, final Dimension parentMoveDelta, final boolean processX, final boolean processY) {
+
+ Rectangle bounds = null;
+ boolean isPinned = false;
+ if (graphicalEditPart.resolveSemanticElement() instanceof DDiagramElement) {
+ DDiagramElement dDiagramElement = (DDiagramElement) graphicalEditPart.resolveSemanticElement();
+ isPinned = new PinHelper().isPinned(dDiagramElement);
+ if (isPinned) {
+ bounds = graphicalEditPart.getFigure().getBounds().getCopy();
+ }
+ }
+
+ if (!isPinned) {
+ // Compute location after arrange
+ bounds = this.getBounds(graphicalEditPart);
+
+ if (bounds != null) {
+ final Dimension moveDelta = bounds.getTopLeft().getDifference(graphicalEditPart.getFigure().getBounds().getTopLeft());
+ moveDelta.scale(1 / scale);
+
+ // final Dimension sizeDelta =
+ // bounds.getSize().getDifference(graphicalEditPart.getFigure().getBounds().getSize());
+ // sizeDelta.scale(1 / scale);
+
+ bounds = new Rectangle(graphicalEditPart.getFigure().getBounds()).translate(new Point(moveDelta.width, moveDelta.height));
+ // bounds.setSize(bounds.getSize().getExpanded(sizeDelta));
+ }
+ }
+ if (parentMoveDelta != null) {
+ bounds = bounds.getTranslated(new Point(parentMoveDelta.width, parentMoveDelta.height));
+ } else if (!(graphicalEditPart.getParent() instanceof IDDiagramEditPart) && bounds != null) {
+ final IGraphicalEditPart parent = (IGraphicalEditPart) graphicalEditPart.getParent();
+ final Rectangle parentBounds = getBounds(parent, scale);
+
+ if (!isPinned(parent)) {
+ final Dimension moveDelta = getScaledMoveDelta(parent, parentBounds, scale);
+ bounds = bounds.getTranslated(new Point(moveDelta.width, moveDelta.height));
+ }
+ }
+ graphicalEditPart.getFigure().translateToAbsolute(bounds);
+
+ if (!isPinned && launchNormalArrange) {
+ // Compute size after arrange (with auto-size)
+ final Dimension moveDelta = getScaledMoveDelta(graphicalEditPart, bounds, scale);
+ final Dimension sizeWithAutoSize = getSizeAfterAutoSize(graphicalEditPart, bounds, scale, moveDelta, processX, processY);
+ bounds.setSize(sizeWithAutoSize);
+ }
+ return bounds;
+ }
+
+ /**
+ * Compute the delta between the actual location of the <code>part</code>
+ * and the target bounds.
+ *
+ * @param part
+ * The edit part to deal with
+ * @param targetBounds
+ * The target bounds
+ * @param scale
+ * The current scale of the diagram
+ * @return the delta between the actual location of the <code>part</code>
+ * and the target bounds
+ */
+ private Dimension getScaledMoveDelta(final IGraphicalEditPart part, final Rectangle targetBounds, final double scale) {
+ final Point topLeft = part.getFigure().getBounds().getTopLeft();
+ part.getFigure().translateToAbsolute(topLeft);
+ final Dimension moveDelta = targetBounds.getTopLeft().getDifference(topLeft);
+ moveDelta.scale(1 / scale);
+ return moveDelta;
+ }
+
+ /**
+ * Compute the size of this editPart after arrange all if this editPart is
+ * in auto-size mode. This calculation is approximate by the leftmost child
+ * and its size.
+ *
+ * @param part
+ * The concern edit part
+ * @param actualBounds
+ * The current bounds of this edit part
+ * @param scale
+ * The current scale of the diagram
+ * @param moveDelta
+ * The parent move delta if it is know, null otherwise
+ * @return The size after arrange all (if needed).
+ */
+ private Dimension getSizeAfterAutoSize(final IGraphicalEditPart part, final Rectangle actualBounds, final double scale, final Dimension moveDelta, final boolean processX, final boolean processY) {
+ final Dimension result = new Dimension(actualBounds.getSize());
+ boolean shouldWidthAutoSized = ArrangeAllWithAutoSize.shouldBeAutosized(part) || part instanceof ShapeCompartmentEditPart;
+ boolean shouldHeightAutoSized = shouldWidthAutoSized;
+ if ((!shouldWidthAutoSized && !shouldHeightAutoSized) && part.getNotationView() instanceof Node) {
+ final Node node = (Node) part.getNotationView();
+ final LayoutConstraint layoutConstraint = node.getLayoutConstraint();
+ if (layoutConstraint instanceof Size) {
+ final Size size = (Size) layoutConstraint;
+ shouldWidthAutoSized = size.getWidth() == -1;
+ shouldHeightAutoSized = size.getHeight() == -1;
+ }
+ }
+
+ // Take into account the default size for some specific figures (we set
+ // a default size explicitly in createMainFigure of
+ // DNodeContainerEditPart and DNodeContainerEditPart)
+ Dimension defaultSize = new Dimension(0, 0);
+ final IFigure f = part.getFigure();
+ if (f instanceof BorderedNodeFigure && ((BorderedNodeFigure) f).getMainFigure() instanceof DefaultSizeNodeFigure) {
+ defaultSize = ((DefaultSizeNodeFigure) ((BorderedNodeFigure) f).getMainFigure()).getDefaultSize();
+ }
+ if (shouldWidthAutoSized && processX) {
+ final int rightSizeXCoordinate = getRightSizeXCoordinateOfRightMostChild(part, scale, moveDelta);
+ result.width = Math.max(defaultSize.width, rightSizeXCoordinate - actualBounds.x);
+ }
+ if (shouldHeightAutoSized && processY) {
+ final int bottomSizeYCoordinate = getBottomSizeYCoordinateOfLowestChild(part, scale, moveDelta);
+ result.height = Math.max(defaultSize.height, bottomSizeYCoordinate - actualBounds.y);
+ }
+ return result;
+ }
+
+ /**
+ * Return the x axis coordinate of the right size of the rightmost child
+ * (after the arrange all).
+ *
+ * @param part
+ * The parent
+ * @param scale
+ * The current scale of the diagram
+ * @param moveDelta
+ * The parent move delta if it is know, null otherwise
+ * @param launchNormalArrange
+ * Tell if the normal arrange process will be called before the
+ * border item arrange
+ * @return the x axis coordinate of the right size of the rightmost child
+ */
+ private int getRightSizeXCoordinateOfRightMostChild(final IGraphicalEditPart part, final double scale, final Dimension moveDelta) {
+ int result = 0;
+ final Collection<IGraphicalEditPart> children = Collections2.filter(
+ part.getChildren(),
+ Predicates.and(Predicates.instanceOf(IGraphicalEditPart.class), Predicates.not(Predicates.instanceOf(AbstractDiagramBorderNodeEditPart.class)),
+ Predicates.not(Predicates.instanceOf(AbstractDiagramNameEditPart.class))));
+ for (IGraphicalEditPart child : children) {
+ if (child instanceof ShapeCompartmentEditPart) {
+ // Only delegates to the grandchildren
+ final Collection<IGraphicalEditPart> grandchildren = Collections2.filter(
+ child.getChildren(),
+ Predicates.and(Predicates.instanceOf(IGraphicalEditPart.class), Predicates.not(Predicates.instanceOf(AbstractDiagramBorderNodeEditPart.class)),
+ Predicates.not(Predicates.instanceOf(AbstractDiagramNameEditPart.class))));
+ for (IGraphicalEditPart grandchild : grandchildren) {
+ final Rectangle bounds = getBounds(grandchild, scale, moveDelta, true, false);
+ final int rightSizeXCoordinate = bounds.x + bounds.width;
+ if (result < rightSizeXCoordinate) {
+ result = rightSizeXCoordinate;
+ }
+ }
+ } else {
+ final Rectangle bounds = getBounds(child, scale, moveDelta, true, false);
+ final int rightSizeXCoordinate = bounds.x + bounds.width;
+ if (result < rightSizeXCoordinate) {
+ result = rightSizeXCoordinate;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Return the y axis coordinate of the bottom size of the lowest child
+ * (after the arrange all).
+ *
+ * @param part
+ * The parent
+ * @param scale
+ * The current scale of the diagram
+ * @param moveDelta
+ * The parent move delta if it is know, null otherwise
+ * @return the y axis coordinate of the bottom size of the lowest child
+ */
+ private int getBottomSizeYCoordinateOfLowestChild(final IGraphicalEditPart part, final double scale, final Dimension moveDelta) {
+ int result = 0;
+ final Collection<IGraphicalEditPart> children = Collections2.filter(
+ part.getChildren(),
+ Predicates.and(Predicates.instanceOf(IGraphicalEditPart.class), Predicates.not(Predicates.instanceOf(AbstractDiagramBorderNodeEditPart.class)),
+ Predicates.not(Predicates.instanceOf(AbstractDiagramNameEditPart.class))));
+ for (IGraphicalEditPart child : children) {
+ if (child instanceof ShapeCompartmentEditPart) {
+ // Only delegates to the grandchildren
+ final Collection<IGraphicalEditPart> grandchildren = Collections2.filter(
+ child.getChildren(),
+ Predicates.and(Predicates.instanceOf(IGraphicalEditPart.class), Predicates.not(Predicates.instanceOf(AbstractDiagramBorderNodeEditPart.class)),
+ Predicates.not(Predicates.instanceOf(AbstractDiagramNameEditPart.class))));
+ for (IGraphicalEditPart grandchild : grandchildren) {
+ final Rectangle bounds = getBounds(grandchild, scale, moveDelta, false, true);
+ final int bottomSizeYCoordinate = bounds.y + bounds.height;
+ if (result < bottomSizeYCoordinate) {
+ result = bottomSizeYCoordinate;
+ }
+ }
+ } else {
+ final Rectangle bounds = getBounds(child);
+ final int bottomSizeYCoordinate = bounds.y + bounds.height;
+ if (result < bottomSizeYCoordinate) {
+ result = bottomSizeYCoordinate;
+ }
+ }
+ }
+ return result;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/CompositeDownTopLayoutProvider.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/CompositeDownTopLayoutProvider.java
new file mode 100644
index 0000000000..1553291cfd
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/CompositeDownTopLayoutProvider.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout.provider;
+
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gef.ConnectionEditPart;
+
+/**
+ * Specialization of a down to top diagram layout leveraging specific layout
+ * settings associated with a given diagram instance.
+ *
+ * @author cbrun
+ */
+@SuppressWarnings("restriction")
+public class CompositeDownTopLayoutProvider extends AbstractCompositeLayoutProvider {
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Rectangle translateToGraph(final Rectangle r) {
+ final Rectangle rDP = new Rectangle(r);
+ getMapMode().LPtoDP(rDP);
+ return rDP;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Rectangle translateFromGraph(final Rectangle rect) {
+ final Rectangle rLP = new Rectangle(rect);
+ getMapMode().DPtoLP(rLP);
+ return rLP;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected boolean layoutTopDown(final ConnectionEditPart poly) {
+ return true;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/CompositeDownTopProvider.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/CompositeDownTopProvider.java
new file mode 100644
index 0000000000..21ec61f316
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/CompositeDownTopProvider.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout.provider;
+
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.services.layout.AbstractLayoutEditPartProvider;
+
+import org.eclipse.sirius.diagram.ui.tools.api.layout.provider.AbstractLayoutProvider;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.provider.CompoundLayoutProvider;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.provider.LayoutProvider;
+
+/**
+ * {@link org.eclipse.gmf.runtime.diagram.ui.services.layout.AbstractLayoutNodeProvider}
+ * with a Down/Top organization.
+ *
+ * @author ymortier
+ */
+public class CompositeDownTopProvider implements LayoutProvider {
+
+ /** The delegated GMF provider. */
+ private AbstractLayoutEditPartProvider layoutNodeProvider;
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.layout.provider.LayoutProvider#getLayoutNodeProvider(org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart)
+ */
+ public AbstractLayoutEditPartProvider getLayoutNodeProvider(final IGraphicalEditPart container) {
+ if (this.layoutNodeProvider == null) {
+ final CompoundLayoutProvider clp = new CompoundLayoutProvider();
+ final CompositeDownTopLayoutProvider cdtp = new CompositeDownTopLayoutProvider();
+
+ clp.addProvider(cdtp);
+ clp.addProvider(new PinnedElementsLayoutProvider(cdtp));
+ if (ENABLE_BORDERED_NODES_ARRANGE_ALL) {
+ // ArrangeSelectionLayoutProvider wrap all providers to manage
+ // the selected diagram element on diagram "Arrange all"
+ AbstractLayoutProvider abstractLayoutProvider = new BorderItemAwareLayoutProvider(clp);
+ this.layoutNodeProvider = new ArrangeSelectionLayoutProvider(abstractLayoutProvider);
+ } else {
+ this.layoutNodeProvider = new ArrangeSelectionLayoutProvider(clp);
+ }
+ }
+ return this.layoutNodeProvider;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.layout.provider.LayoutProvider#provides(org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart)
+ */
+ public boolean provides(final IGraphicalEditPart container) {
+ /*
+ * we should always provide even if container is not the diagram, to
+ * handle the case of arrange all action when an element in a container
+ * is selected
+ */
+ return true;
+ }
+
+ public boolean isDiagramLayoutProvider() {
+ return true;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/CompositeLeftRightLayoutProvider.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/CompositeLeftRightLayoutProvider.java
new file mode 100644
index 0000000000..8eec27a4c1
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/CompositeLeftRightLayoutProvider.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout.provider;
+
+import org.eclipse.draw2d.PositionConstants;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.draw2d.graph.DirectedGraph;
+import org.eclipse.gef.ConnectionEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart;
+
+/**
+ * Specialization of a left to right diagram layout leveraging specific layout
+ * settings associated with a given diagram instance.
+ *
+ * @author cbrun
+ */
+@SuppressWarnings("restriction")
+public class CompositeLeftRightLayoutProvider extends AbstractCompositeLayoutProvider {
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.internal.layout.provider.AbstractCompositeLayoutProvider#translateToGraph(org.eclipse.draw2d.geometry.Rectangle)
+ */
+ @Override
+ public Rectangle translateToGraph(final Rectangle r) {
+ final Rectangle rDP = new Rectangle(r);
+ getMapMode().LPtoDP(rDP);
+ return rDP;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Rectangle translateFromGraph(final Rectangle rect) {
+ final Rectangle rLP = new Rectangle(rect);
+ getMapMode().DPtoLP(rLP);
+ return rLP;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected boolean layoutTopDown(final ConnectionEditPart poly) {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.providers.internal.CompositeLayoutProvider#createGraph()
+ */
+ @Override
+ protected DirectedGraph createGraph() {
+ DirectedGraph g = super.createGraph();
+ g.setDirection(PositionConstants.EAST);
+ return g;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.providers.internal.CompositeLayoutProvider#getLayoutDirection(org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart)
+ */
+ protected int getLayoutDirection(GraphicalEditPart ep) {
+ return PositionConstants.EAST;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/CompositeLeftRightProvider.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/CompositeLeftRightProvider.java
new file mode 100644
index 0000000000..f3ca716c25
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/CompositeLeftRightProvider.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout.provider;
+
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.services.layout.AbstractLayoutEditPartProvider;
+import org.eclipse.gmf.runtime.notation.View;
+
+import org.eclipse.sirius.description.CompositeLayout;
+import org.eclipse.sirius.description.Layout;
+import org.eclipse.sirius.description.LayoutDirection;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.provider.AbstractLayoutProvider;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.provider.CompoundLayoutProvider;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.provider.LayoutProvider;
+import org.eclipse.sirius.diagram.ui.tools.internal.layout.DiagramLayoutCustomization;
+
+/**
+ * Provides {@link CompositeLeftRightLayoutProvider}.
+ *
+ * @author ymortier
+ */
+public class CompositeLeftRightProvider implements LayoutProvider {
+
+ /** The delegated GMF provider. */
+ private AbstractLayoutEditPartProvider layoutNodeProvider;
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.layout.provider.LayoutProvider#getLayoutNodeProvider(org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart)
+ */
+ public AbstractLayoutEditPartProvider getLayoutNodeProvider(final IGraphicalEditPart container) {
+ if (this.layoutNodeProvider == null) {
+ final CompoundLayoutProvider clp = new CompoundLayoutProvider();
+ final CompositeLeftRightLayoutProvider cdtp = new CompositeLeftRightLayoutProvider();
+ clp.addProvider(cdtp);
+ clp.addProvider(new PinnedElementsLayoutProvider(cdtp));
+ if (ENABLE_BORDERED_NODES_ARRANGE_ALL) {
+ // ArrangeSelectionLayoutProvider wrap all providers to manage
+ // the selected diagram element on diagram "Arrange all"
+ AbstractLayoutProvider abstractLayoutProvider = new BorderItemAwareLayoutProvider(clp);
+ this.layoutNodeProvider = new ArrangeSelectionLayoutProvider(abstractLayoutProvider);
+ } else {
+ this.layoutNodeProvider = new ArrangeSelectionLayoutProvider(clp);
+ }
+ }
+ return this.layoutNodeProvider;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.layout.provider.LayoutProvider#provides(org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart)
+ */
+ public boolean provides(final IGraphicalEditPart container) {
+ return isInDDiagramWithConfiguredLeftRightLayout(container.getNotationView());
+ }
+
+ private boolean isInDDiagramWithConfiguredLeftRightLayout(final View view) {
+ final Layout foundLayout = DiagramLayoutCustomization.findLayoutSettings(view);
+ if (foundLayout instanceof CompositeLayout) {
+ return ((CompositeLayout) foundLayout).getDirection() == LayoutDirection.LEFT_TO_RIGHT;
+ }
+ return false;
+ }
+
+ public boolean isDiagramLayoutProvider() {
+ return true;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/CompositeTopDownLayoutProvider.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/CompositeTopDownLayoutProvider.java
new file mode 100644
index 0000000000..3d2b7b27c8
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/CompositeTopDownLayoutProvider.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout.provider;
+
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gef.ConnectionEditPart;
+
+/**
+ * Specialization of a down to top diagram layout leveraging specific layout
+ * settings associated with a given diagram instance.
+ *
+ * @author cbrun
+ */
+@SuppressWarnings("restriction")
+public class CompositeTopDownLayoutProvider extends AbstractCompositeLayoutProvider {
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Rectangle translateToGraph(final Rectangle r) {
+ final Rectangle rDP = new Rectangle(r);
+ getMapMode().LPtoDP(rDP);
+ return rDP;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Rectangle translateFromGraph(final Rectangle rect) {
+ final Rectangle rLP = new Rectangle(rect);
+ getMapMode().DPtoLP(rLP);
+ return rLP;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected boolean layoutTopDown(final ConnectionEditPart poly) {
+ return false;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/CompositeTopDownProvider.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/CompositeTopDownProvider.java
new file mode 100644
index 0000000000..220b9b0a5c
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/CompositeTopDownProvider.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2011 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout.provider;
+
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.services.layout.AbstractLayoutEditPartProvider;
+import org.eclipse.gmf.runtime.notation.View;
+
+import org.eclipse.sirius.description.CompositeLayout;
+import org.eclipse.sirius.description.Layout;
+import org.eclipse.sirius.description.LayoutDirection;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.provider.AbstractLayoutProvider;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.provider.CompoundLayoutProvider;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.provider.LayoutProvider;
+import org.eclipse.sirius.diagram.ui.tools.internal.layout.DiagramLayoutCustomization;
+
+/**
+ * Provides
+ * {@link org.eclipse.sirius.common.ui.tools.api.graphical.layout.CompositeTopDownProvider}
+ * .
+ *
+ * @author ymortier
+ */
+public class CompositeTopDownProvider implements LayoutProvider {
+
+ /** The delegated GMF provider. */
+ private AbstractLayoutEditPartProvider layoutNodeProvider;
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.layout.provider.LayoutProvider#getLayoutNodeProvider(org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart)
+ */
+ public AbstractLayoutEditPartProvider getLayoutNodeProvider(final IGraphicalEditPart container) {
+ if (this.layoutNodeProvider == null) {
+ final CompoundLayoutProvider clp = new CompoundLayoutProvider();
+ final CompositeTopDownLayoutProvider cdtp = new CompositeTopDownLayoutProvider();
+
+ clp.addProvider(cdtp);
+ clp.addProvider(new PinnedElementsLayoutProvider(cdtp));
+ if (ENABLE_BORDERED_NODES_ARRANGE_ALL) {
+ // ArrangeSelectionLayoutProvider wrap all providers to manage
+ // the selected diagram element on diagram "Arrange all"
+ AbstractLayoutProvider abstractLayoutProvider = new BorderItemAwareLayoutProvider(clp);
+ this.layoutNodeProvider = new ArrangeSelectionLayoutProvider(abstractLayoutProvider);
+ } else {
+ this.layoutNodeProvider = new ArrangeSelectionLayoutProvider(clp);
+ }
+ }
+ return this.layoutNodeProvider;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.layout.provider.LayoutProvider#provides(org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart)
+ */
+ public boolean provides(final IGraphicalEditPart container) {
+ return isInDDiagramWithConfiguredTopDownLayout(container.getNotationView());
+ }
+
+ private boolean isInDDiagramWithConfiguredTopDownLayout(final View view) {
+ final Layout foundLayout = DiagramLayoutCustomization.findLayoutSettings(view);
+ if (foundLayout instanceof CompositeLayout) {
+ return ((CompositeLayout) foundLayout).getDirection() == LayoutDirection.TOP_TO_BOTTOM;
+ }
+ return false;
+ }
+
+ public boolean isDiagramLayoutProvider() {
+ return true;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/LayoutProviderDescriptor.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/LayoutProviderDescriptor.java
new file mode 100644
index 0000000000..1ea3375082
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/LayoutProviderDescriptor.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2011 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout.provider;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+
+import org.eclipse.sirius.diagram.part.SiriusDiagramEditorPlugin;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.provider.LayoutProvider;
+
+/**
+ * The descriptor of a {@link LayoutProvider}.
+ *
+ * @author ymortier
+ */
+public class LayoutProviderDescriptor extends AbstractProviderDescriptor {
+
+ /** The layout provider. */
+ private LayoutProvider provider;
+
+ /**
+ * Create a new descriptor with the specified configuration element.
+ *
+ * @param element
+ * the configuration element.
+ */
+ public LayoutProviderDescriptor(final IConfigurationElement element) {
+ super(element);
+ }
+
+ /**
+ * Return the layout provider.
+ *
+ * @return the layout provider.
+ */
+ public LayoutProvider getProviderInstance() {
+ if (provider == null) {
+ try {
+ provider = (LayoutProvider) element.createExecutableExtension("providerClass"); //$NON-NLS-1$
+ } catch (final CoreException e) {
+ SiriusDiagramEditorPlugin.getInstance().logError("CoreException during the initialization of the AIR Layout Provider " + this.getProviderClassName(), e);
+ }
+ }
+ return provider;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/LayoutService.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/LayoutService.java
new file mode 100644
index 0000000000..1e0b15ade6
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/LayoutService.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2011 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout.provider;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.emf.common.EMFPlugin;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+
+import org.eclipse.sirius.diagram.ui.tools.api.layout.provider.LayoutProvider;
+
+/**
+ * This class provides layout facilities based on the declared providers.
+ *
+ * @author ymortier
+ */
+public final class LayoutService {
+
+ /** All providers. */
+ private static List<LayoutProviderDescriptor> layoutProviders = new ArrayList<LayoutProviderDescriptor>();
+
+ static {
+ LayoutService.parseExtensionMetadata();
+ }
+
+ /** Name of the extension point to parse for extender providers. */
+ private static final String LAYOUT_PROVIDER_EXTENSION_POINT = "org.eclipse.sirius.diagram.layoutProvider"; //$NON-NLS-1$
+
+ /** Externalized here to avoid too many distinct usages. */
+ private static final String TAG_ENGINE = "layoutProvider";
+
+ /**
+ * Avoid instantiation.
+ */
+ private LayoutService() {
+
+ }
+
+ /**
+ * This will parse the currently running platform for extensions and store
+ * all the match engines that can be found.
+ */
+ private static void parseExtensionMetadata() {
+ if (EMFPlugin.IS_ECLIPSE_RUNNING) {
+ final IExtension[] extensions = Platform.getExtensionRegistry().getExtensionPoint(LAYOUT_PROVIDER_EXTENSION_POINT).getExtensions();
+ for (IExtension extension : extensions) {
+ final IConfigurationElement[] configElements = extension.getConfigurationElements();
+ for (IConfigurationElement configElement : configElements) {
+ final AbstractProviderDescriptor desc = LayoutService.parseEngine(configElement);
+ if (desc instanceof LayoutProviderDescriptor) {
+ layoutProviders.add((LayoutProviderDescriptor) desc);
+ }
+ }
+ }
+ Collections.sort(layoutProviders);
+ }
+ }
+
+ private static AbstractProviderDescriptor parseEngine(final IConfigurationElement configElement) {
+ if (!configElement.getName().equals(TAG_ENGINE)) {
+ return null;
+ }
+ final AbstractProviderDescriptor desc = new LayoutProviderDescriptor(configElement);
+ return desc;
+ }
+
+ /**
+ * Return the {@link LayoutProvider} to use with the specified
+ * {@link org.eclipse.gef.EditPart}.
+ *
+ * @param editPart
+ * the edit part.
+ * @return the {@link LayoutProvider} to use with the specified
+ * {@link org.eclipse.gef.EditPart}.
+ */
+ public static LayoutProvider getProvider(final IGraphicalEditPart editPart) {
+ final Iterator<LayoutProviderDescriptor> iterDescriptors = LayoutService.layoutProviders.listIterator();
+ while (iterDescriptors.hasNext()) {
+ final LayoutProviderDescriptor currentDescriptor = iterDescriptors.next();
+ final LayoutProvider provider = currentDescriptor.getProviderInstance();
+ if (provider != null) {
+ if (provider.provides(editPart)) {
+ return provider;
+ }
+ } else {
+ iterDescriptors.remove();
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/OrderedTreeLayoutProvider.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/OrderedTreeLayoutProvider.java
new file mode 100644
index 0000000000..5df978f1af
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/OrderedTreeLayoutProvider.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * Copyright (c) 2008 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout.provider;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.services.layout.AbstractLayoutEditPartProvider;
+import org.eclipse.gmf.runtime.notation.Diagram;
+import org.eclipse.gmf.runtime.notation.View;
+
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.description.DiagramDescription;
+import org.eclipse.sirius.description.Layout;
+import org.eclipse.sirius.description.OrderedTreeLayout;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.LayoutUtils;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.provider.AbstractLayoutProvider;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.provider.CompoundLayoutProvider;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.provider.GridLayoutProvider;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.provider.LayoutProvider;
+
+/**
+ * A tree ordered LayoutProvider, used for diagrams which have configured a
+ * {@link OrderedTreeLayout}.
+ * <p>
+ * Uses a properly configured {@link GridLayoutProvider} internally, a tree
+ * being seen as a partially filled grid.
+ *
+ * @author mchauvin
+ */
+public class OrderedTreeLayoutProvider implements LayoutProvider {
+ /**
+ * Simple flag to easily switch between the old/new behaviors during
+ * development.
+ */
+ private static final boolean PIN_MANAGEMENT_ON_TREE_LAYOUT = true;
+
+ /**
+ * The underlying grid provider.
+ */
+ private GridLayoutProvider airGridLayoutProvider;
+
+ /**
+ * {@inheritDoc}
+ */
+ public AbstractLayoutEditPartProvider getLayoutNodeProvider(final IGraphicalEditPart container) {
+ AbstractLayoutProvider layoutProvider = null;
+ if (isDDiagramWithConfiguredOrderedTreeLayout(container)) {
+ if (PIN_MANAGEMENT_ON_TREE_LAYOUT) {
+ final CompoundLayoutProvider clp = new CompoundLayoutProvider();
+ GridLayoutProvider layoutNodeProvider = getGridLayoutProvider();
+ clp.addProvider(layoutNodeProvider);
+ clp.addProvider(new PinnedElementsLayoutProvider(layoutNodeProvider));
+ // We return an ArrangeAllOnlyLayoutProvider as no
+ // "Arrange Selection" should be done on such layout.
+ if (ENABLE_BORDERED_NODES_ARRANGE_ALL) {
+ AbstractLayoutProvider abstractLayoutProvider = new BorderItemAwareLayoutProvider(clp);
+ layoutProvider = new ArrangeAllOnlyLayoutProvider(abstractLayoutProvider);
+ } else {
+ layoutProvider = new ArrangeAllOnlyLayoutProvider(clp);
+ }
+ } else {
+ return getGridLayoutProvider();
+ }
+ }
+ return layoutProvider;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean provides(final IGraphicalEditPart container) {
+ return isDDiagramWithConfiguredOrderedTreeLayout(container);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isDiagramLayoutProvider() {
+ return false;
+ }
+
+ /**
+ * Tests whether the specified edit part is a {@link DDiagram} which has
+ * been configured to use an {@link OrderedTreeLayout}.
+ */
+ private boolean isDDiagramWithConfiguredOrderedTreeLayout(final IGraphicalEditPart container) {
+ final View view = container.getNotationView();
+ final EObject modelElement = view.getElement();
+ if (view instanceof Diagram && modelElement instanceof DDiagram) {
+ final DDiagram vp = (DDiagram) modelElement;
+ final DiagramDescription desc = vp.getDescription();
+ if (desc != null) {
+ final Layout layout = desc.getLayout();
+ if (layout instanceof OrderedTreeLayout) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns a properly configured {@link GridLayoutProvider} suitable to
+ * layout a tree.
+ */
+ private GridLayoutProvider getGridLayoutProvider() {
+ if (airGridLayoutProvider == null) {
+ airGridLayoutProvider = new AdjustedGridLayout();
+ airGridLayoutProvider.setColumnSizeMode(GridLayoutProvider.DIMENSION_BY_LINE_OR_COLUMN);
+ airGridLayoutProvider.setLineSizeMode(GridLayoutProvider.DIMENSION_BY_LINE_OR_COLUMN);
+ airGridLayoutProvider.getPadding().left = LayoutUtils.SCALE;
+ airGridLayoutProvider.getPadding().right = LayoutUtils.SCALE;
+ }
+ return airGridLayoutProvider;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/PinnedElementsLayoutProvider.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/PinnedElementsLayoutProvider.java
new file mode 100644
index 0000000000..2b202eecc2
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/provider/PinnedElementsLayoutProvider.java
@@ -0,0 +1,217 @@
+/*******************************************************************************
+ * Copyright (c) 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout.provider;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.commands.CompoundCommand;
+import org.eclipse.gef.editparts.ZoomManager;
+import org.eclipse.gef.requests.ChangeBoundsRequest;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramRootEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+import org.eclipse.sirius.diagram.edit.api.part.AbstractDiagramElementContainerEditPart;
+import org.eclipse.sirius.diagram.edit.api.part.IDiagramBorderNodeEditPart;
+import org.eclipse.sirius.diagram.edit.api.part.IDiagramContainerEditPart;
+import org.eclipse.sirius.diagram.edit.api.part.IDiagramElementEditPart;
+import org.eclipse.sirius.diagram.edit.api.part.IDiagramListEditPart;
+import org.eclipse.sirius.diagram.edit.api.part.IDiagramNameEditPart;
+import org.eclipse.sirius.diagram.edit.api.part.IDiagramNodeEditPart;
+import org.eclipse.sirius.diagram.internal.edit.parts.DNodeContainerViewNodeContainerCompartment2EditPart;
+import org.eclipse.sirius.diagram.internal.edit.parts.DNodeContainerViewNodeContainerCompartmentEditPart;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.PinHelper;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.provider.DefaultLayoutProvider;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.provider.ExtendableLayoutProvider;
+import org.eclipse.sirius.diagram.ui.tools.internal.layout.ArrangeAllWithAutoSize;
+import org.eclipse.sirius.diagram.ui.tools.internal.layout.PinnedElementsHandler;
+
+/**
+ * A layout provider which handles pinned elements after an initial layout.
+ *
+ * @author pcdavid
+ */
+public class PinnedElementsLayoutProvider extends DefaultLayoutProvider {
+ /**
+ * The layout provider which was executed before us. Needed to obtain the
+ * new
+ */
+ private final ExtendableLayoutProvider baseProvider;
+
+ private Predicate<Object> validateAllElementInArrayListAreIDiagramElementEditPart = new Predicate<Object>() {
+
+ public boolean apply(Object input) {
+ return input instanceof IDiagramElementEditPart;
+ }
+ };
+
+ /**
+ * Creates a <code>FixOverlapsProvider</code>.
+ *
+ * @param baseProvider
+ * the layout provider which computed the initial locations.
+ */
+ public PinnedElementsLayoutProvider(final ExtendableLayoutProvider baseProvider) {
+ this.baseProvider = baseProvider;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Command layoutEditParts(final List selectedObjects, final IAdaptable layoutHint) {
+ final Map<IGraphicalEditPart, Rectangle> initialBounds = Maps.newHashMap(baseProvider.getExtender().getUpdatedBounds());
+ if (ArrangeAllWithAutoSize.isEnabled()) {
+ adjustAutoSizedContainers(initialBounds);
+ }
+ final Collection<IGraphicalEditPart> editParts = Lists.newArrayList(Iterables.filter(selectedObjects, IGraphicalEditPart.class));
+ // Removes the connectionEditPart
+ editParts.removeAll(Lists.newArrayList(Iterables.filter(selectedObjects, ConnectionEditPart.class)));
+ final CompoundCommand cc = new CompoundCommand();
+
+ // Finds if there are unpinned diagram elements to keep fixed stored in
+ // the LayoutHint as a Collection
+ ArrayList<IDiagramElementEditPart> elementstToKeepFixed = Lists.newArrayList();
+ if (layoutHint.getAdapter(Collection.class) instanceof ArrayList<?>
+ && Iterables.all((ArrayList<?>) layoutHint.getAdapter(Collection.class), validateAllElementInArrayListAreIDiagramElementEditPart)) {
+ elementstToKeepFixed = (ArrayList<IDiagramElementEditPart>) layoutHint.getAdapter(Collection.class);
+ }
+ handlePinnedElements(editParts, initialBounds, cc, elementstToKeepFixed);
+ return cc.unwrap();
+ }
+
+ private void adjustAutoSizedContainers(final Map<IGraphicalEditPart, Rectangle> initialBounds) {
+ PinHelper pinHelper = new PinHelper();
+ for (Entry<IGraphicalEditPart, Rectangle> entry : initialBounds.entrySet()) {
+ if (entry.getKey() instanceof AbstractDiagramElementContainerEditPart) {
+ final AbstractDiagramElementContainerEditPart container = (AbstractDiagramElementContainerEditPart) entry.getKey();
+ if (!pinHelper.isPinned(container.resolveDiagramElement())) {
+ final Rectangle bounds = entry.getValue().getCopy();
+ final Rectangle autoSizedBounds = container.getAutosizedDimensions();
+ bounds.width = autoSizedBounds.width;
+ bounds.height = autoSizedBounds.height;
+ entry.setValue(bounds);
+ }
+ }
+ }
+ }
+
+ private void handlePinnedElements(final Collection<IGraphicalEditPart> editParts, final Map<IGraphicalEditPart, Rectangle> initialBounds, final CompoundCommand cmd,
+ ArrayList<IDiagramElementEditPart> elementstToKeepFixed) {
+ /*
+ * Depth-first recursion on containers.
+ */
+ for (IGraphicalEditPart part : editParts) {
+ final Collection<IGraphicalEditPart> children = getChildrenOfInterest(part);
+ if (!children.isEmpty()) {
+ handlePinnedElements(children, initialBounds, cmd, elementstToKeepFixed);
+ }
+ }
+ /*
+ * Base case: handle pinned elements at this particular level.
+ */
+ final Map<IGraphicalEditPart, Rectangle> initialBoundsForThisLevel = Maps.filterEntries(initialBounds, new Predicate<Map.Entry<IGraphicalEditPart, Rectangle>>() {
+ public boolean apply(final Entry<IGraphicalEditPart, Rectangle> input) {
+ return editParts.contains(input.getKey());
+ }
+ });
+ final PinnedElementsHandler handler = new PinnedElementsHandler(editParts, initialBoundsForThisLevel, elementstToKeepFixed);
+ final Map<IGraphicalEditPart, Point> newPositions = handler.computeSolution();
+ for (Entry<IGraphicalEditPart, Point> entry : newPositions.entrySet()) {
+ final IGraphicalEditPart part = entry.getKey();
+ final Point position = entry.getValue();
+ final Command cbc = createChangeBoundsCommand(part, position);
+ cmd.add(cbc);
+ }
+ }
+
+ /**
+ * Finds the "real" children of the specified edit part that needs to be
+ * laid out.
+ */
+ private Collection<IGraphicalEditPart> getChildrenOfInterest(final IGraphicalEditPart gep) {
+ final Iterable<IGraphicalEditPart> rawChildren = Iterables.filter(gep.getChildren(), IGraphicalEditPart.class);
+ // Ignore these, which are technically children edit parts but not
+ // "inside" the container.
+ final Predicate<Object> invalidChildKind = Predicates.or(Predicates.instanceOf(IDiagramBorderNodeEditPart.class), Predicates.instanceOf(IDiagramNameEditPart.class));
+ // These are OK.
+ final Predicate<Object> validChildKind = Predicates.or(Predicates.instanceOf(IDiagramNodeEditPart.class), Predicates.instanceOf(IDiagramContainerEditPart.class),
+ Predicates.instanceOf(IDiagramListEditPart.class));
+ final Predicate<Object> isProperChild = Predicates.and(validChildKind, Predicates.not(invalidChildKind));
+ final Collection<IGraphicalEditPart> result = Lists.newArrayList(Iterables.filter(rawChildren, isProperChild));
+ // Containers have an intermediate level of children edit parts. We
+ // ignore these "wrapper" parts, but must look inside for proper
+ // children of the container.
+ for (IGraphicalEditPart part : Iterables.filter(rawChildren, Predicates.not(isProperChild))) {
+ if (part instanceof DNodeContainerViewNodeContainerCompartmentEditPart || part instanceof DNodeContainerViewNodeContainerCompartment2EditPart) {
+ result.addAll(getChildrenOfInterest(part));
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Create the command that changes the bounds of the specified edit part.
+ *
+ * @param editPart
+ * the specified edit part
+ *
+ * @param newPosition
+ * the new position of the figure.
+ * @return the command that changes the bounds of the specified edit part.
+ */
+ protected Command createChangeBoundsCommand(final IGraphicalEditPart editPart, final Point newPosition) {
+ Command result = null;
+ final Object existingRequest = this.findRequest(editPart, org.eclipse.gef.RequestConstants.REQ_MOVE);
+ ChangeBoundsRequest request = null;
+ double scale = 1.0;
+ if (editPart.getRoot() instanceof DiagramRootEditPart) {
+ final ZoomManager zoomManager = ((DiagramRootEditPart) editPart.getRoot()).getZoomManager();
+ scale = zoomManager.getZoom();
+ }
+ if (existingRequest instanceof ChangeBoundsRequest) {
+ request = (ChangeBoundsRequest) existingRequest;
+ } else if (existingRequest == null) {
+ request = new ChangeBoundsRequest();
+ request.setEditParts(editPart);
+ result = this.buildCommandWrapper(request, editPart);
+ }
+ if (newPosition != null) {
+ final Dimension delta = newPosition.getDifference(editPart.getFigure().getBounds().getLocation());
+ delta.width *= scale;
+ delta.height *= scale;
+ if (request != null) {
+ request.setMoveDelta(new Point(delta.width, delta.height));
+ request.setLocation(newPosition);
+ request.setType(org.eclipse.gef.RequestConstants.REQ_MOVE);
+ } else {
+ // no move, return null.
+ return null;
+ }
+ }
+ return result;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/semantic/AbstractSemanticLayoutDataKey.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/semantic/AbstractSemanticLayoutDataKey.java
new file mode 100644
index 0000000000..f6afc2e260
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/semantic/AbstractSemanticLayoutDataKey.java
@@ -0,0 +1,102 @@
+/*******************************************************************************
+ * Copyright (c) 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout.semantic;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+
+import com.google.common.base.Objects;
+
+import org.eclipse.sirius.diagram.ui.tools.api.layout.LayoutDataKey;
+
+/**
+ * Common behavior for Semantic*LayoutDataKey classes.
+ *
+ * @author dlecan
+ */
+public abstract class AbstractSemanticLayoutDataKey implements LayoutDataKey, Comparable<AbstractSemanticLayoutDataKey> {
+
+ /** URI Fragment of the element's target semantic element. */
+ private final String semanticElementURIFragment;
+
+ /**
+ * Constructor.
+ *
+ * @param semanticElement
+ * The element the create the key.
+ */
+ public AbstractSemanticLayoutDataKey(final EObject semanticElement) {
+ this.semanticElementURIFragment = EcoreUtil.getURI(semanticElement).fragment();
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param uriFragment
+ * String to use to create the new key.
+ */
+ public AbstractSemanticLayoutDataKey(final String uriFragment) {
+ semanticElementURIFragment = uriFragment;
+ }
+
+ protected String getSemanticElementURIFragment() {
+ return semanticElementURIFragment;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(semanticElementURIFragment);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ boolean result = false;
+ if (this == obj) {
+ result = true;
+ } else if (obj != null && getClass().isAssignableFrom(obj.getClass()) && getSemanticElementURIFragment() != null) {
+ result = getId().equals(((LayoutDataKey) obj).getId());
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return "Key ID: " + getId();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getId() {
+ return getSemanticElementURIFragment();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int compareTo(final AbstractSemanticLayoutDataKey o) {
+ return getId().compareTo(o.getId());
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/semantic/SemanticEdgeLayoutDataKey.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/semantic/SemanticEdgeLayoutDataKey.java
new file mode 100644
index 0000000000..1e0a7f6cc1
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/semantic/SemanticEdgeLayoutDataKey.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout.semantic;
+
+import org.eclipse.emf.ecore.EObject;
+
+import org.eclipse.sirius.diagram.ui.tools.internal.layout.EdgeLayoutDataKey;
+
+/**
+ * Kind of key use to store the layout data corresponding to a semantic element
+ * represented by a {@link org.eclipse.sirius.DEdge}. The key is the URI of
+ * the semantic element.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ */
+public class SemanticEdgeLayoutDataKey extends AbstractSemanticLayoutDataKey implements EdgeLayoutDataKey {
+
+ /**
+ * Constructor.
+ *
+ * @param uriFragment
+ * String to use.
+ */
+ public SemanticEdgeLayoutDataKey(final String uriFragment) {
+ super(uriFragment);
+ }
+
+ /**
+ * Default constructor.
+ *
+ * @param semanticElement
+ * The element to build the key
+ */
+ public SemanticEdgeLayoutDataKey(final EObject semanticElement) {
+ super(semanticElement);
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/semantic/SemanticNodeLayoutDataKey.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/semantic/SemanticNodeLayoutDataKey.java
new file mode 100644
index 0000000000..59ff42b786
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/semantic/SemanticNodeLayoutDataKey.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout.semantic;
+
+import org.eclipse.emf.ecore.EObject;
+
+import org.eclipse.sirius.diagram.ui.tools.internal.layout.NodeLayoutDataKey;
+
+/**
+ * Kind of key use to store the layout data corresponding to a semantic element
+ * represented by a {@link org.eclipse.sirius.AbstractDNode} or a
+ * {@link org.eclipse.sirius.DDiagram}.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ *
+ */
+public class SemanticNodeLayoutDataKey extends AbstractSemanticLayoutDataKey implements NodeLayoutDataKey {
+
+ /**
+ * Constructor.
+ *
+ * @param uriFragment
+ * String to use.
+ */
+ public SemanticNodeLayoutDataKey(final String uriFragment) {
+ super(uriFragment);
+ }
+
+ /**
+ * Default constructor.
+ *
+ * @param semanticElement
+ * The element to build the key
+ */
+ public SemanticNodeLayoutDataKey(final EObject semanticElement) {
+ super(semanticElement);
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/semantic/SiriusLayoutDataManagerForSemanticElements.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/semantic/SiriusLayoutDataManagerForSemanticElements.java
new file mode 100644
index 0000000000..185c8fc6a9
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/layout/semantic/SiriusLayoutDataManagerForSemanticElements.java
@@ -0,0 +1,173 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.layout.semantic;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.emf.ecore.EObject;
+
+import org.eclipse.sirius.AbstractDNode;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DEdge;
+import org.eclipse.sirius.DSemanticDecorator;
+import org.eclipse.sirius.diagram.layoutdata.AbstractLayoutData;
+import org.eclipse.sirius.diagram.layoutdata.EdgeLayoutData;
+import org.eclipse.sirius.diagram.layoutdata.NodeLayoutData;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.AbstractSiriusLayoutDataManager;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.LayoutDataHelper;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.LayoutDataKey;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.SiriusLayoutDataManager;
+import org.eclipse.sirius.diagram.ui.tools.internal.layout.AdvancedSiriusLayoutDataManager;
+
+/**
+ * SiriusLayoutDataManager drives by the semantic elements (EObject). Use for
+ * layout duplication.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ *
+ */
+public class SiriusLayoutDataManagerForSemanticElements extends AbstractSiriusLayoutDataManager implements AdvancedSiriusLayoutDataManager {
+
+ private static final SiriusLayoutDataManagerForSemanticElements INSTANCE = new SiriusLayoutDataManagerForSemanticElements();
+
+ private final Map<SemanticNodeLayoutDataKey, NodeLayoutData> nodeLayoutDataMap = new HashMap<SemanticNodeLayoutDataKey, NodeLayoutData>();
+
+ private final Map<SemanticEdgeLayoutDataKey, EdgeLayoutData> edgeLayoutDataMap = new HashMap<SemanticEdgeLayoutDataKey, EdgeLayoutData>();
+
+ /**
+ * Default constructor.
+ */
+ public SiriusLayoutDataManagerForSemanticElements() {
+ // Nothing.
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.layout.SiriusLayoutDataManager#addLayoutData(org.eclipse.sirius.diagram.ui.tools.api.layout.LayoutDataKey,
+ * org.eclipse.sirius.diagram.layoutdata.AbstractLayoutData)
+ */
+ public void addLayoutData(final LayoutDataKey key, final AbstractLayoutData layoutData) {
+ if (!checkKeyType(key)) {
+ // Kind of key not manage
+ layoutData.setId(null);
+ return;
+ }
+
+ if (key instanceof SemanticNodeLayoutDataKey) {
+ if (layoutData instanceof NodeLayoutData) {
+ nodeLayoutDataMap.put((SemanticNodeLayoutDataKey) key, (NodeLayoutData) layoutData);
+ } else {
+ // Bad type of layoutData for this key
+ }
+ } else if (key instanceof SemanticEdgeLayoutDataKey) {
+ if (layoutData instanceof EdgeLayoutData) {
+ edgeLayoutDataMap.put((SemanticEdgeLayoutDataKey) key, (EdgeLayoutData) layoutData);
+ } else {
+ // Bad type of layoutData for this key
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.layout.SiriusLayoutDataManager#getLayoutData(org.eclipse.sirius.diagram.ui.tools.api.layout.LayoutDataKey)
+ */
+ public AbstractLayoutData getLayoutData(final LayoutDataKey key) {
+ AbstractLayoutData result = null;
+ if (checkKeyType(key)) {
+ if (key instanceof SemanticNodeLayoutDataKey) {
+ result = nodeLayoutDataMap.get(key);
+ } else if (key instanceof SemanticEdgeLayoutDataKey) {
+ result = edgeLayoutDataMap.get(key);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Check if the key is manage by this manager.
+ *
+ * @param key
+ * the key to check
+ * @return
+ */
+ private boolean checkKeyType(final LayoutDataKey key) {
+ return key instanceof SemanticNodeLayoutDataKey || key instanceof SemanticEdgeLayoutDataKey;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.layout.SiriusLayoutDataManager#getInstance()
+ */
+ public SiriusLayoutDataManager getInstance() {
+ return INSTANCE;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.layout.SiriusLayoutDataManager#createKey(org.eclipse.sirius.DSemanticDecorator)
+ */
+ public LayoutDataKey createKey(final DSemanticDecorator semanticDecorator) {
+ LayoutDataKey result = null;
+ final EObject realSemanticElement = semanticDecorator.getTarget();
+ if (semanticDecorator instanceof DEdge) {
+ result = new SemanticEdgeLayoutDataKey(realSemanticElement);
+ } else if (semanticDecorator instanceof AbstractDNode || semanticDecorator instanceof DDiagram) {
+ result = new SemanticNodeLayoutDataKey(realSemanticElement);
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.layout.SiriusLayoutDataManager#containsData()
+ */
+ public boolean containsData() {
+ return !nodeLayoutDataMap.isEmpty() || !edgeLayoutDataMap.isEmpty();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.layout.SiriusLayoutDataManager#clearLayoutData()
+ */
+ public void clearLayoutData() {
+ nodeLayoutDataMap.clear();
+ edgeLayoutDataMap.clear();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<SemanticEdgeLayoutDataKey, EdgeLayoutData> getEdgeLayoutData() {
+ return edgeLayoutDataMap;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<? extends LayoutDataKey, ? extends NodeLayoutData> getRootNodeLayoutData() {
+ return (Map<? extends LayoutDataKey, ? extends NodeLayoutData>) LayoutDataHelper.INSTANCE.getRootLayoutData(nodeLayoutDataMap);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map<SemanticNodeLayoutDataKey, NodeLayoutData> getNodeLayoutData() {
+ return nodeLayoutDataMap;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/BehaviorsPropertySection.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/BehaviorsPropertySection.java
new file mode 100644
index 0000000000..eb77d9d3b8
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/BehaviorsPropertySection.java
@@ -0,0 +1,133 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.properties;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DSemanticDiagram;
+import org.eclipse.sirius.business.api.componentization.DiagramComponentizationManager;
+import org.eclipse.sirius.business.api.session.Session;
+import org.eclipse.sirius.business.api.session.SessionManager;
+import org.eclipse.sirius.description.tool.BehaviorTool;
+import org.eclipse.sirius.diagram.ui.tools.internal.commands.ActivateBehaviorToolsCommand;
+import org.eclipse.sirius.diagram.ui.tools.internal.commands.DeactivateBehaviorToolsCommand;
+
+/**
+ * Sections that allows the user to choose activated filters.
+ *
+ * @author ymortier
+ */
+public class BehaviorsPropertySection extends FiltersPropertySection {
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.internal.properties.FiltersPropertySection#getAppliedElements()
+ */
+ @Override
+ protected Collection<?> getAppliedElements() {
+ final Collection<BehaviorTool> result = new HashSet<BehaviorTool>();
+ if (getDiagram() != null) {
+ result.addAll(getDiagram().getActivateBehaviors());
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.internal.properties.FiltersPropertySection#getAvailableElements()
+ */
+ @Override
+ protected Collection<?> getAvailableElements() {
+ final Collection<BehaviorTool> result = new HashSet<BehaviorTool>();
+ final DDiagram diagram = getDiagram();
+ if (diagram != null && diagram.getDescription() != null) {
+ Session session = null;
+ if (diagram instanceof DSemanticDiagram) {
+ session = SessionManager.INSTANCE.getSession(((DSemanticDiagram) diagram).getTarget());
+ }
+ final Iterator<?> iterTools = new DiagramComponentizationManager().getAllTools(session.getSelectedSiriuss(false), diagram.getDescription()).iterator();
+ while (iterTools.hasNext()) {
+ final Object currentTool = iterTools.next();
+ if (currentTool instanceof BehaviorTool) {
+ result.add((BehaviorTool) currentTool);
+ }
+ }
+ }
+ result.removeAll(getAppliedElements());
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.internal.properties.FiltersPropertySection#createFeatureComposite(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ protected Composite createFeatureComposite(final Composite composite) {
+ final Composite featureComposite = getWidgetFactory().createComposite(composite, SWT.NONE);
+ featureComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ featureComposite.setLayout(new GridLayout());
+
+ final Label featureLabel = getWidgetFactory().createLabel(featureComposite, "Activated Behaviors", SWT.NONE);
+ featureLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
+ return featureComposite;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.internal.properties.FiltersPropertySection#createChoiceComposite(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ protected Composite createChoiceComposite(final Composite composite) {
+ final Composite choiceComposite = getWidgetFactory().createComposite(composite, SWT.NONE);
+ choiceComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ choiceComposite.setLayout(new GridLayout());
+
+ final Label choiceLabel = getWidgetFactory().createLabel(choiceComposite, "Available Behaviors", SWT.NONE);
+ choiceLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ return choiceComposite;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.internal.properties.FiltersPropertySection#newElementsSelected(java.util.Collection)
+ */
+ @Override
+ protected void newElementsSelected(final Collection<?> newElements) {
+ domain.getCommandStack().execute(new ActivateBehaviorToolsCommand(domain, getDiagram(), Lists.newArrayList(Iterables.filter(newElements, BehaviorTool.class))));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.internal.properties.FiltersPropertySection#oldElementsRemoved(java.util.Collection)
+ */
+ @Override
+ protected void oldElementsRemoved(final Collection<?> oldElements) {
+ domain.getCommandStack().execute(new DeactivateBehaviorToolsCommand(domain, getDiagram(), Lists.newArrayList(Iterables.filter(oldElements, BehaviorTool.class))));
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/CompositeEObjectPropertySource.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/CompositeEObjectPropertySource.java
new file mode 100644
index 0000000000..d33657cdd0
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/CompositeEObjectPropertySource.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.properties;
+
+import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.gef.requests.GroupRequest;
+import org.eclipse.ui.IEditorPart;
+
+import org.eclipse.sirius.common.ui.tools.api.util.EclipseUIUtil;
+import org.eclipse.sirius.diagram.part.SiriusDiagramEditor;
+import org.eclipse.sirius.diagram.part.SiriusDiagramEditorPlugin;
+import org.eclipse.sirius.diagram.tools.api.editor.DDiagramEditor;
+import org.eclipse.sirius.diagram.tools.api.requests.RequestConstants;
+import org.eclipse.sirius.ui.tools.api.properties.AbstractCompositeEObjectPropertySource;
+
+/**
+ * Specialization for the manage of Diagram elements.
+ *
+ * @author ymortier
+ */
+public class CompositeEObjectPropertySource extends AbstractCompositeEObjectPropertySource {
+
+ /**
+ * Creates a new <code>CompositeEObjectPropertySource</code>.
+ */
+ public CompositeEObjectPropertySource() {
+ super();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.views.properties.IPropertySource#setPropertyValue(java.lang.Object,
+ * java.lang.Object)
+ */
+ @Override
+ public void setPropertyValue(final Object id, final Object value) {
+ super.setPropertyValue(id, value);
+ final Identifier identifier = (Identifier) id;
+ /*
+ * FIXME CBR : the following code handle the case where the reference is
+ * a "Many" one in refreshing
+ */
+ if (identifier.getId() instanceof String) {
+ if (identifier.getEObject().eClass().getEStructuralFeature(((String) identifier.getId()).toLowerCase()) != null) {
+ final EStructuralFeature feat = identifier.getEObject().eClass().getEStructuralFeature(((String) identifier.getId()).toLowerCase());
+ if (feat instanceof EReference && ((EReference) feat).isMany()) {
+ final IEditorPart part = EclipseUIUtil.getActiveEditor();
+ if (part instanceof SiriusDiagramEditor) {
+ ((SiriusDiagramEditor) part).getDiagramEditPart().performRequest(new GroupRequest(RequestConstants.REQ_REFRESH_VIEWPOINT));
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.ui.tools.api.properties.AbstractCompositeEObjectPropertySource#getItemProvidersAdapterFactory()
+ */
+ @Override
+ protected AdapterFactory getItemProvidersAdapterFactory() {
+ AdapterFactory adapterFactory = null;
+ final IEditorPart part = EclipseUIUtil.getActiveEditor();
+ if (part instanceof DDiagramEditor) {
+ adapterFactory = ((DDiagramEditor) part).getAdapterFactory();
+ } else {
+ adapterFactory = SiriusDiagramEditorPlugin.getInstance().getItemProvidersAdapterFactory();
+ }
+ return adapterFactory;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/DiagramColorAndFontPropertySection.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/DiagramColorAndFontPropertySection.java
new file mode 100644
index 0000000000..67d5183558
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/DiagramColorAndFontPropertySection.java
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * Copyright (c) 2011 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.properties;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.emf.ecore.ENamedElement;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.gmf.runtime.common.core.command.ICommand;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.internal.properties.Properties;
+import org.eclipse.gmf.runtime.diagram.ui.properties.sections.appearance.DiagramColorsAndFontsPropertySection;
+import org.eclipse.gmf.runtime.draw2d.ui.figures.FigureUtilities;
+import org.eclipse.gmf.runtime.emf.core.util.PackageUtil;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Button;
+
+import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter;
+import org.eclipse.sirius.business.api.query.EObjectQuery;
+import org.eclipse.sirius.description.DescriptionFactory;
+import org.eclipse.sirius.description.UserFixedColor;
+import org.eclipse.sirius.diagram.internal.refresh.diagram.ViewPropertiesSynchronizer;
+import org.eclipse.sirius.diagram.ui.tools.internal.dialogs.ColorPalettePopup;
+
+/**
+ * Class necessary to remove default color option.
+ *
+ * @author jdupont
+ *
+ */
+@SuppressWarnings("restriction")
+public class DiagramColorAndFontPropertySection extends DiagramColorsAndFontsPropertySection {
+
+ /**
+ * {@inheritDoc}
+ *
+ * @overides
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.properties.sections.appearance.ColorsAndFontsPropertySection#changeColor(org.eclipse.swt.events.SelectionEvent,
+ * org.eclipse.swt.widgets.Button, java.lang.String, java.lang.String,
+ * org.eclipse.jface.resource.ImageDescriptor)
+ */
+ @Override
+ protected RGB changeColor(final SelectionEvent event, final Button button, final String propertyId, final String commandName, final ImageDescriptor imageDescriptor) {
+
+ RGB colorToReturn = null;
+
+ if (!Properties.ID_FILLCOLOR.equals(propertyId) && !Properties.ID_LINECOLOR.equals(propertyId) && !Properties.ID_FONTCOLOR.equals(propertyId)) {
+ colorToReturn = super.changeColor(event, button, propertyId, commandName, imageDescriptor);
+ } else {
+ final ColorPalettePopup popup = new ColorPalettePopup(button.getParent().getShell(), IDialogConstants.BUTTON_BAR_HEIGHT);
+ final Rectangle r = button.getBounds();
+ final Point location = button.getParent().toDisplay(r.x, r.y);
+ popup.open(new Point(location.x, location.y + r.height));
+ if (popup.getSelectedColor() == null && !popup.useDefaultColor()) {
+ return null;
+ }
+ // selectedColor should be null if we are to use the default color
+ final RGB selectedColor = popup.getSelectedColor();
+
+ final EStructuralFeature feature = (EStructuralFeature) PackageUtil.getElement(propertyId);
+
+ // Update model in response to user
+
+ final List<ICommand> commands = new ArrayList<ICommand>();
+ final Iterator<?> it = getInputIterator();
+
+ colorToReturn = selectedColor;
+ RGB color = selectedColor;
+ while (it.hasNext()) {
+ final IGraphicalEditPart ep = (IGraphicalEditPart) it.next();
+ color = selectedColor;
+ if (popup.useDefaultColor()) {
+ final Object preferredValue = ep.getPreferredValue(feature);
+ if (preferredValue instanceof Integer) {
+ color = FigureUtilities.integerToRGB((Integer) preferredValue);
+ }
+ }
+
+ // If we are using default colors, we want to return the color
+ // of the first selected element to be consistent
+ if (colorToReturn == null) {
+ colorToReturn = color;
+ }
+
+ if (color != null) {
+ final RGB finalColor = color; // need a final variable
+ commands.add(createCommand(commandName, ((View) ep.getModel()).eResource(), new Runnable() {
+
+ public void run() {
+ final ENamedElement element = PackageUtil.getElement(propertyId);
+ if (element instanceof EStructuralFeature) {
+ ep.setStructuralFeatureValue(feature, FigureUtilities.RGBToInteger(finalColor));
+ }
+
+ // get the view.
+ final View view = (View) ep.getModel();
+ // change the color.
+ final UserFixedColor newColor = DescriptionFactory.eINSTANCE.createUserFixedColor();
+ newColor.setName("<anonymous>");
+ newColor.setBlue(finalColor.blue);
+ newColor.setGreen(finalColor.green);
+ newColor.setRed(finalColor.red);
+
+ IInterpreter interpreter = new EObjectQuery(view).getSession().getInterpreter();
+ new ViewPropertiesSynchronizer().synchronizeDDiagramElementStyleColorProperties(view, newColor, propertyId, interpreter);
+ }
+ }));
+ }
+ }
+ if (!commands.isEmpty()) {
+ executeAsCompositeCommand(commandName, commands);
+ final Image overlyedImage = new ColorOverlayImageDescriptor(imageDescriptor.getImageData(), color).createImage();
+ disposeImage(button.getImage());
+ button.setImage(overlyedImage);
+ }
+ }
+ return colorToReturn;
+
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/DiagramConnectionAppearancePropertySection.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/DiagramConnectionAppearancePropertySection.java
new file mode 100644
index 0000000000..f93361d58b
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/DiagramConnectionAppearancePropertySection.java
@@ -0,0 +1,316 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.properties;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.emf.ecore.ENamedElement;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gmf.runtime.common.core.command.ICommand;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.internal.properties.Properties;
+import org.eclipse.gmf.runtime.diagram.ui.properties.sections.appearance.ConnectionAppearancePropertySection;
+import org.eclipse.gmf.runtime.draw2d.ui.figures.FigureUtilities;
+import org.eclipse.gmf.runtime.emf.core.util.PackageUtil;
+import org.eclipse.gmf.runtime.notation.Routing;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IWorkbenchPart;
+
+import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter;
+import org.eclipse.sirius.BracketEdgeStyle;
+import org.eclipse.sirius.DEdge;
+import org.eclipse.sirius.DSemanticDecorator;
+import org.eclipse.sirius.EdgeStyle;
+import org.eclipse.sirius.business.api.query.EObjectQuery;
+import org.eclipse.sirius.description.DescriptionFactory;
+import org.eclipse.sirius.description.UserFixedColor;
+import org.eclipse.sirius.diagram.internal.refresh.diagram.ViewPropertiesSynchronizer;
+import org.eclipse.sirius.diagram.part.SiriusDiagramEditorPlugin;
+import org.eclipse.sirius.diagram.tools.internal.actions.style.ResetStylePropertiesToDefaultValuesAction;
+import org.eclipse.sirius.diagram.ui.tools.internal.dialogs.ColorPalettePopup;
+
+/**
+ * allow color customization of diagram edges.
+ *
+ * @author fmorel
+ *
+ */
+@SuppressWarnings("restriction")
+public class DiagramConnectionAppearancePropertySection extends ConnectionAppearancePropertySection {
+
+ /** button to set back the view to default color. */
+ protected Button resetStylePropertiesToDefaultValuesButton;
+
+ private Composite routingGroups;
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.properties.sections.appearance.ColorsAndFontsPropertySection#changeColor(org.eclipse.swt.events.SelectionEvent,
+ * org.eclipse.swt.widgets.Button, java.lang.String, java.lang.String,
+ * org.eclipse.jface.resource.ImageDescriptor)
+ */
+ @Override
+ protected RGB changeColor(final SelectionEvent event, final Button button, final String propertyId, final String commandName, final ImageDescriptor imageDescriptor) {
+
+ RGB colorToReturn = null;
+ if (!Properties.ID_FILLCOLOR.equals(propertyId) && !Properties.ID_LINECOLOR.equals(propertyId) && !Properties.ID_FONTCOLOR.equals(propertyId)) {
+ colorToReturn = super.changeColor(event, button, propertyId, commandName, imageDescriptor);
+ } else {
+ final ColorPalettePopup popup = new ColorPalettePopup(button.getParent().getShell(), IDialogConstants.BUTTON_BAR_HEIGHT);
+ // popup.setPreviousColor(previousColor);
+ final Rectangle r = button.getBounds();
+ final Point location = button.getParent().toDisplay(r.x, r.y);
+ popup.open(new Point(location.x, location.y + r.height));
+ if (popup.getSelectedColor() == null && !popup.useDefaultColor()) {
+ return null;
+ }
+ // selectedColor should be null if we are to use the default color
+ final RGB selectedColor = popup.getSelectedColor();
+
+ final EStructuralFeature feature = (EStructuralFeature) PackageUtil.getElement(propertyId);
+
+ // Update model in response to user
+
+ final List<ICommand> commands = new ArrayList<ICommand>();
+ final Iterator<?> it = getInputIterator();
+
+ colorToReturn = selectedColor;
+ RGB color = selectedColor;
+ while (it.hasNext()) {
+ final IGraphicalEditPart ep = (IGraphicalEditPart) it.next();
+
+ color = selectedColor;
+ if (popup.useDefaultColor()) {
+ final Object preferredValue = ep.getPreferredValue(feature);
+ if (preferredValue instanceof Integer) {
+ color = FigureUtilities.integerToRGB((Integer) preferredValue);
+ }
+ }
+
+ // If we are using default colors, we want to return the color
+ // of the first selected element to be consistent
+ if (colorToReturn == null) {
+ colorToReturn = color;
+ }
+
+ if (color != null) {
+ final RGB finalColor = color; // need a final variable
+ commands.add(createCommand(commandName, ((View) ep.getModel()).eResource(), new Runnable() {
+
+ public void run() {
+ final ENamedElement element = PackageUtil.getElement(propertyId);
+ if (element instanceof EStructuralFeature) {
+ ep.setStructuralFeatureValue(feature, FigureUtilities.RGBToInteger(finalColor));
+ }
+
+ // get the view.
+ final View view = (View) ep.getModel();
+
+ // change the color.
+ final UserFixedColor newColor = DescriptionFactory.eINSTANCE.createUserFixedColor();
+ newColor.setName("<anonymous>");
+ newColor.setBlue(finalColor.blue);
+ newColor.setGreen(finalColor.green);
+ newColor.setRed(finalColor.red);
+
+ IInterpreter interpreter = new EObjectQuery(view).getSession().getInterpreter();
+ new ViewPropertiesSynchronizer().synchronizeDDiagramElementStyleColorProperties(view, newColor, propertyId, interpreter);
+ }
+ }));
+ }
+ }
+ if (!commands.isEmpty()) {
+ executeAsCompositeCommand(commandName, commands);
+ final Image overlyedImage = new ColorOverlayImageDescriptor(imageDescriptor.getImageData(), color).createImage();
+ disposeImage(button.getImage());
+ button.setImage(overlyedImage);
+ }
+ }
+ return colorToReturn;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.properties.sections.appearance.ShapeColorsAndFontsPropertySection#createFontsGroup(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ protected Composite createFontsGroup(final Composite parent) {
+ final Composite toolBar = super.createFontsGroup(parent);
+
+ final String path = "icons/undo_edit.gif";
+ final Image image = SiriusDiagramEditorPlugin.getInstance().getBundledImage(path);
+
+ resetStylePropertiesToDefaultValuesButton = new Button(toolBar, SWT.PUSH);
+ resetStylePropertiesToDefaultValuesButton.setToolTipText(ResetStylePropertiesToDefaultValuesAction.ACTION_NAME);
+ resetStylePropertiesToDefaultValuesButton.setImage(image);
+ resetStylePropertiesToDefaultValuesButton.addSelectionListener(new ResetStylePropertiesToDefaultValuesSelectionAdapter(this));
+ resetStylePropertiesToDefaultValuesButton.setEnabled(!isReadOnly());
+
+ return toolBar;
+ }
+
+ /**
+ * Overridden to access to the routing group.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ protected void createRouterOptionsGroup(Composite groups) {
+ super.createRouterOptionsGroup(groups);
+ routingGroups = groups;
+ }
+
+ /**
+ * Overridden to display property of selection only if semantic element of
+ * selection exists.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public void setInput(IWorkbenchPart workbenchPart, ISelection selection) {
+ if (selection.isEmpty() || !(selection instanceof StructuredSelection)) {
+ super.setInput(workbenchPart, selection);
+ return;
+ }
+ StructuredSelection structuredSelection = (StructuredSelection) selection;
+ List<Object> newSelection = new ArrayList<Object>();
+ Iterator<?> it = structuredSelection.iterator();
+ while (it.hasNext()) {
+ Object selectionItem = it.next();
+ if (transformSelection(selectionItem) != null) {
+ newSelection.add(selectionItem);
+ }
+ }
+ composite.setVisible(!newSelection.isEmpty());
+ super.setInput(workbenchPart, new StructuredSelection(newSelection));
+ }
+
+ /**
+ * Transform selection to have {@link DSemanticDecorator} instead of
+ * {@link EditPart} or null if the semantic element (target) not exists.
+ *
+ * @param selection
+ * the currently selected object
+ * @return the unwrapped object
+ */
+ protected Object transformSelection(final Object selection) {
+
+ Object object = selection;
+
+ if (object instanceof EditPart) {
+ object = ((EditPart) object).getModel();
+ } else if (object instanceof IAdaptable) {
+ object = ((IAdaptable) object).getAdapter(View.class);
+ }
+
+ if (object instanceof View) {
+ object = ((View) object).getElement();
+ }
+
+ if (object instanceof DSemanticDecorator) {
+ EObject target = ((DSemanticDecorator) object).getTarget();
+ if (target == null || target.eResource() == null) {
+ object = null;
+ }
+ }
+ return object;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.properties.sections.appearance.ColorsAndFontsPropertySection#dispose()
+ */
+ @Override
+ public void dispose() {
+ resetStylePropertiesToDefaultValuesButton = null;
+ routingGroups = null;
+ super.dispose();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.properties.sections.appearance.ShapeColorsAndFontsPropertySection#refresh()
+ */
+ @Override
+ public void refresh() {
+ if (!isDisposed() && getSingleInput() != null) {
+ super.refresh();
+ executeAsReadAction(new Runnable() {
+
+ public void run() {
+ boolean hasBracketStyle = false;
+ final IGraphicalEditPart ep = getSingleInput();
+ if (ep != null) {
+ final View view = (View) ep.getModel();
+ final EObject dDiagElement = view.getElement();
+ if (dDiagElement instanceof DEdge) {
+ DEdge dEdge = (DEdge) dDiagElement;
+ EdgeStyle edgeStyle = dEdge.getOwnedStyle();
+ hasBracketStyle = edgeStyle instanceof BracketEdgeStyle;
+ }
+ boolean isReadOnly = isReadOnly();
+ boolean isCustomizedView = ResetStylePropertiesToDefaultValuesSelectionAdapter.isCustomizedView(view);
+ resetStylePropertiesToDefaultValuesButton.setEnabled(!isReadOnly && isCustomizedView);
+ enableRoutingGroup(hasBracketStyle);
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * Disable the routing group and all its children for Bracket edge.
+ *
+ * @param hasBracketStyle
+ * true if we must disable, false otherwise
+ */
+ private void enableRoutingGroup(boolean hasBracketStyle) {
+ routingGroups.setEnabled(!hasBracketStyle);
+ for (Control childControl : routingGroups.getChildren()) {
+ childControl.setEnabled(!hasBracketStyle);
+ if (childControl instanceof Composite) {
+ Composite childComposite = (Composite) childControl;
+ for (Control childOfChildControl : childComposite.getChildren()) {
+ childOfChildControl.setEnabled(!hasBracketStyle);
+ }
+ }
+ }
+ for (Object object : Routing.VALUES) {
+ Object buttonObj = buttons.get(object);
+ if (buttonObj instanceof Button) {
+ Button button = (Button) buttonObj;
+ button.setEnabled(!hasBracketStyle);
+ }
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/DiagramShapeColorAndFontPropertySection.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/DiagramShapeColorAndFontPropertySection.java
new file mode 100644
index 0000000000..17be9d354e
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/DiagramShapeColorAndFontPropertySection.java
@@ -0,0 +1,445 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.properties;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.emf.ecore.ENamedElement;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gmf.runtime.common.core.command.ICommand;
+import org.eclipse.gmf.runtime.diagram.core.util.ViewType;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.internal.properties.Properties;
+import org.eclipse.gmf.runtime.diagram.ui.properties.sections.appearance.ShapeColorsAndFontsPropertySection;
+import org.eclipse.gmf.runtime.draw2d.ui.figures.FigureUtilities;
+import org.eclipse.gmf.runtime.emf.core.util.PackageUtil;
+import org.eclipse.gmf.runtime.notation.NotationPackage;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.accessibility.AccessibleAdapter;
+import org.eclipse.swt.accessibility.AccessibleEvent;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.ui.IWorkbenchPart;
+
+import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter;
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.BasicLabelStyle;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DSemanticDecorator;
+import org.eclipse.sirius.business.api.query.DDiagramElementQuery;
+import org.eclipse.sirius.business.api.query.EObjectQuery;
+import org.eclipse.sirius.description.DescriptionFactory;
+import org.eclipse.sirius.description.UserFixedColor;
+import org.eclipse.sirius.diagram.ImagesPath;
+import org.eclipse.sirius.diagram.business.api.image.ImageSelector;
+import org.eclipse.sirius.diagram.business.api.image.ImageSelectorService;
+import org.eclipse.sirius.diagram.edit.api.part.IDiagramElementEditPart;
+import org.eclipse.sirius.diagram.internal.refresh.diagram.ViewPropertiesSynchronizer;
+import org.eclipse.sirius.diagram.part.SiriusDiagramEditorPlugin;
+import org.eclipse.sirius.diagram.tools.internal.actions.style.ResetStylePropertiesToDefaultValuesAction;
+import org.eclipse.sirius.diagram.tools.internal.actions.style.SetStyleToWorkspaceImageAction;
+import org.eclipse.sirius.diagram.ui.tools.internal.dialogs.ColorPalettePopup;
+
+/**
+ * allow color customization of diagram nodes.
+ *
+ * @author fmorel
+ */
+@SuppressWarnings("restriction")
+public class DiagramShapeColorAndFontPropertySection extends ShapeColorsAndFontsPropertySection {
+
+ /**
+ * button to set back the view to default color.
+ */
+ protected Button resetStylePropertiesToDefaultValuesButton;
+
+ /**
+ * button to allow user to select an image in the workspace and set the
+ * selected image as view backgroud image.
+ */
+ protected Button setStyleToWorkspaceImageButton;
+
+ /**
+ * button to set back the view to default color.
+ */
+ private Button fontUnderlineButton;
+
+ /**
+ * button to set back the view to default color.
+ */
+ private Button fontStrikeThroughButton;
+
+ /**
+ * {@inheritDoc}
+ *
+ * @overrides
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.properties.sections.appearance.ColorsAndFontsPropertySection#changeColor(org.eclipse.swt.events.SelectionEvent,
+ * org.eclipse.swt.widgets.Button, java.lang.String, java.lang.String,
+ * org.eclipse.jface.resource.ImageDescriptor)
+ */
+ @Override
+ protected RGB changeColor(final SelectionEvent event, final Button button, final String propertyId, final String commandName, final ImageDescriptor imageDescriptor) {
+
+ RGB colorToReturn = null;
+
+ if (!Properties.ID_FILLCOLOR.equals(propertyId) && !Properties.ID_LINECOLOR.equals(propertyId) && !Properties.ID_FONTCOLOR.equals(propertyId)) {
+ colorToReturn = super.changeColor(event, button, propertyId, commandName, imageDescriptor);
+ } else {
+ final ColorPalettePopup popup = new ColorPalettePopup(button.getParent().getShell(), IDialogConstants.BUTTON_BAR_HEIGHT);
+ final Rectangle r = button.getBounds();
+ final Point location = button.getParent().toDisplay(r.x, r.y);
+ popup.open(new Point(location.x, location.y + r.height));
+ if (popup.getSelectedColor() == null && !popup.useDefaultColor()) {
+ return null;
+ }
+ // selectedColor should be null if we are to use the default color
+ final RGB selectedColor = popup.getSelectedColor();
+
+ final EStructuralFeature feature = (EStructuralFeature) PackageUtil.getElement(propertyId);
+
+ // Update model in response to user
+
+ final List<ICommand> commands = new ArrayList<ICommand>();
+ final Iterator<?> it = getInputIterator();
+
+ colorToReturn = selectedColor;
+ RGB color = selectedColor;
+ while (it.hasNext()) {
+ final IGraphicalEditPart ep = (IGraphicalEditPart) it.next();
+ color = selectedColor;
+ if (popup.useDefaultColor()) {
+ final Object preferredValue = ep.getPreferredValue(feature);
+ if (preferredValue instanceof Integer) {
+ color = FigureUtilities.integerToRGB((Integer) preferredValue);
+ }
+ }
+
+ // If we are using default colors, we want to return the color
+ // of the first selected element to be consistent
+ if (colorToReturn == null) {
+ colorToReturn = color;
+ }
+
+ if (color != null) {
+ final RGB finalColor = color; // need a final variable
+ commands.add(createCommand(commandName, ((View) ep.getModel()).eResource(), new Runnable() {
+
+ public void run() {
+ final ENamedElement element = PackageUtil.getElement(propertyId);
+ if (element instanceof EStructuralFeature) {
+ ep.setStructuralFeatureValue(feature, FigureUtilities.RGBToInteger(finalColor));
+ }
+
+ // get the view.
+ final View view = (View) ep.getModel();
+ // change the color.
+ final UserFixedColor newColor = DescriptionFactory.eINSTANCE.createUserFixedColor();
+ newColor.setName("<anonymous>");
+ newColor.setBlue(finalColor.blue);
+ newColor.setGreen(finalColor.green);
+ newColor.setRed(finalColor.red);
+
+ IInterpreter interpreter = new EObjectQuery(view).getSession().getInterpreter();
+ // new
+ // ViewPropertiesSynchronizer().synchronizeDDiagramElementStyleProperties(view);
+ new ViewPropertiesSynchronizer().synchronizeDDiagramElementStyleColorProperties(view, newColor, propertyId, interpreter);
+ }
+
+ }));
+ }
+ }
+ if (!commands.isEmpty()) {
+ executeAsCompositeCommand(commandName, commands);
+ final Image overlyedImage = new ColorOverlayImageDescriptor(imageDescriptor.getImageData(), color).createImage();
+ disposeImage(button.getImage());
+ button.setImage(overlyedImage);
+ }
+ }
+ return colorToReturn;
+
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.properties.sections.appearance.ColorsAndFontsPropertySection#createFontsAndColorsGroups(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ protected Group createFontsAndColorsGroups(final Composite parent) {
+ return super.createFontsAndColorsGroups(parent);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.properties.sections.appearance.ShapeColorsAndFontsPropertySection#createFontsGroup(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ protected Composite createFontsGroup(final Composite parent) {
+ final Composite toolBar = super.createFontsGroup(parent);
+
+ final Image imageUndo = SiriusDiagramEditorPlugin.getInstance().getBundledImage(ImagesPath.UNDO_ICON);
+ final Image imageImage = SiriusDiagramEditorPlugin.getInstance().getBundledImage(ImagesPath.IMAGE_ICON);
+ final Image imageUnderline = SiriusDiagramEditorPlugin.getInstance().getBundledImage(ImagesPath.UNDERLINE_ICON);
+ final Image imageStrikeThrough = SiriusDiagramEditorPlugin.getInstance().getBundledImage(ImagesPath.STRIKE_THROUGH_ICON);
+
+ fontUnderlineButton = new Button(toolBar, SWT.TOGGLE);
+ fontUnderlineButton.setImage(imageUnderline);
+ fontUnderlineButton.getAccessible().addAccessibleListener(new AccessibleAdapter() {
+ @Override
+ public void getName(final AccessibleEvent e) {
+ e.result = "Underline";
+ }
+ });
+
+ fontStrikeThroughButton = new Button(toolBar, SWT.TOGGLE);
+ fontStrikeThroughButton.setImage(imageStrikeThrough);
+ fontStrikeThroughButton.getAccessible().addAccessibleListener(new AccessibleAdapter() {
+ @Override
+ public void getName(final AccessibleEvent e) {
+ e.result = "StrikeThrough";
+ }
+ });
+
+ new Label(toolBar, SWT.LEFT);
+ new Label(toolBar, SWT.LEFT);
+ new Label(toolBar, SWT.LEFT);
+
+ setStyleToWorkspaceImageButton = new Button(toolBar, SWT.PUSH);
+ setStyleToWorkspaceImageButton.setToolTipText(SetStyleToWorkspaceImageAction.SET_STYLE_TO_WORKSPACE_IMAGE_ACTION_NAME);
+ setStyleToWorkspaceImageButton.setImage(imageImage);
+ setStyleToWorkspaceImageButton.addSelectionListener(new SelectionAdapter() {
+
+ @Override
+ public void widgetSelected(final SelectionEvent event) {
+ setBackgroundImage(event);
+ }
+ });
+ setStyleToWorkspaceImageButton.setEnabled(!isReadOnly());
+
+ resetStylePropertiesToDefaultValuesButton = new Button(toolBar, SWT.PUSH);
+ resetStylePropertiesToDefaultValuesButton.setToolTipText(ResetStylePropertiesToDefaultValuesAction.ACTION_NAME);
+ resetStylePropertiesToDefaultValuesButton.setImage(imageUndo);
+ resetStylePropertiesToDefaultValuesButton.addSelectionListener(new ResetStylePropertiesToDefaultValuesSelectionAdapter(this));
+ resetStylePropertiesToDefaultValuesButton.setEnabled(!isReadOnly());
+
+ fontUnderlineButton.addSelectionListener(new SelectionAdapter() {
+
+ @Override
+ public void widgetSelected(final SelectionEvent event) {
+ updateFontUnderline();
+ }
+ });
+
+ fontStrikeThroughButton.addSelectionListener(new SelectionAdapter() {
+
+ @Override
+ public void widgetSelected(final SelectionEvent event) {
+ updateFontStrikeThrough();
+ }
+ });
+
+ return toolBar;
+ }
+
+ /**
+ * Overridden to display property of selection only if semantic element of
+ * selection exists.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public void setInput(IWorkbenchPart workbenchPart, ISelection selection) {
+ if (selection.isEmpty() || !(selection instanceof StructuredSelection)) {
+ super.setInput(workbenchPart, selection);
+ return;
+ }
+ StructuredSelection structuredSelection = (StructuredSelection) selection;
+ List<Object> newSelection = new ArrayList<Object>();
+ Iterator<?> it = structuredSelection.iterator();
+ while (it.hasNext()) {
+ Object selectionItem = it.next();
+ if (transformSelection(selectionItem) != null) {
+ newSelection.add(selectionItem);
+ }
+ }
+ composite.setVisible(!newSelection.isEmpty());
+ super.setInput(workbenchPart, new StructuredSelection(newSelection));
+ }
+
+ /**
+ * Transform selection to have {@link DSemanticDecorator} instead of
+ * {@link EditPart} or null if the semantic element (target) not exists.
+ *
+ * @param selection
+ * the currently selected object
+ * @return the unwrapped object
+ */
+ protected Object transformSelection(final Object selection) {
+
+ Object object = selection;
+
+ if (object instanceof EditPart) {
+ object = ((EditPart) object).getModel();
+ } else if (object instanceof IAdaptable) {
+ object = ((IAdaptable) object).getAdapter(View.class);
+ }
+
+ if (object instanceof View) {
+ object = ((View) object).getElement();
+ }
+
+ if (object instanceof DSemanticDecorator) {
+ EObject target = ((DSemanticDecorator) object).getTarget();
+ if (target == null || target.eResource() == null) {
+ object = null;
+ }
+ }
+ return object;
+ }
+
+ /**
+ * Change fill color to default color.
+ *
+ * @param event
+ * event from the button push.
+ */
+ protected void setBackgroundImage(final SelectionEvent event) {
+ ImageSelector imageSelector = ImageSelectorService.INSTANCE.getImageSelector();
+ List<BasicLabelStyle> styles = getStyles();
+ for (BasicLabelStyle basicLabelStyle : styles) {
+ String imagePath = imageSelector.selectImage(basicLabelStyle);
+ if (imagePath != null) {
+ ImageSelectorService.INSTANCE.updateStyle(basicLabelStyle, imagePath);
+ }
+ }
+ }
+
+ private List<BasicLabelStyle> getStyles() {
+ List<BasicLabelStyle> styles = new ArrayList<BasicLabelStyle>();
+ for (Object selectedEditPart : input) {
+ if (selectedEditPart instanceof IDiagramElementEditPart) {
+ IDiagramElementEditPart diagramElementEditPart = (IDiagramElementEditPart) selectedEditPart;
+ DDiagramElement dde = diagramElementEditPart.resolveDiagramElement();
+ DDiagramElementQuery ddeQuery = new DDiagramElementQuery(dde);
+ Option<BasicLabelStyle> oldStyle = ddeQuery.getLabelStyle();
+ if (oldStyle.some()) {
+ BasicLabelStyle basicLabelStyle = oldStyle.get();
+ styles.add(basicLabelStyle);
+ }
+ }
+ }
+ return styles;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.properties.sections.appearance.ColorsAndFontsPropertySection#dispose()
+ */
+ @Override
+ public void dispose() {
+ super.dispose();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.properties.sections.appearance.ShapeColorsAndFontsPropertySection#refresh()
+ */
+ @Override
+ public void refresh() {
+ if (!isDisposed()) {
+ super.refresh();
+ executeAsReadAction(new Runnable() {
+
+ public void run() {
+ final IGraphicalEditPart ep = getSingleInput();
+ if (ep != null) {
+ final View view = (View) ep.getModel();
+ boolean isCustomizedView = ResetStylePropertiesToDefaultValuesSelectionAdapter.isCustomizedView(view);
+ boolean enableWorkspaceImageButton = true;
+ if (ViewType.NOTE.equals(view.getType()) || ViewType.TEXT.equals(view.getType())) {
+ enableWorkspaceImageButton = false;
+ }
+ final boolean isReadOnly = isReadOnly();
+ if (resetStylePropertiesToDefaultValuesButton != null) {
+ resetStylePropertiesToDefaultValuesButton.setEnabled(!isReadOnly && isCustomizedView);
+ }
+ if (setStyleToWorkspaceImageButton != null) {
+ setStyleToWorkspaceImageButton.setEnabled(!isReadOnly && enableWorkspaceImageButton);
+ }
+ boolean underlined = (Boolean) ep.getStructuralFeatureValue(NotationPackage.eINSTANCE.getFontStyle_Underline());
+ boolean striked = (Boolean) ep.getStructuralFeatureValue(NotationPackage.eINSTANCE.getFontStyle_StrikeThrough());
+ fontUnderlineButton.setSelection(underlined);
+ fontStrikeThroughButton.setSelection(striked);
+ }
+ }
+ });
+ }
+ }
+
+ private void updateFontUnderline() {
+ // Update model in response to user
+ final List<ICommand> commands = new ArrayList<ICommand>();
+ final Iterator<?> it = getInputIterator();
+
+ while (it.hasNext()) {
+ final IGraphicalEditPart ep = (IGraphicalEditPart) it.next();
+ commands.add(createCommand(FONT_COMMAND_NAME, ((View) ep.getModel()).eResource(), new Runnable() {
+
+ public void run() {
+ ep.setStructuralFeatureValue(NotationPackage.eINSTANCE.getFontStyle_Underline(), Boolean.valueOf(fontUnderlineButton.getSelection()));
+ }
+ }));
+ }
+
+ executeAsCompositeCommand(FONT_COMMAND_NAME, commands);
+
+ }
+
+ private void updateFontStrikeThrough() {
+ // Update model in response to user
+ final List<ICommand> commands = new ArrayList<ICommand>();
+ final Iterator<?> it = getInputIterator();
+
+ while (it.hasNext()) {
+ final IGraphicalEditPart ep = (IGraphicalEditPart) it.next();
+ commands.add(createCommand(FONT_COMMAND_NAME, ((View) ep.getModel()).eResource(), new Runnable() {
+
+ public void run() {
+ ep.setStructuralFeatureValue(NotationPackage.eINSTANCE.getFontStyle_StrikeThrough(), Boolean.valueOf(fontStrikeThroughButton.getSelection()));
+ }
+ }));
+ }
+
+ executeAsCompositeCommand(FONT_COMMAND_NAME, commands);
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/DocumentationPropertySection.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/DocumentationPropertySection.java
new file mode 100644
index 0000000000..47eda9942a
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/DocumentationPropertySection.java
@@ -0,0 +1,297 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2011 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.properties;
+
+import java.util.List;
+
+import org.eclipse.emf.common.command.CompoundCommand;
+import org.eclipse.emf.ecore.EAttribute;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.edit.command.SetCommand;
+import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.gmf.runtime.notation.Diagram;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.text.Document;
+import org.eclipse.jface.text.ITextListener;
+import org.eclipse.jface.text.TextEvent;
+import org.eclipse.jface.text.source.SourceViewer;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CLabel;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.views.properties.tabbed.AbstractPropertySection;
+import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;
+
+import org.eclipse.sirius.description.DescriptionPackage;
+import org.eclipse.sirius.diagram.internal.edit.parts.DDiagramEditPart;
+import org.eclipse.sirius.diagram.part.SiriusDiagramEditor;
+import org.eclipse.sirius.diagram.part.SiriusDiagramEditorPlugin;
+
+/**
+ * Section that allows to set a documentation about a diagram.
+ *
+ * @author smonnier
+ *
+ */
+public class DocumentationPropertySection extends AbstractPropertySection {
+
+ /** The label width that will be used for section names. */
+ public static final int LABEL_WIDTH = 292;
+
+ /** Full path of the help icon. */
+ public static final String ICONS_PREFERENCES_HELP = "icons/help.gif"; //$NON-NLS-1$
+
+ /** The default size of the SourceViewer. */
+ protected static final int SOURCE_VIEWER_DEFAULT_SIZE = 150;
+
+ /** SourceViewer control of the section. */
+ protected SourceViewer sourceViewer;
+
+ /** Label control of the section. */
+ protected CLabel nameLabel;
+
+ /** Main composite. **/
+ protected Composite composite;
+
+ /**
+ * Current selected object or first object in the selection when multiple
+ * objects are selected.
+ */
+ protected EObject eObject;
+
+ /** The list of currently selected objects. */
+ protected List<EObject> eObjectList;
+
+ /**
+ * Internal text listener for updating all content dependent actions. The
+ * updating is done asynchronously.
+ */
+ class TextListener implements ITextListener {
+
+ public void textChanged(TextEvent event) {
+ handleTextModified();
+ }
+
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.views.properties.tabbed.ITabbedPropertySection#createControls(org.eclipse.swt.widgets.Composite,
+ * org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage)
+ */
+ @Override
+ public void createControls(Composite parent, TabbedPropertySheetPage tabbedPropertySheetPage) {
+ super.createControls(parent, tabbedPropertySheetPage);
+
+ composite = getWidgetFactory().createFlatFormComposite(parent);
+ composite.setLayout(new GridLayout(3, false));
+
+ nameLabel = getWidgetFactory().createCLabel(composite, getLabelText(), SWT.TOP);
+ nameLabel.setLayoutData(new GridData(SWT.NULL, SWT.TOP, false, true));
+
+ CLabel help = getWidgetFactory().createCLabel(composite, "");
+ help.setImage(getHelpIcon());
+ help.setLayoutData(new GridData(SWT.NULL, SWT.TOP, false, true));
+ help.setToolTipText(getToolTipText());
+
+ int styles = SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI | SWT.BORDER;
+ sourceViewer = new SourceViewer(composite, null, styles);
+ GridData layoutData = new GridData(GridData.FILL_BOTH);
+ layoutData.widthHint = SOURCE_VIEWER_DEFAULT_SIZE;
+ layoutData.heightHint = SOURCE_VIEWER_DEFAULT_SIZE;
+ sourceViewer.getControl().setLayoutData(layoutData);
+
+ TextListener fTextListener = new TextListener();
+ sourceViewer.addTextListener(fTextListener);
+ // sourceViewer.addTextInputListener(fTextListener);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.editor.properties.sections.common.AbstractSiriusPropertySection#setInput(org.eclipse.ui.IWorkbenchPart,
+ * org.eclipse.jface.viewers.ISelection)
+ */
+ @Override
+ public void setInput(IWorkbenchPart part, ISelection selection) {
+ super.setInput(part, selection);
+ nameLabel.setText(getLabelText());
+ if (selection instanceof StructuredSelection && ((StructuredSelection) selection).getFirstElement() instanceof DDiagramEditPart) {
+ DDiagramEditPart ddep = (DDiagramEditPart) ((StructuredSelection) selection).getFirstElement();
+ eObject = ((Diagram) ddep.getModel()).getElement();
+ eObjectList = ((IStructuredSelection) selection).toList();
+ }
+ }
+
+ /**
+ * Handle the text modified event.
+ */
+ protected void handleTextModified() {
+ String newText = sourceViewer.getDocument().get();
+ boolean equals = isEqual(newText);
+
+ if (!equals) {
+ EditingDomain editingDomain = ((SiriusDiagramEditor) getPart()).getEditingDomain();
+ Object value = getFeatureValue(newText);
+ if (eObjectList.size() == 1) {
+ // apply the property change to single selected object
+ editingDomain.getCommandStack().execute(SetCommand.create(editingDomain, eObject, getFeature(), value));
+ } else {
+ CompoundCommand compoundCommand = new CompoundCommand();
+ /* apply the property change to all selected elements */
+ for (EObject nextObject : eObjectList) {
+ compoundCommand.append(SetCommand.create(editingDomain, nextObject, getFeature(), value));
+ }
+ editingDomain.getCommandStack().execute(compoundCommand);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.views.properties.tabbed.view.ITabbedPropertySection#refresh()
+ */
+ @Override
+ public void refresh() {
+ if (getFeatureAsText() != null) {
+ sourceViewer.setDocument(new Document(getFeatureAsText()));
+ }
+ }
+
+ /**
+ * Determine if the provided string value is an equal representation of the
+ * current setting of the text property.
+ *
+ * @param newText
+ * the new string value.
+ * @return <code>True</code> if the new string value is equal to the current
+ * property setting, <code>False</code> otherwise.
+ * @see org.eclipse.sirius.editor.properties.sections.AbstractMultilinePropertySection#isEqual(String)
+ */
+ protected boolean isEqual(String newText) {
+ return getFeatureAsText().equals(newText);
+ }
+
+ /**
+ * Get the feature for the text field of this section.
+ *
+ * @return The feature for the text.
+ * @see org.eclipse.sirius.editor.properties.sections.AbstractMultilinePropertySection#getFeature()
+ */
+ public EAttribute getFeature() {
+ return DescriptionPackage.eINSTANCE.getDocumentedElement_Documentation();
+ }
+
+ /**
+ * Get the base description.
+ *
+ * @return The description for the feature.
+ * @see org.eclipse.sirius.editor.properties.sections.AbstractMultilinePropertySection#getPropertyDescription()
+ */
+ protected String getPropertyDescription() {
+ return "Use this field to save notes about this representation.";
+ }
+
+ protected String getToolTipText() {
+ return getPropertyDescription();
+ }
+
+ /**
+ * Get the value of the default feature as text for the text field of the
+ * section.
+ *
+ * @return The value of the default feature as text.
+ */
+ protected String getDefaultFeatureAsText() {
+ String value = "";
+ if (eObject != null && eObject.eGet(getFeature()) != null) {
+ value = eObject.eGet(getFeature()).toString();
+ }
+ return value;
+ }
+
+ /**
+ * Get the value of the feature as text for the text field of the section.
+ *
+ * @return The value of the feature as text.
+ */
+ protected String getFeatureAsText() {
+ // final EStructuralFeature eFeature = getFeature();
+ // final IItemPropertyDescriptor propertyDescriptor =
+ // getPropertyDescriptor(eFeature);
+ // if (propertyDescriptor != null)
+ // return
+ // propertyDescriptor.getLabelProvider(eObject).getText(eObject.eGet(eFeature));
+ return getDefaultFeatureAsText();
+ }
+
+ /**
+ * Get the new value of the feature for the text field of the section.
+ *
+ * @param newText
+ * The new value of the feature as a string.
+ * @return The new value of the feature.
+ * @see org.eclipse.sirius.editor.properties.sections.AbstractMultilinePropertySection#getFeatureValue()
+ */
+ protected Object getFeatureValue(String newText) {
+ return newText;
+ }
+
+ /**
+ * Get the default label for the text field of the section.
+ *
+ * @return The default label for the text field.
+ */
+ protected String getDefaultLabelText() {
+ return "Documentation:"; //$NON-NLS-1$
+ }
+
+ /**
+ * Get the label for the text field of the section.
+ *
+ * @return The label for the text field.
+ */
+ protected String getLabelText() {
+ return getDefaultLabelText();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void makeReadonly() {
+ sourceViewer.setEditable(false);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void makeWrittable() {
+ sourceViewer.setEditable(true);
+ }
+
+ /**
+ * Creates and return the help icon to show in our label.
+ *
+ * @return The help icon to show in our label.
+ */
+ protected Image getHelpIcon() {
+ ImageDescriptor findImageDescriptor = SiriusDiagramEditorPlugin.findImageDescriptor(ICONS_PREFERENCES_HELP);
+ return SiriusDiagramEditorPlugin.getInstance().getImage(findImageDescriptor);
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/ExtendedPropertySource.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/ExtendedPropertySource.java
new file mode 100644
index 0000000000..2cc54d7022
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/ExtendedPropertySource.java
@@ -0,0 +1,422 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.properties;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.common.ui.celleditor.ExtendedDialogCellEditor;
+import org.eclipse.emf.ecore.EEnumLiteral;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.emf.edit.provider.IItemPropertyDescriptor;
+import org.eclipse.emf.edit.provider.IItemPropertySource;
+import org.eclipse.emf.edit.ui.provider.PropertyDescriptor;
+import org.eclipse.gmf.runtime.emf.core.util.EMFCoreUtil;
+import org.eclipse.jface.viewers.BaseLabelProvider;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.TextCellEditor;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.views.properties.IPropertyDescriptor;
+import org.eclipse.ui.views.properties.IPropertySource;
+
+import org.eclipse.sirius.common.tools.api.util.StringUtil;
+import org.eclipse.sirius.DSemanticDecorator;
+import org.eclipse.sirius.SiriusPlugin;
+import org.eclipse.sirius.diagram.ui.tools.internal.dialogs.ExtendedFeatureEditorDialog;
+import org.eclipse.sirius.ecore.extender.business.api.accessor.ExtensionFeatureDescription;
+import org.eclipse.sirius.ecore.extender.business.api.accessor.ModelAccessor;
+import org.eclipse.sirius.ecore.extender.business.api.accessor.exception.FeatureNotFoundException;
+import org.eclipse.sirius.ecore.extender.business.api.permission.IPermissionAuthority;
+
+/**
+ * Property source for the extension framework.
+ *
+ * @author ymortier
+ */
+public class ExtendedPropertySource implements IPropertySource {
+
+ /** Empty String array. */
+ private static final String[] EMPTY_STRING_ARRAY = new String[0];
+
+ /** Empty properties descriptors array. */
+ private static final IPropertyDescriptor[] EMPTY = new IPropertyDescriptor[0];
+
+ /**
+ * The target.
+ */
+ private DSemanticDecorator target;
+
+ /**
+ * The adapterFactory of the caller
+ */
+ private AdapterFactory adapterFactory;
+
+ /**
+ * Create a new {@link ExtendedPropertySource} for the specified element.
+ *
+ * @param target
+ * the element.
+ * @param adapterFactory
+ * the adapterFactory of the caller
+ */
+ public ExtendedPropertySource(DSemanticDecorator target, AdapterFactory adapterFactory) {
+ this.target = target;
+ this.adapterFactory = adapterFactory;
+ }
+
+ /**
+ * Returns the model accesor.
+ *
+ * @return the model accesor.
+ */
+ protected ModelAccessor getModelAccessor() {
+ return SiriusPlugin.getDefault().getModelAccessorRegistry().getModelAccessor(target);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.views.properties.IPropertySource#getEditableValue()
+ */
+ public Object getEditableValue() {
+ return target.getTarget();
+ }
+
+ /**
+ * Returns the properties descriptors. {@inheritDoc}
+ *
+ * @see org.eclipse.ui.views.properties.IPropertySource#getPropertyDescriptors()
+ */
+ public IPropertyDescriptor[] getPropertyDescriptors() {
+ if (this.target == null || this.target.getTarget() == null || this.getModelAccessor() == null) {
+ return EMPTY;
+ }
+ final List<IPropertyDescriptor> propertyDescriptors = new ArrayList<IPropertyDescriptor>();
+ for (Object featureDescription : getModelAccessor().getAllExtensionFeatureDescriptions(this.target.getTarget())) {
+ if (featureDescription instanceof ExtensionFeatureDescription) {
+ final boolean isReferenceContainment = ((ExtensionFeatureDescription) featureDescription).isReference() && ((ExtensionFeatureDescription) featureDescription).isContainment();
+ if (!isReferenceContainment) {
+ propertyDescriptors.add(createPropertyDescriptor((ExtensionFeatureDescription) featureDescription));
+ }
+ }
+ }
+ return propertyDescriptors.toArray(new IPropertyDescriptor[propertyDescriptors.size()]);
+ }
+
+ private IPropertyDescriptor createPropertyDescriptor(final ExtensionFeatureDescription featureDescription) {
+ final IPropertyDescriptor result;
+ final IItemPropertyDescriptor emfPropertyDescriptor = featureDescription.getPropertyDescriptor(target.getTarget());
+ if (emfPropertyDescriptor == null) {
+ result = new ExtendedPropertyDescriptor(featureDescription);
+ } else {
+ //
+ // the feature description provides a property descriptor. We can
+ // use it to creates the UI.
+ result = new PropertyDescriptor(target.getTarget(), emfPropertyDescriptor);
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.views.properties.IPropertySource#getPropertyValue(java.lang.Object)
+ */
+ public Object getPropertyValue(final Object id) {
+ Object object = null;
+ if (id instanceof ExtensionFeatureDescription) {
+ try {
+ object = getModelAccessor().eGet(target.getTarget(), ExtendedPropertySource.getFeatureName((ExtensionFeatureDescription) id));
+ } catch (final FeatureNotFoundException e) {
+ // do nothing -> return null
+ }
+ } else {
+ final IItemPropertySource ips = (IItemPropertySource) adapterFactory.adapt(target.getTarget(), IItemPropertySource.class);
+ if (ips != null) {
+ object = ips.getPropertyDescriptor(target.getTarget(), id).getPropertyValue(target.getTarget());
+ }
+ if (target.getTarget() instanceof IAdaptable) {
+ final IPropertySource propertySource = (IPropertySource) ((IAdaptable) target.getTarget()).getAdapter(IPropertySource.class);
+ object = propertySource.getPropertyValue(id);
+ }
+
+ }
+ return object != null ? object : StringUtil.EMPTY_STRING;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.views.properties.IPropertySource#isPropertySet(java.lang.Object)
+ */
+ public boolean isPropertySet(final Object id) {
+ return this.getPropertyValue(id) != null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.views.properties.IPropertySource#resetPropertyValue(java.lang.Object)
+ */
+ public void resetPropertyValue(final Object id) {
+ // TODOYMO Auto-generated method stub
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.views.properties.IPropertySource#setPropertyValue(java.lang.Object,
+ * java.lang.Object)
+ */
+ public void setPropertyValue(final Object id, final Object value) {
+ if (id instanceof ExtensionFeatureDescription) {
+ final ExtensionFeatureDescription desc = (ExtensionFeatureDescription) id;
+ if (desc.isAttribute()) {
+ try {
+ this.getModelAccessor().eSet(target.getTarget(), ExtendedPropertySource.getFeatureName((ExtensionFeatureDescription) id), value);
+ } catch (final FeatureNotFoundException e) {
+ SiriusPlugin.getDefault().error("Error while setting the property value", e);
+ }
+ } else if (desc.isReference()) {
+ this.getModelAccessor().eClear(target.getTarget(), ExtendedPropertySource.getFeatureName((ExtensionFeatureDescription) id));
+ if (value instanceof Collection) {
+ final Iterator<?> iterValues = ((Collection<?>) value).iterator();
+ while (iterValues.hasNext()) {
+ try {
+ this.getModelAccessor().eAdd(target.getTarget(), ExtendedPropertySource.getFeatureName((ExtensionFeatureDescription) id), iterValues.next());
+ } catch (final FeatureNotFoundException e) {
+ // do nothing
+ }
+ }
+ }
+ }
+ } else {
+ final IItemPropertySource ips = (IItemPropertySource) adapterFactory.adapt(target.getTarget(), IItemPropertySource.class);
+ if (ips != null) {
+ ips.getPropertyDescriptor(target.getTarget(), id).setPropertyValue(target.getTarget(), value);
+ }
+ }
+ // else throw new AssertionError?();
+ }
+
+ /**
+ * The property source descriptor.
+ *
+ * @author ymortier
+ */
+ private class ExtendedPropertyDescriptor extends BaseLabelProvider implements IPropertyDescriptor, ILabelProvider {
+
+ /** The description of this extension. */
+ private ExtensionFeatureDescription extensionDescription;
+
+ /**
+ * Creates a new <code>ExtendedPropertyDescriptor</code>.
+ *
+ * @param extensionDescription
+ * the corresponding extension.
+ */
+ public ExtendedPropertyDescriptor(final ExtensionFeatureDescription extensionDescription) {
+ this.extensionDescription = extensionDescription;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.views.properties.IPropertyDescriptor#createPropertyEditor(org.eclipse.swt.widgets.Composite)
+ */
+ public CellEditor createPropertyEditor(final Composite parent) {
+ final EObject editableValue = (EObject) getEditableValue();
+ CellEditor editor = null;
+
+ if (!getPermissionAuthority(editableValue).canEditInstance(editableValue)) {
+ // do nothing -> leave editor to null
+ } else if (extensionDescription.isAttribute()) {
+ editor = new TextCellEditor(parent);
+ } else if (extensionDescription.isReference()) {
+ List<EObject> referenceValues = Collections.emptyList();
+ try {
+ referenceValues = (List<EObject>) getModelAccessor().eGet(editableValue, ExtendedPropertySource.getFeatureName(extensionDescription));
+ } catch (final FeatureNotFoundException e) {
+ SiriusPlugin.getDefault().error("Error while retrieving reference values", e);
+ }
+ final List<EObject> ref = referenceValues == null ? Collections.EMPTY_LIST : referenceValues;
+
+ editor = new ExtendedDialogCellEditor(parent, getLabelProvider()) {
+
+ @Override
+ protected Object openDialogBox(final Control cellEditorWindow) {
+ final ExtendedFeatureEditorDialog dialog = new ExtendedFeatureEditorDialog(parent.getShell(), getChoices(), ref, extensionDescription);
+ dialog.open();
+ return dialog.getResult();
+ }
+ };
+ } else {
+ throw new UnsupportedOperationException("unknown extension");
+ }
+ return editor;
+ }
+
+ private IPermissionAuthority getPermissionAuthority(final EObject instance) {
+ final ModelAccessor accessor = SiriusPlugin.getDefault().getModelAccessorRegistry().getModelAccessor(instance);
+ return accessor.getPermissionAuthority();
+ }
+
+ /**
+ * Returns the values that can be added into the reference description.
+ *
+ * @return the values that can be added into the reference description.
+ */
+ private List<EObject> getChoices() {
+ final List<EObject> result = new LinkedList<EObject>();
+ if (this.extensionDescription.isReference()) {
+ if (!extensionDescription.isContainment()) {
+ final EObject root = EcoreUtil.getRootContainer(target.getTarget());
+ result.addAll(getModelAccessor().eAllContents(root, extensionDescription.getTypeName()));
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @see IPropertyDescriptor#getCategory()
+ */
+ public String getCategory() {
+ return "Extended";
+ }
+
+ /**
+ * @see IPropertyDescriptor#getDescription()
+ */
+ public String getDescription() {
+ return "Property source for the extension framework";
+ }
+
+ /**
+ * @see IPropertyDescriptor#getDisplayName()
+ */
+ public String getDisplayName() {
+ return ExtendedPropertySource.getFeatureName(this.extensionDescription);
+ }
+
+ /**
+ * @see IPropertyDescriptor#getFilterFlags()
+ */
+ public String[] getFilterFlags() {
+ return EMPTY_STRING_ARRAY;
+ }
+
+ /**
+ * @see IPropertyDescriptor#getHelpContextIds()
+ */
+ public Object getHelpContextIds() {
+ return null;
+ }
+
+ /**
+ * @see IPropertyDescriptor#getId()
+ */
+ public Object getId() {
+ return this.extensionDescription;
+ }
+
+ /**
+ * @see IPropertyDescriptor#getLabelProvider()
+ */
+ public ILabelProvider getLabelProvider() {
+ return this;
+ }
+
+ /**
+ * @see IPropertyDescriptor#isCompatibleWith(IPropertyDescriptor)
+ */
+ public boolean isCompatibleWith(final IPropertyDescriptor anotherProperty) {
+ if (anotherProperty instanceof ExtendedPropertyDescriptor) {
+ return this.extensionDescription.equals(((ExtendedPropertyDescriptor) anotherProperty).extensionDescription);
+ }
+ return false;
+ }
+
+ /**
+ * @see ILabelProvider#getImage(Object)
+ */
+ public Image getImage(final Object element) {
+ // No specific image by default
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.ILabelProvider#getText(java.lang.Object)
+ */
+ public String getText(final Object element) {
+
+ String text = null;
+
+ if (element instanceof EObject) {
+ try {
+ text = String.valueOf(getModelAccessor().eGet((EObject) element, ExtendedPropertySource.getFeatureName(extensionDescription)));
+ } catch (final FeatureNotFoundException e) {
+ SiriusPlugin.getDefault().error("Error while getting the property value", e);
+ text = e.getMessage();
+ }
+ } else if (element instanceof Collection) {
+ final StringBuffer sb = new StringBuffer("[");
+ boolean first = true;
+ final Iterator<?> iterCollection = ((Collection<?>) element).iterator();
+ while (iterCollection.hasNext()) {
+ final Object next = iterCollection.next();
+ if (first) {
+ first = false;
+ } else {
+ sb.append(", ");
+ }
+ if (next instanceof EObject) {
+ sb.append(EMFCoreUtil.getQualifiedName((EObject) next, true));
+ } else if (next instanceof Collection) {
+ sb.append(this.getText(next));
+ } else {
+ sb.append(String.valueOf(next));
+ }
+ }
+ sb.append("]");
+ text = sb.toString();
+ } else if (element == null) {
+ text = "";
+ } else if (element instanceof EEnumLiteral) {
+ text = ((EEnumLiteral) element).getLiteral();
+ } else {
+ return String.valueOf(element);
+ }
+ return text;
+ }
+ }
+
+ /**
+ *
+ * @param extensionDescription
+ * @return
+ */
+ private static String getFeatureName(final ExtensionFeatureDescription extensionDescription) {
+ return extensionDescription.getName();
+
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/ExtensionSemanticPropertiesSection.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/ExtensionSemanticPropertiesSection.java
new file mode 100644
index 0000000000..c02bd89eab
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/ExtensionSemanticPropertiesSection.java
@@ -0,0 +1,182 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.properties;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.edit.provider.IItemPropertySource;
+import org.eclipse.emf.edit.ui.provider.PropertySource;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gmf.runtime.diagram.ui.properties.sections.AdvancedPropertySection;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.views.properties.IPropertySource;
+import org.eclipse.ui.views.properties.IPropertySourceProvider;
+
+import org.eclipse.sirius.DSemanticDecorator;
+import org.eclipse.sirius.diagram.part.SiriusDiagramEditorPlugin;
+import org.eclipse.sirius.diagram.tools.api.editor.DDiagramEditor;
+
+/**
+ * Property section mixing both Extension and Semantic attributes.
+ *
+ * @author ymortier
+ *
+ */
+public class ExtensionSemanticPropertiesSection extends AdvancedPropertySection implements IPropertySourceProvider {
+
+ private List<Object> transformedSelection;
+
+ private IWorkbenchPart part;
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.views.properties.IPropertySourceProvider#getPropertySource(java.lang.Object)
+ */
+ public IPropertySource getPropertySource(final Object object) {
+
+ IPropertySource propertySrc = null;
+ final AdapterFactory adapterFactory = getAdapterFactory(object);
+ if (object instanceof IPropertySource) {
+ propertySrc = (IPropertySource) object;
+ } else if (object instanceof DSemanticDecorator) {
+ propertySrc = new ExtendedPropertySource((DSemanticDecorator) object, adapterFactory);
+ } else {
+ if (adapterFactory != null) {
+ final IItemPropertySource ips = (IItemPropertySource) adapterFactory.adapt(object, IItemPropertySource.class);
+ if (ips != null) {
+ propertySrc = new PropertySource(object, ips);
+ }
+ }
+ if (propertySrc == null && object instanceof IAdaptable) {
+ propertySrc = (IPropertySource) ((IAdaptable) object).getAdapter(IPropertySource.class);
+ }
+
+ }
+ return propertySrc;
+ }
+
+ /**
+ * Get the adapter factory.
+ *
+ * @param object
+ * the object
+ * @return the retrieved adapter factory
+ */
+ protected AdapterFactory getAdapterFactory(final Object object) {
+ AdapterFactory adapterFactory = null;
+ if (object != null) {
+ if (part instanceof DDiagramEditor) {
+ adapterFactory = ((DDiagramEditor) part).getAdapterFactory();
+ } else {
+ adapterFactory = SiriusDiagramEditorPlugin.getInstance().getItemProvidersAdapterFactory();
+ }
+ }
+ return adapterFactory;
+ }
+
+ @Override
+ protected IPropertySourceProvider getPropertySourceProvider() {
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.properties.sections.AdvancedPropertySection#setInput(org.eclipse.ui.IWorkbenchPart,
+ * org.eclipse.jface.viewers.ISelection)
+ */
+ @Override
+ public void setInput(final IWorkbenchPart workbenchPart, final ISelection selection) {
+ this.part = workbenchPart;
+ if (selection.isEmpty() || !(selection instanceof StructuredSelection)) {
+ super.setInput(workbenchPart, selection);
+ return;
+ }
+ final StructuredSelection structuredSelection = (StructuredSelection) selection;
+ transformedSelection = new ArrayList<Object>(structuredSelection.size());
+ final Iterator<?> it = structuredSelection.iterator();
+ while (it.hasNext()) {
+ final Object r = transformSelection(it.next());
+ if (r != null) {
+ transformedSelection.add(r);
+ }
+ }
+ super.setInput(workbenchPart, new StructuredSelection(transformedSelection));
+ }
+
+ /**
+ * Transform the selection to get the designer element from the GMF one.
+ *
+ * @param selected
+ * the GMF element
+ * @return the Designer element
+ */
+ protected Object transformSelection(final Object selected) {
+
+ Object dElement = selected;
+
+ if (selected instanceof EditPart) {
+ final Object model = ((EditPart) selected).getModel();
+ if (model instanceof View) {
+ final EObject element = ((View) model).getElement();
+ if (element instanceof DSemanticDecorator) {
+ dElement = element;
+ }
+ }
+
+ } else if (selected instanceof View) {
+ if (((View) selected).getElement() instanceof DSemanticDecorator) {
+ dElement = ((View) selected).getElement();
+ }
+ } else if (selected instanceof IAdaptable) {
+ final View view = (View) ((IAdaptable) selected).getAdapter(View.class);
+ if (view != null) {
+ if (view.getElement() instanceof DSemanticDecorator) {
+ dElement = view.getElement();
+ }
+ }
+ }
+ return dElement;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.gmf.runtime.diagram.ui.properties.sections.AdvancedPropertySection#refresh()
+ */
+ @Override
+ public void refresh() {
+ if (this.transformedSelection != null) {
+ final Iterator<?> inputs = this.transformedSelection.iterator();
+ boolean isValid = true;
+ while (inputs.hasNext() && isValid) {
+ final Object input = inputs.next();
+ if (input instanceof DSemanticDecorator && (((DSemanticDecorator) input).eResource() == null || ((DSemanticDecorator) input).eResource().getResourceSet() == null)) {
+ isValid = false;
+ }
+ }
+ if (!isValid) {
+ this.setInput(this.part, StructuredSelection.EMPTY);
+ }
+ }
+ super.refresh();
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/FiltersPropertySection.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/FiltersPropertySection.java
new file mode 100644
index 0000000000..d2ad921578
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/FiltersPropertySection.java
@@ -0,0 +1,485 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2011 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.properties;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.emf.common.notify.Adapter;
+import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.common.notify.impl.AdapterImpl;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.provider.EcoreItemProviderAdapterFactory;
+import org.eclipse.emf.edit.provider.ComposeableAdapterFactory;
+import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
+import org.eclipse.emf.edit.provider.ItemProvider;
+import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory;
+import org.eclipse.emf.edit.provider.resource.ResourceItemProviderAdapterFactory;
+import org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider;
+import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.gef.EditPart;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.swt.SWT;
+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.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.views.properties.tabbed.AbstractPropertySection;
+import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.SiriusPlugin;
+import org.eclipse.sirius.description.DiagramDescription;
+import org.eclipse.sirius.description.audit.provider.AuditItemProviderAdapterFactory;
+import org.eclipse.sirius.description.filter.FilterDescription;
+import org.eclipse.sirius.description.filter.provider.FilterItemProviderAdapterFactory;
+import org.eclipse.sirius.description.provider.DescriptionItemProviderAdapterFactory;
+import org.eclipse.sirius.description.tool.provider.ToolItemProviderAdapterFactory;
+import org.eclipse.sirius.description.validation.provider.ValidationItemProviderAdapterFactory;
+import org.eclipse.sirius.diagram.internal.edit.parts.DDiagramEditPart;
+import org.eclipse.sirius.diagram.ui.tools.internal.commands.ActivateFiltersCommand;
+import org.eclipse.sirius.diagram.ui.tools.internal.commands.DeactivateFiltersCommand;
+import org.eclipse.sirius.provider.SiriusItemProviderAdapterFactory;
+import org.eclipse.sirius.ecore.extender.business.api.accessor.ModelAccessor;
+import org.eclipse.sirius.ecore.extender.business.api.permission.IPermissionAuthority;
+
+/**
+ * This Property section shows currently activated filters and helps in
+ * adding/removing new ones.
+ *
+ *
+ *
+ * @author cbrun
+ */
+@Deprecated
+public class FiltersPropertySection extends AbstractPropertySection {
+
+ /** The editing domain. */
+ protected TransactionalEditingDomain domain;
+
+ /** the choice table. */
+ protected Table choiceTable;
+
+ /** teh feature table. */
+ protected Table featureTable;
+
+ AdapterFactoryLabelProvider myAdapterFactoryLabelProvider;
+
+ private ComposedAdapterFactory adapterFactory;
+
+ private DDiagram diagram;
+
+ private TableViewer availableElementsTableViewer;
+
+ private TableViewer selectedElementsTableViewer;
+
+ private Button addButton;
+
+ private Button removeButton;
+
+ private final IDoubleClickListener availableElementsTableDoubleClickListener = new IDoubleClickListener() {
+ public void doubleClick(final DoubleClickEvent event) {
+ if (addButton.isEnabled()) {
+ addButton.notifyListeners(SWT.Selection, null);
+ }
+ }
+ };
+
+ private final IDoubleClickListener selectedElementsTableDoubleClickListener = new IDoubleClickListener() {
+ public void doubleClick(final DoubleClickEvent event) {
+ if (removeButton.isEnabled()) {
+ removeButton.notifyListeners(SWT.Selection, null);
+ }
+ }
+ };
+
+ /** The edit part to refresh. */
+ private EditPart editPart;
+
+ private final Adapter viewpointListener = new AdapterImpl() {
+
+ @Override
+ public void notifyChanged(final Notification msg) {
+ super.notifyChanged(msg);
+ viewpointChanged();
+ }
+
+ };
+
+ // TODOCBR comment this.
+ /**
+ * .
+ *
+ * @param newElements
+ * .
+ */
+ protected void newElementsSelected(final Collection<?> newElements) {
+ domain.getCommandStack().execute(new ActivateFiltersCommand(domain, getDiagram(), Lists.newArrayList(Iterables.filter(newElements, FilterDescription.class))));
+ }
+
+ // TODOCBR comment this !
+ /**
+ * .
+ *
+ * @param oldElements
+ * .
+ */
+ protected void oldElementsRemoved(final Collection<?> oldElements) {
+ domain.getCommandStack().execute(new DeactivateFiltersCommand(domain, getDiagram(), Lists.newArrayList(Iterables.filter(oldElements, FilterDescription.class))));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.views.properties.tabbed.AbstractPropertySection#aboutToBeShown()
+ */
+ @Override
+ public void aboutToBeShown() {
+ availableElementsTableViewer.addDoubleClickListener(availableElementsTableDoubleClickListener);
+ selectedElementsTableViewer.addDoubleClickListener(selectedElementsTableDoubleClickListener);
+
+ addButton.addSelectionListener(new SelectionListener() {
+
+ public void widgetDefaultSelected(final SelectionEvent e) {
+
+ }
+
+ public void widgetSelected(final SelectionEvent e) {
+ final List<Object> newElements = new ArrayList<Object>();
+ final IStructuredSelection selection = (IStructuredSelection) availableElementsTableViewer.getSelection();
+ final Iterator<?> i = selection.iterator();
+ while (i.hasNext()) {
+ final Object value = i.next();
+ newElements.add(value);
+ }
+ /*
+ * affect the viewpoint model
+ */
+ newElementsSelected(newElements);
+ }
+
+ });
+ removeButton.addSelectionListener(new SelectionListener() {
+
+ public void widgetDefaultSelected(final SelectionEvent e) {
+
+ }
+
+ public void widgetSelected(final SelectionEvent e) {
+ final List<Object> oldElements = new ArrayList<Object>();
+ final IStructuredSelection selection = (IStructuredSelection) selectedElementsTableViewer.getSelection();
+ Object firstValue = null;
+
+ final Iterator<?> i = selection.iterator();
+ while (i.hasNext()) {
+ final Object value = i.next();
+ if (firstValue == null) {
+ firstValue = value;
+ }
+ selectedElementsTableViewer.remove(value);
+ oldElements.add(value);
+ }
+ oldElementsRemoved(oldElements);
+
+ }
+
+ });
+ }
+
+ private void addSemanticListener(final DDiagram viewPoint) {
+ viewPoint.eAdapters().add(viewpointListener);
+ }
+
+ /**
+ * Create the adpater factory.
+ *
+ * @return the created factory
+ */
+ protected ComposedAdapterFactory createAdapterFactory() {
+ final List<ComposeableAdapterFactory> factories = new ArrayList<ComposeableAdapterFactory>();
+ factories.add(new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE));
+ fillItemProviderFactories(factories);
+ return new ComposedAdapterFactory(factories);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.views.properties.tabbed.AbstractPropertySection#createControls(org.eclipse.swt.widgets.Composite,
+ * org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage)
+ */
+ @Override
+ public void createControls(final Composite parent, final TabbedPropertySheetPage aTabbedPropertySheetPage) {
+ super.createControls(parent, aTabbedPropertySheetPage);
+
+ final Composite composite = getWidgetFactory().createFlatFormComposite(parent);
+ composite.setLayout(new GridLayout(3, false));
+
+ final Composite choiceComposite = createChoiceComposite(composite);
+
+ choiceTable = getWidgetFactory().createTable(choiceComposite, SWT.MULTI | SWT.BORDER);
+ choiceTable.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ availableElementsTableViewer = new TableViewer(choiceTable);
+
+ final Composite controlButtons = getWidgetFactory().createComposite(composite, SWT.NONE);
+ controlButtons.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
+
+ final GridLayout controlsButtonGridLayout = new GridLayout();
+ controlButtons.setLayout(controlsButtonGridLayout);
+
+ new Label(controlButtons, SWT.NONE);
+
+ addButton = getWidgetFactory().createButton(controlButtons, "Add >", SWT.PUSH);
+ addButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
+
+ removeButton = getWidgetFactory().createButton(controlButtons, "< Remove", SWT.PUSH);
+ removeButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
+
+ final Label spaceLabel = new Label(controlButtons, SWT.NONE);
+ final GridData spaceLabelGridData = new GridData();
+ spaceLabelGridData.verticalSpan = 2;
+ spaceLabel.setLayoutData(spaceLabelGridData);
+
+ final Composite featureComposite = createFeatureComposite(composite);
+
+ featureTable = getWidgetFactory().createTable(featureComposite, SWT.MULTI | SWT.BORDER);
+ featureTable.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ selectedElementsTableViewer = new TableViewer(featureTable);
+
+ }
+
+ private IPermissionAuthority getPermissionAuthority() {
+ final ModelAccessor accessor = SiriusPlugin.getDefault().getModelAccessorRegistry().getModelAccessor(diagram);
+ return accessor.getPermissionAuthority();
+ }
+
+ /**
+ * Create the feature section.
+ *
+ * @param composite
+ * the parent container.
+ * @return the created composite
+ */
+ protected Composite createFeatureComposite(final Composite composite) {
+ final Composite featureComposite = getWidgetFactory().createComposite(composite, SWT.NONE);
+ featureComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ featureComposite.setLayout(new GridLayout());
+
+ final Label featureLabel = getWidgetFactory().createLabel(featureComposite, "Applied filters", SWT.NONE);
+ featureLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
+ return featureComposite;
+ }
+
+ /**
+ * Create the choice section.
+ *
+ * @param composite
+ * the parent container
+ * @return teh created composite
+ */
+ protected Composite createChoiceComposite(final Composite composite) {
+ final Composite choiceComposite = getWidgetFactory().createComposite(composite, SWT.NONE);
+ choiceComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ choiceComposite.setLayout(new GridLayout());
+
+ final Label choiceLabel = getWidgetFactory().createLabel(choiceComposite, "Available filters", SWT.NONE);
+ choiceLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ return choiceComposite;
+ }
+
+ /**
+ * fill the item provider factory list.
+ *
+ * @param factories
+ * the list to fill
+ */
+ protected void fillItemProviderFactories(final List<ComposeableAdapterFactory> factories) {
+ factories.add(new SiriusItemProviderAdapterFactory());
+ factories.add(new DescriptionItemProviderAdapterFactory());
+ factories.add(new ToolItemProviderAdapterFactory());
+ factories.add(new FilterItemProviderAdapterFactory());
+ factories.add(new ValidationItemProviderAdapterFactory());
+ factories.add(new AuditItemProviderAdapterFactory());
+ factories.add(new EcoreItemProviderAdapterFactory());
+ factories.add(new ResourceItemProviderAdapterFactory());
+ factories.add(new ReflectiveItemProviderAdapterFactory());
+ }
+
+ /**
+ * Get all applied elements.
+ *
+ * @return the applied elements.
+ */
+ protected Collection<?> getAppliedElements() {
+ final Collection<FilterDescription> result = new HashSet<FilterDescription>();
+ if (diagram != null) {
+ result.addAll(diagram.getActivatedFilters());
+ }
+ return result;
+ }
+
+ /**
+ * Get all available elements.
+ *
+ * @return the available elements
+ */
+ protected Collection<?> getAvailableElements() {
+ final Collection<FilterDescription> result = new HashSet<FilterDescription>();
+
+ if (diagram != null && diagram.getDescription() != null) {
+ final DiagramDescription desc = diagram.getDescription();
+ result.addAll(desc.getFilters());
+ }
+ result.removeAll(getAppliedElements());
+ return result;
+ }
+
+ protected DDiagram getDiagram() {
+ return diagram;
+ }
+
+ protected EditPart getEditPart() {
+ return editPart;
+ }
+
+ private ItemProvider getItemProvider(final Collection<?> choices) {
+ return new ItemProvider(getItemProvidersAdapterFactory(), choices);
+ }
+
+ private AdapterFactory getItemProvidersAdapterFactory() {
+ if (adapterFactory == null) {
+ adapterFactory = createAdapterFactory();
+ }
+ return adapterFactory;
+ }
+
+ private AdapterFactoryLabelProvider getLabelProvider() {
+ if (myAdapterFactoryLabelProvider == null) {
+ myAdapterFactoryLabelProvider = new AdapterFactoryLabelProvider(getItemProvidersAdapterFactory());
+ }
+ return myAdapterFactoryLabelProvider;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.views.properties.tabbed.AbstractPropertySection#refresh()
+ */
+ @Override
+ public void refresh() {
+ Display.getDefault().syncExec(new Runnable() {
+
+ public void run() {
+ /*
+ * Set content/label provider
+ */
+ if (!availableElementsTableViewer.getTable().isDisposed()) {
+ availableElementsTableViewer.setLabelProvider(getLabelProvider());
+ selectedElementsTableViewer.setLabelProvider(getLabelProvider());
+ availableElementsTableViewer.setContentProvider(new AdapterFactoryContentProvider(getItemProvidersAdapterFactory()));
+ selectedElementsTableViewer.setContentProvider(new AdapterFactoryContentProvider(getItemProvidersAdapterFactory()));
+
+ availableElementsTableViewer.setInput(getItemProvider(getAvailableElements()));
+ selectedElementsTableViewer.setInput(getItemProvider(getAppliedElements()));
+ }
+ }
+
+ });
+ }
+
+ private void removeSemanticListener(final DDiagram dia) {
+ dia.eAdapters().remove(viewpointListener);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.views.properties.tabbed.AbstractPropertySection#setInput(org.eclipse.ui.IWorkbenchPart,
+ * org.eclipse.jface.viewers.ISelection)
+ */
+ @Override
+ public void setInput(final IWorkbenchPart part, final ISelection selection) {
+ super.setInput(part, selection);
+ if (selection instanceof IStructuredSelection) {
+ final Object input = ((IStructuredSelection) selection).getFirstElement();
+ if (input instanceof DDiagramEditPart) {
+ final EObject vp = ((DDiagramEditPart) input).resolveSemanticElement();
+ editPart = ((DDiagramEditPart) input).getRoot();
+ if (vp instanceof DDiagram) {
+ setSirius((DDiagram) vp);
+ this.domain = ((DDiagramEditPart) input).getEditingDomain();
+ }
+ }
+ }
+ refresh();
+ }
+
+ private void setSirius(final DDiagram newDia) {
+ if (!getPermissionAuthority().canEditInstance(newDia)) {
+ featureTable.setEnabled(false);
+ addButton.setEnabled(false);
+ removeButton.setEnabled(false);
+ choiceTable.setEnabled(false);
+ }
+ if (diagram == newDia) {
+ return;
+ }
+
+ if (diagram != null) {
+ removeSemanticListener(diagram);
+ }
+ diagram = newDia;
+ refresh();
+
+ if (diagram != null) {
+ addSemanticListener(diagram);
+ }
+
+ }
+
+ private void viewpointChanged() {
+ refresh();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.ui.views.properties.tabbed.AbstractPropertySection#dispose()
+ */
+ @Override
+ public void dispose() {
+ super.dispose();
+ if (getDiagram() != null) {
+ removeSemanticListener(getDiagram());
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/ResetStylePropertiesToDefaultValuesSelectionAdapter.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/ResetStylePropertiesToDefaultValuesSelectionAdapter.java
new file mode 100644
index 0000000000..98fb19d400
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/ResetStylePropertiesToDefaultValuesSelectionAdapter.java
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * Copyright (c) 2012 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.properties;
+
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.emf.transaction.util.TransactionUtil;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.properties.sections.appearance.ColorsAndFontsPropertySection;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.Style;
+import org.eclipse.sirius.business.api.query.DDiagramElementQuery;
+import org.eclipse.sirius.diagram.business.api.query.ViewQuery;
+import org.eclipse.sirius.diagram.edit.api.part.AbstractDiagramContainerEditPart;
+import org.eclipse.sirius.diagram.tools.internal.commands.ResetStylePropertiesToDefaultValuesCommand;
+
+/**
+ * A {@link SelectionAdapter} to reset some style properties to their default
+ * values.
+ *
+ * @author <a href="mailto:esteban.dugueperoux@obeo.fr">Esteban Dugueperoux</a>
+ */
+public class ResetStylePropertiesToDefaultValuesSelectionAdapter extends SelectionAdapter {
+
+ private ColorsAndFontsPropertySection colorAndFontPropertySection;
+
+ /**
+ * Default constructor.
+ *
+ * @param colorAndFontPropertySection
+ * the {@link ColorsAndFontsPropertySection} from which get
+ * selected styles for which reset customizations
+ */
+ public ResetStylePropertiesToDefaultValuesSelectionAdapter(ColorsAndFontsPropertySection colorAndFontPropertySection) {
+ this.colorAndFontPropertySection = colorAndFontPropertySection;
+ }
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ List<?> input = colorAndFontPropertySection.getInput();
+ if (!input.isEmpty()) {
+ DDiagram dDiagram = (DDiagram) colorAndFontPropertySection.getSingleInput().getNotationView().getDiagram().getElement();
+ TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(dDiagram);
+ Map<View, DDiagramElement> customizedViews = new LinkedHashMap<View, DDiagramElement>();
+ Map<IGraphicalEditPart, Style> oldStyles = new HashMap<IGraphicalEditPart, Style>();
+ for (Object obj : input) {
+ if (obj instanceof IGraphicalEditPart) {
+ IGraphicalEditPart graphicalEditPart = (IGraphicalEditPart) obj;
+ View notationView = graphicalEditPart.getNotationView();
+ DDiagramElement dDiagramElement = null;
+ EObject semanticElement = graphicalEditPart.resolveSemanticElement();
+ if (semanticElement instanceof DDiagramElement) {
+ dDiagramElement = (DDiagramElement) semanticElement;
+ if (new DDiagramElementQuery(dDiagramElement).isCustomized() || new ViewQuery(notationView).isCustomized()) {
+ customizedViews.put(notationView, dDiagramElement);
+ oldStyles.put(graphicalEditPart, dDiagramElement.getStyle());
+ }
+ } else if (dDiagramElement == null && new ViewQuery(notationView).isCustomized()) {
+ customizedViews.put(notationView, dDiagramElement);
+ }
+ }
+ }
+ if (!customizedViews.isEmpty()) {
+ Command resetStylePropertiesToDefaultValuesCommand = new ResetStylePropertiesToDefaultValuesCommand(domain, dDiagram, customizedViews);
+ domain.getCommandStack().execute(resetStylePropertiesToDefaultValuesCommand);
+ Set<Entry<IGraphicalEditPart, Style>> entrySet = oldStyles.entrySet();
+ for (Entry<IGraphicalEditPart, Style> entry : entrySet) {
+ if (entry.getKey() instanceof AbstractDiagramContainerEditPart) {
+ AbstractDiagramContainerEditPart graphicalEditPart = (AbstractDiagramContainerEditPart) entry.getKey();
+ graphicalEditPart.reInitFigure();
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Tells if the specified {@link View} is customized.
+ *
+ * @param view
+ * the specified {@link View}
+ * @return true if the specified {@link View} is customized, false else
+ */
+ public static boolean isCustomizedView(View view) {
+ boolean isCustomized = false;
+ EObject element = view.getElement();
+ if (element instanceof DDiagramElement) {
+ DDiagramElement dDiagramElement = (DDiagramElement) element;
+ DDiagramElementQuery dDiagramElementQuery = new DDiagramElementQuery(dDiagramElement);
+ if (dDiagramElementQuery.isCustomized()) {
+ isCustomized = true;
+ }
+ }
+ ViewQuery viewQuery = new ViewQuery(view);
+ if (!isCustomized && viewQuery.isCustomized()) {
+ isCustomized = true;
+ }
+ return isCustomized;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/SemanticAndExtensionPropertySection.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/SemanticAndExtensionPropertySection.java
new file mode 100644
index 0000000000..0af524e285
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/SemanticAndExtensionPropertySection.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.properties;
+
+import java.util.Iterator;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.ui.views.properties.IPropertySource;
+import org.eclipse.ui.views.properties.IPropertySourceProvider;
+
+import org.eclipse.sirius.DDiagramElement;
+
+/**
+ * Displays the semantic and the extension properties.
+ *
+ * @author ymortier
+ */
+public class SemanticAndExtensionPropertySection extends SemanticPropertySection {
+
+ /** The provider for the extension. */
+ private IPropertySourceProvider extendedPropertySourceProvider;
+
+ /**
+ * Creates a new <code>SemanticAndExtensionPropertySection</code>.
+ */
+ public SemanticAndExtensionPropertySection() {
+ this.extendedPropertySourceProvider = new ExtensionSemanticPropertiesSection();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.internal.properties.SemanticPropertySection#getPropertySource(java.lang.Object)
+ */
+ @Override
+ public IPropertySource getPropertySource(final Object object) {
+ final IPropertySource propertySource = super.getPropertySource(object);
+ if (propertySource instanceof CompositeEObjectPropertySource) {
+ final CompositeEObjectPropertySource compositePropertySource = (CompositeEObjectPropertySource) propertySource;
+ if (object instanceof DDiagramElement) {
+ final DDiagramElement viewPointElement = (DDiagramElement) object;
+ final Iterator<EObject> iterElementsToDestroy = viewPointElement.getSemanticElements().iterator();
+ while (iterElementsToDestroy.hasNext()) {
+ final EObject semanticElement = iterElementsToDestroy.next();
+ final IPropertySource extendedPropertySource = this.extendedPropertySourceProvider.getPropertySource(object);
+ compositePropertySource.addPropertySource(semanticElement, extendedPropertySource);
+ }
+ }
+ }
+ return propertySource;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/SemanticPropertySection.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/SemanticPropertySection.java
new file mode 100644
index 0000000000..3ce88d2e93
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/SemanticPropertySection.java
@@ -0,0 +1,234 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.properties;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.edit.provider.IItemPropertySource;
+import org.eclipse.emf.edit.ui.provider.PropertySource;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.views.properties.IPropertySource;
+import org.eclipse.ui.views.properties.IPropertySourceProvider;
+
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DSemanticDecorator;
+import org.eclipse.sirius.SiriusPlugin;
+import org.eclipse.sirius.diagram.part.SiriusDiagramEditorPlugin;
+import org.eclipse.sirius.diagram.tools.api.editor.DDiagramEditor;
+import org.eclipse.sirius.diagram.ui.tools.api.properties.AbstractPropertySection;
+import org.eclipse.sirius.ecore.extender.business.api.accessor.ModelAccessor;
+
+/**
+ * Properties for the semantic model.
+ *
+ * @author ymortier
+ */
+public class SemanticPropertySection extends AbstractPropertySection implements IPropertySourceProvider {
+
+ private List<Object> transformedSelection;
+
+ private IWorkbenchPart part;
+
+ /**
+ * Returns the property source of the specified objet.
+ *
+ * @param object
+ * the object.
+ * @return the property source of the specified objet.
+ */
+ public IPropertySource getPropertySource(final Object object) {
+
+ IPropertySource propSrc = null;
+
+ if (object instanceof IPropertySource) {
+ propSrc = (IPropertySource) object;
+ } else if (object instanceof DDiagramElement) {
+ final DDiagramElement diagramElement = (DDiagramElement) object;
+ final Iterator<EObject> iterElementsToDestroy = diagramElement.getSemanticElements().iterator();
+ final CompositeEObjectPropertySource propertySource = new CompositeEObjectPropertySource();
+ final ModelAccessor accessor = SiriusPlugin.getDefault().getModelAccessorRegistry().getModelAccessor(diagramElement);
+ while (iterElementsToDestroy.hasNext()) {
+ final EObject semanticElement = iterElementsToDestroy.next();
+ if (!(accessor.isExtension(semanticElement))) {
+ final AdapterFactory af = getAdapterFactory(semanticElement);
+ if (af != null) {
+ final IItemPropertySource ips = (IItemPropertySource) af.adapt(semanticElement, IItemPropertySource.class);
+ if (ips != null) {
+ final IPropertySource targetPropertySource = new PropertySource(semanticElement, ips);
+ propertySource.addPropertySource(semanticElement, targetPropertySource);
+ }
+ }
+ }
+ }
+ propSrc = propertySource;
+ } else if (object instanceof DSemanticDecorator) {
+ final CompositeEObjectPropertySource propertySource = new CompositeEObjectPropertySource();
+ final ModelAccessor accessor = SiriusPlugin.getDefault().getModelAccessorRegistry().getModelAccessor((EObject) object);
+ final EObject semanticElement = ((DSemanticDecorator) object).getTarget();
+ if (!(accessor.isExtension(semanticElement))) {
+ final AdapterFactory af = getAdapterFactory(semanticElement);
+ if (af != null) {
+ final IItemPropertySource ips = (IItemPropertySource) af.adapt(semanticElement, IItemPropertySource.class);
+ if (ips != null) {
+ final IPropertySource targetPropertySource = new PropertySource(semanticElement, ips);
+ propertySource.addPropertySource(semanticElement, targetPropertySource);
+ }
+ }
+ }
+ propSrc = propertySource;
+ } else {
+ final AdapterFactory af = getAdapterFactory(object);
+ if (af != null) {
+ final IItemPropertySource ips = (IItemPropertySource) af.adapt(object, IItemPropertySource.class);
+ if (ips != null) {
+ return new PropertySource(object, ips);
+ }
+ }
+ if (object instanceof IAdaptable) {
+ propSrc = (IPropertySource) ((IAdaptable) object).getAdapter(IPropertySource.class);
+ }
+ }
+ return propSrc;
+
+ }
+
+ /**
+ * Returns the provider.
+ *
+ * @return the provider.
+ */
+ @Override
+ protected IPropertySourceProvider getPropertySourceProvider() {
+ return this;
+ }
+
+ /**
+ * Transform selection to have {@link DSemanticDecorator} instead of
+ * {@link EditPart} or null if the semantic element (target) not exists.
+ *
+ * @param selection
+ * the currently selected object
+ * @return the unwrapped object
+ */
+ protected Object transformSelection(final Object selection) {
+
+ Object object = selection;
+
+ if (object instanceof EditPart) {
+ object = ((EditPart) object).getModel();
+ } else if (object instanceof IAdaptable) {
+ object = ((IAdaptable) object).getAdapter(View.class);
+ }
+
+ if (object instanceof View) {
+ object = ((View) object).getElement();
+ }
+
+ if (object instanceof DSemanticDecorator) {
+ EObject target = ((DSemanticDecorator) object).getTarget();
+ if (target == null || target.eResource() == null) {
+ object = null;
+ }
+ }
+ return object;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.properties.AbstractPropertySection#setInput(org.eclipse.ui.IWorkbenchPart,
+ * org.eclipse.jface.viewers.ISelection)
+ */
+ @Override
+ public void setInput(final IWorkbenchPart workbenchPart, final ISelection selection) {
+ this.part = workbenchPart;
+ if (selection.isEmpty() || !(selection instanceof StructuredSelection)) {
+ super.setInput(workbenchPart, selection);
+ return;
+ }
+ final StructuredSelection structuredSelection = (StructuredSelection) selection;
+ transformedSelection = new ArrayList<Object>(structuredSelection.size());
+ final Iterator<?> it = structuredSelection.iterator();
+ while (it.hasNext()) {
+ final Object r = transformSelection(it.next());
+ if (r != null) {
+ transformedSelection.add(r);
+ }
+ }
+ super.setInput(workbenchPart, new StructuredSelection(transformedSelection));
+ }
+
+ /**
+ * Get the adapter factory.
+ *
+ * @param object
+ * the object
+ * @return the retrieved adapter factory
+ */
+ protected AdapterFactory getAdapterFactory(final Object object) {
+ AdapterFactory adapterFactory = null;
+ if (object != null) {
+ if (part instanceof DDiagramEditor) {
+ adapterFactory = ((DDiagramEditor) part).getAdapterFactory();
+ } else {
+ adapterFactory = SiriusDiagramEditorPlugin.getInstance().getItemProvidersAdapterFactory();
+ }
+ }
+ return adapterFactory;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.properties.AbstractPropertySection#refresh()
+ */
+ @Override
+ public void refresh() {
+ if (this.transformedSelection != null) {
+ final Iterator<?> inputs = this.transformedSelection.iterator();
+ boolean isValid = true;
+ while (inputs.hasNext() && isValid) {
+ final Object input = inputs.next();
+ if (input instanceof DSemanticDecorator && (((DSemanticDecorator) input).eResource() == null || ((DSemanticDecorator) input).eResource().getResourceSet() == null)) {
+ isValid = false;
+ }
+ }
+ if (!isValid) {
+ this.setInput(this.part, StructuredSelection.EMPTY);
+ }
+ }
+ super.refresh();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.properties.AbstractPropertySection#getSelectedObject()
+ */
+ @Override
+ public Object getSelectedObject() {
+ Object result = null;
+ if (!transformedSelection.isEmpty()) {
+ result = transformedSelection.get(0);
+ }
+ return result;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/StylePropertySection.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/StylePropertySection.java
new file mode 100644
index 0000000000..d1d53b7b0b
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/StylePropertySection.java
@@ -0,0 +1,285 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.properties;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.edit.provider.IItemPropertySource;
+import org.eclipse.emf.edit.ui.provider.PropertySource;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gmf.runtime.notation.ConnectorStyle;
+import org.eclipse.gmf.runtime.notation.FontStyle;
+import org.eclipse.gmf.runtime.notation.Routing;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.ui.views.properties.IPropertySource;
+
+import org.eclipse.sirius.DSemanticDecorator;
+import org.eclipse.sirius.DStylizable;
+import org.eclipse.sirius.EdgeRouting;
+import org.eclipse.sirius.EdgeStyle;
+import org.eclipse.sirius.FontFormat;
+import org.eclipse.sirius.LabelStyle;
+import org.eclipse.sirius.RGBValues;
+import org.eclipse.sirius.Style;
+import org.eclipse.sirius.SiriusPackage;
+import org.eclipse.sirius.SiriusPlugin;
+import org.eclipse.sirius.ecore.extender.business.api.accessor.ModelAccessor;
+import org.eclipse.sirius.ecore.extender.business.api.permission.IPermissionAuthority;
+
+/**
+ * Properties section that shows the properties of a style of a DiagramElement.
+ *
+ * @author ymortier
+ */
+public class StylePropertySection extends SemanticPropertySection {
+
+ private Map<DStylizable, View> map = new HashMap<DStylizable, View>();
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.internal.properties.SemanticPropertySection#getPropertySource(java.lang.Object)
+ */
+ @Override
+ public IPropertySource getPropertySource(final Object object) {
+
+ IPropertySource propSrc = null;
+
+ if (object instanceof IPropertySource) {
+ propSrc = (IPropertySource) object;
+ }
+ //
+ // We should display the ColorMapping if the style is an EdgeStyle and
+ // if the stroke color is not null.
+ else if (object instanceof EObject && !getPermissionAuthority((EObject) object).canEditInstance((EObject) object)) {
+ // do nothing -> return null
+ } else if (object instanceof DStylizable && ((DStylizable) object).getStyle() instanceof EdgeStyle && ((EdgeStyle) ((DStylizable) object).getStyle()).getStrokeColor() != null) {
+ final DStylizable stylizable = (DStylizable) object;
+ final View view = map.get(stylizable);
+
+ final EdgeStyle edgeStyle = (EdgeStyle) stylizable.getStyle();
+ final RGBValues rgb = edgeStyle.getStrokeColor();
+ final CompositeEObjectPropertySource propertySource = new CompositeEObjectPropertySource();
+ AdapterFactory af = getAdapterFactory(edgeStyle);
+ if (af != null) {
+ final IItemPropertySource ips = (IItemPropertySource) af.adapt(edgeStyle, IItemPropertySource.class);
+ if (ips != null) {
+ final IPropertySource targetPropertySource = new StylePropertySource(edgeStyle, view, ips);
+ propertySource.addPropertySource(edgeStyle, targetPropertySource);
+ }
+ }
+ af = getAdapterFactory(rgb);
+ if (af != null) {
+ final IItemPropertySource ips = (IItemPropertySource) af.adapt(rgb, IItemPropertySource.class);
+ if (ips != null) {
+ final IPropertySource targetPropertySource = new StylePropertySource(rgb, view, ips);
+ propertySource.addPropertySource(rgb, targetPropertySource);
+ }
+ }
+ propSrc = propertySource;
+ } else {
+ //
+ // Other styles.
+ propSrc = getPropertySourceForOtherStyles(object);
+ }
+ return propSrc;
+
+ }
+
+ private IPropertySource getPropertySourceForOtherStyles(final Object object) {
+
+ IPropertySource propSrc = null;
+
+ if (object instanceof DStylizable) {
+ final DStylizable stylizable = (DStylizable) object;
+ final View view = map.get(stylizable);
+ final Style style = stylizable.getStyle();
+ if (style != null) {
+ final AdapterFactory af = getAdapterFactory(style);
+ if (af != null) {
+ final IItemPropertySource ips = (IItemPropertySource) af.adapt(style, IItemPropertySource.class);
+ if (ips != null) {
+ final IPropertySource targetPropertySource = new StylePropertySource(style, view, ips);
+ propSrc = targetPropertySource;
+ }
+ }
+ }
+ }
+ if (propSrc == null) {
+ final AdapterFactory af = getAdapterFactory(object);
+ if (af != null) {
+ final IItemPropertySource ips = (IItemPropertySource) af.adapt(object, IItemPropertySource.class);
+ if (ips != null) {
+ propSrc = new StylePropertySource(object, ips);
+ }
+ }
+ if (propSrc == null && object instanceof IAdaptable) {
+ propSrc = (IPropertySource) ((IAdaptable) object).getAdapter(IPropertySource.class);
+ }
+ }
+
+ return propSrc;
+ }
+
+ private IPermissionAuthority getPermissionAuthority(final EObject instance) {
+ final ModelAccessor accessor = SiriusPlugin.getDefault().getModelAccessorRegistry().getModelAccessor(instance);
+ return accessor.getPermissionAuthority();
+ }
+
+ /**
+ * Transform selection to have {@link DSemanticDecorator} instead of
+ * {@link EditPart} or null if the semantic element (target) not exists.
+ *
+ * @param selection
+ * the currently selected object
+ * @return the unwrapped object
+ */
+ @Override
+ protected Object transformSelection(final Object selection) {
+
+ Object object = selection;
+ View view = null;
+
+ if (object instanceof EditPart) {
+ object = ((EditPart) object).getModel();
+ } else if (object instanceof IAdaptable) {
+ object = ((IAdaptable) object).getAdapter(View.class);
+ }
+
+ if (object instanceof View) {
+ view = (View) object;
+ object = view.getElement();
+ }
+
+ if (view != null && object instanceof DStylizable) {
+ map.put((DStylizable) object, view);
+ }
+
+ if (object instanceof DSemanticDecorator) {
+ EObject target = ((DSemanticDecorator) object).getTarget();
+ if (target == null || target.eResource() == null) {
+ object = null;
+ }
+ }
+ return object;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * This is used to automatically set the "custom" attribute of a Style if
+ * there is any manual change in the PropertySection.
+ *
+ * @author mPorhel
+ *
+ */
+ private static class StylePropertySource extends PropertySource {
+
+ private View view;
+
+ /**
+ * An instance is constructed from an object and its item property
+ * source.
+ */
+ public StylePropertySource(final Object object, final IItemPropertySource itemPropertySource) {
+ super(object, itemPropertySource);
+ this.view = null;
+ }
+
+ /**
+ * An instance is constructed from an object, its edit part and its item
+ * property source.
+ */
+ public StylePropertySource(final Object object, final View view, final IItemPropertySource itemPropertySource) {
+ super(object, itemPropertySource);
+ this.view = view;
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.emf.edit.ui.provider.PropertySource#setPropertyValue(java.lang.Object,
+ * java.lang.Object)
+ */
+ @Override
+ public void setPropertyValue(final Object propertyId, final Object value) {
+ if (this.object instanceof Style && propertyId instanceof String) {
+ Style style = (Style) object;
+ String featureName = (String) propertyId;
+ EStructuralFeature feature = style.eClass().getEStructuralFeature(featureName);
+ if (feature != null && !style.getCustomFeatures().contains(feature.getName())) {
+ style.getCustomFeatures().add(feature.getName());
+ }
+ } else if (object instanceof EObject && ((EObject) object).eContainer() instanceof Style && propertyId instanceof String) {
+ EObject containedValue = (EObject) object;
+ Style style = (Style) containedValue.eContainer();
+ EStructuralFeature feature = containedValue.eContainingFeature();
+ if (feature != null && !style.getCustomFeatures().contains(feature.getName())) {
+ style.getCustomFeatures().add(feature.getName());
+ }
+ }
+ super.setPropertyValue(propertyId, value);
+
+ if (this.object instanceof LabelStyle) {
+ updateNotationView(propertyId, value);
+ } else if (this.object instanceof EdgeStyle) {
+ updateNotationView(propertyId, value);
+ } else if (this.object instanceof RGBValues) {
+ updateNotationView(propertyId, value);
+ }
+ }
+
+ private void updateNotationView(final Object propertyId, final Object value) {
+ if (view != null && view.getStyles() != null) {
+ for (Object notationStyle : view.getStyles()) {
+ if (notationStyle instanceof FontStyle) {
+ final FontStyle fontStyle = (FontStyle) notationStyle;
+ if (value instanceof FontFormat && propertyId.equals(SiriusPackage.Literals.BASIC_LABEL_STYLE__LABEL_FORMAT.getName())) {
+ if (FontFormat.BOLD_LITERAL == value) {
+ fontStyle.setBold(true);
+ fontStyle.setItalic(false);
+ } else if (FontFormat.ITALIC_LITERAL == value) {
+ fontStyle.setBold(false);
+ fontStyle.setItalic(true);
+ } else if (FontFormat.BOLD_ITALIC_LITERAL == value) {
+ fontStyle.setBold(true);
+ fontStyle.setItalic(true);
+ } else if (FontFormat.NORMAL_LITERAL == value) {
+ fontStyle.setBold(false);
+ fontStyle.setItalic(false);
+ }
+ } else if (value instanceof Integer && propertyId.equals(SiriusPackage.Literals.BASIC_LABEL_STYLE__LABEL_SIZE.getName())) {
+ fontStyle.setFontHeight((Integer) value);
+ }
+ } else if (notationStyle instanceof ConnectorStyle) {
+ ConnectorStyle connectorStyle = (ConnectorStyle) notationStyle;
+ if (value instanceof EdgeRouting && propertyId.equals(SiriusPackage.Literals.EDGE_STYLE__ROUTING_STYLE.getName())) {
+ if (EdgeRouting.MANHATTAN_LITERAL == value) {
+ connectorStyle.setRouting(Routing.RECTILINEAR_LITERAL);
+ } else if (EdgeRouting.STRAIGHT_LITERAL == value) {
+ connectorStyle.setRouting(Routing.MANUAL_LITERAL);
+ } else if (EdgeRouting.TREE_LITERAL == value) {
+ connectorStyle.setRouting(Routing.TREE_LITERAL);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/ValidationPropertySection.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/ValidationPropertySection.java
new file mode 100644
index 0000000000..19667b9bc0
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/ValidationPropertySection.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.properties;
+
+import java.util.Collection;
+import java.util.HashSet;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+import org.eclipse.sirius.description.validation.ValidationRule;
+import org.eclipse.sirius.diagram.ui.tools.internal.commands.ActivateRulesCommand;
+import org.eclipse.sirius.diagram.ui.tools.internal.commands.DeactivateRulesCommand;
+
+/**
+ * This Property section shows currently activated validation rules and helps in
+ * adding/removing new ones.
+ *
+ *
+ *
+ * @author cbrun
+ *
+ */
+public class ValidationPropertySection extends FiltersPropertySection {
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.internal.properties.FiltersPropertySection#getAppliedElements()
+ */
+ @Override
+ protected Collection<?> getAppliedElements() {
+ final Collection<ValidationRule> result = new HashSet<ValidationRule>();
+ if (getDiagram() != null) {
+ result.addAll(getDiagram().getActivatedRules());
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.internal.properties.FiltersPropertySection#getAvailableElements()
+ */
+ @Override
+ protected Collection<?> getAvailableElements() {
+ final Collection<ValidationRule> result = new HashSet<ValidationRule>();
+ if (getDiagram() != null && getDiagram().getDescription() != null && getDiagram().getDescription().getValidationSet() != null) {
+ result.addAll(getDiagram().getDescription().getValidationSet().getAllRules());
+ }
+ result.removeAll(getAppliedElements());
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.internal.properties.FiltersPropertySection#createFeatureComposite(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ protected Composite createFeatureComposite(final Composite composite) {
+ final Composite featureComposite = getWidgetFactory().createComposite(composite, SWT.NONE);
+ featureComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ featureComposite.setLayout(new GridLayout());
+
+ final Label featureLabel = getWidgetFactory().createLabel(featureComposite, "Activated rules", SWT.NONE);
+ featureLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
+ return featureComposite;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.internal.properties.FiltersPropertySection#createChoiceComposite(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ protected Composite createChoiceComposite(final Composite composite) {
+ final Composite choiceComposite = getWidgetFactory().createComposite(composite, SWT.NONE);
+ choiceComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ choiceComposite.setLayout(new GridLayout());
+
+ final Label choiceLabel = getWidgetFactory().createLabel(choiceComposite, "Available rules", SWT.NONE);
+ choiceLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ return choiceComposite;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.internal.properties.FiltersPropertySection#newElementsSelected(java.util.Collection)
+ */
+ @Override
+ protected void newElementsSelected(final Collection<?> newElements) {
+ domain.getCommandStack().execute(new ActivateRulesCommand(domain, getDiagram(), Lists.newArrayList(Iterables.filter(newElements, ValidationRule.class))));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.internal.properties.FiltersPropertySection#oldElementsRemoved(java.util.Collection)
+ */
+ @Override
+ protected void oldElementsRemoved(final Collection<?> oldElements) {
+ domain.getCommandStack().execute(new DeactivateRulesCommand(domain, getDiagram(), Lists.newArrayList(Iterables.filter(oldElements, ValidationRule.class))));
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/filter/ExtendedPropertyFilter.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/filter/ExtendedPropertyFilter.java
new file mode 100644
index 0000000000..80774b7879
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/filter/ExtendedPropertyFilter.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.properties.filter;
+
+import java.util.Iterator;
+
+import org.eclipse.emf.ecore.EObject;
+
+import org.eclipse.sirius.SiriusPlugin;
+import org.eclipse.sirius.diagram.ui.tools.api.properties.filter.AbstractPropertyFilter;
+import org.eclipse.sirius.ecore.extender.business.api.accessor.ModelAccessor;
+import org.eclipse.sirius.ecore.extender.business.api.accessor.ModelAccessorsRegistry;
+
+/**
+ * Filters the extension property section.
+ *
+ * @author ymortier
+ */
+public class ExtendedPropertyFilter extends AbstractPropertyFilter {
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.properties.filter.AbstractPropertyFilter#select(java.lang.Object)
+ */
+ @Override
+ public boolean select(final Object toTest) {
+ final boolean select = super.select(toTest);
+ boolean areAnnotation = false;
+ ModelAccessorsRegistry modelAccessorRegistry = SiriusPlugin.getDefault().getModelAccessorRegistry();
+ final Iterator<EObject> iterSemantics = this.semanticElements.iterator();
+ while (iterSemantics.hasNext() && !areAnnotation) {
+ final EObject next = iterSemantics.next();
+ ModelAccessor modelAccessor = modelAccessorRegistry.getModelAccessor(next);
+ if (modelAccessor.hasExtension(next)) {
+ areAnnotation = true;
+ } else if (modelAccessor.isExtension(next)) {
+ areAnnotation = true;
+ }
+
+ }
+ return select && areAnnotation;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/filter/SemanticExtensionPropertyFilter.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/filter/SemanticExtensionPropertyFilter.java
new file mode 100644
index 0000000000..b2c2fa6fe0
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/filter/SemanticExtensionPropertyFilter.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.properties.filter;
+
+import org.eclipse.sirius.diagram.ui.tools.api.properties.filter.AbstractPropertyFilter;
+
+/**
+ * Filters the Extension property section. Shows the section only if the
+ * semantic element has extended properties.
+ *
+ * @author ymortier
+ */
+public class SemanticExtensionPropertyFilter extends AbstractPropertyFilter {
+
+ private SemanticPropertyFilter semanticPropertyFilter = new SemanticPropertyFilter();
+
+ private ExtendedPropertyFilter extendedPropertyFilter = new ExtendedPropertyFilter();
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.properties.filter.AbstractPropertyFilter#select(java.lang.Object)
+ */
+ @Override
+ public boolean select(final Object toTest) {
+ return super.select(toTest) && semanticPropertyFilter.select(toTest) && extendedPropertyFilter.select(toTest);
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/filter/SemanticPropertyFilter.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/filter/SemanticPropertyFilter.java
new file mode 100644
index 0000000000..2963af0345
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/filter/SemanticPropertyFilter.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.properties.filter;
+
+import java.util.Iterator;
+
+import org.eclipse.emf.ecore.EObject;
+
+import org.eclipse.sirius.SiriusPlugin;
+import org.eclipse.sirius.diagram.ui.tools.api.properties.filter.AbstractPropertyFilter;
+import org.eclipse.sirius.ecore.extender.business.api.accessor.ModelAccessor;
+import org.eclipse.sirius.ecore.extender.business.api.accessor.ModelAccessorsRegistry;
+
+/**
+ * Filters for semantic elements.
+ *
+ * @author ymortier
+ */
+public class SemanticPropertyFilter extends AbstractPropertyFilter {
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.properties.filter.AbstractPropertyFilter#select(java.lang.Object)
+ */
+ @Override
+ public boolean select(final Object toTest) {
+ final boolean select = super.select(toTest);
+ boolean areAnnotation = true;
+ ModelAccessorsRegistry modelAccessorRegistry = SiriusPlugin.getDefault().getModelAccessorRegistry();
+ final Iterator<EObject> iterSemantics = this.semanticElements.iterator();
+ while (iterSemantics.hasNext() && areAnnotation) {
+ final EObject next = iterSemantics.next();
+ ModelAccessor modelAccessor = modelAccessorRegistry.getModelAccessor(next);
+ if (!modelAccessor.isExtension(next)) {
+ areAnnotation = false;
+ }
+ }
+ return select && !areAnnotation;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/filter/StylePropertyFilter.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/filter/StylePropertyFilter.java
new file mode 100644
index 0000000000..48a507bf11
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/properties/filter/StylePropertyFilter.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.properties.filter;
+
+import org.eclipse.sirius.DStylizable;
+import org.eclipse.sirius.diagram.ui.tools.api.properties.filter.AbstractPropertyFilter;
+
+/**
+ * Filter for the style section.
+ *
+ * @author ymortier
+ */
+public class StylePropertyFilter extends AbstractPropertyFilter {
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.ui.tools.api.properties.filter.AbstractPropertyFilter#select(java.lang.Object)
+ */
+ @Override
+ public boolean select(final Object toTest) {
+ return super.select(toTest) && this.viewPointElement instanceof DStylizable;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/routers/BracketConnectionRouter.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/routers/BracketConnectionRouter.java
new file mode 100644
index 0000000000..fd3df8be50
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/routers/BracketConnectionRouter.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2012 Obeo. All Rights Reserved.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ ****************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.routers;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.draw2d.AbstractRouter;
+import org.eclipse.draw2d.Connection;
+import org.eclipse.draw2d.geometry.PointList;
+
+import org.eclipse.sirius.diagram.business.internal.bracket.BracketConnectionQuery;
+
+/**
+ * Routes Connections directly from the source anchor to the target anchor with
+ * some bendpoints inside. Adapts bendpoints location from orientation and
+ * offset.
+ *
+ * @author <a href="mailto:esteban.dugueperoux@obeo.fr">Esteban Dugueperoux</a>
+ */
+public class BracketConnectionRouter extends AbstractRouter {
+
+ /** The figure constraints for each {@link Connection}. */
+ private Map<Connection, Object> constraints = new HashMap<Connection, Object>();
+
+ /** A common {@link BracketConnectionQuery} to the source and target anchor. */
+ private BracketConnectionQuery bracketConnectionQuery;
+
+ /**
+ * Constructs a new DimensionConnectionRouter.
+ *
+ * @param bracketConnectionQuery
+ * {@link BracketConnectionQuery}
+ */
+ public BracketConnectionRouter(BracketConnectionQuery bracketConnectionQuery) {
+ this.bracketConnectionQuery = bracketConnectionQuery;
+ }
+
+ /**
+ * Sets the constraint for the given {@link Connection}.
+ *
+ * @param connection
+ * The connection whose constraint we are setting
+ * @param constraint
+ * The constraint
+ */
+ public void setConstraint(Connection connection, Object constraint) {
+ constraints.put(connection, constraint);
+ }
+
+ /**
+ * Gets the constraint for the given {@link Connection}.
+ *
+ * @param connection
+ * The connection whose constraint we are retrieving
+ * @return The constraint
+ */
+ public Object getConstraint(Connection connection) {
+ return constraints.get(connection);
+ }
+
+ /**
+ * Removes the given connection from the map of constraints.
+ *
+ * @param connection
+ * The connection to remove
+ */
+ public void remove(Connection connection) {
+ constraints.remove(connection);
+ }
+
+ /**
+ * Routes the given Connection directly between the source and target
+ * anchors.
+ *
+ * @param connection
+ * the {@link Connection} to be routed
+ */
+ public void route(Connection connection) {
+ final PointList newPointList = bracketConnectionQuery.getPointListFromConstraint();
+ connection.setPoints(newPointList);
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/routers/DBranchRouter.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/routers/DBranchRouter.java
new file mode 100644
index 0000000000..b661321a55
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/routers/DBranchRouter.java
@@ -0,0 +1,204 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2010 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Obeo - some corrections
+ ****************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.routers;
+
+import org.eclipse.draw2d.AbstractRouter;
+import org.eclipse.draw2d.Connection;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.PointList;
+import org.eclipse.gmf.runtime.draw2d.ui.geometry.LineSeg;
+import org.eclipse.gmf.runtime.draw2d.ui.internal.routers.OrthogonalRouterUtilities;
+
+/**
+ * Specific AIR Tree Router to correct some anomalies from the GMF one.
+ *
+ * (original author is sshaw)
+ *
+ * @author ymortier
+ */
+public class DBranchRouter extends AbstractRouter {
+
+ private final DTreeRouter tree;
+
+ /**
+ * Creates a new branch router.
+ *
+ * @param tree
+ * the tree router.
+ */
+ public DBranchRouter(final DTreeRouter tree) {
+ super();
+ this.tree = tree;
+ }
+
+ /**
+ * bla.
+ *
+ * @see org.eclipse.draw2d.ConnectionRouter#route(org.eclipse.draw2d.Connection)
+ *
+ * case 1: connection has never been routed before and needs points to
+ * be populated. points.size() < 4
+ *
+ * case 2: user moved the trunk vertex of the connection by either
+ * moving the line attached to the target or second last target line
+ *
+ * case 3: user moved the source or target shape causing a layout of
+ * the connection.
+ *
+ * case 4: user moved the source line attached to the source shape.
+ *
+ * case 5: connection is being rerouted as a result of an invalidation
+ * from case 2.
+ *
+ * @param conn
+ * the connection.
+ *
+ */
+ public void route(final Connection conn) {
+ internalRoute(conn);
+ }
+
+ /**
+ * @param conn
+ */
+ private void internalRoute(final Connection conn) {
+ final Point ptTrunkLoc = getTrunkLocation(conn);
+
+ getTree().setTrunkLocation(conn, ptTrunkLoc);
+
+ final Point ptSourceLoc = getSourceLocation(conn, ptTrunkLoc);
+
+ final PointList points = recreateBranch(conn, ptSourceLoc, ptTrunkLoc);
+ conn.setPoints(points);
+ }
+
+ /**
+ * getTrunkLocation Method to retrieve the trunk location in relative
+ * coordinates.
+ *
+ * @param conn
+ * Connection being routed
+ * @return Point that is the trunk location in relative coordinates.
+ */
+ protected Point getTrunkLocation(final Connection conn) {
+
+ final PointList points = getTree().getPointsFromConstraint(conn);
+ final Point ptTrunkLoc = getTree().getTrunkLocation(conn); // default;
+
+ // check valid again based on constraint
+ if (getTree().isTreeBranch(conn, points)) {
+ if (getTree().isTopDown(conn)) {
+ ptTrunkLoc.x = points.getPoint(3).x;
+ } else {
+ ptTrunkLoc.y = points.getPoint(3).y;
+ }
+
+ if (getTree().isOrthogonalTreeBranch(conn, points)) {
+ if (getTree().isTopDown(conn)) {
+ ptTrunkLoc.y = points.getPoint(2).y;
+ } else {
+ ptTrunkLoc.x = points.getPoint(2).x;
+ }
+ }
+ }
+
+ return ptTrunkLoc;
+ }
+
+ /**
+ * getSourceLocation Method to retrieve the source location where the
+ * connection is connected to the source element.
+ *
+ * @param conn
+ * Connection to be routed.
+ * @param ptTrunkLoc
+ * Point trunk location in relative coordinates
+ * @return Point source location in relative coordinates
+ */
+ public Point getSourceLocation(final Connection conn, final Point ptTrunkLoc) {
+
+ /* source reference is in absolute */
+ final Point ptSourceRef = conn.getSourceAnchor().getReferencePoint();
+
+ /* get trunk location in absolute */
+ Point absoluteTrunkLocation = ptTrunkLoc.getCopy();
+ conn.translateToAbsolute(absoluteTrunkLocation);
+
+ final boolean bTopDown = getTree().isTopDown(conn);
+
+ /* branch offset is in absolute */
+ final int branchOffset = bTopDown ? ptSourceRef.x : ptSourceRef.y;
+
+ Point ref;
+
+ if (bTopDown) {
+ ref = new Point(branchOffset, absoluteTrunkLocation.y);
+ } else {
+ ref = new Point(absoluteTrunkLocation.x, branchOffset);
+ }
+
+ /*
+ * the reference point should be in relative for
+ * getOrthogonalLineSegToAnchorLoc method
+ */
+ conn.translateToRelative(ref);
+
+ final LineSeg line = OrthogonalRouterUtilities.getOrthogonalLineSegToAnchorLoc(conn, conn.getSourceAnchor(), ref);
+ return line.getOrigin();
+ }
+
+ /**
+ * recreateBranch Utility method used to recreate the points list for the
+ * branch connection given a trunk vertex location and a source attachpoint
+ * location.
+ *
+ * @param conn
+ * Connection used to do translate points to relative
+ * coordinates.
+ * @param ptSourceLoc
+ * Point that is attached to the source node
+ * @param ptTrunkLoc
+ * Point that is the vertex between the line attached to the
+ * target and the "shoulder" line that holds the individual
+ * source branches.
+ * @return PointList that represents the full connection tree branch.
+ */
+ public PointList recreateBranch(final Connection conn, final Point ptSourceLoc, final Point ptTrunkLoc) {
+ final PointList points = new PointList(4);
+ final boolean bTopDown = getTree().isTopDown(conn);
+
+ points.addPoint(new Point(ptSourceLoc));
+
+ final Point pt2 = bTopDown ? new Point(ptSourceLoc.x, ptTrunkLoc.y) : new Point(ptTrunkLoc.x, ptSourceLoc.y);
+ points.addPoint(pt2);
+
+ points.addPoint(new Point(ptTrunkLoc));
+
+ final LineSeg line = OrthogonalRouterUtilities.getOrthogonalLineSegToAnchorLoc(conn, conn.getTargetAnchor(), ptTrunkLoc);
+ final Point ptTargetLoc = line.getOrigin();
+
+ final Point pt4 = bTopDown ? new Point(ptTrunkLoc.x, ptTargetLoc.y) : new Point(ptTargetLoc.x, ptTrunkLoc.y);
+ points.addPoint(pt4);
+
+ return points;
+ }
+
+ /**
+ * getTree Getter method for the container tree router.
+ *
+ * @return Returns the tree.
+ */
+ protected DTreeRouter getTree() {
+ return tree;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/routers/DForestRouter.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/routers/DForestRouter.java
new file mode 100644
index 0000000000..255f94c125
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/routers/DForestRouter.java
@@ -0,0 +1,336 @@
+/******************************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Obeo - adaptation
+ * Maxime Porhel (Obeo) <maxime.porhel@obeo.fr> - Trac bug #1524 : Layout issue after modification made in breakdown diagram.
+ ****************************************************************************/
+
+package org.eclipse.sirius.diagram.ui.tools.internal.routers;
+
+import java.util.HashMap;
+
+import org.eclipse.draw2d.BendpointConnectionRouter;
+import org.eclipse.draw2d.Connection;
+import org.eclipse.draw2d.ConnectionAnchor;
+import org.eclipse.draw2d.ConnectionRouter;
+import org.eclipse.draw2d.FreeformViewport;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.PointList;
+import org.eclipse.draw2d.geometry.PrecisionPoint;
+import org.eclipse.gmf.runtime.draw2d.ui.internal.routers.ITreeConnection;
+import org.eclipse.gmf.runtime.draw2d.ui.internal.routers.OrthogonalRouter;
+
+/**
+ * A router for Sirius .
+ *
+ * @author ymortier
+ */
+public class DForestRouter extends BendpointConnectionRouter implements OrthogonalRouter {
+
+ private final HashMap connections = new HashMap();
+
+ private final HashMap trunkVertexes = new HashMap();
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.BendpointConnectionRouter#remove(org.eclipse.draw2d.Connection)
+ */
+ @Override
+ public void remove(final Connection conn) {
+ if (conn.getSourceAnchor() == null || conn.getTargetAnchor() == null) {
+ return;
+ }
+
+ final ConnectionRouter connectionRouter = getSubRouter(conn);
+ if (connectionRouter != null) {
+ connectionRouter.remove(conn);
+ }
+
+ super.remove(conn);
+ }
+
+ /**
+ * Utility method to retrieve the sub router that manages the individual
+ * trees.
+ *
+ * @param conn
+ * <code>Connection</code> to be routered
+ * @return <code>TreeRouter</code> that will end up routing the given
+ * <code>Connection</code>.
+ */
+ public DTreeRouter getSubRouter(final Connection conn) {
+ if (conn.getTargetAnchor() == null) {
+ return null;
+ }
+
+ String hint = "base"; //$NON-NLS-1$
+ if (conn instanceof ITreeConnection) {
+ hint = ((ITreeConnection) conn).getHint();
+ }
+
+ final AnchorKey connectionKey = new AnchorKey(conn.getTargetAnchor(), hint);
+ DTreeRouter connectionRouter = (DTreeRouter) connections.get(connectionKey);
+ if (connectionRouter == null) {
+ DTreeRouter oldConnectionRouter = null;
+ if (!"base".equals(hint)) {
+ // Search only with hint (if the targetAnchor has been moved but
+ // the target is the same)
+ oldConnectionRouter = getSubRouterWithHint(hint);
+ }
+ if (connectionRouter == null) {
+ connectionRouter = new DTreeRouter();
+ if (oldConnectionRouter != null) {
+ // Reuse the trunk location of the previous router to avoid
+ // to reset with the default trunk location
+ try {
+ connectionRouter.setTrunkLocation(conn, oldConnectionRouter.getTrunkLocation(conn));
+ } catch (NullPointerException e) {
+ // We are probably in reconnection, so the
+ // oldConnectionRouter has not already the connection in
+ // its list.
+ connectionRouter.setTrunkOrientation(oldConnectionRouter.getTrunkOrientation());
+ connectionRouter.setTrunkVertex(oldConnectionRouter.getTrunkVertex());
+ }
+ }
+ // remove connection of other routers after reconnectiontool
+ for (Object obj : connections.values()) {
+ if (obj instanceof DTreeRouter) {
+ ((DTreeRouter) obj).remove(conn);
+ }
+ }
+ }
+ connections.put(connectionKey, connectionRouter);
+ }
+
+ return connectionRouter;
+ }
+
+ /**
+ * Search the router only on the hint of the ITreeConnection (usefull for
+ * example if the targetAnchor has been moved on the same target node and we
+ * want to use the same router).
+ *
+ * @param hint
+ * The hint about the connection which determines which tree this
+ * connection will be contributed to
+ * @return <code>TreeRouter</code> that will end up routing the given
+ * <code>Connection</code>.
+ */
+ private DTreeRouter getSubRouterWithHint(String hint) {
+ for (Object obj : connections.keySet()) {
+ if (obj instanceof AnchorKey) {
+ if (hint.equals(((AnchorKey) obj).getQualifier())) {
+ return (DTreeRouter) connections.get(obj);
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.BendpointConnectionRouter#route(org.eclipse.draw2d.Connection)
+ */
+ @Override
+ public void route(final Connection conn) {
+ internalRoute(conn);
+ }
+
+ /**
+ * @param conn
+ */
+ private void internalRoute(final Connection conn) {
+ if (conn != null) {
+ if (conn.getTargetAnchor().getOwner() == null || conn.getSourceAnchor().getOwner() == null) {
+ final PointList points = conn.getPoints();
+ points.removeAllPoints();
+
+ final Point delta = getFreeformViewport(conn).getViewLocation();
+
+ final Point ref1 = conn.getTargetAnchor().getReferencePoint().getCopy();
+ // conn.getTargetAnchor().getOwner().translateToAbsolute(ref1);
+ final Point ref2 = conn.getSourceAnchor().getReferencePoint().getCopy();
+ // conn.getSourceAnchor().getOwner().translateToAbsolute(ref2);
+ final PrecisionPoint precisePt = new PrecisionPoint();
+
+ precisePt.setLocation(conn.getSourceAnchor().getLocation(ref1).getTranslated(delta));
+ points.addPoint(precisePt);
+
+ precisePt.setLocation(conn.getTargetAnchor().getLocation(ref2).getTranslated(delta));
+ points.addPoint(precisePt);
+ conn.setPoints(points);
+ return;
+ }
+
+ final DTreeRouter treeRouter = getSubRouter(conn);
+
+ if (treeRouter != null) {
+
+ // remove existing trunk vertex before routing occurs.
+ Dimension trunk = treeRouter.getTrunkVertex();
+ if (trunk != null) {
+ final AnchorKey trunkKey = new AnchorKey(conn.getTargetAnchor(), trunk);
+ trunkVertexes.remove(trunkKey);
+ }
+
+ treeRouter.route(conn);
+
+ trunk = treeRouter.getTrunkVertex();
+ final Dimension adjustedTrunk = accountForTrunkOverlap(trunk, conn);
+ if (!adjustedTrunk.equals(trunk)) {
+ treeRouter.setTrunkVertex(adjustedTrunk);
+ treeRouter.invalidate(conn);
+ }
+
+ }
+ }
+ }
+
+ /**
+ * Returns the {@link FreeformViewport} that owned this figure.
+ *
+ * @return the {@link FreeformViewport} that owned this figure.
+ */
+ private FreeformViewport getFreeformViewport(final IFigure figure) {
+ IFigure current = figure;
+ while (!(current instanceof FreeformViewport) && current != null) {
+ current = current.getParent();
+ }
+ return (FreeformViewport) current;
+ }
+
+ /**
+ * This method is copy/paste from
+ * org.eclipse.gmf.runtime.draw2d.ui.internal.routers.ForestRouter
+ *
+ * Makes sure the routed tree doesn't intersect with an existing tree in the
+ * "forest". This is called recursively for each trunk.
+ *
+ * @param trunk
+ * <code>Dimension</code> trunkVertex value to compare
+ * @param conn
+ * <code>Connection</code> that is connection currently being
+ * routed
+ * @return <code>Dimension</code> new trunk vertex value
+ */
+ private Dimension accountForTrunkOverlap(final Dimension trunk, final Connection conn) {
+ Dimension result = trunk;
+ if (conn.getTargetAnchor() != null && conn.getTargetAnchor().getOwner() == null) {
+
+ final AnchorKey trunkKey = new AnchorKey(conn.getTargetAnchor(), trunk);
+
+ // check if trunk vertex doesn't exist or if it exceeds a maximum
+ // then
+ // return.
+ int ownerExt = conn.getTargetAnchor().getOwner().getBounds().width / 2;
+ int trunkExt = trunk.width;
+
+ if (conn instanceof ITreeConnection) {
+ if (((ITreeConnection) conn).getOrientation() == ITreeConnection.Orientation.VERTICAL) {
+ ownerExt = conn.getTargetAnchor().getOwner().getBounds().height / 2;
+ trunkExt = trunk.height;
+ }
+ }
+
+ if (trunkVertexes.get(trunkKey) == null || Math.abs(trunkExt) > ownerExt) {
+ trunkVertexes.put(trunkKey, Boolean.TRUE);
+ result = trunk;
+ } else {
+ final Dimension newTrunk = new Dimension(trunk);
+ if (((ITreeConnection) conn).getOrientation() == ITreeConnection.Orientation.HORIZONTAL) {
+ newTrunk.expand(10, 0);
+ } else {
+ newTrunk.expand(0, 10);
+ }
+ result = accountForTrunkOverlap(newTrunk, conn);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * This class is copy/paste from
+ * org.eclipse.gmf.runtime.draw2d.ui.internal.routers.ForestRouter
+ *
+ * @author sshaw
+ */
+ private static class AnchorKey {
+
+ private final ConnectionAnchor anchor;
+
+ private final Object qualifier;
+
+ AnchorKey(final ConnectionAnchor anchor, final Object qualifier) {
+ this.anchor = anchor;
+ this.qualifier = qualifier;
+ }
+
+ @Override
+ public boolean equals(final Object object) {
+ boolean isEqual = false;
+ AnchorKey hashKey;
+
+ if (object instanceof AnchorKey) {
+ hashKey = (AnchorKey) object;
+ final ConnectionAnchor hkA1 = hashKey.getAnchor();
+ final Object hkA2 = hashKey.getQualifier();
+
+ isEqual = hkA1.equals(anchor) && hkA2.equals(qualifier);
+ }
+ return isEqual;
+ }
+
+ /**
+ * Accessor to retrieve the <code>ConnectionAnchor</code> that is stored
+ * as part of the key.
+ *
+ * @return the <code>ConnectionAnchor</code> that is used for the key.
+ */
+ public ConnectionAnchor getAnchor() {
+ return anchor;
+ }
+
+ /**
+ * Accessor to retrieve the qualifier object that is stored as part of
+ * the key.
+ *
+ * @return the <code>Object</code> that is designated the qualifier.
+ */
+ public Object getQualifier() {
+ return qualifier;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return anchor.hashCode() ^ qualifier.hashCode();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.AbstractRouter#invalidate(org.eclipse.draw2d.Connection)
+ */
+ @Override
+ public void invalidate(final Connection conn) {
+ if (conn != null && conn.getSourceAnchor() != null && conn.getTargetAnchor() != null) {
+ super.invalidate(conn);
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/routers/DTreeRouter.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/routers/DTreeRouter.java
new file mode 100644
index 0000000000..c256e33296
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/routers/DTreeRouter.java
@@ -0,0 +1,563 @@
+/******************************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Obeo - adaptation
+ * Maxime Porhel (Obeo) <maxime.porhel@obeo.fr> - Trac bug #1501 : Issues with tree routing style.
+ ****************************************************************************/
+
+package org.eclipse.sirius.diagram.ui.tools.internal.routers;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.eclipse.draw2d.AbsoluteBendpoint;
+import org.eclipse.draw2d.Bendpoint;
+import org.eclipse.draw2d.BendpointConnectionRouter;
+import org.eclipse.draw2d.Connection;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.PointList;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gmf.runtime.draw2d.ui.geometry.LineSeg;
+import org.eclipse.gmf.runtime.draw2d.ui.internal.routers.ITreeConnection;
+import org.eclipse.gmf.runtime.draw2d.ui.internal.routers.OrthogonalRouter;
+import org.eclipse.gmf.runtime.draw2d.ui.mapmode.MapModeUtil;
+
+import com.google.common.collect.Lists;
+
+/**
+ * The tree router of a forest router.
+ */
+public class DTreeRouter extends BendpointConnectionRouter implements OrthogonalRouter {
+
+ private static final int DEFAULT_TRUNK_HEIGHT = 16;
+
+ /** The branch router. */
+ private final DBranchRouter branchRouter = new DBranchRouter(this);
+
+ /** All connections. */
+ private final ArrayList connectionList = new ArrayList();
+
+ private Dimension trunkVertex;
+
+ private Orientation trunkOrientation;
+
+ private boolean updatingPeers;
+
+ /**
+ * Describes the orientation of the tree.
+ */
+ static final class Orientation {
+
+ /**
+ * Constant for the top orientation
+ */
+ public static final Orientation TOP = new Orientation();
+
+ /**
+ * Constant for the bottom orientation
+ */
+ public static final Orientation BOTTOM = new Orientation();
+
+ /**
+ * Constant for the right orientation
+ */
+ public static final Orientation RIGHT = new Orientation();
+
+ /**
+ * Constant for the left orientation
+ */
+ public static final Orientation LEFT = new Orientation();
+
+ private Orientation() {
+ // Empty constructor
+ }
+
+ /**
+ * getEdge Method to return the edge point of the given Rectangle
+ * representative of the orientation value of the instance.
+ *
+ * @param bounds
+ * Rectangle to retrieve the edge value from.
+ * @return Point that is the edge of the rectangle for the orientation
+ * of this.
+ */
+ public Point getEdge(final Rectangle bounds) {
+ Point result = bounds.getLeft();
+ if (this == TOP) {
+ result = bounds.getTop();
+ } else if (this == BOTTOM) {
+ result = bounds.getBottom();
+ } else if (this == RIGHT) {
+ result = bounds.getRight();
+ }
+ return result;
+ }
+
+ }
+
+ /**
+ * Create a new DTreeRouter.
+ */
+ public DTreeRouter() {
+ super();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.AbstractRouter#invalidate(org.eclipse.draw2d.Connection)
+ */
+ @Override
+ public void invalidate(final Connection conn) {
+ if (conn.getSourceAnchor() == null || conn.getSourceAnchor().getOwner() == null || conn.getTargetAnchor() == null || conn.getTargetAnchor().getOwner() == null) {
+ return;
+ }
+
+ final ListIterator li = Lists.newArrayList(connectionList).listIterator();
+ while (li.hasNext()) {
+ final Connection connNext = (Connection) li.next();
+
+ if (!trunkVertexEqual(connNext, conn)) {
+ updateConstraint(connNext);
+ }
+ }
+ }
+
+ private boolean trunkVertexEqual(final Connection connMaster, final Connection connSlave) {
+ final PointList cmPts = connMaster.getPoints();
+ final PointList csPts = connSlave.getPoints();
+ if (cmPts.size() > 2 && csPts.size() > 2) {
+ return cmPts.getPoint(2).equals(csPts.getPoint(2));
+ }
+
+ return false;
+ }
+
+ private Rectangle getTargetAnchorRelativeBounds(final Connection conn) {
+ final Rectangle bounds = conn.getTargetAnchor().getOwner().getBounds().getCopy();
+ conn.getTargetAnchor().getOwner().translateToAbsolute(bounds);
+ conn.translateToRelative(bounds);
+ return bounds;
+ }
+
+ private Rectangle getSourceAnchorRelativeBounds(final Connection conn) {
+ final Rectangle bounds = conn.getSourceAnchor().getOwner().getBounds().getCopy();
+ conn.getSourceAnchor().getOwner().translateToAbsolute(bounds);
+ conn.translateToRelative(bounds);
+ return bounds;
+ }
+
+ /**
+ * getTrunkLocation Method to retrieve the trunk location in relative
+ * coordinates based on current tree state.
+ *
+ * @param conn
+ * Connection being routed
+ * @return Point that is the trunk location in relative coordinates.
+ */
+ public Point getTrunkLocation(final Connection conn) {
+ final Dimension vertex = getTrunkVertex();
+ final Point target = getTrunkOrientation().getEdge(getTargetAnchorRelativeBounds(conn));
+ Point ptTrunkLoc = new Point(vertex.width, vertex.height);
+ ptTrunkLoc = ptTrunkLoc.getTranslated(target);
+ return ptTrunkLoc;
+ }
+
+ /**
+ * setTrunkLocation Setter method to set the trunk location. Translates the
+ * point into a relative point from the target edge.
+ *
+ * @param conn
+ * Connection being routed
+ * @param ptTrunkLoc
+ * Point that is the trunk location in relative coordinates.
+ */
+ public void setTrunkLocation(final Connection conn, final Point ptTrunkLoc) {
+ final Point ptRelTrunkLoc = new Point(ptTrunkLoc);
+
+ final Rectangle targetAnchorBounds = getTargetAnchorRelativeBounds(conn);
+
+ // update orientation
+ if (isTopDown(conn)) {
+ if (ptTrunkLoc.y < targetAnchorBounds.getCenter().y) {
+ setTrunkOrientation(Orientation.TOP);
+ } else {
+ setTrunkOrientation(Orientation.BOTTOM);
+ }
+ } else {
+ if (ptTrunkLoc.x < targetAnchorBounds.getCenter().x) {
+ setTrunkOrientation(Orientation.LEFT);
+ } else {
+ setTrunkOrientation(Orientation.RIGHT);
+ }
+ }
+
+ final Point target = getTrunkOrientation().getEdge(targetAnchorBounds);
+
+ final Dimension currentVertex = ptRelTrunkLoc.getDifference(target);
+ setTrunkVertex(currentVertex);
+ }
+
+ /**
+ * UpdateConstraint Updates the constraint value for the connection based on
+ * the tree vertex.
+ *
+ * @param conn
+ * Connection whose constraint is to be updated.
+ */
+ protected void updateConstraint(final Connection conn) {
+ boolean update = conn != null && conn.getSourceAnchor() != null && conn.getTargetAnchor() != null;
+ update = update && conn.getSourceAnchor().getOwner() != null && conn.getTargetAnchor().getOwner() != null;
+ if (update) {
+ if (isUpdatingPeers()) {
+ return;
+ }
+
+ List bendpoints = (List) conn.getRoutingConstraint();
+ if (bendpoints == null) {
+ bendpoints = new ArrayList(conn.getPoints().size());
+ }
+
+ final Point sourceRefPoint = conn.getSourceAnchor().getReferencePoint();
+ conn.translateToRelative(sourceRefPoint);
+
+ final Point targetRefPoint = conn.getTargetAnchor().getReferencePoint();
+ conn.translateToRelative(targetRefPoint);
+
+ final Point ptTrunk = getTrunkLocation(conn);
+ final Point ptSource = getBranchRouter().getSourceLocation(conn, ptTrunk);
+
+ bendpoints.clear();
+ final PointList pts = getBranchRouter().recreateBranch(conn, ptSource, ptTrunk);
+ for (int i = 0; i < pts.size(); i++) {
+ final Bendpoint bp = new AbsoluteBendpoint(pts.getPoint(i));
+ bendpoints.add(bp);
+ }
+
+ setUpdatingPeers(true);
+
+ try {
+ setConstraint(conn, bendpoints);
+ conn.invalidate();
+ conn.validate();
+ } finally {
+ setUpdatingPeers(false);
+ }
+ }
+ }
+
+ /**
+ * getPointsFromConstraint Utility method retrieve the PointList equivalent
+ * of the bendpoint constraint set in the Connection.
+ *
+ * @param conn
+ * Connection to retrieve the constraint from.
+ * @return PointList list of points that is the direct equivalent of the set
+ * constraint.
+ */
+ public PointList getPointsFromConstraint(final Connection conn) {
+ final List bendpoints = (List) conn.getRoutingConstraint();
+ if (bendpoints == null) {
+ return new PointList();
+ }
+
+ final PointList points = new PointList(bendpoints.size());
+ for (int i = 0; i < bendpoints.size(); i++) {
+ final Bendpoint bp = (Bendpoint) bendpoints.get(i);
+ points.addPoint(bp.getLocation());
+ }
+
+ DTreeRouter.straightenPoints(points, MapModeUtil.getMapMode(conn).DPtoLP(3));
+ return points;
+ }
+
+ /**
+ * straightenPoints This is a simpler version of the.
+ *
+ * @see updateIfNotRectilinear that simply ensures that the lines are
+ * horizontal or vertical without any intelligence in terms of shortest
+ * distance around a rectangle.
+ *
+ * @param newLine
+ * PointList to check for rectilinear qualities and change if
+ * necessary.
+ * @param tolerance
+ * int tolerance value by which points will be straightened in
+ * HiMetrics
+ */
+ protected static void straightenPoints(final PointList newLine, final int tolerance) {
+ for (int i = 0; i < newLine.size() - 1; i++) {
+ final Point ptCurrent = newLine.getPoint(i);
+ final Point ptNext = newLine.getPoint(i + 1);
+
+ final int xDelta = Math.abs(ptNext.x - ptCurrent.x);
+ final int yDelta = Math.abs(ptNext.y - ptCurrent.y);
+
+ if (xDelta < yDelta) {
+ if (xDelta > tolerance) {
+ return;
+ }
+ if (i == newLine.size() - 2) {
+ // The last point is more important than the other (not
+ // change the end of the line)
+ ptCurrent.x = ptNext.x;
+ } else {
+ ptNext.x = ptCurrent.x;
+ }
+ } else {
+ if (yDelta > tolerance) {
+ return;
+ }
+ if (i == newLine.size() - 2) {
+ // The last point is more important than the other (not
+ // change the end of the line)
+ ptCurrent.y = ptNext.y;
+ } else {
+ ptNext.y = ptCurrent.y;
+ }
+ }
+
+ newLine.setPoint(ptNext, i + 1);
+ }
+ }
+
+ /**
+ * Returns the branch router in the chain.
+ *
+ * @return The getBranchRouter router
+ *
+ */
+ protected DBranchRouter getBranchRouter() {
+ return branchRouter;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.BendpointConnectionRouter#remove(org.eclipse.draw2d.Connection)
+ */
+ @Override
+ public void remove(final Connection conn) {
+ if (conn.getSourceAnchor() == null || conn.getTargetAnchor() == null) {
+ return;
+ }
+
+ final int index = connectionList.indexOf(conn);
+ connectionList.remove(conn);
+ for (int i = index + 1; i < connectionList.size(); i++) {
+ ((Connection) connectionList.get(i)).revalidate();
+ }
+
+ getBranchRouter().remove(conn);
+ }
+
+ /**
+ * isTopDown Utility method to determine if the connection should routed in
+ * a top-down fashion or in a horizontal fashion.
+ *
+ * @param conn
+ * Connection to query
+ * @return boolean true if connection should be routed top-down, false
+ * otherwise.
+ */
+ public boolean isTopDown(final Connection conn) {
+ if (conn instanceof ITreeConnection) {
+ return ((ITreeConnection) conn).getOrientation().equals(ITreeConnection.Orientation.VERTICAL);
+ }
+ return true;
+ }
+
+ /**
+ * checkTrunkVertex Method to initialize the trunk vertex to a default value
+ * if not already set
+ *
+ * @param conn
+ * Connection to be routed.
+ */
+ private void checkTrunkVertex(final Connection conn) {
+ if (getTrunkVertex() == null) {
+ final Rectangle sourceRect = getSourceAnchorRelativeBounds(conn);
+ final Rectangle targetRect = getTargetAnchorRelativeBounds(conn);
+
+ final Dimension defaultTrunk = new Dimension(0, DEFAULT_TRUNK_HEIGHT);
+ conn.translateToRelative(defaultTrunk);
+
+ if (isTopDown(conn)) {
+ if (sourceRect.getCenter().y < targetRect.getCenter().y) {
+ setTrunkVertex(new Dimension(0, -defaultTrunk.height));
+ setTrunkOrientation(Orientation.TOP);
+ } else {
+ setTrunkVertex(new Dimension(0, defaultTrunk.height));
+ setTrunkOrientation(Orientation.BOTTOM);
+ }
+ } else {
+ if (sourceRect.getCenter().x < targetRect.getCenter().x) {
+ setTrunkVertex(new Dimension(-defaultTrunk.height, 0));
+ setTrunkOrientation(Orientation.LEFT);
+ } else {
+ setTrunkVertex(new Dimension(defaultTrunk.height, 0));
+ setTrunkOrientation(Orientation.RIGHT);
+ }
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.BendpointConnectionRouter#route(org.eclipse.draw2d.Connection)
+ */
+ @Override
+ public void route(final Connection conn) {
+ internalRoute(conn);
+ }
+
+ /**
+ * @param conn
+ */
+ private void internalRoute(final Connection conn) {
+ if (conn.getSourceAnchor() == null || conn.getSourceAnchor().getOwner() == null || conn.getTargetAnchor() == null || conn.getTargetAnchor().getOwner() == null) {
+ super.route(conn);
+ return;
+ }
+
+ if (!connectionList.contains(conn)) {
+ connectionList.add(conn);
+ }
+
+ checkTrunkVertex(conn);
+
+ getBranchRouter().route(conn);
+ invalidate(conn);
+ }
+
+ /**
+ * Returns the trunk vertex.
+ *
+ * @return Returns the truckVertex.
+ */
+ protected Dimension getTrunkVertex() {
+ return trunkVertex;
+ }
+
+ /**
+ * Sets the trunk vertex.
+ *
+ * @param trunkVertex
+ * The trunkVertex to set.
+ */
+ protected void setTrunkVertex(final Dimension trunkVertex) {
+ this.trunkVertex = trunkVertex;
+ }
+
+ /**
+ * Returns the trunk orientation.
+ *
+ * @return Returns the trunkOrientation.
+ */
+ protected Orientation getTrunkOrientation() {
+ return trunkOrientation;
+ }
+
+ /**
+ * Sets the trunk orientation.
+ *
+ * @param trunkOrientation
+ * The trunkOrientation to set.
+ */
+ protected void setTrunkOrientation(final Orientation trunkOrientation) {
+ this.trunkOrientation = trunkOrientation;
+ }
+
+ /**
+ * Utility method to determine if the given set of points conforms to the
+ * constraints of being an orthogonal connection tree-branch. 1. Points size
+ * must be 4. 2. Source point resides with-in boundary of source shape based
+ * on orientation 3. Target point resides with-in boundary of target shape
+ * based on orientation 4. Middle line is perpendicular to the 2 end lines.
+ *
+ * @param conn
+ * the <code>Connection</code> to test
+ * @param points
+ * <code>PointList</code> to test constraints against
+ * @return <code>boolean</code> <code>true</code> if points represent valid
+ * orthogaonl tree branch, <code>false</code> otherwise.
+ */
+ public boolean isOrthogonalTreeBranch(final Connection conn, final PointList points) {
+ boolean result = false;
+ if (isTreeBranch(conn, points)) {
+ final LineSeg branch = new LineSeg(points.getPoint(0), points.getPoint(1));
+ final LineSeg trunkShoulder = new LineSeg(points.getPoint(1), points.getPoint(2));
+ final LineSeg trunk = new LineSeg(points.getPoint(2), points.getPoint(3));
+
+ if (isTopDown(conn)) {
+ result = branch.isVertical() && trunkShoulder.isHorizontal() && trunk.isVertical();
+ } else {
+ result = branch.isHorizontal() && trunkShoulder.isVertical() && trunk.isHorizontal();
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Utility method to determine if the given set of points conforms to the
+ * constraints of being a connection tree-branch. 1. Points size must be 4.
+ * 2. Source point resides with-in boundary of source shape based on
+ * orientation 3. Target point resides with-in boundary of target shape
+ * based on orientation
+ *
+ * @param conn
+ * the <code>Connection</code> to test
+ * @param points
+ * the <code>PointList</code> to test constraints against
+ * @return <code>boolean</code> <code>true</code> if points represent valid
+ * tree branch, <code>false</code> otherwise.
+ */
+ public boolean isTreeBranch(final Connection conn, final PointList points) {
+ boolean result = false;
+ if (points.size() == 4) {
+ // just check if ends are with-in the owner bounding box
+ final Rectangle targetBounds = getTargetAnchorRelativeBounds(conn);
+ final Rectangle sourceBounds = getSourceAnchorRelativeBounds(conn);
+
+ if (isTopDown(conn)) {
+ result = (points.getPoint(0).x > sourceBounds.x && points.getPoint(0).x < sourceBounds.x + sourceBounds.width)
+ && (points.getPoint(3).x > targetBounds.x && points.getPoint(3).x < targetBounds.x + targetBounds.width);
+ } else {
+ result = (points.getPoint(0).y > sourceBounds.y && points.getPoint(0).y < sourceBounds.y + sourceBounds.height)
+ && (points.getPoint(3).y > targetBounds.y && points.getPoint(3).y < targetBounds.y + targetBounds.height);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns the updating peers.
+ *
+ * @return Returns the updatingPeers.
+ */
+ protected boolean isUpdatingPeers() {
+ return updatingPeers;
+ }
+
+ /**
+ * Set the updating peers.
+ *
+ * @param updatingPeers
+ * The updatingPeers to set.
+ */
+ protected void setUpdatingPeers(final boolean updatingPeers) {
+ this.updatingPeers = updatingPeers;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/routers/SiriusBendpointConnectionRouter.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/routers/SiriusBendpointConnectionRouter.java
new file mode 100644
index 0000000000..eeb9f39d0b
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/routers/SiriusBendpointConnectionRouter.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.routers;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.draw2d.Bendpoint;
+import org.eclipse.draw2d.BendpointConnectionRouter;
+import org.eclipse.draw2d.Connection;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.PointList;
+import org.eclipse.draw2d.geometry.PrecisionPoint;
+
+/**
+ * This class override the default BendpointConnectionRouter to avoid the
+ * duplication of the start and the end point of the figure. <BR>
+ * It seems that the default BendpointConnectionRouter waiting a constraint
+ * without the start and the end point. But the GMF
+ * ConnectionEditPart.refreshBendpoint set a constraint with the start and the
+ * end point.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ *
+ */
+public class SiriusBendpointConnectionRouter extends BendpointConnectionRouter {
+ private static final PrecisionPoint A_POINT = new PrecisionPoint();
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.draw2d.BendpointConnectionRouter#route(org.eclipse.draw2d.Connection)
+ */
+ @Override
+ public void route(Connection conn) {
+ PointList points = conn.getPoints();
+ points.removeAllPoints();
+
+ List bendpoints = (List) getConstraint(conn);
+ if (bendpoints == null) {
+ bendpoints = Collections.EMPTY_LIST;
+ }
+
+ Point ref1;
+ Point ref2;
+
+ if (bendpoints.isEmpty()) {
+ ref1 = conn.getTargetAnchor().getReferencePoint();
+ ref2 = conn.getSourceAnchor().getReferencePoint();
+ } else if (bendpoints.size() >= 3) {
+ // Take the point just after the start point
+ ref1 = new Point(((Bendpoint) bendpoints.get(1)).getLocation());
+ conn.translateToAbsolute(ref1);
+ // Take the point just before the end point
+ ref2 = new Point(((Bendpoint) bendpoints.get(bendpoints.size() - 2)).getLocation());
+ conn.translateToAbsolute(ref2);
+ } else {
+ ref1 = new Point(((Bendpoint) bendpoints.get(0)).getLocation());
+ conn.translateToAbsolute(ref1);
+ ref2 = new Point(((Bendpoint) bendpoints.get(bendpoints.size() - 1)).getLocation());
+ conn.translateToAbsolute(ref2);
+ }
+
+ A_POINT.setLocation(conn.getSourceAnchor().getLocation(ref1));
+ conn.translateToRelative(A_POINT);
+ points.addPoint(A_POINT);
+
+ if (bendpoints.size() > 2) {
+ for (int i = 1; i < bendpoints.size() - 1; i++) {
+ Bendpoint bp = (Bendpoint) bendpoints.get(i);
+ points.addPoint(bp.getLocation());
+ }
+ }
+
+ A_POINT.setLocation(conn.getTargetAnchor().getLocation(ref2));
+ conn.translateToRelative(A_POINT);
+ points.addPoint(A_POINT);
+ conn.setPoints(points);
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/util/EditPartQuery.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/util/EditPartQuery.java
new file mode 100644
index 0000000000..e225ab57ac
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/util/EditPartQuery.java
@@ -0,0 +1,236 @@
+/*******************************************************************************
+ * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.util;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.PositionConstants;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IBorderItemEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IBorderedShapeEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.gef.ui.figures.NodeFigure;
+import org.eclipse.gmf.runtime.notation.Bounds;
+import org.eclipse.gmf.runtime.notation.Node;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+import org.eclipse.sirius.diagram.tools.api.graphical.edit.styles.IBorderItemOffsets;
+
+/**
+ * Queries on GMF edit parts.
+ * <p>
+ * The class is named <code>EditPartQuery</code> instead of the longer but more
+ * accurate <code>IGraphicalEditPartQuery</code> only to avoid an overly long
+ * and cumbersome name.
+ *
+ * @author pcdavid
+ */
+public class EditPartQuery {
+ private final IGraphicalEditPart part;
+
+ /**
+ * Constructor.
+ *
+ * @param part
+ * the graphical edit part to query.
+ */
+ public EditPartQuery(IGraphicalEditPart part) {
+ this.part = Preconditions.checkNotNull(part);
+ }
+
+ /**
+ * Returns the first ancestor (in the hierarchy of edit parts) of this part
+ * which is of the specified type.
+ *
+ * @param <T>
+ * the type.
+ * @param type
+ * the type of the ancestor to look for.
+ * @return the closest ancestor of the specified part which is compatible
+ * with <code>type</code>, or <code>null</code> if there is none.
+ */
+ public <T> T getFirstAncestorOfType(Class<T> type) {
+ if (part == null) {
+ return null;
+ }
+ EditPart current = part.getParent();
+ while (current != null && !type.isInstance(current)) {
+ current = current.getParent();
+ }
+ return type.cast(current);
+ }
+
+ /**
+ * Returns all ancestors (in the hierarchy of edit parts) of this part which
+ * are of the specified type.
+ *
+ * @param <T>
+ * the type.
+ * @param type
+ * the type of the ancestor to look for.
+ * @return all the ancestors of this part which are compatible with
+ * <code>type</code> from the closest to the farthest.
+ */
+ public <T> List<T> getAllAncestorsOfType(Class<T> type) {
+ if (part == null) {
+ return null;
+ }
+ ArrayList<T> result = Lists.newArrayList();
+ EditPart current = part.getParent();
+ while (current != null) {
+ if (type.isInstance(current)) {
+ result.add(type.cast(current));
+ }
+ current = current.getParent();
+ }
+ return result;
+ }
+
+ /**
+ * Return the list of Node corresponding to the BorderItemEditPart that is
+ * on the expected side.
+ *
+ * @param expectedSide
+ * The side ({@link org.eclipse.draw2d.PositionConstants}) where
+ * the children must be
+ * @return the list of Node corresponding to the BorderItemEditPart that is
+ * on the expected side.
+ */
+ public List<Node> getBorderedNodes(final int expectedSide) {
+ List<Node> result = new ArrayList<Node>();
+ if (part instanceof IBorderedShapeEditPart) {
+ Iterable<IBorderItemEditPart> bordersItemPart = (Iterable<IBorderItemEditPart>) Iterables.filter(part.getChildren(),
+ Predicates.and(Predicates.instanceOf(IBorderItemEditPart.class), new Predicate<IBorderItemEditPart>() {
+ public boolean apply(IBorderItemEditPart input) {
+ int currentSide = input.getBorderItemLocator().getCurrentSideOfParent();
+ return expectedSide == currentSide;
+ }
+ }));
+ for (IBorderItemEditPart borderItemEditPart : bordersItemPart) {
+ result.add((Node) borderItemEditPart.getModel());
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Return a Map with a move delta for each nodes that must be moved
+ * following the resize of the parent.
+ *
+ * @param expectedSide
+ * the side on which the border item appears as defined in
+ * {@link PositionConstants}. Possible values are
+ * <ul>
+ * <li>{@link org.eclipse.draw2d.PositionConstants#EAST}, if
+ * parent is resized from North or South</li>
+ * <li>{@link org.eclipse.draw2d.PositionConstants#WEST}, if
+ * parent is resized from North or South</li>
+ * <li>{@link org.eclipse.draw2d.PositionConstants#NORTH}, if
+ * parent is resized from East or West</li>
+ * <li>{@link org.eclipse.draw2d.PositionConstants#SOUTH}, if
+ * parent is resized from East or West</li>
+ * </ul>
+ * @param parentResizeSize
+ * the resize size of the parent
+ * @return A Map with a move delta for each nodes that must be moved
+ */
+ public Map<Node, Integer> getBorderedNodesToMoveWithDelta(int expectedSide, int parentResizeSize) {
+ Map<Node, Integer> result = new HashMap<Node, Integer>();
+ if (part instanceof IBorderedShapeEditPart) {
+ // calculate the parent bounds with consideration for the handle
+ // bounds inset.
+ IFigure parentFigure = ((IBorderedShapeEditPart) part).getMainFigure();
+ Rectangle parentBounds = parentFigure.getBounds();
+ if (parentFigure instanceof NodeFigure) {
+ parentBounds = ((NodeFigure) parentFigure).getHandleBounds().getCopy();
+ }
+
+ List<Node> expectedSideNodes = getBorderedNodes(expectedSide);
+ if (parentResizeSize < 0) {
+ // The container is reduced
+ if (expectedSide == PositionConstants.EAST || expectedSide == PositionConstants.WEST) {
+ // If the parent is reduced from the north (or from the
+ // south and the new height is too small, the bordered node
+ // must be moved to be near the bottom of parent.
+ result = getBorderedNodesToMoveVerticallyWithDelta(expectedSideNodes, parentBounds, parentResizeSize);
+ } else if (expectedSide == PositionConstants.NORTH || expectedSide == PositionConstants.SOUTH) {
+ // If the parent is reduced from the east (or from the west
+ // and the new width is too small, the bordered node must be
+ // moved to be near the right of parent.
+ result = getBorderedNodesToMoveHorizontallyWithDelta(expectedSideNodes, parentBounds, parentResizeSize);
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @param nodes
+ * Nodes potentially concerned by this resize.
+ * @param parentBounds
+ * The available bounds to consider for the parent
+ * @param parentResizeSize
+ * the resize size of the parent
+ */
+ private Map<Node, Integer> getBorderedNodesToMoveVerticallyWithDelta(List<Node> nodes, Rectangle parentBounds, int parentResizeSize) {
+ Map<Node, Integer> result = new HashMap<Node, Integer>();
+ for (Node node : nodes) {
+ if (node.getLayoutConstraint() instanceof Bounds) {
+ Bounds borderedNodeBounds = (Bounds) node.getLayoutConstraint();
+ // Compute the distance between the bottom of the
+ // container and the bottom of the bordered node (we
+ // add the default_offset because it is used for
+ // our DBorderItemLocator).
+ int distanceFromBottom = parentBounds.height - IBorderItemOffsets.DEFAULT_OFFSET.height - (borderedNodeBounds.getY() + borderedNodeBounds.getHeight());
+ if (distanceFromBottom < -parentResizeSize) {
+ result.put(node, distanceFromBottom + parentResizeSize);
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @param nodes
+ * Nodes potentially concerned by this resize.
+ * @param parentBounds
+ * The available bounds to consider for the parent
+ * @param parentResizeSize
+ * the resize size of the parent
+ */
+ private Map<Node, Integer> getBorderedNodesToMoveHorizontallyWithDelta(List<Node> nodes, Rectangle parentBounds, int parentResizeSize) {
+ Map<Node, Integer> result = new HashMap<Node, Integer>();
+ for (Node node : nodes) {
+ if (node.getLayoutConstraint() instanceof Bounds) {
+ Bounds borderedNodeBounds = (Bounds) node.getLayoutConstraint();
+ // Compute the distance between the right of the
+ // container and the right of the bordered node (we
+ // add the default_offset because it is used for
+ // our DBorderItemLocator).
+ int distanceFromRight = parentBounds.width - IBorderItemOffsets.DEFAULT_OFFSET.height - (borderedNodeBounds.getX() + borderedNodeBounds.getWidth());
+ if (distanceFromRight < -parentResizeSize) {
+ result.put(node, distanceFromRight + parentResizeSize);
+ }
+ }
+ }
+ return result;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/outlineview/DiagramOutlineWithBookPages.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/outlineview/DiagramOutlineWithBookPages.java
new file mode 100644
index 0000000000..8db5d6eab2
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/outlineview/DiagramOutlineWithBookPages.java
@@ -0,0 +1,204 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.views.outlineview;
+
+import org.eclipse.gef.GraphicalViewer;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.part.PageBook;
+
+import org.eclipse.sirius.common.ui.tools.api.util.IObjectActionDelegateWrapper;
+import org.eclipse.sirius.common.ui.tools.api.util.SWTUtil;
+import org.eclipse.sirius.diagram.part.SiriusDiagramEditorPlugin;
+import org.eclipse.sirius.diagram.tools.internal.editor.DiagramOutlinePage;
+import org.eclipse.sirius.diagram.tools.internal.editor.DiagramOutlinePageListener;
+import org.eclipse.sirius.diagram.ui.tools.internal.views.providers.filters.FiltersTableViewer;
+import org.eclipse.sirius.diagram.ui.tools.internal.views.providers.layers.LayersTableViewer;
+import org.eclipse.sirius.diagram.ui.tools.internal.views.providers.outline.OutlineComparator;
+import org.eclipse.sirius.diagram.ui.tools.internal.views.providers.outline.OutlineContentProvider;
+import org.eclipse.sirius.diagram.ui.tools.internal.views.providers.outline.OutlineLabelProvider;
+
+/**
+ * A diagram outline page which has layer page, to hide or show layers, and a
+ * filter page to hide or show layers.
+ *
+ * @author mchauvin
+ */
+public class DiagramOutlineWithBookPages extends DiagramOutlinePage {
+
+ /** The id of the layers. 3 */
+ protected static final int ID_LAYERS = 3;
+
+ /** The id of the layers. 4 */
+ protected static final int ID_FILTERS = 4;
+
+ /** the layers tooltip text. */
+ private static final String LAYER_TIP_TEXT = "Layers";
+
+ /** the layers tooltip text. */
+ private static final String FILTER_TIP_TEXT = "Filters";
+
+ /** The layers icon descriptor. */
+ private static final ImageDescriptor DESC_LAYER = SiriusDiagramEditorPlugin.getBundledImageDescriptor("icons/layers.gif");
+
+ /** The filters icon descriptor. */
+ private static final ImageDescriptor DESC_FILTER = SiriusDiagramEditorPlugin.getBundledImageDescriptor("icons/filters.gif");
+
+ /** The show layers action */
+ private IAction showLayersAction;
+
+ /** The show layers action */
+ private IAction showFiltersAction;
+
+ /** The layers SWT control */
+ private Control layers;
+
+ /** The filters SWT control */
+ private Control filters;
+
+ /**
+ * Constructor.
+ *
+ * @param input
+ * the input for the outline tree viewer
+ * @param viewer
+ * the graphical viewer the graphical viewer reference
+ * @param menuContributions
+ * the popup menu contribution for the outline tree viewer
+ */
+ public DiagramOutlineWithBookPages(final Object input, final GraphicalViewer viewer, final IObjectActionDelegateWrapper[] menuContributions) {
+ super(input, new OutlineLabelProvider(), new OutlineContentProvider(), new OutlineComparator(), viewer, menuContributions);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.tools.internal.editor.DiagramOutlinePage#createControls(org.eclipse.ui.part.PageBook)
+ */
+ @Override
+ protected void createControls(final PageBook pb) {
+ super.createControls(pb);
+ layers = createLayersControl(pb);
+ filters = createFiltersControl(pb);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.tools.internal.editor.DiagramOutlinePage#configureControls(org.eclipse.jface.action.IToolBarManager)
+ */
+ @Override
+ protected void configureControls(final IToolBarManager tbm) {
+ super.configureControls(tbm);
+ configureLayers(tbm);
+ configureFilters(tbm);
+ }
+
+ private void configureLayers(final IToolBarManager tbm) {
+ showLayersAction = new Action() {
+ @Override
+ public void run() {
+ showPage(ID_LAYERS);
+ }
+ };
+ showLayersAction.setImageDescriptor(DESC_LAYER);
+ showLayersAction.setToolTipText(LAYER_TIP_TEXT);
+ tbm.add(showLayersAction);
+ }
+
+ private void configureFilters(final IToolBarManager tbm) {
+ showFiltersAction = new Action() {
+ @Override
+ public void run() {
+ showPage(ID_FILTERS);
+ }
+ };
+ showFiltersAction.setImageDescriptor(DESC_FILTER);
+ showFiltersAction.setToolTipText(FILTER_TIP_TEXT);
+ tbm.add(showFiltersAction);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.tools.internal.editor.DiagramOutlinePage#showPage(int)
+ */
+ @Override
+ protected void showPage(final int id) {
+ switch (id) {
+ case ID_FILTERS:
+ super.uncheckProvidedActions();
+ showLayersAction.setChecked(false);
+ showFiltersAction.setChecked(true);
+ super.showPage(filters);
+ break;
+ case ID_LAYERS:
+ super.uncheckProvidedActions();
+ showFiltersAction.setChecked(false);
+ showLayersAction.setChecked(true);
+ super.showPage(layers);
+ break;
+ default:
+ showLayersAction.setChecked(false);
+ showFiltersAction.setChecked(false);
+ super.showPage(id);
+ break;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.diagram.tools.internal.editor.DiagramOutlinePage#dispose()
+ */
+ @Override
+ public void dispose() {
+ if (contentProvider instanceof DiagramOutlinePageListener) {
+ this.removeListener((DiagramOutlinePageListener) contentProvider);
+ }
+ this.filters.dispose();
+ this.layers.dispose();
+ super.dispose();
+ }
+
+ /**
+ * Create the main control for layers.
+ *
+ * @param parent
+ * the parent
+ * @return the created control.
+ */
+ protected Control createLayersControl(final Composite parent) {
+
+ final Composite control = SWTUtil.createCompositeBothFill(parent, 1, false);
+ LayersTableViewer.createLayersTableViewer(control, this.diagramWorkbenchPart);
+ return control;
+ }
+
+ /**
+ * Create the main control for layers.
+ *
+ * @param parent
+ * the parent
+ * @return the created control.
+ */
+ protected Control createFiltersControl(final Composite parent) {
+
+ final Composite control = SWTUtil.createCompositeBothFill(parent, 1, false);
+ FiltersTableViewer.createFiltersTableViewer(control, this.diagramWorkbenchPart);
+ return control;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/filters/FiltersActivationAdapter.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/filters/FiltersActivationAdapter.java
new file mode 100644
index 0000000000..3845413a53
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/filters/FiltersActivationAdapter.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.views.providers.filters;
+
+import java.util.Collection;
+
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.common.notify.impl.AdapterImpl;
+import org.eclipse.jface.viewers.StructuredViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.ui.PlatformUI;
+
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.SiriusPackage;
+import org.eclipse.sirius.description.filter.FilterDescription;
+
+/**
+ * An adapter to listen layer activation change.
+ *
+ * @author mchauvin
+ */
+public class FiltersActivationAdapter extends AdapterImpl {
+
+ /** The structured viewer to update. */
+ private StructuredViewer viewer;
+
+ /**
+ * Set the viewer.
+ *
+ * @param viewer
+ * the viewer to update when the model change
+ */
+ public void setViewer(final Viewer viewer) {
+ if (viewer instanceof StructuredViewer) {
+ this.viewer = (StructuredViewer) viewer;
+ }
+ }
+
+ private void update(final DDiagram diagram, final FilterDescription filter, final boolean activate) {
+ PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ if (viewer != null) {
+ viewer.update(filter, null);
+ }
+ }
+ });
+ }
+
+ private void update(final DDiagram notifier, final Collection<FilterDescription> filters, final boolean b) {
+ PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ if (viewer != null && filters != null) {
+ for (FilterDescription filter : filters) {
+ viewer.update(filter, null);
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.emf.common.notify.impl.AdapterImpl#notifyChanged(org.eclipse.emf.common.notify.Notification)
+ */
+ @Override
+ public void notifyChanged(final Notification msg) {
+ final Object notifier = msg.getNotifier();
+ if (notifier instanceof DDiagram) {
+ final int featureID = msg.getFeatureID(DDiagram.class);
+ if (featureID == SiriusPackage.DDIAGRAM__ACTIVATED_FILTERS) {
+
+ switch (msg.getEventType()) {
+
+ case Notification.ADD:
+ final FilterDescription filterToAdd = (FilterDescription) msg.getNewValue();
+ update((DDiagram) notifier, filterToAdd, true);
+ break;
+ case Notification.ADD_MANY:
+ @SuppressWarnings("unchecked")
+ final Collection<FilterDescription> filtersToAdd = (Collection<FilterDescription>) msg.getNewValue();
+ update((DDiagram) notifier, filtersToAdd, true);
+ break;
+ case Notification.REMOVE:
+ final FilterDescription filterToRemove = (FilterDescription) msg.getOldValue();
+ update((DDiagram) notifier, filterToRemove, false);
+ break;
+ case Notification.REMOVE_MANY:
+ @SuppressWarnings("unchecked")
+ final Collection<FilterDescription> filtersToRemove = (Collection<FilterDescription>) msg.getOldValue();
+ update((DDiagram) notifier, filtersToRemove, false);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/filters/FiltersCellModifier.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/filters/FiltersCellModifier.java
new file mode 100644
index 0000000000..ba8411c6de
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/filters/FiltersCellModifier.java
@@ -0,0 +1,130 @@
+/*******************************************************************************
+ * Copyright (c) 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.views.providers.filters;
+
+import java.util.List;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gef.ui.palette.PaletteViewer;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.jface.viewers.ICellModifier;
+import org.eclipse.swt.widgets.Item;
+
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.description.filter.FilterDescription;
+import org.eclipse.sirius.diagram.tools.internal.handler.ChangeFilterActivation;
+
+/**
+ * The cell modifier.
+ *
+ * @author mchauvin
+ */
+public class FiltersCellModifier implements ICellModifier {
+ private final IDiagramWorkbenchPart diagramPart;
+
+ private final String[] filtersColumns;
+
+ /**
+ * Construct a new cell modifier.
+ *
+ * @param adapter
+ * the layer activation adapter
+ * @param part
+ * the workbench diagram part
+ * @param columns
+ * the layer table columns
+ */
+ public FiltersCellModifier(final FiltersActivationAdapter adapter, final IDiagramWorkbenchPart part, final String[] columns) {
+ diagramPart = part;
+ filtersColumns = columns;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.ICellModifier#canModify(java.lang.Object,
+ * java.lang.String)
+ */
+ public boolean canModify(final Object element, final String property) {
+
+ if (property.equals(filtersColumns[0])) {
+ /* first column */
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.ICellModifier#getValue(java.lang.Object,
+ * java.lang.String)
+ */
+ public Object getValue(final Object element, final String property) {
+
+ final FilterDescription filter = (FilterDescription) element;
+ Object result = null;
+
+ if (property.equals(filtersColumns[0])) {
+ /* first column */
+ final DiagramEditPart diaEditPart = diagramPart.getDiagramEditPart();
+ final Object obj = diaEditPart.getModel();
+ if (obj instanceof View) {
+ final EObject designerElement = ((View) obj).getElement();
+ if (designerElement instanceof DDiagram) {
+ final List<FilterDescription> activatedFilters = ((DDiagram) designerElement).getActivatedFilters();
+ if (activatedFilters.contains(element)) {
+ result = Boolean.TRUE;
+ } else {
+ result = Boolean.FALSE;
+ }
+ }
+ }
+ } else {
+ /* second column */
+ result = filter.getName();
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.ICellModifier#modify(java.lang.Object,
+ * java.lang.String, java.lang.Object)
+ */
+ public void modify(final Object element, final String property, final Object value) {
+ Object objElement;
+
+ if (element instanceof Item) {
+ objElement = ((Item) element).getData();
+ } else {
+ objElement = element;
+ }
+
+ final FilterDescription filterDescription = (FilterDescription) objElement;
+
+ if (property.equals(filtersColumns[0])) {
+ final DiagramEditPart diaEditPart = diagramPart.getDiagramEditPart();
+ final Object obj = diaEditPart.getModel();
+ if (obj instanceof View) {
+ final EObject designerElement = ((View) obj).getElement();
+ final PaletteViewer paletteViewer = diagramPart.getDiagramGraphicalViewer().getEditDomain().getPaletteViewer();
+ if (designerElement instanceof DDiagram && paletteViewer != null) {
+ final Runnable change = new ChangeFilterActivation(diagramPart, (DDiagram) designerElement, filterDescription, value.equals(Boolean.TRUE));
+ change.run();
+ }
+ }
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/filters/FiltersContentProvider.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/filters/FiltersContentProvider.java
new file mode 100644
index 0000000000..85fbf9c24a
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/filters/FiltersContentProvider.java
@@ -0,0 +1,120 @@
+/*******************************************************************************
+ * Copyright (c) 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.views.providers.filters;
+
+import java.util.Collections;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.description.DiagramDescription;
+
+/**
+ * The content provider.
+ *
+ * @author mchauvin
+ */
+public class FiltersContentProvider implements IStructuredContentProvider {
+
+ /** The EMF adapter */
+ private FiltersActivationAdapter filtersActivationAdapter;
+
+ /** The diagram workbench part */
+ private IDiagramWorkbenchPart diagramPart;
+
+ /**
+ * Create a new content providers to display layers.
+ *
+ * @param adapter
+ * the layer activation adapter
+ * @param part
+ * the part responsible of the diagram access
+ */
+ public FiltersContentProvider(final FiltersActivationAdapter adapter, final IDiagramWorkbenchPart part) {
+ filtersActivationAdapter = adapter;
+ diagramPart = part;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
+ */
+ public Object[] getElements(final Object inputElement) {
+ if (inputElement instanceof DiagramDescription) {
+ final DiagramDescription diagramDesc = (DiagramDescription) inputElement;
+ return diagramDesc.getFilters().toArray();
+ }
+ return Collections.EMPTY_LIST.toArray();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.IContentProvider#dispose()
+ */
+ public void dispose() {
+ if (diagramPart != null) {
+ final DiagramEditPart diaEditPart = diagramPart.getDiagramEditPart();
+ final Object obj = diaEditPart.getModel();
+ if (obj instanceof View) {
+ removeListenerFrom((View) obj);
+ }
+ diagramPart = null;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer,
+ * java.lang.Object, java.lang.Object)
+ */
+ public void inputChanged(final Viewer viewer, final Object oldInput, final Object newInput) {
+ if (oldInput != null) {
+ filtersActivationAdapter.setViewer(viewer);
+ final DiagramEditPart diaEditPart = diagramPart.getDiagramEditPart();
+ final Object obj = diaEditPart.getModel();
+ if (obj instanceof View) {
+ removeListenerFrom((View) obj);
+ }
+ }
+ if (newInput != null) {
+ filtersActivationAdapter.setViewer(viewer);
+ final DiagramEditPart diaEditPart = diagramPart.getDiagramEditPart();
+ final Object obj = diaEditPart.getModel();
+ if (obj instanceof View) {
+ addListenerTo((View) obj);
+ }
+ }
+ }
+
+ private void removeListenerFrom(final View oldInput) {
+ final EObject element = oldInput.getElement();
+ if (element instanceof DDiagram) {
+ final DDiagram diagram = (DDiagram) element;
+ diagram.eAdapters().remove(filtersActivationAdapter);
+ }
+ }
+
+ private void addListenerTo(final View newInput) {
+ final EObject element = newInput.getElement();
+ if (element instanceof DDiagram) {
+ final DDiagram diagram = (DDiagram) element;
+ diagram.eAdapters().add(filtersActivationAdapter);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/filters/FiltersLabelProvider.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/filters/FiltersLabelProvider.java
new file mode 100644
index 0000000000..daced55348
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/filters/FiltersLabelProvider.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.views.providers.filters;
+
+import java.util.List;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.swt.graphics.Image;
+
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.description.filter.FilterDescription;
+import org.eclipse.sirius.diagram.ImagesPath;
+import org.eclipse.sirius.diagram.part.SiriusDiagramEditorPlugin;
+
+/**
+ * The label provider.
+ *
+ * @author mchauvin
+ */
+public class FiltersLabelProvider extends LabelProvider implements ITableLabelProvider {
+
+ private IDiagramWorkbenchPart diagramPart;
+
+ /**
+ * Construct a new Layer label provider.
+ *
+ * @param part
+ * the part responsible of the diagram access.
+ */
+ public FiltersLabelProvider(final IDiagramWorkbenchPart part) {
+ diagramPart = part;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object,
+ * int)
+ */
+ public Image getColumnImage(final Object element, final int columnIndex) {
+ if (columnIndex == 0 && diagramPart != null) {
+
+ final DiagramEditPart diaEditPart = diagramPart.getDiagramEditPart();
+ final Object obj = diaEditPart.getModel();
+ if (obj instanceof View) {
+ final EObject designerElement = ((View) obj).getElement();
+ if (designerElement instanceof DDiagram) {
+ final List<FilterDescription> activatedFilters = ((DDiagram) designerElement).getActivatedFilters();
+ Image img = null;
+ if (activatedFilters.contains(element)) {
+ img = SiriusDiagramEditorPlugin.getInstance().getBundledImage(ImagesPath.ACTIVE_FILTER_ICON);
+ } else {
+ img = SiriusDiagramEditorPlugin.getInstance().getBundledImage(ImagesPath.INACTIVE_FILTER_ICON);
+ }
+ return img;
+ }
+ }
+
+ }
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object,
+ * int)
+ */
+ public String getColumnText(final Object element, final int columnIndex) {
+ switch (columnIndex) {
+ case 1:
+ if (element instanceof FilterDescription) {
+ return ((FilterDescription) element).getName();
+ }
+ break;
+ default:
+ break;
+ }
+ return null;
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.BaseLabelProvider#dispose()
+ */
+ @Override
+ public void dispose() {
+ super.dispose();
+ diagramPart = null;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/filters/FiltersTableViewer.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/filters/FiltersTableViewer.java
new file mode 100644
index 0000000000..cc366495e5
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/filters/FiltersTableViewer.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.views.providers.filters;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.CheckboxCellEditor;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.diagram.ImagesPath;
+import org.eclipse.sirius.diagram.part.SiriusDiagramEditorPlugin;
+
+/**
+ * Filters table viewer.
+ *
+ * @author mchauvin
+ */
+public final class FiltersTableViewer {
+
+ private static final String[] COLUMNS = { " ", "Filter" };
+
+ /**
+ * Avoid instantiation.
+ */
+ private FiltersTableViewer() {
+
+ }
+
+ /**
+ * Create a new Filters table viewer.
+ *
+ * @param control
+ * the parent composite
+ * @param workbenchPart
+ * the workbench part to access diagram part
+ * @return new viewer to enable or disable filters
+ */
+ public static TableViewer createFiltersTableViewer(final Composite control, final IDiagramWorkbenchPart workbenchPart) {
+
+ final TableViewer tableViewer = new TableViewer(control, SWT.BORDER | SWT.FULL_SELECTION);
+ final Table table = tableViewer.getTable();
+
+ table.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ TableColumn tc = new TableColumn(table, SWT.LEFT, 0);
+ tc.setText(COLUMNS[0]);
+ tc.setWidth(30);
+ tc.setImage(SiriusDiagramEditorPlugin.getInstance().getBundledImage(ImagesPath.FILTER_ACTIVATION_ICON));
+
+ tc = new TableColumn(table, SWT.LEFT, 1);
+ tc.setText(COLUMNS[1]);
+ tc.setWidth(200);
+
+ // Can only changes the first column - the visible column
+ final CellEditor[] editors = new CellEditor[2];
+ editors[0] = new CheckboxCellEditor(table);
+ for (int i = 1; i < 2; i++) {
+ editors[i] = null;
+ }
+
+ tableViewer.setColumnProperties(COLUMNS);
+
+ tableViewer.setCellEditors(editors);
+ final FiltersActivationAdapter adapter = new FiltersActivationAdapter();
+ tableViewer.setCellModifier(new FiltersCellModifier(adapter, workbenchPart, COLUMNS));
+ tableViewer.setContentProvider(new FiltersContentProvider(adapter, workbenchPart));
+ tableViewer.setLabelProvider(new FiltersLabelProvider(workbenchPart));
+
+ if (workbenchPart != null) {
+ final EObject eObj = workbenchPart.getDiagram().getElement();
+ if (eObj instanceof DDiagram) {
+ final DDiagram diagram = (DDiagram) eObj;
+ tableViewer.setInput(diagram.getDescription());
+ }
+ }
+
+ /* Lines are not visible in the specifications */
+ table.setLinesVisible(true);
+ table.setHeaderVisible(true);
+ return tableViewer;
+
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/layers/LayersActivationAdapter.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/layers/LayersActivationAdapter.java
new file mode 100644
index 0000000000..1628445032
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/layers/LayersActivationAdapter.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.views.providers.layers;
+
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.common.notify.impl.AdapterImpl;
+import org.eclipse.jface.viewers.StructuredViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.ui.PlatformUI;
+
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.SiriusPackage;
+import org.eclipse.sirius.description.Layer;
+import org.eclipse.sirius.diagram.tools.api.graphical.edit.palette.PaletteManager;
+
+/**
+ * An adapter to listen layer activation change.
+ *
+ * @author mchauvin
+ */
+public class LayersActivationAdapter extends AdapterImpl {
+
+ /** The structured viewer to update. */
+ private StructuredViewer viewer;
+
+ /** The palette manager to update. */
+ private PaletteManager paletteManager;
+
+ /**
+ * Set the viewer.
+ *
+ * @param viewer
+ * the viewer to update when the model change
+ */
+ public void setViewer(final Viewer viewer) {
+ if (viewer instanceof StructuredViewer) {
+ this.viewer = (StructuredViewer) viewer;
+ }
+ }
+
+ /**
+ * Set the palette manager.
+ *
+ * @param paletteManager
+ * the palette manager to update when the model change
+ */
+ public void setPaletteManager(final PaletteManager paletteManager) {
+ this.paletteManager = paletteManager;
+ }
+
+ private void update(final DDiagram diagram, final Layer layer, final boolean activate) {
+ PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ if (viewer != null) {
+ viewer.update(layer, null);
+ }
+
+ if (paletteManager != null) {
+ /* refresh the palette */
+ if (activate) {
+ paletteManager.showLayer(layer);
+ } else {
+ paletteManager.hideLayer(layer);
+ }
+ }
+
+ }
+ });
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.emf.common.notify.impl.AdapterImpl#notifyChanged(org.eclipse.emf.common.notify.Notification)
+ */
+ @Override
+ public void notifyChanged(final Notification msg) {
+ final Object notifier = msg.getNotifier();
+ if (notifier instanceof DDiagram) {
+ final int featureID = msg.getFeatureID(DDiagram.class);
+ if (featureID == SiriusPackage.DDIAGRAM__ACTIVATED_LAYERS) {
+
+ switch (msg.getEventType()) {
+
+ case Notification.ADD:
+ final Layer layerToAdd = (Layer) msg.getNewValue();
+ update((DDiagram) notifier, layerToAdd, true);
+ break;
+ case Notification.REMOVE:
+ final Layer layerToRemove = (Layer) msg.getOldValue();
+ update((DDiagram) notifier, layerToRemove, false);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/layers/LayersCellModifier.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/layers/LayersCellModifier.java
new file mode 100644
index 0000000000..ad6eceb0ca
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/layers/LayersCellModifier.java
@@ -0,0 +1,172 @@
+/*******************************************************************************
+ * Copyright (c) 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.views.providers.layers;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.List;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.emf.transaction.util.TransactionUtil;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.viewers.ICellModifier;
+import org.eclipse.swt.widgets.Item;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.progress.IProgressService;
+
+import org.eclipse.sirius.common.tools.api.util.EqualityHelper;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.business.api.query.IdentifiedElementQuery;
+import org.eclipse.sirius.description.Layer;
+import org.eclipse.sirius.diagram.tools.api.editor.DDiagramEditor;
+import org.eclipse.sirius.diagram.ui.tools.internal.commands.ChangeLayerActivationCommand;
+
+/**
+ * The cell modifier.
+ *
+ * @author mchauvin
+ */
+public class LayersCellModifier implements ICellModifier {
+
+ /** The EMF adapter */
+ private final LayersActivationAdapter layerActivationAdapter;
+
+ private final IDiagramWorkbenchPart diagramPart;
+
+ private final String[] layerColumns;
+
+ /**
+ * Construct a new cell modifier.
+ *
+ * @param adapter
+ * the layer activation adapter
+ * @param part
+ * the workbench diagram part
+ * @param columns
+ * the layer table columns
+ */
+ public LayersCellModifier(final LayersActivationAdapter adapter, final IDiagramWorkbenchPart part, final String[] columns) {
+ layerActivationAdapter = adapter;
+ diagramPart = part;
+ layerColumns = columns;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.ICellModifier#canModify(java.lang.Object,
+ * java.lang.String)
+ */
+ public boolean canModify(final Object element, final String property) {
+
+ if (property.equals(layerColumns[0])) {
+ /* first column */
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.ICellModifier#getValue(java.lang.Object,
+ * java.lang.String)
+ */
+ public Object getValue(final Object element, final String property) {
+
+ final Layer layer = (Layer) element;
+ Object result = null;
+
+ if (property.equals(layerColumns[0])) {
+ /* first column */
+ final DiagramEditPart diaEditPart = diagramPart.getDiagramEditPart();
+ final Object obj = diaEditPart.getModel();
+ if (obj instanceof View) {
+ final EObject designerElement = ((View) obj).getElement();
+ if (designerElement instanceof DDiagram) {
+ final List<Layer> activatedLayers = ((DDiagram) designerElement).getActivatedLayers();
+ if (EqualityHelper.contains(activatedLayers, (EObject) element)) {
+ result = Boolean.TRUE;
+ } else {
+ result = Boolean.FALSE;
+ }
+ }
+ }
+ } else {
+ /* second column */
+ result = new IdentifiedElementQuery(layer).getLabel();
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.ICellModifier#modify(java.lang.Object,
+ * java.lang.String, java.lang.Object)
+ */
+ public void modify(final Object element, final String property, final Object value) {
+
+ Object objElement;
+
+ if (element instanceof Item) {
+ objElement = ((Item) element).getData();
+ } else {
+ objElement = element;
+ }
+
+ final Layer layer = (Layer) objElement;
+
+ if (property.equals(layerColumns[0])) {
+ final DiagramEditPart diaEditPart = diagramPart.getDiagramEditPart();
+ final Object obj = diaEditPart.getModel();
+ if (obj instanceof View) {
+
+ final EObject designerElement = ((View) obj).getElement();
+
+ final DDiagramEditor diagramEditor = (DDiagramEditor) diagramPart.getDiagramGraphicalViewer().getProperty(DDiagramEditor.EDITOR_ID);
+
+ if (designerElement instanceof DDiagram && diagramEditor != null) {
+ final DDiagram dDiagram = (DDiagram) designerElement;
+ layerActivationAdapter.setPaletteManager(diagramEditor.getPaletteManager());
+
+ final IWorkbench wb = PlatformUI.getWorkbench();
+ final IProgressService ps = wb.getProgressService();
+ try {
+ ps.busyCursorWhile(new IRunnableWithProgress() {
+
+ public void run(final IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+ monitor.beginTask("Apply layer modifications...", 1);
+ TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(dDiagram);
+ Command changeActivatedLayersCmd = new ChangeLayerActivationCommand(domain, dDiagram, layer);
+ domain.getCommandStack().execute(changeActivatedLayersCmd);
+ monitor.done();
+ }
+ });
+ } catch (final InvocationTargetException e) {
+ if (e.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) e.getCause();
+ }
+ throw new RuntimeException(e.getCause());
+ } catch (final InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/layers/LayersContentProvider.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/layers/LayersContentProvider.java
new file mode 100644
index 0000000000..f05b0b2775
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/layers/LayersContentProvider.java
@@ -0,0 +1,164 @@
+/*******************************************************************************
+ * Copyright (c) 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.views.providers.layers;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DSemanticDiagram;
+import org.eclipse.sirius.business.api.componentization.DiagramComponentizationManager;
+import org.eclipse.sirius.business.api.session.Session;
+import org.eclipse.sirius.business.api.session.SessionManager;
+import org.eclipse.sirius.description.DiagramDescription;
+import org.eclipse.sirius.description.Layer;
+
+/**
+ * The content provider.
+ *
+ * @author mchauvin
+ */
+public class LayersContentProvider implements IStructuredContentProvider {
+
+ /** The EMF adapter */
+ private final LayersActivationAdapter layerActivationAdapter;
+
+ /** The Session listener */
+ private final LayersEventsListener eventListener;
+
+ /** The diagram workbench part */
+ private IDiagramWorkbenchPart diagramPart;
+
+ /** the diagram session */
+ private Session session;
+
+ /**
+ * Create a new content providers to display layers.
+ *
+ * @param adapter
+ * the layer activation adapter
+ * @param listener
+ * the session listener
+ * @param part
+ * the part responsible of the diagram access
+ */
+ public LayersContentProvider(final LayersActivationAdapter adapter, final LayersEventsListener listener, final IDiagramWorkbenchPart part) {
+ layerActivationAdapter = adapter;
+ eventListener = listener;
+ diagramPart = part;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
+ */
+ public Object[] getElements(final Object inputElement) {
+ if (inputElement instanceof DDiagram) {
+ final DiagramDescription diagramDesc = ((DDiagram) inputElement).getDescription();
+ final Collection<Layer> allLayers = new DiagramComponentizationManager().getAllLayers(session.getSelectedSiriuss(false), diagramDesc);
+ final Collection<Layer> layers = new ArrayList<Layer>();
+ for (final Layer layer : allLayers) {
+ if (layer != null && layer != diagramDesc.getDefaultLayer()) {
+ layers.add(layer);
+ }
+ }
+ return layers.toArray();
+ }
+ return Collections.EMPTY_LIST.toArray();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.IContentProvider#dispose()
+ */
+ public void dispose() {
+ if (diagramPart != null) {
+ final DiagramEditPart diaEditPart = diagramPart.getDiagramEditPart();
+ final Object obj = diaEditPart.getModel();
+ if (obj instanceof View) {
+ removeListenerFrom((View) obj);
+ }
+ diagramPart = null;
+ }
+ if (session != null) {
+ session = null;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer,
+ * java.lang.Object, java.lang.Object)
+ */
+ public void inputChanged(final Viewer viewer, final Object oldInput, final Object newInput) {
+ layerActivationAdapter.setViewer(viewer);
+ eventListener.setViewer(viewer);
+
+ if (oldInput != null) {
+ final DiagramEditPart diaEditPart = diagramPart.getDiagramEditPart();
+ final Object obj = diaEditPart.getModel();
+ if (obj instanceof View) {
+ removeListenerFrom((View) obj);
+ }
+ }
+ if (newInput != null) {
+ final DiagramEditPart diaEditPart = diagramPart.getDiagramEditPart();
+ final Object obj = diaEditPart.getModel();
+ if (obj instanceof View) {
+ addListenerTo((View) obj);
+ }
+ }
+ }
+
+ private void removeListenerFrom(final View oldInput) {
+ final EObject element = oldInput.getElement();
+ if (element instanceof DDiagram) {
+ final DDiagram diagram = (DDiagram) element;
+ diagram.eAdapters().remove(layerActivationAdapter);
+ removeListenerToSession();
+ }
+ }
+
+ private void addListenerTo(final View newInput) {
+ final EObject element = newInput.getElement();
+ if (element instanceof DDiagram) {
+ final DDiagram diagram = (DDiagram) element;
+ diagram.eAdapters().add(layerActivationAdapter);
+ if (diagram instanceof DSemanticDiagram) {
+ session = SessionManager.INSTANCE.getSession(((DSemanticDiagram) diagram).getTarget());
+ addListenerToSession();
+ }
+ }
+ }
+
+ private void addListenerToSession() {
+ if (session != null) {
+ session.addListener(eventListener);
+ }
+ }
+
+ private void removeListenerToSession() {
+ if (session != null) {
+ session.removeListener(eventListener);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/layers/LayersEventsListener.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/layers/LayersEventsListener.java
new file mode 100644
index 0000000000..545393cd48
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/layers/LayersEventsListener.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.views.providers.layers;
+
+import org.eclipse.jface.viewers.StructuredViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.ui.PlatformUI;
+
+import org.eclipse.sirius.business.api.session.SessionListener;
+
+/**
+ * A listener to update the viewer.
+ *
+ * @author mchauvin
+ */
+public class LayersEventsListener implements SessionListener {
+
+ /** The structured viewer to update. */
+ private StructuredViewer viewer;
+
+ /**
+ * Set the viewer.
+ *
+ * @param viewer
+ * the viewer to update when the model change
+ */
+ public void setViewer(final Viewer viewer) {
+ if (viewer instanceof StructuredViewer) {
+ this.viewer = (StructuredViewer) viewer;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.business.api.session.SessionListener#notify(int)
+ */
+ public void notify(final int changeKind) {
+ switch (changeKind) {
+ case SessionListener.SELECTED_VIEWS_CHANGE_KIND:
+ case SessionListener.VSM_UPDATED:
+ updateViewer();
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ private void updateViewer() {
+ PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ if (viewer != null && !viewer.getControl().isDisposed()) {
+ viewer.refresh();
+ }
+ }
+ });
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/layers/LayersLabelProvider.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/layers/LayersLabelProvider.java
new file mode 100644
index 0000000000..18af9c8d1c
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/layers/LayersLabelProvider.java
@@ -0,0 +1,178 @@
+/*******************************************************************************
+ * Copyright (c) 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.views.providers.layers;
+
+import java.util.List;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.ViewerCell;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+
+import org.eclipse.sirius.common.tools.api.util.EqualityHelper;
+import org.eclipse.sirius.common.tools.api.util.StringUtil;
+import org.eclipse.sirius.common.ui.tools.api.util.ImageProvider;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.business.api.query.IdentifiedElementQuery;
+import org.eclipse.sirius.description.Layer;
+import org.eclipse.sirius.diagram.ImagesPath;
+import org.eclipse.sirius.diagram.part.SiriusDiagramEditorPlugin;
+
+/**
+ * The label provider.
+ *
+ * @author mchauvin
+ */
+public class LayersLabelProvider extends ColumnLabelProvider {
+
+ private IDiagramWorkbenchPart diagramPart;
+
+ private int columnIndex;
+
+ /**
+ * Construct a new Layer label provider.
+ *
+ * @param part
+ * the part responsible of the diagram access.
+ */
+ public LayersLabelProvider(final IDiagramWorkbenchPart part) {
+ diagramPart = part;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.ColumnLabelProvider#getImage(java.lang.Object)
+ */
+ @Override
+ public Image getImage(Object element) {
+ Image result = null;
+ if (columnIndex == 0 && diagramPart != null) {
+ final DiagramEditPart diaEditPart = diagramPart.getDiagramEditPart();
+ final Object obj = diaEditPart.getModel();
+ if (obj instanceof View) {
+ final EObject designerElement = ((View) obj).getElement();
+ if (designerElement instanceof DDiagram) {
+ final List<Layer> activatedLayers = ((DDiagram) designerElement).getActivatedLayers();
+ Image img = null;
+ if (EqualityHelper.contains(activatedLayers, (EObject) element)) {
+ img = SiriusDiagramEditorPlugin.getInstance().getBundledImage(ImagesPath.ACTIVE_LAYER_ICON);
+ } else {
+ img = SiriusDiagramEditorPlugin.getInstance().getBundledImage(ImagesPath.INACTIVE_LAYER_ICON);
+ }
+ result = img;
+ }
+ }
+ } else if (columnIndex == 1) {
+ if (element instanceof Layer) {
+ Layer layer = (Layer) element;
+ if (!StringUtil.isEmpty(layer.getIcon())) {
+ result = ImageProvider.getImageFromPath(layer.getIcon());
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.ColumnLabelProvider#getText(java.lang.Object)
+ */
+ @Override
+ public String getText(Object element) {
+ switch (columnIndex) {
+ case 2:
+ if (element instanceof Layer) {
+ return new IdentifiedElementQuery((Layer) element).getLabel();
+ }
+ break;
+ default:
+ break;
+ }
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.CellLabelProvider#getToolTipText(java.lang.Object)
+ */
+ @Override
+ public String getToolTipText(Object element) {
+ if (element instanceof Layer) {
+ String endUserDoc = ((Layer) element).getEndUserDocumentation();
+ if (endUserDoc != null && endUserDoc.trim().length() > 0) {
+ return endUserDoc;
+ }
+ }
+ return super.getToolTipText(element);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.CellLabelProvider#getToolTipShift(java.lang.Object)
+ */
+ @Override
+ public Point getToolTipShift(final Object object) {
+ return new Point(5, 5);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.CellLabelProvider#getToolTipDisplayDelayTime(java.lang.Object)
+ */
+ @Override
+ public int getToolTipDisplayDelayTime(final Object object) {
+ return 200;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.CellLabelProvider#getToolTipStyle(java.lang.Object)
+ */
+ @Override
+ public int getToolTipStyle(final Object object) {
+ return SWT.SHADOW_OUT;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.ColumnLabelProvider#update(org.eclipse.jface.viewers.ViewerCell)
+ */
+ @Override
+ public void update(final ViewerCell cell) {
+ columnIndex = cell.getColumnIndex();
+ super.update(cell);
+ }
+
+ /**
+ *
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.BaseLabelProvider#dispose()
+ */
+ @Override
+ public void dispose() {
+ super.dispose();
+ diagramPart = null;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/layers/LayersTableViewer.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/layers/LayersTableViewer.java
new file mode 100644
index 0000000000..7771c931e2
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/layers/LayersTableViewer.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2009 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.views.providers.layers;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.CheckboxCellEditor;
+import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.window.ToolTip;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.diagram.ImagesPath;
+import org.eclipse.sirius.diagram.part.SiriusDiagramEditorPlugin;
+
+/**
+ * Factory class to create a layers table viewer.
+ *
+ * @author mchauvin
+ */
+public final class LayersTableViewer {
+
+ private static final String[] COLUMNS = { " ", " ", "Layer" };
+
+ /**
+ * Avoid instantiation.
+ */
+ private LayersTableViewer() {
+ }
+
+ /**
+ * Create a new Layers table viewer.
+ *
+ * @param control
+ * the parent SWT control
+ * @param diagramPart
+ * the workbench part to access diagram part
+ * @return new viewer to hide or show layers.
+ */
+ public static TableViewer createLayersTableViewer(final Composite control, final IDiagramWorkbenchPart diagramPart) {
+
+ final TableViewer tableViewer = new TableViewer(control, SWT.BORDER | SWT.FULL_SELECTION);
+ ColumnViewerToolTipSupport.enableFor(tableViewer, ToolTip.RECREATE);
+
+ final Table table = tableViewer.getTable();
+
+ table.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ TableColumn tc = new TableColumn(table, SWT.LEFT, 0);
+ tc.setText(COLUMNS[0]);
+ tc.setWidth(30);
+ tc.setImage(SiriusDiagramEditorPlugin.getInstance().getBundledImage(ImagesPath.LAYER_ACTIVATION_ICON));
+
+ tc = new TableColumn(table, SWT.CENTER, 1);
+ tc.setText(COLUMNS[1]);
+ tc.setWidth(30);
+
+ tc = new TableColumn(table, SWT.LEFT, 2);
+ tc.setText(COLUMNS[2]);
+ tc.setWidth(200);
+
+ // Can only changes the first column - the visible column
+ final CellEditor[] editors = new CellEditor[3];
+ editors[0] = new CheckboxCellEditor(table);
+ for (int i = 1; i < 3; i++) {
+ editors[i] = null;
+ }
+
+ tableViewer.setColumnProperties(COLUMNS);
+
+ tableViewer.setCellEditors(editors);
+ final LayersActivationAdapter adapter = new LayersActivationAdapter();
+ final LayersEventsListener sessionListener = new LayersEventsListener();
+ tableViewer.setCellModifier(new LayersCellModifier(adapter, diagramPart, COLUMNS));
+ tableViewer.setContentProvider(new LayersContentProvider(adapter, sessionListener, diagramPart));
+ tableViewer.setLabelProvider(new LayersLabelProvider(diagramPart));
+
+ if (diagramPart != null) {
+ final EObject eObj = diagramPart.getDiagram().getElement();
+ if (eObj instanceof DDiagram) {
+ final DDiagram diagram = (DDiagram) eObj;
+ tableViewer.setInput(diagram);
+ }
+ }
+
+ /* Lines are not visible in the specifications */
+ table.setLinesVisible(true);
+ table.setHeaderVisible(true);
+ return tableViewer;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/outline/OutlineComparator.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/outline/OutlineComparator.java
new file mode 100644
index 0000000000..e3958c0c08
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/outline/OutlineComparator.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2008 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.views.providers.outline;
+
+import org.eclipse.jface.viewers.ViewerComparator;
+
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DEdge;
+import org.eclipse.sirius.business.api.query.DDiagramElementQuery;
+
+/**
+ * A comparator for the outline tree viewer.
+ *
+ * @author Mariot Chauvin (mchauvin)
+ */
+public class OutlineComparator extends ViewerComparator {
+
+ private static final int VISIBLE_ELEMENT = 0;
+
+ private static final int HIDDEN_ELEMENT = 2;
+
+ private static final int OTHER_NON_VISIBLE_ELEMENT = 4;
+
+ private static final int VIEW_NODE = 0;
+
+ private static final int VIEW_EDGE = 1;
+
+ private static final int OTHER = 64;
+
+ /**
+ * Constructor.
+ */
+ public OutlineComparator() {
+ super();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.ViewerComparator#category(java.lang.Object)
+ */
+ @Override
+ public int category(final Object element) {
+
+ int value = 0;
+ if (element instanceof DDiagramElement) {
+ if (((DDiagramElement) element).isVisible()) {
+ value += VISIBLE_ELEMENT;
+ } else if (new DDiagramElementQuery((DDiagramElement) element).isHidden()) {
+ value += HIDDEN_ELEMENT;
+ } else {
+ value += OTHER_NON_VISIBLE_ELEMENT;
+ }
+
+ if (element instanceof DEdge) {
+ value += VIEW_EDGE;
+ } else {
+ value += VIEW_NODE;
+ }
+
+ } else {
+ value += OTHER;
+ }
+ return value;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.ViewerComparator#isSorterProperty(java.lang.Object,
+ * java.lang.String)
+ */
+ @Override
+ public boolean isSorterProperty(final Object element, final String property) {
+ return false;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/outline/OutlineContentProvider.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/outline/OutlineContentProvider.java
new file mode 100644
index 0000000000..3e5faeb798
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/outline/OutlineContentProvider.java
@@ -0,0 +1,329 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.views.providers.outline;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.provider.EcoreItemProviderAdapterFactory;
+import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
+import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory;
+import org.eclipse.emf.edit.provider.resource.ResourceItemProviderAdapterFactory;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.emf.transaction.util.TransactionUtil;
+import org.eclipse.gmf.runtime.notation.Diagram;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DDiagramElementContainer;
+import org.eclipse.sirius.DEdge;
+import org.eclipse.sirius.DNode;
+import org.eclipse.sirius.DSemanticDiagram;
+import org.eclipse.sirius.business.api.componentization.DiagramMappingsManager;
+import org.eclipse.sirius.business.api.componentization.DiagramMappingsManagerRegistry;
+import org.eclipse.sirius.business.api.query.DDiagramElementQuery;
+import org.eclipse.sirius.business.api.session.Session;
+import org.eclipse.sirius.business.api.session.SessionManager;
+import org.eclipse.sirius.business.internal.metamodel.helper.LayerHelper;
+import org.eclipse.sirius.diagram.tools.internal.editor.DiagramOutlinePageListener;
+import org.eclipse.sirius.provider.SiriusItemProviderAdapterFactory;
+import org.eclipse.sirius.ui.business.api.provider.AbstractDDiagramElementLabelItemProvider;
+import org.eclipse.sirius.ui.business.api.provider.DEdgeLabelItemProvider;
+import org.eclipse.sirius.ui.business.api.provider.DNodeLabelItemProvider;
+
+/**
+ * This class is responsible of the outline tree viewer content.
+ *
+ * @author Mariot Chauvin (mchauvin)
+ */
+public class OutlineContentProvider implements ITreeContentProvider, DiagramOutlinePageListener {
+
+ /** The EMF adapter */
+ OutlineContentResourceSetListener outlineContentResourceSetListener = new OutlineContentResourceSetListener();
+
+ private boolean checkParent(final EObject parent) {
+
+ boolean check = false;
+
+ // should never happen but avoid an NPE if it happens
+ if (parent == null) {
+ check = true;
+ } else if (parent instanceof DDiagram) {
+ check = true;
+ } else if (parent instanceof DDiagramElementContainer) {
+ check = true;
+ }
+
+ return check;
+ }
+
+ private DDiagram getDiagramContainer(final EObject element) {
+
+ DDiagram dia = null;
+
+ if (element instanceof DDiagram) {
+ dia = (DDiagram) element;
+ } else if (element != null) {
+ dia = getDiagramContainer(element.eContainer());
+ }
+ return dia;
+ }
+
+ private List<Object> clearFilteredElements(final List<? extends Object> elements, final DDiagram vp) {
+ Session session = SessionManager.INSTANCE.getSession(((DSemanticDiagram) vp).getTarget());
+ DiagramMappingsManager mappingManager = DiagramMappingsManagerRegistry.INSTANCE.getDiagramMappingsManager(session, vp);
+ final List<Object> result = new ArrayList<Object>(elements.size());
+ final Iterator<? extends Object> it = elements.iterator();
+ while (it.hasNext()) {
+ final Object element = it.next();
+ if (element instanceof DDiagramElement) {
+ DDiagramElement dde = (DDiagramElement) element;
+ if (!isFiltered(mappingManager, dde)) {
+ result.add(dde);
+ }
+ } else if (element instanceof AbstractDDiagramElementLabelItemProvider) {
+ Option<DDiagramElement> optionTarget = ((AbstractDDiagramElementLabelItemProvider) element).getDiagramElementTarget();
+ if (optionTarget.some() && !isFiltered(mappingManager, optionTarget.get())) {
+ result.add(element);
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Check if the diagram element is filtered.
+ *
+ * @param dde
+ * The diagram element to check.
+ */
+ private boolean isFiltered(DiagramMappingsManager session, DDiagramElement dde) {
+ boolean isFiltered = true;
+ if (dde.isVisible()) {
+ isFiltered = false;
+ } else if (LayerHelper.isInActivatedLayer(session, dde) && !new DDiagramElementQuery(dde).isFiltered()) {
+ isFiltered = false;
+ }
+ return isFiltered;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang.Object)
+ */
+ public Object getParent(final Object element) {
+
+ Object theParent = null;
+
+ // diagram is the root object
+ if (element instanceof DDiagram) {
+ return theParent;
+ } else if (element instanceof DNode) {
+
+ final DNode vn = (DNode) element;
+ final EObject parent = vn.eContainer();
+
+ if (parent instanceof DNode) {
+ theParent = parent;
+ } else if (checkParent(parent)) {
+ theParent = parent;
+ }
+ }
+
+ else if (element instanceof DDiagramElement) {
+
+ final DDiagramElement vpe = (DDiagramElement) element;
+ final EObject parent = vpe.eContainer();
+
+ if (checkParent(parent)) {
+ theParent = parent;
+ }
+ }
+
+ return theParent;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object)
+ */
+ public Object[] getChildren(final Object parentElement) {
+
+ Object[] children = null;
+
+ if (parentElement instanceof DDiagram) {
+ final DDiagram diagram = (DDiagram) parentElement;
+ children = clearFilteredElements(diagram.getOwnedDiagramElements(), diagram).toArray();
+ }
+
+ else if (parentElement instanceof DNode) {
+ final DNode dNode = (DNode) parentElement;
+ List<Object> originalChildren = new ArrayList<Object>(dNode.getOwnedBorderedNodes());
+
+ // if the current node should have a DNodeLabelItem has children
+ if (DNodeLabelItemProvider.hasRelevantLabelItem(dNode)) {
+ originalChildren.add(0, new DNodeLabelItemProvider(getAdapterFactory(), dNode));
+ }
+ children = clearFilteredElements(originalChildren, getDiagramContainer(dNode)).toArray();
+ }
+
+ else if (parentElement instanceof DEdge) {
+ final DEdge dEdge = (DEdge) parentElement;
+ List<Object> originalChildren = new ArrayList<Object>();
+
+ // if the current node should have a DEdgeLabelItem has children
+ if (DEdgeLabelItemProvider.hasRelevantLabelItem(dEdge)) {
+ originalChildren.add(0, new DEdgeLabelItemProvider(getAdapterFactory(), dEdge));
+ }
+ // if (DEdgeBeginLabelItemProvider.hasRelevantLabelItem(dEdge)) {
+ // originalChildren.add(0, new
+ // DEdgeBeginLabelItemProvider(getAdapterFactory(), dEdge));
+ // }
+ // if (DEdgeEndLabelItemProvider.hasRelevantLabelItem(dEdge)) {
+ // originalChildren.add(0, new
+ // DEdgeEndLabelItemProvider(getAdapterFactory(), dEdge));
+ // }
+ children = clearFilteredElements(originalChildren, getDiagramContainer(dEdge)).toArray();
+ }
+
+ else if (parentElement instanceof DDiagramElementContainer) {
+ final DDiagramElementContainer diagramElementContainer = (DDiagramElementContainer) parentElement;
+ children = clearFilteredElements(diagramElementContainer.getElements(), getDiagramContainer(diagramElementContainer)).toArray();
+ }
+
+ return children;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object)
+ */
+ public boolean hasChildren(final Object element) {
+
+ boolean hasChildren = false;
+
+ if (element instanceof DDiagram || element instanceof DNode || element instanceof DEdge || element instanceof DDiagramElementContainer) {
+ hasChildren = getChildren(element).length > 0;
+ }
+ // in other case return false
+ return hasChildren;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
+ */
+ public Object[] getElements(final Object inputElement) {
+
+ // in case of diagram return the viewpoint
+ if (inputElement instanceof Diagram) {
+ final Diagram diagram = (Diagram) inputElement;
+ final EObject viewpointDiagram = diagram.getElement();
+ if (viewpointDiagram != null) {
+ return new Object[] { viewpointDiagram };
+ }
+ }
+
+ // all other case return the element
+ return new Object[] { inputElement };
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.IContentProvider#dispose()
+ */
+ public void dispose() {
+ // do nothing
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer,
+ * java.lang.Object, java.lang.Object)
+ */
+ public void inputChanged(final Viewer viewer, final Object oldInput, final Object newInput) {
+ if (oldInput != null) {
+ removeListenerFrom((View) oldInput);
+ }
+ if (newInput != null) {
+ outlineContentResourceSetListener.setViewer(viewer);
+ addListenerTo((View) newInput);
+ }
+ }
+
+ private void removeListenerFrom(final View oldInput) {
+ final EObject element = oldInput.getElement();
+ if (element instanceof DDiagram) {
+ final DDiagram diagram = (DDiagram) element;
+ TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(diagram);
+ /* Editing domain is null */
+ if (domain != null) {
+ domain.removeResourceSetListener(outlineContentResourceSetListener);
+ }
+ }
+ }
+
+ private void addListenerTo(final View newInput) {
+ final EObject element = newInput.getElement();
+ if (element instanceof DDiagram) {
+ final DDiagram diagram = (DDiagram) element;
+ TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(diagram);
+ if (domain != null) {
+ domain.addResourceSetListener(outlineContentResourceSetListener);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.common.ui.tools.api.outline.DiagramOutlinePageListener#activate(int)
+ */
+ public void activate(int page) {
+ this.outlineContentResourceSetListener.activate(page);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.common.ui.tools.api.outline.DiagramOutlinePageListener#deactivate(int)
+ */
+ public void deactivate(int page) {
+ this.outlineContentResourceSetListener.deactivate(page);
+ }
+
+ /**
+ * Returns the adapter factory used by this viewer.
+ *
+ * @return The adapter factory used by this viewer.
+ */
+ public AdapterFactory getAdapterFactory() {
+ List<AdapterFactory> factories = new ArrayList<AdapterFactory>();
+ factories.add(new SiriusItemProviderAdapterFactory());
+ factories.add(new ResourceItemProviderAdapterFactory());
+ factories.add(new EcoreItemProviderAdapterFactory());
+ factories.add(new ReflectiveItemProviderAdapterFactory());
+ return new ComposedAdapterFactory(factories);
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/outline/OutlineContentResourceSetListener.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/outline/OutlineContentResourceSetListener.java
new file mode 100644
index 0000000000..3c17cd185f
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/outline/OutlineContentResourceSetListener.java
@@ -0,0 +1,326 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.views.providers.outline;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.ecore.provider.EcoreItemProviderAdapterFactory;
+import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
+import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory;
+import org.eclipse.emf.edit.provider.resource.ResourceItemProviderAdapterFactory;
+import org.eclipse.emf.transaction.DemultiplexingListener;
+import org.eclipse.emf.transaction.ResourceSetChangeEvent;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.jface.viewers.StructuredViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.widgets.Display;
+
+import com.google.common.collect.Sets;
+
+import org.eclipse.sirius.AbstractDNode;
+import org.eclipse.sirius.DDiagram;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DEdge;
+import org.eclipse.sirius.DNode;
+import org.eclipse.sirius.DNodeContainer;
+import org.eclipse.sirius.DNodeList;
+import org.eclipse.sirius.SiriusPackage;
+import org.eclipse.sirius.business.api.helper.SiriusUtil;
+import org.eclipse.sirius.diagram.tools.internal.editor.DiagramOutlinePageListener;
+import org.eclipse.sirius.provider.SiriusItemProviderAdapterFactory;
+import org.eclipse.sirius.ui.business.api.provider.DEdgeLabelItemProvider;
+import org.eclipse.sirius.ui.business.api.provider.DNodeLabelItemProvider;
+
+/**
+ * This class is an EMF Transaction resource listener which listen post commit
+ * notifications to update a {@link StructuredViewer} of the outline.
+ *
+ * @author Mariot Chauvin (mchauvin)
+ */
+public class OutlineContentResourceSetListener extends DemultiplexingListener implements DiagramOutlinePageListener {
+
+ /** The structured viewer to update. */
+ private StructuredViewer viewer;
+
+ private boolean active;
+
+ private Set<DDiagram> toRefresh;
+
+ private Set<Object> toUpdate;
+
+ /** flag signaling a refresh request made while the outline was disabled. */
+ private boolean deferredRefresh;
+
+ /**
+ * Set the viewer.
+ *
+ * @param viewer
+ * the viewer to update when the model change
+ */
+ public void setViewer(final Viewer viewer) {
+ if (viewer instanceof StructuredViewer) {
+ this.viewer = (StructuredViewer) viewer;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.emf.transaction.DemultiplexingListener#resourceSetChanged(org.eclipse.emf.transaction.ResourceSetChangeEvent)
+ */
+ @Override
+ public void resourceSetChanged(ResourceSetChangeEvent event) {
+ if (active) {
+ toRefresh = Sets.newHashSet();
+ toUpdate = Sets.newHashSet();
+ super.resourceSetChanged(event);
+ refreshOutline();
+ toRefresh = null;
+ toUpdate = null;
+ } else {
+ toRefresh = Sets.newHashSet();
+ toUpdate = Sets.newHashSet();
+ deferredRefresh = true;
+ super.resourceSetChanged(event);
+ }
+ }
+
+ private void refreshOutline() {
+ if (!toRefresh.isEmpty()) {
+ refreshViewer();
+ } else {
+ updateViewer();
+ }
+ }
+
+ private void refreshViewer() {
+ for (final DDiagram diagram : toRefresh) {
+ refreshViewer(diagram);
+ }
+ }
+
+ private void updateViewer() {
+ for (final Object object : toUpdate) {
+ updateViewer(object);
+ }
+ }
+
+ private void refreshViewer(final DDiagram diagram) {
+ Display.getDefault().asyncExec(new Runnable() {
+ public void run() {
+ if (viewer != null && viewer.getControl() != null && !viewer.getControl().isDisposed()) {
+ viewer.refresh(diagram, true);
+ }
+ }
+ });
+ }
+
+ private void updateViewer(final Object object) {
+ Display.getDefault().asyncExec(new Runnable() {
+ public void run() {
+ if (viewer != null && viewer.getControl() != null && !viewer.getControl().isDisposed()) {
+ viewer.update(object, null);
+ }
+ }
+ });
+ }
+
+ private void addToRefresh(final DDiagram diagram) {
+ toRefresh.add(diagram);
+ }
+
+ private void addToUpdate(final Object object) {
+ toUpdate.add(object);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.emf.transaction.DemultiplexingListener#handleNotification(org.eclipse.emf.transaction.TransactionalEditingDomain,
+ * org.eclipse.emf.common.notify.Notification)
+ */
+ @Override
+ protected void handleNotification(TransactionalEditingDomain domain, Notification notification) {
+ final Object notifier = notification.getNotifier();
+
+ if (notifier instanceof DDiagramElement) {
+
+ caseDDiagramElement(notification, (DDiagramElement) notifier);
+
+ if (notifier instanceof AbstractDNode) {
+ caseAbstractDNode(notification, (AbstractDNode) notifier);
+ }
+
+ if (notifier instanceof DEdge) {
+ caseDEdge(notification, (DEdge) notifier);
+ }
+
+ if (notifier instanceof DNodeContainer) {
+ caseDNodeContainer(notification, (DNodeContainer) notifier);
+ } else if (notifier instanceof DNodeList) {
+ caseDNodeList(notification, (DNodeList) notifier);
+ }
+
+ } else if (notifier instanceof DDiagram) {
+ caseDDiagram(notification, (DDiagram) notifier);
+ }
+ }
+
+ private void caseDDiagramElement(final Notification n, final DDiagramElement diagramElement) {
+ final int featureID = n.getFeatureID(DDiagramElement.class);
+
+ switch (featureID) {
+ case SiriusPackage.DDIAGRAM_ELEMENT__VISIBLE:
+ addToRefresh(SiriusUtil.findDiagram(diagramElement));
+ break;
+ case SiriusPackage.DDIAGRAM_ELEMENT__NAME:
+ addToUpdate(diagramElement);
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void caseAbstractDNode(final Notification n, final AbstractDNode node) {
+ final int featureID = n.getFeatureID(AbstractDNode.class);
+
+ switch (featureID) {
+ case SiriusPackage.ABSTRACT_DNODE__OWNED_BORDERED_NODES:
+ case SiriusPackage.ABSTRACT_DNODE__GRAPHICAL_FILTERS:
+ addToRefresh(SiriusUtil.findDiagram(node));
+ break;
+ default:
+ break;
+ }
+ if (DNodeLabelItemProvider.hasRelevantLabelItem(node)) {
+ addToUpdate(new DNodeLabelItemProvider(getAdapterFactoryForNodeLabelItems(), (DNode) node));
+ }
+ }
+
+ private void caseDEdge(final Notification n, final DEdge edge) {
+ if (DEdgeLabelItemProvider.hasRelevantLabelItem(edge)) {
+ addToUpdate(new DEdgeLabelItemProvider(getAdapterFactoryForNodeLabelItems(), edge));
+ }
+ // if (DEdgeBeginLabelItemProvider.hasRelevantLabelItem(edge)) {
+ // addToUpdate(new
+ // DEdgeBeginLabelItemProvider(getAdapterFactoryForNodeLabelItems(),
+ // (DEdge) edge));
+ // }
+ // if (DEdgeEndLabelItemProvider.hasRelevantLabelItem(edge)) {
+ // addToUpdate(new
+ // DEdgeEndLabelItemProvider(getAdapterFactoryForNodeLabelItems(),
+ // (DEdge) edge));
+ // }
+ }
+
+ /**
+ * Returns the adapter factory to use to define labelItems.
+ *
+ * @return The adapter factory used to define labelItems.
+ */
+ private AdapterFactory getAdapterFactoryForNodeLabelItems() {
+ List<AdapterFactory> factories = new ArrayList<AdapterFactory>();
+ factories.add(new SiriusItemProviderAdapterFactory());
+ factories.add(new ResourceItemProviderAdapterFactory());
+ factories.add(new EcoreItemProviderAdapterFactory());
+ factories.add(new ReflectiveItemProviderAdapterFactory());
+ return new ComposedAdapterFactory(factories);
+ }
+
+ private void caseDNodeContainer(final Notification n, final DNodeContainer nodeContainer) {
+ final int featureID = n.getFeatureID(DNodeContainer.class);
+
+ switch (featureID) {
+ case SiriusPackage.DNODE_CONTAINER__OWNED_DIAGRAM_ELEMENTS:
+ addToRefresh(SiriusUtil.findDiagram(nodeContainer));
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void caseDNodeList(final Notification n, final DNodeList nodeList) {
+ final int featureID = n.getFeatureID(DNodeList.class);
+
+ switch (featureID) {
+ case SiriusPackage.DNODE_LIST__OWNED_ELEMENTS:
+ addToRefresh(SiriusUtil.findDiagram(nodeList));
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void caseDDiagram(final Notification n, final DDiagram diagram) {
+ final int featureID = n.getFeatureID(DDiagram.class);
+ if (featureID == SiriusPackage.DDIAGRAM__OWNED_DIAGRAM_ELEMENTS) {
+ switch (n.getEventType()) {
+ case Notification.ADD:
+ case Notification.REMOVE:
+ case Notification.REMOVE_MANY:
+ addToRefresh(diagram);
+ break;
+ default:
+ break;
+ }
+ } else if (featureID == SiriusPackage.DDIAGRAM__ACTIVATED_FILTERS) {
+ switch (n.getEventType()) {
+ case Notification.ADD:
+ case Notification.REMOVE:
+ case Notification.REMOVE_MANY:
+ addToRefresh(diagram);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.common.ui.tools.api.outline.DiagramOutlinePageListener#activate(int)
+ */
+ public void activate(int page) {
+ switch (page) {
+ case DiagramOutlinePageListener.OUTLINE:
+ active = true;
+ if (deferredRefresh) {
+ deferredRefresh = false;
+ refreshOutline();
+ toRefresh = null;
+ toUpdate = null;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.sirius.common.ui.tools.api.outline.DiagramOutlinePageListener#deactivate(int)
+ */
+ public void deactivate(int page) {
+ switch (page) {
+ case DiagramOutlinePageListener.OUTLINE:
+ active = false;
+ break;
+ default:
+ break;
+ }
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/outline/OutlineLabelProvider.java b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/outline/OutlineLabelProvider.java
new file mode 100644
index 0000000000..ff697e0544
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram/specific/org/eclipse/sirius/diagram/ui/tools/internal/views/providers/outline/OutlineLabelProvider.java
@@ -0,0 +1,187 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 THALES GLOBAL SERVICES.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.tools.internal.views.providers.outline;
+
+import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.edit.provider.IItemLabelProvider;
+import org.eclipse.emf.edit.ui.provider.ExtendedImageRegistry;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.viewers.DecorationOverlayIcon;
+import org.eclipse.jface.viewers.IDecoration;
+import org.eclipse.jface.viewers.IFontProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+
+import org.eclipse.sirius.common.tools.api.util.Option;
+import org.eclipse.sirius.DDiagramElement;
+import org.eclipse.sirius.DEdge;
+import org.eclipse.sirius.DSemanticDecorator;
+import org.eclipse.sirius.business.api.query.DDiagramElementQuery;
+import org.eclipse.sirius.diagram.part.SiriusDiagramEditorPlugin;
+import org.eclipse.sirius.provider.SiriusEditPlugin;
+import org.eclipse.sirius.ui.business.api.provider.AbstractDDiagramElementLabelItemProvider;
+import org.eclipse.sirius.ui.tools.api.image.ImagesPath;
+
+/**
+ * Label provider for the diagram outline tree.
+ *
+ * @author Mariot Chauvin (mchauvin)
+ */
+public class OutlineLabelProvider extends LabelProvider implements IFontProvider {
+
+ /** */
+ private AdapterFactory factory;
+
+ /**
+ * Constructor.
+ *
+ * @param adapterFactory
+ */
+ public OutlineLabelProvider() {
+ this.factory = SiriusDiagramEditorPlugin.getInstance().getItemProvidersAdapterFactory();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.LabelProvider#getImage(java.lang.Object)
+ */
+ @Override
+ public Image getImage(final Object element) {
+ Image result = null;
+ if (element instanceof DSemanticDecorator) {
+ result = getImage((DSemanticDecorator) element);
+ } else if (element instanceof AbstractDDiagramElementLabelItemProvider) {
+ result = getImage((AbstractDDiagramElementLabelItemProvider) element);
+ }
+ return result;
+ }
+
+ /**
+ * Returns the image for the label of the given DNodeLabelItemProvider.
+ *
+ * @param element
+ * the element for which to provide the label image
+ * @return the image used to label the element, or <code>null</code> if
+ * there is no image for the given object
+ */
+ private Image getImage(final AbstractDDiagramElementLabelItemProvider element) {
+ Image result;
+ ImageDescriptor descriptor = ExtendedImageRegistry.getInstance().getImageDescriptor(element.getImage(element.getTarget()));
+ if (descriptor == null) {
+ descriptor = ImageDescriptor.getMissingImageDescriptor();
+ }
+ result = SiriusDiagramEditorPlugin.getInstance().getImage(descriptor);
+
+ Option<DDiagramElement> optionTarget = element.getDiagramElementTarget();
+ if (optionTarget.some() && new DDiagramElementQuery(optionTarget.get()).isLabelHidden()) {
+ final ImageDescriptor decoratorDescriptor = ExtendedImageRegistry.getInstance().getImageDescriptor(SiriusEditPlugin.INSTANCE.getImage(ImagesPath.HIDDEN_DECORATOR));
+ final DecorationOverlayIcon finalDescriptor = new DecorationOverlayIcon(result, decoratorDescriptor, IDecoration.TOP_LEFT);
+ result = SiriusDiagramEditorPlugin.getInstance().getImage(finalDescriptor);
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns the image for the label of the given DSemanticDecorator.
+ *
+ * @param element
+ * the element for which to provide the label image
+ * @return the image used to label the element, or <code>null</code> if
+ * there is no image for the given object
+ */
+ private Image getImage(DSemanticDecorator element) {
+ Image result = null;
+ final EObject target = element.getTarget();
+ if (target != null) {
+ final IItemLabelProvider labelProvider = (IItemLabelProvider) this.factory.adapt(target, IItemLabelProvider.class);
+ if (labelProvider != null) {
+ ImageDescriptor descriptor = ExtendedImageRegistry.getInstance().getImageDescriptor(labelProvider.getImage(target));
+ if (descriptor == null) {
+ descriptor = ImageDescriptor.getMissingImageDescriptor();
+ }
+ result = SiriusDiagramEditorPlugin.getInstance().getImage(descriptor);
+
+ if (element instanceof DEdge) {
+ final ImageDescriptor decoratorDescriptor = ExtendedImageRegistry.getInstance().getImageDescriptor(SiriusEditPlugin.INSTANCE.getImage(ImagesPath.VIEW_EDGE_DECORATOR));
+ final DecorationOverlayIcon finalDescriptor = new DecorationOverlayIcon(result, decoratorDescriptor, IDecoration.BOTTOM_LEFT);
+ result = SiriusDiagramEditorPlugin.getInstance().getImage(finalDescriptor);
+
+ result = computeFoldDecorator(result, (DEdge) element);
+ }
+
+ if (element instanceof DDiagramElement && new DDiagramElementQuery((DDiagramElement) element).isHidden()) {
+ final ImageDescriptor decoratorDescriptor = ExtendedImageRegistry.getInstance().getImageDescriptor(SiriusEditPlugin.INSTANCE.getImage(ImagesPath.HIDDEN_DECORATOR));
+ final DecorationOverlayIcon finalDescriptor = new DecorationOverlayIcon(result, decoratorDescriptor, IDecoration.TOP_LEFT);
+ result = SiriusDiagramEditorPlugin.getInstance().getImage(finalDescriptor);
+
+ }
+ }
+ }
+ return result;
+ }
+
+ private Image computeFoldDecorator(final Image baseImage, final DEdge edge) {
+ if (new DDiagramElementQuery(edge).isFolded()) {
+ final ImageDescriptor foldDescription = ExtendedImageRegistry.getInstance().getImageDescriptor(SiriusEditPlugin.INSTANCE.getImage(ImagesPath.FOLD_DECORATOR));
+ final DecorationOverlayIcon finalFoldDescriptor = new DecorationOverlayIcon(baseImage, foldDescription, IDecoration.TOP_RIGHT);
+ return SiriusDiagramEditorPlugin.getInstance().getImage(finalFoldDescriptor);
+ }
+ return baseImage;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.LabelProvider#getText(java.lang.Object)
+ */
+ @Override
+ public String getText(final Object element) {
+ String result = null;
+ if (element instanceof DSemanticDecorator) {
+ final EObject target = ((DSemanticDecorator) element).getTarget();
+ if (target != null) {
+ final IItemLabelProvider labelProvider = (IItemLabelProvider) this.factory.adapt(target, IItemLabelProvider.class);
+ if (labelProvider != null) {
+ result = labelProvider.getText(target);
+ }
+ }
+ } else if (element instanceof AbstractDDiagramElementLabelItemProvider) {
+ result = ((AbstractDDiagramElementLabelItemProvider) element).getText(((AbstractDDiagramElementLabelItemProvider) element).getTarget());
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.jface.viewers.IFontProvider#getFont(java.lang.Object)
+ */
+ public Font getFont(final Object element) {
+ Font result = JFaceResources.getDefaultFont();
+ if (element instanceof DDiagramElement) {
+ final DDiagramElement vpe = (DDiagramElement) element;
+ if (!vpe.isVisible()) {
+ result = JFaceResources.getFontRegistry().getItalic(JFaceResources.DEFAULT_FONT);
+ }
+ } else if (element instanceof AbstractDDiagramElementLabelItemProvider) {
+ Option<DDiagramElement> optionTarget = ((AbstractDDiagramElementLabelItemProvider) element).getDiagramElementTarget();
+ if (optionTarget.some() && new DDiagramElementQuery(optionTarget.get()).isLabelHidden()) {
+ result = JFaceResources.getFontRegistry().getItalic(JFaceResources.DEFAULT_FONT);
+ }
+ }
+ return result;
+ }
+}

Back to the top