public boolean handleChange(Object oldValue, Object newValue, IFigure figure) { IPV oldPV = pvMap.get(pvNamePropID); if (oldPV != null) { oldPV.stop(); oldPV.removeListener(pvListenerMap.get(pvNamePropID)); } pvMap.remove(pvNamePropID); String newPVName = ((String) newValue).trim(); if (newPVName.length() <= 0) return false; try { lastWriteAccess = null; IPV newPV = BOYPVFactory.createPV(newPVName, isAllValuesBuffered); WidgetPVListener pvListener = new WidgetPVListener(pvNamePropID); newPV.addListener(pvListener); pvMap.put(pvNamePropID, newPV); pvListenerMap.put(pvNamePropID, pvListener); newPV.start(); } catch (Exception e) { OPIBuilderPlugin.getLogger() .log( Level.WARNING, "Unable to connect to PV:" + //$NON-NLS-1$ newPVName, e); } return false; }
public void doActivate() { if (editpart.getExecutionMode() == ExecutionMode.RUN_MODE) { pvMap.clear(); final Map<StringProperty, PVValueProperty> pvPropertyMap = editpart.getWidgetModel().getPVMap(); for (final StringProperty sp : pvPropertyMap.keySet()) { if (sp.getPropertyValue() == null || ((String) sp.getPropertyValue()).trim().length() <= 0) { continue; } try { IPV pv = BOYPVFactory.createPV((String) sp.getPropertyValue(), isAllValuesBuffered); pvMap.put(sp.getPropertyID(), pv); WidgetPVListener pvListener = new WidgetPVListener(sp.getPropertyID()); pv.addListener(pvListener); pvListenerMap.put(sp.getPropertyID(), pvListener); } catch (Exception e) { OPIBuilderPlugin.getLogger() .log( Level.WARNING, "Unable to connect to PV:" + (String) sp.getPropertyValue(), e); //$NON-NLS-1$ } } } }
@SuppressWarnings("deprecation") public void run(IAction action) { try { if (window == null) window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); final IWorkbenchPage page = window.getActivePage(); page.showView(IPageLayout.ID_RES_NAV); } catch (WorkbenchException e) { final String message = NLS.bind("Failed to open navigator. \n{0}", e.getMessage()); MessageDialog.openError(null, "Error", message); OPIBuilderPlugin.getLogger().log(Level.WARNING, message, e); } }
/** Start all PVs. This should be called as the last step in editpart.activate(). */ public void startPVs() { // the pv should be started at the last minute for (String pvPropId : pvMap.keySet()) { IPV pv = pvMap.get(pvPropId); try { pv.start(); } catch (Exception e) { OPIBuilderPlugin.getLogger() .log(Level.WARNING, "Unable to connect to PV:" + pv.getName(), e); // $NON-NLS-1$ } } }
/** * Render a new OPI in the same shell. The file path changes but the macros remain the same. Is * this correct? */ @Override public void setOPIInput(IEditorInput input) throws PartInitException { try { if (input instanceof IFileEditorInput) { this.path = ((IFileEditorInput) input).getFile().getFullPath(); } else if (input instanceof RunnerInput) { this.path = ((RunnerInput) input).getPath(); } displayModel = createDisplayModel(); setTitle(); resizeToContents(); } catch (Exception e) { OPIBuilderPlugin.getLogger().log(Level.WARNING, "Failed to replace OPIShell contents.", e); } }
@Override public void activate() { if (!isActive()) { super.activate(); initFigure(getFigure()); // add listener to all properties. for (String id : getWidgetModel().getAllPropertyIDs()) { AbstractWidgetProperty property = getWidgetModel().getProperty(id); if (property != null) { WidgetPropertyChangeListener listener = new WidgetPropertyChangeListener(this, property); property.addPropertyChangeListener(listener); propertyListenerMap.put(id, listener); property.setExecutionMode(executionMode); property.setWidgetModel(getWidgetModel()); } } registerBasePropertyChangeHandlers(); registerPropertyChangeHandlers(); if (executionMode == ExecutionMode.RUN_MODE) { // hook open display action Set<String> allPropIds = getWidgetModel().getAllPropertyIDs(); if (allPropIds.contains(AbstractWidgetModel.PROP_ACTIONS) && allPropIds.contains(AbstractWidgetModel.PROP_ENABLED)) { hookMouseClickAction(); } // script and rules execution ScriptsInput scriptsInput = getWidgetModel().getScriptsInput(); scriptDataList = new ArrayList<ScriptData>(scriptsInput.getScriptList()); for (RuleData rd : getWidgetModel().getRulesInput().getRuleDataList()) { scriptDataList.add(rd.convertToScriptData()); } for (final ScriptData scriptData : scriptDataList) { final IPV[] pvArray = new IPV[scriptData.getPVList().size()]; int i = 0; for (PVTuple pvTuple : scriptData.getPVList()) { String pvName = pvTuple.pvName; if (pvMap.containsKey(pvName)) { pvArray[i] = pvMap.get(pvName); } else { try { IPV pv = BOYPVFactory.createPV(pvName, false, 2); pvMap.put(pvName, pv); addToConnectionHandler(pvName, pv); pvArray[i] = pv; } catch (Exception e) { String message = NLS.bind( "Unable to connect to PV: {0}! \n" + "This may cause error when executing the script.", pvName); OPIBuilderPlugin.getLogger().log(Level.WARNING, message, e); ConsoleService.getInstance().writeError(message); pvArray[i] = null; } } i++; } ScriptService.getInstance() .registerScript(scriptData, AbstractBaseEditPart.this, pvArray); UIBundlingThread.getInstance() .addRunnable( new Runnable() { @Override public void run() { if (!isActive()) { // already deactivated return; } hasStartedPVs = true; for (IPV pv : pvArray) if (pv != null && !pv.isStarted()) try { pv.start(); } catch (Exception e) { OPIBuilderPlugin.getLogger() .log( Level.WARNING, "Unable to start PV " + pv.getName(), e); //$NON-NLS-1$ } } }); } } doActivate(); } // Rap specified code displayDisposeListener = new Runnable() { @Override public void run() { deactivate(); } }; SingleSourceHelper.rapActivateBaseEditPart(this); }
// Private constructor means you can't open an OPIShell without adding // it to the cache. private OPIShell(Display display, IPath path, MacrosInput macrosInput) throws Exception { this.path = path; this.macrosInput = macrosInput; icon = OPIBuilderPlugin.imageDescriptorFromPlugin( OPIBuilderPlugin.PLUGIN_ID, "icons/OPIRunner.png") .createImage(display); shell = new Shell(display); shell.setImage(icon); displayModel = new DisplayModel(path); displayModel.setOpiRuntime(this); actionRegistry = new ActionRegistry(); viewer = new GraphicalViewerImpl(); viewer.createControl(shell); viewer.setEditPartFactory(new WidgetEditPartFactory(ExecutionMode.RUN_MODE)); viewer.setRootEditPart( new ScalableFreeformRootEditPart() { @Override public DragTracker getDragTracker(Request req) { return new DragEditPartsTracker(this); } @Override public boolean isSelectable() { return false; } }); EditDomain editDomain = new EditDomain() { @Override public void loadDefaultTool() { setActiveTool(new RuntimePatchedSelectionTool()); } }; editDomain.addViewer(viewer); displayModel = createDisplayModel(); setTitle(); shell.setLayout(new FillLayout()); shell.addShellListener( new ShellListener() { private boolean firstRun = true; public void shellIconified(ShellEvent e) {} public void shellDeiconified(ShellEvent e) {} public void shellDeactivated(ShellEvent e) {} public void shellClosed(ShellEvent e) { // Remove this shell from the cache. openShells.remove(OPIShell.this); sendUpdateCommand(); } public void shellActivated(ShellEvent e) { if (firstRun) { // Resize the shell after it's open, so we can take into account different window // borders. // Do this only the first time it's activated. resizeToContents(); shell.setFocus(); firstRun = false; } } }); shell.addDisposeListener( new DisposeListener() { @Override public void widgetDisposed(DisposeEvent e) { if (!icon.isDisposed()) icon.dispose(); } }); /* * Don't open the Shell here, as it causes SWT to think the window is on top when it really isn't. * Wait until the window is open, then call shell.setFocus() in the activated listener. * * Make some attempt at sizing the shell, sometimes a shell is not given focus and the shellActivated * listener callback doesn't resize the window. It's better to have something a little too large as the * default. Related to Eclipse bug 96700. */ shell.setSize( displayModel.getSize().width + WINDOW_BORDER_X, displayModel.getSize().height + WINDOW_BORDER_Y); shell.setVisible(true); }
/** * An OPIShell is a CS-Studio OPI presented in an SWT shell, which allows more free integration with * the host operating system. In most ways it behaves like an OPIView. * * <p>All OPIShells are maintained in a static set within this class. To maintain a cache of all * shells, construction is limited to a static method. The private constructor means that this class * cannot be extended. * * <p>In order for the OPIShell to be integrated with Eclipse functionality, in particular the * right-click context menu, it needs to be registered against an existing IViewPart. * * @author Will Rogers, Matthew Furseman */ public final class OPIShell implements IOPIRuntime { // Estimates for the size of a window border, for how much // bigger to make a shell than the size of its contents. private static final int WINDOW_BORDER_X = 30; private static final int WINDOW_BORDER_Y = 30; private static Logger log = OPIBuilderPlugin.getLogger(); public static final String OPI_SHELLS_CHANGED_ID = "org.csstudio.opibuilder.opiShellsChanged"; // Cache of open OPI shells in order of opening. private static final Set<OPIShell> openShells = new LinkedHashSet<OPIShell>(); // The view against which the context menu is registered. private IViewPart view; // Variables that do not change for any shell. private final Image icon; private final Shell shell; private final ActionRegistry actionRegistry; private final GraphicalViewer viewer; // Variables that change if OPI input is changed. private DisplayModel displayModel; private IPath path; // macrosInput should not be null. If there are no macros it should // be an empty MacrosInput object. private MacrosInput macrosInput; // Private constructor means you can't open an OPIShell without adding // it to the cache. private OPIShell(Display display, IPath path, MacrosInput macrosInput) throws Exception { this.path = path; this.macrosInput = macrosInput; icon = OPIBuilderPlugin.imageDescriptorFromPlugin( OPIBuilderPlugin.PLUGIN_ID, "icons/OPIRunner.png") .createImage(display); shell = new Shell(display); shell.setImage(icon); displayModel = new DisplayModel(path); displayModel.setOpiRuntime(this); actionRegistry = new ActionRegistry(); viewer = new GraphicalViewerImpl(); viewer.createControl(shell); viewer.setEditPartFactory(new WidgetEditPartFactory(ExecutionMode.RUN_MODE)); viewer.setRootEditPart( new ScalableFreeformRootEditPart() { @Override public DragTracker getDragTracker(Request req) { return new DragEditPartsTracker(this); } @Override public boolean isSelectable() { return false; } }); EditDomain editDomain = new EditDomain() { @Override public void loadDefaultTool() { setActiveTool(new RuntimePatchedSelectionTool()); } }; editDomain.addViewer(viewer); displayModel = createDisplayModel(); setTitle(); shell.setLayout(new FillLayout()); shell.addShellListener( new ShellListener() { private boolean firstRun = true; public void shellIconified(ShellEvent e) {} public void shellDeiconified(ShellEvent e) {} public void shellDeactivated(ShellEvent e) {} public void shellClosed(ShellEvent e) { // Remove this shell from the cache. openShells.remove(OPIShell.this); sendUpdateCommand(); } public void shellActivated(ShellEvent e) { if (firstRun) { // Resize the shell after it's open, so we can take into account different window // borders. // Do this only the first time it's activated. resizeToContents(); shell.setFocus(); firstRun = false; } } }); shell.addDisposeListener( new DisposeListener() { @Override public void widgetDisposed(DisposeEvent e) { if (!icon.isDisposed()) icon.dispose(); } }); /* * Don't open the Shell here, as it causes SWT to think the window is on top when it really isn't. * Wait until the window is open, then call shell.setFocus() in the activated listener. * * Make some attempt at sizing the shell, sometimes a shell is not given focus and the shellActivated * listener callback doesn't resize the window. It's better to have something a little too large as the * default. Related to Eclipse bug 96700. */ shell.setSize( displayModel.getSize().width + WINDOW_BORDER_X, displayModel.getSize().height + WINDOW_BORDER_Y); shell.setVisible(true); } /** * In order for the right-click menu to work, this shell must be registered with a view. Register * the context menu against the view. Make the view the default. * * @param view */ public void registerWithView(IViewPart view) { this.view = view; actionRegistry.registerAction(new RefreshOPIAction(this)); SingleSourceHelper.registerRCPRuntimeActions(actionRegistry, this); OPIRunnerContextMenuProvider contextMenuProvider = new OPIRunnerContextMenuProvider(viewer, this); getSite().registerContextMenu(contextMenuProvider, viewer); viewer.setContextMenu(contextMenuProvider); } public MacrosInput getMacrosInput() { return macrosInput; } public IPath getPath() { return path; } public void raiseToTop() { shell.forceFocus(); shell.forceActive(); shell.setFocus(); shell.setActive(); } @Override public boolean equals(Object o) { boolean equal = false; if (o instanceof OPIShell) { OPIShell opiShell = (OPIShell) o; equal = opiShell.getMacrosInput().equals(this.getMacrosInput()); equal &= opiShell.getPath().equals(this.path); } return equal; } public void close() { shell.close(); dispose(); } private DisplayModel createDisplayModel() throws Exception { displayModel = new DisplayModel(path); XMLUtil.fillDisplayModelFromInputStream(ResourceUtil.pathToInputStream(path), displayModel); if (macrosInput != null) { macrosInput = macrosInput.getCopy(); macrosInput.getMacrosMap().putAll(displayModel.getMacrosInput().getMacrosMap()); displayModel.setPropertyValue(AbstractContainerModel.PROP_MACROS, macrosInput); } viewer.setContents(displayModel); displayModel.setViewer(viewer); displayModel.setOpiRuntime(this); return displayModel; } private void setTitle() { if (displayModel.getName() != null && displayModel.getName().trim().length() > 0) { shell.setText(displayModel.getName()); } else { // If the name doesn't exist, use the OPI path shell.setText(path.toString()); } } private void resizeToContents() { int frameX = shell.getSize().x - shell.getClientArea().width; int frameY = shell.getSize().y - shell.getClientArea().height; shell.setSize(displayModel.getSize().width + frameX, displayModel.getSize().height + frameY); } /** * *********************************************************** Static helper methods to manage * open shells. *********************************************************** */ /** This is the only way to create an OPIShell */ public static void openOPIShell(IPath path, MacrosInput macrosInput) { if (macrosInput == null) { macrosInput = new MacrosInput(new LinkedHashMap<String, String>(), false); } boolean alreadyOpen = false; for (OPIShell opiShell : openShells) { if (opiShell.getPath().equals(path) && opiShell.getMacrosInput().equals(macrosInput)) { opiShell.raiseToTop(); alreadyOpen = true; } } if (!alreadyOpen) { OPIShell os = null; try { os = new OPIShell(Display.getCurrent(), path, macrosInput); openShells.add(os); sendUpdateCommand(); } catch (Exception e) { if (os != null) { os.dispose(); } log.log(Level.WARNING, "Failed to create new OPIShell.", e); } } } /** * Close all open OPIShells. Use getAllShells() for a copy of the set, to avoid removing items * during iteration. */ public static void closeAll() { for (OPIShell s : getAllShells()) { s.close(); } } /** Show all open OPIShells. */ public static void showAll() { for (OPIShell s : getAllShells()) { s.raiseToTop(); } } /** * Search the cache of open OPIShells to find a match for the input Shell object. * * <p>Return associated OPIShell or Null if none found */ public static OPIShell getOPIShellForShell(final Shell target) { OPIShell foundShell = null; if (target != null) { for (OPIShell os : openShells) { if (os.shell == target) { foundShell = os; break; } } } return foundShell; } /** * Return a copy of the set of open shells. Returning the same instance may lead to problems when * closing shells. * * @return a copy of the set of open shells. */ public static Set<OPIShell> getAllShells() { return new LinkedHashSet<OPIShell>(openShells); } /** Alert whoever is listening that a new OPIShell has been created. */ private static void sendUpdateCommand() { IServiceLocator serviceLocator = PlatformUI.getWorkbench(); ICommandService commandService = (ICommandService) serviceLocator.getService(ICommandService.class); try { Command command = commandService.getCommand(OPI_SHELLS_CHANGED_ID); command.executeWithChecks(new ExecutionEvent()); } catch (ExecutionException | NotHandledException | NotEnabledException | NotDefinedException e) { log.log(Level.WARNING, "Failed to send OPI shells changed command", e); } } /** * ****************************************** Partial implementation of IOPIRuntime * ****************************************** */ @Override public void addPropertyListener(IPropertyListener listener) { throw new NotImplementedException(); } @Override public void createPartControl(Composite parent) { throw new NotImplementedException(); } @Override public void dispose() { shell.dispose(); actionRegistry.dispose(); } @Override public IWorkbenchPartSite getSite() { if (view != null) { return view.getSite(); } else { return null; } } @Override public String getTitle() { return shell.getText(); } @Override public Image getTitleImage() { throw new NotImplementedException(); } @Override public String getTitleToolTip() { return shell.getToolTipText(); } @Override public void removePropertyListener(IPropertyListener listener) { throw new NotImplementedException(); } @Override public void setFocus() { throw new NotImplementedException(); } @SuppressWarnings("rawtypes") @Override public Object getAdapter(Class adapter) { if (adapter == ActionRegistry.class) return this.actionRegistry; if (adapter == GraphicalViewer.class) return this.viewer; return null; } @Override public void setWorkbenchPartName(String name) { throw new NotImplementedException(); } /** * Render a new OPI in the same shell. The file path changes but the macros remain the same. Is * this correct? */ @Override public void setOPIInput(IEditorInput input) throws PartInitException { try { if (input instanceof IFileEditorInput) { this.path = ((IFileEditorInput) input).getFile().getFullPath(); } else if (input instanceof RunnerInput) { this.path = ((RunnerInput) input).getPath(); } displayModel = createDisplayModel(); setTitle(); resizeToContents(); } catch (Exception e) { OPIBuilderPlugin.getLogger().log(Level.WARNING, "Failed to replace OPIShell contents.", e); } } @Override public IEditorInput getOPIInput() { IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(displayModel.getOpiFilePath()); return new FileEditorInput(file); } @Override public DisplayModel getDisplayModel() { return displayModel; } @Override public int hashCode() { return Objects.hash(OPIShell.class, macrosInput, path); } }