X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;ds=inline;f=bundles%2Forg.simantics.browsing.ui.platform%2Fsrc%2Forg%2Fsimantics%2Fbrowsing%2Fui%2Fplatform%2FPageBookView.java;fp=bundles%2Forg.simantics.browsing.ui.platform%2Fsrc%2Forg%2Fsimantics%2Fbrowsing%2Fui%2Fplatform%2FPageBookView.java;h=e6f027a73ab2c01bdd7be4e428dd2278583f6408;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.browsing.ui.platform/src/org/simantics/browsing/ui/platform/PageBookView.java b/bundles/org.simantics.browsing.ui.platform/src/org/simantics/browsing/ui/platform/PageBookView.java new file mode 100644 index 000000000..e6f027a73 --- /dev/null +++ b/bundles/org.simantics.browsing.ui.platform/src/org/simantics/browsing/ui/platform/PageBookView.java @@ -0,0 +1,1152 @@ +/******************************************************************************* + * Copyright (c) 2000, 2010 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.simantics.browsing.ui.platform; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import org.eclipse.core.commands.common.EventManager; +import org.eclipse.core.runtime.Platform; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.PropertyChangeEvent; +import org.eclipse.jface.util.SafeRunnable; +import org.eclipse.jface.viewers.IPostSelectionProvider; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.IPartListener; +import org.eclipse.ui.IPartListener2; +import org.eclipse.ui.IViewPart; +import org.eclipse.ui.IViewSite; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchPartReference; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.SubActionBars; +import org.eclipse.ui.internal.WorkbenchPlugin; +import org.eclipse.ui.internal.util.Util; +import org.eclipse.ui.part.IPage; +import org.eclipse.ui.part.IPageBookViewPage; +import org.eclipse.ui.part.IPageSite; +import org.eclipse.ui.part.PageBook; +import org.eclipse.ui.part.ViewPart; +import org.simantics.browsing.ui.common.IPageBookViewPagePartInit; + +/** + * Abstract superclass of all multi-page workbench views. + *

+ * Within the workbench there are many views which track the active part. If a + * part is activated these views display some properties for the active part. A + * simple example is the Outline View, which displays the outline + * for the active editor. To avoid loss of context when part activation changes, + * these views may implement a multi-page approach. A separate page is + * maintained within the view for each source view. If a part is activated the + * associated page for the part is brought to top. If a part is closed the + * associated page is disposed. PageBookView is a base + * implementation for multi page views. + *

+ *

+ * PageBookViews provide an IPageSite for each of + * their pages. This site is supplied during the page's initialization. The page + * may supply a selection provider for this site. PageBookViews + * deal with these selection providers in a similar way to a workbench page's + * SelectionService. When a page is made visible, if its site has a + * selection provider, then changes in the selection are listened for and the + * current selection is obtained and fired as a selection change event. + * Selection changes are no longer listened for when a page is made invisible. + *

+ *

+ * This class should be subclassed by clients wishing to define new multi-page + * views. + *

+ *

+ * When a PageBookView is created the following methods are + * invoked. Subclasses must implement these. + *

+ *

+ *

+ * When a part is activated the base implementation does not know if a page + * should be created for the part. Therefore, it delegates creation to the + * subclass. + *

+ *

+ *

+ * When a part is closed the base implementation will destroy the page + * associated with the particular part. The page was created by a subclass, so + * the subclass must also destroy it. Subclasses must implement these. + *

+ *

+ * + * Otherwise a carbon copy of {@link org.eclipse.ui.part.PageBookView} but + * {@link #partActivated(IWorkbenchPart)} has been slightly customized to not + * always show the default page if an activated page does not provide a property + * page. + * + * @author Tuukka Lehtonen + */ +@SuppressWarnings({"rawtypes", "unchecked", "deprecation", "restriction"}) +public abstract class PageBookView extends ViewPart implements IPartListener { + /** + * The pagebook control, or null if not initialized. + */ + private PageBook book; + + /** + * The page record for the default page. + */ + private PageRec defaultPageRec; + + /** + * Map from parts to part records (key type: IWorkbenchPart; + * value type: PartRec). + */ + private final Map mapPartToRec = new HashMap(); + + /** + * Map from pages to view sites Note that view sites were not added to page + * recs to avoid breaking binary compatibility with previous builds + */ + private final Map mapPageToSite = new HashMap(); + + /** + * Map from pages to the number of pageRecs actively associated with a page. + */ + private final Map mapPageToNumRecs = new HashMap(); + + /** + * The page rec which provided the current page or null + */ + private PageRec activeRec; + + /** + * If the part is hidden (usually an editor) then store it so we can + * continue to track it when it becomes visible. + */ + private IWorkbenchPart hiddenPart = null; + + /** + * The action bar property listener. + */ + private final IPropertyChangeListener actionBarPropListener = new IPropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent event) { + if (event.getProperty().equals(SubActionBars.P_ACTION_HANDLERS) + && activeRec != null + && event.getSource() == activeRec.subActionBars) { + refreshGlobalActionHandlers(); + } + } + }; + + /** + * Selection change listener to listen for page selection changes + */ + private final ISelectionChangedListener selectionChangedListener = new ISelectionChangedListener() { + @Override + public void selectionChanged(SelectionChangedEvent event) { + pageSelectionChanged(event); + } + }; + + /** + * Selection change listener to listen for page selection changes + */ + private final ISelectionChangedListener postSelectionListener = new ISelectionChangedListener() { + @Override + public void selectionChanged(SelectionChangedEvent event) { + postSelectionChanged(event); + } + }; + + /** + * Selection provider for this view's site + */ + private final SelectionProvider selectionProvider = new SelectionProvider(); + + /** + * A data structure used to store the information about a single page within + * a pagebook view. + */ + protected static class PageRec { + + /** + * The part. + */ + public IWorkbenchPart part; + + /** + * The page. + */ + public IPage page; + + /** + * The page's action bars + */ + public SubActionBars subActionBars; + + /** + * Creates a new page record initialized to the given part and page. + * + * @param part + * @param page + */ + public PageRec(IWorkbenchPart part, IPage page) { + this.part = part; + this.page = page; + } + + /** + * Disposes of this page record by nulling its fields. + */ + public void dispose() { + part = null; + page = null; + } + } + + private static class SelectionManager extends EventManager { + /** + * + * @param listener + * listen + */ + public void addSelectionChangedListener( + ISelectionChangedListener listener) { + addListenerObject(listener); + } + + /** + * + * @param listener + * listen + */ + public void removeSelectionChangedListener( + ISelectionChangedListener listener) { + removeListenerObject(listener); + } + + /** + * + * @param event + * the event + */ + public void selectionChanged(final SelectionChangedEvent event) { + // pass on the notification to listeners + Object[] listeners = getListeners(); + for (int i = 0; i < listeners.length; ++i) { + final ISelectionChangedListener l = (ISelectionChangedListener) listeners[i]; + Platform.run(new SafeRunnable() { + @Override + public void run() { + l.selectionChanged(event); + } + }); + } + } + + } + + /** + * A selection provider/listener for this view. It is a selection provider + * for this view's site. + */ + protected class SelectionProvider implements IPostSelectionProvider { + + private final SelectionManager fSelectionListener = new SelectionManager(); + + private final SelectionManager fPostSelectionListeners = new SelectionManager(); + + /* + * (non-Javadoc) Method declared on ISelectionProvider. + */ + @Override + public void addSelectionChangedListener( + ISelectionChangedListener listener) { + fSelectionListener.addSelectionChangedListener(listener); + } + + /* + * (non-Javadoc) Method declared on ISelectionProvider. + */ + @Override + public ISelection getSelection() { + // get the selection provider from the current page + IPage currentPage = getCurrentPage(); + // during workbench startup we may be in a state when + // there is no current page + if (currentPage == null) { + return StructuredSelection.EMPTY; + } + IPageSite site = getPageSite(currentPage); + if (site == null) { + return StructuredSelection.EMPTY; + } + ISelectionProvider selProvider = site.getSelectionProvider(); + if (selProvider != null) { + return selProvider.getSelection(); + } + return StructuredSelection.EMPTY; + } + + /* + * (non-Javadoc) Method declared on ISelectionProvider. + */ + @Override + public void removeSelectionChangedListener( + ISelectionChangedListener listener) { + fSelectionListener.removeSelectionChangedListener(listener); + } + + /** + * The selection has changed. Process the event, notifying selection + * listeners and post selection listeners. + * + * @param event + * the change + */ + public void selectionChanged(final SelectionChangedEvent event) { + fSelectionListener.selectionChanged(event); + } + + /** + * The selection has changed, so notify any post-selection listeners. + * + * @param event + * the change + */ + public void postSelectionChanged(final SelectionChangedEvent event) { + fPostSelectionListeners.selectionChanged(event); + } + + /* + * (non-Javadoc) Method declared on ISelectionProvider. + */ + @Override + public void setSelection(ISelection selection) { + // get the selection provider from the current page + IPage currentPage = getCurrentPage(); + // during workbench startup we may be in a state when + // there is no current page + if (currentPage == null) { + return; + } + IPageSite site = getPageSite(currentPage); + if (site == null) { + return; + } + ISelectionProvider selProvider = site.getSelectionProvider(); + // and set its selection + if (selProvider != null) { + selProvider.setSelection(selection); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.IPostSelectionProvider#addPostSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener) + */ + @Override + public void addPostSelectionChangedListener( + ISelectionChangedListener listener) { + fPostSelectionListeners.addSelectionChangedListener(listener); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.viewers.IPostSelectionProvider#removePostSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener) + */ + @Override + public void removePostSelectionChangedListener( + ISelectionChangedListener listener) { + fPostSelectionListeners.removeSelectionChangedListener(listener); + } + } + + /** + * Creates a new pagebook view. + */ + protected PageBookView() { + super(); + } + + /** + * Creates and returns the default page for this view. + *

+ * Subclasses must implement this method. + *

+ *

+ * Subclasses must call initPage with the new page (if it is an + * IPageBookViewPage) before calling createControl on the + * page. + *

+ * + * @param book + * the pagebook control + * @return the default page + */ + protected abstract IPage createDefaultPage(PageBook book); + + /** + * Creates a page for a given part. Adds it to the pagebook but does not + * show it. + * + * @param part + * The part we are making a page for. + * @return IWorkbenchPart + */ + private PageRec createPage(IWorkbenchPart part) { + PageRec rec = doCreatePage(part); + if (rec != null) { + mapPartToRec.put(part, rec); + preparePage(rec); + } + return rec; + } + + /** + * Prepares the page in the given page rec for use in this view. + * + * @param rec + */ + private void preparePage(PageRec rec) { + IPageSite site = null; + Integer count; + + if (!doesPageExist(rec.page)) { + if (rec.page instanceof IPageBookViewPage) { + site = ((IPageBookViewPage) rec.page).getSite(); + } + if (site == null) { + // We will create a site for our use + site = new PageSite(getViewSite()); + } + mapPageToSite.put(rec.page, site); + + rec.subActionBars = (SubActionBars) site.getActionBars(); + rec.subActionBars.addPropertyChangeListener(actionBarPropListener); + // for backward compability with IPage + rec.page.setActionBars(rec.subActionBars); + + count = new Integer(0); + } else { + site = (IPageSite) mapPageToSite.get(rec.page); + rec.subActionBars = (SubActionBars) site.getActionBars(); + count = ((Integer) mapPageToNumRecs.get(rec.page)); + } + + mapPageToNumRecs.put(rec.page, new Integer(count.intValue() + 1)); + } + + /** + * Initializes the given page with a page site. + *

+ * Subclasses should call this method after the page is created but before + * creating its controls. + *

+ *

+ * Subclasses may override + *

+ * + * @param page + * The page to initialize + */ + protected void initPage(IPageBookViewPage page) { + + try { + page.init(new PageSite(getViewSite())); + } catch (PartInitException e) { + WorkbenchPlugin.log(getClass(), "initPage", e); //$NON-NLS-1$ + } + + if(page instanceof IPageBookViewPagePartInit) { + ((IPageBookViewPagePartInit)page).initPart(this); + } + + } + + /** + * The PageBookView implementation of this + * IWorkbenchPart method creates a PageBook + * control with its default page showing. Subclasses may extend. + */ + @Override + public void createPartControl(Composite parent) { + + // Create the page book. + book = new PageBook(parent, SWT.NONE); + + // Create the default page rec. + IPage defaultPage = createDefaultPage(book); + defaultPageRec = new PageRec(null, defaultPage); + preparePage(defaultPageRec); + + // Show the default page + showPageRec(defaultPageRec); + + // Listen to part activation events. + getSite().getPage().addPartListener(partListener); + showBootstrapPart(); + } + + /** + * The PageBookView implementation of this + * IWorkbenchPart method cleans up all the pages. Subclasses + * may extend. + */ + @Override + public void dispose() { + // stop listening to part activation + getSite().getPage().removePartListener(partListener); + + // Deref all of the pages. + activeRec = null; + if (defaultPageRec != null) { + // check for null since the default page may not have + // been created (ex. perspective never visible) + defaultPageRec.page.dispose(); + defaultPageRec = null; + } + Map clone = (Map) ((HashMap) mapPartToRec).clone(); + Iterator itr = clone.values().iterator(); + while (itr.hasNext()) { + PageRec rec = (PageRec) itr.next(); + removePage(rec); + } + + // Run super. + super.dispose(); + } + + /** + * Creates a new page in the pagebook for a particular part. This page will + * be made visible whenever the part is active, and will be destroyed with a + * call to doDestroyPage. + *

+ * Subclasses must implement this method. + *

+ *

+ * Subclasses must call initPage with the new page (if it is an + * IPageBookViewPage) before calling createControl on the + * page. + *

+ * + * @param part + * the input part + * @return the record describing a new page for this view + * @see #doDestroyPage + */ + protected abstract PageRec doCreatePage(IWorkbenchPart part); + + /** + * Destroys a page in the pagebook for a particular part. This page was + * returned as a result from doCreatePage. + *

+ * Subclasses must implement this method. + *

+ * + * @param part + * the input part + * @param pageRecord + * a page record for the part + * @see #doCreatePage + */ + protected abstract void doDestroyPage(IWorkbenchPart part, + PageRec pageRecord); + + /** + * Returns true if the page has already been created. + * + * @param page + * the page to test + * @return true if this page has already been created. + */ + protected boolean doesPageExist(IPage page) { + return mapPageToNumRecs.containsKey(page); + } + + /** + * The PageBookView implementation of this + * IAdaptable method delegates to the current page, if it + * implements IAdaptable. + */ + @Override + public Object getAdapter(Class key) { + // delegate to the current page, if supported + IPage page = getCurrentPage(); + Object adapter = Util.getAdapter(page, key); + if (adapter != null) { + return adapter; + } + // if the page did not find the adapter, look for one provided by + // this view before delegating to super. + adapter = getViewAdapter(key); + if (adapter != null) { + return adapter; + } + // delegate to super + return super.getAdapter(key); + } + + /** + * Returns an adapter of the specified type, as provided by this view (not + * the current page), or null if this view does not provide + * an adapter of the specified adapter. + *

+ * The default implementation returns null. Subclasses may + * override. + *

+ * + * @param adapter + * the adapter class to look up + * @return a object castable to the given class, or null if + * this object does not have an adapter for the given class + * @since 3.2 + */ + protected Object getViewAdapter(Class adapter) { + return null; + } + + /** + * Returns the active, important workbench part for this view. + *

+ * When the page book view is created it has no idea which part within the + * workbook should be used to generate the first page. Therefore, it + * delegates the choice to subclasses of PageBookView. + *

+ *

+ * Implementors of this method should return an active, important part in + * the workbench or null if none found. + *

+ *

+ * Subclasses must implement this method. + *

+ * + * @return the active important part, or null if none + */ + protected abstract IWorkbenchPart getBootstrapPart(); + + /** + * Returns the part which contributed the current page to this view. + * + * @return the part which contributed the current page or null + * if no part contributed the current page + */ + protected IWorkbenchPart getCurrentContributingPart() { + if (activeRec == null) { + return null; + } + return activeRec.part; + } + + /** + * Returns the currently visible page for this view or null + * if no page is currently visible. + * + * @return the currently visible page + */ + public IPage getCurrentPage() { + if (activeRec == null) { + return null; + } + return activeRec.page; + } + + /** + * Returns the view site for the given page of this view. + * + * @param page + * the page + * @return the corresponding site, or null if not found + */ + protected PageSite getPageSite(IPage page) { + return (PageSite) mapPageToSite.get(page); + } + + /** + * Returns the default page for this view. + * + * @return the default page + */ + public IPage getDefaultPage() { + return defaultPageRec.page; + } + + /** + * Returns the pagebook control for this view. + * + * @return the pagebook control, or null if not initialized + */ + protected PageBook getPageBook() { + return book; + } + + /** + * Returns the page record for the given part. + * + * @param part + * the part + * @return the corresponding page record, or null if not + * found + */ + protected PageRec getPageRec(IWorkbenchPart part) { + return (PageRec) mapPartToRec.get(part); + } + + /** + * Returns the page record for the given page of this view. + * + * @param page + * the page + * @return the corresponding page record, or null if not + * found + */ + protected PageRec getPageRec(IPage page) { + Iterator itr = mapPartToRec.values().iterator(); + while (itr.hasNext()) { + PageRec rec = (PageRec) itr.next(); + if (rec.page == page) { + return rec; + } + } + return null; + } + + /** + * Returns whether the given part should be added to this view. + *

+ * Subclasses must implement this method. + *

+ * + * @param part + * the input part + * @return true if the part is relevant, and + * false otherwise + */ + protected abstract boolean isImportant(IWorkbenchPart part); + + /* + * (non-Javadoc) Method declared on IViewPart. + */ + @Override + public void init(IViewSite site) throws PartInitException { + site.setSelectionProvider(selectionProvider); + super.init(site); + } + + /** + * The PageBookView implementation of this + * IPartListener method shows the page when the given part is + * activated. Subclasses may extend. + */ + @Override + public void partActivated(IWorkbenchPart part) { + // Is this an important part? If not just return. + if (!isImportant(part)) { + return; + } + hiddenPart = null; + + // Create a page for the part. + PageRec rec = getPageRec(part); + if (rec == null) { + rec = createPage(part); + } + + // Show the page. + if (rec != null) { + showPageRec(rec); + } else { + Control[] children = book.getChildren(); + //System.out.println("CHILDREN: " + Arrays.toString(children)); + if (children.length < 2) { + //System.out.println("showing default page"); + showPageRec(defaultPageRec); + } + } + } + + /** + * The PageBookView implementation of this + * IPartListener method does nothing. Subclasses may extend. + */ + @Override + public void partBroughtToTop(IWorkbenchPart part) { + // Do nothing by default + } + + /** + * The PageBookView implementation of this + * IPartListener method deal with the closing of the active + * part. Subclasses may extend. + */ + @Override + public void partClosed(IWorkbenchPart part) { + // Update the active part. + if (activeRec != null && activeRec.part == part) { + showPageRec(defaultPageRec); + } + + // Find and remove the part page. + PageRec rec = getPageRec(part); + if (rec != null) { + removePage(rec); + } + if (part == hiddenPart) { + hiddenPart = null; + } + } + + /** + * The PageBookView implementation of this + * IPartListener method does nothing. Subclasses may extend. + */ + @Override + public void partDeactivated(IWorkbenchPart part) { + // Do nothing. + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.IPartListener#partOpened(org.eclipse.ui.IWorkbenchPart) + */ + @Override + public void partOpened(IWorkbenchPart part) { + // Do nothing by default. + } + + /** + * Refreshes the global actions for the active page. + */ + private void refreshGlobalActionHandlers() { + // Clear old actions. + IActionBars bars = getViewSite().getActionBars(); + bars.clearGlobalActionHandlers(); + + // Set new actions. + Map newActionHandlers = activeRec.subActionBars + .getGlobalActionHandlers(); + if (newActionHandlers != null) { + Set keys = newActionHandlers.entrySet(); + Iterator iter = keys.iterator(); + while (iter.hasNext()) { + Map.Entry entry = (Map.Entry) iter.next(); + bars.setGlobalActionHandler((String) entry.getKey(), + (IAction) entry.getValue()); + } + } + } + + /** + * Removes a page record. If it is the last reference to the page dispose of + * it - otherwise just decrement the reference count. + * + * @param rec + */ + private void removePage(PageRec rec) { + mapPartToRec.remove(rec.part); + + int newCount = ((Integer) mapPageToNumRecs.get(rec.page)).intValue() - 1; + + if (newCount == 0) { + Object site = mapPageToSite.remove(rec.page); + mapPageToNumRecs.remove(rec.page); + + Control control = rec.page.getControl(); + if (control != null && !control.isDisposed()) { + // Dispose the page's control so pages don't have to do this in + // their + // dispose method. + // The page's control is a child of this view's control so if + // this view + // is closed, the page's control will already be disposed. + control.dispose(); + } + + // free the page + doDestroyPage(rec.part, rec); + + if (rec.subActionBars != null) { + rec.subActionBars.dispose(); + } + + if (site instanceof PageSite) { + ((PageSite) site).dispose(); + } + } else { + mapPageToNumRecs.put(rec.page, new Integer(newCount)); + } + } + + /* + * (non-Javadoc) Method declared on IWorkbenchPart. + */ + @Override + public void setFocus() { + // first set focus on the page book, in case the page + // doesn't properly handle setFocus + if (book != null) { + book.setFocus(); + } + // then set focus on the page, if any + if (activeRec != null) { + activeRec.page.setFocus(); + } + } + + /** + * Handle page selection changes. + * + * @param event + */ + private void pageSelectionChanged(SelectionChangedEvent event) { + // forward this change from a page to our site's selection provider + SelectionProvider provider = (SelectionProvider) getSite() + .getSelectionProvider(); + if (provider != null) { + provider.selectionChanged(event); + } + } + + /** + * Handle page selection changes. + * + * @param event + */ + private void postSelectionChanged(SelectionChangedEvent event) { + // forward this change from a page to our site's selection provider + SelectionProvider provider = (SelectionProvider) getSite() + .getSelectionProvider(); + if (provider != null) { + provider.postSelectionChanged(event); + } + } + + /** + * Shows a page for the active workbench part. + */ + private void showBootstrapPart() { + IWorkbenchPart part = getBootstrapPart(); + if (part != null) { + partActivated(part); + } + } + + /** + * Shows page contained in the given page record in this view. The page + * record must be one from this pagebook view. + *

+ * The PageBookView implementation of this method asks the + * pagebook control to show the given page's control, and records that the + * given page is now current. Subclasses may extend. + *

+ * + * @param pageRec + * the page record containing the page to show + */ + protected void showPageRec(PageRec pageRec) { + // If already showing do nothing + if (activeRec == pageRec) { + return; + } + // If the page is the same, just set activeRec to pageRec + if (activeRec != null && pageRec != null + && activeRec.page == pageRec.page) { + activeRec = pageRec; + return; + } + + // Hide old page. + if (activeRec != null) { + PageSite pageSite = (PageSite) mapPageToSite.get(activeRec.page); + + activeRec.subActionBars.deactivate(); + + // deactivate the nested services + pageSite.deactivate(); + + // remove our selection listener + ISelectionProvider provider = pageSite.getSelectionProvider(); + if (provider != null) { + provider + .removeSelectionChangedListener(selectionChangedListener); + if (provider instanceof IPostSelectionProvider) { + ((IPostSelectionProvider) provider) + .removePostSelectionChangedListener(postSelectionListener); + } + } + } + + // Show new page. + activeRec = pageRec; + Control pageControl = activeRec.page.getControl(); + if (pageControl != null && !pageControl.isDisposed()) { + PageSite pageSite = (PageSite) mapPageToSite.get(activeRec.page); + + // Verify that the page control is not disposed + // If we are closing, it may have already been disposed + book.showPage(pageControl); + activeRec.subActionBars.activate(); + refreshGlobalActionHandlers(); + + // activate the nested services + pageSite.activate(); + + // add our selection listener + ISelectionProvider provider = pageSite.getSelectionProvider(); + if (provider != null) { + provider.addSelectionChangedListener(selectionChangedListener); + if (provider instanceof IPostSelectionProvider) { + ((IPostSelectionProvider) provider) + .addPostSelectionChangedListener(postSelectionListener); + } + } + // Update action bars. + getViewSite().getActionBars().updateActionBars(); + } + } + + /** + * Returns the selectionProvider for this page book view. + * + * @return a SelectionProvider + */ + protected SelectionProvider getSelectionProvider() { + return selectionProvider; + } + + private final IPartListener2 partListener = new IPartListener2() { + @Override + public void partActivated(IWorkbenchPartReference partRef) { + IWorkbenchPart part = partRef.getPart(false); + PageBookView.this.partActivated(part); + } + + @Override + public void partBroughtToTop(IWorkbenchPartReference partRef) { + PageBookView.this.partBroughtToTop(partRef.getPart(false)); + } + + @Override + public void partClosed(IWorkbenchPartReference partRef) { + PageBookView.this.partClosed(partRef.getPart(false)); + } + + @Override + public void partDeactivated(IWorkbenchPartReference partRef) { + PageBookView.this.partDeactivated(partRef.getPart(false)); + } + + @Override + public void partHidden(IWorkbenchPartReference partRef) { + PageBookView.this.partHidden(partRef.getPart(false)); + } + + @Override + public void partInputChanged(IWorkbenchPartReference partRef) { + } + + @Override + public void partOpened(IWorkbenchPartReference partRef) { + PageBookView.this.partOpened(partRef.getPart(false)); + } + + @Override + public void partVisible(IWorkbenchPartReference partRef) { + PageBookView.this.partVisible(partRef.getPart(false)); + } + }; + + /** + * Make sure that the part is not considered if it is hidden. + * @param part + * @since 3.5 + */ + protected void partHidden(IWorkbenchPart part) { + if (part == null || part != getCurrentContributingPart()) { + return; + } + // if we've minimized the editor stack, that's no reason to + // drop our content + if (getSite().getPage().getPartState( + getSite().getPage().getReference(part)) == IWorkbenchPage.STATE_MINIMIZED) { + return; + } + // if we're switching from a part source in our own stack, + // we also don't want to clear our content. + if (part instanceof IViewPart) { + final IViewPart[] viewStack = getSite().getPage() + .getViewStack(this); + if (containsPart(viewStack, part)) { + return; + } + } + hiddenPart = part; + showPageRec(defaultPageRec); + } + + /** + * @param viewStack + * @param part + * @return true if the part is in the viewStack + */ + private boolean containsPart(IViewPart[] viewStack, IWorkbenchPart part) { + if (viewStack == null) { + return false; + } + for (int i = 0; i < viewStack.length; i++) { + if (viewStack[i] == part) { + return true; + } + } + return false; + } + + /** + * Make sure that the part is not considered if it is hidden. + * + * @param part + * @since 3.5 + */ + protected void partVisible(IWorkbenchPart part) { + if (part == null || part != hiddenPart) { + return; + } + partActivated(part); + } +}