]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.diagram/src/org/simantics/diagram/handler/HighlightMode.java
Logger fixes after merge commit:fdbe8762
[simantics/platform.git] / bundles / org.simantics.diagram / src / org / simantics / diagram / handler / HighlightMode.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.diagram.handler;\r
13 \r
14 import java.awt.BasicStroke;\r
15 import java.awt.Color;\r
16 import java.awt.Shape;\r
17 import java.awt.geom.Area;\r
18 import java.awt.geom.Path2D;\r
19 import java.util.Collection;\r
20 import java.util.concurrent.Future;\r
21 import java.util.concurrent.TimeUnit;\r
22 \r
23 import org.simantics.g2d.canvas.ICanvasContext;\r
24 import org.simantics.g2d.canvas.SGDesignation;\r
25 import org.simantics.g2d.canvas.impl.AbstractCanvasParticipant;\r
26 import org.simantics.g2d.canvas.impl.SGNodeReflection.SGCleanup;\r
27 import org.simantics.g2d.canvas.impl.SGNodeReflection.SGInit;\r
28 import org.simantics.g2d.element.ElementClass;\r
29 import org.simantics.g2d.element.ElementHints;\r
30 import org.simantics.g2d.element.ElementUtils;\r
31 import org.simantics.g2d.element.IElement;\r
32 import org.simantics.g2d.element.handler.SelectionOutline;\r
33 import org.simantics.scenegraph.g2d.G2DParentNode;\r
34 import org.simantics.scenegraph.g2d.nodes.ShapeNode;\r
35 import org.simantics.scenegraph.g2d.nodes.SingleElementNode;\r
36 import org.simantics.utils.datastructures.hints.IHintContext.Key;\r
37 import org.simantics.utils.datastructures.hints.IHintListener;\r
38 import org.simantics.utils.datastructures.hints.IHintObservable;\r
39 import org.simantics.utils.threads.ThreadUtils;\r
40 \r
41 /**\r
42  * This participant highlights the specified DiagramSelection on its source\r
43  * diagram as a stroked frame tightly surrounding the selected elements.\r
44  * \r
45  * @author Tuukka Lehtonen\r
46  */\r
47 public class HighlightMode extends AbstractCanvasParticipant implements IHintListener {\r
48 \r
49     private final Color  CUT_COLOR  = Color.ORANGE;\r
50     private final Color  COPY_COLOR = new Color(128, 220, 150);\r
51 \r
52     private final BasicStroke DEFAULT_STROKE = new BasicStroke(3.0f);\r
53 \r
54     DiagramSelection     selection;\r
55     int                  selectionId;\r
56     int                  paintPriority;\r
57 \r
58     SingleElementNode    highlightNode;\r
59     Collection<IElement> highlightElements;\r
60 \r
61     public HighlightMode(DiagramSelection selection, int selectionId, int paintPriority) {\r
62         this.selection = selection;\r
63         this.selectionId = selectionId;\r
64         this.paintPriority = paintPriority;\r
65     }\r
66 \r
67     @SGInit(designation = SGDesignation.CANVAS)\r
68     public void init(G2DParentNode parent) {\r
69         highlightNode = parent.addNode("cut/copy source highlight", SingleElementNode.class);\r
70         highlightNode.setZIndex(paintPriority);\r
71         highlightNode.setVisible(false);\r
72 \r
73         // This slows rendering down too much to use.\r
74         //highlightNode.setComposite(AlphaComposite.SrcOver.derive(0.4f));\r
75 \r
76         this.highlightElements = selection.getOriginalElements();\r
77 \r
78         for (IElement e : highlightElements)\r
79             e.addHintListener(this);\r
80 \r
81         paintSelectionFrames(highlightNode, selection, selectionId);\r
82     }\r
83 \r
84     @SGCleanup\r
85     public void cleanupSG() {\r
86         for (IElement e : highlightElements)\r
87             e.removeHintListener(this);\r
88 \r
89         highlightNode.remove();\r
90     }\r
91 \r
92     void paintSelectionFrames(G2DParentNode parentNode, DiagramSelection selection, int selectionId) {\r
93         Area cutArea = new Area();\r
94         for (IElement e : selection.getOriginalElements()) {\r
95             ElementClass ec = e.getElementClass();\r
96             SelectionOutline so = ec.getAtMostOneItemOfClass(SelectionOutline.class);\r
97             Shape shape = so != null ? so.getSelectionShape(e) : ElementUtils.getElementShapeOrBoundsOnDiagram(e);\r
98             cutArea.add(new Area(shape));\r
99         }\r
100         if (!cutArea.isEmpty()) {\r
101             // Is rendering of Area slower than Path2D?\r
102             Path2D.Double path = new Path2D.Double(cutArea);\r
103 \r
104             ShapeNode shapeNode = parentNode.getOrCreateNode("highlight", ShapeNode.class);\r
105             shapeNode.setShape(path);\r
106             shapeNode.setScaleStroke(true);\r
107             shapeNode.setStroke(DEFAULT_STROKE);\r
108             shapeNode.setFill(false);\r
109             shapeNode.setColor(selection.isCut() ? CUT_COLOR : COPY_COLOR);\r
110 \r
111             highlightNode.setVisible(true);\r
112         }\r
113     }\r
114 \r
115     @Override\r
116     public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) {\r
117         if (key == ElementHints.KEY_TRANSFORM) {\r
118             //System.out.println("transform changed for " + sender + " to " + newValue);\r
119             highlightNode.setVisible(false);\r
120             deferredHighlightUpdate();\r
121         }\r
122     }\r
123 \r
124     @Override\r
125     public void hintRemoved(IHintObservable sender, Key key, Object oldValue) {\r
126     }\r
127 \r
128     Future<?> updateTask;\r
129 \r
130     private synchronized void deferredHighlightUpdate() {\r
131         if (updateTask == null) {\r
132             updateTask = ThreadUtils.getNonBlockingWorkExecutor().schedule(\r
133                     updateScheduler,\r
134                     100,\r
135                     TimeUnit.MILLISECONDS);\r
136         }\r
137     }\r
138 \r
139     Runnable updateScheduler = new Runnable() {\r
140         @Override\r
141         public void run() {\r
142             ICanvasContext ctx = getContext();\r
143             if (ctx != null)\r
144                 ThreadUtils.asyncExec(ctx.getThreadAccess(), painter);\r
145         }\r
146     };\r
147 \r
148     Runnable painter = new Runnable() {\r
149         @Override\r
150         public void run() {\r
151             if (!isRemoved())\r
152                 paintSelectionFrames(highlightNode, selection, selectionId);\r
153             updateTask = null;\r
154         }\r
155     };\r
156 \r
157 }