- fixed scrolling sync issue
- fixed duplicate db entries
This commit is contained in:
parent
310c9bbb8f
commit
ac942481e3
|
@ -179,7 +179,11 @@ public class Tx implements ITx {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(ITx o) {
|
public int compareTo(ITx o) {
|
||||||
return this.getBeginTime().compareTo(o.getBeginTime());
|
int res = this.getBeginTime().compareTo(o.getBeginTime());
|
||||||
|
if(res!=0)
|
||||||
|
return res;
|
||||||
|
else
|
||||||
|
return this.getId().compareTo(o.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -121,24 +121,19 @@ public class TxDisplay implements PropertyChangeListener, ISelectionProvider, Mo
|
||||||
top.setLayout(new FillLayout(SWT.HORIZONTAL));
|
top.setLayout(new FillLayout(SWT.HORIZONTAL));
|
||||||
|
|
||||||
SashForm topSash = new SashForm(top, SWT.SMOOTH);
|
SashForm topSash = new SashForm(top, SWT.SMOOTH);
|
||||||
topSash.setBackground(topSash.getDisplay().getSystemColor(
|
topSash.setBackground(topSash.getDisplay().getSystemColor(SWT.COLOR_GRAY));
|
||||||
SWT.COLOR_GRAY));
|
|
||||||
|
|
||||||
Composite composite = new Composite(topSash, SWT.NONE);
|
Composite composite = new Composite(topSash, SWT.NONE);
|
||||||
composite.setLayout(new FillLayout(SWT.HORIZONTAL));
|
composite.setLayout(new FillLayout(SWT.HORIZONTAL));
|
||||||
|
|
||||||
SashForm leftSash = new SashForm(composite, SWT.SMOOTH);
|
SashForm leftSash = new SashForm(composite, SWT.SMOOTH);
|
||||||
leftSash.setBackground(leftSash.getDisplay().getSystemColor(
|
leftSash.setBackground(leftSash.getDisplay().getSystemColor(SWT.COLOR_GRAY));
|
||||||
SWT.COLOR_GRAY));
|
|
||||||
|
|
||||||
Composite namePane = createTextPane(leftSash, "Name");
|
Composite namePane = createTextPane(leftSash, "Name");
|
||||||
namePane.setBackground(namePane.getDisplay().getSystemColor(
|
namePane.setBackground(namePane.getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
|
||||||
SWT.COLOR_WIDGET_BACKGROUND));
|
|
||||||
|
|
||||||
nameListScrolled = new ScrolledComposite(namePane, SWT.H_SCROLL
|
nameListScrolled = new ScrolledComposite(namePane, SWT.H_SCROLL | SWT.V_SCROLL);
|
||||||
| SWT.V_SCROLL);
|
nameListScrolled.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
|
||||||
nameListScrolled.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
|
|
||||||
true, 1, 1));
|
|
||||||
nameListScrolled.setExpandHorizontal(true);
|
nameListScrolled.setExpandHorizontal(true);
|
||||||
nameListScrolled.setExpandVertical(true);
|
nameListScrolled.setExpandVertical(true);
|
||||||
nameListScrolled.setAlwaysShowScrollBars(true);
|
nameListScrolled.setAlwaysShowScrollBars(true);
|
||||||
|
@ -168,12 +163,9 @@ public class TxDisplay implements PropertyChangeListener, ISelectionProvider, Mo
|
||||||
nameListScrolled.setContent(nameList);
|
nameListScrolled.setContent(nameList);
|
||||||
|
|
||||||
Composite valuePane = createTextPane(leftSash, "Value");
|
Composite valuePane = createTextPane(leftSash, "Value");
|
||||||
valuePane.setBackground(valuePane.getDisplay().getSystemColor(
|
valuePane.setBackground(valuePane.getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
|
||||||
SWT.COLOR_WIDGET_BACKGROUND));
|
valueListScrolled = new ScrolledComposite(valuePane, SWT.H_SCROLL | SWT.V_SCROLL);
|
||||||
valueListScrolled = new ScrolledComposite(valuePane, SWT.H_SCROLL
|
valueListScrolled.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
|
||||||
| SWT.V_SCROLL);
|
|
||||||
valueListScrolled.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
|
|
||||||
true, 1, 1));
|
|
||||||
valueListScrolled.setExpandHorizontal(true);
|
valueListScrolled.setExpandHorizontal(true);
|
||||||
valueListScrolled.setExpandVertical(true);
|
valueListScrolled.setExpandVertical(true);
|
||||||
valueListScrolled.setAlwaysShowScrollBars(true);
|
valueListScrolled.setAlwaysShowScrollBars(true);
|
||||||
|
@ -212,32 +204,27 @@ public class TxDisplay implements PropertyChangeListener, ISelectionProvider, Mo
|
||||||
trackList.setStreams(streams);
|
trackList.setStreams(streams);
|
||||||
trackList.setRuler(ruler);
|
trackList.setRuler(ruler);
|
||||||
trackList.addPainter(new TrackPainter(trackList));
|
trackList.addPainter(new TrackPainter(trackList));
|
||||||
CursorPainter cp = new CursorPainter(trackList,
|
CursorPainter cp = new CursorPainter(trackList, trackList.getScaleFactor() * 10);
|
||||||
trackList.getScaleFactor() * 10);
|
|
||||||
trackList.addPainter(cp);
|
trackList.addPainter(cp);
|
||||||
cursorPainters.add(cp);
|
cursorPainters.add(cp);
|
||||||
trackList.setMaxTime(1);
|
trackList.setMaxTime(1);
|
||||||
trackList.addMouseListener(this);
|
trackList.addMouseListener(this);
|
||||||
|
|
||||||
nameListScrolled.getVerticalBar().addSelectionListener(
|
nameListScrolled.getVerticalBar().addSelectionListener(new SelectionAdapter() {
|
||||||
new SelectionAdapter() {
|
|
||||||
public void widgetSelected(SelectionEvent e) {
|
public void widgetSelected(SelectionEvent e) {
|
||||||
int y = ((ScrollBar) e.widget).getSelection();
|
int y = ((ScrollBar) e.widget).getSelection();
|
||||||
valueListScrolled.setOrigin(
|
valueListScrolled.setOrigin(valueListScrolled.getOrigin().x, y);
|
||||||
valueListScrolled.getOrigin().x, y);
|
trackList.setOrigin(trackList.getOrigin().x, y);
|
||||||
trackList.scrollToY(y);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
valueListScrolled.getVerticalBar().addSelectionListener(
|
valueListScrolled.getVerticalBar().addSelectionListener(new SelectionAdapter() {
|
||||||
new SelectionAdapter() {
|
|
||||||
public void widgetSelected(SelectionEvent e) {
|
public void widgetSelected(SelectionEvent e) {
|
||||||
int y = ((ScrollBar) e.widget).getSelection();
|
int y = ((ScrollBar) e.widget).getSelection();
|
||||||
nameListScrolled.setOrigin(
|
nameListScrolled.setOrigin(nameListScrolled.getOrigin().x, y);
|
||||||
nameListScrolled.getOrigin().x, y);
|
trackList.setOrigin(trackList.getOrigin().x, y);
|
||||||
trackList.scrollToY(y);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
trackList.getVerticalBar().addSelectionListener(new SelectionAdapter() {
|
trackList.addSelectionListener(new SelectionAdapter() {
|
||||||
public void widgetSelected(SelectionEvent e) {
|
public void widgetSelected(SelectionEvent e) {
|
||||||
int y = trackList.getVerticalBar().getSelection();
|
int y = trackList.getVerticalBar().getSelection();
|
||||||
nameListScrolled.setOrigin(nameListScrolled.getOrigin().x, y);
|
nameListScrolled.setOrigin(nameListScrolled.getOrigin().x, y);
|
||||||
|
@ -263,8 +250,7 @@ public class TxDisplay implements PropertyChangeListener, ISelectionProvider, Mo
|
||||||
namePane.setLayout(gl_namePane);
|
namePane.setLayout(gl_namePane);
|
||||||
|
|
||||||
CLabel nameLabel = new CLabel(namePane, SWT.NONE);
|
CLabel nameLabel = new CLabel(namePane, SWT.NONE);
|
||||||
GridData gd_nameLabel = new GridData(SWT.CENTER, SWT.CENTER, true,
|
GridData gd_nameLabel = new GridData(SWT.CENTER, SWT.CENTER, true, false, 1, 1);
|
||||||
false, 1, 1);
|
|
||||||
gd_nameLabel.heightHint = Ruler.height - 2;
|
gd_nameLabel.heightHint = Ruler.height - 2;
|
||||||
nameLabel.setLayoutData(gd_nameLabel);
|
nameLabel.setLayoutData(gd_nameLabel);
|
||||||
nameLabel.setText(text);
|
nameLabel.setText(text);
|
||||||
|
@ -272,8 +258,7 @@ public class TxDisplay implements PropertyChangeListener, ISelectionProvider, Mo
|
||||||
Label nameSep = new Label(namePane, SWT.SEPARATOR | SWT.HORIZONTAL);
|
Label nameSep = new Label(namePane, SWT.SEPARATOR | SWT.HORIZONTAL);
|
||||||
nameSep.setBackground(SWTResourceManager.getColor(SWT.COLOR_DARK_GRAY));
|
nameSep.setBackground(SWTResourceManager.getColor(SWT.COLOR_DARK_GRAY));
|
||||||
nameSep.setForeground(SWTResourceManager.getColor(SWT.COLOR_BLACK));
|
nameSep.setForeground(SWTResourceManager.getColor(SWT.COLOR_BLACK));
|
||||||
GridData gd_nameSep = new GridData(SWT.FILL, SWT.CENTER, true, false,
|
GridData gd_nameSep = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1);
|
||||||
1, 1);
|
|
||||||
gd_nameSep.heightHint = 2;
|
gd_nameSep.heightHint = 2;
|
||||||
nameSep.setLayoutData(gd_nameSep);
|
nameSep.setLayoutData(gd_nameSep);
|
||||||
return namePane;
|
return namePane;
|
||||||
|
@ -290,7 +275,7 @@ public class TxDisplay implements PropertyChangeListener, ISelectionProvider, Mo
|
||||||
protected void updateTracklist() {
|
protected void updateTracklist() {
|
||||||
int yoffs = 0;
|
int yoffs = 0;
|
||||||
int nameMaxWidth = 0;
|
int nameMaxWidth = 0;
|
||||||
int previousHeight=trackVerticalOffset.size()==0?0: trackVerticalOffset.lastKey();
|
int previousHeight = trackVerticalOffset.size() == 0 ? 0 : trackVerticalOffset.lastKey();
|
||||||
IWaveformPainter painter = null;
|
IWaveformPainter painter = null;
|
||||||
trackVerticalOffset.clear();
|
trackVerticalOffset.clear();
|
||||||
actualValues.clear();
|
actualValues.clear();
|
||||||
|
@ -305,8 +290,7 @@ public class TxDisplay implements PropertyChangeListener, ISelectionProvider, Mo
|
||||||
painter = new StreamPainter(trackList, even, height, (ITxStream<? extends ITxEvent>) waveform);
|
painter = new StreamPainter(trackList, even, height, (ITxStream<? extends ITxEvent>) waveform);
|
||||||
actualValues.put(waveform, "");
|
actualValues.put(waveform, "");
|
||||||
} else if (waveform instanceof ISignal<?>) {
|
} else if (waveform instanceof ISignal<?>) {
|
||||||
painter = new SignalPainter(trackList, even, height,
|
painter = new SignalPainter(trackList, even, height, (ISignal<?>) waveform);
|
||||||
(ISignal<?>) waveform);
|
|
||||||
actualValues.put(waveform, "---");
|
actualValues.put(waveform, "---");
|
||||||
}
|
}
|
||||||
trackList.addWavefromPainter(yoffs, painter);
|
trackList.addWavefromPainter(yoffs, painter);
|
||||||
|
@ -324,8 +308,9 @@ public class TxDisplay implements PropertyChangeListener, ISelectionProvider, Mo
|
||||||
valueList.redraw();
|
valueList.redraw();
|
||||||
trackList.redraw();
|
trackList.redraw();
|
||||||
top.layout(new Control[] { valueList, nameList, trackList });
|
top.layout(new Control[] { valueList, nameList, trackList });
|
||||||
if(previousHeight>trackVerticalOffset.lastKey()){
|
if (previousHeight > trackVerticalOffset.lastKey()) {
|
||||||
trackList.scrollToY(trackList.getOrigin().y-(previousHeight-trackVerticalOffset.lastKey()));
|
Point o = trackList.getOrigin();
|
||||||
|
trackList.setOrigin(o.x, o.y - (previousHeight - trackVerticalOffset.lastKey()));
|
||||||
}
|
}
|
||||||
setSelection(new StructuredSelection());
|
setSelection(new StructuredSelection());
|
||||||
}
|
}
|
||||||
|
@ -347,12 +332,11 @@ public class TxDisplay implements PropertyChangeListener, ISelectionProvider, Mo
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeSelectionChangedListener(
|
public void removeSelectionChangedListener(ISelectionChangedListener listener) {
|
||||||
ISelectionChangedListener listener) {
|
|
||||||
listeners.remove(listener);
|
listeners.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Control getControl(){
|
public Control getControl() {
|
||||||
return top;
|
return top;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,8 +360,7 @@ public class TxDisplay implements PropertyChangeListener, ISelectionProvider, Mo
|
||||||
currentSelection = (ITx) sel;
|
currentSelection = (ITx) sel;
|
||||||
currentWaveformSelection = currentSelection.getStream();
|
currentWaveformSelection = currentSelection.getStream();
|
||||||
selectionChanged = true;
|
selectionChanged = true;
|
||||||
} else if (sel instanceof IWaveform<?>
|
} else if (sel instanceof IWaveform<?> && currentWaveformSelection != sel) {
|
||||||
&& currentWaveformSelection != sel) {
|
|
||||||
currentSelection = null;
|
currentSelection = null;
|
||||||
currentWaveformSelection = (IWaveform<? extends IWaveformEvent>) sel;
|
currentWaveformSelection = (IWaveform<? extends IWaveformEvent>) sel;
|
||||||
selectionChanged = true;
|
selectionChanged = true;
|
||||||
|
@ -388,7 +371,7 @@ public class TxDisplay implements PropertyChangeListener, ISelectionProvider, Mo
|
||||||
currentSelection = null;
|
currentSelection = null;
|
||||||
currentWaveformSelection = null;
|
currentWaveformSelection = null;
|
||||||
}
|
}
|
||||||
if(currentWaveformSelection!=null && !streams.contains(currentWaveformSelection)){
|
if (currentWaveformSelection != null && !streams.contains(currentWaveformSelection)) {
|
||||||
streams.add(currentWaveformSelection);
|
streams.add(currentWaveformSelection);
|
||||||
}
|
}
|
||||||
if (selectionChanged) {
|
if (selectionChanged) {
|
||||||
|
@ -425,11 +408,14 @@ public class TxDisplay implements PropertyChangeListener, ISelectionProvider, Mo
|
||||||
Entry<Long, List<ITxEvent>> entry = stream.getEvents().lowerEntry(currentSelection.getBeginTime());
|
Entry<Long, List<ITxEvent>> entry = stream.getEvents().lowerEntry(currentSelection.getBeginTime());
|
||||||
if (entry != null)
|
if (entry != null)
|
||||||
do {
|
do {
|
||||||
|
System.out.println(currentSelection.getBeginTime() + " -> " + entry.getKey());
|
||||||
for (ITxEvent evt : entry.getValue()) {
|
for (ITxEvent evt : entry.getValue()) {
|
||||||
if (evt.getType() == ITxEvent.Type.BEGIN)
|
System.out.println("\t-> " + evt.toString());
|
||||||
|
if (evt.getType() == ITxEvent.Type.BEGIN) {
|
||||||
transaction = evt.getTransaction();
|
transaction = evt.getTransaction();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (transaction == null)
|
if (transaction == null)
|
||||||
entry = stream.getEvents().lowerEntry(entry.getKey());
|
entry = stream.getEvents().lowerEntry(entry.getKey());
|
||||||
} while (entry != null && transaction == null);
|
} while (entry != null && transaction == null);
|
||||||
|
@ -446,19 +432,18 @@ public class TxDisplay implements PropertyChangeListener, ISelectionProvider, Mo
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseDown(MouseEvent e) {
|
public void mouseDown(MouseEvent e) {
|
||||||
if(e.button==1 || e.button==3){
|
if (e.button == 1 || e.button == 3) {
|
||||||
if (e.widget == trackList) {
|
if (e.widget == trackList) {
|
||||||
Object o = trackList.getClicked(new Point(e.x, e.y));
|
Object o = trackList.getClicked(new Point(e.x, e.y));
|
||||||
if (o != null)
|
if (o != null)
|
||||||
setSelection(new StructuredSelection(o));
|
setSelection(new StructuredSelection(o));
|
||||||
} else if (e.widget == valueList || e.widget == nameList) {
|
} else if (e.widget == valueList || e.widget == nameList) {
|
||||||
Entry<Integer, IWaveform<? extends IWaveformEvent>> entry = trackVerticalOffset
|
Entry<Integer, IWaveform<? extends IWaveformEvent>> entry = trackVerticalOffset.floorEntry(e.y);
|
||||||
.floorEntry(e.y);
|
|
||||||
if (entry != null)
|
if (entry != null)
|
||||||
setSelection(new StructuredSelection(entry.getValue()));
|
setSelection(new StructuredSelection(entry.getValue()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(e.button==3){
|
if (e.button == 3) {
|
||||||
top.getMenu().setVisible(true);
|
top.getMenu().setVisible(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -474,33 +459,25 @@ public class TxDisplay implements PropertyChangeListener, ISelectionProvider, Mo
|
||||||
protected void paintNames(GC gc, Rectangle rect) {
|
protected void paintNames(GC gc, Rectangle rect) {
|
||||||
if (streams.size() > 0) {
|
if (streams.size() > 0) {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
IWaveform<? extends IWaveformEvent> wave = (IWaveform<? extends IWaveformEvent>) nameList
|
IWaveform<? extends IWaveformEvent> wave = (IWaveform<? extends IWaveformEvent>) nameList.getData(SELECTION);
|
||||||
.getData(SELECTION);
|
|
||||||
Integer firstKey = trackVerticalOffset.floorKey(rect.y);
|
Integer firstKey = trackVerticalOffset.floorKey(rect.y);
|
||||||
if (firstKey == null)
|
if (firstKey == null)
|
||||||
firstKey = trackVerticalOffset.firstKey();
|
firstKey = trackVerticalOffset.firstKey();
|
||||||
Integer lastKey = trackVerticalOffset
|
Integer lastKey = trackVerticalOffset.floorKey(rect.y + rect.height);
|
||||||
.floorKey(rect.y + rect.height);
|
Rectangle subArea = new Rectangle(rect.x, 0, rect.width, trackList.getTrackHeight());
|
||||||
Rectangle subArea = new Rectangle(rect.x, 0, rect.width,
|
|
||||||
trackList.getTrackHeight());
|
|
||||||
if (lastKey == firstKey) {
|
if (lastKey == firstKey) {
|
||||||
IWaveform<? extends IWaveformEvent> w = trackVerticalOffset
|
IWaveform<? extends IWaveformEvent> w = trackVerticalOffset.get(firstKey);
|
||||||
.get(firstKey);
|
|
||||||
if (w instanceof ITxStream<?>)
|
if (w instanceof ITxStream<?>)
|
||||||
subArea.height *= ((ITxStream<?>) w).getMaxConcurrency();
|
subArea.height *= ((ITxStream<?>) w).getMaxConcurrency();
|
||||||
drawTextFormat(gc, subArea, firstKey, w.getFullName(),
|
drawTextFormat(gc, subArea, firstKey, w.getFullName(), wave != null && w.getId() == wave.getId());
|
||||||
wave != null && w.getId() == wave.getId());
|
|
||||||
} else {
|
} else {
|
||||||
for (Entry<Integer, IWaveform<? extends IWaveformEvent>> entry : trackVerticalOffset
|
for (Entry<Integer, IWaveform<? extends IWaveformEvent>> entry : trackVerticalOffset.subMap(firstKey, true, lastKey, true)
|
||||||
.subMap(firstKey, true, lastKey, true).entrySet()) {
|
.entrySet()) {
|
||||||
IWaveform<? extends IWaveformEvent> w = entry.getValue();
|
IWaveform<? extends IWaveformEvent> w = entry.getValue();
|
||||||
subArea.height = trackList.getTrackHeight();
|
subArea.height = trackList.getTrackHeight();
|
||||||
if (w instanceof ITxStream<?>)
|
if (w instanceof ITxStream<?>)
|
||||||
subArea.height *= ((ITxStream<?>) w)
|
subArea.height *= ((ITxStream<?>) w).getMaxConcurrency();
|
||||||
.getMaxConcurrency();
|
drawTextFormat(gc, subArea, entry.getKey(), w.getFullName(), wave != null && w.getId() == wave.getId());
|
||||||
drawTextFormat(gc, subArea, entry.getKey(),
|
|
||||||
w.getFullName(),
|
|
||||||
wave != null && w.getId() == wave.getId());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -509,61 +486,43 @@ public class TxDisplay implements PropertyChangeListener, ISelectionProvider, Mo
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected void paintValues(GC gc, Rectangle rect) {
|
protected void paintValues(GC gc, Rectangle rect) {
|
||||||
if (streams.size() > 0) {
|
if (streams.size() > 0) {
|
||||||
IWaveform<? extends IWaveformEvent> wave = (IWaveform<? extends IWaveformEvent>) nameList
|
IWaveform<? extends IWaveformEvent> wave = (IWaveform<? extends IWaveformEvent>) nameList.getData(SELECTION);
|
||||||
.getData(SELECTION);
|
|
||||||
Integer firstKey = trackVerticalOffset.floorKey(rect.y);
|
Integer firstKey = trackVerticalOffset.floorKey(rect.y);
|
||||||
if (firstKey == null)
|
if (firstKey == null)
|
||||||
firstKey = trackVerticalOffset.firstKey();
|
firstKey = trackVerticalOffset.firstKey();
|
||||||
Integer lastKey = trackVerticalOffset
|
Integer lastKey = trackVerticalOffset.floorKey(rect.y + rect.height);
|
||||||
.floorKey(rect.y + rect.height);
|
Rectangle subArea = new Rectangle(rect.x, 0, rect.width, trackList.getTrackHeight());
|
||||||
Rectangle subArea = new Rectangle(rect.x, 0, rect.width,
|
|
||||||
trackList.getTrackHeight());
|
|
||||||
if (lastKey == firstKey) {
|
if (lastKey == firstKey) {
|
||||||
IWaveform<? extends IWaveformEvent> w = trackVerticalOffset
|
IWaveform<? extends IWaveformEvent> w = trackVerticalOffset.get(firstKey);
|
||||||
.get(firstKey);
|
|
||||||
if (w instanceof ITxStream<?>)
|
if (w instanceof ITxStream<?>)
|
||||||
subArea.height *= ((ITxStream<?>) w).getMaxConcurrency();
|
subArea.height *= ((ITxStream<?>) w).getMaxConcurrency();
|
||||||
drawTextFormat(gc, subArea, firstKey, actualValues.get(w),
|
drawTextFormat(gc, subArea, firstKey, actualValues.get(w), wave != null && w.getId() == wave.getId());
|
||||||
wave != null && w.getId() == wave.getId());
|
|
||||||
} else {
|
} else {
|
||||||
for (Entry<Integer, IWaveform<? extends IWaveformEvent>> entry : trackVerticalOffset
|
for (Entry<Integer, IWaveform<? extends IWaveformEvent>> entry : trackVerticalOffset.subMap(firstKey, true, lastKey, true)
|
||||||
.subMap(firstKey, true, lastKey, true).entrySet()) {
|
.entrySet()) {
|
||||||
IWaveform<? extends IWaveformEvent> w = entry.getValue();
|
IWaveform<? extends IWaveformEvent> w = entry.getValue();
|
||||||
subArea.height = trackList.getTrackHeight();
|
subArea.height = trackList.getTrackHeight();
|
||||||
if (w instanceof ITxStream<?>)
|
if (w instanceof ITxStream<?>)
|
||||||
subArea.height *= ((ITxStream<?>) w)
|
subArea.height *= ((ITxStream<?>) w).getMaxConcurrency();
|
||||||
.getMaxConcurrency();
|
drawTextFormat(gc, subArea, entry.getKey(), actualValues.get(w), wave != null && w.getId() == wave.getId());
|
||||||
drawTextFormat(gc, subArea, entry.getKey(),
|
|
||||||
actualValues.get(w), wave != null
|
|
||||||
&& w.getId() == wave.getId());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void drawTextFormat(GC gc, Rectangle subArea, int yOffset,
|
protected void drawTextFormat(GC gc, Rectangle subArea, int yOffset, String value, boolean highlite) {
|
||||||
String value, boolean highlite) {
|
|
||||||
Point size = gc.textExtent(value);
|
Point size = gc.textExtent(value);
|
||||||
if (highlite) {
|
if (highlite) {
|
||||||
gc.setBackground(SWTResourceManager
|
gc.setBackground(SWTResourceManager.getColor(SWT.COLOR_LIST_SELECTION));
|
||||||
.getColor(SWT.COLOR_LIST_SELECTION));
|
gc.setForeground(SWTResourceManager.getColor(SWT.COLOR_LIST_SELECTION_TEXT));
|
||||||
gc.setForeground(SWTResourceManager
|
gc.fillRectangle(subArea.x, subArea.y + yOffset, subArea.width, subArea.height);
|
||||||
.getColor(SWT.COLOR_LIST_SELECTION_TEXT));
|
|
||||||
gc.fillRectangle(subArea.x, subArea.y + yOffset, subArea.width,
|
|
||||||
subArea.height);
|
|
||||||
gc.setFont(nameFontB);
|
gc.setFont(nameFontB);
|
||||||
} else {
|
} else {
|
||||||
gc.setBackground(SWTResourceManager
|
gc.setBackground(SWTResourceManager.getColor(SWT.COLOR_LIST_BACKGROUND));
|
||||||
.getColor(SWT.COLOR_LIST_BACKGROUND));
|
gc.setForeground(SWTResourceManager.getColor(SWT.COLOR_LIST_FOREGROUND));
|
||||||
gc.setForeground(SWTResourceManager
|
|
||||||
.getColor(SWT.COLOR_LIST_FOREGROUND));
|
|
||||||
gc.setFont(nameFont);
|
gc.setFont(nameFont);
|
||||||
}
|
}
|
||||||
gc.drawText(
|
gc.drawText(value, subArea.x + 5, subArea.y + yOffset + (trackList.getTrackHeight() - size.y) / 2, true);
|
||||||
value,
|
|
||||||
subArea.x + 5,
|
|
||||||
subArea.y + yOffset + (trackList.getTrackHeight() - size.y) / 2,
|
|
||||||
true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getMaxTime() {
|
public long getMaxTime() {
|
||||||
|
@ -590,15 +549,17 @@ public class TxDisplay implements PropertyChangeListener, ISelectionProvider, Mo
|
||||||
|
|
||||||
public void dragStart(DragSourceEvent event) {
|
public void dragStart(DragSourceEvent event) {
|
||||||
if (event.y < trackVerticalOffset.lastKey() + trackList.getTrackHeight()) {
|
if (event.y < trackVerticalOffset.lastKey() + trackList.getTrackHeight()) {
|
||||||
// event.data = trackVerticalOffset.floorEntry(event.y).getValue().getFullName();
|
// event.data =
|
||||||
|
// trackVerticalOffset.floorEntry(event.y).getValue().getFullName();
|
||||||
event.doit = true;
|
event.doit = true;
|
||||||
// System.out.println("dragStart at location "+new Point(event.x, event.y));
|
// System.out.println("dragStart at location "+new
|
||||||
|
// Point(event.x, event.y));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dragSetData(DragSourceEvent event) {
|
public void dragSetData(DragSourceEvent event) {
|
||||||
event.data = trackVerticalOffset.floorEntry(event.y).getValue().getFullName();
|
event.data = trackVerticalOffset.floorEntry(event.y).getValue().getFullName();
|
||||||
// System.out.println("dragSetData with data " + event.data);
|
// System.out.println("dragSetData with data " + event.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dragFinished(DragSourceEvent event) {
|
public void dragFinished(DragSourceEvent event) {
|
||||||
|
@ -629,10 +590,12 @@ public class TxDisplay implements PropertyChangeListener, ISelectionProvider, Mo
|
||||||
public void drop(DropTargetEvent event) {
|
public void drop(DropTargetEvent event) {
|
||||||
Object data = event.data;
|
Object data = event.data;
|
||||||
DropTarget tgt = (DropTarget) event.widget;
|
DropTarget tgt = (DropTarget) event.widget;
|
||||||
Point dropPoint = ((Canvas)tgt.getControl()).toControl(event.x, event.y);
|
Point dropPoint = ((Canvas) tgt.getControl()).toControl(event.x, event.y);
|
||||||
String fullname1 = trackVerticalOffset.floorEntry(dropPoint.y).getValue().getFullName();
|
String fullname1 = trackVerticalOffset.floorEntry(dropPoint.y).getValue().getFullName();
|
||||||
// System.out.println("drop with data '" + event.data +"' at location "+dropPoint + " and origin " + nameListScrolled.getOrigin());
|
// System.out.println("drop with data '" + event.data
|
||||||
// System.out.println("drop on " + fullname1);
|
// +"' at location "+dropPoint + " and origin " +
|
||||||
|
// nameListScrolled.getOrigin());
|
||||||
|
// System.out.println("drop on " + fullname1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dropAccept(DropTargetEvent event) {
|
public void dropAccept(DropTargetEvent event) {
|
||||||
|
|
|
@ -68,35 +68,37 @@ public class StreamPainter implements IWaveformPainter{
|
||||||
for(int y1=area.y+this.waveCanvas.getTrackHeight()/2; y1<area.y+totalHeight; y1+=this.waveCanvas.getTrackHeight())
|
for(int y1=area.y+this.waveCanvas.getTrackHeight()/2; y1<area.y+totalHeight; y1+=this.waveCanvas.getTrackHeight())
|
||||||
gc.drawLine(area.x, y1, area.x+area.width, y1);
|
gc.drawLine(area.x, y1, area.x+area.width, y1);
|
||||||
if(firstTx==lastTx)
|
if(firstTx==lastTx)
|
||||||
for(ITxEvent x:(Collection<? extends ITxEvent>)firstTx.getValue())
|
for(ITxEvent txEvent:(Collection<? extends ITxEvent>)firstTx.getValue())
|
||||||
drawTx(gc, area, x.getTransaction());
|
drawTx(gc, area, txEvent.getTransaction());
|
||||||
else{
|
else{
|
||||||
seenTx.clear();
|
seenTx.clear();
|
||||||
NavigableMap<Long,?> entries = stream.getEvents().subMap(firstTx.getKey(), true, lastTx.getKey(), true);
|
NavigableMap<Long,?> entries = stream.getEvents().subMap(firstTx.getKey(), true, lastTx.getKey(), true);
|
||||||
for(Entry<Long, ?> tx: entries.entrySet())
|
boolean highlighed=false;
|
||||||
for(ITxEvent x:(Collection<? extends ITxEvent>)tx.getValue()){
|
gc.setForeground(this.waveCanvas.colors[WaveformCanvas.Colors.LINE.ordinal()]);
|
||||||
if(x.getType()==ITxEvent.Type.BEGIN)
|
gc.setBackground(this.waveCanvas.colors[WaveformCanvas.Colors.TX_BG.ordinal()]);
|
||||||
seenTx.add(x.getTransaction());
|
for(Entry<Long, ?> entry: entries.entrySet())
|
||||||
if(x.getType()==ITxEvent.Type.END){
|
for(ITxEvent txEvent:(Collection<? extends ITxEvent>)entry.getValue()){
|
||||||
drawTx(gc, area, x.getTransaction());
|
if(txEvent.getType()==ITxEvent.Type.BEGIN)
|
||||||
seenTx.remove(x.getTransaction());
|
seenTx.add(txEvent.getTransaction());
|
||||||
|
if(txEvent.getType()==ITxEvent.Type.END){
|
||||||
|
ITx tx = txEvent.getTransaction();
|
||||||
|
highlighed|=waveCanvas.currentSelection!=null && waveCanvas.currentSelection.getId()==tx.getId();
|
||||||
|
drawTx(gc, area, tx);
|
||||||
|
seenTx.remove(tx);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
for(ITx tx:seenTx){
|
for(ITx tx:seenTx){
|
||||||
drawTx(gc, area, tx);
|
drawTx(gc, area, tx);
|
||||||
}
|
}
|
||||||
|
if(highlighed){
|
||||||
|
gc.setForeground(this.waveCanvas.colors[WaveformCanvas.Colors.LINE_HIGHLITE.ordinal()]);
|
||||||
|
gc.setBackground(this.waveCanvas.colors[WaveformCanvas.Colors.TX_BG_HIGHLITE.ordinal()]);
|
||||||
|
drawTx(gc, area, waveCanvas.currentSelection);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void drawTx(GC gc, Rectangle area, ITx tx) {
|
protected void drawTx(GC gc, Rectangle area, ITx tx) {
|
||||||
if(waveCanvas.currentSelection!=null && waveCanvas.currentSelection.getId()==tx.getId()){
|
|
||||||
gc.setForeground(this.waveCanvas.colors[WaveformCanvas.Colors.LINE_HIGHLITE.ordinal()]);
|
|
||||||
gc.setBackground(this.waveCanvas.colors[WaveformCanvas.Colors.TX_BG_HIGHLITE.ordinal()]);
|
|
||||||
}else {
|
|
||||||
gc.setForeground(this.waveCanvas.colors[WaveformCanvas.Colors.LINE.ordinal()]);
|
|
||||||
gc.setBackground(this.waveCanvas.colors[WaveformCanvas.Colors.TX_BG.ordinal()]);
|
|
||||||
}
|
|
||||||
int offset = tx.getConcurrencyIndex()*this.waveCanvas.getTrackHeight();
|
int offset = tx.getConcurrencyIndex()*this.waveCanvas.getTrackHeight();
|
||||||
Rectangle bb = new Rectangle(
|
Rectangle bb = new Rectangle(
|
||||||
(int)(tx.getBeginTime()/this.waveCanvas.getScaleFactor()), area.y+offset+upper,
|
(int)(tx.getBeginTime()/this.waveCanvas.getScaleFactor()), area.y+offset+upper,
|
||||||
|
|
|
@ -32,6 +32,7 @@ import org.eclipse.swt.graphics.Transform;
|
||||||
import org.eclipse.swt.widgets.Canvas;
|
import org.eclipse.swt.widgets.Canvas;
|
||||||
import org.eclipse.swt.widgets.Composite;
|
import org.eclipse.swt.widgets.Composite;
|
||||||
import org.eclipse.swt.widgets.Display;
|
import org.eclipse.swt.widgets.Display;
|
||||||
|
import org.eclipse.swt.widgets.Event;
|
||||||
import org.eclipse.swt.widgets.ScrollBar;
|
import org.eclipse.swt.widgets.ScrollBar;
|
||||||
import org.eclipse.wb.swt.SWTResourceManager;
|
import org.eclipse.wb.swt.SWTResourceManager;
|
||||||
|
|
||||||
|
@ -42,27 +43,14 @@ import com.minres.scviewer.database.IWaveformEvent;
|
||||||
|
|
||||||
public class WaveformCanvas extends Canvas {
|
public class WaveformCanvas extends Canvas {
|
||||||
public enum Colors {
|
public enum Colors {
|
||||||
LINE,
|
LINE, LINE_HIGHLITE, TRACK_BG_EVEN, TRACK_BG_HIGHLITE, TRACK_BG_ODD, TX_BG, TX_BG_HIGHLITE, TX_BORDER, SIGNAL0, SIGNAL1, SIGNALZ, SIGNALX, SIGNAL_TEXT, CURSOR
|
||||||
LINE_HIGHLITE,
|
|
||||||
TRACK_BG_EVEN,
|
|
||||||
TRACK_BG_HIGHLITE,
|
|
||||||
TRACK_BG_ODD,
|
|
||||||
TX_BG,
|
|
||||||
TX_BG_HIGHLITE,
|
|
||||||
TX_BORDER,
|
|
||||||
SIGNAL0,
|
|
||||||
SIGNAL1,
|
|
||||||
SIGNALZ,
|
|
||||||
SIGNALX,
|
|
||||||
SIGNAL_TEXT,
|
|
||||||
CURSOR
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Color[] colors=new Color[Colors.values().length];
|
Color[] colors = new Color[Colors.values().length];
|
||||||
|
|
||||||
private int trackHeight = 50;
|
private int trackHeight = 50;
|
||||||
private long scaleFactor = 1000000L;
|
private long scaleFactor = 1000000L;
|
||||||
private int level=6;
|
private int level = 6;
|
||||||
private long maxTime;
|
private long maxTime;
|
||||||
protected Point origin; /* original size */
|
protected Point origin; /* original size */
|
||||||
protected Transform transform;
|
protected Transform transform;
|
||||||
|
@ -75,14 +63,18 @@ public class WaveformCanvas extends Canvas {
|
||||||
ITx currentSelection;
|
ITx currentSelection;
|
||||||
IWaveform<? extends IWaveformEvent> currentWaveformSelection;
|
IWaveform<? extends IWaveformEvent> currentWaveformSelection;
|
||||||
|
|
||||||
|
private List<SelectionAdapter> selectionListeners;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for ScrollableCanvas.
|
* Constructor for ScrollableCanvas.
|
||||||
* @param parent the parent of this control.
|
*
|
||||||
* @param style the style of this control.
|
* @param parent
|
||||||
|
* the parent of this control.
|
||||||
|
* @param style
|
||||||
|
* the style of this control.
|
||||||
*/
|
*/
|
||||||
public WaveformCanvas(final Composite parent, int style) {
|
public WaveformCanvas(final Composite parent, int style) {
|
||||||
super( parent, style |SWT.DOUBLE_BUFFERED| SWT.NO_BACKGROUND|SWT.NO_REDRAW_RESIZE|SWT.V_SCROLL|SWT.H_SCROLL);
|
super(parent, style | SWT.DOUBLE_BUFFERED | SWT.NO_BACKGROUND | SWT.NO_REDRAW_RESIZE | SWT.V_SCROLL | SWT.H_SCROLL);
|
||||||
addControlListener(new ControlAdapter() { /* resize listener. */
|
addControlListener(new ControlAdapter() { /* resize listener. */
|
||||||
public void controlResized(ControlEvent event) {
|
public void controlResized(ControlEvent event) {
|
||||||
syncScrollBars();
|
syncScrollBars();
|
||||||
|
@ -93,38 +85,39 @@ public class WaveformCanvas extends Canvas {
|
||||||
paint(event.gc);
|
paint(event.gc);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
painterList=new LinkedList<IPainter>();
|
painterList = new LinkedList<IPainter>();
|
||||||
origin=new Point(0,0);
|
origin = new Point(0, 0);
|
||||||
transform = new Transform(getDisplay());
|
transform = new Transform(getDisplay());
|
||||||
trackVerticalOffset=new TreeMap<Integer, IWaveformPainter>();
|
trackVerticalOffset = new TreeMap<Integer, IWaveformPainter>();
|
||||||
|
selectionListeners = new LinkedList<>();
|
||||||
initScrollBars();
|
initScrollBars();
|
||||||
initColors(null);
|
initColors(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initColors(HashMap<Colors, RGB> colourMap){
|
private void initColors(HashMap<Colors, RGB> colourMap) {
|
||||||
Display d = getDisplay();
|
Display d = getDisplay();
|
||||||
if(colourMap!=null){
|
if (colourMap != null) {
|
||||||
for(Colors c:Colors.values()){
|
for (Colors c : Colors.values()) {
|
||||||
if(colourMap.containsKey(c)){
|
if (colourMap.containsKey(c)) {
|
||||||
colors[c.ordinal()].dispose();
|
colors[c.ordinal()].dispose();
|
||||||
colors[c.ordinal()]=new Color(d, colourMap.get(c));
|
colors[c.ordinal()] = new Color(d, colourMap.get(c));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
colors[Colors.LINE.ordinal()]=SWTResourceManager.getColor(SWT.COLOR_RED);
|
colors[Colors.LINE.ordinal()] = SWTResourceManager.getColor(SWT.COLOR_RED);
|
||||||
colors[Colors.LINE_HIGHLITE.ordinal()]=SWTResourceManager.getColor(SWT.COLOR_CYAN);
|
colors[Colors.LINE_HIGHLITE.ordinal()] = SWTResourceManager.getColor(SWT.COLOR_CYAN);
|
||||||
colors[Colors.TRACK_BG_EVEN.ordinal()]=SWTResourceManager.getColor(SWT.COLOR_BLACK);
|
colors[Colors.TRACK_BG_EVEN.ordinal()] = SWTResourceManager.getColor(SWT.COLOR_BLACK);
|
||||||
colors[Colors.TRACK_BG_ODD.ordinal()]=SWTResourceManager.getColor(40,40,40);
|
colors[Colors.TRACK_BG_ODD.ordinal()] = SWTResourceManager.getColor(40, 40, 40);
|
||||||
colors[Colors.TRACK_BG_HIGHLITE.ordinal()]=SWTResourceManager.getColor(40,40,80);
|
colors[Colors.TRACK_BG_HIGHLITE.ordinal()] = SWTResourceManager.getColor(40, 40, 80);
|
||||||
colors[Colors.TX_BG.ordinal()]=SWTResourceManager.getColor(SWT.COLOR_GREEN);
|
colors[Colors.TX_BG.ordinal()] = SWTResourceManager.getColor(SWT.COLOR_GREEN);
|
||||||
colors[Colors.TX_BG_HIGHLITE.ordinal()]=SWTResourceManager.getColor(SWT.COLOR_DARK_GREEN);
|
colors[Colors.TX_BG_HIGHLITE.ordinal()] = SWTResourceManager.getColor(SWT.COLOR_DARK_GREEN);
|
||||||
colors[Colors.TX_BORDER.ordinal()]=SWTResourceManager.getColor(SWT.COLOR_RED);
|
colors[Colors.TX_BORDER.ordinal()] = SWTResourceManager.getColor(SWT.COLOR_RED);
|
||||||
colors[Colors.SIGNAL0.ordinal()]=SWTResourceManager.getColor(SWT.COLOR_DARK_GREEN);
|
colors[Colors.SIGNAL0.ordinal()] = SWTResourceManager.getColor(SWT.COLOR_DARK_GREEN);
|
||||||
colors[Colors.SIGNAL1.ordinal()]=SWTResourceManager.getColor(SWT.COLOR_DARK_GREEN);
|
colors[Colors.SIGNAL1.ordinal()] = SWTResourceManager.getColor(SWT.COLOR_DARK_GREEN);
|
||||||
colors[Colors.SIGNALZ.ordinal()]=SWTResourceManager.getColor(SWT.COLOR_GRAY);
|
colors[Colors.SIGNALZ.ordinal()] = SWTResourceManager.getColor(SWT.COLOR_GRAY);
|
||||||
colors[Colors.SIGNALX.ordinal()]=SWTResourceManager.getColor(SWT.COLOR_RED);
|
colors[Colors.SIGNALX.ordinal()] = SWTResourceManager.getColor(SWT.COLOR_RED);
|
||||||
colors[Colors.SIGNAL_TEXT.ordinal()]=SWTResourceManager.getColor(SWT.COLOR_WHITE);
|
colors[Colors.SIGNAL_TEXT.ordinal()] = SWTResourceManager.getColor(SWT.COLOR_WHITE);
|
||||||
colors[Colors.CURSOR.ordinal()]=SWTResourceManager.getColor(SWT.COLOR_YELLOW);
|
colors[Colors.CURSOR.ordinal()] = SWTResourceManager.getColor(SWT.COLOR_YELLOW);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,24 +129,41 @@ public class WaveformCanvas extends Canvas {
|
||||||
this.streams = streams;
|
this.streams = streams;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Ruler getRuler(){
|
public Ruler getRuler() {
|
||||||
return ruler;
|
return ruler;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRuler(Ruler ruler) {
|
public void setRuler(Ruler ruler) {
|
||||||
this.ruler=ruler;
|
this.ruler = ruler;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Point getOrigin() {
|
public Point getOrigin() {
|
||||||
return origin;
|
return origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setOrigin(Point origin) {
|
||||||
|
setOrigin(origin.x, origin.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOrigin(int x, int y) {
|
||||||
|
checkWidget();
|
||||||
|
ScrollBar hBar = getHorizontalBar();
|
||||||
|
hBar.setSelection(-x);
|
||||||
|
x = -hBar.getSelection();
|
||||||
|
ScrollBar vBar = getVerticalBar();
|
||||||
|
vBar.setSelection(-y);
|
||||||
|
y = -vBar.getSelection();
|
||||||
|
origin.x = x;
|
||||||
|
origin.y = y;
|
||||||
|
syncScrollBars();
|
||||||
|
}
|
||||||
|
|
||||||
public long getMaxTime() {
|
public long getMaxTime() {
|
||||||
return maxTime;
|
return maxTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMaxTime(long maxTime){
|
public void setMaxTime(long maxTime) {
|
||||||
this.maxTime=maxTime;
|
this.maxTime = maxTime;
|
||||||
syncScrollBars();
|
syncScrollBars();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,9 +177,10 @@ public class WaveformCanvas extends Canvas {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setZoomLevel(int level) {
|
public void setZoomLevel(int level) {
|
||||||
this.level=level;
|
this.level = level;
|
||||||
this.scaleFactor = (long) Math.pow(10, level);
|
this.scaleFactor = (long) Math.pow(10, level);
|
||||||
if(ruler!=null) ruler.setStartPoint(-origin.x*scaleFactor);
|
if (ruler != null)
|
||||||
|
ruler.setStartPoint(-origin.x * scaleFactor);
|
||||||
syncScrollBars();
|
syncScrollBars();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,7 +197,7 @@ public class WaveformCanvas extends Canvas {
|
||||||
redraw();
|
redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removePainter(IPainter painter){
|
public void removePainter(IPainter painter) {
|
||||||
painterList.remove(painter);
|
painterList.remove(painter);
|
||||||
redraw();
|
redraw();
|
||||||
}
|
}
|
||||||
|
@ -206,37 +217,11 @@ public class WaveformCanvas extends Canvas {
|
||||||
*/
|
*/
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
transform.dispose();
|
transform.dispose();
|
||||||
for(Colors c:Colors.values()) colors[c.ordinal()].dispose();
|
for (Colors c : Colors.values())
|
||||||
|
colors[c.ordinal()].dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void scrollToY(int y){
|
|
||||||
ScrollBar vBar = getVerticalBar();
|
|
||||||
vBar.setSelection(y);
|
|
||||||
scrollVertically(vBar);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void scrollToX(int x){
|
|
||||||
ScrollBar hBar = getHorizontalBar();
|
|
||||||
hBar.setSelection(x);
|
|
||||||
scrollHorizontally(hBar);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Scroll horizontally */
|
|
||||||
private void scrollHorizontally(ScrollBar scrollBar) {
|
|
||||||
if (painterList.size()==0) return;
|
|
||||||
origin.x= -scrollBar.getSelection();
|
|
||||||
if(ruler!=null) ruler.setStartPoint(-origin.x*scaleFactor);
|
|
||||||
syncScrollBars();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Scroll vertically */
|
|
||||||
private void scrollVertically(ScrollBar scrollBar) {
|
|
||||||
if (painterList.size()==0) return;
|
|
||||||
origin.y = -scrollBar.getSelection();
|
|
||||||
syncScrollBars();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initalize the scrollbar and register listeners. */
|
/* Initalize the scrollbar and register listeners. */
|
||||||
private void initScrollBars() {
|
private void initScrollBars() {
|
||||||
ScrollBar horizontal = getHorizontalBar();
|
ScrollBar horizontal = getHorizontalBar();
|
||||||
|
@ -244,7 +229,11 @@ public class WaveformCanvas extends Canvas {
|
||||||
horizontal.setVisible(true);
|
horizontal.setVisible(true);
|
||||||
horizontal.addSelectionListener(new SelectionAdapter() {
|
horizontal.addSelectionListener(new SelectionAdapter() {
|
||||||
public void widgetSelected(SelectionEvent event) {
|
public void widgetSelected(SelectionEvent event) {
|
||||||
scrollHorizontally((ScrollBar) event.widget);
|
if (painterList.size() == 0)
|
||||||
|
return;
|
||||||
|
setOrigin(-((ScrollBar) event.widget).getSelection(), origin.y);
|
||||||
|
if (ruler != null)
|
||||||
|
ruler.setStartPoint(-origin.x * scaleFactor);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ScrollBar vertical = getVerticalBar();
|
ScrollBar vertical = getVerticalBar();
|
||||||
|
@ -252,26 +241,28 @@ public class WaveformCanvas extends Canvas {
|
||||||
vertical.setVisible(true);
|
vertical.setVisible(true);
|
||||||
vertical.addSelectionListener(new SelectionAdapter() {
|
vertical.addSelectionListener(new SelectionAdapter() {
|
||||||
public void widgetSelected(SelectionEvent event) {
|
public void widgetSelected(SelectionEvent event) {
|
||||||
scrollVertically((ScrollBar) event.widget);
|
if (painterList.size() == 0)
|
||||||
|
return;
|
||||||
|
setOrigin(origin.x, -((ScrollBar) event.widget).getSelection());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Synchronize the scrollbar with the image. If the transform is out
|
* Synchronize the scrollbar with the image. If the transform is out of
|
||||||
* of range, it will correct it. This function considers only following
|
* range, it will correct it. This function considers only following factors
|
||||||
* factors :<b> transform, image size, client area</b>.
|
* :<b> transform, image size, client area</b>.
|
||||||
*/
|
*/
|
||||||
private void syncScrollBars() {
|
private void syncScrollBars() {
|
||||||
if (painterList.size()==0) {
|
if (painterList.size() == 0) {
|
||||||
redraw();
|
redraw();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int height=1;
|
int height = 1;
|
||||||
if(trackVerticalOffset.size()>0)
|
if (trackVerticalOffset.size() > 0)
|
||||||
height=trackVerticalOffset.lastKey()+trackVerticalOffset.lastEntry().getValue().getMinHeight();
|
height = trackVerticalOffset.lastKey() + trackVerticalOffset.lastEntry().getValue().getMinHeight();
|
||||||
|
|
||||||
int width = (int) (maxTime/scaleFactor);
|
int width = (int) (maxTime / scaleFactor);
|
||||||
ScrollBar horizontal = getHorizontalBar();
|
ScrollBar horizontal = getHorizontalBar();
|
||||||
horizontal.setIncrement((int) (getClientArea().width / 100));
|
horizontal.setIncrement((int) (getClientArea().width / 100));
|
||||||
horizontal.setPageIncrement(getClientArea().width);
|
horizontal.setPageIncrement(getClientArea().width);
|
||||||
|
@ -279,7 +270,7 @@ public class WaveformCanvas extends Canvas {
|
||||||
if (width > cw) { /* image is wider than client area */
|
if (width > cw) { /* image is wider than client area */
|
||||||
horizontal.setMaximum(width);
|
horizontal.setMaximum(width);
|
||||||
horizontal.setEnabled(true);
|
horizontal.setEnabled(true);
|
||||||
if (((int) - origin.x) > horizontal.getMaximum() - cw)
|
if (((int) -origin.x) > horizontal.getMaximum() - cw)
|
||||||
origin.x = -horizontal.getMaximum() + cw;
|
origin.x = -horizontal.getMaximum() + cw;
|
||||||
} else { /* image is narrower than client area */
|
} else { /* image is narrower than client area */
|
||||||
horizontal.setEnabled(false);
|
horizontal.setEnabled(false);
|
||||||
|
@ -291,10 +282,10 @@ public class WaveformCanvas extends Canvas {
|
||||||
vertical.setIncrement((int) (getClientArea().height / 100));
|
vertical.setIncrement((int) (getClientArea().height / 100));
|
||||||
vertical.setPageIncrement((int) (getClientArea().height));
|
vertical.setPageIncrement((int) (getClientArea().height));
|
||||||
int ch = getClientArea().height;
|
int ch = getClientArea().height;
|
||||||
if (height> ch) { /* image is higher than client area */
|
if (height > ch) { /* image is higher than client area */
|
||||||
vertical.setMaximum(height);
|
vertical.setMaximum(height);
|
||||||
vertical.setEnabled(true);
|
vertical.setEnabled(true);
|
||||||
if (((int) - origin.y) > vertical.getMaximum() - ch)
|
if (((int) -origin.y) > vertical.getMaximum() - ch)
|
||||||
origin.y = -vertical.getMaximum() + ch;
|
origin.y = -vertical.getMaximum() + ch;
|
||||||
} else { /* image is less higher than client area */
|
} else { /* image is less higher than client area */
|
||||||
vertical.setMaximum((int) (ch));
|
vertical.setMaximum((int) (ch));
|
||||||
|
@ -304,21 +295,30 @@ public class WaveformCanvas extends Canvas {
|
||||||
vertical.setThumb(ch);
|
vertical.setThumb(ch);
|
||||||
ruler.setScaleFactor(scaleFactor);
|
ruler.setScaleFactor(scaleFactor);
|
||||||
redraw();
|
redraw();
|
||||||
|
Event e = new Event();
|
||||||
|
e.widget = this;
|
||||||
|
SelectionEvent ev = new SelectionEvent(e);
|
||||||
|
ev.x = origin.x;
|
||||||
|
ev.y = origin.y;
|
||||||
|
for (SelectionAdapter a : selectionListeners) {
|
||||||
|
a.widgetSelected(ev);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Paint function */
|
/* Paint function */
|
||||||
private void paint(GC gc) {
|
private void paint(GC gc) {
|
||||||
Rectangle clientRect = getClientArea(); /* Canvas' painting area */
|
Rectangle clientRect = getClientArea(); /* Canvas' painting area */
|
||||||
clientRect.x=-origin.x;
|
clientRect.x = -origin.x;
|
||||||
clientRect.y=-origin.y;
|
clientRect.y = -origin.y;
|
||||||
// reset the transform
|
// reset the transform
|
||||||
transform.identity();
|
transform.identity();
|
||||||
// shift the content
|
// shift the content
|
||||||
transform.translate(origin.x, origin.y);
|
transform.translate(origin.x, origin.y);
|
||||||
gc.setTransform(transform);
|
gc.setTransform(transform);
|
||||||
gc.setClipping(clientRect);
|
gc.setClipping(clientRect);
|
||||||
if (painterList.size()>0 && trackVerticalOffset.size()>0) {
|
if (painterList.size() > 0 && trackVerticalOffset.size() > 0) {
|
||||||
for(IPainter painter: painterList)
|
for (IPainter painter : painterList)
|
||||||
painter.paintArea(gc, clientRect);
|
painter.paintArea(gc, clientRect);
|
||||||
} else {
|
} else {
|
||||||
gc.fillRectangle(clientRect);
|
gc.fillRectangle(clientRect);
|
||||||
|
@ -327,19 +327,19 @@ public class WaveformCanvas extends Canvas {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object getClicked(Point point) {
|
public Object getClicked(Point point) {
|
||||||
for(IPainter p:Lists.reverse(painterList)){
|
for (IPainter p : Lists.reverse(painterList)) {
|
||||||
if(p instanceof TrackPainter){
|
if (p instanceof TrackPainter) {
|
||||||
int y= point.y-origin.y;
|
int y = point.y - origin.y;
|
||||||
int x=point.x-origin.x;
|
int x = point.x - origin.x;
|
||||||
Entry<Integer, IWaveformPainter> entry = trackVerticalOffset.floorEntry(y);
|
Entry<Integer, IWaveformPainter> entry = trackVerticalOffset.floorEntry(y);
|
||||||
if(entry!=null){
|
if (entry != null) {
|
||||||
if(entry.getValue() instanceof StreamPainter){
|
if (entry.getValue() instanceof StreamPainter) {
|
||||||
return ((StreamPainter)entry.getValue()).getClicked(new Point(x,y-entry.getKey()));
|
return ((StreamPainter) entry.getValue()).getClicked(new Point(x, y - entry.getKey()));
|
||||||
}else if(entry.getValue() instanceof SignalPainter)
|
} else if (entry.getValue() instanceof SignalPainter)
|
||||||
return ((SignalPainter)entry.getValue()).getSignal();
|
return ((SignalPainter) entry.getValue()).getSignal();
|
||||||
}
|
}
|
||||||
}else if(p instanceof CursorPainter){
|
} else if (p instanceof CursorPainter) {
|
||||||
if(Math.abs(point.x*scaleFactor-((CursorPainter)p).getTime())<2){
|
if (Math.abs(point.x * scaleFactor - ((CursorPainter) p).getTime()) < 2) {
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -348,33 +348,42 @@ public class WaveformCanvas extends Canvas {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSelected(ITx currentSelection, IWaveform<? extends IWaveformEvent> currentWaveformSelection) {
|
public void setSelected(ITx currentSelection, IWaveform<? extends IWaveformEvent> currentWaveformSelection) {
|
||||||
this.currentSelection=currentSelection;
|
this.currentSelection = currentSelection;
|
||||||
this.currentWaveformSelection=currentWaveformSelection;
|
this.currentWaveformSelection = currentWaveformSelection;
|
||||||
if(currentSelection!=null) reveal(currentSelection);
|
if (currentSelection != null)
|
||||||
|
reveal(currentSelection);
|
||||||
redraw();
|
redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reveal(ITx tx){
|
public void reveal(ITx tx) {
|
||||||
int lower = (int) (tx.getBeginTime()/scaleFactor);
|
int lower = (int) (tx.getBeginTime() / scaleFactor);
|
||||||
int higher=(int) (tx.getEndTime()/scaleFactor);
|
int higher = (int) (tx.getEndTime() / scaleFactor);
|
||||||
Point size = getSize();
|
Point size = getSize();
|
||||||
if(lower<-origin.x){
|
size.x -= getVerticalBar().getSize().x + 2;
|
||||||
scrollToX(lower);
|
size.y -= getHorizontalBar().getSize().y;
|
||||||
} else if(higher>(size.x-origin.x)){
|
if (lower < -origin.x) {
|
||||||
scrollToX(higher-size.x);
|
setOrigin(-lower, origin.y);
|
||||||
|
} else if (higher > (size.x - origin.x)) {
|
||||||
|
setOrigin(size.x - higher, origin.y);
|
||||||
}
|
}
|
||||||
for(Entry<Integer, IWaveformPainter> entry:trackVerticalOffset.entrySet()){
|
for (Entry<Integer, IWaveformPainter> entry : trackVerticalOffset.entrySet()) {
|
||||||
if(entry.getValue() instanceof StreamPainter && ((StreamPainter)entry.getValue()).getStream()==tx.getStream()){
|
if (entry.getValue() instanceof StreamPainter && ((StreamPainter) entry.getValue()).getStream() == tx.getStream()) {
|
||||||
int top = entry.getKey()+trackHeight*tx.getConcurrencyIndex();
|
int top = entry.getKey() + trackHeight * tx.getConcurrencyIndex();
|
||||||
int bottom = top+trackHeight*(tx.getConcurrencyIndex()+1);
|
int bottom = top + trackHeight;
|
||||||
if(top<-origin.y){
|
if (top < -origin.y) {
|
||||||
scrollToY(bottom);
|
setOrigin(origin.x, -top);
|
||||||
} else if(bottom>(size.y-origin.y)){
|
} else if (bottom > (size.y - origin.y)) {
|
||||||
scrollToY(bottom-size.y);
|
setOrigin(origin.x, size.y - bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addSelectionListener(SelectionAdapter selectionAdapter) {
|
||||||
|
selectionListeners.add(selectionAdapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeSelectionListener(SelectionAdapter selectionAdapter) {
|
||||||
|
selectionListeners.remove(selectionAdapter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ public class TextDbLoader implements IWaveformDbLoader{
|
||||||
@Override
|
@Override
|
||||||
boolean load(IWaveformDb db, File file) throws Exception {
|
boolean load(IWaveformDb db, File file) throws Exception {
|
||||||
this.db=db
|
this.db=db
|
||||||
|
this.streams=[]
|
||||||
FileInputStream fis = new FileInputStream(file)
|
FileInputStream fis = new FileInputStream(file)
|
||||||
byte[] buffer = new byte[x.size()]
|
byte[] buffer = new byte[x.size()]
|
||||||
def readCnt = fis.read(buffer, 0, x.size())
|
def readCnt = fis.read(buffer, 0, x.size())
|
||||||
|
|
|
@ -51,7 +51,11 @@ class Tx implements ITx {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(ITx o) {
|
public int compareTo(ITx o) {
|
||||||
return beginTime.compareTo(o.beginTime)
|
def res =beginTime.compareTo(o.beginTime)
|
||||||
|
if(res!=0)
|
||||||
|
return res
|
||||||
|
else
|
||||||
|
return id.compareTo(o.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,12 +8,15 @@ class TxEvent implements ITxEvent {
|
||||||
|
|
||||||
final ITxEvent.Type type;
|
final ITxEvent.Type type;
|
||||||
|
|
||||||
Tx transaction;
|
final Tx transaction;
|
||||||
|
|
||||||
|
final Long time
|
||||||
|
|
||||||
TxEvent(ITxEvent.Type type, ITx transaction) {
|
TxEvent(ITxEvent.Type type, ITx transaction) {
|
||||||
super();
|
super();
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.transaction = transaction;
|
this.transaction = transaction;
|
||||||
|
this.time = type==ITxEvent.Type.BEGIN?transaction.beginTime:transaction.endTime
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -23,15 +26,11 @@ class TxEvent implements ITxEvent {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
int compareTo(IWaveformEvent o) {
|
int compareTo(IWaveformEvent o) {
|
||||||
time.compareTo(o.getTime())
|
time.compareTo(o.time)
|
||||||
}
|
|
||||||
|
|
||||||
Long getTime(){
|
|
||||||
type==ITxEvent.Type.BEGIN?transaction.beginTime:transaction.endTime
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
String toString() {
|
String toString() {
|
||||||
type.toString()+"@"+getTime()+" of tx #"+transaction.id;
|
type.toString()+"@"+time+" of tx #"+transaction.id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,7 +92,9 @@ class TxStream extends HierNode implements ITxStream {
|
||||||
}
|
}
|
||||||
|
|
||||||
private putEvent(ITxEvent event){
|
private putEvent(ITxEvent event){
|
||||||
if(!events.containsKey(event.time)) events.put(event.time, [])
|
if(!events.containsKey(event.time))
|
||||||
|
events.put(event.time, [event])
|
||||||
|
else
|
||||||
events[event.time]<<event
|
events[event.time]<<event
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,3 +8,6 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.7
|
||||||
Export-Package: com.minres.scviewer.database
|
Export-Package: com.minres.scviewer.database
|
||||||
Bundle-ActivationPolicy: lazy
|
Bundle-ActivationPolicy: lazy
|
||||||
Service-Component: OSGI-INF/component.xml
|
Service-Component: OSGI-INF/component.xml
|
||||||
|
Require-Bundle: org.eclipse.equinox.ds;bundle-version="1.4.200",
|
||||||
|
org.eclipse.equinox.util;bundle-version="1.0.500",
|
||||||
|
org.eclipse.osgi.services;bundle-version="3.4.0"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="com.minres.scviewer.database">
|
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="com.minres.scviewer.database">
|
||||||
<implementation class="com.minres.scviewer.database.WaveformDb"/>
|
<implementation class="com.minres.scviewer.database.WaveformDb"/>
|
||||||
<reference bind="bind" cardinality="0..n" interface="com.minres.scviewer.database.IWaveformDbLoader" name="IWaveformDbLoader" policy="dynamic" unbind="unbind"/>
|
<reference bind="bind" cardinality="1..n" interface="com.minres.scviewer.database.IWaveformDbLoader" name="IWaveformDbLoader" policy="dynamic" unbind="unbind"/>
|
||||||
</scr:component>
|
</scr:component>
|
|
@ -29,11 +29,11 @@ http://www.eclipse.org/legal/epl-v10.html
|
||||||
</url>
|
</url>
|
||||||
|
|
||||||
<requires>
|
<requires>
|
||||||
|
<import plugin="org.eclipse.equinox.ds" version="1.4.200" match="greaterOrEqual"/>
|
||||||
|
<import plugin="org.eclipse.equinox.util" version="1.0.500" match="greaterOrEqual"/>
|
||||||
|
<import plugin="org.eclipse.osgi.services" version="3.4.0" match="greaterOrEqual"/>
|
||||||
<import plugin="com.minres.scviewer.database" version="1.0.0" match="greaterOrEqual"/>
|
<import plugin="com.minres.scviewer.database" version="1.0.0" match="greaterOrEqual"/>
|
||||||
<import plugin="org.codehaus.groovy" version="1.8.6" match="greaterOrEqual"/>
|
<import plugin="org.codehaus.groovy" version="1.8.6" match="greaterOrEqual"/>
|
||||||
<import plugin="org.eclipse.equinox.util" version="1.0.500" match="greaterOrEqual"/>
|
|
||||||
<import plugin="org.eclipse.equinox.ds" version="1.4.200" match="greaterOrEqual"/>
|
|
||||||
<import plugin="org.eclipse.osgi.services" version="3.4.0" match="greaterOrEqual"/>
|
|
||||||
<import plugin="org.eclipse.osgi"/>
|
<import plugin="org.eclipse.osgi"/>
|
||||||
<import plugin="org.eclipse.core.runtime"/>
|
<import plugin="org.eclipse.core.runtime"/>
|
||||||
<import plugin="org.eclipse.core.resources"/>
|
<import plugin="org.eclipse.core.resources"/>
|
||||||
|
@ -43,9 +43,14 @@ http://www.eclipse.org/legal/epl-v10.html
|
||||||
<import plugin="org.eclipse.ui.ide"/>
|
<import plugin="org.eclipse.ui.ide"/>
|
||||||
<import plugin="org.eclipse.ui.views.properties.tabbed"/>
|
<import plugin="org.eclipse.ui.views.properties.tabbed"/>
|
||||||
<import plugin="org.eclipse.swt"/>
|
<import plugin="org.eclipse.swt"/>
|
||||||
<import plugin="org.eclipse.ui.views"/>
|
|
||||||
<import plugin="org.apache.ant"/>
|
<import plugin="org.apache.ant"/>
|
||||||
|
<import plugin="com.google.guava" version="15.0.0" match="greaterOrEqual"/>
|
||||||
|
<import plugin="com.minres.scviewer.database.swt" version="1.0.0" match="greaterOrEqual"/>
|
||||||
|
<import plugin="org.eclipse.core.expressions" version="3.4.600" match="greaterOrEqual"/>
|
||||||
|
<import plugin="org.eclipse.jface"/>
|
||||||
<import plugin="org.junit"/>
|
<import plugin="org.junit"/>
|
||||||
|
<import plugin="org.eclipse.swt" version="3.103.1" match="greaterOrEqual"/>
|
||||||
|
<import plugin="org.eclipse.equinox.registry"/>
|
||||||
</requires>
|
</requires>
|
||||||
|
|
||||||
<plugin
|
<plugin
|
||||||
|
@ -96,4 +101,17 @@ http://www.eclipse.org/legal/epl-v10.html
|
||||||
version="0.0.0"
|
version="0.0.0"
|
||||||
unpack="false"/>
|
unpack="false"/>
|
||||||
|
|
||||||
|
<plugin
|
||||||
|
id="org.junit"
|
||||||
|
download-size="0"
|
||||||
|
install-size="0"
|
||||||
|
version="0.0.0"/>
|
||||||
|
|
||||||
|
<plugin
|
||||||
|
id="org.hamcrest.core"
|
||||||
|
download-size="0"
|
||||||
|
install-size="0"
|
||||||
|
version="0.0.0"
|
||||||
|
unpack="false"/>
|
||||||
|
|
||||||
</feature>
|
</feature>
|
||||||
|
|
Loading…
Reference in New Issue