Package org.eclipse.ui.internal

Source Code of org.eclipse.ui.internal.WorkbenchPage

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

package org.eclipse.ui.internal;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;

import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.dynamichelpers.ExtensionTracker;
import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.internal.provisional.action.ICoolBarManager2;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.util.IPropertyChangeListener;
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.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
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.swt.widgets.Shell;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorDescriptor;
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.ISaveablesLifecycleListener;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IShowEditorInput;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IViewReference;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartReference;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.IWorkbenchPreferenceConstants;
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.contexts.IContextService;
import org.eclipse.ui.internal.StartupThreading.StartupRunnable;
import org.eclipse.ui.internal.contexts.ContextAuthority;
import org.eclipse.ui.internal.dialogs.CustomizePerspectiveDialog;
import org.eclipse.ui.internal.dnd.SwtUtil;
import org.eclipse.ui.internal.intro.IIntroConstants;
import org.eclipse.ui.internal.misc.UIListenerLogging;
import org.eclipse.ui.internal.misc.UIStats;
import org.eclipse.ui.internal.registry.ActionSetRegistry;
import org.eclipse.ui.internal.registry.EditorDescriptor;
import org.eclipse.ui.internal.registry.EditorRegistry;
import org.eclipse.ui.internal.registry.IActionSetDescriptor;
import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
import org.eclipse.ui.internal.registry.PerspectiveDescriptor;
import org.eclipse.ui.internal.registry.UIExtensionTracker;
import org.eclipse.ui.internal.tweaklets.GrabFocus;
import org.eclipse.ui.internal.tweaklets.TabBehaviour;
import org.eclipse.ui.internal.tweaklets.Tweaklets;
import org.eclipse.ui.internal.util.PrefUtil;
import org.eclipse.ui.internal.util.Util;
import org.eclipse.ui.model.IWorkbenchAdapter;
import org.eclipse.ui.part.MultiEditor;
import org.eclipse.ui.presentations.IStackPresentationSite;

