]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.g2d/src/org/simantics/g2d/diagram/participant/ZOrderHandler.java
007d039f23715e4ec65446739c8cc941cbe80cd5
[simantics/platform.git] / bundles / org.simantics.g2d / src / org / simantics / g2d / diagram / participant / ZOrderHandler.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.g2d.diagram.participant;
13
14 import java.awt.Shape;
15 import java.util.ArrayList;
16 import java.util.Collections;
17 import java.util.Comparator;
18 import java.util.List;
19 import java.util.Map.Entry;
20 import java.util.Set;
21
22 import org.eclipse.core.runtime.ListenerList;
23 import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency;
24 import org.simantics.g2d.diagram.DiagramHints;
25 import org.simantics.g2d.diagram.DiagramUtils;
26 import org.simantics.g2d.diagram.IDiagram;
27 import org.simantics.g2d.diagram.handler.PickContext;
28 import org.simantics.g2d.diagram.handler.PickRequest;
29 import org.simantics.g2d.diagram.handler.PickRequest.PickPolicy;
30 import org.simantics.g2d.diagram.handler.TransactionContext.TransactionType;
31 import org.simantics.g2d.element.ElementUtils;
32 import org.simantics.g2d.element.IElement;
33 import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler;
34 import org.simantics.scenegraph.g2d.events.command.Command;
35 import org.simantics.scenegraph.g2d.events.command.CommandEvent;
36 import org.simantics.scenegraph.g2d.events.command.Commands;
37 import org.simantics.utils.threads.ThreadUtils;
38
39 import gnu.trove.map.hash.TObjectIntHashMap;
40
41 /**
42  * This participant handles commands that manipulate z-ordering of elements.
43  * 
44  * @author Toni Kalajainen
45  */
46 public class ZOrderHandler extends AbstractDiagramParticipant {
47
48     @Dependency Selection sel;
49     @Dependency PickContext pickContext;
50
51     private final ListenerList<ZOrderListener> zOrderListeners = new ListenerList<>(ListenerList.IDENTITY);
52
53     public void addOrderListener(ZOrderListener listener) {
54         zOrderListeners.add(listener);
55     }
56
57     public void removeOrderListener(ZOrderListener listener) {
58         zOrderListeners.remove(listener);
59     }
60
61     @EventHandler(priority = 0)
62     public boolean handleCommand(CommandEvent ce) {
63         assertDependencies();
64         Command c = ce.command;
65
66         if (c.equals( Commands.BRING_UP )) {
67             final Set<IElement> selectedElements = sel.getAllSelections();
68             if (selectedElements==null || selectedElements.isEmpty()) return true;
69             //Shape area = ElementUtils.getElementBoundsOnDiagram(selectedElements);
70             Shape area = ElementUtils.getElementShapesOnDiagram(selectedElements);
71             if (area==null) return true;
72             final ArrayList<IElement> pickedElements = new ArrayList<IElement>();
73             PickRequest req = new PickRequest(area).context(getContext());
74             req.pickPolicy = PickPolicy.PICK_INTERSECTING_OBJECTS;
75             pickContext.pick(diagram, req, pickedElements);
76             DiagramUtils.inDiagramTransaction(diagram, TransactionType.WRITE, new Runnable() {
77                 @Override
78                 public void run() {
79                     List<IElement> elements = diagram.getElements();
80
81                     boolean changed = false;
82                     int nextPos = elements.size()-1;
83                     for (int i=pickedElements.size()-1; i>=0; i--)
84                     {
85                         IElement e = pickedElements.get(i);
86                         int index = elements.indexOf(e);
87                         if (index != -1 && selectedElements.contains(e)) {
88                             changed |= diagram.moveTo(e, nextPos);
89                             nextPos = index;
90                         }
91                     }
92                     if (changed) {
93                         notifyZOrderListeners(diagram);
94                         setDirty();
95                         scheduleSynchronizeElementOrder(diagram);
96                     }
97                 }
98             });
99             return true;
100         }
101         if (c.equals( Commands.SEND_DOWN)) {
102             final Set<IElement> selectedElements = sel.getAllSelections();
103             if (selectedElements==null || selectedElements.isEmpty()) return true;
104             //Shape area = ElementUtils.getElementBoundsOnDiagram(selectedElements);
105             Shape area = ElementUtils.getElementShapesOnDiagram(selectedElements);
106             if (area==null) return true;
107             final ArrayList<IElement> pickedElements = new ArrayList<IElement>();
108             PickRequest req = new PickRequest(area).context(getContext());
109             req.pickPolicy = PickPolicy.PICK_INTERSECTING_OBJECTS;
110             pickContext.pick(diagram, req, pickedElements);
111             DiagramUtils.inDiagramTransaction(diagram, TransactionType.WRITE, new Runnable() {
112                 @Override
113                 public void run() {
114                     List<IElement> elements = diagram.getElements();
115
116                     boolean changed = false;
117                     int nextPos = 0;
118                     for (int i=0; i<pickedElements.size(); i++)
119                     {
120                         IElement e = pickedElements.get(i);
121                         int index = elements.indexOf(e);
122                         if (index != -1 && selectedElements.contains(e)) {
123                             changed |= diagram.moveTo(e, nextPos);
124                             nextPos = index;
125                         }
126                     }
127                     if (changed) {
128                         notifyZOrderListeners(diagram);
129                         setDirty();
130                         scheduleSynchronizeElementOrder(diagram);
131                     }
132                 }
133             });
134             return true;
135         }
136         if (c.equals( Commands.BRING_TO_TOP) ){
137             DiagramUtils.inDiagramTransaction(diagram, TransactionType.WRITE, new Runnable() {
138                 @Override
139                 public void run() {
140                     boolean changed = false;
141                     for (Entry<Integer, Set<IElement>> e : sel.getSelections().entrySet())
142                     {
143                         ArrayList<IElement> ll = new ArrayList<IElement>(e.getValue());
144                         _sortByOrder(ll);
145                         for (int i=ll.size()-1; i>=0; i--) {
146                             if (diagram.containsElement(ll.get(i)))
147                                 changed |= diagram.bringToTop(ll.get(i));
148                         }
149                     }
150                     if (changed) {
151                         notifyZOrderListeners(diagram);
152                         setDirty();
153                         scheduleSynchronizeElementOrder(diagram);
154                     }
155                 }
156             });
157             return true;
158         }
159         if (c.equals( Commands.SEND_TO_BOTTOM) ){
160             DiagramUtils.inDiagramTransaction(diagram, TransactionType.WRITE, new Runnable() {
161                 @Override
162                 public void run() {
163                     boolean changed = false;
164                     for (Entry<Integer, Set<IElement>> e : sel.getSelections().entrySet())
165                     {
166                         ArrayList<IElement> ll = new ArrayList<IElement>(e.getValue());
167                         _sortByOrder(ll);
168                         for (int i=0; i<ll.size(); i++) {
169                             if (diagram.containsElement(ll.get(i)))
170                                 changed |= diagram.sendToBottom(ll.get(i));
171                         }
172                     }
173                     if (changed) {
174                         notifyZOrderListeners(diagram);
175                         setDirty();
176                         scheduleSynchronizeElementOrder(diagram);
177                     }
178                 }
179             });
180             return true;
181         }
182         return false;
183     }
184
185     void scheduleSynchronizeElementOrder(final IDiagram diagram) {
186         // Make sure that a mutator exists before doing this.
187         if (diagram.getHint(DiagramHints.KEY_MUTATOR) == null)
188             return;
189
190         // Perform back-end write in background thread to make the UI more
191         // responsive.
192         ThreadUtils.getBlockingWorkExecutor().execute(() -> {
193             DiagramUtils.mutateDiagram(diagram, m -> m.synchronizeElementOrder());
194                 //System.out.println("z-order synchronized to back-end");
195         });
196     }
197
198     void notifyZOrderListeners(IDiagram diagram) {
199         for (Object l : zOrderListeners.getListeners()) {
200             ((ZOrderListener) l).orderChanged(diagram);
201         }
202     }
203
204     void _sortByOrder(List<IElement> list)
205     {
206         List<IElement> elements = diagram.getElements();
207         final TObjectIntHashMap<IElement> position = new TObjectIntHashMap<IElement>();
208         for (IElement e : list)
209             position.put(e, elements.indexOf(e));
210         Comparator<IElement> c = new Comparator<IElement>() {
211             @Override
212             public int compare(IElement o1, IElement o2) {
213                 int pos1 = position.get(o1);
214                 int pos2 = position.get(o2);
215                 return pos2-pos1;
216             }
217         };
218         Collections.sort(list, c);
219     }
220
221 }