April 23, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

The (J)Face of Eclipse, Page 3

  • November 17, 2005
  • By Peter Nehrer
  • Send Email »
  • More Articles »

Method inputChanged(Viewer, Object, Object) notifies the provider that the given viewer changed its input (both old and new are given). This happens as a result of calling the viewer's setInput(Object) method. The content provider may use this method to add itself as a listener of the new input object, if required, and the model's API supports it, to be able to react to any changes in the model. When such changes are detected, the content provider updates the viewer accordingly (for example, by inserting new elements and/or removing deleted ones). However, in this example you assume the model is static and you do not need to monitor its changes.

The dispose() method gives the content provider a chance to clean up any resources it may have used up. You don't need to do anything here, either. Method getElements(Object) comes from IStructuredContentProvider, a supertype of ITreeContentProvider, and your implementation simply delegates to getChildren(Object).

Listing 1: Implementing ITreeContentProvider

public Object[] getChildren(Object parentElement) {
   if (parentElement instanceof IViewCategory) {
      Object[] children = ((IViewCategory) parentElement).getViews();
      mapChildrenToParent(children, parentElement);
      return children;
   }

   if (parentElement instanceof IViewRegistry)
      return ((IViewRegistry) parentElement).getCategories();

   return EMPTY_ARRAY;
}

public Object getParent(Object element) {
   if (element instanceof IViewDescriptor)
      return parentMap == null ? null : parentMap.get(element);

   if (element instanceof IViewCategory)
      return registry;

   return null;
}

public boolean hasChildren(Object element) {
   return getChildren(element).length > 0;
}

Your label provider implementation remains largely the same, except it now has to handle elements of type IViewCategory, in addition to IViewDescriptors. You will notice that you use a shared workbench image for categories (all share the same one). You obtain this image directly from the workbench registry of shared images, which means that you don't have to manage its disposal (in fact, you must not dispose it because you don't create it yourself).

You continue to use the default ViewerSorter, which sorts your elements according to their displayed labels using the default text collator. Lastly, you set the workbench view registry as the viewer's input because that is the model your content provider implementation understands.

Interacting with Superview

You want to allow the user to interact with your Superview—show the selected view, display its properties in a dialog box, and use a multi-page wizard to show the view in another window. You also want to support the optional exclusion of Superview from the displayed list of views. To accomplish this, you use a combination of viewer listeners and actions.

First, you install an IOpenListener on the viewer to be notified of its "open" events. These occur whenever the user double-clicks an entry in the viewer (or single-clicks it, depending on their workbench configuration), or hits the Enter key when the viewer has input focus and its selection is not empty. You react to these events by first obtaining the viewer's selection (you know it's an IStructuredSelection because that is what StructuredViewers work with), and determining the type of its first element (there will never be more than element because you don't explicitly configure the viewer to allow multi-element selections). If the selected element is an IViewDescriptor, you show its corresponding view in the current workbench window (the details of this operation are not relevant right now). When an IViewCategory is selected, you either expand or collapse it, depending on its current state (doing this, I believe, makes the tree viewer behave more intuitively; otherwise, the user would always have to click the +/- sign to expand/collapse categories).

Listing 2: Installing IOpenListener

viewer.addOpenListener(new IOpenListener() {]
   public void open(OpenEvent event) {]
      IStructuredSelection sel =
         (IStructuredSelection) event.getSelection();
      Object element = sel.getFirstElement();
      if (element instanceof IViewDescriptor)
         showView((IViewDescriptor) element);
      else if (element instanceof IViewCategory) {
         if (viewer.getExpandedState(element))
             viewer.collapseToLevel(element, TreeViewer.ALL_LEVELS);
      else
         viewer.expandToLevel(element, 1);
      }
   }
});

Most Eclipse users are accustomed to the power of the context menu—right-clicking anything onscreen usually brings up a menu with all possible operations relevant in the given context. Therefore, you add a context menu to the Superview as well. You do this with the help of a JFace class, the MenuManager, that handles the creation and population of the actual context menu widget. Each menu option is backed by a JFace Action, which performs its actual function.

Because your context menu options are only applicable when a view is selected (not when a category is selected), you have to enable or disable them based on the viewer's selection. Eclipse UI provides a convenience action class named BaseSelectionListenerAction (this is not strictly JFace, but that's good enough for this example), which can act as a listener to viewers' selection changes, and enable/disable itself based on current selection. You use this class to implement your context menu actions. For convenience, you put the selection-based enablement logic, as well as extraction of an IViewDescriptor from the selection in an abstract nested class named SelectedViewAction, which extends BaseSelectionListenerAction; you then subclass this one to implement each particular action.

An alternative approach to enabling/disabling context menu options based on selection would be to rebuild the menu each time it is shown. To do that, you would configure the menu manager to remove all menu items from the menu before it is shown, and install a menu listener that would add only the relevant menu options back to the menu.

Your actions must be instantiated before you can populate the context menu. You instantiate each selection-dependent action as an anonymous subclass of SelectedViewAction, passing its menu label (with the designated accelerator character prefixed with an ampersand) to its constructor. The run method of your "show view" action does the same as the IOpenListener—it shows the selected view in the current workbench window. I'll get back to the details of the other two actions—"show in window" and "view properties"—after you implement the required dialog and wizard. Lastly, you install each action as the viewer's selection change listener and manually invoke its selectionChanged method using the viewer's current selection, to initialize its enablement.

The last feature on your list, optional exclusion of the Superview from its own contents, does not depend on any selection. Therefore, it is not necessary to create its action as a subclass of SelectedViewAction; the plain Action will suffice. Note that you instantiate it with the checkbox style, so that it appears in the menu as checked/unchecked, depending on its state; in its run method, you use this "checked" state to determine whether to add or remove the filter. The filter itself is a subclass of ViewerFilter, instantiated lazily in the addSuperviewFilter method. It only allows elements other than the one that represents your Superview (in other words, an IViewDescriptor with an ID that equals the Superview's ID). Note also that filters are added, rather than set, which means that it is possible to have multiple filters installed in any given viewer.

Finally, you populate the context menu by simply adding each action to the menu manager instance—the manager creates the corresponding menu contribution item on your behalf. Lastly, you call the manager's createContextMenu(Control) method to create the actual menu widget and set it as the viewer's context menu.

Listing 3: Actions and context menu creation

SelectedViewAction showViewAction =
   new SelectedViewAction("Sh&ow") {
      protected void run(IViewDescriptor view) {
         showView(view);
      }
};

viewer.addSelectionChangedListener(showViewAction);
showViewAction.selectionChanged((IStructuredSelection)
   viewer.getSelection());

// ...

MenuManager contextMenuManager = new MenuManager();
contextMenuManager.add(showViewAction);
// ...

Menu contextMenu =
   contextMenuManager.createContextMenu(viewer.getTree());
viewer.getTree().setMenu(contextMenu);




Page 3 of 5



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel