The Pliny NoteEditor is expressed in Eclipse as an Eclipse workbench EditorPart (note that, although the names are similar, the GEF EditPart and the workbench EditorPart are entirely different things!), but a few other classes participate in making the NoteEditor operate. Furthermore, the NoteEditor has to appear in the plugin's plugin.xml file so that the workbench as a whole knows about the editor and knows how to invoke and present it.
NoteEditor in plugin.xml
Here is one of the two fragments of the plugin.xml file that refers to the NoteEditor:
<extension point="org.eclipse.ui.editors"> <editor class="uk.ac.kcl.cch.jb.pliny.editors.NoteEditor" contributorClass="uk.ac.kcl.cch.jb.pliny.editors.NoteEditorActionBarContributor" default="false" icon="icons/noteIcon.gif" id="uk.ac.kcl.cch.jb.pliny.noteEditor" name="Note Editor"/> [...]
It is outside of the scope of this document to describe the details of this material too closely here. You should consult Eclipse documentation for further details. However, a few basic points should be made:
A further bit of plugin.xml that supports the note editor is:
<extension point="org.eclipse.ui.elementFactories"> <factory class="uk.ac.kcl.cch.jb.pliny.editors.NoteEditorInputFactory" id="uk.ac.kcl.cch.jb.pliny.noteEditorInputFactory"/> [...]
Eclipse's elementFactories are involved in supporting the ability Eclipse has of remembering what editors where open from one session to the next. Information about the open editors are saved at the time Eclipse was shutting down and this list is consulted next time Eclipse starts up so that they can be reopened again. At shutdown time, each open editor is given a chance to store state information about itself in an Eclipse org.eclipse.ui.IMemento object which is written to disk. When Eclipse restarts it recreates the IMemento from the disk file and then consults this IMemento object to see what editors were open and calls the appropriate factory class described in this bit of plugin.xml to take the data stored in the IMemento class for the editor and transform it back into information the Editor can work with.
The NoteEditorInput class
Editors have input objects that identify what is being edited. In much of standard Eclipse these are files and Eclipse provides a mechanism to allow the file to be specified that we won't address directly here. However, Eclipse's design recognises that editors might well be needed for things other than files and so provides a model for allowing other things than files to be provided as input to an editor. For the NoteEditor, the input is, of course, a Pliny uk.ac.kcl.cch.jb.pliny.model.NoteLucened resource, and the uk.ac.kcl.cch.jb.pliny.editors.NoteEditorInput class has been written to Eclipse's model to handle this.
NoteEditorInput implements org.eclipse.ui.IStorageEditorInput, which is the interface that allows it to act as an input object within Eclipse. When Eclipse starts up an instance of the Note Editor it expects to deliver to the editor an instance of this class that identifies what is to be edited -- for the Note Editor, this is a particular NoteLucened object. If you look at the code for NoteEditorInput you can see that it holds a particular NoteLucened object.
In Pliny a Note Editor can be opened in more than one way, for example:
In all cases a particular NoteLucened object has been identified as the one to open. The code that causes the open to happen must create a NoteEditorInput instance, put the NoteLucened object in it, and then ask Eclipse to open the appropriate editor -- with the editor identified by giving the editor's id (as defined in the plugin.xml file).
NoteEditorInput also implements org.eclipse.ui.IPersistableElement and org.eclipse.core.runtime.IAdaptable interfaces. These interfaces define methods that allow Eclipse to write information in the NoteEditorInput class to the IMemento mentioned earlier, so that the identification of the open class will persist from one Eclipse session to the next.
Finally, NoteEditorInput implements the equals() method. Eclipse uses this to establish whether an editor on a particular item is already open at the time it is asked to open one. If it finds -- through consulting the equals() method -- that one is indeed already open, then instead of opening a second instance, it moves the focus to the already open editor.
The NoteEditorInputFactory class
As was mentioned above, the uk.ac.kcl.cch.jb.pliny.editors.NoteEditorInputFactory class supports the Eclipse workbench during its startup in the task of restarting Editors that were open when it was last shut down.
As described earlier, during shutdown the NoteEditorInput object for each open Note Editor is consulted by the workbench and given a chance to write data to a IMemento object to identify what is open. All that needs to be written for a NoteEditorInput to uniquely identify which note it is presenting is the DB key which identifies uniquely the particular instance of NoteLucened that this editor is working on. When the Eclipse workbench is restarted, then, the IMemento object contains the DB key for the particular NoteLucened object. This factory class takes the key, uses it to fetch the appropriate NoteLucened object, and packages it up in a NoteEditorInput object.
The NoteEditor class
The uk.ac.kcl.cch.jb.pliny.editors.NoteEditor class is the class that really implements the editor. To be an editor in Eclipse it needs to implement Eclipse's org.eclipse.ui.IEditorPart which in the case of the NoteEditor it does by defining itself as an extension of org.eclipse.ui.part.EditorPart. Then, when Eclipse needs to start a new Note Editor it creates a new instance of this class and passes it an instance of uk.ac.kcl.cch.jb.pliny.editors.NoteEditorInput (which tells it which NoteLucened object to open) by calling the new instance's init() method. The following are a few notes about the NoteEditor class.
NoteEditor's createPartControl method
The Eclipse workbench calls the method createPartControl to create the GUI component of the editor. As you might recall from what the NoteEditor looks like, it contains two parts:
Actions for the NoteEditor
Most mouse interactions within the reference area such as dragging or selecting are handled by GEF and use its policies/command approach described elsewhere. However, certain interactions make use of the Eclipse workbench's Action model. Actions in editors are rather complex -- in Eclipse menu and main toolbar actions attached to editors are managed by a org.eclipse.gef.ui.actions.ActionBarContributor, which for the NoteEditor is uk.ac.kcl.cch.jb.pliny.editors.NoteEditorActionBarContributor (described further below). The editor instance itself manages actions displayed in its main graphical area, and also manages the updating of what Eclipse calls Global actions. This action work is done in NoteEditor's method createActions().
Method createActions() does the following tasks:
Actions and GEF Commands
As was mentioned above, GEF uses a Command concept as a way transform user interactions on the screen into changes in the underlaying data model. Commands can be (and for Pliny commands always are) defined as undoable and redoable, so support for undo and redo is also provided.
Because the user will not separate actions in the reference area (managed by GEF) from actions in the note content are (managed by SWT and JFace) and will expect undo to work for both, I have applied GEF's Command approach to changes within the SWT and JFace components of the NoteEditor as well as the GEF ones, and both GEF and SWT/JFace environments share a single GEF CommandStack. Thus, all actions that need to be undoable within the NoteEditor -- whether or not they come from GEF or SWT/JFace are handled through Commands and a single CommandStack, and can, therefore, use the same undo or redo action to request undo or redo.
The NoteEditorActionBarContributor class
Eclipse editors do not have their own menubar area, and share space for the main Eclipse menu bar with other editors. For this reason, Actions that should appear on the menu bar need to be created and managed through an instance of a class called an ActionBarContributor (org.eclipse.gef.ui.actions.ActionBarContributor). Only one instance of an action bar contributor is created for all instances of a particular class of Editor -- all open instances of the NoteEditor, then, share a single instance of the NoteEditor's action bar contributor uk.ac.kcl.cch.jb.pliny.editors.NoteEditorActionBarContributor.
NoteEditorActionBarContributor provides several methods that Eclipse calls when necessary: