2015-11-06 19:29:36 +01:00
|
|
|
/*******************************************************************************
|
|
|
|
* Copyright (c) 2015 MINRES Technologies GmbH and others.
|
|
|
|
* 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
|
|
|
|
*
|
|
|
|
* Contributors:
|
|
|
|
* MINRES Technologies GmbH - initial API and implementation
|
|
|
|
*******************************************************************************/
|
|
|
|
package com.minres.scviewer.database.swt.internal;
|
|
|
|
|
|
|
|
import java.util.Collection;
|
2015-11-13 23:44:44 +01:00
|
|
|
import java.util.LinkedList;
|
|
|
|
import java.util.List;
|
2015-11-06 19:29:36 +01:00
|
|
|
|
2015-11-13 23:44:44 +01:00
|
|
|
import org.eclipse.swt.SWT;
|
|
|
|
import org.eclipse.swt.graphics.Color;
|
2015-11-06 19:29:36 +01:00
|
|
|
import org.eclipse.swt.graphics.GC;
|
2015-11-13 23:44:44 +01:00
|
|
|
import org.eclipse.swt.graphics.Path;
|
|
|
|
import org.eclipse.swt.graphics.Point;
|
2015-11-06 19:29:36 +01:00
|
|
|
import org.eclipse.swt.graphics.Rectangle;
|
2015-11-13 23:44:44 +01:00
|
|
|
import org.eclipse.swt.widgets.Display;
|
2015-11-06 19:29:36 +01:00
|
|
|
|
|
|
|
import com.minres.scviewer.database.ITx;
|
|
|
|
import com.minres.scviewer.database.ITxRelation;
|
2015-11-13 23:44:44 +01:00
|
|
|
import com.minres.scviewer.database.ITxStream;
|
2015-11-15 22:15:37 +01:00
|
|
|
import com.minres.scviewer.database.RelationType;
|
2015-11-13 23:44:44 +01:00
|
|
|
import com.minres.scviewer.database.ui.WaveformColors;
|
2015-11-06 19:29:36 +01:00
|
|
|
|
|
|
|
public class ArrowPainter implements IPainter {
|
|
|
|
|
2015-11-15 22:15:37 +01:00
|
|
|
private final int xCtrlOffset = 50;
|
|
|
|
|
|
|
|
private final int yCtrlOffset = 30;
|
2015-11-13 23:44:44 +01:00
|
|
|
|
|
|
|
private WaveformCanvas waveCanvas;
|
|
|
|
|
2015-11-06 19:29:36 +01:00
|
|
|
private ITx tx;
|
|
|
|
|
2015-11-15 22:15:37 +01:00
|
|
|
private List<LinkEntry> iRect;
|
2015-11-13 23:44:44 +01:00
|
|
|
|
2015-11-15 22:15:37 +01:00
|
|
|
private List<LinkEntry> oRect;
|
2015-11-06 19:29:36 +01:00
|
|
|
|
2015-11-13 23:44:44 +01:00
|
|
|
private Rectangle txRectangle;
|
2015-11-15 22:15:37 +01:00
|
|
|
|
|
|
|
private RelationType highlightType;
|
|
|
|
|
2019-03-17 20:03:22 +01:00
|
|
|
private long selectionOffset;
|
|
|
|
|
2015-11-13 23:44:44 +01:00
|
|
|
long scaleFactor;
|
2015-11-15 22:15:37 +01:00
|
|
|
|
2015-11-13 23:44:44 +01:00
|
|
|
boolean deferredUpdate;
|
2015-11-06 19:29:36 +01:00
|
|
|
|
2015-11-15 22:15:37 +01:00
|
|
|
public ArrowPainter(WaveformCanvas waveCanvas, RelationType relationType) {
|
2015-11-06 19:29:36 +01:00
|
|
|
this.waveCanvas = waveCanvas;
|
2015-11-15 22:15:37 +01:00
|
|
|
highlightType=relationType;
|
2015-11-13 23:44:44 +01:00
|
|
|
setTx(null);
|
|
|
|
}
|
2015-11-06 19:29:36 +01:00
|
|
|
|
2015-11-15 22:15:37 +01:00
|
|
|
public RelationType getHighlightType() {
|
|
|
|
return highlightType;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setHighlightType(RelationType highlightType) {
|
|
|
|
this.highlightType = highlightType;
|
|
|
|
}
|
|
|
|
|
2015-11-13 23:44:44 +01:00
|
|
|
public ITx getTx() {
|
|
|
|
return tx;
|
2015-11-06 19:29:36 +01:00
|
|
|
}
|
2015-11-13 23:44:44 +01:00
|
|
|
|
|
|
|
public void setTx(ITx newTx) {
|
|
|
|
this.tx = newTx;
|
2015-11-15 22:15:37 +01:00
|
|
|
iRect = new LinkedList<>();
|
|
|
|
oRect = new LinkedList<>();
|
|
|
|
scaleFactor = waveCanvas.getScaleFactor();
|
|
|
|
if (tx != null) {
|
2015-11-13 23:44:44 +01:00
|
|
|
calculateGeometries();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected void calculateGeometries() {
|
2015-11-15 22:15:37 +01:00
|
|
|
deferredUpdate = false;
|
|
|
|
ITxStream<?> stream = tx.getStream();
|
|
|
|
IWaveformPainter painter = waveCanvas.wave2painterMap.get(stream);
|
|
|
|
if (painter == null) { // stream has been added but painter not yet
|
|
|
|
// created
|
|
|
|
deferredUpdate = true;
|
2015-11-13 23:44:44 +01:00
|
|
|
return;
|
|
|
|
}
|
2019-03-17 20:03:22 +01:00
|
|
|
selectionOffset = waveCanvas.getXOffset();
|
2015-11-15 22:15:37 +01:00
|
|
|
int laneHeight = painter.getHeight() / stream.getMaxConcurrency();
|
2019-03-17 20:03:22 +01:00
|
|
|
txRectangle = new Rectangle((int) (tx.getBeginTime() / scaleFactor-waveCanvas.getXOffset()),
|
2015-11-15 22:15:37 +01:00
|
|
|
waveCanvas.rulerHeight + painter.getVerticalOffset() + laneHeight * tx.getConcurrencyIndex(),
|
|
|
|
(int) ((tx.getEndTime() - tx.getBeginTime()) / scaleFactor), laneHeight);
|
2015-11-13 23:44:44 +01:00
|
|
|
deriveGeom(tx.getIncomingRelations(), iRect, false);
|
|
|
|
deriveGeom(tx.getOutgoingRelations(), oRect, true);
|
|
|
|
}
|
|
|
|
|
2015-11-15 22:15:37 +01:00
|
|
|
protected void deriveGeom(Collection<ITxRelation> relations, List<LinkEntry> res, boolean useTarget) {
|
|
|
|
for (ITxRelation iTxRelation : relations) {
|
|
|
|
ITx otherTx = useTarget ? iTxRelation.getTarget() : iTxRelation.getSource();
|
|
|
|
if (waveCanvas.wave2painterMap.containsKey(otherTx.getStream())) {
|
|
|
|
ITxStream<?> stream = otherTx.getStream();
|
|
|
|
IWaveformPainter painter = waveCanvas.wave2painterMap.get(stream);
|
|
|
|
int laneHeight = painter.getHeight() / stream.getMaxConcurrency();
|
2019-03-17 20:03:22 +01:00
|
|
|
Rectangle bb = new Rectangle((int) (otherTx.getBeginTime() / scaleFactor-waveCanvas.getXOffset()),
|
2015-11-15 22:15:37 +01:00
|
|
|
waveCanvas.rulerHeight + painter.getVerticalOffset()
|
|
|
|
+ laneHeight * otherTx.getConcurrencyIndex(),
|
|
|
|
(int) ((otherTx.getEndTime() - otherTx.getBeginTime()) / scaleFactor), laneHeight);
|
|
|
|
res.add(new LinkEntry(bb, iTxRelation.getRelationType()));
|
2015-11-13 23:44:44 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-06 19:29:36 +01:00
|
|
|
@Override
|
|
|
|
public void paintArea(GC gc, Rectangle area) {
|
2015-11-15 22:15:37 +01:00
|
|
|
Color fgColor = waveCanvas.colors[WaveformColors.REL_ARROW.ordinal()];
|
|
|
|
Color highliteColor = waveCanvas.colors[WaveformColors.REL_ARROW_HIGHLITE.ordinal()];
|
|
|
|
|
|
|
|
if (deferredUpdate || (tx != null && waveCanvas.getScaleFactor() != scaleFactor)) {
|
|
|
|
scaleFactor = waveCanvas.getScaleFactor();
|
2015-11-13 23:44:44 +01:00
|
|
|
calculateGeometries();
|
|
|
|
}
|
2019-03-17 20:03:22 +01:00
|
|
|
if(txRectangle == null) return;
|
|
|
|
int correctionValue = (int)(selectionOffset - waveCanvas.getXOffset());
|
|
|
|
Rectangle correctedTargetRectangle = new Rectangle(txRectangle.x+correctionValue, txRectangle.y, txRectangle.width, txRectangle.height);
|
2015-11-15 22:15:37 +01:00
|
|
|
for (LinkEntry entry : iRect) {
|
2019-03-17 20:03:22 +01:00
|
|
|
Rectangle correctedRectangle = new Rectangle(entry.rectangle.x+correctionValue, entry.rectangle.y, entry.rectangle.width, entry.rectangle.height);
|
2015-11-15 22:15:37 +01:00
|
|
|
Point target = drawPath(gc, highlightType.equals(entry.relationType) ? highliteColor : fgColor,
|
2019-03-17 20:03:22 +01:00
|
|
|
correctedRectangle, correctedTargetRectangle);
|
2015-11-15 22:15:37 +01:00
|
|
|
drawArrow(gc, target);
|
2015-11-13 23:44:44 +01:00
|
|
|
}
|
2015-11-15 22:15:37 +01:00
|
|
|
for (LinkEntry entry : oRect) {
|
2019-03-17 20:03:22 +01:00
|
|
|
Rectangle correctedRectangle = new Rectangle(entry.rectangle.x+correctionValue, entry.rectangle.y, entry.rectangle.width, entry.rectangle.height);
|
|
|
|
Point target = drawPath(gc, highlightType.equals(entry.relationType) ? highliteColor : fgColor, correctedTargetRectangle,
|
|
|
|
correctedRectangle);
|
2015-11-15 22:15:37 +01:00
|
|
|
drawArrow(gc, target);
|
2015-11-13 23:44:44 +01:00
|
|
|
}
|
2015-11-06 19:29:36 +01:00
|
|
|
}
|
|
|
|
|
2015-11-15 22:15:37 +01:00
|
|
|
protected void drawArrow(GC gc, Point target) {
|
|
|
|
gc.drawLine(target.x - 8, target.y - 5, target.x, target.y);
|
|
|
|
gc.drawLine(target.x - 8, target.y + 5, target.x, target.y);
|
|
|
|
}
|
|
|
|
|
2015-11-13 23:44:44 +01:00
|
|
|
protected Point drawPath(GC gc, Color fgColor, Rectangle srcRectangle, Rectangle tgtRectangle) {
|
2015-11-15 22:15:37 +01:00
|
|
|
Point point1 = new Point(0, srcRectangle.y + srcRectangle.height / 2);
|
|
|
|
Point point2 = new Point(0, tgtRectangle.y + tgtRectangle.height / 2);
|
2015-11-13 23:44:44 +01:00
|
|
|
|
|
|
|
point1.x = srcRectangle.x;
|
|
|
|
point2.x = tgtRectangle.x;
|
2015-11-06 19:29:36 +01:00
|
|
|
|
2015-11-15 22:15:37 +01:00
|
|
|
if (point2.x > point1.x + srcRectangle.width)
|
|
|
|
point1.x += srcRectangle.width;
|
|
|
|
if (point1.x > point2.x + tgtRectangle.width)
|
|
|
|
point2.x += tgtRectangle.width;
|
|
|
|
|
|
|
|
Path path = new Path(Display.getCurrent());
|
|
|
|
path.moveTo(point1.x, point1.y);
|
|
|
|
if (point1.y == point2.y) {
|
|
|
|
Point center = new Point((point1.x + point2.x) / 2, point1.y - yCtrlOffset);
|
|
|
|
path.cubicTo(point1.x + xCtrlOffset, point1.y, center.x - xCtrlOffset, center.y, center.x, center.y);
|
|
|
|
path.cubicTo(center.x + xCtrlOffset, center.y, point2.x - xCtrlOffset, point2.y, point2.x, point2.y);
|
2015-11-13 23:44:44 +01:00
|
|
|
} else
|
2015-11-15 22:15:37 +01:00
|
|
|
path.cubicTo(point1.x + xCtrlOffset, point1.y, point2.x - xCtrlOffset, point2.y, point2.x, point2.y);
|
2015-11-13 23:44:44 +01:00
|
|
|
gc.setAntialias(SWT.ON);
|
|
|
|
gc.setForeground(fgColor);
|
|
|
|
gc.drawPath(path);
|
|
|
|
path.dispose();
|
|
|
|
return point2;
|
|
|
|
}
|
2015-11-15 22:15:37 +01:00
|
|
|
|
|
|
|
class LinkEntry {
|
|
|
|
public Rectangle rectangle;
|
|
|
|
public RelationType relationType;
|
|
|
|
|
|
|
|
public LinkEntry(Rectangle rectangle, RelationType relationType) {
|
|
|
|
super();
|
|
|
|
this.rectangle = rectangle;
|
|
|
|
this.relationType = relationType;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-06 19:29:36 +01:00
|
|
|
}
|