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: * Dan Rubel (dan_rubel@instantiations.com) - accessor to get context menu ids
011: *******************************************************************************/package org.eclipse.ui.internal;
012:
013: import java.util.ArrayList;
014: import java.util.Collection;
015: import java.util.HashSet;
016: import java.util.Iterator;
017:
018: import org.eclipse.core.expressions.Expression;
019: import org.eclipse.core.runtime.IConfigurationElement;
020: import org.eclipse.core.runtime.Platform;
021: import org.eclipse.jface.action.IAction;
022: import org.eclipse.jface.action.MenuManager;
023: import org.eclipse.jface.viewers.ISelectionProvider;
024: import org.eclipse.swt.widgets.Display;
025: import org.eclipse.swt.widgets.Shell;
026: import org.eclipse.ui.IActionBars;
027: import org.eclipse.ui.IKeyBindingService;
028: import org.eclipse.ui.IWorkbenchPage;
029: import org.eclipse.ui.IWorkbenchPart;
030: import org.eclipse.ui.IWorkbenchPartReference;
031: import org.eclipse.ui.IWorkbenchPartSite;
032: import org.eclipse.ui.IWorkbenchWindow;
033: import org.eclipse.ui.SubActionBars;
034: import org.eclipse.ui.commands.ICommandService;
035: import org.eclipse.ui.contexts.IContextService;
036: import org.eclipse.ui.handlers.IHandlerService;
037: import org.eclipse.ui.internal.commands.SlaveCommandService;
038: import org.eclipse.ui.internal.contexts.SlaveContextService;
039: import org.eclipse.ui.internal.expressions.ActivePartExpression;
040: import org.eclipse.ui.internal.handlers.SlaveHandlerService;
041: import org.eclipse.ui.internal.progress.WorkbenchSiteProgressService;
042: import org.eclipse.ui.internal.services.ServiceLocator;
043: import org.eclipse.ui.internal.testing.WorkbenchPartTestable;
044: import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
045: import org.eclipse.ui.services.IServiceLocator;
046: import org.eclipse.ui.services.IServiceScopes;
047: import org.eclipse.ui.testing.IWorkbenchPartTestable;
048:
049: /**
050: * <code>PartSite</code> is the general implementation for an
051: * <code>IWorkbenchPartSite</code>. A site maintains the context for a part,
052: * including the part, its pane, active contributions, selection provider, etc.
053: * Together, these components make up the complete behavior for a part as if it
054: * was implemented by one person.
055: *
056: * The <code>PartSite</code> lifecycle is as follows ..
057: *
058: * <ol>
059: * <li>a site is constructed </li>
060: * <li>a part is constructed and stored in the part </li>
061: * <li>the site calls part.init() </li>
062: * <li>a pane is constructed and stored in the site </li>
063: * <li>the action bars for a part are constructed and stored in the site </li>
064: * <li>the pane is added to a presentation </li>
065: * <li>the SWT widgets for the pane and part are created </li>
066: * <li>the site is activated, causing the actions to become visible </li>
067: * </ol>
068: */
069: public abstract class PartSite implements IWorkbenchPartSite {
070:
071: /**
072: * This is a helper method for the register context menu functionality. It
073: * is provided so that different implementations of the
074: * <code>IWorkbenchPartSite</code> interface don't have to worry about how
075: * context menus should work.
076: *
077: * @param menuId
078: * the menu id
079: * @param menuManager
080: * the menu manager
081: * @param selectionProvider
082: * the selection provider
083: * @param includeEditorInput
084: * whether editor inputs should be included in the structured
085: * selection when calculating contributions
086: * @param part
087: * the part for this site
088: * @param menuExtenders
089: * the collection of menu extenders for this site
090: * @see IWorkbenchPartSite#registerContextMenu(MenuManager,
091: * ISelectionProvider)
092: */
093: public static final void registerContextMenu(final String menuId,
094: final MenuManager menuManager,
095: final ISelectionProvider selectionProvider,
096: final boolean includeEditorInput,
097: final IWorkbenchPart part, final Collection menuExtenders) {
098: /*
099: * Check to see if the same menu manager and selection provider have
100: * already been used. If they have, then we can just add another menu
101: * identifier to the existing PopupMenuExtender.
102: */
103: final Iterator extenderItr = menuExtenders.iterator();
104: boolean foundMatch = false;
105: while (extenderItr.hasNext()) {
106: final PopupMenuExtender existingExtender = (PopupMenuExtender) extenderItr
107: .next();
108: if (existingExtender.matches(menuManager,
109: selectionProvider, part)) {
110: existingExtender.addMenuId(menuId);
111: foundMatch = true;
112: break;
113: }
114: }
115:
116: if (!foundMatch) {
117: menuExtenders.add(new PopupMenuExtender(menuId,
118: menuManager, selectionProvider, part,
119: includeEditorInput));
120: }
121: }
122:
123: private IWorkbenchPartReference partReference;
124:
125: private IWorkbenchPart part;
126:
127: private IWorkbenchPage page;
128:
129: private String extensionID;
130:
131: private String pluginID;
132:
133: private String extensionName;
134:
135: private ISelectionProvider selectionProvider;
136:
137: private SubActionBars actionBars;
138:
139: private KeyBindingService keyBindingService;
140:
141: protected ArrayList menuExtenders;
142:
143: private WorkbenchSiteProgressService progressService;
144:
145: protected final ServiceLocator serviceLocator;
146:
147: /**
148: * Build the part site.
149: *
150: * @param ref
151: * the part reference
152: * @param part
153: * the part
154: * @param page
155: * the page it belongs to
156: */
157: public PartSite(IWorkbenchPartReference ref, IWorkbenchPart part,
158: IWorkbenchPage page) {
159: this .partReference = ref;
160: this .part = part;
161: this .page = page;
162: extensionID = "org.eclipse.ui.UnknownID"; //$NON-NLS-1$
163: extensionName = "Unknown Name"; //$NON-NLS-1$
164:
165: // Initialize the service locator.
166: final IServiceLocator parentServiceLocator = page
167: .getWorkbenchWindow();
168: this .serviceLocator = new ServiceLocator(parentServiceLocator);
169:
170: initializeDefaultServices();
171: }
172:
173: /**
174: * Initialize the local services.
175: */
176: private void initializeDefaultServices() {
177: serviceLocator.registerService(IWorkbenchPartSite.class, this );
178: final IHandlerService parentService = (IHandlerService) serviceLocator
179: .getService(IHandlerService.class);
180: final Expression defaultExpression = new ActivePartExpression(
181: part);
182: final IHandlerService slave = new SlaveHandlerService(
183: parentService, defaultExpression);
184: serviceLocator.registerService(IHandlerService.class, slave);
185:
186: final IContextService parentContextService = (IContextService) serviceLocator
187: .getService(IContextService.class);
188: final IContextService contextService = new SlaveContextService(
189: parentContextService, defaultExpression);
190: serviceLocator.registerService(IContextService.class,
191: contextService);
192:
193: final ICommandService parentCommandService = (ICommandService) serviceLocator
194: .getService(ICommandService.class);
195: final ICommandService commandService = new SlaveCommandService(
196: parentCommandService, IServiceScopes.PARTSITE_SCOPE,
197: this );
198: serviceLocator.registerService(ICommandService.class,
199: commandService);
200: }
201:
202: /**
203: * Dispose the contributions.
204: */
205: public void dispose() {
206: if (menuExtenders != null) {
207: HashSet managers = new HashSet(menuExtenders.size());
208: for (int i = 0; i < menuExtenders.size(); i++) {
209: PopupMenuExtender ext = (PopupMenuExtender) menuExtenders
210: .get(i);
211: managers.add(ext.getManager());
212: ext.dispose();
213: }
214: if (managers.size() > 0) {
215: for (Iterator iterator = managers.iterator(); iterator
216: .hasNext();) {
217: MenuManager mgr = (MenuManager) iterator.next();
218: mgr.dispose();
219: }
220: }
221: menuExtenders = null;
222: }
223:
224: if (keyBindingService != null) {
225: keyBindingService.dispose();
226: }
227:
228: if (progressService != null) {
229: progressService.dispose();
230: }
231:
232: if (serviceLocator != null) {
233: serviceLocator.dispose();
234: }
235: }
236:
237: /**
238: * Returns the action bars for the part. If this part is a view then it has
239: * exclusive use of the action bars. If this part is an editor then the
240: * action bars are shared among this editor and other editors of the same
241: * type.
242: */
243: public IActionBars getActionBars() {
244: return actionBars;
245: }
246:
247: /**
248: * Returns the part registry extension ID.
249: *
250: * @return the registry extension ID
251: */
252: public String getId() {
253: return extensionID;
254: }
255:
256: /**
257: * Returns the page containing this workbench site's part.
258: *
259: * @return the page containing this part
260: */
261: public IWorkbenchPage getPage() {
262: return page;
263: }
264:
265: /**
266: * Gets the part pane.
267: */
268: public PartPane getPane() {
269: return ((WorkbenchPartReference) partReference).getPane();
270: }
271:
272: /**
273: * Returns the part.
274: */
275: public IWorkbenchPart getPart() {
276: return part;
277: }
278:
279: /**
280: * Returns the part reference.
281: */
282: public IWorkbenchPartReference getPartReference() {
283: return partReference;
284: }
285:
286: /**
287: * Returns the part registry plugin ID. It cannot be <code>null</code>.
288: *
289: * @return the registry plugin ID
290: */
291: public String getPluginId() {
292: return pluginID;
293: }
294:
295: /**
296: * Returns the registered name for this part.
297: */
298: public String getRegisteredName() {
299: return extensionName;
300: }
301:
302: /**
303: * Returns the selection provider for a part.
304: */
305: public ISelectionProvider getSelectionProvider() {
306: return selectionProvider;
307: }
308:
309: /**
310: * Returns the shell containing this part.
311: *
312: * @return the shell containing this part
313: */
314: public Shell getShell() {
315: PartPane pane = getPane();
316:
317: // Compatibility: This method should not be used outside the UI
318: // thread... but since this condition
319: // was not always in the JavaDoc, we still try to return our best guess
320: // about the shell if it is
321: // called from the wrong thread.
322: Display currentDisplay = Display.getCurrent();
323: if (currentDisplay == null
324: || currentDisplay != getWorkbenchWindow()
325: .getWorkbench().getDisplay()) {
326: // Uncomment this to locate places that try to access the shell from
327: // a background thread
328: // WorkbenchPlugin.log(new Exception("Error:
329: // IWorkbenchSite.getShell() was called outside the UI thread. Fix
330: // this code.")); //$NON-NLS-1$
331:
332: return getWorkbenchWindow().getShell();
333: }
334:
335: if (pane == null) {
336: return getWorkbenchWindow().getShell();
337: }
338:
339: Shell s = pane.getShell();
340:
341: if (s == null) {
342: return getWorkbenchWindow().getShell();
343: }
344:
345: return s;
346: }
347:
348: /**
349: * Returns the workbench window containing this part.
350: *
351: * @return the workbench window containing this part
352: */
353: public IWorkbenchWindow getWorkbenchWindow() {
354: return page.getWorkbenchWindow();
355: }
356:
357: /**
358: * Register a popup menu for extension.
359: */
360: public void registerContextMenu(String menuID, MenuManager menuMgr,
361: ISelectionProvider selProvider) {
362: if (menuExtenders == null) {
363: menuExtenders = new ArrayList(1);
364: }
365:
366: registerContextMenu(menuID, menuMgr, selProvider, true,
367: getPart(), menuExtenders);
368: }
369:
370: /**
371: * Register a popup menu with the default id for extension.
372: */
373: public void registerContextMenu(MenuManager menuMgr,
374: ISelectionProvider selProvider) {
375: registerContextMenu(getId(), menuMgr, selProvider);
376: }
377:
378: // getContextMenuIds() added by Dan Rubel (dan_rubel@instantiations.com)
379: /**
380: * Get the registered popup menu identifiers
381: */
382: public String[] getContextMenuIds() {
383: if (menuExtenders == null) {
384: return new String[0];
385: }
386: ArrayList menuIds = new ArrayList(menuExtenders.size());
387: for (Iterator iter = menuExtenders.iterator(); iter.hasNext();) {
388: final PopupMenuExtender extender = (PopupMenuExtender) iter
389: .next();
390: menuIds.addAll(extender.getMenuIds());
391: }
392: return (String[]) menuIds.toArray(new String[menuIds.size()]);
393: }
394:
395: /**
396: * Sets the action bars for the part.
397: */
398: public void setActionBars(SubActionBars bars) {
399: actionBars = bars;
400: }
401:
402: /**
403: * Sets the configuration element for a part.
404: */
405: public void setConfigurationElement(
406: IConfigurationElement configElement) {
407:
408: // Get extension ID.
409: extensionID = configElement.getAttribute("id"); //$NON-NLS-1$
410:
411: // Get plugin ID.
412: pluginID = configElement.getNamespace();
413:
414: // Get extension name.
415: String name = configElement.getAttribute("name"); //$NON-NLS-1$
416: if (name != null) {
417: extensionName = name;
418: }
419: }
420:
421: protected void setPluginId(String pluginId) {
422: this .pluginID = pluginId;
423: }
424:
425: /**
426: * Sets the part registry extension ID.
427: *
428: * @param id
429: * the registry extension ID
430: */
431: protected void setId(String id) {
432: extensionID = id;
433: }
434:
435: /**
436: * Sets the part.
437: */
438: public void setPart(IWorkbenchPart newPart) {
439: part = newPart;
440: }
441:
442: /**
443: * Sets the registered name for this part.
444: *
445: * @param name
446: * the registered name
447: */
448: protected void setRegisteredName(String name) {
449: extensionName = name;
450: }
451:
452: /**
453: * Set the selection provider for a part.
454: */
455: public void setSelectionProvider(ISelectionProvider provider) {
456: selectionProvider = provider;
457: }
458:
459: /*
460: * @see IWorkbenchPartSite#getKeyBindingService()
461: */
462: public IKeyBindingService getKeyBindingService() {
463: if (keyBindingService == null) {
464: keyBindingService = new KeyBindingService(this );
465:
466: // TODO why is this here? and it should be using HandlerSubmissions
467: // directly..
468: if (this instanceof EditorSite) {
469: EditorActionBuilder.ExternalContributor contributor = (EditorActionBuilder.ExternalContributor) ((EditorSite) this )
470: .getExtensionActionBarContributor();
471:
472: if (contributor != null) {
473: ActionDescriptor[] actionDescriptors = contributor
474: .getExtendedActions();
475:
476: if (actionDescriptors != null) {
477: for (int i = 0; i < actionDescriptors.length; i++) {
478: ActionDescriptor actionDescriptor = actionDescriptors[i];
479:
480: if (actionDescriptor != null) {
481: IAction action = actionDescriptors[i]
482: .getAction();
483:
484: if (action != null
485: && action
486: .getActionDefinitionId() != null) {
487: keyBindingService
488: .registerAction(action);
489: }
490: }
491: }
492: }
493: }
494: }
495: }
496:
497: return keyBindingService;
498: }
499:
500: protected String getInitialScopeId() {
501: return null;
502: }
503:
504: /**
505: * Get an adapter for this type.
506: *
507: * @param adapter
508: * @return
509: */
510: public final Object getAdapter(Class adapter) {
511:
512: if (IWorkbenchSiteProgressService.class == adapter) {
513: return getSiteProgressService();
514: }
515:
516: if (IWorkbenchPartTestable.class == adapter) {
517: return new WorkbenchPartTestable(this );
518: }
519:
520: return Platform.getAdapterManager().getAdapter(this , adapter);
521: }
522:
523: public void activateActionBars(boolean forceVisibility) {
524: if (actionBars != null) {
525: actionBars.activate(forceVisibility);
526: }
527: }
528:
529: public void deactivateActionBars(boolean forceHide) {
530: if (actionBars != null) {
531: actionBars.deactivate(forceHide);
532: }
533: }
534:
535: /**
536: * Get a progress service for the receiver.
537: *
538: * @return WorkbenchSiteProgressService
539: */
540: private WorkbenchSiteProgressService getSiteProgressService() {
541: if (progressService == null) {
542: progressService = new WorkbenchSiteProgressService(this );
543: }
544: return progressService;
545: }
546:
547: public final Object getService(final Class key) {
548: return serviceLocator.getService(key);
549: }
550:
551: public final boolean hasService(final Class key) {
552: return serviceLocator.hasService(key);
553: }
554:
555: /**
556: * Prints out the identifier, the plug-in identifier and the registered
557: * name. This is for debugging purposes only.
558: *
559: * @since 3.2
560: */
561: public String toString() {
562: final StringBuffer buffer = new StringBuffer();
563: buffer.append("PartSite(id="); //$NON-NLS-1$
564: buffer.append(getId());
565: buffer.append(",pluginId="); //$NON-NLS-1$
566: buffer.append(getPluginId());
567: buffer.append(",registeredName="); //$NON-NLS-1$
568: buffer.append(getRegisteredName());
569: buffer.append(",hashCode="); //$NON-NLS-1$
570: buffer.append(hashCode());
571: buffer.append(')');
572: return buffer.toString();
573: }
574: }
|