blob: 5cad68c34ca0f4f4128c73328d4dcebdc7908b04 [file] [log] [blame]
/**********************************************************************
* Copyright (c) 2005, 2014 IBM Corporation, Ericsson
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM - Initial API and implementation
* Bernd Hufmann - Updated for TMF
**********************************************************************/
package org.eclipse.tracecompass.tmf.ui.views.uml2sd;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.swt.SWT;
import org.eclipse.swt.accessibility.ACC;
import org.eclipse.swt.accessibility.Accessible;
import org.eclipse.swt.accessibility.AccessibleAdapter;
import org.eclipse.swt.accessibility.AccessibleControlAdapter;
import org.eclipse.swt.accessibility.AccessibleControlEvent;
import org.eclipse.swt.accessibility.AccessibleEvent;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.tracecompass.internal.tmf.ui.Activator;
import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.AsyncMessage;
import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.AsyncMessageReturn;
import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.BaseMessage;
import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.ExecutionOccurrence;
import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.Frame;
import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.GraphNode;
import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.ITimeRange;
import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.Lifeline;
import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.Metrics;
import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.SDTimeEvent;
import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.SyncMessage;
import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IColor;
import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.impl.ColorImpl;
import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.SDViewPref;
import org.eclipse.tracecompass.tmf.ui.views.uml2sd.util.TimeEventComparator;
/**
* <p>
* The time compression bar implementation.
* </p>
*
* @version 1.0
* @author sveyrier
*/
public class TimeCompressionBar extends ScrollView implements DisposeListener {
// ------------------------------------------------------------------------
// Constants
// ------------------------------------------------------------------------
private static final int BASE_RED_VALUE = 255;
private static final int BASE_GREEN_BLUE_VALUE = 225;
private static final int COLOR_STEP = 25;
private static final int NUMBER_STEPS = 10;
// ------------------------------------------------------------------------
// Attributes
// ------------------------------------------------------------------------
/**
* The listener list
*/
private List<ITimeCompressionListener> fListenerList = null;
/**
* The current frame displayed.
*/
private Frame fFrame = null;
/**
* List of time events.
*/
private List<SDTimeEvent> fNodeList = null;
/**
* The minimum time delta.
*/
private ITmfTimestamp fMinTime = TmfTimestamp.fromSeconds(0);
/**
* The maximum time delta.
*/
private ITmfTimestamp fMaxTime = TmfTimestamp.fromSeconds(0);
/**
* The current zoom value.
*/
private float fZoomValue = 1;
/**
* The tooltip to display.
*/
private DrawableToolTip fTooltip = null;
/**
* Array of colors for displaying wight of time deltas.
*/
private ColorImpl[] fColors;
/**
* The accessible object reference.
*/
private Accessible fAccessible = null;
/**
* The focused widget reference.
*/
private int fFocusedWidget = -1;
/**
* The current lifeline.
*/
private Lifeline fLifeline = null;
/**
* The current start event value.
*/
private int fLifelineStart = 0;
/**
* The current number of events.
*/
private int fLifelineNumEvents = 0;
/**
* The Current color of range to display.
*/
private IColor fLifelineColor = null;
/**
* The next graph node y coordinate.
*/
private int fNextNodeY = 0;
/**
* The previous graph node y coordinate.
*/
private int fPrevNodeY = 0;
// ------------------------------------------------------------------------
// Constructors
// ------------------------------------------------------------------------
/**
* Standard constructor
*
* @param parent
* The parent composite
* @param s
* The style bits
*/
public TimeCompressionBar(Composite parent, int s) {
super(parent, s | SWT.NO_BACKGROUND, false);
setVScrollBarMode(ScrollView.ALWAYS_OFF);
setHScrollBarMode(ScrollView.ALWAYS_OFF);
fListenerList = new ArrayList<>();
fColors = new ColorImpl[NUMBER_STEPS];
int greenBlue = BASE_GREEN_BLUE_VALUE;
final int step = COLOR_STEP;
for (int i = 0; i < fColors.length; i++) {
fColors[i] = new ColorImpl(Display.getDefault(), BASE_RED_VALUE, greenBlue, greenBlue);
greenBlue -= step;
}
super.addDisposeListener(this);
fAccessible = getViewControl().getAccessible();
fAccessible.addAccessibleListener(new AccessibleAdapter() {
@Override
public void getName(AccessibleEvent e) {
// Case toolTip
if (e.childID == 0) {
if (fTooltip != null) {
e.result = fTooltip.getAccessibleText();
}
} else if (e.childID == 1) {
createFakeTooltip();
e.result = fTooltip.getAccessibleText();
}
}
});
fAccessible.addAccessibleControlListener(new AccessibleControlAdapter() {
@Override
public void getFocus(AccessibleControlEvent e) {
if (fFocusedWidget == -1) {
e.childID = ACC.CHILDID_SELF;
}
else {
e.childID = fFocusedWidget;
}
}
@Override
public void getRole(AccessibleControlEvent e) {
switch (e.childID) {
case ACC.CHILDID_SELF:
e.detail = ACC.ROLE_CLIENT_AREA;
break;
case 0:
e.detail = ACC.ROLE_TOOLTIP;
break;
case 1:
e.detail = ACC.ROLE_LABEL;
break;
default:
break;
}
}
@Override
public void getState(AccessibleControlEvent e) {
e.detail = ACC.STATE_FOCUSABLE;
if (e.childID == ACC.CHILDID_SELF) {
e.detail |= ACC.STATE_FOCUSED;
} else {
e.detail |= ACC.STATE_SELECTABLE;
if (e.childID == fFocusedWidget) {
e.detail |= ACC.STATE_FOCUSED | ACC.STATE_SELECTED | ACC.STATE_CHECKED;
}
}
}
});
getViewControl().addTraverseListener(new LocalTraverseListener());
addTraverseListener(new LocalTraverseListener());
getViewControl().addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
redraw();
}
@Override
public void focusLost(FocusEvent e) {
redraw();
}
});
}
// ------------------------------------------------------------------------
// Methods
// ------------------------------------------------------------------------
/**
* Sets the focus widget
*
* @param newFocusShape
* widget reference to set
*/
void setFocus(int newFocusShape) {
fFocusedWidget = newFocusShape;
if (fFocusedWidget == -1) {
getViewControl().getAccessible().setFocus(ACC.CHILDID_SELF);
} else {
getViewControl().getAccessible().setFocus(fFocusedWidget);
}
}
/**
* Sets the current frame.
*
* @param theFrame
* The frame to set
*/
public void setFrame(Frame theFrame) {
fFrame = theFrame;
fMinTime = fFrame.getMinTime();
fMaxTime = fFrame.getMaxTime();
}
@Override
protected void drawContents(GC gc, int clipx, int clipy, int clipw, int cliph) {
if (fFrame == null) {
return;
}
fNodeList = new ArrayList<>();
int messageArraysStep = 1;
if ((Metrics.getMessageFontHeigth() + Metrics.MESSAGES_NAME_SPACING * 2) * fZoomValue < Metrics.MESSAGE_SIGNIFICANT_VSPACING + 1) {
messageArraysStep = Math.round(Metrics.MESSAGE_SIGNIFICANT_VSPACING + 1 / ((Metrics.getMessageFontHeigth() + Metrics.MESSAGES_NAME_SPACING * 2) * fZoomValue));
}
int firstVisible = fFrame.getFirstVisibleSyncMessage();
if (firstVisible > 0) {
firstVisible = firstVisible - 1;
}
for (int i = firstVisible; i < fFrame.syncMessageCount(); i = i + messageArraysStep) {
SyncMessage m = fFrame.getSyncMessage(i);
if (addMessageIfVisible(m)) {
break;
}
}
firstVisible = fFrame.getFirstVisibleSyncMessageReturn();
if (firstVisible > 0) {
firstVisible = firstVisible - 1;
}
for (int i = firstVisible; i < fFrame.syncMessageReturnCount(); i = i + messageArraysStep) {
SyncMessage m = fFrame.getSyncMessageReturn(i);
if (addMessageIfVisible(m)) {
break;
}
}
firstVisible = fFrame.getFirstVisibleAsyncMessage();
if (firstVisible > 0) {
firstVisible = firstVisible - 1;
}
for (int i = firstVisible; i < fFrame.asyncMessageCount(); i = i + messageArraysStep) {
BaseMessage m = fFrame.getAsyncMessage(i);
if (addMessageIfVisible(m)) {
break;
}
}
firstVisible = fFrame.getFirstVisibleAsyncMessageReturn();
if (firstVisible > 0) {
firstVisible = firstVisible - 1;
}
for (int i = firstVisible; i < fFrame.asyncMessageReturnCount(); i = i + messageArraysStep) {
AsyncMessageReturn m = fFrame.getAsyncMessageReturn(i);
if (addMessageIfVisible(m)) {
break;
}
}
List<SDTimeEvent> executionOccurrencesWithTime = fFrame.getExecutionOccurrencesWithTime();
if (executionOccurrencesWithTime != null) {
fNodeList.addAll(executionOccurrencesWithTime);
}
SDTimeEvent[] temp = fNodeList.toArray(new SDTimeEvent[fNodeList.size()]);
Arrays.sort(temp, new TimeEventComparator());
fNodeList = Arrays.asList(temp);
Image dbuffer = new Image(getDisplay(), getClientArea().width, getClientArea().height);
GC gcim = new GC(dbuffer);
for (int i = 0; i < fNodeList.size() - 1; i++) {
SDTimeEvent m1 = fNodeList.get(i);
SDTimeEvent m2 = fNodeList.get(i + 1);
if ((SDViewPref.getInstance().excludeExternalTime()) && ((m1.getGraphNode() instanceof BaseMessage) && (m2.getGraphNode() instanceof BaseMessage))) {
BaseMessage mes1 = (BaseMessage) m1.getGraphNode();
BaseMessage mes2 = (BaseMessage) m2.getGraphNode();
if ((mes2.getStartLifeline() == null) || (mes1.getEndLifeline() == null)) {
continue;
}
}
fMinTime = fFrame.getMinTime();
fMaxTime = fFrame.getMaxTime();
ITmfTimestamp minMaxdelta = fMaxTime.getDelta(fMinTime);
double gr = (minMaxdelta.getValue()) / (double) NUMBER_STEPS;
ITmfTimestamp delta = m2.getTime().getDelta(m1.getTime()).getDelta(fMinTime);
long absDelta = Math.abs(delta.getValue());
ColorImpl color;
if (gr != 0) {
int colIndex = Math.round((float) (absDelta / gr));
if (colIndex < fColors.length && colIndex > 0) {
color = fColors[colIndex - 1];
} else if (colIndex <= 0) {
color = fColors[0];
} else {
color = fColors[fColors.length - 1];
}
} else {
color = fColors[0];
}
if (color.getColor() instanceof Color) {
gcim.setBackground((Color) color.getColor());
}
PairOfYs poy = adjustHeights(m1, m2);
int y1 = poy.getY1();
int y2 = poy.getY2();
gcim.fillRectangle(contentsToViewX(0), contentsToViewY(Math.round(y1 * fZoomValue)), 10, Math.round((y2 - y1) * fZoomValue) + 1);
if (messageArraysStep == 1) {
Color backupColor = gcim.getForeground();
gcim.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
gcim.drawRectangle(contentsToViewX(0), contentsToViewY(Math.round(y1 * fZoomValue)), 9, Math.round((y2 - y1) * fZoomValue));
gcim.setForeground(backupColor);
}
}
if (getViewControl().isFocusControl() || isFocusControl()) {
gcim.drawFocus(contentsToViewX(0), contentsToViewY(Math.round(fPrevNodeY * fZoomValue)), contentsToViewX(10), Math.round((fNextNodeY - fPrevNodeY) * fZoomValue));
}
try {
gc.drawImage(dbuffer, 0, 0, getClientArea().width, getClientArea().height, 0, 0, getClientArea().width, getClientArea().height);
} catch (Exception e) {
Activator.getDefault().logError("Error drawing image", e); //$NON-NLS-1$
}
gcim.dispose();
dbuffer.dispose();
gc.dispose();
}
private boolean addMessageIfVisible(BaseMessage m) {
if (m instanceof ITimeRange) {
ITimeRange timeRange = (ITimeRange) m;
if (timeRange.hasTimeInfo()) {
SDTimeEvent t = new SDTimeEvent(timeRange.getStartTime(), m.getStartOccurrence(), timeRange);
fNodeList.add(t);
if (m instanceof AsyncMessage) {
t = new SDTimeEvent(timeRange.getEndTime(), m.getEndOccurrence(), timeRange);
fNodeList.add(t);
}
return isNotVisible(m);
}
}
return false;
}
private boolean isNotVisible(BaseMessage m) {
return m.getY() * fZoomValue > getContentsY() + getVisibleHeight();
}
private static int addHeightIfAsynchronousMessage(SDTimeEvent timeEvent, int yPos) {
if (timeEvent.getGraphNode() instanceof AsyncMessage) {
AsyncMessage as = (AsyncMessage) timeEvent.getGraphNode();
if (as.getEndTime() == timeEvent.getTime()) {
return yPos + as.getHeight();
}
}
return yPos;
}
private static int addHeight(SDTimeEvent timeEvent, int yPos) {
ExecutionOccurrence eo = (ExecutionOccurrence) timeEvent.getGraphNode();
if (timeEvent.getEvent() == eo.getEndOccurrence()) {
return yPos + eo.getHeight();
}
return yPos;
}
private static int addHeightIfExecutionOccurence(SDTimeEvent timeWidget, int yPos) {
if (timeWidget.getGraphNode() instanceof ExecutionOccurrence) {
ExecutionOccurrence eo2 = (ExecutionOccurrence) timeWidget.getGraphNode();
if (timeWidget.getEvent() == eo2.getEndOccurrence()) {
return yPos + eo2.getHeight();
}
}
return yPos;
}
/**
* Checks for focus of children.
*
* @param children
* Control to check
* @return true if child is on focus else false
*/
protected boolean checkFocusOnChilds(Control children) {
if (children instanceof Composite) {
Control[] child = ((Composite) children).getChildren();
for (int i = 0; i < child.length; i++) {
if (child[i].isFocusControl()) {
return true;
}
checkFocusOnChilds(child[i]);
}
}
return false;
}
@Override
public boolean isFocusControl() {
Control[] child = getChildren();
for (int i = 0; i < child.length; i++) {
if (child[i].isFocusControl()) {
return true;
}
checkFocusOnChilds(child[i]);
}
return false;
}
@Override
protected void contentsMouseMoveEvent(MouseEvent event) {
if (fTooltip != null) {
fTooltip.hideToolTip();
}
super.contentsMouseMoveEvent(event);
if (!isFocusControl() || getViewControl().isFocusControl()) {
Control[] child = getParent().getChildren();
for (int i = 0; i < child.length; i++) {
if (child[i].isFocusControl()) {
break;
}
}
}
setFocus(-1);
}
@Override
protected void contentsMouseHover(MouseEvent e) {
if (fTooltip == null) {
fTooltip = new DrawableToolTip(this);
}
if (fFrame != null) {
setFocus(0);
for (int i = 0; i < fNodeList.size() - 1; i++) {
SDTimeEvent m1 = fNodeList.get(i);
SDTimeEvent m2 = fNodeList.get(i + 1);
if (skipIfLifelineIsNull(m1, m2)) {
continue;
}
PairOfYs poy = adjustHeights(m1, m2);
int m1Y = Math.round(poy.getY1() * fZoomValue);
int m2Y = Math.round(poy.getY2() * fZoomValue);
if ((m1Y < e.y) && (m2Y >= e.y)) {
ITmfTimestamp delta = m2.getTime().getDelta(m1.getTime());
fTooltip.showToolTip(delta, fMinTime, fMaxTime);
}
}
}
setFocus(0);
}
@Override
protected void contentsMouseExit(MouseEvent e) {
if (fTooltip != null) {
fTooltip.hideToolTip();
}
}
@Override
protected void contentsMouseUpEvent(MouseEvent event) {
selectTimeDelta(event.y, 0);
setFocus();
super.contentsMouseUpEvent(event);
}
/**
* Force the time compression bar to highlight the event occurrences between
* the two given messages. The event occurrences are highlighted on the
* first message's end lifeline
*
* @param mes1
* the first message
* @param mes2
* the second message
*/
public void highlightRegion(BaseMessage mes1, BaseMessage mes2) {
BaseMessage localMes1 = mes1;
BaseMessage localMes2 = mes2;
if (fFrame == null) {
return;
}
if (!(localMes1 instanceof ITimeRange)) {
return;
}
if (!(localMes2 instanceof ITimeRange)) {
return;
}
ITimeRange t1 = (ITimeRange) localMes1;
ITimeRange t2 = (ITimeRange) localMes2;
ITmfTimestamp time1 = t1.getStartTime();
ITmfTimestamp time2 = t2.getStartTime();
int event1 = localMes1.getEventOccurrence();
int event2 = localMes2.getEventOccurrence();
if (localMes1 instanceof AsyncMessage) {
AsyncMessage as = (AsyncMessage) localMes1;
time1 = as.getEndTime();
event1 = as.getEndOccurrence();
}
if (localMes2 instanceof AsyncMessage) {
AsyncMessage as = (AsyncMessage) localMes2;
if (as.getEndOccurrence() > as.getStartOccurrence()) {
time1 = as.getEndTime();
event1 = as.getEndOccurrence();
} else {
time1 = as.getStartTime();
event1 = as.getStartOccurrence();
}
}
if (event1 > event2) {
BaseMessage tempMes = localMes2;
localMes2 = localMes1;
localMes1 = tempMes;
t1 = (ITimeRange) localMes1;
t2 = (ITimeRange) localMes2;
time1 = t1.getStartTime();
time2 = t2.getStartTime();
event1 = localMes1.getEventOccurrence();
event2 = localMes2.getEventOccurrence();
if (localMes1 instanceof AsyncMessage) {
AsyncMessage as = (AsyncMessage) localMes1;
time1 = as.getEndTime();
event1 = as.getEndOccurrence();
}
if (localMes2 instanceof AsyncMessage) {
AsyncMessage as = (AsyncMessage) localMes2;
if (as.getEndOccurrence() > as.getStartOccurrence()) {
time1 = as.getEndTime();
event1 = as.getEndOccurrence();
} else {
time1 = as.getStartTime();
event1 = as.getStartOccurrence();
}
}
}
ITmfTimestamp minMaxdelta = fMaxTime.getDelta(fMinTime);
double gr = (minMaxdelta.getValue()) / (double) NUMBER_STEPS;
ITmfTimestamp delta = time2.getDelta(time1).getDelta(fMinTime);
long absDelta = Math.abs(delta.getValue());
int colIndex = 0;
if (gr != 0) {
colIndex = Math.round((float) (absDelta / gr));
if (colIndex >= fColors.length) {
colIndex = fColors.length - 1;
} else if (colIndex < 0) {
colIndex = 0;
}
} else {
colIndex = 0;
}
for (int j = 0; j < fListenerList.size(); j++) {
ITimeCompressionListener list = fListenerList.get(j);
if (localMes1.getEndLifeline() != null) {
list.deltaSelected(localMes1.getEndLifeline(), event1, event2 - event1, fColors[colIndex]);
} else if (localMes2.getStartLifeline() != null) {
list.deltaSelected(localMes2.getStartLifeline(), event1, event2 - event1, fColors[colIndex]);
} else {
list.deltaSelected(localMes1.getStartLifeline(), event1, event2 - event1, fColors[colIndex]);
}
}
}
/**
* Force the time compression bar to highlight the event occurrences between
* the two given messages. The event occurrences are highlighted on the
* first message's end lifeline
*
* @param mes1
* the first message
* @param mes2
* the second message
*/
public void highlightRegionSync(final BaseMessage mes1, final BaseMessage mes2) {
getDisplay().syncExec(() -> highlightRegion(mes1, mes2));
}
@Override
public void scrollBy(int x, int y) {
// Do nothing
}
/**
* Sets the zoom value.
*
* @param value
* The zoom value to set.
*/
public void setZoom(float value) {
fZoomValue = value;
redraw();
}
/**
* Adds a listener to the time compression listener list to be notified
* about selected deltas.
*
* @param listener
* The listener to add
*/
public void addTimeCompressionListener(ITimeCompressionListener listener) {
if (!fListenerList.contains(listener)) {
fListenerList.add(listener);
}
}
/**
* Removes a time compression listener.
*
* @param listener
* The listener to remove.
*/
public void removeSelectionChangedListener(ITimeCompressionListener listener) {
fListenerList.remove(listener);
}
@Override
public void widgetDisposed(DisposeEvent e) {
if (fTooltip != null) {
fTooltip.dispose();
}
super.removeDisposeListener(this);
for (int i = 0; i < fColors.length; i++) {
fColors[i].dispose();
}
}
@Override
protected void keyPressedEvent(KeyEvent event) {
if (fTooltip != null) {
fTooltip.hideToolTip();
}
if (!isFocusControl() || getViewControl().isFocusControl()) {
Control[] child = getParent().getChildren();
for (int i = 0; i < child.length; i++) {
if (child[i].isFocusControl()) {
break;
}
}
}
setFocus(-1);
boolean top = false;
if (fNextNodeY == 0) {
top = true;
}
if ((fFrame != null) && (fNextNodeY == 0)) {
for (int i = 0; i < fNodeList.size() - 1 && i < 1; i++) {
SDTimeEvent m1 = fNodeList.get(i);
SDTimeEvent m2 = fNodeList.get(i + 1);
if (skipIfLifelineIsNull(m1, m2)) {
continue;
}
PairOfYs poy = adjustHeights(m1, m2);
fPrevNodeY = Math.round(poy.getY1() * fZoomValue);
fNextNodeY = Math.round(poy.getY2() * fZoomValue);
}
}
if (fLifeline != null) {
for (int j = 0; j < fListenerList.size(); j++) {
ITimeCompressionListener list = fListenerList.get(j);
list.deltaSelected(fLifeline, fLifelineStart, fLifelineNumEvents, fLifelineColor);
}
}
if (event.keyCode == SWT.ARROW_DOWN) {
if (!top) {
selectTimeDelta(fNextNodeY + 1, 1);
} else {
selectTimeDelta(fPrevNodeY + 1, 1);
}
setFocus(1);
} else if (event.keyCode == SWT.ARROW_UP) {
selectTimeDelta(fPrevNodeY - 1, 2);
setFocus(1);
} else if (event.keyCode == SWT.ARROW_RIGHT) {
selectTimeDelta(fPrevNodeY, 1);
setFocus(1);
}
super.keyPressedEvent(event);
}
/**
* Selects the time delta for given delta y coordinate and direction.
*
* @param dy
* The delta in y coordinate.
* @param direction
* 0 no direction, 1 = down, 2 = up
*/
protected void selectTimeDelta(int dy, int direction) {
SDTimeEvent lastM1 = null;
SDTimeEvent lastM2 = null;
int lastY1 = 0;
int lastY2 = 0;
boolean done = false;
if (fFrame != null) {
for (int i = 0; i < fNodeList.size() - 1; i++) {
SDTimeEvent m1 = fNodeList.get(i);
SDTimeEvent m2 = fNodeList.get(i + 1);
if (skipIfLifelineIsNull(m1, m2)) {
continue;
}
PairOfYs poy = adjustHeights(m1, m2);
int m1Y = Math.round(poy.getY1() * fZoomValue);
int m2Y = Math.round(poy.getY2() * fZoomValue);
if ((m1Y < dy) && (m2Y > dy) || (!done && m2Y > dy && direction == 1 && lastM1 != null) || (!done && m1Y > dy && direction == 2 && lastM1 != null)) {
if (m1Y > dy && direction == 2) {
m1 = lastM1;
m2 = lastM2;
m1Y = lastY1;
m2Y = lastY2;
}
done = true;
fPrevNodeY = m1Y;
fNextNodeY = m2Y;
ITmfTimestamp minMaxdelta = fMaxTime.getDelta(fMinTime);
double gr = (minMaxdelta.getValue()) / (double) NUMBER_STEPS;
ITmfTimestamp delta = m2.getTime().getDelta(m1.getTime()).getDelta(fMinTime);
long absDelta = Math.abs(delta.getValue());
int colIndex = 0;
if (gr != 0) {
colIndex = Math.round((float) (absDelta / gr));
if (colIndex >= fColors.length) {
colIndex = fColors.length - 1;
} else if (colIndex < 0) {
colIndex = 0;
}
} else {
colIndex = 0;
}
if (m1.getGraphNode() instanceof BaseMessage) {
BaseMessage mes1 = (BaseMessage) m1.getGraphNode();
if (mes1.getEndLifeline() != null) {
fLifeline = mes1.getEndLifeline();
fLifelineStart = m1.getEvent();
fLifelineNumEvents = m2.getEvent() - m1.getEvent();
fLifelineColor = fColors[colIndex];
} else if (m2.getGraphNode() instanceof BaseMessage && ((BaseMessage) m2.getGraphNode()).getStartLifeline() != null) {
fLifeline = ((BaseMessage) m2.getGraphNode()).getStartLifeline();
fLifelineStart = m1.getEvent();
fLifelineNumEvents = m2.getEvent() - m1.getEvent();
fLifelineColor = fColors[colIndex];
} else {
fLifeline = mes1.getStartLifeline();
fLifelineStart = m1.getEvent();
fLifelineNumEvents = m2.getEvent() - m1.getEvent();
fLifelineColor = fColors[colIndex];
}
} else if (m1.getGraphNode() instanceof ExecutionOccurrence) {
if (m2.getGraphNode() instanceof ExecutionOccurrence) {
ExecutionOccurrence eo = (ExecutionOccurrence) m2.getGraphNode();
fLifeline = eo.getLifeline();
fLifelineStart = m1.getEvent();
fLifelineNumEvents = m2.getEvent() - m1.getEvent();
fLifelineColor = fColors[colIndex];
} else {
ExecutionOccurrence eo = (ExecutionOccurrence) m1.getGraphNode();
fLifeline = eo.getLifeline();
fLifelineStart = m1.getEvent();
fLifelineNumEvents = m2.getEvent() - m1.getEvent();
fLifelineColor = fColors[colIndex];
}
}
for (int j = 0; j < fListenerList.size(); j++) {
ITimeCompressionListener list = fListenerList.get(j);
list.deltaSelected(fLifeline, fLifelineStart, fLifelineNumEvents, fLifelineColor);
}
break;
}
lastM1 = m1;
lastM2 = m2;
lastY1 = m1Y;
lastY2 = m2Y;
}
}
}
/**
* Creates a fake tool tip.
*/
protected void createFakeTooltip() {
if (fTooltip == null) {
fTooltip = new DrawableToolTip(this);
}
if (fFrame != null) {
setFocus(0);
for (int i = 0; i < fNodeList.size() - 1; i++) {
SDTimeEvent m1 = fNodeList.get(i);
SDTimeEvent m2 = fNodeList.get(i + 1);
if (skipIfLifelineIsNull(m1, m2)) {
continue;
}
PairOfYs poy = adjustHeights(m1, m2);
int m1Y = Math.round(poy.getY1() * fZoomValue);
int m2Y = Math.round(poy.getY2() * fZoomValue);
if ((m1Y < fPrevNodeY + 1) && (m2Y >= fPrevNodeY + 1)) {
ITmfTimestamp delta = m2.getTime().getDelta(m1.getTime());
fTooltip.showToolTip(delta, fMinTime, fMaxTime);
fTooltip.hideToolTip();
}
}
}
}
private static PairOfYs adjustHeights(SDTimeEvent m1, SDTimeEvent m2) {
int y1 = ((GraphNode) m1.getGraphNode()).getY();
int y2 = ((GraphNode) m2.getGraphNode()).getY();
y1 = addHeightIfAsynchronousMessage(m1, y1);
y2 = addHeightIfAsynchronousMessage(m2, y2);
if (m1.getGraphNode() instanceof ExecutionOccurrence) {
y1 = addHeight(m1, y1);
y2 = addHeightIfExecutionOccurence(m2, y2);
}
return new PairOfYs(y1, y2);
}
private static class PairOfYs {
private final int fY1, fY2;
public PairOfYs(int y1, int y2) {
fY1 = y1;
fY2 = y2;
}
public int getY1() {
return fY1;
}
public int getY2() {
return fY2;
}
}
private static boolean skipIfLifelineIsNull(SDTimeEvent m1, SDTimeEvent m2) {
if ((SDViewPref.getInstance().excludeExternalTime()) && ((m1.getGraphNode() instanceof BaseMessage) && (m2.getGraphNode() instanceof BaseMessage))) {
BaseMessage mes1 = (BaseMessage) m1.getGraphNode();
BaseMessage mes2 = (BaseMessage) m2.getGraphNode();
if ((mes2.getStartLifeline() == null) || (mes1.getEndLifeline() == null)) {
return true;
}
}
return false;
}
/**
* Traverse Listener implementation.
*/
protected static class LocalTraverseListener implements TraverseListener {
@Override
public void keyTraversed(TraverseEvent e) {
if ((e.detail == SWT.TRAVERSE_TAB_NEXT) || (e.detail == SWT.TRAVERSE_TAB_PREVIOUS)) {
e.doit = true;
}
}
}
}