/*******************************************************************************
* 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.e4.core.contexts.ContextFunction;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
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.swt.widgets.Widget;
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.contexts.IContextService;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.internal.KeyBindingService;
import org.eclipse.ui.internal.PartSite;
import org.eclipse.ui.internal.PopupMenuExtender;
import org.eclipse.ui.internal.WorkbenchPlugin;
import org.eclipse.ui.internal.contexts.NestableContextService;
import org.eclipse.ui.internal.expressions.ActivePartExpression;
import org.eclipse.ui.internal.handlers.LegacyHandlerService;
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.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>
*
* This class only compile with Eclipse version starting from [4.2
* On previous versions, use MultiPageEditorSite
*
* @see org.eclipse.ui.part.MultiPageEditorSite.class
*/
public class MultiPageEditorSite4x 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 MultiPageEditorSite4x#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;
/** Since 4.x */
private NestableContextService contextService;
/** Since 4.x */
private IEclipseContext context;
private boolean active = false;
/**
* 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 MultiPageEditorSite4x(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();
// }
// }
// });
// Updated for e4
// Copied from CT org.eclipse.ui.part.MultiPageEditorSite()
PartSite site = (PartSite)mainEditorSite;
IServiceLocatorCreator slc = (IServiceLocatorCreator)mainEditorSite.getService(IServiceLocatorCreator.class);
this.serviceLocator = (ServiceLocator)slc.createServiceLocator(getMainEditorSite(), null, new IDisposable() {
public void dispose() {
// Check close method in original MPE
// getMultiPageEditor().close();
// copied from 4.2 org.eclipse.ui.part.MultiPageEditorPart.close()
// 3.x implementation closes the editor when the ISL is disposed
PartSite partSite = (PartSite)getMainEditorSite();
MPart model = partSite.getModel();
Widget widget = (Widget)model.getWidget();
if(widget != null && !widget.isDisposed()) {
getMainEditorSite().getPage().closeEditor(getMultiPageEditorPart(), true);
}
}
});
context = site.getModel().getContext().createChild("MultiPageEditorSite"); //$NON-NLS-1$
serviceLocator.setContext(context);
initializeDefaultServices();
}
/**
* Returns the multi-page editor.
*
* @return the multi-page editor
*/
public IEditorPart getMultiPageEditorPart() {
return (IEditorPart)mainEditorSite.getPart();
}
/**
* 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));
// serviceLocator.registerService(IMultiPageEditorSiteHolder.class,
// new IMultiPageEditorSiteHolder() {
// public MultiPageEditorSite getSite() {
// return MultiPageEditorSite.this;
// }
// });
context.set(IContextService.class.getName(), new ContextFunction() {
@Override
public Object compute(IEclipseContext ctxt) {
if(contextService == null) {
contextService = new NestableContextService(ctxt.getParent().get(IContextService.class), new ActivePartExpression(mainEditorSite.getPart()));
}
return contextService;
}
});
// create a local handler service so that when this page
// activates/deactivates, its handlers will also be taken into/out of
// consideration during handler lookups
IHandlerService handlerService = new LegacyHandlerService(context);
context.set(IHandlerService.class, handlerService);
}
/**
* Notifies the multi page editor service that the component within which it
* exists has become active.
*
* @since 3.2
*/
public final void activate() {
active = true;
context.activate();
serviceLocator.activate();
if(contextService != null) {
contextService.activate();
}
}
/**
* Notifies the multi page editor service that the component within which it
* exists has been deactived.
*
* @since 3.2
*/
public final void deactivate() {
active = false;
if(contextService != null) {
contextService.deactivate();
}
serviceLocator.deactivate();
context.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(contextService != null) {
contextService.dispose();
}
if(serviceLocator != null) {
serviceLocator.dispose();
}
context.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) {
MultiPageEditorSite4x.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) {
MultiPageEditorSite4x.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) {
Object service = serviceLocator.getService(key);
if(active && service instanceof INestable) {
// services need to know that it is currently in an active state
((INestable)service).activate();
}
return service;
}
/**
* 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, context, 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, context, 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 MultiPageEditorSite4x#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 IEclipseContext context, final Collection menuExtenders) {
try {
//4.2.2
PartSite.registerContextMenu(menuId, menuManager, selectionProvider, includeEditorInput, part, context, menuExtenders);
} catch (NoSuchMethodError ex) {
//Method not found (4.2.0, 4.2.1)
/*
* 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) {
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 ex2) {
Activator.log.error(ex2);
}
}
}
}
}