Chapter 21. Data Exchange within CSS

Table of Contents

CSS Data Types
Context Menu Contributions
Drag-and-Drop

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.

CSS Data Types

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.

Context Menu Contributions

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.

Use or Adapt to CSS Types

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.

Allow additions to the context menu

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));

Contributing to context menus

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>

Handling the invocation from a context menu

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, ...

Drag-and-Drop

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.

Drag Source, Drop Target

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);
  }
};

Common Pitfalls

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;
   }
};