]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.browsing.ui.swt/src/org/simantics/browsing/ui/swt/TabbedPropertyPage.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.browsing.ui.swt / src / org / simantics / browsing / ui / swt / TabbedPropertyPage.java
index 031d1a5223ea90842a039963a47418fdec050ef8..81e0898488d656434cfa697aa16542adab8429c3 100644 (file)
-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- *     VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.browsing.ui.swt;\r
-\r
-\r
-/*******************************************************************************\r
- * Copyright (c) 2000, 2008 IBM Corporation and others.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- *     IBM Corporation - initial API and implementation\r
- *******************************************************************************/\r
-\r
-import java.util.ArrayList;\r
-import java.util.List;\r
-\r
-import org.eclipse.core.commands.util.Tracing;\r
-import org.eclipse.core.runtime.Assert;\r
-import org.eclipse.core.runtime.ISafeRunnable;\r
-import org.eclipse.core.runtime.SafeRunner;\r
-import org.eclipse.jface.resource.ImageDescriptor;\r
-import org.eclipse.jface.viewers.ISelectionProvider;\r
-import org.eclipse.jface.viewers.SelectionChangedEvent;\r
-import org.eclipse.swt.SWT;\r
-import org.eclipse.swt.custom.CTabFolder;\r
-import org.eclipse.swt.custom.CTabItem;\r
-import org.eclipse.swt.events.SelectionAdapter;\r
-import org.eclipse.swt.events.SelectionEvent;\r
-import org.eclipse.swt.graphics.Image;\r
-import org.eclipse.swt.layout.FillLayout;\r
-import org.eclipse.swt.widgets.Composite;\r
-import org.eclipse.swt.widgets.Control;\r
-import org.eclipse.swt.widgets.Display;\r
-import org.eclipse.swt.widgets.Item;\r
-import org.eclipse.ui.IEditorInput;\r
-import org.eclipse.ui.IEditorPart;\r
-import org.eclipse.ui.IKeyBindingService;\r
-import org.eclipse.ui.IMemento;\r
-import org.eclipse.ui.INestableKeyBindingService;\r
-import org.eclipse.ui.IPartService;\r
-import org.eclipse.ui.IViewPart;\r
-import org.eclipse.ui.IViewSite;\r
-import org.eclipse.ui.IWorkbenchPart;\r
-import org.eclipse.ui.IWorkbenchPartSite;\r
-import org.eclipse.ui.PartInitException;\r
-import org.eclipse.ui.internal.WorkbenchPlugin;\r
-import org.eclipse.ui.internal.misc.Policy;\r
-import org.eclipse.ui.internal.services.INestable;\r
-import org.eclipse.ui.internal.services.IServiceLocatorCreator;\r
-import org.eclipse.ui.internal.util.Util;\r
-import org.eclipse.ui.part.MultiPageEditorPart;\r
-import org.eclipse.ui.part.MultiPageEditorSite;\r
-import org.eclipse.ui.part.MultiPageSelectionProvider;\r
-import org.eclipse.ui.part.PageSwitcher;\r
-import org.eclipse.ui.part.ViewPart;\r
-import org.eclipse.ui.services.IDisposable;\r
-import org.eclipse.ui.services.IServiceLocator;\r
-\r
-/**\r
- * A multi-page editor is an editor with multiple pages, each of which may\r
- * contain an editor or an arbitrary SWT control.\r
- * <p>\r
- * Subclasses must implement the following methods:\r
- * <ul>\r
- * <li><code>createPages</code> - to create the required pages by calling one\r
- * of the <code>addPage</code> methods</li>\r
- * <li><code>IEditorPart.doSave</code> - to save contents of editor</li>\r
- * <li><code>IEditorPart.doSaveAs</code> - to save contents of editor</li>\r
- * <li><code>IEditorPart.isSaveAsAllowed</code> - to enable Save As</li>\r
- * <li><code>IEditorPart.gotoMarker</code> - to scroll to a marker</li>\r
- * </ul>\r
- * </p>\r
- * <p>\r
- * Multi-page editors have a single action bar contributor, which manages\r
- * contributions for all the pages. The contributor must be a subclass of\r
- * <code>AbstractMultiPageEditorActionBarContributor</code>. Note that since\r
- * any nested editors are created directly in code by callers of\r
- * <code>addPage(IEditorPart,IEditorInput)</code>, nested editors do not have\r
- * their own contributors.\r
- * </p>\r
- * \r
- * @see org.eclipse.ui.part.MultiPageEditorActionBarContributor\r
- * \r
- * NOTE: this class was originally copied from MultiPageEditorPart and adapter to work as a ViewPart.\r
- */\r
-@SuppressWarnings({"restriction","deprecation","unchecked","rawtypes"})\r
-public abstract class TabbedPropertyPage extends ViewPart {\r
-\r
-    /**\r
-     * Subclasses that override {@link #createPageContainer(Composite)} can use\r
-     * this constant to get a site for the container that can be active while\r
-     * the current page is deactivated.\r
-     * \r
-     * @since 3.4\r
-     * @see #activateSite()\r
-     * @see #deactivateSite(boolean, boolean)\r
-     * @see #getPageSite(int)\r
-     */\r
-    protected static final int PAGE_CONTAINER_SITE = 65535;\r
-\r
-    /**\r
-     * Private tracing output.\r
-     */\r
-    private static final String TRACING_COMPONENT = "MPE"; //$NON-NLS-1$\r
-\r
-    /**\r
-     * The active service locator. This value may be <code>null</code> if\r
-     * there is no selected page, or if the selected page is a control with\r
-     * no site.\r
-     */\r
-    private INestable activeServiceLocator;\r
-\r
-    /**\r
-     * The container widget.\r
-     */\r
-    private CTabFolder container;\r
-    private Composite pageContainer;\r
-\r
-    /**\r
-     * List of nested editors. Element type: IEditorPart. Need to hang onto them\r
-     * here, in addition to using get/setData on the items, because dispose()\r
-     * needs to access them, but widgetry has already been disposed at that\r
-     * point.\r
-     */\r
-    private final ArrayList nestedEditors = new ArrayList(3);\r
-\r
-    private final List pageSites = new ArrayList(3);\r
-\r
-    private IServiceLocator pageContainerSite;\r
-\r
-    /**\r
-     * Creates and adds a new page containing the given control to this\r
-     * multi-page editor. The control may be <code>null</code>, allowing it\r
-     * to be created and set later using <code>setControl</code>.\r
-     * \r
-     * @param control\r
-     *            the control, or <code>null</code>\r
-     * @return the index of the new page\r
-     * \r
-     * @see MultiPageEditorPart#setControl(int, Control)\r
-     */\r
-    public int addPage(Control control) {\r
-        int index = getPageCount();\r
-        addPage(index, control);\r
-        return index;\r
-    }\r
-\r
-    /**\r
-     * @param control the control to add as a page\r
-     * @param text the page title text\r
-     * @param image the page title image\r
-     * @return\r
-     */\r
-    public int addPage(Control control, String text, Image image) {\r
-        int result = addPage(control);\r
-        setPageText(result, text);\r
-        setPageImage(result, image);\r
-        return result;\r
-    }\r
-\r
-    /**\r
-     * Creates and adds a new page containing the given control to this\r
-     * multi-page editor. The page is added at the given index. The control may\r
-     * be <code>null</code>, allowing it to be created and set later using\r
-     * <code>setControl</code>.\r
-     * \r
-     * @param index\r
-     *            the index at which to add the page (0-based)\r
-     * @param control\r
-     *            the control, or <code>null</code>\r
-     * \r
-     * @see MultiPageEditorPart#setControl(int, Control)\r
-     */\r
-    public void addPage(int index, Control control) {\r
-        createItem(index, control);\r
-    }\r
-\r
-    /**\r
-     * Creates an empty container. Creates a CTabFolder with no style bits set,\r
-     * and hooks a selection listener which calls <code>pageChange()</code>\r
-     * whenever the selected tab changes.\r
-     * \r
-     * @param parent\r
-     *            The composite in which the container tab folder should be\r
-     *            created; must not be <code>null</code>.\r
-     * @return a new container\r
-     */\r
-    private CTabFolder createContainer(Composite parent) {\r
-        // use SWT.FLAT style so that an extra 1 pixel border is not reserved\r
-        // inside the folder\r
-        parent.setLayout(new FillLayout());\r
-        final CTabFolder newContainer = new CTabFolder(parent, getContainerStyle());\r
-        newContainer.addSelectionListener(new SelectionAdapter() {\r
-            @Override\r
-            public void widgetSelected(SelectionEvent e) {\r
-                int newPageIndex = newContainer.indexOf((CTabItem) e.item);\r
-                pageChange(newPageIndex);\r
-            }\r
-        });\r
-        return newContainer;\r
-    }\r
-\r
-    /**\r
-     * Override this to customize the style given to the container\r
-     * {@link CTabFolder} instance created by\r
-     * {@link #createContainer(Composite)}. Default value is {@value SWT#BOTTOM}\r
-     * | {@value SWT#FLAT}.\r
-     * \r
-     * @return swt style mask for {@link CTabFolder}\r
-     */\r
-    protected int getContainerStyle() {\r
-        return SWT.BOTTOM | SWT.FLAT;\r
-    }\r
-\r
-    /**\r
-     * Creates a tab item at the given index and places the given control in the\r
-     * new item. The item is a CTabItem with no style bits set.\r
-     * \r
-     * @param index\r
-     *            the index at which to add the control\r
-     * @param control\r
-     *            is the control to be placed in an item\r
-     * @return a new item\r
-     */\r
-    private CTabItem createItem(int index, Control control) {\r
-        CTabItem item = new CTabItem(getTabFolder(), SWT.NONE, index);\r
-        item.setControl(control);\r
-        return item;\r
-    }\r
-\r
-    /**\r
-     * Creates the pages of this multi-page editor.\r
-     * <p>\r
-     * Subclasses must implement this method.\r
-     * </p>\r
-     */\r
-    protected abstract void createPages();\r
-\r
-    /**\r
-     * The <code>MultiPageEditor</code> implementation of this\r
-     * <code>IWorkbenchPart</code> method creates the control for the\r
-     * multi-page editor by calling <code>createContainer</code>, then\r
-     * <code>createPages</code>. Subclasses should implement\r
-     * <code>createPages</code> rather than overriding this method.\r
-     * \r
-     * @param parent\r
-     *            The parent in which the editor should be created; must not be\r
-     *            <code>null</code>.\r
-     */\r
-    @Override\r
-    public final void createPartControl(Composite parent) {\r
-        this.pageContainer = createPageContainer(parent);\r
-        this.container = createContainer(pageContainer);\r
-        createPages();\r
-        // set the active page (page 0 by default), unless it has already been\r
-        // done\r
-        if (getActivePage() == -1) {\r
-            setActivePage(0);\r
-            IViewSite site = getViewSite();\r
-            if (site!=null) {\r
-                final IServiceLocator serviceLocator = site;\r
-                if (serviceLocator instanceof INestable) {\r
-                    activeServiceLocator = (INestable) serviceLocator;\r
-                    activeServiceLocator.activate();\r
-                }\r
-            }\r
-        }\r
-        initializePageSwitching();\r
-    }\r
-\r
-    /**\r
-     * Initialize the MultiPageEditorPart to use the page switching command.\r
-     * Clients can override this method with an empty body if they wish to\r
-     * opt-out.\r
-     * \r
-     * @since 3.4\r
-     */\r
-    protected void initializePageSwitching() {\r
-        new PageSwitcher(getSite().getPart()) {\r
-            @Override\r
-            public Object[] getPages() {\r
-                int pageCount = getPageCount();\r
-                Object[] result = new Object[pageCount];\r
-                for (int i = 0; i < pageCount; i++) {\r
-                    result[i] = new Integer(i);\r
-                }\r
-                return result;\r
-            }\r
-\r
-            @Override\r
-            public String getName(Object page) {\r
-                return getPageText(((Integer) page).intValue());\r
-            }\r
-\r
-            @Override\r
-            public ImageDescriptor getImageDescriptor(Object page) {\r
-                Image image = getPageImage(((Integer) page).intValue());\r
-                if (image == null)\r
-                    return null;\r
-\r
-                return ImageDescriptor.createFromImage(image);\r
-            }\r
-\r
-            @Override\r
-            public void activatePage(Object page) {\r
-                setActivePage(((Integer) page).intValue());\r
-            }\r
-\r
-            @Override\r
-            public int getCurrentPageIndex() {\r
-                return getActivePage();\r
-            }\r
-        };\r
-    }\r
-\r
-    /**\r
-     * Creates the parent control for the container returned by\r
-     * {@link #getContainer() }.\r
-     * \r
-     * <p>\r
-     * Subclasses may extend and must call super implementation first.\r
-     * </p>\r
-     * \r
-     * @param parent\r
-     *            the parent for all of the editors contents.\r
-     * @return the parent for this editor's container. Must not be\r
-     *         <code>null</code>.\r
-     * \r
-     * @since 3.2\r
-     */\r
-    protected Composite createPageContainer(Composite parent) {\r
-        return parent;\r
-    }\r
-\r
-    public Composite getPageContainer() {\r
-        return pageContainer;\r
-    }\r
-\r
-    /**\r
-     * Creates the site for the given nested editor. The\r
-     * <code>MultiPageEditorPart</code> implementation of this method creates\r
-     * an instance of <code>MultiPageEditorSite</code>. Subclasses may\r
-     * reimplement to create more specialized sites.\r
-     * \r
-     * @param editor\r
-     *            the nested editor\r
-     * @return the editor site\r
-     */\r
-    protected IViewSite createSite(IViewPart editor) {\r
-        return new TabbedPropertyPageViewSite(this, editor);\r
-    }\r
-\r
-    /**\r
-     * The <code>MultiPageEditorPart</code> implementation of this\r
-     * <code>IWorkbenchPart</code> method disposes all nested editors.\r
-     * Subclasses may extend.\r
-     */\r
-    @Override\r
-    public void dispose() {\r
-        for (int i = 0; i < nestedEditors.size(); ++i) {\r
-            IEditorPart editor = (IEditorPart) nestedEditors.get(i);\r
-            disposePart(editor);\r
-        }\r
-        nestedEditors.clear();\r
-        if (pageContainerSite instanceof IDisposable) {\r
-            ((IDisposable) pageContainerSite).dispose();\r
-            pageContainerSite = null;\r
-        }\r
-        for (int i = 0; i < pageSites.size(); i++) {\r
-            IServiceLocator sl = (IServiceLocator) pageSites.get(i);\r
-            if (sl instanceof IDisposable) {\r
-                ((IDisposable) sl).dispose();\r
-            }\r
-        }\r
-        pageSites.clear();\r
-    }\r
-\r
-    /**\r
-     * Returns the active nested editor if there is one.\r
-     * <p>\r
-     * Subclasses should not override this method\r
-     * </p>\r
-     * \r
-     * @return the active nested editor, or <code>null</code> if none\r
-     */\r
-    protected IEditorPart getActiveEditor() {\r
-        int index = getActivePage();\r
-        if (index != -1) {\r
-            return getEditor(index);\r
-        }\r
-        return null;\r
-    }\r
-\r
-    /**\r
-     * Returns the index of the currently active page, or -1 if there is no\r
-     * active page.\r
-     * <p>\r
-     * Subclasses should not override this method\r
-     * </p>\r
-     * \r
-     * @return the index of the active page, or -1 if there is no active page\r
-     */\r
-    protected int getActivePage() {\r
-        CTabFolder tabFolder = getTabFolder();\r
-        if (tabFolder != null && !tabFolder.isDisposed()) {\r
-            return tabFolder.getSelectionIndex();\r
-        }\r
-        return -1;\r
-    }\r
-\r
-    /**\r
-     * Returns the composite control containing this multi-page editor's pages.\r
-     * This should be used as the parent when creating controls for the\r
-     * individual pages. That is, when calling <code>addPage(Control)</code>,\r
-     * the passed control should be a child of this container.\r
-     * <p>\r
-     * Warning: Clients should not assume that the container is any particular\r
-     * subclass of Composite. The actual class used may change in order to\r
-     * improve the look and feel of multi-page editors. Any code making\r
-     * assumptions on the particular subclass would thus be broken.\r
-     * </p>\r
-     * <p>\r
-     * Subclasses should not override this method\r
-     * </p>\r
-     * \r
-     * @return the composite, or <code>null</code> if\r
-     *         <code>createPartControl</code> has not been called yet\r
-     */\r
-    protected Composite getContainer() {\r
-        return container;\r
-    }\r
-\r
-    /**\r
-     * Returns the control for the given page index, or <code>null</code> if\r
-     * no control has been set for the page. The page index must be valid.\r
-     * <p>\r
-     * Subclasses should not override this method\r
-     * </p>\r
-     * \r
-     * @param pageIndex\r
-     *            the index of the page\r
-     * @return the control for the specified page, or <code>null</code> if\r
-     *         none has been set\r
-     */\r
-    protected Control getControl(int pageIndex) {\r
-        return getItem(pageIndex).getControl();\r
-    }\r
-\r
-    /**\r
-     * Returns the editor for the given page index. The page index must be\r
-     * valid.\r
-     * \r
-     * @param pageIndex\r
-     *            the index of the page\r
-     * @return the editor for the specified page, or <code>null</code> if the\r
-     *         specified page was not created with\r
-     *         <code>addPage(IEditorPart,IEditorInput)</code>\r
-     */\r
-    protected IEditorPart getEditor(int pageIndex) {\r
-        Item item = getItem(pageIndex);\r
-        if (item != null) {\r
-            Object data = item.getData();\r
-            if (data instanceof IEditorPart) {\r
-                return (IEditorPart) data;\r
-            }\r
-        }\r
-        return null;\r
-    }\r
-\r
-    /**\r
-     * Returns the service locator for the given page index. This method can be\r
-     * used to create service locators for pages that are just controls. The\r
-     * page index must be valid.\r
-     * <p>\r
-     * This will return the editor site service locator for an editor, and\r
-     * create one for a page that is just a control.\r
-     * </p>\r
-     * \r
-     * @param pageIndex\r
-     *            the index of the page\r
-     * @return the editor for the specified page, or <code>null</code> if the\r
-     *         specified page was not created with\r
-     *         <code>addPage(IEditorPart,IEditorInput)</code>\r
-     * @since 3.4\r
-     */\r
-    protected final IServiceLocator getPageSite(int pageIndex) {\r
-        if (pageIndex == PAGE_CONTAINER_SITE) {\r
-            return getPageContainerSite();\r
-        }\r
-\r
-        Item item = getItem(pageIndex);\r
-        if (item != null) {\r
-            Object data = item.getData();\r
-            if (data instanceof IEditorPart) {\r
-                return ((IEditorPart) data).getSite();\r
-            } else if (data instanceof IServiceLocator) {\r
-                return (IServiceLocator) data;\r
-            } else if (data == null) {\r
-                IServiceLocatorCreator slc = (IServiceLocatorCreator) getSite()\r
-                .getService(IServiceLocatorCreator.class);\r
-                IServiceLocator sl = slc.createServiceLocator(getSite(), null, new IDisposable() {\r
-                    @Override\r
-                    public void dispose() {\r
-                        // TODO Auto-generated method stub\r
-                    }\r
-                });\r
-                item.setData(sl);\r
-                pageSites.add(sl);\r
-                return sl;\r
-            }\r
-        }\r
-        return null;\r
-    }\r
-\r
-    /**\r
-     * @return A site that can be used with a header.\r
-     * @since 3.4\r
-     * @see #createPageContainer(Composite)\r
-     * @see #PAGE_CONTAINER_SITE\r
-     * @see #getPageSite(int)\r
-     */\r
-    private IServiceLocator getPageContainerSite() {\r
-        if (pageContainerSite == null) {\r
-            IServiceLocatorCreator slc = (IServiceLocatorCreator) getSite()\r
-            .getService(IServiceLocatorCreator.class);\r
-            pageContainerSite = slc.createServiceLocator(getSite(), null, new IDisposable() {\r
-                @Override\r
-                public void dispose() {\r
-                    // TODO Auto-generated method stub\r
-                }\r
-            });\r
-        }\r
-        return pageContainerSite;\r
-    }\r
-\r
-    /**\r
-     * Returns the tab item for the given page index (page index is 0-based).\r
-     * The page index must be valid.\r
-     * \r
-     * @param pageIndex\r
-     *            the index of the page\r
-     * @return the tab item for the given page index\r
-     */\r
-    private CTabItem getItem(int pageIndex) {\r
-        return getTabFolder().getItem(pageIndex);\r
-    }\r
-\r
-    /**\r
-     * Returns the number of pages in this multi-page editor.\r
-     * \r
-     * @return the number of pages\r
-     */\r
-    protected int getPageCount() {\r
-        CTabFolder folder = getTabFolder();\r
-        // May not have been created yet, or may have been disposed.\r
-        if (folder != null && !folder.isDisposed()) {\r
-            return folder.getItemCount();\r
-        }\r
-        return 0;\r
-    }\r
-\r
-    /**\r
-     * Returns the image for the page with the given index, or <code>null</code>\r
-     * if no image has been set for the page. The page index must be valid.\r
-     * \r
-     * @param pageIndex\r
-     *            the index of the page\r
-     * @return the image, or <code>null</code> if none\r
-     */\r
-    protected Image getPageImage(int pageIndex) {\r
-        return getItem(pageIndex).getImage();\r
-    }\r
-\r
-    /**\r
-     * Returns the text label for the page with the given index. Returns the\r
-     * empty string if no text label has been set for the page. The page index\r
-     * must be valid.\r
-     * \r
-     * @param pageIndex\r
-     *            the index of the page\r
-     * @return the text label for the page\r
-     */\r
-    protected String getPageText(int pageIndex) {\r
-        return getItem(pageIndex).getText();\r
-    }\r
-\r
-    /**\r
-     * Returns the tab folder containing this multi-page editor's pages.\r
-     * \r
-     * @return the tab folder, or <code>null</code> if\r
-     *         <code>createPartControl</code> has not been called yet\r
-     */\r
-    protected CTabFolder getTabFolder() {\r
-        return container;\r
-    }\r
-\r
-    /**\r
-     * Handles a property change notification from a nested editor. The default\r
-     * implementation simply forwards the change to listeners on this multi-page\r
-     * editor by calling <code>firePropertyChange</code> with the same\r
-     * property id. For example, if the dirty state of a nested editor changes\r
-     * (property id <code>IEditorPart.PROP_DIRTY</code>), this method handles\r
-     * it by firing a property change event for\r
-     * <code>IEditorPart.PROP_DIRTY</code> to property listeners on this\r
-     * multi-page editor.\r
-     * <p>\r
-     * Subclasses may extend or reimplement this method.\r
-     * </p>\r
-     * \r
-     * @param propertyId\r
-     *            the id of the property that changed\r
-     */\r
-    protected void handlePropertyChange(int propertyId) {\r
-        firePropertyChange(propertyId);\r
-    }\r
-\r
-    /**\r
-     * The <code>MultiPageEditorPart</code> implementation of this\r
-     * <code>IEditorPart</code> method sets its site to the given site, its\r
-     * input to the given input, and the site's selection provider to a\r
-     * <code>MultiPageSelectionProvider</code>. Subclasses may extend this\r
-     * method.\r
-     * \r
-     * @param site\r
-     *            The site for which this part is being created; must not be\r
-     *            <code>null</code>.\r
-     * @param input\r
-     *            The input on which this editor should be created; must not be\r
-     *            <code>null</code>.\r
-     * @throws PartInitException\r
-     *             If the initialization of the part fails -- currently never.\r
-     */\r
-    @Override\r
-    public void init(IViewSite site, IMemento memento)\r
-    throws PartInitException {\r
-        setSite(site);\r
-        site.setSelectionProvider(new TabbedPageSelectionProvider(this));\r
-    }\r
-\r
-    /**\r
-     * Notifies this multi-page editor that the page with the given id has been\r
-     * activated. This method is called when the user selects a different tab.\r
-     * <p>\r
-     * The <code>MultiPageEditorPart</code> implementation of this method sets\r
-     * focus to the new page, and notifies the action bar contributor (if there\r
-     * is one). This checks whether the action bar contributor is an instance of\r
-     * <code>MultiPageEditorActionBarContributor</code>, and, if so, calls\r
-     * <code>setActivePage</code> with the active nested editor. This also\r
-     * fires a selection change event if required.\r
-     * </p>\r
-     * <p>\r
-     * Subclasses may extend this method.\r
-     * </p>\r
-     * \r
-     * @param newPageIndex\r
-     *            the index of the activated page\r
-     */\r
-    protected void pageChange(int newPageIndex) {\r
-        deactivateSite(false, false);\r
-\r
-        IPartService partService = (IPartService) getSite().getService(\r
-                IPartService.class);\r
-        if (partService != null && partService.getActivePart() == this) {\r
-            setFocus(newPageIndex);\r
-        }\r
-\r
-        IEditorPart activeEditor = getEditor(newPageIndex);\r
-\r
-//        IEditorActionBarContributor contributor = getViewSite()\r
-//                .getActionBarContributor();\r
-//        if (contributor != null\r
-//                && contributor instanceof MultiPageEditorActionBarContributor) {\r
-//            ((MultiPageEditorActionBarContributor) contributor)\r
-//                    .setActivePage(activeEditor);\r
-//        }\r
-\r
-        if (activeEditor != null) {\r
-            ISelectionProvider selectionProvider = activeEditor.getSite()\r
-            .getSelectionProvider();\r
-            if (selectionProvider != null) {\r
-                ISelectionProvider outerProvider = getSite()\r
-                .getSelectionProvider();\r
-                if (outerProvider instanceof MultiPageSelectionProvider) {\r
-                    SelectionChangedEvent event = new SelectionChangedEvent(\r
-                            selectionProvider, selectionProvider.getSelection());\r
-\r
-                    MultiPageSelectionProvider provider = (MultiPageSelectionProvider) outerProvider;\r
-                    provider.fireSelectionChanged(event);\r
-                    provider.firePostSelectionChanged(event);\r
-                } else {\r
-                    if (Policy.DEBUG_MPE) {\r
-                        Tracing.printTrace(TRACING_COMPONENT,\r
-                                "MultiPageEditorPart " + getTitle() //$NON-NLS-1$\r
-                                + " did not propogate selection for " //$NON-NLS-1$\r
-                                + activeEditor.getTitle());\r
-                    }\r
-                }\r
-            }\r
-        }\r
-\r
-        activateSite();\r
-    }\r
-\r
-    /**\r
-     * This method can be used by implementors of\r
-     * {@link MultiPageEditorPart#createPageContainer(Composite)} to deactivate\r
-     * the active inner editor services while their header has focus. A\r
-     * deactivateSite() must have a matching call to activateSite() when\r
-     * appropriate.\r
-     * <p>\r
-     * An new inner editor will have its site activated on a\r
-     * {@link MultiPageEditorPart#pageChange(int)}.\r
-     * </p>\r
-     * <p>\r
-     * <b>Note:</b> This API is evolving in 3.4 and this might not be its final\r
-     * form.\r
-     * </p>\r
-     * \r
-     * @param immediate\r
-     *            immediately deactivate the legacy keybinding service\r
-     * @param containerSiteActive\r
-     *            Leave the page container site active.\r
-     * @since 3.4\r
-     * @see #activateSite()\r
-     * @see #createPageContainer(Composite)\r
-     * @see #getPageSite(int)\r
-     * @see #PAGE_CONTAINER_SITE\r
-     */\r
-    protected final void deactivateSite(boolean immediate,\r
-            boolean containerSiteActive) {\r
-        // Deactivate the nested services from the last active service locator.\r
-        if (activeServiceLocator != null) {\r
-            activeServiceLocator.deactivate();\r
-            activeServiceLocator = null;\r
-        }\r
-\r
-        final int pageIndex = getActivePage();\r
-        final IKeyBindingService service = getSite().getKeyBindingService();\r
-        if (pageIndex < 0 || pageIndex >= getPageCount() || immediate) {\r
-            // There is no selected page, so deactivate the active service.\r
-            if (service instanceof INestableKeyBindingService) {\r
-                final INestableKeyBindingService nestableService = (INestableKeyBindingService) service;\r
-                nestableService.activateKeyBindingService(null);\r
-            } else {\r
-                WorkbenchPlugin\r
-                .log("MultiPageEditorPart.setFocus()   Parent key binding service was not an instance of INestableKeyBindingService.  It was an instance of " + service.getClass().getName() + " instead."); //$NON-NLS-1$ //$NON-NLS-2$\r
-            }\r
-        }\r
-\r
-        if (containerSiteActive) {\r
-            IServiceLocator containerSite = getPageContainerSite();\r
-            if (containerSite instanceof INestable) {\r
-                activeServiceLocator = (INestable) containerSite;\r
-                activeServiceLocator.activate();\r
-            }\r
-        }\r
-    }\r
-\r
-    /**\r
-     * This method can be used by implementors of\r
-     * {@link #createPageContainer(Composite)} to activate the active inner\r
-     * editor services when their header loses focus.\r
-     * <p>\r
-     * An new inner editor will have its site activated on a\r
-     * {@link #pageChange(int)}.\r
-     * </p>\r
-     * <p>\r
-     * <b>Note:</b> This API is evolving in 3.4 and this might not be its final\r
-     * form.\r
-     * </p>\r
-     * \r
-     * @since 3.4\r
-     * @see #deactivateSite(boolean,boolean)\r
-     * @see #createPageContainer(Composite)\r
-     * @see #getPageSite(int)\r
-     */\r
-    protected final void activateSite() {\r
-        if (activeServiceLocator != null) {\r
-            activeServiceLocator.deactivate();\r
-            activeServiceLocator = null;\r
-        }\r
-\r
-        final IKeyBindingService service = getSite().getKeyBindingService();\r
-        final int pageIndex = getActivePage();\r
-        final IEditorPart editor = getEditor(pageIndex);\r
-\r
-        if (editor != null) {\r
-            // active the service for this inner editor\r
-            if (service instanceof INestableKeyBindingService) {\r
-                final INestableKeyBindingService nestableService = (INestableKeyBindingService) service;\r
-                nestableService.activateKeyBindingService(editor\r
-                        .getEditorSite());\r
-\r
-            } else {\r
-                WorkbenchPlugin\r
-                .log("MultiPageEditorPart.setFocus()   Parent key binding service was not an instance of INestableKeyBindingService.  It was an instance of " + service.getClass().getName() + " instead."); //$NON-NLS-1$ //$NON-NLS-2$\r
-            }\r
-            // Activate the services for the new service locator.\r
-            final IServiceLocator serviceLocator = editor.getEditorSite();\r
-            if (serviceLocator instanceof INestable) {\r
-                activeServiceLocator = (INestable) serviceLocator;\r
-                activeServiceLocator.activate();\r
-            }\r
-\r
-        } else {\r
-            Item item = getItem(pageIndex);\r
-\r
-            // There is no selected editor, so deactivate the active service.\r
-            if (service instanceof INestableKeyBindingService) {\r
-                final INestableKeyBindingService nestableService = (INestableKeyBindingService) service;\r
-                nestableService.activateKeyBindingService(null);\r
-            } else {\r
-                WorkbenchPlugin\r
-                .log("MultiPageEditorPart.setFocus()   Parent key binding service was not an instance of INestableKeyBindingService.  It was an instance of " + service.getClass().getName() + " instead."); //$NON-NLS-1$ //$NON-NLS-2$\r
-            }\r
-\r
-            if (item.getData() instanceof INestable) {\r
-                activeServiceLocator = (INestable) item.getData();\r
-                activeServiceLocator.activate();\r
-            }\r
-        }\r
-    }\r
-\r
-    /**\r
-     * Disposes the given part and its site.\r
-     * \r
-     * @param part\r
-     *            The part to dispose; must not be <code>null</code>.\r
-     */\r
-    private void disposePart(final IWorkbenchPart part) {\r
-        SafeRunner.run(new ISafeRunnable() {\r
-            public void run() {\r
-                IWorkbenchPartSite partSite = part.getSite();\r
-                part.dispose();\r
-                if (partSite instanceof MultiPageEditorSite) {\r
-                    ((MultiPageEditorSite) partSite).dispose();\r
-                }\r
-            }\r
-\r
-            public void handleException(Throwable e) {\r
-                // Exception has already being logged by Core. Do nothing.\r
-            }\r
-        });\r
-    }\r
-\r
-    /**\r
-     * Removes the page with the given index from this multi-page editor. The\r
-     * controls for the page are disposed of; if the page has an editor, it is\r
-     * disposed of too. The page index must be valid.\r
-     * \r
-     * @param pageIndex\r
-     *            the index of the page\r
-     * @see MultiPageEditorPart#addPage(Control)\r
-     * @see MultiPageEditorPart#addPage(IEditorPart, IEditorInput)\r
-     */\r
-    public void removePage(int pageIndex) {\r
-        Assert.isTrue(pageIndex >= 0 && pageIndex < getPageCount());\r
-        // get editor (if any) before disposing item\r
-        IEditorPart editor = getEditor(pageIndex);\r
-\r
-        // get control for the item if it's not an editor\r
-        CTabItem item = getItem(pageIndex);\r
-        IServiceLocator pageLocator = null;\r
-        if (item.getData() instanceof IServiceLocator) {\r
-            pageLocator = (IServiceLocator) item.getData();\r
-        }\r
-        Control pageControl = item.getControl();\r
-\r
-        // dispose item before disposing editor, in case there's an exception\r
-        // in editor's dispose\r
-        item.dispose();\r
-\r
-        if (pageControl != null) {\r
-            pageControl.dispose();\r
-        }\r
-\r
-        // dispose editor (if any)\r
-        if (editor != null) {\r
-            nestedEditors.remove(editor);\r
-            disposePart(editor);\r
-        }\r
-        if (pageLocator != null) {\r
-            pageSites.remove(pageLocator);\r
-            if (pageLocator instanceof IDisposable) {\r
-                ((IDisposable) pageLocator).dispose();\r
-            }\r
-        }\r
-    }\r
-\r
-    /**\r
-     * Sets the currently active page.\r
-     * \r
-     * @param pageIndex\r
-     *            the index of the page to be activated; the index must be valid\r
-     */\r
-    protected void setActivePage(int pageIndex) {\r
-        Assert.isTrue(pageIndex >= 0 && pageIndex < getPageCount());\r
-        getTabFolder().setSelection(pageIndex);\r
-        pageChange(pageIndex);\r
-    }\r
-\r
-    /**\r
-     * Sets the control for the given page index. The page index must be valid.\r
-     * \r
-     * @param pageIndex\r
-     *            the index of the page\r
-     * @param control\r
-     *            the control for the specified page, or <code>null</code> to\r
-     *            clear the control\r
-     */\r
-    protected void setControl(int pageIndex, Control control) {\r
-        getItem(pageIndex).setControl(control);\r
-    }\r
-\r
-    /**\r
-     * The <code>MultiPageEditor</code> implementation of this\r
-     * <code>IWorkbenchPart</code> method sets focus on the active nested\r
-     * editor, if there is one.\r
-     * <p>\r
-     * Subclasses may extend or reimplement.\r
-     * </p>\r
-     */\r
-    @Override\r
-    public void setFocus() {\r
-        setFocus(getActivePage());\r
-    }\r
-\r
-    /**\r
-     * Sets focus to the control for the given page. If the page has an editor,\r
-     * this calls its <code>setFocus()</code> method. Otherwise, this calls\r
-     * <code>setFocus</code> on the control for the page.\r
-     * \r
-     * @param pageIndex\r
-     *            the index of the page\r
-     */\r
-    private void setFocus(int pageIndex) {\r
-        final IEditorPart editor = getEditor(pageIndex);\r
-        if (editor != null) {\r
-            editor.setFocus();\r
-\r
-        } else {\r
-            // Give the page's control focus.\r
-            final Control control = getControl(pageIndex);\r
-            if (control != null) {\r
-                control.setFocus();\r
-            }\r
-        }\r
-    }\r
-\r
-    /**\r
-     * Sets the image for the page with the given index, or <code>null</code>\r
-     * to clear the image for the page. The page index must be valid.\r
-     * \r
-     * @param pageIndex\r
-     *            the index of the page\r
-     * @param image\r
-     *            the image, or <code>null</code>\r
-     */\r
-    protected void setPageImage(int pageIndex, Image image) {\r
-        getItem(pageIndex).setImage(image);\r
-    }\r
-\r
-    /**\r
-     * Sets the text label for the page with the given index. The page index\r
-     * must be valid. The text label must not be null.\r
-     * \r
-     * @param pageIndex\r
-     *            the index of the page\r
-     * @param text\r
-     *            the text label\r
-     */\r
-    protected void setPageText(int pageIndex, String text) {\r
-        getItem(pageIndex).setText(text);\r
-    }\r
-\r
-    /**\r
-     * If there is an adapter registered against the subclass of\r
-     * MultiPageEditorPart return that. Otherwise, delegate to the internal\r
-     * editor.\r
-     * \r
-     * @see org.eclipse.ui.part.WorkbenchPart#getAdapter(java.lang.Class)\r
-     */\r
-    @Override\r
-    public Object getAdapter(Class adapter) {\r
-        Object result = super.getAdapter(adapter);\r
-        // restrict delegating to the UI thread for bug 144851\r
-        if (result == null && Display.getCurrent()!=null) {\r
-            IEditorPart innerEditor = getActiveEditor();\r
-            // see bug 138823 - prevent some subclasses from causing\r
-            // an infinite loop\r
-            if (innerEditor != null && innerEditor != this) {\r
-                result = Util.getAdapter(innerEditor, adapter);\r
-            }\r
-        }\r
-        return result;\r
-    }\r
-\r
-//    /**\r
-//     * Find the editors contained in this multi-page editor\r
-//     * whose editor input match the provided input.\r
-//     * @param input the editor input\r
-//     * @return the editors contained in this multi-page editor\r
-//     * whose editor input match the provided input\r
-//     * @since 3.3\r
-//     */\r
-//    public final IEditorPart[] findEditors(IEditorInput input) {\r
-//        List result = new ArrayList();\r
-//        int count = getPageCount();\r
-//        for (int i = 0; i < count; i++) {\r
-//            IEditorPart editor = getEditor(i);\r
-//            if (editor != null\r
-//                    && editor.getEditorInput() != null\r
-//                    && editor.getEditorInput().equals(input)) {\r
-//                result.add(editor);\r
-//            }\r
-//        }\r
-//        return (IEditorPart[]) result.toArray(new IEditorPart[result.size()]);\r
-//    }\r
-//\r
-//    /**\r
-//     * Set the active page of this multi-page editor to the\r
-//     * page that contains the given editor part. This method has\r
-//     * no effect of the given editor part is not contained in this\r
-//     * multi-page editor.\r
-//     * @param editorPart the editor part\r
-//     * @since 3.3\r
-//     */\r
-//    public final void setActiveEditor(IEditorPart editorPart) {\r
-//        int count = getPageCount();\r
-//        for (int i = 0; i < count; i++) {\r
-//            IEditorPart editor = getEditor(i);\r
-//            if (editor == editorPart) {\r
-//                setActivePage(i);\r
-//                break;\r
-//            }\r
-//        }\r
-//    }\r
-\r
-//    private IViewPart part;\r
-//\r
-//    public IViewSite getSite() {\r
-//        return part.getViewSite();\r
-//    }\r
-//\r
-//    public IViewPart getPart() {\r
-//        return part;\r
-//    }\r
-//\r
-\r
-    @Override\r
-    public IViewSite getViewSite() {\r
-        if(part instanceof IViewPart) return ((IViewPart) part).getViewSite();\r
-        else return null;\r
-    }\r
-\r
-    @Override\r
-    public IWorkbenchPartSite getSite() {\r
-        return part.getSite();\r
-    };\r
-\r
-    IWorkbenchPart part;\r
-\r
-    public TabbedPropertyPage(IWorkbenchPart part) {\r
-        this.part = part;\r
-        // Given part may be null\r
-//        assert(part != null);\r
-//        setSite(part.getSite());\r
-    }\r
-\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * 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:
+ *     VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.browsing.ui.swt;
+
+
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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
+ *******************************************************************************/
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.commands.util.Tracing;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CTabFolder;
+import org.eclipse.swt.custom.CTabItem;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Item;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IKeyBindingService;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.INestableKeyBindingService;
+import org.eclipse.ui.IPartService;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IViewSite;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.misc.Policy;
+import org.eclipse.ui.internal.services.INestable;
+import org.eclipse.ui.internal.services.IServiceLocatorCreator;
+import org.eclipse.ui.internal.util.Util;
+import org.eclipse.ui.part.MultiPageEditorPart;
+import org.eclipse.ui.part.MultiPageEditorSite;
+import org.eclipse.ui.part.MultiPageSelectionProvider;
+import org.eclipse.ui.part.PageSwitcher;
+import org.eclipse.ui.part.ViewPart;
+import org.eclipse.ui.services.IDisposable;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * A multi-page editor is an editor with multiple pages, each of which may
+ * contain an editor or an arbitrary SWT control.
+ * <p>
+ * Subclasses must implement the following methods:
+ * <ul>
+ * <li><code>createPages</code> - to create the required pages by calling one
+ * of the <code>addPage</code> methods</li>
+ * <li><code>IEditorPart.doSave</code> - to save contents of editor</li>
+ * <li><code>IEditorPart.doSaveAs</code> - to save contents of editor</li>
+ * <li><code>IEditorPart.isSaveAsAllowed</code> - to enable Save As</li>
+ * <li><code>IEditorPart.gotoMarker</code> - to scroll to a marker</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Multi-page editors have a single action bar contributor, which manages
+ * contributions for all the pages. The contributor must be a subclass of
+ * <code>AbstractMultiPageEditorActionBarContributor</code>. Note that since
+ * any nested editors are created directly in code by callers of
+ * <code>addPage(IEditorPart,IEditorInput)</code>, nested editors do not have
+ * their own contributors.
+ * </p>
+ * 
+ * @see org.eclipse.ui.part.MultiPageEditorActionBarContributor
+ * 
+ * NOTE: this class was originally copied from MultiPageEditorPart and adapter to work as a ViewPart.
+ */
+@SuppressWarnings({"restriction","deprecation","unchecked","rawtypes"})
+public abstract class TabbedPropertyPage extends ViewPart {
+
+    /**
+     * Subclasses that override {@link #createPageContainer(Composite)} can use
+     * this constant to get a site for the container that can be active while
+     * the current page is deactivated.
+     * 
+     * @since 3.4
+     * @see #activateSite()
+     * @see #deactivateSite(boolean, boolean)
+     * @see #getPageSite(int)
+     */
+    protected static final int PAGE_CONTAINER_SITE = 65535;
+
+    /**
+     * Private tracing output.
+     */
+    private static final String TRACING_COMPONENT = "MPE"; //$NON-NLS-1$
+
+    /**
+     * The active service locator. This value may be <code>null</code> if
+     * there is no selected page, or if the selected page is a control with
+     * no site.
+     */
+    private INestable activeServiceLocator;
+
+    /**
+     * The container widget.
+     */
+    private CTabFolder container;
+    private Composite pageContainer;
+
+    /**
+     * List of nested editors. Element type: IEditorPart. Need to hang onto them
+     * here, in addition to using get/setData on the items, because dispose()
+     * needs to access them, but widgetry has already been disposed at that
+     * point.
+     */
+    private final ArrayList nestedEditors = new ArrayList(3);
+
+    private final List pageSites = new ArrayList(3);
+
+    private IServiceLocator pageContainerSite;
+
+    /**
+     * Creates and adds a new page containing the given control to this
+     * multi-page editor. The control may be <code>null</code>, allowing it
+     * to be created and set later using <code>setControl</code>.
+     * 
+     * @param control
+     *            the control, or <code>null</code>
+     * @return the index of the new page
+     * 
+     * @see MultiPageEditorPart#setControl(int, Control)
+     */
+    public int addPage(Control control) {
+        int index = getPageCount();
+        addPage(index, control);
+        return index;
+    }
+
+    /**
+     * @param control the control to add as a page
+     * @param text the page title text
+     * @param image the page title image
+     * @return
+     */
+    public int addPage(Control control, String text, Image image) {
+        int result = addPage(control);
+        setPageText(result, text);
+        setPageImage(result, image);
+        return result;
+    }
+
+    /**
+     * Creates and adds a new page containing the given control to this
+     * multi-page editor. The page is added at the given index. The control may
+     * be <code>null</code>, allowing it to be created and set later using
+     * <code>setControl</code>.
+     * 
+     * @param index
+     *            the index at which to add the page (0-based)
+     * @param control
+     *            the control, or <code>null</code>
+     * 
+     * @see MultiPageEditorPart#setControl(int, Control)
+     */
+    public void addPage(int index, Control control) {
+        createItem(index, control);
+    }
+
+    /**
+     * Creates an empty container. Creates a CTabFolder with no style bits set,
+     * and hooks a selection listener which calls <code>pageChange()</code>
+     * whenever the selected tab changes.
+     * 
+     * @param parent
+     *            The composite in which the container tab folder should be
+     *            created; must not be <code>null</code>.
+     * @return a new container
+     */
+    private CTabFolder createContainer(Composite parent) {
+        // use SWT.FLAT style so that an extra 1 pixel border is not reserved
+        // inside the folder
+        parent.setLayout(new FillLayout());
+        final CTabFolder newContainer = new CTabFolder(parent, getContainerStyle());
+        newContainer.addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                int newPageIndex = newContainer.indexOf((CTabItem) e.item);
+                pageChange(newPageIndex);
+            }
+        });
+        return newContainer;
+    }
+
+    /**
+     * Override this to customize the style given to the container
+     * {@link CTabFolder} instance created by
+     * {@link #createContainer(Composite)}. Default value is {@value SWT#BOTTOM}
+     * | {@value SWT#FLAT}.
+     * 
+     * @return swt style mask for {@link CTabFolder}
+     */
+    protected int getContainerStyle() {
+        return SWT.BOTTOM | SWT.FLAT;
+    }
+
+    /**
+     * Creates a tab item at the given index and places the given control in the
+     * new item. The item is a CTabItem with no style bits set.
+     * 
+     * @param index
+     *            the index at which to add the control
+     * @param control
+     *            is the control to be placed in an item
+     * @return a new item
+     */
+    private CTabItem createItem(int index, Control control) {
+        CTabItem item = new CTabItem(getTabFolder(), SWT.NONE, index);
+        item.setControl(control);
+        return item;
+    }
+
+    /**
+     * Creates the pages of this multi-page editor.
+     * <p>
+     * Subclasses must implement this method.
+     * </p>
+     */
+    protected abstract void createPages();
+
+    /**
+     * The <code>MultiPageEditor</code> implementation of this
+     * <code>IWorkbenchPart</code> method creates the control for the
+     * multi-page editor by calling <code>createContainer</code>, then
+     * <code>createPages</code>. Subclasses should implement
+     * <code>createPages</code> rather than overriding this method.
+     * 
+     * @param parent
+     *            The parent in which the editor should be created; must not be
+     *            <code>null</code>.
+     */
+    @Override
+    public final void createPartControl(Composite parent) {
+        this.pageContainer = createPageContainer(parent);
+        this.container = createContainer(pageContainer);
+        createPages();
+        // set the active page (page 0 by default), unless it has already been
+        // done
+        if (getActivePage() == -1) {
+            setActivePage(0);
+            IViewSite site = getViewSite();
+            if (site!=null) {
+                final IServiceLocator serviceLocator = site;
+                if (serviceLocator instanceof INestable) {
+                    activeServiceLocator = (INestable) serviceLocator;
+                    activeServiceLocator.activate();
+                }
+            }
+        }
+        initializePageSwitching();
+    }
+
+    /**
+     * Initialize the MultiPageEditorPart to use the page switching command.
+     * Clients can override this method with an empty body if they wish to
+     * opt-out.
+     * 
+     * @since 3.4
+     */
+    protected void initializePageSwitching() {
+        new PageSwitcher(getSite().getPart()) {
+            @Override
+            public Object[] getPages() {
+                int pageCount = getPageCount();
+                Object[] result = new Object[pageCount];
+                for (int i = 0; i < pageCount; i++) {
+                    result[i] = new Integer(i);
+                }
+                return result;
+            }
+
+            @Override
+            public String getName(Object page) {
+                return getPageText(((Integer) page).intValue());
+            }
+
+            @Override
+            public ImageDescriptor getImageDescriptor(Object page) {
+                Image image = getPageImage(((Integer) page).intValue());
+                if (image == null)
+                    return null;
+
+                return ImageDescriptor.createFromImage(image);
+            }
+
+            @Override
+            public void activatePage(Object page) {
+                setActivePage(((Integer) page).intValue());
+            }
+
+            @Override
+            public int getCurrentPageIndex() {
+                return getActivePage();
+            }
+        };
+    }
+
+    /**
+     * Creates the parent control for the container returned by
+     * {@link #getContainer() }.
+     * 
+     * <p>
+     * Subclasses may extend and must call super implementation first.
+     * </p>
+     * 
+     * @param parent
+     *            the parent for all of the editors contents.
+     * @return the parent for this editor's container. Must not be
+     *         <code>null</code>.
+     * 
+     * @since 3.2
+     */
+    protected Composite createPageContainer(Composite parent) {
+        return parent;
+    }
+
+    public Composite getPageContainer() {
+        return pageContainer;
+    }
+
+    /**
+     * Creates the site for the given nested editor. The
+     * <code>MultiPageEditorPart</code> implementation of this method creates
+     * an instance of <code>MultiPageEditorSite</code>. Subclasses may
+     * reimplement to create more specialized sites.
+     * 
+     * @param editor
+     *            the nested editor
+     * @return the editor site
+     */
+    protected IViewSite createSite(IViewPart editor) {
+        return new TabbedPropertyPageViewSite(this, editor);
+    }
+
+    /**
+     * The <code>MultiPageEditorPart</code> implementation of this
+     * <code>IWorkbenchPart</code> method disposes all nested editors.
+     * Subclasses may extend.
+     */
+    @Override
+    public void dispose() {
+        for (int i = 0; i < nestedEditors.size(); ++i) {
+            IEditorPart editor = (IEditorPart) nestedEditors.get(i);
+            disposePart(editor);
+        }
+        nestedEditors.clear();
+        if (pageContainerSite instanceof IDisposable) {
+            ((IDisposable) pageContainerSite).dispose();
+            pageContainerSite = null;
+        }
+        for (int i = 0; i < pageSites.size(); i++) {
+            IServiceLocator sl = (IServiceLocator) pageSites.get(i);
+            if (sl instanceof IDisposable) {
+                ((IDisposable) sl).dispose();
+            }
+        }
+        pageSites.clear();
+    }
+
+    /**
+     * Returns the active nested editor if there is one.
+     * <p>
+     * Subclasses should not override this method
+     * </p>
+     * 
+     * @return the active nested editor, or <code>null</code> if none
+     */
+    protected IEditorPart getActiveEditor() {
+        int index = getActivePage();
+        if (index != -1) {
+            return getEditor(index);
+        }
+        return null;
+    }
+
+    /**
+     * Returns the index of the currently active page, or -1 if there is no
+     * active page.
+     * <p>
+     * Subclasses should not override this method
+     * </p>
+     * 
+     * @return the index of the active page, or -1 if there is no active page
+     */
+    protected int getActivePage() {
+        CTabFolder tabFolder = getTabFolder();
+        if (tabFolder != null && !tabFolder.isDisposed()) {
+            return tabFolder.getSelectionIndex();
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the composite control containing this multi-page editor's pages.
+     * This should be used as the parent when creating controls for the
+     * individual pages. That is, when calling <code>addPage(Control)</code>,
+     * the passed control should be a child of this container.
+     * <p>
+     * Warning: Clients should not assume that the container is any particular
+     * subclass of Composite. The actual class used may change in order to
+     * improve the look and feel of multi-page editors. Any code making
+     * assumptions on the particular subclass would thus be broken.
+     * </p>
+     * <p>
+     * Subclasses should not override this method
+     * </p>
+     * 
+     * @return the composite, or <code>null</code> if
+     *         <code>createPartControl</code> has not been called yet
+     */
+    protected Composite getContainer() {
+        return container;
+    }
+
+    /**
+     * Returns the control for the given page index, or <code>null</code> if
+     * no control has been set for the page. The page index must be valid.
+     * <p>
+     * Subclasses should not override this method
+     * </p>
+     * 
+     * @param pageIndex
+     *            the index of the page
+     * @return the control for the specified page, or <code>null</code> if
+     *         none has been set
+     */
+    protected Control getControl(int pageIndex) {
+        return getItem(pageIndex).getControl();
+    }
+
+    /**
+     * Returns the editor for the given page index. The page index must be
+     * valid.
+     * 
+     * @param pageIndex
+     *            the index of the page
+     * @return the editor for the specified page, or <code>null</code> if the
+     *         specified page was not created with
+     *         <code>addPage(IEditorPart,IEditorInput)</code>
+     */
+    protected IEditorPart getEditor(int pageIndex) {
+        Item item = getItem(pageIndex);
+        if (item != null) {
+            Object data = item.getData();
+            if (data instanceof IEditorPart) {
+                return (IEditorPart) data;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns the service locator for the given page index. This method can be
+     * used to create service locators for pages that are just controls. The
+     * page index must be valid.
+     * <p>
+     * This will return the editor site service locator for an editor, and
+     * create one for a page that is just a control.
+     * </p>
+     * 
+     * @param pageIndex
+     *            the index of the page
+     * @return the editor for the specified page, or <code>null</code> if the
+     *         specified page was not created with
+     *         <code>addPage(IEditorPart,IEditorInput)</code>
+     * @since 3.4
+     */
+    protected final IServiceLocator getPageSite(int pageIndex) {
+        if (pageIndex == PAGE_CONTAINER_SITE) {
+            return getPageContainerSite();
+        }
+
+        Item item = getItem(pageIndex);
+        if (item != null) {
+            Object data = item.getData();
+            if (data instanceof IEditorPart) {
+                return ((IEditorPart) data).getSite();
+            } else if (data instanceof IServiceLocator) {
+                return (IServiceLocator) data;
+            } else if (data == null) {
+                IServiceLocatorCreator slc = (IServiceLocatorCreator) getSite()
+                .getService(IServiceLocatorCreator.class);
+                IServiceLocator sl = slc.createServiceLocator(getSite(), null, new IDisposable() {
+                    @Override
+                    public void dispose() {
+                        // TODO Auto-generated method stub
+                    }
+                });
+                item.setData(sl);
+                pageSites.add(sl);
+                return sl;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @return A site that can be used with a header.
+     * @since 3.4
+     * @see #createPageContainer(Composite)
+     * @see #PAGE_CONTAINER_SITE
+     * @see #getPageSite(int)
+     */
+    private IServiceLocator getPageContainerSite() {
+        if (pageContainerSite == null) {
+            IServiceLocatorCreator slc = (IServiceLocatorCreator) getSite()
+            .getService(IServiceLocatorCreator.class);
+            pageContainerSite = slc.createServiceLocator(getSite(), null, new IDisposable() {
+                @Override
+                public void dispose() {
+                    // TODO Auto-generated method stub
+                }
+            });
+        }
+        return pageContainerSite;
+    }
+
+    /**
+     * Returns the tab item for the given page index (page index is 0-based).
+     * The page index must be valid.
+     * 
+     * @param pageIndex
+     *            the index of the page
+     * @return the tab item for the given page index
+     */
+    private CTabItem getItem(int pageIndex) {
+        return getTabFolder().getItem(pageIndex);
+    }
+
+    /**
+     * Returns the number of pages in this multi-page editor.
+     * 
+     * @return the number of pages
+     */
+    protected int getPageCount() {
+        CTabFolder folder = getTabFolder();
+        // May not have been created yet, or may have been disposed.
+        if (folder != null && !folder.isDisposed()) {
+            return folder.getItemCount();
+        }
+        return 0;
+    }
+
+    /**
+     * Returns the image for the page with the given index, or <code>null</code>
+     * if no image has been set for the page. The page index must be valid.
+     * 
+     * @param pageIndex
+     *            the index of the page
+     * @return the image, or <code>null</code> if none
+     */
+    protected Image getPageImage(int pageIndex) {
+        return getItem(pageIndex).getImage();
+    }
+
+    /**
+     * Returns the text label for the page with the given index. Returns the
+     * empty string if no text label has been set for the page. The page index
+     * must be valid.
+     * 
+     * @param pageIndex
+     *            the index of the page
+     * @return the text label for the page
+     */
+    protected String getPageText(int pageIndex) {
+        return getItem(pageIndex).getText();
+    }
+
+    /**
+     * Returns the tab folder containing this multi-page editor's pages.
+     * 
+     * @return the tab folder, or <code>null</code> if
+     *         <code>createPartControl</code> has not been called yet
+     */
+    protected CTabFolder getTabFolder() {
+        return container;
+    }
+
+    /**
+     * Handles a property change notification from a nested editor. The default
+     * implementation simply forwards the change to listeners on this multi-page
+     * editor by calling <code>firePropertyChange</code> with the same
+     * property id. For example, if the dirty state of a nested editor changes
+     * (property id <code>IEditorPart.PROP_DIRTY</code>), this method handles
+     * it by firing a property change event for
+     * <code>IEditorPart.PROP_DIRTY</code> to property listeners on this
+     * multi-page editor.
+     * <p>
+     * Subclasses may extend or reimplement this method.
+     * </p>
+     * 
+     * @param propertyId
+     *            the id of the property that changed
+     */
+    protected void handlePropertyChange(int propertyId) {
+        firePropertyChange(propertyId);
+    }
+
+    /**
+     * The <code>MultiPageEditorPart</code> implementation of this
+     * <code>IEditorPart</code> method sets its site to the given site, its
+     * input to the given input, and the site's selection provider to a
+     * <code>MultiPageSelectionProvider</code>. Subclasses may extend this
+     * method.
+     * 
+     * @param site
+     *            The site for which this part is being created; must not be
+     *            <code>null</code>.
+     * @param input
+     *            The input on which this editor should be created; must not be
+     *            <code>null</code>.
+     * @throws PartInitException
+     *             If the initialization of the part fails -- currently never.
+     */
+    @Override
+    public void init(IViewSite site, IMemento memento)
+    throws PartInitException {
+        setSite(site);
+        site.setSelectionProvider(new TabbedPageSelectionProvider(this));
+    }
+
+    /**
+     * Notifies this multi-page editor that the page with the given id has been
+     * activated. This method is called when the user selects a different tab.
+     * <p>
+     * The <code>MultiPageEditorPart</code> implementation of this method sets
+     * focus to the new page, and notifies the action bar contributor (if there
+     * is one). This checks whether the action bar contributor is an instance of
+     * <code>MultiPageEditorActionBarContributor</code>, and, if so, calls
+     * <code>setActivePage</code> with the active nested editor. This also
+     * fires a selection change event if required.
+     * </p>
+     * <p>
+     * Subclasses may extend this method.
+     * </p>
+     * 
+     * @param newPageIndex
+     *            the index of the activated page
+     */
+    protected void pageChange(int newPageIndex) {
+        deactivateSite(false, false);
+
+        IPartService partService = (IPartService) getSite().getService(
+                IPartService.class);
+        if (partService != null && partService.getActivePart() == this) {
+            setFocus(newPageIndex);
+        }
+
+        IEditorPart activeEditor = getEditor(newPageIndex);
+
+//        IEditorActionBarContributor contributor = getViewSite()
+//                .getActionBarContributor();
+//        if (contributor != null
+//                && contributor instanceof MultiPageEditorActionBarContributor) {
+//            ((MultiPageEditorActionBarContributor) contributor)
+//                    .setActivePage(activeEditor);
+//        }
+
+        if (activeEditor != null) {
+            ISelectionProvider selectionProvider = activeEditor.getSite()
+            .getSelectionProvider();
+            if (selectionProvider != null) {
+                ISelectionProvider outerProvider = getSite()
+                .getSelectionProvider();
+                if (outerProvider instanceof MultiPageSelectionProvider) {
+                    SelectionChangedEvent event = new SelectionChangedEvent(
+                            selectionProvider, selectionProvider.getSelection());
+
+                    MultiPageSelectionProvider provider = (MultiPageSelectionProvider) outerProvider;
+                    provider.fireSelectionChanged(event);
+                    provider.firePostSelectionChanged(event);
+                } else {
+                    if (Policy.DEBUG_MPE) {
+                        Tracing.printTrace(TRACING_COMPONENT,
+                                "MultiPageEditorPart " + getTitle() //$NON-NLS-1$
+                                + " did not propogate selection for " //$NON-NLS-1$
+                                + activeEditor.getTitle());
+                    }
+                }
+            }
+        }
+
+        activateSite();
+    }
+
+    /**
+     * This method can be used by implementors of
+     * {@link MultiPageEditorPart#createPageContainer(Composite)} to deactivate
+     * the active inner editor services while their header has focus. A
+     * deactivateSite() must have a matching call to activateSite() when
+     * appropriate.
+     * <p>
+     * An new inner editor will have its site activated on a
+     * {@link MultiPageEditorPart#pageChange(int)}.
+     * </p>
+     * <p>
+     * <b>Note:</b> This API is evolving in 3.4 and this might not be its final
+     * form.
+     * </p>
+     * 
+     * @param immediate
+     *            immediately deactivate the legacy keybinding service
+     * @param containerSiteActive
+     *            Leave the page container site active.
+     * @since 3.4
+     * @see #activateSite()
+     * @see #createPageContainer(Composite)
+     * @see #getPageSite(int)
+     * @see #PAGE_CONTAINER_SITE
+     */
+    protected final void deactivateSite(boolean immediate,
+            boolean containerSiteActive) {
+        // Deactivate the nested services from the last active service locator.
+        if (activeServiceLocator != null) {
+            activeServiceLocator.deactivate();
+            activeServiceLocator = null;
+        }
+
+        final int pageIndex = getActivePage();
+        final IKeyBindingService service = getSite().getKeyBindingService();
+        if (pageIndex < 0 || pageIndex >= getPageCount() || immediate) {
+            // There is no selected page, so deactivate the active service.
+            if (service instanceof INestableKeyBindingService) {
+                final INestableKeyBindingService nestableService = (INestableKeyBindingService) service;
+                nestableService.activateKeyBindingService(null);
+            } else {
+                WorkbenchPlugin
+                .log("MultiPageEditorPart.setFocus()   Parent key binding service was not an instance of INestableKeyBindingService.  It was an instance of " + service.getClass().getName() + " instead."); //$NON-NLS-1$ //$NON-NLS-2$
+            }
+        }
+
+        if (containerSiteActive) {
+            IServiceLocator containerSite = getPageContainerSite();
+            if (containerSite instanceof INestable) {
+                activeServiceLocator = (INestable) containerSite;
+                activeServiceLocator.activate();
+            }
+        }
+    }
+
+    /**
+     * This method can be used by implementors of
+     * {@link #createPageContainer(Composite)} to activate the active inner
+     * editor services when their header loses focus.
+     * <p>
+     * An new inner editor will have its site activated on a
+     * {@link #pageChange(int)}.
+     * </p>
+     * <p>
+     * <b>Note:</b> This API is evolving in 3.4 and this might not be its final
+     * form.
+     * </p>
+     * 
+     * @since 3.4
+     * @see #deactivateSite(boolean,boolean)
+     * @see #createPageContainer(Composite)
+     * @see #getPageSite(int)
+     */
+    protected final void activateSite() {
+        if (activeServiceLocator != null) {
+            activeServiceLocator.deactivate();
+            activeServiceLocator = null;
+        }
+
+        final IKeyBindingService service = getSite().getKeyBindingService();
+        final int pageIndex = getActivePage();
+        final IEditorPart editor = getEditor(pageIndex);
+
+        if (editor != null) {
+            // active the service for this inner editor
+            if (service instanceof INestableKeyBindingService) {
+                final INestableKeyBindingService nestableService = (INestableKeyBindingService) service;
+                nestableService.activateKeyBindingService(editor
+                        .getEditorSite());
+
+            } else {
+                WorkbenchPlugin
+                .log("MultiPageEditorPart.setFocus()   Parent key binding service was not an instance of INestableKeyBindingService.  It was an instance of " + service.getClass().getName() + " instead."); //$NON-NLS-1$ //$NON-NLS-2$
+            }
+            // Activate the services for the new service locator.
+            final IServiceLocator serviceLocator = editor.getEditorSite();
+            if (serviceLocator instanceof INestable) {
+                activeServiceLocator = (INestable) serviceLocator;
+                activeServiceLocator.activate();
+            }
+
+        } else {
+            Item item = getItem(pageIndex);
+
+            // There is no selected editor, so deactivate the active service.
+            if (service instanceof INestableKeyBindingService) {
+                final INestableKeyBindingService nestableService = (INestableKeyBindingService) service;
+                nestableService.activateKeyBindingService(null);
+            } else {
+                WorkbenchPlugin
+                .log("MultiPageEditorPart.setFocus()   Parent key binding service was not an instance of INestableKeyBindingService.  It was an instance of " + service.getClass().getName() + " instead."); //$NON-NLS-1$ //$NON-NLS-2$
+            }
+
+            if (item.getData() instanceof INestable) {
+                activeServiceLocator = (INestable) item.getData();
+                activeServiceLocator.activate();
+            }
+        }
+    }
+
+    /**
+     * Disposes the given part and its site.
+     * 
+     * @param part
+     *            The part to dispose; must not be <code>null</code>.
+     */
+    private void disposePart(final IWorkbenchPart part) {
+        SafeRunner.run(new ISafeRunnable() {
+            public void run() {
+                IWorkbenchPartSite partSite = part.getSite();
+                part.dispose();
+                if (partSite instanceof MultiPageEditorSite) {
+                    ((MultiPageEditorSite) partSite).dispose();
+                }
+            }
+
+            public void handleException(Throwable e) {
+                // Exception has already being logged by Core. Do nothing.
+            }
+        });
+    }
+
+    /**
+     * Removes the page with the given index from this multi-page editor. The
+     * controls for the page are disposed of; if the page has an editor, it is
+     * disposed of too. The page index must be valid.
+     * 
+     * @param pageIndex
+     *            the index of the page
+     * @see MultiPageEditorPart#addPage(Control)
+     * @see MultiPageEditorPart#addPage(IEditorPart, IEditorInput)
+     */
+    public void removePage(int pageIndex) {
+        Assert.isTrue(pageIndex >= 0 && pageIndex < getPageCount());
+        // get editor (if any) before disposing item
+        IEditorPart editor = getEditor(pageIndex);
+
+        // get control for the item if it's not an editor
+        CTabItem item = getItem(pageIndex);
+        IServiceLocator pageLocator = null;
+        if (item.getData() instanceof IServiceLocator) {
+            pageLocator = (IServiceLocator) item.getData();
+        }
+        Control pageControl = item.getControl();
+
+        // dispose item before disposing editor, in case there's an exception
+        // in editor's dispose
+        item.dispose();
+
+        if (pageControl != null) {
+            pageControl.dispose();
+        }
+
+        // dispose editor (if any)
+        if (editor != null) {
+            nestedEditors.remove(editor);
+            disposePart(editor);
+        }
+        if (pageLocator != null) {
+            pageSites.remove(pageLocator);
+            if (pageLocator instanceof IDisposable) {
+                ((IDisposable) pageLocator).dispose();
+            }
+        }
+    }
+
+    /**
+     * Sets the currently active page.
+     * 
+     * @param pageIndex
+     *            the index of the page to be activated; the index must be valid
+     */
+    protected void setActivePage(int pageIndex) {
+        Assert.isTrue(pageIndex >= 0 && pageIndex < getPageCount());
+        getTabFolder().setSelection(pageIndex);
+        pageChange(pageIndex);
+    }
+
+    /**
+     * Sets the control for the given page index. The page index must be valid.
+     * 
+     * @param pageIndex
+     *            the index of the page
+     * @param control
+     *            the control for the specified page, or <code>null</code> to
+     *            clear the control
+     */
+    protected void setControl(int pageIndex, Control control) {
+        getItem(pageIndex).setControl(control);
+    }
+
+    /**
+     * The <code>MultiPageEditor</code> implementation of this
+     * <code>IWorkbenchPart</code> method sets focus on the active nested
+     * editor, if there is one.
+     * <p>
+     * Subclasses may extend or reimplement.
+     * </p>
+     */
+    @Override
+    public void setFocus() {
+        setFocus(getActivePage());
+    }
+
+    /**
+     * Sets focus to the control for the given page. If the page has an editor,
+     * this calls its <code>setFocus()</code> method. Otherwise, this calls
+     * <code>setFocus</code> on the control for the page.
+     * 
+     * @param pageIndex
+     *            the index of the page
+     */
+    private void setFocus(int pageIndex) {
+        final IEditorPart editor = getEditor(pageIndex);
+        if (editor != null) {
+            editor.setFocus();
+
+        } else {
+            // Give the page's control focus.
+            final Control control = getControl(pageIndex);
+            if (control != null) {
+                control.setFocus();
+            }
+        }
+    }
+
+    /**
+     * Sets the image for the page with the given index, or <code>null</code>
+     * to clear the image for the page. The page index must be valid.
+     * 
+     * @param pageIndex
+     *            the index of the page
+     * @param image
+     *            the image, or <code>null</code>
+     */
+    protected void setPageImage(int pageIndex, Image image) {
+        getItem(pageIndex).setImage(image);
+    }
+
+    /**
+     * Sets the text label for the page with the given index. The page index
+     * must be valid. The text label must not be null.
+     * 
+     * @param pageIndex
+     *            the index of the page
+     * @param text
+     *            the text label
+     */
+    protected void setPageText(int pageIndex, String text) {
+        getItem(pageIndex).setText(text);
+    }
+
+    /**
+     * If there is an adapter registered against the subclass of
+     * MultiPageEditorPart return that. Otherwise, delegate to the internal
+     * editor.
+     * 
+     * @see org.eclipse.ui.part.WorkbenchPart#getAdapter(java.lang.Class)
+     */
+    @Override
+    public Object getAdapter(Class adapter) {
+        Object result = super.getAdapter(adapter);
+        // restrict delegating to the UI thread for bug 144851
+        if (result == null && Display.getCurrent()!=null) {
+            IEditorPart innerEditor = getActiveEditor();
+            // see bug 138823 - prevent some subclasses from causing
+            // an infinite loop
+            if (innerEditor != null && innerEditor != this) {
+                result = Util.getAdapter(innerEditor, adapter);
+            }
+        }
+        return result;
+    }
+
+//    /**
+//     * Find the editors contained in this multi-page editor
+//     * whose editor input match the provided input.
+//     * @param input the editor input
+//     * @return the editors contained in this multi-page editor
+//     * whose editor input match the provided input
+//     * @since 3.3
+//     */
+//    public final IEditorPart[] findEditors(IEditorInput input) {
+//        List result = new ArrayList();
+//        int count = getPageCount();
+//        for (int i = 0; i < count; i++) {
+//            IEditorPart editor = getEditor(i);
+//            if (editor != null
+//                    && editor.getEditorInput() != null
+//                    && editor.getEditorInput().equals(input)) {
+//                result.add(editor);
+//            }
+//        }
+//        return (IEditorPart[]) result.toArray(new IEditorPart[result.size()]);
+//    }
+//
+//    /**
+//     * Set the active page of this multi-page editor to the
+//     * page that contains the given editor part. This method has
+//     * no effect of the given editor part is not contained in this
+//     * multi-page editor.
+//     * @param editorPart the editor part
+//     * @since 3.3
+//     */
+//    public final void setActiveEditor(IEditorPart editorPart) {
+//        int count = getPageCount();
+//        for (int i = 0; i < count; i++) {
+//            IEditorPart editor = getEditor(i);
+//            if (editor == editorPart) {
+//                setActivePage(i);
+//                break;
+//            }
+//        }
+//    }
+
+//    private IViewPart part;
+//
+//    public IViewSite getSite() {
+//        return part.getViewSite();
+//    }
+//
+//    public IViewPart getPart() {
+//        return part;
+//    }
+//
+
+    @Override
+    public IViewSite getViewSite() {
+        if(part instanceof IViewPart) return ((IViewPart) part).getViewSite();
+        else return null;
+    }
+
+    @Override
+    public IWorkbenchPartSite getSite() {
+        return part.getSite();
+    };
+
+    IWorkbenchPart part;
+
+    public TabbedPropertyPage(IWorkbenchPart part) {
+        this.part = part;
+        // Given part may be null
+//        assert(part != null);
+//        setSite(part.getSite());
+    }
+
+}