Support free tutorials









vogella training Training Books



Eclipse Editor Plugin - Tutorial

Lars Vogel

Version 1.2

01.09.2011

Revision History
Revision 0.1 03.06.2010 Lars
Vogel
Separated from Eclipse RCP tutorial
Revision 0.2 - 1.2 04.11.2010 - 01.09.2011 Lars
Vogel
bug fixes and enhancements

How to create an Eclipse Editor

This tutorial describes how to create an editor and how this editor can be filled from a view. The tutorial is based on Eclipse 3.7 (Eclipse Indigo).


Table of Contents

1. Eclipse Editors
1.1. Overview
1.2. Steps required to create an editor
1.3. IEditorInput
1.4. IEditorPart and EditorPart
1.5. Setting the Editor Title und Tooltip
1.6. Saving the Editor Content
1.7. API for working with Editors
2. Prerequisites for this tutorial
3. Tutorial: Creation of an editor
3.1. Create project and data model
3.2. Editor area
3.3. Editor Input
3.4. Adding the editor
3.5. Command for opening the editor
3.6. View changes
4. Support this website
4.1. Thank you
4.2. Questions and Discussion
5. Links and Literature
5.1. Source Code
5.2. Eclipse Resources
5.3. vogella Resources

1. Eclipse Editors

1.1. Overview

Eclipse uses editors and views to maintain data. An editor typically requires that the user explicitly select "save" to apply the changes to the data while a view typically changes the data immediately.

All editors are opened in the same area. Via the perspective you can configure if the editor area is visible or not.

1.2. Steps required to create an editor

The following steps are required to create and use an editor within an RCP application.

  • Make the editor area visible in your perspective

  • Create an IEditorInput class

  • Define an extension for the "org.eclipse.ui.editors" extension point

  • Implement the class for the editor, this class must implement IEditorPart

1.3. IEditorInput

IEditorInput serves as the model for the editor and is supposed to be a light-weight representation of the model. Eclipse will buffer IEditorInput objects therefore this object should be relatively small.

For example the Eclipse IDE uses IEditorInput objects to identify files without handling with the complete file. small.

Based on the equals() method of the IEditorInput the system will determine if the corresponding editor is already open or if a new editor must be opened.

1.4. IEditorPart and EditorPart

The editor is defined via the extension point "org.eclipse.ui.editors". The class which implement the editor must implement the interface "IEditorPart". In most cases it extends the abstract class "EditorPart".

The editor receives the IEditorSite and the IEditorInput in the init() method. It must set the input via the setInput() method and the side via the setSite() method.

init() is called before createPartControl() therefore you can use the input during your UI creation (which happens in createPartControl()).

1.5. Setting the Editor Title und Tooltip

By default the Editor will use the tooltip and title from the EditorInput.

Typically the EditorInput is only a light-weight representation of the real object. Therefore you may want to change the title and tooltip in your Editor. Use setPartName() to set the title of the Editor. To set the tooltip you have to override the method getTitleToolTip() (despite the Javadoc description). See Bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=107772 for details.

1.6. Saving the Editor Content

In an editor the method isDirty() is used to inform the workbench if the content of the editor is changed. For inform the workbench that the dirty property of the editor has changed you fired an event.

firePropertyChange(IEditorPart.PROP.DIRTY); 

1.7. API for working with Editors

You can open an Editor via the current active page. For this you need the EditorInput object and the ID for the editor which is defined in the "org.eclipse.ui.editors" extension point.

page.openEditor(new YourEditorInput(), ID_OF_THE_EDITOR); 

To get the page you can use:

// If you are in a view
getViewSite().getPage();
// If you are in an command
HandlerUtil.getActiveWorkbenchWindow(event).getActivePage();
// Somewhere else
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); 

2. Prerequisites for this tutorial

This tutorial assumes what you have basic understanding of development for the Eclipse platform. Please see Eclipse RCP Tutorial or Eclipse Plug-in Tutorial if you need any basic information.

3. Tutorial: Creation of an editor

This tutorials describes the creation of an editor. It also shows how an editor can interact with a view. We will create a view which shows several persons.

3.1. Create project and data model

Create a new RCP project "de.vogella.rcp.editor.example". Use the "RCP application with a view" as a template. Create the package "de.vogella.rcp.editor.example.model" and create the following classes in this package.

package de.vogella.rcp.editor.example.model;

public class Person {
  private static int counter = 0;
  private int id;
  private String firstName;
  private String lastName;

  public Person(String firstName, String lastName) {
    id = counter++;
    this.firstName = firstName;
    this.lastName = lastName;
  }

  public int getId() {
    return id;
  }

