Chapter 11. Generic Editors

In Eclipse, editors are parts that have an associated input inside a workbench window and additional lifecycle methods, such as save and revert. This chapter answers questions about interacting with editors and about writing your own editors, whether they are text based or graphical. See Chapter 15 for a complete treatment of questions about writing your own text-based editors.

FAQ 206: What is the difference between a view and an editor?

When they first start to write plug-ins that contribute visual components, people are often confused about whether they should write a view or an editor. Superficially, the two appear to be very similar: Both are parts that make up a workbench page, both can contain arbitrary visual subcomponents, and both have various mechanisms for plugging in actions and menus. Let’s start with some common misconceptions about the differences between views and editors.

  • Editors display the contents of a file, and views contain groups of files or things other than files. Wrong. Both editors and views can have arbitrary contents from a file or multiple files or be from something that is not a file at all.

  • Editors display text and views display tables or trees. Wrong again. There are no constraints about what goes into an editor or a view. For example, the plug-in Manifest Editor is form-based, whereas the Console view shows plain text.

What are the real differences between views and editors? Here are the main ones.

  • There is generally only one instance of a given view per workbench page, but there can be several instances of the same type of editor.

  • Editors can appear in only one region of the page, whereas views can be moved to any part of the page and minimized as fast views.

  • Editors can be in a dirty state, meaning that their contents are unsaved and will be lost if the editor is closed without saving.

  • Views have a local toolbar, whereas editors contribute buttons to the global toolbar.

  • Editors can be associated with a file name or an extension, and this association can be changed by users.

Note

FAQ 206: What is the difference between a view and an editor?

FAQ 146 What is a viewer?

FAQ 195 What is a view?

FAQ 207: How do I open an editor programmatically?

Use the openEditor methods on org.eclipse.ui.IWorkbenchPage to open an editor on a given input. The openEditor methods require you to supply the ID of the editor to open. You can use the editor registry to find out what editor ID is appropriate for a given file name, using the getDefaultEditor method on IEditorRegistry. In Eclipse 3.0, the editor opening methods that were specific to IFile were moved to the IDE class.

IWorkbenchPage page = ...;
IFile file = ...;
IEditorDescriptor desc = PlatformUI.getWorkbench().
   getEditorRegistry().getDefaultEditor(file.getName());
page.openEditor(
   new FileEditorInput(file),
   desc.getId());

Note

FAQ 207: How do I open an editor programmatically?

FAQ 38 Is Eclipse 3.0 going to break all of my old plug-ins?

FAQ 170 How do I find the active workbench page?

FAQ 300 How do I open an editor on a file in the workspace?

FAQ 208: How do I open an external editor?

A special editor ID is used to indicate that a file should be opened using an external editor. When you ask it to open an editor with this ID, the platform delegates to the operating system to select and open an appropriate editor for the given input. This ID can be used to open an editor on IFile instances or on any other kind of input that implements IPathEditorInput. Here is an example snippet that opens an external editor on an IFile instance:

IWorkbenchPage page = ...;
IFile file = ...;
page.openEditor(
   new FileEditorInput(file),
   IEditorRegistry.SYSTEM_EXTERNAL_EDITOR_ID);

Note that this technique applies only to Eclipse 3.0 or greater. On older versions of Eclipse, a special convenience method, openSystemEditor on IWorkbenchPage, accomplished the same task. This method was removed from the workbench API as part of the Eclipse 3.0 rich client refactoring.

Note

FAQ 208: How do I open an external editor?

FAQ 170 How do I find the active workbench page?

FAQ 300 How do I open an editor on a file in the workspace?

FAQ 209: How do I dynamically register an editor to handle a given extension?

You can’t. Editors, like most other extensions to the platform, must be specified declaratively in the plug-in manifest file. You cannot dynamically install a new editor except by dynamically installing a new plug-in containing the new editor.

The only thing you can currently do programmatically is specify the default editor to use for a given file name or extension. The editor must already be registered with the platform through a plug-in and must already declare that it supports files with that name or extension.

Here is an example snippet that sets the default editor for text files to be the built-in platform text editor:

IEditorRegistry registry =
        PlatformUI.getWorkbench().getEditorRegistry();
registry.setDefaultEditor("*.txt",
        "org.eclipse.ui.DefaultTextEditor");

Note

FAQ 209: How do I dynamically register an editor to handle a given extension?

FAQ 211 How do I create my own editor?

FAQ 210: How do I switch to vi or emacs-style key bindings?

Eclipse has a built-in key-binding configuration that emulates emacs-style key bindings. You can switch to this mode by using the Keys preference page. There is no equivalent configuration setting to emulate vi, largely because of its mode-oriented approach. On the Web, however, there is a plug-in that emulates vi-style key bindings in Eclipse.

Note

FAQ 210: How do I switch to vi or emacs-style key bindings?

FAQ 228 How do I create my own key-binding configuration?

