diff --git a/com.minres.scviewer.database.sqlite/src/com/minres/scviewer/database/sqlite/SQLiteDbLoader.java b/com.minres.scviewer.database.sqlite/src/com/minres/scviewer/database/sqlite/SQLiteDbLoader.java index a6e05ed..d677b73 100644 --- a/com.minres.scviewer.database.sqlite/src/com/minres/scviewer/database/sqlite/SQLiteDbLoader.java +++ b/com.minres.scviewer.database.sqlite/src/com/minres/scviewer/database/sqlite/SQLiteDbLoader.java @@ -14,6 +14,7 @@ import java.beans.IntrospectionException; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.sql.SQLException; import java.util.ArrayList; @@ -91,6 +92,8 @@ public class SQLiteDbLoader implements IWaveformDbLoader { if (buffer[i] != x[i]) return false; } catch(FileNotFoundException e) { return false; + } catch(IOException e) { //if an I/O error occurs + return false; } database=new SQLiteDatabase(file.getAbsolutePath()); database.setData("TIMERESOLUTION", 1L); diff --git a/com.minres.scviewer.database.ui.swt/META-INF/MANIFEST.MF b/com.minres.scviewer.database.ui.swt/META-INF/MANIFEST.MF index 1e8ad75..a11ba7f 100644 --- a/com.minres.scviewer.database.ui.swt/META-INF/MANIFEST.MF +++ b/com.minres.scviewer.database.ui.swt/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: SWT widget Bundle-SymbolicName: com.minres.scviewer.database.ui.swt -Bundle-Version: 2.1.0.qualifier +Bundle-Version: 2.2.0.qualifier Bundle-Vendor: MINRES Technologies GmbH Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Require-Bundle: org.eclipse.swt;bundle-version="3.103.1", diff --git a/com.minres.scviewer.database.ui.swt/pom.xml b/com.minres.scviewer.database.ui.swt/pom.xml index 95ddd22..34b8a4f 100644 --- a/com.minres.scviewer.database.ui.swt/pom.xml +++ b/com.minres.scviewer.database.ui.swt/pom.xml @@ -8,5 +8,5 @@ 2.0.0-SNAPSHOT ../com.minres.scviewer.parent - 2.1.0-SNAPSHOT + 2.2.0-SNAPSHOT \ No newline at end of file diff --git a/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/swt/Constants.java b/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/swt/Constants.java index 679fc92..4abb67c 100644 --- a/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/swt/Constants.java +++ b/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/swt/Constants.java @@ -2,8 +2,11 @@ package com.minres.scviewer.database.swt; public class Constants { - public final static String[] unitString={"fs", "ps", "ns", "us", "ms"};//, "s"}; + public static final String[] unitString={"fs", "ps", "ns", "us", "ms"};//, "s"}; - public final static int[] unitMultiplier={1, 3, 10, 30, 100, 300}; + public static final int[] unitMultiplier={1, 3, 10, 30, 100, 300}; + + public static final String CONTENT_PROVIDER_TAG = "TOOLTIP_CONTENT_PROVIDER"; + public static final String HELP_PROVIDER_TAG = "TOOLTIP_HELP_PROVIDER"; } diff --git a/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/swt/ToolTipContentProvider.java b/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/swt/ToolTipContentProvider.java new file mode 100644 index 0000000..6d46a31 --- /dev/null +++ b/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/swt/ToolTipContentProvider.java @@ -0,0 +1,10 @@ +package com.minres.scviewer.database.swt; + +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Composite; + +public interface ToolTipContentProvider { + + public boolean createContent(Composite parent, Point pt); + +} \ No newline at end of file diff --git a/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/swt/ToolTipHelpTextProvider.java b/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/swt/ToolTipHelpTextProvider.java new file mode 100644 index 0000000..8892b80 --- /dev/null +++ b/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/swt/ToolTipHelpTextProvider.java @@ -0,0 +1,12 @@ +package com.minres.scviewer.database.swt; + +import org.eclipse.swt.widgets.Widget; + +public interface ToolTipHelpTextProvider { + /** + * Get help text + * @param widget the widget that is under help + * @return a help text string + */ + public String getHelpText(Widget widget); +} \ No newline at end of file diff --git a/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/swt/internal/RelSelectionDialog.java b/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/swt/internal/RelSelectionDialog.java new file mode 100644 index 0000000..fc53660 --- /dev/null +++ b/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/swt/internal/RelSelectionDialog.java @@ -0,0 +1,73 @@ +package com.minres.scviewer.database.swt.internal; + +import static org.eclipse.swt.events.SelectionListener.widgetSelectedAdapter; + +import java.util.ArrayList; +import java.util.stream.Collectors; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.RowLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Dialog; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.List; +import org.eclipse.swt.widgets.Shell; + +import com.minres.scviewer.database.ITx; +import com.minres.scviewer.database.ITxRelation; + +class RelSelectionDialog extends Dialog { + private java.util.List entries; + + private java.util.List entryTx; + + private ITxRelation selected = null; + + public RelSelectionDialog(Shell shell, ArrayList candidates, boolean target) { + super(shell); + entries = candidates; + entryTx = entries.stream().map(r->target?r.getTarget():r.getSource()).collect(Collectors.toCollection(ArrayList::new)); + } + +public ITxRelation open() { + Shell parent = getParent(); + Shell dialog = new Shell(parent, SWT.SHEET | SWT.APPLICATION_MODAL); + dialog.setMinimumSize(10, 10); + + RowLayout rowLayout = new RowLayout(SWT.VERTICAL); + //rowLayout.fill = true; // Overriding default values. + rowLayout.marginWidth=3; + rowLayout.marginHeight=0; + rowLayout.marginLeft = 3; + rowLayout.marginTop = 0; + rowLayout.marginRight = 3; + rowLayout.marginBottom = 0; + dialog.setLayout(rowLayout); + final Label lbl = new Label(dialog,SWT.NONE); + lbl.setText("Select one:"); + final List list = new List (dialog, SWT.NONE); + for (ITx iTx : entryTx) { + list.add ("#tx" + iTx.getId()+" ("+iTx.getStream().getFullName()+")"); + } + list.addListener (SWT.Selection, e -> { + int selection = list.getSelectionIndex(); + if(selection>=0) { + selected=entries.get(selection); + dialog.close(); + } + }); + final Button bt = new Button(dialog, SWT.PUSH | SWT.RIGHT); + bt.setText("Dismiss"); + bt.setAlignment(SWT.CENTER); + bt.addSelectionListener(widgetSelectedAdapter(e -> dialog.close())); + dialog.pack(); + dialog.open(); + Display display = parent.getDisplay(); + while (!dialog.isDisposed()) { + if (!display.readAndDispatch()) + display.sleep(); + } + return selected; + } +} \ No newline at end of file diff --git a/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/swt/internal/ToolTipHandler.java b/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/swt/internal/ToolTipHandler.java new file mode 100644 index 0000000..087e0f6 --- /dev/null +++ b/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/swt/internal/ToolTipHandler.java @@ -0,0 +1,140 @@ +package com.minres.scviewer.database.swt.internal; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.RowLayout; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.Widget; + +import com.minres.scviewer.database.swt.Constants; +import com.minres.scviewer.database.swt.ToolTipContentProvider; +import com.minres.scviewer.database.swt.ToolTipHelpTextProvider; + +class ToolTipHandler { + + private final Display display; + private Shell parentShell; + private Shell shell; + + private Widget tipWidget; // widget this tooltip is hovering over + private Point tipPosition; // the position being hovered over + + private static final int hoverYOffset = 1; + + /** + * Creates a new tooltip handler + * + * @param parent the parent Shell + */ + public ToolTipHandler(Shell parent) { + display = parent.getDisplay(); + parentShell = parent; + } + + /** + * Enables customized hover help for a specified control + * + * @control the control on which to enable hoverhelp + */ + public void activateHoverHelp(final Control control) { + Listener listener = new Listener () { + Shell tip = null; + @Override + public void handleEvent (Event event) { + switch (event.type) { + case SWT.KeyDown:{ + if (tip != null && tip.isVisible() && event.keyCode == SWT.F2) { + tip.setFocus(); + break; + } + } + case SWT.Dispose: + case SWT.MouseMove: + case SWT.MouseDown: { + if (tip != null){ + tip.dispose (); + tip = null; + tipWidget=null; + } + break; + } + case SWT.MouseHover: { + Object o = control.getData(Constants.CONTENT_PROVIDER_TAG); + if(o != null && o instanceof ToolTipContentProvider) { + ToolTipContentProvider provider = ((ToolTipContentProvider)o); + Point pt = new Point (event.x, event.y); + tipPosition = control.toDisplay(pt); + if (tip != null && !tip.isDisposed ()) tip.dispose (); + tip = new Shell (parentShell, SWT.ON_TOP | SWT.NO_FOCUS | SWT.TOOL); + tip.setBackground (display.getSystemColor (SWT.COLOR_INFO_BACKGROUND)); + RowLayout layout=new RowLayout(SWT.VERTICAL); + layout.fill=true; + tip.setLayout(layout); + boolean visible = provider.createContent(tip, pt); + tip.pack(); + setHoverLocation(tip, tipPosition); + tip.setVisible (visible); + if(visible) + tipWidget=event.widget; + } + } + } + } + }; + control.addListener (SWT.Dispose, listener); + control.addListener (SWT.KeyDown, listener); + //control.addListener (SWT.MouseMove, listener); + control.addListener (SWT.MouseHover, listener); + control.addListener (SWT.MouseDown, listener); + + /* + * Trap F1 Help to pop up a custom help box + */ + control.addHelpListener(event -> { + if (tipWidget == null) return; + ToolTipHelpTextProvider handler = (ToolTipHelpTextProvider)tipWidget.getData(Constants.HELP_PROVIDER_TAG); + if (handler == null) return; + String text = handler.getHelpText(tipWidget); + if (text == null) return; + + if (shell.isVisible()) { + shell.setVisible(false); + Shell helpShell = new Shell(parentShell, SWT.SHELL_TRIM); + helpShell.setLayout(new FillLayout()); + Label label = new Label(helpShell, SWT.NONE); + label.setText(text); + helpShell.pack(); + setHoverLocation(helpShell, tipPosition); + helpShell.open(); + } + }); + // control.addKeyListener(KeyListener.keyPressedAdapter( e-> { + // if (e.keyCode == SWT.F2 && shell.isVisible()) { + // shell.setFocus(); + // } + // })); + } + + /** + * Sets the location for a hovering shell + * @param shell the object that is to hover + * @param position the position of a widget to hover over + * @return the top-left location for a hovering box + */ + private void setHoverLocation(Shell shell, Point position) { + Rectangle displayBounds = shell.getDisplay().getBounds(); + Rectangle shellBounds = shell.getBounds(); + shellBounds.x = Math.max(Math.min(position.x, displayBounds.width - shellBounds.width), 0); + shellBounds.y = Math.max(Math.min(position.y + hoverYOffset, displayBounds.height - shellBounds.height), 0); + shell.setBounds(shellBounds); + } +} \ No newline at end of file diff --git a/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/swt/internal/WaveformCanvas.java b/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/swt/internal/WaveformCanvas.java index 06687bc..dd29137 100644 --- a/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/swt/internal/WaveformCanvas.java +++ b/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/swt/internal/WaveformCanvas.java @@ -426,7 +426,7 @@ public class WaveformCanvas extends Canvas{ } } - public List getClicked(Point point) { + public List getElementsAt(Point point) { LinkedList result=new LinkedList<>(); for (IPainter p : Lists.reverse(painterList)) { if (p instanceof TrackAreaPainter) { diff --git a/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/swt/internal/WaveformViewer.java b/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/swt/internal/WaveformViewer.java index 7f0654f..7cc3267 100644 --- a/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/swt/internal/WaveformViewer.java +++ b/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/swt/internal/WaveformViewer.java @@ -15,6 +15,7 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.text.DecimalFormat; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -24,6 +25,7 @@ import java.util.Map.Entry; import java.util.NavigableMap; import java.util.NoSuchElementException; import java.util.TreeMap; +import java.util.stream.Collectors; import org.eclipse.core.runtime.ListenerList; import org.eclipse.jface.util.LocalSelectionTransfer; @@ -97,7 +99,7 @@ public class WaveformViewer implements IWaveformViewer { private PropertyChangeSupport pcs; - static final DecimalFormat df = new DecimalFormat("#.00####"); + static final DecimalFormat df = new DecimalFormat("#0.00####"); private ITx currentTxSelection; @@ -115,6 +117,8 @@ public class WaveformViewer implements IWaveformViewer { final WaveformCanvas waveformCanvas; + final ToolTipHandler toolTipHandler; + private boolean revealSelected=false; private Composite top; @@ -159,7 +163,7 @@ public class WaveformViewer implements IWaveformViewer { down=true; if((e.stateMask&SWT.MODIFIER_MASK)!=0) return; //don't react on modifier if (e.button == 1) { - initialSelected = waveformCanvas.getClicked(start); + initialSelected = waveformCanvas.getElementsAt(start); } else if (e.button == 3) { Menu topMenu= top.getMenu(); if(topMenu!=null) topMenu.setVisible(true); @@ -248,7 +252,7 @@ public class WaveformViewer implements IWaveformViewer { protected long snapOffsetToEvent(Point p) { long time= waveformCanvas.getTimeForOffset(p.x); long scaling=5*waveformCanvas.getScaleFactor(); - for(Object o:waveformCanvas.getClicked(p)){ + for(Object o:waveformCanvas.getElementsAt(p)){ Entry floorEntry=null, ceilEntry=null; if(o instanceof TrackEntry){ TrackEntry entry = (TrackEntry) o; @@ -417,6 +421,9 @@ public class WaveformViewer implements IWaveformViewer { createStreamDropTarget(valueList); createWaveformDragSource(waveformCanvas); createWaveformDropTarget(waveformCanvas); + + toolTipHandler = new ToolTipHandler(parent.getShell()); + toolTipHandler.activateHoverHelp(waveformCanvas); } private Composite createTextPane(SashForm leftSash, String text) { @@ -809,25 +816,41 @@ public class WaveformViewer implements IWaveformViewer { } else { if (direction == GotoDirection.NEXT) { Collection outRel=currentTxSelection.getOutgoingRelations(); - for(ITxRelation rel:outRel){ - if(relationType.equals(rel.getRelationType())){ - setSelection(new StructuredSelection(rel.getTarget()), true); - return; - } - } + ITxRelation tx = selectTxToNavigateTo(outRel, relationType, true); + if(tx!=null) setSelection(new StructuredSelection(tx.getTarget()), true); } else if (direction == GotoDirection.PREV) { Collection inRel=currentTxSelection.getIncomingRelations(); - for(ITxRelation rel:inRel){ - if(relationType.equals(rel.getRelationType())){ - setSelection(new StructuredSelection(rel.getSource()), true); - return; - } - } + ITxRelation tx = selectTxToNavigateTo(inRel, relationType, false); + if(tx!=null) setSelection(new StructuredSelection(tx.getSource()), true); } } } } + private ITxRelation selectTxToNavigateTo(Collection rel, RelationType relationType, boolean target) { + ArrayList candidates = rel.stream().filter(r -> relationType.equals(r.getRelationType())).collect(Collectors.toCollection(ArrayList::new)); + //new RelSelectionDialog(waveformCanvas.getShell(), candidates, target).open(); + switch (candidates.size()) { + case 0: return null; + case 1: return candidates.get(0); + default: + ArrayList visibleCandidates = candidates.stream().filter(r -> streamsVisible(r)).collect(Collectors.toCollection(ArrayList::new)); + if(visibleCandidates.size()==0) { + return new RelSelectionDialog(waveformCanvas.getShell(), candidates, target).open(); + } else if(visibleCandidates.size()==1) { + return visibleCandidates.size()==1?visibleCandidates.get(0):null; + } else { + return new RelSelectionDialog(waveformCanvas.getShell(), visibleCandidates, target).open(); + } + } + } + + private boolean streamsVisible(ITxRelation relation) { + final ITxStream src = relation.getSource().getStream(); + final ITxStream tgt = relation.getTarget().getStream(); + return streams.stream().anyMatch(x -> x.waveform == src) && streams.stream().anyMatch(x -> x.waveform == tgt); + } + /* (non-Javadoc) * @see com.minres.scviewer.database.swt.IWaveformPanel#moveCursor(com.minres.scviewer.database.swt.GotoDirection) */ @@ -1130,6 +1153,10 @@ public class WaveformViewer implements IWaveformViewer { return null; } + public List getElementsAt(Point pt){ + return waveformCanvas.getElementsAt(pt); + } + private void createWaveformDragSource(final Canvas canvas) { Transfer[] types = new Transfer[] { LocalSelectionTransfer.getTransfer() }; DragSource dragSource = new DragSource(canvas, DND.DROP_MOVE); @@ -1137,7 +1164,7 @@ public class WaveformViewer implements IWaveformViewer { dragSource.addDragListener(new DragSourceAdapter() { public void dragStart(DragSourceEvent event) { event.doit = false; - List clicked = waveformCanvas.getClicked(new Point(event.x, event.y)); + List clicked = waveformCanvas.getElementsAt(new Point(event.x, event.y)); for(Object o:clicked){ if(o instanceof CursorPainter){ LocalSelectionTransfer.getTransfer().setSelection(new StructuredSelection(o)); @@ -1150,7 +1177,7 @@ public class WaveformViewer implements IWaveformViewer { public void dragSetData(DragSourceEvent event) { if (LocalSelectionTransfer.getTransfer().isSupportedType(event.dataType)) { - event.data=waveformCanvas.getClicked(new Point(event.x, event.y)); + event.data=waveformCanvas.getElementsAt(new Point(event.x, event.y)); } } }); diff --git a/com.minres.scviewer.database.ui/src/com/minres/scviewer/database/ui/IWaveformViewer.java b/com.minres.scviewer.database.ui/src/com/minres/scviewer/database/ui/IWaveformViewer.java index 6575cfc..77ced9b 100644 --- a/com.minres.scviewer.database.ui/src/com/minres/scviewer/database/ui/IWaveformViewer.java +++ b/com.minres.scviewer.database.ui/src/com/minres/scviewer/database/ui/IWaveformViewer.java @@ -18,6 +18,7 @@ import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.widgets.Control; @@ -62,6 +63,8 @@ public interface IWaveformViewer extends PropertyChangeListener, ISelectionProvi public TrackEntry getEntryForStream(IWaveform source); + public List getElementsAt(Point pt); + public void moveSelectedTrack(int i); public void setHighliteRelation(RelationType relationType); diff --git a/com.minres.scviewer.e4.application/Application.e4xmi b/com.minres.scviewer.e4.application/Application.e4xmi index 42c316c..66eb04a 100644 --- a/com.minres.scviewer.e4.application/Application.e4xmi +++ b/com.minres.scviewer.e4.application/Application.e4xmi @@ -123,17 +123,22 @@ - + - + - + + + + EnableHover + + @@ -156,6 +161,7 @@ + type:user @@ -286,6 +292,7 @@ + diff --git a/com.minres.scviewer.e4.application/META-INF/MANIFEST.MF b/com.minres.scviewer.e4.application/META-INF/MANIFEST.MF index 3fee919..a5566e3 100644 --- a/com.minres.scviewer.e4.application/META-INF/MANIFEST.MF +++ b/com.minres.scviewer.e4.application/META-INF/MANIFEST.MF @@ -2,37 +2,37 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Bundle-Name Bundle-SymbolicName: com.minres.scviewer.e4.application;singleton:=true -Bundle-Version: 2.3.0.qualifier +Bundle-Version: 2.4.0.qualifier Bundle-Vendor: %Bundle-Vendor Require-Bundle: javax.inject;bundle-version="1.0.0", - org.eclipse.core.runtime;bundle-version="3.11.1", - org.eclipse.swt;bundle-version="3.104.1", - org.eclipse.e4.ui.model.workbench;bundle-version="1.1.100", - org.eclipse.jface;bundle-version="3.11.0", - org.eclipse.e4.ui.services;bundle-version="1.2.0", - org.eclipse.e4.ui.workbench;bundle-version="1.3.0", - org.eclipse.e4.core.di;bundle-version="1.5.0", - org.eclipse.e4.ui.di;bundle-version="1.1.0", - org.eclipse.e4.core.contexts;bundle-version="1.4.0", - com.minres.scviewer.database.ui.swt;bundle-version="1.0.0", - com.minres.scviewer.database.ui, - com.minres.scviewer.database;bundle-version="1.0.0", - org.eclipse.equinox.ds;bundle-version="1.4.300", - org.eclipse.equinox.util;bundle-version="1.0.500", - org.eclipse.osgi.services;bundle-version="3.5.0", - org.eclipse.e4.core.services;bundle-version="2.0.0", - org.eclipse.osgi.services;bundle-version="3.5.0", - org.eclipse.core.jobs, - org.eclipse.osgi, - com.google.guava, - org.eclipse.equinox.preferences, - org.eclipse.core.expressions, - org.eclipse.e4.core.commands;bundle-version="0.11.0", - org.eclipse.e4.ui.workbench.addons.swt, - com.opcoach.e4.preferences, - org.eclipse.e4.core.di.extensions, - org.eclipse.e4.ui.css.swt.theme;bundle-version="0.10.0" + org.eclipse.core.runtime;bundle-version="3.11.1", + org.eclipse.swt;bundle-version="3.104.1", + org.eclipse.e4.ui.model.workbench;bundle-version="1.1.100", + org.eclipse.jface;bundle-version="3.11.0", + org.eclipse.e4.ui.services;bundle-version="1.2.0", + org.eclipse.e4.ui.workbench;bundle-version="1.3.0", + org.eclipse.e4.core.di;bundle-version="1.5.0", + org.eclipse.e4.ui.di;bundle-version="1.1.0", + org.eclipse.e4.core.contexts;bundle-version="1.4.0", + com.minres.scviewer.database.ui.swt;bundle-version="1.0.0", + com.minres.scviewer.database.ui, + com.minres.scviewer.database;bundle-version="1.0.0", + org.eclipse.equinox.ds;bundle-version="1.4.300", + org.eclipse.equinox.util;bundle-version="1.0.500", + org.eclipse.osgi.services;bundle-version="3.5.0", + org.eclipse.e4.core.services;bundle-version="2.0.0", + org.eclipse.osgi.services;bundle-version="3.5.0", + org.eclipse.core.jobs, + org.eclipse.osgi, + com.google.guava, + org.eclipse.equinox.preferences, + org.eclipse.core.expressions, + org.eclipse.e4.core.commands;bundle-version="0.11.0", + org.eclipse.e4.ui.workbench.addons.swt, + com.opcoach.e4.preferences, + org.eclipse.e4.core.di.extensions, + org.eclipse.e4.ui.css.swt.theme;bundle-version="0.10.0" Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Import-Package: com.minres.scviewer.database, - javax.inject;version="1.0.0" + javax.inject;version="1.0.0" Automatic-Module-Name: com.minres.scviewer.e4.application diff --git a/com.minres.scviewer.e4.application/icons/lightbulb.png b/com.minres.scviewer.e4.application/icons/lightbulb.png new file mode 100644 index 0000000..d22fde8 Binary files /dev/null and b/com.minres.scviewer.e4.application/icons/lightbulb.png differ diff --git a/com.minres.scviewer.e4.application/icons/magifier_zoom_out.png b/com.minres.scviewer.e4.application/icons/magifier_zoom_out.png new file mode 100755 index 0000000..81f2819 Binary files /dev/null and b/com.minres.scviewer.e4.application/icons/magifier_zoom_out.png differ diff --git a/com.minres.scviewer.e4.application/icons/magnifier.png b/com.minres.scviewer.e4.application/icons/magnifier.png new file mode 100755 index 0000000..cf3d97f Binary files /dev/null and b/com.minres.scviewer.e4.application/icons/magnifier.png differ diff --git a/com.minres.scviewer.e4.application/icons/magnifier_zoom_in.png b/com.minres.scviewer.e4.application/icons/magnifier_zoom_in.png new file mode 100755 index 0000000..af4fe07 Binary files /dev/null and b/com.minres.scviewer.e4.application/icons/magnifier_zoom_in.png differ diff --git a/com.minres.scviewer.e4.application/pom.xml b/com.minres.scviewer.e4.application/pom.xml index a0c8e84..2fb3288 100644 --- a/com.minres.scviewer.e4.application/pom.xml +++ b/com.minres.scviewer.e4.application/pom.xml @@ -1,7 +1,7 @@ 4.0.0 com.minres.scviewer.e4.application - 2.3.0-SNAPSHOT + 2.4.0-SNAPSHOT com.minres.scviewer com.minres.scviewer.parent diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/Messages.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/Messages.java index 5e54b04..5227a22 100644 --- a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/Messages.java +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/Messages.java @@ -22,6 +22,7 @@ public class Messages extends NLS { public static String RelationTypeToolControl_1; public static String ResourceManager_0; public static String SCViewerPreferencesPage_0; + public static String SCViewerPreferencesPage_1; public static String StatusBarControl_1; public static String StatusBarControl_2; public static String StatusBarControl_3; diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/EnableHover.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/EnableHover.java new file mode 100644 index 0000000..557c61a --- /dev/null +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/EnableHover.java @@ -0,0 +1,49 @@ + +package com.minres.scviewer.e4.application.handlers; + +import java.util.LinkedList; +import java.util.List; + +import javax.annotation.PostConstruct; +import javax.inject.Inject; + +import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.eclipse.e4.core.contexts.Active; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.core.di.extensions.Preference; +import org.eclipse.e4.ui.model.application.MApplication; +import org.eclipse.e4.ui.model.application.ui.basic.MPart; +import org.eclipse.e4.ui.model.application.ui.basic.MWindow; +import org.eclipse.e4.ui.model.application.ui.menu.MHandledItem; +import org.eclipse.e4.ui.workbench.modeling.EModelService; + +import com.minres.scviewer.e4.application.preferences.PreferenceConstants; + +@SuppressWarnings("restriction") +public class EnableHover { + static final String TAG_NAME = "EnableHover"; //$NON-NLS-1$ + + @Inject + @Preference(nodePath = PreferenceConstants.PREFERENCES_SCOPE) + IEclipsePreferences prefs; + + @Inject + MApplication application; + + @PostConstruct + public void initialize(EModelService modelService) { + List tags = new LinkedList<>(); + tags.add(TAG_NAME); + List elements = modelService.findElements(application, null, MHandledItem.class, tags ); + // cover initialization stuff, sync it with code + for( MHandledItem hi : elements ){ + hi.setSelected(prefs.getBoolean(PreferenceConstants.SHOW_HOVER, true)); + } + } + + @Execute + public void execute(@Active MPart part, @Active MWindow window, MHandledItem handledItem, EModelService modelService ) { + prefs.putBoolean(PreferenceConstants.SHOW_HOVER, handledItem.isSelected()); + } + +} \ No newline at end of file diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/messages.properties b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/messages.properties index 124b0c4..264be16 100644 --- a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/messages.properties +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/messages.properties @@ -16,6 +16,7 @@ RelationTypeToolControl_0=------------ RelationTypeToolControl_1=Select ResourceManager_0=Wrong decorate corner SCViewerPreferencesPage_0=Check for changed database +SCViewerPreferencesPage_1=Show hover window in waveform StatusBarControl_1=Currently running: StatusBarControl_2=\nLast task: StatusBarControl_3=Currently running: diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/AboutDialog.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/AboutDialog.java index 7ed8815..d137e59 100644 --- a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/AboutDialog.java +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/AboutDialog.java @@ -50,9 +50,6 @@ import com.minres.scviewer.e4.application.Messages; */ public class AboutDialog extends Dialog { - /** The product title. */ - private String productTitle=Messages.AboutDialog_0; - /** The copyright text. */ private String copyrightText=Messages.AboutDialog_1; @@ -106,8 +103,8 @@ public class AboutDialog extends Dialog { styledText.setLayoutData(gd_styledText); Version version = Platform.getProduct().getDefiningBundle().getVersion(); String versionString = String.format("%d.%d.%d", version.getMajor(), version.getMinor(), version.getMicro()); - String pt = NLS.bind(Messages.AboutDialog_0, versionString); - styledText.setText(pt+copyrightText); + String productTitle = NLS.bind(Messages.AboutDialog_0, versionString); + styledText.setText(productTitle+copyrightText); styledText.setBackground(white); styledText.setWordWrap(true); styledText.setLeftMargin(5); diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/TransactionDetails.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/TransactionDetails.java index bb39838..a562c1e 100644 --- a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/TransactionDetails.java +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/TransactionDetails.java @@ -97,7 +97,7 @@ public class TransactionDetails { /** The attribute filter. */ TxAttributeFilter attributeFilter; - + /** The view sorter. */ TxAttributeViewerSorter viewSorter; @@ -124,12 +124,12 @@ public class TransactionDetails { treeViewer.expandAll(true); } }); - + nameFilter.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); attributeFilter = new TxAttributeFilter(); viewSorter = new TxAttributeViewerSorter(); - + treeViewer = new TreeViewer(parent); treeViewer.setContentProvider(new TransactionTreeContentProvider()); treeViewer.setLabelProvider(new TxPropertiesLabelProvider()); @@ -148,7 +148,7 @@ public class TransactionDetails { public void treeExpanded(TreeExpansionEvent event) { treeViewer.getSelection(); } - + }); // Set up the table @@ -188,14 +188,14 @@ public class TransactionDetails { } }); // Pack the columns -// for (int i = 0, n = table.getColumnCount(); i < n; i++) { -// table.getColumn(i).pack(); -// } + // for (int i = 0, n = table.getColumnCount(); i < n; i++) { + // table.getColumn(i).pack(); + // } // Turn on the header and the lines tree.setHeaderVisible(true); tree.setLinesVisible(true); - + treeViewer.addDoubleClickListener(new IDoubleClickListener(){ @Override @@ -213,7 +213,7 @@ public class TransactionDetails { } } } - + }); parent.addControlListener(new ControlAdapter() { public void controlResized(ControlEvent e) { @@ -279,7 +279,7 @@ public class TransactionDetails { } else { treeViewer.setInput(null); } - + } private void setExpandedState(TreeItem[] treeItems, ArrayList states) { @@ -294,7 +294,7 @@ public class TransactionDetails { ret.add(treeItem.getItemCount()>0?treeItem.getExpanded():true); return ret; } - + private int getTopItemHier(ArrayList names){ int indexInParent=-1; TreeItem obj = treeViewer.getTree().getTopItem(); @@ -314,7 +314,7 @@ public class TransactionDetails { } return indexInParent; } - + private void setTopItemFromHier(ArrayList names, int indexInParent) { if(indexInParent<0 || names.size()==0 ) return; TreeItem selItem=null; @@ -375,16 +375,16 @@ public class TransactionDetails { */ String txToString(ITx tx){ StringBuilder sb = new StringBuilder(); - sb.append("tx#").append(tx.getId()).append("[").append(timeToString(tx.getBeginTime())). //$NON-NLS-1$ //$NON-NLS-2$ - append(" - ").append(timeToString(tx.getEndTime())).append("]"); //$NON-NLS-1$ //$NON-NLS-2$ + sb.append("tx#").append(tx.getId()).append("[").append(timeToString(tx.getBeginTime())); //$NON-NLS-1$ //$NON-NLS-2$ + sb.append(" - ").append(timeToString(tx.getEndTime())).append("]"); //$NON-NLS-1$ //$NON-NLS-2$ return sb.toString(); } - + /** * The Class TxAttributeViewerSorter. */ class TxAttributeViewerSorter extends ViewerComparator { - + /** The Constant ASCENDING. */ private static final int ASCENDING = 0; @@ -469,7 +469,7 @@ public class TransactionDetails { */ @Override public boolean select(Viewer viewer, Object parentElement, Object element) { - + if (searchString == null || searchString.length() == 0) { return true; } @@ -482,7 +482,7 @@ public class TransactionDetails { if(element instanceof Object[]) { return (((Object[])element)[0]).toString().toLowerCase().matches(searchString.toLowerCase()); } - + return false; } } @@ -491,19 +491,19 @@ public class TransactionDetails { * The Enum Type. */ enum Type {/** The props. */ -PROPS, /** The attrs. */ - ATTRS, /** The in rel. */ - IN_REL, /** The out rel. */ - OUT_REL} + PROPS, /** The attrs. */ + ATTRS, /** The in rel. */ + IN_REL, /** The out rel. */ + OUT_REL} /** * The Class TreeNode. */ class TreeNode{ - + /** The type. */ public Type type; - + /** The element. */ public ITx element; @@ -624,16 +624,16 @@ PROPS, /** The attrs. */ * The Class AttributeLabelProvider. */ class AttributeLabelProvider extends LabelProvider implements IStyledLabelProvider { - + /** The field. */ final int field; - + /** The Constant NAME. */ public static final int NAME=0; - + /** The Constant TYPE. */ public static final int TYPE=1; - + /** The Constant VALUE. */ public static final int VALUE=2; @@ -678,13 +678,18 @@ PROPS, /** The attrs. */ String value = attribute.getValue().toString(); if((DataType.UNSIGNED == attribute.getDataType() || DataType.INTEGER==attribute.getDataType()) && !"0".equals(value)) { try { - value = attribute.getValue().toString() + " [0x"+Long.toHexString(Long.parseLong(attribute.getValue().toString()))+"]"; + value += " [0x"+Long.toHexString(Long.parseLong(attribute.getValue().toString()))+"]"; } catch(NumberFormatException e) { } } return new StyledString(value); }else if(element instanceof Object[]){ Object[] elements = (Object[]) element; - return new StyledString(elements[field].toString()); + Object o = elements[field]; + if(o instanceof ITx) { + ITx tx = (ITx)o; + return new StyledString(txToString(tx)+" ("+tx.getStream().getFullName()+")"); + } else + return new StyledString(o.toString()); } else if(element instanceof ITx){ return new StyledString(txToString((ITx) element)); }else diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/WaveformViewer.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/WaveformViewer.java index 5495e59..3993103 100644 --- a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/WaveformViewer.java +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/WaveformViewer.java @@ -65,14 +65,26 @@ import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.FocusListener; +import org.eclipse.swt.events.PaintEvent; +import org.eclipse.swt.events.PaintListener; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.TableItem; +import org.eclipse.swt.widgets.Widget; +import com.minres.scviewer.database.DataType; import com.minres.scviewer.database.ITx; +import com.minres.scviewer.database.ITxAttribute; import com.minres.scviewer.database.ITxEvent; import com.minres.scviewer.database.ITxRelation; import com.minres.scviewer.database.IWaveform; @@ -80,6 +92,8 @@ import com.minres.scviewer.database.IWaveformDb; import com.minres.scviewer.database.IWaveformDbFactory; import com.minres.scviewer.database.RelationType; import com.minres.scviewer.database.swt.Constants; +import com.minres.scviewer.database.swt.ToolTipContentProvider; +import com.minres.scviewer.database.swt.ToolTipHelpTextProvider; import com.minres.scviewer.database.swt.WaveformViewerFactory; import com.minres.scviewer.database.ui.GotoDirection; import com.minres.scviewer.database.ui.ICursor; @@ -366,6 +380,84 @@ public class WaveformViewer implements IFileChangeListener, IPreferenceChangeLis prefs.addPreferenceChangeListener(this); waveformPane.addDisposeListener(this); + + waveformPane.getWaveformControl().setData(Constants.HELP_PROVIDER_TAG, new ToolTipHelpTextProvider() { + @Override + public String getHelpText(Widget widget) { + return "Waveform pane: press F2 to set the focus to the tooltip"; + } + }); + waveformPane.getWaveformControl().setData(Constants.CONTENT_PROVIDER_TAG, new ToolTipContentProvider() { + @Override + public boolean createContent(Composite parent, Point pt) { + if(!prefs.getBoolean(PreferenceConstants.SHOW_HOVER, true)) return false; + List res = waveformPane.getElementsAt(pt); + if(res.size()>0) + if(res.get(0) instanceof ITx) { + ITx tx = (ITx)res.get(0); + final Display display = parent.getDisplay(); + final Font font = new Font(Display.getCurrent(), "Terminal", 10, SWT.NORMAL); + + final Label label = new Label(parent, SWT.NONE); + label.setForeground(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND)); + label.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND)); + label.setText(tx.toString()); + label.setFont(font); + + final Table table = new Table(parent, SWT.NONE); + table.setHeaderVisible(true); + table.setLinesVisible(true); + table.setFont(font); + table.setForeground(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND)); + table.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND)); + table.setRedraw(false); + + final TableColumn nameCol = new TableColumn(table, SWT.LEFT); + nameCol.setText("Attribute"); + final TableColumn valueCol = new TableColumn(table, SWT.LEFT); + valueCol.setText("Value"); + + for (ITxAttribute iTxAttribute : tx.getAttributes()) { + String value = iTxAttribute.getValue().toString(); + if((DataType.UNSIGNED == iTxAttribute.getDataType() || DataType.INTEGER==iTxAttribute.getDataType()) && !"0".equals(value)) { + try { + value += " [0x"+Long.toHexString(Long.parseLong(iTxAttribute.getValue().toString()))+"]"; + } catch(NumberFormatException e) { } + } + TableItem item = new TableItem(table, SWT.NONE); + item.setText(0, iTxAttribute.getName()); + item.setText(1, value); + } + nameCol.pack(); + valueCol.pack(); + table.setRedraw(true); + + parent.addPaintListener(new PaintListener() { + @Override + public void paintControl(PaintEvent e) { + Rectangle area = parent.getClientArea(); + valueCol.setWidth(area.width - nameCol.getWidth()); + } + }); + parent.addFocusListener(FocusListener.focusGainedAdapter(e -> { + table.setFocus(); + })); + return true; + } else if(res.get(0) instanceof TrackEntry) { + TrackEntry te = (TrackEntry)res.get(0); + final Display display = parent.getDisplay(); + final Font font = new Font(Display.getCurrent(), "Terminal", 10, SWT.NORMAL); + + final Label label = new Label(parent, SWT.NONE); + label.setForeground(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND)); + label.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND)); + label.setText(te.waveform.getFullName()); + label.setFont(font); + return true; + } + return false; + } + }); } /* (non-Javadoc) diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/preferences/DefaultValuesInitializer.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/preferences/DefaultValuesInitializer.java index 17afd9b..a2fdd5c 100644 --- a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/preferences/DefaultValuesInitializer.java +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/preferences/DefaultValuesInitializer.java @@ -67,6 +67,7 @@ public class DefaultValuesInitializer extends AbstractPreferenceInitializer { IPreferenceStore store = new ScopedPreferenceStore(InstanceScope.INSTANCE, PreferenceConstants.PREFERENCES_SCOPE); store.setDefault(PreferenceConstants.DATABASE_RELOAD, true); + store.setDefault(PreferenceConstants.SHOW_HOVER, true); for (WaveformColors c : WaveformColors.values()) { store.setDefault(c.name()+"_COLOR", StringConverter.asString(colors[c.ordinal()].getRGB())); //$NON-NLS-1$ } diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/preferences/PreferenceConstants.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/preferences/PreferenceConstants.java index b9ed912..9a6d057 100644 --- a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/preferences/PreferenceConstants.java +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/preferences/PreferenceConstants.java @@ -21,6 +21,9 @@ public class PreferenceConstants { /** The Constant DATABASE_RELOAD. */ public static final String DATABASE_RELOAD="databaseReload"; //$NON-NLS-1$ + /** The Constant DATABASE_RELOAD. */ + public static final String SHOW_HOVER="showWaveformHover"; //$NON-NLS-1$ + /** The Constant LINE_COLOR. */ public static final String LINE_COLOR="LINE_COLOR"; //$NON-NLS-1$ diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/preferences/SCViewerPreferencesPage.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/preferences/SCViewerPreferencesPage.java index ef8f9ab..25005e9 100644 --- a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/preferences/SCViewerPreferencesPage.java +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/preferences/SCViewerPreferencesPage.java @@ -36,6 +36,8 @@ public class SCViewerPreferencesPage extends FieldEditorPreferencePage { addField(new BooleanFieldEditor(PreferenceConstants.DATABASE_RELOAD, Messages.SCViewerPreferencesPage_0, getFieldEditorParent())); + addField(new BooleanFieldEditor(PreferenceConstants.SHOW_HOVER, Messages.SCViewerPreferencesPage_1, + getFieldEditorParent())); } diff --git a/com.minres.scviewer.e4.product/pom.xml b/com.minres.scviewer.e4.product/pom.xml index effbfb5..b23c351 100644 --- a/com.minres.scviewer.e4.product/pom.xml +++ b/com.minres.scviewer.e4.product/pom.xml @@ -10,7 +10,7 @@ ../com.minres.scviewer.parent com.minres.scviewer.e4.product - 2.3.0-SNAPSHOT + 2.4.0-SNAPSHOT eclipse-repository com.minres.scviewer diff --git a/com.minres.scviewer.e4.product/scviewer.product b/com.minres.scviewer.e4.product/scviewer.product index 6a40894..90c16d6 100644 --- a/com.minres.scviewer.e4.product/scviewer.product +++ b/com.minres.scviewer.e4.product/scviewer.product @@ -1,7 +1,7 @@ - + @@ -47,7 +47,6 @@ - diff --git a/com.minres.scviewer.parent/pom.xml b/com.minres.scviewer.parent/pom.xml index f7296c1..e8a9fef 100644 --- a/com.minres.scviewer.parent/pom.xml +++ b/com.minres.scviewer.parent/pom.xml @@ -12,7 +12,7 @@ ../com.minres.scviewer.database.sqlite ../com.minres.scviewer.database.text ../com.minres.scviewer.database.vcd - ../com.minres.scviewer.database.leveldb + ../com.minres.scviewer.database.test ../com.minres.scviewer.database.ui ../com.minres.scviewer.database.ui.swt