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

Time for action – responding to selection changes

When the selection is changed in the E4 selection service, parts can be notified that a new selection is available through injection. Although an @Inject field could be used, there would be no trigger that could be used to update the view. Instead, a method with an injected parameter will be used to trigger the update.

  1. Add the required packages to the bundle's package imports, by right-clicking on the com.packtpub.e4.clock.ui project and navigating to Plug-in Tools | Open Manifest to open the bundle's manifest. On the Dependencies tab, click on Add under the Imported Packages section and enter org.eclipse.e4.ui.services.
  2. In the TimeZoneTableView class, create a method called setTimeZone. The method name isn't specifically important, but the method needs to be annotated with @Inject and @Optional, and the argument needs to be annotated with @Named(IServiceConstants.ACTIVE_SELECTION). It should look like:
    @Inject
    @Optional
    public void setTimeZone(
     @Named(IServiceConstants.ACTIVE_SELECTION) ZoneId timeZone) {
    }
  3. In the method, if the selection is not null, set the value on the tableViewer using the setSelection method. Since this takes an ISelection type, wrap the selected TimeZone within a StructuredSelection instance as follows:
    if (timeZone != null) {
      // NOTE may generate a NullPointerException
      tableViewer.setSelection(new StructuredSelection(timeZone));
      tableViewer.reveal(timeZone);
    }
  4. If the application is run, a NullPointerException will be thrown from inside the setSelection call, which indicates that the tableViewer variable is null. The reason is because the call to set the time zone occurs before the @PostConstruct annotated method is called, so the tableViewer has not been instantiated yet. The solution is to ignore selection events when the viewer has not been constructed, by adding a guard to the surrounding if block that checks to see that the tableViewer is not null:
    if (timeZone != null && tableViewer != null) {
      tableViewer.setSelection(new StructuredSelection(timeZone));
      tableViewer.reveal(timeZone);
    }
  5. Now when the application is run, and a time zone is selected in the Time Zone Tree View, the corresponding object should be selected in the Time Zone Table View.

What just happened?

The selected object is stored in the E4 scope, with the key specified in the IServiceConstants.ACTIVE_SELECTION constant. When the selection changes, the setTimeZone method is automatically called. To prevent problems with propagating empty selections, if the selected value is null then it is not forwarded on.

Since the selection can change and be set at any time, including before the part is fully constructed, it is necessary to guard the code to ignore selections if the viewer is null.

The treeViewer expects a value of type ISelection, so the time zone is wrapped in a StructuredSelection instance, and then passed to the treeViewer. The reveal step is optional, and will focus the viewer on the selected object if it is available.

Have a go hero – adding selection support to the table view

Now that the selection works from the tree viewer to the table viewer, try the following:

  • Add a setTimeZone method to the TimeZoneTreeViewer to allow the selection to display items in the tree viewer.
  • Add a SelectionChangeListener to the TimeZoneTableViewer so that a selection in the table view will trigger a change in other views.
  • In the setTimeZone methods, check that the tableViewer hasn't been disposed as well as the null check.
  • To prevent calls to the setTimeZone method from taking effect before the viewer has been constructed, assign the viewer to a local variable in the corresponding @PostContstruct method first, and then at the end of the method assign the local variable to the field.
  • Create a standard StructuredChangeListener class that can forward selection events to a generic JFace viewer which can be re-used.
  • Convert the optional ESelectionService with a non-optional Provider<ESelectionService>, and use the get method to acquire the selection service on demand or pass it into the generic class created in the previous step.

Pop quiz – understanding selection

Q1. How do viewers work with selected objects?

Q2. What event listener is used to receive notifications of a viewer's selection updates?

Q3. What service is used in E4 to maintain the selected object in the current window?

Q4. How does the selected object in E4 get propagated to parts?