VIPlugin (http://eclipse-plugins.2y.net/eclipse/plugin_details.jsp?id=331)

FAQ 211: How do I create my own editor?

All editors start by making a subclass of EditorPart from the org.eclipse.ui.part package. At this basic level, editors are very generic. They take an input object that implements IEditorInput, they know how to draw themselves by implementing the createPartControl method, and they may know how to respond to a request to save their contents. To create a bare-bones editor, you have to implement only a small handful of methods. Figure 11.1 shows a working editor that displays a simple label.

A minimal editor

Figure 11.1. A minimal editor

Some required methods, declared abstract in EditorPart, have been omitted from this snippet, but the editor will work if their implementations are empty:

public class MinimalEditor extends EditorPart {
   private Label contents;
   public void createPartControl(Composite parent) {
      contents = new Label(parent, SWT.NONE);
      contents.setText("Minimal Editor");
   }
   public void init(IEditorSite site, IEditorInput input) {
      setSite(site);
      setInput(input);
   }
   public void setFocus() {
      if (contents != null)
         contents.setFocus();
   }
}

The plug-in manifest entry for defining this editor is as follows:

<editor
   name="Minimal Editor"
   extensions="min"
   icon="icons/sample.gif"
   class="org.eclipse.faq.examples.editor.MinimalEditor"
   id="org.eclipse.faq.examples.editor.MinimalEditor">
</editor>

The extensions attribute describes what file types this editor will automatically be associated with. In this case, the editor will be associated with files ending in min. An editor can instead be associated with a particular file name by replacing the extensions attribute with a filenames attribute. Either of these attributes can specify a comma-separated list for associating an editor with multiple file name extensions and/or file names. A user can always choose to associate an editor with a different file name or extension from the Workbench > File Associations preference page.

Note

A minimal editor

FAQ 264 How do I get started with creating a custom text editor?

FAQ 335 How do I write an editor for my own language?

FAQ 212: How do I enable the Save and Revert actions?

An editor with unsaved changes is said to be dirty. If an editor is closed while dirty, changes made in the editor since the last save should be discarded. The framework asks an editor whether it is dirty by calling the IEditorPart method isDirty. When the dirty state of an editor changes, it lets the world know by firing a property change event, IEditorPart.PROP_DIRTY, on the property.

Here are the relevant minimal-editor example sections that control the dirty state:

public class MinimalEditor extends EditorPart {
   protected boolean dirty = false;
   ...
   public boolean isDirty() {
      return dirty;
   }
   protected void setDirty(boolean value) {
      dirty = value;
      firePropertyChange(PROP_DIRTY);
   }
}

The editor Save action should persist the current editor contents and then set the dirty state to false. Unlike most actions that are defined within an instance of IAction, the editor Save and Save As... actions are built directly into the editor part. These actions are always enabled when the editor is in a dirty state. The editor must support these actions by implementing the methods on ISaveablePart, which is extended by IEditorPart. Here are trivial implementations of these methods from the minimal-editor example:

public void doSave(IProgressMonitor monitor) {
   setDirty(false);
}
public void doSaveAs() {
   doSave(null);
}
public boolean isSaveAsAllowed() {
   return false;
}

Unlike the Save action, the Revert action is not built into the editor framework. The Revert action is one of the standard workbench global actions and is entirely optional for editors to implement. The global action is hooked in just like other global actions. The Revert action should be equivalent to closing an editor without saving, then reopening on the previously saved contents. Like the Save action, it should change the dirty state to false and fire a property change event on IEditorPart.PROP_DIRTY when it completes successfully.

Note

FAQ 212: How do I enable the Save and Revert actions?

FAQ 213 How do I enable global actions such as Cut, Paste, and Print in my editor?

FAQ 213: How do I enable global actions such as Cut, Paste, and Print in my editor?

Your editor’s IEditorActionBarContributor, defined in the editor definition in the plugin.xml file, is responsible for enabling global actions. Whenever your editor becomes the active part, the method setActiveEditor is called on the action bar contributor. This is where you can retarget the global actions for your editor. Keep in mind that each editor type has only one editor action bar contributor, so you need to update your actions to reflect the current editor. In this example, the global Print action is being retargeted to the active editor:

IAction print = ...;
public void setActiveEditor(IEditorPart part) {
   IActionBars bars= getActionBars();
   if (bars == null)
      return;
   print.setEditor(part);
   bars.setGlobalActionHandler(
      IWorkbenchActionConstants.PRINT, print);
   bars.updateActionBars();
}

Note

FAQ 213: How do I enable global actions such as Cut, Paste, and Print in my editor?

FAQ 231 How do I hook into global actions, such as Copy and Delete?

FAQ 214: How do I hook my editor to the Back and Forward buttons?

Each workbench page maintains a navigation history of interesting locations that have been visited in the page’s editors. All editors, not only text editors, can contribute locations to this history, allowing the user to quickly jump between these locations by using the Back and Forward buttons on the toolbar. To enable this, your editor must implement INavigationLocationProvider. This interface is used to ask an editor to create an INavigationLocation object, which is a representation of the current editor state. When the user clicks the Back or Forward button, the previous or next location in the history restores its position using the restoreLocation method on INavigationLocation.

The contract that should be followed for an INavigationLocation is that when the user jumps in one direction, a subsequent jump in the opposite direction should take the user back to the starting point. To support this, your implementation of restoreLocation must add a history entry for the current location before restoring the old location.

You can imagine that this will quickly lead to duplication of entries if the user continues to jump backward and forward several times. This duplication is avoided by the mergeInto method on INavigationLocation. If the location to be merged is the same as or is overlapping the receiver location, the method should merge the two entries and return true. If the locations don’t overlap, it simply returns false.

A navigation location can also choose to support persistence. When an editor closes, any locations associated with that editor are asked to store their state in an IMemento. When the user jumps back to a location in an editor that has been closed, the location will be given the editor’s IEditorInput object and the IMemento that was stored. Using this information, the location instance must be able to restore its state and navigate to its location in the editor. Note that you can easily obtain the editor instance from the input object by using IWorkbenchPage.findEditor(IEditorInput).

Now we know how to create and restore editor locations, but how are entries added to the navigation history in the first place? Anyone can mark an interesting location in an open editor by calling the markLocation method on INavigationHistory. Code that causes the cursor or selection to jump to another location in an editor should call this method both before and after performing the jump. As mentioned, implementations of restoreLocation should also mark the current location before restoring an old one. Regardless of whether the specific editor has any support for navigation history, markLocation will work. If the editor doesn’t implement INavigationLocationProvider, a history entry will be added, allowing the user to jump back to that editor but without returning to any particular location. The following snippet shows an action that is added to the sample HTML editor. When the action is invoked, it will add the current cursor position to the navigation history:

public class MarkLocationAction extends Action {
   private IEditorPart editor;
   public MarkLocationAction(IEditorPart editor) {
      super("Mark Location in History", null);
      this.editor = editor;
   }
   public void run() {
      IWorkbenchPage page = editor.getSite().getPage();
      page.getNavigationHistory().markLocation(editor);
   }
}

FAQ 215: How do I create a form-based editor, such as the plug-in Manifest Editor?

The org.eclipse.ui.forms plug-in provides a framework for building form-based editors. The components in this plug-in have long been the framework for building the PDE and Install/Update editors and views but have been made into official API only in the Eclipse 3.0 release.

To give you a quick overview, a form-based editor is created by subclassing the abstract FormEditor class. This class allows you to add any number of tabbed pages, which can be either traditional editor components or form-based pages (IFormPage). Each form page creates the displays for a single IForm, and each form may contain multiple FormParts representing each section in the form.

There are various flavors of IForm subtypes, depending on whether you want multiple sections, scrolling, or different layout styles. An example of a form-based editor is the PDE plug-in Manifest Editor, implemented by the ManifestEditor class in the org.eclipse.pde.ui plug-in.

Note

FAQ 215: How do I create a form-based editor, such as the plug-in Manifest Editor?

FAQ 211 How do I create my own editor?

FAQ 216: How do I create a graphical editor?

The Eclipse Platform and SDK do not have support for creating graphical editors. However, a subproject of the Eclipse Tools Project is dedicated to a framework for graphical editors: the Graphical Editor Framework (GEF). GEF provides viewers for displaying graphical information and a controller for managing the interaction between those viewers and your domain model.

GEF makes few assumptions about what your model looks like and imposes no restrictions on where its viewers can be displayed. This allows you to use GEF for displaying a wide variety of graphical information in dialogs, views, and editors within an Eclipse application.

Note

FAQ 216: How do I create a graphical editor?

The GEF Web page (http://eclipse.org/gef)

FAQ 217: How do I make an editor that contains another editor?

In its most abstract sense, an editor is simply a container for arbitrary SWT controls. As such, an editor can contain views, editors, wizards, and any other visual control. In practice, many of these types of controls don’t make sense in the context of an editor. However, an editor is commonly composed of several pages, some of which may also be used as stand-alone editors. The most common example is an editor that provides a rendered WYSIWYG (what you see is what you get) page and a source page that shows raw text. The PDE plug-in Manifest Editor, implemented by the ManifestEditor class in the PDE UI plug-in, is such an editor. The platform provides infrastructure for this common editor type in the MultiPageEditorPart class.

Creating a subclass of MultiPageEditorPart requires that you implement many of the same methods as you would for a standard editor. The main difference is that instead of implementing createPartControl, you must implement createPages. In this method, you must create the controls for each page within the editor. These pages can be either standard editor parts or arbitrary SWT controls. The nested editors don’t need to know anything about their container; from their point of view they are simply standard editors.

Your subclass of MultiPageEditorPart isn’t required to do much beyond creating the initial set of pages. The superclass will take care of implementing the presentation for displaying the pages and for allowing the user to switch pages. If necessary, you can programmatically add or remove pages at any time by calling addPage or removePage. You can also programmatically switch pages by using setActivePage and respond to page changes by overriding pageChange.

The simplest way to get going with a multi-page editor is to edit your plugin.xml with the Manifest Editor. Select the Extensions tab, click on Add..., select org.eclipse.ui.editors in the extension point list, and choose Multi-page Editor from the list of available templates. This will add all the required pieces for a basic multi-page editor to your plug-in.

Note

FAQ 217: How do I make an editor that contains another editor?

FAQ 215 How do I create a form-based editor, such as the plug-in Manifest Editor?

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.135.213.212