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