Simple Eclipse RCP 3 Application - View and Editor integration

1- Introduction

The document was written based on:
  • Eclipse: 4.4 (LUNA)

In this document, I will create an RCP application with advanced functionality. The basics of RCP will not be repeated. So if you're a beginner with RCP you should preview the document "RCP for beginners" before practicing this tutorial.
The problem is mentioned:
  1. Whenever you make data changes on the Editor, SAVE button will Enabled to allow users to click to save the data. Handling the data saving of Editor.
  2. View displays a list of departments. Users click to select one department  on this View, it will be displayed on the Editor.
  3. Re- updates View when the data on Editor changes. 

2- Create Project RCPTarget

We quickly create a RCPTarget project, which used to declare RCP libraries and runtime environment.
  • File/New/Project
  • File/New/Other...
Enter:
  • Name: Eclipse RCP
  • Location: http://download.eclipse.org/eclipse/updates/4.4/
Click "Set as Target Platform" for libraries take effect on the entire project within the workspace.

3- Create RCP Project

Quick create a RCP Workbench project.
  • File/New/Other...
Enter:
  • Project Name: RCPApplication
Enter:
  • Activator: org.o7planning.tutorial.rcpapplication.Activator
Enter:
  • Package Name: org.o7planning.tutorial.rcpapplication
Project has been created:
You can test by right-clicking on the project, and select Run As/Eclipse Application.

4- Preview Project

This is an image after completing Project.

5- Menu, Toolbar and Action

Normally you can create Menu Items, Toolbar Items from the Commands, declared in plugin.xml. However, you can also create them through customized Action class, or  Action(s) available in the   RCP Workbench library.
ApplicationActionBarAdvisor.java
package org.o7planning.tutorial.rcpapplication;

import org.eclipse.jface.action.ICoolBarManager;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.swt.SWT;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction;
import org.eclipse.ui.application.ActionBarAdvisor;
import org.eclipse.ui.application.IActionBarConfigurer;

public class ApplicationActionBarAdvisor extends ActionBarAdvisor {

  private IWorkbenchAction saveAction;
  private IWorkbenchAction exitAction;
  private IWorkbenchAction aboutAction;

  public ApplicationActionBarAdvisor(IActionBarConfigurer configurer) {
      super(configurer);
  }

  @Override
  protected void makeActions(IWorkbenchWindow window) {

      saveAction = ActionFactory.SAVE.create(window);
      this.register(saveAction);

      exitAction = ActionFactory.QUIT.create(window);
      this.register(exitAction);

      aboutAction = ActionFactory.ABOUT.create(window);
      this.register(aboutAction);

      super.makeActions(window);
  }

  @Override
  protected void fillMenuBar(IMenuManager menuBar) {
      // File
      MenuManager fileMenu = new MenuManager("&File", "file");
      menuBar.add(fileMenu);
      fileMenu.add(exitAction);

      // Help
      MenuManager helpMenu = new MenuManager("&Help", "help");
      menuBar.add(helpMenu);
      helpMenu.add(aboutAction);

      super.fillMenuBar(menuBar);
  }

  @Override
  protected void fillCoolBar(ICoolBarManager coolBar) {
      IToolBarManager toolBar1 = new ToolBarManager(SWT.FLAT | SWT.RIGHT );
      toolBar1.add(saveAction);

      coolBar.add(toolBar1);

      IToolBarManager toolBar2 = new ToolBarManager(SWT.FLAT | SWT.RIGHT );

      toolBar2.add(exitAction);
      coolBar.add(toolBar2);
  }
}

6- Complete Code of the Project

Data Model:

Department.java
package org.o7planning.tutorial.rcpapplication.model;

public class Department {

  private Integer deptId;
  private String deptNo;
  private String deptName;
  private String location;

  public Department() {

  }

  public Department(Integer deptId, String deptNo, String deptName,
          String location) {
      this.deptId = deptId;
      this.deptNo = deptNo;
      this.deptName = deptName;
      this.deptName = deptName;
  }

  public Integer getDeptId() {
      return deptId;
  }

  public void setDeptId(Integer deptId) {
      this.deptId = deptId;
  }

