This makes active threads much easier to spot.
Adds notion of thickness to the "StateItem". In order to
use it, override StateItem#getHeightFactor().
The patch also introduces the notion of a style map.
This is loosely based on CSS fill styles. The styles
in the map are suggestions and do not need to be implemented
by the UI, but could at a later date.
The styleMap is passes as follows where each step can override the
base map:
* LinuxStyle (Style on an analysis level)
* StateItem (Style on a per-view level)
* PresentationProvider (Style on a per-event level)
Change-Id: I0a5f33d958a1ec1746ace9a66fecd728fb5a68ed
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Reviewed-on: https://git.eclipse.org/r/85092
Reviewed-by: Hudson CI
Reviewed-by: Genevieve Bastien <gbastien+lttng@versatic.net>
Tested-by: Genevieve Bastien <gbastien+lttng@versatic.net>
package org.eclipse.tracecompass.internal.analysis.os.linux.ui.registry;
-import org.eclipse.swt.graphics.RGB;
-import org.eclipse.swt.graphics.RGBA;
+import java.util.Map;
+
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEventStyleStrings;
+
+import com.google.common.collect.ImmutableMap;
/**
* A Linux style
/**
* Unknown state for thread or CPU
*/
- UNKNOWN(Messages.LinuxStyles_unknown, new RGB(100, 100, 100), 0.33f),
+ UNKNOWN(Messages.LinuxStyles_unknown, 100, 100, 100, 255, 0.33f),
/**
* Wait for an unknown reason
*/
- WAIT_UNKNOWN(Messages.LinuxStyles_wait, new RGB(200, 200, 200), 0.50f),
+ WAIT_UNKNOWN(Messages.LinuxStyles_wait, 200, 200, 200, 255, 0.50f),
/**
* Wait to be scheduled back in
*/
- WAIT_BLOCKED(Messages.LinuxStyles_waitBlocked, new RGB(200, 200, 0), 0.50f),
+ WAIT_BLOCKED(Messages.LinuxStyles_waitBlocked, 200, 200, 0, 255, 0.50f),
/**
* Wait for the CPU to be available
*/
- WAIT_FOR_CPU(Messages.LinuxStyles_waitForCPU, new RGB(200, 100, 0), 0.50f),
+ WAIT_FOR_CPU(Messages.LinuxStyles_waitForCPU, 200, 100, 0, 255, 0.50f),
/**
* CPU is idle
*/
- IDLE(Messages.LinuxStyles_idle, new RGB(200, 200, 200), 0.66f),
+ IDLE(Messages.LinuxStyles_idle, 200, 200, 200, 255, 0.66f),
/**
* CPU or thread is in usermode
*/
- USERMODE(Messages.LinuxStyles_usermode, new RGB(0, 200, 0), 1.00f),
+ USERMODE(Messages.LinuxStyles_usermode, 0, 200, 0, 255, 1.00f),
/**
* CPU or thread is in a system call
*/
- SYSCALL(Messages.LinuxStyles_systemCall, new RGB(0, 0, 200), 1.00f),
+ SYSCALL(Messages.LinuxStyles_systemCall, 0, 0, 200, 255, 1.00f),
/**
* CPU is in an IRQ
*/
- INTERRUPTED(Messages.LinuxStyles_Interrupt, new RGB(200, 0, 100), 0.75f),
+ INTERRUPTED(Messages.LinuxStyles_Interrupt, 200, 0, 100, 255, 0.75f),
/**
* A Softirq or tasklet is raised
*/
- SOFT_IRQ_RAISED(Messages.LinuxStyles_softIrqRaised, new RGB(200, 200, 0), 1.00f),
+ SOFT_IRQ_RAISED(Messages.LinuxStyles_softIrqRaised, 200, 200, 0, 255, 1.00f),
/**
* CPU is in a softirq or tasklet
*/
- SOFT_IRQ(Messages.LinuxStyles_softrq, new RGB(200, 150, 100), 1.00f);
-
- private final float fHeightFactor;
- private RGBA fColor;
- private String fLabel;
+ SOFT_IRQ(Messages.LinuxStyles_softrq, 200, 150, 100, 255, 1.00f);
- /**
- * A Linux style
- *
- * @param label
- * The label of the style
- * @param color
- * the color
- * @param heightFactor
- * the hint of the height
- */
- private LinuxStyle(String label, RGB color, float heightFactor) {
- this(label, new RGBA(color.red, color.green, color.blue, 255), heightFactor);
- }
+ private final Map<String, Object> fMap;
/**
* A Linux style
*
* @param label
* the label of the style
- * @param color
- * the color
+ * @param red
+ * red value, must be between 0 and 255
+ * @param green
+ * green value, must be between 0 and 255
+ * @param blue
+ * blue value, must be between 0 and 255
+ * @param alpha
+ * value, must be between 0 and 255
* @param heightFactor
* the hint of the height, between 0 and 1.0
*/
- private LinuxStyle(String label, RGBA color, float heightFactor) {
+ private LinuxStyle(String label, int red, int green, int blue, int alpha, float heightFactor) {
+ if (label == null) {
+ throw new IllegalArgumentException("Label cannot be null"); //$NON-NLS-1$
+ }
+ if (red > 255 || red < 0) {
+ throw new IllegalArgumentException("Red needs to be between 0 and 255"); //$NON-NLS-1$
+ }
+ if (green > 255 || green < 0) {
+ throw new IllegalArgumentException("Green needs to be between 0 and 255"); //$NON-NLS-1$
+ }
+ if (blue > 255 || blue < 0) {
+ throw new IllegalArgumentException("Blue needs to be between 0 and 255"); //$NON-NLS-1$
+ }
+ if (alpha > 255 || alpha < 0) {
+ throw new IllegalArgumentException("alpha needs to be between 0 and 255"); //$NON-NLS-1$
+ }
if (heightFactor > 1.0 || heightFactor < 0) {
- throw new IllegalStateException("Height factor needs to be between 0 and 1.0, given hint : " + heightFactor); //$NON-NLS-1$
+ throw new IllegalArgumentException("Height factor needs to be between 0 and 1.0, given hint : " + heightFactor); //$NON-NLS-1$
}
- fLabel = label;
- fColor = color;
- fHeightFactor = heightFactor;
+ fMap = ImmutableMap.of(ITimeEventStyleStrings.label(), label,
+ ITimeEventStyleStrings.fillStyle(), ITimeEventStyleStrings.solidColorFillStyle(),
+ ITimeEventStyleStrings.fillColor(), red << 24 | green << 16 | blue << 8 | alpha,
+ ITimeEventStyleStrings.heightFactor(), heightFactor);
}
/**
* @return the label to display
*/
public String getLabel() {
- return fLabel;
- }
-
- /**
- * Get the color
- *
- * @return the color to display
- */
- public RGBA getColor() {
- return fColor;
+ return (String) fMap.get(ITimeEventStyleStrings.label());
}
/**
- * Get the hint height, to be multiplied by the
+ * Get a map of the values corresponding to the fields in
+ * {@link ITimeEventStyleStrings}
*
- * @return the heightHint
+ * @return the map corresponding to the api defined in
+ * {@link ITimeEventStyleStrings}
*/
- public float getHeightFactor() {
- return fHeightFactor;
+ public Map<String, Object> toMap() {
+ return fMap;
}
}
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.tracecompass.analysis.os.linux.core.kernel.KernelAnalysisModule;
import org.eclipse.tracecompass.analysis.os.linux.core.kernel.StateValues;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.StateItem;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphPresentationProvider;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEvent;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEventStyleStrings;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.NullTimeEvent;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeEvent;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.Utils;
private static final Map<Integer, StateItem> STATE_MAP;
private static final List<StateItem> STATE_LIST;
+ private static final StateItem[] STATE_TABLE;
private static StateItem createState(LinuxStyle style) {
- return new StateItem(style.getColor().rgb, style.getLabel());
+ int rgbInt = (int) style.toMap().getOrDefault(ITimeEventStyleStrings.fillColor(), 0);
+ RGB color = new RGB(rgbInt >> 24 & 0xff, rgbInt >> 16 & 0xff, rgbInt >> 8 & 0xff);
+ return new StateItem(color, style.getLabel()) {
+ @Override
+ public Map<String, Object> getStyleMap() {
+ return style.toMap();
+ }
+ };
}
static {
ImmutableMap.Builder<Integer, StateItem> builder = new ImmutableMap.Builder<>();
+ /*
+ * ADD STATE MAPPING HERE
+ */
builder.put(StateValues.PROCESS_STATUS_UNKNOWN, createState(LinuxStyle.UNKNOWN));
builder.put(StateValues.PROCESS_STATUS_RUN_USERMODE, createState(LinuxStyle.USERMODE));
builder.put(StateValues.PROCESS_STATUS_RUN_SYSCALL, createState(LinuxStyle.SYSCALL));
builder.put(StateValues.PROCESS_STATUS_WAIT_BLOCKED, createState(LinuxStyle.WAIT_BLOCKED));
builder.put(StateValues.PROCESS_STATUS_WAIT_FOR_CPU, createState(LinuxStyle.WAIT_FOR_CPU));
builder.put(StateValues.PROCESS_STATUS_WAIT_UNKNOWN, createState(LinuxStyle.WAIT_UNKNOWN));
+ /*
+ * DO NOT MODIFY AFTER
+ */
STATE_MAP = builder.build();
STATE_LIST = ImmutableList.copyOf(STATE_MAP.values());
+ STATE_TABLE = STATE_LIST.toArray(new StateItem[STATE_LIST.size()]);
}
/**
@Override
public StateItem[] getStateTable() {
- return STATE_LIST.toArray(new StateItem[STATE_LIST.size()]);
+ return STATE_TABLE;
}
@Override
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.tracecompass.analysis.os.linux.core.kernel.KernelAnalysisModule;
import org.eclipse.tracecompass.analysis.os.linux.core.kernel.StateValues;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.StateItem;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphPresentationProvider;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEvent;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEventStyleStrings;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.NullTimeEvent;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeEvent;
private static final List<StateItem> STATE_LIST;
private static StateItem createState(LinuxStyle style) {
- return new StateItem(style.getColor().rgb, style.getLabel());
+ int rgbInt = (int) style.toMap().getOrDefault(ITimeEventStyleStrings.fillColor(), 0);
+ RGB color = new RGB(rgbInt >> 24 & 0xff, rgbInt >> 16 & 0xff, rgbInt >> 8 & 0xff);
+ return new StateItem(color, style.getLabel());
}
static {
package org.eclipse.tracecompass.tmf.ui.widgets.timegraph;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.Map;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEvent;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEventStyleStrings;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeEvent;
/**
* Interface for the time graph widget provider
*/
public interface ITimeGraphPresentationProvider {
- /** State table index for an invisible event
+ /**
+ * State table index for an invisible event
*/
final int INVISIBLE = -1;
- /** State table index for a transparent event (only borders drawn)
+ /**
+ * State table index for a transparent event (only borders drawn)
*/
final int TRANSPARENT = -2;
*/
String getStateTypeName();
- /**
- * Returns the name of state type depending on the given entry.
- * Note that this overwrites the name which is return by getStateTypeName().
- *
- * @param entry
- * the entry
- * @return the name of state type depending on the given entry or null.
- */
- String getStateTypeName(ITimeGraphEntry entry);
+ /**
+ * Returns the name of state type depending on the given entry. Note that
+ * this overwrites the name which is return by getStateTypeName().
+ *
+ * @param entry
+ * the entry
+ * @return the name of state type depending on the given entry or null.
+ */
+ String getStateTypeName(ITimeGraphEntry entry);
/**
* Returns table of states with state name to state color relationship.
/**
* Returns the index in the state table corresponding to this time event.
- * The index should correspond to a state in the state table,
- * otherwise the color SWT.COLOR_BLACK will be used.
- * If the index returned is TRANSPARENT, only the event borders will be drawn.
- * If the index returned is INVISIBLE or another negative, the event will not be drawn.
+ * The index should correspond to a state in the state table, otherwise the
+ * color SWT.COLOR_BLACK will be used. If the index returned is TRANSPARENT,
+ * only the event borders will be drawn. If the index returned is INVISIBLE
+ * or another negative, the event will not be drawn.
*
- * @param event the time event
+ * @param event
+ * the time event
* @return the corresponding state table index
*
* @see #getStateTable
void postDrawEvent(ITimeEvent event, Rectangle bounds, GC gc);
/**
- * Returns the height of this item. This value is ignored if the time graph has a fixed item height.
+ * Returns the height of this item. This value is ignored if the time graph
+ * has a fixed item height.
*
- * @param entry the entry
+ * @param entry
+ * the entry
* @return the item height
*
* @see TimeGraphViewer#setItemHeight
/**
* Provides the image icon for a given entry.
*
- * @param entry the entry
+ * @param entry
+ * the entry
* @return the image icon
*/
Image getItemImage(ITimeGraphEntry entry);
String getEventName(ITimeEvent event);
/**
- * Returns a map of name and value providing additional information
- * to display in the tool tip for this event.
+ * Returns a map of name and value providing additional information to
+ * display in the tool tip for this event.
*
- * @param event the time event
+ * @param event
+ * the time event
* @return a map of tool tip information
*/
Map<String, String> getEventHoverToolTipInfo(ITimeEvent event);
/**
- * Returns a map of name and value providing additional information
- * to display in the tool tip for this event.
+ * Returns a map of name and value providing additional information to
+ * display in the tool tip for this event.
*
- * @param event the time event
- * @param hoverTime the time corresponding to the mouse hover position
+ * @param event
+ * the time event
+ * @param hoverTime
+ * the time corresponding to the mouse hover position
* @return a map of tool tip information
*/
Map<String, String> getEventHoverToolTipInfo(ITimeEvent event, long hoverTime);
/**
- * Check whether time and duration should be displayed in tooltip (after items from
- * {@link #getEventHoverToolTipInfo(ITimeEvent)}).
+ * Check whether time and duration should be displayed in tooltip (after
+ * items from {@link #getEventHoverToolTipInfo(ITimeEvent)}).
*
- * @return <code>true</code> if times and duration should be displayed on tooltip, <code>false</code> otherwise.
+ * @return <code>true</code> if times and duration should be displayed on
+ * tooltip, <code>false</code> otherwise.
*/
public boolean displayTimesInTooltip();
+ /**
+ * Get the style map of a given ITimeEvent
+ *
+ * @param event
+ * the time event
+ * @return the style map, as detailed in {@link ITimeEventStyleStrings}
+ * @since 2.4
+ */
+ default Map<String, Object> getEventStyle(ITimeEvent event) {
+ StateItem stateItem = null;
+ if (event instanceof TimeEvent) {
+ int index = getStateTableIndex(event);
+ StateItem[] stateTable = getStateTable();
+ if (index >= 0 && index < stateTable.length) {
+ stateItem = stateTable[index];
+ }
+ }
+ Map<String, Object> styleMap = new HashMap<>();
+ if (stateItem != null) {
+ styleMap.putAll(stateItem.getStyleMap());
+ }
+ styleMap.putAll(getSpecificEventStyle(event));
+ return styleMap;
+ }
+
+ /**
+ * Get the specific style map for a given event.
+ *
+ * @param event
+ * the time event
+ * @return a style map containing the elements as detailed in
+ * {@link ITimeEventStyleStrings} to override
+ * @since 2.4
+ */
+ default Map<String, Object> getSpecificEventStyle(ITimeEvent event) {
+ return Collections.emptyMap();
+ }
}
**********************************************************************/
package org.eclipse.tracecompass.tmf.ui.widgets.timegraph;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
import org.eclipse.swt.graphics.RGB;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEventStyleStrings;
/**
* Class that contains the color of a state and the corresponding state string
*/
public static final String UNDEFINED_STATE_NAME = "Undefined"; //$NON-NLS-1$
+ private static final int UNDEFINED_COLOR_VALUE = 0xff;
+
// ------------------------------------------------------------------------
// Attributes
// ------------------------------------------------------------------------
- /**
- * The State color
- */
- private RGB fStateColor;
- /**
- * The State string.
- */
- private String fStateString;
+ private final Map<String, Object> fStyleMap;
+
+ private final Map<String, Object> fReadOnlyStyleMap;
// ------------------------------------------------------------------------
// Constructors
/**
* Creates a state item with given color and unspecified name.
*
- * @param stateColor A state color
+ * @param stateColor
+ * A state color
*/
public StateItem(RGB stateColor) {
this(stateColor, UNDEFINED_STATE_NAME);
/**
* Creates a state color - state string pair.
*
- * @param stateColor A state color
- * @param stateString A state string
+ * @param stateColor
+ * A state color
+ * @param stateString
+ * A state string
*/
public StateItem(RGB stateColor, String stateString) {
- fStateColor = stateColor;
- fStateString = stateString;
+ int stateColorInt = stateColor.red << 24 | stateColor.green << 16 | stateColor.blue << 8 | 0xff;
+ fStyleMap = new HashMap<>();
+ fReadOnlyStyleMap = Collections.unmodifiableMap(fStyleMap);
+ fStyleMap.put(ITimeEventStyleStrings.fillStyle(), ITimeEventStyleStrings.solidColorFillStyle());
+ fStyleMap.put(ITimeEventStyleStrings.fillColor(), stateColorInt);
+ fStyleMap.put(ITimeEventStyleStrings.label(), stateString);
}
// ------------------------------------------------------------------------
* @return Returns the state color.
*/
public RGB getStateColor() {
- return fStateColor;
+ int rgbInt = (int) fStyleMap.getOrDefault(ITimeEventStyleStrings.fillColor(), UNDEFINED_COLOR_VALUE);
+ return new RGB((rgbInt >> 24) & 0xff, (rgbInt >> 16) & 0xff, (rgbInt >> 8) & 0xff);
}
/**
* Sets the state color.
*
- * @param stateColor A state color to set
+ * @param stateColor
+ * A state color to set
*/
public void setStateColor(RGB stateColor) {
- fStateColor = stateColor;
+ fStyleMap.put(ITimeEventStyleStrings.fillColor(), stateColor);
}
/**
* @return the state string.
*/
public String getStateString() {
- return fStateString;
+ return String.valueOf(fStyleMap.getOrDefault(ITimeEventStyleStrings.label(), UNDEFINED_STATE_NAME));
}
/**
* Sets the state string
- * @param stateString A state string to set
+ *
+ * @param stateString
+ * A state string to set
*/
public void setStateString(String stateString) {
- fStateString = stateString;
+ fStyleMap.put(ITimeEventStyleStrings.label(), stateString);
+ }
+
+ /**
+ * Gets the height factor of a given state (how thick it will be when
+ * displayed)
+ *
+ * @return The map of styles
+ *
+ * @since 2.4
+ */
+ public Map<String, Object> getStyleMap() {
+ return fReadOnlyStyleMap;
}
}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2017 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * <p>
+ * <em>Time event styles</em>, this is for reference purposes. Many values will
+ * be unsupported.
+ * </p>
+ * <p>
+ * Special care is needed when populating the map as it is untyped. The API is
+ * as follows
+ * </p>
+ * <ul>
+ * <li>{@link #label()} a <em>String</em> to show in the legend</li>
+ * <li>{@link #fillStyle()} can be {@link #solidColorFillStyle()},
+ * {@link #gradientColorFillStyle()} or {@link #hatchPatternFillStyle()}.</li>
+ * <li>{@link #heightFactor()} a <em>Float</em> between 0 and 1.0f</li>
+ * <li>{@link #fillColor()} an <em>integer</em> encoding RGBA over 4 bytes (1
+ * byte red, 1 byte green, 1 byte blue, 1 byte alpha)</li>
+ * <li>{@link #fillColorEnd()} an <em>integer</em> encoding RGBA over 4 bytes (1
+ * byte red, 1 byte green, 1 byte blue, 1 byte alpha)</li>
+ * <li>{@link #borderColor()} an <em>integer</em> encoding RGBA over 4 bytes (1
+ * byte red, 1 byte green, 1 byte blue, 1 byte alpha)</li>
+ * <li>{@link #borderEnable()} a <em>boolean</em></li>
+ * <li>{@link #borderThickness()} an <em>integer</em></li>
+ * </ul>
+ *
+ * @author Matthew Khouzam
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @since 2.4
+ */
+@NonNullByDefault
+public interface ITimeEventStyleStrings {
+
+ /**
+ * The label to display in the legend
+ *
+ * @return the key to get the value
+ */
+ static String label() {
+ return ".label"; //$NON-NLS-1$
+ }
+
+ /**
+ * Height factor, can be between 0.0 and 1.0f.
+ *
+ * @return the key to get the value
+ */
+ static String heightFactor() {
+ return ".height.factor"; //$NON-NLS-1$
+ }
+
+ /**
+ * Fill style, can be {@link #solidColorFillStyle()},
+ * {@link #gradientColorFillStyle()} or {@link #hatchPatternFillStyle()}
+ *
+ * @return the key to get the value
+ */
+ static String fillStyle() {
+ return ".fill";//$NON-NLS-1$
+ }
+
+ /**
+ * Color fill style, this is a solid color, so it should make an event that
+ * is uniformly filled with a color. The color is defined in the
+ * {@link #fillColor()} parameter.
+ *
+ * @see #fillStyle()
+ *
+ * @return the color fill style
+ */
+ static String solidColorFillStyle() {
+ return "color"; //$NON-NLS-1$
+ }
+
+ /**
+ * Color fill style, this is a gradient color, it should make an event that
+ * transitions from {@link #fillColor()} to {@link #fillColorEnd()}.
+ *
+ * @see #fillStyle()
+ *
+ * @return the color fill style
+ */
+ static String gradientColorFillStyle() {
+ return "gradient"; //$NON-NLS-1$
+ }
+
+ /**
+ * Color fill style, this is a hatch pattern, it should make an event that
+ * has a hatch pattern with {@link #fillColor()} and
+ * {@link #fillColorEnd()}.
+ *
+ * @see #fillStyle()
+ * @return the color fill style
+ */
+ static String hatchPatternFillStyle() {
+ return "hatch"; //$NON-NLS-1$
+ }
+
+ /**
+ * Fill color, used in all styles except for image.
+ *
+ * @return the key to get the value
+ */
+ static String fillColor() {
+ return ".fill.color";//$NON-NLS-1$
+ }
+
+ /**
+ * Second fill color, used in gradients
+ *
+ * @return the key to get the value
+ */
+ static String fillColorEnd() {
+ return ".fill.color_end";//$NON-NLS-1$
+ }
+
+ /**
+ * Shadow the time event
+ *
+ * @return the key to get the value
+ */
+ static String shadowEnabled() {
+ return ".shadow.enable";//$NON-NLS-1$
+ }
+
+ /**
+ * Border
+ *
+ * @return the key to get the value
+ */
+ static String borderEnable() {
+ return ".border.enable";//$NON-NLS-1$
+ }
+
+ /**
+ * Border thickness
+ *
+ * @return the key to get the value
+ */
+ static String borderThickness() {
+ return ".border.weight";//$NON-NLS-1$
+ }
+
+ /**
+ * Border color
+ *
+ * @return the key to get the value
+ */
+ static String borderColor() {
+ return ".border.color";//$NON-NLS-1$
+ }
+
+}
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
+import org.eclipse.tracecompass.common.core.log.TraceCompassLog;
import org.eclipse.tracecompass.common.core.math.SaturatedArithmetic;
import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
import org.eclipse.tracecompass.tmf.ui.signal.TmfTimeViewAlignmentInfo;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ILinkEvent;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.IMarkerEvent;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEvent;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEventStyleStrings;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.Utils.Resolution;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.Utils.TimeFormat;
MouseWheelListener, MouseTrackListener, TraverseListener, ISelectionProvider,
MenuDetectListener, ITmfTimeGraphDrawingHelper, ITimeGraphColorListener, Listener {
- /** Constant indicating that all levels of the time graph should be expanded */
+ /**
+ * Constant indicating that all levels of the time graph should be expanded
+ */
public static final int ALL_LEVELS = AbstractTreeViewer.ALL_LEVELS;
private static final int DRAG_MARGIN = 5;
private static final int DRAG_ZOOM = 3;
private static final int DRAG_SELECTION = 4;
- private static final int CUSTOM_ITEM_HEIGHT = -1; // get item height from provider
+ /**
+ * Get item height from provider
+ */
+ private static final int CUSTOM_ITEM_HEIGHT = -1;
private static final double ZOOM_FACTOR = 1.5;
private static final double ZOOM_IN_FACTOR = 0.8;
private static final int SNAP_WIDTH = 3;
private static final int ARROW_HOVER_MAX_DIST = 5;
- private static final double ARROW_RATIO = Math.sqrt(3) / 2; // base to height ratio
-
+ /**
+ * base to height ratio
+ */
+ private static final double ARROW_RATIO = Math.sqrt(3) / 2;
private static final int NO_STATUS = -1;
private static final int STATUS_WITHOUT_CURSOR_TIME = -2;
private static final int MAX_LABEL_LENGTH = 256;
- private static final int PPI = 72; // points per inch
+ /** points per inch */
+ private static final int PPI = 72;
private static final int DPI = Display.getDefault().getDPI().y;
private static final int VERTICAL_ZOOM_DELAY = 400;
private int fDragX0 = 0;
private int fDragX = 0;
private boolean fHasNamespaceFocus = false;
- private long fDragTime0 = 0; // used to preserve accuracy of modified selection
+ /**
+ * Used to preserve accuracy of modified selection
+ */
+ private long fDragTime0 = 0;
private int fIdealNameSpace = 0;
private boolean fAutoResizeColumns = true;
private long fTime0bak;
private int fBorderWidth = 0;
private int fHeaderHeight = 0;
+ private boolean fFirstHeightWarning = true;
+
/**
* Standard constructor
*
/**
* Sets the timegraph provider used by this timegraph viewer.
*
- * @param timeGraphProvider the timegraph provider
+ * @param timeGraphProvider
+ * the timegraph provider
*/
public void setTimeGraphProvider(ITimeGraphPresentationProvider timeGraphProvider) {
fTimeGraphProvider = timeGraphProvider;
* Assign the status line manager
*
* @param statusLineManager
- * The status line manager, or null to disable status line messages
+ * The status line manager, or null to disable status line
+ * messages
*/
public void setStatusLineManager(IStatusLineManager statusLineManager) {
if (fStatusLineManager != null && statusLineManager == null) {
}
redraw();
}
+
@Override
public void controlMoved(ControlEvent e) {
redraw();
/**
* Refresh the links (arrows) of this widget
*
- * @param events The link event list
+ * @param events
+ * The link event list
*/
public void refreshArrows(List<ILinkEvent> events) {
fItemData.refreshArrows(events);
*/
public void setTopIndex(int idx) {
int index = Math.min(idx, fItemData.fExpandedItems.length - countPerPage());
- index = Math.max(0, index);
+ index = Math.max(0, index);
fTopIndex = index;
redraw();
}
}
/**
- * Set the expanded state of a given entry to certain relative level.
- * It will call fireTreeEvent() for each changed entry. At the end
- * it will call redraw().
+ * Set the expanded state of a given entry to certain relative level. It
+ * will call fireTreeEvent() for each changed entry. At the end it will call
+ * redraw().
*
* @param entry
* The entry
}
/*
- * Inner class for finding relative level with at least one
- * collapsed entry.
+ * Inner class for finding relative level with at least one collapsed entry.
*/
private class SearchNode {
SearchNode(ITimeGraphEntry e, int l) {
entry = e;
level = l;
}
+
ITimeGraphEntry entry;
int level;
}
}
/**
- * Set the expanded state of a given entry to certain relative level.
- * It will call fireTreeEvent() for each changed entry. No redraw is done.
+ * Set the expanded state of a given entry to certain relative level. It
+ * will call fireTreeEvent() for each changed entry. No redraw is done.
*
* @param entry
* The entry
* Menu event callback on {@link ITimeGraphEntry}s
*
* @param event
- * The MenuDetectEvent, with field {@link TypedEvent#data} set to the selected {@link ITimeGraphEntry}
+ * The MenuDetectEvent, with field {@link TypedEvent#data} set to
+ * the selected {@link ITimeGraphEntry}
*/
private void fireMenuEventOnTimeGraphEntry(MenuDetectEvent event) {
for (MenuDetectListener listener : fTimeGraphEntryMenuListeners) {
* Menu event callback on {@link ITimeEvent}s
*
* @param event
- * The MenuDetectEvent, with field {@link TypedEvent#data} set to the selected {@link ITimeEvent}
+ * The MenuDetectEvent, with field {@link TypedEvent#data} set to
+ * the selected {@link ITimeEvent}
*/
private void fireMenuEventOnTimeEvent(MenuDetectEvent event) {
for (MenuDetectListener listener : fTimeEventMenuListeners) {
nextTime = endTime;
}
} else if (n == -1 && nextEvent.getTime() + nextEvent.getDuration() < selectedTime) {
- // for previous event go to its end time unless we were already there
+ // for previous event go to its end time unless we were already
+ // there
nextTime = nextEvent.getTime() + nextEvent.getDuration();
}
if (extend) {
/**
* Zoom based on mouse cursor location with mouse scrolling
*
- * @param zoomIn true to zoom in, false to zoom out
+ * @param zoomIn
+ * true to zoom in, false to zoom out
*/
public void zoom(boolean zoomIn) {
int globalX = getDisplay().getCursorLocation().x;
/**
* Hide arrows
*
- * @param hideArrows true to hide arrows
+ * @param hideArrows
+ * true to hide arrows
*/
public void hideArrows(boolean hideArrows) {
fHideArrows = hideArrows;
Point size = getSize();
return x >= fTimeProvider.getNameSpace() && x < size.x && y >= 0 && y < size.y;
}
+
/**
* Gets the {@link ITimeGraphEntry} at the given location.
*
int timeWidth = size.x - nameWidth - RIGHT_MARGIN;
if (x >= 0 && size.x >= nameWidth) {
if (time1 - time0 > timeWidth) {
- // nanosecond smaller than one pixel: use the first integer nanosecond of this pixel's time range
+ // nanosecond smaller than one pixel: use the first integer
+ // nanosecond of this pixel's time range
hitTime = time0 + (long) Math.ceil((time1 - time0) * ((double) x / timeWidth));
} else {
- // nanosecond greater than one pixel: use the nanosecond that covers this pixel start position
+ // nanosecond greater than one pixel: use the nanosecond that
+ // covers this pixel start position
hitTime = time0 + (long) Math.floor((time1 - time0) * ((double) x / timeWidth));
}
}
/**
* Get the bounds of the specified entry relative to its parent time graph.
*
- * @param entry the time graph entry
+ * @param entry
+ * the time graph entry
* @return the bounds of the entry, or null if the entry is not visible
* @since 2.3
*/
/**
* Draw the background layer. Fills the background of the control's name
- * space and states space, updates the background of items if necessary,
- * and draws the item's name text and middle line.
+ * space and states space, updates the background of items if necessary, and
+ * draws the item's name text and middle line.
*
* @param bounds
* The bounds of the control
break;
}
Item item = fItemData.fExpandedItems[i];
- // draw the background of selected item and items with no time events
- if (! item.fEntry.hasTimeEvents()) {
+ // draw the background of selected item and items with no time
+ // events
+ if (!item.fEntry.hasTimeEvents()) {
gc.setBackground(getColorScheme().getBkColorGroup(item.fSelected, fIsInFocus));
gc.fillRectangle(itemRect);
} else if (item.fSelected) {
*
* The algorithm was taken from this site, not the code itself
*/
- private static void drawArrowHead(int x0, int y0, int x1, int y1, GC gc)
- {
+ private static void drawArrowHead(int x0, int y0, int x1, int y1, GC gc) {
int factor = 10;
double cos = 0.9510;
double sin = 0.3090;
}
boolean visible = rect.width == 0 ? false : true;
rect.width = Math.max(1, rect.width);
- Color black = Display.getDefault().getSystemColor(SWT.COLOR_BLACK);
+ Color black = Display.getDefault().getSystemColor(SWT.COLOR_BLACK);
gc.setForeground(black);
+ Map<String, Object> styleMap = fTimeGraphProvider.getEventStyle(event);
+ float heightFactor = (float) styleMap.getOrDefault(ITimeEventStyleStrings.heightFactor(), 1.0f);
+ if (heightFactor > 1.0 || heightFactor < 0) {
+ if (fFirstHeightWarning) {
+ TraceCompassLog.getLogger(this.getClass()).warning("Heightfactor out of range : " + heightFactor + " for event " + event.toString() + " - clamping results"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
+ fFirstHeightWarning = false;
+ }
+ heightFactor = Math.max(0.0f, Math.min(1.0f, heightFactor));
+ }
+
+ int height = (int) (rect.height * heightFactor);
+ Rectangle drawRect = new Rectangle(rect.x, rect.y + ((rect.height - height) / 2), rect.width, height);
if (colorIdx == ITimeGraphPresentationProvider.TRANSPARENT) {
if (visible) {
// Only draw the top and bottom borders
- gc.drawLine(rect.x, rect.y, rect.x + rect.width - 1, rect.y);
- gc.drawLine(rect.x, rect.y + rect.height - 1, rect.x + rect.width - 1, rect.y + rect.height - 1);
- if (rect.width == 1) {
- gc.drawPoint(rect.x, rect.y - 2);
+ gc.drawLine(drawRect.x, drawRect.y, drawRect.x + drawRect.width - 1, drawRect.y);
+ gc.drawLine(drawRect.x, drawRect.y + drawRect.height - 1, drawRect.x + drawRect.width - 1, drawRect.y + drawRect.height - 1);
+ if (drawRect.width == 1) {
+ gc.drawPoint(drawRect.x, drawRect.y - 2);
}
}
- fTimeGraphProvider.postDrawEvent(event, rect, gc);
+ fTimeGraphProvider.postDrawEvent(event, drawRect, gc);
return false;
}
Color stateColor = null;
// fill all rect area
gc.setBackground(stateColor);
if (visible) {
- gc.fillRectangle(rect);
+ gc.fillRectangle(drawRect);
} else if (fBlendSubPixelEvents) {
gc.setAlpha(128);
- gc.fillRectangle(rect);
+ gc.fillRectangle(drawRect);
gc.setAlpha(255);
}
if (reallySelected) {
- gc.drawLine(rect.x, rect.y - 1, rect.x + rect.width - 1, rect.y - 1);
- gc.drawLine(rect.x, rect.y + rect.height, rect.x + rect.width - 1, rect.y + rect.height);
+ gc.drawLine(drawRect.x, drawRect.y - 1, drawRect.x + drawRect.width - 1, drawRect.y - 1);
+ gc.drawLine(drawRect.x, drawRect.y + drawRect.height, drawRect.x + drawRect.width - 1, drawRect.y + drawRect.height);
}
if (!visible) {
- gc.drawPoint(rect.x, rect.y - 2);
+ gc.drawPoint(drawRect.x, drawRect.y - 2);
}
- fTimeGraphProvider.postDrawEvent(event, rect, gc);
+ fTimeGraphProvider.postDrawEvent(event, drawRect, gc);
return visible;
}
final int PREFERRED_HEIGHT = 13;
final int MIN_MARGIN = 1;
final int MAX_MARGIN = 6;
- return height <= MARGIN_THRESHOLD ? 0 :
- Math.max(Math.min(height - PREFERRED_HEIGHT, MAX_MARGIN), MIN_MARGIN);
+ return height <= MARGIN_THRESHOLD ? 0 : Math.max(Math.min(height - PREFERRED_HEIGHT, MAX_MARGIN), MIN_MARGIN);
}
private void setFontForHeight(int pixels, GC gc) {
* Provide the possibility to control the wait cursor externally e.g. data
* requests in progress
*
- * @param waitInd Should we wait indefinitely?
+ * @param waitInd
+ * Should we wait indefinitely?
*/
public void waitCursor(boolean waitInd) {
// Update cursor as indicated
updateCursor(e.x, e.stateMask);
fTimeGraphScale.setDragRange(fDragX0, fDragX);
} else {
- idx = getItemIndexAtY(e.y);
- selectItem(idx, false);
- fireSelectionChanged();
+ idx = getItemIndexAtY(e.y);
+ selectItem(idx, false);
+ fireSelectionChanged();
}
}
}
} else if (e.button == fDragButton && DRAG_SPLIT_LINE == fDragState) {
fDragState = DRAG_NONE;
redraw();
- } else if (e.button == fDragButton && DRAG_SELECTION == fDragState) {
+ } else if (e.button == fDragButton && DRAG_SELECTION == fDragState) {
fDragState = DRAG_NONE;
if (fDragX == fDragX0) { // click without selecting anything
long time = getTimeAtX(e.x);
}
/*
- * On some platforms the mouse scroll event is sent to the
- * control that has focus even if it is not under the cursor.
- * Handle the event only if over the time graph control.
+ * On some platforms the mouse scroll event is sent to the control that
+ * has focus even if it is not under the cursor. Handle the event only
+ * if over the time graph control.
*/
Point size = getSize();
Rectangle bounds = new Rectangle(0, 0, size.x, size.y);
zoom(e.count > 0);
} else if (horizontalScroll) {
horizontalScroll(e.count > 0);
- } else if (verticalScroll){
+ } else if (verticalScroll) {
setTopIndex(getTopIndex() - e.count);
}
}
/**
* Set the minimum item width
*
- * @param width The minimum width
+ * @param width
+ * The minimum width
*/
public void setMinimumItemWidth(int width) {
this.fMinimumItemWidth = width;
}
/**
- * @param filter The filter object to be attached to the view
+ * @param filter
+ * The filter object to be attached to the view
*/
public void addFilter(@NonNull ViewerFilter filter) {
if (!fFilters.contains(filter)) {
}
/**
- * @param filter The filter object to be attached to the view
+ * @param filter
+ * The filter object to be attached to the view
*/
public void removeFilter(@NonNull ViewerFilter filter) {
fFilters.remove(filter);
fEventColorMap[i] = fResourceManager.createColor(stateItems[i].getStateColor());
}
} else {
- fEventColorMap = new Color[] { };
+ fEventColorMap = new Color[] {};
}
redraw();
}
/* existing items keep their old expanded state */
item.fExpanded = oldItem.fExpanded;
} else {
- /* new items set the expanded state according to auto-expand level */
+ /*
+ * new items set the expanded state according to auto-expand
+ * level
+ */
item.fExpanded = fAutoExpandLevel == ALL_LEVELS || level < fAutoExpandLevel;
}
item.fHasChildren = true;
Point p = toControl(e.x, e.y);
if (e.detail == SWT.MENU_MOUSE && isOverTimeSpace(p.x, p.y)) {
if (fPendingMenuDetectEvent == null) {
- /* Feature in Linux. The MenuDetectEvent is received before mouseDown.
- * Store the event and trigger it later just before handling mouseUp.
- * This allows for the method to detect if mouse is used to drag zoom.
+ /*
+ * Feature in Linux. The MenuDetectEvent is received before
+ * mouseDown. Store the event and trigger it later just before
+ * handling mouseUp. This allows for the method to detect if
+ * mouse is used to drag zoom.
*/
fPendingMenuDetectEvent = e;
/*