From 316647031af50c94cf838cc69f000959dba93dd2 Mon Sep 17 00:00:00 2001 From: Eyck Jentzsch Date: Sun, 22 Nov 2015 12:14:27 +0100 Subject: [PATCH] 2: Reload dialog opens while dialog is open Task-Url: https://github.com/eyck/txviewer/issues/issue/2 --- .../internal/util/FileMonitor.java | 56 +- .../e4/application/parts/WaveformViewer.java | 836 ++++++++++++++++++ 2 files changed, 878 insertions(+), 14 deletions(-) create mode 100644 com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/WaveformViewer.java diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/internal/util/FileMonitor.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/internal/util/FileMonitor.java index 5c42523..3989582 100644 --- a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/internal/util/FileMonitor.java +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/internal/util/FileMonitor.java @@ -18,6 +18,7 @@ import java.util.List; import java.util.Timer; import java.util.TimerTask; +// TODO: Auto-generated Javadoc /** * Class monitoring a {@link File} for changes. * @@ -25,8 +26,12 @@ import java.util.TimerTask; */ public class FileMonitor { + /** The timer. */ private Timer timer; + private boolean enabled; + + /** The timer entries. */ private Hashtable timerEntries; /** @@ -36,17 +41,16 @@ public class FileMonitor { // Create timer, run timer thread as daemon. timer = new Timer(true); timerEntries = new Hashtable(); + enabled=true; } /** * Adds a monitored file with a FileChangeListener. - * - * @param listener - * listener to notify when the file changed. - * @param fileName - * name of the file to monitor. - * @param period - * polling period in milliseconds. + * + * @param listener listener to notify when the file changed. + * @param file the file + * @param period polling period in milliseconds. + * @return the i modification checker */ public IModificationChecker addFileChangeListener(IFileChangeListener listener, File file, long period) { return addFileChangeListener(listener, Arrays.asList(new File[]{file}), period); @@ -55,12 +59,11 @@ public class FileMonitor { /** * Adds a monitored file with a FileChangeListener. * List filesToLoad - * @param listener - * listener to notify when the file changed. - * @param fileName - * name of the file to monitor. - * @param period - * polling period in milliseconds. + * + * @param listener listener to notify when the file changed. + * @param files the files + * @param period polling period in milliseconds. + * @return the i modification checker */ public IModificationChecker addFileChangeListener(IFileChangeListener listener, List files, long period) { removeFileChangeListener(listener); @@ -90,7 +93,15 @@ public class FileMonitor { * the file that changed */ protected void fireFileChangeEvent(IFileChangeListener listener, List file) { - listener.fileChanged(file); + if(enabled) listener.fileChanged(file); + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; } /** @@ -98,14 +109,25 @@ public class FileMonitor { */ class FileSetMonitorTask extends TimerTask implements IModificationChecker{ + /** The listener. */ IFileChangeListener listener; + /** The monitored files. */ private List monitoredFiles; + /** The last modified times. */ private List lastModifiedTimes; + /** The period. */ public final long period; + /** + * Instantiates a new file set monitor task. + * + * @param listener the listener + * @param monitoredFiles the monitored files + * @param period the period + */ public FileSetMonitorTask(IFileChangeListener listener, List monitoredFiles, long period) { this.period=period; this.monitoredFiles = monitoredFiles; @@ -120,10 +142,16 @@ public class FileMonitor { } } + /* (non-Javadoc) + * @see java.util.TimerTask#run() + */ public void run() { check(); } + /* (non-Javadoc) + * @see com.minres.scviewer.e4.application.internal.util.IModificationChecker#check() + */ public void check() { boolean res = false; for(int i=0; i filesToLoad; + + /** The persisted state. */ + Map persistedState; + + /** The browser state. */ + private Object browserState; + + /** The details settings. */ + private Object detailsSettings; + + /** The navigation relation type. */ + private RelationType navigationRelationType=IWaveformViewer.NEXT_PREV_IN_STREAM ; + + /** The file monitor. */ + FileMonitor fileMonitor = new FileMonitor(); + + /** The file checker. */ + IModificationChecker fileChecker; + + /** + * Creates the composite. + * + * @param part the part + * @param parent the parent + * @param dbFactory the db factory + */ + @PostConstruct + public void createComposite(MPart part, Composite parent, IWaveformDbFactory dbFactory) { + myPart = part; + myParent = parent; + database = dbFactory.getDatabase(); + database.addPropertyChangeListener(new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + if ("WAVEFORMS".equals(evt.getPropertyName())) { + myParent.getDisplay().syncExec(new Runnable() { + @Override + public void run() { + waveformPane.setMaxTime(database.getMaxTime()); + } + }); + } + } + }); + waveformPane = factory.createPanel(parent); + waveformPane.setMaxTime(0); + waveformPane.addPropertyChangeListener(IWaveformViewer.CURSOR_PROPERTY, new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + Long time = (Long) evt.getNewValue(); + eventBroker.post(WaveStatusBarControl.CURSOR_TIME, waveformPane.getScaledTime(time)); + long marker = waveformPane.getSelectedMarkerTime(); + eventBroker.post(WaveStatusBarControl.MARKER_DIFF, waveformPane.getScaledTime(time - marker)); + + } + }); + waveformPane.addPropertyChangeListener(IWaveformViewer.MARKER_PROPERTY, new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + Long time = (Long) evt.getNewValue(); + eventBroker.post(WaveStatusBarControl.MARKER_TIME, waveformPane.getScaledTime(time)); + long cursor = waveformPane.getCursorTime(); + eventBroker.post(WaveStatusBarControl.MARKER_DIFF, waveformPane.getScaledTime(cursor - time)); + } + }); + waveformPane.addSelectionChangedListener(new ISelectionChangedListener() { + @Override + public void selectionChanged(SelectionChangedEvent event) { + if (event.getSelection() instanceof IStructuredSelection) + selectionService.setSelection(event.getSelection()); + } + }); + zoomLevel = waveformPane.getZoomLevels(); + setupColors(); + checkForUpdates = prefs.getBoolean(PreferenceConstants.DATABASE_RELOAD, true); + filesToLoad = new ArrayList(); + persistedState = part.getPersistedState(); + Integer files = persistedState.containsKey(DATABASE_FILE + "S") + ? Integer.parseInt(persistedState.get(DATABASE_FILE + "S")) : 0; + for (int i = 0; i < files; i++) { + filesToLoad.add(new File(persistedState.get(DATABASE_FILE + i))); + } + if (filesToLoad.size() > 0) + loadDatabase(persistedState); + eventBroker.post(WaveStatusBarControl.ZOOM_LEVEL, zoomLevel[waveformPane.getZoomLevel()]); + menuService.registerContextMenu(waveformPane.getNameControl(), + "com.minres.scviewer.e4.application.popupmenu.namecontext"); + menuService.registerContextMenu(waveformPane.getValueControl(), + "com.minres.scviewer.e4.application.popupmenu.namecontext"); + menuService.registerContextMenu(waveformPane.getWaveformControl(), + "com.minres.scviewer.e4.application.popupmenu.wavecontext"); + ePartService.addPartListener(new PartListener() { + @Override + public void partActivated(MPart part) { + if (part == myPart) { + if (fileChecker != null) + fileChecker.check(); + updateAll(); + } + } + }); + prefs.addPreferenceChangeListener(this); + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener#preferenceChange(org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent) + */ + @Override + public void preferenceChange(PreferenceChangeEvent event) { + if (PreferenceConstants.DATABASE_RELOAD.equals(event.getKey())) { + checkForUpdates = (Boolean) event.getNewValue(); + fileChecker = null; + if (checkForUpdates) + fileChecker = fileMonitor.addFileChangeListener(WaveformViewer.this, filesToLoad, + FILE_CHECK_INTERVAL); + else + fileMonitor.removeFileChangeListener(this); + } else { + setupColors(); + } + } + + /** + * Setup colors. + */ + protected void setupColors() { + DefaultValuesInitializer initializer = new DefaultValuesInitializer(); + HashMap colorPref = new HashMap<>(); + for (WaveformColors c : WaveformColors.values()) { + String prefValue = prefs.get(c.name() + "_COLOR", + StringConverter.asString(initializer.colors[c.ordinal()].getRGB())); + RGB rgb = StringConverter.asRGB(prefValue); + colorPref.put(c, rgb); + } + waveformPane.setColors(colorPref); + } + + /** + * Load database. + * + * @param state the state + */ + protected void loadDatabase(final Map state) { + fileMonitor.removeFileChangeListener(this); + Job job = new Job(" My Job") { + @Override + protected IStatus run(IProgressMonitor monitor) { + // convert to SubMonitor and set total number of work units + SubMonitor subMonitor = SubMonitor.convert(monitor, filesToLoad.size()); + subMonitor.setTaskName("Loading database"); + try { + for (File file : filesToLoad) { + // TimeUnit.SECONDS.sleep(2); + database.load(file); + database.addPropertyChangeListener(waveformPane); + subMonitor.worked(1); + if (monitor.isCanceled()) + return Status.CANCEL_STATUS; + } + // sleep a second + } catch (Exception e) { + database = null; + e.printStackTrace(); + return Status.CANCEL_STATUS; + } + subMonitor.done(); + monitor.done(); + return Status.OK_STATUS; + } + }; + job.addJobChangeListener(new JobChangeAdapter() { + @Override + public void done(IJobChangeEvent event) { + if (event.getResult() == Status.OK_STATUS) + myParent.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + waveformPane.setMaxTime(database.getMaxTime()); + if (state != null) + restoreWaveformViewerState(state); + fileChecker = null; + if (checkForUpdates) + fileChecker = fileMonitor.addFileChangeListener(WaveformViewer.this, filesToLoad, + FILE_CHECK_INTERVAL); + } + }); + } + }); + job.schedule(0); + } + + /* (non-Javadoc) + * @see com.minres.scviewer.e4.application.internal.util.IFileChangeListener#fileChanged(java.util.List) + */ + @Override + public void fileChanged(List file) { + final Display display = myParent.getDisplay(); + display.asyncExec(new Runnable() { + @Override + public void run() { + if (MessageDialog.openQuestion(display.getActiveShell(), "Database re-load", + "Would you like to reload the database?")) { + Map state = new HashMap<>(); + saveWaveformViewerState(state); + waveformPane.getStreamList().clear(); + database.clear(); + if (filesToLoad.size() > 0) + loadDatabase(state); + } + } + }); + fileMonitor.removeFileChangeListener(this); + } + + /** + * Sets the part input. + * + * @param partInput the new part input + */ + @Inject + @Optional + public void setPartInput(@Named("input") Object partInput) { + if (partInput instanceof File) { + filesToLoad = new ArrayList(); + File file = (File) partInput; + if (file.exists()) { + filesToLoad.add(file); + try { + String ext = getFileExtension(file.getName()); + if ("vcd".equals(ext.toLowerCase())) { + if (askIfToLoad(new File(renameFileExtension(file.getCanonicalPath(), "txdb")))) { + filesToLoad.add(new File(renameFileExtension(file.getCanonicalPath(), "txdb"))); + } else if (askIfToLoad(new File(renameFileExtension(file.getCanonicalPath(), "txlog")))) { + filesToLoad.add(new File(renameFileExtension(file.getCanonicalPath(), "txlog"))); + } + } else if ("txdb".equals(ext.toLowerCase()) || "txlog".equals(ext.toLowerCase())) { + if (askIfToLoad(new File(renameFileExtension(file.getCanonicalPath(), "vcd")))) { + filesToLoad.add(new File(renameFileExtension(file.getCanonicalPath(), "vcd"))); + } + } + } catch (IOException e) { // silently ignore any error + } + } + if (filesToLoad.size() > 0) + loadDatabase(persistedState); + } + } + + /** + * Sets the focus. + */ + @Focus + public void setFocus() { + myParent.setFocus(); + } + + /** + * Save state. + * + * @param part the part + */ + @PersistState + public void saveState(MPart part) { + // save changes + Map persistedState = part.getPersistedState(); + persistedState.put(DATABASE_FILE + "S", Integer.toString(filesToLoad.size())); + Integer index = 0; + for (File file : filesToLoad) { + persistedState.put(DATABASE_FILE + index, file.getAbsolutePath()); + index++; + } + saveWaveformViewerState(persistedState); + } + + /** + * Save waveform viewer state. + * + * @param persistedState the persisted state + */ + protected void saveWaveformViewerState(Map persistedState) { + Integer index; + persistedState.put(SHOWN_WAVEFORM + "S", Integer.toString(waveformPane.getStreamList().size())); + index = 0; + for (TrackEntry trackEntry : waveformPane.getStreamList()) { + persistedState.put(SHOWN_WAVEFORM + index, trackEntry.waveform.getFullName()); + index++; + } + List cursors = waveformPane.getCursorList(); + persistedState.put(SHOWN_CURSOR + "S", Integer.toString(cursors.size())); + index = 0; + for (ICursor cursor : cursors) { + persistedState.put(SHOWN_CURSOR + index, Long.toString(cursor.getTime())); + index++; + } + persistedState.put(ZOOM_LEVEL, Integer.toString(waveformPane.getZoomLevel())); + } + + /** + * Restore waveform viewer state. + * + * @param state the state + */ + protected void restoreWaveformViewerState(Map state) { + updateAll(); + Integer waves = state.containsKey(SHOWN_WAVEFORM + "S") ? Integer.parseInt(state.get(SHOWN_WAVEFORM + "S")) : 0; + 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 (res.size() > 0) + waveformPane.getStreamList().addAll(res); + Integer cursorLength = state.containsKey(SHOWN_CURSOR + "S") ? Integer.parseInt(state.get(SHOWN_CURSOR + "S")) + : 0; + List cursors = waveformPane.getCursorList(); + if (cursorLength == cursors.size()) { + for (int i = 0; i < cursorLength; i++) { + Long time = Long.parseLong(state.get(SHOWN_CURSOR + i)); + cursors.get(i).setTime(time); + } + } + if (state.containsKey(ZOOM_LEVEL)) { + try { + Integer scale = Integer.parseInt(state.get(ZOOM_LEVEL)); + waveformPane.setZoomLevel(scale); + } catch (NumberFormatException e) { + } + } + } + + /** + * Update all. + */ + private void updateAll() { + eventBroker.post(ACTIVE_WAVEFORMVIEW, this); + eventBroker.post(WaveStatusBarControl.ZOOM_LEVEL, zoomLevel[waveformPane.getZoomLevel()]); + long cursor = waveformPane.getCursorTime(); + long marker = waveformPane.getSelectedMarkerTime(); + eventBroker.post(WaveStatusBarControl.CURSOR_TIME, waveformPane.getScaledTime(cursor)); + eventBroker.post(WaveStatusBarControl.MARKER_TIME, waveformPane.getScaledTime(marker)); + eventBroker.post(WaveStatusBarControl.MARKER_DIFF, waveformPane.getScaledTime(cursor - marker)); + } + + /** + * Gets the adds the waveform event. + * + * @param o the o + * @return the adds the waveform event + */ + @Inject + @Optional + public void getAddWaveformEvent(@UIEventTopic(WaveformViewer.ADD_WAVEFORM) Object o) { + Object sel = o == null ? selectionService.getSelection() : o; + if (sel instanceof IStructuredSelection) + for (Object el : ((IStructuredSelection) sel).toArray()) { + if (el instanceof IWaveform) + addStreamToList((IWaveform) el, false); + } + } + + /** + * Ask if to load. + * + * @param txFile the tx file + * @return true, if successful + */ + protected boolean askIfToLoad(File txFile) { + if (txFile.exists() && MessageDialog.openQuestion(myParent.getDisplay().getActiveShell(), "Database open", + "Would you like to open the adjacent database " + txFile.getName() + " as well?")) { + return true; + } + return false; + } + + /** + * Rename file extension. + * + * @param source the source + * @param newExt the new ext + * @return the string + */ + protected static String renameFileExtension(String source, String newExt) { + String target; + String currentExt = getFileExtension(source); + if (currentExt.equals("")) { + target = source + "." + newExt; + } else { + target = source.replaceFirst(Pattern.quote("." + currentExt) + "$", Matcher.quoteReplacement("." + newExt)); + } + return target; + } + + /** + * Gets the file extension. + * + * @param f the f + * @return the file extension + */ + protected static String getFileExtension(String f) { + String ext = ""; + int i = f.lastIndexOf('.'); + if (i > 0 && i < f.length() - 1) { + ext = f.substring(i + 1); + } + return ext; + } + + /** + * Gets the model. + * + * @return the model + */ + public IWaveformDb getModel() { + return database; + } + + /** + * Gets the database. + * + * @return the database + */ + public IWaveformDb getDatabase() { + return database; + } + + /** + * Adds the stream to list. + * + * @param obj the obj + * @param insert the insert + */ + public void addStreamToList(IWaveform obj, boolean insert) { + addStreamsToList(new IWaveform[] { obj }, insert); + } + + /** + * Adds the streams to list. + * + * @param iWaveforms the i waveforms + * @param insert the insert + */ + public void addStreamsToList(IWaveform[] iWaveforms, boolean insert) { + List streams = new LinkedList<>(); + for (IWaveform stream : iWaveforms) + streams.add(new TrackEntry(stream)); + IStructuredSelection selection = (IStructuredSelection) waveformPane.getSelection(); + if (selection.size() == 0) { + waveformPane.getStreamList().addAll(streams); + } else { + Object first = selection.getFirstElement(); + IWaveform stream = (first instanceof ITx) ? ((ITx) first).getStream() : (IWaveform) first; + TrackEntry trackEntry = waveformPane.getEntryForStream(stream); + int index = waveformPane.getStreamList().indexOf(trackEntry); + if (!insert) + index++; + waveformPane.getStreamList().addAll(index, streams); + } + } + + /** + * Removes the stream from list. + * + * @param stream the stream + */ + public void removeStreamFromList(IWaveform stream) { + TrackEntry trackEntry = waveformPane.getEntryForStream(stream); + waveformPane.getStreamList().remove(trackEntry); + } + + /** + * Removes the streams from list. + * + * @param iWaveforms the i waveforms + */ + public void removeStreamsFromList(IWaveform[] iWaveforms) { + for (IWaveform stream : iWaveforms) + removeStreamFromList(stream); + } + + /** + * Move selected. + * + * @param i the i + */ + public void moveSelected(int i) { + waveformPane.moveSelectedTrack(i); + } + + + /** + * Move selection. + * + * @param direction the direction + */ + public void moveSelection(GotoDirection direction ) { + moveSelection(direction, navigationRelationType); + } + + /** + * Move selection. + * + * @param direction the direction + * @param relationType the relation type + */ + public void moveSelection(GotoDirection direction, RelationType relationType) { + waveformPane.moveSelection(direction, relationType); + } + + /** + * Move cursor. + * + * @param direction the direction + */ + public void moveCursor(GotoDirection direction) { + waveformPane.moveCursor(direction); + } + + /** + * Sets the zoom level. + * + * @param level the new zoom level + */ + public void setZoomLevel(Integer level) { + if (level < 0) + level = 0; + if (level > zoomLevel.length - 1) + level = zoomLevel.length - 1; + waveformPane.setZoomLevel(level); + updateAll(); + } + + /** + * Sets the zoom fit. + */ + public void setZoomFit() { + waveformPane.setZoomLevel(6); + updateAll(); + } + + /** + * Gets the zoom level. + * + * @return the zoom level + */ + public int getZoomLevel() { + return waveformPane.getZoomLevel(); + } + + /** + * Gets the selection. + * + * @return the selection + */ + public ISelection getSelection() { + return waveformPane.getSelection(); + } + + /** + * Sets the selection. + * + * @param structuredSelection the new selection + */ + public void setSelection(IStructuredSelection structuredSelection) { + waveformPane.setSelection(structuredSelection, true); + } + + /** + * Gets the scaled time. + * + * @param time the time + * @return the scaled time + */ + public String getScaledTime(Long time) { + return waveformPane.getScaledTime(time); + } + + /** + * Store design brower state. + * + * @param browserState the browser state + */ + public void storeDesignBrowerState(Object browserState) { + this.browserState=browserState; + } + + /** + * Retrieve design brower state. + * + * @return the object + */ + public Object retrieveDesignBrowerState() { + return browserState; + } + + /** + * Store transaction details settings + * + * @param detailsSettings the details settings + */ + public void storeDetailsSettings(Object detailsSettings) { + this.detailsSettings=detailsSettings; + } + + /** + * Retrieve design details settings. + * + * @return the details settings + */ + public Object retrieveDetailsSettings() { + return detailsSettings; + } + + /** + * Gets the all relation types. + * + * @return the all relation types + */ + public List getAllRelationTypes() { + List res =new ArrayList<>(); + res.add(IWaveformViewer.NEXT_PREV_IN_STREAM); + res.addAll(database.getAllRelationTypes()); + return res; + } + + /** + * Gets the selection relation types. + * + * @return the selection relation types + */ + public List getSelectionRelationTypes() { + List res =new ArrayList<>(); + res.add(IWaveformViewer.NEXT_PREV_IN_STREAM); + ISelection selection = waveformPane.getSelection(); + if(selection instanceof IStructuredSelection && !selection.isEmpty()){ + IStructuredSelection sel=(IStructuredSelection) selection; + if(sel.getFirstElement() instanceof ITx){ + ITx tx = (ITx) sel.getFirstElement(); + for(ITxRelation rel:tx.getIncomingRelations()){ + if(!res.contains(rel.getRelationType())) + res.add(rel.getRelationType()); + } + for(ITxRelation rel:tx.getOutgoingRelations()){ + if(!res.contains(rel.getRelationType())) + res.add(rel.getRelationType()); + } + } + } + return res; + } + + /** + * Gets the relation type filter. + * + * @return the relation type filter + */ + public RelationType getRelationTypeFilter() { + return navigationRelationType; + } + + /** + * Sets the navigation relation type. + * + * @param relationName the new navigation relation type + */ + public void setNavigationRelationType(String relationName) { + setNavigationRelationType(RelationType.create(relationName)); + } + + /** + * Sets the navigation relation type. + * + * @param relationType the new navigation relation type + */ + public void setNavigationRelationType(RelationType relationType) { + if(navigationRelationType!=relationType) waveformPane.setHighliteRelation(relationType); + navigationRelationType=relationType; + } + +} \ No newline at end of file