/*******************************************************************************
- * Copyright (c) 2011, 2013 Ericsson
+ * Copyright (c) 2011, 2014 Ericsson
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
* Bernd Hufmann - Changed to updated histogram data model
* Francois Chouinard - Reformat histogram labels on format change
* Patrick Tasse - Support selection range
+ * Xavier Raynaud - Support multi-trace coloring
*******************************************************************************/
package org.eclipse.linuxtools.tmf.ui.views.histogram;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
-import org.eclipse.swt.events.FocusAdapter;
-import org.eclipse.swt.events.FocusEvent;
-import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
/**
* Re-usable histogram widget.
// ------------------------------------------------------------------------
// Histogram colors
+
+ // System colors, they do not need to be disposed
private final Color fBackgroundColor = Display.getCurrent().getSystemColor(SWT.COLOR_WHITE);
private final Color fSelectionForegroundColor = Display.getCurrent().getSystemColor(SWT.COLOR_BLUE);
private final Color fSelectionBackgroundColor = Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
private final Color fLastEventColor = Display.getCurrent().getSystemColor(SWT.COLOR_DARK_RED);
- private final Color fHistoBarColor = new Color(Display.getDefault(), 74, 112, 139);
- private final Color fLostEventColor = new Color(Display.getCurrent(), 208, 62, 120);
- private final Color fFillColor = Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
+
+ // Application colors, they need to be disposed
+ private final Color[] fHistoBarColors = new Color[] {new Color(Display.getDefault(), 90, 90, 255), // blue
+ new Color(Display.getDefault(), 0, 240, 0), // green
+ new Color(Display.getDefault(), 255, 0, 0), // red
+ new Color(Display.getDefault(), 0, 255, 255), // cyan
+ new Color(Display.getDefault(), 255, 80, 255), // magenta
+ new Color(Display.getDefault(), 200, 200, 0), // yellow
+ new Color(Display.getDefault(), 200, 150, 0), // brown
+ new Color(Display.getDefault(), 150, 255, 150), // light green
+ new Color(Display.getDefault(), 200, 80, 80), // dark red
+ new Color(Display.getDefault(), 30, 150, 150), // dark cyan
+ new Color(Display.getDefault(), 200, 200, 255), // light blue
+ new Color(Display.getDefault(), 0, 120, 0), // dark green
+ new Color(Display.getDefault(), 255, 150, 150), // lighter red
+ new Color(Display.getDefault(), 140, 80, 140), // dark magenta
+ new Color(Display.getDefault(), 150, 100, 50), // brown
+ new Color(Display.getDefault(), 255, 80, 80), // light red
+ new Color(Display.getDefault(), 200, 200, 200), // light grey
+ new Color(Display.getDefault(), 255, 200, 80), // orange
+ new Color(Display.getDefault(), 255, 255, 80), // pale yellow
+ new Color(Display.getDefault(), 255, 200, 200), // pale red
+ new Color(Display.getDefault(), 255, 200, 255), // pale magenta
+ new Color(Display.getDefault(), 255, 255, 200), // pale pale yellow
+ new Color(Display.getDefault(), 200, 255, 255), // pale pale blue
+ };
private final Color fTimeRangeColor = new Color(Display.getCurrent(), 255, 128, 0);
+ private final Color fLostEventColor = new Color(Display.getCurrent(), 208, 62, 120);
// Drag states
/**
private Font fFont;
// Histogram text fields
- private Text fMaxNbEventsText;
- private Text fMinNbEventsText;
- private Text fTimeRangeStartText;
- private Text fTimeRangeEndText;
+ private Label fMaxNbEventsLabel;
+ private Label fMinNbEventsLabel;
+ private Label fTimeRangeStartLabel;
+ private Label fTimeRangeEndLabel;
/**
* Histogram drawing area
*/
private int fOffset = 0;
+ /**
+ * show the traces or not
+ * @since 3.0
+ */
+ static boolean showTraces = true;
+
// ------------------------------------------------------------------------
// Construction
// ------------------------------------------------------------------------
*/
public void dispose() {
TmfSignalManager.deregister(this);
-
- fHistoBarColor.dispose();
- fLastEventColor.dispose();
+ fLostEventColor.dispose();
+ for (Color c : fHistoBarColors) {
+ c.dispose();
+ }
fTimeRangeColor.dispose();
+ fFont.dispose();
fDataModel.removeHistogramListener(this);
+ fDataModel.dispose();
}
private Composite createWidget(final Composite parent) {
- final Color labelColor = parent.getBackground();
fFont = adjustFont(parent);
final int initalWidth = 10;
gridData = new GridData();
gridData.horizontalAlignment = SWT.RIGHT;
gridData.verticalAlignment = SWT.TOP;
- fMaxNbEventsText = new Text(composite, SWT.READ_ONLY | SWT.RIGHT);
- fMaxNbEventsText.setFont(fFont);
- fMaxNbEventsText.setBackground(labelColor);
- fMaxNbEventsText.setEditable(false);
- fMaxNbEventsText.setText("0"); //$NON-NLS-1$
- fMaxNbEventsText.setLayoutData(gridData);
+ fMaxNbEventsLabel = new Label(composite, SWT.RIGHT);
+ fMaxNbEventsLabel.setFont(fFont);
+ fMaxNbEventsLabel.setText("0"); //$NON-NLS-1$
+ fMaxNbEventsLabel.setLayoutData(gridData);
// Histogram itself
Composite canvasComposite = new Composite(composite, SWT.BORDER);
canvasComposite.setLayoutData(gridData);
canvasComposite.setLayout(new FillLayout());
fCanvas = new Canvas(canvasComposite, SWT.DOUBLE_BUFFERED);
+ fCanvas.addDisposeListener(new DisposeListener() {
+ @Override
+ public void widgetDisposed(DisposeEvent e) {
+ Object image = fCanvas.getData(IMAGE_KEY);
+ if (image instanceof Image) {
+ ((Image) image).dispose();
+ }
+ }
+ });
// Y-axis min event (always 0...)
gridData = new GridData();
gridData.horizontalAlignment = SWT.RIGHT;
gridData.verticalAlignment = SWT.BOTTOM;
- fMinNbEventsText = new Text(composite, SWT.READ_ONLY | SWT.RIGHT);
- fMinNbEventsText.setFont(fFont);
- fMinNbEventsText.setBackground(labelColor);
- fMinNbEventsText.setEditable(false);
- fMinNbEventsText.setText("0"); //$NON-NLS-1$
- fMinNbEventsText.setLayoutData(gridData);
+ fMinNbEventsLabel = new Label(composite, SWT.RIGHT);
+ fMinNbEventsLabel.setFont(fFont);
+ fMinNbEventsLabel.setText("0"); //$NON-NLS-1$
+ fMinNbEventsLabel.setLayoutData(gridData);
// Dummy cell
gridData = new GridData(initalWidth, SWT.DEFAULT);
gridData = new GridData();
gridData.horizontalAlignment = SWT.LEFT;
gridData.verticalAlignment = SWT.BOTTOM;
- fTimeRangeStartText = new Text(composite, SWT.READ_ONLY);
- fTimeRangeStartText.setFont(fFont);
- fTimeRangeStartText.setBackground(labelColor);
- fTimeRangeStartText.setLayoutData(gridData);
+ fTimeRangeStartLabel = new Label(composite, SWT.NONE);
+ fTimeRangeStartLabel.setFont(fFont);
+ fTimeRangeStartLabel.setLayoutData(gridData);
// Window range end time
gridData = new GridData();
gridData.horizontalAlignment = SWT.RIGHT;
gridData.verticalAlignment = SWT.BOTTOM;
- fTimeRangeEndText = new Text(composite, SWT.READ_ONLY);
- fTimeRangeEndText.setFont(fFont);
- fTimeRangeEndText.setBackground(labelColor);
- fTimeRangeEndText.setLayoutData(gridData);
-
- FocusListener listener = new FocusAdapter() {
- @Override
- public void focusGained(FocusEvent e) {
- fCanvas.setFocus();
- }
- };
- fMaxNbEventsText.addFocusListener(listener);
- fMinNbEventsText.addFocusListener(listener);
- fTimeRangeStartText.addFocusListener(listener);
- fTimeRangeEndText.addFocusListener(listener);
+ fTimeRangeEndLabel = new Label(composite, SWT.NONE);
+ fTimeRangeEndLabel.setFont(fFont);
+ fTimeRangeEndLabel.setLayoutData(gridData);
return composite;
}
}
/**
- * Returns the text control for the maximum of events in one bar
+ * Set the max number events to be displayed
*
- * @return the text control
- * @since 2.2
+ * @param maxNbEvents
+ * the maximum number of events
+ */
+ void setMaxNbEvents(long maxNbEvents) {
+ fMaxNbEventsLabel.setText(Long.toString(maxNbEvents));
+ fMaxNbEventsLabel.getParent().layout();
+ fCanvas.redraw();
+ }
+
+ /**
+ * Return <code>true</code> if the traces must be displayed in the histogram,
+ * <code>false</code> otherwise.
+ * @return whether the traces should be displayed
+ * @since 3.0
+ */
+ public boolean showTraces() {
+ return showTraces && fDataModel.getNbTraces() < getMaxNbTraces();
+ }
+
+ /**
+ * Returns the maximum number of traces the histogram can display with separate colors.
+ * If there is more traces, histogram will use only one color to display them.
+ * @return the maximum number of traces the histogram can display.
+ * @since 3.0
+ */
+ public int getMaxNbTraces() {
+ return fHistoBarColors.length;
+ }
+
+ /**
+ * Returns the color used to display the trace at the given index.
+ * @param traceIndex a trace index
+ * @return a {@link Color}
+ * @since 3.0
*/
- public Text getMaxNbEventsText() {
- return fMaxNbEventsText;
+ public Color getTraceColor(int traceIndex) {
+ return fHistoBarColors[traceIndex % fHistoBarColors.length];
}
// ------------------------------------------------------------------------
*/
public void clear() {
fDataModel.clear();
+ if (fDragState == DRAG_SELECTION) {
+ updateSelectionTime();
+ }
+ fDragState = DRAG_NONE;
+ fDragButton = 0;
synchronized (fDataModel) {
fScaledData = null;
}
}
- /**
- * Increase the histogram bucket corresponding to [timestamp]
- *
- * @param eventCount The new event count
- * @param timestamp The latest timestamp
- */
- public void countEvent(final long eventCount, final long timestamp) {
- fDataModel.countEvent(eventCount, timestamp);
- }
-
- /**
- * Sets the current event time and refresh the display
- *
- * @param timestamp The time of the current event
- * @deprecated As of 2.1, use {@link #setSelection(long, long)}
- */
- @Deprecated
- public void setCurrentEvent(final long timestamp) {
- fSelectionBegin = (timestamp > 0) ? timestamp : 0;
- fSelectionEnd = (timestamp > 0) ? timestamp : 0;
- fDataModel.setSelectionNotifyListeners(timestamp, timestamp);
- }
-
/**
* Sets the current selection time range and refresh the display
*
case SWT.HOME:
index = 0;
- while (index < fScaledData.fLastBucket && fScaledData.fData[index] == 0) {
+ while (index < fScaledData.fLastBucket && fScaledData.fData[index].isEmpty()) {
index++;
}
if (index < fScaledData.fLastBucket) {
case SWT.ARROW_RIGHT:
index = Math.max(0, fScaledData.fSelectionBeginBucket + 1);
- while (index < fScaledData.fWidth && fScaledData.fData[index] == 0) {
+ while (index < fScaledData.fWidth && fScaledData.fData[index].isEmpty()) {
index++;
}
if (index < fScaledData.fLastBucket) {
case SWT.END:
index = fScaledData.fLastBucket;
- while (index >= 0 && fScaledData.fData[index] == 0) {
+ while (index >= 0 && fScaledData.fData[index].isEmpty()) {
index--;
}
if (index >= 0) {
case SWT.ARROW_LEFT:
index = Math.min(fScaledData.fLastBucket - 1, fScaledData.fSelectionBeginBucket - 1);
- while (index >= 0 && fScaledData.fData[index] == 0) {
+ while (index >= 0 && fScaledData.fData[index].isEmpty()) {
index--;
}
if (index >= 0) {
// Display histogram and update X-,Y-axis labels
updateRangeTextControls();
long maxNbEvents = HistogramScaledData.hideLostEvents ? fScaledData.fMaxValue : fScaledData.fMaxCombinedValue;
- fMaxNbEventsText.setText(Long.toString(maxNbEvents));
+ fMaxNbEventsLabel.setText(Long.toString(maxNbEvents));
// The Y-axis area might need to be re-sized
- GridData gd = (GridData) fMaxNbEventsText.getLayoutData();
- gd.widthHint = Math.max(gd.widthHint, fMaxNbEventsText.computeSize(SWT.DEFAULT, SWT.DEFAULT).x);
- fMaxNbEventsText.getParent().layout();
+ GridData gd = (GridData) fMaxNbEventsLabel.getLayoutData();
+ gd.widthHint = Math.max(gd.widthHint, fMaxNbEventsLabel.computeSize(SWT.DEFAULT, SWT.DEFAULT).x);
+ fMaxNbEventsLabel.getParent().layout();
}
}
}
fCanvas.removeMouseWheelListener(listener);
}
+ /**
+ * Add a key listener to the histogram
+ * @param listener the key listener
+ * @since 3.1
+ */
+ public void addKeyListener(KeyListener listener) {
+ fCanvas.addKeyListener(listener);
+ }
+
+ /**
+ * Remove a key listener from the histogram
+ * @param listener the key listener
+ * @since 3.1
+ */
+ public void removeKeyListener(KeyListener listener) {
+ fCanvas.removeKeyListener(listener);
+ }
+
// ------------------------------------------------------------------------
// Helper functions
// ------------------------------------------------------------------------
*/
private void updateRangeTextControls() {
if (fDataModel.getStartTime() < fDataModel.getEndTime()) {
- fTimeRangeStartText.setText(TmfTimestampFormat.getDefaulTimeFormat().format(fDataModel.getStartTime()));
- fTimeRangeEndText.setText(TmfTimestampFormat.getDefaulTimeFormat().format(fDataModel.getEndTime()));
+ fTimeRangeStartLabel.setText(TmfTimestampFormat.getDefaulTimeFormat().format(fDataModel.getStartTime()));
+ fTimeRangeEndLabel.setText(TmfTimestampFormat.getDefaulTimeFormat().format(fDataModel.getEndTime()));
} else {
- fTimeRangeStartText.setText(""); //$NON-NLS-1$
- fTimeRangeEndText.setText(""); //$NON-NLS-1$
+ fTimeRangeStartLabel.setText(""); //$NON-NLS-1$
+ fTimeRangeEndLabel.setText(""); //$NON-NLS-1$
}
}
// Retrieve image; re-create only if necessary
Image image = (Image) fCanvas.getData(IMAGE_KEY);
if (image == null || image.getBounds().width != canvasWidth || image.getBounds().height != canvasHeight) {
+ if (image != null) {
+ image.dispose();
+ }
image = new Image(event.display, canvasWidth, canvasHeight);
fCanvas.setData(IMAGE_KEY, image);
}
final int width = image.getBounds().width;
final int height = image.getBounds().height;
- // Turn off anti-aliasing
- int aliasing = imageGC.getAntialias();
- imageGC.setAntialias(SWT.OFF);
-
// Clear the drawing area
imageGC.setBackground(fBackgroundColor);
imageGC.fillRectangle(0, 0, image.getBounds().width + 1, image.getBounds().height + 1);
// Draw the histogram bars
final int limit = width < scaledData.fWidth ? width : scaledData.fWidth;
double factor = HistogramScaledData.hideLostEvents ? scaledData.fScalingFactor : scaledData.fScalingFactorCombined;
+ final boolean showTracesColors = showTraces();
for (int i = 0; i < limit; i++) {
- final int value = (int) Math.ceil(scaledData.fData[i] * factor);
+ HistogramBucket hb = scaledData.fData[i];
+ int totalNbEvents = hb.getNbEvents();
+ int value = (int) Math.ceil(totalNbEvents * factor);
int x = i + fOffset;
// in Linux, the last pixel in a line is not drawn,
}
// then draw normal events second, to overwrite that extra pixel
- imageGC.setForeground(fHistoBarColor);
- imageGC.drawLine(x, height - value, x, height);
+ if (!hb.isEmpty()) {
+ if (showTracesColors) {
+ for (int traceIndex = 0; traceIndex < hb.getNbTraces(); traceIndex++) {
+ int nbEventsForTrace = hb.getNbEvent(traceIndex);
+ if (nbEventsForTrace > 0) {
+ Color c = fHistoBarColors[traceIndex % fHistoBarColors.length];
+ imageGC.setForeground(c);
+ imageGC.drawLine(x, height - value, x, height);
+ totalNbEvents -= nbEventsForTrace;
+ value = (int) Math.ceil(totalNbEvents * scaledData.fScalingFactor);
+ }
+ }
+ } else {
+ Color c = fHistoBarColors[0];
+ imageGC.setForeground(c);
+ imageGC.drawLine(x, height - value, x, height);
+ }
+ }
}
// Draw the selection bars
drawDelimiter(imageGC, fLastEventColor, height, delimiterIndex);
// Fill the area to the right of delimiter with background color
- imageGC.setBackground(fFillColor);
+ imageGC.setBackground(fComposite.getBackground());
imageGC.fillRectangle(delimiterIndex + 1, 0, width - (delimiterIndex + 1), height);
- // Restore anti-aliasing
- imageGC.setAntialias(aliasing);
-
} catch (final Exception e) {
// Do nothing
}
startTime = 0;
}
final long endTime = fScaledData.getBucketEndTime(index);
- final int nbEvents = (index >= 0) ? fScaledData.fData[index] : 0;
+ final int nbEvents = (index >= 0) ? fScaledData.fData[index].getNbEvents() : 0;
final String newLine = System.getProperty("line.separator"); //$NON-NLS-1$
final StringBuffer buffer = new StringBuffer();
int selectionBeginBucket = Math.min(fScaledData.fSelectionBeginBucket, fScaledData.fSelectionEndBucket);