Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: bc1915ca2e58237609cc3d6f7d1c0f1808f3a682 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/*******************************************************************************
 * Copyright (c) 2015, 2016 THALES GLOBAL SERVICES.
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *    Obeo - initial API and implementation
 *******************************************************************************/
package org.eclipse.sirius.diagram.ui.tools.internal.ruler;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.draw2d.geometry.PrecisionRectangle;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.Request;
import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.internal.ruler.SnapToGeometryEx;
import org.eclipse.sirius.diagram.ui.edit.api.part.AbstractBorderedDiagramElementEditPart;
import org.eclipse.sirius.diagram.ui.edit.api.part.AbstractDiagramBorderNodeEditPart;
import org.eclipse.sirius.diagram.ui.edit.api.part.IStyleEditPart;
import org.eclipse.sirius.diagram.ui.graphical.edit.policies.SnapChangeBoundsRequest;
import org.eclipse.sirius.diagram.ui.internal.edit.policies.SnapBendpointRequest;
import org.eclipse.sirius.diagram.ui.tools.internal.ui.NoCopyDragEditPartsTrackerEx;
import org.eclipse.sirius.ext.gef.query.EditPartQuery;
import org.eclipse.sirius.ext.gmf.runtime.editparts.GraphicalHelper;

import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;

/**
 * Overridden to support all visible shapes in SnapToShape and not only brothers
 * ones. See {@link NoCopyDragEditPartsTrackerEx#SNAP_TO_ALL_SHAPE_KEY}.
 * 
 * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a>
 */
public class SiriusSnapToGeometry extends SnapToGeometryEx {

    boolean snapToAll;

    /**
     * A vertical or horizontal snapping point.<BR>
     * Only overridden to have access to constructor.
     */
    class SiriusEntry extends Entry {
        protected SiriusEntry(int type, int location) {
            super(type, location);
        }
    }

    /**
     * Default constructor.
     * 
     * @param container
     *            the container editpart
     */
    public SiriusSnapToGeometry(GraphicalEditPart container) {
        super(container);
    }

    @Override
    public int snapRectangle(Request request, int snapOrientation, PrecisionRectangle baseRect, PrecisionRectangle result) {
        // Get snapToAll mode from request (set by the
        // SiriusDragEditPartsTrackerEx or by the SiriusResizeTracker)
        Object snapToAllExtendedData = request.getExtendedData().get(NoCopyDragEditPartsTrackerEx.SNAP_TO_ALL_SHAPE_KEY);
        boolean oldSnapToAll = snapToAll;
        snapToAll = (snapToAllExtendedData == null && NoCopyDragEditPartsTrackerEx.DEFAULT_SNAP_TO_SHAPE_MODE) || (snapToAllExtendedData != null && ((Boolean) snapToAllExtendedData).booleanValue());
        if (!snapToAll) {
            if (request instanceof SnapChangeBoundsRequest) {
                snapToAll = ((SnapChangeBoundsRequest) request).isSnapToAllShape();
            } else if (request instanceof SnapBendpointRequest) {
                snapToAll = ((SnapBendpointRequest) request).isSnapToAllShape();
            }
        }

        if (oldSnapToAll != snapToAll) {
            // Reset previous computed horizontal rows and vertical column
            // being snapped to.
            rows = null;
            cols = null;
        }

        return super.snapRectangle(request, snapOrientation, baseRect, result);
    }

