Add syscall state info in CFV, support of initial time range, bugfixes
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.ui / src / org / eclipse / linuxtools / tmf / ui / widgets / timegraph / widgets / TimeGraphControl.java
CommitLineData
fb5cad3d
PT
1/*****************************************************************************\r
2 * Copyright (c) 2007, 2008 Intel Corporation, 2009, 2010, 2011, 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 * Ruslan A. Scherbakov, Intel - Initial API and implementation\r
11 * Alvaro Sanchez-Leon - Updated for TMF\r
12 * Patrick Tasse - Refactoring\r
13 *\r
14 *****************************************************************************/\r
15\r
16package org.eclipse.linuxtools.tmf.ui.widgets.timegraph.widgets;\r
17\r
18import java.util.ArrayList;\r
19import java.util.Iterator;\r
20import java.util.List;\r
21import java.util.Vector;\r
22\r
b83af2c3
PT
23import org.eclipse.jface.resource.JFaceResources;\r
24import org.eclipse.jface.resource.LocalResourceManager;\r
fb5cad3d
PT
25import org.eclipse.jface.viewers.ISelection;\r
26import org.eclipse.jface.viewers.ISelectionChangedListener;\r
27import org.eclipse.jface.viewers.ISelectionProvider;\r
b83af2c3 28import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphPresentationProvider;\r
fb5cad3d 29import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.ITimeGraphTreeListener;\r
b83af2c3 30import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.StateItem;\r
fb5cad3d
PT
31import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.TimeGraphTreeExpansionEvent;\r
32import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeEvent;\r
33import org.eclipse.linuxtools.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;\r
34import org.eclipse.swt.SWT;\r
35import org.eclipse.swt.events.ControlEvent;\r
36import org.eclipse.swt.events.ControlListener;\r
37import org.eclipse.swt.events.FocusEvent;\r
38import org.eclipse.swt.events.FocusListener;\r
39import org.eclipse.swt.events.KeyEvent;\r
40import org.eclipse.swt.events.KeyListener;\r
41import org.eclipse.swt.events.MouseEvent;\r
42import org.eclipse.swt.events.MouseListener;\r
43import org.eclipse.swt.events.MouseMoveListener;\r
44import org.eclipse.swt.events.MouseTrackListener;\r
45import org.eclipse.swt.events.MouseWheelListener;\r
46import org.eclipse.swt.events.PaintEvent;\r
47import org.eclipse.swt.events.SelectionEvent;\r
48import org.eclipse.swt.events.SelectionListener;\r
49import org.eclipse.swt.events.TraverseEvent;\r
50import org.eclipse.swt.events.TraverseListener;\r
b83af2c3 51import org.eclipse.swt.graphics.Color;\r
fb5cad3d
PT
52import org.eclipse.swt.graphics.Cursor;\r
53import org.eclipse.swt.graphics.GC;\r
54import org.eclipse.swt.graphics.Image;\r
55import org.eclipse.swt.graphics.Point;\r
56import org.eclipse.swt.graphics.Rectangle;\r
57import org.eclipse.swt.widgets.Composite;\r
b83af2c3 58import org.eclipse.swt.widgets.Display;\r
fb5cad3d
PT
59import org.eclipse.swt.widgets.Event;\r
60import org.eclipse.swt.widgets.Listener;\r
61import org.eclipse.swt.widgets.ScrollBar;\r
62\r
63public class TimeGraphControl extends TimeGraphBaseControl implements FocusListener, KeyListener, MouseMoveListener, MouseListener, MouseWheelListener, ControlListener, SelectionListener, MouseTrackListener, TraverseListener, ISelectionProvider {\r
64\r
65 private static final int DRAG_NONE = 0;\r
66 private static final int DRAG_TRACE_ITEM = 1;\r
67 private static final int DRAG_SPLIT_LINE = 2;\r
68 public static final boolean DEFAULT_DRAW_THREAD_JOIN = true;\r
69 public static final boolean DEFAULT_DRAW_THREAD_WAIT = true;\r
70 public static final boolean DEFAULT_DRAW_THREAD_RELEASE = true;\r
71 public static final int H_SCROLLBAR_MAX = Integer.MAX_VALUE - 1;\r
b83af2c3 72 private static final int CUSTOM_ITEM_HEIGHT = -1; // get item height from provider\r
fb5cad3d
PT
73\r
74 private static final double zoomCoeff = 1.5;\r
75\r
76 private ITimeDataProvider _timeProvider;\r
77 private boolean _isInFocus = false;\r
78 private boolean _isDragCursor3 = false;\r
79 private boolean _isWaitCursor = true;\r
80 private boolean _mouseOverSplitLine = false;\r
b83af2c3 81 private int _itemHeight = CUSTOM_ITEM_HEIGHT;\r
fb5cad3d
PT
82 private int _minimumItemWidth = 0;\r
83 private int _topIndex = 0;\r
84 private int _dragState = DRAG_NONE;\r
85 private int _dragX0 = 0;\r
86 private int _dragX = 0;\r
87 private int _idealNameSpace = 0;\r
88 // private double _timeStep = 10000000;\r
89 private long _time0bak;\r
90 private long _time1bak;\r
b83af2c3 91 private ITimeGraphPresentationProvider fTimeGraphProvider = null;\r
fb5cad3d
PT
92 private ItemData _data = null;\r
93 private List<SelectionListener> _selectionListeners;\r
94 private List<ISelectionChangedListener> _selectionChangedListeners = new ArrayList<ISelectionChangedListener>();\r
95 private List<ITimeGraphTreeListener> _treeListeners = new ArrayList<ITimeGraphTreeListener>();\r
96 private Cursor _dragCursor3;\r
97 private Cursor _WaitCursor;\r
98\r
99 // Vertical formatting formatting for the state control view\r
100 private boolean _visibleVerticalScroll = true;\r
101 private int _borderWidth = 0;\r
102 private int _headerHeight = 0;\r
103\r
104 private Listener mouseScrollFilterListener;\r
105\r
b83af2c3
PT
106 protected LocalResourceManager fResourceManager = new LocalResourceManager(JFaceResources.getResources());\r
107 protected Color[] fEventColorMap = null;\r
108\r
fb5cad3d
PT
109 public TimeGraphControl(Composite parent, TimeGraphColorScheme colors) {\r
110\r
111 super(parent, colors, SWT.NO_BACKGROUND | SWT.H_SCROLL | SWT.DOUBLE_BUFFERED);\r
112\r
113 _data = new ItemData();\r
114\r
115 addFocusListener(this);\r
116 addMouseListener(this);\r
117 addMouseMoveListener(this);\r
118 addMouseTrackListener(this);\r
119 addMouseWheelListener(this);\r
120 addTraverseListener(this);\r
121 addKeyListener(this);\r
122 addControlListener(this);\r
123 ScrollBar scrollHor = getHorizontalBar();\r
124\r
125 if (scrollHor != null) {\r
126 scrollHor.addSelectionListener(this);\r
127 }\r
128\r
129 _dragCursor3 = new Cursor(super.getDisplay(), SWT.CURSOR_SIZEWE);\r
130 _WaitCursor = new Cursor(super.getDisplay(), SWT.CURSOR_WAIT);\r
131 }\r
132\r
133 @Override\r
134 public void dispose() {\r
135 super.dispose();\r
136 _dragCursor3.dispose();\r
137 _WaitCursor.dispose();\r
b83af2c3 138 fResourceManager.dispose();\r
fb5cad3d
PT
139 }\r
140\r
141 /**\r
142 * Sets the timegraph provider used by this timegraph viewer.\r
143 * \r
144 * @param timeGraphProvider the timegraph provider\r
145 */\r
b83af2c3 146 public void setTimeGraphProvider(ITimeGraphPresentationProvider timeGraphProvider) {\r
fb5cad3d 147 fTimeGraphProvider = timeGraphProvider;\r
b83af2c3
PT
148 _data.provider = timeGraphProvider;\r
149// RGB[] eventColorTable = fTimeGraphProvider.getEventColorTable();\r
150// if (eventColorTable != null) {\r
151// fEventColorMap = new Color[eventColorTable.length];\r
152// for (int i = 0; i < eventColorTable.length; i++) {\r
153// fEventColorMap[i] = fResourceManager.createColor(eventColorTable[i]);\r
154// }\r
155// } else {\r
156// fEventColorMap = new Color[] { };\r
157// }\r
158\r
159 StateItem[] stateItems = fTimeGraphProvider.getStateTable();\r
160 if (stateItems != null) {\r
161 fEventColorMap = new Color[stateItems.length];\r
162 for (int i = 0; i < stateItems.length; i++) {\r
163 fEventColorMap[i] = fResourceManager.createColor(stateItems[i].getStateColor());\r
164 }\r
165 } else {\r
166 fEventColorMap = new Color[] { };\r
167 }\r
168 \r
169 \r
fb5cad3d
PT
170 }\r
171\r
172 public void setTimeProvider(ITimeDataProvider timeProvider) {\r
173 _timeProvider = timeProvider;\r
174 adjustScrolls();\r
175 redraw();\r
176 }\r
177\r
178 public void addSelectionListener(SelectionListener listener) {\r
179 if (listener == null)\r
180 SWT.error(SWT.ERROR_NULL_ARGUMENT);\r
181 if (null == _selectionListeners)\r
182 _selectionListeners = new ArrayList<SelectionListener>();\r
183 _selectionListeners.add(listener);\r
184 }\r
185\r
186 public void removeSelectionListener(SelectionListener listener) {\r
187 if (null != _selectionListeners)\r
188 _selectionListeners.remove(listener);\r
189 }\r
190\r
191 public void fireSelectionChanged() {\r
192 if (null != _selectionListeners) {\r
193 Iterator<SelectionListener> it = _selectionListeners.iterator();\r
194 while (it.hasNext()) {\r
195 SelectionListener listener = it.next();\r
196 listener.widgetSelected(null);\r
197 }\r
198 }\r
199 }\r
200\r
201 public void fireDefaultSelection() {\r
202 if (null != _selectionListeners) {\r
203 Iterator<SelectionListener> it = _selectionListeners.iterator();\r
204 while (it.hasNext()) {\r
205 SelectionListener listener = it.next();\r
206 listener.widgetDefaultSelected(null);\r
207 }\r
208 }\r
209 }\r
210\r
b83af2c3 211 public ITimeGraphEntry[] getTraces() {\r
fb5cad3d
PT
212 return _data.getTraces();\r
213 }\r
214\r
215 public boolean[] getTraceFilter() {\r
216 return _data.getTraceFilter();\r
217 }\r
218\r
219 public void refreshData() {\r
220 _data.refreshData();\r
221 adjustScrolls();\r
222 redraw();\r
223 }\r
224\r
225 public void refreshData(ITimeGraphEntry traces[]) {\r
226 _data.refreshData(traces);\r
227 adjustScrolls();\r
228 redraw();\r
229 }\r
230\r
231 public void adjustScrolls() {\r
232 if (null == _timeProvider) {\r
233 getHorizontalBar().setValues(0, 1, 1, 1, 1, 1);\r
234 return;\r
235 }\r
236\r
237 // HORIZONTAL BAR\r
238 // Visible window\r
239 long time0 = _timeProvider.getTime0();\r
240 long time1 = _timeProvider.getTime1();\r
241 // Time boundaries\r
242 long timeMin = _timeProvider.getMinTime();\r
243 long timeMax = _timeProvider.getMaxTime();\r
244\r
245 long delta = timeMax - timeMin;\r
246\r
247 int timePos = 0;\r
248 int thumb = H_SCROLLBAR_MAX;\r
249\r
250 if (delta != 0) {\r
251 // Thumb size (page size)\r
252 thumb = Math.max(1, (int) (H_SCROLLBAR_MAX * ((double) (time1 - time0) / delta)));\r
253 // At the beginning of visible window\r
254 timePos = (int) (H_SCROLLBAR_MAX * ((double) (time0 - timeMin) / delta));\r
255 }\r
256\r
257 // position, minimum, maximum, thumb size, increment (half page)t, page\r
258 // increment size (full page)\r
259 getHorizontalBar().setValues(timePos, 0, H_SCROLLBAR_MAX, thumb, Math.max(1, thumb / 2), Math.max(2, thumb));\r
260 }\r
261\r
262 boolean ensureVisibleItem(int idx, boolean redraw) {\r
263 boolean changed = false;\r
264 if (idx < 0) {\r
265 for (idx = 0; idx < _data._expandedItems.length; idx++) {\r
266 if (((TimeGraphItem) _data._expandedItems[idx])._selected)\r
267 break;\r
268 }\r
269 }\r
270 if (idx >= _data._expandedItems.length)\r
271 return changed;\r
272 if (idx < _topIndex) {\r
b83af2c3 273 setTopIndex(idx);\r
fb5cad3d
PT
274 //FIXME:getVerticalBar().setSelection(_topItem);\r
275 if (redraw)\r
276 redraw();\r
277 changed = true;\r
278 } else {\r
279 int page = countPerPage();\r
280 if (idx >= _topIndex + page) {\r
b83af2c3 281 setTopIndex(idx - page + 1);\r
fb5cad3d
PT
282 //FIXME:getVerticalBar().setSelection(_topItem);\r
283 if (redraw)\r
284 redraw();\r
285 changed = true;\r
286 }\r
287 }\r
288 return changed;\r
289 }\r
290\r
291 public void setTopIndex(int idx) {\r
292 idx = Math.min(idx, _data._expandedItems.length - countPerPage());\r
293 idx = Math.max(0, idx);\r
294 _topIndex = idx;\r
295 redraw();\r
296 }\r
297\r
298 public void setExpandedState(ITimeGraphEntry entry, boolean expanded) {\r
299 TimeGraphItem item = _data.findItem(entry);\r
300 if (item != null && item._expanded != expanded) {\r
301 item._expanded = expanded;\r
302 _data.updateExpandedItems();\r
303 redraw();\r
304 }\r
305 }\r
306\r
307 public void addTreeListener (ITimeGraphTreeListener listener) {\r
308 if (!_treeListeners.contains(listener)) {\r
309 _treeListeners.add(listener);\r
310 }\r
311 }\r
312\r
313 public void removeTreeListener (ITimeGraphTreeListener listener) {\r
314 if (_treeListeners.contains(listener)) {\r
315 _treeListeners.remove(listener);\r
316 }\r
317 }\r
318\r
319 public void fireTreeEvent(ITimeGraphEntry entry, boolean expanded) {\r
320 TimeGraphTreeExpansionEvent event = new TimeGraphTreeExpansionEvent(this, entry);\r
321 for (ITimeGraphTreeListener listener : _treeListeners) {\r
322 if (expanded) {\r
323 listener.treeExpanded(event);\r
324 } else {\r
325 listener.treeCollapsed(event);\r
326 }\r
327 }\r
328 }\r
329\r
330 @Override\r
331 public ISelection getSelection() {\r
332 TimeGraphSelection sel = new TimeGraphSelection();\r
333 ITimeGraphEntry trace = getSelectedTrace();\r
334 if (null != trace && null != _timeProvider) {\r
335 long selectedTime = _timeProvider.getSelectedTime();\r
336 ITimeEvent event = Utils.findEvent(trace, selectedTime, 0);\r
337 if (event != null)\r
338 sel.add(event);\r
339 else\r
340 sel.add(trace);\r
341 }\r
342 return sel;\r
343 }\r
344\r
345 public ISelection getSelectionTrace() {\r
346 TimeGraphSelection sel = new TimeGraphSelection();\r
347 ITimeGraphEntry trace = getSelectedTrace();\r
348 if (null != trace) {\r
349 sel.add(trace);\r
350 }\r
351 return sel;\r
352 }\r
353\r
3ac6ad1a
BH
354 \r
355 // TODO select implementation for selectTrace\r
356// public void selectTrace(int n) {\r
357// if (n != 1 && n != -1)\r
358// return;\r
359// boolean changed = false;\r
360// int lastSelection = -1;\r
361// for (int i = 0; i < _data._expandedItems.length; i++) {\r
362// TimeGraphItem item = (TimeGraphItem) _data._expandedItems[i];\r
363// if (item._selected) {\r
364// lastSelection = i;\r
365// if (1 == n && i < _data._expandedItems.length - 1) {\r
366// item._selected = false;\r
367// if (item._hasChildren) {\r
368// _data.expandItem(i);\r
369// fireTreeEvent(item._trace, item._expanded);\r
370// }\r
371// item = (TimeGraphItem) _data._expandedItems[i + 1];\r
372// if (item._hasChildren) {\r
373// _data.expandItem(i + 1);\r
374// fireTreeEvent(item._trace, item._expanded);\r
375// item = (TimeGraphItem) _data._expandedItems[i + 2];\r
376// }\r
377// item._selected = true;\r
378// changed = true;\r
379// } else if (-1 == n && i > 0) {\r
380// i--;\r
381// TimeGraphItem prevItem = (TimeGraphItem) _data._expandedItems[i];\r
382// if (prevItem._hasChildren) {\r
383// if (prevItem._expanded) {\r
384// if (i > 0) {\r
385// i--;\r
386// prevItem = (TimeGraphItem) _data._expandedItems[i];\r
387// }\r
388// }\r
389// if (!prevItem._expanded) {\r
390// _data.expandItem(i);\r
391// fireTreeEvent(prevItem._trace, prevItem._expanded);\r
392// prevItem = (TimeGraphItem) _data._expandedItems[i + prevItem.children.size()];\r
393// item._selected = false;\r
394// prevItem._selected = true;\r
395// changed = true;\r
396// }\r
397// } else {\r
398// item._selected = false;\r
399// prevItem._selected = true;\r
400// changed = true;\r
401// }\r
402// }\r
403// break;\r
404// }\r
405// }\r
406// if (lastSelection < 0 && _data._expandedItems.length > 0) {\r
407// TimeGraphItem item = (TimeGraphItem) _data._expandedItems[0];\r
408// if (item._hasChildren) {\r
409// _data.expandItem(0);\r
410// fireTreeEvent(item._trace, item._expanded);\r
411// item = (TimeGraphItem) _data._expandedItems[1];\r
412// item._selected = true;\r
413// changed = true;\r
414// } else {\r
415// item._selected = true;\r
416// changed = true;\r
417// }\r
418// }\r
419// if (changed) {\r
420// ensureVisibleItem(-1, false);\r
421// redraw();\r
422// fireSelectionChanged();\r
423// }\r
424// }\r
425\r
fb5cad3d 426 public void selectTrace(int n) {\r
3ac6ad1a 427 if ((n != 1) && (n != -1)) {\r
fb5cad3d 428 return;\r
3ac6ad1a
BH
429 }\r
430\r
fb5cad3d
PT
431 boolean changed = false;\r
432 int lastSelection = -1;\r
433 for (int i = 0; i < _data._expandedItems.length; i++) {\r
434 TimeGraphItem item = (TimeGraphItem) _data._expandedItems[i];\r
435 if (item._selected) {\r
436 lastSelection = i;\r
3ac6ad1a 437 if ((1 == n) && (i < _data._expandedItems.length - 1)) {\r
fb5cad3d 438 item._selected = false;\r
fb5cad3d 439 item = (TimeGraphItem) _data._expandedItems[i + 1];\r
fb5cad3d
PT
440 item._selected = true;\r
441 changed = true;\r
3ac6ad1a
BH
442 } else if ((-1 == n) && (i > 0)) {\r
443 item._selected = false;\r
444 item = (TimeGraphItem) _data._expandedItems[i - 1];\r
445 item._selected = true;\r
446 changed = true;\r
fb5cad3d
PT
447 }\r
448 break;\r
449 }\r
450 }\r
3ac6ad1a 451\r
fb5cad3d
PT
452 if (lastSelection < 0 && _data._expandedItems.length > 0) {\r
453 TimeGraphItem item = (TimeGraphItem) _data._expandedItems[0];\r
3ac6ad1a
BH
454 item._selected = true;\r
455 changed = true;\r
fb5cad3d 456 }\r
3ac6ad1a 457\r
fb5cad3d
PT
458 if (changed) {\r
459 ensureVisibleItem(-1, false);\r
460 redraw();\r
461 fireSelectionChanged();\r
462 }\r
463 }\r
3ac6ad1a 464 \r
fb5cad3d
PT
465 public void selectEvent(int n) {\r
466 if (null == _timeProvider)\r
467 return;\r
468 ITimeGraphEntry trace = getSelectedTrace();\r
469 if (trace == null)\r
470 return;\r
471 long selectedTime = _timeProvider.getSelectedTime();\r
472 long endTime = _timeProvider.getEndTime();\r
473 ITimeEvent nextEvent;\r
474 if (-1 == n && selectedTime > endTime)\r
475 nextEvent = Utils.findEvent(trace, selectedTime, 0);\r
476 else\r
477 nextEvent = Utils.findEvent(trace, selectedTime, n);\r
478 if (null == nextEvent && -1 == n)\r
479 nextEvent = Utils.getFirstEvent(trace);\r
480 if (null != nextEvent) {\r
481 long nextTime = nextEvent.getTime();\r
482 // If last event detected e.g. going back or not moving to a next\r
483 // event\r
484 if (nextTime <= selectedTime && n == 1) {\r
485 // Select to the end of this last event\r
486 nextTime = nextEvent.getTime() + nextEvent.getDuration();\r
487 // but not beyond the end of the trace\r
488 if (nextTime > endTime) {\r
489 nextTime = endTime;\r
490 }\r
491 }\r
3ac6ad1a 492 _timeProvider.setSelectedTimeNotify(nextTime, true);\r
fb5cad3d
PT
493 fireSelectionChanged();\r
494 } else if (1 == n) {\r
3ac6ad1a 495 _timeProvider.setSelectedTimeNotify(endTime, true);\r
fb5cad3d
PT
496 fireSelectionChanged();\r
497 }\r
498 }\r
499\r
500 public void selectNextEvent() {\r
501 selectEvent(1);\r
502 // Notify if visible time window has been adjusted\r
503 _timeProvider.setStartFinishTimeNotify(_timeProvider.getTime0(), _timeProvider.getTime1());\r
504 }\r
505\r
506 public void selectPrevEvent() {\r
507 selectEvent(-1);\r
508 // Notify if visible time window has been adjusted\r
509 _timeProvider.setStartFinishTimeNotify(_timeProvider.getTime0(), _timeProvider.getTime1());\r
510 }\r
511\r
512 public void selectNextTrace() {\r
513 selectTrace(1);\r
514 }\r
515\r
516 public void selectPrevTrace() {\r
517 selectTrace(-1);\r
518 }\r
519\r
520 /**\r
521 * Zooming based on mouse cursor location with mouse scrolling\r
522 * \r
523 * @param zoomIn\r
524 */\r
525 public void zoom(boolean zoomIn) {\r
526 int globalX = getDisplay().getCursorLocation().x;\r
527 Point p = toControl(globalX, 0);\r
528 int nameSpace = _timeProvider.getNameSpace();\r
529 int timeSpace = _timeProvider.getTimeSpace();\r
530 int xPos = Math.max(nameSpace, Math.min(nameSpace + timeSpace, p.x));\r
531 long time0 = _timeProvider.getTime0();\r
532 long time1 = _timeProvider.getTime1();\r
533 long interval = time1 - time0;\r
534 if (interval == 0) {\r
535 interval = 1;\r
536 } // to allow getting out of single point interval\r
537 long newInterval;\r
538 if (zoomIn) {\r
539 newInterval = Math.max(Math.round((double) interval * 0.8), _timeProvider.getMinTimeInterval());\r
540 } else {\r
541 newInterval = (long) Math.ceil((double) interval * 1.25);\r
542 }\r
543 long center = time0 + Math.round(((double) (xPos - nameSpace) / timeSpace * interval));\r
544 long newTime0 = center - Math.round((double) newInterval * (center - time0) / interval);\r
545 long newTime1 = newTime0 + newInterval;\r
546 _timeProvider.setStartFinishTime(newTime0, newTime1);\r
547 }\r
548\r
549 /**\r
550 * zoom in using single click\r
551 */\r
552 public void zoomIn() {\r
553 long _time0 = _timeProvider.getTime0();\r
554 long _time1 = _timeProvider.getTime1();\r
555 long _range = _time1 - _time0;\r
556 long selTime = _timeProvider.getSelectedTime();\r
557 if (selTime <= _time0 || selTime >= _time1) {\r
558 selTime = (_time0 + _time1) / 2;\r
559 }\r
560 long time0 = selTime - (long) ((selTime - _time0) / zoomCoeff);\r
561 long time1 = selTime + (long) ((_time1 - selTime) / zoomCoeff);\r
562\r
563 long inaccuracy = (_timeProvider.getMaxTime() - _timeProvider.getMinTime()) - (time1 - time0);\r
564\r
565 // Trace.debug("selTime:" + selTime + " time0:" + time0 + " time1:"\r
566 // + time1 + " inaccuracy:" + inaccuracy);\r
567\r
568 if (inaccuracy > 0 && inaccuracy < 100) {\r
569 _timeProvider.setStartFinishTimeNotify(_timeProvider.getMinTime(), _timeProvider.getMaxTime());\r
570 return;\r
571 }\r
572\r
573 long m = _timeProvider.getMinTimeInterval();\r
574 if ((time1 - time0) < m) {\r
575 time0 = selTime - (long) ((selTime - _time0) * m / _range);\r
576 time1 = time0 + m;\r
577 }\r
578\r
579 _timeProvider.setStartFinishTimeNotify(time0, time1);\r
580 }\r
581\r
582 /**\r
583 * zoom out using single click\r
584 */\r
585 public void zoomOut() {\r
586 long _time0 = _timeProvider.getTime0();\r
587 long _time1 = _timeProvider.getTime1();\r
588 long selTime = _timeProvider.getSelectedTime();\r
589 if (selTime <= _time0 || selTime >= _time1) {\r
590 selTime = (_time0 + _time1) / 2;\r
591 }\r
592 long time0 = (long) (selTime - (selTime - _time0) * zoomCoeff);\r
593 long time1 = (long) (selTime + (_time1 - selTime) * zoomCoeff);\r
594\r
595 long inaccuracy = (_timeProvider.getMaxTime() - _timeProvider.getMinTime()) - (time1 - time0);\r
596 if (inaccuracy > 0 && inaccuracy < 100) {\r
597 _timeProvider.setStartFinishTimeNotify(_timeProvider.getMinTime(), _timeProvider.getMaxTime());\r
598 return;\r
599 }\r
600\r
601 _timeProvider.setStartFinishTimeNotify(time0, time1);\r
602 }\r
603\r
604 public ITimeGraphEntry getSelectedTrace() {\r
605 ITimeGraphEntry trace = null;\r
606 int idx = getSelectedIndex();\r
607 if (idx >= 0)\r
608 trace = _data._expandedItems[idx]._trace;\r
609 return trace;\r
610 }\r
611\r
612 public int getSelectedIndex() {\r
613 int idx = -1;\r
614 for (int i = 0; i < _data._expandedItems.length; i++) {\r
615 TimeGraphItem item = (TimeGraphItem) _data._expandedItems[i];\r
616 if (item._selected) {\r
617 idx = i;\r
618 break;\r
619 }\r
620 }\r
621 return idx;\r
622 }\r
623\r
624 boolean toggle(int idx) {\r
625 boolean toggled = false;\r
626 if (idx >= 0 && idx < _data._expandedItems.length) {\r
627 TimeGraphItem item = (TimeGraphItem) _data._expandedItems[idx];\r
628 if (item._hasChildren) {\r
629 item._expanded = !item._expanded;\r
630 _data.updateExpandedItems();\r
631 adjustScrolls();\r
632 redraw();\r
633 toggled = true;\r
634 fireTreeEvent(item._trace, item._expanded);\r
635 }\r
636 }\r
637 return toggled;\r
638 }\r
639\r
640 int getItemIndexAtY(int y) {\r
641 if (y < 0) {\r
642 return -1;\r
643 }\r
b83af2c3
PT
644 if (_itemHeight == CUSTOM_ITEM_HEIGHT) {\r
645 int ySum = 0;\r
646 for (int idx = _topIndex; idx < _data._expandedItems.length; idx++) {\r
647 ySum += _data._expandedItems[idx].itemHeight;\r
648 if (y < ySum) {\r
649 return idx;\r
650 }\r
651 }\r
652 return -1;\r
653 }\r
fb5cad3d
PT
654 int idx = y / _itemHeight;\r
655 idx += _topIndex;\r
656 if (idx < _data._expandedItems.length) {\r
657 return idx;\r
658 }\r
659 return -1;\r
660 }\r
661\r
662 boolean isOverSplitLine(int x) {\r
663 if (x < 0 || null == _timeProvider)\r
664 return false;\r
665 int w = 4;\r
666 int nameWidth = _timeProvider.getNameSpace();\r
667 if (x > nameWidth - w && x < nameWidth + w) {\r
668 return true;\r
669 } else {\r
670 return false;\r
671 }\r
672 }\r
673\r
674 TimeGraphItem getItem(Point pt) {\r
675 int idx = getItemIndexAtY(pt.y);\r
676 return idx >= 0 ? (TimeGraphItem) _data._expandedItems[idx] : null;\r
677 }\r
678\r
679 long getTimeAtX(int x) {\r
680 if (null == _timeProvider)\r
681 return -1;\r
682 long hitTime = -1;\r
683 Point size = getCtrlSize();\r
684 long time0 = _timeProvider.getTime0();\r
685 long time1 = _timeProvider.getTime1();\r
686 int nameWidth = _timeProvider.getNameSpace();\r
687 x -= nameWidth;\r
688 if (x >= 0 && size.x >= nameWidth) {\r
689 if (time1 - time0 > size.x - nameWidth - RIGHT_MARGIN) {\r
690 // get the last possible time represented by the pixel position\r
691 // by taking the time of the next pixel position minus 1\r
692 // nanosecond\r
693 hitTime = time0 + (long) ((time1 - time0) * ((double) (x + 1) / (size.x - nameWidth - RIGHT_MARGIN))) - 1;\r
694 } else {\r
695 hitTime = time0 + (long) ((time1 - time0) * ((double) (x) / (size.x - nameWidth - RIGHT_MARGIN)));\r
696 }\r
697 }\r
698 return hitTime;\r
699 }\r
700\r
701 void selectItem(int idx, boolean addSelection) {\r
702 boolean changed = false;\r
703 if (addSelection) {\r
704 if (idx >= 0 && idx < _data._expandedItems.length) {\r
705 TimeGraphItem item = (TimeGraphItem) _data._expandedItems[idx];\r
706 changed = (item._selected == false);\r
707 item._selected = true;\r
708 }\r
709 } else {\r
710 for (int i = 0; i < _data._expandedItems.length; i++) {\r
711 TimeGraphItem item = (TimeGraphItem) _data._expandedItems[i];\r
712 if ((i == idx && !item._selected) || (idx == -1 && item._selected)) {\r
713 changed = true;\r
714 }\r
715 item._selected = i == idx;\r
716 }\r
717 }\r
718 changed |= ensureVisibleItem(idx, true);\r
719 if (changed)\r
720 redraw();\r
721 }\r
722\r
723 public void selectItem(ITimeGraphEntry trace, boolean addSelection) {\r
724 int idx = _data.findItemIndex(trace);\r
725 selectItem(idx, addSelection);\r
726 }\r
727\r
728 public int countPerPage() {\r
729 int height = getCtrlSize().y;\r
730 int count = 0;\r
b83af2c3
PT
731 if (_itemHeight == CUSTOM_ITEM_HEIGHT) {\r
732 int ySum = 0;\r
733 for (int idx = _topIndex; idx < _data._expandedItems.length; idx++) {\r
734 ySum += _data._expandedItems[idx].itemHeight;\r
735 if (ySum >= height) {\r
736 return count;\r
737 }\r
738 count++;\r
739 }\r
740 for (int idx = _topIndex - 1; idx >= 0; idx--) {\r
741 ySum += _data._expandedItems[idx].itemHeight;\r
742 if (ySum >= height) {\r
743 return count;\r
744 }\r
745 count++;\r
746 }\r
747 return count;\r
748 }\r
749 if (height > 0) {\r
fb5cad3d 750 count = height / _itemHeight;\r
b83af2c3 751 }\r
fb5cad3d
PT
752 return count;\r
753 }\r
754\r
755 public int getTopIndex() {\r
756 return _topIndex;\r
757 }\r
758\r
759 public int getExpandedElementCount() {\r
760 return _data._expandedItems.length;\r
761 }\r
762\r
763 Point getCtrlSize() {\r
764 Point size = getSize();\r
765 if (getHorizontalBar().isVisible()) {\r
766 size.y -= getHorizontalBar().getSize().y;\r
767 }\r
768 return size;\r
769 }\r
770\r
771 Rectangle getNameRect(Rectangle bound, int idx, int nameWidth) {\r
fb5cad3d 772 int x = bound.x;\r
b83af2c3 773 int y = bound.y + (idx - _topIndex) * _itemHeight;\r
fb5cad3d
PT
774 int width = nameWidth;\r
775 int height = _itemHeight;\r
b83af2c3
PT
776 if (_itemHeight == CUSTOM_ITEM_HEIGHT) {\r
777 int ySum = 0;\r
778 for (int i = _topIndex; i < idx; i++) {\r
779 ySum += _data._expandedItems[i].itemHeight;\r
780 }\r
781 y = bound.y + ySum;\r
782 height = _data._expandedItems[idx].itemHeight;\r
783 }\r
fb5cad3d
PT
784 return new Rectangle(x, y, width, height);\r
785 }\r
786\r
787 Rectangle getStatesRect(Rectangle bound, int idx, int nameWidth) {\r
fb5cad3d 788 int x = bound.x + nameWidth;\r
b83af2c3 789 int y = bound.y + (idx - _topIndex) * _itemHeight;\r
fb5cad3d
PT
790 int width = bound.width - x;\r
791 int height = _itemHeight;\r
b83af2c3
PT
792 if (_itemHeight == CUSTOM_ITEM_HEIGHT) {\r
793 int ySum = 0;\r
794 for (int i = _topIndex; i < idx; i++) {\r
795 ySum += _data._expandedItems[i].itemHeight;\r
796 }\r
797 y = bound.y + ySum;\r
798 height = _data._expandedItems[idx].itemHeight;\r
799 }\r
fb5cad3d
PT
800 return new Rectangle(x, y, width, height);\r
801 }\r
802\r
fb5cad3d
PT
803 @Override\r
804 void paint(Rectangle bounds, PaintEvent e) {\r
805 GC gc = e.gc;\r
806 gc.setBackground(_colors.getColor(TimeGraphColorScheme.BACKGROUND));\r
807 drawBackground(gc, bounds.x, bounds.y, bounds.width, bounds.height);\r
808\r
809 if (bounds.width < 2 || bounds.height < 2 || null == _timeProvider)\r
810 return;\r
811\r
812 _idealNameSpace = 0;\r
813 int nameSpace = _timeProvider.getNameSpace();\r
814\r
815 // draw empty name space background\r
b83af2c3
PT
816 gc.setBackground(_colors.getBkColor(false, false, true));\r
817 drawBackground(gc, bounds.x, bounds.y, nameSpace, bounds.height);\r
fb5cad3d 818\r
b83af2c3 819 drawItems(bounds, _timeProvider, _data._expandedItems, _topIndex, nameSpace, gc);\r
fb5cad3d
PT
820\r
821 // draw selected time\r
822 long time0 = _timeProvider.getTime0();\r
823 long time1 = _timeProvider.getTime1();\r
824 long selectedTime = _timeProvider.getSelectedTime();\r
825 double pixelsPerNanoSec = (bounds.width - nameSpace <= RIGHT_MARGIN) ? 0 : (double) (bounds.width - nameSpace - RIGHT_MARGIN) / (time1 - time0);\r
826 int x = bounds.x + nameSpace + (int) ((double) (selectedTime - time0) * pixelsPerNanoSec);\r
827 if (x >= nameSpace && x < bounds.x + bounds.width) {\r
828 gc.setForeground(_colors.getColor(TimeGraphColorScheme.SELECTED_TIME));\r
829 gc.drawLine(x, bounds.y, x, bounds.y + bounds.height);\r
830 }\r
831\r
832 // draw drag line, no line if name space is 0.\r
833 if (DRAG_SPLIT_LINE == _dragState) {\r
834 gc.setForeground(_colors.getColor(TimeGraphColorScheme.BLACK));\r
835 gc.drawLine(bounds.x + nameSpace, bounds.y, bounds.x + nameSpace, bounds.y + bounds.height - 1);\r
836 } else if (DRAG_NONE == _dragState && _mouseOverSplitLine && _timeProvider.getNameSpace() > 0) {\r
837 gc.setForeground(_colors.getColor(TimeGraphColorScheme.RED));\r
838 gc.drawLine(bounds.x + nameSpace, bounds.y, bounds.x + nameSpace, bounds.y + bounds.height - 1);\r
839 }\r
840 }\r
841\r
842 public void drawItems(Rectangle bounds, ITimeDataProvider timeProvider, TimeGraphItem[] items, int topIndex, int nameSpace, GC gc) {\r
fb5cad3d
PT
843 for (int i = topIndex; i < items.length; i++) {\r
844 TimeGraphItem item = (TimeGraphItem) items[i];\r
b83af2c3 845 drawItem(item, bounds, timeProvider, i, nameSpace, gc);\r
fb5cad3d 846 }\r
b83af2c3 847 fTimeGraphProvider.postDrawControl(bounds, gc);\r
fb5cad3d
PT
848 }\r
849\r
850 /**\r
851 * Draws the item\r
852 * \r
853 * @param item the item to draw\r
854 * @param bounds the container rectangle\r
855 * @param i the item index\r
856 * @param nameSpace the name space\r
857 * @param gc\r
858 */\r
b83af2c3
PT
859 protected void drawItem(TimeGraphItem item, Rectangle bounds, ITimeDataProvider timeProvider, int i, int nameSpace, GC gc) {\r
860 ITimeGraphEntry entry = item._trace;\r
fb5cad3d
PT
861 long time0 = timeProvider.getTime0();\r
862 long time1 = timeProvider.getTime1();\r
fb5cad3d
PT
863 long selectedTime = timeProvider.getSelectedTime();\r
864\r
865 Rectangle nameRect = getNameRect(bounds, i, nameSpace);\r
866 if (nameRect.y >= bounds.y + bounds.height) {\r
867 return;\r
868 }\r
869\r
870 if (item._trace.getTimeEventsIterator() == null) {\r
871 Rectangle statesRect = getStatesRect(bounds, i, nameSpace);\r
872 nameRect.width += statesRect.width;\r
873 drawName(item, nameRect, gc);\r
874 } else {\r
875 drawName(item, nameRect, gc);\r
876 }\r
877 Rectangle rect = getStatesRect(bounds, i, nameSpace);\r
b83af2c3
PT
878 if (rect.isEmpty()) {\r
879 fTimeGraphProvider.postDrawEntry(entry, bounds, gc);\r
fb5cad3d 880 return;\r
b83af2c3 881 }\r
fb5cad3d
PT
882 if (time1 <= time0) {\r
883 gc.setBackground(_colors.getBkColor(false, false, false));\r
884 gc.fillRectangle(rect);\r
b83af2c3 885 fTimeGraphProvider.postDrawEntry(entry, bounds, gc);\r
fb5cad3d
PT
886 return;\r
887 }\r
888\r
889 // Initialize _rect1 to same values as enclosing rectangle rect\r
890 Rectangle stateRect = Utils.clone(rect);\r
891 boolean selected = item._selected;\r
892 // K pixels per second\r
893 double pixelsPerNanoSec = (rect.width <= RIGHT_MARGIN) ? 0 : (double) (rect.width - RIGHT_MARGIN) / (time1 - time0);\r
894\r
895 boolean group = item._trace.getTimeEventsIterator() == null;\r
896\r
b83af2c3
PT
897 if (!group) {\r
898 fillSpace(rect, gc, selected);\r
fb5cad3d
PT
899 // Drawing rectangle is smaller than reserved space\r
900 stateRect.y += 3;\r
901 stateRect.height -= 6;\r
902\r
b83af2c3
PT
903 long maxDuration = (timeProvider.getTimeSpace() == 0) ? Long.MAX_VALUE : 1 * (time1 - time0) / timeProvider.getTimeSpace();\r
904 Iterator<ITimeEvent> iterator = entry.getTimeEventsIterator(time0, time1, maxDuration);\r
905\r
906 int lastX = -1;\r
907 while (iterator.hasNext()) {\r
908 ITimeEvent event = iterator.next();\r
909 int x = rect.x + (int) ((event.getTime() - time0) * pixelsPerNanoSec);\r
910 int xEnd = rect.x + (int) ((event.getTime() + event.getDuration() - time0) * pixelsPerNanoSec);\r
911 if (x >= rect.x + rect.width || xEnd < rect.x) {\r
912 // event is out of bounds\r
913 continue;\r
914 }\r
915 xEnd = Math.min(rect.x + rect.width, xEnd);\r
916 stateRect.x = Math.max(rect.x, x);\r
917 stateRect.width = Math.max(0, xEnd - stateRect.x + 1);\r
918 if (stateRect.x == lastX) {\r
919 stateRect.width -= 1;\r
920 if (stateRect.width > 0) {\r
921 gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));\r
922 gc.drawPoint(stateRect.x, stateRect.y - 2);\r
923 stateRect.x += 1;\r
f7e7159c 924 }\r
b83af2c3
PT
925 } else {\r
926 lastX = x;\r
fb5cad3d 927 }\r
b83af2c3
PT
928 boolean timeSelected = selectedTime >= event.getTime() && selectedTime < event.getTime() + event.getDuration();\r
929 drawState(_colors, event, stateRect, gc, selected, timeSelected);\r
fb5cad3d
PT
930 }\r
931 }\r
b83af2c3 932 fTimeGraphProvider.postDrawEntry(entry, bounds, gc);\r
fb5cad3d
PT
933 }\r
934\r
b83af2c3 935 protected void drawName(TimeGraphItem item, Rectangle bounds, GC gc) {\r
fb5cad3d
PT
936 boolean group = item._trace.getTimeEventsIterator() == null;\r
937 if (group) {\r
938 gc.setBackground(_colors.getBkColorGroup(item._selected, _isInFocus));\r
939 gc.fillRectangle(bounds);\r
940 if (item._selected && _isInFocus) {\r
941 gc.setForeground(_colors.getBkColor(item._selected, _isInFocus, false));\r
942 gc.drawRectangle(bounds.x, bounds.y, bounds.width - 1, bounds.height - 1);\r
943 }\r
944 } else {\r
945 gc.setBackground(_colors.getBkColor(item._selected, _isInFocus, true));\r
946 gc.setForeground(_colors.getFgColor(item._selected, _isInFocus));\r
947 gc.fillRectangle(bounds);\r
948 }\r
949\r
950 // No name to be drawn\r
951 if (_timeProvider.getNameSpace() == 0) {\r
952 return;\r
953 }\r
954\r
955 int leftMargin = MARGIN + item.level * EXPAND_SIZE;\r
956 if (item._hasChildren) {\r
957 gc.setForeground(_colors.getFgColorGroup(false, false));\r
958 gc.setBackground(_colors.getBkColor(false, false, false));\r
959 Rectangle rect = Utils.clone(bounds);\r
960 rect.x += leftMargin;\r
961 rect.y += (bounds.height - EXPAND_SIZE) / 2;\r
962 rect.width = EXPAND_SIZE;\r
963 rect.height = EXPAND_SIZE;\r
964 gc.fillRectangle(rect);\r
965 gc.drawRectangle(rect.x, rect.y, rect.width - 1, rect.height - 1);\r
966 int midy = rect.y + rect.height / 2;\r
967 gc.drawLine(rect.x + 2, midy, rect.x + rect.width - 3, midy);\r
968 if (!item._expanded) {\r
969 int midx = rect.x + rect.width / 2;\r
970 gc.drawLine(midx, rect.y + 2, midx, rect.y + rect.height - 3);\r
971 }\r
972 }\r
973 leftMargin += EXPAND_SIZE + MARGIN;\r
974\r
975 Image img = fTimeGraphProvider.getItemImage(item._trace);\r
976 if (img != null) {\r
977 // draw icon\r
978 int imgHeight = img.getImageData().height;\r
979 int imgWidth = img.getImageData().width;\r
980 int x = leftMargin;\r
981 int y = bounds.y + (bounds.height - imgHeight) / 2;\r
982 gc.drawImage(img, x, y);\r
983 leftMargin += imgWidth + MARGIN;\r
984 }\r
985 String name = item._name;\r
986 Point size = gc.stringExtent(name);\r
987 if (_idealNameSpace < leftMargin + size.x + MARGIN) {\r
988 _idealNameSpace = leftMargin + size.x + MARGIN;\r
989 }\r
990 if (!group) {\r
991 // cut long string with "..."\r
992 int width = bounds.width - leftMargin;\r
993 int cuts = 0;\r
994 while (size.x > width && name.length() > 1) {\r
995 cuts++;\r
996 name = name.substring(0, name.length() - 1);\r
997 size = gc.stringExtent(name + "..."); //$NON-NLS-1$\r
998 }\r
999 if (cuts > 0) {\r
1000 name += "..."; //$NON-NLS-1$\r
1001 }\r
1002 }\r
1003 Rectangle rect = Utils.clone(bounds);\r
1004 rect.x += leftMargin;\r
1005 rect.width -= leftMargin;\r
1006 // draw text\r
1007 if (rect.width > 0) {\r
b83af2c3
PT
1008 rect.y += (bounds.height - gc.stringExtent(name).y) / 2;\r
1009 gc.setForeground(_colors.getFgColor(item._selected, _isInFocus));\r
fb5cad3d
PT
1010 int textWidth = Utils.drawText(gc, name, rect, true);\r
1011 leftMargin += textWidth + MARGIN;\r
1012 rect.y -= 2;\r
1013\r
1014 if (!group) {\r
1015 // draw middle line\r
1016 int x = bounds.x + leftMargin;\r
1017 int width = bounds.width - x;\r
1018 int midy = bounds.y + bounds.height / 2;\r
1019 gc.setForeground(_colors.getColor(TimeGraphColorScheme.MID_LINE));\r
1020 gc.drawLine(x, midy, x + width, midy);\r
1021 }\r
1022 }\r
1023 }\r
1024\r
b83af2c3
PT
1025 protected void drawState(TimeGraphColorScheme colors, ITimeEvent event,\r
1026 Rectangle rect, GC gc, boolean selected, boolean timeSelected) {\r
fb5cad3d 1027\r
b83af2c3
PT
1028 int colorIdx = fTimeGraphProvider.getEventTableIndex(event);\r
1029 if (colorIdx < 0) {\r
1030 return;\r
f7e7159c 1031 }\r
b83af2c3 1032 boolean visible = rect.width == 0 ? false : true;\r
fb5cad3d
PT
1033\r
1034 if (visible) {\r
b83af2c3
PT
1035 Color stateColor = null;\r
1036 if (colorIdx < fEventColorMap.length) {\r
1037 stateColor = fEventColorMap[colorIdx];\r
1038 } else {\r
1039 stateColor = Display.getDefault().getSystemColor(SWT.COLOR_BLACK);\r
1040 }\r
1041 \r
1042 timeSelected = timeSelected && selected;\r
1043 if (timeSelected) {\r
1044 // modify the color?\r
1045 }\r
fb5cad3d 1046 // fill all rect area\r
b83af2c3 1047 gc.setBackground(stateColor);\r
fb5cad3d 1048 gc.fillRectangle(rect);\r
b83af2c3
PT
1049 // get the border color?\r
1050 gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));\r
fb5cad3d
PT
1051\r
1052 // draw bounds\r
1053 if (!timeSelected) {\r
b83af2c3
PT
1054 // Draw the top and bottom borders i.e. no side borders\r
1055 // top\r
1056 gc.drawLine(rect.x, rect.y, rect.x + rect.width - 1, rect.y);\r
1057 // bottom\r
1058 gc.drawLine(rect.x, rect.y + rect.height - 1, rect.x + rect.width - 1, rect.y + rect.height - 1);\r
fb5cad3d
PT
1059 }\r
1060 } else {\r
b83af2c3
PT
1061 gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));\r
1062 gc.drawPoint(rect.x, rect.y - 2);\r
1063 /*\r
fb5cad3d
PT
1064 // selected rectangle area is not visible but can be represented\r
1065 // with a broken vertical line of specified width.\r
b83af2c3 1066 int width = 1;\r
fb5cad3d 1067 rect.width = width;\r
b83af2c3 1068 gc.setForeground(stateColor);\r
fb5cad3d
PT
1069 int s = gc.getLineStyle();\r
1070 int w = gc.getLineWidth();\r
1071 gc.setLineStyle(SWT.LINE_DOT);\r
1072 gc.setLineWidth(width);\r
b83af2c3 1073 // Trace.debug("Rectangle not visible, drawing vertical line with: "\r
fb5cad3d
PT
1074 // + rect.x + "," + rect.y + "," + rect.x + "," + rect.y\r
1075 // + rect.height);\r
b83af2c3 1076 gc.drawLine(rect.x, rect.y, rect.x, rect.y + rect.height - 1);\r
fb5cad3d
PT
1077 gc.setLineStyle(s);\r
1078 gc.setLineWidth(w);\r
b83af2c3
PT
1079 if (!timeSelected) {\r
1080 gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));\r
1081 gc.drawPoint(rect.x, rect.y);\r
1082 gc.drawPoint(rect.x, rect.y + rect.height - 1);\r
1083 }\r
1084 */\r
fb5cad3d 1085 }\r
b83af2c3 1086 fTimeGraphProvider.postDrawEvent(event, rect, gc);\r
fb5cad3d
PT
1087 }\r
1088\r
b83af2c3 1089 protected void fillSpace(Rectangle rect, GC gc, boolean selected) {\r
fb5cad3d
PT
1090 gc.setBackground(_colors.getBkColor(selected, _isInFocus, false));\r
1091 gc.fillRectangle(rect);\r
1092 // draw middle line\r
1093 gc.setForeground(_colors.getColor(TimeGraphColorScheme.MID_LINE));\r
1094 int midy = rect.y + rect.height / 2;\r
1095 gc.drawLine(rect.x, midy, rect.x + rect.width, midy);\r
1096 }\r
1097\r
1098 @Override\r
1099 public void keyTraversed(TraverseEvent e) {\r
1100 if ((e.detail == SWT.TRAVERSE_TAB_NEXT) || (e.detail == SWT.TRAVERSE_TAB_PREVIOUS))\r
1101 e.doit = true;\r
1102 }\r
1103\r
1104 @Override\r
1105 public void keyPressed(KeyEvent e) {\r
1106 int idx = -1;\r
1107 if (_data._expandedItems.length == 0) {\r
1108 return;\r
1109 }\r
1110 if (SWT.HOME == e.keyCode) {\r
1111 idx = 0;\r
1112 } else if (SWT.END == e.keyCode) {\r
1113 idx = _data._expandedItems.length - 1;\r
1114 } else if (SWT.ARROW_DOWN == e.keyCode) {\r
1115 idx = getSelectedIndex();\r
1116 if (idx < 0)\r
1117 idx = 0;\r
1118 else if (idx < _data._expandedItems.length - 1)\r
1119 idx++;\r
1120 } else if (SWT.ARROW_UP == e.keyCode) {\r
1121 idx = getSelectedIndex();\r
1122 if (idx < 0)\r
1123 idx = 0;\r
1124 else if (idx > 0)\r
1125 idx--;\r
1126 } else if (SWT.ARROW_LEFT == e.keyCode) {\r
1127 selectPrevEvent();\r
1128 } else if (SWT.ARROW_RIGHT == e.keyCode) {\r
1129 selectNextEvent();\r
1130 } else if (SWT.PAGE_DOWN == e.keyCode) {\r
1131 int page = countPerPage();\r
1132 idx = getSelectedIndex();\r
1133 if (idx < 0)\r
1134 idx = 0;\r
1135 idx += page;\r
1136 if (idx >= _data._expandedItems.length)\r
1137 idx = _data._expandedItems.length - 1;\r
1138 } else if (SWT.PAGE_UP == e.keyCode) {\r
1139 int page = countPerPage();\r
1140 idx = getSelectedIndex();\r
1141 if (idx < 0)\r
1142 idx = 0;\r
1143 idx -= page;\r
1144 if (idx < 0)\r
1145 idx = 0;\r
1146 } else if (SWT.CR == e.keyCode) {\r
1147 idx = getSelectedIndex();\r
1148 if (idx >= 0) {\r
1149 if (_data._expandedItems[idx]._hasChildren) {\r
1150 toggle(idx);\r
1151 } else {\r
1152 fireDefaultSelection();\r
1153 }\r
1154 }\r
1155 idx = -1;\r
1156 }\r
1157 if (idx >= 0) {\r
1158 selectItem(idx, false);\r
1159 fireSelectionChanged();\r
1160 }\r
1161 }\r
1162\r
1163 @Override\r
1164 public void keyReleased(KeyEvent e) {\r
1165 }\r
1166\r
1167 @Override\r
1168 public void focusGained(FocusEvent e) {\r
1169 _isInFocus = true;\r
1170 redraw();\r
1171 }\r
1172\r
1173 @Override\r
1174 public void focusLost(FocusEvent e) {\r
1175 _isInFocus = false;\r
1176 if (DRAG_NONE != _dragState) {\r
1177 setCapture(false);\r
1178 _dragState = DRAG_NONE;\r
1179 }\r
1180 redraw();\r
1181 }\r
1182\r
1183 public boolean isInFocus() {\r
1184 return _isInFocus;\r
1185 }\r
1186\r
b83af2c3
PT
1187 /**\r
1188 * Provide the possibilty to control the wait cursor externally e.g. data\r
1189 * requests in progress\r
1190 * \r
1191 * @param waitInd\r
1192 */\r
1193 public void waitCursor(boolean waitInd) {\r
1194 // Update cursor as indicated\r
1195 if (waitInd) {\r
1196 setCursor(_WaitCursor);\r
1197 _isWaitCursor = true;\r
1198 } else {\r
1199 setCursor(null);\r
1200 _isWaitCursor = false;\r
1201 }\r
1202\r
1203 // Get ready for next mouse move\r
1204 _isDragCursor3 = false;\r
1205 }\r
1206\r
1207 /**\r
1208 * <p>\r
1209 * If the x, y position is over the vertical split line (name to time\r
1210 * ranges), then change the cursor to a drag cursor to indicate the user the\r
1211 * possibility of resizing\r
1212 * </p>\r
1213 * \r
1214 * @param x\r
1215 * @param y\r
1216 */\r
1217 void updateCursor(int x, int y) {\r
1218 // if Wait cursor not active, check for the need to change to a drag\r
1219 // cursor\r
1220 if (_isWaitCursor == false) {\r
1221 boolean isSplitLine = isOverSplitLine(x);\r
1222 // No dragcursor is name space is fixed to zero\r
1223 if (isSplitLine && !_isDragCursor3 && _timeProvider.getNameSpace() > 0) {\r
1224 setCursor(_dragCursor3);\r
1225 _isDragCursor3 = true;\r
1226 } else if (!isSplitLine && _isDragCursor3) {\r
1227 setCursor(null);\r
1228 _isDragCursor3 = false;\r
1229 }\r
1230 }\r
1231 }\r
1232\r
fb5cad3d
PT
1233 @Override\r
1234 public void mouseMove(MouseEvent e) {\r
1235 if (null == _timeProvider)\r
1236 return;\r
1237 Point size = getCtrlSize();\r
1238 if (DRAG_TRACE_ITEM == _dragState) {\r
1239 int nameWidth = _timeProvider.getNameSpace();\r
1240 int x = e.x - nameWidth;\r
1241 if (x > 0 && size.x > nameWidth && _dragX != x) {\r
1242 _dragX = x;\r
1243 double pixelsPerNanoSec = (size.x - nameWidth <= RIGHT_MARGIN) ? 0 : (double) (size.x - nameWidth - RIGHT_MARGIN) / (_time1bak - _time0bak);\r
1244 long timeDelta = (long) ((pixelsPerNanoSec == 0) ? 0 : ((_dragX - _dragX0) / pixelsPerNanoSec));\r
1245 long time1 = _time1bak - timeDelta;\r
1246 long maxTime = _timeProvider.getMaxTime();\r
1247 if (time1 > maxTime)\r
1248 time1 = maxTime;\r
1249 long time0 = time1 - (_time1bak - _time0bak);\r
1250 if (time0 < _timeProvider.getMinTime()) {\r
1251 time0 = _timeProvider.getMinTime();\r
1252 time1 = time0 + (_time1bak - _time0bak);\r
1253 }\r
1254 _timeProvider.setStartFinishTime(time0, time1);\r
1255 }\r
1256 } else if (DRAG_SPLIT_LINE == _dragState) {\r
1257 _dragX = e.x;\r
1258 _timeProvider.setNameSpace(e.x);\r
1259 } else if (DRAG_NONE == _dragState) {\r
1260 boolean mouseOverSplitLine = isOverSplitLine(e.x);\r
1261 if (_mouseOverSplitLine != mouseOverSplitLine) {\r
1262 redraw();\r
1263 }\r
1264 _mouseOverSplitLine = mouseOverSplitLine;\r
1265 // Make sure any time changes are notified to the application e.g.\r
1266 // getting back from the horizontal scroll bar or zoomed using the\r
1267 // mouse wheel\r
1268 _timeProvider.notifyStartFinishTime();\r
1269 }\r
1270 updateCursor(e.x, e.y);\r
1271 }\r
1272\r
1273 @Override\r
1274 public void mouseDoubleClick(MouseEvent e) {\r
1275 if (null == _timeProvider)\r
1276 return;\r
1277 if (1 == e.button) {\r
1278 if (isOverSplitLine(e.x) && _timeProvider.getNameSpace() != 0) {\r
1279 _timeProvider.setNameSpace(_idealNameSpace);\r
1280 boolean mouseOverSplitLine = isOverSplitLine(e.x);\r
1281 if (_mouseOverSplitLine != mouseOverSplitLine) {\r
1282 redraw();\r
1283 }\r
1284 _mouseOverSplitLine = mouseOverSplitLine;\r
1285 return;\r
1286 }\r
1287 int idx = getItemIndexAtY(e.y);\r
1288 if (idx >= 0) {\r
1289 selectItem(idx, false);\r
1290 fireDefaultSelection();\r
1291 }\r
1292 }\r
1293 }\r
1294\r
fb5cad3d
PT
1295 @Override\r
1296 public void mouseDown(MouseEvent e) {\r
1297 if (null == _timeProvider)\r
1298 return;\r
1299 int idx;\r
1300 if (1 == e.button) {\r
1301 int nameSpace = _timeProvider.getNameSpace();\r
1302 if (nameSpace != 0) {\r
1303 if (isOverSplitLine(e.x)) {\r
1304 _dragState = DRAG_SPLIT_LINE;\r
1305 _dragX = _dragX0 = e.x;\r
1306 _time0bak = _timeProvider.getTime0();\r
1307 _time1bak = _timeProvider.getTime1();\r
1308 redraw();\r
1309 return;\r
1310 }\r
1311 }\r
1312\r
1313 idx = getItemIndexAtY(e.y);\r
1314 if (idx >= 0) {\r
1315 TimeGraphItem item = _data._expandedItems[idx];\r
1316 if (item._hasChildren && e.x < nameSpace && e.x < MARGIN + (item.level + 1) * EXPAND_SIZE) {\r
1317 toggle(idx);\r
1318 } else {\r
1319 long hitTime = getTimeAtX(e.x);\r
1320 if (hitTime >= 0) {\r
1321 // _timeProvider.setSelectedTimeInt(hitTime, false);\r
1322 setCapture(true);\r
1323 _dragState = DRAG_TRACE_ITEM;\r
1324 _dragX = _dragX0 = e.x - nameSpace;\r
1325 _time0bak = _timeProvider.getTime0();\r
1326 _time1bak = _timeProvider.getTime1();\r
1327 }\r
1328 }\r
1329 selectItem(idx, false);\r
1330 fireSelectionChanged();\r
1331 } else {\r
1332 selectItem(idx, false); // clear selection\r
1333 redraw();\r
1334 fireSelectionChanged();\r
1335 }\r
1336 }\r
1337 }\r
1338\r
1339 @Override\r
1340 public void mouseUp(MouseEvent e) {\r
1341 if (DRAG_NONE != _dragState) {\r
1342 setCapture(false);\r
1343 if (DRAG_TRACE_ITEM == _dragState) {\r
1344 // Notify time provider to check the need for listener\r
1345 // notification\r
1346 _timeProvider.notifyStartFinishTime();\r
1347 if (_dragX == _dragX0) { // click without drag\r
1348 long time = getTimeAtX(e.x);\r
3ac6ad1a 1349 _timeProvider.setSelectedTimeNotify(time, false);\r
fb5cad3d
PT
1350 }\r
1351 } else if (DRAG_SPLIT_LINE == _dragState) {\r
1352 redraw();\r
1353 }\r
1354 _dragState = DRAG_NONE;\r
1355 }\r
1356 }\r
1357\r
fb5cad3d
PT
1358 @Override\r
1359 public void mouseEnter(MouseEvent e) {\r
1360 if (mouseScrollFilterListener == null) {\r
1361 mouseScrollFilterListener = new Listener() {\r
1362 // This filter is used to prevent scrolling of the view when the\r
1363 // mouse wheel is used to zoom\r
1364 @Override\r
1365 public void handleEvent(Event event) {\r
1366 event.doit = false;\r
1367 }\r
1368 };\r
1369 getDisplay().addFilter(SWT.MouseWheel, mouseScrollFilterListener);\r
1370 }\r
1371 }\r
1372\r
1373 @Override\r
1374 public void mouseExit(MouseEvent e) {\r
1375 if (mouseScrollFilterListener != null) {\r
1376 getDisplay().removeFilter(SWT.MouseWheel, mouseScrollFilterListener);\r
1377 mouseScrollFilterListener = null;\r
1378 }\r
1379 if (_mouseOverSplitLine) {\r
1380 _mouseOverSplitLine = false;\r
1381 redraw();\r
1382 }\r
1383 }\r
1384\r
1385 @Override\r
1386 public void mouseHover(MouseEvent e) {\r
1387 }\r
1388\r
1389 @Override\r
1390 public void mouseScrolled(MouseEvent e) {\r
1391 if ((mouseScrollFilterListener == null) || _dragState != DRAG_NONE) {\r
1392 return;\r
1393 }\r
b83af2c3 1394 if (e.x < _timeProvider.getNameSpace() || e.x > getSize().x) {\r
fb5cad3d 1395 setTopIndex(getTopIndex() - e.count);\r
b83af2c3 1396 } else if (_timeProvider.getTime0() != _timeProvider.getTime1()) {\r
fb5cad3d
PT
1397 if (e.count > 0) {\r
1398 zoom(true);\r
1399 } else if (e.count < 0) {\r
1400 zoom(false);\r
1401 }\r
1402 }\r
1403 }\r
1404\r
b83af2c3
PT
1405 @Override\r
1406 public void controlMoved(ControlEvent e) {\r
1407 }\r
1408\r
1409 @Override\r
1410 public void controlResized(ControlEvent e) {\r
1411 adjustScrolls();\r
1412 }\r
1413\r
1414 @Override\r
1415 public void widgetDefaultSelected(SelectionEvent e) {\r
1416 }\r
1417\r
1418 @Override\r
1419 public void widgetSelected(SelectionEvent e) {\r
1420 if (e.widget == getVerticalBar()) {\r
1421 setTopIndex(getVerticalBar().getSelection());\r
1422 } else if (e.widget == getHorizontalBar() && null != _timeProvider) {\r
1423 int start = getHorizontalBar().getSelection();\r
1424 long time0 = _timeProvider.getTime0();\r
1425 long time1 = _timeProvider.getTime1();\r
1426 long timeMin = _timeProvider.getMinTime();\r
1427 long timeMax = _timeProvider.getMaxTime();\r
1428 long delta = timeMax - timeMin;\r
1429\r
1430 long range = time1 - time0;\r
1431 // _timeRangeFixed = true;\r
1432 time0 = timeMin + Math.round(delta * ((double) start / H_SCROLLBAR_MAX));\r
1433 time1 = time0 + range;\r
1434\r
1435 // TODO: Follow-up with Bug 310310\r
1436 // In Linux SWT.DRAG is the only value received\r
1437 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=310310\r
1438 if (e.detail == SWT.DRAG) {\r
1439 _timeProvider.setStartFinishTime(time0, time1);\r
1440 } else {\r
1441 _timeProvider.setStartFinishTimeNotify(time0, time1);\r
1442 }\r
1443 }\r
1444 }\r
1445\r
fb5cad3d
PT
1446 public boolean isVisibleVerticalScroll() {\r
1447 return _visibleVerticalScroll;\r
1448 }\r
1449\r
1450 @Override\r
1451 public int getBorderWidth() {\r
1452 return _borderWidth;\r
1453 }\r
1454\r
1455 public void setBorderWidth(int borderWidth) {\r
1456 this._borderWidth = borderWidth;\r
1457 }\r
1458\r
1459 public int getHeaderHeight() {\r
1460 return _headerHeight;\r
1461 }\r
1462\r
1463 public void setHeaderHeight(int headerHeight) {\r
1464 this._headerHeight = headerHeight;\r
1465 }\r
1466\r
1467 public int getItemHeight() {\r
1468 return _itemHeight;\r
1469 }\r
1470\r
1471 public void setItemHeight(int rowHeight) {\r
1472 this._itemHeight = rowHeight;\r
1473 }\r
1474\r
1475 public void setMinimumItemWidth(int width) {\r
1476 this._minimumItemWidth = width;\r
1477 }\r
1478\r
1479 public int getMinimumItemWidth() {\r
1480 return _minimumItemWidth;\r
1481 }\r
1482\r
1483 public Vector<ITimeGraphEntry> getFilteredOut() {\r
1484 return _data.getFilteredOut();\r
1485 }\r
1486\r
1487 // @Override\r
1488 @Override\r
1489 public void addSelectionChangedListener(ISelectionChangedListener listener) {\r
1490 if (listener != null) {\r
1491 if (!_selectionChangedListeners.contains(listener)) {\r
1492 _selectionChangedListeners.add(listener);\r
1493 }\r
1494 }\r
1495 }\r
1496\r
1497 // @Override\r
1498 @Override\r
1499 public void removeSelectionChangedListener(ISelectionChangedListener listener) {\r
1500 if (listener != null) {\r
1501 _selectionChangedListeners.remove(listener);\r
1502 }\r
1503 }\r
1504\r
1505 // @Override\r
1506 @Override\r
1507 public void setSelection(ISelection selection) {\r
1508 if (selection instanceof TimeGraphSelection) {\r
1509 TimeGraphSelection sel = (TimeGraphSelection) selection;\r
1510 Object ob = sel.getFirstElement();\r
1511 if (ob instanceof ITimeGraphEntry) {\r
1512 ITimeGraphEntry trace = (ITimeGraphEntry) ob;\r
1513 selectItem(trace, false);\r
1514 }\r
1515 }\r
1516\r
1517 }\r
1518\r
1519}\r
1520\r
1521class ItemData {\r
1522 public TimeGraphItem[] _expandedItems = new TimeGraphItem[0];\r
1523 public TimeGraphItem[] _items = new TimeGraphItem[0];\r
1524 private ITimeGraphEntry _traces[] = new ITimeGraphEntry[0];\r
1525 private boolean traceFilter[] = new boolean[0];\r
1526 private Vector<ITimeGraphEntry> filteredOut = new Vector<ITimeGraphEntry>();\r
b83af2c3 1527 public ITimeGraphPresentationProvider provider;\r
fb5cad3d
PT
1528\r
1529 public ItemData() {\r
1530 }\r
1531\r
1532 TimeGraphItem findItem(ITimeGraphEntry entry) {\r
1533 if (entry == null)\r
1534 return null;\r
1535\r
1536 for (int i = 0; i < _items.length; i++) {\r
1537 TimeGraphItem item = _items[i];\r
1538 if (item._trace == entry) {\r
1539 return item;\r
1540 }\r
1541 }\r
1542\r
1543 return null;\r
1544 }\r
1545\r
1546 int findItemIndex(ITimeGraphEntry trace) {\r
1547 if (trace == null)\r
1548 return -1;\r
1549\r
1550 for (int i = 0; i < _expandedItems.length; i++) {\r
1551 TimeGraphItem item = _expandedItems[i];\r
1552 if (item._trace == trace) {\r
1553 return i;\r
1554 }\r
1555 }\r
1556\r
1557 return -1;\r
1558 }\r
1559\r
1560 public void refreshData() {\r
1561 List<TimeGraphItem> itemList = new ArrayList<TimeGraphItem>();\r
1562 filteredOut.clear();\r
1563 for (int i = 0; i < _traces.length; i++) {\r
1564 ITimeGraphEntry entry = _traces[i];\r
1565 refreshData(itemList, null, 0, entry);\r
1566 }\r
1567 _items = itemList.toArray(new TimeGraphItem[0]);\r
1568 updateExpandedItems();\r
1569 }\r
1570\r
1571 private void refreshData(List<TimeGraphItem> itemList, TimeGraphItem parent, int level, ITimeGraphEntry entry) {\r
1572 TimeGraphItem item = new TimeGraphItem(entry, entry.getName(), level);\r
1573 if (parent != null) {\r
1574 parent.children.add(item);\r
1575 }\r
b83af2c3 1576 item.itemHeight = provider.getItemHeight(entry);\r
fb5cad3d
PT
1577 itemList.add(item);\r
1578 if (entry.hasChildren()) {\r
1579 item._expanded = true;\r
1580 item._hasChildren = true;\r
1581 for (ITimeGraphEntry child : entry.getChildren()) {\r
1582 refreshData(itemList, item, level + 1, child);\r
1583 }\r
1584 }\r
1585 }\r
1586\r
1587 public void updateExpandedItems() {\r
1588 List<TimeGraphItem> expandedItemList = new ArrayList<TimeGraphItem>();\r
1589 for (int i = 0; i < _traces.length; i++) {\r
1590 ITimeGraphEntry entry = _traces[i];\r
1591 TimeGraphItem item = findItem(entry);\r
1592 refreshExpanded(expandedItemList, item);\r
1593 }\r
1594 _expandedItems = expandedItemList.toArray(new TimeGraphItem[0]);\r
1595 }\r
1596\r
1597 private void refreshExpanded(List<TimeGraphItem> expandedItemList, TimeGraphItem item) {\r
1598 expandedItemList.add(item);\r
1599 if (item._hasChildren && item._expanded) {\r
1600 for (TimeGraphItem child : item.children) {\r
1601 refreshExpanded(expandedItemList, child);\r
1602 }\r
1603 }\r
1604 }\r
1605\r
1606 public void expandItem(int idx) {\r
1607 if (idx < 0 || idx >= _expandedItems.length)\r
1608 return;\r
1609 TimeGraphItem item = (TimeGraphItem) _expandedItems[idx];\r
1610 if (item._hasChildren && !item._expanded) {\r
1611 item._expanded = true;\r
1612 updateExpandedItems();\r
1613 }\r
1614 }\r
1615\r
1616 public void refreshData(ITimeGraphEntry traces[]) {\r
1617 if (traces == null || traces.length == 0) {\r
1618 traceFilter = null;\r
1619 } else if (traceFilter == null || traces.length != traceFilter.length) {\r
1620 traceFilter = new boolean[traces.length];\r
1621 java.util.Arrays.fill(traceFilter, true);\r
1622 }\r
1623\r
1624 _traces = traces;\r
1625 refreshData();\r
1626 }\r
1627\r
b83af2c3 1628 public ITimeGraphEntry[] getTraces() {\r
fb5cad3d
PT
1629 return _traces;\r
1630 }\r
1631\r
1632 public boolean[] getTraceFilter() {\r
1633 return traceFilter;\r
1634 }\r
1635\r
1636 public Vector<ITimeGraphEntry> getFilteredOut() {\r
1637 return filteredOut;\r
1638 }\r
1639}\r
This page took 0.099781 seconds and 5 git commands to generate.