Eclipse Plug-in Development:Beginner's Guide(Second Edition)
上QQ阅读APP看书,第一时间看更新

Time for action – adding a double-click listener

Typically, a tree view is used to show content in a hierarchical manner. However, a tree on its own is not enough to be able to show all the details associated with an object. When the user double-clicks on an element, more details can be shown.

  1. At the end of the create method in TimeZoneTreeView, register a lambda block that implements the IDoubleClickListener interface with the addDoubleClickListener method on the treeViewer. As with the example in Chapter 1, Creating Your First Plug-in, this will open a message dialog to verify that it works as expected:
    treeViewer.addDoubleClickListener(event -> {
        Viewer viewer = event.getViewer();
        Shell shell = viewer.getControl().getShell();
        MessageDialog.openInformation(shell, "Double click",
         "Double click detected");
    });
  2. Run the target Eclipse instance, and open the Time Zone Tree View. Double-click on the tree, and a shell will be displayed with the message Double click detected. The dialog is modal and prevents other components in the user interface from being selected until it is dismissed.
  3. To find the selected objects, a viewer returns an ISelection interface (which only provides an isEmpty method) and an IStructuredSelection (which provides an iterator and other accessor methods). There are also a couple of specialized subtypes, such as ITreeSelection, which can be interrogated for the path that led to the selection in the tree. In the create method of the TimeZoneTreeView class, where the doubleClick method of the DoubleClickListener lambda is present, replace the MessageDialog as follows:
    // MessageDialog.openInformation(shell, "Double click",
    //  "Double click detected");
    ISelection sel = viewer.getSelection();
    Object selectedValue;
    if (!(sel instanceof IStructuredSelection) || sel.isEmpty()) {
      selectedValue = null;
    } else {
      selectedValue = ((IStructuredSelection)sel).getFirstElement();
    }
    if (selectedValue instanceof ZoneId) {
      ZoneId timeZone = (ZoneId)selectedValue;
      MessageDialog.openInformation(shell, timeZone.getId(),
       timeZone.toString());
    }
  4. Run the Eclipse instance, and open the Time Zone Tree View. Double-click on the tree, and a shell will be displayed with the ZoneId string representation.
  5. To display more information about the ZoneId in the displayed window, create a subclass of MessageDialog called TimeZoneDialog in the com.packtpub.e4.clock.ui.internal package:
    public class TimeZoneDialog extends MessageDialog {
      private ZoneId timeZone;
      public TimeZoneDialog(Shell parentShell, ZoneId timeZone) {
        super(parentShell, timeZone.getId(), null, "Time Zone "
         + timeZone.getId(), INFORMATION,
         new String[] { IDialogConstants.OK_LABEL }, 0);
         this.timeZone = timeZone;
      }
    }
  6. The TimeZoneDialog content is created in the createCustomArea method, which can be implemented as follows:
    protected Control createCustomArea(Composite parent) {
      ClockWidget clock =
       new ClockWidget(parent,SWT.NONE, new RGB(128,255,0));
      return parent;
    }
  7. Finally, change the TimeZoneTreeView call to MessageDialog.open() to use the TimeZoneDialog instead:
    if (selectedValue instanceof ZoneId) {
      ZoneId timeZone = (ZoneId) selectedValue;
      // MessageDialog.openInformation(shell, timeZone.getID(),
      // timeZone.toString());
      new TimeZoneDialog(shell, timeZone).open();
    }
  8. Run the Eclipse instance, double-click on a time zone, and the dialog should appear:

What just happened?

A double-click listener was added to the viewer by registering it with addDoubleClickListener. Initially, a standard information dialog was displayed; but then a custom subclass of MessageDialog was used which included a ClockWidget. In order to get the appropriate ZoneId, it was accessed via the currently selected object from the TreeViewer.

Selection handled by viewers is managed through an ISelection interface. The viewer's getSelection method should always return a non-null value, although it may be isEmpty. There are two relevant sub-interfaces: IStructuredSelection and ITreeSelection.

The ITreeSelection interface is a subtype of IStructuredSelection, which adds methods specific to trees. This includes the ability to find out what the selected object(s) and their parents are in the tree.

The IStructuredSelection interface is the most commonly used interface when dealing with selection types for viewers. If the selection is not empty, it is almost always an instance of an IStructuredSelection. As a result, the following snippet of code appears regularly:

ISelection sel = viewer.getSelection();
Object selectedValue;
if (!(sel instanceof IStructuredSelection) || sel.isEmpty()) {
  selectedValue = null;
} else {
  selectedValue = ((IStructuredSelection)sel).getFirstElement();
}

This snippet gets the selection from the viewer, and if it's not an IStructuredSelection, or it's empty, assigns null to selectedValue. If it's not empty, it casts it to IStructuredSelection and calls getFirstElement to get the single selected value.

Note that the selection may have more than one selected value, in which case the getFirstElement only returns the first selected element. IStructuredSelection provides an iterator to step through all selected objects.

Pop quiz – understanding interaction

Q1. How can TreeViewer instances be made to respond to a click?

Q2. Why are Dialog subclasses created?