  public String getFirstName() {
    return firstName;
  }

  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }

  public String getLastName() {
    return lastName;
  }

  public void setLastName(String lastName) {
    this.lastName = lastName;
  }

  @Override
  public String toString() {
    return firstName + " " + lastName;
  }

  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result
        + ((firstName == null) ? 0 : firstName.hashCode());
    result = prime * result
        + ((lastName == null) ? 0 : lastName.hashCode());
    return result;
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj)
      return true;
    if (obj == null)
      return false;
    if (getClass() != obj.getClass())
      return false;
    Person other = (Person) obj;
    if (firstName == null) {
      if (other.firstName != null)
        return false;
    } else if (!firstName.equals(other.firstName))
      return false;
    if (lastName == null) {
      if (other.lastName != null)
        return false;
    } else if (!lastName.equals(other.lastName))
      return false;
    return true;
  }

} 

The following class will serve as a data model content provider.

package de.vogella.rcp.editor.example.model;

import java.util.ArrayList;
import java.util.List;

public class MyModel {

  private static MyModel model;
  private List<Person> persons = new ArrayList<Person>();

  private MyModel() {
    Person person = new Person("Hans", "Nase");
    persons.add(person);
    person = new Person("Jim", "Knopf");
    persons.add(person);
  }

  public static MyModel getInstance() {
    if (model == null) {
      model = new MyModel();
    }
    return model;
  }

  public List<Person> getPersons() {
    return persons;
  }

  public Person getPersonById(int id) {
    for (Person person : persons) {
      if (person.getId() == id) {
        System.out.println("returned");
        return person;
      }
    }
    return null;
  }
} 

3.2. Editor area

Make the editor area visible by changing your Perspective.java.

package de.vogella.rcp.editor.example;

import org.eclipse.ui.IPageLayout;

public class Perspective implements IPerspectiveFactory {

  public void createInitialLayout(IPageLayout layout) {
//    layout.setEditorAreaVisible(false);
    layout.setFixed(true);
  }

} 

3.3. Editor Input

Create the following new class "MyPersonEditorInput" which implements IEditorInput.

package de.vogella.rcp.editor.example.editor;

import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IPersistableElement;

public class MyPersonEditorInput implements IEditorInput {

    private final int id;

    public MyPersonEditorInput(int id) {
        this.id = id;
    }
    public int getId() {
        return id;
    }

    @Override
    public boolean exists() {
        return true;
    }

    @Override
    public ImageDescriptor getImageDescriptor() {
        return null;
    }

    @Override
    public String getName() {
        return String.valueOf(id);
    }

    @Override
    public IPersistableElement getPersistable() {
        return null;
    }

    @Override
    public String getToolTipText() {
        return "Displays a person";
    }

    @Override
    public Object getAdapter(Class adapter) {
        return null;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + id;
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        MyPersonEditorInput other = (MyPersonEditorInput) obj;
        if (id != other.id)
            return false;
        return true;
    }
   

} 

3.4. Adding the editor

Go to plugin.xml and add the extension "org.eclipse.ui.editors".

Do not use a template. Use the ID "de.vogella.rcp.editor.example.editor.personeditor", any name you want and the class "de.vogella.rcp.editor.example.editor.MyPersonEditor".

Click on the class hyperlink to create the class. Make sure the variable "ID" matches the ID of the editor extension.

package de.vogella.rcp.editor.example.editor;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.EditorPart;

import de.vogella.rcp.editor.example.model.MyModel;
import de.vogella.rcp.editor.example.model.Person;

public class MyPersonEditor extends EditorPart {
  public static final String ID = "de.vogella.rcp.editor.example.editor.personeditor";
  private Person person;
  private MyPersonEditorInput input;

  // Will be called before createPartControl
  @Override
  public void init(IEditorSite site, IEditorInput input)
      throws PartInitException {
    if (!(input instanceof MyPersonEditorInput)) {
      throw new RuntimeException("Wrong input");
    }

    MyPersonEditorInput new_name = (MyPersonEditorInput) input;
    this.input = (MyPersonEditorInput) input;
    setSite(site);
    setInput(input);
    person = MyModel.getInstance().getPersonById(this.input.getId());
    setPartName("Person ID: " + person.getId());
  }

  @Override
  public void createPartControl(Composite parent) {
    GridLayout layout = new GridLayout();
    layout.numColumns = 2;
    parent.setLayout(layout);
    Label label1 = new Label(parent, SWT.NONE);
    label1.setText("First Name");
    Text text = new Text(parent, SWT.BORDER);
    text.setText(person.getFirstName());
    text.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
    new Label(parent, SWT.NONE).setText("Last Name");
    Text lastName = new Text(parent, SWT.BORDER);
    lastName.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true,
        false));
    lastName.setText(person.getLastName());
  }

  @Override
  public void doSave(IProgressMonitor monitor) {
    // person.getAddress().setCountry(text2.getText());
  }

  @Override
  public void doSaveAs() {
  }

  @Override
  public boolean isDirty() {

    return false;
  }

  @Override
  public boolean isSaveAsAllowed() {
    return false;
  }

  @Override
  public void setFocus() {
  }

} 

