Package org.eclipse.ui.forms.editor

Source Code of org.eclipse.ui.forms.editor.FormEditor

/*******************************************************************************
* Copyright (c) 2000, 2007 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.ui.forms.editor;

import java.util.Vector;

import org.eclipse.core.runtime.ListenerList;
import org.eclipse.jface.dialogs.IPageChangeProvider;
import org.eclipse.jface.dialogs.IPageChangedListener;
import org.eclipse.jface.dialogs.PageChangedEvent;
import org.eclipse.jface.util.SafeRunnable;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorActionBarContributor;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.forms.IManagedForm;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.part.MultiPageEditorActionBarContributor;
import org.eclipse.ui.part.MultiPageEditorPart;
import org.eclipse.ui.part.MultiPageSelectionProvider;

/**
* This class forms a base of multi-page form editors that typically use one or
* more pages with forms and one page for raw source of the editor input.
* <p>
* Pages are added 'lazily' i.e. adding a page reserves a tab for it but does
* not cause the page control to be created. Page control is created when an
* attempt is made to select the page in question. This allows editors with
* several tabs and complex pages to open quickly.
* <p>
* Subclasses should extend this class and implement <code>addPages</code>
* method. One of the two <code>addPage</code> methods should be called to
* contribute pages to the editor. One adds complete (standalone) editors as
* nested tabs. These editors will be created right away and will be hooked so
* that key bindings, selection service etc. is compatible with the one for the
* standalone case. The other method adds classes that implement
* <code>IFormPage</code> interface. These pages will be created lazily and
* they will share the common key binding and selection service. Since 3.1,
* FormEditor is a page change provider. It allows listeners to attach to it and
* get notified when pages are changed. This new API in JFace allows dynamic
* help to update on page changes.
*
* @since 3.0
*/
public abstract class FormEditor extends MultiPageEditorPart implements
    IPageChangeProvider {

  /**
   * An array of pages currently in the editor. Page objects are not limited
   * to those that implement <code>IFormPage</code>, hence the size of this
   * array matches the number of pages as viewed by the user.
   * <p>
   * Subclasses can access this field but should not modify it.
   */
  protected Vector pages = new Vector();

  private FormToolkit toolkit;

  private int currentPage = -1;

  private ListenerList pageListeners = new ListenerList();

  private static class FormEditorSelectionProvider extends
      MultiPageSelectionProvider {
    private ISelection globalSelection;

    /**
     * @param formEditor the editor
     */
    public FormEditorSelectionProvider(FormEditor formEditor) {
      super(formEditor);
    }

    public ISelection getSelection() {
      IEditorPart activeEditor = ((FormEditor) getMultiPageEditor())
          .getActiveEditor();
      if (activeEditor != null) {
        ISelectionProvider selectionProvider = activeEditor.getSite()
            .getSelectionProvider();
        if (selectionProvider != null)
          return selectionProvider.getSelection();
      }
      if (globalSelection != null) {
          return globalSelection;
      }
      return StructuredSelection.EMPTY;
    }

    /*
     * (non-Javadoc) Method declared on <code> ISelectionProvider </code> .
     */
    public void setSelection(ISelection selection) {
      IEditorPart activeEditor = ((FormEditor) getMultiPageEditor())
          .getActiveEditor();
      if (activeEditor != null) {
        ISelectionProvider selectionProvider = activeEditor.getSite()
            .getSelectionProvider();
        if (selectionProvider != null)
          selectionProvider.setSelection(selection);
      } else {
        this.globalSelection = selection;
        fireSelectionChanged(new SelectionChangedEvent(this,
            globalSelection));
      }
    }
  }

  /**
   * The constructor.
   */
  public FormEditor() {
  }

  /**
   * Overrides super to plug in a different selection provider.
   */
  public void init(IEditorSite site, IEditorInput input)
      throws PartInitException {
    setSite(site);
    setInput(input);
    site.setSelectionProvider(new FormEditorSelectionProvider(this));
  }

  /**
   * Creates the common toolkit for this editor and adds pages to the editor.
   *
   * @see #addPages
   */
  protected void createPages() {
    addPages();
  }

  /*
   * @see org.eclipse.ui.part.MultiPageEditorPart#createPageContainer(org.eclipse.swt.widgets.Composite)
   */
  protected Composite createPageContainer(Composite parent) {
    parent = super.createPageContainer(parent);
    toolkit = createToolkit(parent.getDisplay());
    return parent;
  }

  /**
   * Creates the form toolkit. The method can be implemented to substitute a
   * subclass of the toolkit that should be used for this editor. A typical
   * use of this method would be to create the form toolkit using one shared
   * <code>FormColors</code> object to share resources across the multiple
   * editor instances.
   *
   * @param display
   *            the display to use when creating the toolkit
   * @return the newly created toolkit instance
   */
  protected FormToolkit createToolkit(Display display) {
    return new FormToolkit(display);
  }

  /**
   * Subclass should implement this method to add pages to the editor using
   * 'addPage(IFormPage)' method.
   */
  protected abstract void addPages();

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.jface.dialogs.IPageChangeProvider#addPageChangedListener(org.eclipse.jface.dialogs.IPageChangedListener)
   */
  public void addPageChangedListener(IPageChangedListener listener) {
    pageListeners.add(listener);
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.jface.dialogs.IPageChangeProvider#removePageChangedListener(org.eclipse.jface.dialogs.IPageChangedListener)
   */
  public void removePageChangedListener(IPageChangedListener listener) {
    pageListeners.remove(listener);
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.jface.dialogs.IPageChangeProvider#getSelectedPage()
   */
  public Object getSelectedPage() {
    return getActivePageInstance();
  }

  /**
   * Adds the form page to this editor. Form page will be loaded lazily. Its
   * part control will not be created until it is activated for the first
   * time.
   *
   * @param page
   *            the form page to add
   */
  public int addPage(IFormPage page) throws PartInitException {
    int i = super.addPage(page.getPartControl());
    configurePage(i, page);
    return i;
  }

  /**
   * Adds the form page to this editor at the specified index (0-based). Form
   * page will be loaded lazily. Its part control will not be created until it
   * is activated for the first time.
   *
   * @param index
   *            the position to add the page at (0-based)
   * @param page
   *            the form page to add
   * @since 3.1
   */
  public void addPage(int index, IFormPage page) throws PartInitException {
    super.addPage(index, page.getPartControl());
    configurePage(index, page);
  }

  /**
   * Adds a simple SWT control as a page. Overrides superclass implementation
   * to keep track of pages.
   *
   * @param control
   *            the page control to add
   * @return the 0-based index of the newly added page
   */
  public int addPage(Control control) {
    int i = super.addPage(control);
    try {
      registerPage(-1, control);
    } catch (PartInitException e) {
      // cannot happen for controls
    }
    return i;
  }

  /**
   * Adds a simple SWT control as a page. Overrides superclass implementation
   * to keep track of pages.
   *
   * @param control
   *            the page control to add
   * @param index
   *            the index at which to add the page (0-based)
   * @since 3.1
   */
  public void addPage(int index, Control control) {
    super.addPage(index, control);
    try {
      registerPage(index, control);
    } catch (PartInitException e) {
      // cannot happen for controls
    }
  }

  /**
   * Tests whether the editor is dirty by checking all the pages that
   * implement <code>IFormPage</code>. If none of them is dirty, the method
   * delegates further processing to <code>super.isDirty()</code>.
   *
   * @return <code>true</code> if any of the pages in the editor are dirty,
   *         <code>false</code> otherwise.
   * @since 3.1
   */

  public boolean isDirty() {
    if (pages != null) {
      for (int i = 0; i < pages.size(); i++) {
        Object page = pages.get(i);
        if (page instanceof IFormPage) {
          IFormPage fpage = (IFormPage) page;
          if (fpage.isDirty())
            return true;
        }
      }
    }
    return super.isDirty();
  }
 
  /**
   * Commits all dirty pages in the editor. This method should
   * be called as a first step of a 'save' operation.
   * @param onSave <code>true</code> if commit is performed as part
   * of the 'save' operation, <code>false</code> otherwise.
   * @since 3.3
   */

  protected void commitPages(boolean onSave) {
    if (pages != null) {
      for (int i = 0; i < pages.size(); i++) {
        Object page = (IFormPage)pages.get(i);
        if (page instanceof IFormPage) {
          IFormPage fpage = (IFormPage)page;
          IManagedForm mform = fpage.getManagedForm();
          if (mform != null && mform.isDirty())
            mform.commit(onSave);
        }
      }
    } 
  }

  /**
   * Adds a complete editor part to the multi-page editor.
   *
   * @see MultiPageEditorPart#addPage(IEditorPart, IEditorInput)
   */
  public int addPage(IEditorPart editor, IEditorInput input)
      throws PartInitException {
    int index = super.addPage(editor, input);
    if (editor instanceof IFormPage)
      configurePage(index, (IFormPage) editor);
    else
      registerPage(-1, editor);
    return index;
  }

  /**
   * Adds a complete editor part to the multi-page editor at the specified
   * position.
   *
   * @see MultiPageEditorPart#addPage(int, IEditorPart, IEditorInput)
   * @since 3.1
   */
  public void addPage(int index, IEditorPart editor, IEditorInput input)
      throws PartInitException {
    super.addPage(index, editor, input);
    if (editor instanceof IFormPage)
      configurePage(index, (IFormPage) editor);
    else
      registerPage(index, editor);
  }

  /**
   * Configures the form page.
   *
   * @param index
   *            the page index
   * @param page
   *            the page to configure
   * @throws PartInitException
   *             if there are problems in configuring the page
   */
  protected void configurePage(int index, IFormPage page)
      throws PartInitException {
    setPageText(index, page.getTitle());
    // setPageImage(index, page.getTitleImage());
    page.setIndex(index);
    registerPage(index, page);
  }

  /**
   * Overrides the superclass to remove the page from the page table.
   *
   * @param pageIndex
   *            the 0-based index of the page in the editor
   */
  public void removePage(int pageIndex) {
    if (pageIndex >= 0 && pageIndex < pages.size()) {
      Object page = pages.get(pageIndex);
      pages.remove(page);
      if (page instanceof IFormPage) {
        IFormPage fpage = (IFormPage) page;
        if (!fpage.isEditor())
          fpage.dispose();
        updatePageIndices();
      }
    }
    super.removePage(pageIndex);
  }

  // fix the page indices after the removal
  private void updatePageIndices() {
    for (int i = 0; i < pages.size(); i++) {
      Object page = pages.get(i);
      if (page instanceof IFormPage) {
        IFormPage fpage = (IFormPage) page;
        fpage.setIndex(i);
      }
    }
  }

  /**
   * Called to indicate that the editor has been made dirty or the changes
   * have been saved.
   */
  public void editorDirtyStateChanged() {
    firePropertyChange(PROP_DIRTY);
  }

  /**
   * Disposes the pages and the toolkit after disposing the editor itself.
   * Subclasses must call 'super' when reimplementing the method.
   */
  public void dispose() {
    super.dispose();
    for (int i = 0; i < pages.size(); i++) {
      Object page = pages.get(i);
      if (page instanceof IFormPage) {
        IFormPage fpage = (IFormPage) page;
        // don't dispose source pages because they will
        // be disposed as nested editors by the superclass
        if (!fpage.isEditor())
          fpage.dispose();
      }
    }
    pages = null;
    // toolkit may be null if editor has been instantiated
    // but never created - see defect #62190
    if (toolkit != null) {
      toolkit.dispose();
      toolkit = null;
    }
  }

  /**
   * Returns the toolkit owned by this editor.
   *
   * @return the toolkit object
   */
  public FormToolkit getToolkit() {
    return toolkit;
  }

  /**
   * Widens the visibility of the method in the superclass.
   *
   * @return the active nested editor
   */
  public IEditorPart getActiveEditor() {
    return super.getActiveEditor();
  }

  /**
   * Returns the current page index. The value is identical to the value of
   * 'getActivePage()' except during the page switch, when this method still
   * has the old active page index.
   * <p>
   * Another important difference is during the editor closing. When the tab
   * folder is disposed, 'getActivePage()' will return -1, while this method
   * will still return the last active page.
   *
   * @see #getActivePage
   * @return the currently selected page or -1 if no page is currently
   *         selected
   */
  protected int getCurrentPage() {
    return currentPage;
  }

  /**
   * @see MultiPageEditorPart#pageChange(int)
   */
  protected void pageChange(int newPageIndex) {
    // fix for windows handles
    int oldPageIndex = getCurrentPage();
    if (oldPageIndex != -1 && pages.size() > oldPageIndex
        && pages.get(oldPageIndex) instanceof IFormPage
        && oldPageIndex != newPageIndex) {
      // Check the old page
      IFormPage oldFormPage = (IFormPage) pages.get(oldPageIndex);
      if (oldFormPage.canLeaveThePage() == false) {
        setActivePage(oldPageIndex);
        return;
      }
    }
    // Now is the absolute last moment to create the page control.
    Object page = pages.get(newPageIndex);
    if (page instanceof IFormPage) {
      IFormPage fpage = (IFormPage) page;
      if (fpage.getPartControl() == null) {
        fpage.createPartControl(getContainer());
        setControl(newPageIndex, fpage.getPartControl());
        fpage.getPartControl().setMenu(getContainer().getMenu());
      }
    }
    if (oldPageIndex != -1 && pages.size() > oldPageIndex
        && pages.get(oldPageIndex) instanceof IFormPage) {
      // Commit old page before activating the new one
      IFormPage oldFormPage = (IFormPage) pages.get(oldPageIndex);
      IManagedForm mform = oldFormPage.getManagedForm();
      if (mform != null)
        mform.commit(false);
    }
    if (pages.size() > newPageIndex
        && pages.get(newPageIndex) instanceof IFormPage)
      ((IFormPage) pages.get(newPageIndex)).setActive(true);
    if (oldPageIndex != -1 && pages.size() > oldPageIndex
        && newPageIndex != oldPageIndex &&
        pages.get(oldPageIndex) instanceof IFormPage)
      ((IFormPage) pages.get(oldPageIndex)).setActive(false);
    // Call super - this will cause pages to switch
    super.pageChange(newPageIndex);
    this.currentPage = newPageIndex;
    IFormPage newPage = getActivePageInstance();
    if (newPage != null)
      firePageChanged(new PageChangedEvent(this, newPage));
  }

  /**
   * Sets the active page using the unique page identifier.
   *
   * @param pageId
   *            the id of the page to switch to
   * @return page that was set active or <samp>null </samp> if not found.
   */
  public IFormPage setActivePage(String pageId) {
    for (int i = 0; i < pages.size(); i++) {
      Object page = pages.get(i);
      if (page instanceof IFormPage) {
        IFormPage fpage = (IFormPage) page;
        if (fpage.getId().equals(pageId)) {
          setActivePage(i);
          return fpage;
        }
      }
    }
    return null;
  }

  /**
   * Finds the page instance that has the provided id.
   *
   * @param pageId
   *            the id of the page to find
   * @return page with the matching id or <code>null</code> if not found.
   */
  public IFormPage findPage(String pageId) {
    for (int i = 0; i < pages.size(); i++) {
      Object page = pages.get(i);
      if (page instanceof IFormPage) {
        IFormPage fpage = (IFormPage) pages.get(i);
        if (fpage.getId().equals(pageId))
          return fpage;
      }
    }
    return null;
  }

  /**
   * Sets the active page using the unique page identifier and sets its input
   * to the provided object.
   *
   * @param pageId
   *            the id of the page to switch to
   * @param pageInput
   *            the page input
   * @return page that was set active or <samp>null </samp> if not found.
   */
  public IFormPage setActivePage(String pageId, Object pageInput) {
    IFormPage page = setActivePage(pageId);
    if (page != null) {
      IManagedForm mform = page.getManagedForm();
      if (mform != null)
        mform.setInput(pageInput);
    }
    return page;
  }

  /**
   * Iterates through the pages calling similar method until a page is found
   * that contains the desired page input.
   *
   * @param pageInput
   *            the object to select and reveal
   * @return the page that accepted the request or <code>null</code> if no
   *         page has the desired object.
   * @see #setActivePage(String, Object)
   */
  public IFormPage selectReveal(Object pageInput) {
    for (int i = 0; i < pages.size(); i++) {
      Object page = pages.get(i);
      if (page instanceof IFormPage) {
        IFormPage fpage = (IFormPage) page;
        if (fpage.selectReveal(pageInput))
          return fpage;
      }
    }
    return null;
  }

  /**
   * Returns active page instance if the currently selected page index is not
   * -1, or <code>null</code> if it is.
   *
   * @return active page instance if selected, or <code>null</code> if no
   *         page is currently active.
   */
  public IFormPage getActivePageInstance() {
    int index = getActivePage();
    if (index != -1) {
      Object page = pages.get(index);
      if (page instanceof IFormPage)
        return (IFormPage) page;
    }
    return null;
  }

  /**
   * @see MultiPageEditorPart#setActivePage(int)
   */
  protected void setActivePage(int pageIndex) {
    // fix for window handles problem
    // this should be called only when the editor is first opened
    if (pages.size() > pageIndex
        && pages.get(pageIndex) instanceof IFormPage) {
      pageChange(pageIndex);
      IFormPage activePage = (IFormPage) pages.get(pageIndex);
      activePage.setActive(true);
      super.setActivePage(pageIndex);
    } else
      super.setActivePage(pageIndex);
    updateActionBarContributor(pageIndex);
  }

  /**
   * Notifies action bar contributor about page change.
   *
   * @param pageIndex
   *            the index of the new page
   */
  protected void updateActionBarContributor(int pageIndex) {
    // this is to enable the undo/redo actions before a page change has
    // occurred
    IEditorActionBarContributor contributor = getEditorSite()
        .getActionBarContributor();
    if (contributor != null
        && contributor instanceof MultiPageEditorActionBarContributor) {
      ((MultiPageEditorActionBarContributor) contributor)
          .setActivePage(getEditor(pageIndex));
    }
  }

  /**
   * Closes the editor programmatically.
   *
   * @param save
   *            if <code>true</code>, the content should be saved before
   *            closing.
   */
  public void close(final boolean save) {
    Display display = getSite().getShell().getDisplay();
    display.asyncExec(new Runnable() {
      public void run() {
        if (toolkit != null) {
          getSite().getPage().closeEditor(FormEditor.this, save);
        }
      }
    });
  }

  private void registerPage(int index, Object page) throws PartInitException {
    if (!pages.contains(page)) {
      if (index == -1)
        pages.add(page);
      else
        pages.add(index, page);
    }
    if (page instanceof IFormPage) {
      IFormPage fpage = (IFormPage) page;
      if (fpage.isEditor() == false)
        fpage.init(getEditorSite(), getEditorInput());
    }
  }

  private void firePageChanged(final PageChangedEvent event) {
    Object[] listeners = pageListeners.getListeners();
    for (int i = 0; i < listeners.length; ++i) {
      final IPageChangedListener l = (IPageChangedListener) listeners[i];
      SafeRunnable.run(new SafeRunnable() {
        public void run() {
          l.pageChanged(event);
        }
      });
    }
  }
}
TOP

Related Classes of org.eclipse.ui.forms.editor.FormEditor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.