/**
* A collection of views and editors in a workbench.
*/
public class WorkbenchPage extends CompatibleWorkbenchPage implements
        IWorkbenchPage {
 
  private static final String ATT_AGGREGATE_WORKING_SET_ID = "aggregateWorkingSetId"; //$NON-NLS-1$
 
    private WorkbenchWindow window;

    private IAdaptable input;

    private IWorkingSet workingSet;
   
    private AggregateWorkingSet aggregateWorkingSet;

    private Composite composite;
   
    //Could be delete. This information is in the active part list;
    private ActivationList activationList = new ActivationList();

  /**
   * This field controls whether or not the ActivationList will
   * remove Fast Views from its list of active views. It's currently
   * only <core>true</code> when new editors are added, allowing
   * a minimized View that opens (but doesn't activate) a new editor
   * to remain active.
   */
  private boolean includeActiveFastViews = false;

    private EditorManager editorMgr;

    private EditorAreaHelper editorPresentation;

    private ListenerList propertyChangeListeners = new ListenerList();

    private PageSelectionService selectionService = new PageSelectionService(
            this);

    private WorkbenchPagePartList partList = new WorkbenchPagePartList(selectionService);

    private IActionBars actionBars;
   
    private ActionSetManager actionSets;
   
    private ViewFactory viewFactory;

    private PerspectiveList perspList = new PerspectiveList();

    private PerspectiveDescriptor deferredActivePersp;

    private NavigationHistory navigationHistory = new NavigationHistory(this);
   
    private IStickyViewManager stickyViewMan = StickyViewManager.getInstance(this);

    /**
     * If we're in the process of activating a part, this points to the new part.
     * Otherwise, this is null.
     */
    private IWorkbenchPartReference partBeingActivated = null;
   
    /**
     * Contains a list of perspectives that may be dirty due to plugin
     * installation and removal.
     */
    private Set dirtyPerspectives = new HashSet();
   
    private IPropertyChangeListener workingSetPropertyChangeListener = 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)) {
                if(event.getOldValue().equals(workingSet)) {
            setWorkingSet(null);
          }
               
                // room for optimization here
                List newList = new ArrayList(Arrays.asList(workingSets));
                if (newList.remove(event.getOldValue())) {
            setWorkingSets((IWorkingSet []) newList
                .toArray(new IWorkingSet [newList.size()]));
          }
            }
        }
    };

    private ActionSwitcher actionSwitcher = new ActionSwitcher();

  private IExtensionTracker tracker;
   
    // Deferral count... delays disposing parts and sending certain events if nonzero
    private int deferCount = 0;
    // Parts waiting to be disposed
    private List pendingDisposals = new ArrayList();
   
  private IExtensionChangeHandler perspectiveChangeHandler = new IExtensionChangeHandler() {

    /* (non-Javadoc)
     * @see org.eclipse.core.runtime.dynamicHelpers.IExtensionChangeHandler#removeExtension(org.eclipse.core.runtime.IExtension, java.lang.Object[])
     */
    public void removeExtension(IExtension extension, Object[] objects) {
      boolean suggestReset = false;
      for (int i = 0; i < objects.length; i++) {
        if (objects[i] instanceof DirtyPerspectiveMarker) {
          String id = ((DirtyPerspectiveMarker)objects[i]).perspectiveId;
          if (!dirtyPerspectives.remove(id)) {
            dirtyPerspectives.add(id); // otherwise we will be dirty
          }
          PerspectiveDescriptor persp = (PerspectiveDescriptor) getPerspective();
          if (persp == null || persp.hasCustomDefinition()) {
            continue;
          }
          if (persp.getId().equals(id)) {
            suggestReset = true;
          }
        }
      }
      if (suggestReset) {
        suggestReset();
      }
    }
       
        /* (non-Javadoc)
         * @see org.eclipse.core.runtime.dynamicHelpers.IExtensionChangeHandler#addExtension(org.eclipse.core.runtime.dynamicHelpers.IExtensionTracker, org.eclipse.core.runtime.IExtension)
         */
        public void addExtension(IExtensionTracker tracker, IExtension extension) {
            if (WorkbenchPage.this != getWorkbenchWindow().getActivePage()) {
        return;
      }
           
            // Get the current perspective.
            PerspectiveDescriptor persp = (PerspectiveDescriptor) getPerspective();
            if (persp == null) {
        return;
      }
            String currentId = persp.getId();
            IConfigurationElement[] elements = extension.getConfigurationElements();
            boolean suggestReset = false;
            for (int i = 0; i < elements.length; i++) {
                // If any of these refer to the current perspective, output
                // a message saying this perspective will need to be reset
                // in order to see the changes.  For any other case, the
                // perspective extension registry will be rebuilt anyway so
                // just ignore it.
                String id = elements[i].getAttribute(IWorkbenchRegistryConstants.ATT_TARGET_ID);
                if (id == null) {
          continue;
        }
                if (id.equals(currentId) && !persp.hasCustomDefinition()) {
                    suggestReset = true;
                }
                else {
                    dirtyPerspectives.add(id);
                }
                DirtyPerspectiveMarker marker = new DirtyPerspectiveMarker(id);
                tracker.registerObject(extension, marker, IExtensionTracker.REF_STRONG);
            }
            if (suggestReset) {
        suggestReset();
      }

        }
  };
  private IWorkingSet[] workingSets = new IWorkingSet[0];
  private String aggregateWorkingSetId;

  private IExtensionPoint getPerspectiveExtensionPoint() {
    return Platform.getExtensionRegistry().getExtensionPoint(PlatformUI.PLUGIN_ID, IWorkbenchRegistryConstants.PL_PERSPECTIVE_EXTENSIONS);
  }

    /**
     * Manages editor contributions and action set part associations.
     */
    private class ActionSwitcher {
        private IWorkbenchPart activePart;

        private IEditorPart topEditor;

        private ArrayList oldActionSets = 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)) {
                  activePart = newPart;
                  topEditor = (IEditorPart) newPart;
                    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;
      }

            if (activePart == topEditor) {
              updateActivePart(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();
            site.activateActionBars(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();
            site.deactivateActionBars(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 (oldActionSets.equals(newActionSets)) {
        return false;
      }

      IContextService service = (IContextService) window
          .getService(IContextService.class);
      try {
        service.activateContext(ContextAuthority.DEFER_EVENTS);

        // show the new
        for (int i = 0; i < newActionSets.size(); i++) {
          actionSets.showAction((IActionSetDescriptor) newActionSets
              .get(i));
        }

        // hide the old
        for (int i = 0; i < oldActionSets.size(); i++) {
          actionSets.hideAction((IActionSetDescriptor) oldActionSets
              .get(i));
        }

        oldActionSets = newActionSets;

      } finally {
        service.activateContext(ContextAuthority.SEND_EVENTS);
      }
      Perspective persp = getActivePerspective();
      if (persp == null) {
        return false;
      }

      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
   * @throws WorkbenchException
   *             on null layout id
   */
    public WorkbenchPage(WorkbenchWindow w, String layoutID, IAdaptable input)
            throws WorkbenchException {
        super();
        if (layoutID == null) {
      throw new WorkbenchException(WorkbenchMessages.WorkbenchPage_UndefinedPerspective);
    }
        init(w, layoutID, input, true);
    }

    /**
     * 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
     * @throws WorkbenchException
     */
    public WorkbenchPage(WorkbenchWindow w, IAdaptable input)
            throws WorkbenchException {
        super();
        init(w, null, input, false);
    }

    /**
     * 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 (composite!=null && composite.isVisible()
            && !((GrabFocus)Tweaklets.get(GrabFocus.KEY)).grabFocusAllowed(part)) {
          return;
        }
       
        // If zoomed, unzoom.
        zoomOutIfNecessary(part);

        if (part instanceof MultiEditor) {
            part = ((MultiEditor) part).getActiveEditor();
        }
        // Activate part.
        //if (window.getActivePage() == this) {
        IWorkbenchPartReference ref = getReference(part);
        internalBringToTop(ref);
        setActivePart(part);
    }

    /**
     * Activates a part. The part is given focus, the pane is hilighted.
     */
    private void activatePart(final IWorkbenchPart part) {
        Platform.run(new SafeRunnable(WorkbenchMessages.WorkbenchPage_ErrorActivatingView) {
                    public void run() {
                        if (part != null) {
                            //part.setFocus();
                            PartPane pane = getPane(part);
                            pane.setFocus();
                            PartSite site = (PartSite) part.getSite();
                            pane.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;
    }
       
        persp.getFastViewManager().addViewReference(FastViewBar.FASTVIEWBAR_ID, -1, ref, true);
    }
   
    /**
     * Add a fast view.
     */
    public void makeFastView(IViewReference ref) {
        Perspective persp = getActivePerspective();
        if (persp == null) {
      return;
    }

        FastViewManager fvm = persp.getFastViewManager();
        if (fvm.isFastView(ref)) {
            return;
        }
       
        // Do real work.
        persp.makeFastView(ref);

        updateActivePart();
       
        // The view is now invisible.
        // If it is active then deactivate it.

        // Notify listeners.
        window.firePerspectiveChanged(this, getPerspective(), ref,
                CHANGE_FAST_VIEW_ADD);
        window.firePerspectiveChanged(this, getPerspective(),
                CHANGE_FAST_VIEW_ADD);
    }

    /**
     * Adds an IPartListener to the part service.
     */
    public void addPartListener(IPartListener l) {
        partList.getPartService().addPartListener(l);
    }

    /**
     * Adds an IPartListener to the part service.
     */
    public void addPartListener(IPartListener2 l) {
        partList.getPartService().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);
    }
   
    private ILayoutContainer getContainer(IWorkbenchPart part) {
        PartPane pane = getPane(part);
        if (pane == null) {
            return null;
        }
       
        return pane.getContainer();
    }

    private ILayoutContainer getContainer(IWorkbenchPartReference part) {
        PartPane pane = getPane(part);
        if (pane == null) {
            return null;
        }
       
        return pane.getContainer();
    }
   
    private PartPane getPane(IWorkbenchPart part) {
        if (part == null) {
            return null;
        }
        return getPane(getReference(part));
    }
   
    private PartPane getPane(IWorkbenchPartReference part) {
        if (part == null) {
            return null;
        }
       
        return ((WorkbenchPartReference)part).getPane();
    }

   
    /**
     * Brings a part to the front of its stack. Does not update the active part or
     * active editor. This should only be called if the caller knows that the part
     * is not in the same stack as the active part or active editor, or if the caller
     * is prepared to update activation after the call.
     *
     * @param part
     */
    private boolean internalBringToTop(IWorkbenchPartReference part) {

        boolean broughtToTop = false;
       
        // Move part.
        if (part instanceof IEditorReference) {
            ILayoutContainer container = getContainer(part);
            if (container instanceof PartStack) {
                PartStack stack = (PartStack)container;
                PartPane newPart = getPane(part);
                if (stack.getSelection() != newPart) {
                    stack.setSelection(newPart);
                }
                broughtToTop = true;
            }
        } else if (part instanceof IViewReference) {
            Perspective persp = getActivePerspective();
            if (persp != null) {
                broughtToTop = persp.bringToTop((IViewReference)part);
            }
        }
       
        // Ensure that this part is considered the most recently activated part
        // in this stack
        activationList.bringToTop(part);
       
        return broughtToTop;
    }

   
    /**
     * Moves a part forward in the Z order of a perspective so it is visible.
     * If the part is in the same stack as the active part, the new part is
     * activated.
     *
     * @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 (!((GrabFocus)Tweaklets.get(GrabFocus.KEY)).grabFocusAllowed(part)) {
          return;
        }

        String label = null; // debugging only
        if (UIStats.isDebugging(UIStats.BRING_PART_TO_TOP)) {
            label = part != null ? part.getTitle() : "none"; //$NON-NLS-1$
        }
       
        try {
            UIStats.start(UIStats.BRING_PART_TO_TOP, label);
           
            IWorkbenchPartReference ref = getReference(part);
            ILayoutContainer activeEditorContainer = getContainer(getActiveEditor());
            ILayoutContainer activePartContainer = getContainer(getActivePart());
            ILayoutContainer newPartContainer = getContainer(part);
           
            if (newPartContainer == activePartContainer) {
                makeActive(ref);
            } else if (newPartContainer == activeEditorContainer) {
                if (ref instanceof IEditorReference) {
                  if (part!=null) {
                      IWorkbenchPartSite site = part.getSite();
            if (site instanceof PartSite) {
              ref = ((PartSite) site).getPane()
                  .getPartReference();
            }
                  }
                    makeActiveEditor((IEditorReference)ref);
                } else {
                    makeActiveEditor(null);
                }
            } else {
                internalBringToTop(ref);
                if (ref != null) {
                    partList.firePartBroughtToTop(ref);
                }
            }
        } finally {
            UIStats.end(UIStats.BRING_PART_TO_TOP, part, 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;
      }

            // Notify listeners that we are doing a reset.
            window.firePerspectiveChanged(this, desc, CHANGE_RESET);

            // Create new persp from original template.
            // Suppress the perspectiveOpened and perspectiveClosed events otherwise it looks like two
            // instances of the same perspective are open temporarily (see bug 127470).
            Perspective newPersp = createPerspective(desc, false);
            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);

            // Install new persp.
            setPerspective(newPersp);

            // Destroy old persp.
            disposePerspective(oldPersp, false);

            // Update the Coolbar layout.
            resetToolBarLayout();

            // restore the maximized intro
            if (introViewAdapter != null) {
                try {
                    // ensure that the intro is visible in the new perspective
                    showView(IIntroConstants.INTRO_VIEW_ID);
                    if (introFullScreen) {
            toggleZoom(introPane.getPartReference());
          }
                } catch (PartInitException e) {
                    WorkbenchPlugin.log("Could not restore intro", //$NON-NLS-1$
                            WorkbenchPlugin.getStatus(e));
                } finally {
                    // 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 desc
     *            identifies the new perspective.
     */
    private void busySetPerspective(IPerspectiveDescriptor desc) {
        // Create new layout.
        String label = desc.getId(); // debugging only
        Perspective newPersp = null;
        try {
            UIStats.start(UIStats.SWITCH_PERSPECTIVE, label);
            PerspectiveDescriptor realDesc = (PerspectiveDescriptor) desc;
            newPersp = findPerspective(realDesc);
            if (newPersp == null) {
                newPersp = createPerspective(realDesc, true);
                if (newPersp == null) {
          return;
        }
            }

            // Change layout.
            setPerspective(newPersp);
        } finally {
            UIStats.end(UIStats.SWITCH_PERSPECTIVE, desc.getId(), 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) {
            busyShowView(view, mode);
            return view;
        }

        // Show the view.
        view = persp.showView(viewID, secondaryID);
        if (view != null) {
            busyShowView(view, mode);
           
            IWorkbenchPartReference partReference = getReference(view);
            PartPane partPane = getPane(partReference);
            partPane.setInLayout(true);

            window.firePerspectiveChanged(this, getPerspective(),
                    partReference, CHANGE_VIEW_SHOW);
            window.firePerspectiveChanged(this, getPerspective(),
                    CHANGE_VIEW_SHOW);
        }
        return view;
    }

    /*
     * Performs showing of the view in the given mode.
     */
    private void busyShowView(IViewPart part, int mode) {
        if (!((GrabFocus)Tweaklets.get(GrabFocus.KEY)).grabFocusAllowed(part)) {
          return;
        }
        if (mode == VIEW_ACTIVATE) {
      activate(part);
    } else if (mode == VIEW_VISIBLE) {
            IWorkbenchPartReference ref = getActivePartReference();
            // if there is no active part or it's not a view, bring to top
            if (ref == null || !(ref instanceof IViewReference)) {
        bringToTop(part);
      } else {
                // otherwise check to see if the we're in the same stack as the active view
                IViewReference activeView = (IViewReference) ref;
                IViewReference[] viewStack = getViewReferenceStack(part);
                for (int i = 0; i < viewStack.length; i++) {
                    if (viewStack[i].equals(activeView)) {
            return;
          }
                }
                bringToTop(part);
            }
        }
    }

    /**
     * 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 ref != null && 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);
    }

    private void updateActivePart() {
       
        if (isDeferred()) {
            return;
        }
       
        IWorkbenchPartReference oldActivePart = partList.getActivePartReference();
        IWorkbenchPartReference oldActiveEditor = partList.getActiveEditorReference();
        IWorkbenchPartReference newActivePart = null;
        IEditorReference newActiveEditor = null;
       
        if (!window.isClosing()) {
            // If an editor is active, try to keep an editor active
            if (oldActivePart == oldActiveEditor) {
                newActiveEditor = (IEditorReference)activationList.getActiveReference(true);
                newActivePart = newActiveEditor;
                if (newActivePart == null) {
                    // Only activate a non-editor if there's no editors left
                    newActivePart = activationList.getActiveReference(false);
                }
            } else {
                // If a non-editor is active, activate whatever was activated most recently
                newActivePart = activationList.getActiveReference(false);
               
                if (newActivePart instanceof IEditorReference) {
                    // If that happens to be an editor, make it the active editor as well
                    newActiveEditor = (IEditorReference)newActivePart;
                } else {
                    // Otherwise, select whatever editor was most recently active
                    newActiveEditor = (IEditorReference)activationList.getActiveReference(true);
                }  
            }
        }

        if (newActiveEditor != oldActiveEditor) {
            makeActiveEditor(newActiveEditor);
        }
       
        if (newActivePart != oldActivePart) {
            makeActive(newActivePart);
        }
    }
   
    /**
     * Makes the given part active. Brings it in front if necessary. Permits null
     * (indicating that no part should be active).
     *
     * @since 3.1
     *
     * @param ref new active part (or null)
     */
    private void makeActive(IWorkbenchPartReference ref) {
        if (ref == null) {
            setActivePart(null);
        } else {
            IWorkbenchPart newActive = ref.getPart(true);
            if (newActive == null) {
                setActivePart(null);
            } else {
                activate(newActive);
            }
        }
    }
   
    /**
     * Makes the given editor active. Brings it to front if necessary. Permits <code>null</code>
     * (indicating that no editor is active).
     *
     * @since 3.1
     *
     * @param ref the editor to make active, or <code>null</code> for no active editor
     */
    private void makeActiveEditor(IEditorReference ref) {
        if (ref == getActiveEditorReference()) {
            return;
        }
       
        IEditorPart part = (ref == null) ? null : ref.getEditor(true);
       
        if (part != null) {
            editorMgr.setVisibleEditor(ref, false);
            navigationHistory.markEditor(part);
        }
       
        actionSwitcher.updateTopEditor(part);

        if (ref != null) {
            activationList.bringToTop(getReference(part));
        }
       
        partList.setActiveEditor(ref);
    }
   
    /**
     * See IWorkbenchPage
     */
    public boolean closeEditors(IEditorReference[] refArray, boolean save) {
        if (refArray.length == 0) {
            return true;
        }
       
        // Check if we're being asked to close any parts that are already closed or cannot
        // be closed at this time
        ArrayList toClose = new ArrayList();
        for (int i = 0; i < refArray.length; i++) {
            IEditorReference reference = refArray[i];
           
            // If we're in the middle of creating this part, this is a programming error. Abort the entire
            // close operation. This usually occurs if someone tries to open a dialog in a method that
            // isn't allowed to do so, and a *syncExec tries to close the part. If this shows up in a log
            // file with a dialog's event loop on the stack, then the code that opened the dialog is usually
            // at fault.
            if (reference == partBeingActivated) {
                WorkbenchPlugin.log(new RuntimeException("WARNING: Blocked recursive attempt to close part "  //$NON-NLS-1$
                        + partBeingActivated.getId() + " while still in the middle of activating it")); //$NON-NLS-1$
                return false;
            }
           
            if(reference instanceof WorkbenchPartReference) {
                WorkbenchPartReference ref = (WorkbenchPartReference) reference;
               
                // If we're being asked to close a part that is disposed (ie: already closed),
                // skip it and proceed with closing the remaining parts.
                if (ref.isDisposed()) {
                    continue;
                }
            }
           
            toClose.add(reference);
        }
       
        IEditorReference[] editorRefs = (IEditorReference[]) toClose.toArray(new IEditorReference[toClose.size()]);
       
        // notify the model manager before the close
        List partsToClose = new ArrayList();
        for (int i = 0; i < editorRefs.length; i++) {
            IEditorPart refPart = editorRefs[i].getEditor(false);
            if (refPart != null) {
              partsToClose.add(refPart);
            }
        }
        SaveablesList modelManager = null;
        Object postCloseInfo = null;
        if(partsToClose.size()>0) {
          modelManager = (SaveablesList) getWorkbenchWindow().getService(ISaveablesLifecycleListener.class);
          // this may prompt for saving and return null if the user canceled:
          postCloseInfo = modelManager.preCloseParts(partsToClose, save, getWorkbenchWindow());
          if (postCloseInfo==null) {
            return false;
          }
        }

        // Fire pre-removal changes
        for (int i = 0; i < editorRefs.length; i++) {
            IEditorReference ref = editorRefs[i];
           
            // Notify interested listeners before the close
            window.firePerspectiveChanged(this, getPerspective(), ref,
                    CHANGE_EDITOR_CLOSE);
           
        }       
       
        deferUpdates(true);
        try {       
          if(modelManager!=null) {
              modelManager.postClose(postCloseInfo);
            }
         
          // Close all editors.
          for (int i = 0; i < editorRefs.length; i++) {
              IEditorReference ref = editorRefs[i];
             
              // Remove editor from the presentation
                editorPresentation.closeEditor(ref);
             
                partRemoved((WorkbenchPartReference)ref);               
          }
        } finally {
            deferUpdates(false);
        }
                       
        // Notify interested listeners after the close
        window.firePerspectiveChanged(this, getPerspective(),
                CHANGE_EDITOR_CLOSE);
       
        // Return true on success.
        return true;
    }
   
    /**
     * Enables or disables listener notifications. This is used to delay listener notifications until the
     * end of a public method.
     *
     * @param shouldDefer
     */
    private void deferUpdates(boolean shouldDefer) {
        if (shouldDefer) {
            if (deferCount == 0) {
                startDeferring();
            }
            deferCount++;
        } else {
            deferCount--;
            if (deferCount == 0) {
                handleDeferredEvents();
            }
        }
    }
   
    private void startDeferring() {
        editorPresentation.getLayoutPart().deferUpdates(true);
    }

    private void handleDeferredEvents() {
        editorPresentation.getLayoutPart().deferUpdates(false);
        updateActivePart();
        WorkbenchPartReference[] disposals = (WorkbenchPartReference[]) pendingDisposals.toArray(new WorkbenchPartReference[pendingDisposals.size()]);
        pendingDisposals.clear();
        for (int i = 0; i < disposals.length; i++) {
            WorkbenchPartReference reference = disposals[i];
            disposePart(reference);
        }
       
    }
   
    private boolean isDeferred() {
        return deferCount > 0;
    }

    /**
     * See IWorkbenchPage#closeEditor
     */
    public boolean closeEditor(IEditorReference editorRef, boolean save) {
        return closeEditors(new IEditorReference[] {editorRef}, save);
    }

    /**
     * See IWorkbenchPage#closeEditor
     */
    public boolean closeEditor(IEditorPart editor, boolean save) {
        IWorkbenchPartReference ref = getReference(editor);
        if (ref instanceof IEditorReference) {
          return closeEditors(new IEditorReference[] {(IEditorReference) ref}, save);
        }
        return false;
    }

    /**
     * @see IWorkbenchPage#closePerspective(IPerspectiveDescriptor, boolean, boolean)
     */
    public void closePerspective(IPerspectiveDescriptor desc, boolean saveParts, boolean closePage) {
        Perspective persp = findPerspective(desc);
        if (persp != null) {
      closePerspective(persp, saveParts, closePage);
    }
    }

    /**
   * Closes the specified perspective. If last perspective, then entire page
   * is closed.
   *
   * @param persp
   *            the perspective to be closed
   * @param saveParts
   *            whether the parts that are being closed should be saved
   *            (editors if last perspective, views if not shown in other
   *            parspectives)
   */
    /* package */
    void closePerspective(Perspective persp, boolean saveParts, boolean closePage) {

        // Always unzoom
        if (isZoomed()) {
      zoomOut();
    }

        List partsToSave = new ArrayList();
        List viewsToClose = new ArrayList();
        // collect views that will go away and views that are dirty
        IViewReference[] viewReferences = persp.getViewReferences();
        for (int i = 0; i < viewReferences.length; i++) {
      IViewReference reference = viewReferences[i];
          if (getViewFactory().getReferenceCount(reference) == 1) {
            IViewPart viewPart = reference.getView(false);
            if (viewPart != null) {
              viewsToClose.add(viewPart);
              if (saveParts && reference.isDirty()) {
                partsToSave.add(viewPart);
              }
            }
          }
    }
        if (saveParts && perspList.size() == 1) {
          // collect editors that are dirty
          IEditorReference[] editorReferences = getEditorReferences();
          for (int i = 0; i < editorReferences.length; i++) {
        IEditorReference reference = editorReferences[i];
          if (reference.isDirty()) {
            IEditorPart editorPart = reference.getEditor(false);
            if (editorPart != null) {
              partsToSave.add(editorPart);
            }
          }
      }
        }
        if (saveParts && !partsToSave.isEmpty()) {
          if (!EditorManager.saveAll(partsToSave, true, true, false, window)) {
            // user canceled
            return;
          }
      }
        // Close all editors on last perspective close
        if (perspList.size() == 1 && getEditorManager().getEditorCount() > 0) {
            // Close all editors
            if (!closeAllEditors(false)) {
        return;
      }
        }
       
        // closeAllEditors already notified the saveables list about the editors.
        SaveablesList saveablesList = (SaveablesList) getWorkbenchWindow().getWorkbench().getService(ISaveablesLifecycleListener.class);
        // we took care of the saving already, so pass in false (postCloseInfo will be non-null)
        Object postCloseInfo = saveablesList.preCloseParts(viewsToClose, false, getWorkbenchWindow());
        saveablesList.postClose(postCloseInfo);

        // Dispose of the perspective
        boolean isActive = (perspList.getActive() == persp);
        if (isActive) {
      setPerspective(perspList.getNextActive());
    }
        disposePerspective(persp, true);
        if (closePage && perspList.size() == 0) {
      close();
    }
    }

    /**
     * Forces all perspectives on the page to zoom out.
     */
    public void unzoomAllPerspectives() {
      for (Iterator perspIter = perspList.iterator(); perspIter.hasNext();) {
      Perspective persp = (Perspective) perspIter.next();
      persp.getPresentation().forceNoZoom();
    }
    }
   
    /**
     * @see IWorkbenchPage#closeAllPerspectives(boolean, boolean)
     */
    public void closeAllPerspectives(boolean saveEditors, boolean closePage) {

        if (perspList.isEmpty()) {
      return;
    }

        // Always unzoom
        if (isZoomed()) {
      zoomOut();
    }

        if(saveEditors) {
          if (!saveAllEditors(true)) {
            return;
          }
        }
        // Close all editors
        if (!closeAllEditors(false)) {
      return;
    }

        // Deactivate the active perspective and part
        setPerspective((Perspective) null);

        // Close each perspective in turn
        PerspectiveList oldList = perspList;
        perspList = new PerspectiveList();
        Iterator itr = oldList.iterator();
        while (itr.hasNext()) {
      closePerspective((Perspective) itr.next(), false, false);
    }
        if (closePage) {
            close();
        }
    }

    /**
     * Creates the client composite.
     */
    private void createClientComposite() {
        final Composite parent = window.getPageComposite();
        StartupThreading.runWithoutExceptions(new StartupRunnable() {

      public void runWithException() {
        composite = new Composite(parent, SWT.NONE);
        composite.setVisible(false); // Make visible on activate.
        // force the client composite to be layed out
        parent.layout();
      }
    });
      
    }

    /**
     * Creates a new view set. Return null on failure.
     *
     * @param desc the perspective descriptor
     * @param notify whether to fire a perspective opened event
     */
    private Perspective createPerspective(PerspectiveDescriptor desc, boolean notify) {
        String label = desc.getId(); // debugging only
        try {
            UIStats.start(UIStats.CREATE_PERSPECTIVE, label);
            Perspective persp = new Perspective(desc, this);
            perspList.add(persp);
            if (notify) {
              window.firePerspectiveOpened(this, desc);
            }
            //if the perspective is fresh and uncustomzied then it is not dirty
            //no reset will be prompted for
            if (!desc.hasCustomDefinition()) {
        dirtyPerspectives.remove(desc.getId());
      }
            return persp;
        } catch (WorkbenchException e) {
            if (!((Workbench) window.getWorkbench()).isStarting()) {
                MessageDialog
                        .openError(
                                window.getShell(),
                                WorkbenchMessages.Error,
                                NLS.bind(WorkbenchMessages.Workbench_showPerspectiveError,desc.getId() ));
            }
            return null;
        } finally {
            UIStats.end(UIStats.CREATE_PERSPECTIVE, desc.getId(), label);
        }
    }

    /**
     * This is called by child objects after a part has been added to the page.
     * The page will in turn notify its listeners.
     */
    /* package */ void partAdded(WorkbenchPartReference ref) {
        activationList.add(ref);
        partList.addPart(ref);
       
        // If we're adding a new editor then allow fast views
        // to remain open
        if (ref instanceof IEditorReference) {
          includeActiveFastViews = true;
          updateActivePart();
          includeActiveFastViews = false;
        }
        else
          updateActivePart();
    }
   
    /**
     * This is called by child objects after a part has been added to the page.
     * The part will be queued for disposal after all listeners have been notified
     */
    /* package */ void partRemoved(WorkbenchPartReference ref) {
        activationList.remove(ref);
        disposePart(ref);
    }
   
    private void disposePart(WorkbenchPartReference ref) {
        if (isDeferred()) {
            pendingDisposals.add(ref);
        } else {
            partList.removePart(ref);
            ref.dispose();
        }
    }
   
    /**
     * Deactivates a part. The pane is unhilighted.
     */
    private void deactivatePart(IWorkbenchPart part) {
        if (part != null) {
            PartSite site = (PartSite) part.getSite();
            site.getPane().showFocus(false);
        }
    }
   
  /**
   * Detaches a view from the WorkbenchWindow.
   */
  public void detachView(IViewReference ref){
    Perspective persp = getActivePerspective();
    if(persp == null) {
      return;
    }
   
    PerspectiveHelper presentation = persp.getPresentation();   
    presentation.detachPart(ref);
  }
 
  /**
   * Removes a detachedwindow.
   */
  public void attachView(IViewReference ref){
      PerspectiveHelper presentation = getPerspectivePresentation();
       presentation.attachPart(ref);
  }

    /**
     * Cleanup.
     */
    public void dispose() {

        // Always unzoom
        if (isZoomed()) {
      zoomOut();
    }

        makeActiveEditor(null);
        makeActive(null);
       
        // Close and dispose the editors.
        closeAllEditors(false);
       
        // Need to make sure model data is cleaned up when the page is
    // disposed. Collect all the views on the page and notify the
    // saveable list of a pre/post close. This will free model data.
    IWorkbenchPartReference[] partsToClose = getOpenParts();
    List dirtyParts = new ArrayList(partsToClose.length);
    for (int i = 0; i < partsToClose.length; i++) {
      IWorkbenchPart part = partsToClose[i].getPart(false);
      if (part != null && part instanceof IViewPart) {
        dirtyParts.add(part);
      }
    }
    SaveablesList saveablesList = (SaveablesList) getWorkbenchWindow().getWorkbench().getService(ISaveablesLifecycleListener.class);
    Object postCloseInfo = saveablesList.preCloseParts(dirtyParts, false,getWorkbenchWindow());
    saveablesList.postClose(postCloseInfo);

        // Get rid of perspectives. This will close the views.
        Iterator itr = perspList.iterator();
        while (itr.hasNext()) {
            Perspective perspective = (Perspective) itr.next();
            window.firePerspectiveClosed(this, perspective.getDesc());
            perspective.dispose();
        }
        perspList = new PerspectiveList();

        // Capture views.
        IViewReference refs[] = viewFactory.getViews();

        if (refs.length > 0) {
            // Dispose views.
            for (int i = 0; i < refs.length; i++) {
                final WorkbenchPartReference ref = (WorkbenchPartReference) refs[i];
                //partList.removePart(ref);
                //firePartClosed(refs[i]);
                Platform.run(new SafeRunnable() {
                    public void run() {
//                        WorkbenchPlugin.log(new Status(IStatus.WARNING, WorkbenchPlugin.PI_WORKBENCH,
//                                Status.OK, "WorkbenchPage leaked a refcount for view " + ref.getId(), null));  //$NON-NLS-1$//$NON-NLS-2$
                       
                        ref.dispose();
                    }
   
                    public void handleException(Throwable e) {
                    }
                });
            }
        }
       
        activationList = new ActivationList();

        // Get rid of editor presentation.
        editorPresentation.dispose();

        // Get rid of composite.
        composite.dispose();

        navigationHistory.dispose();

        stickyViewMan.clear();
       
        if (tracker != null) {
      tracker.close();
    }
       
        // if we're destroying a window in a non-shutdown situation then we should
        // clean up the working set we made.
        if (!window.getWorkbench().isClosing()) {
            if (aggregateWorkingSet != null) {
              PlatformUI.getWorkbench().getWorkingSetManager().removeWorkingSet(aggregateWorkingSet);
            }
        }
    }

    /**
     * Dispose a perspective.
     *
     * @param persp the perspective descriptor
     * @param notify whether to fire a perspective closed event
     */
    private void disposePerspective(Perspective persp, boolean notify) {
        // Get rid of perspective.
        perspList.remove(persp);
        if (notify) {
          window.firePerspectiveClosed(this, persp.getDesc());
        }
        persp.dispose();

        stickyViewMan.remove(persp.getDesc().getId());
    }

    /**
     * @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 = window.createCustomizePerspectiveDialog(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 itr = perspList.iterator();
        while (itr.hasNext()) {
            Perspective mgr = (Perspective) itr.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;
    }
        return ref.getView(true);
    }

    /*
     * (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);
    }


    /**
     * 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) {
       
        UIListenerLogging.logPagePropertyChanged(this, changeId, oldValue, 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() {
        Collection collection = actionSets.getVisibleItems();
       
        return (IActionSetDescriptor[]) collection.toArray(new IActionSetDescriptor[collection.size()]);
    }

    /**
     * @see IWorkbenchPage
     */
    public IEditorPart getActiveEditor() {
        return partList.getActiveEditor();
    }

    /**
     * Returns the reference for the active editor, or <code>null</code>
     * if there is no active editor.
     *
     * @return the active editor reference or <code>null</code>
     */
    public IEditorReference getActiveEditorReference() {
        return partList.getActiveEditorReference();
    }
   
    /*
     * (non-Javadoc) Method declared on IPartService
     */
    public IWorkbenchPart getActivePart() {
        return partList.getActivePart();
    }

    /*
     * (non-Javadoc) Method declared on IPartService
     */
    public IWorkbenchPartReference getActivePartReference() {
        return partList.getActivePartReference();
    }

    /**
     * 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;
    }

    //  for dynamic UI - change access from private to protected
    // for testing purposes only, changed from protected to public
    /**
     * Answer the editor manager for this window.
     */
    public 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 ISaveablePart[] getDirtyParts() {
        List result = new ArrayList(3);
        IWorkbenchPartReference[] allParts = getAllParts();
        for (int i = 0; i < allParts.length; i++) {
            IWorkbenchPartReference reference = allParts[i];
           
            IWorkbenchPart part = reference.getPart(false);
            if (part != null && part instanceof ISaveablePart) {
                ISaveablePart saveable = (ISaveablePart)part;
                if (saveable.isDirty()) {
                    result.add(saveable);
                }
            }
        }
       
        return (ISaveablePart[]) result.toArray(new ISaveablePart[result.size()]);
    }
 
    /**
     * See IWorkbenchPage.
     */
    public IEditorPart findEditor(IEditorInput input) {
        return getEditorManager().findEditor(input);
    }

    /**
     * See IWorkbenchPage.
     */
    public IEditorReference[] findEditors(IEditorInput input, String editorId, int matchFlags) {
      return getEditorManager().findEditors(input, editorId, matchFlags);
    }
   
    /**
     * See IWorkbenchPage.
     */
    public IEditorReference[] getEditorReferences() {
        return editorPresentation.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.WorkbenchPage_UnknownLabel;
        IWorkbenchAdapter adapter = (IWorkbenchAdapter) Util.getAdapter(input,
                IWorkbenchAdapter.class);
        if (adapter != null) {
      label = adapter.getLabel(input);
    }
        Perspective persp = getActivePerspective();
        if (persp != null) {
      label = NLS.bind(WorkbenchMessages.WorkbenchPage_PerspectiveFormat,  label, persp.getDesc().getLabel());
    } else if (deferredActivePersp != null) {
      label = NLS.bind(WorkbenchMessages.WorkbenchPage_PerspectiveFormat,label, deferredActivePersp.getLabel());
    }
        return label;
    }

    /**
     * Returns the perspective.
     */
    public IPerspectiveDescriptor getPerspective() {
        if (deferredActivePersp != null) {
      return deferredActivePersp;
    }
        Perspective persp = getActivePerspective();
        if (persp != null) {
      return persp.getDesc();
    } else {
      return null;
    }
    }

    /*
     * (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 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() {
    return getViews(null, true);
    }
 
  /**
   * Returns all view parts in the specified perspective
   *
   * @param persp the perspective
   * @return an array of view parts
   * @since 3.1
   */
  /*package*/IViewPart[] getViews(Perspective persp, boolean restore) {     
        if (persp == null) {
      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(restore);
                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.removeActionSet(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) {
       
        // Sanity check.
        if (ref == null) {
      return;
    }

        Perspective persp = getActivePerspective();
        if (persp == null) {
      return;
    }

        boolean promptedForSave = false;
        IViewPart view = ref.getView(false);
        if (view != null) {

            if (!certifyPart(view)) {
                return;
            }
           
            // Confirm.
        if (view instanceof ISaveablePart) {
          ISaveablePart saveable = (ISaveablePart)view;
          if (saveable.isSaveOnCloseNeeded()) {
            IWorkbenchWindow window = view.getSite().getWorkbenchWindow();
            boolean success = EditorManager.saveAll(Collections.singletonList(view), true, true, false, window);
            if (!success) {
              // the user cancelled.
              return;
            }
            promptedForSave = true;
          }
        }
        }
       
        int refCount = getViewFactory().getReferenceCount(ref);
        SaveablesList saveablesList = null;
        Object postCloseInfo = null;
        if (refCount == 1) {
          IWorkbenchPart actualPart = ref.getPart(false);
          if (actualPart != null) {
        saveablesList = (SaveablesList) actualPart
            .getSite().getService(ISaveablesLifecycleListener.class);
        postCloseInfo = saveablesList.preCloseParts(Collections
            .singletonList(actualPart), !promptedForSave, this
            .getWorkbenchWindow());
        if (postCloseInfo==null) {
          // cancel
          return;
        }
      }
        }
       
        // Notify interested listeners before the hide
        window.firePerspectiveChanged(this, persp.getDesc(), ref,
                CHANGE_VIEW_HIDE);

        PartPane pane = getPane(ref);
        pane.setInLayout(false);
       
        updateActivePart();
       
        if (saveablesList != null) {
          saveablesList.postClose(postCloseInfo);
        }

        // Hide the part.
        persp.hideView(ref);

        // Notify interested listeners after the hide
        window.firePerspectiveChanged(this, getPerspective(), CHANGE_VIEW_HIDE);
    }

    /* package */void refreshActiveView() {
        updateActivePart();
    }

    /**
     * See IPerspective
     */
    public void hideView(IViewPart view) {
        hideView((IViewReference)getReference(view));
    }

    /**
     * Initialize the page.
     *
     * @param w
     *            the parent window
     * @param layoutID
     *            may be <code>null</code> if restoring from file
     * @param input
     *            the page input
     * @param openExtras
     *            whether to process the perspective extras preference
     */
    private void init(WorkbenchWindow w, String layoutID, IAdaptable input, boolean openExtras)
            throws WorkbenchException {
        // Save args.
        this.window = w;
        this.input = input;
        actionSets = new ActionSetManager(w);

        // Create presentation.
        createClientComposite();
        editorPresentation = new EditorAreaHelper(this);
        editorMgr = new EditorManager(window, this, editorPresentation);

    // add this page as a client to be notified when the UI has re-orded perspectives
    // so that the order can be properly maintained in the receiver.
    // E.g. a UI might support drag-and-drop and will need to make this known to ensure
    // #saveState and #restoreState do not lose this re-ordering
    w.addPerspectiveReorderListener(new IReorderListener() {
      public void reorder(Object perspective, int newLoc) {
        perspList.reorder((IPerspectiveDescriptor)perspective, newLoc);       
      }
    });
   
    if (openExtras) {
      openPerspectiveExtras();
    }
   
        // Get perspective descriptor.
        if (layoutID != null) {
            PerspectiveDescriptor desc = (PerspectiveDescriptor) WorkbenchPlugin
                    .getDefault().getPerspectiveRegistry()
                    .findPerspectiveWithId(layoutID);
            if (desc == null) {
        throw new WorkbenchException(
                        NLS.bind(WorkbenchMessages.WorkbenchPage_ErrorCreatingPerspective,layoutID ));
      }
            Perspective persp = findPerspective(desc);
            if (persp == null) {
              persp = createPerspective(desc, true);
            }
            perspList.setActive(persp);
            window.firePerspectiveActivated(this, desc);
        }
       
        getExtensionTracker()
                .registerHandler(
                        perspectiveChangeHandler,
                        ExtensionTracker
                                .createExtensionPointFilter(getPerspectiveExtensionPoint()));
    }
   
    /**
   * Opens the perspectives specified in the PERSPECTIVE_BAR_EXTRAS preference (see bug 84226).
   */
  public void openPerspectiveExtras() {
        String extras = PrefUtil.getAPIPreferenceStore().getString(
        IWorkbenchPreferenceConstants.PERSPECTIVE_BAR_EXTRAS);
    StringTokenizer tok = new StringTokenizer(extras, ", "); //$NON-NLS-1$
    ArrayList descs = new ArrayList();
    while (tok.hasMoreTokens()) {
      String id = tok.nextToken();
            IPerspectiveDescriptor desc = WorkbenchPlugin.getDefault().getPerspectiveRegistry().findPerspectiveWithId(id);
            if (desc != null) {
              descs.add(desc);
            }
    }
    // HACK: The perspective switcher currently adds the button for a new perspective to the beginning of the list.
    // So, we process the extra perspectives in reverse order here to have their buttons appear in the order declared.
    for (int i = descs.size(); --i >= 0;) {
      PerspectiveDescriptor desc = (PerspectiveDescriptor) descs.get(i);
            if (findPerspective(desc) == null) {
              createPerspective(desc, true);
            }
    }
  }

  /**
     * See IWorkbenchPage.
     */
    public boolean isPartVisible(IWorkbenchPart part) {
      PartPane pane = getPane(part);
      return pane != null && pane.getVisible();
    }
   
    /**
     * 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;
    }
    }
   
    /**
     * Return whether the view is closeable or not.
     *
     * @param ref the view reference to check.  Must not be <code>null</code>.
     * @return true if the part is closeable.
     * @since 3.1.1
     */
    public boolean isCloseable(IViewReference ref) {
    Perspective persp = getActivePerspective();
    if (persp != null) {
      return persp.isCloseable(ref);
    }
    return false;
  }

    /**
     * Return whether the view is moveable or not.
     *
     * @param ref the view reference to check.  Must not be <code>null</code>.
     * @return true if the part is moveable.
     * @since 3.1.1
     */
    public boolean isMoveable(IViewReference ref) {
    Perspective persp = getActivePerspective();
    if (persp != null) {
      return persp.isMoveable(ref);
    }
    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();
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.IWorkbenchPage#isPageZoomed()
     */
    public boolean isPageZoomed() {
        Perspective persp = getActivePerspective();
        if (persp == null) {
      return false;
    }
        if (persp.getPresentation() == null) {
      return false;
    }
       
        if (Perspective.useNewMinMax(persp))
          return persp.getPresentation().getMaximizedStack() != null;
       
        // Default to the legacy code
      return isZoomed();
    }
   
    /**
     * Returns whether the page is zoomed.
     * @return <code>true</code> if the page is zoomed.
     *
     * <strong>NOTE:</strong> As of 3.3 this method should always return 'false'
     * when using the new min/max behavior. It is only used for
     * legacy 'zoom' handling.
     *
     */
   public boolean isZoomed() {
        Perspective persp = getActivePerspective();
        if (persp == null) {
      return false;
    }
        if (persp.getPresentation() == null) {
      return false;
    }
        return persp.getPresentation().isZoomed();
    }

    /**
     * This method is called when the page is activated.
     */
    protected void onActivate() {
        composite.setVisible(true);
        Perspective persp = getActivePerspective();

        if (persp != null) {
            persp.onActivate();
            updateVisibility(null, persp);
        }
    }

    /**
     * This method is called when the page is deactivated.
     */
    protected void onDeactivate() {
      makeActiveEditor(null);
        makeActive(null);
        if (getActivePerspective() != null) {
      getActivePerspective().onDeactivate();
    }
        composite.setVisible(false);
    }

    /**
     * See IWorkbenchPage.
     */
    public void reuseEditor(IReusableEditor editor, IEditorInput input) {
       
        // Rather than calling editor.setInput on the editor directly, we do it through the part reference.
        // This case lets us detect badly behaved editors that are not firing a PROP_INPUT event in response
        // to the input change... but if all editors obeyed their API contract, the "else" branch would be
        // sufficient.
        IWorkbenchPartReference ref = getReference(editor);
        if (ref instanceof EditorReference) {
            EditorReference editorRef = (EditorReference) ref;
           
            editorRef.setInput(input);
        } else {
            editor.setInput(input);
        }
        navigationHistory.markEditor(editor);
    }

    /**
     * See IWorkbenchPage.
     */
    public IEditorPart openEditor(IEditorInput input, String editorID)
            throws PartInitException {
        return openEditor(input, editorID, true, MATCH_INPUT);
    }

    /**
     * See IWorkbenchPage.
     */
    public IEditorPart openEditor(IEditorInput input, String editorID,
      boolean activate) throws PartInitException {
    return openEditor(input, editorID, activate, MATCH_INPUT);
    }
 
    /**
     * See IWorkbenchPage.
     */
    public IEditorPart openEditor(final IEditorInput input,
            final String editorID, final boolean activate, final int matchFlags)
            throws PartInitException {
      return openEditor(input, editorID, activate, matchFlags, null);
    }
 
    /**
     * This is not public API but for use internally.  editorState can be <code>null</code>.
     */
    public IEditorPart openEditor(final IEditorInput input,
            final String editorID, final boolean activate, final int matchFlags,
            final IMemento editorState)
            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, matchFlags, editorState);
                        } catch (PartInitException e) {
                            ex[0] = e;
                        }
                    }
                });
        if (ex[0] != null) {
      throw ex[0];
    }
        return result[0];
    }

   
    /*
     * Added to fix Bug 178235 [EditorMgmt] DBCS 3.3 - Cannot open file with external program.
     * Opens a new editor using the given input and descriptor. (Normally, editors are opened using
     * an editor ID and an input.)
     */
    public IEditorPart openEditorFromDescriptor(final IEditorInput input,
        final IEditorDescriptor editorDescriptor, final boolean activate,
        final IMemento editorState)
    throws PartInitException {
      if (input == null || !(editorDescriptor instanceof EditorDescriptor)) {
        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] = busyOpenEditorFromDescriptor(input, (EditorDescriptor)editorDescriptor,
                activate, editorState);
          } catch (PartInitException e) {
            ex[0] = e;
          }
        }
      });
      if (ex[0] != null) {
        throw ex[0];
      }
      return result[0];
    }
   
    /**
     * @see #openEditor(IEditorInput, String, boolean, int)
   */
    private IEditorPart busyOpenEditor(IEditorInput input, String editorID,
            boolean activate, int matchFlags, IMemento editorState) throws PartInitException {

        final Workbench workbench = (Workbench) getWorkbenchWindow()
                .getWorkbench();
        workbench.largeUpdateStart();

        try {
            return busyOpenEditorBatched(input, editorID, activate, matchFlags, editorState);

        } finally {
            workbench.largeUpdateEnd();
        }
    }

    /*
     * Added to fix Bug 178235 [EditorMgmt] DBCS 3.3 - Cannot open file with external program.
     * See openEditorFromDescriptor().
     */
    private IEditorPart busyOpenEditorFromDescriptor(IEditorInput input, EditorDescriptor editorDescriptor,
        boolean activate, IMemento editorState) throws PartInitException {
     
      final Workbench workbench = (Workbench) getWorkbenchWindow()
      .getWorkbench();
      workbench.largeUpdateStart();
     
      try {
        return busyOpenEditorFromDescriptorBatched(input, editorDescriptor, activate, editorState);
       
      } finally {
        workbench.largeUpdateEnd();
      }
    }
   
    /**
     * Do not call this method.  Use <code>busyOpenEditor</code>.
     *
     * @see IWorkbenchPage#openEditor(IEditorInput, String, boolean)
     */
    private IEditorPart busyOpenEditorBatched(IEditorInput input,
            String editorID, boolean activate,  int matchFlags, IMemento editorState) throws PartInitException {

        // If an editor already exists for the input, use it.
    IEditorPart editor = null;
    // Reuse an existing open editor, unless we are in "new editor tab management" mode
    editor = getEditorManager().findEditor(editorID, input, ((TabBehaviour)Tweaklets.get(TabBehaviour.KEY)).getReuseEditorMatchFlags(matchFlags));
        if (editor != null) {
            if (IEditorRegistry.SYSTEM_EXTERNAL_EDITOR_ID.equals(editorID)) {
                if (editor.isDirty()) {
                    MessageDialog dialog = new MessageDialog(
                            getWorkbenchWindow().getShell(),
                            WorkbenchMessages.Save,
                            null, // accept the default window icon
                            NLS.bind(WorkbenchMessages.WorkbenchPage_editorAlreadyOpenedMsg,  input.getName()),
                            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 {
                // do the IShowEditorInput notification before showing the editor
                // to reduce flicker
                if (editor instanceof IShowEditorInput) {
                    ((IShowEditorInput) editor).showEditorInput(input);
                }
                showEditor(activate, editor);
                return editor;
            }
        }


        // 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, editorState);
        if (ref != null) {
            editor = ref.getEditor(true);
        }

        if (editor != null) {
            setEditorAreaVisible(true);
            if (activate) {
                if (editor instanceof MultiEditor) {
          activate(((MultiEditor) editor).getActiveEditor());
        } else {
          activate(editor);
        }
            } else {
                bringToTop(editor);
            }
            window.firePerspectiveChanged(this, getPerspective(), ref,
                    CHANGE_EDITOR_OPEN);
            window.firePerspectiveChanged(this, getPerspective(),
                    CHANGE_EDITOR_OPEN);
        }

        return editor;
    }
   
    /*
     * Added to fix Bug 178235 [EditorMgmt] DBCS 3.3 - Cannot open file with external program.
     * See openEditorFromDescriptor().
     */
    private IEditorPart busyOpenEditorFromDescriptorBatched(IEditorInput input,
            EditorDescriptor editorDescriptor, boolean activate, IMemento editorState) throws PartInitException {

      IEditorPart editor = null;
        // Create a new one. This may cause the new editor to
        // become the visible (i.e top) editor.
        IEditorReference ref = null;
        ref = getEditorManager().openEditorFromDescriptor(editorDescriptor, input, editorState);
    if (ref != null) {
            editor = ref.getEditor(true);
        }

        if (editor != null) {
            setEditorAreaVisible(true);
            if (activate) {
                if (editor instanceof MultiEditor) {
          activate(((MultiEditor) editor).getActiveEditor());
        } else {
          activate(editor);
        }
            } else {
                bringToTop(editor);
            }
            window.firePerspectiveChanged(this, getPerspective(), ref,
                    CHANGE_EDITOR_OPEN);
            window.firePerspectiveChanged(this, getPerspective(),
                    CHANGE_EDITOR_OPEN);
        }

        return editor;
    }
   
    public void openEmptyTab() {
      IEditorPart editor = null;
        EditorReference ref = null;
        ref = (EditorReference) getEditorManager().openEmptyTab();
        if (ref != null) {
            editor = ref.getEmptyEditor((EditorDescriptor) ((EditorRegistry) WorkbenchPlugin
          .getDefault().getEditorRegistry())
          .findEditor(EditorRegistry.EMPTY_EDITOR_ID));
        }

        if (editor != null) {
            setEditorAreaVisible(true);
      activate(editor);
            window.firePerspectiveChanged(this, getPerspective(), ref,
                    CHANGE_EDITOR_OPEN);
            window.firePerspectiveChanged(this, getPerspective(),
                    CHANGE_EDITOR_OPEN);
        }
    }

    private void showEditor(boolean activate, IEditorPart editor) {
        setEditorAreaVisible(true);
        if (activate) {
            zoomOutIfNecessary(editor);
            activate(editor);
        } else {
            bringToTop(editor);
        }
    }

    /**
     * See IWorkbenchPage.
     */
    public boolean isEditorPinned(IEditorPart editor) {
      WorkbenchPartReference ref = (WorkbenchPartReference)getReference(editor);
        return ref != null && ref.isPinned();
    }
   
    /**
     * 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;
    }

        // Do real work.
        persp.removeFastView(ref);

        // Notify listeners.
        window.firePerspectiveChanged(this, getPerspective(), ref,
                CHANGE_FAST_VIEW_REMOVE);
        window.firePerspectiveChanged(this, getPerspective(),
                CHANGE_FAST_VIEW_REMOVE);
    }

    /**
     * Removes an IPartListener from the part service.
     */
    public void removePartListener(IPartListener l) {
        partList.getPartService().removePartListener(l);
    }

    /**
     * Removes an IPartListener from the part service.
     */
    public void removePartListener(IPartListener2 l) {
        partList.getPartService().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;
    }

        if (part instanceof MultiEditor) {
            part = ((MultiEditor) part).getActiveEditor();
        }

        // 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.
        ICoolBarManager2 mgr = (ICoolBarManager2) window.getCoolBarManager2();
        try {
            mgr.getControl2().setRedraw(false);
            BusyIndicator.showWhile(null, new Runnable() {
                public void run() {
                    busyResetPerspective();
                }
            });
        } finally {
            mgr.getControl2().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,
            final IPerspectiveDescriptor activeDescriptor) {
        StartupThreading.runWithoutExceptions(new StartupRunnable() {

      public void runWithException() throws Throwable {
        deferUpdates(true);
      }});
       
        try {
            // Restore working set
            String pageName = memento.getString(IWorkbenchConstants.TAG_LABEL);
           
            String label = null; // debugging only
            if (UIStats.isDebugging(UIStats.RESTORE_WORKBENCH)) {
                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$
        }
                final MultiStatus result = new MultiStatus(
                        PlatformUI.PLUGIN_ID,
                        IStatus.OK,
                        NLS.bind(WorkbenchMessages.WorkbenchPage_unableToRestorePerspective, pageName ),
                        null);
   
                String workingSetName = memento
                        .getString(IWorkbenchConstants.TAG_WORKING_SET);
                if (workingSetName != null) {
                    AbstractWorkingSetManager workingSetManager = (AbstractWorkingSetManager) getWorkbenchWindow()
                            .getWorkbench().getWorkingSetManager();
                    setWorkingSet(workingSetManager.getWorkingSet(workingSetName));
                }
               
              IMemento workingSetMem = memento
            .getChild(IWorkbenchConstants.TAG_WORKING_SETS);
              if (workingSetMem != null) {
          IMemento[] workingSetChildren = workingSetMem
              .getChildren(IWorkbenchConstants.TAG_WORKING_SET);
          List workingSetList = new ArrayList(
              workingSetChildren.length);
          for (int i = 0; i < workingSetChildren.length; i++) {
            IWorkingSet set = getWorkbenchWindow().getWorkbench()
                .getWorkingSetManager().getWorkingSet(
                    workingSetChildren[i].getID());
            if (set != null) {
              workingSetList.add(set);
            }
          }

          workingSets = (IWorkingSet[]) workingSetList
              .toArray(new IWorkingSet[workingSetList.size()]);
        }
             
              aggregateWorkingSetId = memento.getString(ATT_AGGREGATE_WORKING_SET_ID);
             
              IWorkingSet setWithId = window.getWorkbench().getWorkingSetManager().getWorkingSet(aggregateWorkingSetId);
             
              // check to see if the set has already been made and assign it if it has
              if (setWithId instanceof AggregateWorkingSet) {
          aggregateWorkingSet = (AggregateWorkingSet) setWithId;
        }
                // 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 activePartSecondaryID = null;
                if (activePartID != null) {
                    activePartSecondaryID = ViewFactory
                            .extractSecondaryId(activePartID);
                    if (activePartSecondaryID != null) {
                        activePartID = ViewFactory.extractPrimaryId(activePartID);
                    }
                }
                final String activePerspectiveID = childMem
                        .getString(IWorkbenchConstants.TAG_ACTIVE_PERSPECTIVE);
   
                // Restore perspectives.
                final IMemento perspMems[] = childMem
                        .getChildren(IWorkbenchConstants.TAG_PERSPECTIVE);
                final Perspective activePerspectiveArray [] = new Perspective[1];
               
                for (int i = 0; i < perspMems.length; i++) {
                   
                        final IMemento current = perspMems[i];
          StartupThreading
              .runWithoutExceptions(new StartupRunnable() {

                public void runWithException() throws Throwable {
                  Perspective persp = new Perspective(null,
                      WorkbenchPage.this);
                  result.merge(persp.restoreState(current));
                  final IPerspectiveDescriptor desc = persp
                      .getDesc();
                  if (desc.equals(activeDescriptor)) {
                    activePerspectiveArray[0] = persp;
                  } else if ((activePerspectiveArray[0] == null)
                      && desc.getId().equals(
                          activePerspectiveID)) {
                    activePerspectiveArray[0] = persp;
                  }
                  perspList.add(persp);
                  window.firePerspectiveOpened(
                      WorkbenchPage.this, desc);
                }
              });
                }
                Perspective activePerspective = activePerspectiveArray[0];
                boolean restoreActivePerspective = false;
                if (activeDescriptor == null) {
          restoreActivePerspective = true;

                } else if (activePerspective != null
                        && activePerspective.getDesc().equals(activeDescriptor)) {
                    restoreActivePerspective = true;
                } else {
                    restoreActivePerspective = false;
                    activePerspective = createPerspective((PerspectiveDescriptor) activeDescriptor, true);
                    if (activePerspective == null) {
                        result
                                .merge(new Status(
                                        IStatus.ERROR,
                                        PlatformUI.PLUGIN_ID,
                                        0,
                                        NLS.bind(WorkbenchMessages.Workbench_showPerspectiveError, activeDescriptor.getId() ),
                                        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);
                }
                if (activePerspective != null && restoreActivePerspective) {
          result.merge(activePerspective.restoreState());
        }
   
                if (activePerspective != null) {
                  final Perspective myPerspective = activePerspective;
                  final String myActivePartId = activePartID, mySecondaryId = activePartSecondaryID;
                  StartupThreading.runWithoutExceptions(new StartupRunnable() {

            public void runWithException() throws Throwable {
              window.firePerspectiveActivated(WorkbenchPage.this, myPerspective
                                .getDesc());
       
                        // Restore active part.
                        if (myActivePartId != null) {
                            IViewReference ref = myPerspective.findView(
                                myActivePartId, mySecondaryId);
                           
                            if (ref != null) {
                                activationList.setActive(ref);
                            }
                        }
            }});
                   
                }
   
                childMem = memento
                        .getChild(IWorkbenchConstants.TAG_NAVIGATION_HISTORY);
                if (childMem != null) {
          navigationHistory.restoreState(childMem);
        } else if (getActiveEditor() != null) {
          navigationHistory.markEditor(getActiveEditor());
        }
               
                // restore sticky view state
                stickyViewMan.restore(memento);
                   
                return result;
            } finally {
              String blame = activeDescriptor == null ? pageName : activeDescriptor.getId();
                UIStats.end(UIStats.RESTORE_WORKBENCH, blame, "WorkbenchPage" + label); //$NON-NLS-1$
            }
        } finally {
          StartupThreading.runWithoutExceptions(new StartupRunnable() {

        public void runWithException() throws Throwable {
          deferUpdates(false);
        }
      });
        }
    }

    /**
     * See IWorkbenchPage
     */
    public boolean saveAllEditors(boolean confirm) {
        return saveAllEditors(confirm, false);
    }

    /**
     * @param confirm
     * @param addNonPartSources true if saveables from non-part sources should be saved too
     * @return false if the user cancelled
     *
     */
    public boolean saveAllEditors(boolean confirm, boolean addNonPartSources) {
        return getEditorManager().saveAll(confirm, false, addNonPartSources);
    }

    /*
     * 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.firePerspectiveSavedAs(this, oldDesc, newDesc);
    }

    /**
     * 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,
                NLS.bind(WorkbenchMessages.WorkbenchPage_unableToSavePerspective, getLabel()),
                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) {
            if (getActivePart() instanceof IViewPart) {
                IViewReference ref = (IViewReference) getReference(getActivePart());
                if (ref != null) {
                    childMem.putString(IWorkbenchConstants.TAG_ACTIVE_PART,
                            ViewFactory.getKey(ref));
                }
            } else {
                childMem.putString(IWorkbenchConstants.TAG_ACTIVE_PART,
                        getActivePart().getSite().getId());
            }
        }

        // Save each perspective in opened order
        Iterator itr = perspList.iterator();
        while (itr.hasNext()) {
            Perspective persp = (Perspective) itr.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());
        }
       
        IMemento workingSetMem = memento
        .createChild(IWorkbenchConstants.TAG_WORKING_SETS);
    for (int i = 0; i < workingSets.length; i++) {
      workingSetMem.createChild(IWorkbenchConstants.TAG_WORKING_SET,
          workingSets[i].getName());
    }
   
    if (aggregateWorkingSetId != null) {
      memento.putString(ATT_AGGREGATE_WORKING_SET_ID, aggregateWorkingSetId);
    }

        navigationHistory.saveState(memento
                .createChild(IWorkbenchConstants.TAG_NAVIGATION_HISTORY));
       
       
        // save the sticky activation state
        stickyViewMan.save(memento);
       
    return result;
    }
   
    private String getId(IWorkbenchPart part) {
        return getId(getReference(part));
    }
   
    private String getId(IWorkbenchPartReference ref) {
        if (ref == null) {
            return "null"; //$NON-NLS-1$
        } return ref.getId();
    }

    /**
     * Sets the active part.
     */
    private void setActivePart(IWorkbenchPart newPart) {
        // Optimize it.
        if (getActivePart() == newPart) {
            return;
        }
       
        if (partBeingActivated != null) {
            if (partBeingActivated.getPart(false) != newPart) {
                WorkbenchPlugin.log(new RuntimeException(NLS.bind(
                        "WARNING: Prevented recursive attempt to activate part {0} while still in the middle of activating part {1}", //$NON-NLS-1$
                        getId(newPart), getId(partBeingActivated))));
            }
            return;
        }

        //No need to change the history if the active editor is becoming the
        // active part
        String label = null; // debugging only
        if (UIStats.isDebugging(UIStats.ACTIVATE_PART)) {
            label = newPart != null ? newPart.getTitle() : "none"; //$NON-NLS-1$
        }
        try {
            IWorkbenchPartReference partref = getReference(newPart);
            IWorkbenchPartReference realPartRef = null;
      if (newPart != null) {
        IWorkbenchPartSite site = newPart.getSite();
        if (site instanceof PartSite) {
          realPartRef = ((PartSite) site).getPane()
              .getPartReference();
        }
      }

            partBeingActivated = realPartRef;
           
            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 = getActivePart();
            if (oldPart != null) {
                deactivatePart(oldPart);
            }
           
            // Set active part.
            if (newPart != null) {
                activationList.setActive(newPart);
                if (newPart instanceof IEditorPart) {
          makeActiveEditor((IEditorReference)realPartRef);
        }
            }
            activatePart(newPart);
           
            actionSwitcher.updateActivePart(newPart);
           
            partList.setActivePart(partref);
        } finally {
            partBeingActivated = null;
          Object blame = newPart == null ? (Object)this : newPart;
            UIStats.end(UIStats.ACTIVATE_PART, blame, 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();
            updateActivePart();
            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;
    }

        window.largeUpdateStart();
        try {
          if (oldPersp != null) {
            // fire the pre-deactivate
        window.firePerspectivePreDeactivate(this, oldPersp.getDesc());
          }
         
          if (newPersp != null) {
              IStatus status = newPersp.restoreState();
              if (status.getSeverity() != IStatus.OK) {
                  String title = WorkbenchMessages.WorkbenchPage_problemRestoringTitle;
                  String msg = WorkbenchMessages.WorkbenchPage_errorReadingState;
                  ErrorDialog.openError(getWorkbenchWindow().getShell(), title,
                          msg, status);
              }
          }
 
 
          // Deactivate the old layout
          if (oldPersp != null) {
        oldPersp.onDeactivate();

        // Notify listeners of deactivation
        window.firePerspectiveDeactivated(this, oldPersp.getDesc());
          }
 
          // Activate the new layout
          perspList.setActive(newPersp);
          if (newPersp != null) {
              newPersp.onActivate();
 
              // Notify listeners of activation
              window.firePerspectiveActivated(this, newPersp.getDesc());
          }
 
          updateVisibility(oldPersp, newPersp);
 
            // Update the window
            window.updateActionSets();

            // Update sticky views
            stickyViewMan.update(oldPersp, newPersp);
           
        } finally {
            window.largeUpdateEnd();
            if (newPersp == null) {
        return;
      }
            IPerspectiveDescriptor desc = newPersp.getDesc();
            if (desc == null) {
        return;
      }
            if (dirtyPerspectives.remove(desc.getId())) {
              suggestReset();
            }
        }
    }

    void perspectiveActionSetChanged(Perspective perspective, IActionSetDescriptor descriptor, int changeType) {
        if (perspective == getActivePerspective()) {
            actionSets.change(descriptor, changeType);
        }
    }
   
  /*
     * Update visibility state of all views.
     */
    private void updateVisibility(Perspective oldPersp, Perspective newPersp) {
       
        // Flag all parts in the old perspective
        IWorkbenchPartReference[] oldRefs = new IWorkbenchPartReference[0];
        if (oldPersp != null) {
            oldRefs = oldPersp.getViewReferences();
            for (int i = 0; i < oldRefs.length; i++) {
                PartPane pane = ((WorkbenchPartReference) oldRefs[i]).getPane();
                pane.setInLayout(false);
            }
        }
       
        PerspectiveHelper pres = null;
        // Make parts in the new perspective visible
        if (newPersp != null) {
            pres = newPersp.getPresentation();
            IWorkbenchPartReference[] newRefs = newPersp.getViewReferences();
            for (int i = 0; i < newRefs.length; i++) {
                WorkbenchPartReference ref = (WorkbenchPartReference)newRefs[i];
                PartPane pane = ref.getPane();
                if (pres.isPartVisible(ref)) {
                    activationList.bringToTop(ref);
                }

                pane.setInLayout(true);
            }
        }

        updateActivePart();

        // Hide any parts in the old perspective that are no longer visible
        for (int i = 0; i < oldRefs.length; i++) {
            WorkbenchPartReference ref = (WorkbenchPartReference)oldRefs[i];
              
            PartPane pane = ref.getPane();
            if (pres == null || !pres.isPartVisible(ref)) {
                pane.setVisible(false);
            }
        }
    }

    /**
     * Sets the perspective.
     *
     * @param desc
     *            identifies the new perspective.
     */
    public void setPerspective(final IPerspectiveDescriptor desc) {
      if (Util.equals(getPerspective(), desc)) {
        return;
      }
        // 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.
        ICoolBarManager2 mgr = (ICoolBarManager2) window.getCoolBarManager2();
        try {
            mgr.getControl2().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.getControl2().setRedraw(true);
            IWorkbenchPart part = getActivePart();
            if (part != null) {
        part.setFocus();
      }
        }
    }
   
    /**
     * Allow access to the part service for this page ... used internally to
     * propogate certain types of events to the page part listeners.
     * @return the part service for this page.
     */
    public PartService getPartService() {
      return (PartService)partList.getPartService();
    }

    /**
     * Restore the toolbar layout for the active perspective.
     */
    protected void resetToolBarLayout() {
      ICoolBarManager2 mgr = (ICoolBarManager2) window.getCoolBarManager2();
      mgr.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(workingSetPropertyChangeListener);
        } else {
            WorkbenchPlugin.getDefault().getWorkingSetManager()
                    .removePropertyChangeListener(workingSetPropertyChangeListener);
        }
    }

    /**
     * @see IWorkbenchPage
     */
    public void showActionSet(String actionSetID) {
        Perspective persp = getActivePerspective();
        if (persp != null) {
            ActionSetRegistry reg = WorkbenchPlugin.getDefault()
                 .getActionSetRegistry();
           
            IActionSetDescriptor desc = reg.findActionSet(actionSetID);
            if (desc != null) {
                persp.addActionSet(desc);
                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 (secondaryID != null) {
            if (secondaryID.length() == 0
                    || secondaryID.indexOf(ViewFactory.ID_SEP) != -1) {
        throw new IllegalArgumentException(WorkbenchMessages.WorkbenchPage_IllegalSecondaryId);
      }
        }
        if (!certifyMode(mode)) {
      throw new IllegalArgumentException(WorkbenchMessages.WorkbenchPage_IllegalViewMode);
    }

        // 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.WorkbenchPage_AbnormalWorkbenchCondition);
    }
    }

    /**
     * @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);
        }
            }
        }
    }

    /**
     * Sets the state of the given part.
     *
     * @param ref part whose state should be modified (not null)
     * @param newState one of the IStackPresentationSite.STATE_* constants
     */
    public void setState(IWorkbenchPartReference ref, int newState) {
        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.isDocked()) {
            pane.setZoomed(newState == IStackPresentationSite.STATE_MAXIMIZED);
            return;
        }

        if (ref instanceof IViewReference
                && persp.isFastView((IViewReference) ref)) {
            persp.setFastViewState(newState);
            return;
        }

      if (Perspective.useNewMinMax(persp)) {
          // set the container's state to the new one
          PartStack parent = ((PartStack)pane.getContainer());
          parent.setState(newState);
          return;
      }
     
        boolean wasZoomed = isZoomed();
        boolean isZoomed = newState == IStackPresentationSite.STATE_MAXIMIZED;
   
        // Update zoom status.
        if (wasZoomed && !isZoomed) {
            zoomOut();
        } else if (!wasZoomed && isZoomed) {
            persp.getPresentation().zoomIn(ref);
            activate(ref.getPart(true));
        }
     
        PartStack parent = ((PartStack)pane.getContainer());
       
        if (parent != null) {
            parent.setMinimized(newState == IStackPresentationSite.STATE_MINIMIZED);
        }
}
   
    /* (non-Javadoc)
     * @see org.eclipse.ui.IWorkbenchPage#setPartState(org.eclipse.ui.IWorkbenchPartReference, int)
     */
    public void setPartState(IWorkbenchPartReference ref, int state) {
      setState(ref, state);
    }
   
    /**
     * Returns the maximized/minimized/restored state of the given part reference
     *
     * @param ref part to query (not null)
     * @return one of the IStackPresentationSite.STATE_* constants
     */
    int getState(IWorkbenchPartReference ref) {
        Perspective persp = getActivePerspective();
        if (persp == null) {
      return IStackPresentationSite.STATE_RESTORED;
    }

        PartPane pane = ((WorkbenchPartReference) ref).getPane();
     
        if (ref instanceof IViewReference
                && persp.isFastView((IViewReference) ref)) {
            return persp.getFastViewState();
        }     
       
        PartStack parent = ((PartStack)pane.getContainer());
       
        if (parent != null) {
          return parent.getState();
        }
       
        return IStackPresentationSite.STATE_RESTORED;
    }
   
    /* (non-Javadoc)
     * @see org.eclipse.ui.IWorkbenchPage#getPartState(org.eclipse.ui.IWorkbenchPartReference)
     */
    public int getPartState(IWorkbenchPartReference ref) {
      return getState(ref);
    }
   
    /* (non-Javadoc)
     * @see org.eclipse.ui.IWorkbenchPage#toggleZoom(org.eclipse.ui.IWorkbenchPartReference)
     */
    public void toggleZoom(IWorkbenchPartReference ref) {
      int oldState = getState(ref);
      boolean shouldZoom = oldState != IStackPresentationSite.STATE_MAXIMIZED;
      int newState = shouldZoom ? IStackPresentationSite.STATE_MAXIMIZED : IStackPresentationSite.STATE_RESTORED;
     
      setState(ref, newState);
    }

    /**
     * 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.isDocked()) {
                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() });
        }
    }

   
    /* (non-Javadoc)
     * @see org.eclipse.ui.IWorkbenchPage#zoomOut()
     */
    public 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() && partChangeAffectsZoom(((PartSite)part.getSite()).getPartReference())) {
      zoomOut();
    }
    }

    /**
     *
     */
    public int getEditorReuseThreshold() {
      return ((TabBehaviour)Tweaklets.get(TabBehaviour.KEY)).getEditorReuseThreshold();
    }

    /**
     *
     */
    public void setEditorReuseThreshold(int openEditors) {
    }

    /*
     * Returns the editors in activation order (oldest first).
     */
    public IEditorReference[] getSortedEditors() {
        return activationList.getEditors();
    }

    /**
     * @see IWorkbenchPage#getOpenPerspectives()
     */
    public IPerspectiveDescriptor[] getOpenPerspectives() {
        Perspective opened[] = perspList.getOpenedPerspectives();
        IPerspectiveDescriptor[] result = new IPerspectiveDescriptor[opened.length];
        for (int i = 0; i < result.length; i++) {
            result[i] = opened[i].getDesc();
        }
        return result;
    }
   
    /**
     * Return all open Perspective objects.
     *
     * @return all open Perspective objects
     * @since 3.1
     */
    /*package*/Perspective [] getOpenInternalPerspectives() {
        return perspList.getOpenedPerspectives();
    }
 
  /**
   * Checks perspectives in the order they were activiated
   * for the specfied part.  The first sorted perspective
   * that contains the specified part is returned.
   *
   * @param part specified part to search for
   * @return the first sorted perspespective containing the part
   * @since 3.1
   */
  /*package*/Perspective getFirstPerspectiveWithView(IViewPart part) {
    Perspective [] perspectives = perspList.getSortedPerspectives();
    for (int i=perspectives.length - 1; i >= 0; i--) {
      if (perspectives[i].containsView(part)) {
        return perspectives[i];
      }
    }
    // we should never get here
    return null;
  }

    /**
     * Returns the perspectives in activation order (oldest first).
     */
    public 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();
    }

    /**
     * Returns the reference to the given part, or <code>null</code> if it has no reference
     * (i.e. it is not a top-level part in this workbench page).
     *
     * @param part the part
     * @return the part's reference or <code>null</code> if the given part does not belong
     * to this workbench page
     */
    public IWorkbenchPartReference getReference(IWorkbenchPart part) {
        if (part == null) {
            return null;
        }
        IWorkbenchPartSite site = part.getSite();
        if (!(site instanceof PartSite)) {
          return null;
        }
        PartSite partSite = ((PartSite) site);
        PartPane pane = partSite.getPane();
        if (pane instanceof MultiEditorInnerPane) {
            MultiEditorInnerPane innerPane = (MultiEditorInnerPane) pane;
            return innerPane.getParentPane().getPartReference();
        }
        return partSite.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;
      }
      IWorkbenchPartReference ref = getReference(part);
      if (ref != null) {
        if (ref == parts.get(parts.size() - 1)) {
          return;
        }
        parts.remove(ref);
        parts.add(ref);
      }
        }
       
        /*
     * Ensures that the given part appears AFTER any other part in the same
     * container.
     */
        void bringToTop(IWorkbenchPartReference ref) {
            ILayoutContainer targetContainer = getContainer(ref);
           
            int newIndex = lastIndexOfContainer(targetContainer);
           
            //New index can be -1 if there is no last index
            if (newIndex >= 0 && ref == parts.get(newIndex))
        return;
     
            parts.remove(ref);
            if(newIndex >= 0)
              parts.add(newIndex, ref);
            else
              parts.add(ref);
        }
       
        /*
         * Returns the last (most recent) index of the given container in the activation list, or returns
         * -1 if the given container does not appear in the activation list.
         */
        int lastIndexOfContainer(ILayoutContainer container) {
            for (int i = parts.size() - 1; i >= 0; i--) {
                IWorkbenchPartReference ref = (IWorkbenchPartReference)parts.get(i);

                ILayoutContainer cnt = getContainer(ref);
                if (cnt == container) {
                    return i;
                }
            }
           
            return -1;
        }

        /*
         * 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;
                }
            }
            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);
        }

        private IWorkbenchPart getActive(int start) {
            IWorkbenchPartReference ref = getActiveReference(start, false);
           
            if (ref == null) {
                return null;
            }
           
            return ref.getPart(true);
        }
       
        public IWorkbenchPartReference getActiveReference(boolean editorsOnly) {
            return getActiveReference(parts.size() - 1, editorsOnly);
        }
       
        private IWorkbenchPartReference getActiveReference(int start, boolean editorsOnly) {
            // First look for parts that aren't obscured by the current zoom state
            IWorkbenchPartReference nonObscured = getActiveReference(start, editorsOnly, true);
           
            if (nonObscured != null) {
                return nonObscured;
            }
           
            // Now try all the rest of the parts
            return getActiveReference(start, editorsOnly, false);
        }
       
        /*
         * Find a part in the list starting from the end and filter fast views
         * and views from other perspectives.
         */
        private IWorkbenchPartReference getActiveReference(int start, boolean editorsOnly, boolean skipPartsObscuredByZoom) {
            IWorkbenchPartReference[] views = getViewReferences();
            for (int i = start; i >= 0; i--) {
                WorkbenchPartReference ref = (WorkbenchPartReference) parts
                        .get(i);

                if (editorsOnly && !(ref instanceof IEditorReference)) {
                    continue;
                }
               
                // Skip parts whose containers have disabled auto-focus
                PartPane pane = ref.getPane();

                if (pane != null) {
                    if (!pane.allowsAutoFocus()) {
                        continue;
                    }
                   
                    if (skipPartsObscuredByZoom) {
                        if (pane.isObscuredByZoom()) {
                            continue;
                        }
                    }
                }

                // Skip fast views (unless overridden)
                if (ref instanceof IViewReference) {
                    if (includeActiveFastViews || !((IViewReference) ref).isFastView()) {
                        for (int j = 0; j < views.length; j++) {
                            if (views[j] == ref) {
                                return ref;
                            }
                        }
                    }
                } else {
                    return ref;
                }
            }
            return null;
        }

        /*
         * Retuns the index of the part within the activation list. The higher
         * the index, the more recently it was used.
         */
        int indexOf(IWorkbenchPart part) {
          IWorkbenchPartReference ref = getReference(part);
          if (ref == null) {
            return -1;
          }
            return parts.indexOf(ref);
        }

        /*
         * Returns the index of the part reference within the activation list. 
         * The higher the index, the more recent it was used.
         */
        int indexOf(IWorkbenchPartReference ref) {
            return parts.indexOf(ref);
        }

        /*
         * Remove a part from the list
         */
        boolean remove(IWorkbenchPartReference ref) {
            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 editor = (IEditorReference)getActiveReference(parts.size() - 1, true);
           
            if (editor == null) {
                return null;
            }
           
            return editor.getEditor(true);
        }
    }

    /**
     * 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();
            usedList = new ArrayList();
        }

        /**
         * Update the order of the perspectives in the opened list
         *
         * @param perspective
         * @param newLoc
         */
        public void reorder(IPerspectiveDescriptor perspective, int newLoc) {
      int oldLocation = 0;
      Perspective movedPerspective = null;
      for (Iterator iterator = openedList.iterator(); iterator.hasNext();) {
        Perspective openPerspective = (Perspective) iterator.next();
        if (openPerspective.getDesc().equals(perspective)) {
          oldLocation = openedList.indexOf(openPerspective);
          movedPerspective = openPerspective;
        }
      }
     
      if (oldLocation == newLoc) {
        return;
      }
     
      openedList.remove(oldLocation);
      openedList.add(newLoc, movedPerspective);
     
    }

    /**
     * Return all perspectives in the order they were activated.
     *
     * @return an array of perspectives sorted by activation order, least
     *         recently activated perspective last.
     */
        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.
         * @param perspective the perspective to add
         * @return boolean <code>true</code> if the perspective was added
         */
        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) {
                updateActionSets(active, null);
                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;
      }

            updateActionSets(active, perspective);
            active = perspective;

            if (perspective != null) {
                usedList.remove(perspective);
                usedList.add(perspective);
            }
        }
       
        private void updateActionSets(Perspective oldPersp, Perspective newPersp) {
      // Update action sets

      IContextService service = (IContextService) window
          .getService(IContextService.class);
      try {
        service.activateContext(ContextAuthority.DEFER_EVENTS);
        if (newPersp != null) {
          IActionSetDescriptor[] newAlwaysOn = newPersp
              .getAlwaysOnActionSets();
          for (int i = 0; i < newAlwaysOn.length; i++) {
            IActionSetDescriptor descriptor = newAlwaysOn[i];

            actionSets.showAction(descriptor);
          }

          IActionSetDescriptor[] newAlwaysOff = newPersp
              .getAlwaysOffActionSets();
          for (int i = 0; i < newAlwaysOff.length; i++) {
            IActionSetDescriptor descriptor = newAlwaysOff[i];

            actionSets.maskAction(descriptor);
          }
        }

        if (oldPersp != null) {
          IActionSetDescriptor[] newAlwaysOn = oldPersp
              .getAlwaysOnActionSets();
          for (int i = 0; i < newAlwaysOn.length; i++) {
            IActionSetDescriptor descriptor = newAlwaysOn[i];

            actionSets.hideAction(descriptor);
          }

          IActionSetDescriptor[] newAlwaysOff = oldPersp
              .getAlwaysOffActionSets();
          for (int i = 0; i < newAlwaysOff.length; i++) {
            IActionSetDescriptor descriptor = newAlwaysOff[i];

            actionSets.unmaskAction(descriptor);
          }
        }
      } finally {
        service.activateContext(ContextAuthority.SEND_EVENTS);
      }
    }
    }

    // for dynamic UI
    protected void addPerspective(Perspective persp) {
        perspList.add(persp);
        window.firePerspectiveOpened(this, persp.getDesc());
    }

    /**
   * Find the stack of view references stacked with this view part.
   *
   * @param part
   *            the part
   * @return the stack of references
   * @since 3.0
   */
    private IViewReference[] getViewReferenceStack(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) {
                    IViewReference view = ((ViewPane) layoutPart)
                            .getViewReference();
                    if (view != null) {
            list.add(view);
          }
                }
            }

            // sort the list by activation order (most recently activated first)
            Collections.sort(list, new Comparator() {
                public int compare(Object o1, Object o2) {
                    int pos1 = (-1)
                            * activationList
                                    .indexOf((IWorkbenchPartReference) o1);
                    int pos2 = (-1)
                            * activationList
                                    .indexOf((IWorkbenchPartReference) o2);
                    return pos1 - pos2;
                }
            });

            return (IViewReference[]) list.toArray(new IViewReference[list
                    .size()]);
        }

        return new IViewReference[] { (IViewReference) getReference(part) };
    }

    /*
     * (non-Javadoc)
     *
     * @see org.eclipse.ui.IWorkbenchPage#getViewStack(org.eclipse.ui.IViewPart)
     */
    public IViewPart[] getViewStack(IViewPart part) {
        IViewReference[] refStack = getViewReferenceStack(part);
        if (refStack == null) {
      return null;
    }

        List result = new ArrayList();
      
        for (int i = 0; i < refStack.length; i++) {
            IViewPart next = refStack[i].getView(false);
            if (next != null) {
                result.add(next);
            }
        }

        return (IViewPart[]) result.toArray(new IViewPart[result.size()]);
    }

    /**
     * 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(((deltaWidth + sashInfo.right
                    .getBounds().x) - rightBounds.x)
                    / 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(((sashInfo.left.getBounds().x - deltaWidth) - leftBounds.x)
                            / 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(((deltaHeight + sashInfo.bottom
                    .getBounds().y) - bottomBounds.y)
                    / 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(((sashInfo.top.getBounds().y - deltaHeight) - topBounds.y)
                            / 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);
    }
   
  /**
   * Returns all parts that are owned by this page
   *
   * @return
   */
  IWorkbenchPartReference[] getAllParts() {
    IViewReference[] views = viewFactory.getViews();
    IEditorReference[] editors = getEditorReferences();
   
    IWorkbenchPartReference[] result = new IWorkbenchPartReference[views.length + editors.length];
    int resultIdx = 0;
   
    for (int i = 0; i < views.length; i++) {
      result[resultIdx++] = views[i];
    }
   
    for (int i = 0; i < editors.length; i++) {
      result[resultIdx++] = editors[i];
    }
   
    return result;
  }
 
  /**
   * Returns all open parts that are owned by this page (that is, all parts
   * for which a part opened event would have been sent -- these would be
   * activated parts whose controls have already been created.
   */
  IWorkbenchPartReference[] getOpenParts() {
    IWorkbenchPartReference[] refs = getAllParts();
    List result = new ArrayList();
   
    for (int i = 0; i < refs.length; i++) {
      IWorkbenchPartReference reference = refs[i];
     
      IWorkbenchPart part = reference.getPart(false);
      if (part != null) {
        result.add(reference);
      }
    }
   
    return (IWorkbenchPartReference[]) result.toArray(new IWorkbenchPartReference[result.size()]);
  }     
   
    /**
     * Sanity-checks the objects in this page. Throws an Assertation exception
     * if an object's internal state is invalid. ONLY INTENDED FOR USE IN THE
     * UI TEST SUITES.
     */
    public void testInvariants() {
        Perspective persp = getActivePerspective();
       
        if (persp != null) {

            persp.testInvariants();
           
            // When we have widgets, ensure that there is no situation where the editor area is visible
            // and the perspective doesn't want an editor area.
            if (!SwtUtil.isDisposed(getClientComposite()) && editorPresentation.getLayoutPart().isVisible()) {
                Assert.isTrue(persp.isEditorAreaVisible());
            }
        }
       
    }

  /* (non-Javadoc)
   * @see org.eclipse.ui.IWorkbenchPage#getExtensionTracker()
   */
  public IExtensionTracker getExtensionTracker() {
    if (tracker == null) {
      tracker = new UIExtensionTracker(getWorkbenchWindow().getWorkbench().getDisplay());
    }
    return tracker;   
  }

    /*
     * (non-Javadoc)
     *
     * @see org.eclipse.ui.IWorkbenchPage#getNewWizardShortcuts()
     */
    public String[] getNewWizardShortcuts() {
        Perspective persp = getActivePerspective();
        if (persp == null) {
            return new String[0];
        }
        return persp.getNewWizardShortcuts();
    }

    /*
     * (non-Javadoc)
     *
     * @see org.eclipse.ui.IWorkbenchPage#getPerspectiveShortcuts()
     */
    public String[] getPerspectiveShortcuts() {
        Perspective persp = getActivePerspective();
        if (persp == null) {
            return new String[0];
        }
        return persp.getPerspectiveShortcuts();
    }

    /*
     * (non-Javadoc)
     *
     * @see org.eclipse.ui.IWorkbenchPage#getShowViewShortcuts()
     */
    public String[] getShowViewShortcuts() {
        Perspective persp = getActivePerspective();
        if (persp == null) {
            return new String[0];
        }
        return persp.getShowViewShortcuts();
    }
   
    /**
   * @since 3.1
   */
  private void suggestReset() {
    final IWorkbench workbench = getWorkbenchWindow().getWorkbench();
        workbench.getDisplay().asyncExec(new Runnable() {
            public void run() {
                Shell parentShell = null;
               
        IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
                if (window == null) {
                    if (workbench.getWorkbenchWindowCount() == 0) {
            return;
          }
                    window = workbench.getWorkbenchWindows()[0];
                }

                parentShell = window.getShell();

                if (MessageDialog
                        .openQuestion(
                                parentShell,
                                WorkbenchMessages.Dynamic_resetPerspectiveTitle,
                                WorkbenchMessages.Dynamic_resetPerspectiveMessage)) {
                    IWorkbenchPage page = window.getActivePage();
                    if (page == null) {
            return;
          }
                    page.resetPerspective();
                }
            }
        });

   
  }
   
    public boolean isPartVisible(IWorkbenchPartReference reference) {       
        IWorkbenchPart part = reference.getPart(false);
        // Can't be visible if it isn't created yet
        if (part == null) {
            return false;
        }
       
        return isPartVisible(part);
    }

  public IWorkingSet[] getWorkingSets() {
    return workingSets;
  }

  public void setWorkingSets(IWorkingSet[] newWorkingSets) {
    if (newWorkingSets == null) {
      newWorkingSets = new IWorkingSet[0];
    }

    IWorkingSet[] oldWorkingSets = workingSets;
   
    // filter out any duplicates if necessary
    if (newWorkingSets.length > 1) { 
      Set setOfSets = new HashSet();
      for (int i = 0; i < newWorkingSets.length; i++) {
        if (newWorkingSets[i] == null) {
          throw new IllegalArgumentException();
        }
        setOfSets.add(newWorkingSets[i]);
      }
      newWorkingSets = (IWorkingSet[]) setOfSets
          .toArray(new IWorkingSet[setOfSets.size()]);
    }

    workingSets = newWorkingSets;
    if (!Arrays.equals(oldWorkingSets, newWorkingSets)) {
      firePropertyChange(CHANGE_WORKING_SETS_REPLACE, oldWorkingSets,
          newWorkingSets);
      if (aggregateWorkingSet != null) {
        aggregateWorkingSet.setComponents(workingSets);
      }
    }
    if (newWorkingSets != null) {
      WorkbenchPlugin
          .getDefault()
          .getWorkingSetManager()
          .addPropertyChangeListener(workingSetPropertyChangeListener);
    } else {
      WorkbenchPlugin.getDefault().getWorkingSetManager()
          .removePropertyChangeListener(
              workingSetPropertyChangeListener);
    }
  }
 
  public IWorkingSet getAggregateWorkingSet() {
    if (aggregateWorkingSet == null) {
      IWorkingSetManager workingSetManager = PlatformUI.getWorkbench()
          .getWorkingSetManager();
      aggregateWorkingSet = (AggregateWorkingSet) workingSetManager.getWorkingSet(
              getAggregateWorkingSetId());
      if (aggregateWorkingSet == null) {
        aggregateWorkingSet = (AggregateWorkingSet) workingSetManager
            .createAggregateWorkingSet(
                getAggregateWorkingSetId(),
                WorkbenchMessages.WorkbenchPage_workingSet_default_label,
                getWorkingSets());
        workingSetManager.addWorkingSet(aggregateWorkingSet);
      }
    }
    return aggregateWorkingSet;
  }

  private String getAggregateWorkingSetId() { 
    if (aggregateWorkingSetId == null) {
      aggregateWorkingSetId = "Aggregate for window " + System.currentTimeMillis(); //$NON-NLS-1$
    }
    return aggregateWorkingSetId;
  }
}
TOP

Related Classes of org.eclipse.ui.internal.WorkbenchPage

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