blob: 37d7a8bd2018c1df174409527f0db10a71a499ac [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.ui.forms.editor;
import java.util.Vector;
import org.eclipse.jface.viewers.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.ui.*;
import org.eclipse.ui.forms.IManagedForm;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.part.*;
/**
* 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.0
*/
public abstract class FormEditor extends MultiPageEditorPart {
private FormToolkit toolkit;
protected Vector pages;
private IEditorPart sourcePage;
private int currentPage = -1;
private static class FormEditorSelectionProvider
extends
MultiPageSelectionProvider {
private ISelection globalSelection;
/**
* @param multiPageEditor
*/
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();
}
return globalSelection;
}
/*
* (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() {
pages = new Vector();
}
/**
* 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() {
toolkit = createToolkit(getContainer().getDisplay());
addPages();
}
/**
* 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();
/**
* 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 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(control);
} catch (PartInitException e) {
// cannot happen for controls
}
return i;
}
/**
* Adds the complete editor part to the multi-page editor.
*/
public int addPage(IEditorPart editor, IEditorInput input)
throws PartInitException {
int index = super.addPage(editor, input);
if (editor instanceof IFormPage) {
configurePage(index, (IFormPage) editor);
}
return index;
}
/**
* 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(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.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 oldPage = getCurrentPage();
if (oldPage != -1 && pages.size() > oldPage
&& pages.get(oldPage) instanceof IFormPage
&& oldPage != newPageIndex) {
// Check the old page
IFormPage oldFormPage = (IFormPage) pages.get(oldPage);
if (oldFormPage.canLeaveThePage() == false) {
setActivePage(oldPage);
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 (oldPage != -1 && pages.size() > oldPage
&& pages.get(oldPage) instanceof IFormPage) {
// Commit old page before activating the new one
IFormPage oldFormPage = (IFormPage) pages.get(oldPage);
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 (oldPage != -1 && pages.size() > oldPage
&& pages.get(oldPage) instanceof IFormPage)
((IFormPage) pages.get(oldPage)).setActive(false);
// Call super - this will cause pages to switch
super.pageChange(newPageIndex);
this.currentPage = newPageIndex;
}
/**
* 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
*/
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(Object page) throws PartInitException {
if (!pages.contains(page))
pages.add(page);
if (page instanceof IFormPage) {
IFormPage fpage = (IFormPage) page;
if (fpage.isEditor() == false)
fpage.init(getEditorSite(), getEditorInput());
}
}
}