Creating a New Editor
Consider an instance where you want to integrate a new plug-in in Eclipse that requires a novel editor format different to the conventional editors (xml, java) that are supported in Eclipse by default. In such an instance, you can create a new editor in Eclipse.Â
When inserting an editor to a specific plug-in tool, you may have to generate a perspective and insert the editor in that perspective. You make the editor area visible and map the editor implementation in that perspective.
In order to develop any form of editor and integrate it with Eclipse, you need to do the following:
- 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
)
The following sections explain how to write three common types of editors during the plug-in development process.
First, generate a simple plug-in with the Eclipse default plug-in support. You can select the Hello, World
plug-in as the template. After creating the plug-in for adding a text editor, you can delete the Hello, World
plug-in’s default classes.
Creating the project and data model
The model class for the editor contains the elements that need to be defined in the editor and the implementations of the equals()
method. An example is shown below.
package org.wso2.developerstudio.text.editor.sample.model; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.util.ArrayList; import java.util.Date; import java.util.List; public class TextEditorModel { private PropertyChangeSupport changes = new PropertyChangeSupport(this); public static final String FIELD_ID = "id"; public static final String FIELD_SUMMARY = "summary"; public static final String FIELD_DESCRIPTION = "description"; public static final String FIELD_COMPLETE = "complete"; public static final String FIELD_DUEDATE = "dueDate"; public static final String FIELD_DEPENDENTS = "dependents"; private long id; private String summary; private String description; private boolean done; private Date dueDate; private List<Long> dependents = new ArrayList<>(); public TextEditorModel(long i) { id = i; } public TextEditorModel(long i, String summary, String description, boolean b, Date date) { this.id = i; this.summary = summary; this.description = description; this.done = b; this.dueDate = date; } public long getId() { return id; } public String getSummary() { return summary; } public void setSummary(String summary) { changes.firePropertyChange(FIELD_SUMMARY, this.summary, this.summary = summary); } public String getDescription() { return description; } public void setDescription(String description) { changes.firePropertyChange(FIELD_DESCRIPTION, this.description, this.description = description); } public boolean isDone() { return done; } public void setDone(boolean isDone) { changes.firePropertyChange(FIELD_COMPLETE, this.done, this.done = isDone); } public Date getDueDate() { return dueDate; } public void setDueDate(Date dueDate) { changes.firePropertyChange(FIELD_DUEDATE, this.dueDate, this.dueDate = dueDate); } public List<Long> getDependentTasks() { return dependents; } public void setDependentTasks(List<Long> dependents) { this.dependents = dependents; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (int) (id ^ (id >>> 32)); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; TextEditorModel other = (TextEditorModel) obj; if (id != other.id) return false; return true; } @Override public String toString() { return "Todo [id=" + id + ", summary=" + summary + "]"; } public TextEditorModel copy() { return new TextEditorModel(id, summary, description, done, dueDate); } public void addPropertyChangeListener(PropertyChangeListener l) { changes.addPropertyChangeListener(l); } public void removePropertyChangeListener(PropertyChangeListener l) { changes.removePropertyChangeListener(l); } }
The following class, which acts as the editor input class for the new editor, should implement the IEditorInput
class.
package org.wso2.developerstudio.text.editor.inputs; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IPersistableElement; public class TextEditorInput implements IEditorInput { private final long id; public TextEditorInput(long id) { this.id = id; } public long 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 Editor Tutorial tooltip"; } @Override public Object getAdapter(Class adapter) { return null; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (int) (id ^ (id >>> 32)); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; TextEditorInput other = (TextEditorInput) obj; if (id != other.id) return false; return true; } }
Creating the content provider
Create the content provider class for your editor model and input as shown below,
package org.wso2.developerstudio.text.editor.sample.model; import java.util.ArrayList; import java.util.Date; import java.util.List; public class TextEditorContentProvider { private static TextEditorContentProvider taskService = new TextEditorContentProvider(); private List<TextEditorModel> textModels = new ArrayList<TextEditorModel>(); private TextEditorContentProvider() { TextEditorModel textEditorModel = new TextEditorModel(0, "New Decription", "New Description Information", false, new Date()); textModels.add(textEditorModel); textEditorModel = new TextEditorModel(1, "Write Documentation", "Write a documentation about editors", true, new Date()); textModels.add(textEditorModel); } public static TextEditorContentProvider getInstance() { return taskService; } public List<TextEditorModel> getTasks() { return textModels; } public TextEditorModel getTaskById(long id) { for (TextEditorModel todo : textModels) { if (todo.getId() == id) { return todo; } } return null; } }
Adding the editor through the extension point
When adding any sort of editor to Eclipse, you need to extend the in-built org.eclipse.ui.editors
 extension point and define the class that is implementing the editor.
You do this in the plugin.xml
file of your plug-in. On the Extensions tab, click Add, add org.eclipse.ui.editors
 in the filter and add the extension point. A form appears in the pane on the right. Add an ID and a class to extend this extension point and click the class link to create the class. Once you fill in the details, it should look similar to the following,
Make sure that the class you just created for the extension point contains the following content:
package org.wso2.developerstudio.text.editor.sample.model; Â import java.util.Date; 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.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.DateTime; 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 org.wso2.developerstudio.text.editor.inputs.TextEditorInput; public class SampleTextEditor extends EditorPart { public static final String ID = "org.wso2.developerstudio.eclipse.text.editor"; private TextEditorModel todo; private TextEditorInput input; // Will be called before createPartControl @Override public void init(IEditorSite site, IEditorInput input) throws PartInitException { if (!(input instanceof TextEditorInput)) { throw new RuntimeException("Wrong input"); } this.input = (TextEditorInput) input; setSite(site); setInput(input); todo = TextEditorContentProvider.getInstance().getTaskById(this.input.getId()); setPartName("Todo ID: " + todo.getId()); } @Override public void createPartControl(Composite parent) { GridLayout layout = new GridLayout(); layout.numColumns = 2; parent.setLayout(layout); new Label(parent, SWT.NONE).setText("Summary"); Text text = new Text(parent, SWT.BORDER); text.setText(todo.getSummary()); text.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false)); new Label(parent, SWT.NONE).setText("Description"); Text lastName = new Text(parent, SWT.BORDER); lastName.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false)); lastName.setText(todo.getDescription()); new Label(parent, SWT.NONE).setText("Done"); Button doneBtn = new Button(parent, SWT.CHECK); doneBtn.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false)); doneBtn.setSelection(todo.isDone()); new Label(parent, SWT.NONE).setText("Due Date"); DateTime dueDate = new DateTime(parent, SWT.CHECK); dueDate.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false)); Date date = todo.getDueDate(); dueDate.setDate(date.getYear(), date.getMonth(), date.getDay()); } @Override public void doSave(IProgressMonitor monitor) { } @Override public void doSaveAs() { } @Override public boolean isDirty() { return false; } @Override public boolean isSaveAsAllowed() { return false; } @Override public void setFocus() { } }
Adding the command to open the editor
The final step in adding an editor via your plug-in is to add a command to open your editor in Eclipse. Eclipse has an extension point to embed your command easily. You create it in your plugin.xml
file in the same way you added the extension point to integrate your editor.
The class content should be as shown below,
Â
package org.wso2.developerstudio.text.editor; import java.util.Map; 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.commands.AbstractHandler; import org.eclipse.ui.handlers.HandlerUtil; import org.wso2.developerstudio.text.editor.inputs.TextEditorInput; import org.wso2.developerstudio.text.editor.sample.model.SampleTextEditor; import org.wso2.developerstudio.text.editor.sample.model.TextEditorModel; @SuppressWarnings("deprecation") public class EditorCallHandler extends AbstractHandler {   @Override   public Object execute(ExecutionEvent event) throws ExecutionException {     // get the page     IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindow(event);     IWorkbenchPage page = window.getActivePage();     // get the selection     ISelection selection = HandlerUtil.getCurrentSelection(event);     if (selection != null && selection instanceof IStructuredSelection) {       Object obj = ((IStructuredSelection) selection).getFirstElement();       // if we had a selection lets open the editor       if (obj != null) {         TextEditorModel todo = (TextEditorModel) obj;         TextEditorInput input = new TextEditorInput(todo.getId());         try {           page.openEditor(input, SampleTextEditor.ID);         } catch (PartInitException e) {           throw new RuntimeException(e);         }       }     }     return null;   }  @Override  public Object execute(Map parameterValuesByName)    throws org.eclipse.ui.commands.ExecutionException {   // TODO Auto-generated method stub   return null;  } }
Add the
editorOverview
class to integrate your editor to a view and enable you to open your editor on a double click event for a particular view element,Â
Â
package org.wso2.developerstudio.text.editor.sample.view; 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 org.wso2.developerstudio.text.editor.sample.model.TextEditorContentProvider; import org.wso2.developerstudio.text.editor.sample.model.TextEditorModel; public class TextEditorOverview extends ViewPart { public static final String ID = "org.wso2.developerstudio.text.editor.sample.textEditorOverview"; private ListViewer viewer; @Override public void createPartControl(Composite parent) { viewer = new ListViewer(parent); viewer.setContentProvider(ArrayContentProvider.getInstance()); viewer.setLabelProvider(new LabelProvider() { @Override public String getText(Object element) { TextEditorModel p = (TextEditorModel) element; return p.getSummary(); }; }); viewer.setInput(TextEditorContentProvider.getInstance().getTasks()); getSite().setSelectionProvider(viewer); hookDoubleClickCommand(); } private void hookDoubleClickCommand() { viewer.addDoubleClickListener(new IDoubleClickListener() { @Override public void doubleClick(DoubleClickEvent event) { IHandlerService handlerService = (IHandlerService) getSite().getService(IHandlerService.class); try { handlerService.executeCommand("org.wso2.developerstudio.text.editor.sample.openEditor", null); } catch (Exception ex) { throw new RuntimeException(ex.getMessage()); } } }); } @Override public void setFocus() { viewer.getControl().setFocus(); } }
Â
Â
Run Eclipse in the self-host mode, click Window > Show View and select the new view Text Editor Overview. The created editor appears in the editor pane of Eclipse.
Text Editor
Writing a text based editor on top of Developer Studio Kernel is almost the same as writing an editor on top of Eclipse. The only difference is that you need to extend the TextEditor
class in your editor instead of the EditorPart
class.
This class extends the org.eclipse.ui.editors.text.TextEditor
. Note that to import this external dependency, you may have to first import it as a dependency feature in your MANIFEST.MF
file. The MANIFEST.MF
file maintains all external and internal dependency information of an Eclipse project. Whenever you import a dependency, you need to mention it in the MANIFEST.MF
file in order for the project to resolve its dependencies. Therefore, in this case, you need to explicitly import org.eclipse.jface.text
via your MANIFEST.MF
file to enable the dependency to implement your text editor.
You can integrate your new editor (in place of the previous editor integrated above) with the view and view the results.
There are many other features you can integrate with your text editor like content assistance and rules. For a step by step guide on how to write a text based editor on top of Eclipse, see the Eclipse Editor Plugin - Tutorial in the Vogella documentation.
Form Editor
In general, forms are UIs used to take user input to provide better user input management and improve the look and feel. Eclipse has in-built support for forms via a forms API and you can use this to integrate forms into Eclipse via an in-built extension point.
In order to add a form, you need to add a view and then embed your form in the view. Create an Eclipse plug-in project with the Developer Studio Kernel plug-in samples and use the sample with a view. You can modify this view sample to embed forms into the view. For more information, see Eclipse Forms API - Tutorial in the Vogella documentation.