Commit | Line | Data |
---|---|---|
fb5cad3d PT |
1 | /*****************************************************************************\r |
2 | * Copyright (c) 2007 Intel Corporation, 2009, 2012 Ericsson.\r | |
3 | * All rights reserved. This program and the accompanying materials\r | |
4 | * are made available under the terms of the Eclipse Public License v1.0\r | |
5 | * which accompanies this distribution, and is available at\r | |
6 | * http://www.eclipse.org/legal/epl-v10.html\r | |
7 | *\r | |
8 | * Contributors:\r | |
9 | * Intel Corporation - Initial API and implementation\r | |
10 | * Vitaly A. Provodin, Intel - Initial API and implementation\r | |
11 | * Alvaro Sanchez-Leon - Updated for TMF\r | |
12 | * Patrick Tasse - Refactoring\r | |
13 | *\r | |
14 | *****************************************************************************/\r | |
15 | package org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets;\r | |
16 | \r | |
17 | import java.util.Iterator;\r | |
18 | import java.util.Map;\r | |
19 | \r | |
20 | import org.eclipse.linuxtools.internal.tmf.ui.Messages;\r | |
b83af2c3 | 21 | import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphPresentationProvider;\r |
fb5cad3d PT |
22 | import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeEvent;\r |
23 | import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;\r | |
24 | import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets.Utils.Resolution;\r | |
25 | import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets.Utils.TimeFormat;\r | |
26 | import org.eclipse.swt.SWT;\r | |
27 | import org.eclipse.swt.events.MouseAdapter;\r | |
28 | import org.eclipse.swt.events.MouseEvent;\r | |
b83af2c3 | 29 | import org.eclipse.swt.events.MouseMoveListener;\r |
fb5cad3d PT |
30 | import org.eclipse.swt.events.MouseTrackAdapter;\r |
31 | import org.eclipse.swt.graphics.Point;\r | |
32 | import org.eclipse.swt.graphics.Rectangle;\r | |
fb5cad3d PT |
33 | import org.eclipse.swt.layout.GridLayout;\r |
34 | import org.eclipse.swt.widgets.Control;\r | |
35 | import org.eclipse.swt.widgets.Display;\r | |
36 | import org.eclipse.swt.widgets.Shell;\r | |
37 | import org.eclipse.swt.widgets.Table;\r | |
38 | import org.eclipse.swt.widgets.TableColumn;\r | |
39 | import org.eclipse.swt.widgets.TableItem;\r | |
fb5cad3d | 40 | \r |
013a5f1c AM |
41 | /**\r |
42 | * Handler for the tool tips in the generic time graph view.\r | |
43 | *\r | |
44 | * @version 1.0\r | |
45 | * @author Alvaro Sanchez-Leon\r | |
46 | * @author Patrick Tasse\r | |
47 | */\r | |
fb5cad3d PT |
48 | public class TimeGraphTooltipHandler {\r |
49 | \r | |
6a08b49e PT |
50 | private Shell _tipShell;\r |
51 | private Table _tipTable;\r | |
fb5cad3d | 52 | private Point _tipPosition;\r |
013a5f1c | 53 | private final ITimeDataProvider _timeDataProvider;\r |
b83af2c3 | 54 | ITimeGraphPresentationProvider _utilImp = null;\r |
fb5cad3d | 55 | \r |
3934297e AM |
56 | /**\r |
57 | * Standard constructor\r | |
58 | *\r | |
59 | * @param parent\r | |
6a08b49e | 60 | * The parent shell (unused, can be null)\r |
3934297e AM |
61 | * @param rUtilImpl\r |
62 | * The presentation provider\r | |
63 | * @param timeProv\r | |
64 | * The time provider\r | |
65 | */\r | |
b83af2c3 | 66 | public TimeGraphTooltipHandler(Shell parent, ITimeGraphPresentationProvider rUtilImpl,\r |
fb5cad3d | 67 | ITimeDataProvider timeProv) {\r |
fb5cad3d PT |
68 | \r |
69 | this._utilImp = rUtilImpl;\r | |
70 | this._timeDataProvider = timeProv;\r | |
6a08b49e PT |
71 | }\r |
72 | \r | |
73 | private void createTooltipShell(Shell parent) {\r | |
74 | final Display display = parent.getDisplay();\r | |
75 | if (_tipShell != null && ! _tipShell.isDisposed()) {\r | |
76 | _tipShell.dispose();\r | |
77 | }\r | |
fb5cad3d PT |
78 | _tipShell = new Shell(parent, SWT.ON_TOP | SWT.TOOL);\r |
79 | GridLayout gridLayout = new GridLayout();\r | |
80 | gridLayout.numColumns = 2;\r | |
81 | gridLayout.marginWidth = 2;\r | |
82 | gridLayout.marginHeight = 2;\r | |
83 | _tipShell.setLayout(gridLayout);\r | |
6a08b49e | 84 | _tipShell.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));\r |
fb5cad3d PT |
85 | \r |
86 | _tipTable = new Table(_tipShell, SWT.NONE);\r | |
b83af2c3 PT |
87 | new TableColumn(_tipTable, SWT.NONE);\r |
88 | new TableColumn(_tipTable, SWT.NONE);\r | |
fb5cad3d PT |
89 | _tipTable.setForeground(display\r |
90 | .getSystemColor(SWT.COLOR_INFO_FOREGROUND));\r | |
91 | _tipTable.setBackground(display\r | |
92 | .getSystemColor(SWT.COLOR_INFO_BACKGROUND));\r | |
93 | _tipTable.setHeaderVisible(false);\r | |
94 | _tipTable.setLinesVisible(false);\r | |
95 | \r | |
6a08b49e PT |
96 | _tipTable.addMouseListener(new MouseAdapter() {\r |
97 | @Override\r | |
98 | public void mouseDown(MouseEvent e) {\r | |
99 | _tipShell.dispose();\r | |
100 | }\r | |
101 | });\r | |
102 | \r | |
103 | _tipTable.addMouseTrackListener(new MouseTrackAdapter() {\r | |
104 | @Override\r | |
105 | public void mouseExit(MouseEvent e) {\r | |
106 | _tipShell.dispose();\r | |
107 | }\r | |
108 | });\r | |
109 | \r | |
110 | _tipTable.addMouseMoveListener(new MouseMoveListener() {\r | |
111 | @Override\r | |
112 | public void mouseMove(MouseEvent e) {\r | |
113 | _tipShell.dispose();\r | |
114 | }\r | |
115 | });\r | |
fb5cad3d PT |
116 | }\r |
117 | \r | |
3934297e AM |
118 | /**\r |
119 | * Callback for the mouse-over tooltip\r | |
120 | *\r | |
121 | * @param control\r | |
122 | * The control object to use\r | |
123 | */\r | |
fb5cad3d | 124 | public void activateHoverHelp(final Control control) {\r |
fb5cad3d PT |
125 | control.addMouseListener(new MouseAdapter() {\r |
126 | @Override\r | |
127 | public void mouseDown(MouseEvent e) {\r | |
6a08b49e PT |
128 | if (_tipShell != null && ! _tipShell.isDisposed()) {\r |
129 | _tipShell.dispose();\r | |
b83af2c3 PT |
130 | }\r |
131 | }\r | |
132 | });\r | |
133 | \r | |
134 | control.addMouseMoveListener(new MouseMoveListener() {\r | |
135 | @Override\r | |
136 | public void mouseMove(MouseEvent e) {\r | |
6a08b49e PT |
137 | if (_tipShell != null && ! _tipShell.isDisposed()) {\r |
138 | _tipShell.dispose();\r | |
b83af2c3 | 139 | }\r |
fb5cad3d PT |
140 | }\r |
141 | });\r | |
142 | \r | |
143 | control.addMouseTrackListener(new MouseTrackAdapter() {\r | |
144 | @Override\r | |
145 | public void mouseExit(MouseEvent e) {\r | |
6a08b49e PT |
146 | if (_tipShell != null && ! _tipShell.isDisposed()) {\r |
147 | Point pt = control.toDisplay(e.x, e.y);\r | |
148 | if (! _tipShell.getBounds().contains(pt)) {\r | |
149 | _tipShell.dispose();\r | |
150 | }\r | |
b83af2c3 | 151 | }\r |
fb5cad3d PT |
152 | }\r |
153 | \r | |
154 | private void addItem(String name, String value) {\r | |
155 | TableItem line = new TableItem(_tipTable, SWT.NONE);\r | |
156 | line.setText(0, name);\r | |
157 | line.setText(1, value);\r | |
158 | }\r | |
159 | \r | |
6a08b49e | 160 | private void fillValues(Point pt, TimeGraphControl timeGraphControl, ITimeGraphEntry entry) {\r |
f379b3eb | 161 | if (entry == null) {\r |
fb5cad3d PT |
162 | return;\r |
163 | }\r | |
f379b3eb | 164 | if (entry.hasTimeEvents()) {\r |
6a08b49e PT |
165 | long currPixelTime = timeGraphControl.getTimeAtX(pt.x);\r |
166 | long nextPixelTime = timeGraphControl.getTimeAtX(pt.x + 1);\r | |
167 | if (nextPixelTime == currPixelTime) {\r | |
168 | nextPixelTime++;\r | |
169 | }\r | |
170 | ITimeEvent currEvent = Utils.findEvent(entry, currPixelTime, 0);\r | |
171 | ITimeEvent nextEvent = Utils.findEvent(entry, currPixelTime, 1);\r | |
172 | \r | |
173 | // if there is no current event at the start of the current pixel range,\r | |
174 | // or if the current event starts before the current pixel range,\r | |
175 | // use the next event as long as it starts within the current pixel range\r | |
176 | if (currEvent == null || currEvent.getTime() < currPixelTime) {\r | |
177 | if (nextEvent != null && nextEvent.getTime() < nextPixelTime) {\r | |
178 | currEvent = nextEvent;\r | |
179 | }\r | |
180 | }\r | |
181 | \r | |
549f3c43 | 182 | // state name\r |
9cd23350 BH |
183 | String stateTypeName = _utilImp.getStateTypeName(entry);\r |
184 | String entryName = entry.getName();\r | |
185 | if (stateTypeName == null) {\r | |
186 | stateTypeName = _utilImp.getStateTypeName();\r | |
187 | }\r | |
188 | \r | |
189 | if (!entryName.isEmpty()) {\r | |
190 | addItem(stateTypeName, entry.getName());\r | |
191 | }\r | |
192 | \r | |
6a08b49e | 193 | if (currEvent == null) {\r |
b83af2c3 PT |
194 | return;\r |
195 | }\r | |
9cd23350 | 196 | \r |
6a08b49e PT |
197 | // state\r |
198 | String state = _utilImp.getEventName(currEvent);\r | |
fb5cad3d PT |
199 | if (state != null) {\r |
200 | addItem(Messages.TmfTimeTipHandler_TRACE_STATE, state);\r | |
201 | }\r | |
202 | \r | |
6a08b49e PT |
203 | // This block receives a list of <String, String> values to be added to the tip table\r |
204 | Map<String, String> eventAddOns = _utilImp.getEventHoverToolTipInfo(currEvent);\r | |
fb5cad3d PT |
205 | if (eventAddOns != null) {\r |
206 | for (Iterator<String> iter = eventAddOns.keySet().iterator(); iter.hasNext();) {\r | |
abbdd66a | 207 | String message = iter.next();\r |
fb5cad3d PT |
208 | addItem(message, eventAddOns.get(message));\r |
209 | }\r | |
210 | }\r | |
211 | \r | |
212 | long eventStartTime = -1;\r | |
213 | long eventDuration = -1;\r | |
214 | long eventEndTime = -1;\r | |
215 | \r | |
6a08b49e PT |
216 | eventStartTime = currEvent.getTime();\r |
217 | eventDuration = currEvent.getDuration();\r | |
abbdd66a AM |
218 | if (eventDuration < 0 && nextEvent != null) {\r |
219 | eventEndTime = nextEvent.getTime();\r | |
220 | eventDuration = eventEndTime - eventStartTime;\r | |
221 | } else {\r | |
222 | eventEndTime = eventStartTime + eventDuration;\r | |
fb5cad3d PT |
223 | }\r |
224 | \r | |
fb5cad3d PT |
225 | Resolution res = Resolution.NANOSEC;\r |
226 | if (_timeDataProvider.isCalendarFormat()) {\r | |
fb5cad3d PT |
227 | addItem(Messages.TmfTimeTipHandler_TRACE_DATE, eventStartTime > -1 ?\r |
228 | Utils.formatDate(eventStartTime)\r | |
229 | : "?"); //$NON-NLS-1$\r | |
230 | if (eventDuration > 0) {\r | |
231 | addItem(Messages.TmfTimeTipHandler_TRACE_START_TIME, eventStartTime > -1 ?\r | |
232 | Utils.formatTime(eventStartTime, TimeFormat.ABSOLUTE, res)\r | |
233 | : "?"); //$NON-NLS-1$\r | |
234 | \r | |
235 | addItem(Messages.TmfTimeTipHandler_TRACE_STOP_TIME, eventEndTime > -1 ?\r | |
236 | Utils.formatTime(eventEndTime, TimeFormat.ABSOLUTE, res)\r | |
237 | : "?"); //$NON-NLS-1$\r | |
238 | } else {\r | |
239 | addItem(Messages.TmfTimeTipHandler_TRACE_EVENT_TIME, eventStartTime > -1 ?\r | |
240 | Utils.formatTime(eventStartTime, TimeFormat.ABSOLUTE, res)\r | |
241 | : "?"); //$NON-NLS-1$\r | |
242 | }\r | |
243 | } else {\r | |
244 | if (eventDuration > 0) {\r | |
245 | addItem(Messages.TmfTimeTipHandler_TRACE_START_TIME, eventStartTime > -1 ?\r | |
246 | Utils.formatTime(eventStartTime, TimeFormat.RELATIVE, res)\r | |
247 | : "?"); //$NON-NLS-1$\r | |
248 | \r | |
249 | addItem(Messages.TmfTimeTipHandler_TRACE_STOP_TIME, eventEndTime > -1 ?\r | |
250 | Utils.formatTime(eventEndTime, TimeFormat.RELATIVE, res)\r | |
251 | : "?"); //$NON-NLS-1$\r | |
252 | } else {\r | |
253 | addItem(Messages.TmfTimeTipHandler_TRACE_EVENT_TIME, eventStartTime > -1 ?\r | |
254 | Utils.formatTime(eventStartTime, TimeFormat.RELATIVE, res)\r | |
255 | : "?"); //$NON-NLS-1$\r | |
256 | }\r | |
257 | }\r | |
258 | \r | |
259 | if (eventDuration > 0) {\r | |
260 | // Duration in relative format in any case\r | |
261 | addItem(Messages.TmfTimeTipHandler_DURATION, eventDuration > -1 ?\r | |
262 | Utils.formatTime(eventDuration, TimeFormat.RELATIVE, res)\r | |
263 | : "?"); //$NON-NLS-1$\r | |
264 | }\r | |
265 | }\r | |
266 | }\r | |
267 | \r | |
268 | @Override\r | |
269 | public void mouseHover(MouseEvent event) {\r | |
270 | Point pt = new Point(event.x, event.y);\r | |
6a08b49e PT |
271 | TimeGraphControl timeGraphControl = (TimeGraphControl) event.widget;\r |
272 | createTooltipShell(timeGraphControl.getShell());\r | |
273 | ITimeGraphEntry entry = timeGraphControl.getEntry(pt);\r | |
b83af2c3 | 274 | _tipTable.remove(0, _tipTable.getItemCount() - 1);\r |
6a08b49e | 275 | fillValues(pt, timeGraphControl, entry);\r |
1571f4e4 PT |
276 | if (_tipTable.getItemCount() == 0) {\r |
277 | return;\r | |
278 | }\r | |
0c779b95 | 279 | _tipTable.getColumn(0).pack();\r |
b83af2c3 | 280 | _tipTable.getColumn(1).pack();\r |
b83af2c3 | 281 | _tipShell.pack();\r |
fb5cad3d PT |
282 | _tipPosition = control.toDisplay(pt);\r |
283 | _tipShell.pack();\r | |
284 | setHoverLocation(_tipShell, _tipPosition);\r | |
285 | _tipShell.setVisible(true);\r | |
286 | }\r | |
287 | });\r | |
288 | }\r | |
289 | \r | |
abbdd66a | 290 | private static void setHoverLocation(Shell shell, Point position) {\r |
fb5cad3d PT |
291 | Rectangle displayBounds = shell.getDisplay().getBounds();\r |
292 | Rectangle shellBounds = shell.getBounds();\r | |
6a08b49e PT |
293 | if (position.x + shellBounds.width + 16 > displayBounds.width && position.x - shellBounds.width - 16 >= 0) {\r |
294 | shellBounds.x = position.x - shellBounds.width - 16;\r | |
295 | } else {\r | |
296 | shellBounds.x = Math.max(Math.min(position.x + 16, displayBounds.width - shellBounds.width), 0);\r | |
297 | }\r | |
298 | if (position.y + shellBounds.height + 16 > displayBounds.height && position.y - shellBounds.height - 16 >= 0) {\r | |
299 | shellBounds.y = position.y - shellBounds.height - 16;\r | |
300 | } else {\r | |
301 | shellBounds.y = Math.max(Math.min(position.y + 16, displayBounds.height - shellBounds.height), 0);\r | |
302 | }\r | |
fb5cad3d PT |
303 | shell.setBounds(shellBounds);\r |
304 | }\r | |
305 | \r | |
549f3c43 | 306 | } |