Search This Blog

Friday 4 June 2010

Eclipse plugin development: running a plugin as an RCP application, custom problems view

The Eclipse framework comes with extremely powerful and reusable tools.
One of these is the problems view, which doesn't work (on Eclipse Galileo) when running the plugin as a RCP application.


Here comes a custom problem view simple and minimal implementation, as a replacement of the original one, for RCP plugins.


-----------
the view



package org.eclipse.gmf.helpDesigner.helpDesigner.diagram.part;

import java.util.List;

import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Table;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.part.ViewPart;

public class ProblemsView extends ViewPart {
 public static final String ID = "org.eclipse.gmf.helpDesigner.helpDesigner.diagram.part.ProblemsView";

 public TableViewer viewer;
 private UpdateJob updateJob;

 public void createPartControl(Composite parent) {
  createViewer(parent);
  updateJob = new UpdateJob("updateMarkers");
  IEditorPart editorPart = getSite().getPage().getActiveEditor();
  updateJob.setEditorPart(editorPart);
  updateJob.setProblemsView(this);
  updateJob.schedule();
  viewer.setInput(updateJob.getMarkerList());
 }

 private void createViewer(Composite parent) {
  viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL
    | SWT.V_SCROLL | SWT.FULL_SELECTION);
  createColumns(viewer);
  viewer.setContentProvider(new MarkerContentProvider());
  viewer.setLabelProvider(new MarkerLabelProvider());
 }

 // This will create the columns for the table
 private void createColumns(TableViewer viewer) {

  String[] titles = { "Description", "Location", "Type" };
  int[] bounds = { 100, 100, 100 };

  for (int i = 0; i < titles.length; i++) {
   TableViewerColumn column = new TableViewerColumn(viewer, SWT.NONE);
   column.getColumn().setText(titles[i]);
   column.getColumn().setWidth(bounds[i]);
   column.getColumn().setResizable(true);
   column.getColumn().setMoveable(true);
  }
  Table table = viewer.getTable();
  table.setHeaderVisible(true);
  table.setLinesVisible(true);
 }

 /**
  * Passing the focus request to the viewer's control.
  */
 public void setFocus() {
  viewer.getControl().setFocus();
 }

 public static Display getDisplay() {
  Display display = Display.getCurrent();
  // may be null if outside the UI thread
  if (display == null)
   display = Display.getDefault();
  return display;
 }

 public void clearMarkers() {
  getDisplay().syncExec(new Runnable() {
   public void run() {
    while (viewer.getElementAt(0) != null) {
     viewer.remove(viewer.getElementAt(0));
    }
   }
  });
 }

 public void addMarkers(final List markers) {
  getDisplay().syncExec(new Runnable() {
   public void run() {
    viewer.add(markers.toArray());
   }
  });
 }
}

which I've mapped in my plugin.xml of the diagram code generated by GMF with the following xml mapping
<extension point="org.eclipse.ui.views">
	   <view
	         class="org.eclipse.gmf.helpDesigner.helpDesigner.diagram.part.ProblemsView"
	         id="org.eclipse.gmf.helpDesigner.helpDesigner.diagram.part.ProblemsView"
	         icon="icons\eview16\problems_view.gif"
	         name="Problems view">
	   </view>
</extension>
the job updating the markers

package org.eclipse.gmf.helpDesigner.helpDesigner.diagram.part;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.gef.EditPartViewer;
import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil;
import org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.ui.IEditorPart;

public class UpdateJob extends Job {

 public UpdateJob(String name) {
  super(name);
 }

 private List markerList;
 private IEditorPart editorPart;
 private ProblemsView problemsView;

 public List getMarkerList() {
  return markerList;
 }

 public void setEditorPart(IEditorPart editorPart) {
  this.editorPart = editorPart;
 }

 public void setProblemsView(ProblemsView problemsView) {
  this.problemsView = problemsView;
 }

