~ubuntu-branches/ubuntu/utopic/eclipse-linuxtools/utopic

« back to all changes in this revision

Viewing changes to lttng/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/views/histogram/Histogram.java

  • Committer: Package Import Robot
  • Author(s): Jakub Adam
  • Date: 2014-05-12 18:11:40 UTC
  • mfrom: (3.1.2 sid)
  • Revision ID: package-import@ubuntu.com-20140512181140-w237r3vsah1tmybz
Tags: 2.2.1-1
* New upstream release.
* Refreshed d/patches.
* Removed eclipse-cdt-valgrind-remote package, all its functionality
  is now provided by eclipse-cdt-profiling-framework-remote.
* Added remove-license-feature.patch.
* Bump Standards-Version to 3.9.5.
* Enable eclipse-changelog package.
* Enable eclipse-rpm-editor package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*******************************************************************************
2
 
 * Copyright (c) 2011, 2012 Ericsson
 
2
 * Copyright (c) 2011, 2013 Ericsson
3
3
 *
4
4
 * All rights reserved. This program and the accompanying materials are
5
5
 * made available under the terms of the Eclipse Public License v1.0 which
9
9
 * Contributors:
10
10
 *   Francois Chouinard - Initial API and implementation
11
11
 *   Bernd Hufmann - Changed to updated histogram data model
12
 
 *   Francois Chouinard - Initial API and implementation
 
12
 *   Francois Chouinard - Reformat histogram labels on format change
 
13
 *   Patrick Tasse - Support selection range
13
14
 *******************************************************************************/
14
15
 
15
16
package org.eclipse.linuxtools.tmf.ui.views.histogram;
16
17
 
 
18
import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler;
 
19
import org.eclipse.linuxtools.tmf.core.signal.TmfSignalManager;
 
20
import org.eclipse.linuxtools.tmf.core.signal.TmfTimestampFormatUpdateSignal;
 
21
import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp;
 
22
import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
 
23
import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestampDelta;
 
24
import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestampFormat;
17
25
import org.eclipse.linuxtools.tmf.ui.views.TmfView;
 
26
import org.eclipse.osgi.util.NLS;
18
27
import org.eclipse.swt.SWT;
19
28
import org.eclipse.swt.events.ControlEvent;
20
29
import org.eclipse.swt.events.ControlListener;
 
30
import org.eclipse.swt.events.FocusAdapter;
 
31
import org.eclipse.swt.events.FocusEvent;
 
32
import org.eclipse.swt.events.FocusListener;
21
33
import org.eclipse.swt.events.KeyEvent;
22
34
import org.eclipse.swt.events.KeyListener;
23
35
import org.eclipse.swt.events.MouseEvent;
24
36
import org.eclipse.swt.events.MouseListener;
 
37
import org.eclipse.swt.events.MouseMoveListener;
25
38
import org.eclipse.swt.events.MouseTrackListener;
 
39
import org.eclipse.swt.events.MouseWheelListener;
26
40
import org.eclipse.swt.events.PaintEvent;
27
41
import org.eclipse.swt.events.PaintListener;
28
42
import org.eclipse.swt.graphics.Color;
36
50
import org.eclipse.swt.widgets.Canvas;
37
51
import org.eclipse.swt.widgets.Composite;
38
52
import org.eclipse.swt.widgets.Display;
 
53
import org.eclipse.swt.widgets.Label;
39
54
import org.eclipse.swt.widgets.Text;
40
55
 
41
56
/**
72
87
 * <li>number of events in that time range
73
88
 * </ul>
74
89
 *
75
 
 * @version 1.0
 
90
 * @version 1.1
76
91
 * @author Francois Chouinard
77
92
 */
78
 
public abstract class Histogram implements ControlListener, PaintListener, KeyListener, MouseListener, MouseTrackListener, IHistogramModelListener {
 
93
public abstract class Histogram implements ControlListener, PaintListener, KeyListener, MouseListener, MouseMoveListener, MouseTrackListener, IHistogramModelListener {
79
94
 
80
95
    // ------------------------------------------------------------------------
81
96
    // Constants
83
98
 
84
99
    // Histogram colors
85
100
    private final Color fBackgroundColor = Display.getCurrent().getSystemColor(SWT.COLOR_WHITE);
86
 
    private final Color fCurrentEventColor = Display.getCurrent().getSystemColor(SWT.COLOR_RED);
 
101
    private final Color fSelectionForegroundColor = Display.getCurrent().getSystemColor(SWT.COLOR_BLUE);
 
102
    private final Color fSelectionBackgroundColor = Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
87
103
    private final Color fLastEventColor = Display.getCurrent().getSystemColor(SWT.COLOR_DARK_RED);
88
104
    private final Color fHistoBarColor = new Color(Display.getDefault(), 74, 112, 139);
89
 
 
90
 
    // Timestamp scale (nanosecond)
91
 
    /**
92
 
     * The time scale of the histogram (nano seconds)
93
 
     */
94
 
    public static final byte TIME_SCALE = -9;
95
 
 
96
 
