November 25, 2014
Hot Topics:

Programming the Eclipse Workbench

  • March 7, 2006
  • By Peter Nehrer
  • Send Email »
  • More Articles »

Editor's Object Model

While the editor's input is very simple — a list of unique strings — and could be represented by one of Java's collection classes, a feature is required that these classes don't provide — you want to be notified whenever the model changes (e.g., elements are added or removed). Thus, create a simple wrapper equipped with listener/event mechanism, which will allow any interested party to register themselves as a listener and be notified (via a custom event) whenever changes are made to the underlying list.

You would be correct in concluding that you could just as easily maintain an instance of ArrayList internal to the editor, provide access to it only via editor's public methods, and in those methods track any changes to the list. However, models accompanied by a listener/event notification mechanism are more flexible (e.g., may be used outside of an editor context) and their use is wide-spread throughout Eclipse.

Now, the content provider can be implemented, which both converts the object model into a list of string elements (suitable for displaying in the ListViewer) and updates the viewer whenever changes are detected in the model (this part is accomplished by registering the content provider as the model's listener whenever the input changes).

Finishing the Minimal Implementation

A few methods in the editor class remain to be implemented. For simplicity, the "Save As" functionality is not going to be supported, and thus false from method isSaveAsAllowed will always be returned. Saving back to the original input, however, will be supported, and thus the method doSave(IProgressMonitor) will be implemented. Its body is rather trivial — write the model's elements into a flat text file, each on its own line. However, one important protocol that you need to support here is the editor's "dirty" state; recall that an editor is in this state when it contains unpersisted data that will be lost when the application closes. Our editor implementation is required to maintain this state (and provide it via method isDirty), and notify any interested listeners (via their IPropertyListener interface) whenever this state changes. When a save is successful, the editor should no longer be dirty; thus, we should set our internal flag to false and fire a property change event (with ID PROP_DIRTY) to indicate the change. The doSave method may only be called when the editor is in fact dirty, and so we don't have to check if the state did in fact change.

Contributing Editor Actions

To implement the action bar contributor for the editor, you must go back to the Plug-in Manifest Editor and in the extension's details section, click the "contributorClass" label (which looks like a hyperlink). This class instantiates all actions in its constructor and contributes them to their respective action bars: the Add action is appended to the top-level Edit menu (since it already has similar Add actions), and the Delete, Undo, and Redo actions is set as "global action" handles. What this means is that whenever this contributor is active, it will provide its own implementations of the global Delete, Undo, and Redo actions defined by the Workbench and accessible in the Edit menu as well as through keyboard shortcuts.

Regardless of its particular function, each action class you implement must be aware of its "target" editor instance; that is, the particular editor with which it is to interact. The contributor is notified whenever an editor instance becomes active in its setActiveEditor(IEditorPart) method; thus, you propagate this notification to each action instance and allow it to respond accordingly.

Using Operation History

Now that you have the right infrastructure in place, you can implement each action class. The Add action is the simplest — all it needs to do is solicit input from the user (for example, using the JFace InputDialog) and add it to the active editor's model, if appropriate. Similarly, the Delete action needs to remove the elements currently selected in the active editor. However, Delete should be disabled when there are no selected elements. Thus, this action must be aware of the active editor's selection changes. You can accomplish that by exposing the editor's viewer selection via the ISelectionProvider interface and registering the Delete action as a ISelectionChangedListener on the active editor instance.

While you could implement the above actions to perform their functions directly on the active editor's model, you would run into a problem: how would Undo and Redo be implemented? These two actions don't provide any model-specific functionality; all they need to do is undo the last action, or redo the action that was last undone, whatever it may be. Ideally, they would be able to undo and redo multiple actions, not just one.

Because this is a frequently encountered problem in interactive applications with editing capabilities, the Workbench provides IWorkbenchOperationSupport, which is a service that allows the application to represent its user invokable actions in a command-like pattern and use the IOperationHistory to execute, undo, and redo them. This service is rather flexible and I won't go into much detail beyond what's necessary for this exercise. In short, the functionality of Add and Delete is encapsulated in the respective IUndoableOperation, which knows how to execute, undo, and redo itself. The actions simply execute the operation in the editor's undo context and allow the Undo and Redo actions to navigate the operation history as required. As the last bit, you register the editor itself as an operation history listener and mark it dirty whenever there is an unsaved operation in its context.

Test-Running the Editor

To see the results, run the plug-in as an Eclipse Application. When the runtime workbench appears, switch to the Resource Perspective (though you can use any other perspective with a view that allows you to manipulate your Workspace). Create a new, simple project, and in it a simple file with extension ".list". This will cause a new, empty file to be created and opened in the List Editor we just developed. You should now be able to add elements using the "Add List Element..." action in the main Edit menu, and delete them (when selected) using the Del key. You can also save and re-open the modified files.

One oddity you may notice is that the Content Outline view, usually present in most perspectives by default, displays a message stating that the outline is not available. As its name indicates, this view is used to present a concise outline of the active editor's contents. In order to do this, the editor must provide a special adapter whose job it is to display an editor-specific outline. We did not develop one in this article, mostly because our content model cannot get any simpler than a list, and thus the outline itself would have to be nothing more than a list. For more information about this feature, see class ContentOutline.

Conclusion

The Eclipse Workbench serves as a reusable foundation for developing desktop applications. It consists mainly of views and editors, commonly referred to as Workbench Parts. Views and editors expose their functionality as actions, which they contribute to their respective action bars. As an example, you were shown how to develop a simple editor for manipulating a list of elements, with support for global actions and undoable operations.

Resources

About the Author

Peter Nehrer is an independent software consultant living in Toronto, Ontario. He specializes in Eclipse-based enterprise solutions and J2EE applications. His professional interests include development tools, model-driven software development, and information sharing. He is the author and contributor to several Eclipse-related Open Source projects. Peter is an IBM Certified Solutons Developer for XML and related technologies. He holds an M.S. in Computer Science from the University of Massachusetts at Amherst, MA.





Page 3 of 3



Comment and Contribute

 


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

 

 


Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Sitemap | Contact Us

Rocket Fuel