Add support for selected event in Properties view.
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.ui / src / org / eclipse / linuxtools / tmf / ui / views / histogram / Histogram.java
CommitLineData
c392540b 1/*******************************************************************************
e0752744 2 * Copyright (c) 2011, 2012 Ericsson
20ff3b75 3 *
c392540b
FC
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
20ff3b75 8 *
c392540b
FC
9 * Contributors:
10 * Francois Chouinard - Initial API and implementation
fbd124dd 11 * Bernd Hufmann - Changed to updated histogram data model
e0752744 12 * Francois Chouinard - Initial API and implementation
c392540b
FC
13 *******************************************************************************/
14
e0752744 15package org.eclipse.linuxtools.tmf.ui.views.histogram;
c392540b
FC
16
17import org.eclipse.linuxtools.tmf.ui.views.TmfView;
18import org.eclipse.swt.SWT;
19import org.eclipse.swt.events.ControlEvent;
20import org.eclipse.swt.events.ControlListener;
21import org.eclipse.swt.events.KeyEvent;
22import org.eclipse.swt.events.KeyListener;
23import org.eclipse.swt.events.MouseEvent;
24import org.eclipse.swt.events.MouseListener;
25import org.eclipse.swt.events.MouseTrackListener;
26import org.eclipse.swt.events.PaintEvent;
27import org.eclipse.swt.events.PaintListener;
28import org.eclipse.swt.graphics.Color;
29import org.eclipse.swt.graphics.Font;
30import org.eclipse.swt.graphics.FontData;
31import org.eclipse.swt.graphics.GC;
32import org.eclipse.swt.graphics.Image;
e60df94a 33import org.eclipse.swt.layout.FillLayout;
c392540b
FC
34import org.eclipse.swt.layout.GridData;
35import org.eclipse.swt.layout.GridLayout;
36import org.eclipse.swt.widgets.Canvas;
37import org.eclipse.swt.widgets.Composite;
38import org.eclipse.swt.widgets.Display;
39import org.eclipse.swt.widgets.Text;
40
41/**
b544077e 42 * Re-usable histogram widget.
20ff3b75 43 *
b544077e 44 * It has the following features:
c392540b
FC
45 * <ul>
46 * <li>Y-axis labels displaying min/max count values
47 * <li>X-axis labels displaying time range
48 * <li>a histogram displaying the distribution of values over time (note that
49 * the histogram might not necessarily fill the whole canvas)
50 * </ul>
51 * The widget also has 2 'markers' to identify:
52 * <ul>
53 * <li>a red dashed line over the bar that contains the currently selected event
54 * <li>a dark red dashed line that delimits the right end of the histogram (if
55 * it doesn't fill the canvas)
56 * </ul>
57 * Clicking on the histogram will select the current event at the mouse
58 * location.
59 * <p>
60 * Once the histogram is selected, there is some limited keyboard support:
61 * <ul>
62 * <li>Home: go to the first histogram bar
63 * <li>End: go to the last histogram bar
64 * <li>Left: go to the previous histogram
65 * <li>Right: go to the next histogram bar
66 * </ul>
67 * Finally, when the mouse hovers over the histogram, a tool tip showing the
68 * following information about the corresponding histogram bar time range:
69 * <ul>
70 * <li>start of the time range
71 * <li>end of the time range
72 * <li>number of events in that time range
73 * </ul>
20ff3b75 74 *
b544077e
BH
75 * @version 1.0
76 * @author Francois Chouinard
c392540b 77 */
fbd124dd 78public abstract class Histogram implements ControlListener, PaintListener, KeyListener, MouseListener, MouseTrackListener, IHistogramModelListener {
c392540b
FC
79
80 // ------------------------------------------------------------------------
81 // Constants
82 // ------------------------------------------------------------------------
83
c392540b
FC
84 // Histogram colors
85 private final Color fBackgroundColor = Display.getCurrent().getSystemColor(SWT.COLOR_WHITE);
86 private final Color fCurrentEventColor = Display.getCurrent().getSystemColor(SWT.COLOR_RED);
87 private final Color fLastEventColor = Display.getCurrent().getSystemColor(SWT.COLOR_DARK_RED);
88 private final Color fHistoBarColor = new Color(Display.getDefault(), 74, 112, 139);
89
90 // Timestamp scale (nanosecond)
b544077e
BH
91 /**
92 * The time scale of the histogram (nano seconds)
93 */
c392540b 94 public static final byte TIME_SCALE = -9;
09e86496 95
b544077e
BH
96 /**
97 * The histogram bar width (number of pixels).
98 */
fbd124dd 99 public static final int HISTOGRAM_BAR_WIDTH = 1;
c392540b
FC
100
101 // ------------------------------------------------------------------------
102 // Attributes
103 // ------------------------------------------------------------------------
104
105 // Owner view
b544077e
BH
106 /**
107 * The parent TMF view.
108 */
c392540b
FC
109 protected TmfView fParentView;
110
111 // Histogram text fields
112 private Text fMaxNbEventsText;
113 private Text fMinNbEventsText;
114 private Text fTimeRangeStartText;
115 private Text fTimeRangeEndText;
116
b544077e
BH
117 /**
118 * Histogram drawing area
119 */
c392540b 120 protected Canvas fCanvas;
b544077e
BH
121 /**
122 * The histogram data model.
123 */
c392540b 124 protected final HistogramDataModel fDataModel;
b544077e 125 /**
20ff3b75 126 * The histogram data model scaled to current resolution and screen width.
b544077e 127 */
c392540b
FC
128 protected HistogramScaledData fScaledData;
129
130 protected long fCurrentEventTime = 0;
131
132 // ------------------------------------------------------------------------
133 // Construction
134 // ------------------------------------------------------------------------
135
b544077e
BH
136 /**
137 * Standard constructor.
20ff3b75 138 *
b544077e
BH
139 * @param view A reference to the parent TMF view.
140 * @param parent A parent composite
141 */
09e86496 142 public Histogram(final TmfView view, final Composite parent) {
c392540b
FC
143 fParentView = view;
144
145 createWidget(parent);
146 fDataModel = new HistogramDataModel();
fbd124dd 147 fDataModel.addHistogramListener(this);
c392540b
FC
148 clear();
149
150 fCanvas.addControlListener(this);
151 fCanvas.addPaintListener(this);
152 fCanvas.addKeyListener(this);
153 fCanvas.addMouseListener(this);
154 fCanvas.addMouseTrackListener(this);
155 }
156
b544077e
BH
157 /**
158 * Dispose resources and deregisters listeners.
159 */
c392540b
FC
160 public void dispose() {
161 fHistoBarColor.dispose();
fbd124dd 162 fDataModel.removeHistogramListener(this);
c392540b
FC
163 }
164
09e86496 165 private void createWidget(final Composite parent) {
c392540b 166
0301dc43 167 final Color labelColor = parent.getBackground();
c392540b
FC
168 final Font fFont = adjustFont(parent);
169
170 final int initalWidth = 10;
171
172 // --------------------------------------------------------------------
173 // Define the histogram
174 // --------------------------------------------------------------------
175
09e86496 176 final GridLayout gridLayout = new GridLayout();
c392540b
FC
177 gridLayout.numColumns = 3;
178 gridLayout.marginHeight = 0;
179 gridLayout.marginWidth = 0;
180 gridLayout.marginTop = 0;
181 gridLayout.horizontalSpacing = 0;
182 gridLayout.verticalSpacing = 0;
183 gridLayout.marginLeft = 0;
184 gridLayout.marginRight = 0;
09e86496 185 final Composite composite = new Composite(parent, SWT.FILL);
c392540b
FC
186 composite.setLayout(gridLayout);
187
188 // Use all the horizontal space
189 GridData gridData = new GridData();
190 gridData.horizontalAlignment = SWT.FILL;
191 gridData.verticalAlignment = SWT.FILL;
192 gridData.grabExcessHorizontalSpace = true;
193 composite.setLayoutData(gridData);
194
195 // Y-axis max event
196 gridData = new GridData();
197 gridData.horizontalAlignment = SWT.RIGHT;
198 gridData.verticalAlignment = SWT.TOP;
199 fMaxNbEventsText = new Text(composite, SWT.READ_ONLY | SWT.RIGHT);
200 fMaxNbEventsText.setFont(fFont);
201 fMaxNbEventsText.setBackground(labelColor);
202 fMaxNbEventsText.setEditable(false);
203 fMaxNbEventsText.setText("0"); //$NON-NLS-1$
204 fMaxNbEventsText.setLayoutData(gridData);
205
206 // Histogram itself
e60df94a 207 Composite canvasComposite = new Composite(composite, SWT.BORDER);
c392540b
FC
208 gridData = new GridData();
209 gridData.horizontalSpan = 2;
210 gridData.verticalSpan = 2;
211 gridData.horizontalAlignment = SWT.FILL;
212 gridData.verticalAlignment = SWT.FILL;
213 gridData.grabExcessHorizontalSpace = true;
e60df94a
PT
214 canvasComposite.setLayoutData(gridData);
215 canvasComposite.setLayout(new FillLayout());
216 fCanvas = new Canvas(canvasComposite, SWT.DOUBLE_BUFFERED);
c392540b
FC
217
218 // Y-axis min event (always 0...)
219 gridData = new GridData();
220 gridData.horizontalAlignment = SWT.RIGHT;
221 gridData.verticalAlignment = SWT.BOTTOM;
222 fMinNbEventsText = new Text(composite, SWT.READ_ONLY | SWT.RIGHT);
223 fMinNbEventsText.setFont(fFont);
224 fMinNbEventsText.setBackground(labelColor);
225 fMinNbEventsText.setEditable(false);
226 fMinNbEventsText.setText("0"); //$NON-NLS-1$
227 fMinNbEventsText.setLayoutData(gridData);
228
229 // Dummy cell
230 gridData = new GridData(initalWidth, SWT.DEFAULT);
231 gridData.horizontalAlignment = SWT.RIGHT;
232 gridData.verticalAlignment = SWT.BOTTOM;
09e86496 233 final Text dummyText = new Text(composite, SWT.READ_ONLY);
c392540b
FC
234 dummyText.setFont(fFont);
235 dummyText.setBackground(labelColor);
236 dummyText.setEditable(false);
237 dummyText.setText(""); //$NON-NLS-1$
238 dummyText.setLayoutData(gridData);
239
240 // Window range start time
241 gridData = new GridData();
242 gridData.horizontalAlignment = SWT.LEFT;
243 gridData.verticalAlignment = SWT.BOTTOM;
244 fTimeRangeStartText = new Text(composite, SWT.READ_ONLY);
245 fTimeRangeStartText.setFont(fFont);
246 fTimeRangeStartText.setBackground(labelColor);
247 fTimeRangeStartText.setText(HistogramUtils.nanosecondsToString(0));
248 fTimeRangeStartText.setLayoutData(gridData);
249
250 // Window range end time
251 gridData = new GridData();
252 gridData.horizontalAlignment = SWT.RIGHT;
253 gridData.verticalAlignment = SWT.BOTTOM;
254 fTimeRangeEndText = new Text(composite, SWT.READ_ONLY);
255 fTimeRangeEndText.setFont(fFont);
256 fTimeRangeEndText.setBackground(labelColor);
257 fTimeRangeEndText.setText(HistogramUtils.nanosecondsToString(0));
258 fTimeRangeEndText.setLayoutData(gridData);
259 }
260
abbdd66a 261 private static Font adjustFont(final Composite composite) {
c392540b 262 // Reduce font size for a more pleasing rendering
09e86496
FC
263 final int fontSizeAdjustment = -2;
264 final Font font = composite.getFont();
265 final FontData fontData = font.getFontData()[0];
c392540b
FC
266 return new Font(font.getDevice(), fontData.getName(), fontData.getHeight() + fontSizeAdjustment, fontData.getStyle());
267 }
268
269 // ------------------------------------------------------------------------
270 // Accessors
271 // ------------------------------------------------------------------------
272
b544077e
BH
273 /**
274 * Returns the start time (equal first bucket time).
275 * @return the start time.
276 */
c392540b 277 public long getStartTime() {
fbd124dd 278 return fDataModel.getFirstBucketTime();
c392540b
FC
279 }
280
b544077e
BH
281 /**
282 * Returns the end time.
283 * @return the end time.
284 */
c392540b
FC
285 public long getEndTime() {
286 return fDataModel.getEndTime();
287 }
288
b544077e
BH
289 /**
290 * Returns the time limit (end of last bucket)
291 * @return the time limit.
292 */
c392540b
FC
293 public long getTimeLimit() {
294 return fDataModel.getTimeLimit();
295 }
09e86496 296
20ff3b75
AM
297 /**
298 * Returns a data model reference.
b544077e
BH
299 * @return data model.
300 */
fbd124dd
BH
301 public HistogramDataModel getDataModel() {
302 return fDataModel;
303 }
c392540b
FC
304
305 // ------------------------------------------------------------------------
306 // Operations
307 // ------------------------------------------------------------------------
b544077e 308 /**
20ff3b75 309 * Updates the time range.
b544077e
BH
310 * @param startTime A start time
311 * @param endTime A end time.
312 */
c392540b
FC
313 public abstract void updateTimeRange(long startTime, long endTime);
314
315 /**
316 * Clear the histogram and reset the data
317 */
318 public void clear() {
319 fDataModel.clear();
320 fScaledData = null;
c392540b
FC
321 }
322
323 /**
324 * Increase the histogram bucket corresponding to [timestamp]
20ff3b75
AM
325 *
326 * @param eventCount
327 * The new event count
c392540b 328 * @param timestamp
20ff3b75 329 * The latest timestamp
c392540b 330 */
09e86496 331 public void countEvent(final long eventCount, final long timestamp) {
fbd124dd 332 fDataModel.countEvent(eventCount, timestamp);
c392540b
FC
333 }
334
335 /**
336 * Sets the current event time and refresh the display
20ff3b75 337 *
c392540b 338 * @param timestamp
20ff3b75 339 * The time of the current event
c392540b 340 */
09e86496 341 public void setCurrentEvent(final long timestamp) {
74237cc3 342 fCurrentEventTime = (timestamp > 0) ? timestamp : 0;
fbd124dd 343 fDataModel.setCurrentEventNotifyListeners(timestamp);
c392540b
FC
344 }
345
346 /**
347 * Computes the timestamp of the bucket at [offset]
20ff3b75 348 *
c392540b
FC
349 * @param offset offset from the left on the histogram
350 * @return the start timestamp of the corresponding bucket
351 */
09e86496 352 public synchronized long getTimestamp(final int offset) {
c392540b
FC
353 assert offset > 0 && offset < fScaledData.fWidth;
354 try {
fbd124dd 355 return fDataModel.getFirstBucketTime() + fScaledData.fBucketDuration * offset;
09e86496 356 } catch (final Exception e) {
c392540b
FC
357 return 0; // TODO: Fix that racing condition (NPE)
358 }
359 }
360
361 /**
362 * Computes the offset of the timestamp in the histogram
20ff3b75 363 *
c392540b
FC
364 * @param timestamp the timestamp
365 * @return the offset of the corresponding bucket (-1 if invalid)
366 */
09e86496 367 public synchronized int getOffset(final long timestamp) {
20ff3b75 368 if (timestamp < fDataModel.getFirstBucketTime() || timestamp > fDataModel.getEndTime()) {
c392540b 369 return -1;
20ff3b75 370 }
fbd124dd 371 return (int) ((timestamp - fDataModel.getFirstBucketTime()) / fScaledData.fBucketDuration);
c392540b
FC
372 }
373
374 /**
375 * Move the currently selected bar cursor to a non-empty bucket.
20ff3b75 376 *
c392540b
FC
377 * @param keyCode the SWT key code
378 */
09e86496 379 protected void moveCursor(final int keyCode) {
c392540b 380
20ff3b75 381 if (fScaledData.fCurrentBucket == HistogramScaledData.OUT_OF_RANGE_BUCKET) {
c392540b 382 return;
20ff3b75 383 }
c392540b
FC
384
385 int index;
386 switch (keyCode) {
387
388 case SWT.HOME:
389 index = 0;
20ff3b75 390 while (index < fScaledData.fLastBucket && fScaledData.fData[index] == 0) {
c392540b 391 index++;
20ff3b75
AM
392 }
393 if (index < fScaledData.fLastBucket) {
c392540b 394 fScaledData.fCurrentBucket = index;
20ff3b75 395 }
c392540b
FC
396 break;
397
398 case SWT.ARROW_RIGHT:
399 index = fScaledData.fCurrentBucket + 1;
20ff3b75 400 while (index < fScaledData.fWidth && fScaledData.fData[index] == 0) {
c392540b 401 index++;
20ff3b75
AM
402 }
403 if (index < fScaledData.fLastBucket) {
c392540b 404 fScaledData.fCurrentBucket = index;
20ff3b75 405 }
c392540b
FC
406 break;
407
408 case SWT.END:
409 index = fScaledData.fLastBucket;
20ff3b75 410 while (index >= 0 && fScaledData.fData[index] == 0) {
c392540b 411 index--;
20ff3b75
AM
412 }
413 if (index >= 0) {
c392540b 414 fScaledData.fCurrentBucket = index;
20ff3b75 415 }
c392540b
FC
416 break;
417
418 case SWT.ARROW_LEFT:
419 index = fScaledData.fCurrentBucket - 1;
20ff3b75 420 while (index >= 0 && fScaledData.fData[index] == 0) {
c392540b 421 index--;
20ff3b75
AM
422 }
423 if (index >= 0) {
c392540b 424 fScaledData.fCurrentBucket = index;
20ff3b75 425 }
c392540b
FC
426 break;
427
428 default:
429 return;
430 }
431
432 updateCurrentEventTime();
433 }
434
435 /**
436 * Refresh the histogram display
437 */
fbd124dd
BH
438 @Override
439 public void modelUpdated() {
20ff3b75 440 if (!fCanvas.isDisposed() && fCanvas.getDisplay() != null) {
c392540b
FC
441 fCanvas.getDisplay().asyncExec(new Runnable() {
442 @Override
443 public void run() {
444 if (!fCanvas.isDisposed()) {
445 // Retrieve and normalize the data
09e86496
FC
446 final int canvasWidth = fCanvas.getBounds().width;
447 final int canvasHeight = fCanvas.getBounds().height;
20ff3b75 448 if (canvasWidth <= 0 || canvasHeight <= 0) {
40890fec 449 return;
20ff3b75 450 }
c392540b 451 fDataModel.setCurrentEvent(fCurrentEventTime);
fbd124dd 452 fScaledData = fDataModel.scaleTo(canvasWidth, canvasHeight, HISTOGRAM_BAR_WIDTH);
0316808c
FC
453 synchronized(fScaledData) {
454 if (fScaledData != null) {
455 fCanvas.redraw();
456 // Display histogram and update X-,Y-axis labels
457 fTimeRangeStartText.setText(HistogramUtils.nanosecondsToString(fDataModel.getFirstBucketTime()));
458 fTimeRangeEndText.setText(HistogramUtils.nanosecondsToString(fDataModel.getEndTime()));
459 fMaxNbEventsText.setText(Long.toString(fScaledData.fMaxValue));
460 // The Y-axis area might need to be re-sized
461 fMaxNbEventsText.getParent().layout();
462 }
09e86496 463 }
c392540b
FC
464 }
465 }
466 });
20ff3b75 467 }
c392540b
FC
468 }
469
470 // ------------------------------------------------------------------------
471 // Helper functions
472 // ------------------------------------------------------------------------
473
474 private void updateCurrentEventTime() {
09e86496 475 final long bucketStartTime = getTimestamp(fScaledData.fCurrentBucket);
c392540b
FC
476 ((HistogramView) fParentView).updateCurrentEventTime(bucketStartTime);
477 }
478
479 // ------------------------------------------------------------------------
480 // PaintListener
481 // ------------------------------------------------------------------------
b544077e
BH
482 /**
483 * Image key string for the canvas.
484 */
c392540b
FC
485 protected final String IMAGE_KEY = "double-buffer-image"; //$NON-NLS-1$
486
487 @Override
09e86496 488 public void paintControl(final PaintEvent event) {
c392540b
FC
489
490 // Get the geometry
09e86496
FC
491 final int canvasWidth = fCanvas.getBounds().width;
492 final int canvasHeight = fCanvas.getBounds().height;
c392540b
FC
493
494 // Make sure we have something to draw upon
20ff3b75 495 if (canvasWidth <= 0 || canvasHeight <= 0) {
c392540b 496 return;
20ff3b75 497 }
c392540b
FC
498
499 // Retrieve image; re-create only if necessary
500 Image image = (Image) fCanvas.getData(IMAGE_KEY);
501 if (image == null || image.getBounds().width != canvasWidth || image.getBounds().height != canvasHeight) {
502 image = new Image(event.display, canvasWidth, canvasHeight);
503 fCanvas.setData(IMAGE_KEY, image);
504 }
505
506 // Draw the histogram on its canvas
09e86496 507 final GC imageGC = new GC(image);
c392540b
FC
508 formatImage(imageGC, image);
509 event.gc.drawImage(image, 0, 0);
510 imageGC.dispose();
511 }
512
09e86496 513 private void formatImage(final GC imageGC, final Image image) {
c392540b 514
20ff3b75 515 if (fScaledData == null) {
c392540b 516 return;
20ff3b75 517 }
c392540b 518
09e86496 519 final HistogramScaledData scaledData = new HistogramScaledData(fScaledData);
c392540b
FC
520
521 try {
522 // Get drawing boundaries
09e86496
FC
523 final int width = image.getBounds().width;
524 final int height = image.getBounds().height;
c392540b
FC
525
526 // Clear the drawing area
527 imageGC.setBackground(fBackgroundColor);
528 imageGC.fillRectangle(0, 0, image.getBounds().width + 1, image.getBounds().height + 1);
529
530 // Draw the histogram bars
531 imageGC.setBackground(fHistoBarColor);
09e86496 532 final int limit = width < scaledData.fWidth ? width : scaledData.fWidth;
c392540b 533 for (int i = 1; i < limit; i++) {
e60df94a 534 final int value = (int) Math.ceil(scaledData.fData[i] * scaledData.fScalingFactor);
c392540b
FC
535 imageGC.fillRectangle(i, height - value, 1, value);
536 }
537
538 // Draw the current event bar
09e86496 539 final int currentBucket = scaledData.fCurrentBucket;
20ff3b75 540 if (currentBucket >= 0 && currentBucket < limit) {
c392540b 541 drawDelimiter(imageGC, fCurrentEventColor, height, currentBucket);
20ff3b75 542 }
c392540b
FC
543
544 // Add a dashed line as a delimiter (at the right of the last bar)
545 int lastEventIndex = limit - 1;
20ff3b75 546 while (lastEventIndex >= 0 && scaledData.fData[lastEventIndex] == 0) {
c392540b 547 lastEventIndex--;
20ff3b75 548 }
c392540b
FC
549 lastEventIndex += (lastEventIndex < limit - 1) ? 1 : 0;
550 drawDelimiter(imageGC, fLastEventColor, height, lastEventIndex);
09e86496 551 } catch (final Exception e) {
c392540b
FC
552 // Do nothing
553 }
554 }
555
abbdd66a
AM
556 private static void drawDelimiter(final GC imageGC, final Color color,
557 final int height, final int index) {
c392540b 558 imageGC.setBackground(color);
09e86496 559 final int dash = height / 4;
c392540b
FC
560 imageGC.fillRectangle(index, 0 * dash, 1, dash - 1);
561 imageGC.fillRectangle(index, 1 * dash, 1, dash - 1);
562 imageGC.fillRectangle(index, 2 * dash, 1, dash - 1);
563 imageGC.fillRectangle(index, 3 * dash, 1, height - 3 * dash);
564 }
565
566 // ------------------------------------------------------------------------
567 // KeyListener
568 // ------------------------------------------------------------------------
569
570 @Override
09e86496 571 public void keyPressed(final KeyEvent event) {
c392540b
FC
572 moveCursor(event.keyCode);
573 }
574
575 @Override
09e86496 576 public void keyReleased(final KeyEvent event) {
c392540b
FC
577 }
578
579 // ------------------------------------------------------------------------
580 // MouseListener
581 // ------------------------------------------------------------------------
582
583 @Override
09e86496 584 public void mouseDoubleClick(final MouseEvent event) {
c392540b
FC
585 }
586
587 @Override
09e86496 588 public void mouseDown(final MouseEvent event) {
c392540b
FC
589 if (fDataModel.getNbEvents() > 0 && fScaledData.fLastBucket >= event.x) {
590 fScaledData.fCurrentBucket = event.x;
591 updateCurrentEventTime();
592 }
593 }
594
595 @Override
09e86496 596 public void mouseUp(final MouseEvent event) {
c392540b
FC
597 }
598
599 // ------------------------------------------------------------------------
600 // MouseTrackListener
601 // ------------------------------------------------------------------------
602
603 @Override
09e86496 604 public void mouseEnter(final MouseEvent event) {
c392540b
FC
605 }
606
607 @Override
09e86496 608 public void mouseExit(final MouseEvent event) {
c392540b
FC
609 }
610
611 @Override
09e86496 612 public void mouseHover(final MouseEvent event) {
74237cc3 613 if (fDataModel.getNbEvents() > 0 && fScaledData != null && fScaledData.fLastBucket >= event.x) {
09e86496 614 final String tooltip = formatToolTipLabel(event.x);
c392540b
FC
615 fCanvas.setToolTipText(tooltip);
616 }
617 }
618
09e86496 619 private String formatToolTipLabel(final int index) {
466857f6 620 long startTime = fScaledData.getBucketStartTime(index);
09e86496 621 // negative values are possible if time values came into the model in decreasing order
20ff3b75 622 if (startTime < 0) {
fbd124dd 623 startTime = 0;
20ff3b75 624 }
466857f6 625 final long endTime = fScaledData.getBucketEndTime(index);
09e86496 626 final int nbEvents = (index >= 0) ? fScaledData.fData[index] : 0;
c392540b 627
09e86496 628 final StringBuffer buffer = new StringBuffer();
c392540b
FC
629 buffer.append("Range = ["); //$NON-NLS-1$
630 buffer.append(HistogramUtils.nanosecondsToString(startTime));
631 buffer.append(","); //$NON-NLS-1$
632 buffer.append(HistogramUtils.nanosecondsToString(endTime));
633 buffer.append(")\n"); //$NON-NLS-1$
634 buffer.append("Event count = "); //$NON-NLS-1$
635 buffer.append(nbEvents);
636 return buffer.toString();
637 }
638
639 // ------------------------------------------------------------------------
640 // ControlListener
641 // ------------------------------------------------------------------------
642
643 @Override
09e86496 644 public void controlMoved(final ControlEvent event) {
fbd124dd 645 fDataModel.complete();
c392540b
FC
646 }
647
648 @Override
09e86496 649 public void controlResized(final ControlEvent event) {
fbd124dd 650 fDataModel.complete();
c392540b 651 }
c392540b 652}
This page took 0.064521 seconds and 5 git commands to generate.