blob: 278efe13df161981305d64292494ce3dc9f8ff87 [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.internal;
import java.util.HashMap;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.util.SafeRunnable;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IViewReference;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.misc.UIStats;
import org.eclipse.ui.internal.registry.IViewDescriptor;
import org.eclipse.ui.internal.registry.IViewRegistry;
import org.eclipse.ui.internal.registry.ViewDescriptor;
/**
* The ViewFactory is used to control the creation and disposal of views.
* It implements a reference counting strategy so that one view can be shared
* by more than one client.
*/
/*package*/ class ViewFactory {
private class ViewReference extends WorkbenchPartReference implements IViewReference {
private String secondaryId;
private boolean create = true;
public ViewReference(String id) {
this(id, null);
}
public ViewReference(String id, String secondaryId) {
ViewDescriptor desc = (ViewDescriptor) viewReg.find(id);
ImageDescriptor iDesc = null;
String title = null;
if (desc != null) {
iDesc = desc.getImageDescriptor();
title = desc.getLabel();
}
init(id, title, null, iDesc);
this.secondaryId = secondaryId;
}
/* (non-Javadoc)
* @see org.eclipse.ui.internal.WorkbenchPartReference#dispose()
*/
public void dispose() {
super.dispose();
create = false;
}
/* (non-Javadoc)
* @see org.eclipse.ui.IWorkbenchPartReference#getPage()
*/
public IWorkbenchPage getPage() {
return page;
}
/* (non-Javadoc)
* @see org.eclipse.ui.IWorkbenchPartReference#getPart(boolean)
*/
public IWorkbenchPart getPart(boolean restore) {
if (part != null)
return part;
if (!create)
return null;
if (restore) {
IStatus status = restoreView(this);
if (status.getSeverity() == IStatus.ERROR) {
create = false;
Workbench workbench = (Workbench) PlatformUI.getWorkbench();
if (!workbench.isStarting()) {
ErrorDialog.openError(page.getWorkbenchWindow().getShell(), WorkbenchMessages.getString("ViewFactory.unableToRestoreViewTitle"), //$NON-NLS-1$
WorkbenchMessages.format("ViewFactory.unableToRestoreViewMessage", new String[] { getTitle()}), //$NON-NLS-1$
status, IStatus.WARNING | IStatus.ERROR);
}
} else {
releaseReferences();
}
}
return part;
}
/* (non-Javadoc)
* @see org.eclipse.ui.internal.WorkbenchPartReference#getRegisteredName()
*/
public String getRegisteredName() {
if (part != null)
return part.getSite().getRegisteredName();
IViewRegistry reg = viewReg;
IViewDescriptor desc = reg.find(getId());
if (desc != null)
return desc.getLabel();
return getTitle();
}
/* (non-Javadoc)
* @see org.eclipse.ui.IViewReference
*/
public String getSecondaryId() {
return secondaryId;
}
/* (non-Javadoc)
* @see org.eclipse.ui.IViewReference#getView(boolean)
*/
public IViewPart getView(boolean restore) {
return (IViewPart) getPart(restore);
}
/* (non-Javadoc)
* @see org.eclipse.ui.IViewReference#isFastView()
*/
public boolean isFastView() {
return page.isFastView(this);
}
}
private ReferenceCounter counter;
private HashMap mementoTable = new HashMap();
private WorkbenchPage page;
private IViewRegistry viewReg;
/**
* ViewManager constructor comment.
*/
public ViewFactory(WorkbenchPage page, IViewRegistry reg) {
super();
this.page = page;
this.viewReg = reg;
counter = new ReferenceCounter();
}
/**
* @param ref the <code>IViewReference</code> to restore.
* @return <code>IStatus</code>
*/
public IStatus busyRestoreView(final IViewReference ref) {
if (ref.getPart(false) != null)
return new Status(IStatus.OK, PlatformUI.PLUGIN_ID, 0, "", null); //$NON-NLS-1$
final String viewID = ref.getId();
final IMemento stateMem = (IMemento) mementoTable.get(viewID);
mementoTable.remove(viewID);
final boolean resetPart[] = { true };
final IStatus result[] = new IStatus[] { new Status(IStatus.OK, PlatformUI.PLUGIN_ID, 0, "", null)}; //$NON-NLS-1$
Platform.run(new SafeRunnable() {
public void handleException(Throwable e) {
if (resetPart[0]) {
((ViewReference) ref).setPart(null);
page.hideView(ref);
}
//Execption is already logged.
result[0] = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0, WorkbenchMessages.format("Perspective.exceptionRestoringView", new String[] { viewID }), //$NON-NLS-1$
e);
}
public void run() {
IViewDescriptor desc = viewReg.find(viewID);
if (desc == null) {
result[0] = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0, WorkbenchMessages.format("ViewFactory.couldNotCreate", new Object[] { viewID }), //$NON-NLS-1$
null);
return;
}
// Create the view.
IViewPart view = null;
String label = desc.getLabel();
try {
try {
UIStats.start(UIStats.CREATE_PART, label);
view = desc.createView();
} finally {
UIStats.end(UIStats.CREATE_PART, label);
}
((ViewReference) ref).setPart(view);
} catch (CoreException e) {
PartPane pane = ((ViewReference) ref).getPane();
if (pane != null) {
page.getPerspectivePresentation().removePart(pane);
pane.dispose();
}
result[0] = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0, WorkbenchMessages.format("ViewFactory.initException", new Object[] { desc.getID()}), //$NON-NLS-1$
e);
return;
}
// Create site
ViewSite site = new ViewSite(ref, view, page, desc);
try {
try {
UIStats.start(UIStats.INIT_PART, label);
view.init(site, stateMem);
} finally {
UIStats.end(UIStats.INIT_PART, label);
}
} catch (PartInitException e) {
releaseView(ref);
result[0] = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0, WorkbenchMessages.format("Perspective.exceptionRestoringView", new String[] { viewID }), //$NON-NLS-1$
e);
return;
}
if (view.getSite() != site) {
releaseView(ref);
result[0] = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0, WorkbenchMessages.format("ViewFactory.siteException", new Object[] { desc.getID()}), //$NON-NLS-1$
null);
return;
}
PartPane pane = ((ViewReference) ref).getPane();
if (pane == null) {
pane = new ViewPane(ref, page, page.getPerspective().getTheme());
((ViewReference) ref).setPane(pane);
}
site.setPane(pane);
site.setActionBars(new ViewActionBars(page.getActionBars(), (ViewPane) pane));
resetPart[0] = false;
site.getPane().createChildControl();
result[0] = new Status(IStatus.OK, PlatformUI.PLUGIN_ID, 0, "", null); //$NON-NLS-1$
}
});
return result[0];
}
/**
* Creates an instance of a view defined by id.
*
* This factory implements reference counting. The first call to this
* method will return a new view. Subsequent calls will return the
* first view with an additional reference count. The view is
* disposed when releaseView is called an equal number of times
* to getView.
*/
public IViewReference createView(final String id) throws PartInitException {
return createView(id, null);
}
/**
* Creates an instance of a view defined by id and secondary id.
*
* This factory implements reference counting. The first call to this
* method will return a new view. Subsequent calls will return the
* first view with an additional reference count. The view is
* disposed when releaseView is called an equal number of times
* to createView.
*/
public IViewReference createView(String id, String secondaryId) throws PartInitException {
IViewDescriptor desc = viewReg.find(id);
// ensure that the view id is valid
if (desc == null)
throw new PartInitException(WorkbenchMessages.format("ViewFactory.couldNotCreate", new Object[] { id })); //$NON-NLS-1$
// ensure that multiple instances are allowed if a secondary id is given
if (secondaryId != null) {
if (!desc.getAllowMultiple()) {
throw new PartInitException(WorkbenchMessages.format("ViewFactory.noMultiple", new Object[] { id })); //$NON-NLS-1$
}
}
String key = getKey(id, secondaryId);
IViewReference ref = (IViewReference) counter.get(key);
if (ref == null) {
ref = new ViewReference(id, secondaryId);
counter.put(key, ref);
} else {
counter.addRef(key);
}
return ref;
}
/**
* Remove a view rec from the manager.
*
* The IViewPart.dispose method must be called at a higher level.
*/
private void destroyView(IViewPart view) {
// Free action bars, pane, etc.
PartSite site = (PartSite) view.getSite();
ViewActionBars actionBars = (ViewActionBars) site.getActionBars();
actionBars.dispose();
PartPane pane = site.getPane();
pane.dispose();
// Free the site.
site.dispose();
}
/**
* Returns the key to use in the ReferenceCounter.
*
* @param id the primary view id
* @param secondaryId the secondary view id or <code>null</code>
* @return the key to use in the ReferenceCounter
*/
private String getKey(String id, String secondaryId) {
return secondaryId == null ? id : id + '/' + secondaryId;
}
/**
* Returns the view with the given id, or <code>null</code> if not found.
*/
public IViewReference getView(String id) {
return getView(id, null);
}
/**
* Returns the view with the given id and secondary id, or <code>null</code> if not found.
*/
public IViewReference getView(String id, String secondaryId) {
String key = getKey(id, secondaryId);
return (IViewReference) counter.get(key);
}
/**
* @return the <code>IViewRegistry</code> used by this factory.
* @since 3.0
*/
public IViewRegistry getViewRegistry() {
return viewReg;
}
/**
* Returns a list of views which are open.
*/
public IViewReference[] getViews() {
List list = counter.values();
IViewReference[] array = new IViewReference[list.size()];
list.toArray(array);
return array;
}
/**
* @return the <code>WorkbenchPage</code> used by this factory.
* @since 3.0
*/
public WorkbenchPage getWorkbenchPage() {
return page;
}
/**
* Returns whether a view with the given id exists.
*/
public boolean hasView(String id) {
return getView(id) != null;
}
/**
* Releases an instance of a view.
*
* This factory does reference counting. For more info see
* getView.
*/
public void releaseView(IViewReference viewRef) {
String key = getKey(viewRef.getId(), viewRef.getSecondaryId());
IViewReference ref = (IViewReference) counter.get(key);
if (ref == null)
return;
int count = counter.removeRef(key);
if (count <= 0) {
IViewPart view = (IViewPart) ref.getPart(false);
if (view != null)
destroyView(view);
}
}
/**
* Restore view states.
*
* @param memento the <code>IMemento</code> to restore from.
* @return <code>IStatus</code>
*/
public IStatus restoreState(IMemento memento) {
IMemento mem[] = memento.getChildren(IWorkbenchConstants.TAG_VIEW);
for (int i = 0; i < mem.length; i++) {
//for dynamic UI - add the next line to replace subsequent code that is commented out
restoreViewState(mem[i]);
}
return new Status(IStatus.OK, PlatformUI.PLUGIN_ID, 0, "", null); //$NON-NLS-1$
}
/**
* Creates an instance of a view defined by id.
*
* This factory implements reference counting. The first call to this
* method will return a new view. Subsequent calls will return the
* first view with an additional reference count. The view is
* disposed when releaseView is called an equal number of times
* to getView.
*/
public IStatus restoreView(final IViewReference ref) {
final IStatus result[] = new IStatus[1];
BusyIndicator.showWhile(page.getWorkbenchWindow().getShell().getDisplay(), new Runnable() {
public void run() {
result[0] = busyRestoreView(ref);
}
});
return result[0];
}
/**
* Save view states.
*
* @param memento the <code>IMemento</code> to save to.
* @return <code>IStatus</code>
*/
public IStatus saveState(IMemento memento) {
final MultiStatus result = new MultiStatus(PlatformUI.PLUGIN_ID, IStatus.OK, WorkbenchMessages.getString("ViewFactory.problemsSavingViews"), null); //$NON-NLS-1$
final IViewReference refs[] = getViews();
for (int i = 0; i < refs.length; i++) {
//for dynamic UI - add the following line to replace subsequent code which is commented out
saveViewState(memento, refs[i], result);
}
return result;
}
// for dynamic UI
public IMemento saveViewState(IMemento memento, IViewReference ref, MultiStatus res) {
final MultiStatus result = res;
final IMemento viewMemento = memento.createChild(IWorkbenchConstants.TAG_VIEW);
viewMemento.putString(IWorkbenchConstants.TAG_ID, ref.getId());
final IViewReference viewRef = ref;
final IViewPart view = (IViewPart)ref.getPart(false);
if(view != null) {
Platform.run(new SafeRunnable() {
public void run() {
view.saveState(viewMemento.createChild(IWorkbenchConstants.TAG_VIEW_STATE));
}
public void handleException(Throwable e) {
result.add(new Status(
IStatus.ERROR,PlatformUI.PLUGIN_ID,0,
WorkbenchMessages.format("ViewFactory.couldNotSave",new String[]{viewRef.getTitle()}), //$NON-NLS-1$
e));
}
});
} else {
IMemento mem = (IMemento)mementoTable.get(ref.getId());
if(mem != null) {
IMemento child = viewMemento.createChild(IWorkbenchConstants.TAG_VIEW_STATE);
child.putMemento(mem);
}
}
return viewMemento;
}
// for dynamic UI
public void restoreViewState(IMemento memento){
String id = memento.getString(IWorkbenchConstants.TAG_ID);
mementoTable.put(id, memento.getChild(IWorkbenchConstants.TAG_VIEW_STATE));
}
}