blob: 77dd1dab32318b5b0ce4531d9313d09711e8874e [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.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
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.jface.action.CoolBarManager;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.ListenerList;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.util.SafeRunnable;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IEditorRegistry;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.INavigationHistory;
import org.eclipse.ui.IPartListener;
import org.eclipse.ui.IPartListener2;
import org.eclipse.ui.IPerspectiveDescriptor;
import org.eclipse.ui.IPerspectiveRegistry;
import org.eclipse.ui.IReusableEditor;
import org.eclipse.ui.ISaveablePart;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IViewReference;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartReference;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkingSet;
import org.eclipse.ui.IWorkingSetManager;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.SubActionBars;
import org.eclipse.ui.WorkbenchException;
import org.eclipse.ui.internal.dialogs.CustomizePerspectiveDialog;
import org.eclipse.ui.internal.misc.UIStats;
import org.eclipse.ui.internal.registry.IActionSetDescriptor;
import org.eclipse.ui.internal.registry.IStickyViewDescriptor;
import org.eclipse.ui.internal.registry.IViewRegistry;
import org.eclipse.ui.internal.registry.PerspectiveDescriptor;
import org.eclipse.ui.model.IWorkbenchAdapter;
import org.eclipse.ui.part.MultiEditor;
/**
* A collection of views and editors in a workbench.
*/
public class WorkbenchPage extends CompatibleWorkbenchPage implements IWorkbenchPage {
private WorkbenchWindow window;
private IAdaptable input;
private IWorkingSet workingSet;
private Composite composite;
private ControlListener resizeListener;
private IWorkbenchPart activePart;
//Could be delete. This information is in the active part list;
private ActivationList activationList = new ActivationList();
private IEditorPart lastActiveEditor;
private EditorManager editorMgr;
private EditorAreaHelper editorPresentation;
private PartListenerList partListeners = new PartListenerList();
private PartListenerList2 partListeners2 = new PartListenerList2();
private ListenerList propertyChangeListeners = new ListenerList();
private PageSelectionService selectionService =
new PageSelectionService(this);
private IActionBars actionBars;
private ViewFactory viewFactory;
private PerspectiveList perspList = new PerspectiveList();
private PerspectiveDescriptor deferredActivePersp;
private NavigationHistory navigationHistory = new NavigationHistory(this);
//for dynamic UI - saving state for editors, views and perspectives
private HashMap stateMap = new HashMap();
private IPropertyChangeListener propertyChangeListener =
new IPropertyChangeListener() {
/*
* Remove the working set from the page if the working set is deleted.
*/
public void propertyChange(PropertyChangeEvent event) {
String property = event.getProperty();
if (IWorkingSetManager.CHANGE_WORKING_SET_REMOVE.equals(property)
&& event.getOldValue().equals(workingSet)) {
setWorkingSet(null);
} else if (LayoutPart.PROP_VISIBILITY.equals(property)) {
WorkbenchPartReference ref =
(WorkbenchPartReference) ((PartPane) event.getSource())
.getPartReference();
//Make sure the new visible part is restored.
ref.getPart(Boolean.TRUE.equals(event.getNewValue()));
if (ref == null)
return;
if (Boolean.TRUE.equals(event.getNewValue())) {
String label = "visible::" + ref.getTitle(); //$NON-NLS-1$
try {
UIStats.start(UIStats.NOTIFY_PART_LISTENERS, label);
partListeners2.firePartVisible(ref);
} finally {
UIStats.end(UIStats.NOTIFY_PART_LISTENERS, label);
}
} else {
String label = "hidden::" + ref.getTitle(); //$NON-NLS-1$
try {
UIStats.start(UIStats.NOTIFY_PART_LISTENERS, label);
partListeners2.firePartHidden(ref);
} finally {
UIStats.end(UIStats.NOTIFY_PART_LISTENERS, label);
}
}
}
}
};
// a set of perspectives in which sticky views have already been created.
private Set stickyPerspectives = new HashSet(7);
private ActionSwitcher actionSwitcher = new ActionSwitcher();
/**
* Manages editor contributions and action set part associations.
*/
private class ActionSwitcher {
private IWorkbenchPart activePart;
private IEditorPart topEditor;
private ArrayList actionSets = new ArrayList();
/**
* Updates the contributions given the new part as the active part.
*
* @param newPart
* the new active part, may be <code>null</code>
*/
public void updateActivePart(IWorkbenchPart newPart) {
if (activePart == newPart)
return;
boolean isNewPartAnEditor = newPart instanceof IEditorPart;
if (isNewPartAnEditor) {
String oldId = null;
if (topEditor != null)
oldId = topEditor.getSite().getId();
String newId = newPart.getSite().getId();
// if the active part is an editor and the new editor
// is the same kind of editor, then we don't have to do
// anything
if (activePart == topEditor && newId.equals(oldId))
return;
// remove the contributions of the old editor
// if it is a different kind of editor
if (oldId != null && !oldId.equals(newId))
deactivateContributions(topEditor, true);
// if a view was the active part, disable its contributions
if (activePart != null && activePart != topEditor)
deactivateContributions(activePart, true);
// show (and enable) the contributions of the new editor
// if it is a different kind of editor or if the
// old active part was a view
if (!newId.equals(oldId) || activePart != topEditor)
activateContributions(newPart, true);
} else if (newPart == null) {
if (activePart != null)
// remove all contributions
deactivateContributions(activePart, true);
} else {
// new part is a view
// if old active part is a view, remove all contributions,
// but if old part is an editor only disable
if (activePart != null)
deactivateContributions(
activePart,
activePart instanceof IViewPart);
activateContributions(newPart, true);
}
ArrayList newActionSets = null;
if (isNewPartAnEditor
|| (activePart == topEditor && newPart == null))
newActionSets = calculateActionSets(newPart, null);
else
newActionSets = calculateActionSets(newPart, topEditor);
if (!updateActionSets(newActionSets))
updateActionBars();
if (isNewPartAnEditor) {
topEditor = (IEditorPart) newPart;
} else if (activePart == topEditor && newPart == null) {
// since we removed all the contributions, we clear the top
// editor
topEditor = null;
}
activePart = newPart;
}
/**
* Updates the contributions given the new part as the topEditor.
*
* @param newEditor
* the new top editor, may be <code>null</code>
*/
public void updateTopEditor(IEditorPart newEditor) {
if (topEditor == newEditor)
return;
String oldId = null;
if (topEditor != null)
oldId = topEditor.getSite().getId();
String newId = null;
if (newEditor != null)
newId = newEditor.getSite().getId();
if (oldId == null ? newId == null : oldId.equals(newId)) {
// we don't have to change anything
topEditor = newEditor;
return;
}
// Remove the contributions of the old editor
if (topEditor != null)
deactivateContributions(topEditor, true);
// Show (disabled) the contributions of the new editor
if (newEditor != null)
activateContributions(newEditor, false);
ArrayList newActionSets =
calculateActionSets(activePart, newEditor);
if (!updateActionSets(newActionSets))
updateActionBars();
topEditor = newEditor;
}
/**
* Activates the contributions of the given part. If <code>enable</code>
* is <code>true</code> the contributions are visible and enabled,
* otherwise they are disabled.
*
* @param part
* the part whose contributions are to be activated
* @param enable
* <code>true</code> the contributions are to be enabled,
* not just visible.
*/
private void activateContributions(
IWorkbenchPart part,
boolean enable) {
PartSite site = (PartSite) part.getSite();
SubActionBars actionBars = (SubActionBars) site.getActionBars();
actionBars.activate(enable);
}
/**
* Deactivates the contributions of the given part. If <code>remove</code>
* is <code>true</code> the contributions are removed, otherwise they
* are disabled.
*
* @param part
* the part whose contributions are to be deactivated
* @param remove
* <code>true</code> the contributions are to be removed,
* not just disabled.
*/
private void deactivateContributions(
IWorkbenchPart part,
boolean remove) {
PartSite site = (PartSite) part.getSite();
SubActionBars actionBars = (SubActionBars) site.getActionBars();
actionBars.deactivate(remove);
}
/**
* Calculates the action sets to show for the given part and editor
*
* @param part
* the active part, may be <code>null</code>
* @param editor
* the current editor, may be <code>null</code>, may be
* the active part
* @return the new action sets
*/
private ArrayList calculateActionSets(
IWorkbenchPart part,
IEditorPart editor) {
ArrayList newActionSets = new ArrayList();
if (part != null) {
IActionSetDescriptor[] partActionSets =
WorkbenchPlugin
.getDefault()
.getActionSetRegistry()
.getActionSetsFor(
part.getSite().getId());
for (int i = 0; i < partActionSets.length; i++) {
newActionSets.add(partActionSets[i]);
}
}
if (editor != null && editor != part) {
IActionSetDescriptor[] editorActionSets =
WorkbenchPlugin
.getDefault()
.getActionSetRegistry()
.getActionSetsFor(
editor.getSite().getId());
for (int i = 0; i < editorActionSets.length; i++) {
newActionSets.add(editorActionSets[i]);
}
}
return newActionSets;
}
/**
* Updates the actions we are showing for the active part and current
* editor.
*
* @param newActionSets
* the action sets to show
* @return <code>true</code> if the action sets changed
*/
private boolean updateActionSets(ArrayList newActionSets) {
if (actionSets.equals(newActionSets))
return false;
Perspective persp = getActivePerspective();
if (persp == null) {
actionSets = newActionSets;
return false;
}
// hide the old
for (int i = 0; i < actionSets.size(); i++) {
persp.hideActionSet(
((IActionSetDescriptor) actionSets.get(i)).getId());
}
// show the new
for (int i = 0; i < newActionSets.size(); i++) {
persp.showActionSet(
((IActionSetDescriptor) newActionSets.get(i)).getId());
}
actionSets = newActionSets;
window.updateActionSets(); // this calls updateActionBars
window.firePerspectiveChanged(
WorkbenchPage.this,
getPerspective(),
CHANGE_ACTION_SET_SHOW);
return true;
}
}
/**
* Constructs a new page with a given perspective and input.
*
* @param w
* the parent window
* @param layoutID
* must not be <code>null</code>
* @param input
* the page input
*/
public WorkbenchPage(WorkbenchWindow w, String layoutID, IAdaptable input)
throws WorkbenchException {
super();
if (layoutID == null)
throw new WorkbenchException(WorkbenchMessages.getString("WorkbenchPage.UndefinedPerspective")); //$NON-NLS-1$
init(w, layoutID, input);
}
/**
* Constructs a page. <code>restoreState(IMemento)</code> should be
* called to restore this page from data stored in a persistance file.
*
* @param w
* the parent window
* @param input
* the page input
*/
public WorkbenchPage(WorkbenchWindow w, IAdaptable input)
throws WorkbenchException {
super();
init(w, null, input);
}
/**
* Activates a part. The part will be brought to the front and given focus.
*
* @param part
* the part to activate
*/
public void activate(IWorkbenchPart part) {
// Sanity check.
if (!certifyPart(part))
return;
if (window.isClosing())
return;
// If zoomed, unzoom.
if (isZoomed() && partChangeAffectsZoom(getReference(part)))
zoomOut();
if (part instanceof MultiEditor) {
part = ((MultiEditor) part).getActiveEditor();
}
// Activate part.
if (window.getActivePage() == this) {
bringToTop(part);
setActivePart(part);
} else {
activationList.setActive(part);
activePart = part;
}
}
/**
* Activates a part. The part is given focus, the pane is hilighted.
*/
private void activatePart(final IWorkbenchPart part) {
Platform.run(new SafeRunnable(WorkbenchMessages.getString("WorkbenchPage.ErrorActivatingView")) { //$NON-NLS-1$
public void run() {
if (part != null) {
part.setFocus();
PartSite site = (PartSite) part.getSite();
site.getPane().showFocus(true);
updateTabList(part);
SubActionBars bars = (SubActionBars) site.getActionBars();
bars.partChanged(part);
}
}
});
}
/**
* Add a fast view.
*/
public void addFastView(IViewReference ref) {
Perspective persp = getActivePerspective();
if (persp == null)
return;
// If view is zoomed unzoom.
if (isZoomed() && partChangeAffectsZoom(ref))
zoomOut();
// Do real work.
persp.addFastView(ref);
// The view is now invisible.
// If it is active then deactivate it.
if (ref.getPart(false) == activePart) {
activate(activationList.getActive());
}
// Notify listeners.
window.updateFastViewBar();
window.firePerspectiveChanged(
this,
getPerspective(),
CHANGE_FAST_VIEW_ADD);
}
/**
* Adds an IPartListener to the part service.
*/
public void addPartListener(IPartListener l) {
partListeners.addPartListener(l);
}
/**
* Adds an IPartListener to the part service.
*/
public void addPartListener(IPartListener2 l) {
partListeners2.addPartListener(l);
}
/**
* Implements IWorkbenchPage
*
* @see org.eclipse.ui.IWorkbenchPage#addPropertyChangeListener(IPropertyChangeListener)
* @since 2.0
* @deprecated individual views should store a working set if needed and
* register a property change listener directly with the
* working set manager to receive notification when the view
* working set is removed.
*/
public void addPropertyChangeListener(IPropertyChangeListener listener) {
propertyChangeListeners.add(listener);
}
/*
* (non-Javadoc) Method declared on ISelectionListener.
*/
public void addSelectionListener(ISelectionListener listener) {
selectionService.addSelectionListener(listener);
}
/*
* (non-Javadoc) Method declared on ISelectionListener.
*/
public void addSelectionListener(
String partId,
ISelectionListener listener) {
selectionService.addSelectionListener(partId, listener);
}
/*
* (non-Javadoc) Method declared on ISelectionListener.
*/
public void addPostSelectionListener(ISelectionListener listener) {
selectionService.addPostSelectionListener(listener);
}
/*
* (non-Javadoc) Method declared on ISelectionListener.
*/
public void addPostSelectionListener(
String partId,
ISelectionListener listener) {
selectionService.addPostSelectionListener(partId, listener);
}
/**
* Moves a part forward in the Z order of a perspective so it is visible.
*
* @param part
* the part to bring to move forward
*/
public void bringToTop(IWorkbenchPart part) {
// Sanity check.
Perspective persp = getActivePerspective();
if (persp == null || !certifyPart(part))
return;
// If zoomed then ignore.
if (isZoomed() && partChangeAffectsZoom(getReference(part)))
return;
String label = part != null ? part.getTitle() : "none"; //$NON-NLS-1$
boolean broughtToTop = false;
try {
UIStats.start(UIStats.BRING_PART_TO_TOP, label);
// Move part.
if (part instanceof IEditorPart) {
IEditorReference ref = (IEditorReference) getReference(part);
broughtToTop = getEditorManager().setVisibleEditor(ref, false);
actionSwitcher.updateTopEditor((IEditorPart) part);
if (broughtToTop) {
lastActiveEditor = null;
}
} else if (part instanceof IViewPart) {
IViewReference ref = (IViewReference) getReference(part);
broughtToTop = persp.bringToTop(ref);
}
if (broughtToTop) {
// Need to make sure that the part lists are sorted correctly.
activationList.setActive(part);
firePartBroughtToTop(part);
}
} finally {
UIStats.end(UIStats.BRING_PART_TO_TOP, label);
}
}
/**
* Resets the layout for the perspective. The active part in the old layout
* is activated in the new layout for consistent user context.
*
* Assumes the busy cursor is active.
*/
private void busyResetPerspective() {
ViewIntroAdapterPart introViewAdapter = ((WorkbenchIntroManager)getWorkbenchWindow().getWorkbench().getIntroManager()).getViewIntroAdapterPart();
PartPane introPane = null;
boolean introFullScreen = false;
if (introViewAdapter != null) {
introPane = ((PartSite)introViewAdapter.getSite()).getPane();
introViewAdapter.setHandleZoomEvents(false);
introFullScreen = introPane.isZoomed();
}
//try to prevent intro flicker.
if (introFullScreen)
window.getShell().setRedraw(false);
try {
// Always unzoom
if (isZoomed())
zoomOut();
// Get the current perspective.
// This describes the working layout of the page and differs from
// the original template.
Perspective oldPersp = getActivePerspective();
// Map the current perspective to the original template.
// If the original template cannot be found then it has been deleted.
// In
// that case just return. (PR#1GDSABU).
IPerspectiveRegistry reg =
WorkbenchPlugin.getDefault().getPerspectiveRegistry();
PerspectiveDescriptor desc =
(PerspectiveDescriptor) reg.findPerspectiveWithId(
oldPersp.getDesc().getId());
if (desc == null)
desc =
(PerspectiveDescriptor) reg.findPerspectiveWithId(
((PerspectiveDescriptor) oldPersp.getDesc())
.getOriginalId());
if (desc == null)
return;
IContributionItem item =
window.findPerspectiveShortcut(oldPersp.getDesc(), this);
if (item == null)
return;
// Notify listeners that we are doing a reset.
window.firePerspectiveChanged(this, desc, CHANGE_RESET);
// Create new persp from original template.
Perspective newPersp = createPerspective(desc);
if (newPersp == null) {
// We're not going through with the reset, so it is complete.
window.firePerspectiveChanged(this, desc, CHANGE_RESET_COMPLETE);
return;
}
// Update the perspective list and shortcut
perspList.swap(oldPersp, newPersp);
((PerspectiveBarContributionItem) item).setPerspective(newPersp.getDesc());
// Install new persp.
setPerspective(newPersp);
// Destroy old persp.
disposePerspective(oldPersp);
// Update the Coolbar layout.
resetToolBarLayout();
// restore the maximized intro
if (introViewAdapter != null) {
if (introFullScreen)
toggleZoom(introPane.getPartReference());
// we want the intro back to a normal state before we fire the event
introViewAdapter.setHandleZoomEvents(true);
}
// Notify listeners that we have completed our reset.
window.firePerspectiveChanged(this, desc, CHANGE_RESET_COMPLETE);
}
finally {
// reset the handling of zoom events (possibly for the second time) in case there was
// an exception thrown
if (introViewAdapter != null)
introViewAdapter.setHandleZoomEvents(true);
if (introFullScreen)
window.getShell().setRedraw(true);
}
}
/**
* Implements <code>setPerspective</code>.
*
* Assumes that busy cursor is active.
*
* @param persp
* identifies the new perspective.
*/
private void busySetPerspective(IPerspectiveDescriptor desc) {
// Create new layout.
String label = desc.getId();
try {
UIStats.start(UIStats.SWITCH_PERSPECTIVE, label);
PerspectiveDescriptor realDesc = (PerspectiveDescriptor) desc;
Perspective newPersp = findPerspective(realDesc);
if (newPersp == null) {
newPersp = createPerspective(realDesc);
if (newPersp == null)
return;
window.addPerspectiveShortcut(realDesc, this);
}
// Change layout.
setPerspective(newPersp);
} finally {
UIStats.end(UIStats.SWITCH_PERSPECTIVE, label);
}
}
/**
* Shows a view.
*
* Assumes that a busy cursor is active.
*/
private IViewPart busyShowView(
String viewID,
String secondaryID,
int mode)
throws PartInitException {
Perspective persp = getActivePerspective();
if (persp == null)
return null;
// If this view is already visible just return.
IViewReference ref = persp.findView(viewID, secondaryID);
IViewPart view = null;
if (ref != null)
view = ref.getView(true);
if (view != null) {
if (mode == VIEW_ACTIVATE)
activate(view);
else if (mode == VIEW_VISIBLE)
bringToTop(view);
return view;
}
// Show the view.
view = persp.showView(viewID, secondaryID);
if (view != null) {
zoomOutIfNecessary(view);
if (mode == VIEW_ACTIVATE)
activate(view);
else if (mode == VIEW_VISIBLE)
bringToTop(view);
window.firePerspectiveChanged(
this,
getPerspective(),
CHANGE_VIEW_SHOW);
// Just in case view was fast.
window.updateFastViewBar();
}
return view;
}
/**
* Returns whether a part exists in the current page.
*/
private boolean certifyPart(IWorkbenchPart part) {
//Workaround for bug 22325
if (part != null && !(part.getSite() instanceof PartSite))
return false;
if (part instanceof IEditorPart) {
IEditorReference ref = (IEditorReference) getReference(part);
return getEditorManager().containsEditor(ref);
}
if (part instanceof IViewPart) {
Perspective persp = getActivePerspective();
return persp != null && persp.containsView((IViewPart) part);
}
return false;
}
/**
* Closes the perspective.
*/
public boolean close() {
final boolean[] ret = new boolean[1];
BusyIndicator.showWhile(null, new Runnable() {
public void run() {
ret[0] = window.closePage(WorkbenchPage.this, true);
}
});
return ret[0];
}
/**
* See IWorkbenchPage
*/
public boolean closeAllSavedEditors() {
// get the Saved editors
IEditorReference editors[] = getEditorReferences();
IEditorReference savedEditors[] = new IEditorReference[editors.length];
int j = 0;
for (int i = 0; i < editors.length; i++) {
IEditorReference editor = editors[i];
if (!editor.isDirty()) {
savedEditors[j++] = editor;
}
}
//there are no unsaved editors
if (j == 0)
return true;
IEditorReference[] newSaved = new IEditorReference[j];
System.arraycopy(savedEditors, 0, newSaved, 0, j);
return closeEditors(newSaved, false);
}
/**
* See IWorkbenchPage
*/
public boolean closeAllEditors(boolean save) {
return closeEditors(getEditorReferences(), save);
}
/**
* See IWorkbenchPage
*/
public boolean closeEditors(IEditorReference[] editorRefs, boolean save) {
if (save) {
// Intersect the dirty editors with the editors that are closing
IEditorPart[] dirty = getDirtyEditors();
List intersect = new ArrayList();
for (int i = 0; i < editorRefs.length; i++) {
IEditorReference reference = editorRefs[i];
IEditorPart refPart = reference.getEditor(false);
if (refPart != null) {
for (int j = 0; j < dirty.length; j++) {
if (refPart.equals(dirty[j])) {
intersect.add(refPart);
break;
}
}
}
}
// Save parts, exit the method if cancel is pressed.
if (intersect.size() > 0) {
if (!EditorManager.saveAll(intersect, true, getWorkbenchWindow()))
return false;
}
}
// If the user has not cancelled a possible save request
// and if part is added or removed always unzoom.
if (isZoomed())
zoomOut();
// Deactivate part if the active part is being closed.
boolean deactivated = false;
for (int i=0 ; i < editorRefs.length ; i++) {
IWorkbenchPart part = editorRefs[i].getPart(false);
if (part == activePart) {
deactivated = true;
setActivePart(null);
}
if (lastActiveEditor == part) {
lastActiveEditor = null;
actionSwitcher.updateTopEditor(null);
}
}
// Close all editors.
for (int i = 0; i < editorRefs.length; i++) {
IEditorReference ref = editorRefs[i];
getEditorManager().closeEditor(ref);
activationList.remove(ref);
firePartClosed(ref);
disposePart(ref);
}
if (!window.isClosing() && deactivated) {
activate(activationList.getActive());
}
// Notify interested listeners
window.firePerspectiveChanged(
this,
getPerspective(),
CHANGE_EDITOR_CLOSE);
// Return true on success.
return true;
}
/**
* See IWorkbenchPage#closeEditor
*/
public boolean closeEditor(IEditorReference editorRef, boolean save) {
IEditorPart editor = editorRef.getEditor(false);
if (editor != null)
return closeEditor(editor, save);
getEditorManager().closeEditor(editorRef);
activationList.remove(editorRef);
firePartClosed(editorRef);
return true;
}
/**
* See IWorkbenchPage#closeEditor
*/
public boolean closeEditor(IEditorPart editor, boolean save) {
// Sanity check.
if (!certifyPart(editor))
return false;
// Save part.
if (save && !getEditorManager().saveEditor(editor, true))
return false;
boolean partWasVisible = (editor == getActiveEditor());
IEditorReference ref = (IEditorReference) getReference(editor);
activationList.remove(ref);
boolean partWasActive = (editor == activePart);
// Removing following lines to fix:
// http://dev.eclipse.org/bugs/show_bug.cgi?id=28031
// // Deactivate part.
// if (partWasActive)
// setActivePart(null);
// if (lastActiveEditor == editor) {
// actionSwitcher.updateTopEditor(null);
// lastActiveEditor = null;
// }
// Close the part.
getEditorManager().closeEditor(ref);
firePartClosed(ref);
disposePart(ref);
// Notify interested listeners
window.firePerspectiveChanged(
this,
getPerspective(),
CHANGE_EDITOR_CLOSE);
// Activate new part.
if (partWasActive) {
IWorkbenchPart top = activationList.getTopEditor();
zoomOutIfNecessary(top);
if (top == null) {
// Fix for bug #31122 (side effect from fix 28031 above)
actionSwitcher.updateTopEditor(null);
if (lastActiveEditor == editor)
lastActiveEditor = null;
// End - Fix for bug #31122
top = activationList.getActive();
}
if (top != null)
activate(top);
else
setActivePart(null);
} else if (partWasVisible) {
IEditorPart top = activationList.getTopEditor();
zoomOutIfNecessary(top);
// The editor we are bringing to top may already the visible
// editor (due to editor manager behavior when it closes and
// editor).
// If this is the case, bringToTop will not call
// firePartBroughtToTop.
// We must fire it from here.
if (top != null) {
boolean isTop = editorMgr.getVisibleEditor() == top;
bringToTop(top);
if (isTop)
firePartBroughtToTop(top);
} else
actionSwitcher.updateTopEditor(top);
}
// Return true on success.
return true;
}
/**
* Closes the specified perspective. If last perspective, then entire page
* is closed.
*
* @param desc
* the descriptor of the perspective to be closed
* @param save
* whether the page's editors should be save if last perspective
*/
/* package */
void closePerspective(IPerspectiveDescriptor desc, boolean save) {
Perspective persp = findPerspective(desc);
if (persp != null)
closePerspective(persp, save, true);
}
/**
* Closes the specified perspective. If last perspective, then entire page
* is closed.
*
* @param persp
* the perspective to be closed
* @param save
* whether the page's editors should be save if last perspective
*/
/* package */
void closePerspective(Perspective persp, boolean save, boolean closePage) {
// Always unzoom
if (isZoomed())
zoomOut();
// Close all editors on last perspective close
if (perspList.size() == 1 && getEditorManager().getEditorCount() > 0) {
// Close all editors
if (!closeAllEditors(save))
return;
}
// Dispose of the perspective
boolean isActive = (perspList.getActive() == persp);
window.removePerspectiveShortcut(persp.getDesc(), this);
if (isActive)
setPerspective(perspList.getNextActive());
disposePerspective(persp);
if (closePage && perspList.size() == 0)
close();
}
/**
* Closes all perspectives in the page. The page is kept so as not to lose
* the input.
*
* @param save
* whether the page's editors should be saved
*/
/* package */
void closeAllPerspectives() {
if (perspList.isEmpty())
return;
// Always unzoom
if (isZoomed())
zoomOut();
// Close all editors
if (!closeAllEditors(true))
return;
// Deactivate the active perspective and part
setPerspective((Perspective) null);
// Close each perspective in turn
PerspectiveList oldList = perspList;
perspList = new PerspectiveList();
Iterator enum = oldList.iterator();
while (enum.hasNext())
closePerspective((Perspective) enum.next(), false, false);
close();
}
/**
* Creates the client composite.
*/
private void createClientComposite() {
final Composite parent = window.getPageComposite();
composite = new Composite(parent, SWT.NONE);
composite.setVisible(false); // Make visible on activate.
composite.setBounds(parent.getClientArea());
resizeListener = new ControlAdapter() {
public void controlResized(ControlEvent e) {
composite.setBounds(parent.getClientArea());
}
};
parent.addControlListener(resizeListener);
}
/**
* Creates a new view set. Return null on failure.
*/
private Perspective createPerspective(PerspectiveDescriptor desc) {
String label = desc.getId();
try {
UIStats.start(UIStats.CREATE_PERSPECTIVE, label);
Perspective persp = new Perspective(desc, this);
perspList.add(persp);
window.firePerspectiveOpened(this, desc);
IViewReference refs[] = persp.getViewReferences();
for (int i = 0; i < refs.length; i++) {
IViewReference ref = refs[i];
if (ref != null)
addPart(ref);
}
return persp;
} catch (WorkbenchException e) {
if (!((Workbench) window.getWorkbench()).isStarting()) {
MessageDialog.openError(window.getShell(), WorkbenchMessages.getString("Error"), //$NON-NLS-1$
WorkbenchMessages.format("Workbench.showPerspectiveError", new String[] { desc.getId()})); //$NON-NLS-1$
}
return null;
} finally {
UIStats.end(UIStats.CREATE_PERSPECTIVE, label);
}
}
/**
* Open the tracker to allow the user to move the specified part using
* keyboard.
*/
public void openTracker(ViewPane pane) {
Perspective persp = getActivePerspective();
if (persp != null)
persp.openTracker(pane);
}
/**
* Add a part to the activation list.
*/
protected void addPart(IWorkbenchPartReference ref) {
activationList.add(ref);
}
/**
* Remove a part from the activation list.
*/
protected void removePart(IWorkbenchPartReference ref) {
activationList.remove(ref);
}
/**
* Deactivates a part. The pane is unhilighted.
*/
private void deactivatePart(IWorkbenchPart part) {
if (part != null) {
PartSite site = (PartSite) part.getSite();
site.getPane().showFocus(false);
}
}
private void disposePart(IWorkbenchPartReference ref) {
final WorkbenchPartReference ref0 = (WorkbenchPartReference) ref;
Platform.run(new SafeRunnable() {
public void run() {
ref0.dispose();
}
public void handleException(Throwable e) {
//Exception has already being logged by Core. Do nothing.
}
});
}
/**
* Cleanup.
*/
public void dispose() {
// Always unzoom
if (isZoomed())
zoomOut();
// Close and dispose the editors.
closeAllEditors(false);
// Capture views.
IViewReference refs[] = viewFactory.getViews();
// Get rid of perspectives. This will close the views.
Iterator enum = perspList.iterator();
while (enum.hasNext()) {
Perspective perspective = (Perspective) enum.next();
window.removePerspectiveShortcut(perspective.getDesc(), this);
window.firePerspectiveClosed(this, perspective.getDesc());
perspective.dispose();
}
perspList = new PerspectiveList();
// Dispose views.
final int errors[] = { 0 };
for (int i = 0; i < refs.length; i++) {
final WorkbenchPartReference ref = (WorkbenchPartReference) refs[i];
firePartClosed(refs[i]);
Platform.run(new SafeRunnable() {
public void run() {
ref.dispose();
}
public void handleException(Throwable e) {
errors[0]++;
}
});
}
if (errors[0] > 0) {
String message;
if (errors[0] == 1)
message = WorkbenchMessages.getString("WorkbenchPage.oneErrorClosingPage"); //$NON-NLS-1$
else
message = WorkbenchMessages.getString("WorkbenchPage.multipleErrorsClosingPage"); //$NON-NLS-1$
MessageDialog.openError(null, WorkbenchMessages.getString("Error"), message); //$NON-NLS-1$
}
activePart = null;
activationList = new ActivationList();
// Get rid of editor presentation.
editorPresentation.dispose();
// Get rid of composite.
window.getPageComposite().removeControlListener(resizeListener);
composite.dispose();
navigationHistory.dispose();
stickyPerspectives.clear();
}
/**
* Dispose a perspective.
*/
private void disposePerspective(Perspective persp) {
// Get views.
IViewReference refs[] = persp.getViewReferences();
// Get rid of perspective.
perspList.remove(persp);
window.firePerspectiveClosed(this, persp.getDesc());
persp.dispose();
// Loop through the views.
for (int i = 0; i < refs.length; i++) {
IViewReference ref = refs[i];
//If the part is no longer reference then dispose it.
boolean exists = viewFactory.hasView(ref);
if (!exists) {
firePartClosed(ref);
activationList.remove(ref);
disposePart(ref);
}
}
stickyPerspectives.remove(persp.getDesc());
}
/**
* @return NavigationHistory
*/
public INavigationHistory getNavigationHistory() {
return navigationHistory;
}
/**
* Edits the action sets.
*/
public boolean editActionSets() {
Perspective persp = getActivePerspective();
if (persp == null)
return false;
// Create list dialog.
CustomizePerspectiveDialog dlg =
new CustomizePerspectiveDialog(window.getShell(), persp);
// Open.
boolean ret = (dlg.open() == Window.OK);
if (ret) {
window.updateActionSets();
window.firePerspectiveChanged(this, getPerspective(), CHANGE_RESET);
window.firePerspectiveChanged(this, getPerspective(), CHANGE_RESET_COMPLETE);
}
return ret;
}
/**
* Returns the first view manager with given ID.
*/
public Perspective findPerspective(IPerspectiveDescriptor desc) {
Iterator enum = perspList.iterator();
while (enum.hasNext()) {
Perspective mgr = (Perspective) enum.next();
if (desc.getId().equals(mgr.getDesc().getId()))
return mgr;
}
return null;
}
/**
* See IWorkbenchPage@findView.
*/
public IViewPart findView(String id) {
IViewReference ref = findViewReference(id);
if (ref == null)
return null;
// Create the control first - needed for fast views only
IViewPart view = ref.getView(true);
ViewPane pane = (ViewPane) ((WorkbenchPartReference) ref).getPane();
Control ctrl = pane.getControl();
if (ctrl == null)
pane.createControl(getClientComposite());
return view;
}
/* (non-Javadoc)
* @see org.eclipse.ui.IWorkbenchPage
*/
public IViewReference findViewReference(String viewId) {
return findViewReference(viewId, null);
}
/* (non-Javadoc)
* @see org.eclipse.ui.IWorkbenchPage
*/
public IViewReference findViewReference(String viewId, String secondaryId) {
Perspective persp = getActivePerspective();
if (persp == null)
return null;
return persp.findView(viewId, secondaryId);
}
/**
* Fire part activation out.
*/
private void firePartActivated(IWorkbenchPart part) {
String label = "activate::" + (part != null ? part.getTitle() : "none"); //$NON-NLS-1$ //$NON-NLS-2$
try {
UIStats.start(UIStats.NOTIFY_PART_LISTENERS, label);
partListeners.firePartActivated(part);
partListeners2.firePartActivated(getReference(part));
selectionService.partActivated(part);
} finally {
UIStats.end(UIStats.NOTIFY_PART_LISTENERS, label);
}
}
/**
* Fire part brought to top out.
*/
private void firePartBroughtToTop(IWorkbenchPart part) {
String label = "bringToTop::" + (part != null ? part.getTitle() : "none"); //$NON-NLS-1$ //$NON-NLS-2$
try {
UIStats.start(UIStats.NOTIFY_PART_LISTENERS, label);
partListeners.firePartBroughtToTop(part);
partListeners2.firePartBroughtToTop(getReference(part));
selectionService.partBroughtToTop(part);
} finally {
UIStats.end(UIStats.NOTIFY_PART_LISTENERS, label);
}
}
/**
* Fire part close out.
*/
private void firePartClosed(IWorkbenchPartReference ref) {
String label = "close" + ref.getTitle(); //$NON-NLS-1$
try {
UIStats.start(UIStats.NOTIFY_PART_LISTENERS, label);
IWorkbenchPart part = ref.getPart(false);
if (part != null) {
partListeners.firePartClosed(part);
selectionService.partClosed(part);
}
partListeners2.firePartClosed(ref);
} finally {
UIStats.end(UIStats.NOTIFY_PART_LISTENERS, label);
}
}
/**
* Fire part deactivation out.
*/
private void firePartDeactivated(IWorkbenchPart part) {
String label = "deactivate" + (part != null ? part.getTitle() : "none"); //$NON-NLS-1$ //$NON-NLS-2$
try {
UIStats.start(UIStats.NOTIFY_PART_LISTENERS, label);
partListeners.firePartDeactivated(part);
partListeners2.firePartDeactivated(getReference(part));
selectionService.partDeactivated(part);
} finally {
UIStats.end(UIStats.NOTIFY_PART_LISTENERS, label);
}
}
/**
* Fire part open out.
*/
public void firePartOpened(IWorkbenchPart part) {
String label = "deactivate" + (part != null ? part.getTitle() : "none"); //$NON-NLS-1$ //$NON-NLS-2$
try {
UIStats.start(UIStats.NOTIFY_PART_LISTENERS, label);
partListeners.firePartOpened(part);
partListeners2.firePartOpened(getReference(part));
selectionService.partOpened(part);
} finally {
UIStats.end(UIStats.NOTIFY_PART_LISTENERS, label);
}
}
/**
* Fire part input changed out.
*/
private void firePartInputChanged(IWorkbenchPart part) {
String label = "inputChanged" + (part != null ? part.getTitle() : "none"); //$NON-NLS-1$ //$NON-NLS-2$
try {
UIStats.start(UIStats.NOTIFY_PART_LISTENERS, label);
partListeners2.firePartInputChanged(getReference(part));
selectionService.partInputChanged(part);
} finally {
UIStats.end(UIStats.NOTIFY_PART_LISTENERS, label);
}
}
/**
* Notify property change listeners about a property change.
*
* @param changeId
* the change id
* @param oldValue
* old property value
* @param newValue
* new property value
*/
private void firePropertyChange(
String changeId,
Object oldValue,
Object newValue) {
Object[] listeners = propertyChangeListeners.getListeners();
PropertyChangeEvent event =
new PropertyChangeEvent(this, changeId, oldValue, newValue);
for (int i = 0; i < listeners.length; i++) {
((IPropertyChangeListener) listeners[i]).propertyChange(event);
}
}
/*
* Returns the action bars.
*/
public IActionBars getActionBars() {
if (actionBars == null)
actionBars = new WWinActionBars(window);
return actionBars;
}
/**
* Returns an array of the visible action sets.
*/
public IActionSetDescriptor[] getActionSets() {
Perspective persp = getActivePerspective();
if (persp != null)
return persp.getActionSets();
else
return new IActionSetDescriptor[0];
}
/**
* @see IWorkbenchPage
*/
public IEditorPart getActiveEditor() {
return getEditorManager().getVisibleEditor();
}
/*
* (non-Javadoc) Method declared on IPartService
*/
public IWorkbenchPart getActivePart() {
return activePart;
}
/*
* (non-Javadoc) Method declared on IPartService
*/
public IWorkbenchPartReference getActivePartReference() {
return getReference(activePart);
}
/**
* Returns the active perspective for the page, <code>null</code> if
* none.
*/
public Perspective getActivePerspective() {
return perspList.getActive();
}
/**
* Returns the client composite.
*/
public Composite getClientComposite() {
return composite;
}
/**
* Answer the editor manager for this window.
*/
// for dynamic UI - change access from private to protected
protected EditorManager getEditorManager() {
return editorMgr;
}
/**
* Answer the perspective presentation.
*/
public PerspectiveHelper getPerspectivePresentation() {
if (getActivePerspective() != null)
return getActivePerspective().getPresentation();
return null;
}
/**
* Answer the editor presentation.
*/
public EditorAreaHelper getEditorPresentation() {
return editorPresentation;
}
/**
* See IWorkbenchPage.
*/
public IEditorPart[] getEditors() {
final IEditorReference refs[] = getEditorReferences();
final ArrayList result = new ArrayList(refs.length);
Display d = getWorkbenchWindow().getShell().getDisplay();
//Must be backward compatible.
d.syncExec(new Runnable() {
public void run() {
for (int i = 0; i < refs.length; i++) {
IWorkbenchPart part = refs[i].getPart(true);
if (part != null)
result.add(part);
}
}
});
final IEditorPart editors[] = new IEditorPart[result.size()];
return (IEditorPart[]) result.toArray(editors);
}
public IEditorPart[] getDirtyEditors() {
return getEditorManager().getDirtyEditors();
}
public IEditorPart findEditor(IEditorInput input) {
return getEditorManager().findEditor(input);
}
/**
* See IWorkbenchPage.
*/
public IEditorReference[] getEditorReferences() {
return getEditorManager().getEditors();
}
/**
* Returns the docked views.
*/
public IViewReference[] getFastViews() {
Perspective persp = getActivePerspective();
if (persp != null)
return persp.getFastViews();
else
return new IViewReference[0];
}
/**
* @see IWorkbenchPage
*/
public IAdaptable getInput() {
return input;
}
/**
* Returns the page label. This is a combination of the page input and
* active perspective.
*/
public String getLabel() {
String label = WorkbenchMessages.getString("WorkbenchPage.UnknownLabel"); //$NON-NLS-1$
if (input != null) {
IWorkbenchAdapter adapter =
(IWorkbenchAdapter) input.getAdapter(IWorkbenchAdapter.class);
if (adapter != null)
label = adapter.getLabel(input);
}
Perspective persp = getActivePerspective();
if (persp != null)
label = WorkbenchMessages.format("WorkbenchPage.PerspectiveFormat", new Object[] { label, persp.getDesc().getLabel()}); //$NON-NLS-1$
else if (deferredActivePersp != null)
label = WorkbenchMessages.format("WorkbenchPage.PerspectiveFormat", new Object[] { label, deferredActivePersp.getLabel()}); //$NON-NLS-1$
return label;
}
/**
* Returns the new wizard actions the page. This is List of Strings.
*/
public ArrayList getNewWizardActionIds() {
Perspective persp = getActivePerspective();
if (persp != null)
return persp.getNewWizardActionIds();
else
return new ArrayList();
}
/**
* Returns the perspective.
*/
public IPerspectiveDescriptor getPerspective() {
if (deferredActivePersp != null)
return deferredActivePersp;
Perspective persp = getActivePerspective();
if (persp != null)
return persp.getDesc();
else
return null;
}
/**
* Returns the perspective actions for this page. This is List of Strings.
*/
public ArrayList getPerspectiveActionIds() {
Perspective persp = getActivePerspective();
if (persp != null)
return persp.getPerspectiveActionIds();
else
return new ArrayList();
}
/*
* (non-Javadoc) Method declared on ISelectionService
*/
public ISelection getSelection() {
return selectionService.getSelection();
}
/*
* (non-Javadoc) Method declared on ISelectionService
*/
public ISelection getSelection(String partId) {
return selectionService.getSelection(partId);
}
/**
* Returns the ids of the parts to list in the Show In... prompter. This is
* a List of Strings.
*/
public ArrayList getShowInPartIds() {
Perspective persp = getActivePerspective();
if (persp != null)
return persp.getShowInPartIds();
else
return new ArrayList();
}
/**
* The user successfully performed a Show In... action on the specified
* part. Update the list of Show In items accordingly.
*/
public void performedShowIn(String partId) {
Perspective persp = getActivePerspective();
if (persp != null) {
persp.performedShowIn(partId);
}
}
/**
* Sorts the given collection of show in target part ids in MRU order.
*/
public void sortShowInPartIds(ArrayList partIds) {
final Perspective persp = getActivePerspective();
if (persp != null) {
Collections.sort(partIds, new Comparator() {
public int compare(Object a, Object b) {
long ta = persp.getShowInTime((String) a);
long tb = persp.getShowInTime((String) b);
return (ta == tb) ? 0 : ((ta > tb) ? -1 : 1);
}
});
}
}
/**
* Returns the show view actions the page. This is a List of Strings.
*/
public ArrayList getShowViewActionIds() {
Perspective persp = getActivePerspective();
if (persp != null)
return persp.getShowViewActionIds();
else
return new ArrayList();
}
/**
* Returns the unprotected window.
*/
protected WorkbenchWindow getUnprotectedWindow() {
return window;
}
/*
* Returns the view factory.
*/
public ViewFactory getViewFactory() {
if (viewFactory == null) {
viewFactory =
new ViewFactory(
this,
WorkbenchPlugin.getDefault().getViewRegistry());
}
return viewFactory;
}
/**
* See IWorkbenchPage.
*/
public IViewReference[] getViewReferences() {
Perspective persp = getActivePerspective();
if (persp != null)
return persp.getViewReferences();
else
return new IViewReference[0];
}
/**
* See IWorkbenchPage.
*/
public IViewPart[] getViews() {
Perspective persp = getActivePerspective();
if (persp != null) {
IViewReference refs[] = persp.getViewReferences();
ArrayList parts = new ArrayList(refs.length);
for (int i = 0; i < refs.length; i++) {
IWorkbenchPart part = refs[i].getPart(true);
if (part != null)
parts.add(part);
}
IViewPart[] result = new IViewPart[parts.size()];
return (IViewPart[]) parts.toArray(result);
}
return new IViewPart[0];
}
/**
* See IWorkbenchPage.
*/
public IWorkbenchWindow getWorkbenchWindow() {
return window;
}
/**
* Implements IWorkbenchPage
*
* @see org.eclipse.ui.IWorkbenchPage#getWorkingSet()
* @since 2.0
* @deprecated individual views should store a working set if needed
*/
public IWorkingSet getWorkingSet() {
return workingSet;
}
/**
* @see IWorkbenchPage
*/
public void hideActionSet(String actionSetID) {
Perspective persp = getActivePerspective();
if (persp != null) {
persp.hideActionSet(actionSetID);
window.updateActionSets();
window.firePerspectiveChanged(
this,
getPerspective(),
CHANGE_ACTION_SET_HIDE);
}
}
/* (non-Javadoc)
* @see org.eclipse.ui.IWorkbenchPage#hideView(org.eclipse.ui.IViewReference)
*/
public void hideView(IViewReference ref) {
if (ref == null)
return;
IWorkbenchPart part = ref.getPart(false);
if (part != null) {
hideView((IViewPart) part);
} else {
hideView(getActivePerspective(), ref);
}
}
/* package */ void refreshActiveView() {
IWorkbenchPart nextActive = activationList.getActive();
if (nextActive != activePart) {
if (nextActive != null) {
activate(nextActive);
} else {
setActivePart(null);
}
}
}
/**
* See IPerspective
*/
public void hideView(IViewPart view) {
// Sanity check.
Perspective persp = getActivePerspective();
if (persp == null || !certifyPart(view))
return;
// If part is added / removed always unzoom.
IViewReference ref = (IViewReference) getReference(view);
if (isZoomed() && !isFastView(ref))
zoomOut();
// Confirm.
if (!persp.canCloseView(view))
return;
// Activate new part.
if (view == activePart) {
IWorkbenchPart prevActive = activationList.getPreviouslyActive();
if (prevActive != null)
activate(prevActive);
else
setActivePart(null);
}
hideView(persp, ref);
}
private void hideView(Perspective persp, IViewReference ref) {
// Hide the part.
persp.hideView(ref);
// If the part is no longer reference then dispose it.
boolean exists = viewFactory.hasView(ref);
if (!exists) {
firePartClosed(ref);
disposePart(ref);
activationList.remove(ref);
/*
* Bug 42684. A ViewPane instance has been disposed, but an attempt
* is then made to remove focus from it. This happens because the
* ViewPane is still viewed as the active part. The activePart
* should always be modified when the view is changed. activePart
* isn't really needed anymore (see declaration).
*/
activePart = activationList.getActive();
}
// Notify interested listeners
window.firePerspectiveChanged(this, getPerspective(), CHANGE_VIEW_HIDE);
// Just in case view was fast.
window.updateFastViewBar();
//if it was the last part, close the perspective
// lastPartClosePerspective();
}
/**
* Initialize the page.
*
* @param w
* the parent window
* @param layoutID
* may be <code>null</code> if restoring from file
* @param input
* the page input
*/
private void init(WorkbenchWindow w, String layoutID, IAdaptable input)
throws WorkbenchException {
// Save args.
this.window = w;
this.input = input;
// Create presentation.
createClientComposite();
editorPresentation = new EditorAreaHelper(this);
editorMgr = new EditorManager(window, this, editorPresentation);
// Get perspective descriptor.
if (layoutID != null) {
PerspectiveDescriptor desc =
(PerspectiveDescriptor) WorkbenchPlugin
.getDefault()
.getPerspectiveRegistry()
.findPerspectiveWithId(layoutID);
if (desc == null)
throw new WorkbenchException(WorkbenchMessages.getString("WorkbenchPage.ErrorRecreatingPerspective")); //$NON-NLS-1$
Perspective persp = createPerspective(desc);
if (persp == null)
return;
perspList.setActive(persp);
window.firePerspectiveActivated(this, desc);
}
}
/**
* See IWorkbenchPage.
*/
public boolean isPartVisible(IWorkbenchPart part) {
return ((PartSite) part.getSite()).getPane().isVisible();
}
/**
* See IWorkbenchPage.
*/
public boolean isEditorAreaVisible() {
Perspective persp = getActivePerspective();
if (persp == null)
return false;
return persp.isEditorAreaVisible();
}
/**
* Returns whether the view is fast.
*/
public boolean isFastView(IViewReference ref) {
Perspective persp = getActivePerspective();
if (persp != null)
return persp.isFastView(ref);
else
return false;
}
/**
* Returns whether the layout of the active
* perspective is fixed.
*/
public boolean isFixedLayout() {
Perspective persp = getActivePerspective();
if (persp != null)
return persp.isFixedLayout();
else
return false;
}
/**
* Return the active fast view or null if there are no fast views or if
* there are all minimized.
*/
public IViewReference getActiveFastView() {
Perspective persp = getActivePerspective();
if (persp != null)
return persp.getActiveFastView();
else
return null;
}
/**
* Return true if the perspective has a dirty editor.
*/
protected boolean isSaveNeeded() {
return getEditorManager().isSaveAllNeeded();
}
/**
* Returns whether the page is zoomed.
*/
public boolean isZoomed() {
Perspective persp = getActivePerspective();
if (persp == null)
return false;
if (persp.getPresentation() == null)
return false;
return persp.getPresentation().isZoomed();
}
/**
* Returns <code>true</code> if the window needs to unzoom for the given
* IWorkbenchPart to be seen by the user. Returns false otherwise.
*
* @param part
* the part whose visibility is to be determined
* @return <code>true</code> if the window needs to unzoom for the given
* IWorkbenchPart to be seen by the user, <code>false</code>
* otherwise.
*/
private boolean needToZoomOut(IWorkbenchPart part) {
// part is an editor
if (part instanceof IEditorPart) {
if (getActivePart() instanceof IViewPart) {
return true;
}
EditorSite site = (EditorSite) part.getSite();
EditorPane pane = (EditorPane) site.getPane();
EditorStack book = pane.getWorkbook();
return !book.equals(book.getEditorArea().getActiveWorkbook());
}
// part is a view
if (part instanceof IViewPart) {
if (isFastView((IViewReference) getReference(part))
|| part.equals(getActivePart()))
return false;
else
return true;
}
return true;
}
/**
* This method is called when the page is activated.
*/
protected void onActivate() {
Iterator enum = perspList.iterator();
while (enum.hasNext()) {
Perspective perspective = (Perspective) enum.next();
window.addPerspectiveShortcut(perspective.getDesc(), this);
}
composite.setVisible(true);
Perspective persp = getActivePerspective();
if (persp != null) {
window.selectPerspectiveShortcut(persp.getDesc(), this, true);
persp.onActivate();
updateVisibility(null, persp);
}
if (activePart == null && persp != null) {
IViewReference refs[] = persp.getViewReferences();
for (int i = 0; i < refs.length; i++) {
IViewReference ref = refs[i];
if (ref != null) {
activePart = ref.getPart(false);
if (activePart != null)
break;
}
}
}
if (activePart != null) {
activationList.setActive(activePart);
activatePart(activePart);
actionSwitcher.updateActivePart(activePart);
if (activePart instanceof IEditorPart) {
lastActiveEditor = (IEditorPart) activePart;
actionSwitcher.updateTopEditor((IEditorPart) activePart);
} else {
IEditorPart editor = editorMgr.getVisibleEditor();
if (editor != null) {
actionSwitcher.updateTopEditor(editor);
// inform the site's action bars of the current editor
// (important that this occur during page opening).
PartSite site = (PartSite) editor.getSite();
SubActionBars bars = (SubActionBars) site.getActionBars();
bars.partChanged(editor);
}
}
firePartActivated(activePart);
} else {
composite.setFocus();
}
}
/**
* This method is called when the page is deactivated.
*/
protected void onDeactivate() {
if (activePart != null) {
deactivatePart(activePart);
actionSwitcher.updateActivePart(null);
firePartDeactivated(activePart);
}
actionSwitcher.updateTopEditor(null);
lastActiveEditor = null;
if (getActivePerspective() != null)
getActivePerspective().onDeactivate();
composite.setVisible(false);
Iterator enum = perspList.iterator();
while (enum.hasNext()) {
Perspective perspective = (Perspective) enum.next();
window.removePerspectiveShortcut(perspective.getDesc(), this);
}
}
/**
* See IWorkbenchPage.
*/
public void reuseEditor(IReusableEditor editor, IEditorInput input) {
editor.setInput(input);
firePartInputChanged(editor);
}
/**
* See IWorkbenchPage.
*/
public IEditorPart openEditor(IEditorInput input, String editorID)
throws PartInitException {
return openEditor(input, editorID, true);
}
/**
* See IWorkbenchPage.
*/
public IEditorPart openEditor(
final IEditorInput input,
final String editorID,
final boolean activate)
throws PartInitException {
if (input == null || editorID == null) {
throw new IllegalArgumentException();
}
final IEditorPart result[] = new IEditorPart[1];
final PartInitException ex[] = new PartInitException[1];
BusyIndicator
.showWhile(
window.getWorkbench().getDisplay(),
new Runnable() {
public void run() {
try {
result[0] = busyOpenEditor(input, editorID, activate);
} catch (PartInitException e) {
ex[0] = e;
}
}
});
if (ex[0] != null)
throw ex[0];
return result[0];
}
/**
* See IWorkbenchPage.openEditor
*/
private IEditorPart busyOpenEditor(
IEditorInput input,
String editorID,
boolean activate)
throws PartInitException {
// If an editor already exists for the input use it.
IEditorPart editor = getEditorManager().findEditor(input);
if (editor != null) {
if (IEditorRegistry.SYSTEM_EXTERNAL_EDITOR_ID.equals(editorID)) {
if (editor.isDirty()) {
MessageDialog dialog = new MessageDialog(getWorkbenchWindow().getShell(), WorkbenchMessages.getString("Save"), //$NON-NLS-1$
null, // accept the default window icon
WorkbenchMessages.format("WorkbenchPage.editorAlreadyOpenedMsg", new String[] { input.getName()}), //$NON-NLS-1$
MessageDialog.QUESTION,
new String[] {
IDialogConstants.YES_LABEL,
IDialogConstants.NO_LABEL,
IDialogConstants.CANCEL_LABEL },
0);
int saveFile = dialog.open();
if (saveFile == 0) {
try {
final IEditorPart editorToSave = editor;
getWorkbenchWindow()
.run(false, false, new IRunnableWithProgress() {
public void run(IProgressMonitor monitor)
throws
InvocationTargetException,
InterruptedException {
editorToSave.doSave(monitor);
}
});
} catch (InvocationTargetException e) {
throw (RuntimeException) e.getTargetException();
} catch (InterruptedException e) {
return null;
}
} else if (saveFile == 2) {
return null;
}
}
} else {
showEditor(activate, editor);
return editor;
}
}
// Disabled turning redraw off, because it causes setFocus
// in activate(editor) to fail.
// getClientComposite().setRedraw(false);
// Remember the old visible editor
IEditorPart oldVisibleEditor = getEditorManager().getVisibleEditor();
// Otherwise, create a new one. This may cause the new editor to
// become the visible (i.e top) editor.
IEditorReference ref = null;
ref = getEditorManager().openEditor(editorID, input, true);
if (ref != null) {
editor = ref.getEditor(true);
addPart(ref);
}
if (editor != null) {
//firePartOpened(editor);
zoomOutIfNecessary(editor);
setEditorAreaVisible(true);
if (activate) {
if (editor instanceof MultiEditor)
activate(((MultiEditor) editor).getActiveEditor());
else
activate(editor);
} else {
activationList.setActive(editor);
if (activePart != null) {
// ensure the activation list is in a valid state
activationList.setActive(activePart);
}
// The previous openEditor call may create a new editor
// and make it visible, so send the notification.
IEditorPart visibleEditor =
getEditorManager().getVisibleEditor();
if ((visibleEditor == editor)
&& (oldVisibleEditor != editor)) {
actionSwitcher.updateTopEditor(editor);
firePartBroughtToTop(editor);
} else {
bringToTop(editor);
}
}
window.firePerspectiveChanged(
this,
getPerspective(),
CHANGE_EDITOR_OPEN);
}
// getClientComposite().setRedraw(true);
return editor;
}
private void showEditor(boolean activate, IEditorPart editor) {
zoomOutIfNecessary(editor);
setEditorAreaVisible(true);
if (activate)
activate(editor);
else
bringToTop(editor);
}
/**
* See IWorkbenchPage.
*/
public boolean isEditorPinned(IEditorPart editor) {
return !((EditorSite) editor.getEditorSite()).getReuseEditor();
}
/**
* Returns whether changes to a part will affect zoom. There are a few
* conditions for this .. - we are zoomed. - the part is contained in the
* main window. - the part is not the zoom part - the part is not a fast
* view - the part and the zoom part are not in the same editor workbook
*/
private boolean partChangeAffectsZoom(IWorkbenchPartReference ref) {
PartPane pane = ((WorkbenchPartReference) ref).getPane();
if (pane instanceof MultiEditorInnerPane)
pane = ((MultiEditorInnerPane) pane).getParentPane();
return getActivePerspective().getPresentation().partChangeAffectsZoom(
pane);
}
/**
* Removes a fast view.
*/
public void removeFastView(IViewReference ref) {
Perspective persp = getActivePerspective();
if (persp == null)
return;
// If parts change always update zoom.
if (isZoomed())
zoomOut();
// Do real work.
persp.removeFastView(ref);
// Notify listeners.
window.updateFastViewBar();
window.firePerspectiveChanged(
this,
getPerspective(),
CHANGE_FAST_VIEW_REMOVE);
}
/**
* Removes an IPartListener from the part service.
*/
public void removePartListener(IPartListener l) {
partListeners.removePartListener(l);
}
/**
* Removes an IPartListener from the part service.
*/
public void removePartListener(IPartListener2 l) {
partListeners2.removePartListener(l);
}
/**
* Implements IWorkbenchPage
*
* @see org.eclipse.ui.IWorkbenchPage#removePropertyChangeListener(IPropertyChangeListener)
* @since 2.0
* @deprecated individual views should store a working set if needed and
* register a property change listener directly with the
* working set manager to receive notification when the view
* working set is removed.
*/
public void removePropertyChangeListener(IPropertyChangeListener listener) {
propertyChangeListeners.remove(listener);
}
/*
* (non-Javadoc) Method declared on ISelectionListener.
*/
public void removeSelectionListener(ISelectionListener listener) {
selectionService.removeSelectionListener(listener);
}
/*
* (non-Javadoc) Method declared on ISelectionListener.
*/
public void removeSelectionListener(
String partId,
ISelectionListener listener) {
selectionService.removeSelectionListener(partId, listener);
}
/*
* (non-Javadoc) Method declared on ISelectionListener.
*/
public void removePostSelectionListener(ISelectionListener listener) {
selectionService.removePostSelectionListener(listener);
}
/*
* (non-Javadoc) Method declared on ISelectionListener.
*/
public void removePostSelectionListener(
String partId,
ISelectionListener listener) {
selectionService.removePostSelectionListener(partId, listener);
}
/**
* This method is called when a part is activated by clicking within it. In
* response, the part, the pane, and all of its actions will be activated.
*
* In the current design this method is invoked by the part pane when the
* pane, the part, or any children gain focus.
*/
public void requestActivation(IWorkbenchPart part) {
// Sanity check.
if (!certifyPart(part))
return;
// Real work.
setActivePart(part);
}
/**
* Resets the layout for the perspective. The active part in the old layout
* is activated in the new layout for consistent user context.
*/
public void resetPerspective() {
// Run op in busy cursor.
// Use set redraw to eliminate the "flash" that can occur in the
// coolbar as the perspective is reset.
CoolBarManager mgr = window.getCoolBarManager();
try {
mgr.getControl().setRedraw(false);
BusyIndicator.showWhile(null, new Runnable() {
public void run() {
busyResetPerspective();
}
});
} finally {
mgr.getControl().setRedraw(true);
}
}
/**
* Restore this page from the memento and ensure that the active
* perspective is equals the active descriptor otherwise create a new
* perspective for that descriptor. If activeDescriptor is null active the
* old perspective.
*/
public IStatus restoreState(
IMemento memento,
IPerspectiveDescriptor activeDescritor) {
// Restore working set
String pageName = memento.getString(IWorkbenchConstants.TAG_LABEL);
String label = pageName == null ? "" : "::" + pageName; //$NON-NLS-1$ //$NON-NLS-2$
try {
UIStats.start(UIStats.RESTORE_WORKBENCH, "WorkbenchPage" + label); //$NON-NLS-1$
if (pageName == null)
pageName = ""; //$NON-NLS-1$
MultiStatus result = new MultiStatus(PlatformUI.PLUGIN_ID, IStatus.OK, WorkbenchMessages.format("WorkbenchPage.unableToRestorePerspective", new String[] { pageName }), //$NON-NLS-1$
null);
String workingSetName =
memento.getString(IWorkbenchConstants.TAG_WORKING_SET);
if (workingSetName != null) {
WorkingSetManager workingSetManager =
(WorkingSetManager) getWorkbenchWindow()
.getWorkbench()
.getWorkingSetManager();
setWorkingSet(workingSetManager.getWorkingSet(workingSetName));
}
// Restore editor manager.
IMemento childMem =
memento.getChild(IWorkbenchConstants.TAG_EDITORS);
result.merge(getEditorManager().restoreState(childMem));
childMem = memento.getChild(IWorkbenchConstants.TAG_VIEWS);
if (childMem != null)
result.merge(getViewFactory().restoreState(childMem));
// Get persp block.
childMem = memento.getChild(IWorkbenchConstants.TAG_PERSPECTIVES);
String activePartID =
childMem.getString(IWorkbenchConstants.TAG_ACTIVE_PART);
String activePerspectiveID =
childMem.getString(IWorkbenchConstants.TAG_ACTIVE_PERSPECTIVE);
// Restore perspectives.
IMemento perspMems[] =
childMem.getChildren(IWorkbenchConstants.TAG_PERSPECTIVE);
Perspective activePerspective = null;
for (int i = 0; i < perspMems.length; i++) {
try {
Perspective persp = new Perspective(null, this);
result.merge(persp.restoreState(perspMems[i]));
IPerspectiveDescriptor desc = persp.getDesc();
if (desc.equals(activeDescritor))
activePerspective = persp;
else if (
(activePerspective == null)
&& desc.getId().equals(activePerspectiveID))
activePerspective = persp;
perspList.add(persp);
} catch (WorkbenchException e) {
}
}
boolean restoreActivePerspective = false;
if (activeDescritor == null)
restoreActivePerspective = true;
else if (
activePerspective != null
&& activePerspective.getDesc().equals(activeDescritor)) {
restoreActivePerspective = true;
} else {
restoreActivePerspective = false;
activePerspective =
createPerspective((PerspectiveDescriptor) activeDescritor);
if (activePerspective == null) {
result.merge(new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, 0, WorkbenchMessages.format("Workbench.showPerspectiveError", new String[] { activeDescritor.getId()}), //$NON-NLS-1$
null));
}
}
perspList.setActive(activePerspective);
// Make sure we have a valid perspective to work with,
// otherwise return.
activePerspective = perspList.getActive();
if (activePerspective == null) {
activePerspective = perspList.getNextActive();
perspList.setActive(activePerspective);
result.merge(activePerspective.restoreState());
}
if (activePerspective != null && restoreActivePerspective)
result.merge(activePerspective.restoreState());
if (activePerspective != null) {
window.firePerspectiveActivated(
this,
activePerspective.getDesc());
// Restore active part.
if (activePartID != null) {
IViewReference ref =
activePerspective.findView(activePartID);
IViewPart view = null;
if (ref != null)
view = ref.getView(true);
if (view != null)
activePart = view;
}
}
childMem =
memento.getChild(IWorkbenchConstants.TAG_NAVIGATION_HISTORY);
if (childMem != null)
navigationHistory.restoreState(childMem);
else if (getActiveEditor() != null)
navigationHistory.markEditor(getActiveEditor());
return result;
} finally {
UIStats.end(UIStats.RESTORE_WORKBENCH, "WorkbenchPage" + label); //$NON-NLS-1$
}
}
/**
* See IWorkbenchPage
*/
public boolean saveAllEditors(boolean confirm) {
return getEditorManager().saveAll(confirm, false);
}
/*
* Saves the workbench part.
*/
protected boolean savePart(
ISaveablePart saveable,
IWorkbenchPart part,
boolean confirm) {
// Do not certify part do allow editors inside a multipageeditor to
// call this.
return getEditorManager().savePart(saveable, part, confirm);
}
/**
* Saves an editors in the workbench. If <code>confirm</code> is <code>true</code>
* the user is prompted to confirm the command.
*
* @param confirm
* if user confirmation should be sought
* @return <code>true</code> if the command succeeded, or <code>false</code>
* if the user cancels the command
*/
public boolean saveEditor(IEditorPart editor, boolean confirm) {
return savePart(editor, editor, confirm);
}
/**
* Saves the current perspective.
*/
public void savePerspective() {
Perspective persp = getActivePerspective();
if (persp == null)
return;
// Always unzoom.
if (isZoomed())
zoomOut();
persp.saveDesc();
}
/**
* Saves the perspective.
*/
public void savePerspectiveAs(IPerspectiveDescriptor newDesc) {
Perspective persp = getActivePerspective();
if (persp == null)
return;
IPerspectiveDescriptor oldDesc = persp.getDesc();
// Always unzoom.
if (isZoomed())
zoomOut();
persp.saveDescAs(newDesc);
window.updatePerspectiveShortcut(oldDesc, newDesc, this);
}
/**
* Save the state of the page.
*/
public IStatus saveState(IMemento memento) {
// We must unzoom to get correct layout.
if (isZoomed())
zoomOut();
MultiStatus result = new MultiStatus(PlatformUI.PLUGIN_ID, IStatus.OK, WorkbenchMessages.format("WorkbenchPage.unableToSavePerspective", new String[] { getLabel()}), //$NON-NLS-1$
null);
// Save editor manager.
IMemento childMem =
memento.createChild(IWorkbenchConstants.TAG_EDITORS);
result.merge(editorMgr.saveState(childMem));
childMem = memento.createChild(IWorkbenchConstants.TAG_VIEWS);
result.merge(getViewFactory().saveState(childMem));
// Create persp block.
childMem = memento.createChild(IWorkbenchConstants.TAG_PERSPECTIVES);
if (getPerspective() != null)
childMem.putString(
IWorkbenchConstants.TAG_ACTIVE_PERSPECTIVE,
getPerspective().getId());
if (getActivePart() != null)
childMem.putString(
IWorkbenchConstants.TAG_ACTIVE_PART,
getActivePart().getSite().getId());
// Save each perspective in opened order
Iterator enum = perspList.iterator();
while (enum.hasNext()) {
Perspective persp = (Perspective) enum.next();
IMemento gChildMem =
childMem.createChild(IWorkbenchConstants.TAG_PERSPECTIVE);
result.merge(persp.saveState(gChildMem));
}
// Save working set if set
if (workingSet != null) {
memento.putString(
IWorkbenchConstants.TAG_WORKING_SET,
workingSet.getName());
}
navigationHistory.saveState(
memento.createChild(IWorkbenchConstants.TAG_NAVIGATION_HISTORY));
return result;
}
/**
* Sets the active part.
*/
private void setActivePart(IWorkbenchPart newPart) {
// Optimize it.
if (activePart == newPart)
return;
//No need to change the history if the active editor is becoming the
// active part
boolean markLocation = newPart != lastActiveEditor;
String label = newPart != null ? newPart.getTitle() : "none"; //$NON-NLS-1$
try {
UIStats.start(UIStats.ACTIVATE_PART, label);
// Notify perspective. It may deactivate fast view.
Perspective persp = getActivePerspective();
if (persp != null)
persp.partActivated(newPart);
// Deactivate old part
IWorkbenchPart oldPart = activePart;
if (oldPart != null) {
deactivatePart(oldPart);
}
// Set active part.
activePart = newPart;
if (newPart != null) {
activationList.setActive(newPart);
if (newPart instanceof IEditorPart) {
lastActiveEditor = (IEditorPart) newPart;
IEditorReference ref =
(IEditorReference) getReference(lastActiveEditor);
editorMgr.setVisibleEditor(ref, true);
}
}
activatePart(activePart);
if (markLocation
&& activePart != null
&& activePart instanceof IEditorPart)
navigationHistory.markEditor((IEditorPart) activePart);
// Fire notifications
if (oldPart != null)
firePartDeactivated(oldPart);
// Update actions now so old actions have heard part deactivated
// and
// new actions can hear part activated.
actionSwitcher.updateActivePart(newPart);
if (newPart != null)
firePartActivated(newPart);
} finally {
UIStats.end(UIStats.ACTIVATE_PART, label);
}
}
/**
* See IWorkbenchPage.
*/
public void setEditorAreaVisible(boolean showEditorArea) {
Perspective persp = getActivePerspective();
if (persp == null)
return;
if (showEditorArea == persp.isEditorAreaVisible())
return;
// If parts change always update zoom.
if (isZoomed())
zoomOut();
// Update editor area visibility.
if (showEditorArea) {
persp.showEditorArea();
window.firePerspectiveChanged(
this,
getPerspective(),
CHANGE_EDITOR_AREA_SHOW);
} else {
persp.hideEditorArea();
if (activePart instanceof IEditorPart) {
IEditorPart e = (IEditorPart) activePart;
setActivePart(null);
// preserve editor contributions
actionSwitcher.updateTopEditor(e);
}
window.firePerspectiveChanged(
this,
getPerspective(),
CHANGE_EDITOR_AREA_HIDE);
}
}
/**
* Sets the layout of the page. Assumes the new perspective is not null.
* Keeps the active part if possible. Updates the window menubar and
* toolbar if necessary.
*/
private void setPerspective(Perspective newPersp) {
// Don't do anything if already active layout
Perspective oldPersp = getActivePerspective();
if (oldPersp == newPersp)
return;
if (newPersp != null) {
IStatus status = newPersp.restoreState();
if (status.getSeverity() != IStatus.OK) {
String title = WorkbenchMessages.getString("WorkbenchPage.problemRestoringTitle"); //$NON-NLS-1$
String msg = WorkbenchMessages.getString("WorkbenchPage.errorReadingState"); //$NON-NLS-1$
ErrorDialog.openError(
getWorkbenchWindow().getShell(),
title,
msg,
status);
}
}
// Deactivate active part.
// ensure the switcher is not showing any action sets
// so it will reshow them in the new perspective
actionSwitcher.updateTopEditor(null);
IWorkbenchPart oldActivePart = activePart;
setActivePart(null);
// Deactivate the old layout
if (oldPersp != null) {
oldPersp.onDeactivate();
window.selectPerspectiveShortcut(oldPersp.getDesc(), this, false);
}
// Activate the new layout
perspList.setActive(newPersp);
if (newPersp != null) {
newPersp.onActivate();
// Notify listeners of activation
window.firePerspectiveActivated(this, newPersp.getDesc());
// Update the shortcut
window.selectPerspectiveShortcut(newPersp.getDesc(), this, true);
} else {
// No need to remember old active part since there
// is no new active perspective to activate it in.
oldActivePart = null;
}
// Update the window
window.updateActionSets();
window.updateFastViewBar();
updateVisibility(oldPersp, newPersp);
// Reactivate active part.
if (oldActivePart != null) {
String id = oldActivePart.getSite().getId();
oldPersp.setOldPartID(id);
if (oldActivePart instanceof IEditorPart
&& isEditorAreaVisible()) {
activate(oldActivePart);
} else if (oldActivePart instanceof IViewPart) {
IEditorPart ed = editorMgr.getVisibleEditor();
if (ed != null)
actionSwitcher.updateTopEditor(ed);
if (findView(id) != null) {
activate(oldActivePart);
} else {
activateOldPart(newPersp);
}
} else {
activateOldPart(newPersp);
}
} else { //no active part
IEditorPart ed = editorMgr.getVisibleEditor();
if (ed != null) {
actionSwitcher.updateTopEditor(ed);
} else {
activateOldPart(newPersp);
}
}
if (getActivePart() == null && activationList.getActive() != null) {
activate(activationList.getActive());
}
if (editorPresentation != null)
editorPresentation.showVisibleEditor();
if (newPersp != null && oldPersp != null ) {
if (!stickyPerspectives.contains(newPersp.getDesc())) {
IViewRegistry viewReg = WorkbenchPlugin.getDefault().getViewRegistry();
IStickyViewDescriptor [] stickyDescs = viewReg.getStickyViews();
for (int i = 0; i < stickyDescs.length; i++) {
try {
// show a sticky view if it was in the last perspective
if (oldPersp.findView(stickyDescs[i].getId()) != null) {
showView(stickyDescs[i].getId(), null, IWorkbenchPage.VIEW_CREATE);
}
}
catch (PartInitException e) {
WorkbenchPlugin.log("Could not open view :" + stickyDescs[i].getId(), new Status(IStatus.ERROR, WorkbenchPlugin.PI_WORKBENCH, IStatus.ERROR, "Could not open view :" + stickyDescs[i].getId(), e)); //$NON-NLS-1$ //$NON-NLS-2$
}
}
stickyPerspectives.add(newPersp.getDesc());
}
}
}
/*
* Update visibility state of all views.
*/
private void updateVisibility(Perspective oldPersp, Perspective newPersp) {
HashSet set = new HashSet();
IWorkbenchPartReference[] refs;
if (oldPersp != null) {
refs = oldPersp.getViewReferences();
for (int i = 0; i < refs.length; i++) {
PartPane pane = ((WorkbenchPartReference) refs[i]).getPane();
if (pane != null)
set.add(pane);
}
}
if (newPersp != null) {
refs = newPersp.getViewReferences();
for (int i = 0; i < refs.length; i++) {
PartPane pane = ((WorkbenchPartReference) refs[i]).getPane();
if (pane != null)
set.add(pane);
}
PerspectiveHelper pres = newPersp.getPresentation();
for (Iterator iter = set.iterator(); iter.hasNext();) {
PartPane pane = (PartPane) iter.next();
String secondaryId = null;
if (pane instanceof ViewPane) {
ViewPane vp = (ViewPane) pane;
IViewReference ref = (IViewReference)vp.getPartReference();
secondaryId = ref.getSecondaryId();
}
boolean isVisible = pres.isPartVisible(pane.getID(), secondaryId);
pane.setVisible(isVisible);
}
} else {
for (Iterator iter = set.iterator(); iter.hasNext();) {
PartPane pane = (PartPane) iter.next();
pane.setVisible(false);
}
}
}
private void activateOldPart(Perspective newPersp) {
if (window.isClosing())
return;
if (newPersp != null) {
String oldID = newPersp.getOldPartID();
IWorkbenchPart prevOldPart = null;
if (oldID != null)
prevOldPart = findView(oldID);
if (prevOldPart != null)
activate(prevOldPart);
else if (isEditorAreaVisible())
activate(getActiveEditor());
}
}
/**
* Sets the perspective.
*
* @param persp
* identifies the new perspective.
*/
public void setPerspective(final IPerspectiveDescriptor desc) {
// Going from multiple to single rows can make the coolbar
// and its adjacent views appear jumpy as perspectives are
// switched. Turn off redraw to help with this.
CoolBarManager mgr = window.getCoolBarManager();
try {
mgr.getControl().setRedraw(false);
getClientComposite().setRedraw(false);
// Run op in busy cursor.
BusyIndicator.showWhile(null, new Runnable() {
public void run() {
busySetPerspective(desc);
}
});
} finally {
getClientComposite().setRedraw(true);
mgr.getControl().setRedraw(true);
IWorkbenchPart part = getActivePart();
if (part != null)
part.setFocus();
}
}
/**
* Restore the toolbar layout for the active perspective.
*/
protected void resetToolBarLayout() {
window.getCoolBarManager().resetItemOrder();
}
/**
* Sets the active working set for the workbench page. Notifies property
* change listener about the change.
*
* @param newWorkingSet
* the active working set for the page. May be null.
* @since 2.0
* @deprecated individual views should store a working set if needed
*/
public void setWorkingSet(IWorkingSet newWorkingSet) {
IWorkingSet oldWorkingSet = workingSet;
workingSet = newWorkingSet;
if (oldWorkingSet != newWorkingSet) {
firePropertyChange(
CHANGE_WORKING_SET_REPLACE,
oldWorkingSet,
newWorkingSet);
}
if (newWorkingSet != null) {
WorkbenchPlugin
.getDefault()
.getWorkingSetManager()
.addPropertyChangeListener(
propertyChangeListener);
} else {
WorkbenchPlugin
.getDefault()
.getWorkingSetManager()
.removePropertyChangeListener(propertyChangeListener);
}
}
/**
* @see IWorkbenchPage
*/
public void showActionSet(String actionSetID) {
Perspective persp = getActivePerspective();
if (persp != null) {
persp.showActionSet(actionSetID);
window.updateActionSets();
window.firePerspectiveChanged(
this,
getPerspective(),
CHANGE_ACTION_SET_SHOW);
}
}
/**
* See IWorkbenchPage.
*/
public IViewPart showView(String viewID) throws PartInitException {
return showView(viewID, null, VIEW_ACTIVATE);
}
/* (non-Javadoc)
* @see org.eclipse.ui.IWorkbenchPage#showView(java.lang.String, java.lang.String, int)
*/
public IViewPart showView(
final String viewID,
final String secondaryID,
final int mode) throws PartInitException {
if (!certifyMode(mode))
throw new IllegalArgumentException(WorkbenchMessages.getString("WorkbenchPage.IllegalViewMode")); //$NON-NLS-1$
// Run op in busy cursor.
final Object[] result = new Object[1];
BusyIndicator.showWhile(null, new Runnable() {
public void run() {
try {
result[0] = busyShowView(viewID, secondaryID, mode);
} catch (PartInitException e) {
result[0] = e;
}
}
});
if (result[0] instanceof IViewPart)
return (IViewPart) result[0];
else if (result[0] instanceof PartInitException)
throw (PartInitException) result[0];
else
throw new PartInitException(WorkbenchMessages.getString("WorkbenchPage.AbnormalWorkbenchCondition")); //$NON-NLS-1$
}
/**
* @param mode the mode to test
* @return whether the mode is recognized
* @since 3.0
*/
private boolean certifyMode(int mode) {
switch(mode) {
case VIEW_ACTIVATE:
case VIEW_VISIBLE:
case VIEW_CREATE:
return true;
default:
return false;
}
}
/**
* Hides the active fast view. Has no effect if there is no fast view active.
*/
public void hideFastView() {
Perspective persp = getActivePerspective();
if (persp != null) {
IViewReference ref = persp.getActiveFastView();
if (ref != null) {
toggleFastView(ref);
}
}
}
/**
* Toggles the visibility of a fast view. If the view is active it is
* deactivated. Otherwise, it is activated.
*/
public void toggleFastView(IViewReference ref) {
Perspective persp = getActivePerspective();
if (persp != null) {
persp.toggleFastView(ref);
// if the fast view has been deactivated
if (ref != persp.getActiveFastView()) {
IWorkbenchPart previouslyActive =
activationList.getPreviouslyActive();
IEditorPart activeEditor = getActiveEditor();
if (activeEditor != null
&& previouslyActive instanceof IEditorPart)
setActivePart(activeEditor);
else
setActivePart(previouslyActive);
}
}
}
/**
* Zoom in on a part. If the part is already in zoom then zoom out.
*/
public void toggleZoom(IWorkbenchPartReference ref) {
Perspective persp = getActivePerspective();
if (persp == null)
return;
PartPane pane = ((WorkbenchPartReference) ref).getPane();
// If target part is detached fire the zoom event. Note this doesn't
// actually cause any changes in size and is required to support
// intro state changes. We may want to introduce the notion of a zoomed
// (fullscreen) detached view at a later time.
if (pane.getWindow() instanceof DetachedWindow) {
pane.setZoomed(!pane.isZoomed());
return;
}
if (ref instanceof IViewReference && persp.isFastView((IViewReference)ref)) {
persp.toggleFastViewZoom();
return;
}
// Update zoom status.
if (isZoomed()) {
zoomOut();
return;
} else {
persp.getPresentation().zoomIn(ref);
activate(ref.getPart(true));
}
}
/**
* updateActionBars method comment.
*/
public void updateActionBars() {
window.updateActionBars();
}
/**
* Sets the tab list of this page's composite appropriately when a part is
* activated.
*/
private void updateTabList(IWorkbenchPart part) {
PartSite site = (PartSite) part.getSite();
PartPane pane = site.getPane();
if (pane instanceof ViewPane) {
ViewPane viewPane = (ViewPane) pane;
Control[] tabList = viewPane.getTabList();
if (pane.getWindow() instanceof DetachedWindow) {
viewPane.getControl().getShell().setTabList(tabList);
} else {
getClientComposite().setTabList(tabList);
}
} else if (pane instanceof EditorPane) {
EditorSashContainer ea = ((EditorPane) pane).getWorkbook().getEditorArea();
ea.updateTabList();
getClientComposite().setTabList(new Control[] { ea.getParent()});
}
}
/**
* The title of the given part has changed. For views, updates the fast
* view button if necessary.
*/
public void updateTitle(IViewReference ref) {
if (isFastView(ref)) {
// Would be more efficient to just update label of single tool item
// but we don't have access to it from here.
window.updateFastViewBar();
}
}
/**
* Zooms out a zoomed in part.
*/
/* package */
void zoomOut() {
Perspective persp = getActivePerspective();
if (persp != null)
persp.getPresentation().zoomOut();
}
/**
* Zooms out a zoomed in part if it is necessary to do so for the user to
* view the IWorkbenchPart that is the argument. Otherwise, does nothing.
*
* @param part
* the part to be made viewable
*/
private void zoomOutIfNecessary(IWorkbenchPart part) {
if (isZoomed() && needToZoomOut(part))
zoomOut();
}
/**
* @see IPageLayout.
*/
public int getEditorReuseThreshold() {
IPreferenceStore store =
WorkbenchPlugin.getDefault().getPreferenceStore();
return store.getInt(IPreferenceConstants.REUSE_EDITORS);
}
/**
* @see IPageLayout.
*/
public void setEditorReuseThreshold(int openEditors) {
}
/*
* Returns the editors in activation order (oldest first).
*/
public IEditorReference[] getSortedEditors() {
return activationList.getEditors();
}
/**
* Returns an iterator over the opened perspectives
*/
protected IPerspectiveDescriptor[] getOpenedPerspectives() {
Perspective opened[] = perspList.getSortedPerspectives();
IPerspectiveDescriptor[] result =
new IPerspectiveDescriptor[opened.length];
for (int i = 0; i < result.length; i++) {
result[i] = opened[i].getDesc();
}
return result;
}
/*
* Returns the perspectives in activation order (oldest first).
*/
protected IPerspectiveDescriptor[] getSortedPerspectives() {
Perspective sortedArray[] = perspList.getSortedPerspectives();
IPerspectiveDescriptor[] result =
new IPerspectiveDescriptor[sortedArray.length];
for (int i = 0; i < result.length; i++) {
result[i] = sortedArray[i].getDesc();
}
return result;
}
/*
* Returns the parts in activation order (oldest first).
*/
public IWorkbenchPartReference[] getSortedParts() {
return activationList.getParts();
}
public IWorkbenchPartReference getReference(IWorkbenchPart part) {
if (part == null)
return null;
PartPane pane = ((PartSite) part.getSite()).getPane();
if (pane instanceof MultiEditorInnerPane) {
MultiEditorInnerPane innerPane = (MultiEditorInnerPane) pane;
return innerPane.getParentPane().getPartReference();
}
if (pane == null) {
/*
* An error has occurred while creating the view.
*/
IViewReference refs[] = getViewReferences();
for (int i = 0; i < refs.length; i++) {
if (refs[i].getPart(false) == part)
return refs[i];
}
return null;
}
return pane.getPartReference();
}
private class ActivationList {
//List of parts in the activation order (oldest first)
List parts = new ArrayList();
/*
* Add/Move the active part to end of the list;
*/
void setActive(IWorkbenchPart part) {
if (parts.size() <= 0)
return;
PartPane pane = ((PartSite) part.getSite()).getPane();
if (pane instanceof MultiEditorInnerPane) {
MultiEditorInnerPane innerPane = (MultiEditorInnerPane) pane;
setActive(
innerPane.getParentPane().getPartReference().getPart(true));
} else {
IWorkbenchPartReference ref = getReference(part);
if (ref == parts.get(parts.size() - 1))
return;
parts.remove(ref);
parts.add(ref);
}
pane.addPropertyChangeListener(propertyChangeListener);
}
/*
* Add/Move the active part to end of the list;
*/
void setActive(IWorkbenchPartReference ref) {
setActive(ref.getPart(true));
}
/*
* Add the active part to the beginning of the list.
*/
void add(IWorkbenchPartReference ref) {
if (parts.indexOf(ref) >= 0)
return;
IWorkbenchPart part = ref.getPart(false);
if (part != null) {
PartPane pane = ((PartSite) part.getSite()).getPane();
if (pane instanceof MultiEditorInnerPane) {
MultiEditorInnerPane innerPane =
(MultiEditorInnerPane) pane;
add(innerPane.getParentPane().getPartReference());
return;
}
}
PartPane pane = ((WorkbenchPartReference) ref).getPane();
if (pane != null)
pane.addPropertyChangeListener(propertyChangeListener);
parts.add(0, ref);
}
/*
* Return the active part. Filter fast views.
*/
IWorkbenchPart getActive() {
if (parts.isEmpty())
return null;
return getActive(parts.size() - 1);
}
/*
* Return the previously active part. Filter fast views.
*/
IWorkbenchPart getPreviouslyActive() {
if (parts.size() < 2)
return null;
return getActive(parts.size() - 2);
}
/*
* Find a part in the list starting from the end and filter fast views
* and views from other perspectives.
*/
private IWorkbenchPart getActive(int start) {
IWorkbenchPartReference[] views = getViewReferences();
for (int i = start; i >= 0; i--) {
IWorkbenchPartReference ref =
(IWorkbenchPartReference) parts.get(i);
// Skip parts whose containers have disabled auto-focus
IWorkbenchPart part = ref.getPart(false);
if (part != null) {
IWorkbenchPartSite site = part.getSite();
if (site instanceof PartSite) {
PartSite partSite = (PartSite)site;
ILayoutContainer container = partSite.getPane().getContainer();
if ((container != null) && (!container.allowsAutoFocus())) {
continue;
}
}
}
// Skip fastviews
if (ref instanceof IViewReference) {
if (!((IViewReference) ref).isFastView() ) {
for (int j = 0; j < views.length; j++) {
if (views[j] == ref) {
return ref.getPart(true);
}
}
}
} else {
return ref.getPart(true);
}
}
return null;
}
/*
* Retuns the index of the part within the activation list. The higher
* the index, the more recent it was used.
*/
int indexOf(IWorkbenchPart part) {
return parts.indexOf(getReference(part));
}
/*
* Remove a part from the list
*/
boolean remove(IWorkbenchPartReference ref) {
PartPane pane = ((WorkbenchPartReference) ref).getPane();
if (pane != null)
pane.removePropertyChangeListener(propertyChangeListener);
return parts.remove(ref);
}
/*
* Returns the editors in activation order (oldest first).
*/
private IEditorReference[] getEditors() {
ArrayList editors = new ArrayList(parts.size());
for (Iterator i = parts.iterator(); i.hasNext();) {
IWorkbenchPartReference part =
(IWorkbenchPartReference) i.next();
if (part instanceof IEditorReference) {
editors.add(part);
}
}
return (IEditorReference[]) editors.toArray(
new IEditorReference[editors.size()]);
}
/*
* Return a list with all parts (editors and views).
*/
private IWorkbenchPartReference[] getParts() {
IWorkbenchPartReference[] views = getViewReferences();
ArrayList resultList = new ArrayList(parts.size());
for (Iterator iterator = parts.iterator(); iterator.hasNext();) {
IWorkbenchPartReference ref =
(IWorkbenchPartReference) iterator.next();
if (ref instanceof IViewReference) {
//Filter views from other perspectives
for (int i = 0; i < views.length; i++) {
if (views[i] == ref) {
resultList.add(ref);
break;
}
}
} else {
resultList.add(ref);
}
}
IWorkbenchPartReference[] result =
new IWorkbenchPartReference[resultList.size()];
return (IWorkbenchPartReference[]) resultList.toArray(result);
}
/*
* Returns the topmost editor on the stack, or null if none.
*/
IEditorPart getTopEditor() {
IEditorReference editors[] = getEditors();
if (editors.length > 0) {
return editors[editors.length - 1].getEditor(true);
}
return null;
}
}
/**
* Helper class to keep track of all opened perspective. Both the opened
* and used order is kept.
*/
private class PerspectiveList {
/**
* List of perspectives in the order they were opened;
*/
private List openedList;
/**
* List of perspectives in the order they were used. Last element is
* the most recently used, and first element is the least recently
* used.
*/
private List usedList;
/**
* The perspective explicitly set as being the active one
*/
private Perspective active;
/**
* Creates an empty instance of the perspective list
*/
public PerspectiveList() {
openedList = new ArrayList(15);
usedList = new ArrayList(15);
}
/**
* Return all perspectives in the order they were activated.
*/
public Perspective[] getSortedPerspectives() {
Perspective[] result = new Perspective[usedList.size()];
return (Perspective[]) usedList.toArray(result);
}
/**
* Adds a perspective to the list. No check is done for a duplicate
* when adding.
*/
public boolean add(Perspective perspective) {
openedList.add(perspective);
usedList.add(0, perspective);
//It will be moved to top only when activated.
return true;
}
/**
* Returns an iterator on the perspective list in the order they were
* opened.
*/
public Iterator iterator() {
return openedList.iterator();
}
/**
* Returns an array with all opened perspectives
*/
public Perspective[] getOpenedPerspectives() {
Perspective[] result = new Perspective[openedList.size()];
return (Perspective[]) openedList.toArray(result);
}
/**
* Removes a perspective from the list.
*/
public boolean remove(Perspective perspective) {
if (active == perspective)
active = null;
usedList.remove(perspective);
return openedList.remove(perspective);
}
/**
* Swap the opened order of old perspective with the new perspective.
*/
public void swap(
Perspective oldPerspective,
Perspective newPerspective) {
int oldIndex = openedList.indexOf(oldPerspective);
int newIndex = openedList.indexOf(newPerspective);
if (oldIndex < 0 || newIndex < 0)
return;
openedList.set(oldIndex, newPerspective);
openedList.set(newIndex, oldPerspective);
}
/**
* Returns whether the list contains any perspectives
*/
public boolean isEmpty() {
return openedList.isEmpty();
}
/**
* Returns the most recently used perspective in the list.
*/
public Perspective getActive() {
return active;
}
/**
* Returns the next most recently used perspective in the list.
*/
public Perspective getNextActive() {
if (active == null) {
if (usedList.isEmpty())
return null;
else
return (Perspective) usedList.get(usedList.size() - 1);
} else {
if (usedList.size() < 2)
return null;
else
return (Perspective) usedList.get(usedList.size() - 2);
}
}
/**
* Returns the number of perspectives opened
*/
public int size() {
return openedList.size();
}
/**
* Marks the specified perspective as the most recently used one in the
* list.
*/
public void setActive(Perspective perspective) {
if (perspective == active)
return;
active = perspective;
if (perspective != null) {
usedList.remove(perspective);
usedList.add(perspective);
}
}
}
//for dynamic UI
protected HashMap getStateMap() {
return stateMap;
}
//for dynamic UI
protected void addPerspective(Perspective persp) {
perspList.add(persp);
}
/* (non-Javadoc)
* @see org.eclipse.ui.IWorkbenchPage#getViewStack(org.eclipse.ui.IViewPart)
*/
public IViewPart [] getViewStack(IViewPart part) {
// Sanity check.
Perspective persp = getActivePerspective();
if (persp == null || !certifyPart(part))
return null;
ILayoutContainer container = ((PartSite)part.getSite()).getPane().getContainer();
if (container instanceof ViewStack) {
ViewStack folder = (ViewStack) container;
final ArrayList list = new ArrayList(folder.getChildren().length);
for (int i = 0; i < folder.getChildren().length; i++) {
LayoutPart layoutPart = folder.getChildren()[i];
if (layoutPart instanceof ViewPane) {
IViewPart view = findView(((ViewPane)layoutPart).getViewReference().getId());
if (view != null)
list.add(view);
}
}
// sort the list by activation order
Collections.sort(list, new Comparator() {
public int compare(Object o1, Object o2) {
int pos1 = (-1) * activationList.indexOf((IWorkbenchPart) o1);
int pos2 = (-1) * activationList.indexOf((IWorkbenchPart) o2);
return pos1 - pos2;
}});
return (IViewPart []) list.toArray(new IViewPart [list.size()]);
}
return new IViewPart [] {part};
}
/**
* Allow for programmatically resizing a part.
* <p>
* <em>EXPERIMENTAL</em>
* </p>
* <p>
* Known limitations:
* <ul>
* <li>currently applies only to views</li>
* <li>has no effect when view is zoomed</li>
* </ul>
*/
public void resizeView(IViewPart part, int width, int height) {
SashInfo sashInfo = new SashInfo();
PartPane pane = ((PartSite)part.getSite()).getPane();
ILayoutContainer container = pane.getContainer();
LayoutTree tree = getPerspectivePresentation().getLayout().root.find(((ViewStack)container));
// retrieve our layout sashes from the layout tree
findSashParts(tree, pane.findSashes(), sashInfo);
// first set the width
float deltaWidth = width - pane.getBounds().width;
if (sashInfo.right != null) {
Rectangle rightBounds = sashInfo.rightNode.getBounds();
// set the new ratio
sashInfo.right.setRatio(
((float) ((deltaWidth + sashInfo.right.getBounds().x) - rightBounds.x))
/ ((float) rightBounds.width));
// complete the resize
sashInfo.rightNode.setBounds(rightBounds);
}
else if (sashInfo.left != null) {
Rectangle leftBounds = sashInfo.leftNode.getBounds();
// set the ratio
sashInfo.left.setRatio(
(float) ((sashInfo.left.getBounds().x - deltaWidth) - leftBounds.x)
/ ((float) leftBounds.width));
// complete the resize
sashInfo.leftNode.setBounds(sashInfo.leftNode.getBounds());
}
// next set the height
float deltaHeight = height - pane.getBounds().height;
if (sashInfo.bottom != null) {
Rectangle bottomBounds = sashInfo.bottomNode.getBounds();
// set the new ratio
sashInfo.bottom.setRatio(
((float) ((deltaHeight + sashInfo.bottom.getBounds().y) - bottomBounds.y))
/ ((float) bottomBounds.height));
// complete the resize
sashInfo.bottomNode.setBounds(bottomBounds);
}
else if (sashInfo.top != null) {
Rectangle topBounds = sashInfo.topNode.getBounds();
// set the ratio
sashInfo.top.setRatio(
(float) ((sashInfo.top.getBounds().y - deltaHeight) - topBounds.y)
/ ((float) topBounds.height));
// complete the resize
sashInfo.topNode.setBounds(topBounds);
}
}
// provides sash information for the given pane
private class SashInfo {
private LayoutPartSash right;
private LayoutPartSash left;
private LayoutPartSash top;
private LayoutPartSash bottom;
private LayoutTreeNode rightNode;
private LayoutTreeNode leftNode;
private LayoutTreeNode topNode;
private LayoutTreeNode bottomNode;
}
private void findSashParts(LayoutTree tree, PartPane.Sashes sashes, SashInfo info) {
LayoutTree parent = tree.getParent();
if (parent == null)
return;
if (parent.part instanceof LayoutPartSash) {
// get the layout part sash from this tree node
LayoutPartSash sash = (LayoutPartSash) parent.part;
// make sure it has a sash control
Control control = sash.getControl();
if (control != null) {
// check for a vertical sash
if (sash.isVertical()) {
if (sashes.left == control) {
info.left = sash;
info.leftNode = parent.findSash(sash);
}
else if (sashes.right == control) {
info.right = sash;
info.rightNode = parent.findSash(sash);
}
}
// check for a horizontal sash
else {
if (sashes.top == control) {
info.top = sash;
info.topNode = parent.findSash(sash);
}
else if (sashes.bottom == control) {
info.bottom = sash;
info.bottomNode = parent.findSash(sash);
}
}
}
}
// recursive call to continue up the tree
findSashParts(parent, sashes, info);
}
}