Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Redor2014-08-18 09:23:39 +0000
committerLaurent Redor2014-09-19 12:42:25 +0000
commit0adbf17506973bcc22828e91d4e0c12ec3f5dffe (patch)
treeb8e6cb4ec7b9b7b1d19f65934ecc4729cfd15896
parentde0edb93cc042e3eef2f93179794549a83d136c3 (diff)
downloadorg.eclipse.sirius-0adbf17506973bcc22828e91d4e0c12ec3f5dffe.tar.gz
org.eclipse.sirius-0adbf17506973bcc22828e91d4e0c12ec3f5dffe.tar.xz
org.eclipse.sirius-0adbf17506973bcc22828e91d4e0c12ec3f5dffe.zip
[442289] Add distribute actions
* Add 4 distribute actions (in tabbar, in contextual menu Format/Distribute, in menu bar Diagram/Distribute) * The new DistributeRequest is now handled by the SiriusContainerEditPolicy with the getDistributeCommand * Disable these actions for sequence diagram (SequenceContainerCreationPolicy and SequenceNodeCreationPolicy) * Update the release notes and the user documentation. Bug: 442289 Change-Id: I5cd5d7c10fcf0e0a0b13d210ce88590e918aef40 Signed-off-by: Laurent Redor <laurent.redor@obeo.fr>
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceContainerCreationPolicy.java12
-rw-r--r--plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceNodeCreationPolicy.java6
-rw-r--r--plugins/org.eclipse.sirius.diagram.ui/META-INF/MANIFEST.MF1
-rw-r--r--plugins/org.eclipse.sirius.diagram.ui/icons/distributeCentersHorizontal.gifbin0 -> 218 bytes
-rw-r--r--plugins/org.eclipse.sirius.diagram.ui/icons/distributeCentersVertical.gifbin0 -> 238 bytes
-rw-r--r--plugins/org.eclipse.sirius.diagram.ui/icons/distributeWithUniformGapHorizontal.gifbin0 -> 178 bytes
-rw-r--r--plugins/org.eclipse.sirius.diagram.ui/icons/distributeWithUniformGapVertical.gifbin0 -> 172 bytes
-rw-r--r--plugins/org.eclipse.sirius.diagram.ui/icons/license.txt4
-rw-r--r--plugins/org.eclipse.sirius.diagram.ui/plugin.xml21
-rw-r--r--plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/graphical/edit/policies/SiriusContainerEditPolicy.java28
-rw-r--r--plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/internal/edit/commands/DistributeCommand.java609
-rw-r--r--plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/internal/providers/SiriusContributionItemProvider.java21
-rw-r--r--plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/api/requests/DistributeRequest.java47
-rw-r--r--plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/api/requests/RequestConstants.java5
-rw-r--r--plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/api/ui/actions/ActionIds.java20
-rw-r--r--plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/internal/actions/distribute/DistributeAction.java347
-rw-r--r--plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/internal/editor/tabbar/actions/DistributeMenuManager.java47
-rw-r--r--plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/internal/editor/tabbar/actions/TabbarDistributeMenuManager.java117
-rw-r--r--plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/internal/editor/tabbar/contributions/DistributeMenuExtensionContributionFactory.java33
-rw-r--r--plugins/org.eclipse.sirius.diagram.ui/src/org/eclipse/sirius/diagram/ui/tools/api/image/DiagramImagesPath.java18
-rw-r--r--plugins/org.eclipse.sirius.doc/doc/Release Notes.html82
-rw-r--r--plugins/org.eclipse.sirius.doc/doc/Release Notes.textile11
-rw-r--r--plugins/org.eclipse.sirius.doc/doc/user/diagrams/Diagrams.html115
-rw-r--r--plugins/org.eclipse.sirius.doc/doc/user/diagrams/Diagrams.textile44
-rw-r--r--plugins/org.eclipse.sirius.doc/doc/user/diagrams/images/distribute_Centers.pngbin0 -> 31796 bytes
-rw-r--r--plugins/org.eclipse.sirius.doc/doc/user/diagrams/images/distribute_WithUniformGap.pngbin0 -> 30307 bytes
-rw-r--r--plugins/org.eclipse.sirius.doc/doc/user/diagrams/images/distribute_initialState.pngbin0 -> 50331 bytes
27 files changed, 1520 insertions, 68 deletions
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceContainerCreationPolicy.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceContainerCreationPolicy.java
index 0fcbfc28a4..24d22a08dd 100644
--- a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceContainerCreationPolicy.java
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceContainerCreationPolicy.java
@@ -62,6 +62,7 @@ import org.eclipse.sirius.diagram.ui.graphical.edit.policies.ContainerCreationEd
import org.eclipse.sirius.diagram.ui.graphical.edit.policies.CreationUtil;
import org.eclipse.sirius.diagram.ui.tools.api.command.DoNothingCommand;
import org.eclipse.sirius.diagram.ui.tools.api.editor.DDiagramEditor;
+import org.eclipse.sirius.diagram.ui.tools.api.requests.DistributeRequest;
import org.eclipse.sirius.diagram.ui.tools.internal.edit.command.CommandFactory;
import org.eclipse.sirius.ext.base.Option;
import org.eclipse.sirius.ext.gmf.runtime.editparts.GraphicalHelper;
@@ -70,9 +71,9 @@ import org.eclipse.sirius.viewpoint.description.tool.AbstractToolDescription;
import com.google.common.collect.Lists;
/**
- * An extension of the standard Sirius ContainerCreationEditPolicy which
- * knows how to handle the specific tools use to create frames (i.e. Interaction
- * Uses and Combined Fragments).
+ * An extension of the standard Sirius ContainerCreationEditPolicy which knows
+ * how to handle the specific tools use to create frames (i.e. Interaction Uses
+ * and Combined Fragments).
*
* @author pcdavid
*/
@@ -342,4 +343,9 @@ public class SequenceContainerCreationPolicy extends ContainerCreationEditPolicy
final IDiagramCommandFactory diagramCommandFactory = cmdFactoryProvider.getCommandFactory(domain);
return new SequenceDelegatingCommandFactory(diagramCommandFactory, domain, seqDiag, predecessor, location);
}
+
+ @Override
+ protected Command getDistributeCommand(DistributeRequest request) {
+ return UnexecutableCommand.INSTANCE;
+ }
}
diff --git a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceNodeCreationPolicy.java b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceNodeCreationPolicy.java
index bab9e72d4f..a1f9d7f212 100644
--- a/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceNodeCreationPolicy.java
+++ b/plugins/org.eclipse.sirius.diagram.sequence.ui/src/org/eclipse/sirius/diagram/sequence/ui/tool/internal/edit/policy/SequenceNodeCreationPolicy.java
@@ -57,6 +57,7 @@ import org.eclipse.sirius.diagram.ui.graphical.edit.policies.CreationUtil;
import org.eclipse.sirius.diagram.ui.graphical.edit.policies.NodeCreationEditPolicy;
import org.eclipse.sirius.diagram.ui.tools.api.editor.DDiagramEditor;
import org.eclipse.sirius.diagram.ui.tools.api.layout.LayoutUtils;
+import org.eclipse.sirius.diagram.ui.tools.api.requests.DistributeRequest;
import org.eclipse.sirius.ext.base.Option;
import org.eclipse.sirius.ext.base.Options;
import org.eclipse.sirius.ext.gmf.runtime.editparts.GraphicalHelper;
@@ -242,4 +243,9 @@ public class SequenceNodeCreationPolicy extends NodeCreationEditPolicy {
final IDiagramCommandFactory diagramCommandFactory = cmdFactoryProvider.getCommandFactory(domain);
return new SequenceDelegatingCommandFactory(diagramCommandFactory, domain, seqDiag, startingEndPredecessor, finishingEndPredecessor, location);
}
+
+ @Override
+ protected Command getDistributeCommand(DistributeRequest request) {
+ return UnexecutableCommand.INSTANCE;
+ }
}
diff --git a/plugins/org.eclipse.sirius.diagram.ui/META-INF/MANIFEST.MF b/plugins/org.eclipse.sirius.diagram.ui/META-INF/MANIFEST.MF
index 52e2818461..9f15a22457 100644
--- a/plugins/org.eclipse.sirius.diagram.ui/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.sirius.diagram.ui/META-INF/MANIFEST.MF
@@ -131,6 +131,7 @@ Export-Package: org.eclipse.sirius.diagram.description.concern.provider;version=
org.eclipse.sirius.diagram.ui.tools.api.wizards.page;version="2.0.0",
org.eclipse.sirius.diagram.ui.tools.internal.actions;version="2.0.0";x-internal:=true,
org.eclipse.sirius.diagram.ui.tools.internal.actions.delete;version="2.0.0";x-internal:=true,
+ org.eclipse.sirius.diagram.ui.tools.internal.actions.distribute;version="2.0.0";x-internal:=true,
org.eclipse.sirius.diagram.ui.tools.internal.actions.layout;version="2.0.0";x-internal:=true,
org.eclipse.sirius.diagram.ui.tools.internal.actions.pinning;version="2.0.0";x-internal:=true,
org.eclipse.sirius.diagram.ui.tools.internal.actions.refresh;version="2.0.0";x-internal:=true,
diff --git a/plugins/org.eclipse.sirius.diagram.ui/icons/distributeCentersHorizontal.gif b/plugins/org.eclipse.sirius.diagram.ui/icons/distributeCentersHorizontal.gif
new file mode 100644
index 0000000000..9a58a2ef84
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.ui/icons/distributeCentersHorizontal.gif
Binary files differ
diff --git a/plugins/org.eclipse.sirius.diagram.ui/icons/distributeCentersVertical.gif b/plugins/org.eclipse.sirius.diagram.ui/icons/distributeCentersVertical.gif
new file mode 100644
index 0000000000..ca8ebfc3d2
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.ui/icons/distributeCentersVertical.gif
Binary files differ
diff --git a/plugins/org.eclipse.sirius.diagram.ui/icons/distributeWithUniformGapHorizontal.gif b/plugins/org.eclipse.sirius.diagram.ui/icons/distributeWithUniformGapHorizontal.gif
new file mode 100644
index 0000000000..752946b49d
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.ui/icons/distributeWithUniformGapHorizontal.gif
Binary files differ
diff --git a/plugins/org.eclipse.sirius.diagram.ui/icons/distributeWithUniformGapVertical.gif b/plugins/org.eclipse.sirius.diagram.ui/icons/distributeWithUniformGapVertical.gif
new file mode 100644
index 0000000000..6021441a1f
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.ui/icons/distributeWithUniformGapVertical.gif
Binary files differ
diff --git a/plugins/org.eclipse.sirius.diagram.ui/icons/license.txt b/plugins/org.eclipse.sirius.diagram.ui/icons/license.txt
index 1aed0c7dfa..fc1c9c64d7 100644
--- a/plugins/org.eclipse.sirius.diagram.ui/icons/license.txt
+++ b/plugins/org.eclipse.sirius.diagram.ui/icons/license.txt
@@ -14,6 +14,10 @@ icons/collapseall.gif - org.eclipse.debug.ui - org.eclipse.debug.ui/icons/full/e
icons/delete.gif - org.eclipse.ui org.eclipse.ui/icons/full/obj16/delete_obj.gif
icons/deleteModel.gif - org.eclipse.search - org.eclipse.search/icons/full/elcl16/search_remall.gif
icons/disabled_co.gif - org.eclipse.debug.ui - org.eclipse.debug.ui/icons/full/elcl16/disabled_co.gif
+icons/distributeCentersHorizontal.gif - org.eclipse.gef - org.eclipse.gef/src/org/eclipse/gef/internal/icons/alignleft.gif
+icons/distributeCentersVertical.gif - org.eclipse.gef - org.eclipse.gef/src/org/eclipse/gef/internal/icons/alignleft.gif
+icons/distributeWithUniformGapHorizontal.gif - org.eclipse.gef - org.eclipse.gef/src/org/eclipse/gef/internal/icons/alignleft.gif
+icons/distributeWithUniformGapVertical.gif - org.eclipse.gef - org.eclipse.gef/src/org/eclipse/gef/internal/icons/alignleft.gif
icons/enabled_co.gif - org.eclipse.debug.ui - org.eclipse.debug.ui/icons/full/elcl16/enabled_co.gif
icons/expand.gif - org.eclipse.gmf.runtime.diagram.ui - org.eclipse.gmf.runtime.diagram.ui/icons/expand.gif
icons/expandall.gif - org.eclipse.debug.ui - org.eclipse.debug.ui/icons/full/elcl16/expandall.gif
diff --git a/plugins/org.eclipse.sirius.diagram.ui/plugin.xml b/plugins/org.eclipse.sirius.diagram.ui/plugin.xml
index 6d9bf80674..7f0c2375b5 100644
--- a/plugins/org.eclipse.sirius.diagram.ui/plugin.xml
+++ b/plugins/org.eclipse.sirius.diagram.ui/plugin.xml
@@ -149,6 +149,14 @@
<partAction toolbarPath="/arrangeMenu/arrangeGroup" id="arrangeBorderedNodesActionToolBar"/>
<!-- Add the DeselectAll action after selectAll action-->
<partAction menubarPath="/edit/selectAll" id="deselectAll"/>
+ <!-- Add distribute action in new group -->
+ <partMenu menubarPath="/diagramMenu/alignMenu" id="distributeMenu"/>
+ <partMenuGroup menubarPath="/diagramMenu/distributeMenu/" id="distributeHorizontalGroup"/>
+ <partMenuGroup menubarPath="/diagramMenu/distributeMenu/" id="distributeVerticalGroup"/>
+ <partAction menubarPath="/diagramMenu/distributeMenu/distributeHorizontalGroup" id="distributeHorizontallyWithUniformGaps"/>
+ <partAction menubarPath="/diagramMenu/distributeMenu/distributeHorizontalGroup" id="distributeCentersHorizontally"/>
+ <partAction menubarPath="/diagramMenu/distributeMenu/distributeVerticalGroup" id="distributeVerticallyWithUniformGaps"/>
+ <partAction menubarPath="/diagramMenu/distributeMenu/distributeVerticalGroup" id="distributeCentersVertically"/>
</partContribution>
<popupContribution class="org.eclipse.sirius.diagram.ui.tools.internal.menu.DiagramEditorContextMenuProvider">
@@ -162,6 +170,14 @@
<popupAction path="/formatMenu/pinGroup" id="pinElementsAction" />
<popupAction path="/formatMenu/pinGroup" id="unpinElementsAction" />
<popupAction path="/formatMenu/arrangeMenu/arrangeGroup" id="arrangeBorderedNodesAction"/>
+ <!-- Add distribute action in new distribute group -->
+ <popupMenu path="/formatMenu/alignMenu" id="distributeMenu"/>
+ <popupMenuGroup path="/formatMenu/distributeMenu/" id="distributeHorizontalGroup"/>
+ <popupMenuGroup path="/formatMenu/distributeMenu/" id="distributeVerticalGroup"/>
+ <popupAction path="/formatMenu/distributeMenu/distributeHorizontalGroup" id="distributeHorizontallyWithUniformGaps" />
+ <popupAction path="/formatMenu/distributeMenu/distributeHorizontalGroup" id="distributeCentersHorizontally"/>
+ <popupAction path="/formatMenu/distributeMenu/distributeVerticalGroup" id="distributeVerticallyWithUniformGaps"/>
+ <popupAction path="/formatMenu/distributeMenu/distributeVerticalGroup" id="distributeCentersVertically"/>
</popupContribution>
<popupContribution
class="org.eclipse.sirius.diagram.ui.tools.internal.menu.DiagramEditorContextMenuProvider">
@@ -1088,6 +1104,11 @@
point="org.eclipse.ui.menus">
<menuContribution
allPopups="false"
+ class="org.eclipse.sirius.diagram.ui.tools.internal.editor.tabbar.contributions.DistributeMenuExtensionContributionFactory"
+ locationURI="toolbar:org.eclipse.sirius.diagram.ui.tabbar?after=org.eclipse.sirius.diagram.ui.tabbar.arrangeselection">
+ </menuContribution>
+ <menuContribution
+ allPopups="false"
class="org.eclipse.sirius.diagram.ui.tools.internal.editor.tabbar.contributions.AlignMenutExtensionContributionFactory"
locationURI="toolbar:org.eclipse.sirius.diagram.ui.tabbar?after=org.eclipse.sirius.diagram.ui.tabbar.arrangeselection">
</menuContribution>
diff --git a/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/graphical/edit/policies/SiriusContainerEditPolicy.java b/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/graphical/edit/policies/SiriusContainerEditPolicy.java
index fa1b19fb52..0ff533d034 100644
--- a/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/graphical/edit/policies/SiriusContainerEditPolicy.java
+++ b/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/graphical/edit/policies/SiriusContainerEditPolicy.java
@@ -45,6 +45,8 @@ import org.eclipse.gmf.runtime.emf.commands.core.command.CompositeTransactionalC
import org.eclipse.gmf.runtime.notation.Node;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.sirius.diagram.ui.internal.edit.commands.DistributeCommand;
+import org.eclipse.sirius.diagram.ui.tools.api.requests.DistributeRequest;
import org.eclipse.sirius.diagram.ui.tools.internal.commands.SnapCommand;
import org.eclipse.sirius.diagram.ui.tools.internal.ui.GMFRuntimeCompatibility;
@@ -57,6 +59,16 @@ import org.eclipse.sirius.diagram.ui.tools.internal.ui.GMFRuntimeCompatibility;
*
*/
public class SiriusContainerEditPolicy extends ContainerEditPolicy {
+
+ @Override
+ public Command getCommand(Request request) {
+ if (org.eclipse.sirius.diagram.ui.tools.api.requests.RequestConstants.REQ_DISTRIBUTE.equals(request.getType())) {
+ return getDistributeCommand((DistributeRequest) request);
+ }
+
+ return super.getCommand(request);
+ }
+
// CHECKSTYLE:OFF
/**
* Override this method for version before GMF 1.5.0 with Eclipse 3.6.
@@ -186,5 +198,21 @@ public class SiriusContainerEditPolicy extends ContainerEditPolicy {
}
return null;
}
+
// CHECKSTYLE:ON
+
+ /**
+ * Gets a distribute command.
+ *
+ * @param request
+ * The distribute request
+ * @return command
+ */
+ protected Command getDistributeCommand(DistributeRequest request) {
+ List<IGraphicalEditPart> editparts = request.getEditParts();
+ if (!editparts.isEmpty() && getHost() instanceof IGraphicalEditPart) {
+ return new ICommandProxy(new DistributeCommand(((IGraphicalEditPart) getHost()).getEditingDomain(), editparts, request.getDistributeType()));
+ }
+ return null;
+ }
}
diff --git a/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/internal/edit/commands/DistributeCommand.java b/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/internal/edit/commands/DistributeCommand.java
new file mode 100644
index 0000000000..17e097e4f4
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/internal/edit/commands/DistributeCommand.java
@@ -0,0 +1,609 @@
+/*******************************************************************************
+ * Copyright (c) 2014 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.internal.edit.commands;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.PositionConstants;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.gmf.runtime.common.core.command.CommandResult;
+import org.eclipse.gmf.runtime.diagram.ui.commands.SetBoundsCommand;
+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.figures.IBorderItemLocator;
+import org.eclipse.gmf.runtime.emf.commands.core.command.AbstractTransactionalCommand;
+import org.eclipse.gmf.runtime.emf.commands.core.command.CompositeTransactionalCommand;
+import org.eclipse.gmf.runtime.emf.core.util.EObjectAdapter;
+import org.eclipse.gmf.runtime.notation.Node;
+import org.eclipse.sirius.diagram.ui.business.internal.operation.ShiftDirectBorderedNodesOperation;
+import org.eclipse.sirius.diagram.ui.tools.api.figure.locator.DBorderItemLocator;
+import org.eclipse.sirius.diagram.ui.tools.internal.actions.distribute.DistributeAction;
+import org.eclipse.sirius.diagram.ui.tools.internal.edit.command.CommandFactory;
+
+import com.google.common.base.Function;
+import com.google.common.base.Functions;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+/**
+ * This command distributes shapes.<BR>
+ * Performance information: This command is only time consumming on execution,
+ * not creation. The "real" command, <code>wrappedCommand</code>, is created
+ * during the execution.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ */
+public class DistributeCommand extends AbstractTransactionalCommand {
+ /** Command created only during the execution of the DistributeCommand. */
+ CompositeTransactionalCommand wrappedCommand;
+
+ /** List of parts to distribute. */
+ List<IGraphicalEditPart> editPartsToDistribute;
+
+ /**
+ * The distribution type must be one of:
+ * <UL>
+ * <LI>DistributeAction.HORIZONTALLY_WITH_UNIFORM_GAPS</LI>
+ * <LI>DistributeAction.CENTERS_HORIZONTALLY</LI>
+ * <LI>DistributeAction.VERTICALLY_WITH_UNIFORM_GAPS</LI>
+ * <LI>DistributeAction.CENTERS_VERTICALLY</LI>
+ * </UL>
+ */
+ private int distributeType;
+
+ /**
+ * Default constructor.
+ *
+ * @param domain
+ * my editing domain
+ * @param host
+ * the <i>host</i> EditPart on which the corresponding policy is
+ * installed.
+ * @param moveDelta
+ * The move delta
+ * @param movedEditParts
+ * Selected edit parts that will be moved (distributed)
+ */
+ public DistributeCommand(TransactionalEditingDomain domain, List<IGraphicalEditPart> editPartsToDistribute, int distributeType) {
+ super(domain, DistributeAction.getLabel(distributeType, true), null);
+ this.editPartsToDistribute = editPartsToDistribute;
+ this.distributeType = distributeType;
+ }
+
+ @Override
+ protected CommandResult doExecuteWithResult(IProgressMonitor monitor, IAdaptable info) {
+ CommandResult result = CommandResult.newOKCommandResult();
+ if (wrappedCommand == null) {
+ wrappedCommand = new CompositeTransactionalCommand(getEditingDomain(), this.getLabel());
+
+ HashMap<IGraphicalEditPart, Rectangle> partToBounds = Maps.newHashMap();
+ for (IGraphicalEditPart part : editPartsToDistribute) {
+ Rectangle bounds = part.getFigure().getBounds().getCopy();
+ partToBounds.put(part, bounds);
+ }
+
+ if (distributeType == DistributeAction.HORIZONTALLY_WITH_UNIFORM_GAPS) {
+ distributeHorizontallyWithUniformGaps(partToBounds);
+ } else if (distributeType == DistributeAction.CENTERS_HORIZONTALLY) {
+ distributeCentersHorizontally(partToBounds);
+ } else if (distributeType == DistributeAction.VERTICALLY_WITH_UNIFORM_GAPS) {
+ distributeVerticallyWithUniformGaps(partToBounds);
+ } else if (distributeType == DistributeAction.CENTERS_VERTICALLY) {
+ distributeCentersVertically(partToBounds);
+ }
+ }
+
+ if (wrappedCommand.size() > 0) {
+ if (wrappedCommand.canExecute()) {
+ try {
+ wrappedCommand.execute(new NullProgressMonitor(), null);
+ } catch (ExecutionException e) {
+ result = CommandResult.newErrorCommandResult(e);
+ }
+ } else {
+ // Not expected to be there
+ result = CommandResult.newWarningCommandResult("The distribution of selected elements can not be done.", null);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * A {@link Comparator} that sorts the {@link IGraphicalEditPart parts} by
+ * the x coordinate of the center of the bounds of the part.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ */
+ public class PartByCenter implements Comparator<IGraphicalEditPart> {
+
+ HashMap<IGraphicalEditPart, Rectangle> partToBounds;
+
+ /**
+ * Default constructor.
+ */
+ public PartByCenter(HashMap<IGraphicalEditPart, Rectangle> partToBounds) {
+ this.partToBounds = partToBounds;
+ }
+
+ @Override
+ public int compare(IGraphicalEditPart part1, IGraphicalEditPart part2) {
+ Integer a = Integer.valueOf(partToBounds.get(part1).getCenter().x);
+ Integer b = Integer.valueOf(partToBounds.get(part2).getCenter().x);
+ return a.compareTo(b);
+ }
+ }
+
+ /**
+ * A {@link Comparator} that sorts the {@link IGraphicalEditPart parts} by
+ * the y coordinate of the center of the bounds of the part.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ */
+ public class PartByMiddle implements Comparator<IGraphicalEditPart> {
+
+ HashMap<IGraphicalEditPart, Rectangle> partToBounds;
+
+ /**
+ * Default constructor.
+ */
+ public PartByMiddle(HashMap<IGraphicalEditPart, Rectangle> partToBounds) {
+ this.partToBounds = partToBounds;
+ }
+
+ @Override
+ public int compare(IGraphicalEditPart part1, IGraphicalEditPart part2) {
+ Integer a = Integer.valueOf(partToBounds.get(part1).getCenter().y);
+ Integer b = Integer.valueOf(partToBounds.get(part2).getCenter().y);
+ return a.compareTo(b);
+ }
+ }
+
+ /**
+ * A function to get the new bounds according to the bounds of the previous
+ * edit part and the gap. The {@link #apply(Object, Rectangle, int)} must be
+ * called instead of {@link #apply(Object)} for this function. This function
+ * does not modify the original bounds.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ *
+ * @param <IGraphicalEditPart>
+ * The edit part from which getting the new bounds
+ * @param <Rectangle>
+ * The returned value
+ */
+ public abstract class GetNewBoundsFunction implements Function<IGraphicalEditPart, Rectangle> {
+ protected int gap;
+
+ protected Rectangle previousPartBounds;
+
+ public Rectangle apply(IGraphicalEditPart input, Rectangle previousPartBounds, int gap) {
+ this.gap = gap;
+ this.previousPartBounds = previousPartBounds;
+ return apply(input);
+ };
+ };
+
+ /**
+ * A function with {@link HashMap<IGraphicalEditPart, Rectangle>} as
+ * parameter.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ *
+ */
+ public abstract class FunctionWithBounds implements Function<IGraphicalEditPart, Integer> {
+ HashMap<IGraphicalEditPart, Rectangle> partsToBounds;
+
+ public FunctionWithBounds(HashMap<IGraphicalEditPart, Rectangle> partsToBounds) {
+ this.partsToBounds = partsToBounds;
+ }
+
+ @Override
+ public Integer apply(IGraphicalEditPart input) {
+ return apply(partsToBounds.get(input));
+ }
+
+ protected abstract Integer apply(Rectangle rectangle);
+
+ };
+
+ /**
+ * Get the x coordinate of the left side of the edit part.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ */
+ public class GetLeftFunction extends FunctionWithBounds {
+ public GetLeftFunction(HashMap<IGraphicalEditPart, Rectangle> partsToBounds) {
+ super(partsToBounds);
+ }
+
+ protected Integer apply(Rectangle rectangle) {
+ return new Integer(rectangle.x);
+ };
+ };
+
+ /**
+ * Get the x coordinate of the center of the edit part.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ */
+ public class GetCenterFunction extends FunctionWithBounds {
+ public GetCenterFunction(HashMap<IGraphicalEditPart, Rectangle> partsToBounds) {
+ super(partsToBounds);
+ }
+
+ protected Integer apply(Rectangle rectangle) {
+ return new Integer(rectangle.getCenter().x);
+ };
+ };
+
+ /**
+ * Get the x coordinate of the right side of the edit part.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ */
+ public class GetRightFunction extends FunctionWithBounds {
+ public GetRightFunction(HashMap<IGraphicalEditPart, Rectangle> partsToBounds) {
+ super(partsToBounds);
+ }
+
+ protected Integer apply(Rectangle rectangle) {
+ return new Integer(rectangle.getRight().x);
+ };
+ };
+
+ /**
+ * Get the y coordinate of the top side of the edit part.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ */
+ public class GetTopFunction extends FunctionWithBounds {
+ public GetTopFunction(HashMap<IGraphicalEditPart, Rectangle> partsToBounds) {
+ super(partsToBounds);
+ }
+
+ protected Integer apply(Rectangle rectangle) {
+ return new Integer(rectangle.y);
+ };
+ };
+
+ /**
+ * Get the y coordinate of the center the edit part.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ */
+ public class GetMiddleFunction extends FunctionWithBounds {
+ public GetMiddleFunction(HashMap<IGraphicalEditPart, Rectangle> partsToBounds) {
+ super(partsToBounds);
+ }
+
+ protected Integer apply(Rectangle rectangle) {
+ return new Integer(rectangle.getCenter().y);
+ };
+ };
+
+ /**
+ * Get the y coordinate of the bottom side of the edit part.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ */
+ public class GetBottomFunction extends FunctionWithBounds {
+ public GetBottomFunction(HashMap<IGraphicalEditPart, Rectangle> partsToBounds) {
+ super(partsToBounds);
+ }
+
+ protected Integer apply(Rectangle rectangle) {
+ return new Integer(rectangle.getBottom().y);
+ };
+ };
+
+ /**
+ * Get width of the edit part.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ */
+ public class GetWidthFunction extends FunctionWithBounds {
+ public GetWidthFunction(HashMap<IGraphicalEditPart, Rectangle> partsToBounds) {
+ super(partsToBounds);
+ }
+
+ protected Integer apply(Rectangle rectangle) {
+ return new Integer(rectangle.width);
+ };
+ };
+
+ /**
+ * Get height of the edit part.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ */
+ public class GetHeightFunction extends FunctionWithBounds {
+ public GetHeightFunction(HashMap<IGraphicalEditPart, Rectangle> partsToBounds) {
+ super(partsToBounds);
+ }
+
+ protected Integer apply(Rectangle rectangle) {
+ return new Integer(rectangle.height);
+ };
+ };
+
+ /**
+ * Function to compute the gap for the parts to distribute.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ */
+ public abstract class GetGapFunction {
+ protected Set<IGraphicalEditPart> partsToDistribute;
+
+ protected Function<IGraphicalEditPart, Integer> getFirstPartMainAxisFunction;
+
+ protected Function<IGraphicalEditPart, Integer> getLastPartMainAxisFunction;
+
+ protected Function<IGraphicalEditPart, Integer> getSizeFunction;
+
+ public GetGapFunction(Set<IGraphicalEditPart> partsToDistribute, Function<IGraphicalEditPart, Integer> getFirstPartMainAxisFunction,
+ Function<IGraphicalEditPart, Integer> getLastPartMainAxisFunction, Function<IGraphicalEditPart, Integer> getSizeFunction) {
+ this.partsToDistribute = partsToDistribute;
+ this.getFirstPartMainAxisFunction = getFirstPartMainAxisFunction;
+ this.getLastPartMainAxisFunction = getLastPartMainAxisFunction;
+ this.getSizeFunction = getSizeFunction;
+ }
+
+ public abstract int apply(IGraphicalEditPart firstPart, IGraphicalEditPart lastPart);
+ }
+
+ /**
+ * Must be called only when <code>wrappedCommand</code> is initialized.
+ *
+ * @param partsToBounds
+ * List of parts to distribute associated with their bounds (the
+ * bounds of their figure).
+ */
+ private void distributeHorizontallyWithUniformGaps(final HashMap<IGraphicalEditPart, Rectangle> partsToBounds) {
+ GetNewBoundsFunction setXFunction = new GetNewBoundsFunction() {
+ public Rectangle apply(IGraphicalEditPart input) {
+ return partsToBounds.get(input).getCopy().setX(previousPartBounds.getRight().x + gap);
+ };
+ };
+ distributeWithUniformGaps(partsToBounds.keySet(), new GetLeftFunction(partsToBounds), new GetTopFunction(partsToBounds), new GetRightFunction(partsToBounds), new GetBottomFunction(
+ partsToBounds), new GetWidthFunction(partsToBounds), new PartByCenter(partsToBounds), setXFunction, Functions.forMap(partsToBounds));
+ }
+
+ /**
+ * Must be called only when <code>wrappedCommand</code> is initialized.
+ *
+ * @param partsToBounds
+ * List of parts to distribute associated with their bounds.
+ */
+ private void distributeVerticallyWithUniformGaps(final HashMap<IGraphicalEditPart, Rectangle> partsToBounds) {
+ GetNewBoundsFunction setYFunction = new GetNewBoundsFunction() {
+ public Rectangle apply(IGraphicalEditPart input) {
+ return partsToBounds.get(input).getCopy().setY(previousPartBounds.getBottom().y + gap);
+ };
+ };
+ distributeWithUniformGaps(partsToBounds.keySet(), new GetTopFunction(partsToBounds), new GetLeftFunction(partsToBounds), new GetBottomFunction(partsToBounds), new GetRightFunction(
+ partsToBounds), new GetHeightFunction(partsToBounds), new PartByMiddle(partsToBounds), setYFunction, Functions.forMap(partsToBounds));
+ }
+
+ private void distributeWithUniformGaps(Set<IGraphicalEditPart> partsToDistribute, Function<IGraphicalEditPart, Integer> getFirstPartMainAxisFunction,
+ Function<IGraphicalEditPart, Integer> getFirstPartSecondAxisFunction, Function<IGraphicalEditPart, Integer> getLastPartMainAxisFunction,
+ Function<IGraphicalEditPart, Integer> getLastPartSecondAxisFunction, Function<IGraphicalEditPart, Integer> getSizeFunction, Comparator<IGraphicalEditPart> comparator,
+ GetNewBoundsFunction setValueFunction, Function<IGraphicalEditPart, Rectangle> getBoundsFunction) {
+ distribute(partsToDistribute, getFirstPartMainAxisFunction, getFirstPartSecondAxisFunction, getLastPartMainAxisFunction, getLastPartSecondAxisFunction, comparator, setValueFunction,
+ getBoundsFunction, new GetGapFunction(partsToDistribute, getFirstPartMainAxisFunction, getLastPartMainAxisFunction, getSizeFunction) {
+ @Override
+ public int apply(IGraphicalEditPart firstPart, IGraphicalEditPart lastPart) {
+ // Get available space between these 2 parts
+ int availableSpaceBetweenFirstAndLast = getFirstPartMainAxisFunction.apply(lastPart) - getLastPartMainAxisFunction.apply(firstPart);
+ // Get remaining space considering the size of other
+ // parts
+ int availableSpace = availableSpaceBetweenFirstAndLast;
+ for (IGraphicalEditPart part : partsToDistribute) {
+ if (!part.equals(firstPart) && !part.equals(lastPart)) {
+ availableSpace -= getSizeFunction.apply(part);
+ }
+ }
+ return availableSpace / (partsToDistribute.size() - 1);
+ }
+ });
+ }
+
+ /**
+ * Must be called only when <code>wrappedCommand</code> is initialized.
+ *
+ * @param partsToBounds
+ * List of parts to distribute associated with their bounds.
+ */
+ private void distributeCentersHorizontally(final HashMap<IGraphicalEditPart, Rectangle> partsToBounds) {
+ GetNewBoundsFunction setCenterFunction = new GetNewBoundsFunction() {
+ public Rectangle apply(IGraphicalEditPart input) {
+ Rectangle r = partsToBounds.get(input).getCopy();
+ return r.setX(previousPartBounds.getCenter().x + gap - (r.width / 2));
+ };
+ };
+
+ distributeCenters(partsToBounds.keySet(), new GetCenterFunction(partsToBounds), new GetTopFunction(partsToBounds), new GetBottomFunction(partsToBounds), new GetWidthFunction(partsToBounds),
+ new PartByCenter(partsToBounds), setCenterFunction, Functions.forMap(partsToBounds));
+ }
+
+ /**
+ * Must be called only when <code>wrappedCommand</code> is initialized.
+ *
+ * @param partsToBounds
+ * List of parts to distribute associated with their bounds.
+ */
+ private void distributeCentersVertically(final HashMap<IGraphicalEditPart, Rectangle> partsToBounds) {
+ GetNewBoundsFunction setMiddleFunction = new GetNewBoundsFunction() {
+ public Rectangle apply(IGraphicalEditPart input) {
+ Rectangle r = partsToBounds.get(input).getCopy();
+ return r.setY(previousPartBounds.getCenter().y + gap - (r.height / 2));
+ };
+ };
+ distributeCenters(partsToBounds.keySet(), new GetMiddleFunction(partsToBounds), new GetLeftFunction(partsToBounds), new GetRightFunction(partsToBounds), new GetHeightFunction(partsToBounds),
+ new PartByMiddle(partsToBounds), setMiddleFunction, Functions.forMap(partsToBounds));
+ }
+
+ private void distributeCenters(Set<IGraphicalEditPart> partsToDistribute, Function<IGraphicalEditPart, Integer> getMainAxisFunction,
+ Function<IGraphicalEditPart, Integer> getFirstPartSecondAxisFunction, Function<IGraphicalEditPart, Integer> getLastPartSecondAxisFunction,
+ Function<IGraphicalEditPart, Integer> getSizeFunction, Comparator<IGraphicalEditPart> comparator, GetNewBoundsFunction setValueFunction,
+ Function<IGraphicalEditPart, Rectangle> getBoundsFunction) {
+ distribute(partsToDistribute, getMainAxisFunction, getFirstPartSecondAxisFunction, getMainAxisFunction, getLastPartSecondAxisFunction, comparator, setValueFunction, getBoundsFunction,
+ new GetGapFunction(partsToDistribute, getMainAxisFunction, getMainAxisFunction, getSizeFunction) {
+ @Override
+ public int apply(IGraphicalEditPart firstPart, IGraphicalEditPart lastPart) {
+ return (getFirstPartMainAxisFunction.apply(lastPart) - getLastPartMainAxisFunction.apply(firstPart)) / (partsToDistribute.size() - 1);
+ }
+ });
+ }
+
+ /**
+ * Generic distribute method that distributes shapes according to parameters
+ * to customize the distribution.
+ *
+ * @param partsToDistribute
+ * List of {@link IGraphicalEditPart parts} to distribute
+ * (including the first and the last that don't move).
+ * @param getFirstPartMainAxisFunction
+ * A function that returns the x or y coordinate of the Point to
+ * consider for detecting the first part
+ * @param getFirstPartSecondAxisFunction
+ * If at least two part have the same coordinate for the main
+ * axis, this function is used to choose the first part
+ * @param getLastPartMainAxisFunction
+ * A function that returns the x or y coordinate of the Point to
+ * consider for detecting the last part
+ * @param getLastPartSecondAxisFunction
+ * If at least two part have the same coordinate for the main
+ * axis, this function is used to choose the last part
+ * @param comparator
+ * A comparator to sort the part from left to right or from top
+ * to bottom
+ * @param getNewBoundsFunction
+ * A function to set the new location of the part after
+ * distribution
+ * @param getBoundsFunction
+ * A function that returns the current bounds rectangle
+ * @param getGapFunction
+ * A function to get the gap between each part after distribution
+ */
+ private void distribute(Collection<IGraphicalEditPart> partsToDistribute, Function<IGraphicalEditPart, Integer> getFirstPartMainAxisFunction,
+ Function<IGraphicalEditPart, Integer> getFirstPartSecondAxisFunction, Function<IGraphicalEditPart, Integer> getLastPartMainAxisFunction,
+ Function<IGraphicalEditPart, Integer> getLastPartSecondAxisFunction, Comparator<IGraphicalEditPart> comparator, GetNewBoundsFunction getNewBoundsFunction,
+ Function<IGraphicalEditPart, Rectangle> getBoundsFunction, GetGapFunction getGapFunction) {
+ // Get first and last parts
+ int firstPartMainAxis = 0;
+ int firstPartSecondAxis = 0;
+ int lastPartMainAxis = 0;
+ int lastPartSecondAxis = 0;
+ IGraphicalEditPart firstPart = null;
+ IGraphicalEditPart lastPart = null;
+ for (IGraphicalEditPart part : partsToDistribute) {
+ if (firstPart == null || getFirstPartMainAxisFunction.apply(part) < firstPartMainAxis
+ || (getFirstPartMainAxisFunction.apply(part) == firstPartMainAxis && getFirstPartSecondAxisFunction.apply(part) < firstPartSecondAxis)) {
+ firstPart = part;
+ firstPartMainAxis = getFirstPartMainAxisFunction.apply(part);
+ firstPartSecondAxis = getFirstPartSecondAxisFunction.apply(part);
+ }
+ if (lastPart == null || getLastPartMainAxisFunction.apply(part) > lastPartMainAxis
+ || (getLastPartMainAxisFunction.apply(part) == lastPartMainAxis && getLastPartSecondAxisFunction.apply(part) > lastPartSecondAxis)) {
+ lastPart = part;
+ lastPartMainAxis = getLastPartMainAxisFunction.apply(part);
+ lastPartSecondAxis = getLastPartSecondAxisFunction.apply(part);
+ }
+ }
+ // Get the gap between each parts
+ int gap = getGapFunction.apply(firstPart, lastPart);
+ // Sort other parts according to their centers
+ List<IGraphicalEditPart> partsToMove = Lists.newArrayList(partsToDistribute);
+ partsToMove.remove(firstPart);
+ partsToMove.remove(lastPart);
+ Collections.sort(partsToMove, comparator);
+ Rectangle previousPartBounds = getBoundsFunction.apply(firstPart);
+ // Move other parts with the same gap
+ if (!(partsToMove.get(0) instanceof IBorderItemEditPart)) {
+ for (IGraphicalEditPart editPart : partsToMove) {
+ Rectangle newBounds = getNewBoundsFunction.apply(editPart, previousPartBounds, gap);
+ IAdaptable adapter = new EObjectAdapter((Node) editPart.getModel());
+ wrappedCommand.compose(new SetBoundsCommand(wrappedCommand.getEditingDomain(), wrappedCommand.getLabel(), adapter, newBounds));
+ previousPartBounds = newBounds;
+ }
+ } else {
+ HashMap<IGraphicalEditPart, IFigure> partToFigureToIgnore = Maps.newHashMap();
+ List<IFigure> additionalFiguresForConflictsDetection = Lists.newArrayList();
+ for (IGraphicalEditPart editPart : partsToMove) {
+ partToFigureToIgnore.put(editPart, editPart.getFigure());
+ }
+
+ for (IGraphicalEditPart editPart : partsToMove) {
+ Rectangle expectedNewBounds = getNewBoundsFunction.apply(editPart, previousPartBounds, gap);
+ Rectangle newBounds = expectedNewBounds.getCopy();
+ if (editPart instanceof IBorderItemEditPart) {
+ // If this bounds is for a border node, we must check that
+ // there is no conflicts with existing
+ IBorderItemEditPart borderEditPart = (IBorderItemEditPart) editPart;
+ IBorderItemLocator borderItemLocator = borderEditPart.getBorderItemLocator();
+ if (borderItemLocator instanceof DBorderItemLocator) {
+ newBounds = ((DBorderItemLocator) borderItemLocator).getValidLocation(newBounds, editPart.getFigure(), partToFigureToIgnore.values(), additionalFiguresForConflictsDetection);
+ } else {
+ newBounds = borderItemLocator.getValidLocation(newBounds, editPart.getFigure());
+ }
+ // Remove this figure from the list to ignore and add them
+ // to the additional figures with its new bounds.
+ partToFigureToIgnore.remove(editPart);
+ editPart.getFigure().setBounds(newBounds);
+ additionalFiguresForConflictsDetection.add(editPart.getFigure());
+ }
+ Dimension delta = newBounds.getLocation().getDifference(getBoundsFunction.apply(editPart).getLocation());
+ if (delta.width != 0) {
+ wrappedCommand.compose(CommandFactory.createICommand(wrappedCommand.getEditingDomain(), new ShiftDirectBorderedNodesOperation(Lists.newArrayList((Node) editPart.getModel()),
+ delta.width, PositionConstants.HORIZONTAL)));
+ } else {
+ wrappedCommand.compose(CommandFactory.createICommand(wrappedCommand.getEditingDomain(), new ShiftDirectBorderedNodesOperation(Lists.newArrayList((Node) editPart.getModel()),
+ delta.height, PositionConstants.VERTICAL)));
+ }
+ previousPartBounds = expectedNewBounds;
+ }
+ }
+ }
+
+ @Override
+ public boolean canUndo() {
+ if (wrappedCommand.size() > 0 && wrappedCommand != null) {
+ return wrappedCommand.canUndo();
+ }
+ return true;
+ }
+
+ @Override
+ public boolean canRedo() {
+ if (wrappedCommand.size() > 0 && wrappedCommand != null) {
+ return wrappedCommand.canRedo();
+ }
+ return true;
+ }
+
+ @Override
+ public void dispose() {
+ editPartsToDistribute = null;
+ wrappedCommand = null;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/internal/providers/SiriusContributionItemProvider.java b/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/internal/providers/SiriusContributionItemProvider.java
index 6567c8b2f2..ab6cc2748f 100644
--- a/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/internal/providers/SiriusContributionItemProvider.java
+++ b/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/internal/providers/SiriusContributionItemProvider.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2008 THALES GLOBAL SERVICES.
+ * Copyright (c) 2007, 2014 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
@@ -14,16 +14,19 @@ import org.eclipse.gmf.runtime.common.ui.services.action.contributionitem.Abstra
import org.eclipse.gmf.runtime.common.ui.util.IWorkbenchPartDescriptor;
import org.eclipse.gmf.runtime.diagram.ui.printing.actions.PrintPreviewAction;
import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuManager;
import org.eclipse.sirius.diagram.ui.tools.api.ui.actions.ActionIds;
import org.eclipse.sirius.diagram.ui.tools.internal.actions.DeselectAllAction;
import org.eclipse.sirius.diagram.ui.tools.internal.actions.SaveAsImageFileAction;
import org.eclipse.sirius.diagram.ui.tools.internal.actions.SelectHiddenElementsAction;
import org.eclipse.sirius.diagram.ui.tools.internal.actions.TabbarRouterAction;
+import org.eclipse.sirius.diagram.ui.tools.internal.actions.distribute.DistributeAction;
import org.eclipse.sirius.diagram.ui.tools.internal.actions.layout.ArrangeBorderedNodesAction;
import org.eclipse.sirius.diagram.ui.tools.internal.actions.layout.CopyLayoutAction;
import org.eclipse.sirius.diagram.ui.tools.internal.actions.layout.PasteLayoutAction;
import org.eclipse.sirius.diagram.ui.tools.internal.actions.pinning.PinElementsEclipseAction;
import org.eclipse.sirius.diagram.ui.tools.internal.actions.pinning.UnpinElementsEclipseAction;
+import org.eclipse.sirius.diagram.ui.tools.internal.editor.tabbar.actions.DistributeMenuManager;
import org.eclipse.sirius.diagram.ui.tools.internal.print.SiriusDiagramPrintPreviewAction;
import org.eclipse.sirius.diagram.ui.tools.internal.print.SiriusEnhancedPrintActionHelper;
import org.eclipse.ui.IWorkbenchPage;
@@ -64,9 +67,25 @@ public class SiriusContributionItemProvider extends AbstractContributionItemProv
result = TabbarRouterAction.createTreeRouterAction(workbenchPage);
} else if (ActionIds.DESELECT_ALL.equals(actionId)) {
result = new DeselectAllAction();
+ } else if (ActionIds.DISTRIBUTE_HORIZONTALLY_WITH_UNIFORM_GAPS.equals(actionId)) {
+ result = DistributeAction.createDistributeHorizontallyWithUniformGapsAction(workbenchPage, false);
+ } else if (ActionIds.DISTRIBUTE_CENTERS_HORIZONTALLY.equals(actionId)) {
+ result = DistributeAction.createDistributeCentersHorizontallyAction(workbenchPage, false);
+ } else if (ActionIds.DISTRIBUTE_VERTICALLY_WITH_UNIFORM_GAPS.equals(actionId)) {
+ result = DistributeAction.createDistributeVerticallyWithUniformGapsAction(workbenchPage, false);
+ } else if (ActionIds.DISTRIBUTE_CENTERS_VERTICALLY.equals(actionId)) {
+ result = DistributeAction.createDistributeCentersVerticallyAction(workbenchPage, false);
} else {
result = super.createAction(actionId, partDescriptor);
}
return result;
}
+
+ @Override
+ protected IMenuManager createMenuManager(String menuId, IWorkbenchPartDescriptor partDescriptor) {
+ if (menuId.equals(ActionIds.MENU_DISTRIBUTE)) {
+ return new DistributeMenuManager();
+ }
+ return super.createMenuManager(menuId, partDescriptor);
+ }
}
diff --git a/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/api/requests/DistributeRequest.java b/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/api/requests/DistributeRequest.java
new file mode 100644
index 0000000000..b722cb0d27
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/api/requests/DistributeRequest.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2014 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.requests;
+
+import org.eclipse.gef.requests.ChangeBoundsRequest;
+
+/**
+ * A {@link ChangeBoundsRequest} to manage distribution of shapes.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ */
+public class DistributeRequest extends ChangeBoundsRequest {
+
+ /**
+ * The distribution type must by one of:
+ * <UL>
+ * <LI>DistributeAction.HORIZONTALLY_WITH_UNIFORM_GAPS</LI>
+ * <LI>DistributeAction.CENTERS_HORIZONTALLY</LI>
+ * <LI>DistributeAction.VERTICALLY_WITH_UNIFORM_GAPS</LI>
+ * <LI>DistributeAction.CENTERS_VERTICALLY</LI>
+ * </UL>
+ */
+ private int distributeType;
+
+ /**
+ * Default constructor.
+ */
+ public DistributeRequest() {
+ super(RequestConstants.REQ_DISTRIBUTE);
+ }
+
+ public void setDistributeType(int distributeType) {
+ this.distributeType = distributeType;
+ }
+
+ public int getDistributeType() {
+ return distributeType;
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/api/requests/RequestConstants.java b/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/api/requests/RequestConstants.java
index 3db92922a1..6e879cfe19 100644
--- a/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/api/requests/RequestConstants.java
+++ b/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/api/requests/RequestConstants.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2010 THALES GLOBAL SERVICES.
+ * Copyright (c) 2010, 2014 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
@@ -41,4 +41,7 @@ public interface RequestConstants extends org.eclipse.gmf.runtime.diagram.ui.req
/** request type for quotation rotation. */
String REQ_ROTATE_BENDPOINT = "rotateBendpoint";
+ /** request to distribute shapes. */
+ String REQ_DISTRIBUTE = "distribute";
+
}
diff --git a/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/api/ui/actions/ActionIds.java b/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/api/ui/actions/ActionIds.java
index d7112946af..7adae69504 100644
--- a/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/api/ui/actions/ActionIds.java
+++ b/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/api/ui/actions/ActionIds.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2009, 2009 THALES GLOBAL SERVICES.
+ * Copyright (c) 2009, 2014 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
@@ -10,6 +10,8 @@
*******************************************************************************/
package org.eclipse.sirius.diagram.ui.tools.api.ui.actions;
+import org.eclipse.sirius.diagram.ui.tools.api.requests.RequestConstants;
+
/**
* A list of constants defining the diagram action and menu action ids.
* <p>
@@ -59,4 +61,20 @@ public interface ActionIds {
/** Action to deselect all elements (select diagram). **/
String DESELECT_ALL = "deselectAll";
+
+ /** Id of menu that groups distribute actions. **/
+ String MENU_DISTRIBUTE = "distributeMenu";
+
+ /** Action's id to distribute centers horizontally. */
+ String DISTRIBUTE_CENTERS_HORIZONTALLY = RequestConstants.REQ_DISTRIBUTE + "CentersHorizontally";
+
+ /** Action's id to distribute horizontally with uniform gaps. */
+ String DISTRIBUTE_HORIZONTALLY_WITH_UNIFORM_GAPS = RequestConstants.REQ_DISTRIBUTE + "HorizontallyWithUniformGaps";
+
+ /** Action's id to distribute centers vertically. */
+ String DISTRIBUTE_CENTERS_VERTICALLY = RequestConstants.REQ_DISTRIBUTE + "CentersVertically";
+
+ /** Action's id to distribute vertically with uniform gaps. */
+ String DISTRIBUTE_VERTICALLY_WITH_UNIFORM_GAPS = RequestConstants.REQ_DISTRIBUTE + "VerticallyWithUniformGaps";
+
}
diff --git a/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/internal/actions/distribute/DistributeAction.java b/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/internal/actions/distribute/DistributeAction.java
new file mode 100644
index 0000000000..afbaf74e9a
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/internal/actions/distribute/DistributeAction.java
@@ -0,0 +1,347 @@
+/*******************************************************************************
+ * Copyright (c) 2014 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.actions.distribute;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.draw2d.PositionConstants;
+import org.eclipse.gef.ConnectionEditPart;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.Request;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.tools.ToolUtilities;
+import org.eclipse.gmf.runtime.common.core.util.StringStatics;
+import org.eclipse.gmf.runtime.diagram.ui.actions.DiagramAction;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IBorderItemEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.sirius.diagram.ui.provider.DiagramUIPlugin;
+import org.eclipse.sirius.diagram.ui.tools.api.image.DiagramImagesPath;
+import org.eclipse.sirius.diagram.ui.tools.api.requests.DistributeRequest;
+import org.eclipse.sirius.diagram.ui.tools.api.ui.actions.ActionIds;
+import org.eclipse.ui.IWorkbenchPage;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+/**
+ * A {@link DiagramAction} to distribute shapes.<BR>
+ * Inspired by the class
+ * {@link org.eclipse.gmf.runtime.diagram.ui.actions.internal.ArrangeAction}.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ */
+@SuppressWarnings("restriction")
+public class DistributeAction extends DiagramAction {
+
+ /** Constant indicating horizontal distribution with uniform gaps. */
+ public static final int HORIZONTALLY_WITH_UNIFORM_GAPS = 0;
+
+ /** Constant indicating distribution of centers horizontally. */
+ public static final int CENTERS_HORIZONTALLY = 1;
+
+ /** Constant indicating vertical distribution with uniform gaps. */
+ public static final int VERTICALLY_WITH_UNIFORM_GAPS = 2;
+
+ /** Constant indicating distribution of centers vertically. */
+ public static final int CENTERS_VERTICALLY = 3;
+
+ /** Prefix used for label when the action is displayed in the tab bar. */
+ private static final String DISTRIBUTE_PREFIX = "Distribute ";
+
+ /** Label for horizontal distribution with uniform gaps. */
+ private static final String HORIZONTALLY_WITH_UNIFORM_GAPS_LABEL = "Horizontally With Uniform Gaps";
+
+ /** Label for distribution of centers horizontally. */
+ private static final String CENTERS_HORIZONTALLY_LABEL = "Centers Evenly Horizontally";
+
+ /** Label for vertical distribution with uniform gaps. */
+ private static final String VERTICALLY_WITH_UNIFORM_GAPS_LABEL = "Vertically With Uniform Gaps";
+
+ /** Label for distribution of centers vertically. */
+ private static final String CENTERS_VERTICALLY_LABEL = "Centers Evenly Vertically";
+
+ /**
+ * The distribution type must by one of:
+ * <UL>
+ * <LI>DistributeAction.HORIZONTALLY_WITH_UNIFORM_GAPS</LI>
+ * <LI>DistributeAction.CENTERS_HORIZONTALLY</LI>
+ * <LI>DistributeAction.VERTICALLY_WITH_UNIFORM_GAPS</LI>
+ * <LI>DistributeAction.CENTERS_VERTICALLY</LI>
+ * </UL>
+ */
+ private int distributeType;
+
+ /**
+ * Constructs a DistributeAction with the given part and distribute type.
+ *
+ * The distribute type must by one of:
+ * <UL>
+ * <LI>DistributeAction.HORIZONTALLY_WITH_UNIFORM_GAPS</LI>
+ * <LI>DistributeAction.CENTERS_HORIZONTALLY</LI>
+ * <LI>DistributeAction.VERTICALLY_WITH_UNIFORM_GAPS</LI>
+ * <LI>DistributeAction.CENTERS_VERTICALLY</LI>
+ * </UL>
+ *
+ * @param workbenchPage
+ * the workbench part used to obtain context
+ * @param distributeType
+ * The distribute type
+ * @param isToolbarItem
+ * the indicator of whether or not this is a toolbar action as
+ * opposed to a context-menu action.
+ */
+ protected DistributeAction(IWorkbenchPage workbenchPage, int distributeType, boolean isToolbarItem) {
+ super(workbenchPage);
+ this.distributeType = distributeType;
+ setText(getLabel(distributeType, isToolbarItem));
+ setToolTipText(getText());
+ }
+
+ /**
+ * Get the label of the action according to <code>distributionType</code>
+ * and <code>isToolbarItem</code>.
+ *
+ * @param distributeType
+ * the kind of distribution.
+ * @param isToolbarItem
+ * the indicator of whether or not this is a toolbar action as
+ * opposed to a context-menu action
+ * @return The label
+ */
+ public static String getLabel(int distributeType, boolean isToolbarItem) {
+ String label = StringStatics.BLANK;
+ switch (distributeType) {
+ case DistributeAction.HORIZONTALLY_WITH_UNIFORM_GAPS:
+ label = DistributeAction.HORIZONTALLY_WITH_UNIFORM_GAPS_LABEL;
+ break;
+ case DistributeAction.CENTERS_HORIZONTALLY:
+ label = DistributeAction.CENTERS_HORIZONTALLY_LABEL;
+ break;
+ case DistributeAction.VERTICALLY_WITH_UNIFORM_GAPS:
+ label = DistributeAction.VERTICALLY_WITH_UNIFORM_GAPS_LABEL;
+ break;
+ case DistributeAction.CENTERS_VERTICALLY:
+ label = DistributeAction.CENTERS_VERTICALLY_LABEL;
+ break;
+ default:
+ break;
+ }
+ if (isToolbarItem && !StringStatics.BLANK.equals(label)) {
+ // Add distribute prefix
+ label = DistributeAction.DISTRIBUTE_PREFIX + label;
+ }
+ return label;
+ }
+
+ /**
+ * Creates the Distribute action to distribute shapes horizontally with
+ * uniform gaps.
+ *
+ * @param workbenchPage
+ * the workbench part used to obtain context
+ * @param isToolbarItem
+ * the indicator of whether or not this is a toolbar action as
+ * opposed to a context-menu action.
+ * @return the corresponding action
+ */
+ public static DistributeAction createDistributeHorizontallyWithUniformGapsAction(IWorkbenchPage workbenchPage, boolean isToolbarItem) {
+ DistributeAction action = new DistributeAction(workbenchPage, DistributeAction.HORIZONTALLY_WITH_UNIFORM_GAPS, isToolbarItem);
+ action.setId(ActionIds.DISTRIBUTE_HORIZONTALLY_WITH_UNIFORM_GAPS);
+ ImageDescriptor bundledImageDescriptor = DiagramUIPlugin.Implementation.getBundledImageDescriptor(DiagramImagesPath.DISTRIBUTE_WITH_UNIFORM_GAPS_HORIZONTALLY);
+ action.setImageDescriptor(bundledImageDescriptor);
+ action.setHoverImageDescriptor(bundledImageDescriptor);
+ return action;
+ }
+
+ /**
+ * Creates the Distribute action to distribute evenly centers of shapes
+ * horizontally.
+ *
+ * @param workbenchPage
+ * the workbench part used to obtain context
+ * @param isToolbarItem
+ * the indicator of whether or not this is a toolbar action as
+ * opposed to a context-menu action.
+ * @return the corresponding action
+ */
+ public static DistributeAction createDistributeCentersHorizontallyAction(IWorkbenchPage workbenchPage, boolean isToolbarItem) {
+ DistributeAction action = new DistributeAction(workbenchPage, DistributeAction.CENTERS_HORIZONTALLY, isToolbarItem);
+ action.setId(ActionIds.DISTRIBUTE_CENTERS_HORIZONTALLY);
+ ImageDescriptor bundledImageDescriptor = DiagramUIPlugin.Implementation.getBundledImageDescriptor(DiagramImagesPath.DISTRIBUTE_CENTERS_HORIZONTALLY);
+ action.setImageDescriptor(bundledImageDescriptor);
+ action.setHoverImageDescriptor(bundledImageDescriptor);
+ return action;
+ }
+
+ /**
+ * Creates the Distribute action to distribute shapes vertically with
+ * uniform gaps.
+ *
+ * @param workbenchPage
+ * the workbench part used to obtain context
+ * @param isToolbarItem
+ * the indicator of whether or not this is a toolbar action as
+ * opposed to a context-menu action.
+ * @return the corresponding action
+ */
+ public static DistributeAction createDistributeVerticallyWithUniformGapsAction(IWorkbenchPage workbenchPage, boolean isToolbarItem) {
+ DistributeAction action = new DistributeAction(workbenchPage, DistributeAction.VERTICALLY_WITH_UNIFORM_GAPS, isToolbarItem);
+ action.setId(ActionIds.DISTRIBUTE_VERTICALLY_WITH_UNIFORM_GAPS);
+ ImageDescriptor bundledImageDescriptor = DiagramUIPlugin.Implementation.getBundledImageDescriptor(DiagramImagesPath.DISTRIBUTE_WITH_UNIFORM_GAPS_VERTICALLY);
+ action.setImageDescriptor(bundledImageDescriptor);
+ action.setHoverImageDescriptor(bundledImageDescriptor);
+ return action;
+ }
+
+ /**
+ * Creates the Distribute action to distribute evenly centers of shapes
+ * vertically.
+ *
+ * @param workbenchPage
+ * the workbench part used to obtain context
+ * @param isToolbarItem
+ * the indicator of whether or not this is a toolbar action as
+ * opposed to a context-menu action.
+ * @return the corresponding action
+ */
+ public static DistributeAction createDistributeCentersVerticallyAction(IWorkbenchPage workbenchPage, boolean isToolbarItem) {
+ DistributeAction action = new DistributeAction(workbenchPage, DistributeAction.CENTERS_VERTICALLY, isToolbarItem);
+ action.setId(ActionIds.DISTRIBUTE_CENTERS_VERTICALLY);
+ ImageDescriptor bundledImageDescriptor = DiagramUIPlugin.Implementation.getBundledImageDescriptor(DiagramImagesPath.DISTRIBUTE_CENTERS_VERTICALLY);
+ action.setImageDescriptor(bundledImageDescriptor);
+ action.setHoverImageDescriptor(bundledImageDescriptor);
+ return action;
+ }
+
+ @Override
+ protected Request createTargetRequest() {
+ DistributeRequest distributionRequest = new DistributeRequest();
+ distributionRequest.setDistributeType(distributeType);
+ return distributionRequest;
+ }
+
+ @Override
+ protected void updateTargetRequest() {
+ DistributeRequest distributionRequest = (DistributeRequest) getTargetRequest();
+ distributionRequest.setDistributeType(distributeType);
+ distributionRequest.setEditParts(getOperationSet());
+ }
+
+ @Override
+ protected Command getCommand() {
+ Command cmd = null;
+ List<?> operationSet = getOperationSet();
+ if (!operationSet.isEmpty()) {
+ EditPart targetEP = getTargetEditPartForDistributeSelection(operationSet);
+ if (targetEP != null) {
+ cmd = targetEP.getCommand(getTargetRequest());
+ }
+ }
+ return cmd;
+ }
+
+ @Override
+ protected List<?> createOperationSet() {
+ List<?> selection = getSelectedObjects();
+ if (selection.isEmpty() || !(selection.get(0) instanceof IGraphicalEditPart) || selection.size() < 3) {
+ selection = Collections.EMPTY_LIST;
+ } else {
+ // Get the the top level selected edit parts
+ selection = ToolUtilities.getSelectionWithoutDependants(selection);
+ // Remove the connections
+ selection = Lists.newArrayList(Iterables.filter(selection, Predicates.not(Predicates.instanceOf(ConnectionEditPart.class))));
+ EditPart parent = ((EditPart) selection.get(0)).getParent();
+ int sideOfFirstSelection = PositionConstants.NONE;
+ if (selection.get(0) instanceof IBorderItemEditPart) {
+ // If the first selected element is a border node
+ sideOfFirstSelection = ((IBorderItemEditPart) selection.get(0)).getBorderItemLocator().getCurrentSideOfParent();
+ // Check that the side corresponds to the action axis
+ // (horizontal or vertical)
+ if (!isHorizontalAxisAuthorizedForBorderNode(sideOfFirstSelection) && !isVerticalAxisAuthorizedForBorderNode(sideOfFirstSelection)) {
+ selection = Collections.EMPTY_LIST;
+ }
+ }
+
+ for (int i = 1; i < selection.size(); i++) {
+ EditPart part = (EditPart) selection.get(i);
+ if (part.getParent() != parent) {
+ // All the selected shapes must have the same parent.
+ selection = Collections.EMPTY_LIST;
+ break;
+ } else if (sideOfFirstSelection != PositionConstants.NONE && !isABorderNodeOnSameAxis(part, sideOfFirstSelection)) {
+ // All the selected border nodes must have the same
+ // axis.
+ selection = Collections.EMPTY_LIST;
+ break;
+ }
+ }
+ }
+ return selection;
+ }
+
+ private boolean isHorizontalAxisAuthorizedForBorderNode(int side) {
+ return isOnHorizontalAxis(side) && (distributeType == DistributeAction.HORIZONTALLY_WITH_UNIFORM_GAPS || distributeType == DistributeAction.CENTERS_HORIZONTALLY);
+ }
+
+ private boolean isVerticalAxisAuthorizedForBorderNode(int side) {
+ return isOnVerticalAxis(side) && (distributeType == DistributeAction.VERTICALLY_WITH_UNIFORM_GAPS || distributeType == DistributeAction.CENTERS_VERTICALLY);
+ }
+
+ private boolean isABorderNodeOnSameAxis(EditPart part, int expectedSide) {
+ boolean result = false;
+ if (part instanceof IBorderItemEditPart) {
+ int currentSide = ((IBorderItemEditPart) part).getBorderItemLocator().getCurrentSideOfParent();
+ if ((isOnHorizontalAxis(expectedSide) && isOnHorizontalAxis(currentSide)) || (isOnVerticalAxis(expectedSide) && isOnVerticalAxis(currentSide))) {
+ result = true;
+ }
+ }
+ return result;
+ }
+
+ private boolean isOnHorizontalAxis(int side) {
+ return side == PositionConstants.NORTH || side == PositionConstants.SOUTH;
+ }
+
+ private boolean isOnVerticalAxis(int side) {
+ return side == PositionConstants.EAST || side == PositionConstants.WEST;
+ }
+
+ @Override
+ protected boolean isSelectionListener() {
+ return true;
+ }
+
+ @Override
+ protected boolean isOperationHistoryListener() {
+ return true;
+ }
+
+ private EditPart getTargetEditPartForDistributeSelection(List<?> editparts) {
+ // The Distribute request gets sent to the common parent.
+ EditPart parent = ((EditPart) editparts.get(0)).getParent();
+ if (parent != null) {
+ // Check that the parent is the same for all selected edit parts
+ // (normally it was already done via createOperationSet()).
+ for (int i = 1; i < editparts.size(); i++) {
+ EditPart part = (EditPart) editparts.get(i);
+ // if there is no common parent, then Distribute isn't
+ // supported.
+ if (part.getParent() != parent)
+ return null;
+ }
+ }
+ return parent;
+
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/internal/editor/tabbar/actions/DistributeMenuManager.java b/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/internal/editor/tabbar/actions/DistributeMenuManager.java
new file mode 100644
index 0000000000..53c7f72937
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/internal/editor/tabbar/actions/DistributeMenuManager.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2014 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.editor.tabbar.actions;
+
+import org.eclipse.gmf.runtime.common.ui.action.ActionMenuManager;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.sirius.diagram.ui.provider.DiagramUIPlugin;
+import org.eclipse.sirius.diagram.ui.tools.api.image.DiagramImagesPath;
+import org.eclipse.sirius.diagram.ui.tools.api.ui.actions.ActionIds;
+
+/**
+ * The distribute menu manager. It contains all distribute-related actions.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ */
+public class DistributeMenuManager extends ActionMenuManager {
+
+ /**
+ * The distribute menu action containing the UI for the distribute menu
+ * manager
+ */
+ private static class DistributeMenuAction extends Action {
+ public DistributeMenuAction() {
+ setText("&Distribute");
+ setToolTipText("Distribute selected shapes");
+ ImageDescriptor imageDesc = DiagramUIPlugin.Implementation.getBundledImageDescriptor(DiagramImagesPath.DISTRIBUTE_WITH_UNIFORM_GAPS_HORIZONTALLY);
+ setImageDescriptor(imageDesc);
+ setHoverImageDescriptor(imageDesc);
+ }
+ }
+
+ /**
+ * Creates a new instance of the distribute menu manager.
+ */
+ public DistributeMenuManager() {
+ super(ActionIds.MENU_DISTRIBUTE, new DistributeMenuAction(), true);
+ }
+}
diff --git a/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/internal/editor/tabbar/actions/TabbarDistributeMenuManager.java b/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/internal/editor/tabbar/actions/TabbarDistributeMenuManager.java
new file mode 100644
index 0000000000..d63d3b39a1
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/internal/editor/tabbar/actions/TabbarDistributeMenuManager.java
@@ -0,0 +1,117 @@
+/*******************************************************************************
+ * Copyright (c) 2014 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.editor.tabbar.actions;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.eclipse.gmf.runtime.common.ui.action.IDisposableAction;
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.sirius.common.ui.tools.api.util.EclipseUIUtil;
+import org.eclipse.sirius.diagram.ui.tools.api.ui.actions.ActionIds;
+import org.eclipse.sirius.diagram.ui.tools.internal.actions.distribute.DistributeAction;
+import org.eclipse.ui.IWorkbenchPage;
+
+/**
+ * A distribute menu manager which handle cleanly {@link IDisposableAction} and
+ * set correctly handler for tabbar.
+ *
+ * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
+ */
+public class TabbarDistributeMenuManager extends DistributeMenuManager {
+
+ @Override
+ public void add(IAction action) {
+ super.add(action);
+ if (action instanceof IDisposableAction) {
+ ((IDisposableAction) action).init();
+ }
+ }
+
+ @Override
+ protected void itemRemoved(IContributionItem item) {
+ if (item instanceof ActionContributionItem) {
+ IAction action = ((ActionContributionItem) item).getAction();
+ if (action instanceof IDisposableAction) {
+ ((IDisposableAction) action).dispose();
+ }
+ }
+ super.itemRemoved(item);
+ }
+
+ @Override
+ public void dispose() {
+ removeAll();
+ super.dispose();
+ }
+
+ /**
+ * Set the default action id for this menu manager.
+ *
+ * @param actionId
+ * the action id to set
+ */
+ public void setDefaultAction(String actionId) {
+ for (final IContributionItem item : getItems()) {
+ if (item instanceof ActionContributionItem) {
+ if (actionId.equals(((ActionContributionItem) item).getAction().getId())) {
+ final IAction defaultAction = ((ActionContributionItem) item).getAction();
+ setHandler(defaultAction);
+ super.setDefaultAction(defaultAction);
+ return;
+ }
+ }
+ }
+ }
+
+ /**
+ * We should use reflection to access the default handler method
+ *
+ * @param defaultAction
+ * the default action to set
+ */
+ private void setHandler(final IAction defaultAction) {
+ Method method;
+ try {
+ method = MenuCreatorAction.class.getDeclaredMethod("setActionHandler", IAction.class);
+ method.setAccessible(true);
+ method.invoke(super.action, defaultAction);
+ } catch (SecurityException e) {
+ /* do nothing should not happen */
+ } catch (NoSuchMethodException e) {
+ /* do nothing should not happen */
+ } catch (IllegalArgumentException e) {
+ /* do nothing should not happen */
+ } catch (IllegalAccessException e) {
+ /* do nothing should not happen */
+ } catch (InvocationTargetException e) {
+ /* do nothing should not happen */
+ }
+ }
+
+ @Override
+ public void setVisible(boolean visible) {
+ super.setVisible(visible);
+ if (isEmpty() && visible) {
+ IWorkbenchPage page = EclipseUIUtil.getActivePage();
+ if (page != null) {
+ add(DistributeAction.createDistributeHorizontallyWithUniformGapsAction(page, true));
+ add(DistributeAction.createDistributeCentersHorizontallyAction(page, true));
+ add(DistributeAction.createDistributeVerticallyWithUniformGapsAction(page, true));
+ add(DistributeAction.createDistributeCentersVerticallyAction(page, true));
+ setDefaultAction(ActionIds.DISTRIBUTE_HORIZONTALLY_WITH_UNIFORM_GAPS);
+ }
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/internal/editor/tabbar/contributions/DistributeMenuExtensionContributionFactory.java b/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/internal/editor/tabbar/contributions/DistributeMenuExtensionContributionFactory.java
new file mode 100644
index 0000000000..0ba9ddc94f
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.ui/src-diag/org/eclipse/sirius/diagram/ui/tools/internal/editor/tabbar/contributions/DistributeMenuExtensionContributionFactory.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2014 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.editor.tabbar.contributions;
+
+import org.eclipse.sirius.diagram.ui.tools.internal.editor.tabbar.actions.TabbarDistributeMenuManager;
+import org.eclipse.sirius.diagram.ui.tools.internal.editor.tabbar.contributions.expressions.DDiagramElementTabbarExpression;
+import org.eclipse.ui.menus.IContributionRoot;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * {@link SiriusTabbarExtensionContributionFactory} to contribute
+ * {@link TabbarDistributeMenuManager}.
+ *
+ * @author <a href="mailto:esteban.dugueperoux@obeo.fr">Esteban Dugueperoux</a>
+ */
+public class DistributeMenuExtensionContributionFactory extends SiriusTabbarExtensionContributionFactory {
+
+ @Override
+ public void createContributionItems(IServiceLocator serviceLocator, IContributionRoot additions) {
+ super.createContributionItems(serviceLocator, additions);
+ TabbarDistributeMenuManager distributeMenu = new TabbarDistributeMenuManager();
+ additions.addContributionItem(distributeMenu, new DDiagramElementTabbarExpression());
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.ui/src/org/eclipse/sirius/diagram/ui/tools/api/image/DiagramImagesPath.java b/plugins/org.eclipse.sirius.diagram.ui/src/org/eclipse/sirius/diagram/ui/tools/api/image/DiagramImagesPath.java
index df14189d7a..2343f30e6e 100644
--- a/plugins/org.eclipse.sirius.diagram.ui/src/org/eclipse/sirius/diagram/ui/tools/api/image/DiagramImagesPath.java
+++ b/plugins/org.eclipse.sirius.diagram.ui/src/org/eclipse/sirius/diagram/ui/tools/api/image/DiagramImagesPath.java
@@ -148,4 +148,22 @@ public interface DiagramImagesPath {
/** deselect all icon. */
String DESELECT_ALL_ICON = "icons/deselectAll.gif"; //$NON-NLS-1$
+
+ /**
+ * Path of the action's image to distribute centers horizontally.
+ */
+ String DISTRIBUTE_CENTERS_HORIZONTALLY = "icons/distributeCentersHorizontal.gif";
+
+ /**
+ * Path of the action's image to distribute with uniform gaps horizontally.
+ */
+ String DISTRIBUTE_WITH_UNIFORM_GAPS_HORIZONTALLY = "icons/distributeWithUniformGapHorizontal.gif";
+
+ /**
+ * Path of the action's image to distribute middle vertically.
+ */
+ String DISTRIBUTE_CENTERS_VERTICALLY = "icons/distributeCentersVertical.gif";
+
+ /** Path of the action's image to distribute with uniform gaps vertically. */
+ String DISTRIBUTE_WITH_UNIFORM_GAPS_VERTICALLY = "icons/distributeWithUniformGapVertical.gif";
}
diff --git a/plugins/org.eclipse.sirius.doc/doc/Release Notes.html b/plugins/org.eclipse.sirius.doc/doc/Release Notes.html
index 1e16d3e709..cc2ce3831c 100644
--- a/plugins/org.eclipse.sirius.doc/doc/Release Notes.html
+++ b/plugins/org.eclipse.sirius.doc/doc/Release Notes.html
@@ -54,19 +54,15 @@
<img border="0" src="images/containerResize-changedBehavior.gif"/>
</p>
<ul>
- <li>The &#8220;snap to shapes&#8221; is now enabled by default (see
+ <li>The &#171;snap to shapes&#187; is now enabled by default (see
<em>Sirius &gt; Sirius Diagram &gt; Rulers and Grid</em> preference page). This is true only for new diagrams. The existing diagrams are not impacted.
</li>
- </ul>
- <ul>
- <li>The &#8220;Navigate&#8221; top-level contextual menu entry with mixed actions for creating new representations and opening existing ones has been changed by two top-level menus:
+ <li>The &#171;Navigate&#187; top-level contextual menu entry with mixed actions for creating new representations and opening existing ones has been changed by two top-level menus:
<ul>
- <li>One named &#8220;New&#8221;, which lists only the available actions to create new representations on the selected element.</li>
- <li>One named &#8220;Open&#8221;, which lists only the existing representations on the selected element. </li>
+ <li>One named &#171;New&#187;, which lists only the available actions to create new representations on the selected element.</li>
+ <li>One named &#171;Open&#187;, which lists only the existing representations on the selected element. </li>
</ul>
</li>
- </ul>
- <ul>
<li>When a shape is resized (no matter the direction), the edge(s) connection location (toward or from this one) is kept. Before that, edges connections moved according to the ratio of the resizing.</li>
</ul>
<p>Example with this initial state before resizing:
@@ -79,17 +75,28 @@
<br/>
<img border="0" src="images/shapeResize3.png"/>
</p>
+ <ul>
+ <li>There is now the possibility to distribute the selected shapes (see
+ <a href="user/diagrams/Diagrams.html#distribute">Sirius User Manual/Diagrams/Features Overview/Distribute elements</a> for more details):
+ <ul>
+ <li>Distribute horizontally with uniform gaps</li>
+ <li>Distribute centers evenly horizontally</li>
+ <li>Distribute vertically with uniform gaps</li>
+ <li>Distribute centers evenly vertically</li>
+ </ul>
+ </li>
+ </ul>
<h3 id="SpecifierVisibleChanges">Specifier-Visible Changes</h3>
<ul>
- <li>The specifier can now choose to hold the edge ends toward the center of the source, target or both. New fields within the &#8220;advance&#8221; tab of EdgeStyle description have been added to choose for which source or target mappings an edge should be centered. See
+ <li>The specifier can now choose to hold the edge ends toward the center of the source, target or both. New fields within the &#171;advance&#187; tab of EdgeStyle description have been added to choose for which source or target mappings an edge should be centered. See
<a href="specifier/diagrams/Diagrams.html#edges_styles">Edges Styles &gt; Edge Centering</a> in the specifier manual for more details.
</li>
<li>When creating a new Viewpoint Specification Project using the supplied wizard:
- <em>New &gt; Viewpoint Specification Project</em>, the VSM name is now given according to the project name. If the project name is suffixed with &#8220;design&#8221;, the VSM name is provided by the last word before this suffix. Otherwise, the VSM name is given by the last word of the project name.
+ <em>New &gt; Viewpoint Specification Project</em>, the VSM name is now given according to the project name. If the project name is suffixed with &#171;design&#187;, the VSM name is provided by the last word before this suffix. Otherwise, the VSM name is given by the last word of the project name.
</li>
</ul>
<ul>
- <li>The end user can now remove all bend-points between the two edge ends. This action is available on edge context menu &#8220;Remove Bend-points&#8221; or by using the shortcut &#8220;Ctrl&#8221; + &#8220;Shift&#8221; + &#8220;-&#8221;.</li>
+ <li>The end user can now remove all bend-points between the two edge ends. This action is available on edge context menu &#171;Remove Bend-points&#187; or by using the shortcut &#171;Ctrl&#187; + &#171;Shift&#187; + &#171;-&#187;.</li>
</ul>
<h3 id="APIChanges">API Changes</h3>
<h4 id="Changesinorg.eclipse.sirius">Changes in
@@ -244,6 +251,21 @@
<code>isEdgeWithRectilinearRoutingStyle()</code> and
<code>isEdgeWithObliqueRoutingStyle()</code> that respectively checks if an edge has a rectilinear routing style or an oblique routing style.
</li>
+ <li>
+ <code>org.eclipse.sirius.diagram.ui.tools.api.requests.DistributeRequest</code>: A new
+ <code>ChangeBoundsRequest</code> to manage distribution of shapes.
+ </li>
+ <li>A constant
+ <code>REQ_DISTRIBUTE</code> has been added in
+ <code>org.eclipse.sirius.diagram.ui.tools.api.requests.RequestConstants</code> to identify the new type of request,
+ <code>DistributeRequest</code>.
+ </li>
+ <li>Constants have been added in
+ <code>org.eclipse.sirius.diagram.ui.tools.api.ui.actions.ActionIds</code> for the new drop down menu in tabbar and for the four new distribute actions.
+ </li>
+ <li>Constants have been added in
+ <code>org.eclipse.sirius.diagram.ui.tools.api.image.DiagramImagesPath</code> for the icon path of the four new distribute actions.
+ </li>
</ul>
<h4 id="Changesinorg.eclipse.sirius.tree.ui">Changes in
<code>org.eclipse.sirius.tree.ui</code>
@@ -441,7 +463,7 @@
<h3 id="SpecifierVisibleChanges3">Specifier-Visible Changes</h3>
<ul>
<li>The default value of the
- <em>Semantic Candidates Expression</em> for Tree Items has changed from an empty string (meaning &#8220;any compatible element in the session&#8221;) to
+ <em>Semantic Candidates Expression</em> for Tree Items has changed from an empty string (meaning &#171;any compatible element in the session&#187;) to
<code>feature:eAllContents</code> which only looks for compatible candidates inside the current element (recursively). The new behavior is more efficient on large models and consistent with what happens for diagrams. The change does not affect existing VSMs which continue to work as before whatever was the expression they used. Users who want the old behavior on specific mappings can simply remove the expression in the properties view.
</li>
<li>In the
@@ -474,7 +496,7 @@
<code>org.eclipse.diagram</code> again.
</p>
<p>Unlike, the
- <a href="#separationOfDiagramSpecificConcept-step1">Step1</a>, a simple &#8220;Organize Imports&#8221; operation is not enough. First, you will probably need to add dependencies to
+ <a href="#separationOfDiagramSpecificConcept-step1">Step1</a>, a simple &#171;Organize Imports&#187; operation is not enough. First, you will probably need to add dependencies to
<code>org.eclipse.sirius.diagram</code>,
<code>org.eclipse.sirius.diagram.ui</code> or
<code>org.eclipse.sirius.editor.diagram</code> in the MANIFEST.MF of your projects that depend on Sirius diagram classes. The dependencies to add depend on what you really use.
@@ -902,7 +924,7 @@
<code>Multimap</code>.
</li>
<li>
- <code>org.eclipse.sirius.ui.tools.api.project.ModelingProjectManager.initializeAfterLoad()</code> method has been removed. There is no replacement for this method documented as &#8220;Not intended to be used by client&#8221;.
+ <code>org.eclipse.sirius.ui.tools.api.project.ModelingProjectManager.initializeAfterLoad()</code> method has been removed. There is no replacement for this method documented as &#171;Not intended to be used by client&#187;.
</li>
</ul>
<h4 id="Changesinorg.eclipse.sirius.ecore.extender">Changes in
@@ -1146,27 +1168,27 @@ if (rootPackage != null &amp;&amp; rootPackage.getNsURI().equals(DiagramPackage.
<h2 id="sirius1.0M5">Changes in Sirius 1.0.0M5 (from Sirius 1.0M4)</h2>
<h3 id="UserVisibleChanges3">User-Visible Changes</h3>
<ul>
- <li>The table csv export has been improved to handle cropped label. In some specific cases, the cell label is automatically cropped and &#8216;...&#8217; is concatenated to the resulting value. This cropped displayed label was previously exported, now the complete semantic value is exported.</li>
+ <li>The table csv export has been improved to handle cropped label. In some specific cases, the cell label is automatically cropped and &#8249;...&#8250; is concatenated to the resulting value. This cropped displayed label was previously exported, now the complete semantic value is exported.</li>
</ul>
<h3 id="APIChanges5">API Changes</h3>
<h4 id="LibraryExtensions">Library Extensions</h4>
- <p>This milestone (Sirius 1.0M5) introduces several new plug-ins, collectively called &#8220;library extensions&#8221;. They are all named
+ <p>This milestone (Sirius 1.0M5) introduces several new plug-ins, collectively called &#171;library extensions&#187;. They are all named
<code>org.eclipse.sirius.ext.LIB</code>, where
- <code>LIB</code> is the name of a library or component Sirius depends on. These plug-ins are used to isolate generic code which extends existing libraries with features and helpers needed for Sirius, but which do not depend on Sirius themselves. A relatively large part of the code in Sirius is of this kind: things that could/should be in EMF, GMF, Eclipse itself, etc. and which are not Sirius-specific but which make it easier to build Sirius itself. Sirius 1.0M5 introduces several of these library extensions and starts to fill them with existing classes which were &#8220;hidden&#8221; inside Sirius and are now exposed in library extensions. Most of the time, existing code which used the Sirius API will only need to:
+ <code>LIB</code> is the name of a library or component Sirius depends on. These plug-ins are used to isolate generic code which extends existing libraries with features and helpers needed for Sirius, but which do not depend on Sirius themselves. A relatively large part of the code in Sirius is of this kind: things that could/should be in EMF, GMF, Eclipse itself, etc. and which are not Sirius-specific but which make it easier to build Sirius itself. Sirius 1.0M5 introduces several of these library extensions and starts to fill them with existing classes which were &#171;hidden&#187; inside Sirius and are now exposed in library extensions. Most of the time, existing code which used the Sirius API will only need to:
</p>
<ol>
<li>Add the necessary
<code>Import-Package</code> (recommended) or
<code>Require-Bundle</code> to depend on the library extension(s) where the code they use now lives;
</li>
- <li>Perform a simple &#8220;Organize Imports&#8221; operation, which should find the classes and interfaces in their new locations.</li>
+ <li>Perform a simple &#171;Organize Imports&#187; operation, which should find the classes and interfaces in their new locations.</li>
</ol>
<h4 id="separationOfDiagramSpecificConcept-step1">Move diagram-specific EClasses into a separate EPackage</h4>
<p>For historical reasons, the core Sirius metamodels defined in viewpoint.ecore contain both generic (dialect-independant like Viewpoint, RepresentationDescription, DAnalysis...) concepts and diagram-specific ones (e.g. DNode, EdgeStyle, ContainerCreationDescription...). The table and tree metamodels are more cleanly separated.
<br/>This milestone (Sirius 1.0M5) includes the first step towards a full separation of the diagram-specific stuff out of the core of Sirius. So many EClasses have been moved.
</p>
- <p>Most of the time, existing code which used these Sirius EClasses will only need to perform a simple &#8220;Organize Imports&#8221; operation, which should find the classes and interfaces in their new locations.
- <br/>The &#8220;Organize imports&#8221; is not sufficient in case of imported classes existing several time in different packages (
+ <p>Most of the time, existing code which used these Sirius EClasses will only need to perform a simple &#171;Organize Imports&#187; operation, which should find the classes and interfaces in their new locations.
+ <br/>The &#171;Organize imports&#187; is not sufficient in case of imported classes existing several time in different packages (
<code>EFactory</code> classes for example with
<code>DescriptionFactory</code>, or
<code>EPackage</code> classes for example with
@@ -1581,7 +1603,7 @@ if (rootPackage != null &amp;&amp; rootPackage.getNsURI().equals(DiagramPackage.
</li>
</ul>
<h2 id="sirius0.9">Changes in Sirius 0.9.0</h2>
- <p>Version 0.9.0 is the first release under the Sirius name and under the Eclipse Foundation umbrella. Except for the few cases mentioned below (in the &#8220;Other API Changes&#8221;, &#8220;Specifier-Visible Changes&#8221; and &#8220;User-Visible Changes&#8221; sections), Sirius 0.9.0 is functionally equivalent to the latest version of Viewpoint (version 6.10), which was the name of the project before it was open sourced at Eclipse. See the rest of the documentation for the complete list of feature of the Sirius platform.</p>
+ <p>Version 0.9.0 is the first release under the Sirius name and under the Eclipse Foundation umbrella. Except for the few cases mentioned below (in the &#171;Other API Changes&#187;, &#171;Specifier-Visible Changes&#187; and &#171;User-Visible Changes&#187; sections), Sirius 0.9.0 is functionally equivalent to the latest version of Viewpoint (version 6.10), which was the name of the project before it was open sourced at Eclipse. See the rest of the documentation for the complete list of feature of the Sirius platform.</p>
<h3 id="MigratingfromObeoDesignerorViewpointtoSirius">Migrating from Obeo Designer or Viewpoint to Sirius</h3>
<p>If you have existing projects which used this technology before it became Eclipse Sirius and want to migrate to Sirius, you must:</p>
<ol>
@@ -1605,9 +1627,9 @@ if (rootPackage != null &amp;&amp; rootPackage.getNsURI().equals(DiagramPackage.
<code>org.eclipse.sirius.componentization</code> extension point id. The identifier changes for the other extension points follow the same rules as the name changes of the plug-ins they are defined in.
</li>
<li>The migration of your VSMs (
- <code>*.odesign</code> files) is automatic: simply open your files once in the VSM editor, perform some no-op change to make the editor &#8220;dirty&#8221; and save it. The saved version will have been migrated to Sirius.
+ <code>*.odesign</code> files) is automatic: simply open your files once in the VSM editor, perform some no-op change to make the editor &#171;dirty&#187; and save it. The saved version will have been migrated to Sirius.
</li>
- <li>If you had Java code which used the Viewpoint APIs, you will need to update it to use the Sirius APIs. A simple &#8220;Source &gt; Organize Imports&#8221; on your source folders should find most classes you used in their new namespace. The Viewpoint code base and APIs used the term &#8220;Viewpoint&#8221; both for the name of the product and for the name of the concept. When it refered to the name of the product, the names were changed to use &#8220;Sirius&#8221; instead, so you may need to adjust some names in your code beyond just updating the imports (for example,
+ <li>If you had Java code which used the Viewpoint APIs, you will need to update it to use the Sirius APIs. A simple &#171;Source &gt; Organize Imports&#187; on your source folders should find most classes you used in their new namespace. The Viewpoint code base and APIs used the term &#171;Viewpoint&#187; both for the name of the product and for the name of the concept. When it refered to the name of the product, the names were changed to use &#171;Sirius&#187; instead, so you may need to adjust some names in your code beyond just updating the imports (for example,
<code>ViewpointControlCommand</code> is now
<code>SiriusControlCommand</code>).
</li>
@@ -1622,7 +1644,7 @@ if (rootPackage != null &amp;&amp; rootPackage.getNsURI().equals(DiagramPackage.
<h4 id="MigratingModelingProjectsandRepresentationFiles">Migrating Modeling Projects and Representation Files</h4>
<ul>
<li>First migrate any modeler definitions used by your modeling projects and representation files (see the section above).</li>
- <li>Modeling projects created using Viewpoint will not be recognized directly by Sirius, because the nature identfier has changed. You must use the &#8220;Configure/Convert to Modeling Project&#8221; action in the project&#8217;s context menu to make it a Sirius-compatible modeling project (see the section below for the technical details of the change).</li>
+ <li>Modeling projects created using Viewpoint will not be recognized directly by Sirius, because the nature identfier has changed. You must use the &#171;Configure/Convert to Modeling Project&#187; action in the project&#8217;s context menu to make it a Sirius-compatible modeling project (see the section below for the technical details of the change).</li>
<li>The migration of you representation files (
<code>*.aird</code>) is performed automatically when they are loaded in memory. It will become permanent the first time you save it (you can force this by opening a representation, making some arbitrary change and saving the session).
</li>
@@ -1798,20 +1820,20 @@ if (rootPackage != null &amp;&amp; rootPackage.getNsURI().equals(DiagramPackage.
</tr>
</table>
<h4 id="JavaPackagesandClassesNames">Java Packages and Classes Names</h4>
- <p>The Java package names have changed to start with the identifier of the plug-in they are defined in (which has changed). A simple &#8220;Source &gt; Organize Imports&#8221; on your source folders should find most classes you used in their new namespace.</p>
- <p>The Viewpoint code base and APIs used the term &#8220;Viewpoint&#8221; both for the name of the product and for the name of the concept. When it refered to the name of the product, the names where changed to use &#8220;Sirius&#8221; instead (for example,
+ <p>The Java package names have changed to start with the identifier of the plug-in they are defined in (which has changed). A simple &#171;Source &gt; Organize Imports&#187; on your source folders should find most classes you used in their new namespace.</p>
+ <p>The Viewpoint code base and APIs used the term &#171;Viewpoint&#187; both for the name of the product and for the name of the concept. When it refered to the name of the product, the names where changed to use &#171;Sirius&#187; instead (for example,
<code>ViewpointControlCommand</code> is now
<code>SiriusControlCommand</code>).
</p>
<h4 id="ModelsnamespaceURIs">Models namespace URIs</h4>
- <p>All namespace URIs have also been changed from &#8220;http://www.obeo.fr/dsl/viewpoint*&#8221; to &#8220;http://www.eclipse.org/sirius/&#8221;.</p>
+ <p>All namespace URIs have also been changed from &#171;http://www.obeo.fr/dsl/viewpoint*&#187; to &#171;http://www.eclipse.org/sirius/&#187;.</p>
<p>If you have created VSM file (.odesign) or representations file (.aird) with Viewpoint, the changes of the namespace URIs will be automatically migrated during the loading of your VSM or your representations file. These new nsURIs will be stored physically in the file during the first save. If the file is not saved, the automatic migration will be replayed at the next opening.</p>
<h3 id="NatureID">Nature ID</h3>
<p>The modeling project has a specific nature (
<code>org.eclipse.sirius.nature.modelingproject</code>).
- <br/>If you have modeling project created with Viewpoint, you must launch the action &#8220;Configure/Convert to Modeling Project&#8221; to replace old nature id (
+ <br/>If you have modeling project created with Viewpoint, you must launch the action &#171;Configure/Convert to Modeling Project&#187; to replace old nature id (
<code>fr.obeo.dsl.viewpoint.nature.modelingproject</code>) by the new one.
- <br/>If you have many modeling projects to &#8220;migrate&#8221;, you can easily make a script to replace
+ <br/>If you have many modeling projects to &#171;migrate&#187;, you can easily make a script to replace
<code>fr.obeo.dsl.viewpoint.nature.modelingproject</code> by
<code>org.eclipse.sirius.nature.modelingproject</code> in all
<code>.project</code> file of each modeling projects.
@@ -1885,4 +1907,4 @@ void removeSelectedView(DView view);
</li>
</ul>
</body>
-</html>
+</html> \ No newline at end of file
diff --git a/plugins/org.eclipse.sirius.doc/doc/Release Notes.textile b/plugins/org.eclipse.sirius.doc/doc/Release Notes.textile
index acaaaa7bad..11bc2ab936 100644
--- a/plugins/org.eclipse.sirius.doc/doc/Release Notes.textile
+++ b/plugins/org.eclipse.sirius.doc/doc/Release Notes.textile
@@ -15,11 +15,9 @@ h3. User-Visible Changes
* When a node, container or not, is resized to the left, upwards, or both, the location of its children (elements inside a container and border nodes) is not changed. It is possible to retrieve the previous behavior by pressing the F3 function key during the resize.
!images/containerResize-changedBehavior.gif!
* The "snap to shapes" is now enabled by default (see _Sirius > Sirius Diagram > Rulers and Grid_ preference page). This is true only for new diagrams. The existing diagrams are not impacted.
-
* The "Navigate" top-level contextual menu entry with mixed actions for creating new representations and opening existing ones has been changed by two top-level menus:
** One named "New", which lists only the available actions to create new representations on the selected element.
** One named "Open", which lists only the existing representations on the selected element.
-
* When a shape is resized (no matter the direction), the edge(s) connection location (toward or from this one) is kept. Before that, edges connections moved according to the ratio of the resizing.
Example with this initial state before resizing:
!images/shapeResize1.png!
@@ -27,6 +25,11 @@ Result after resizing without this feature (the edges have moved):
!images/shapeResize2.png!
Result after resizing with this feature (the edges keep the same location):
!images/shapeResize3.png!
+* There is now the possibility to distribute the selected shapes (see "Sirius User Manual/Diagrams/Features Overview/Distribute elements":user/diagrams/Diagrams.html#distribute for more details):
+** Distribute horizontally with uniform gaps
+** Distribute centers evenly horizontally
+** Distribute vertically with uniform gaps
+** Distribute centers evenly vertically
h3. Specifier-Visible Changes
@@ -82,6 +85,10 @@ h4. Changes in @org.eclipse.sirius.diagram.ui@
* @org.eclipse.sirius.diagram.ui.business.api.query.ConnectionEditPartQuery@ now provides two new methods @isEdgeWithRectilinearRoutingStyle()@ and @isEdgeWithObliqueRoutingStyle()@ that respectively checks if an edge has a rectilinear routing style or an oblique routing style.
* @org.eclipse.sirius.diagram.ui.business.api.query.ConnectionQuery@ now provides two new methods @getAbsoluteBendpointsConstraint()@ and @getRelativeBendpointsConstraint()@ that returns an option of list of @Bendpoint@ of a connection whether they are respectively @AbsoluteBendpoint@ or @RelatveBendpoint@.
* @org.eclipse.sirius.diagram.ui.business.api.query.EdgeQuery@ also provides two new methods @isEdgeWithRectilinearRoutingStyle()@ and @isEdgeWithObliqueRoutingStyle()@ that respectively checks if an edge has a rectilinear routing style or an oblique routing style.
+* @org.eclipse.sirius.diagram.ui.tools.api.requests.DistributeRequest@: A new @ChangeBoundsRequest@ to manage distribution of shapes.
+* A constant @REQ_DISTRIBUTE@ has been added in @org.eclipse.sirius.diagram.ui.tools.api.requests.RequestConstants@ to identify the new type of request, @DistributeRequest@.
+* Constants have been added in @org.eclipse.sirius.diagram.ui.tools.api.ui.actions.ActionIds@ for the new drop down menu in tabbar and for the four new distribute actions.
+* Constants have been added in @org.eclipse.sirius.diagram.ui.tools.api.image.DiagramImagesPath@ for the icon path of the four new distribute actions.
h4. Changes in @org.eclipse.sirius.tree.ui@
diff --git a/plugins/org.eclipse.sirius.doc/doc/user/diagrams/Diagrams.html b/plugins/org.eclipse.sirius.doc/doc/user/diagrams/Diagrams.html
index 7e148c636d..5c0589696a 100644
--- a/plugins/org.eclipse.sirius.doc/doc/user/diagrams/Diagrams.html
+++ b/plugins/org.eclipse.sirius.doc/doc/user/diagrams/Diagrams.html
@@ -32,6 +32,9 @@
<a href="#Manageedges">Manage edges</a>
</li>
<li>
+ <a href="#distribute">Distribute elements</a>
+ </li>
+ <li>
<a href="#Hidingelements">Hiding elements</a>
</li>
<li>
@@ -187,7 +190,7 @@
</ul>
<h3 id="Manageedges">Manage edges</h3>
<h4 id="RemoveBendpoints">Remove Bend-points</h4>
- <p>You can define some bend-points (or inflection points) on an edge. It is possible to remove all these bend-points to retrieve the original Straight edge. This action is available within the edge context menu or by using the shortcut &#8220;Ctrl&#8221; + &#8220;Shift&#8221; + &#8220;-&#8221;. This action is only available on edges with a &#8220;Straight&#8221; routing style.</p>
+ <p>You can define some bend-points (or inflection points) on an edge. It is possible to remove all these bend-points to retrieve the original Straight edge. This action is available within the edge context menu or by using the shortcut &#171;Ctrl&#187; + &#171;Shift&#187; + &#171;-&#187;. This action is only available on edges with a &#171;Straight&#187; routing style.</p>
<p>The edge state just after its creation:
<br/>
<img border="0" src="images/beforeBendpoints.png"/>
@@ -196,16 +199,68 @@
<br/>
<img border="0" src="images/withBendpoints.png"/>
</p>
- <p>The user executes the &#8220;Remove Bend-points&#8221; action:
+ <p>The user executes the &#171;Remove Bend-points&#187; action:
<br/>
<img border="0" src="images/afterRemoveBendpoints.png"/>
</p>
+ <h3 id="distribute">Distribute elements</h3>
+ <p>Four new actions allow to distribute shapes: </p>
+ <p>
+ <img border="0" src="images/distribute_initialState.png"/>
+ </p>
+ <ul>
+ <li>Distribute centers evenly horizontally: Distributes the selected shapes so that the gap between horizontal centers of each selected shapes will be the same.</li>
+ </ul>
+ <p>
+ <img border="0" src="images/distribute_Centers.png"/>
+ </p>
+ <ul>
+ <li>Distribute with uniform gaps horizontally: Distributes the selected shapes so that the gap between the left side and the right side of each consecutive shapes will be the same.</li>
+ </ul>
+ <p>
+ <img border="0" src="images/distribute_WithUniformGap.png"/>
+ </p>
+ <ul>
+ <li>Distribute centers evenly vertically: Distributes the selected shapes so that the gap between vertical centers of each selected shapes will be the same.</li>
+ </ul>
+ <ul>
+ <li>Distribute with uniform gaps vertically: the gap between the bottom side and the top side of each consecutive shapes will be the same.</li>
+ </ul>
+ <p>These new actions are also available in contextual menu
+ <em>Format/Distribute</em> or in menu bar _ Diagram/Distribute_.
+ </p>
+ <p>Only the top level shapes of the selection are retained for these actions: if inner shapes, border labels or edges are selected, they are ignored.
+ <br/>These actions are enabled only if the selected shapes have the same direct parent. At least 3 shapes should be selected to enable distribute actions.
+ <br/>For border nodes, they will be enabled only if all selected border nodes have the same parent and are on the same axis (top and bottom sides for horizontal actions, left and right for vertical actions). The overlap is forbidden for border nodes, so in some conditions (location already used), these actions may not have accurate results.
+ </p>
+ <h4 id="Firstandlastshapes">First and last shapes</h4>
+ <p>For all distribute actions, the first and the last shapes do not move. The first and last shapes do not depend on the selection order. They depend on the location of each selected shapes and the chosen action.</p>
+ <p>For horizontal distribution with uniform gaps:</p>
+ <ul>
+ <li>the first shape is the leftmost one (with the minimum x location). If several shapes have the same x location, the highest one is the first.</li>
+ <li>the last shape is the rightmost one (with the right side with the maximum x coordinate). If several shapes are aligned to the right, the lowest one is the last.</li>
+ </ul>
+ <p>For horizontal centered distribution:</p>
+ <ul>
+ <li>the first shape is the leftmost one (with its center at the minimum x coordinate). If several shapes are aligned on center, the one with the highest center is the first.</li>
+ <li>the last shape is the rightmost one (with its center at the maximum x coordinate). If several shapes are aligned by center, the one with the lowest center is the last.</li>
+ </ul>
+ <p>For vertical distribution with uniform gaps:</p>
+ <ul>
+ <li>the first shape is the highest one (with the minimum y location). If several shapes have the same y location, the leftmost one is the first.</li>
+ <li>the last shape is the lowest one (with the bottom side with the maximum y coordinate). If several shapes are aligned to the bottom, the rightmost one is the last.</li>
+ </ul>
+ <p>For vertical centered distribution:</p>
+ <ul>
+ <li>the first shape is the highest one (with its center at the minimum y coordinate). If several shapes are aligned on middle, the leftmost one is the first.</li>
+ <li>the last shape is the lowest one (with the bottom side with the maximum y coordinate). If several shapes are aligned by middle, the rightmost one is the last.</li>
+ </ul>
<h3 id="Hidingelements">Hiding elements</h3>
<p>Every graphical element on a diagram can be hidden explicitly. To do that, simply right click on the graphical element (or elements if you want to hide several elements at once) you want to hide. Then, choose
<i>Show/Hide</i> /
<i>Hide Element</i>. The graphical element is now hidden from view.
</p>
- <p>The icon in the tool-bar changes showing a &#8220;check box&#8221; on it as soon as at least one element has been hidden, to remind you that what you see is not a complete view of the model being represented:</p>
+ <p>The icon in the tool-bar changes showing a &#171;check box&#187; on it as soon as at least one element has been hidden, to remind you that what you see is not a complete view of the model being represented:</p>
<p>
<img border="0" src="images/diagram_editor11.png"/>
</p>
@@ -243,12 +298,12 @@
<h4 id="Hidinglabels">Hiding labels</h4>
<h5 id="Nodeslabels">Nodes labels</h5>
<p>It is also possible to hide the node label if it is on the border of its node.</p>
- <p>The approach is the same as for other elements, except that there are a specific menus named &#8220;Hide/Show Label&#8221;. It is possible to call this menu directly on the label or on its node.</p>
+ <p>The approach is the same as for other elements, except that there are a specific menus named &#171;Hide/Show Label&#187;. It is possible to call this menu directly on the label or on its node.</p>
<p>
<img border="0" src="images/diagram_editor_hide_label_1.png"/>
</p>
<h5 id="Edgeslabels">Edges labels</h5>
- <p>It is also possible to hide the edge label. The approach is the same than the nodes labels with the specific menus &#8220;Hide/Show Label&#8221; called from the edge or its label.</p>
+ <p>It is also possible to hide the edge label. The approach is the same than the nodes labels with the specific menus &#171;Hide/Show Label&#187; called from the edge or its label.</p>
<p>
<img border="0" src="images/diagram_editor_hide_edge_label_1.png"/>
</p>
@@ -257,7 +312,7 @@
<p>When working on
<em>big</em> diagrams, you may want to hide the icons of the labels on all shapes or connectors, in order to improve the readability of your representations. To do so, open the Eclipse Preferences (
<em>Window</em>/
- <em>Preferences</em>), and select the &#8220;Appearance&#8221; category (
+ <em>Preferences</em>), and select the &#171;Appearance&#187; category (
<em>Sirius</em>/
<em>Sirius Diagram</em>/
<em>Appearance</em>).
@@ -377,11 +432,11 @@
<p>The port is dropped in the container above the mouse location and linked to its closest edge.</p>
<h3 id="Copypasteoflayout">Copy/paste of layout</h3>
<p>It is possible to duplicate layout of diagram elements, that is to say to replicate mutual organization of diagram elements from one diagram to another. This replication only applies to the same semantic elements between diagrams.</p>
- <p>The next picture shows a partial view of a diagram. The tool to replicate the layout is called &#8220;Copy layout&#8221; and can be activated from the tab-bar or the contextual menu (see &#8220;edit&#8221; section). In this picture, layout of John Doe and Earvin Johnson persons will be replicated to another diagram.</p>
+ <p>The next picture shows a partial view of a diagram. The tool to replicate the layout is called &#171;Copy layout&#187; and can be activated from the tab-bar or the contextual menu (see &#171;edit&#187; section). In this picture, layout of John Doe and Earvin Johnson persons will be replicated to another diagram.</p>
<p>
<img border="0" src="images/diagram_editor_copy_layout1.png"/>
</p>
- <p>The next picture shows the diagram where the layout will be replicated. The tool to paste layout is called &#8220;Paste layout&#8221; and can be activated from the toolbar or the contextual menu (see &#8220;edit&#8221; section).</p>
+ <p>The next picture shows the diagram where the layout will be replicated. The tool to paste layout is called &#171;Paste layout&#187; and can be activated from the toolbar or the contextual menu (see &#171;edit&#187; section).</p>
<p>
<img border="0" src="images/diagram_editor_copy_layout2.png"/>
</p>
@@ -406,7 +461,7 @@
<img border="0" src="images/diagram_editor_pin01.png"/>
</p>
<p>
- <i>Arrange All</i> action lays out all diagram elements in order to produce the &#8220;best&#8221; layout. As we can see on the next picture, all diagram elements are moved.
+ <i>Arrange All</i> action lays out all diagram elements in order to produce the &#171;best&#187; layout. As we can see on the next picture, all diagram elements are moved.
</p>
<p>
<img border="0" src="images/diagram_editor_pin02.png"/>
@@ -440,14 +495,14 @@
<li>it is not possible to pin/unpin edges.</li>
</ul>
<h4 id="Configuration">Configuration</h4>
- <p>Every diagram elements that you move will be pinned by default and will need an unpin operation to be &#8220;moveable&#8221; again.</p>
+ <p>Every diagram elements that you move will be pinned by default and will need an unpin operation to be &#171;moveable&#187; again.</p>
<p>This default behavior can be changed in Eclipse preferences, as can be seen in the next picture.</p>
<p>
<img border="0" src="images/diagram_editor_pin_configuration01.png"/>
</p>
<h4 id="PinUnpinonNotes">Pin/Unpin on Notes</h4>
<p>The notes can be pinned if they are attached to a pinned diagram element. If a note is attached to several elements of which at least one is pinned then the note is pinned.</p>
- <p>Otherwise for notes linked to any elements, it&#8217;s possible to use the preferences &#8220;Move unlinked notes during layout&#8221;. By default, this preference is disabled, in this case the unlinked notes are pinned.</p>
+ <p>Otherwise for notes linked to any elements, it&#8217;s possible to use the preferences &#171;Move unlinked notes during layout&#187;. By default, this preference is disabled, in this case the unlinked notes are pinned.</p>
<p>This default behavior can be changed in Eclipse preferences, as can be seen in the next picture.</p>
<p>
<img border="0" src="images/diagram_editor_note_pin_configuration01.png"/>
@@ -466,7 +521,7 @@
<p>You can also use
<a href="#UsingRegularExpressionstoFindDiagramElements">RegularExpressions</a> to easily retrieve the elements you want to pin/unpin.
</p>
- <p>To see more easily if one or more graphical elements are pinned, the icon in the toolbar change, showing a &#8220;checked&#8221; if an element is pinned.</p>
+ <p>To see more easily if one or more graphical elements are pinned, the icon in the toolbar change, showing a &#171;checked&#187; if an element is pinned.</p>
<p>
<img border="0" src="images/diagram_editor_pin_toolbar_activated.png"/>
</p>
@@ -479,7 +534,7 @@
<li>moving the extremity of an edge to adjust its connection point (to the source or target element) is possible, but will never trigger a reconnection operation.</li>
</ul>
<p>Note that other operations which can change the semantic model are still possible. Only the operations listed above, which are easy to misuse, are disabled/modified.
- <strong>Layout Mode is not a &#8220;read-only&#8221; mode and does not guarantee that the semantic model is not modified when it is enabled.</strong>
+ <strong>Layout Mode is not a &#171;read-only&#187; mode and does not guarantee that the semantic model is not modified when it is enabled.</strong>
</p>
<p>
<strong>Layouting mode</strong> can be activated/disabled on a diagram through the tab bar (when there is no selected element) :
@@ -575,8 +630,8 @@
<em>'a'</em> and
<em>'A'</em> are strictly equivalent);
</li>
- <li>A &#8216;?&#8217; wild-card can be used to replace exactly 1 character in the search ;</li>
- <li>A &#8216;*&#8217; wild-card can be used to replace exactly 0 or more characters in the search.</li>
+ <li>A &#8249;?&#8250; wild-card can be used to replace exactly 1 character in the search ;</li>
+ <li>A &#8249;*&#8250; wild-card can be used to replace exactly 0 or more characters in the search.</li>
</ol>
<h4 id="Examples">Examples</h4>
<p>Consider that you have a Diagram containing the following Diagram elements :</p>
@@ -610,7 +665,7 @@
<ul>
<li>isaBot</li>
</ul>
- <p>As &#8216;?&#8217; stands for
+ <p>As &#8249;?&#8250; stands for
<strong>exactly</strong> one character,
<em>isaBoot</em> and
<em>isaBt</em> aren&#8217;t matching this regular expression.
@@ -633,15 +688,15 @@
<em>'*'</em> represents no character.
</p>
<h3 id="styleCustomizations">Style customizations </h3>
- <p>Although the style of the diagram elements is defined in the VSM, it can be customized for each diagram elements. This customization can be applied from the tool bar, from the &#8220;Style&#8221; and &#8220;Appearance&#8221; tab of the property view, from the &#8220;Diagram&#8221; menu or from the contextual menu Format.</p>
+ <p>Although the style of the diagram elements is defined in the VSM, it can be customized for each diagram elements. This customization can be applied from the tool bar, from the &#171;Style&#187; and &#171;Appearance&#187; tab of the property view, from the &#171;Diagram&#187; menu or from the contextual menu Format.</p>
<p>You have the possibility to customize :</p>
<ul>
<li>in container style : the background color, the background style, the border size, the foreground color, the label alignment, the label size and the label format.</li>
<li>in node style: the border size, the color, the label alignment, format, position and size.</li>
<li>in edge style: the folding style, the color, the label alignment, format, position and size, the line and routing style, the size and the target and source arrow.</li>
</ul>
- <p>Theses customizations can be reset by the &#8220;Reset style customization&#8221; button available in the &#8220;Appearance&#8221; tab of the property view and in the diagram editor tool bar.</p>
- <p>NOTE: in case a user customized a Node with a WorkspaceImage style (through the &#8220;Set style to workspace image&#8221; action), it is considered in its whole customized then it can&#8217;t be updated by the refresh action, only the &#8220;Reset style properties to default values&#8221; action can update it by reset it.</p>
+ <p>Theses customizations can be reset by the &#171;Reset style customization&#187; button available in the &#171;Appearance&#187; tab of the property view and in the diagram editor tool bar.</p>
+ <p>NOTE: in case a user customized a Node with a WorkspaceImage style (through the &#171;Set style to workspace image&#187; action), it is considered in its whole customized then it can&#8217;t be updated by the refresh action, only the &#171;Reset style properties to default values&#187; action can update it by reset it.</p>
<h4 id="routingStylePref">Customize edge routing style from preferences</h4>
<p>You have the possibility to customize the routing style of all new edges from the preferences. In the preference page
<em>Sirius/Sirius Diagram/Connections</em>, you can enable
@@ -723,7 +778,7 @@
</p>
<p>
<em>Notes</em> and
- <em>Text</em> elements are created in a similar way: either a single click somewhere on the diagram (which creates an element with a default size), or a click-drag to create the element with a custom initial size. Once created, one can edit the text inside the note or text zone usual the standard &#8220;direct edit&#8221; behavior (
+ <em>Text</em> elements are created in a similar way: either a single click somewhere on the diagram (which creates an element with a default size), or a click-drag to create the element with a custom initial size. Once created, one can edit the text inside the note or text zone usual the standard &#171;direct edit&#187; behavior (
<em>F2</em>, a slow double click, or by directly starting to enter alpha-numeric text). The only difference between notes and text zones is the visual presentation; notes have a yellow background (by default) and a border which represents a sticky not with a folded top-right corner.
</p>
<p>
@@ -741,13 +796,13 @@
</p>
<p>
<em>Tool Drawers</em>. Tools in the palette may be organized in expandable
- <em>drawers</em> to group them by category. To expand a drawer and show its content, simply click once in the drawer&#8217;s header. Click again to fold it back and hide its tools. When you expand a drawer, some others may be folded automatically if there is not enough space to show all of them. To prevent this, you can &#8220;pin&#8221; a drawer opened by clicking on the &#8220;pin&#8221; icon in the drawer&#8217;s title area when it is expanded. This will force it to be kept opened, and its tools available, at all times.
+ <em>drawers</em> to group them by category. To expand a drawer and show its content, simply click once in the drawer&#8217;s header. Click again to fold it back and hide its tools. When you expand a drawer, some others may be folded automatically if there is not enough space to show all of them. To prevent this, you can &#171;pin&#187; a drawer opened by clicking on the &#171;pin&#187; icon in the drawer&#8217;s title area when it is expanded. This will force it to be kept opened, and its tools available, at all times.
</p>
<p>
<img border="0" src="images/palette_tool_drawer.png"/>
</p>
<p>
- <em>Tool Groups</em>. Most entries in the palette correspond to a single tool, but some of them represent tool groups. Tool groups are identified by a small right-facing arrow on the left of the tool&#8217;s icon. They behave like combo-boxes: click on the arrow to expand the group and reveal all the tools available in this group. Click on the tool you want to activate to make it the default and close the group. You can then use the selected tool as any other, but you have to re-open the popup menu if you want to enable a different one. When the group is expanded, you can click on the &#8220;pin&#8221; icon to the right to of the top-most tool to force the group to stay expanded, so that you can easily have access to all the tools.
+ <em>Tool Groups</em>. Most entries in the palette correspond to a single tool, but some of them represent tool groups. Tool groups are identified by a small right-facing arrow on the left of the tool&#8217;s icon. They behave like combo-boxes: click on the arrow to expand the group and reveal all the tools available in this group. Click on the tool you want to activate to make it the default and close the group. You can then use the selected tool as any other, but you have to re-open the popup menu if you want to enable a different one. When the group is expanded, you can click on the &#171;pin&#187; icon to the right to of the top-most tool to force the group to stay expanded, so that you can easily have access to all the tools.
</p>
<p>
<img border="0" src="images/palette_tool_group.png"/>
@@ -755,7 +810,7 @@
<h4 id="UsingTheToolsFromThePalette">Using The Tools From The Palette</h4>
<p>There are different interaction modes possible for the tools available in the palette. The basic pattern is to select the tool in the palette with a simple left-click on in it the palette, and then apply it once on the diagram.</p>
<p>Normally, when you have used a tool once, it does not stay selected; if you want to reuse it a second time, you have to re-select it in the palette. If you want to apply the same tool several times in a row, simply hold the
- <em>Ctrl</em> key pressed while using it; it will stay &#8220;armed&#8221; until you release the
+ <em>Ctrl</em> key pressed while using it; it will stay &#171;armed&#187; until you release the
<em>Ctrl</em> key or select another tool.
</p>
<p>To deselect a tool without executing it, simply press the
@@ -799,7 +854,7 @@
<strong>not</strong> be moved by the algorithm.
</li>
<li>
- <em>Arrange Linked Bordered Nodes</em> This special action will only concerns nodes which are on the border of another element and which are either the source or the target of at least one edge. When invoked, the action will try to move these bordered nodes on the border of their parent on the most &#8220;natural&#8221; side of their parent element depending on the direction of the edge. For example if a bordered node is on the top side of an element but has an edge which does down to a target element below its parent, this action will move the bordered node to the bottom side so that the edge does not cross the parent element.
+ <em>Arrange Linked Bordered Nodes</em> This special action will only concerns nodes which are on the border of another element and which are either the source or the target of at least one edge. When invoked, the action will try to move these bordered nodes on the border of their parent on the most &#171;natural&#187; side of their parent element depending on the direction of the edge. For example if a bordered node is on the top side of an element but has an edge which does down to a target element below its parent, this action will move the bordered node to the bottom side so that the edge does not cross the parent element.
</li>
</ul>
<p>
@@ -869,13 +924,13 @@
<img border="0" src="images/tabbar_paste_layout.png"/>
<em>Paste Layout</em>. This button is only enabled if you have previously copied the layout of some elements in the clipboard, using the
<em>Copy layout</em> action (only visible in the tab-bar when elements are select).
- <em>Paste layout</em> will apply the same size and positions which were copied in the clipboard to the corresponding elements in the current diagram. For the purpose of this command, the &#8220;corresponding elements&#8221; are the graphical elements which represent the same semantic objects.
+ <em>Paste layout</em> will apply the same size and positions which were copied in the clipboard to the corresponding elements in the current diagram. For the purpose of this command, the &#171;corresponding elements&#187; are the graphical elements which represent the same semantic objects.
</p>
<p>
<img border="0" src="images/tabbar_zoom.png"/>
<em>Zoom Controls</em>. Next in the tab-bar is a set of buttons to control the zoom level. The
<em>Zoom in</em> and
- <em>Zoom out</em> buttons behave similarly to their equivalents in the palette. The combo-box shows the current zoom level and allows you to choose among some pre-defined levels. You can also manually enter a specific zoom level (e.g. &#8220;42&#8221;) and hit
+ <em>Zoom out</em> buttons behave similarly to their equivalents in the palette. The combo-box shows the current zoom level and allows you to choose among some pre-defined levels. You can also manually enter a specific zoom level (e.g. &#171;42&#187;) and hit
<em>Return</em> to apply it.
</p>
<p>
@@ -887,7 +942,7 @@
</p>
<p>
<img border="0" src="images/tabbar_layouting_mode.png"/>
- <em>Layout Mode</em>. This button enables a special &#8220;layout mode&#8221;, in which some operations are prevented from having an effect on the semantic model. It can be used when you want to tweak the layout of a diagram and want to be sure to only make graphical changes, and not semantic ones by mistake. Click on the button to enable the &#8220;layout mode&#8221;, and click again when finished to return to the normal model. When this mode is enabled, the following operations are changed:
+ <em>Layout Mode</em>. This button enables a special &#171;layout mode&#187;, in which some operations are prevented from having an effect on the semantic model. It can be used when you want to tweak the layout of a diagram and want to be sure to only make graphical changes, and not semantic ones by mistake. Click on the button to enable the &#171;layout mode&#187;, and click again when finished to return to the normal model. When this mode is enabled, the following operations are changed:
</p>
<ul>
<li>direct edit is disabled on all elements;</li>
@@ -895,7 +950,7 @@
<li>moving the extremity of an edge to adjust its connection point (to the source or target element) is possible, but will never trigger a reconnection operation.</li>
</ul>
<p>Note that other operations which can change the semantic model are still possible. Only the operations listed above, which are easy to misuse, are disabled/modified.
- <strong>Layout Mode is not a &#8220;read-only&#8221; mode and does not guarantee that the semantic model is not modified when it is enabled.</strong>
+ <strong>Layout Mode is not a &#171;read-only&#187; mode and does not guarantee that the semantic model is not modified when it is enabled.</strong>
</p>
<p>The diagram&#8217;s status line indicates when
<em>Layouting mode</em> is enabled:
@@ -1063,7 +1118,7 @@
<ul>
<li>
<em>Auto-size containers during arrange-all action:</em> Container elements which have an explicit size are normally not resized during an
- <em>Arrange All</em>. This can be problematic if the elements they contain are re-arranged so that the container&#8217;s size is not appropriate anymore. When this preference is enabled, the arrange all action will treat all containers as if they are &#8220;auto-sized&#8221;, and adjust their size to the computed arrangement for their content. After the arrange all action is finished, the containers which had an explicit size before will still have an explicit size (although potentially different); they are only switched to auto-size mode during the arrange all action.
+ <em>Arrange All</em>. This can be problematic if the elements they contain are re-arranged so that the container&#8217;s size is not appropriate anymore. When this preference is enabled, the arrange all action will treat all containers as if they are &#171;auto-sized&#187;, and adjust their size to the computed arrangement for their content. After the arrange all action is finished, the containers which had an explicit size before will still have an explicit size (although potentially different); they are only switched to auto-size mode during the arrange all action.
</li>
<li>
<em>Move unlinked notes during layout:</em> If checked, then the
@@ -1103,4 +1158,4 @@
</p>
<img border="0" src="images/preferences_sirius_diagram_rulers_grid.png"/>
</body>
-</html>
+</html> \ No newline at end of file
diff --git a/plugins/org.eclipse.sirius.doc/doc/user/diagrams/Diagrams.textile b/plugins/org.eclipse.sirius.doc/doc/user/diagrams/Diagrams.textile
index 68a2c04de4..c7f9431860 100644
--- a/plugins/org.eclipse.sirius.doc/doc/user/diagrams/Diagrams.textile
+++ b/plugins/org.eclipse.sirius.doc/doc/user/diagrams/Diagrams.textile
@@ -67,6 +67,50 @@ The user defines some bend-points:
The user executes the "Remove Bend-points" action:
!images/afterRemoveBendpoints.png!
+h3(#distribute). Distribute elements
+
+Four new actions allow to distribute shapes:
+
+!images/distribute_initialState.png!
+
+* Distribute centers evenly horizontally: Distributes the selected shapes so that the gap between horizontal centers of each selected shapes will be the same.
+
+!images/distribute_Centers.png!
+
+* Distribute with uniform gaps horizontally: Distributes the selected shapes so that the gap between the left side and the right side of each consecutive shapes will be the same.
+
+!images/distribute_WithUniformGap.png!
+
+* Distribute centers evenly vertically: Distributes the selected shapes so that the gap between vertical centers of each selected shapes will be the same.
+
+* Distribute with uniform gaps vertically: the gap between the bottom side and the top side of each consecutive shapes will be the same.
+
+These new actions are also available in contextual menu _Format/Distribute_ or in menu bar _ Diagram/Distribute_.
+
+Only the top level shapes of the selection are retained for these actions: if inner shapes, border labels or edges are selected, they are ignored.
+These actions are enabled only if the selected shapes have the same direct parent. At least 3 shapes should be selected to enable distribute actions.
+For border nodes, they will be enabled only if all selected border nodes have the same parent and are on the same axis (top and bottom sides for horizontal actions, left and right for vertical actions). The overlap is forbidden for border nodes, so in some conditions (location already used), these actions may not have accurate results.
+
+h4. First and last shapes
+
+For all distribute actions, the first and the last shapes do not move. The first and last shapes do not depend on the selection order. They depend on the location of each selected shapes and the chosen action.
+
+For horizontal distribution with uniform gaps:
+* the first shape is the leftmost one (with the minimum x location). If several shapes have the same x location, the highest one is the first.
+* the last shape is the rightmost one (with the right side with the maximum x coordinate). If several shapes are aligned to the right, the lowest one is the last.
+
+For horizontal centered distribution:
+* the first shape is the leftmost one (with its center at the minimum x coordinate). If several shapes are aligned on center, the one with the highest center is the first.
+* the last shape is the rightmost one (with its center at the maximum x coordinate). If several shapes are aligned by center, the one with the lowest center is the last.
+
+For vertical distribution with uniform gaps:
+* the first shape is the highest one (with the minimum y location). If several shapes have the same y location, the leftmost one is the first.
+* the last shape is the lowest one (with the bottom side with the maximum y coordinate). If several shapes are aligned to the bottom, the rightmost one is the last.
+
+For vertical centered distribution:
+* the first shape is the highest one (with its center at the minimum y coordinate). If several shapes are aligned on middle, the leftmost one is the first.
+* the last shape is the lowest one (with the bottom side with the maximum y coordinate). If several shapes are aligned by middle, the rightmost one is the last.
+
h3. Hiding elements
Every graphical element on a diagram can be hidden explicitly. To do that, simply right click on the graphical element (or elements if you want to hide several elements at once) you want to hide. Then, choose __Show/Hide__ / __Hide Element__. The graphical element is now hidden from view.
diff --git a/plugins/org.eclipse.sirius.doc/doc/user/diagrams/images/distribute_Centers.png b/plugins/org.eclipse.sirius.doc/doc/user/diagrams/images/distribute_Centers.png
new file mode 100644
index 0000000000..ed0959c7b9
--- /dev/null
+++ b/plugins/org.eclipse.sirius.doc/doc/user/diagrams/images/distribute_Centers.png
Binary files differ
diff --git a/plugins/org.eclipse.sirius.doc/doc/user/diagrams/images/distribute_WithUniformGap.png b/plugins/org.eclipse.sirius.doc/doc/user/diagrams/images/distribute_WithUniformGap.png
new file mode 100644
index 0000000000..09f064f17f
--- /dev/null
+++ b/plugins/org.eclipse.sirius.doc/doc/user/diagrams/images/distribute_WithUniformGap.png
Binary files differ
diff --git a/plugins/org.eclipse.sirius.doc/doc/user/diagrams/images/distribute_initialState.png b/plugins/org.eclipse.sirius.doc/doc/user/diagrams/images/distribute_initialState.png
new file mode 100644
index 0000000000..0ca17b8550
--- /dev/null
+++ b/plugins/org.eclipse.sirius.doc/doc/user/diagrams/images/distribute_initialState.png
Binary files differ

Back to the top