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:
014: import org.eclipse.core.expressions.Expression;
015: import org.eclipse.core.runtime.Assert;
016: import org.eclipse.jface.action.MenuManager;
017: import org.eclipse.jface.viewers.ILabelDecorator;
018: import org.eclipse.jface.viewers.IPostSelectionProvider;
019: import org.eclipse.jface.viewers.ISelectionChangedListener;
020: import org.eclipse.jface.viewers.ISelectionProvider;
021: import org.eclipse.jface.viewers.SelectionChangedEvent;
022: import org.eclipse.swt.widgets.Shell;
023: import org.eclipse.ui.IActionBars;
024: import org.eclipse.ui.IEditorActionBarContributor;
025: import org.eclipse.ui.IEditorPart;
026: import org.eclipse.ui.IEditorSite;
027: import org.eclipse.ui.IKeyBindingService;
028: import org.eclipse.ui.INestableKeyBindingService;
029: import org.eclipse.ui.IWorkbenchPage;
030: import org.eclipse.ui.IWorkbenchPart;
031: import org.eclipse.ui.IWorkbenchWindow;
032: import org.eclipse.ui.commands.ICommandService;
033: import org.eclipse.ui.contexts.IContextService;
034: import org.eclipse.ui.handlers.IHandlerService;
035: import org.eclipse.ui.internal.PartSite;
036: import org.eclipse.ui.internal.PopupMenuExtender;
037: import org.eclipse.ui.internal.WorkbenchPlugin;
038: import org.eclipse.ui.internal.commands.SlaveCommandService;
039: import org.eclipse.ui.internal.contexts.NestableContextService;
040: import org.eclipse.ui.internal.expressions.ActivePartExpression;
041: import org.eclipse.ui.internal.handlers.NestableHandlerService;
042: import org.eclipse.ui.internal.services.INestable;
043: import org.eclipse.ui.internal.services.ServiceLocator;
044: import org.eclipse.ui.services.IServiceLocator;
045: import org.eclipse.ui.services.IServiceScopes;
046:
047: /**
048: * Site for a nested editor within a multi-page editor. Selection is handled by
049: * forwarding the event to the multi-page editor's selection listeners; most
050: * other methods are forwarded to the multi-page editor's site.
051: * <p>
052: * The base implementation of <code>MultiPageEditor.createSite</code> creates
053: * an instance of this class. This class may be instantiated or subclassed.
054: * </p>
055: */
056: public class MultiPageEditorSite implements IEditorSite, INestable {
057:
058: /**
059: * The nested editor.
060: */
061: private IEditorPart editor;
062:
063: /**
064: * The list of popup menu extenders; <code>null</code> if none registered.
065: */
066: private ArrayList menuExtenders;
067:
068: /**
069: * The multi-page editor.
070: */
071: private MultiPageEditorPart multiPageEditor;
072:
073: /**
074: * The post selection changed listener.
075: */
076: private ISelectionChangedListener postSelectionChangedListener = null;
077:
078: /**
079: * The selection change listener, initialized lazily; <code>null</code> if
080: * not yet created.
081: */
082: private ISelectionChangedListener selectionChangedListener = null;
083:
084: /**
085: * The selection provider; <code>null</code> if none.
086: *
087: * @see MultiPageEditorSite#setSelectionProvider(ISelectionProvider)
088: */
089: private ISelectionProvider selectionProvider = null;
090:
091: /**
092: * The cached copy of the key binding service specific to this multi-page
093: * editor site. This value is <code>null</code> if it is not yet
094: * initialized.
095: */
096: private IKeyBindingService service = null;
097:
098: /**
099: * The local service locator for this multi-page editor site. This value is
100: * never <code>null</code>.
101: */
102: private final ServiceLocator serviceLocator;
103:
104: /**
105: * Creates a site for the given editor nested within the given multi-page
106: * editor.
107: *
108: * @param multiPageEditor
109: * the multi-page editor
110: * @param editor
111: * the nested editor
112: */
113: public MultiPageEditorSite(MultiPageEditorPart multiPageEditor,
114: IEditorPart editor) {
115: Assert.isNotNull(multiPageEditor);
116: Assert.isNotNull(editor);
117: this .multiPageEditor = multiPageEditor;
118: this .editor = editor;
119:
120: final IServiceLocator parentServiceLocator = multiPageEditor
121: .getSite();
122: serviceLocator = new ServiceLocator(parentServiceLocator);
123:
124: initializeDefaultServices();
125: }
126:
127: /**
128: * Initialize the slave services for this site.
129: */
130: private void initializeDefaultServices() {
131: final Expression defaultExpression = new ActivePartExpression(
132: multiPageEditor);
133:
134: final IHandlerService parentService = (IHandlerService) serviceLocator
135: .getService(IHandlerService.class);
136: final IHandlerService slave = new NestableHandlerService(
137: parentService, defaultExpression);
138: serviceLocator.registerService(IHandlerService.class, slave);
139:
140: final IContextService parentContext = (IContextService) serviceLocator
141: .getService(IContextService.class);
142: final IContextService context = new NestableContextService(
143: parentContext, defaultExpression);
144: serviceLocator.registerService(IContextService.class, context);
145:
146: final ICommandService parentCommandService = (ICommandService) serviceLocator
147: .getService(ICommandService.class);
148: final ICommandService commandService = new SlaveCommandService(
149: parentCommandService, IServiceScopes.MPESITE_SCOPE,
150: this );
151: serviceLocator.registerService(ICommandService.class,
152: commandService);
153:
154: }
155:
156: /**
157: * Notifies the multi page editor service that the component within which it
158: * exists has become active.
159: *
160: * @since 3.2
161: */
162: public final void activate() {
163: serviceLocator.activate();
164: }
165:
166: /**
167: * Notifies the multi page editor service that the component within which it
168: * exists has been deactived.
169: *
170: * @since 3.2
171: */
172: public final void deactivate() {
173: serviceLocator.deactivate();
174: }
175:
176: /**
177: * Dispose the contributions.
178: */
179: public void dispose() {
180: if (menuExtenders != null) {
181: for (int i = 0; i < menuExtenders.size(); i++) {
182: ((PopupMenuExtender) menuExtenders.get(i)).dispose();
183: }
184: menuExtenders = null;
185: }
186:
187: // Remove myself from the list of nested key binding services.
188: if (service != null) {
189: IKeyBindingService parentService = getEditor().getSite()
190: .getKeyBindingService();
191: if (parentService instanceof INestableKeyBindingService) {
192: INestableKeyBindingService nestableParent = (INestableKeyBindingService) parentService;
193: nestableParent.removeKeyBindingService(this );
194: }
195: service = null;
196: }
197:
198: if (serviceLocator != null) {
199: serviceLocator.dispose();
200: }
201: }
202:
203: /**
204: * The <code>MultiPageEditorSite</code> implementation of this
205: * <code>IEditorSite</code> method returns <code>null</code>, since
206: * nested editors do not have their own action bar contributor.
207: *
208: * @return <code>null</code>
209: */
210: public IEditorActionBarContributor getActionBarContributor() {
211: return null;
212: }
213:
214: /**
215: * The <code>MultiPageEditorSite</code> implementation of this
216: * <code>IEditorSite</code> method forwards to the multi-page editor to
217: * return the action bars.
218: *
219: * @return The action bars from the parent multi-page editor.
220: */
221: public IActionBars getActionBars() {
222: return multiPageEditor.getEditorSite().getActionBars();
223: }
224:
225: /*
226: * (non-Javadoc)
227: *
228: * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
229: */
230: public Object getAdapter(Class adapter) {
231: return null;
232: }
233:
234: /**
235: * The <code>MultiPageEditorSite</code> implementation of this
236: * <code>IWorkbenchPartSite</code> method forwards to the multi-page
237: * editor to return the decorator manager.
238: *
239: * @return The decorator from the workbench window.
240: * @deprecated use IWorkbench.getDecoratorManager()
241: */
242: public ILabelDecorator getDecoratorManager() {
243: return getWorkbenchWindow().getWorkbench()
244: .getDecoratorManager().getLabelDecorator();
245: }
246:
247: /**
248: * Returns the nested editor.
249: *
250: * @return the nested editor
251: */
252: public IEditorPart getEditor() {
253: return editor;
254: }
255:
256: /**
257: * The <code>MultiPageEditorSite</code> implementation of this
258: * <code>IWorkbenchPartSite</code> method returns an empty string since
259: * the nested editor is not created from the registry.
260: *
261: * @return An empty string.
262: */
263: public String getId() {
264: return ""; //$NON-NLS-1$
265: }
266:
267: /*
268: * (non-Javadoc) Method declared on IEditorSite.
269: */
270: public IKeyBindingService getKeyBindingService() {
271: if (service == null) {
272: service = getMultiPageEditor().getEditorSite()
273: .getKeyBindingService();
274: if (service instanceof INestableKeyBindingService) {
275: INestableKeyBindingService nestableService = (INestableKeyBindingService) service;
276: service = nestableService.getKeyBindingService(this );
277:
278: } else {
279: /*
280: * This is an internal reference, and should not be copied by
281: * client code. If you are thinking of copying this, DON'T DO
282: * IT.
283: */
284: WorkbenchPlugin
285: .log("MultiPageEditorSite.getKeyBindingService() 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$
286: }
287: }
288: return service;
289: }
290:
291: /**
292: * Returns the multi-page editor.
293: *
294: * @return the multi-page editor
295: */
296: public MultiPageEditorPart getMultiPageEditor() {
297: return multiPageEditor;
298: }
299:
300: /**
301: * The <code>MultiPageEditorSite</code> implementation of this
302: * <code>IWorkbenchPartSite</code> method forwards to the multi-page
303: * editor to return the workbench page.
304: *
305: * @return The workbench page in which this editor site resides.
306: */
307: public IWorkbenchPage getPage() {
308: return getMultiPageEditor().getSite().getPage();
309: }
310:
311: /*
312: * (non-Javadoc)
313: *
314: * @see org.eclipse.ui.IWorkbenchPartSite#getPart()
315: */
316: public IWorkbenchPart getPart() {
317: return editor;
318: }
319:
320: /**
321: * The <code>MultiPageEditorSite</code> implementation of this
322: * <code>IWorkbenchPartSite</code> method returns an empty string since
323: * the nested editor is not created from the registry.
324: *
325: * @return An empty string.
326: */
327: public String getPluginId() {
328: return ""; //$NON-NLS-1$
329: }
330:
331: /**
332: * Returns the post selection change listener which listens to the nested
333: * editor's selection changes.
334: *
335: * @return the post selection change listener.
336: */
337: private ISelectionChangedListener getPostSelectionChangedListener() {
338: if (postSelectionChangedListener == null) {
339: postSelectionChangedListener = new ISelectionChangedListener() {
340: public void selectionChanged(SelectionChangedEvent event) {
341: MultiPageEditorSite.this
342: .handlePostSelectionChanged(event);
343: }
344: };
345: }
346: return postSelectionChangedListener;
347: }
348:
349: /**
350: * The <code>MultiPageEditorSite</code> implementation of this
351: * <code>IWorkbenchPartSite</code> method returns an empty string since
352: * the nested editor is not created from the registry.
353: *
354: * @return An empty string.
355: */
356: public String getRegisteredName() {
357: return ""; //$NON-NLS-1$
358: }
359:
360: /**
361: * Returns the selection changed listener which listens to the nested
362: * editor's selection changes, and calls <code>handleSelectionChanged</code>.
363: *
364: * @return the selection changed listener
365: */
366: private ISelectionChangedListener getSelectionChangedListener() {
367: if (selectionChangedListener == null) {
368: selectionChangedListener = new ISelectionChangedListener() {
369: public void selectionChanged(SelectionChangedEvent event) {
370: MultiPageEditorSite.this
371: .handleSelectionChanged(event);
372: }
373: };
374: }
375: return selectionChangedListener;
376: }
377:
378: /**
379: * The <code>MultiPageEditorSite</code> implementation of this
380: * <code>IWorkbenchPartSite</code> method returns the selection provider
381: * set by <code>setSelectionProvider</code>.
382: *
383: * @return The current selection provider.
384: */
385: public ISelectionProvider getSelectionProvider() {
386: return selectionProvider;
387: }
388:
389: public final Object getService(final Class key) {
390: return serviceLocator.getService(key);
391: }
392:
393: /**
394: * The <code>MultiPageEditorSite</code> implementation of this
395: * <code>IWorkbenchPartSite</code> method forwards to the multi-page
396: * editor to return the shell.
397: *
398: * @return The shell in which this editor site resides.
399: */
400: public Shell getShell() {
401: return getMultiPageEditor().getSite().getShell();
402: }
403:
404: /**
405: * The <code>MultiPageEditorSite</code> implementation of this
406: * <code>IWorkbenchPartSite</code> method forwards to the multi-page
407: * editor to return the workbench window.
408: *
409: * @return The workbench window in which this editor site resides.
410: */
411: public IWorkbenchWindow getWorkbenchWindow() {
412: return getMultiPageEditor().getSite().getWorkbenchWindow();
413: }
414:
415: /**
416: * Handles a post selection changed even from the nexted editor.
417: * <p>
418: * Subclasses may extend or reimplement this method
419: *
420: * @param event the event
421: *
422: * @since 3.2
423: */
424: protected void handlePostSelectionChanged(
425: SelectionChangedEvent event) {
426: ISelectionProvider parentProvider = getMultiPageEditor()
427: .getSite().getSelectionProvider();
428: if (parentProvider instanceof MultiPageSelectionProvider) {
429: SelectionChangedEvent newEvent = new SelectionChangedEvent(
430: parentProvider, event.getSelection());
431: MultiPageSelectionProvider prov = (MultiPageSelectionProvider) parentProvider;
432: prov.firePostSelectionChanged(newEvent);
433: }
434: }
435:
436: /**
437: * Handles a selection changed event from the nested editor. The default
438: * implementation gets the selection provider from the multi-page editor's
439: * site, and calls <code>fireSelectionChanged</code> on it (only if it is
440: * an instance of <code>MultiPageSelectionProvider</code>), passing a new
441: * event object.
442: * <p>
443: * Subclasses may extend or reimplement this method.
444: * </p>
445: *
446: * @param event
447: * the event
448: */
449: protected void handleSelectionChanged(SelectionChangedEvent event) {
450: ISelectionProvider parentProvider = getMultiPageEditor()
451: .getSite().getSelectionProvider();
452: if (parentProvider instanceof MultiPageSelectionProvider) {
453: SelectionChangedEvent newEvent = new SelectionChangedEvent(
454: parentProvider, event.getSelection());
455: MultiPageSelectionProvider prov = (MultiPageSelectionProvider) parentProvider;
456: prov.fireSelectionChanged(newEvent);
457: }
458: }
459:
460: public final boolean hasService(final Class key) {
461: return serviceLocator.hasService(key);
462: }
463:
464: /**
465: * The <code>MultiPageEditorSite</code> implementation of this
466: * <code>IWorkbenchPartSite</code> method forwards to the multi-page
467: * editor for registration.
468: *
469: * @param menuManager
470: * The menu manager
471: * @param selProvider
472: * The selection provider.
473: */
474: public void registerContextMenu(MenuManager menuManager,
475: ISelectionProvider selProvider) {
476: getMultiPageEditor().getSite().registerContextMenu(menuManager,
477: selProvider);
478: }
479:
480: public final void registerContextMenu(
481: final MenuManager menuManager,
482: final ISelectionProvider selectionProvider,
483: final boolean includeEditorInput) {
484: registerContextMenu(getId(), menuManager, selectionProvider,
485: includeEditorInput);
486: }
487:
488: /**
489: * The <code>MultiPageEditorSite</code> implementation of this
490: * <code>IWorkbenchPartSite</code> method forwards to the multi-page
491: * editor for registration.
492: *
493: * @param menuID
494: * The identifier for the menu.
495: * @param menuMgr
496: * The menu manager
497: * @param selProvider
498: * The selection provider.
499: */
500: public void registerContextMenu(String menuID, MenuManager menuMgr,
501: ISelectionProvider selProvider) {
502: if (menuExtenders == null) {
503: menuExtenders = new ArrayList(1);
504: }
505: PartSite.registerContextMenu(menuID, menuMgr, selProvider,
506: true, editor, menuExtenders);
507: }
508:
509: public final void registerContextMenu(final String menuId,
510: final MenuManager menuManager,
511: final ISelectionProvider selectionProvider,
512: final boolean includeEditorInput) {
513: if (menuExtenders == null) {
514: menuExtenders = new ArrayList(1);
515: }
516: PartSite.registerContextMenu(menuId, menuManager,
517: selectionProvider, includeEditorInput, editor,
518: menuExtenders);
519: }
520:
521: /**
522: * The <code>MultiPageEditorSite</code> implementation of this
523: * <code>IWorkbenchPartSite</code> method remembers the selection
524: * provider, and also hooks a listener on it, which calls
525: * <code>handleSelectionChanged</code> when a selection changed event
526: * occurs.
527: *
528: * @param provider
529: * The selection provider.
530: * @see MultiPageEditorSite#handleSelectionChanged(SelectionChangedEvent)
531: */
532: public void setSelectionProvider(ISelectionProvider provider) {
533: ISelectionProvider oldSelectionProvider = selectionProvider;
534: selectionProvider = provider;
535: if (oldSelectionProvider != null) {
536: oldSelectionProvider
537: .removeSelectionChangedListener(getSelectionChangedListener());
538: if (oldSelectionProvider instanceof IPostSelectionProvider) {
539: ((IPostSelectionProvider) oldSelectionProvider)
540: .removePostSelectionChangedListener(getPostSelectionChangedListener());
541: }
542: }
543: if (selectionProvider != null) {
544: selectionProvider
545: .addSelectionChangedListener(getSelectionChangedListener());
546: if (selectionProvider instanceof IPostSelectionProvider) {
547: ((IPostSelectionProvider) selectionProvider)
548: .addPostSelectionChangedListener(getPostSelectionChangedListener());
549: }
550: }
551: }
552: }
|