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