    @Override
    protected List generateSnapPartsList(List exclusions) {
        if (!snapToAll) {
            // Same code as super.generateSnapPartsList(exclusions); but with
            // border nodes add to children list
            // Don't snap to any figure that is being dragged
            List children = Lists.newArrayList(container.getChildren());
            // Add border nodes
            Iterables.addAll(children, Iterables.filter(container.getParent().getChildren(), AbstractDiagramBorderNodeEditPart.class));
            children.removeAll(exclusions);
            // Remove IStyleEditPart from list of children
            Iterable<Object> filteredChildren = Iterables.filter(children, Predicates.not(Predicates.instanceOf(IStyleEditPart.class)));

            // Don't snap to hidden figures
            List hiddenChildren = new ArrayList<>();
            for (Iterator iter = filteredChildren.iterator(); iter.hasNext(); /* */) {
                GraphicalEditPart child = (GraphicalEditPart) iter.next();
                if (!child.getFigure().isVisible()) {
                    hiddenChildren.add(child);
                }
            }
            Iterables.removeAll(filteredChildren, hiddenChildren);
            return Lists.newArrayList(filteredChildren);
        } else {
            // Get all potential snap targets
            List<Class<?>> expectedClasses = new ArrayList<>();
            expectedClasses.add(AbstractBorderedDiagramElementEditPart.class);
            expectedClasses.add(AbstractDiagramBorderNodeEditPart.class);
            List<EditPart> snapPartsList = new ArrayList<EditPart>(new EditPartQuery(container.getRoot()).getAllChildren(false, expectedClasses));
            // Add children of elements that are being dragged
            List<EditPart> exclusionsWithChildren = new ArrayList<>();
            for (Object editPart : exclusions) {
                if (editPart instanceof EditPart) {
                    exclusionsWithChildren.add((EditPart) editPart);
                    exclusionsWithChildren.addAll(new EditPartQuery((EditPart) editPart).getAllChildren(false, expectedClasses));
                }
            }
            // Don't snap to any figure that is being dragged
            snapPartsList.removeAll(exclusionsWithChildren);

            // Don't snap to hidden figures (not visible for end-user)
            for (Iterator<EditPart> iter = snapPartsList.iterator(); iter.hasNext(); /* */) {
                EditPart snapPart = iter.next();
                if (snapPart instanceof IGraphicalEditPart && !new org.eclipse.sirius.diagram.ui.tools.internal.util.EditPartQuery((IGraphicalEditPart) snapPart).isVisibleOnViewport()) {
                    iter.remove();
                }
            }

            return snapPartsList;
        }

    }

    @Override
    protected void populateRowsAndCols(List parts) {
        // Only center is considered for border nodes (top/middle/bottom and
        // left/center/right for others).
        int nbOfBorderNodes = Iterables.size(Iterables.filter(parts, AbstractDiagramBorderNodeEditPart.class));
        rows = new Entry[(parts.size() - nbOfBorderNodes) * 3 + nbOfBorderNodes];
        cols = new Entry[(parts.size() - nbOfBorderNodes) * 3 + nbOfBorderNodes];
        int currentIndex = 0;
        for (int i = 0; i < parts.size(); i++) {
            IGraphicalEditPart child = (IGraphicalEditPart) parts.get(i);
            Rectangle bounds;
            if (!snapToAll) {
                if (child instanceof AbstractDiagramBorderNodeEditPart) {
                    // Handle specific case of Border Node
                    bounds = GraphicalHelper.getAbsoluteBounds(child);
                    makeRelative(container.getContentPane(), bounds);
                } else {
                    // Same as in super.populateRowsAndCols(parts)
                    bounds = getFigureBounds(child);
                }
            } else {
                bounds = GraphicalHelper.getAbsoluteBounds(child);
                makeRelative(container.getContentPane(), bounds);
            }
            if (!(child instanceof AbstractDiagramBorderNodeEditPart)) {
                // Only center is considered for border node
                cols[currentIndex] = new SiriusEntry(-1, bounds.x);
                rows[currentIndex++] = new SiriusEntry(-1, bounds.y);
            }
            cols[currentIndex] = new SiriusEntry(0, bounds.x + (bounds.width - 1) / 2);
            rows[currentIndex++] = new SiriusEntry(0, bounds.y + (bounds.height - 1) / 2);
            if (!(child instanceof AbstractDiagramBorderNodeEditPart)) {
                // Only center is considered for border node
                cols[currentIndex] = new SiriusEntry(1, bounds.right() - 1);
                rows[currentIndex++] = new SiriusEntry(1, bounds.bottom() - 1);
            }
        }
    }
}

Back to the top