  public String getDeptNo() {
      return deptNo;
  }

  public void setDeptNo(String deptNo) {
      this.deptNo = deptNo;
  }

  public String getDeptName() {
      return deptName;
  }

  public void setDeptName(String deptName) {
      this.deptName = deptName;
  }

  public String getLocation() {
      return location;
  }

  public void setLocation(String location) {
      this.location = location;
  }
}
DepartmentDAO.java
package org.o7planning.tutorial.rcpapplication.model;

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

public class DepartmentDAO {

  private static final List<Department> list = new ArrayList<Department>();

  static {
      list.add(new Department(10, "D10", "ACCOUNTING", "NEW YORK"));
      list.add(new Department(20, "D20", "RESEARCH", "DALLAS"));
      list.add(new Department(30, "D30", "SALES", "CHICAGO"));
      list.add(new Department(40, "D40", "OPERATIONS", "BOSTON"));
  }

  public static List<Department> listDepartment() {
      return list;
  }

  public static int getMaxDeptId() {
      int max = 0;
      for (Department dept : list) {
          if (dept.getDeptId() > max) {
              max = dept.getDeptId();
          }
      }
      return max;
  }

  public static Department findDepartment(int deptId) {
      for (Department dept : list) {
          if (dept.getDeptId() == deptId) {
              return dept;
          }
      }
      return null;
  }

  public static Department findDepartment(String deptNo) {
      for (Department dept : list) {
          if (dept.getDeptNo().equals(deptNo)) {
              return dept;
          }
      }
      return null;
  }

  public static void deleteDepartment(int deptId) {
      Department dept = findDepartment(deptId);
      if (dept == null) {
          return;
      }
      list.remove(dept);
  }

  public static Department updateDepartment(int deptId, String deptNo,
          String deptName, String location) throws DataException {
      Department dept = findDepartment(deptId);
      if (dept == null) {
          return null;
      }
      Department dept2 = findDepartment(deptNo);
      if (dept2 != null && dept2.getDeptId().intValue() != dept.getDeptId()) {
          throw new DataException("Unique Constraints error - deptNo: "
                  + deptNo);
      }
      dept.setDeptNo(deptNo);
      dept.setDeptName(deptName);
      dept.setLocation(location);
      return dept;
  }

  public static Department insertDepartment(String deptNo, String deptName,
          String location) throws DataException {
      Department dept = findDepartment(deptNo);
      if (dept != null) {
          throw new DataException("Unique Constraints error - deptNo: "
                  + deptNo);
      }
      dept = new Department();
      int deptId = getMaxDeptId() + 1;
      dept.setDeptId(deptId);
      dept.setDeptNo(deptNo);
      dept.setDeptName(deptName);
      dept.setLocation(location);
      list.add(dept);
      return dept;
  }
}
DataException.java
package org.o7planning.tutorial.rcpapplication.model;

public class DataException extends Exception {

  private static final long serialVersionUID = 7155764478659670087L;

  public DataException(String message) {
      super(message);
  }
}

Command:

DeptCommand.java
package org.o7planning.tutorial.rcpapplication.command;

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.IEditorPart;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.handlers.HandlerUtil;
import org.o7planning.tutorial.rcpapplication.editor.DeptEditor;
import org.o7planning.tutorial.rcpapplication.editor.DeptEditorInput;
import org.o7planning.tutorial.rcpapplication.model.Department;

public class DeptCommand extends AbstractHandler {

   public static final String ID = "command.dept";

