/*******************************************************************************
* Copyright (c) 2000, 2007 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.papyrus.infra.core.sasheditor.internal.eclipsecopy;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.viewers.ILabelDecorator;
import org.eclipse.jface.viewers.IPostSelectionProvider;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.papyrus.infra.core.sasheditor.Activator;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorActionBarContributor;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IKeyBindingService;
import org.eclipse.ui.INestableKeyBindingService;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.internal.KeyBindingService;
import org.eclipse.ui.internal.PopupMenuExtender;
import org.eclipse.ui.internal.WorkbenchPlugin;
import org.eclipse.ui.internal.services.INestable;
import org.eclipse.ui.internal.services.IServiceLocatorCreator;
import org.eclipse.ui.internal.services.IWorkbenchLocationService;
import org.eclipse.ui.internal.services.ServiceLocator;
import org.eclipse.ui.internal.services.WorkbenchLocationService;
import org.eclipse.ui.part.EditorActionBarContributor;
import org.eclipse.ui.services.IDisposable;
import org.eclipse.ui.services.IServiceLocator;
import org.eclipse.ui.services.IServiceScopes;
/**
* Site for a nested editor within a multi-page editor. Selection is handled by
* forwarding the event to the multi-page editor's selection listeners; most
* other methods are forwarded to the multi-page editor's site.
* <p>
* The base implementation of <code>MultiPageEditor.createSite</code> creates an instance of this class. This class may be instantiated or subclassed.
* </p>
*
* @see org.eclipse.ui.part.MultiPageEditorSite.class
*/
public class MultiPageEditorSite implements IMultiPageEditorSite, INestable {
org.eclipse.ui.part.MultiPageEditorSite e;
/**
* The actionBarContributor associated to the site. Can be null. In this case,
* use the multiEditor ActionBarContributor.
*/
protected EditorActionBarContributor actionBarContributor;
/**
* The nested editor.
*/
private IEditorPart editor;
/**
* The list of popup menu extenders; <code>null</code> if none registered.
*/
private ArrayList menuExtenders;
/**
* The main editor EditorSite.
*/
private IEditorSite mainEditorSite;
/**
* The post selection changed listener.
*/
private ISelectionChangedListener postSelectionChangedListener = null;
/**
* The selection change listener, initialized lazily; <code>null</code> if
* not yet created.
*/
private ISelectionChangedListener selectionChangedListener = null;
/**
* The selection provider; <code>null</code> if none.
*
* @see MultiPageEditorSite#setSelectionProvider(ISelectionProvider)
*/
private ISelectionProvider selectionProvider = null;
/**
* The cached copy of the key binding service specific to this multi-page
* editor site. This value is <code>null</code> if it is not yet
* initialized.
*/
private IKeyBindingService service = null;
/**
* The local service locator for this multi-page editor site. This value is
* never <code>null</code>.
*/
private final ServiceLocator serviceLocator;
/**
* Creates a site for the given editor nested within the given multi-page
* editor.
*
* @param mainEditorSite
* the multi-page editor
* @param editor
* the nested editor
* @param editDomain
* The shared editDomain.
*/
@SuppressWarnings("restriction")
public MultiPageEditorSite(IEditorSite mainEditorSite, IEditorPart editor, EditorActionBarContributor actionBarContributor) {
Assert.isNotNull(mainEditorSite);
Assert.isNotNull(editor);
this.mainEditorSite = mainEditorSite;
this.editor = editor;
this.actionBarContributor = actionBarContributor;
final IServiceLocator parentServiceLocator = mainEditorSite;
IServiceLocatorCreator slc = (IServiceLocatorCreator)parentServiceLocator.getService(IServiceLocatorCreator.class);
this.serviceLocator = (ServiceLocator)slc.createServiceLocator(mainEditorSite, null, new IDisposable() {
public void dispose() {
// final Control control = ((PartSite)getMainEditorSite()).getPane().getControl();
// if(control != null && !control.isDisposed()) {
// ((PartSite)getMainEditorSite()).getPane().doHide();
// }
}
});
initializeDefaultServices();
}
/**
* Return the site of the main editor.
*
* @return
*/
private IWorkbenchPartSite getMainEditorSite() {
return mainEditorSite;
}
/**
* Return the EditorSite of the main editor.
* This is the same object as getMainEditorSite.
* TODO: Remove this one.
*
* @return
*/
private IEditorSite getMainEditorEditorSite() {
return mainEditorSite;
}
/**
* Initialize the slave services for this site.
*/
private void initializeDefaultServices() {
serviceLocator.registerService(IWorkbenchLocationService.class, new WorkbenchLocationService(IServiceScopes.MPESITE_SCOPE, getWorkbenchWindow().getWorkbench(), getWorkbenchWindow(), getMainEditorSite(), this, null, 3));
// Cedric: Does not seem to be used in indigo
// serviceLocator.registerService(IMultiPageEditorSiteHolder.class,
// new IMultiPageEditorSiteHolder() {
// public MultiPageEditorSite getSite() {
// return MultiPageEditorSite.this;
// }
// });
}
/**
* Notifies the multi page editor service that the component within which it
* exists has become active.
*
* @since 3.2
*/
public final void activate() {
serviceLocator.activate();
}
/**
* Notifies the multi page editor service that the component within which it
* exists has been deactived.
*
* @since 3.2
*/
public final void deactivate() {
serviceLocator.deactivate();
}
/**
* Dispose the contributions.
*/
public void dispose() {
if(menuExtenders != null) {
for(int i = 0; i < menuExtenders.size(); i++) {
((PopupMenuExtender)menuExtenders.get(i)).dispose();
}
menuExtenders = null;
}
// Remove myself from the list of nested key binding services.
if(service != null) {
// TODO : check original implem - use main editor site !
IKeyBindingService parentService = getMainEditorSite().getKeyBindingService();
if(parentService instanceof INestableKeyBindingService) {
INestableKeyBindingService nestableParent = (INestableKeyBindingService)parentService;
nestableParent.removeKeyBindingService(this);
}
// TODO : dispose service ?
if(service instanceof KeyBindingService) {
((KeyBindingService)service).dispose();
}
service = null;
}
if(serviceLocator != null) {
serviceLocator.dispose();
}
// dispose properties to help GC
setSelectionProvider(null);
mainEditorSite = null;
editor = null;
actionBarContributor = null;
}
/**
* The <code>MultiPageEditorSite</code> implementation of this <code>IEditorSite</code> method returns the EditorActionBarContributor associated
* to the site if one is defined,
* or the EditorActionBarContributor of the multiEditor.
*
* @return <code>null</code>
*/
public IEditorActionBarContributor getActionBarContributor() {
// If we use an action bar contributor, look for a registered ActionBarContributor.
// TODO : enable next asap
// ActionBarContributor contributor = multiPageEditor.getEditorSite().getActionBarContributor();
// if(contributor instanceof ComposedActionBarContributor)
// {
// ComposedActionBarContributor composedContributor = (ComposedActionBarContributor)contributor;
// return composedContributor.getContributorFor(editor);
// }
// Return the main ActionBarContributor, usually ComposedActionBarContributor
if(actionBarContributor != null) {
return actionBarContributor;
} else {
return getMainEditorEditorSite().getActionBarContributor();
// return null;
}
}
/**
* The <code>MultiPageEditorSite</code> implementation of this <code>IEditorSite</code> method forwards to the multi-page editor to
* return the action bars.
*
* @return The action bars from the parent multi-page editor.
*/
public IActionBars getActionBars() {
return getMainEditorEditorSite().getActionBars();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
*/
public Object getAdapter(Class adapter) {
return null;
}
/**
* The <code>MultiPageEditorSite</code> implementation of this <code>IWorkbenchPartSite</code> method forwards to the multi-page editor
* to return the decorator manager.
*
* @return The decorator from the workbench window.
* @deprecated use IWorkbench.getDecoratorManager()
*/
@Deprecated
public ILabelDecorator getDecoratorManager() {
return getWorkbenchWindow().getWorkbench().getDecoratorManager().getLabelDecorator();
}
/**
* Returns the nested editor.
*
* @return the nested editor
*/
public IEditorPart getEditor() {
return editor;
}
/**
* The <code>MultiPageEditorSite</code> implementation of this <code>IWorkbenchPartSite</code> method returns an empty string since the
* nested editor is not created from the registry.
*
* @return An empty string.
*/
public String getId() {
return ""; //$NON-NLS-1$
}
/*
* (non-Javadoc) Method declared on IEditorSite.
*/
public IKeyBindingService getKeyBindingService() {
if(service == null) {
service = getMainEditorEditorSite().getKeyBindingService();
if(service instanceof INestableKeyBindingService) {
INestableKeyBindingService nestableService = (INestableKeyBindingService)service;
service = nestableService.getKeyBindingService(this);
} else {
/*
* This is an internal reference, and should not be copied by
* client code. If you are thinking of copying this, DON'T DO
* IT.
*/
WorkbenchPlugin.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$
}
}
return service;
}
/**
* The <code>MultiPageEditorSite</code> implementation of this <code>IWorkbenchPartSite</code> method forwards to the multi-page editor
* to return the workbench page.
*
* @return The workbench page in which this editor site resides.
*/
public IWorkbenchPage getPage() {
return getMainEditorSite().getPage();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.IWorkbenchPartSite#getPart()
*/
public IWorkbenchPart getPart() {
return editor;
}
/**
* The <code>MultiPageEditorSite</code> implementation of this <code>IWorkbenchPartSite</code> method returns an empty string since the
* nested editor is not created from the registry.
*
* @return An empty string.
*/
public String getPluginId() {
return ""; //$NON-NLS-1$
}
/**
* Returns the post selection change listener which listens to the nested
* editor's selection changes.
*
* @return the post selection change listener.
*/
private ISelectionChangedListener getPostSelectionChangedListener() {
if(postSelectionChangedListener == null) {
postSelectionChangedListener = new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
MultiPageEditorSite.this.handlePostSelectionChanged(event);
}
};
}
return postSelectionChangedListener;
}
/**
* The <code>MultiPageEditorSite</code> implementation of this <code>IWorkbenchPartSite</code> method returns an empty string since the
* nested editor is not created from the registry.
*
* @return An empty string.
*/
public String getRegisteredName() {
return ""; //$NON-NLS-1$
}
/**
* Returns the selection changed listener which listens to the nested
* editor's selection changes, and calls <code>handleSelectionChanged</code> .
*
* @return the selection changed listener
*/
private ISelectionChangedListener getSelectionChangedListener() {
if(selectionChangedListener == null) {
selectionChangedListener = new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
MultiPageEditorSite.this.handleSelectionChanged(event);
}
};
}
return selectionChangedListener;
}
/**
* The <code>MultiPageEditorSite</code> implementation of this <code>IWorkbenchPartSite</code> method returns the selection provider set
* by <code>setSelectionProvider</code>.
*
* @return The current selection provider.
*/
public ISelectionProvider getSelectionProvider() {
return selectionProvider;
}
public final Object getService(final Class key) {
return serviceLocator.getService(key);
}
/**
* The <code>MultiPageEditorSite</code> implementation of this <code>IWorkbenchPartSite</code> method forwards to the multi-page editor
* to return the shell.
*
* @return The shell in which this editor site resides.
*/
public Shell getShell() {
return getMainEditorSite().getShell();
}
/**
* The <code>MultiPageEditorSite</code> implementation of this <code>IWorkbenchPartSite</code> method forwards to the multi-page editor
* to return the workbench window.
*
* @return The workbench window in which this editor site resides.
*/
public IWorkbenchWindow getWorkbenchWindow() {
return getMainEditorSite().getWorkbenchWindow();
}
/**
* Handles a post selection changed even from the nexted editor.
* <p>
* Subclasses may extend or reimplement this method
*
* @param event
* the event
*
* @since 3.2
*/
protected void handlePostSelectionChanged(SelectionChangedEvent event) {
ISelectionProvider parentProvider = getMainEditorSite().getSelectionProvider();
// TODO : use org.eclipse.ui.part.MultiPageSelectionProvider ?
if(parentProvider instanceof MultiPageSelectionProvider) {
SelectionChangedEvent newEvent = new SelectionChangedEvent(parentProvider, event.getSelection());
MultiPageSelectionProvider prov = (MultiPageSelectionProvider)parentProvider;
prov.firePostSelectionChanged(newEvent);
}
}
/**
* Handles a selection changed event from the nested editor. The default
* implementation gets the selection provider from the multi-page editor's
* site, and calls <code>fireSelectionChanged</code> on it (only if it is an
* instance of <code>MultiPageSelectionProvider</code>), passing a new event
* object.
* <p>
* Subclasses may extend or reimplement this method.
* </p>
*
* @param event
* the event
*/
protected void handleSelectionChanged(SelectionChangedEvent event) {
ISelectionProvider parentProvider = getMainEditorSite().getSelectionProvider();
if(parentProvider instanceof MultiPageSelectionProvider) {
SelectionChangedEvent newEvent = new SelectionChangedEvent(parentProvider, event.getSelection());
MultiPageSelectionProvider prov = (MultiPageSelectionProvider)parentProvider;
prov.fireSelectionChanged(newEvent);
}
}
public final boolean hasService(final Class key) {
return serviceLocator.hasService(key);
}
/**
* The <code>MultiPageEditorSite</code> implementation of this <code>IWorkbenchPartSite</code> method forwards to the multi-page editor
* for registration.
*
* @param menuManager
* The menu manager
* @param selProvider
* The selection provider.
*/
public void registerContextMenu(MenuManager menuManager, ISelectionProvider selProvider) {
getMainEditorSite().registerContextMenu(menuManager, selProvider);
}
public final void registerContextMenu(final MenuManager menuManager, final ISelectionProvider selectionProvider, final boolean includeEditorInput) {
registerContextMenu(getId(), menuManager, selectionProvider, includeEditorInput);
}
/**
* The <code>MultiPageEditorSite</code> implementation of this <code>IWorkbenchPartSite</code> method forwards to the multi-page editor
* for registration.
*
* @param menuID
* The identifier for the menu.
* @param menuMgr
* The menu manager
* @param selProvider
* The selection provider.
*/
public void registerContextMenu(String menuID, MenuManager menuMgr, ISelectionProvider selProvider) {
if(menuExtenders == null) {
menuExtenders = new ArrayList(1);
}
registerContextMenu(menuID, menuMgr, selProvider, true, editor, menuExtenders);
}
public final void registerContextMenu(final String menuId, final MenuManager menuManager, final ISelectionProvider selectionProvider, final boolean includeEditorInput) {
if(menuExtenders == null) {
menuExtenders = new ArrayList(1);
}
registerContextMenu(menuId, menuManager, selectionProvider, includeEditorInput, editor, menuExtenders);
}
/**
* The <code>MultiPageEditorSite</code> implementation of this <code>IWorkbenchPartSite</code> method remembers the selection provider,
* and also hooks a listener on it, which calls <code>handleSelectionChanged</code> when a selection changed event
* occurs.
*
* @param provider
* The selection provider.
* @see MultiPageEditorSite#handleSelectionChanged(SelectionChangedEvent)
*/
public void setSelectionProvider(ISelectionProvider provider) {
ISelectionProvider oldSelectionProvider = selectionProvider;
selectionProvider = provider;
if(oldSelectionProvider != null) {
//see code WindowSelectionService (line287)
// in some case as GraphicalView do not implement IPostSelectionProvider
oldSelectionProvider.removeSelectionChangedListener(getSelectionChangedListener());
if(oldSelectionProvider instanceof IPostSelectionProvider) {
((IPostSelectionProvider)oldSelectionProvider).removePostSelectionChangedListener(getPostSelectionChangedListener());
} else {
oldSelectionProvider.removeSelectionChangedListener(getPostSelectionChangedListener());
}
}
if(selectionProvider != null) {
selectionProvider.addSelectionChangedListener(getSelectionChangedListener());
if(selectionProvider instanceof IPostSelectionProvider) {
((IPostSelectionProvider)selectionProvider).addPostSelectionChangedListener(getPostSelectionChangedListener());
} else {
selectionProvider.addSelectionChangedListener(getPostSelectionChangedListener());
}
}
}
/**
* This is a helper method for the register context menu functionality. It
* is provided so that different implementations of the <code>IWorkbenchPartSite</code> interface don't have to worry about how
* context menus should work.
*
* @param menuId
* the menu id
* @param menuManager
* the menu manager
* @param selectionProvider
* the selection provider
* @param includeEditorInput
* whether editor inputs should be included in the structured
* selection when calculating contributions
* @param part
* the part for this site
* @param menuExtenders
* the collection of menu extenders for this site
* @see IWorkbenchPartSite#registerContextMenu(MenuManager, ISelectionProvider)
*/
public static final void registerContextMenu(final String menuId, final MenuManager menuManager, final ISelectionProvider selectionProvider, final boolean includeEditorInput, final IWorkbenchPart part, final Collection menuExtenders) {
/*
* Check to see if the same menu manager and selection provider have
* already been used. If they have, then we can just add another menu
* identifier to the existing PopupMenuExtender.
*/
final Iterator extenderItr = menuExtenders.iterator();
boolean foundMatch = false;
while(extenderItr.hasNext()) {
final PopupMenuExtender existingExtender = (PopupMenuExtender)extenderItr.next();
if(existingExtender.matches(menuManager, selectionProvider, part)) {
existingExtender.addMenuId(menuId);
foundMatch = true;
break;
}
}
if(!foundMatch) {
//Internal code conflict between 3.8.x and 4.2.2: the Constructor signature has changed. We need to invoke it reflexively in order to compile the code on 4.2.2 and run it on 3.8.x
try {
Constructor<PopupMenuExtender> constructor = PopupMenuExtender.class.getConstructor(String.class, MenuManager.class, ISelectionProvider.class, IWorkbenchPart.class, boolean.class);
PopupMenuExtender extender = constructor.newInstance(menuId, menuManager, selectionProvider, part, includeEditorInput);
menuExtenders.add(extender);
} catch (Exception ex) {
Activator.log.error(ex);
}
}
}
}