]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagramEditor/TerminalInformer.java
Sync git svn branch with SVN repository r33406.
[simantics/platform.git] / bundles / org.simantics.modeling.ui / src / org / simantics / modeling / ui / diagramEditor / TerminalInformer.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.modeling.ui.diagramEditor;\r
13 \r
14 import java.awt.geom.Point2D;\r
15 import java.awt.geom.Rectangle2D;\r
16 import java.util.function.Consumer;\r
17 \r
18 import org.eclipse.jface.action.IStatusLineManager;\r
19 import org.eclipse.jface.resource.ImageDescriptor;\r
20 import org.eclipse.jface.resource.JFaceResources;\r
21 import org.eclipse.jface.resource.ResourceManager;\r
22 import org.eclipse.swt.graphics.Image;\r
23 import org.eclipse.swt.widgets.Control;\r
24 import org.eclipse.swt.widgets.Display;\r
25 import org.eclipse.ui.IWorkbenchPart;\r
26 import org.simantics.databoard.util.ObjectUtils;\r
27 import org.simantics.db.ReadGraph;\r
28 import org.simantics.db.common.procedure.adapter.ProcedureAdapter;\r
29 import org.simantics.db.common.request.BinaryRead;\r
30 import org.simantics.db.exception.DatabaseException;\r
31 import org.simantics.g2d.canvas.ICanvasContext;\r
32 import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency;\r
33 import org.simantics.g2d.diagram.participant.AbstractDiagramParticipant;\r
34 import org.simantics.g2d.diagram.participant.pointertool.PointerInteractor;\r
35 import org.simantics.g2d.diagram.participant.pointertool.TerminalUtil;\r
36 import org.simantics.g2d.diagram.participant.pointertool.TerminalUtil.TerminalInfo;\r
37 import org.simantics.g2d.participant.TransformUtil;\r
38 import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler;\r
39 import org.simantics.scenegraph.g2d.events.KeyEvent;\r
40 import org.simantics.scenegraph.g2d.events.KeyEvent.KeyPressedEvent;\r
41 import org.simantics.scenegraph.g2d.events.MouseEvent;\r
42 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseMovedEvent;\r
43 import org.simantics.ui.SimanticsUI;\r
44 import org.simantics.utils.datastructures.hints.IHintContext.Key;\r
45 import org.simantics.utils.datastructures.hints.IHintContext.KeyOf;\r
46 import org.simantics.utils.ui.ErrorLogger;\r
47 import org.simantics.utils.ui.SWTUtils;\r
48 import org.simantics.utils.ui.workbench.WorkbenchUtils;\r
49 \r
50 /**\r
51  * Shows information about the terminal under the mouse in the Workbench status\r
52  * line.\r
53  * \r
54  * @author Tuukka Lehtonen\r
55  */\r
56 public class TerminalInformer extends AbstractDiagramParticipant {\r
57 \r
58     public static interface TerminalNamingStrategy {\r
59         String getName(ReadGraph graph, TerminalInfo info) throws DatabaseException;\r
60     }\r
61 \r
62     /**\r
63      * If this hint is not set or set to <code>false</code>, this participant\r
64      * will show terminal information in the status bar.\r
65      */\r
66     public static final Key TERMINAL_INFO_DISABLED = new KeyOf(Boolean.class);\r
67 \r
68     @Dependency\r
69     protected PointerInteractor pointerInteractor;\r
70 \r
71     Control                 control;\r
72     transient Display       display;\r
73     IStatusLineManager      statusLine;\r
74     ImageDescriptor         currentImage;\r
75 \r
76     @Dependency\r
77     TransformUtil           util;\r
78 \r
79     Point2D                 p1                     = new Point2D.Double();\r
80     Point2D                 p2                     = new Point2D.Double();\r
81     Rectangle2D             rect                   = new Rectangle2D.Double();\r
82     String                  viewingMessage;\r
83 \r
84     final TerminalNamingStrategy terminalNamingStrategy;\r
85 \r
86     /**\r
87      * @param parentControl\r
88      * @param resourceManager deprecated argument, use <code>null</code>\r
89      * @param statusLine\r
90      * @param terminalNamingStrategy\r
91      */\r
92     public TerminalInformer(Control parentControl, ResourceManager resourceManager, IStatusLineManager statusLine, TerminalNamingStrategy terminalNamingStrategy) {\r
93         this.control = parentControl;\r
94         this.statusLine = statusLine;\r
95         this.terminalNamingStrategy = terminalNamingStrategy;\r
96     }\r
97 \r
98     @Override\r
99     public void removedFromContext(ICanvasContext ctx) {\r
100         super.removedFromContext(ctx);\r
101 \r
102         final IStatusLineManager statusLine = this.statusLine;\r
103         if (display != null && statusLine != null) {\r
104             SWTUtils.asyncExec(display, new Runnable() {\r
105                 @Override\r
106                 public void run() {\r
107                     if (statusLine != null) {\r
108                         statusLine.setMessage(null, null);\r
109                         statusLine.setErrorMessage(null, null);\r
110                     }\r
111                     if (currentImage != null) {\r
112                         JFaceResources.getResources().destroyImage(currentImage);\r
113                     }\r
114                 }\r
115             });\r
116         }\r
117     }\r
118 \r
119     public boolean infoDisabled() {\r
120         return Boolean.TRUE.equals(getHint(TERMINAL_INFO_DISABLED));\r
121     }\r
122 \r
123     private boolean infoEvent(MouseMovedEvent me) {\r
124         return (me.stateMask & MouseEvent.CTRL_MASK) != 0;\r
125     }\r
126 \r
127     private boolean infoEvent(KeyEvent ke) {\r
128         return ke.keyCode == java.awt.event.KeyEvent.VK_CONTROL && (ke instanceof KeyPressedEvent);\r
129     }\r
130 \r
131     @EventHandler(priority = 0)\r
132     public boolean handleKeys(KeyEvent ke) {\r
133         if (infoDisabled() || !infoEvent(ke)) {\r
134             setMessage(null);\r
135             return false;\r
136         }\r
137 \r
138         pickRect(rect);\r
139         return false;\r
140     }\r
141 \r
142     @EventHandler(priority = 0)\r
143     public boolean handleMove(MouseMovedEvent me) {\r
144         double pickDist = pointerInteractor.getPickDistance();\r
145         p1.setLocation(me.controlPosition.getX() - pickDist, me.controlPosition.getY() - pickDist);\r
146         p2.setLocation(me.controlPosition.getX() + pickDist, me.controlPosition.getY() + pickDist);\r
147         util.controlToCanvas(p1, p1);\r
148         util.controlToCanvas(p2, p2);\r
149         rect.setFrameFromDiagonal(p1, p2);\r
150 \r
151         if (infoDisabled() || !infoEvent(me)) {\r
152             setMessage(null);\r
153             return false;\r
154         }\r
155 \r
156         pickRect(rect);\r
157 \r
158         return false;\r
159     }\r
160 \r
161     private void createMessage(TerminalInfo terminal, final Consumer<String> callback) {\r
162         SimanticsUI.getSession().asyncRequest(new TerminalInfoMessage(terminal, terminalNamingStrategy), new ProcedureAdapter<String>() {\r
163             @Override\r
164             public void exception(Throwable t) {\r
165                 ErrorLogger.defaultLogError(t);\r
166             }\r
167             @Override\r
168             public void execute(String result) {\r
169                 callback.accept(result);\r
170             }\r
171         });\r
172     }\r
173 \r
174     private void pickRect(Rectangle2D rect) {\r
175         TerminalInfo terminal = TerminalUtil.pickTerminal(diagram, rect);\r
176         if (terminal != null) {\r
177             createMessage(terminal, message -> setMessage(null, message));\r
178         } else {\r
179             setMessage(null);\r
180         }\r
181     }\r
182 \r
183     private void setMessage(String message) {\r
184         setMessage(null, message);\r
185     }\r
186 \r
187     private void setMessage(final ImageDescriptor imageDescriptor, String _message) {\r
188         // Empty message equals no message.\r
189         if (_message != null && _message.isEmpty())\r
190             _message = null;\r
191         final String message = _message;\r
192 \r
193         if (viewingMessage == null && message == null)\r
194             return;\r
195         if (ObjectUtils.objectEquals(viewingMessage, message))\r
196             return;\r
197 \r
198         this.viewingMessage = message;\r
199 \r
200         SWTUtils.asyncExec(control, new Runnable() {\r
201             @Override\r
202             public void run() {\r
203                 if (control.isDisposed())\r
204                     return;\r
205                 display = control.getDisplay();\r
206 \r
207                 Image img = null;\r
208                 ResourceManager rm = JFaceResources.getResources();\r
209                 if (imageDescriptor != null) {\r
210                     if (imageDescriptor.equals(TerminalInformer.this.currentImage)) {\r
211                         img = (Image) rm.find(imageDescriptor);\r
212                     } else {\r
213                         img = (Image) rm.createImage(imageDescriptor);\r
214                         currentImage = imageDescriptor;\r
215                     }\r
216                 } else {\r
217                     if (currentImage != null) {\r
218                         rm.destroyImage(currentImage);\r
219                         currentImage = null;\r
220                     }\r
221                 }\r
222 \r
223                 IStatusLineManager statusLine = getStatusLine();\r
224                 if (statusLine != null) {\r
225                     statusLine.setMessage(img, message);\r
226                     statusLine.setErrorMessage(null);\r
227                 }\r
228             }\r
229         });\r
230     }\r
231 \r
232     static class TerminalInfoMessage extends BinaryRead<TerminalInfo, TerminalNamingStrategy, String> {\r
233         public TerminalInfoMessage(TerminalInfo info, TerminalNamingStrategy strategy) {\r
234             super(info, strategy);\r
235         }\r
236         @Override\r
237         public String perform(ReadGraph graph) throws DatabaseException {\r
238             return parameter2.getName(graph, parameter);\r
239         }\r
240     }\r
241 \r
242     protected IStatusLineManager getStatusLine() {\r
243         IWorkbenchPart activePart = WorkbenchUtils.getActiveWorkbenchPart();\r
244         if (activePart != null) {\r
245             TerminalInformer.this.statusLine = statusLine = WorkbenchUtils.getStatusLine(activePart);\r
246             return statusLine;\r
247         }\r
248         return null;\r
249     }\r
250 \r
251 }\r