   @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);

       Object selectObj = null;


       // Having selected on DeptListView
       if (selection != null && !selection.isEmpty() && selection instanceof IStructuredSelection ) {
           selectObj = ((IStructuredSelection) selection).getFirstElement();
       }

       
       // No Selection on DeptListView
       // (Create new Department).
       else {
           // Create new Department.
           selectObj = new Department();
       }

       Department dept = (Department) selectObj;
       DeptEditorInput input = new DeptEditorInput(dept);

       boolean found = false;

       // Opening Editor references
       IEditorReference[] eRefs = page.getEditorReferences();
       for (IEditorReference ref : eRefs) {
           IEditorPart editor = ref.getEditor(false);
           if (editor != null && editor instanceof DeptEditor) {
               // Restore
               DeptEditor deptEditor = (DeptEditor) ref.getEditor(true);
               found = true;

               boolean saved = true;

               // If editor is dirty, save it.
               if (deptEditor.isDirty()) {
                   saved = page.saveEditor(deptEditor, true);
               }
               if (saved) {
 
                   // Reset input for DeptEditor.
                   page.reuseEditor(deptEditor, input);
                   deptEditor.showData();
               }
           }
       }
       if (!found) {
           try {
               page.openEditor(input, DeptEditor.ID);
           } catch (PartInitException e) {
               throw new RuntimeException(e);
           }
       }

       return null;
   }
}
MyConstants.java
package org.o7planning.tutorial.rcpapplication.constant;

public class MyConstants {

  public static final int EDITOR_DATA_CHANGED = 999999;  

}

Editor

AbstractBaseEditor.java
package org.o7planning.tutorial.rcpapplication.editor;

import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.EditorPart;
import org.o7planning.tutorial.rcpapplication.constant.MyConstants;
import org.o7planning.tutorial.rcpapplication.other.DirtyListener;
import org.o7planning.tutorial.rcpapplication.other.DirtyUtils;

public abstract class AbstractBaseEditor extends EditorPart {

   private boolean dirty;

   // Will be called before createPartControl
   @Override
   public void init(IEditorSite site, IEditorInput input)
           throws PartInitException {
       // Very Important!!
       setSite(site);
       setInput(input);
   }

 
   // When PROP_DIRTY change, this method will be called by the Workbench.
   // If the method returns true, the SAVE button will enabled, else disable.
   @Override
   public boolean isDirty() {
       return this.dirty;
   }

   // When changing the data editor, call this method to notify to Workbench.
   protected void setDirty(boolean dirty) {
       if (this.dirty != dirty) {
           this.dirty = dirty;
           
           // Notify PROP_DIRTY changes to Workbench.
           this.firePropertyChange(IEditorPart.PROP_DIRTY);
       }
   }

   @Override
   public void doSaveAs() {

   }

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

   @Override
   public void setFocus() {

   }

   // Write code in createPartControl2(Composite)
   @Override
   public final void createPartControl(Composite parent) {
       this.createPartControl2(parent);

       this.showData();
       this.setDirty(false);
       this.firePropertyChange(MyConstants.EDITOR_DATA_CHANGED);

       Control[] controls = this.registryDirtyControls();
       DirtyListener listener = new DirtyListenerImpl();
       DirtyUtils.registryDirty(listener, controls);
   }

   public abstract void showData( );

   // Create controls in this method.
   protected abstract void createPartControl2(Composite parent);

   // If data in Control changed, it fire to Workbench.
   protected abstract Control[] registryDirtyControls();

   class DirtyListenerImpl implements DirtyListener {

       @Override
       public void fireDirty() {
           // If has any change, fire to Editor.
           AbstractBaseEditor.this.setDirty(true);
       }

   }
}
DeptEditor.java
package org.o7planning.tutorial.rcpapplication.editor;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.MessageDialog;
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.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IReusableEditor;
import org.eclipse.ui.IWorkbenchPartConstants;
import org.o7planning.tutorial.rcpapplication.constant.MyConstants;
import org.o7planning.tutorial.rcpapplication.model.Department;
import org.o7planning.tutorial.rcpapplication.model.DepartmentDAO;
import org.o7planning.tutorial.rcpapplication.other.DirtyUtils;


// IReusableEditor: Can setting new input value for this Editor.
public class DeptEditor extends AbstractBaseEditor implements IReusableEditor {

   public static final String ID = "deptEditor";
   private Integer deptId;
   private Text text_deptNo;
   private Text text_deptName;
   private Text text_location;

   public DeptEditor() {
   }

