1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
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
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.g2d.diagram.participant;
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;
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;
39 import gnu.trove.map.hash.TObjectIntHashMap;
42 * This participant handles commands that manipulate z-ordering of elements.
44 * @author Toni Kalajainen
46 public class ZOrderHandler extends AbstractDiagramParticipant {
48 @Dependency Selection sel;
49 @Dependency PickContext pickContext;
51 private final ListenerList zOrderListeners = new ListenerList(ListenerList.IDENTITY);
53 public void addOrderListener(ZOrderListener listener) {
54 zOrderListeners.add(listener);
57 public void removeOrderListener(ZOrderListener listener) {
58 zOrderListeners.remove(listener);
61 @EventHandler(priority = 0)
62 public boolean handleCommand(CommandEvent ce) {
64 Command c = ce.command;
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);
74 req.pickPolicy = PickPolicy.PICK_INTERSECTING_OBJECTS;
75 pickContext.pick(diagram, req, pickedElements);
76 DiagramUtils.inDiagramTransaction(diagram, TransactionType.WRITE, new Runnable() {
79 List<IElement> elements = diagram.getElements();
81 boolean changed = false;
82 int nextPos = elements.size()-1;
83 for (int i=pickedElements.size()-1; i>=0; i--)
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);
93 notifyZOrderListeners(diagram);
95 scheduleSynchronizeElementOrder(diagram);
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);
109 req.pickPolicy = PickPolicy.PICK_INTERSECTING_OBJECTS;
110 pickContext.pick(diagram, req, pickedElements);
111 DiagramUtils.inDiagramTransaction(diagram, TransactionType.WRITE, new Runnable() {
114 List<IElement> elements = diagram.getElements();
116 boolean changed = false;
118 for (int i=0; i<pickedElements.size(); i++)
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);
128 notifyZOrderListeners(diagram);
130 scheduleSynchronizeElementOrder(diagram);
136 if (c.equals( Commands.BRING_TO_TOP) ){
137 DiagramUtils.inDiagramTransaction(diagram, TransactionType.WRITE, new Runnable() {
140 boolean changed = false;
141 for (Entry<Integer, Set<IElement>> e : sel.getSelections().entrySet())
143 ArrayList<IElement> ll = new ArrayList<IElement>(e.getValue());
145 for (int i=ll.size()-1; i>=0; i--) {
146 if (diagram.containsElement(ll.get(i)))
147 changed |= diagram.bringToTop(ll.get(i));
151 notifyZOrderListeners(diagram);
153 scheduleSynchronizeElementOrder(diagram);
159 if (c.equals( Commands.SEND_TO_BOTTOM) ){
160 DiagramUtils.inDiagramTransaction(diagram, TransactionType.WRITE, new Runnable() {
163 boolean changed = false;
164 for (Entry<Integer, Set<IElement>> e : sel.getSelections().entrySet())
166 ArrayList<IElement> ll = new ArrayList<IElement>(e.getValue());
168 for (int i=0; i<ll.size(); i++) {
169 if (diagram.containsElement(ll.get(i)))
170 changed |= diagram.sendToBottom(ll.get(i));
174 notifyZOrderListeners(diagram);
176 scheduleSynchronizeElementOrder(diagram);
185 void scheduleSynchronizeElementOrder(final IDiagram diagram) {
186 // Make sure that a mutator exists before doing this.
187 if (diagram.getHint(DiagramHints.KEY_MUTATOR) == null)
190 // Perform back-end write in background thread to make the UI more
192 ThreadUtils.getBlockingWorkExecutor().execute(() -> {
193 DiagramUtils.mutateDiagram(diagram, m -> m.synchronizeElementOrder());
194 //System.out.println("z-order synchronized to back-end");
198 void notifyZOrderListeners(IDiagram diagram) {
199 for (Object l : zOrderListeners.getListeners()) {
200 ((ZOrderListener) l).orderChanged(diagram);
204 void _sortByOrder(List<IElement> list)
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>() {
212 public int compare(IElement o1, IElement o2) {
213 int pos1 = position.get(o1);
214 int pos2 = position.get(o2);
218 Collections.sort(list, c);