Table of Contents
Maybe the biggest difference between arbitrary RCP plugins and CSS code is the use of common data types, allowing for exchange of these data types via context menus or drag-and-drop. This chapter explains some of the underlying details for those who want to implement their own plugin code that links to CSS.
The plugin org.csstudio.csdata
defines
control system data types like ProcessVariable
,
a class that holds the name of a PV.
By using this data type, CSS code can distinguish PV names
from arbitrary strings.
Applications can define context menus. For example, when the user right-clicks on the list of traces in the Data Browser configuration, a context menu appears that allows operations like adding a trace, removing the selected trace etc.
One very powerful aspect of RCP is the way it allows code to contribute to context menus of other application code. For example, the Data Browser configuration panel defines a context menu with entries for editing the configuration of the current data browser. For those data browser traces that are based on PVs, the context menu will include links to other CSS tools that are capable of handling PVs. The underlying mechanism works as follows.
The application has to provide data in the form of
common CSS data types like ProcessVariable
.
It can do that by directly using these data types,
but in reality the data model of an application probably needs to
store additional information, for example a PV name with color and other
attributes. In that case it needs to implement an Eclipse adapter via
the extension point
org.eclipse.core.runtime.adapters
from its internal
model data types to CSS data types like ProcessVariable
.
When defining a context menu, all RCP applications are encouraged to include one item named "additions" that can be used by other RCP plugins to extend the context menu:
MenuManager menu = .... my menu ...; menu.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
The plugin org.csstudio.ui.menu
defines a context menu
with ID org.csstudio.ui.menu.popup.processvariable
that is automatically added to all context menus
where the selection adapts to a CSS ProcessVariable
.
If you want your tool to appear in such menus, you need to hook into the
PV context menu with mark-up similar to the following:
<!-- Your plugin.xml --> <extension point="org.eclipse.ui.menus"> <menuContribution locationURI="popup:org.csstudio.ui.menu.popup.processvariable"> <command commandId="org.csstudio.my_app.OpenMyTool" icon="icons/my_app.gif" style="push"> </command> </menuContribution> </extension>
This defines a command for the PV context menu. The command is further linked to the actual implementation (handler):
<extension point="org.eclipse.ui.commands"> <command id="org.csstudio.my_app.OpenMyTool" defaultHandler="org.csstudio.my_app.OpenMyTool"> </command> </extension>
Finally, you implement the handler that will be invoked from the context menu like this to receive for example the PV names:
package org.csstudio.my_app; public class OpenMyTool extends AbstractHandler { @Override public Object execute(final ExecutionEvent event) throws ExecutionException { final ISelection selection = HandlerUtil.getActiveMenuSelection(event); final ProcessVariable[] pvs = AdapterUtil.convert(selection, ProcessVariable.class); // Open my view, display the PVs, ...
Eclipse provides Drag-and-Drop support for data types like text and file names.
CSS adds Drag-and-Drop support for any data type that is Serializable
.
The data types from the section called “CSS Data Types” like ProcessVariable
are already
Serializable
, so application code that uses the CSS data types or adapts to
them can easily participate in Drag-and-Drop data exchange.
Drag-and-Drop is also possible within an application via data types that are only used
within that application as long as they are Serializable
.
As a minimum denominator, data can be exchanged as text, which can be useful when interfacing
with non-CSS applications.
The plugin org.csstudio.ui.util
offers helper classes
ControlSystemDragSource
and ControlSystemDropTarget
that allow “dragging” respectively “dropping” of any data type
that supports serialization:
ProcessVariable pv = new ProcessVariable("Fred"); // Assume view somehow displays the pv TableView view = ...; // Allow dragging the PV out of the view new ControlSystemDragSource(view.getControl()) { public Object getSelection() { return pv; } };
// Other control that should allow dropping a PV Control ctl = ...; new ControlSystemDropTarget(ctl, ProcessVariable.class, String.class) { public void handleDrop(final Object item) { if (item instanceof ProcessVariable) ctl.setText(((ProcessVariable) item).getName()); else ctl.setText((String) item); } };
When adding Drag-and-Drop support to an application plugin, it can be helpful
to enable detailed logging.
The warning “Serialization failed” because of a NotSerializableException
indicates that the data passed to the ControlSystemDragSource
is not fully
serializable. Maybe the class itself was marked as implementing Serializable
,
but one or more member variables are using non-serializable objects.
If the “De-Serialization fails” because of a ClassNotFoundException
,
the reason could be that the class used for the transfer is not visible outside the
plugin that defines it.
The code that performs the data transfer is in the plugin org.csstudio.ui.util
.
It can only de-serialize data with known object types.
If your plugin defines a new data type MyDataType implements Serializable
,
you also need to list its package name in the Export-Package
section of your plugin
MANIFEST.MF
.
In addition, the package name of your data type must start with the plugin name, because
the package name is used to determine which plugin class loader to use to create the de-serialized
data instance.
Even if you only plan to drag-and-drop data between views within one and the same plugin, all
custom data types used for those transfers must be visible to the plugin org.csstudio.ui.util
.
When transferring array data types, care must be taken to provide instances of the actual data type for the array like
new MyDataType[] { new MyDataType(), new MyDataType() }
The transfer will fail when sending an object array, even if it contains only instances of the supported data type:
new Object[] { new MyDataType(), new MyDataType() }
When dragging the currently selected data out of a JFace Viewer
, it may thus be
necessary to convert the selection before passing it to the drag source:
new ControlSystemDragSource(viewer.getControl()) { public Object getSelection() { final IStructuredSelection selection = (IStructuredSelection) viewer.getSelection(); final Object[] objs = selection.toArray(); final ProcessVariable[] pvs = Arrays.copyOf(objs, objs.length, ProcessVariable[].class); return pvs; } };