import org.eclipse.swt.events.MouseTrackAdapter;\r
import org.eclipse.swt.graphics.Point;\r
import org.eclipse.swt.graphics.Rectangle;\r
-import org.eclipse.swt.layout.GridData;\r
import org.eclipse.swt.layout.GridLayout;\r
import org.eclipse.swt.widgets.Control;\r
import org.eclipse.swt.widgets.Display;\r
*/\r
public class TimeGraphTooltipHandler {\r
\r
- private final Shell _tipShell;\r
- private final Table _tipTable;\r
+ private Shell _tipShell;\r
+ private Table _tipTable;\r
private Point _tipPosition;\r
private final ITimeDataProvider _timeDataProvider;\r
ITimeGraphPresentationProvider _utilImp = null;\r
* Standard constructor\r
*\r
* @param parent\r
- * The parent composite object\r
+ * The parent shell (unused, can be null)\r
* @param rUtilImpl\r
* The presentation provider\r
* @param timeProv\r
*/\r
public TimeGraphTooltipHandler(Shell parent, ITimeGraphPresentationProvider rUtilImpl,\r
ITimeDataProvider timeProv) {\r
- final Display display = parent.getDisplay();\r
\r
this._utilImp = rUtilImpl;\r
this._timeDataProvider = timeProv;\r
+ }\r
+\r
+ private void createTooltipShell(Shell parent) {\r
+ final Display display = parent.getDisplay();\r
+ if (_tipShell != null && ! _tipShell.isDisposed()) {\r
+ _tipShell.dispose();\r
+ }\r
_tipShell = new Shell(parent, SWT.ON_TOP | SWT.TOOL);\r
GridLayout gridLayout = new GridLayout();\r
gridLayout.numColumns = 2;\r
gridLayout.marginWidth = 2;\r
gridLayout.marginHeight = 2;\r
_tipShell.setLayout(gridLayout);\r
- GridData data = new GridData(GridData.BEGINNING, GridData.BEGINNING,\r
- true, true);\r
- _tipShell.setLayoutData(data);\r
- _tipShell.setBackground(display\r
- .getSystemColor(SWT.COLOR_INFO_BACKGROUND));\r
+ _tipShell.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));\r
\r
_tipTable = new Table(_tipShell, SWT.NONE);\r
new TableColumn(_tipTable, SWT.NONE);\r
_tipTable.setHeaderVisible(false);\r
_tipTable.setLinesVisible(false);\r
\r
- // tipTable.setLayoutData(new GridData(GridData.FILL_HORIZONTAL\r
- // | GridData.VERTICAL_ALIGN_CENTER));\r
+ _tipTable.addMouseListener(new MouseAdapter() {\r
+ @Override\r
+ public void mouseDown(MouseEvent e) {\r
+ _tipShell.dispose();\r
+ }\r
+ });\r
+\r
+ _tipTable.addMouseTrackListener(new MouseTrackAdapter() {\r
+ @Override\r
+ public void mouseExit(MouseEvent e) {\r
+ _tipShell.dispose();\r
+ }\r
+ });\r
+\r
+ _tipTable.addMouseMoveListener(new MouseMoveListener() {\r
+ @Override\r
+ public void mouseMove(MouseEvent e) {\r
+ _tipShell.dispose();\r
+ }\r
+ });\r
}\r
\r
/**\r
* The control object to use\r
*/\r
public void activateHoverHelp(final Control control) {\r
- //FIXME: remove old listeners\r
control.addMouseListener(new MouseAdapter() {\r
@Override\r
public void mouseDown(MouseEvent e) {\r
- if (_tipShell.isVisible()) {\r
- _tipShell.setVisible(false);\r
+ if (_tipShell != null && ! _tipShell.isDisposed()) {\r
+ _tipShell.dispose();\r
}\r
}\r
});\r
control.addMouseMoveListener(new MouseMoveListener() {\r
@Override\r
public void mouseMove(MouseEvent e) {\r
- if (_tipShell.isVisible()) {\r
- _tipShell.setVisible(false);\r
+ if (_tipShell != null && ! _tipShell.isDisposed()) {\r
+ _tipShell.dispose();\r
}\r
}\r
});\r
control.addMouseTrackListener(new MouseTrackAdapter() {\r
@Override\r
public void mouseExit(MouseEvent e) {\r
- if (_tipShell.isVisible()) {\r
- _tipShell.setVisible(false);\r
+ if (_tipShell != null && ! _tipShell.isDisposed()) {\r
+ Point pt = control.toDisplay(e.x, e.y);\r
+ if (! _tipShell.getBounds().contains(pt)) {\r
+ _tipShell.dispose();\r
+ }\r
}\r
}\r
\r
line.setText(1, value);\r
}\r
\r
- private void fillValues(Point pt, TimeGraphControl threadStates, ITimeGraphEntry entry) {\r
+ private void fillValues(Point pt, TimeGraphControl timeGraphControl, ITimeGraphEntry entry) {\r
if (entry == null) {\r
return;\r
}\r
if (entry.hasTimeEvents()) {\r
- ITimeEvent threadEvent = Utils.findEvent(entry, threadStates.getTimeAtX(pt.x), 2);\r
- ITimeEvent nextEvent = Utils.findEvent(entry, threadStates.getTimeAtX(pt.x), 1);\r
+ long currPixelTime = timeGraphControl.getTimeAtX(pt.x);\r
+ long nextPixelTime = timeGraphControl.getTimeAtX(pt.x + 1);\r
+ if (nextPixelTime == currPixelTime) {\r
+ nextPixelTime++;\r
+ }\r
+ ITimeEvent currEvent = Utils.findEvent(entry, currPixelTime, 0);\r
+ ITimeEvent nextEvent = Utils.findEvent(entry, currPixelTime, 1);\r
+\r
+ // if there is no current event at the start of the current pixel range,\r
+ // or if the current event starts before the current pixel range,\r
+ // use the next event as long as it starts within the current pixel range\r
+ if (currEvent == null || currEvent.getTime() < currPixelTime) {\r
+ if (nextEvent != null && nextEvent.getTime() < nextPixelTime) {\r
+ currEvent = nextEvent;\r
+ }\r
+ }\r
+\r
// state name\r
addItem(_utilImp.getStateTypeName(), entry.getName());\r
- if (threadEvent == null) {\r
+ if (currEvent == null) {\r
return;\r
}\r
- // thread state\r
- String state = _utilImp.getEventName(threadEvent);\r
+ // state\r
+ String state = _utilImp.getEventName(currEvent);\r
if (state != null) {\r
addItem(Messages.TmfTimeTipHandler_TRACE_STATE, state);\r
}\r
\r
- // This block receives a\r
- // list of <String, String> values to be added to the tip\r
- // table\r
- Map<String, String> eventAddOns = _utilImp.getEventHoverToolTipInfo(threadEvent);\r
+ // This block receives a list of <String, String> values to be added to the tip table\r
+ Map<String, String> eventAddOns = _utilImp.getEventHoverToolTipInfo(currEvent);\r
if (eventAddOns != null) {\r
for (Iterator<String> iter = eventAddOns.keySet().iterator(); iter.hasNext();) {\r
String message = iter.next();\r
long eventDuration = -1;\r
long eventEndTime = -1;\r
\r
- eventStartTime = threadEvent.getTime();\r
- eventDuration = threadEvent.getDuration();\r
+ eventStartTime = currEvent.getTime();\r
+ eventDuration = currEvent.getDuration();\r
if (eventDuration < 0 && nextEvent != null) {\r
eventEndTime = nextEvent.getTime();\r
eventDuration = eventEndTime - eventStartTime;\r
eventEndTime = eventStartTime + eventDuration;\r
}\r
\r
- // TODO: Check if we need "format"\r
- // TimeFormat format = TimeFormat.RELATIVE;\r
Resolution res = Resolution.NANOSEC;\r
if (_timeDataProvider.isCalendarFormat()) {\r
- // format = TimeFormat.ABSOLUTE; // Absolute format\r
- // // (calendar)\r
- // Add Date\r
addItem(Messages.TmfTimeTipHandler_TRACE_DATE, eventStartTime > -1 ?\r
Utils.formatDate(eventStartTime)\r
: "?"); //$NON-NLS-1$\r
@Override\r
public void mouseHover(MouseEvent event) {\r
Point pt = new Point(event.x, event.y);\r
- TimeGraphControl threadStates = (TimeGraphControl) event.widget;\r
- ITimeGraphEntry entry = threadStates.getEntry(pt);\r
+ TimeGraphControl timeGraphControl = (TimeGraphControl) event.widget;\r
+ createTooltipShell(timeGraphControl.getShell());\r
+ ITimeGraphEntry entry = timeGraphControl.getEntry(pt);\r
_tipTable.remove(0, _tipTable.getItemCount() - 1);\r
- fillValues(pt, threadStates, entry);\r
+ fillValues(pt, timeGraphControl, entry);\r
if (_tipTable.getItemCount() == 0) {\r
return;\r
}\r
private static void setHoverLocation(Shell shell, Point position) {\r
Rectangle displayBounds = shell.getDisplay().getBounds();\r
Rectangle shellBounds = shell.getBounds();\r
- shellBounds.x = Math.max(Math.min(position.x, displayBounds.width\r
- - shellBounds.width), 0);\r
- shellBounds.y = Math.max(Math.min(position.y + 16, displayBounds.height\r
- - shellBounds.height), 0);\r
+ if (position.x + shellBounds.width + 16 > displayBounds.width && position.x - shellBounds.width - 16 >= 0) {\r
+ shellBounds.x = position.x - shellBounds.width - 16;\r
+ } else {\r
+ shellBounds.x = Math.max(Math.min(position.x + 16, displayBounds.width - shellBounds.width), 0);\r
+ }\r
+ if (position.y + shellBounds.height + 16 > displayBounds.height && position.y - shellBounds.height - 16 >= 0) {\r
+ shellBounds.y = position.y - shellBounds.height - 16;\r
+ } else {\r
+ shellBounds.y = Math.max(Math.min(position.y + 16, displayBounds.height - shellBounds.height), 0);\r
+ }\r
shell.setBounds(shellBounds);\r
}\r
\r