   /**
    * Create contents of the editor part.
    *
    * @param parent
    */
   @Override
   public void createPartControl2(Composite parent) {
       Composite container = new Composite(parent, SWT.NONE);
       container.setLayout(new GridLayout(2, false));

       Label lblDeptNo = new Label(container, SWT.NONE);
       lblDeptNo.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false,
               false, 1, 1));
       lblDeptNo.setText("Dept No");

       text_deptNo = new Text(container, SWT.BORDER);
       text_deptNo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true,
               false, 1, 1));

       Label lblDeptName = new Label(container, SWT.NONE);
       lblDeptName.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false,
               false, 1, 1));
       lblDeptName.setText("Dept Name");

       text_deptName = new Text(container, SWT.BORDER);
       text_deptName.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true,
               false, 1, 1));

       Label lblLocation = new Label(container, SWT.NONE);
       lblLocation.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false,
               false, 1, 1));
       lblLocation.setText("Location");

       text_location = new Text(container, SWT.BORDER);
       text_location.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true,
               false, 1, 1));
       new Label(container, SWT.NONE);

       DirtyListenerImpl dirtyListener = new DirtyListenerImpl();
       DirtyUtils.registryDirty(dirtyListener, this.text_deptName,
               this.text_deptNo, this.text_location);
   }

   @Override
   public void doSave(IProgressMonitor monitor) {
       try {
           String deptNo = this.text_deptNo.getText();
           String deptName = this.text_deptName.getText();
           String location = this.text_location.getText();
           if (this.deptId != null) {
               Department dept = DepartmentDAO.updateDepartment(deptId,
                       deptNo, deptName, location);

               this.setInput(new DeptEditorInput(dept));
               this.setDirty(false);
               this.firePropertyChange(MyConstants.EDITOR_DATA_CHANGED);
           } else {
               Department dept = DepartmentDAO.insertDepartment(deptNo,
                       deptName, location);
               this.setInput(new DeptEditorInput(dept));
               this.setDirty(false);
               this.firePropertyChange(MyConstants.EDITOR_DATA_CHANGED);
           }
       } catch (Exception e) {
           MessageDialog.openError(this.getSite().getShell(), "Error",
                   e.getMessage());
           e.printStackTrace();
       }
   }

   @Override
   protected Control[] registryDirtyControls() {
       return new Control[] { this.text_deptName, this.text_deptNo,
               this.text_location };
   }

   @Override
   public void showData() {
       DeptEditorInput ip = (DeptEditorInput) this.getEditorInput();
       Department dept = ip.getDept();

       this.deptId = dept.getDeptId();
       this.text_deptName.setText(dept.getDeptName() == null ? "" : dept
               .getDeptName());
       this.text_deptNo.setText(dept.getDeptNo() == null ? "" : dept
               .getDeptNo());
       this.text_location.setText(dept.getLocation() == null ? "" : dept
               .getLocation());
       // Clear dirty.
       this.setDirty(false);
   }


   // Override setInput(..) with public (IReusableEditor)
   @Override
   public void setInput(IEditorInput input) {
       super.setInput(input);
       firePropertyChange(IWorkbenchPartConstants.PROP_INPUT);
   }

   public String getDeptInfo() {
       DeptEditorInput input = (DeptEditorInput) this.getEditorInput();
       Department dept = input.getDept();
       if (dept == null) {
           return "";
       }
       String info = dept.getDeptNo() + " - " + dept.getDeptName() + " - "
               + dept.getLocation();
       return info;
   }

}
DeptEditorInput.java
package org.o7planning.tutorial.rcpapplication.editor;

import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IPersistableElement;
import org.o7planning.tutorial.rcpapplication.model.Department;

public class DeptEditorInput implements IEditorInput {

  private Department dept;

  public DeptEditorInput(Department dept) {
      this.dept = dept;
  }

  public Department getDept() {
      return dept;
  }

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

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

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

  @Override
  public String getName() {
      // Required!!
      return "Department";
  }

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

  @Override
  public String getToolTipText() {
      // Required!!
      return "Department";
  }

}

Dirty Manager

DirtyListener.java
package org.o7planning.tutorial.rcpapplication.other;

public interface DirtyListener {
   
   public void fireDirty();
}
DirtyUtils.java
package org.o7planning.tutorial.rcpapplication.other;

import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.events.VerifyListener;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Text;

public class DirtyUtils {

