1 /*****************************************************************************
2 * Copyright (c) 2007, 2014 Intel Corporation, Ericsson
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
9 * Intel Corporation - Initial API and implementation
10 * Vitaly A. Provodin, Intel - Initial API and implementation
11 * Alvaro Sanchez-Leon - Updated for TMF
12 * Patrick Tasse - Refactoring
13 *****************************************************************************/
15 package org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.widgets
;
17 import java
.util
.Iterator
;
20 import org
.eclipse
.linuxtools
.internal
.tmf
.ui
.Messages
;
21 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.ITimeGraphPresentationProvider
;
22 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.ILinkEvent
;
23 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.ITimeEvent
;
24 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.ITimeGraphEntry
;
25 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.NullTimeEvent
;
26 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.widgets
.Utils
.Resolution
;
27 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.widgets
.Utils
.TimeFormat
;
28 import org
.eclipse
.swt
.SWT
;
29 import org
.eclipse
.swt
.events
.MouseAdapter
;
30 import org
.eclipse
.swt
.events
.MouseEvent
;
31 import org
.eclipse
.swt
.events
.MouseMoveListener
;
32 import org
.eclipse
.swt
.events
.MouseTrackAdapter
;
33 import org
.eclipse
.swt
.graphics
.Point
;
34 import org
.eclipse
.swt
.graphics
.Rectangle
;
35 import org
.eclipse
.swt
.layout
.GridData
;
36 import org
.eclipse
.swt
.layout
.GridLayout
;
37 import org
.eclipse
.swt
.widgets
.Composite
;
38 import org
.eclipse
.swt
.widgets
.Control
;
39 import org
.eclipse
.swt
.widgets
.Display
;
40 import org
.eclipse
.swt
.widgets
.Label
;
41 import org
.eclipse
.swt
.widgets
.Shell
;
44 * Handler for the tool tips in the generic time graph view.
47 * @author Alvaro Sanchez-Leon
48 * @author Patrick Tasse
50 public class TimeGraphTooltipHandler
{
52 private static final int OFFSET
= 16;
54 private Shell fTipShell
;
55 private Composite fTipComposite
;
56 private ITimeDataProvider fTimeDataProvider
;
57 private ITimeGraphPresentationProvider fTimeGraphProvider
= null;
60 * Standard constructor
63 * The presentation provider
69 public TimeGraphTooltipHandler(ITimeGraphPresentationProvider graphProv
,
70 ITimeDataProvider timeProv
) {
72 this.fTimeGraphProvider
= graphProv
;
73 this.fTimeDataProvider
= timeProv
;
77 * Set the time data provider
79 * @param timeDataProvider
80 * The time data provider
84 public void setTimeProvider(ITimeDataProvider timeDataProvider
) {
85 fTimeDataProvider
= timeDataProvider
;
88 private void createTooltipShell(Shell parent
) {
89 final Display display
= parent
.getDisplay();
90 if (fTipShell
!= null && ! fTipShell
.isDisposed()) {
93 fTipShell
= new Shell(parent
, SWT
.ON_TOP
| SWT
.TOOL
);
94 GridLayout gridLayout
= new GridLayout();
95 gridLayout
.numColumns
= 2;
96 gridLayout
.marginWidth
= 2;
97 gridLayout
.marginHeight
= 2;
98 fTipShell
.setLayout(gridLayout
);
99 fTipShell
.setBackground(display
.getSystemColor(SWT
.COLOR_INFO_BACKGROUND
));
101 fTipComposite
= new Composite(fTipShell
, SWT
.NONE
);
102 fTipComposite
.setLayout(new GridLayout(3, false));
103 setupControl(fTipComposite
);
108 * Callback for the mouse-over tooltip
111 * The control object to use
113 public void activateHoverHelp(final Control control
) {
114 control
.addMouseListener(new MouseAdapter() {
116 public void mouseDown(MouseEvent e
) {
117 if (fTipShell
!= null && ! fTipShell
.isDisposed()) {
123 control
.addMouseMoveListener(new MouseMoveListener() {
125 public void mouseMove(MouseEvent e
) {
126 if (fTipShell
!= null && ! fTipShell
.isDisposed()) {
132 control
.addMouseTrackListener(new MouseTrackAdapter() {
134 public void mouseExit(MouseEvent e
) {
135 if (fTipShell
!= null && ! fTipShell
.isDisposed()) {
136 Point pt
= control
.toDisplay(e
.x
, e
.y
);
137 if (! fTipShell
.getBounds().contains(pt
)) {
143 private void addItem(String name
, String value
) {
144 Label nameLabel
= new Label(fTipComposite
, SWT
.NO_FOCUS
);
145 nameLabel
.setText(name
);
146 setupControl(nameLabel
);
147 Label separator
= new Label(fTipComposite
, SWT
.NO_FOCUS
| SWT
.SEPARATOR
| SWT
.VERTICAL
);
148 GridData gd
= new GridData(SWT
.CENTER
, SWT
.CENTER
, false, false);
149 gd
.heightHint
= nameLabel
.computeSize(SWT
.DEFAULT
, SWT
.DEFAULT
).y
;
150 separator
.setLayoutData(gd
);
151 setupControl(separator
);
152 Label valueLabel
= new Label(fTipComposite
, SWT
.NO_FOCUS
);
153 valueLabel
.setText(value
);
154 setupControl(valueLabel
);
157 private void fillValues(Point pt
, TimeGraphControl timeGraphControl
, ITimeGraphEntry entry
) {
161 if (entry
.hasTimeEvents()) {
162 long currPixelTime
= timeGraphControl
.getTimeAtX(pt
.x
);
163 long nextPixelTime
= timeGraphControl
.getTimeAtX(pt
.x
+ 1);
164 if (nextPixelTime
== currPixelTime
) {
167 ITimeEvent currEvent
= Utils
.findEvent(entry
, currPixelTime
, 0);
168 ITimeEvent nextEvent
= Utils
.findEvent(entry
, currPixelTime
, 1);
170 // if there is no current event at the start of the current pixel range,
171 // or if the current event starts before the current pixel range,
172 // use the next event as long as it starts within the current pixel range
173 if ((currEvent
== null || currEvent
.getTime() < currPixelTime
) &&
174 (nextEvent
!= null && nextEvent
.getTime() < nextPixelTime
)) {
175 currEvent
= nextEvent
;
176 currPixelTime
= nextEvent
.getTime();
180 String stateTypeName
= fTimeGraphProvider
.getStateTypeName(entry
);
181 String entryName
= entry
.getName();
182 if (stateTypeName
== null) {
183 stateTypeName
= fTimeGraphProvider
.getStateTypeName();
186 if (!entryName
.isEmpty()) {
187 addItem(stateTypeName
, entry
.getName());
190 if (currEvent
== null || currEvent
instanceof NullTimeEvent
) {
195 String state
= fTimeGraphProvider
.getEventName(currEvent
);
197 addItem(Messages
.TmfTimeTipHandler_TRACE_STATE
, state
);
200 // This block receives a list of <String, String> values to be added to the tip table
201 Map
<String
, String
> eventAddOns
= fTimeGraphProvider
.getEventHoverToolTipInfo(currEvent
, currPixelTime
);
202 if (eventAddOns
!= null) {
203 for (Iterator
<String
> iter
= eventAddOns
.keySet().iterator(); iter
.hasNext();) {
204 String message
= iter
.next();
205 addItem(message
, eventAddOns
.get(message
));
208 if (fTimeGraphProvider
.displayTimesInTooltip()) {
209 long eventStartTime
= -1;
210 long eventDuration
= -1;
211 long eventEndTime
= -1;
213 eventStartTime
= currEvent
.getTime();
214 eventDuration
= currEvent
.getDuration();
215 if (eventDuration
< 0 && nextEvent
!= null) {
216 eventEndTime
= nextEvent
.getTime();
217 eventDuration
= eventEndTime
- eventStartTime
;
219 eventEndTime
= eventStartTime
+ eventDuration
;
222 Resolution res
= Resolution
.NANOSEC
;
223 TimeFormat tf
= fTimeDataProvider
.getTimeFormat();
224 String startTime
= "?"; //$NON-NLS-1$
225 String duration
= "?"; //$NON-NLS-1$
226 String endTime
= "?"; //$NON-NLS-1$
227 if (fTimeDataProvider
instanceof ITimeDataProviderConverter
) {
228 ITimeDataProviderConverter tdp
= (ITimeDataProviderConverter
) fTimeDataProvider
;
229 if (eventStartTime
> -1) {
230 eventStartTime
= tdp
.convertTime(eventStartTime
);
231 startTime
= Utils
.formatTime(eventStartTime
, tf
, res
);
233 if (eventEndTime
> -1) {
234 eventEndTime
= tdp
.convertTime(eventEndTime
);
235 endTime
= Utils
.formatTime(eventEndTime
, tf
, res
);
237 if (eventDuration
> -1) {
238 duration
= Utils
.formatDelta(eventEndTime
- eventStartTime
, tf
, res
);
241 if (eventStartTime
> -1) {
242 startTime
= Utils
.formatTime(eventStartTime
, tf
, res
);
244 if (eventEndTime
> -1) {
245 endTime
= Utils
.formatTime(eventEndTime
, tf
, res
);
247 if (eventDuration
> -1) {
248 duration
= Utils
.formatDelta(eventDuration
, tf
, res
);
251 if (tf
== TimeFormat
.CALENDAR
) {
252 addItem(Messages
.TmfTimeTipHandler_TRACE_DATE
,
253 eventStartTime
> -1 ? Utils
.formatDate(eventStartTime
) : "?"); //$NON-NLS-1$
255 if (eventDuration
> 0) {
256 addItem(Messages
.TmfTimeTipHandler_TRACE_START_TIME
, startTime
);
257 addItem(Messages
.TmfTimeTipHandler_TRACE_STOP_TIME
, endTime
);
259 addItem(Messages
.TmfTimeTipHandler_TRACE_EVENT_TIME
, startTime
);
262 if (eventDuration
> 0) {
263 addItem(Messages
.TmfTimeTipHandler_DURATION
, duration
);
269 private void fillValues(ILinkEvent linkEvent
) {
270 addItem(Messages
.TmfTimeTipHandler_LINK_SOURCE
, linkEvent
.getEntry().getName());
271 addItem(Messages
.TmfTimeTipHandler_LINK_TARGET
, linkEvent
.getDestinationEntry().getName());
273 // This block receives a list of <String, String> values to be added to the tip table
274 Map
<String
, String
> eventAddOns
= fTimeGraphProvider
.getEventHoverToolTipInfo(linkEvent
);
275 if (eventAddOns
!= null) {
276 for (Iterator
<String
> iter
= eventAddOns
.keySet().iterator(); iter
.hasNext();) {
277 String message
= iter
.next();
278 addItem(message
, eventAddOns
.get(message
));
281 if (fTimeGraphProvider
.displayTimesInTooltip()) {
282 long sourceTime
= linkEvent
.getTime();
283 long duration
= linkEvent
.getDuration();
284 long targetTime
= sourceTime
+ duration
;
285 if (fTimeDataProvider
instanceof ITimeDataProviderConverter
) {
286 ITimeDataProviderConverter tdp
= (ITimeDataProviderConverter
) fTimeDataProvider
;
287 sourceTime
= tdp
.convertTime(sourceTime
);
288 targetTime
= tdp
.convertTime(targetTime
);
289 duration
= targetTime
- sourceTime
;
291 Resolution res
= Resolution
.NANOSEC
;
292 TimeFormat tf
= fTimeDataProvider
.getTimeFormat();
293 if (tf
== TimeFormat
.CALENDAR
) {
294 addItem(Messages
.TmfTimeTipHandler_TRACE_DATE
, Utils
.formatDate(sourceTime
));
297 addItem(Messages
.TmfTimeTipHandler_LINK_SOURCE_TIME
, Utils
.formatTime(sourceTime
, tf
, res
));
298 addItem(Messages
.TmfTimeTipHandler_LINK_TARGET_TIME
, Utils
.formatTime(targetTime
, tf
, res
));
299 addItem(Messages
.TmfTimeTipHandler_DURATION
, Utils
.formatDelta(duration
, tf
, res
));
301 addItem(Messages
.TmfTimeTipHandler_LINK_TIME
, Utils
.formatTime(sourceTime
, tf
, res
));
307 public void mouseHover(MouseEvent event
) {
308 if ((event
.stateMask
& SWT
.BUTTON_MASK
) != 0) {
311 Point pt
= new Point(event
.x
, event
.y
);
312 TimeGraphControl timeGraphControl
= (TimeGraphControl
) event
.widget
;
313 createTooltipShell(timeGraphControl
.getShell());
314 for (Control child
: fTipComposite
.getChildren()) {
317 if ((event
.stateMask
& SWT
.MODIFIER_MASK
) != SWT
.SHIFT
) {
318 ILinkEvent linkEvent
= timeGraphControl
.getArrow(pt
);
319 if (linkEvent
!= null) {
320 fillValues(linkEvent
);
323 if (fTipComposite
.getChildren().length
== 0) {
324 ITimeGraphEntry entry
= timeGraphControl
.getEntry(pt
);
325 fillValues(pt
, timeGraphControl
, entry
);
327 if (fTipComposite
.getChildren().length
== 0) {
331 Point tipPosition
= control
.toDisplay(pt
);
333 setHoverLocation(fTipShell
, tipPosition
);
334 fTipShell
.setVisible(true);
339 private static void setHoverLocation(Shell shell
, Point position
) {
340 Rectangle displayBounds
= shell
.getDisplay().getBounds();
341 Rectangle shellBounds
= shell
.getBounds();
342 if (position
.x
+ shellBounds
.width
+ OFFSET
> displayBounds
.width
&& position
.x
- shellBounds
.width
- OFFSET
>= 0) {
343 shellBounds
.x
= position
.x
- shellBounds
.width
- OFFSET
;
345 shellBounds
.x
= Math
.max(Math
.min(position
.x
+ OFFSET
, displayBounds
.width
- shellBounds
.width
), 0);
347 if (position
.y
+ shellBounds
.height
+ OFFSET
> displayBounds
.height
&& position
.y
- shellBounds
.height
- OFFSET
>= 0) {
348 shellBounds
.y
= position
.y
- shellBounds
.height
- OFFSET
;
350 shellBounds
.y
= Math
.max(Math
.min(position
.y
+ OFFSET
, displayBounds
.height
- shellBounds
.height
), 0);
352 shell
.setBounds(shellBounds
);
355 private void setupControl(Control control
) {
356 control
.setForeground(fTipShell
.getDisplay().getSystemColor(SWT
.COLOR_INFO_FOREGROUND
));
357 control
.setBackground(fTipShell
.getDisplay().getSystemColor(SWT
.COLOR_INFO_BACKGROUND
));
359 control
.addMouseListener(new MouseAdapter() {
361 public void mouseDown(MouseEvent e
) {
366 control
.addMouseTrackListener(new MouseTrackAdapter() {
368 public void mouseExit(MouseEvent e
) {
373 control
.addMouseMoveListener(new MouseMoveListener() {
375 public void mouseMove(MouseEvent e
) {