Previous Page
Next Page

8.4. Editor Lifecycle

Typical editors go through an open-modify-save-close lifecycle. When the editor is opened, the init(IEditorSite, IEditorInput) method is called to set the editor's initial content. When the user modifies the editor's content, the editor must notify others that its content is now "dirty" by using the firePropertyChange(int) method. When a user saves the editor's content, the firePropertyChange(int) method must be used again to notify registered listeners that the editor's content is no longer dirty. Eclipse automatically registers listeners to perform various tasks based on the value returned by the isDirty() method, such as updating the editor's title, adding or removing an asterisk preceding the title, and enabling the Save menu. Finally, when the editor is closed, the editor's content is saved if the isDirty() method returns true.

8.4.1. Dirty editors

You need to ensure that the editor knows whether its content has been modified by the user since the last save operation. To do this, introduce this new field to track whether the current page has been modified relative to the other pages:

private boolean isPageModified;

Whenever the current page's content has been modified, you need to set the new isPageModified field. Whenever the tree is modified, the cell modifier calls the treeModified() method (see Section 8.3.2, Cell modifiers, on page 345), where the new isPageModified field can be set.

public void treeModified() {
   boolean wasDirty = isDirty();
   isPageModified = true;
   if (!wasDirty)
       firePropertyChange(IEditorPart.PROP_DIRTY);
}

Whenever the text editor is modified, the MultiPageEditorPart's addPage() method uses the handlePropertyChange(int) method (see the createSourcePage() method in Section 8.2.2, Editor controls, on page 331) to notify others when the editor's content has changed. You can override this method to set the isPageModified field as appropriate:

protected void handlePropertyChange (int propertyId) {
   if (propertyId == IEditorPart.PROP_DIRTY)
      isPageModified = isDirty();
   super.handlePropertyChange(propertyId);
}

Finally, you need to let other registered listeners know when the editor's content is dirty. The MultiPageEditorPart's isDirty() method appropriately returns true for the nested text editor on the Source page, but knows nothing about modifications to the tree. Overriding this method to add this knowledge causes the Save menu item to be enabled and the editor's title to be updated at the appropriate time.

public boolean isDirty() {
   return isPageModified || super.isDirty();
}

8.4.2. Switching pages

When switching between the Properties and Source pages, any edits made in the Properties page must automatically carry over to the Source page, and vice versa. To accomplish this, override the pageChange(int) method to update the page content as follows:

protected void pageChange(int newPageIndex) {
   switch (newPageIndex) {
      case 0 :
         if (isDirty())
            updateTreeFromTextEditor();
         break;
      case 1 :
         if (isPageModified)
            updateTextEditorFromTree();
         break;
   }
   isPageModified = false;
   super.pageChange(newPageIndex);
}

The updateTreeFromTextEditor() method has already been defined (see Section 8.2.3, Editor model, on page 335), but the updateTextEditorFromTree() method has not, so add it now.

void updateTextEditorFromTree() {
   textEditor
      .getDocumentProvider()
      .getDocument(textEditor.getEditorInput())
      .set(((PropertyFile) treeViewer.getInput()).asText());
}

The updateTextEditorFromTree() method calls a new asText() method in the PropertyFile. The new asText() method reverses the parsing process in the PropertyFile's constructor (see Section 8.2.3, Editor model, on page 335) by reassembling the model into a textual representation.

public String asText() {
   StringWriter stringWriter = new StringWriter(2000);
   PrintWriter writer = new PrintWriter(stringWriter);
   unnamedCategory.appendText(writer);
   Iterator iter = categories.iterator();
   while (iter.hasNext()) {
      writer.println();
      ((PropertyCategory) iter.next()).appendText(writer);
   }
   return stringWriter.toString();
}

The asText() method calls a new appendText(PrintWriter) method in PropertyCategory:

public void appendText(PrintWriter writer) {
   if (name.length() > 0) {
      writer.print("# ");
      writer.println(name);
   }
   Iterator iter = entries.iterator();
   while (iter.hasNext())
      ((PropertyEntry) iter.next()).appendText(writer);
}

which then calls a new appendText(PrintWriter) method in PropertyEntry:

public void appendText(PrintWriter writer) {
   writer.print(key);
   writer.print(" = ");
   writer.println(value);
}

8.4.3. Saving content

Because the current implementation uses the nested text editor to save content into the file being edited, changes on the Properties page will not be noticed unless the user switches to the Source page. The following methods must be modified to update the nested text editor before saving. Since save operations are typically long-running operations, the progress monitor is used to communicate progress to the user (see Section 9.4, Progress Monitor, on page 383).

public void doSave(IProgressMonitor monitor) {
   if (getActivePage() == 0 && isPageModified)
      updateTextEditorFromTree();
   isPageModified = false;
   textEditor.doSave(monitor);
}

public void doSaveAs() {
    if (getActivePage() == 0 && isPageModified)
       updateTextEditorFromTree();
    isPageModified = false;
    textEditor.doSaveAs();
    setInput(textEditor.getEditorInput());
    updateTitle();
}


Previous Page
Next Page