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 815ae84..430e5b7 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 @@ -42,6 +42,7 @@ import com.minres.scviewer.database.IWaveform; import com.minres.scviewer.database.IWaveformEvent; import com.minres.scviewer.database.RelationType; import com.minres.scviewer.database.ui.IWaveformViewer; +import com.minres.scviewer.database.ui.TrackEntry; import com.minres.scviewer.database.ui.WaveformColors; public class WaveformCanvas extends Canvas { @@ -181,6 +182,9 @@ public class WaveformCanvas extends Canvas { return origin; } + public int getWidth() { + return getClientArea().width; + } public void setOrigin(Point origin) { setOrigin(origin.x, origin.y); } @@ -292,9 +296,13 @@ public class WaveformCanvas extends Canvas { } public void addWaveformPainter(IWaveformPainter painter) { + addWaveformPainter(painter, true); + } + + void addWaveformPainter(IWaveformPainter painter, boolean update) { trackAreaPainter.addTrackPainter(painter); wave2painterMap.put(painter.getTrackEntry().waveform, painter); - syncScrollBars(); + if(update) syncScrollBars(); } public List getCursorPainters() { @@ -311,7 +319,7 @@ public class WaveformCanvas extends Canvas { super.dispose(); } - /* Initalize the scrollbar and register listeners. */ + /* Initialize the scrollbar and register listeners. */ private void initScrollBars() { ScrollBar horizontal = getHorizontalBar(); horizontal.setEnabled(false); @@ -469,6 +477,27 @@ public class WaveformCanvas extends Canvas { } } + public void reveal(IWaveform waveform) { + for (IWaveformPainter painter : wave2painterMap.values()) { + TrackEntry te = painter.getTrackEntry(); + if(te.waveform == waveform) { + Point size = getSize(); + //size.x -= getVerticalBar().getSize().x + 2; + size.y -=+rulerHeight; + ScrollBar sb = getHorizontalBar(); + if((sb.getStyle()&SWT.SCROLLBAR_OVERLAY)!=0 && sb.isVisible()) // TODO: check on other platform than MacOSX + size.y-= getHorizontalBar().getSize().y; + int top = te.vOffset; + int bottom = top + trackHeight; + if (top < -origin.y) { + setOrigin(origin.x, -(top-trackHeight)); + } else if (bottom > (size.y - origin.y)) { + setOrigin(origin.x, size.y - bottom); + } + } + } + } + public void reveal(long time) { int scaledTime = (int) (time / scaleFactor); Point size = getSize(); @@ -513,4 +542,11 @@ public class WaveformCanvas extends Canvas { } } + long getMaxVisibleTime() { + return (getClientArea().width+origin.x)*scaleFactor; + } + + long getOriginTime() { + return origin.x * scaleFactor; + } } 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 139e26f..d39f065 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 @@ -66,6 +66,7 @@ import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.ScrollBar; +import org.eclipse.swt.widgets.Widget; import org.eclipse.wb.swt.SWTResourceManager; import com.google.common.collect.Lists; @@ -109,6 +110,8 @@ public class WaveformViewer implements IWaveformViewer { final WaveformCanvas waveformCanvas; + private boolean revealSelected=false; + private Composite top; protected ObservableList streams; @@ -142,12 +145,10 @@ public class WaveformViewer implements IWaveformViewer { @Override public void mouseDown(MouseEvent e) { start=new Point(e.x, e.y); + if((e.stateMask&SWT.MODIFIER_MASK)!=0) return; //don't react on modifier if (e.button == 1) { initialSelected = waveformCanvas.getClicked(start); } else if (e.button == 3) { - List hitted = waveformCanvas.getClicked(start); - if(hitted!=null && hitted.size()>0) - setSelection(new StructuredSelection(hitted)); Menu topMenu= top.getMenu(); if(topMenu!=null) topMenu.setVisible(true); } @@ -155,29 +156,18 @@ public class WaveformViewer implements IWaveformViewer { @Override public void mouseUp(MouseEvent e) { - if (e.button == 1) { + if((e.stateMask&SWT.MODIFIER_MASK&~SWT.SHIFT)!=0) return; //don't react on modifier + if (e.button == 1 && ((e.stateMask&SWT.SHIFT)==0)) { if(Math.abs(e.x-start.x)<3 && Math.abs(e.y-start.y)<3){ - // first set time + // first set cursor time setCursorTime(snapOffsetToEvent(e)); // then set selection and reveal setSelection(new StructuredSelection(initialSelected)); - e.widget.getDisplay().asyncExec(new Runnable() { - @Override - public void run() { - waveformCanvas.redraw(); - updateValueList(); - } - }); + asyncUpdate(e.widget); } - }else if (e.button == 2) { + }else if (e.button == 2 ||(e.button==1 && (e.stateMask&SWT.SHIFT)!=0)) { setMarkerTime(snapOffsetToEvent(e), selectedMarker); - e.widget.getDisplay().asyncExec(new Runnable() { - @Override - public void run() { - waveformCanvas.redraw(); - updateValueList(); - } - }); + asyncUpdate(e.widget); } } @@ -378,6 +368,18 @@ public class WaveformViewer implements IWaveformViewer { @Override public void propertyChange(PropertyChangeEvent pce) { if ("size".equals(pce.getPropertyName()) || "content".equals(pce.getPropertyName())) { + if(revealSelected) { + waveformCanvas.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + update(); + waveformCanvas.reveal(currentWaveformSelection.waveform); + valueList.redraw(); + nameList.redraw(); + } + }); + revealSelected=false; + } else waveformCanvas.getDisplay().asyncExec(new Runnable() { @Override public void run() { @@ -410,13 +412,14 @@ public class WaveformViewer implements IWaveformViewer { streamEntry.currentValue="---"; painter = new SignalPainter(waveformCanvas, even, streamEntry); } - waveformCanvas.addWaveformPainter(painter); + waveformCanvas.addWaveformPainter(painter, false); trackVerticalOffset.put(trackVerticalHeight, streamEntry); tl.setText(streamEntry.waveform.getFullName()); nameMaxWidth = Math.max(nameMaxWidth, tl.getBounds().width); trackVerticalHeight += streamEntry.height; even = !even; } + waveformCanvas.syncScrollBars(); nameList.setSize(nameMaxWidth + 15, trackVerticalHeight); nameListScrolled.setMinSize(nameMaxWidth + 15, trackVerticalHeight); valueList.setSize(calculateValueWidth(), trackVerticalHeight); @@ -566,9 +569,10 @@ public class WaveformViewer implements IWaveformViewer { */ @Override public ISelection getSelection() { - if (currentTxSelection != null) - return new StructuredSelection(currentTxSelection); - else if (currentWaveformSelection != null) { + if (currentTxSelection != null) { + Object[] elem = {currentTxSelection, currentWaveformSelection}; + return new StructuredSelection(elem); + } else if (currentWaveformSelection != null) { Object[] elem = {currentWaveformSelection.waveform, currentWaveformSelection}; return new StructuredSelection(elem); } else @@ -611,6 +615,7 @@ public class WaveformViewer implements IWaveformViewer { currentWaveformSelection = (TrackEntry) sel; if(currentTxSelection!=null && currentTxSelection.getStream()!=currentWaveformSelection) currentTxSelection=null; + selectionChanged = true; } } @@ -623,6 +628,7 @@ public class WaveformViewer implements IWaveformViewer { } if(currentWaveformSelection!=null) currentWaveformSelection.selected=true; if (selectionChanged) { + waveformCanvas.reveal(currentWaveformSelection.waveform); waveformCanvas.setSelected(currentTxSelection); valueList.redraw(); nameList.redraw(); @@ -646,7 +652,16 @@ public class WaveformViewer implements IWaveformViewer { */ @Override public void moveSelection(GotoDirection direction) { - moveSelection(direction, NEXT_PREV_IN_STREAM) ; + if(direction==GotoDirection.NEXT || direction==GotoDirection.PREV) + moveSelection(direction, NEXT_PREV_IN_STREAM) ; + else { + int idx = streams.indexOf(currentWaveformSelection); + if(direction==GotoDirection.UP && idx>0) { + setSelection(new StructuredSelection(streams.get(idx-1))); + } else if(direction==GotoDirection.DOWN && idx<(streams.size()-1)) { + setSelection(new StructuredSelection(streams.get(idx+1))); + } + } } /* (non-Javadoc) @@ -776,17 +791,21 @@ public class WaveformViewer implements IWaveformViewer { @Override public void moveSelectedTrack(int i) { if(currentWaveformSelection!=null){ - ITx selectedTx=currentTxSelection; - TrackEntry selectedWaveform=currentWaveformSelection; int idx = streams.indexOf(currentWaveformSelection); int newIdx=idx+i; if(newIdx>=0 && newIdx100) percent=100; + int diff = (waveformCanvas.getWidth()*percent)/100; +// ScrollBar sb = waveformCanvas.getHorizontalBar(); +// int x = sb.getSelection(); +// System.out.println("Setting sb to "+ (x+diff)); +// if((x+diff)>0) +// sb.setSelection(x+diff); +// else +// sb.setSelection(0); + Point o = waveformCanvas.getOrigin(); + waveformCanvas.setOrigin(o.x-diff, o.y); + waveformCanvas.redraw(); + } + + public void asyncUpdate(Widget widget) { + widget.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + waveformCanvas.redraw(); + updateValueList(); + } + }); + } } 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 7f4bd6a..5a4f967 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 @@ -102,4 +102,6 @@ public interface IWaveformViewer extends PropertyChangeListener, ISelectionProvi public long getBaselineTime(); public void setBaselineTime(Long scale); + + public void scrollHorizontal(int percent); } \ No newline at end of file diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/E4LifeCycle.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/E4LifeCycle.java index 07d2a46..707989f 100644 --- a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/E4LifeCycle.java +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/E4LifeCycle.java @@ -33,6 +33,10 @@ import org.eclipse.equinox.app.IApplicationContext; import org.osgi.service.event.Event; import org.osgi.service.event.EventHandler; +import com.minres.scviewer.e4.application.options.Options; +import com.minres.scviewer.e4.application.options.Options.Multiplicity; +import com.minres.scviewer.e4.application.options.Options.Separator; + /** * This implementation contains e4 LifeCycle annotated methods.
* There is a corresponding entry in plugin.xml (under the @@ -59,7 +63,14 @@ public class E4LifeCycle { */ @PostContextCreate void postContextCreate(IApplicationContext appContext, final IEventBroker eventBroker) { - final String[] args = (String[])appContext.getArguments().get(IApplicationContext.APPLICATION_ARGS); + final String[] args = (String[])appContext.getArguments().get(IApplicationContext.APPLICATION_ARGS); + Options opt = new Options(args, 1); + opt.getSet().addOption("c", Separator.BLANK, Multiplicity.ONCE); + if (!opt.check(Options.DEFAULT_SET, true, true)) { + System.exit(1); + } + final String confFile =opt.getSet().isSet("c")?opt.getSet().getOption("c").getResultValue(0):""; + // react on the first view being created, at that time the UI is available eventBroker.subscribe(UIEvents.UILifeCycle.ACTIVATE, new EventHandler() { @Override @@ -68,9 +79,10 @@ public class E4LifeCycle { if(part!=null){ IEclipseContext ctx = part.getContext(); OpenViewHandler openViewHandler= new OpenViewHandler(); + if(confFile.length()>0) openViewHandler.setConfigFile(confFile); ContextInjectionFactory.inject(openViewHandler, ctx); eventBroker.unsubscribe(this); - for(String name:args){ + for(String name:opt.getSet().getData()){ if(new File(name).exists()) openViewHandler.openViewForFile(name); } } @@ -136,6 +148,7 @@ public class E4LifeCycle { /** The part service. */ @Inject EPartService partService; + String confFile=""; /** * Open view for file. * @@ -150,7 +163,13 @@ public class E4LifeCycle { partService.showPart(part, PartState.ACTIVATE); IEclipseContext ctx=part.getContext(); ctx.modify("input", file); //$NON-NLS-1$ - ctx.declareModifiable("input"); //$NON-NLS-1$ + //ctx.declareModifiable("input"); //$NON-NLS-1$ + ctx.modify("config", confFile); //$NON-NLS-1$ + //ctx.declareModifiable("config"); //$NON-NLS-1$ + } + + public void setConfigFile(String confFile) { + this.confFile=confFile; } } } diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/options/OptionData.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/options/OptionData.java new file mode 100644 index 0000000..e1218c8 --- /dev/null +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/options/OptionData.java @@ -0,0 +1,275 @@ +package com.minres.scviewer.e4.application.options; + +/** + * This class holds all the data for an option. This includes the prefix, the key, the separator + * (for value options), the multiplicity, and all the other settings describing the option. The class + * is designed to be only a data container from a user perspective, i. e. the user has read-access to + * any data determined by the {@link Options#check()}, but not access to any of the other methods + * which are used internally for the operation of the actual check. + */ + +public class OptionData { + + private final static String CLASS = "OptionData"; + + private Options.Prefix prefix = null; + private String key = null; + private boolean detail = false; + private Options.Separator separator = null; + private boolean value = false; + private Options.Multiplicity multiplicity = null; + private java.util.regex.Pattern pattern = null; + private int counter = 0; + private java.util.ArrayList values = null; + private java.util.ArrayList details = null; + +/** + * The constructor + */ + + OptionData(Options.Prefix prefix, + String key, + boolean detail, + Options.Separator separator, + boolean value, + Options.Multiplicity multiplicity) { + + if (prefix == null) throw new IllegalArgumentException(CLASS + ": prefix may not be null"); + if (key == null) throw new IllegalArgumentException(CLASS + ": key may not be null"); + if (separator == null) throw new IllegalArgumentException(CLASS + ": separator may not be null"); + if (multiplicity == null) throw new IllegalArgumentException(CLASS + ": multiplicity may not be null"); + +//.... The data describing the option + + this.prefix = prefix; + this.key = key; + this.detail = detail; + this.separator = separator; + this.value = value; + this.multiplicity = multiplicity; + +//.... Create the pattern to match this option + + if (value) { + if (separator == Options.Separator.BLANK) { + if (detail) { + pattern = java.util.regex.Pattern.compile(prefix.getName() + key + "((\\w|\\.)+)$"); + } else { + pattern = java.util.regex.Pattern.compile(prefix.getName() + key + "$"); + } + } else { + if (detail) { + pattern = java.util.regex.Pattern.compile(prefix.getName() + key + "((\\w|\\.)+)" + separator.getName() + "(.+)$"); + } else { + pattern = java.util.regex.Pattern.compile(prefix.getName() + key + separator.getName() + "(.+)$"); + } + } + } else { + pattern = java.util.regex.Pattern.compile(prefix.getName() + key + "$"); + } + +//.... Structures to hold result data + + if (value) { + values = new java.util.ArrayList(); + if (detail) + details = new java.util.ArrayList(); + } + + } + +/** + * Getter method for prefix property + *

+ * @return The value for the prefix property + */ + + Options.Prefix getPrefix() { + return prefix; + } + +/** + * Getter method for key property + *

+ * @return The value for the key property + */ + + String getKey() { + return key; + } + +/** + * Getter method for detail property + *

+ * @return The value for the detail property + */ + + boolean useDetail() { + return detail; + } + +/** + * Getter method for separator property + *

+ * @return The value for the separator property + */ + + Options.Separator getSeparator() { + return separator; + } + +/** + * Getter method for value property + *

+ * @return The value for the value property + */ + + boolean useValue() { + return value; + } + +/** + * Getter method for multiplicity property + *

+ * @return The value for the multiplicity property + */ + + Options.Multiplicity getMultiplicity() { + return multiplicity; + } + +/** + * Getter method for pattern property + *

+ * @return The value for the pattern property + */ + + java.util.regex.Pattern getPattern() { + return pattern; + } + +/** + * Get the number of results found for this option, which is number of times the key matched + *

+ * @return The number of results + */ + + public int getResultCount() { + if (value) { + return values.size(); + } else { + return counter; + } + } + +/** + * Get the value with the given index. The index can range between 0 and {@link #getResultCount()} - 1. + * However, only for value options, a non-null value will be returned. Non-value options always + * return null. + *

+ * @param index The index for the desired value + *

+ * @return The option value with the given index + *

+ * @throws IllegalArgumentException If the value for index is out of bounds + */ + + public String getResultValue(int index) { + if (!value) return null; + if (index < 0 || index >= getResultCount()) throw new IllegalArgumentException(CLASS + ": illegal value for index"); + return values.get(index); + } + +/** + * Get the detail with the given index. The index can range between 0 and {@link #getResultCount()} - 1. + * However, only for value options which take details, a non-null detail will be returned. Non-value options + * and value options which do not take details always return null. + *

+ * @param index The index for the desired value + *

+ * @return The option detail with the given index + *

+ * @throws IllegalArgumentException If the value for index is out of bounds + */ + + public String getResultDetail(int index) { + if (!detail) return null; + if (index < 0 || index >= getResultCount()) throw new IllegalArgumentException(CLASS + ": illegal value for index"); + return details.get(index); + } + +/** + * Store the data for a match found + */ + + void addResult(String valueData, String detailData) { + if (value) { + if (valueData == null) throw new IllegalArgumentException(CLASS + ": valueData may not be null"); + values.add(valueData); + if (detail) { + if (detailData == null) throw new IllegalArgumentException(CLASS + ": detailData may not be null"); + details.add(detailData); + } + } + counter++; + } + +/** + * This is the overloaded {@link Object#toString()} method, and it is provided mainly for debugging + * purposes. + *

+ * @return A string representing the instance + */ + + public String toString() { + + StringBuffer sb = new StringBuffer(); + + sb.append("Prefix : "); + sb.append(prefix); + sb.append('\n'); + sb.append("Key : "); + sb.append(key); + sb.append('\n'); + sb.append("Detail : "); + sb.append(detail); + sb.append('\n'); + sb.append("Separator : "); + sb.append(separator); + sb.append('\n'); + sb.append("Value : "); + sb.append(value); + sb.append('\n'); + sb.append("Multiplicity: "); + sb.append(multiplicity); + sb.append('\n'); + sb.append("Pattern : "); + sb.append(pattern); + sb.append('\n'); + + sb.append("Results : "); + sb.append(counter); + sb.append('\n'); + if (value) { + if (detail) { + for (int i = 0; i < values.size(); i++) { + sb.append(details.get(i)); + sb.append(" / "); + sb.append(values.get(i)); + sb.append('\n'); + } + } else { + for (int i = 0; i < values.size(); i++) { + sb.append(values.get(i)); + sb.append('\n'); + } + } + } + + return sb.toString(); + + } + +} + + diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/options/OptionSet.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/options/OptionSet.java new file mode 100644 index 0000000..c320f61 --- /dev/null +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/options/OptionSet.java @@ -0,0 +1,276 @@ +package com.minres.scviewer.e4.application.options; + +/** + * This class holds the information for a set of options. A set can hold any number of + * OptionData instances which are checked together to determine success or failure. + *

+ * The approach to use this class looks like this: + *

+ *

    + *
  1. The user uses any of the Options.addSet() (e. g. {@link Options#addSet(String)}) to create + * any number of sets required (or just relies on the default set, if only one set is required) + *
  2. The user adds all required option definitions to each set + *
  3. Using any of the Options.check() methods, each set can be checked whether the options + * that were specified on the command line satisfy its requirements + *
  4. If the check was successful for a given set, several data items are available from this class: + *
      + *
    • All options defined for the set (through with e. g. values, details, and multiplicity are available) + *
    • All data items found (these are the items on the command line which do not start with the prefix, + * i. e. non-option arguments) + *
    • All unmatched arguments on the command line (these are the items on the command line which start + * with the prefix, but do not match to one of the options). + * Programs can elect to ignore these, or react with an error + *
    + *
+ */ + +public class OptionSet { + + private final static String CLASS = "OptionSet"; + + private java.util.ArrayList options = new java.util.ArrayList(); + private java.util.HashMap keys = new java.util.HashMap(); + private java.util.ArrayList unmatched = new java.util.ArrayList(); + private java.util.ArrayList data = new java.util.ArrayList(); + private String setName = null; + private int minData = 0; + private int maxData = 0; + private Options.Prefix prefix = null; + private Options.Multiplicity defaultMultiplicity = null; + +/** + * Constructor + */ + + OptionSet(Options.Prefix prefix, Options.Multiplicity defaultMultiplicity, String setName, int minData, int maxData) { + if (setName == null) throw new IllegalArgumentException(CLASS + ": setName may not be null"); + if (minData < 0) throw new IllegalArgumentException(CLASS + ": minData must be >= 0"); + if (maxData < minData) throw new IllegalArgumentException(CLASS + ": maxData must be >= minData"); + this.prefix = prefix; + this.defaultMultiplicity = defaultMultiplicity; + this.setName = setName; + this.minData = minData; + this.maxData = maxData; + } + +/** + * Get a list of all the options defined for this set + *

+ * @return A list of {@link OptionData} instances defined for this set + */ + + public java.util.ArrayList getOptionData() { + return options; + } + +/** + * Get the data for a specific option, identified by its key name (which is unique) + *

+ * @param key The key for the option + *

+ * @return The {@link OptionData} instance + *

+ * @throws IllegalArgumentException If the key is null or unknown in this set + */ + + public OptionData getOption(String key) { + if (key == null) throw new IllegalArgumentException(CLASS + ": key may not be null"); + if (!keys.containsKey(key)) throw new IllegalArgumentException(CLASS + ": unknown key: " + key); + return keys.get(key); + } + +/** + * Check whether a specific option is set, i. e. whether it was specified at least once on the command line. + *

+ * @param key The key for the option + *

+ * @return true or false, depending on the outcome of the check + *

+ * @throws IllegalArgumentException If the key is null or unknown in this set + */ + + public boolean isSet(String key) { + if (key == null) throw new IllegalArgumentException(CLASS + ": key may not be null"); + if (!keys.containsKey(key)) throw new IllegalArgumentException(CLASS + ": unknown key: " + key); + return keys.get(key).getResultCount() > 0 ? true : false; + } + +/** + * Getter method for setName property + *

+ * @return The value for the setName property + */ + + public String getSetName() { + return setName; + } + +/** + * Getter method for minData property + *

+ * @return The value for the minData property + */ + + public int getMinData() { + return minData; + } + +/** + * Getter method for maxData property + *

+ * @return The value for the maxData property + */ + + public int getMaxData() { + return maxData; + } + +/** + * Return the data items found (these are the items on the command line which do not start with the prefix, i. e. non-option arguments) + *

+ * @return A list of strings with all data items found + */ + + public java.util.ArrayList getData() { + return data; + } + +/** + * Return all unmatched items found (these are the items on the command line which start with the prefix, but do not + * match to one of the options) + *

+ * @return A list of strings with all unmatched items found + */ + + public java.util.ArrayList getUnmatched() { + return unmatched; + } + +/** + * Add a non-value option with the given key, and the default prefix and multiplicity + *

+ * @param key The key for the option + *

+ * @return The set instance itself (to support invocation chaining for addOption() methods) + *

+ * @throws IllegalArgumentException If the key is null or a key with this name has already been defined + */ + + public OptionSet addOption(String key) { + return addOption(key, defaultMultiplicity); + } + +/** + * Add a non-value option with the given key and multiplicity, and the default prefix + *

+ * @param key The key for the option + * @param multiplicity The multiplicity for the option + *

+ * @return The set instance itself (to support invocation chaining for addOption() methods) + *

+ * @throws IllegalArgumentException If the key is null or a key with this name has already been defined + * or if multiplicity is null + */ + + public OptionSet addOption(String key, Options.Multiplicity multiplicity) { + return addOption(key, false, Options.Separator.NONE, false, multiplicity); + } + +/** + * Add a value option with the given key and separator, no details, and the default prefix and multiplicity + *

+ * @param key The key for the option + * @param separator The separator for the option + *

+ * @return The set instance itself (to support invocation chaining for addOption() methods) + *

+ * @throws IllegalArgumentException If the key is null or a key with this name has already been defined + * or if separator is null + */ + + public OptionSet addOption(String key, Options.Separator separator) { + return addOption(key, false, separator, true, defaultMultiplicity); + } + +/** + * Add a value option with the given key, separator, and multiplicity, no details, and the default prefix + *

+ * @param key The key for the option + * @param separator The separator for the option + * @param multiplicity The multiplicity for the option + *

+ * @return The set instance itself (to support invocation chaining for addOption() methods) + *

+ * @throws IllegalArgumentException If the key is null or a key with this name has already been defined + * or if separator or multiplicity are null + */ + + public OptionSet addOption(String key, Options.Separator separator, Options.Multiplicity multiplicity) { + return addOption(key, false, separator, true, multiplicity); + } + +/** + * + * Add a value option with the given key and separator, possibly details, and the default prefix and multiplicity + *

+ * @param key The key for the option + * @param details A boolean indicating whether details are expected for the option + * @param separator The separator for the option + *

+ * @return The set instance itself (to support invocation chaining for addOption() methods) + *

+ * @throws IllegalArgumentException If the key is null or a key with this name has already been defined + * or if separator is null + */ + + public OptionSet addOption(String key, boolean details, Options.Separator separator) { + return addOption(key, details, separator, true, defaultMultiplicity); + } + +/** + * Add a value option with the given key, separator, and multiplicity, possibly details, and the default prefix + *

+ * @param key The key for the option + * @param details A boolean indicating whether details are expected for the option + * @param separator The separator for the option + * @param multiplicity The multiplicity for the option + *

+ * @return The set instance itself (to support invocation chaining for addOption() methods) + *

+ * @throws IllegalArgumentException If the key is null or a key with this name has already been defined + * or if separator or multiplicity are null + */ + + public OptionSet addOption(String key, boolean details, Options.Separator separator, Options.Multiplicity multiplicity) { + return addOption(key, details, separator, true, multiplicity); + } + +/** + * The master method to add an option. Since there are combinations which are not + * acceptable (like a NONE separator and a true value), this method is not public. + * Internally, we only supply acceptable combinations. + */ + + OptionSet addOption(String key, + boolean details, + Options.Separator separator, + boolean value, + Options.Multiplicity multiplicity) { + + if (key == null) throw new IllegalArgumentException(CLASS + ": key may not be null"); + if (multiplicity == null) throw new IllegalArgumentException(CLASS + ": multiplicity may not be null"); + if (separator == null) throw new IllegalArgumentException(CLASS + ": separator may not be null"); + if (keys.containsKey(key)) throw new IllegalArgumentException(CLASS + ": the key " + + key + " has already been defined for this OptionSet"); + + OptionData od = new OptionData(prefix, key, details, separator, value, multiplicity); + options.add(od); + keys.put(key, od); + + return this; + + } + +} + + diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/options/Options.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/options/Options.java new file mode 100644 index 0000000..b7e0282 --- /dev/null +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/options/Options.java @@ -0,0 +1,768 @@ +package com.minres.scviewer.e4.application.options; + +/** + * The central class for option processing. Sets are identified by their name, but there is also + * an anonymous default set, which is very convenient if an application requieres only one set. + */ + +public class Options { + + private final static String CLASS = "Options"; + +/** + * The name used internally for the default set + */ + + public final static String DEFAULT_SET = "DEFAULT_OPTION_SET"; + +/** + * An enum encapsulating the possible separators between value options and their actual values. + */ + + public enum Separator { + +/** + * Separate option and value by ":" + */ + + COLON(':'), + +/** + * Separate option and value by "=" + */ + + EQUALS('='), + +/** + * Separate option and value by blank space + */ + + BLANK(' '), // Or, more precisely, whitespace (as allowed by the CLI) + +/** + * This is just a placeholder in case no separator is required (i. e. for non-value options) + */ + + NONE('D'); // NONE is a placeholder in case no separator is required, 'D' is just an arbitrary dummy value + + private char c; + + private Separator(char c) { + this.c = c; + } + +/** + * Return the actual separator character + *

+ * @return The actual separator character + */ + + char getName() { + return c; + } + + } + +/** + * An enum encapsulating the possible prefixes identifying options (and separating them from command line data items) + */ + + public enum Prefix { + +/** + * Options start with a "-" (typically on Unix platforms) + */ + + DASH('-'), + +/** + * Options start with a "/" (typically on Windows platforms) + */ + + SLASH('/'); + + private char c; + + private Prefix(char c) { + this.c = c; + } + +/** + * Return the actual prefix character + *

+ * @return The actual prefix character + */ + + char getName() { + return c; + } + + } + +/** + * An enum encapsulating the possible multiplicities for options + */ + + public enum Multiplicity { + +/** + * Option needs to occur exactly once + */ + + ONCE, + +/** + * Option needs to occur at least once + */ + + ONCE_OR_MORE, + +/** + * Option needs to occur either once or not at all + */ + + ZERO_OR_ONE, + +/** + * Option can occur any number of times + */ + + ZERO_OR_MORE; + + } + + private java.util.HashMap optionSets = new java.util.HashMap(); + private Prefix prefix = null; + private Multiplicity defaultMultiplicity = null; + private String[] arguments = null; + private boolean ignoreUnmatched = false; + private int defaultMinData = 0; + private int defaultMaxData = 0; + private StringBuffer checkErrors = null; + +/** + * Constructor + *

+ * @param args The command line arguments to check + * @param prefix The prefix to use for all command line options. It can only be set here for all options at + * the same time + * @param defaultMultiplicity The default multiplicity to use for all options (can be overridden when adding an option) + * @param defMinData The default minimum number of data items for all sets (can be overridden when adding a set) + * @param defMaxData The default maximum number of data items for all sets (can be overridden when adding a set) + *

+ * @throws IllegalArgumentException If either args, prefix, or defaultMultiplicity + * is null - or if the data range values don't make sense + */ + + public Options(String args[], Prefix prefix, Multiplicity defaultMultiplicity, int defMinData, int defMaxData) { + + if (args == null) throw new IllegalArgumentException(CLASS + ": args may not be null"); + if (prefix == null) throw new IllegalArgumentException(CLASS + ": prefix may not be null"); + if (defaultMultiplicity == null) throw new IllegalArgumentException(CLASS + ": defaultMultiplicity may not be null"); + + if (defMinData < 0) throw new IllegalArgumentException(CLASS + ": defMinData must be >= 0"); + if (defMaxData < defMinData) throw new IllegalArgumentException(CLASS + ": defMaxData must be >= defMinData"); + + arguments = new String[args.length]; + int i = 0; + for (String s : args) + arguments[i++] = s; + + this.prefix = prefix; + this.defaultMultiplicity = defaultMultiplicity; + this.defaultMinData = defMinData; + this.defaultMaxData = defMaxData; + + } + +/** + * Constructor + *

+ * @param args The command line arguments to check + * @param prefix The prefix to use for all command line options. It can only be set here for all options at + * the same time + * @param defaultMultiplicity The default multiplicity to use for all options (can be overridden when adding an option) + * @param data The default minimum and maximum number of data items for all sets (can be overridden when adding a set) + *

+ * @throws IllegalArgumentException If either args, prefix, or defaultMultiplicity + * is null - or if the data range value doesn't make sense + */ + + public Options(String args[], Prefix prefix, Multiplicity defaultMultiplicity, int data) { + this(args, prefix, defaultMultiplicity, data, data); + } + +/** + * Constructor. The default number of data items is set to 0. + *

+ * @param args The command line arguments to check + * @param prefix The prefix to use for all command line options. It can only be set here for all options at + * the same time + * @param defaultMultiplicity The default multiplicity to use for all options (can be overridden when adding an option) + *

+ * @throws IllegalArgumentException If either args, prefix, or defaultMultiplicity + * is null + */ + + public Options(String args[], Prefix prefix, Multiplicity defaultMultiplicity) { + this(args, prefix, defaultMultiplicity, 0, 0); + } + +/** + * Constructor. The prefix is set to {@link Prefix#DASH}. + *

+ * @param args The command line arguments to check + * @param defaultMultiplicity The default multiplicity to use for all options (can be overridden when adding an option) + * @param defMinData The default minimum number of data items for all sets (can be overridden when adding a set) + * @param defMaxData The default maximum number of data items for all sets (can be overridden when adding a set) + *

+ * @throws IllegalArgumentException If either args or defaultMultiplicity + * is null - or if the data range values don't make sense + */ + + public Options(String args[], Multiplicity defaultMultiplicity, int defMinData, int defMaxData) { + this(args, Prefix.DASH, defaultMultiplicity, defMinData, defMaxData); + } + +/** + * Constructor. The prefix is set to {@link Prefix#DASH}. + *

+ * @param args The command line arguments to check + * @param defaultMultiplicity The default multiplicity to use for all options (can be overridden when adding an option) + * @param data The default minimum and maximum number of data items for all sets (can be overridden when adding a set) + *

+ * @throws IllegalArgumentException If either args or defaultMultiplicity + * is null - or if the data range value doesn't make sense + */ + + public Options(String args[], Multiplicity defaultMultiplicity, int data) { + this(args, Prefix.DASH, defaultMultiplicity, data, data); + } + +/** + * Constructor. The prefix is set to {@link Prefix#DASH}, and the default number of data items is set to 0. + *

+ * @param args The command line arguments to check + * @param defaultMultiplicity The default multiplicity to use for all options (can be overridden when adding an option) + *

+ * @throws IllegalArgumentException If either args or defaultMultiplicity + * is null + */ + + public Options(String args[], Multiplicity defaultMultiplicity) { + this(args, Prefix.DASH, defaultMultiplicity, 0, 0); + } + +/** + * Constructor. The prefix is set to {@link Prefix#DASH}, the default number of data items is set to 0, and + * the multiplicity is set to {@link Multiplicity#ONCE}. + *

+ * @param args The command line arguments to check + *

+ * @throws IllegalArgumentException If args is null + */ + + public Options(String args[]) { + this(args, Prefix.DASH, Multiplicity.ONCE); + } + +/** + * Constructor. The prefix is set to {@link Prefix#DASH}, and + * the multiplicity is set to {@link Multiplicity#ONCE}. + *

+ * @param args The command line arguments to check + * @param data The default minimum and maximum number of data items for all sets (can be overridden when adding a set) + *

+ * @throws IllegalArgumentException If args is null - or if the data range value doesn't make sense + */ + + public Options(String args[], int data) { + this(args, Prefix.DASH, Multiplicity.ONCE, data, data); + } + +/** + * Constructor. The prefix is set to {@link Prefix#DASH}, and + * the multiplicity is set to {@link Multiplicity#ONCE}. + *

+ * @param args The command line arguments to check + * @param defMinData The default minimum number of data items for all sets (can be overridden when adding a set) + * @param defMaxData The default maximum number of data items for all sets (can be overridden when adding a set) + *

+ * @throws IllegalArgumentException If args is null - or if the data range values don't make sense + */ + + public Options(String args[], int defMinData, int defMaxData) { + this(args, Prefix.DASH, Multiplicity.ONCE, defMinData, defMaxData); + } + +/** + * Constructor. The default number of data items is set to 0, and + * the multiplicity is set to {@link Multiplicity#ONCE}. + *

+ * @param args The command line arguments to check + * @param prefix The prefix to use for all command line options. It can only be set here for all options at + * the same time + *

+ * @throws IllegalArgumentException If either args or prefix is null + */ + + public Options(String args[], Prefix prefix) { + this(args, prefix, Multiplicity.ONCE, 0, 0); + } + +/** + * Constructor. The multiplicity is set to {@link Multiplicity#ONCE}. + *

+ * @param args The command line arguments to check + * @param prefix The prefix to use for all command line options. It can only be set here for all options at + * @param data The default minimum and maximum number of data items for all sets (can be overridden when adding a set) + *

+ * @throws IllegalArgumentException If either args or prefix is null + * - or if the data range value doesn't make sense + */ + + public Options(String args[], Prefix prefix, int data) { + this(args, prefix, Multiplicity.ONCE, data, data); + } + +/** + * Constructor. The multiplicity is set to {@link Multiplicity#ONCE}. + *

+ * @param args The command line arguments to check + * @param prefix The prefix to use for all command line options. It can only be set here for all options at + * the same time + * @param defMinData The default minimum number of data items for all sets (can be overridden when adding a set) + * @param defMaxData The default maximum number of data items for all sets (can be overridden when adding a set) + *

+ * @throws IllegalArgumentException If either args or prefix is null + * - or if the data range values don't make sense + */ + + public Options(String args[], Prefix prefix, int defMinData, int defMaxData) { + this(args, prefix, Multiplicity.ONCE, defMinData, defMaxData); + } + +/** + * Return the (first) matching set. This invocation does not ignore unmatched options and requires that + * data items are the last ones on the command line. + *

+ * @return The first set which matches (i. e. the check() method returns true) - or + * null, if no set matches. + */ + + public OptionSet getMatchingSet() { + return getMatchingSet(false, true); + } + +/** + * Return the (first) matching set. + *

+ * @param ignoreUnmatched A boolean to select whether unmatched options can be ignored in the checks or not + * @param requireDataLast A boolean to indicate whether the data items have to be the last ones on the command line or not + *

+ * @return The first set which matches (i. e. the check() method returns true) - or + * null, if no set matches. + */ + + public OptionSet getMatchingSet(boolean ignoreUnmatched, boolean requireDataLast) { + for (String setName : optionSets.keySet()) + if (check(setName, ignoreUnmatched, requireDataLast)) + return optionSets.get(setName); + return null; + } + +/** + * Add an option set. + *

+ * @param setName The name for the set. This must be a unique identifier + * @param minData The minimum number of data items for this set + * @param maxData The maximum number of data items for this set + *

+ * @return The new Optionset instance created. This is useful to allow chaining of addOption() + * calls right after this method + */ + + public OptionSet addSet(String setName, int minData, int maxData) { + if (setName == null) throw new IllegalArgumentException(CLASS + ": setName may not be null"); + if (optionSets.containsKey(setName)) throw new IllegalArgumentException(CLASS + ": a set with the name " + + setName + " has already been defined"); + OptionSet os = new OptionSet(prefix, defaultMultiplicity, setName, minData, maxData); + optionSets.put(setName, os); + return os; + } + +/** + * Add an option set. + *

+ * @param setName The name for the set. This must be a unique identifier + * @param data The minimum and maximum number of data items for this set + *

+ * @return The new Optionset instance created. This is useful to allow chaining of addOption() + * calls right after this method + */ + + public OptionSet addSet(String setName, int data) { + return addSet(setName, data, data); + } + +/** + * Add an option set. The defaults for the number of data items are used. + *

+ * @param setName The name for the set. This must be a unique identifier + *

+ * @return The new Optionset instance created. This is useful to allow chaining of addOption() + * calls right after this method + */ + + public OptionSet addSet(String setName) { + return addSet(setName, defaultMinData, defaultMaxData); + } + +/** + * Return an option set - or null, if no set with the given name exists + *

+ * @param setName The name for the set to retrieve + *

+ * @return The set to retrieve (or null, if no set with the given name exists) + */ + + public OptionSet getSet(String setName) { + return optionSets.get(setName); + } + +/** + * This returns the (anonymous) default set + *

+ * @return The default set + */ + + public OptionSet getSet() { + if (getSet(DEFAULT_SET) == null) + addSet(DEFAULT_SET, defaultMinData, defaultMaxData); + return getSet(DEFAULT_SET); + } + +/** + * The error messages collected during the last option check (invocation of any of the check() methods). This + * is useful to determine what was wrong with the command line arguments provided + *

+ * @return A string with all collected error messages + */ + + public String getCheckErrors() { + return checkErrors.toString(); + } + +/** + * Run the checks for the default set. ignoreUnmatched is set to false, and + * requireDataLast is set to true. + *

+ * @return A boolean indicating whether all checks were successful or not + */ + + public boolean check() { + return check(DEFAULT_SET, false, true); + } + +/** + * Run the checks for the default set. + *

+ * @param ignoreUnmatched A boolean to select whether unmatched options can be ignored in the checks or not + * @param requireDataLast A boolean to indicate whether the data items have to be the last ones on the command line or not + *

+ * @return A boolean indicating whether all checks were successful or not + */ + + public boolean check(boolean ignoreUnmatched, boolean requireDataLast) { + return check(DEFAULT_SET, ignoreUnmatched, requireDataLast); + } + +/** + * Run the checks for the given set. ignoreUnmatched is set to false, and + * requireDataLast is set to true. + *

+ * @param setName The name for the set to check + *

+ * @return A boolean indicating whether all checks were successful or not + *

+ * @throws IllegalArgumentException If either setName is null, or the set is unknown. + */ + + public boolean check(String setName) { + return check(setName, false, true); + } + +/** + * Run the checks for the given set. + *

+ * @param setName The name for the set to check + * @param ignoreUnmatched A boolean to select whether unmatched options can be ignored in the checks or not + * @param requireDataLast A boolean to indicate whether the data items have to be the last ones on the command line or not + *

+ * @return A boolean indicating whether all checks were successful or not + *

+ * @throws IllegalArgumentException If either setName is null, or the set is unknown. + */ + + public boolean check(String setName, boolean ignoreUnmatched, boolean requireDataLast) { + + if (setName == null) throw new IllegalArgumentException(CLASS + ": setName may not be null"); + if (optionSets.get(setName) == null) throw new IllegalArgumentException(CLASS + ": Unknown OptionSet: " + setName); + + checkErrors = new StringBuffer(); + checkErrors.append("Checking set "); + checkErrors.append(setName); + checkErrors.append('\n'); + +//.... Access the data for the set to use + + OptionSet set = optionSets.get(setName); + java.util.ArrayList options = set.getOptionData(); + java.util.ArrayList data = set.getData(); + java.util.ArrayList unmatched = set.getUnmatched(); + +//.... Catch some trivial cases + + if (options.size() == 0) { // No options have been defined at all + if (arguments.length == 0) { // No arguments have been given: in this case, this is a success + return true; + } else { + checkErrors.append("No options have been defined, nothing to check\n"); + return false; + } + } else if (arguments.length == 0) { // Options have been defined, but no arguments given + checkErrors.append("Options have been defined, but no arguments have been given; nothing to check\n"); + return false; + } + +//.... Parse all the arguments given + + int ipos = 0; + int offset = 0; + java.util.regex.Matcher m = null; + String value = null; + String detail = null; + String next = null; + String key = null; + String pre = Character.toString(prefix.getName()); + boolean add = true; + boolean[] matched = new boolean[arguments.length]; + + for (int i = 0; i < matched.length; i++) // Initially, we assume there was no match at all + matched[i] = false; + + while (true) { + + value = null; + detail = null; + offset = 0; + add = true; + key = arguments[ipos]; + + for (OptionData optionData : options) { // For each argument, we may need to check all defined options + m = optionData.getPattern().matcher(key); + if (m.lookingAt()) { + if (optionData.useValue()) { // The code section for value options + if (optionData.useDetail()) { + detail = m.group(1); + offset = 2; // required for correct Matcher.group access below + } + if (optionData.getSeparator() == Separator.BLANK) { // In this case, the next argument must be the value + if (ipos + 1 == arguments.length) { // The last argument, thus no value follows it: Error + checkErrors.append("At end of arguments - no value found following argument "); + checkErrors.append(key); + checkErrors.append('\n'); + add = false; + } else { + next = arguments[ipos + 1]; + if (next.startsWith(pre)) { // The next one is an argument, not a value: Error + checkErrors.append("No value found following argument "); + checkErrors.append(key); + checkErrors.append('\n'); + add = false; + } else { + value = next; + matched[ipos++] = true; // Mark the key and the value + matched[ipos] = true; + } + } + } else { // The value follows the separator in this case + value = m.group(1 + offset); + matched[ipos] = true; + } + } else { // Simple, non-value options + matched[ipos] = true; + } + + if (add) optionData.addResult(value, detail); // Store the result + break; // No need to check more options, we have a match + } + } + + ipos++; // Advance to the next argument to check + if (ipos >= arguments.length) break; // Terminating condition for the check loop + + } + +//.... Identify unmatched arguments and actual (non-option) data + + int first = -1; // Required later for requireDataLast + for (int i = 0; i < matched.length; i++) { // Assemble the list of unmatched options + if (!matched[i]) { + if (arguments[i].startsWith(pre)) { // This is an unmatched option + unmatched.add(arguments[i]); + checkErrors.append("No matching option found for argument "); + checkErrors.append(arguments[i]); + checkErrors.append('\n'); + } else { // This is actual data + if (first < 0) first = i; + data.add(arguments[i]); + } + } + } + +//.... Checks to determine overall success; start with multiplicity of options + + boolean err = true; + + for (OptionData optionData : options) { + + key = optionData.getKey(); + err = false; // Local check result for one option + + switch (optionData.getMultiplicity()) { + case ONCE: if (optionData.getResultCount() != 1) err = true; break; + case ONCE_OR_MORE: if (optionData.getResultCount() == 0) err = true; break; + case ZERO_OR_ONE: if (optionData.getResultCount() > 1) err = true; break; + } + + if (err) { + checkErrors.append("Wrong number of occurences found for argument "); + checkErrors.append(prefix.getName()); + checkErrors.append(key); + checkErrors.append('\n'); + return false; + } + + } + +//.... Check range for data + + if (data.size() < set.getMinData() || data.size() > set.getMaxData()) { + checkErrors.append("Invalid number of data arguments: "); + checkErrors.append(data.size()); + checkErrors.append(" (allowed range: "); + checkErrors.append(set.getMinData()); + checkErrors.append(" ... "); + checkErrors.append(set.getMaxData()); + checkErrors.append(")\n"); + return false; + } + +//.... Check for location of the data in the list of command line arguments + + if (requireDataLast) { + if (first + data.size() != arguments.length) { + checkErrors.append("Invalid data specification: data arguments are not the last ones on the command line\n"); + return false; + } + } + +//.... Check for unmatched arguments + + if (!ignoreUnmatched && unmatched.size() > 0) return false; // Don't accept unmatched arguments + +//.... If we made it to here, all checks were successful + + return true; + + } + +/** + * Add the given non-value option to all known sets. + * See {@link OptionSet#addOption(String)} for details. + */ + + public void addOptionAllSets(String key) { + for (String setName : optionSets.keySet()) + optionSets.get(setName).addOption(key, defaultMultiplicity); + } + +/** + * Add the given non-value option to all known sets. + * See {@link OptionSet#addOption(String, Options.Multiplicity)} for details. + */ + + public void addOptionAllSets(String key, Multiplicity multiplicity) { + for (String setName : optionSets.keySet()) + optionSets.get(setName).addOption(key, false, Separator.NONE, false, multiplicity); + } + +/** + * Add the given value option to all known sets. + * See {@link OptionSet#addOption(String, Options.Separator)} for details. + */ + + public void addOptionAllSets(String key, Separator separator) { + for (String setName : optionSets.keySet()) + optionSets.get(setName).addOption(key, false, separator, true, defaultMultiplicity); + } + +/** + * Add the given value option to all known sets. + * See {@link OptionSet#addOption(String, Options.Separator, Options.Multiplicity)} for details. + */ + + public void addOptionAllSets(String key, Separator separator, Multiplicity multiplicity) { + for (String setName : optionSets.keySet()) + optionSets.get(setName).addOption(key, false, separator, true, multiplicity); + } + +/** + * Add the given value option to all known sets. + * See {@link OptionSet#addOption(String, boolean, Options.Separator)} for details. + */ + + public void addOptionAllSets(String key, boolean details, Separator separator) { + for (String setName : optionSets.keySet()) + optionSets.get(setName).addOption(key, details, separator, true, defaultMultiplicity); + } + +/** + * Add the given value option to all known sets. + * See {@link OptionSet#addOption(String, boolean, Options.Separator, Options.Multiplicity)} for details. + */ + + public void addOptionAllSets(String key, boolean details, Separator separator, Multiplicity multiplicity) { + for (String setName : optionSets.keySet()) + optionSets.get(setName).addOption(key, details, separator, true, multiplicity); + } + +/** + * This is the overloaded {@link Object#toString()} method, and it is provided mainly for debugging + * purposes. + *

+ * @return A string representing the instance + */ + + public String toString() { + + StringBuffer sb = new StringBuffer(); + + for (OptionSet set : optionSets.values()) { + sb.append("Set: "); + sb.append(set.getSetName()); + sb.append('\n'); + for (OptionData data : set.getOptionData()) { + sb.append(data.toString()); + sb.append('\n'); + } + } + + return sb.toString(); + + } + +} + + 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 9b76489..36061ab 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 @@ -14,10 +14,10 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -32,6 +32,7 @@ import javax.inject.Named; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.core.runtime.jobs.IJobChangeEvent; @@ -56,12 +57,16 @@ import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; -import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseTrackListener; +import org.eclipse.swt.events.MouseWheelListener; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; import com.minres.scviewer.database.ITx; import com.minres.scviewer.database.ITxRelation; @@ -75,6 +80,8 @@ import com.minres.scviewer.database.ui.GotoDirection; import com.minres.scviewer.database.ui.ICursor; import com.minres.scviewer.database.ui.IWaveformViewer; import com.minres.scviewer.database.ui.TrackEntry; +import com.minres.scviewer.database.ui.TrackEntry.ValueDisplay; +import com.minres.scviewer.database.ui.TrackEntry.WaveDisplay; import com.minres.scviewer.database.ui.WaveformColors; import com.minres.scviewer.e4.application.Messages; import com.minres.scviewer.e4.application.internal.status.WaveStatusBarControl; @@ -83,7 +90,6 @@ import com.minres.scviewer.e4.application.internal.util.IFileChangeListener; import com.minres.scviewer.e4.application.internal.util.IModificationChecker; import com.minres.scviewer.e4.application.preferences.DefaultValuesInitializer; import com.minres.scviewer.e4.application.preferences.PreferenceConstants; -//import com.minres.scviewer.database.swt.internal.WaveformCanvas; /** * The Class WaveformViewerPart. @@ -103,6 +109,10 @@ public class WaveformViewer implements IFileChangeListener, IPreferenceChangeLis /** The Constant SHOWN_WAVEFORM. */ protected static final String SHOWN_WAVEFORM = "SHOWN_WAVEFORM"; //$NON-NLS-1$ + protected static final String VALUE_DISPLAY = ".VALUE_DISPLAY"; //$NON-NLS-1$ + + protected static final String WAVE_DISPLAY = ".WAVE_DISPLAY"; //$NON-NLS-1$ + /** The Constant SHOWN_CURSOR. */ protected static final String SHOWN_CURSOR = "SHOWN_CURSOR"; //$NON-NLS-1$ @@ -142,7 +152,7 @@ public class WaveformViewer implements IFileChangeListener, IPreferenceChangeLis @Inject ESelectionService selectionService; - /** The e part service. */ + /** The part service. */ @Inject EPartService ePartService; @@ -237,6 +247,106 @@ public class WaveformViewer implements IFileChangeListener, IPreferenceChangeLis selectionService.setSelection(event.getSelection()); } }); + waveformPane.getWaveformControl().addMouseTrackListener(new MouseTrackListener() { + + @Override + public void mouseHover(MouseEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void mouseExit(MouseEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public void mouseEnter(MouseEvent e) { + // TODO Auto-generated method stub + + } + }); + + waveformPane.getWaveformControl().addMouseWheelListener(new MouseWheelListener() { + + @Override + public void mouseScrolled(MouseEvent e) { + // TODO Auto-generated method stub + + } + }); + + waveformPane.getWaveformControl().addListener(SWT.KeyDown, new Listener() { + + @Override + public void handleEvent(Event e) { + int state = e.stateMask & SWT.MODIFIER_MASK; + if(Platform.OS_MACOSX.equals(Platform.getOS())) { //swap cammnd and control for MacOSX + if((state&SWT.COMMAND)!=0) { + state&=~SWT.COMMAND; + state|=SWT.CONTROL; + } else if((state&SWT.CONTROL)!=0) { + state&=~SWT.CONTROL; + state|=SWT.COMMAND; + } + } + if(state==SWT.ALT) { + switch(e.keyCode) { + case SWT.ARROW_LEFT: + waveformPane.scrollHorizontal(-100); + return; + case SWT.ARROW_RIGHT: + waveformPane.scrollHorizontal(100); + return; + case SWT.KEYPAD_ADD: + return; + case SWT.KEYPAD_SUBTRACT: + return; + } + } else if(state==SWT.CTRL) { + int zoomlevel = waveformPane.getZoomLevel(); + switch(e.keyCode) { + case '+': + case SWT.KEYPAD_ADD: + if(zoomlevel>0) + waveformPane.setZoomLevel(zoomlevel-1); + return; + case '-': + case SWT.KEYPAD_SUBTRACT: + if(zoomlevel(); File file = (File) partInput; @@ -411,6 +521,9 @@ public class WaveformViewer implements IFileChangeListener, IPreferenceChangeLis } if (filesToLoad.size() > 0) loadDatabase(persistedState); + if(partConfig instanceof String) { + loadState((String) partConfig); + } } } @@ -466,12 +579,13 @@ public class WaveformViewer implements IFileChangeListener, IPreferenceChangeLis FileInputStream in = new FileInputStream(fileName); props.load(in); in.close(); + @SuppressWarnings({ "unchecked", "rawtypes" }) + HashMap propMap = new HashMap((Map) props); + restoreWaveformViewerState(propMap); + } catch(FileNotFoundException e) { } catch (IOException e) { e.printStackTrace(); } - @SuppressWarnings({ "unchecked", "rawtypes" }) - HashMap propMap = new HashMap((Map) props); - restoreWaveformViewerState(propMap); } /** @@ -485,6 +599,8 @@ public class WaveformViewer implements IFileChangeListener, IPreferenceChangeLis index = 0; for (TrackEntry trackEntry : waveformPane.getStreamList()) { persistedState.put(SHOWN_WAVEFORM + index, trackEntry.waveform.getFullName()); + persistedState.put(SHOWN_WAVEFORM + index + VALUE_DISPLAY, trackEntry.valueDisplay.toString()); + persistedState.put(SHOWN_WAVEFORM + index + WAVE_DISPLAY, trackEntry.waveDisplay.toString()); index++; } List cursors = waveformPane.getCursorList(); @@ -508,8 +624,16 @@ public class WaveformViewer implements IFileChangeListener, IPreferenceChangeLis List res = new LinkedList<>(); for (int i = 0; i < waves; i++) { IWaveform waveform = database.getStreamByName(state.get(SHOWN_WAVEFORM + i)); - if (waveform != null) - res.add(new TrackEntry(waveform)); + if (waveform != null) { + TrackEntry t = new TrackEntry(waveform); + res.add(t); + String v = state.get(SHOWN_WAVEFORM + i + VALUE_DISPLAY); + if(v!=null) + t.valueDisplay=ValueDisplay.valueOf(v); + String s = state.get(SHOWN_WAVEFORM + i + WAVE_DISPLAY); + if(s!=null) + t.waveDisplay=WaveDisplay.valueOf(s); + } } if (res.size() > 0) waveformPane.getStreamList().addAll(res);