  public static void registryDirty(DirtyListener listener,
          Control... controls) {
      if (controls == null) {
          return;
      }

      for (Control control : controls) {

          if (control instanceof Text) {
              Text text = (Text) control;
              text.addVerifyListener(new VerifyListenerImpl(listener));
          }
          // Checkbox or Radio button
          else if (control instanceof Button) {
              Button button = (Button) control;
              button.addSelectionListener(new SelectionListenerImpl(listener));
          }
          // Not support
          else {
              throw new UnsupportedOperationException("Not support for "
                      + control.getClass().getSimpleName());
          }
      }
  }

  static class VerifyListenerImpl implements VerifyListener {
      private DirtyListener listener;

      public VerifyListenerImpl(DirtyListener listener) {
          this.listener = listener;
      }

      @Override
      public void verifyText(VerifyEvent arg0) {
          listener.fireDirty();
      }

  }

  // For Button (Checkbox, Radio).
  static class SelectionListenerImpl implements SelectionListener {

      private DirtyListener listener;

      public SelectionListenerImpl(DirtyListener listener) {
          this.listener = listener;
      }

      @Override
      public void widgetDefaultSelected(SelectionEvent e) {

      }

      @Override
      public void widgetSelected(SelectionEvent e) {
          listener.fireDirty();
      }

  }

}

Content Provider & Label Provider:

AbstractTableContentLabelProvider.java
package org.o7planning.tutorial.rcpapplication.provider;

import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.graphics.Image;

public abstract class AbstractTableContentLabelProvider implements
      ITableLabelProvider, IStructuredContentProvider {

  @Override
  public void dispose() {

  }

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

  }

  @Override
  public void addListener(ILabelProviderListener listener) {

  }

  @Override
  public boolean isLabelProperty(Object element, String property) {
      return false;
  }

  @Override
  public void removeListener(ILabelProviderListener listener) {

  }

  @Override
  public Image getColumnImage(Object element, int columnIndex) {
      return null;
  }

}
ApplicationWorkbenchWindowAdvisor.java
package org.o7planning.tutorial.rcpapplication;

import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IPartListener2;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartReference;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.application.ActionBarAdvisor;
import org.eclipse.ui.application.IActionBarConfigurer;
import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
import org.eclipse.ui.application.WorkbenchWindowAdvisor;
import org.o7planning.tutorial.rcpapplication.editor.DeptEditor;
import org.o7planning.tutorial.rcpapplication.view.DeptListView;
import org.o7planning.tutorial.rcpapplication.view.DeptView;

public class ApplicationWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor {

   public ApplicationWorkbenchWindowAdvisor(
           IWorkbenchWindowConfigurer configurer) {
       super(configurer);
   }

   public ActionBarAdvisor createActionBarAdvisor(
           IActionBarConfigurer configurer) {
       return new ApplicationActionBarAdvisor(configurer);
   }

   public void preWindowOpen() {
       IWorkbenchWindowConfigurer configurer = getWindowConfigurer();
       configurer.setInitialSize(new Point(400, 300));
       configurer.setShowCoolBar(true);
       configurer.setShowStatusLine(true);
       configurer.setShowPerspectiveBar(true);
       configurer.setTitle("Hello RCP");
   }