    /**
97
 
     * The histogram bar width (number of pixels).
98
 
     */
99
 
    public static final int HISTOGRAM_BAR_WIDTH = 1;
 
105
    private final Color fLostEventColor = new Color(Display.getCurrent(), 208, 62, 120);
 
106
    private final Color fFillColor = Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
 
107
    private final Color fTimeRangeColor = new Color(Display.getCurrent(), 255, 128, 0);
 
108
 
 
109
    // Drag states
 
110
    /**
 
111
     * No drag in progress
 
112
     * @since 2.2
 
113
     */
 
114
    protected final int DRAG_NONE = 0;
 
115
    /**
 
116
     * Drag the selection
 
117
     * @since 2.2
 
118
     */
 
119
    protected final int DRAG_SELECTION = 1;
 
120
    /**
 
121
     * Drag the time range
 
122
     * @since 2.2
 
123
     */
 
124
    protected final int DRAG_RANGE = 2;
 
125
    /**
 
126
     * Drag the zoom range
 
127
     * @since 2.2
 
128
     */
 
129
    protected final int DRAG_ZOOM = 3;
100
130
 
101
131
    // ------------------------------------------------------------------------
102
132
    // Attributes
103
133
    // ------------------------------------------------------------------------
104
134
 
105
 
    // Owner view
106
135
    /**
107
136
     * The parent TMF view.
108
137
     */
109
138
    protected TmfView fParentView;
110
139
 
 
140
    private Composite fComposite;
 
141
    private Font fFont;
 
142
 
111
143
    // Histogram text fields
112
144
    private Text fMaxNbEventsText;
113
145
    private Text fMinNbEventsText;
115
147
    private Text fTimeRangeEndText;
116
148
 
117
149
    /**
118
 
     *  Histogram drawing area
 
150
     * Histogram drawing area
119
151
     */
120
152
    protected Canvas fCanvas;
 
153
 
121
154
    /**
122
 
     *  The histogram data model.
 
155
     * The histogram data model.
123
156
     */
124
157
    protected final HistogramDataModel fDataModel;
 
158
 
125
159
    /**
126
160
     * The histogram data model scaled to current resolution and screen width.
127
161
     */
128
162
    protected HistogramScaledData fScaledData;
129
163
 
130
 
    protected long fCurrentEventTime = 0;
 
164
    /**
 
165
     * The current event value
 
166
     */
 
167
    protected long fCurrentEventTime = 0L;
 
168
 
 
169
    /**
 
170
     * The current selection begin time
 
171
     */
 
172
    private long fSelectionBegin = 0L;
 
173
 
 
174
    /**
 
175
     * The current selection end time
 
176
     */
 
177
    private long fSelectionEnd = 0L;
 
178
 
 
179
    /**
 
180
     * The drag state
 
181
     * @see #DRAG_NONE
 
182
     * @see #DRAG_SELECTION
 
183
     * @see #DRAG_RANGE
 
184
     * @see #DRAG_ZOOM
 
185
     * @since 2.2
 
186
     */
 
187
    protected int fDragState = DRAG_NONE;
 
188
 
 
189
    /**
 
190
     * The button that started a mouse drag, or 0 if no drag in progress
 
191
     * @since 2.2
 
192
     */
 
193
    protected int fDragButton = 0;
 
194
 
 
195
    /**
 
196
     * The bucket display offset
 
197
     */
 
198
    private int fOffset = 0;
131
199
 
132
200
    // ------------------------------------------------------------------------
133
201
    // Construction
134
202
    // ------------------------------------------------------------------------
135
203
 
136
204
    /**
137
 
     * Standard constructor.
 
205
     * Full constructor.
138
206
     *
139
207
     * @param view A reference to the parent TMF view.
140
208
     * @param parent A parent composite
142
210
    public Histogram(final TmfView view, final Composite parent) {
143
211
        fParentView = view;
144
212
 
145
 
        createWidget(parent);
 
213
        fComposite = createWidget(parent);
146
214
        fDataModel = new HistogramDataModel();
147
215
        fDataModel.addHistogramListener(this);
148
216
        clear();
152
220
        fCanvas.addKeyListener(this);
153
221
        fCanvas.addMouseListener(this);
154
222
        fCanvas.addMouseTrackListener(this);
 
223
        fCanvas.addMouseMoveListener(this);
 
224
 
 
225
        TmfSignalManager.register(this);
155
226
    }
156
227
 
157
228
    /**
158
 
     * Dispose resources and deregisters listeners.
 
229
     * Dispose resources and unregisters listeners.
159
230
     */
160
231
    public void dispose() {
 
232
        TmfSignalManager.deregister(this);
 
233
 
161
234
        fHistoBarColor.dispose();
 
235
        fLastEventColor.dispose();
 
236
        fTimeRangeColor.dispose();
162
237
        fDataModel.removeHistogramListener(this);
163
238
    }
164
239
 
165
 
