--- /dev/null
+/*******************************************************************************\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