 protected IStatus run(IProgressMonitor monitor) {
  try {
   if (editorPart instanceof IDiagramWorkbenchPart) {
    final IDiagramWorkbenchPart part = (IDiagramWorkbenchPart) editorPart;

    int severity = IStatus.INFO;

    EditPartViewer viewer = part.getDiagramEditPart().getViewer();

    View view = part.getDiagram();

    if (view == null) {
     return Status.CANCEL_STATUS;
    }

    problemsView.clearMarkers();

    for (Iterator it = view.eAllContents(); it.hasNext();) {
     EObject next = (EObject) it.next();
     if (next instanceof View) {
      ValidationMarker[] markers = ValidationMarker
        .getMarkers(viewer, ViewUtil
          .getIdStr((View) next));

      if (markers != null && markers.length > 0) {
       markerList = new ArrayList();
       for (int i = 0; i < markers.length; i++) {
        markerList.add(markers[i]);
       }
       problemsView.addMarkers(markerList);
      }

     }
    }
   }
   return Status.OK_STATUS;
  } finally {
   schedule(2000); //runs every 2 seconds
  }
 }
}

a couple of classes responsible for drawing marker properties in the table

package org.eclipse.gmf.helpDesigner.helpDesigner.diagram.part;

import java.util.List;

import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.Viewer;

public class MarkerContentProvider implements IStructuredContentProvider {

 @Override
 public Object[] getElements(Object inputElement) {
  @SuppressWarnings("unchecked")
  List markers = (List) inputElement;
  return markers.toArray();
 }

 @Override
 public void dispose() {
 }

 @Override
 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
 }

}
package org.eclipse.gmf.helpDesigner.helpDesigner.diagram.part;

import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.swt.graphics.Image;

public class MarkerLabelProvider extends LabelProvider implements
  ITableLabelProvider {

 private static final Image ERROR = HelpDesignerDiagramEditorPlugin
   .getBundledImageDescriptor("icons/obj16/error_tsk.gif")
   .createImage();

 @Override
 public String getColumnText(Object element, int columnIndex) {
  ValidationMarker marker = (ValidationMarker) element;
  switch (columnIndex) {
  case 0:
   return marker.getMessage();
  case 1:
   return marker.getLocation();
  case 2:
   switch (marker.getStatusSeverity()) {
   case Diagnostic.OK:
    return "OK";
   case Diagnostic.INFO:
    return "Info";
   case Diagnostic.WARNING:
    return "Warning";
   case Diagnostic.ERROR:
    return "Error";
   default:
    throw new RuntimeException("Should not happen");
   }
  default:
   throw new RuntimeException("Should not happen");
  }

 }

 @Override
 public Image getColumnImage(Object element, int columnIndex) {
  if (columnIndex == 0) {
   switch (((ValidationMarker) element).getStatusSeverity()) {
   case Diagnostic.ERROR:
    return ERROR;
   }
  }
  return null;
 }

}

4 comments:

  1. Hello,

    I found your post in the eclipse forum (http://www.eclipse.org/forums/index.php?t=msg&th=169079&S=ea234880550bc7c793cea5e3e17ac20c) this is how I got here. I have exactly the same problem (validation works if the project is executed as an eclipse plugin but not when exporting as rcp)
    I introduced your code in my project and it works well (although there is still a lot to be implemented - markers on the graphical figures and relation between markers in the problems view and markers in the graphical view).
    I was curios if finally you used the solution presented in this post or did you finally find a way to use the original Eclipse Problems View ?


    thanks,
    emil.

    ReplyDelete
  2. Hi Emil, sorry for the delay in the answer: I've used the posted solution and didn't manage to use the original Eclipse Problems View.

    ReplyDelete
  3. I did exactly what you have mentioned above,but i can't see the new problems view at my rcp app.I can't even enable it through the windows menu.
    Any ideas?

    ReplyDelete
  4. hello leontiad, send me your code and I'll have a look at it

    ReplyDelete