    private void createWidget(final Composite parent) {
 
240
    private Composite createWidget(final Composite parent) {
166
241
 
167
242
        final Color labelColor = parent.getBackground();
168
 
        final Font fFont = adjustFont(parent);
 
243
        fFont = adjustFont(parent);
169
244
 
170
245
        final int initalWidth = 10;
171
246
 
190
265
        gridData.horizontalAlignment = SWT.FILL;
191
266
        gridData.verticalAlignment = SWT.FILL;
192
267
        gridData.grabExcessHorizontalSpace = true;
 
268
        gridData.grabExcessVerticalSpace = true;
193
269
        composite.setLayoutData(gridData);
194
270
 
195
271
        // Y-axis max event
210
286
        gridData.verticalSpan = 2;
211
287
        gridData.horizontalAlignment = SWT.FILL;
212
288
        gridData.verticalAlignment = SWT.FILL;
 
289
        gridData.heightHint = 0;
 
290
        gridData.widthHint = 0;
213
291
        gridData.grabExcessHorizontalSpace = true;
 
292
        gridData.grabExcessVerticalSpace = true;
214
293
        canvasComposite.setLayoutData(gridData);
215
294
        canvasComposite.setLayout(new FillLayout());
216
295
        fCanvas = new Canvas(canvasComposite, SWT.DOUBLE_BUFFERED);
230
309
        gridData = new GridData(initalWidth, SWT.DEFAULT);
231
310
        gridData.horizontalAlignment = SWT.RIGHT;
232
311
        gridData.verticalAlignment = SWT.BOTTOM;
233
 
        final Text dummyText = new Text(composite, SWT.READ_ONLY);
234
 
        dummyText.setFont(fFont);
235
 
        dummyText.setBackground(labelColor);
236
 
        dummyText.setEditable(false);
237
 
        dummyText.setText(""); //$NON-NLS-1$
238
 
        dummyText.setLayoutData(gridData);
 
312
        final Label dummyLabel = new Label(composite, SWT.NONE);
 
313
        dummyLabel.setLayoutData(gridData);
239
314
 
240
315
        // Window range start time
241
316
        gridData = new GridData();
244
319
        fTimeRangeStartText = new Text(composite, SWT.READ_ONLY);
245
320
        fTimeRangeStartText.setFont(fFont);
246
321
        fTimeRangeStartText.setBackground(labelColor);
247
 
        fTimeRangeStartText.setText(HistogramUtils.nanosecondsToString(0));
248
322
        fTimeRangeStartText.setLayoutData(gridData);
249
323
 
250
324
        // Window range end time
254
328
        fTimeRangeEndText = new Text(composite, SWT.READ_ONLY);
255
329
        fTimeRangeEndText.setFont(fFont);
256
330
        fTimeRangeEndText.setBackground(labelColor);
257
 
        fTimeRangeEndText.setText(HistogramUtils.nanosecondsToString(0));
258
331
        fTimeRangeEndText.setLayoutData(gridData);
 
332
 
 
333
        FocusListener listener = new FocusAdapter() {
 
334
            @Override
 
335
            public void focusGained(FocusEvent e) {
 
336
                fCanvas.setFocus();
 
337
            }
 
338
        };
 
339
        fMaxNbEventsText.addFocusListener(listener);
 
340
        fMinNbEventsText.addFocusListener(listener);
 
341
        fTimeRangeStartText.addFocusListener(listener);
 
342
        fTimeRangeEndText.addFocusListener(listener);
 
343
 
 
344
        return composite;
259
345
    }
260
346
 
261
347
    private static Font adjustFont(final Composite composite) {
271
357
    // ------------------------------------------------------------------------
272
358
 
273
359
    /**
274
 
     * Returns the start time (equal first bucket time).
 
360
     * Returns the start time (equal first bucket time)
275
361
     * @return the start time.
276
362
     */
277
363
    public long getStartTime() {
302
388
        return fDataModel;
303
389
    }
304
390
 
 
391
    /**
 
392
     * Returns the text control for the maximum of events in one bar
 
393
     *
 
394
     * @return the text control
 
395
     * @since 2.2
 
396
     */
 
397
    public Text getMaxNbEventsText() {
 
398
        return fMaxNbEventsText;
 
399
    }
 
400
 
305
401
    // ------------------------------------------------------------------------
306
402
    // Operations
307
403
    // ------------------------------------------------------------------------
310
406
     * @param startTime A start time
311
407
     * @param endTime A end time.
312
408
     */
313
 
    public abstract void updateTimeRange(long startTime, long endTime);
 
409
    public void updateTimeRange(long startTime, long endTime) {
 
410
        if (fDragState == DRAG_NONE) {
 
411
            ((HistogramView) fParentView).updateTimeRange(startTime, endTime);
 
412
        }
 
413
    }
314
414
 
315
415
    /**
316
416
     * Clear the histogram and reset the data
317
417
     */
318
418
    public void clear() {
319
419
        fDataModel.clear();
320
 
        fScaledData = null;
 
420
        if (fDragState == DRAG_SELECTION) {
 
421
            updateSelectionTime();
 
422
        }
 
423
        fDragState = DRAG_NONE;
 
424
        fDragButton = 0;
 
425
        synchronized (fDataModel) {
 
426
            fScaledData = null;
 
427
        }
321
428
    }
322
429
 
323
430
    /**
324
431
     * Increase the histogram bucket corresponding to [timestamp]
325
432
     *
326
 
     * @param eventCount
327
 
     *            The new event count
328
 
     * @param timestamp
329
 
     *            The latest timestamp
 
433
     * @param eventCount The new event count
 
434
     * @param timestamp The latest timestamp
330
435
     */
331
436
    public void countEvent(final long eventCount, final long timestamp) {
332
437
        fDataModel.countEvent(eventCount, timestamp);
335
440
    /**
336
441
     * Sets the current event time and refresh the display
337
442
     *
338
 
     * @param timestamp
339
 
     *            The time of the current event
 
443
     * @param timestamp The time of the current event
 
444
     * @deprecated As of 2.1, use {@link #setSelection(long, long)}
340
445
     */
 
446
    @Deprecated
341
447
    public void setCurrentEvent(final long timestamp) {
342
 
        fCurrentEventTime = (timestamp > 0) ? timestamp : 0;
343
 
        fDataModel.setCurrentEventNotifyListeners(timestamp);
 
448
        fSelectionBegin = (timestamp > 0) ? timestamp : 0;
 
449
        fSelectionEnd = (timestamp > 0) ? timestamp : 0;
 
450
        fDataModel.setSelectionNotifyListeners(timestamp, timestamp);
 
451
    }
 
452
 
 
453
    /**
 
454
     * Sets the current selection time range and refresh the display
 
455
     *
 
456
     * @param beginTime The begin time of the current selection
 
457
     * @param endTime The end time of the current selection
 
458
     * @since 2.1
 
459
     */
 
460
    public void setSelection(final long beginTime, final long endTime) {
 
461
        fSelectionBegin = (beginTime > 0) ? beginTime : 0;
 
462
        fSelectionEnd = (endTime > 0) ? endTime : 0;
 
463
        fDataModel.setSelectionNotifyListeners(beginTime, endTime);
344
464
    }
345
465
 
346
466
    /**
352
472
    public synchronized long getTimestamp(final int offset) {
353
473
        assert offset > 0 && offset < fScaledData.fWidth;
354
474
        try {
355
 
            return fDataModel.getFirstBucketTime() + fScaledData.fBucketDuration * offset;
 
475
            return fScaledData.fFirstBucketTime + fScaledData.fBucketDuration * offset;
356
476
        } catch (final Exception e) {
357
477
            return 0; // TODO: Fix that racing condition (NPE)
358
478
        }
372
492
    }
373
493
 
374
494
    /**
 
495
     * Set the bucket display offset
 
496
     *
 
497
     * @param offset
 
498
     *            the bucket display offset
 
499
     * @since 2.2
 
500
     */
 
501
    protected void setOffset(final int offset) {
 
502
        fOffset = offset;
 
503
    }
 
504
 
 
505
    /**
375
506
     * Move the currently selected bar cursor to a non-empty bucket.
376
507
     *
377
508
     * @param keyCode the SWT key code
378
509
     */
379
510
    protected void moveCursor(final int keyCode) {
380
511
 
381
 
        if (fScaledData.fCurrentBucket == HistogramScaledData.OUT_OF_RANGE_BUCKET) {
382
 
            return;
383
 
        }
384
 
 
385
512
        int index;
386
513
        switch (keyCode) {
387
514
 
388
 
            case SWT.HOME:
389
 
                index = 0;
390
 
                while (index < fScaledData.fLastBucket && fScaledData.fData[index] == 0) {
391
 
                    index++;
392
 
                }
393
 
                if (index < fScaledData.fLastBucket) {
394
 
                    fScaledData.fCurrentBucket = index;
395
 
                }
396
 
                break;
397
 
 
398
 
            case SWT.ARROW_RIGHT:
399
 
                index = fScaledData.fCurrentBucket + 1;
400
 
                while (index < fScaledData.fWidth && fScaledData.fData[index] == 0) {
401
 
                    index++;
402
 
                }
403
 
                if (index < fScaledData.fLastBucket) {
404
 
                    fScaledData.fCurrentBucket = index;
405
 
                }
406
 
                break;
407
 
 
408
 
            case SWT.END:
409
 
                index = fScaledData.fLastBucket;
410
 
                while (index >= 0 && fScaledData.fData[index] == 0) {
411
 
                    index--;
412
 
                }
413
 
                if (index >= 0) {
414
 
                    fScaledData.fCurrentBucket = index;
415
 
                }
416
 
                break;
417
 
 
418
 
            case SWT.ARROW_LEFT:
419
 
                index = fScaledData.fCurrentBucket - 1;
420
 
                while (index >= 0 && fScaledData.fData[index] == 0) {
421
 
                    index--;
422
 
                }
423
 
                if (index >= 0) {
424
 
                    fScaledData.fCurrentBucket = index;
425
 
                }
426
 
                break;
427
 
 
428
 
            default:
429
 
                return;
 
515
        case SWT.HOME:
 
516
            index = 0;
 
517
            while (index < fScaledData.fLastBucket && fScaledData.fData[index] == 0) {
 
518
                index++;
 
519
            }
 
520
            if (index < fScaledData.fLastBucket) {
 
521
                fScaledData.fSelectionBeginBucket = index;
 
522
            }
 
523
            break;
 
524
 
 
525
        case SWT.ARROW_RIGHT:
 
526
            index = Math.max(0, fScaledData.fSelectionBeginBucket + 1);
 
527
            while (index < fScaledData.fWidth && fScaledData.fData[index] == 0) {
 
528
                index++;
 
529
            }
 
530
            if (index < fScaledData.fLastBucket) {
 
531
                fScaledData.fSelectionBeginBucket = index;
 
532
            }
 
533
            break;
 
534
 
 
535
        case SWT.END:
 
536
            index = fScaledData.fLastBucket;
 
537
            while (index >= 0 && fScaledData.fData[index] == 0) {
 
538
                index--;
 
539
            }
 
540
            if (index >= 0) {
 
541
                fScaledData.fSelectionBeginBucket = index;
 
542
            }
 
543
            break;
 
544
 
 
545
        case SWT.ARROW_LEFT:
 
546
            index = Math.min(fScaledData.fLastBucket - 1, fScaledData.fSelectionBeginBucket - 1);
 
547
            while (index >= 0 && fScaledData.fData[index] == 0) {
 
548
                index--;
 
549
            }
 
550
            if (index >= 0) {
 
551
                fScaledData.fSelectionBeginBucket = index;
 
552
            }
 
553
            break;
 
554
 
 
555
        default:
 
556
            return;
430
557
        }
431
558
 
432
 
        updateCurrentEventTime();
 
559
        fScaledData.fSelectionEndBucket = fScaledData.fSelectionBeginBucket;
 
560
        fSelectionBegin = getTimestamp(fScaledData.fSelectionBeginBucket);
 
561
        fSelectionEnd = fSelectionBegin;
 
562
        updateSelectionTime();
433
563
    }
434
564
 
435
565
    /**
448
578
                        if (canvasWidth <= 0 || canvasHeight <= 0) {
449
579
                            return;
450
580
                        }
451
 
                        fDataModel.setCurrentEvent(fCurrentEventTime);
452
 
                        fScaledData = fDataModel.scaleTo(canvasWidth, canvasHeight, HISTOGRAM_BAR_WIDTH);
453
 
                        synchronized(fScaledData) {
 
581
                        fDataModel.setSelection(fSelectionBegin, fSelectionEnd);
 
582
                        fScaledData = fDataModel.scaleTo(canvasWidth, canvasHeight, 1);
 
583
                        synchronized (fDataModel) {
454
584
                            if (fScaledData != null) {
455
585
                                fCanvas.redraw();
456
586
                                // 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));
 
587
                                updateRangeTextControls();
 
588
                                long maxNbEvents = HistogramScaledData.hideLostEvents ? fScaledData.fMaxValue : fScaledData.fMaxCombinedValue;
 
589
                                fMaxNbEventsText.setText(Long.toString(maxNbEvents));
460
590
                                // The Y-axis area might need to be re-sized
 
591
                                GridData gd = (GridData) fMaxNbEventsText.getLayoutData();
 
592
                                gd.widthHint = Math.max(gd.widthHint, fMaxNbEventsText.computeSize(SWT.DEFAULT, SWT.DEFAULT).x);
461
593
                                fMaxNbEventsText.getParent().layout();
462
594
                            }
463
595
                        }
467
599
        }
468
600
    }
469
601
 
 
602
    /**
 
603
     * Add a mouse wheel listener to the histogram
 
604
     * @param listener the mouse wheel listener
 
605
     * @since 2.0
 
606
     */
 
607
    public void addMouseWheelListener(MouseWheelListener listener) {
 
608
        fCanvas.addMouseWheelListener(listener);
 
609
    }
 
610
 
 
611
    /**
 
612
     * Remove a mouse wheel listener from the histogram
 
613
     * @param listener the mouse wheel listener
 
614
     * @since 2.0
 
615
     */
 
616
    public void removeMouseWheelListener(MouseWheelListener listener) {
 
617
        fCanvas.removeMouseWheelListener(listener);
 
618
    }
 
619
 
470
620
    // ------------------------------------------------------------------------
471
621
    // Helper functions
472
622
    // ------------------------------------------------------------------------
473
623
 
474
 
    private void updateCurrentEventTime() {
475
 
        final long bucketStartTime = getTimestamp(fScaledData.fCurrentBucket);
476
 
        ((HistogramView) fParentView).updateCurrentEventTime(bucketStartTime);
 
624
    private void updateSelectionTime() {
 
625
        if (fSelectionBegin > fSelectionEnd) {
 
626
            long end = fSelectionBegin;
 
627
            fSelectionBegin = fSelectionEnd;
 
628
            fSelectionEnd = end;
 
629
        }
 
630
        ((HistogramView) fParentView).updateSelectionTime(fSelectionBegin, fSelectionEnd);
 
631
    }
 
632
 
 
633
    /**
 
634
     * Update the range text controls
 
635
     */
 
636
    private void updateRangeTextControls() {
 
637
        if (fDataModel.getStartTime() < fDataModel.getEndTime()) {
 
638
            fTimeRangeStartText.setText(TmfTimestampFormat.getDefaulTimeFormat().format(fDataModel.getStartTime()));
 
639
            fTimeRangeEndText.setText(TmfTimestampFormat.getDefaulTimeFormat().format(fDataModel.getEndTime()));
 
640
        } else {
 
641
            fTimeRangeStartText.setText(""); //$NON-NLS-1$
 
642
            fTimeRangeEndText.setText(""); //$NON-NLS-1$
 
643
        }
477
644
    }
478
645
 
479
646
    // ------------------------------------------------------------------------
528
695
            imageGC.fillRectangle(0, 0, image.getBounds().width + 1, image.getBounds().height + 1);
529
696
 
530
697
            // Draw the histogram bars
531
 
            imageGC.setBackground(fHistoBarColor);
532
698
            final int limit = width < scaledData.fWidth ? width : scaledData.fWidth;
533
 
            for (int i = 1; i < limit; i++) {
534
 
                final int value = (int) Math.ceil(scaledData.fData[i] * scaledData.fScalingFactor);
535
 
                imageGC.fillRectangle(i, height - value, 1, value);
536
 
            }
537
 
 
538
 
            // Draw the current event bar
539
 
            final int currentBucket = scaledData.fCurrentBucket;
540
 
            if (currentBucket >= 0 && currentBucket < limit) {
541
 
                drawDelimiter(imageGC, fCurrentEventColor, height, currentBucket);
542
 
            }
543
 
 
544
 
            // Add a dashed line as a delimiter (at the right of the last bar)
545
 
            int lastEventIndex = limit - 1;
546
 
            while (lastEventIndex >= 0 && scaledData.fData[lastEventIndex] == 0) {
547
 
                lastEventIndex--;
548
 
            }
549
 
            lastEventIndex += (lastEventIndex < limit - 1) ? 1 : 0;
550
 
            drawDelimiter(imageGC, fLastEventColor, height, lastEventIndex);
 
699
            double factor = HistogramScaledData.hideLostEvents ? scaledData.fScalingFactor : scaledData.fScalingFactorCombined;
 
700
            for (int i = 0; i < limit; i++) {
 
701
                final int value = (int) Math.ceil(scaledData.fData[i] * factor);
 
702
                int x = i + fOffset;
 
703
 
 
704
                // in Linux, the last pixel in a line is not drawn,
 
705
                // so draw lost events first, one pixel too far
 
706
                if (!HistogramScaledData.hideLostEvents) {
 
707
                    imageGC.setForeground(fLostEventColor);
 
708
                    final int lostEventValue = (int) Math.ceil(scaledData.fLostEventsData[i] * factor);
 
709
                    if (lostEventValue != 0) {
 
710
                        // drawing a line is inclusive, so we should remove 1 from y2
 
711
                        // but we don't because Linux
 
712
                        imageGC.drawLine(x, height - value - lostEventValue, x, height - value);
 
713
                    }
 
714
                }
 
715
 
 
716
                // then draw normal events second, to overwrite that extra pixel
 
717
                imageGC.setForeground(fHistoBarColor);
 
718
                imageGC.drawLine(x, height - value, x, height);
 
719
            }
 
720
 
 
721
            // Draw the selection bars
 
722
            int alpha = imageGC.getAlpha();
 
723
            imageGC.setAlpha(100);
 
724
            imageGC.setForeground(fSelectionForegroundColor);
 
725
            imageGC.setBackground(fSelectionBackgroundColor);
 
726
            final int beginBucket = scaledData.fSelectionBeginBucket + fOffset;
 
727
            if (beginBucket >= 0 && beginBucket < limit) {
 
728
                imageGC.drawLine(beginBucket, 0, beginBucket, height);
 
729
            }
 
730
            final int endBucket = scaledData.fSelectionEndBucket + fOffset;
 
731
            if (endBucket >= 0 && endBucket < limit && endBucket != beginBucket) {
 
732
                imageGC.drawLine(endBucket, 0, endBucket, height);
 
733
            }
 
734
            if (Math.abs(endBucket - beginBucket) > 1) {
 
735
                if (endBucket > beginBucket) {
 
736
                    imageGC.fillRectangle(beginBucket + 1, 0, endBucket - beginBucket - 1, height);
 
737
                } else {
 
738
                    imageGC.fillRectangle(endBucket + 1, 0, beginBucket - endBucket - 1, height);
 
739
                }
 
740
            }
 
741
            imageGC.setAlpha(alpha);
 
742
 
 
743
            // Add a dashed line as a delimiter
 
744
            int delimiterIndex = (int) ((getDataModel().getEndTime() - scaledData.getFirstBucketTime()) / scaledData.fBucketDuration) + 1;
 
745
            drawDelimiter(imageGC, fLastEventColor, height, delimiterIndex);
 
746
 
 
747
            // Fill the area to the right of delimiter with background color
 
748
            imageGC.setBackground(fFillColor);
 
749
            imageGC.fillRectangle(delimiterIndex + 1, 0, width - (delimiterIndex + 1), height);
 
750
 
551
751
        } catch (final Exception e) {
552
752
            // Do nothing
553
753
        }
563
763
        imageGC.fillRectangle(index, 3 * dash, 1, height - 3 * dash);
564
764
    }
565
765
 
 
766
    /**
 
767
     * Draw a time range window
 
768
     *
 
769
     * @param imageGC
 
770
     *            the GC
 
771
     * @param rangeStartTime
 
772
     *            the range start time
 
773
     * @param rangeDuration
 
774
     *            the range duration
 
775
     * @since 2.2
 
776
     */
 
777
    protected void drawTimeRangeWindow(GC imageGC, long rangeStartTime, long rangeDuration) {
 
778
 
 
779
        if (fScaledData == null) {
 
780
            return;
 
781
        }
 
782
 
 
783
        // Map times to histogram coordinates
 
784
        long bucketSpan = Math.max(fScaledData.fBucketDuration, 1);
 
785
        long startTime = Math.min(rangeStartTime, rangeStartTime + rangeDuration);
 
786
        int rangeWidth = (int) (Math.abs(rangeDuration) / bucketSpan);
 
787
 
 
788
        int left = (int) ((startTime - fDataModel.getFirstBucketTime()) / bucketSpan);
 
789
        int right = left + rangeWidth;
 
790
        int center = (left + right) / 2;
 
791
        int height = fCanvas.getSize().y;
 
792
        int arc = Math.min(15, rangeWidth);
 
793
 
 
794
        // Draw the selection window
 
795
        imageGC.setForeground(fTimeRangeColor);
 
796
        imageGC.setLineWidth(1);
 
797
        imageGC.setLineStyle(SWT.LINE_SOLID);
 
798
        imageGC.drawRoundRectangle(left, 0, rangeWidth, height - 1, arc, arc);
 
799
 
 
800
        // Fill the selection window
 
801
        imageGC.setBackground(fTimeRangeColor);
 
802
        imageGC.setAlpha(35);
 
803
        imageGC.fillRoundRectangle(left + 1, 1, rangeWidth - 1, height - 2, arc, arc);
 
804
        imageGC.setAlpha(255);
 
805
 
 
806
        // Draw the cross hair
 
807
        imageGC.setForeground(fTimeRangeColor);
 
808
        imageGC.setLineWidth(1);
 
809
        imageGC.setLineStyle(SWT.LINE_SOLID);
 
810
 
 
811
        int chHalfWidth = ((rangeWidth < 60) ? (rangeWidth * 2) / 3 : 40) / 2;
 
812
        imageGC.drawLine(center - chHalfWidth, height / 2, center + chHalfWidth, height / 2);
 
813
        imageGC.drawLine(center, (height / 2) - chHalfWidth, center, (height / 2) + chHalfWidth);
 
814
    }
 
815
 
566
816
    // ------------------------------------------------------------------------
567
817
    // KeyListener
568
818
    // ------------------------------------------------------------------------
586
836
 
587
837
    @Override
588
838
    public void mouseDown(final MouseEvent event) {
589
 
        if (fDataModel.getNbEvents() > 0 && fScaledData.fLastBucket >= event.x) {
590
 
            fScaledData.fCurrentBucket = event.x;
591
 
            updateCurrentEventTime();
 
839
        if (fScaledData != null && event.button == 1 && fDragState == DRAG_NONE && fDataModel.getStartTime() < fDataModel.getEndTime()) {
 
840
            fDragState = DRAG_SELECTION;
 
841
            fDragButton = event.button;
 
842
            if ((event.stateMask & SWT.MODIFIER_MASK) == SWT.SHIFT) {
 
843
                if (Math.abs(event.x - fScaledData.fSelectionBeginBucket) < Math.abs(event.x - fScaledData.fSelectionEndBucket)) {
 
844
                    fScaledData.fSelectionBeginBucket = fScaledData.fSelectionEndBucket;
 
845
                    fSelectionBegin = fSelectionEnd;
 
846
                }
 
847
                fSelectionEnd = Math.min(getTimestamp(event.x), getEndTime());
 
848
                fScaledData.fSelectionEndBucket = (int) ((fSelectionEnd - fScaledData.fFirstBucketTime) / fScaledData.fBucketDuration);
 
849
            } else {
 
850
                fSelectionBegin = Math.min(getTimestamp(event.x), getEndTime());
 
851
                fScaledData.fSelectionBeginBucket = (int) ((fSelectionBegin - fScaledData.fFirstBucketTime) / fScaledData.fBucketDuration);
 
852
                fSelectionEnd = fSelectionBegin;
 
853
                fScaledData.fSelectionEndBucket = fScaledData.fSelectionBeginBucket;
 
854
            }
 
855
            fCanvas.redraw();
592
856
        }
593
857
    }
594
858
 
595
859
    @Override
596
860
    public void mouseUp(final MouseEvent event) {
 
861
        if (fDragState == DRAG_SELECTION && event.button == fDragButton) {
 
862
            fDragState = DRAG_NONE;
 
863
            fDragButton = 0;
 
864
            updateSelectionTime();
 
865
        }
 
866
    }
 
867
 
 
868
    // ------------------------------------------------------------------------
 
869
    // MouseMoveListener
 
870
    // ------------------------------------------------------------------------
 
871
 
 
872
    /**
 
873
     * @since 2.2
 
874
     */
 
875
    @Override
 
876
    public void mouseMove(MouseEvent event) {
 
877
        if (fDragState == DRAG_SELECTION && fDataModel.getStartTime() < fDataModel.getEndTime()) {
 
878
            fSelectionEnd = Math.max(getStartTime(), Math.min(getEndTime(), getTimestamp(event.x)));
 
879
            fScaledData.fSelectionEndBucket = (int) ((fSelectionEnd - fScaledData.fFirstBucketTime) / fScaledData.fBucketDuration);
 
880
            fCanvas.redraw();
 
881
        }
597
882
    }
598
883
 
599
884
    // ------------------------------------------------------------------------
610
895
 
611
896
    @Override
612
897
    public void mouseHover(final MouseEvent event) {
613
 
        if (fDataModel.getNbEvents() > 0 && fScaledData != null && fScaledData.fLastBucket >= event.x) {
614
 
            final String tooltip = formatToolTipLabel(event.x);
615
 
            fCanvas.setToolTipText(tooltip);
 
898
        if (fDataModel.getStartTime() < fDataModel.getEndTime() && fScaledData != null) {
 
899
            int delimiterIndex = (int) ((fDataModel.getEndTime() - fScaledData.getFirstBucketTime()) / fScaledData.fBucketDuration) + 1;
 
900
            if (event.x < delimiterIndex) {
 
901
                final String tooltip = formatToolTipLabel(event.x - fOffset);
 
902
                fCanvas.setToolTipText(tooltip);
 
903
                return;
 
904
            }
616
905
        }
 
906
        fCanvas.setToolTipText(null);
617
907
    }
618
908
 
619
909
    private String formatToolTipLabel(final int index) {
624
914
        }
625
915
        final long endTime = fScaledData.getBucketEndTime(index);
626
916
        final int nbEvents = (index >= 0) ? fScaledData.fData[index] : 0;
627
 
 
 
917
        final String newLine = System.getProperty("line.separator"); //$NON-NLS-1$
628
918
        final StringBuffer buffer = new StringBuffer();
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);
 
919
        int selectionBeginBucket = Math.min(fScaledData.fSelectionBeginBucket, fScaledData.fSelectionEndBucket);
 
920
        int selectionEndBucket = Math.max(fScaledData.fSelectionBeginBucket, fScaledData.fSelectionEndBucket);
 
921
        if (selectionBeginBucket <= index && index <= selectionEndBucket && fSelectionBegin != fSelectionEnd) {
 
922
            TmfTimestampDelta delta = new TmfTimestampDelta(Math.abs(fSelectionEnd - fSelectionBegin), ITmfTimestamp.NANOSECOND_SCALE);
 
923
            buffer.append(NLS.bind(Messages.Histogram_selectionSpanToolTip, delta.toString()));
 
924
            buffer.append(newLine);
 
925
        }
 
926
        buffer.append(NLS.bind(Messages.Histogram_bucketRangeToolTip,
 
927
                new TmfTimestamp(startTime, ITmfTimestamp.NANOSECOND_SCALE).toString(),
 
928
                new TmfTimestamp(endTime, ITmfTimestamp.NANOSECOND_SCALE).toString()));
 
929
        buffer.append(newLine);
 
930
        buffer.append(NLS.bind(Messages.Histogram_eventCountToolTip, nbEvents));
 
931
        if (!HistogramScaledData.hideLostEvents) {
 
932
            final int nbLostEvents = (index >= 0) ? fScaledData.fLostEventsData[index] : 0;
 
933
            buffer.append(newLine);
 
934
            buffer.append(NLS.bind(Messages.Histogram_lostEventCountToolTip, nbLostEvents));
 
935
        }
636
936
        return buffer.toString();
637
937
    }
638
938
 
649
949
    public void controlResized(final ControlEvent event) {
650
950
        fDataModel.complete();
651
951
    }
 
952
 
 
953
    // ------------------------------------------------------------------------
 
954
    // Signal Handlers
 
955
    // ------------------------------------------------------------------------
 
956
 
 
957
    /**
 
958
     * Format the timestamp and update the display
 
959
     *
 
960
     * @param signal
 
961
     *            the incoming signal
 
962
     * @since 2.0
 
963
     */
 
964
    @TmfSignalHandler
 
965
    public void timestampFormatUpdated(TmfTimestampFormatUpdateSignal signal) {
 
966
        updateRangeTextControls();
 
967
 
 
968
        fComposite.layout();
 
969
    }
 
970
 
652
971
}