   @Override
   public void postWindowOpen() {
       Shell shell = getWindowConfigurer().getWindow().getShell();
       shell.setMaximized(true);

   
       // Register at events related to the components of the page (View, Editor,..)
       PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
               .addPartListener(new IPartListener2() {

                   @Override
                   public void partActivated(IWorkbenchPartReference partRef) {

                   }

                   @Override
                   public void partBroughtToTop(IWorkbenchPartReference partRef) {

                   }

                   @Override
                   public void partClosed(IWorkbenchPartReference partRef) {

                   }

                   @Override
                   public void partDeactivated(IWorkbenchPartReference partRef) {

                   }

                   @Override
                   public void partHidden(IWorkbenchPartReference partRef) {

                   }

                   @Override
                   public void partVisible(IWorkbenchPartReference partRef) {

                   }

                   @Override
                   public void partInputChanged(IWorkbenchPartReference partRef) {

                   }


                   // When a View or Editor opened.
                   @Override
                   public void partOpened(IWorkbenchPartReference partRef) {
                       System.out.println("Part OPENED: "
                               + partRef.getPartName());
                       IWorkbenchPart part = partRef.getPart(false);
                       if (part instanceof DeptListView) {
                           DeptListView deptListView = (DeptListView) part;

                           DeptEditor deptEditor = (DeptEditor) partRef
                                   .getPage().findView(DeptEditor.ID);
                           
     
                           // DeptListView listen to Property Change of DeptEditor.
                           if (deptEditor != null) {
                               deptEditor.addPropertyListener(deptListView);
                           }
                       } else if (part instanceof DeptView) {
                           DeptView deptView = (DeptView) part;

                           DeptEditor deptEditor = (DeptEditor) partRef
                                   .getPage().findView(DeptEditor.ID);
 
                           // DeptView listen to Property Change of DeptEditor.
                           if (deptEditor != null) {
                               deptEditor.addPropertyListener(deptView);
                           }
                       } else if (part instanceof DeptEditor) {
                           DeptEditor deptEditor = (DeptEditor) part;
                           DeptView deptView = (DeptView) partRef.getPage()
                                   .findView(DeptView.ID);

                           // DeptView listen to Property Change of DeptEditor.
                           if (deptView != null) {
                               deptEditor.addPropertyListener(deptView);
                           }

                           DeptListView deptListView = (DeptListView) partRef
                                   .getPage().findView(DeptListView.ID);

       
                           // DeptListView listen to Property Change of DeptEditor.
                           if (deptListView != null) {
                               deptEditor.addPropertyListener(deptListView);
                           }
                       }
                   }
               });
   }
}
  • plugin.xml
plugin.xml
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>

  <extension
        id="application"
        point="org.eclipse.core.runtime.applications">
     <application>
        <run
              class="org.o7planning.tutorial.rcpapplication.Application">
        </run>
     </application>
  </extension>
  <extension
        point="org.eclipse.ui.perspectives">
     <perspective
           name="RCP Perspective"
           class="org.o7planning.tutorial.rcpapplication.Perspective"
           id="RCPApplication.perspective">
     </perspective>
  </extension>
  <extension
        point="org.eclipse.ui.views">
     <view
           class="org.o7planning.tutorial.rcpapplication.view.DeptView"
           id="view.dept"
           name="Dept"
           restorable="true">
     </view>
     <view
           class="org.o7planning.tutorial.rcpapplication.view.DeptListView"
           id="view.deptList"
           name="Dept List"
           restorable="true">
     </view>
  </extension>
  <extension
        point="org.eclipse.ui.editors">
     <editor
           class="org.o7planning.tutorial.rcpapplication.editor.DeptEditor"
           default="false"
           id="deptEditor"
           name="Dept Editor">
     </editor>
  </extension>
  <extension
        point="org.eclipse.ui.commands">
     <command
           defaultHandler="org.o7planning.tutorial.rcpapplication.command.DeptCommand"
           id="command.dept"
           name="Dept Command">
     </command>
  </extension>
  <extension
        point="org.eclipse.ui.perspectiveExtensions">
     <perspectiveExtension
           targetID="*">
        <view
              id="view.deptList"
              minimized="false"
              relationship="left"
              relative="org.eclipse.ui.editorss"
              visible="true">
        </view>
        <view
              id="view.dept"
              minimized="false"
              relationship="right"
              relative="org.eclipse.ui.editorss"
              visible="true">
        </view>
     </perspectiveExtension>
  </extension>
  <extension
        point="org.eclipse.ui.menus">
     <menuContribution
           allPopups="false"
           locationURI="menu:org.eclipse.ui.main.menu">
        <menu
              label="Functions">
           <command
                 commandId="command.dept"
                 label="Open Dept"
                 style="push">
           </command>
        </menu>
     </menuContribution>
  </extension>

</plugin>

7- The components of the Project and explain

7.1- Register listening change from Editor, View

When DeptEditor change, it should inform DeptListView and DeptView to update the information. DeptListView & DeptView necessary implements IPropertyListener. View & Editor listen to each other's events, you can write code in the postWindowOpen method of ApplicationWorkbenchWindowAdvisor:
deptEditor.addPropertyListener(deptView);

