001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.part;
011:
012: import java.util.ArrayList;
013: import java.util.Iterator;
014: import java.util.List;
015:
016: import org.eclipse.core.commands.util.Tracing;
017: import org.eclipse.core.runtime.Assert;
018: import org.eclipse.core.runtime.ISafeRunnable;
019: import org.eclipse.core.runtime.SafeRunner;
020: import org.eclipse.jface.viewers.ISelectionProvider;
021: import org.eclipse.jface.viewers.SelectionChangedEvent;
022: import org.eclipse.swt.SWT;
023: import org.eclipse.swt.custom.CTabFolder;
024: import org.eclipse.swt.custom.CTabItem;
025: import org.eclipse.swt.events.SelectionAdapter;
026: import org.eclipse.swt.events.SelectionEvent;
027: import org.eclipse.swt.graphics.Image;
028: import org.eclipse.swt.layout.FillLayout;
029: import org.eclipse.swt.widgets.Composite;
030: import org.eclipse.swt.widgets.Control;
031: import org.eclipse.swt.widgets.Display;
032: import org.eclipse.swt.widgets.Item;
033: import org.eclipse.ui.IEditorActionBarContributor;
034: import org.eclipse.ui.IEditorInput;
035: import org.eclipse.ui.IEditorPart;
036: import org.eclipse.ui.IEditorSite;
037: import org.eclipse.ui.IKeyBindingService;
038: import org.eclipse.ui.INestableKeyBindingService;
039: import org.eclipse.ui.IPropertyListener;
040: import org.eclipse.ui.IWorkbenchPart;
041: import org.eclipse.ui.PartInitException;
042: import org.eclipse.ui.internal.WorkbenchPlugin;
043: import org.eclipse.ui.internal.misc.Policy;
044: import org.eclipse.ui.internal.services.INestable;
045: import org.eclipse.ui.internal.util.Util;
046: import org.eclipse.ui.services.IServiceLocator;
047:
048: /**
049: * A multi-page editor is an editor with multiple pages, each of which may
050: * contain an editor or an arbitrary SWT control.
051: * <p>
052: * Subclasses must implement the following methods:
053: * <ul>
054: * <li><code>createPages</code> - to create the required pages by calling one
055: * of the <code>addPage</code> methods</li>
056: * <li><code>IEditorPart.doSave</code> - to save contents of editor</li>
057: * <li><code>IEditorPart.doSaveAs</code> - to save contents of editor</li>
058: * <li><code>IEditorPart.isSaveAsAllowed</code> - to enable Save As</li>
059: * <li><code>IEditorPart.gotoMarker</code> - to scroll to a marker</li>
060: * </ul>
061: * </p>
062: * <p>
063: * Multi-page editors have a single action bar contributor, which manages
064: * contributions for all the pages. The contributor must be a subclass of
065: * <code>AbstractMultiPageEditorActionBarContributor</code>. Note that since
066: * any nested editors are created directly in code by callers of
067: * <code>addPage(IEditorPart,IEditorInput)</code>, nested editors do not have
068: * their own contributors.
069: * </p>
070: *
071: * @see org.eclipse.ui.part.MultiPageEditorActionBarContributor
072: */
073: public abstract class MultiPageEditorPart extends EditorPart {
074:
075: /**
076: *
077: */
078: private static final String TRACING_COMPONENT = "MPE"; //$NON-NLS-1$
079:
080: /**
081: * The active service locator. This value may be <code>null</code> if
082: * there is no selected page, or if the selected page is a control.
083: */
084: private INestable activeServiceLocator;
085:
086: /**
087: * The container widget.
088: */
089: private CTabFolder container;
090:
091: /**
092: * List of nested editors. Element type: IEditorPart. Need to hang onto them
093: * here, in addition to using get/setData on the items, because dispose()
094: * needs to access them, but widgetry has already been disposed at that
095: * point.
096: */
097: private ArrayList nestedEditors = new ArrayList(3);
098:
099: /**
100: * Creates an empty multi-page editor with no pages.
101: */
102: protected MultiPageEditorPart() {
103: super ();
104: }
105:
106: /**
107: * Creates and adds a new page containing the given control to this
108: * multi-page editor. The control may be <code>null</code>, allowing it
109: * to be created and set later using <code>setControl</code>.
110: *
111: * @param control
112: * the control, or <code>null</code>
113: * @return the index of the new page
114: *
115: * @see MultiPageEditorPart#setControl(int, Control)
116: */
117: public int addPage(Control control) {
118: int index = getPageCount();
119: addPage(index, control);
120: return index;
121: }
122:
123: /**
124: * Creates and adds a new page containing the given control to this
125: * multi-page editor. The page is added at the given index. The control may
126: * be <code>null</code>, allowing it to be created and set later using
127: * <code>setControl</code>.
128: *
129: * @param index
130: * the index at which to add the page (0-based)
131: * @param control
132: * the control, or <code>null</code>
133: *
134: * @see MultiPageEditorPart#setControl(int, Control)
135: */
136: public void addPage(int index, Control control) {
137: createItem(index, control);
138: }
139:
140: /**
141: * Creates and adds a new page containing the given editor to this
142: * multi-page editor. This also hooks a property change listener on the
143: * nested editor.
144: *
145: * @param editor
146: * the nested editor
147: * @param input
148: * the input for the nested editor
149: * @return the index of the new page
150: * @exception PartInitException
151: * if a new page could not be created
152: *
153: * @see MultiPageEditorPart#handlePropertyChange(int) the handler for
154: * property change events from the nested editor
155: */
156: public int addPage(IEditorPart editor, IEditorInput input)
157: throws PartInitException {
158: int index = getPageCount();
159: addPage(index, editor, input);
160: return index;
161: }
162:
163: /**
164: * Creates and adds a new page containing the given editor to this
165: * multi-page editor. The page is added at the given index. This also hooks
166: * a property change listener on the nested editor.
167: *
168: * @param index
169: * the index at which to add the page (0-based)
170: * @param editor
171: * the nested editor
172: * @param input
173: * the input for the nested editor
174: * @exception PartInitException
175: * if a new page could not be created
176: *
177: * @see MultiPageEditorPart#handlePropertyChange(int) the handler for
178: * property change events from the nested editor
179: */
180: public void addPage(int index, IEditorPart editor,
181: IEditorInput input) throws PartInitException {
182: IEditorSite site = createSite(editor);
183: // call init first so that if an exception is thrown, we have created no
184: // new widgets
185: editor.init(site, input);
186: Composite parent2 = new Composite(getContainer(),
187: getOrientation(editor));
188: parent2.setLayout(new FillLayout());
189: editor.createPartControl(parent2);
190: editor.addPropertyListener(new IPropertyListener() {
191: public void propertyChanged(Object source, int propertyId) {
192: MultiPageEditorPart.this
193: .handlePropertyChange(propertyId);
194: }
195: });
196: // create item for page only after createPartControl has succeeded
197: Item item = createItem(index, parent2);
198: // remember the editor, as both data on the item, and in the list of
199: // editors (see field comment)
200: item.setData(editor);
201: nestedEditors.add(editor);
202: }
203:
204: /**
205: * Get the orientation of the editor.
206: *
207: * @param editor
208: * @return int the orientation flag
209: * @see SWT#RIGHT_TO_LEFT
210: * @see SWT#LEFT_TO_RIGHT
211: * @see SWT#NONE
212: */
213: private int getOrientation(IEditorPart editor) {
214: if (editor instanceof IWorkbenchPartOrientation) {
215: return ((IWorkbenchPartOrientation) editor)
216: .getOrientation();
217: }
218: return getOrientation();
219: }
220:
221: /**
222: * Creates an empty container. Creates a CTabFolder with no style bits set,
223: * and hooks a selection listener which calls <code>pageChange()</code>
224: * whenever the selected tab changes.
225: *
226: * @param parent
227: * The composite in which the container tab folder should be
228: * created; must not be <code>null</code>.
229: * @return a new container
230: */
231: private CTabFolder createContainer(Composite parent) {
232: // use SWT.FLAT style so that an extra 1 pixel border is not reserved
233: // inside the folder
234: parent.setLayout(new FillLayout());
235: final CTabFolder newContainer = new CTabFolder(parent,
236: SWT.BOTTOM | SWT.FLAT);
237: newContainer.addSelectionListener(new SelectionAdapter() {
238: public void widgetSelected(SelectionEvent e) {
239: int newPageIndex = newContainer
240: .indexOf((CTabItem) e.item);
241: pageChange(newPageIndex);
242: }
243: });
244: return newContainer;
245: }
246:
247: /**
248: * Creates a tab item at the given index and places the given control in the
249: * new item. The item is a CTabItem with no style bits set.
250: *
251: * @param index
252: * the index at which to add the control
253: * @param control
254: * is the control to be placed in an item
255: * @return a new item
256: */
257: private CTabItem createItem(int index, Control control) {
258: CTabItem item = new CTabItem(getTabFolder(), SWT.NONE, index);
259: item.setControl(control);
260: return item;
261: }
262:
263: /**
264: * Creates the pages of this multi-page editor.
265: * <p>
266: * Subclasses must implement this method.
267: * </p>
268: */
269: protected abstract void createPages();
270:
271: /**
272: * The <code>MultiPageEditor</code> implementation of this
273: * <code>IWorkbenchPart</code> method creates the control for the
274: * multi-page editor by calling <code>createContainer</code>, then
275: * <code>createPages</code>. Subclasses should implement
276: * <code>createPages</code> rather than overriding this method.
277: *
278: * @param parent
279: * The parent in which the editor should be created; must not be
280: * <code>null</code>.
281: */
282: public final void createPartControl(Composite parent) {
283: Composite pageContainer = createPageContainer(parent);
284: this .container = createContainer(pageContainer);
285: createPages();
286: // set the active page (page 0 by default), unless it has already been
287: // done
288: if (getActivePage() == -1) {
289: setActivePage(0);
290: IEditorPart part = getEditor(0);
291: if (part != null) {
292: final IServiceLocator serviceLocator = part
293: .getEditorSite();
294: if (serviceLocator instanceof INestable) {
295: activeServiceLocator = (INestable) serviceLocator;
296: activeServiceLocator.activate();
297: }
298: }
299: }
300: }
301:
302: /**
303: * Creates the parent control for the container returned by
304: * {@link #getContainer() }.
305: *
306: * <p>
307: * Subclasses may extend and must call super implementation first.
308: * </p>
309: *
310: * @param parent
311: * the parent for all of the editors contents.
312: * @return the parent for this editor's container. Must not be
313: * <code>null</code>.
314: *
315: * @since 3.2
316: */
317: protected Composite createPageContainer(Composite parent) {
318: return parent;
319: }
320:
321: /**
322: * Creates the site for the given nested editor. The
323: * <code>MultiPageEditorPart</code> implementation of this method creates
324: * an instance of <code>MultiPageEditorSite</code>. Subclasses may
325: * reimplement to create more specialized sites.
326: *
327: * @param editor
328: * the nested editor
329: * @return the editor site
330: */
331: protected IEditorSite createSite(IEditorPart editor) {
332: return new MultiPageEditorSite(this , editor);
333: }
334:
335: /**
336: * The <code>MultiPageEditorPart</code> implementation of this
337: * <code>IWorkbenchPart</code> method disposes all nested editors.
338: * Subclasses may extend.
339: */
340: public void dispose() {
341: for (int i = 0; i < nestedEditors.size(); ++i) {
342: IEditorPart editor = (IEditorPart) nestedEditors.get(i);
343: disposePart(editor);
344: }
345: nestedEditors.clear();
346: }
347:
348: /**
349: * Returns the active nested editor if there is one.
350: * <p>
351: * Subclasses should not override this method
352: * </p>
353: *
354: * @return the active nested editor, or <code>null</code> if none
355: */
356: protected IEditorPart getActiveEditor() {
357: int index = getActivePage();
358: if (index != -1) {
359: return getEditor(index);
360: }
361: return null;
362: }
363:
364: /**
365: * Returns the index of the currently active page, or -1 if there is no
366: * active page.
367: * <p>
368: * Subclasses should not override this method
369: * </p>
370: *
371: * @return the index of the active page, or -1 if there is no active page
372: */
373: protected int getActivePage() {
374: CTabFolder tabFolder = getTabFolder();
375: if (tabFolder != null && !tabFolder.isDisposed()) {
376: return tabFolder.getSelectionIndex();
377: }
378: return -1;
379: }
380:
381: /**
382: * Returns the composite control containing this multi-page editor's pages.
383: * This should be used as the parent when creating controls for the
384: * individual pages. That is, when calling <code>addPage(Control)</code>,
385: * the passed control should be a child of this container.
386: * <p>
387: * Warning: Clients should not assume that the container is any particular
388: * subclass of Composite. The actual class used may change in order to
389: * improve the look and feel of multi-page editors. Any code making
390: * assumptions on the particular subclass would thus be broken.
391: * </p>
392: * <p>
393: * Subclasses should not override this method
394: * </p>
395: *
396: * @return the composite, or <code>null</code> if
397: * <code>createPartControl</code> has not been called yet
398: */
399: protected Composite getContainer() {
400: return container;
401: }
402:
403: /**
404: * Returns the control for the given page index, or <code>null</code> if
405: * no control has been set for the page. The page index must be valid.
406: * <p>
407: * Subclasses should not override this method
408: * </p>
409: *
410: * @param pageIndex
411: * the index of the page
412: * @return the control for the specified page, or <code>null</code> if
413: * none has been set
414: */
415: protected Control getControl(int pageIndex) {
416: return getItem(pageIndex).getControl();
417: }
418:
419: /**
420: * Returns the editor for the given page index. The page index must be
421: * valid.
422: *
423: * @param pageIndex
424: * the index of the page
425: * @return the editor for the specified page, or <code>null</code> if the
426: * specified page was not created with
427: * <code>addPage(IEditorPart,IEditorInput)</code>
428: */
429: protected IEditorPart getEditor(int pageIndex) {
430: Item item = getItem(pageIndex);
431: if (item != null) {
432: Object data = item.getData();
433: if (data instanceof IEditorPart) {
434: return (IEditorPart) data;
435: }
436: }
437: return null;
438: }
439:
440: /**
441: * Returns the tab item for the given page index (page index is 0-based).
442: * The page index must be valid.
443: *
444: * @param pageIndex
445: * the index of the page
446: * @return the tab item for the given page index
447: */
448: private CTabItem getItem(int pageIndex) {
449: return getTabFolder().getItem(pageIndex);
450: }
451:
452: /**
453: * Returns the number of pages in this multi-page editor.
454: *
455: * @return the number of pages
456: */
457: protected int getPageCount() {
458: CTabFolder folder = getTabFolder();
459: // May not have been created yet, or may have been disposed.
460: if (folder != null && !folder.isDisposed()) {
461: return folder.getItemCount();
462: }
463: return 0;
464: }
465:
466: /**
467: * Returns the image for the page with the given index, or <code>null</code>
468: * if no image has been set for the page. The page index must be valid.
469: *
470: * @param pageIndex
471: * the index of the page
472: * @return the image, or <code>null</code> if none
473: */
474: protected Image getPageImage(int pageIndex) {
475: return getItem(pageIndex).getImage();
476: }
477:
478: /**
479: * Returns the text label for the page with the given index. Returns the
480: * empty string if no text label has been set for the page. The page index
481: * must be valid.
482: *
483: * @param pageIndex
484: * the index of the page
485: * @return the text label for the page
486: */
487: protected String getPageText(int pageIndex) {
488: return getItem(pageIndex).getText();
489: }
490:
491: /**
492: * Returns the tab folder containing this multi-page editor's pages.
493: *
494: * @return the tab folder, or <code>null</code> if
495: * <code>createPartControl</code> has not been called yet
496: */
497: private CTabFolder getTabFolder() {
498: return container;
499: }
500:
501: /**
502: * Handles a property change notification from a nested editor. The default
503: * implementation simply forwards the change to listeners on this multi-page
504: * editor by calling <code>firePropertyChange</code> with the same
505: * property id. For example, if the dirty state of a nested editor changes
506: * (property id <code>IEditorPart.PROP_DIRTY</code>), this method handles
507: * it by firing a property change event for
508: * <code>IEditorPart.PROP_DIRTY</code> to property listeners on this
509: * multi-page editor.
510: * <p>
511: * Subclasses may extend or reimplement this method.
512: * </p>
513: *
514: * @param propertyId
515: * the id of the property that changed
516: */
517: protected void handlePropertyChange(int propertyId) {
518: firePropertyChange(propertyId);
519: }
520:
521: /**
522: * The <code>MultiPageEditorPart</code> implementation of this
523: * <code>IEditorPart</code> method sets its site to the given site, its
524: * input to the given input, and the site's selection provider to a
525: * <code>MultiPageSelectionProvider</code>. Subclasses may extend this
526: * method.
527: *
528: * @param site
529: * The site for which this part is being created; must not be
530: * <code>null</code>.
531: * @param input
532: * The input on which this editor should be created; must not be
533: * <code>null</code>.
534: * @throws PartInitException
535: * If the initialization of the part fails -- currently never.
536: */
537: public void init(IEditorSite site, IEditorInput input)
538: throws PartInitException {
539: setSite(site);
540: setInput(input);
541: site.setSelectionProvider(new MultiPageSelectionProvider(this ));
542: }
543:
544: /**
545: * The <code>MultiPageEditorPart</code> implementation of this
546: * <code>IEditorPart</code> method returns whether the contents of any of
547: * this multi-page editor's nested editors have changed since the last save.
548: * Pages created with <code>addPage(Control)</code> are ignored.
549: * <p>
550: * Subclasses may extend or reimplement this method.
551: * </p>
552: *
553: * @return <code>true</code> if any of the nested editors are dirty;
554: * <code>false</code> otherwise.
555: */
556: public boolean isDirty() {
557: // use nestedEditors to avoid SWT requests; see bug 12996
558: for (Iterator i = nestedEditors.iterator(); i.hasNext();) {
559: IEditorPart editor = (IEditorPart) i.next();
560: if (editor.isDirty()) {
561: return true;
562: }
563: }
564: return false;
565: }
566:
567: /**
568: * Notifies this multi-page editor that the page with the given id has been
569: * activated. This method is called when the user selects a different tab.
570: * <p>
571: * The <code>MultiPageEditorPart</code> implementation of this method sets
572: * focus to the new page, and notifies the action bar contributor (if there
573: * is one). This checks whether the action bar contributor is an instance of
574: * <code>MultiPageEditorActionBarContributor</code>, and, if so, calls
575: * <code>setActivePage</code> with the active nested editor. This also
576: * fires a selection change event if required.
577: * </p>
578: * <p>
579: * Subclasses may extend this method.
580: * </p>
581: *
582: * @param newPageIndex
583: * the index of the activated page
584: */
585: protected void pageChange(int newPageIndex) {
586: // Deactivate the nested services from the last active service locator.
587: if (activeServiceLocator != null) {
588: activeServiceLocator.deactivate();
589: activeServiceLocator = null;
590: }
591:
592: setFocus();
593: IEditorPart activeEditor = getEditor(newPageIndex);
594: IEditorActionBarContributor contributor = getEditorSite()
595: .getActionBarContributor();
596: if (contributor != null
597: && contributor instanceof MultiPageEditorActionBarContributor) {
598: ((MultiPageEditorActionBarContributor) contributor)
599: .setActivePage(activeEditor);
600: }
601: if (activeEditor != null) {
602:
603: // Activate the services for the new service locator.
604: final IServiceLocator serviceLocator = activeEditor
605: .getEditorSite();
606: if (serviceLocator instanceof INestable) {
607: activeServiceLocator = (INestable) serviceLocator;
608: activeServiceLocator.activate();
609: }
610:
611: ISelectionProvider selectionProvider = activeEditor
612: .getSite().getSelectionProvider();
613: if (selectionProvider != null) {
614: ISelectionProvider outerProvider = getSite()
615: .getSelectionProvider();
616: if (outerProvider instanceof MultiPageSelectionProvider) {
617: SelectionChangedEvent event = new SelectionChangedEvent(
618: selectionProvider, selectionProvider
619: .getSelection());
620:
621: MultiPageSelectionProvider provider = (MultiPageSelectionProvider) outerProvider;
622: provider.fireSelectionChanged(event);
623: provider.firePostSelectionChanged(event);
624: } else {
625: if (Policy.DEBUG_MPE) {
626: Tracing
627: .printTrace(
628: TRACING_COMPONENT,
629: "MultiPageEditorPart " + getTitle() //$NON-NLS-1$
630: + " did not propogate selection for " //$NON-NLS-1$
631: + activeEditor
632: .getTitle());
633: }
634: }
635: }
636: }
637: }
638:
639: /**
640: * Disposes the given part and its site.
641: *
642: * @param part
643: * The part to dispose; must not be <code>null</code>.
644: */
645: private void disposePart(final IWorkbenchPart part) {
646: SafeRunner.run(new ISafeRunnable() {
647: public void run() {
648: if (part.getSite() instanceof MultiPageEditorSite) {
649: MultiPageEditorSite partSite = (MultiPageEditorSite) part
650: .getSite();
651: partSite.dispose();
652: }
653: part.dispose();
654: }
655:
656: public void handleException(Throwable e) {
657: // Exception has already being logged by Core. Do nothing.
658: }
659: });
660: }
661:
662: /**
663: * Removes the page with the given index from this multi-page editor. The
664: * controls for the page are disposed of; if the page has an editor, it is
665: * disposed of too. The page index must be valid.
666: *
667: * @param pageIndex
668: * the index of the page
669: * @see MultiPageEditorPart#addPage(Control)
670: * @see MultiPageEditorPart#addPage(IEditorPart, IEditorInput)
671: */
672: public void removePage(int pageIndex) {
673: Assert.isTrue(pageIndex >= 0 && pageIndex < getPageCount());
674: // get editor (if any) before disposing item
675: IEditorPart editor = getEditor(pageIndex);
676:
677: // get control for the item if it's not an editor
678: CTabItem item = getItem(pageIndex);
679: Control pageControl = item.getControl();
680:
681: // dispose item before disposing editor, in case there's an exception
682: // in editor's dispose
683: item.dispose();
684:
685: if (pageControl != null) {
686: pageControl.dispose();
687: }
688:
689: // dispose editor (if any)
690: if (editor != null) {
691: nestedEditors.remove(editor);
692: disposePart(editor);
693: }
694: }
695:
696: /**
697: * Sets the currently active page.
698: *
699: * @param pageIndex
700: * the index of the page to be activated; the index must be valid
701: */
702: protected void setActivePage(int pageIndex) {
703: Assert.isTrue(pageIndex >= 0 && pageIndex < getPageCount());
704: getTabFolder().setSelection(pageIndex);
705: pageChange(pageIndex);
706: }
707:
708: /**
709: * Sets the control for the given page index. The page index must be valid.
710: *
711: * @param pageIndex
712: * the index of the page
713: * @param control
714: * the control for the specified page, or <code>null</code> to
715: * clear the control
716: */
717: protected void setControl(int pageIndex, Control control) {
718: getItem(pageIndex).setControl(control);
719: }
720:
721: /**
722: * The <code>MultiPageEditor</code> implementation of this
723: * <code>IWorkbenchPart</code> method sets focus on the active nested
724: * editor, if there is one.
725: * <p>
726: * Subclasses may extend or reimplement.
727: * </p>
728: */
729: public void setFocus() {
730: setFocus(getActivePage());
731: }
732:
733: /**
734: * Sets focus to the control for the given page. If the page has an editor,
735: * this calls its <code>setFocus()</code> method. Otherwise, this calls
736: * <code>setFocus</code> on the control for the page.
737: *
738: * @param pageIndex
739: * the index of the page
740: */
741: private void setFocus(int pageIndex) {
742: final IKeyBindingService service = getSite()
743: .getKeyBindingService();
744: if (pageIndex < 0 || pageIndex >= getPageCount()) {
745: // There is no selected page, so deactivate the active service.
746: if (service instanceof INestableKeyBindingService) {
747: final INestableKeyBindingService nestableService = (INestableKeyBindingService) service;
748: nestableService.activateKeyBindingService(null);
749: } else {
750: WorkbenchPlugin
751: .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$
752: }
753: return;
754: }
755:
756: final IEditorPart editor = getEditor(pageIndex);
757: if (editor != null) {
758: editor.setFocus();
759: // There is no selected page, so deactivate the active service.
760: if (service instanceof INestableKeyBindingService) {
761: final INestableKeyBindingService nestableService = (INestableKeyBindingService) service;
762: if (editor != null) {
763: nestableService.activateKeyBindingService(editor
764: .getEditorSite());
765: } else {
766: nestableService.activateKeyBindingService(null);
767: }
768: } else {
769: WorkbenchPlugin
770: .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$
771: }
772:
773: } else {
774: // There is no selected editor, so deactivate the active service.
775: if (service instanceof INestableKeyBindingService) {
776: final INestableKeyBindingService nestableService = (INestableKeyBindingService) service;
777: nestableService.activateKeyBindingService(null);
778: } else {
779: WorkbenchPlugin
780: .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$
781: }
782:
783: // Give the page's control focus.
784: final Control control = getControl(pageIndex);
785: if (control != null) {
786: control.setFocus();
787: }
788: }
789: }
790:
791: /**
792: * Sets the image for the page with the given index, or <code>null</code>
793: * to clear the image for the page. The page index must be valid.
794: *
795: * @param pageIndex
796: * the index of the page
797: * @param image
798: * the image, or <code>null</code>
799: */
800: protected void setPageImage(int pageIndex, Image image) {
801: getItem(pageIndex).setImage(image);
802: }
803:
804: /**
805: * Sets the text label for the page with the given index. The page index
806: * must be valid. The text label must not be null.
807: *
808: * @param pageIndex
809: * the index of the page
810: * @param text
811: * the text label
812: */
813: protected void setPageText(int pageIndex, String text) {
814: getItem(pageIndex).setText(text);
815: }
816:
817: /**
818: * If there is an adapter registered against the subclass of
819: * MultiPageEditorPart return that. Otherwise, delegate to the internal
820: * editor.
821: *
822: * @see org.eclipse.ui.part.WorkbenchPart#getAdapter(java.lang.Class)
823: */
824: public Object getAdapter(Class adapter) {
825: Object result = super .getAdapter(adapter);
826: // restrict delegating to the UI thread for bug 144851
827: if (result == null && Display.getCurrent() != null) {
828: IEditorPart innerEditor = getActiveEditor();
829: // see bug 138823 - prevent some subclasses from causing
830: // an infinite loop
831: if (innerEditor != null && innerEditor != this ) {
832: result = Util.getAdapter(innerEditor, adapter);
833: }
834: }
835: return result;
836: }
837:
838: /**
839: * Find the editors contained in this multi-page editor
840: * whose editor input match the provided input.
841: * @param input the editor input
842: * @return the editors contained in this multi-page editor
843: * whose editor input match the provided input
844: * @since 3.3
845: */
846: public final IEditorPart[] findEditors(IEditorInput input) {
847: List result = new ArrayList();
848: int count = getPageCount();
849: for (int i = 0; i < count; i++) {
850: IEditorPart editor = getEditor(i);
851: if (editor != null && editor.getEditorInput() != null
852: && editor.getEditorInput().equals(input)) {
853: result.add(editor);
854: }
855: }
856: return (IEditorPart[]) result.toArray(new IEditorPart[result
857: .size()]);
858: }
859:
860: /**
861: * Set the active page of this multi-page editor to the
862: * page that contains the given editor part. This method has
863: * no effect of the given editor part is not contained in this
864: * multi-page editor.
865: * @param editorPart the editor part
866: * @since 3.3
867: */
868: public final void setActiveEditor(IEditorPart editorPart) {
869: int count = getPageCount();
870: for (int i = 0; i < count; i++) {
871: IEditorPart editor = getEditor(i);
872: if (editor == editorPart) {
873: setActivePage(i);
874: break;
875: }
876: }
877: }
878: }
|