Eclipse Action with Generics

I wrote this code a couple of weeks ago. It’s a nice idea on how to use generics in order to reduce the pain of using the Eclipse API.

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

import org.eclipse.jface.action.IAction;

import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IWorkbenchPart;

/**
 * An eclipse action delegate that performs operations on objects of the
 * specified type. Automatically handles multiple selections. Extend this class
 * specifying the type parameter of the object that the action operates on.
 * Implement the main logic in {@link #runOn(Object, IAction)}.
 *
 * @author Jaksa Vuckovic (vuckovja)
 *
 * @param
 */
public abstract class TypedAction<T> implements IObjectActionDelegate {

  protected List selectedElements = new ArrayList();
  protected Shell shell;

  public void setActivePart(IAction action, IWorkbenchPart targetPart) {
    this.shell = targetPart.getSite().getShell();
  }

  /**
   * The default implementation will iterate over all the selected elements and
   * invoke {@link #runOn(Object, IAction)} on every on of them.
   *
   * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction)
   */
  public void run(IAction action) {
    for (T element : selectedElements) {
      runOn(element, action);
    }
  }

  /**
   * Implement this to invoke the operation on one of the selected elements.
   * This method is called by {@link #run(IAction)} on every selected element.
   *
   * @param selectedElement one of the selected elements
   * @param action the action that has been run
   */
  protected abstract void runOn(T selectedElement, IAction action);

  /**
   * The default implementation will enable the action if all the selected
   * elements are of type T.
   *
   * @see org.eclipse.ui.IActionDelegate#selectionChanged(org.eclipse.jface.action.IAction,
   *      org.eclipse.jface.viewers.ISelection)
   */
  public void selectionChanged(IAction action, ISelection selection) {
    selectedElements.clear();

    boolean enabled = false;

    if (selection instanceof StructuredSelection) {
      enabled = true;

      for (Iterator it = ((StructuredSelection) selection).iterator(); it.hasNext();) {
        try {
          T selectedElement = (T) it.next();
          selectedElements.add(selectedElement);
        } catch (ClassCastException e) {
          enabled = false;
          break;
        }
      }
    }
    action.setEnabled(enabled);
  }
}

Try to refactor your actions to extend this class and you will find a significant reduction in code size

PS: syntax highlighted by Code2HTML, v. 0.9.1

3 comments

  1. K

    Thanks a lot.

    This could further be enhanced by storing a reference to “selection” in selectionChanged() and then looping over the list in run() – This will reduce the execution overhead.

  2. Brad

    Just learning Eclipse and have limited use of generics. Doesn’t the class have to provide a definition of T somewhere? If the
    code as it is here is cut and paste into the browser Eclipse complains.

    If is added as an appended element to the TypedAction name it works — TypedAction

    I’m not sure if that’s what is to be understood here.

Leave a reply to Anonymous Cancel reply