1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.browsing.ui.swt;
\r
15 /*******************************************************************************
\r
16 * Copyright (c) 2000, 2008 IBM Corporation and others.
\r
17 * All rights reserved. This program and the accompanying materials
\r
18 * are made available under the terms of the Eclipse Public License v1.0
\r
19 * which accompanies this distribution, and is available at
\r
20 * http://www.eclipse.org/legal/epl-v10.html
\r
23 * IBM Corporation - initial API and implementation
\r
24 *******************************************************************************/
\r
26 import java.util.ArrayList;
\r
27 import java.util.List;
\r
29 import org.eclipse.core.commands.util.Tracing;
\r
30 import org.eclipse.core.runtime.Assert;
\r
31 import org.eclipse.core.runtime.ISafeRunnable;
\r
32 import org.eclipse.core.runtime.SafeRunner;
\r
33 import org.eclipse.jface.resource.ImageDescriptor;
\r
34 import org.eclipse.jface.viewers.ISelectionProvider;
\r
35 import org.eclipse.jface.viewers.SelectionChangedEvent;
\r
36 import org.eclipse.swt.SWT;
\r
37 import org.eclipse.swt.custom.CTabFolder;
\r
38 import org.eclipse.swt.custom.CTabItem;
\r
39 import org.eclipse.swt.events.SelectionAdapter;
\r
40 import org.eclipse.swt.events.SelectionEvent;
\r
41 import org.eclipse.swt.graphics.Image;
\r
42 import org.eclipse.swt.layout.FillLayout;
\r
43 import org.eclipse.swt.widgets.Composite;
\r
44 import org.eclipse.swt.widgets.Control;
\r
45 import org.eclipse.swt.widgets.Display;
\r
46 import org.eclipse.swt.widgets.Item;
\r
47 import org.eclipse.ui.IEditorInput;
\r
48 import org.eclipse.ui.IEditorPart;
\r
49 import org.eclipse.ui.IKeyBindingService;
\r
50 import org.eclipse.ui.IMemento;
\r
51 import org.eclipse.ui.INestableKeyBindingService;
\r
52 import org.eclipse.ui.IPartService;
\r
53 import org.eclipse.ui.IViewPart;
\r
54 import org.eclipse.ui.IViewSite;
\r
55 import org.eclipse.ui.IWorkbenchPart;
\r
56 import org.eclipse.ui.IWorkbenchPartSite;
\r
57 import org.eclipse.ui.PartInitException;
\r
58 import org.eclipse.ui.internal.WorkbenchPlugin;
\r
59 import org.eclipse.ui.internal.misc.Policy;
\r
60 import org.eclipse.ui.internal.services.INestable;
\r
61 import org.eclipse.ui.internal.services.IServiceLocatorCreator;
\r
62 import org.eclipse.ui.internal.util.Util;
\r
63 import org.eclipse.ui.part.MultiPageEditorPart;
\r
64 import org.eclipse.ui.part.MultiPageEditorSite;
\r
65 import org.eclipse.ui.part.MultiPageSelectionProvider;
\r
66 import org.eclipse.ui.part.PageSwitcher;
\r
67 import org.eclipse.ui.part.ViewPart;
\r
68 import org.eclipse.ui.services.IDisposable;
\r
69 import org.eclipse.ui.services.IServiceLocator;
\r
72 * A multi-page editor is an editor with multiple pages, each of which may
\r
73 * contain an editor or an arbitrary SWT control.
\r
75 * Subclasses must implement the following methods:
\r
77 * <li><code>createPages</code> - to create the required pages by calling one
\r
78 * of the <code>addPage</code> methods</li>
\r
79 * <li><code>IEditorPart.doSave</code> - to save contents of editor</li>
\r
80 * <li><code>IEditorPart.doSaveAs</code> - to save contents of editor</li>
\r
81 * <li><code>IEditorPart.isSaveAsAllowed</code> - to enable Save As</li>
\r
82 * <li><code>IEditorPart.gotoMarker</code> - to scroll to a marker</li>
\r
86 * Multi-page editors have a single action bar contributor, which manages
\r
87 * contributions for all the pages. The contributor must be a subclass of
\r
88 * <code>AbstractMultiPageEditorActionBarContributor</code>. Note that since
\r
89 * any nested editors are created directly in code by callers of
\r
90 * <code>addPage(IEditorPart,IEditorInput)</code>, nested editors do not have
\r
91 * their own contributors.
\r
94 * @see org.eclipse.ui.part.MultiPageEditorActionBarContributor
\r
96 * NOTE: this class was originally copied from MultiPageEditorPart and adapter to work as a ViewPart.
\r
98 @SuppressWarnings({"restriction","deprecation","unchecked","rawtypes"})
\r
99 public abstract class TabbedPropertyPage extends ViewPart {
\r
102 * Subclasses that override {@link #createPageContainer(Composite)} can use
\r
103 * this constant to get a site for the container that can be active while
\r
104 * the current page is deactivated.
\r
107 * @see #activateSite()
\r
108 * @see #deactivateSite(boolean, boolean)
\r
109 * @see #getPageSite(int)
\r
111 protected static final int PAGE_CONTAINER_SITE = 65535;
\r
114 * Private tracing output.
\r
116 private static final String TRACING_COMPONENT = "MPE"; //$NON-NLS-1$
\r
119 * The active service locator. This value may be <code>null</code> if
\r
120 * there is no selected page, or if the selected page is a control with
\r
123 private INestable activeServiceLocator;
\r
126 * The container widget.
\r
128 private CTabFolder container;
\r
129 private Composite pageContainer;
\r
132 * List of nested editors. Element type: IEditorPart. Need to hang onto them
\r
133 * here, in addition to using get/setData on the items, because dispose()
\r
134 * needs to access them, but widgetry has already been disposed at that
\r
137 private final ArrayList nestedEditors = new ArrayList(3);
\r
139 private final List pageSites = new ArrayList(3);
\r
141 private IServiceLocator pageContainerSite;
\r
144 * Creates and adds a new page containing the given control to this
\r
145 * multi-page editor. The control may be <code>null</code>, allowing it
\r
146 * to be created and set later using <code>setControl</code>.
\r
149 * the control, or <code>null</code>
\r
150 * @return the index of the new page
\r
152 * @see MultiPageEditorPart#setControl(int, Control)
\r
154 public int addPage(Control control) {
\r
155 int index = getPageCount();
\r
156 addPage(index, control);
\r
161 * @param control the control to add as a page
\r
162 * @param text the page title text
\r
163 * @param image the page title image
\r
166 public int addPage(Control control, String text, Image image) {
\r
167 int result = addPage(control);
\r
168 setPageText(result, text);
\r
169 setPageImage(result, image);
\r
174 * Creates and adds a new page containing the given control to this
\r
175 * multi-page editor. The page is added at the given index. The control may
\r
176 * be <code>null</code>, allowing it to be created and set later using
\r
177 * <code>setControl</code>.
\r
180 * the index at which to add the page (0-based)
\r
182 * the control, or <code>null</code>
\r
184 * @see MultiPageEditorPart#setControl(int, Control)
\r
186 public void addPage(int index, Control control) {
\r
187 createItem(index, control);
\r
191 * Creates an empty container. Creates a CTabFolder with no style bits set,
\r
192 * and hooks a selection listener which calls <code>pageChange()</code>
\r
193 * whenever the selected tab changes.
\r
196 * The composite in which the container tab folder should be
\r
197 * created; must not be <code>null</code>.
\r
198 * @return a new container
\r
200 private CTabFolder createContainer(Composite parent) {
\r
201 // use SWT.FLAT style so that an extra 1 pixel border is not reserved
\r
202 // inside the folder
\r
203 parent.setLayout(new FillLayout());
\r
204 final CTabFolder newContainer = new CTabFolder(parent, getContainerStyle());
\r
205 newContainer.addSelectionListener(new SelectionAdapter() {
\r
207 public void widgetSelected(SelectionEvent e) {
\r
208 int newPageIndex = newContainer.indexOf((CTabItem) e.item);
\r
209 pageChange(newPageIndex);
\r
212 return newContainer;
\r
216 * Override this to customize the style given to the container
\r
217 * {@link CTabFolder} instance created by
\r
218 * {@link #createContainer(Composite)}. Default value is {@value SWT#BOTTOM}
\r
219 * | {@value SWT#FLAT}.
\r
221 * @return swt style mask for {@link CTabFolder}
\r
223 protected int getContainerStyle() {
\r
224 return SWT.BOTTOM | SWT.FLAT;
\r
228 * Creates a tab item at the given index and places the given control in the
\r
229 * new item. The item is a CTabItem with no style bits set.
\r
232 * the index at which to add the control
\r
234 * is the control to be placed in an item
\r
235 * @return a new item
\r
237 private CTabItem createItem(int index, Control control) {
\r
238 CTabItem item = new CTabItem(getTabFolder(), SWT.NONE, index);
\r
239 item.setControl(control);
\r
244 * Creates the pages of this multi-page editor.
\r
246 * Subclasses must implement this method.
\r
249 protected abstract void createPages();
\r
252 * The <code>MultiPageEditor</code> implementation of this
\r
253 * <code>IWorkbenchPart</code> method creates the control for the
\r
254 * multi-page editor by calling <code>createContainer</code>, then
\r
255 * <code>createPages</code>. Subclasses should implement
\r
256 * <code>createPages</code> rather than overriding this method.
\r
259 * The parent in which the editor should be created; must not be
\r
260 * <code>null</code>.
\r
263 public final void createPartControl(Composite parent) {
\r
264 this.pageContainer = createPageContainer(parent);
\r
265 this.container = createContainer(pageContainer);
\r
267 // set the active page (page 0 by default), unless it has already been
\r
269 if (getActivePage() == -1) {
\r
271 IViewSite site = getViewSite();
\r
273 final IServiceLocator serviceLocator = site;
\r
274 if (serviceLocator instanceof INestable) {
\r
275 activeServiceLocator = (INestable) serviceLocator;
\r
276 activeServiceLocator.activate();
\r
280 initializePageSwitching();
\r
284 * Initialize the MultiPageEditorPart to use the page switching command.
\r
285 * Clients can override this method with an empty body if they wish to
\r
290 protected void initializePageSwitching() {
\r
291 new PageSwitcher(getSite().getPart()) {
\r
293 public Object[] getPages() {
\r
294 int pageCount = getPageCount();
\r
295 Object[] result = new Object[pageCount];
\r
296 for (int i = 0; i < pageCount; i++) {
\r
297 result[i] = new Integer(i);
\r
303 public String getName(Object page) {
\r
304 return getPageText(((Integer) page).intValue());
\r
308 public ImageDescriptor getImageDescriptor(Object page) {
\r
309 Image image = getPageImage(((Integer) page).intValue());
\r
313 return ImageDescriptor.createFromImage(image);
\r
317 public void activatePage(Object page) {
\r
318 setActivePage(((Integer) page).intValue());
\r
322 public int getCurrentPageIndex() {
\r
323 return getActivePage();
\r
329 * Creates the parent control for the container returned by
\r
330 * {@link #getContainer() }.
\r
333 * Subclasses may extend and must call super implementation first.
\r
337 * the parent for all of the editors contents.
\r
338 * @return the parent for this editor's container. Must not be
\r
339 * <code>null</code>.
\r
343 protected Composite createPageContainer(Composite parent) {
\r
347 public Composite getPageContainer() {
\r
348 return pageContainer;
\r
352 * Creates the site for the given nested editor. The
\r
353 * <code>MultiPageEditorPart</code> implementation of this method creates
\r
354 * an instance of <code>MultiPageEditorSite</code>. Subclasses may
\r
355 * reimplement to create more specialized sites.
\r
358 * the nested editor
\r
359 * @return the editor site
\r
361 protected IViewSite createSite(IViewPart editor) {
\r
362 return new TabbedPropertyPageViewSite(this, editor);
\r
366 * The <code>MultiPageEditorPart</code> implementation of this
\r
367 * <code>IWorkbenchPart</code> method disposes all nested editors.
\r
368 * Subclasses may extend.
\r
371 public void dispose() {
\r
372 for (int i = 0; i < nestedEditors.size(); ++i) {
\r
373 IEditorPart editor = (IEditorPart) nestedEditors.get(i);
\r
374 disposePart(editor);
\r
376 nestedEditors.clear();
\r
377 if (pageContainerSite instanceof IDisposable) {
\r
378 ((IDisposable) pageContainerSite).dispose();
\r
379 pageContainerSite = null;
\r
381 for (int i = 0; i < pageSites.size(); i++) {
\r
382 IServiceLocator sl = (IServiceLocator) pageSites.get(i);
\r
383 if (sl instanceof IDisposable) {
\r
384 ((IDisposable) sl).dispose();
\r
391 * Returns the active nested editor if there is one.
\r
393 * Subclasses should not override this method
\r
396 * @return the active nested editor, or <code>null</code> if none
\r
398 protected IEditorPart getActiveEditor() {
\r
399 int index = getActivePage();
\r
401 return getEditor(index);
\r
407 * Returns the index of the currently active page, or -1 if there is no
\r
410 * Subclasses should not override this method
\r
413 * @return the index of the active page, or -1 if there is no active page
\r
415 protected int getActivePage() {
\r
416 CTabFolder tabFolder = getTabFolder();
\r
417 if (tabFolder != null && !tabFolder.isDisposed()) {
\r
418 return tabFolder.getSelectionIndex();
\r
424 * Returns the composite control containing this multi-page editor's pages.
\r
425 * This should be used as the parent when creating controls for the
\r
426 * individual pages. That is, when calling <code>addPage(Control)</code>,
\r
427 * the passed control should be a child of this container.
\r
429 * Warning: Clients should not assume that the container is any particular
\r
430 * subclass of Composite. The actual class used may change in order to
\r
431 * improve the look and feel of multi-page editors. Any code making
\r
432 * assumptions on the particular subclass would thus be broken.
\r
435 * Subclasses should not override this method
\r
438 * @return the composite, or <code>null</code> if
\r
439 * <code>createPartControl</code> has not been called yet
\r
441 protected Composite getContainer() {
\r
446 * Returns the control for the given page index, or <code>null</code> if
\r
447 * no control has been set for the page. The page index must be valid.
\r
449 * Subclasses should not override this method
\r
453 * the index of the page
\r
454 * @return the control for the specified page, or <code>null</code> if
\r
455 * none has been set
\r
457 protected Control getControl(int pageIndex) {
\r
458 return getItem(pageIndex).getControl();
\r
462 * Returns the editor for the given page index. The page index must be
\r
466 * the index of the page
\r
467 * @return the editor for the specified page, or <code>null</code> if the
\r
468 * specified page was not created with
\r
469 * <code>addPage(IEditorPart,IEditorInput)</code>
\r
471 protected IEditorPart getEditor(int pageIndex) {
\r
472 Item item = getItem(pageIndex);
\r
473 if (item != null) {
\r
474 Object data = item.getData();
\r
475 if (data instanceof IEditorPart) {
\r
476 return (IEditorPart) data;
\r
483 * Returns the service locator for the given page index. This method can be
\r
484 * used to create service locators for pages that are just controls. The
\r
485 * page index must be valid.
\r
487 * This will return the editor site service locator for an editor, and
\r
488 * create one for a page that is just a control.
\r
492 * the index of the page
\r
493 * @return the editor for the specified page, or <code>null</code> if the
\r
494 * specified page was not created with
\r
495 * <code>addPage(IEditorPart,IEditorInput)</code>
\r
498 protected final IServiceLocator getPageSite(int pageIndex) {
\r
499 if (pageIndex == PAGE_CONTAINER_SITE) {
\r
500 return getPageContainerSite();
\r
503 Item item = getItem(pageIndex);
\r
504 if (item != null) {
\r
505 Object data = item.getData();
\r
506 if (data instanceof IEditorPart) {
\r
507 return ((IEditorPart) data).getSite();
\r
508 } else if (data instanceof IServiceLocator) {
\r
509 return (IServiceLocator) data;
\r
510 } else if (data == null) {
\r
511 IServiceLocatorCreator slc = (IServiceLocatorCreator) getSite()
\r
512 .getService(IServiceLocatorCreator.class);
\r
513 IServiceLocator sl = slc.createServiceLocator(getSite(), null, new IDisposable() {
\r
515 public void dispose() {
\r
516 // TODO Auto-generated method stub
\r
528 * @return A site that can be used with a header.
\r
530 * @see #createPageContainer(Composite)
\r
531 * @see #PAGE_CONTAINER_SITE
\r
532 * @see #getPageSite(int)
\r
534 private IServiceLocator getPageContainerSite() {
\r
535 if (pageContainerSite == null) {
\r
536 IServiceLocatorCreator slc = (IServiceLocatorCreator) getSite()
\r
537 .getService(IServiceLocatorCreator.class);
\r
538 pageContainerSite = slc.createServiceLocator(getSite(), null, new IDisposable() {
\r
540 public void dispose() {
\r
541 // TODO Auto-generated method stub
\r
545 return pageContainerSite;
\r
549 * Returns the tab item for the given page index (page index is 0-based).
\r
550 * The page index must be valid.
\r
553 * the index of the page
\r
554 * @return the tab item for the given page index
\r
556 private CTabItem getItem(int pageIndex) {
\r
557 return getTabFolder().getItem(pageIndex);
\r
561 * Returns the number of pages in this multi-page editor.
\r
563 * @return the number of pages
\r
565 protected int getPageCount() {
\r
566 CTabFolder folder = getTabFolder();
\r
567 // May not have been created yet, or may have been disposed.
\r
568 if (folder != null && !folder.isDisposed()) {
\r
569 return folder.getItemCount();
\r
575 * Returns the image for the page with the given index, or <code>null</code>
\r
576 * if no image has been set for the page. The page index must be valid.
\r
579 * the index of the page
\r
580 * @return the image, or <code>null</code> if none
\r
582 protected Image getPageImage(int pageIndex) {
\r
583 return getItem(pageIndex).getImage();
\r
587 * Returns the text label for the page with the given index. Returns the
\r
588 * empty string if no text label has been set for the page. The page index
\r
592 * the index of the page
\r
593 * @return the text label for the page
\r
595 protected String getPageText(int pageIndex) {
\r
596 return getItem(pageIndex).getText();
\r
600 * Returns the tab folder containing this multi-page editor's pages.
\r
602 * @return the tab folder, or <code>null</code> if
\r
603 * <code>createPartControl</code> has not been called yet
\r
605 protected CTabFolder getTabFolder() {
\r
610 * Handles a property change notification from a nested editor. The default
\r
611 * implementation simply forwards the change to listeners on this multi-page
\r
612 * editor by calling <code>firePropertyChange</code> with the same
\r
613 * property id. For example, if the dirty state of a nested editor changes
\r
614 * (property id <code>IEditorPart.PROP_DIRTY</code>), this method handles
\r
615 * it by firing a property change event for
\r
616 * <code>IEditorPart.PROP_DIRTY</code> to property listeners on this
\r
617 * multi-page editor.
\r
619 * Subclasses may extend or reimplement this method.
\r
622 * @param propertyId
\r
623 * the id of the property that changed
\r
625 protected void handlePropertyChange(int propertyId) {
\r
626 firePropertyChange(propertyId);
\r
630 * The <code>MultiPageEditorPart</code> implementation of this
\r
631 * <code>IEditorPart</code> method sets its site to the given site, its
\r
632 * input to the given input, and the site's selection provider to a
\r
633 * <code>MultiPageSelectionProvider</code>. Subclasses may extend this
\r
637 * The site for which this part is being created; must not be
\r
638 * <code>null</code>.
\r
640 * The input on which this editor should be created; must not be
\r
641 * <code>null</code>.
\r
642 * @throws PartInitException
\r
643 * If the initialization of the part fails -- currently never.
\r
646 public void init(IViewSite site, IMemento memento)
\r
647 throws PartInitException {
\r
649 site.setSelectionProvider(new TabbedPageSelectionProvider(this));
\r
653 * Notifies this multi-page editor that the page with the given id has been
\r
654 * activated. This method is called when the user selects a different tab.
\r
656 * The <code>MultiPageEditorPart</code> implementation of this method sets
\r
657 * focus to the new page, and notifies the action bar contributor (if there
\r
658 * is one). This checks whether the action bar contributor is an instance of
\r
659 * <code>MultiPageEditorActionBarContributor</code>, and, if so, calls
\r
660 * <code>setActivePage</code> with the active nested editor. This also
\r
661 * fires a selection change event if required.
\r
664 * Subclasses may extend this method.
\r
667 * @param newPageIndex
\r
668 * the index of the activated page
\r
670 protected void pageChange(int newPageIndex) {
\r
671 deactivateSite(false, false);
\r
673 IPartService partService = (IPartService) getSite().getService(
\r
674 IPartService.class);
\r
675 if (partService != null && partService.getActivePart() == this) {
\r
676 setFocus(newPageIndex);
\r
679 IEditorPart activeEditor = getEditor(newPageIndex);
\r
681 // IEditorActionBarContributor contributor = getViewSite()
\r
682 // .getActionBarContributor();
\r
683 // if (contributor != null
\r
684 // && contributor instanceof MultiPageEditorActionBarContributor) {
\r
685 // ((MultiPageEditorActionBarContributor) contributor)
\r
686 // .setActivePage(activeEditor);
\r
689 if (activeEditor != null) {
\r
690 ISelectionProvider selectionProvider = activeEditor.getSite()
\r
691 .getSelectionProvider();
\r
692 if (selectionProvider != null) {
\r
693 ISelectionProvider outerProvider = getSite()
\r
694 .getSelectionProvider();
\r
695 if (outerProvider instanceof MultiPageSelectionProvider) {
\r
696 SelectionChangedEvent event = new SelectionChangedEvent(
\r
697 selectionProvider, selectionProvider.getSelection());
\r
699 MultiPageSelectionProvider provider = (MultiPageSelectionProvider) outerProvider;
\r
700 provider.fireSelectionChanged(event);
\r
701 provider.firePostSelectionChanged(event);
\r
703 if (Policy.DEBUG_MPE) {
\r
704 Tracing.printTrace(TRACING_COMPONENT,
\r
705 "MultiPageEditorPart " + getTitle() //$NON-NLS-1$
\r
706 + " did not propogate selection for " //$NON-NLS-1$
\r
707 + activeEditor.getTitle());
\r
717 * This method can be used by implementors of
\r
718 * {@link MultiPageEditorPart#createPageContainer(Composite)} to deactivate
\r
719 * the active inner editor services while their header has focus. A
\r
720 * deactivateSite() must have a matching call to activateSite() when
\r
723 * An new inner editor will have its site activated on a
\r
724 * {@link MultiPageEditorPart#pageChange(int)}.
\r
727 * <b>Note:</b> This API is evolving in 3.4 and this might not be its final
\r
732 * immediately deactivate the legacy keybinding service
\r
733 * @param containerSiteActive
\r
734 * Leave the page container site active.
\r
736 * @see #activateSite()
\r
737 * @see #createPageContainer(Composite)
\r
738 * @see #getPageSite(int)
\r
739 * @see #PAGE_CONTAINER_SITE
\r
741 protected final void deactivateSite(boolean immediate,
\r
742 boolean containerSiteActive) {
\r
743 // Deactivate the nested services from the last active service locator.
\r
744 if (activeServiceLocator != null) {
\r
745 activeServiceLocator.deactivate();
\r
746 activeServiceLocator = null;
\r
749 final int pageIndex = getActivePage();
\r
750 final IKeyBindingService service = getSite().getKeyBindingService();
\r
751 if (pageIndex < 0 || pageIndex >= getPageCount() || immediate) {
\r
752 // There is no selected page, so deactivate the active service.
\r
753 if (service instanceof INestableKeyBindingService) {
\r
754 final INestableKeyBindingService nestableService = (INestableKeyBindingService) service;
\r
755 nestableService.activateKeyBindingService(null);
\r
758 .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
762 if (containerSiteActive) {
\r
763 IServiceLocator containerSite = getPageContainerSite();
\r
764 if (containerSite instanceof INestable) {
\r
765 activeServiceLocator = (INestable) containerSite;
\r
766 activeServiceLocator.activate();
\r
772 * This method can be used by implementors of
\r
773 * {@link #createPageContainer(Composite)} to activate the active inner
\r
774 * editor services when their header loses focus.
\r
776 * An new inner editor will have its site activated on a
\r
777 * {@link #pageChange(int)}.
\r
780 * <b>Note:</b> This API is evolving in 3.4 and this might not be its final
\r
785 * @see #deactivateSite(boolean,boolean)
\r
786 * @see #createPageContainer(Composite)
\r
787 * @see #getPageSite(int)
\r
789 protected final void activateSite() {
\r
790 if (activeServiceLocator != null) {
\r
791 activeServiceLocator.deactivate();
\r
792 activeServiceLocator = null;
\r
795 final IKeyBindingService service = getSite().getKeyBindingService();
\r
796 final int pageIndex = getActivePage();
\r
797 final IEditorPart editor = getEditor(pageIndex);
\r
799 if (editor != null) {
\r
800 // active the service for this inner editor
\r
801 if (service instanceof INestableKeyBindingService) {
\r
802 final INestableKeyBindingService nestableService = (INestableKeyBindingService) service;
\r
803 nestableService.activateKeyBindingService(editor
\r
808 .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
810 // Activate the services for the new service locator.
\r
811 final IServiceLocator serviceLocator = editor.getEditorSite();
\r
812 if (serviceLocator instanceof INestable) {
\r
813 activeServiceLocator = (INestable) serviceLocator;
\r
814 activeServiceLocator.activate();
\r
818 Item item = getItem(pageIndex);
\r
820 // There is no selected editor, so deactivate the active service.
\r
821 if (service instanceof INestableKeyBindingService) {
\r
822 final INestableKeyBindingService nestableService = (INestableKeyBindingService) service;
\r
823 nestableService.activateKeyBindingService(null);
\r
826 .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
829 if (item.getData() instanceof INestable) {
\r
830 activeServiceLocator = (INestable) item.getData();
\r
831 activeServiceLocator.activate();
\r
837 * Disposes the given part and its site.
\r
840 * The part to dispose; must not be <code>null</code>.
\r
842 private void disposePart(final IWorkbenchPart part) {
\r
843 SafeRunner.run(new ISafeRunnable() {
\r
844 public void run() {
\r
845 IWorkbenchPartSite partSite = part.getSite();
\r
847 if (partSite instanceof MultiPageEditorSite) {
\r
848 ((MultiPageEditorSite) partSite).dispose();
\r
852 public void handleException(Throwable e) {
\r
853 // Exception has already being logged by Core. Do nothing.
\r
859 * Removes the page with the given index from this multi-page editor. The
\r
860 * controls for the page are disposed of; if the page has an editor, it is
\r
861 * disposed of too. The page index must be valid.
\r
864 * the index of the page
\r
865 * @see MultiPageEditorPart#addPage(Control)
\r
866 * @see MultiPageEditorPart#addPage(IEditorPart, IEditorInput)
\r
868 public void removePage(int pageIndex) {
\r
869 Assert.isTrue(pageIndex >= 0 && pageIndex < getPageCount());
\r
870 // get editor (if any) before disposing item
\r
871 IEditorPart editor = getEditor(pageIndex);
\r
873 // get control for the item if it's not an editor
\r
874 CTabItem item = getItem(pageIndex);
\r
875 IServiceLocator pageLocator = null;
\r
876 if (item.getData() instanceof IServiceLocator) {
\r
877 pageLocator = (IServiceLocator) item.getData();
\r
879 Control pageControl = item.getControl();
\r
881 // dispose item before disposing editor, in case there's an exception
\r
882 // in editor's dispose
\r
885 if (pageControl != null) {
\r
886 pageControl.dispose();
\r
889 // dispose editor (if any)
\r
890 if (editor != null) {
\r
891 nestedEditors.remove(editor);
\r
892 disposePart(editor);
\r
894 if (pageLocator != null) {
\r
895 pageSites.remove(pageLocator);
\r
896 if (pageLocator instanceof IDisposable) {
\r
897 ((IDisposable) pageLocator).dispose();
\r
903 * Sets the currently active page.
\r
906 * the index of the page to be activated; the index must be valid
\r
908 protected void setActivePage(int pageIndex) {
\r
909 Assert.isTrue(pageIndex >= 0 && pageIndex < getPageCount());
\r
910 getTabFolder().setSelection(pageIndex);
\r
911 pageChange(pageIndex);
\r
915 * Sets the control for the given page index. The page index must be valid.
\r
918 * the index of the page
\r
920 * the control for the specified page, or <code>null</code> to
\r
921 * clear the control
\r
923 protected void setControl(int pageIndex, Control control) {
\r
924 getItem(pageIndex).setControl(control);
\r
928 * The <code>MultiPageEditor</code> implementation of this
\r
929 * <code>IWorkbenchPart</code> method sets focus on the active nested
\r
930 * editor, if there is one.
\r
932 * Subclasses may extend or reimplement.
\r
936 public void setFocus() {
\r
937 setFocus(getActivePage());
\r
941 * Sets focus to the control for the given page. If the page has an editor,
\r
942 * this calls its <code>setFocus()</code> method. Otherwise, this calls
\r
943 * <code>setFocus</code> on the control for the page.
\r
946 * the index of the page
\r
948 private void setFocus(int pageIndex) {
\r
949 final IEditorPart editor = getEditor(pageIndex);
\r
950 if (editor != null) {
\r
954 // Give the page's control focus.
\r
955 final Control control = getControl(pageIndex);
\r
956 if (control != null) {
\r
957 control.setFocus();
\r
963 * Sets the image for the page with the given index, or <code>null</code>
\r
964 * to clear the image for the page. The page index must be valid.
\r
967 * the index of the page
\r
969 * the image, or <code>null</code>
\r
971 protected void setPageImage(int pageIndex, Image image) {
\r
972 getItem(pageIndex).setImage(image);
\r
976 * Sets the text label for the page with the given index. The page index
\r
977 * must be valid. The text label must not be null.
\r
980 * the index of the page
\r
984 protected void setPageText(int pageIndex, String text) {
\r
985 getItem(pageIndex).setText(text);
\r
989 * If there is an adapter registered against the subclass of
\r
990 * MultiPageEditorPart return that. Otherwise, delegate to the internal
\r
993 * @see org.eclipse.ui.part.WorkbenchPart#getAdapter(java.lang.Class)
\r
996 public Object getAdapter(Class adapter) {
\r
997 Object result = super.getAdapter(adapter);
\r
998 // restrict delegating to the UI thread for bug 144851
\r
999 if (result == null && Display.getCurrent()!=null) {
\r
1000 IEditorPart innerEditor = getActiveEditor();
\r
1001 // see bug 138823 - prevent some subclasses from causing
\r
1002 // an infinite loop
\r
1003 if (innerEditor != null && innerEditor != this) {
\r
1004 result = Util.getAdapter(innerEditor, adapter);
\r
1011 // * Find the editors contained in this multi-page editor
\r
1012 // * whose editor input match the provided input.
\r
1013 // * @param input the editor input
\r
1014 // * @return the editors contained in this multi-page editor
\r
1015 // * whose editor input match the provided input
\r
1018 // public final IEditorPart[] findEditors(IEditorInput input) {
\r
1019 // List result = new ArrayList();
\r
1020 // int count = getPageCount();
\r
1021 // for (int i = 0; i < count; i++) {
\r
1022 // IEditorPart editor = getEditor(i);
\r
1023 // if (editor != null
\r
1024 // && editor.getEditorInput() != null
\r
1025 // && editor.getEditorInput().equals(input)) {
\r
1026 // result.add(editor);
\r
1029 // return (IEditorPart[]) result.toArray(new IEditorPart[result.size()]);
\r
1033 // * Set the active page of this multi-page editor to the
\r
1034 // * page that contains the given editor part. This method has
\r
1035 // * no effect of the given editor part is not contained in this
\r
1036 // * multi-page editor.
\r
1037 // * @param editorPart the editor part
\r
1040 // public final void setActiveEditor(IEditorPart editorPart) {
\r
1041 // int count = getPageCount();
\r
1042 // for (int i = 0; i < count; i++) {
\r
1043 // IEditorPart editor = getEditor(i);
\r
1044 // if (editor == editorPart) {
\r
1045 // setActivePage(i);
\r
1051 // private IViewPart part;
\r
1053 // public IViewSite getSite() {
\r
1054 // return part.getViewSite();
\r
1057 // public IViewPart getPart() {
\r
1063 public IViewSite getViewSite() {
\r
1064 if(part instanceof IViewPart) return ((IViewPart) part).getViewSite();
\r
1069 public IWorkbenchPartSite getSite() {
\r
1070 return part.getSite();
\r
1073 IWorkbenchPart part;
\r
1075 public TabbedPropertyPage(IWorkbenchPart part) {
\r
1077 // Given part may be null
\r
1078 // assert(part != null);
\r
1079 // setSite(part.getSite());
\r