3.5. Command for opening the editor

Create a command "de.vogella.rcp.editor.example.openEditor" with the default handler "de.vogella.rcp.editor.example.handler.CallEditor".

Create the following class "de.vogella.rcp.intro.editor.handler.CallEditor".

package de.vogella.rcp.editor.example.handler;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.handlers.HandlerUtil;

import de.vogella.rcp.editor.example.View;
import de.vogella.rcp.editor.example.editor.MyPersonEditor;
import de.vogella.rcp.editor.example.editor.MyPersonEditorInput;
import de.vogella.rcp.editor.example.model.Person;

public class CallEditor extends AbstractHandler {

  @Override
  public Object execute(ExecutionEvent event) throws ExecutionException {
    System.out.println("called");
    // get the view
    IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindow(event);
    IWorkbenchPage page = window.getActivePage();
    View view = (View) page.findView(View.ID);
    // get the selection
    ISelection selection = view.getSite().getSelectionProvider()
        .getSelection();
    if (selection != null && selection instanceof IStructuredSelection) {
      Object obj = ((IStructuredSelection) selection).getFirstElement();
      // if we had a selection lets open the editor
      if (obj != null) {
        Person person = (Person) obj;
        MyPersonEditorInput input = new MyPersonEditorInput(person.getId());
        try {
          page.openEditor(input, MyPersonEditor.ID);

        } catch (PartInitException e) {
          throw new RuntimeException(e);
        }
      }
    }
    return null;
  }

} 

3.6. View changes

We will change the class "View" to use JFace Viewers and add a double-click listener to call the command. The view makes his viewer available as selection provider via the following line:" getSite().setSelectionProvider(viewer);". This make is possible for the command which opens the editor to get the selection of the view. All workbench parts have a site, which can be accessed via the method getSite(). A site is a Facade which allows access to other parts of the workbench, e.g. the shell, the workbench window, etc. Whenever possible use the site to access Workbench objects.

package de.vogella.rcp.editor.example;

import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.ListViewer;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.part.ViewPart;

import de.vogella.rcp.editor.example.model.MyModel;
import de.vogella.rcp.editor.example.model.Person;

public class View extends ViewPart {
  public static final String ID = "de.vogella.rcp.editor.example.view";

  private ListViewer viewer;

  public void createPartControl(Composite parent) {
    viewer = new ListViewer(parent);
    viewer.setContentProvider(ArrayContentProvider.getInstance());
    viewer.setLabelProvider(new LabelProvider() {
      @Override
      public String getText(Object element) {
        Person p = (Person) element;
        return p.getFirstName() + " " + p.getLastName();
      };
    });
    viewer.setInput(MyModel.getInstance().getPersons());
    getSite().setSelectionProvider(viewer);
    hookDoubleClickCommand();

  }

  private void hookDoubleClickCommand() {
    viewer.addDoubleClickListener(new IDoubleClickListener() {
      public void doubleClick(DoubleClickEvent event) {
        IHandlerService handlerService = (IHandlerService) getSite()
            .getService(IHandlerService.class);
        try {
          handlerService.executeCommand("de.vogella.rcp.editor.example.openEditor", null);
        } catch (Exception ex) {
          throw new RuntimeException("de.vogella.rcp.editor.example.openEditor not found");
        }
      }
    });
  }

  public void setFocus() {
    viewer.getControl().setFocus();
  }
} 

Run the application. If you double-click on an item in the view, the editor should opened.

To participate in the global save command, set the isDirty property in your editor and call firePropertyChange(IEditorPart.PROP_DIRTY); to notify the workbench. I leave this as an exercise to the reader.

4. Support this website

This tutorial is Open Content under the CC BY-NC-SA 3.0 DE license. Source code in this tutorial is distributed under the Eclipse Public License. See the vogella License page for details on the terms of reuse.

Writing and updating these tutorials is a lot of work. If this free community service was helpful, you can support the cause by giving a tip as well as reporting typos and factual errors.

4.1. Thank you

Please consider a contribution if this article helped you. It will help to maintain our content and our Open Source activities.

4.2. Questions and Discussion

If you find errors in this tutorial, please notify me (see the top of the page). Please note that due to the high volume of feedback I receive, I cannot answer questions to your implementation. Ensure you have read the vogella FAQ as I don't respond to questions already answered there.

5. Links and Literature

5.1. Source Code

Source Code of Examples

5.2. Eclipse Resources

JFace Data Binding

5.3. vogella Resources

vogella Training Android and Eclipse Training from the vogella team

Android Tutorial Introduction to Android Programming

GWT Tutorial Program in Java, compile to JavaScript and HTML

Eclipse RCP Tutorial Create native applications in Java

JUnit Tutorial Test your application

Git Tutorial Put all your files in a distributed version control system