com.atlassian.confluence.content.render.xhtml.migration.exceptions.UnknownMacroMigrationException: The macro 'next_previous_links' is unknown.

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();
	  }
	} 

 

Add the following extension to integrate your view to Eclipse.
 


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.

com.atlassian.confluence.content.render.xhtml.migration.exceptions.UnknownMacroMigrationException: The macro 'next_previous_links2' is unknown.