3.4 Building an editor

 < Day Day Up > 



3.4 Building an editor

We now know the base classes and concepts of the Graphical Editing Framework, and we are ready to build our first graphical editor skeleton. In this section we explain how to get started and then go forward step-by-step.

3.4.1 The editor class

First, we have to create the plug-in and then define the editor extension. We do not describe this here because it is a common process of the Eclipse plug-in programming model. The Eclipse documentation provides detailed information about this.

By default, the editor class is created by extending org.eclipse.ui.part.EditorPart. This is the main class of the editor and is responsible for receiving the input, creating and configuring the viewer, handling the input, and saving the input.

Typically you will already have a save option in your model, so we do not discuss the implementation of the methods save, isSaveAsAllowed, and saveAs here.

As a result, we will have the class skeleton shown in Example 3-2.

Example 3-2: ExampleGEFEditor.java (initial stage)

start example
 /**  * This is the example editor skeleton that is build  * in <i>Building an editor</i> in chapter <i>Introduction to GEF</i>.  *  * @see org.eclipse.ui.part.EditorPart  */ public class ExampleGEFEditor extends EditorPart {     public ExampleGEFEditor()     {}     public void createPartControl(Composite parent)     {}     public void setFocus()     {         // what should be done if the editor gains focus?         // it's your part     }     public void doSave(IProgressMonitor monitor)     {         // your save implementation here     }     public void doSaveAs()     {         // your save as implementation here     }     public boolean isDirty()     {         return false;     }     public boolean isSaveAsAllowed()     {         // your implementation here         return false;     }     public void gotoMarker(IMarker marker)     {}     public void init(IEditorSite site, IEditorInput input)         throws PartInitException     {} } 
end example

Note 

JavaDoc comments have been removed for readability reasons.

3.4.2 EditDomain

Next we need an EditDomain. An EditDomain is an interface that logically bundles an editor, viewers, and tools. Therefore, it defines the real editor application.

An EditDomain provides a CommandStack, which keeps track of all executed commands. This is necessary for undo and redo operations and useful to determine if the model was modified (is dirty) or not.

Usually you will have one EditDomain per editor, but it is also possible to share an EditDomain across several editors in a multi-page editor.

It is up to you when to create the EditDomain. It is possible to create it lazily. You can use the class EditDomain directly, however, the Graphical Editing Framework provides an implementation, which additionally knows about the editor that created it. This implementation is called DefaultEditDomain and used in our example shown in Example 3-3.

Example 3-3: Adding EditDomain to the editor

start example
 /** the <code>EditDomain</code>, will be initialized lazily */ private EditDomain editDomain; /**  * Returns the <code>EditDomain</code> used by this editor.  * @return the <code>EditDomain</code> used by this editor  */ public EditDomain getEditDomain() {     if (editDomain == null)         editDomain = new DefaultEditDomain(this);     return editDomain; } 
end example

3.4.3 CommandStack

After adding the EditDomain, we have access to the CommandStack. We will use the CommandStack to indicate when an editor is dirty.

Note 

If you ever execute a command yourself, please ensure that you execute it through the CommandStack.

The CommandStack contains the method isDirty, which indicates if a CommandStack has executed commands after the last save. How does the CommandStack know about the last save? A CommandStack knows about this because we have to tell it whenever the editor is saved.

This is not done by simply delegating the editors isDirty method to the CommandStack; instead, we need a listener that listens to CommandStack changes and updates the dirty state of our editor. Whenever this state changes, we need to inform the Eclipse workbench. But you need not be concerned about this. The superclass EditorPart provides methods for the last part.

We start with the last part, as it is the easiest task. We simply add a flag for the dirty state and a setter that automatically fires an event, as shown in Example 3-4.

Example 3-4: Indicating the dirty state of our editor (part 1)

start example
 /** the dirty state */ private boolean isDirty; /**  * Indicates if the editor has unsaved changes.  * @see EditorPart#isDirty  */ public boolean isDirty() {     return isDirty; } /**  * Sets the dirty state of this editor.  *  * <p>An event will be fired immediately if the new  * state is different than the current one.  *  * @param dirty the new dirty state to set  */ protected void setDirty(boolean dirty) {     if(isDirty != dirty)     {         isDirty = dirty;         firePropertyChange(IEditorPart.PROP_DIRTY);     } } 
end example

Now we implement the listener and attach it to the CommandStack as shown in Example 3-5.

Example 3-5: The CommandStackListener

start example
 /**  * The <code>CommandStackListener</code> that listens for  * <code>CommandStack </code>changes.  */ private CommandStackListener commandStackListener = new CommandStackListener() {     public void commandStackChanged(EventObject event)     {         setDirty(getCommandStack().isDirty());     } }; /**  * Returns the <code>CommandStack</code> of this editor's  * <code>EditDomain</code>.  *  * @return the <code>CommandStack</code>  */ public CommandStack getCommandStack() {     return getEditDomain().getCommandStack(); } /**  * Returns the <code>CommandStackListener</code>.  * @return the <code>CommandStackListener</code>  */ protected CommandStackListener getCommandStackListener() {     return commandStackListener; } 
end example

Attaching the listener should be done when the editor gets it input, and removing it should be done in the editor's dispose method. See Example 3-6.

Example 3-6: Attaching and removing the CommandStackListener

start example
 /**  * Initializes the editor.  * @see EditorPart#init  */ public void init(IEditorSite site, IEditorInput input)     throws PartInitException {     // store site and input     setSite(site);     setInput(input);     // add CommandStackListener     getCommandStack().addCommandStackListener(getCommandStackListener()); } /* (non-Javadoc)  * @see org.eclipse.ui.IWorkbenchPart#dispose()  */ public void dispose() {     // remove CommandStackListener     getCommandStack().removeCommandStackListener(getCommandStackListener());     // important: always call super implementation of dispose     super.dispose(); } 
end example

Do not forget to update the CommandStack when the editor content is saved. See Example 3-7.

Example 3-7: Update CommandStack on editor save

start example
 /**  * TODO: Implement "doSave".  * @see EditorPart#doSave  */ public void doSave(IProgressMonitor monitor) {     // your implementation here     // update CommandStack     getCommandStack().markSaveLocation(); } /**  * TODO: Implement "doSaveAs".  * @see EditorPart#doSaveAs  */ public void doSaveAs() {     // your implementation here     // update CommandStack     getCommandStack().markSaveLocation(); } 
end example

3.4.4 Attaching the viewer

The GraphicalViewer is the next element that must be integrated into our editor. The method createPartControl is the best location to do this. First we create a GraphicalViewer, then we configure this instance, and add it to the EditDomain. See Example 3-8.

Example 3-8: Attaching a GraphicalViewer to our editor

start example
 /** the graphical viewer */ private GraphicalViewer graphicalViewer; /**  * Creates the controls of the editor.  * @see EditorPart#createPartControl  */ public void createPartControl(Composite parent) {     graphicalViewer = createGraphicalViewer(parent); } /**  * Creates a new <code>GraphicalViewer</code>, configures, registers  * and initializes it.     *  * @param parent the parent composite  * @return a new <code>GraphicalViewer</code> */ private GraphicalViewer createGraphicalViewer(Composite parent) {     // create graphical viewer     GraphicalViewer viewer = new ScrollingGraphicalViewer();     viewer.createControl(parent);     // configure the viewer     viewer.getControl().setBackground(parent.getBackground());     viewer.setRootEditPart(new ScalableFreeformRootEditPart());     // hook the viewer into the EditDomain     getEditDomain().addViewer(viewer);     // acticate the viewer as selection provider for Eclipse     getSite().setSelectionProvider(viewer);     // initialize the viewer with input     viewer.setEditPartFactory(getEditPartFactory());     viewer.setContents(getContent());     return viewer; } /**  * Returns the <code>GraphicalViewer</code> of this editor.  * @return the <code>GraphicalViewer</code>  */ public GraphicalViewer getGraphicalViewer() {     return graphicalViewer; } /**  * Returns the content of this editor  * @return the model object  */ protected Object getContent() {     // todo return your model here     return null; } /**  * Returns the <code>EditPartFactory</code> that the  * <code>GraphicalViewer</code> will use.  * @return the <code>EditPartFactory</code>  */ protected EditPartFactory getEditPartFactory() {     // todo return your EditPartFactory here     return null; } 
end example

Note 

Although we have chosen to use the ScalableFreeformRootEditPart here, you are free to use whatever RootEditPart you like.

3.4.5 Being adaptable

One of the key concepts inside Eclipse is the IAdaptable technology. It is also used within the Graphical Editing Framework. That is why we have to ensure that our editor implements this interface so that the GEF elements we have created provide adaptable behavior, which may be of interest to the Graphical Editing Framework itself or to other Eclipse code. So far, we have created the following important GEF elements:

  • EditDomain

  • GraphicalViewer

EditDomain also provides access to a third important element, CommandStack. Example 3-9 shows how to provide adapter access to the elements in our sample editor.

Example 3-9: Overwriting the getAdapter method

start example
 /* (non-Javadoc)  * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)  */ public Object getAdapter(Class adapter) {     // we need to handle common GEF elements we created     if (adapter == GraphicalViewer.class || adapter == EditPartViewer.class)         return getGraphicalViewer();     else if (adapter == CommandStack.class)         return getCommandStack();     else if (adapter == EditDomain.class)         return getEditDomain();     // the super implementation handles the rest     return super.getAdapter(adapter); } 
end example

3.4.6 Introducing the palette

The palette in GEF editors is the home for tools. But before we discuss tools, we need to create a palette inside our editor. The GEF palette is implemented reusing GEF technology; thus it has a model presented in a viewer (the PaletteViewer).

The palette model

The palette model is a simple model starting with a PaletteRoot. Each PaletteViewer needs a PaletteRoot. The PaletteRoot is a palette container (PaletteContainer). Palette containers are used to organize palette entries (PaletteEntry).

Besides the PaletteRoot, there are two additional palette containers - PaletteGroup and PaletteDrawer. We suggest that you use both of them to organize your palette. Each provides a container for palette entries, but the PaletteGroup cannot be collapsed, while the PaletteDrawer can be collapsed.

Additional information can be found in the GEF JavaDoc.

Attaching the palette

Attaching a palette is similar to attaching a viewer. First, we need to create a new PaletteViewer, as shown in Example 3-10.

Example 3-10: Creating a PaletteViewer

start example
 /**  * Creates a new <code>PaletteViewer</code>, configures, registers  * and initializes it.  * @param parent the parent composite  * @return a new <code>PaletteViewer</code>  */ private PaletteViewer createPaletteViewer(Composite parent) {     // create graphical viewer     PaletteViewer viewer = new PaletteViewer();     viewer.createControl(parent);     // hook the viewer into the EditDomain (only one palette per EditDomain)     getEditDomain().setPaletteViewer(viewer);     // important: the palette is initialized via EditDomain     getEditDomain().setPaletteRoot(getPaletteRoot());     return viewer; } /**  * Returns the <code>PaletteRoot</code> this editor's palette uses.  * @return the <code>PaletteRoot</code>  */ protected PaletteRoot getPaletteRoot() {     // todo add your palette entries here     return null; } 
end example

Next, we need to add this viewer to the editor's composite. The SWT SashForm is used to have the palette's width modifiable, as shown in Example 3-11.

Example 3-11: Adding the PaletteViewer to the editor's composite

start example
 /**  * Creates the controls of the editor.  * @see EditorPart#createPartControl  */ public void createPartControl(Composite parent) {     SashForm sashForm = new SashForm(parent, SWT.HORIZONTAL);     sashForm.setWeights(new int[] {30,70});     paletteViewer = createPaletteViewer(sashForm);     graphicalViewer = createGraphicalViewer(sashForm); } /** the palette viewer */ private PaletteViewer paletteViewer; /**  * Returns the <code>PaletteViewer</code> of this editor.  * @return the <code>PaletteViewer</code>  */ public PaletteViewer getPaletteViewer() {     return paletteViewer; } 
end example

There are several default tools available, and we need to add them so that we have an initial PaletteRoot. See Example 3-12.

Example 3-12: Initial PaletteRoot with default tools

start example
 /** the palette root */ private PaletteRoot paletteRoot; /**  * Returns the <code>PaletteRoot</code> this editor's palette uses.  * @return the <code>PaletteRoot</code>  */ protected PaletteRoot getPaletteRoot() {     if (null == paletteRoot)     {         // create root         paletteRoot = new PaletteRoot();         List categories = new ArrayList();         // a group of default control tools         PaletteGroup controls = new PaletteGroup("Controls");         // the selection tool         ToolEntry tool = new SelectionToolEntry();         controls.add(tool);         // use selection tool as default entry         paletteRoot.setDefaultEntry(tool);         // the marquee selection tool         controls.add(new MarqueeToolEntry());         // a separator         PaletteSeparator separator =             new PaletteSeparator(                 EditorExamplePlugin.PLUGIN_ID + ".palette.seperator");         separator.setUserModificationPermission(             PaletteEntry.PERMISSION_NO_MODIFICATION);         controls.add(separator);         // a tool for creating connection         controls.add(             new ConnectionCreationToolEntry(                 "Connections",                 "Create Connections",                 null,                 ImageDescriptor.createFromFile(                     getClass(),                     "icons/connection16.gif"),                 ImageDescriptor.createFromFile(                     getClass(),                     "icons/connection24.gif")));         // todo add your palette drawers and entries here         // add all categroies to root         paletteRoot.addAll(categories);     }     return paletteRoot; } 
end example

Palette customizer

It is possible to attach a palette customizer to the palette. This will enable the users of your editor to modify the palette to work in the way they prefer. For implementation details, please see our completed redbook sample application as described in Chapter 7, "Implementing the sample" on page 203, or the Logic example application provided from the GEF development team.

3.4.7 Actions

Actions are common objects in the Eclipse workbench to do something when user requests are initiated through menu items, toolbar buttons or context menu items. The Graphical Editing Framework provides a set of standard actions and an infrastructure for using these actions within the Graphical Editing Framework.

ActionRegistry

The class org.eclipse.gef.actions.ActionRegistry serves as a container for editor actions. The editor is responsible for providing and maintaining an ActionRegistry. See Example 3-13.

Example 3-13: Adding an ActionRegistry to the editor

start example
 /** the editor's action registry */ private ActionRegistry actionRegistry; /**  * Returns the action registry of this editor.  * @return the action registry  */ public ActionRegistry getActionRegistry() {     if (actionRegistry == null)         actionRegistry = new ActionRegistry();     return actionRegistry; } /* (non-Javadoc)  * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)  */ public Object getAdapter(Class adapter) {     // we need to handle common GEF elements we created     if (adapter == GraphicalViewer.class         || adapter == EditPartViewer.class)         return getGraphicalViewer();     else if (adapter == CommandStack.class)         return getCommandStack();     else if (adapter == EditDomain.class)         return getEditDomain();     else if (adapter == ActionRegistry.class)         return getActionRegistry();     // the super implementation handles the rest     return super.getAdapter(adapter); } /* (non-Javadoc)  * @see org.eclipse.ui.IWorkbenchPart#dispose()  */ public void dispose() {     // remove CommandStackListener     getCommandStack().removeCommandStackListener(getCommandStackListener());     // disposy the ActionRegistry (will dispose all actions)     getActionRegistry().dispose();     // important: always call super implementation of dispose     super.dispose(); } 
end example

Managing actions

As soon as we have the ActionRegistry, we are able to create actions and to register them.

The Graphical Editing Framework provides a set of default actions (redo, undo, delete, print, and save). These actions need some special handling to stay up-to-date with the editor, the CommandStack or the EditParts. The GEF default actions are not implemented as listeners to some events. Instead, they have to be updated manually. This can be done from within the editor as shown in Example 3-14.

Example 3-14: Added infrastructure for supporting different actions

start example
 /** the list of action ids that are to EditPart actions */ private List editPartActionIDs = new ArrayList(); /** the list of action ids that are to CommandStack actions */ private List stackActionIDs = new ArrayList(); /** the list of action ids that are editor actions */ private List editorActionIDs = new ArrayList(); /**  * Adds an <code>EditPart</code> action to this editor.  *  * <p><code>EditPart</code> actions are actions that depend  * and work on the selected <code>EditPart</code>s.  *  * @param action the <code>EditPart</code> action  */ protected void addEditPartAction(SelectionAction action) {     getActionRegistry().registerAction(action);     editPartActionIDs.add(action.getId()); } /**  * Adds an <code>CommandStack</code> action to this editor.  *  * <p><code>CommandStack</code> actions are actions that depend  * and work on the <code>CommandStack</code>.  *  * @param action the <code>CommandStack</code> action  */ protected void addStackAction(StackAction action) {     getActionRegistry().registerAction(action);     stackActionIDs.add(action.getId()); } /**  * Adds an editor action to this editor.  *  * <p><Editor actions are actions that depend  * and work on the editor.  *  * @param action the editor action  */ protected void addEditorAction(EditorPartAction action) {     getActionRegistry().registerAction(action);     editorActionIDs.add(action.getId()); } /**  * Adds an action to this editor's <code>ActionRegistry</code>.  * (This is a helper method.)  *  * @param action the action to add.  */ protected void addAction(IAction action) {     getActionRegistry().registerAction(action); } 
end example

Now that we have the action infrastructure, we must implement the automatic updating of the different actions. Editor actions must be updated when the editor changes, CommandStack actions when the CommandStack changes, and EditPart actions when the selection changes. Example 3-15 shows how to add update support for actions to our sample editor.

Example 3-15: Adding update support for the actions

start example
 /**  * Updates the specified actions.  *  * @param actionIds the list of ids of actions to update  */ private void updateActions(List actionIds) {     for (Iterator ids = actionIds.iterator(); ids.hasNext();)     {         IAction action = getActionRegistry().getAction(ids.next());         if (null != action && action instanceof UpdateAction)             ((UpdateAction) action).update();     } } /**  * The <code>CommandStackListener</code> that listens for  * <code>CommandStack </code>changes.  */ private CommandStackListener commandStackListener =     new CommandStackListener() {     public void commandStackChanged(EventObject event)     {         updateActions(stackActionIDs);         setDirty(getCommandStack().isDirty());     } }; /** the selection listener */ private ISelectionListener selectionListener = new ISelectionListener() {     public void selectionChanged(IWorkbenchPart part, ISelection selection)     {         updateActions(editPartActionIDs);     } }; /**  * Returns the selection listener.  *  * @return the <code>ISelectionListener</code>  */ protected ISelectionListener getSelectionListener() {     return selectionListener; } /**  * Initializes the editor.  * @see EditorPart#init  */ public void init(IEditorSite site, IEditorInput input)     throws PartInitException {     // store site and input     setSite(site);     setInput(input);     // add CommandStackListener     getCommandStack().addCommandStackListener(getCommandStackListener());     // add selection change listener     getSite()         .getWorkbenchWindow()         .getSelectionService()         .addSelectionListener(         getSelectionListener()); } /* (non-Javadoc)  * @see org.eclipse.ui.IWorkbenchPart#dispose()  */ public void dispose() {     // remove CommandStackListener     getCommandStack().removeCommandStackListener(getCommandStackListener());     // remove selection listener     getSite()         .getWorkbenchWindow()         .getSelectionService()         .removeSelectionListener(         getSelectionListener());     / disposy the ActionRegistry (will dispose all actions)     getActionRegistry().dispose();     // important: always call super implementation of dispose     super.dispose(); } /* (non-Javadoc)  * @see org.eclipse.ui.part.WorkbenchPart#firePropertyChange(int)  */ protected void firePropertyChange(int propertyId) {     super.firePropertyChange(propertyId);     updateActions(editorActionIDs); } 
end example

Now, when all the infrastructure is ready, we are able to create and add our actions as shown in Example 3-16.

Example 3-16: Adding actions to the editor

start example
 /**  * Initializes the editor.  * @see EditorPart#init  */ public void init(IEditorSite site, IEditorInput input)     throws PartInitException {     // store site and input     setSite(site);     setInput(input);     // add CommandStackListener     getCommandStack().addCommandStackListener(getCommandStackListener());     // add selection change listener     getSite()         .getWorkbenchWindow()         .getSelectionService()         .addSelectionListener(         getSelectionListener());     // initialize actions     createActions(); } /**  * Creates actions and registers them to the ActionRegistry.  */ protected void createActions() {     addStackAction(new UndoAction(this));     addStackAction(new RedoAction(this));     addEditPartAction(new DeleteAction((IWorkbenchPart) this));     addEditorAction(new SaveAction(this));     addEditorAction(new PrintAction(this)); } 
end example

3.4.8 Adapting to the properties view

EditParts are responsible for delivering IPropertySource adapters for the properties view, but this is not discussed here.

The Graphical Editing Framework provides a solution to cover modifications occurred in the properties view into the CommandStack. This enables the possibility to undo and redo changes.

To enable this, the editor must deliver its own IPropertySheetPage. This IPropertySheetPage is a default PropertySheetPage customized with an undoable root entry provided by GEF. See Example 3-17.

Example 3-17: Making the properties view undoable

start example
 /* (non-Javadoc)  * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)  */ public Object getAdapter(Class adapter) {     // we need to handle common GEF elements we created     if (adapter == GraphicalViewer.class         || adapter == EditPartViewer.class)         return getGraphicalViewer();     else if (adapter == CommandStack.class)         return getCommandStack();     else if (adapter == EditDomain.class)         return getEditDomain();     else if (adapter == ActionRegistry.class)         return getActionRegistry();     else if (adapter == IPropertySheetPage.class)         return getPropertySheetPage();     // the super implementation handles the rest     return super.getAdapter(adapter); } /** the undoable <code>IPropertySheetPage</code> */ private PropertySheetPage undoablePropertySheetPage; /**  * Returns the undoable <code>PropertySheetPage</code> for  * this editor.  *  * @return the undoable <code>PropertySheetPage</code>  */ protected PropertySheetPage getPropertySheetPage() {     if (null == undoablePropertySheetPage)     {         undoablePropertySheetPage = new PropertySheetPage();         undoablePropertySheetPage.setRootEntry(             GEFPlugin.createUndoablePropertySheetEntry(getCommandStack()));     }     return undoablePropertySheetPage; } 
end example

3.4.9 Providing an outline view

Providing an outline view is handled in the typical Eclipse way. We need to provide an adapter of type IContentOutlinePage. We can do this in several ways.

One way is to create a complete SWT based outline view without using the Graphical Editing Framework. In many cases this is suitable and can be easily done, because many components, such as content and label providers or even tree viewers, can be reused to show a tree of your model objects.

If you do not have these reusable components available, then a second way is to build a tree with GEF components. The Graphical Editing Framework provides a TreeViewer and TreeEditParts for this case. You can also reuse actions created for your graphical editor. For details about implementing a model tree with the GEF TreeViewer and TreeEditParts, please see our redbook sample application.

A third way is to provide an overview of your graphical editor. Example 3-18 and Example 3-19 show a possible implementation of this.

Example 3-18: An overview outline page

start example
 /**  * This is a sample implementation of an outline page showing an  * overview of a graphical editor.  *  * @author Gunnar Wagenknecht  */ public class OverviewOutlinePage extends Page implements IContentOutlinePage {     /** the control of the overview */     private Canvas overview;     /** the root edit part */     private ScalableFreeformRootEditPart rootEditPart;     /** the thumbnail */     private Thumbnail thumbnail; /    **      * Creates a new OverviewOutlinePage instance.      * @param rootEditPart the root edit part to show the overview from      */     public OverviewOutlinePage(ScalableFreeformRootEditPart rootEditPart)     {         super();         this.rootEditPart = rootEditPart;     }     /* (non-Javadoc)      * @see ISelectionProvider#addSelectionChangedListener      * (ISelectionChangedListener)      */     public void addSelectionChangedListener(ISelectionChangedListener listener)     {}     /* (non-Javadoc)      * @see IPage#createControl(Composite)      */     public void createControl(Composite parent)     {         // create canvas and lws         overview = new Canvas(parent, SWT.NONE);         LightweightSystem lws = new LightweightSystem(overview);         // create thumbnail         thumbnail =             new ScrollableThumbnail((Viewport) rootEditPart.getFigure());         thumbnail.setBorder(new MarginBorder(3));         thumbnail.setSource(             rootEditPart.getLayer(LayerConstants.PRINTABLE_LAYERS));         lws.setContents(thumbnail);     }     /* (non-Javadoc)      * @see org.eclipse.ui.part.IPage#dispose()      */     public void dispose()     {         if (null != thumbnail)             thumbnail.deactivate();         super.dispose();     }     /* (non-Javadoc)      * @see org.eclipse.ui.part.IPage#getControl()      */     public Control getControl()     {         return overview;     }     /* (non-Javadoc)      * @see org.eclipse.jface.viewers.ISelectionProvider#getSelection()      */     public ISelection getSelection()     {         return StructuredSelection.EMPTY;     }     /* (non-Javadoc)      * @see ISelectionProvider#removeSelectionChangedListener      * (ISelectionChangedListener)      */     public void removeSelectionChangedListener(         ISelectionChangedListener listener)     {}     /* (non-Javadoc)      * @see org.eclipse.ui.part.IPage#setFocus()      */     public void setFocus()     {         if (getControl() != null)             getControl().setFocus();     }     /* (non-Javadoc)      * @see ISelectionProvider#setSelection(ISelection)      */     public void setSelection(ISelection selection)     {} } 
end example

Example 3-19: Attaching the overview to the editor

start example
 /* (non-Javadoc)  * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)  */ public Object getAdapter(Class adapter) {     // we need to handle common GEF elements we created     if (adapter == GraphicalViewer.class         || adapter == EditPartViewer.class)         return getGraphicalViewer();     else if (adapter == CommandStack.class)         return getCommandStack();     else if (adapter == EditDomain.class)         return getEditDomain();     else if (adapter == ActionRegistry.class)         return getActionRegistry();     else if (adapter == IPropertySheetPage.class)         return getPropertySheetPage();     else if (adapter == IContentOutlinePage.class)         return getOverviewOutlinePage();     // the super implementation handles the rest     return super.getAdapter(adapter); } /** the overview outline page */ private OverviewOutlinePage overviewOutlinePage; /**  * Returns the overview for the outline view.  *  * @return the overview  */ protected OverviewOutlinePage getOverviewOutlinePage() {     if (null == overviewOutlinePage && null != getGraphicalViewer())     {         RootEditPart rootEditPart = getGraphicalViewer().getRootEditPart();         if (rootEditPart instanceof ScalableFreeformRootEditPart)         {             overviewOutlinePage =                 new OverviewOutlinePage(                     (ScalableFreeformRootEditPart) rootEditPart);         }     }     return overviewOutlinePage; } 
end example

Now this page can be used in the editor, as shown in Example 3-19.

3.4.10 Controlling your editor with the keyboard

The Graphical Editing Framework uses the concept of KeyHandlers to answer key strokes. By default, the anGEF GraphicalViewer does not answer key strokes. We have to enable this.

This is not a difficult task, because as with all other GEF concepts, there is a default implementation available, which provides a very feature-rich set of keys for interacting with a GraphicalViewer. The default implementation is the class org.eclipse.gef.ui.parts.GraphicalViewerKeyHandler. Example 3-20 shows how to use this key handler with our editor sample.

Example 3-20: Enabling our editor for keyboard interaction

start example
 /**  * Creates a new <code>GraphicalViewer</code>, configures, registers  * and initializes it.  * @param parent the parent composite  * @return a new <code>GraphicalViewer</code>  */ private GraphicalViewer createGraphicalViewer(Composite parent) {     // create graphical viewer     GraphicalViewer viewer = new ScrollingGraphicalViewer();     viewer.createControl(parent);     // configure the viewer     viewer.getControl().setBackground(parent.getBackground());     viewer.setRootEditPart(new ScalableFreeformRootEditPart());     viewer.setKeyHandler(new GraphicalViewerKeyHandler(viewer));     // hook the viewer into the EditDomain     getEditDomain().addViewer(viewer);     // acticate the viewer as selection provider for Eclipse     getSite().setSelectionProvider(viewer);     // initialize the viewer with input     viewer.setEditPartFactory(getEditPartFactory());     viewer.setContents(getContent());     return viewer; } 
end example

Tip 

If you like to attach actions to your own key strokes, you do not need to overwrite the GraphicalViewerKeyHandler. It is simply possible to attach a parent to KeyHandlers. Thus, you simply create your own KeyHandler instance (not GraphicalViewerKeyHandler), configure this KeyHandler instance, and set it as the parent of the GraphicalViewerKeyHandler you created for the GraphicalViewer.



 < Day Day Up > 



Eclipse Development using the Graphical Editing Framework and the Eclipse Modeling Framework
Eclipse Development Using the Graphical Editing Framework And the Eclipse Modeling Framework
ISBN: 0738453161
EAN: 2147483647
Year: 2004
Pages: 70
Authors: IBM Redbooks

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net