deptEditor.addPropertyListener(deptListView);
// Register at events related to the components of the page (View, Editor,..)
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
        .addPartListener(new IPartListener2() {          
  
            // When a View or Editor opened.
            @Override
            public void partOpened(IWorkbenchPartReference partRef) {
                System.out.println("Part OPENED: "
                        + partRef.getPartName());
                IWorkbenchPart part = partRef.getPart(false);
                if (part instanceof DeptListView) {
                    DeptListView deptListView = (DeptListView) part;

                    DeptEditor deptEditor = (DeptEditor) partRef
                            .getPage().findView(DeptEditor.ID);
                    
      
                    // DeptListView listen to Property Change of DeptEditor.
                    if (deptEditor != null) {
                        deptEditor.addPropertyListener(deptListView);
                    }
                } else if (part instanceof DeptView) {
                    DeptView deptView = (DeptView) part;

                    DeptEditor deptEditor = (DeptEditor) partRef
                            .getPage().findView(DeptEditor.ID);
         
                    // DeptView listen to Property Change of DeptEditor.
                    if (deptEditor != null) {
                        deptEditor.addPropertyListener(deptView);
                    }
                } else if (part instanceof DeptEditor) {
                    DeptEditor deptEditor = (DeptEditor) part;
                    DeptView deptView = (DeptView) partRef.getPage()
                            .findView(DeptView.ID);

          
                    // DeptView listen to Property Change of DeptEditor.
                    if (deptView != null) {
                        deptEditor.addPropertyListener(deptView);
                    }

                    DeptListView deptListView = (DeptListView) partRef
                            .getPage().findView(DeptListView.ID);

         
                    // DeptListView listen to Property Change of DeptEditor.
                    if (deptListView != null) {
                        deptEditor.addPropertyListener(deptListView);
                    }
                }
            }
        });
}

7.2- DeptListView

DeptListViewer: Contains a list of departments, when double click on a department it will be shown on DeptEditor.
Screen design:
On DeptListView you need setup SelectionProvider:
// Registration Provider Selection.

this.getSite().setSelectionProvider(tableViewer);
Note:
  • TableViewer, TreeViewer,.. implements ISelectionProvider interface.
You can learn more about how to use this class at:

7.3- DeptEditor

  • AbstractBaseEditor.java  (DeptEditor extends AbstractBaseEditor).
// When PROP_DIRTY change, this method will be called by the Workbench.
// If the method returns true, the SAVE button will enabled, else disable.
@Override
public boolean isDirty() {
    return this.dirty;
}

// When changing the data editor, call this method to notify to Workbench.
protected void setDirty(boolean dirty) {
    if (this.dirty != dirty) {
        this.dirty = dirty;
        
        // Notify PROP_DIRTY changes to Workbench.
        this.firePropertyChange(IEditorPart.PROP_DIRTY);
    }
}

7.4- DeptCommand

DeptCommand is command use to open DeptEditor.

Normally, a command will create an  IEditorInput, open a new Editor and pass Input into. You can also search for available Editors on page, and newly pass IEditorInputthese editors are Editor can re-use (with a new Input), and  it needs implements IReusableEditor.
Getting current page on the workbench window:
// Get the page
IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindow(event);
IWorkbenchPage page = window.getActivePage();
Department dept = (Department) selectObj;
DeptEditorInput input = new DeptEditorInput(dept);

boolean found = false;
// Opening Editor reference
IEditorReference[] eRefs = page.getEditorReferences();
for (IEditorReference ref : eRefs) {
   IEditorPart editor = ref.getEditor(false);
   if (editor != null && editor instanceof DeptEditor) {
       // Restore
       DeptEditor deptEditor = (DeptEditor) ref.getEditor(true);
       found = true;

       boolean saved = true;
 
       // If editor is dirty, save it
       if (deptEditor.isDirty()) {
           saved = page.saveEditor(deptEditor, true);
       }
       if (saved) {

           // Set new input for DeptEditor
           page.reuseEditor(deptEditor, input);
           deptEditor.showData();
       }
   }
}

8- Run Application

Note: If the first run the application does not show the view, right-click the Perspective Bar, select Reset.