/******************************************************************************* * Copyright (c) 2005 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.bpel.common.ui.composite; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import org.eclipse.bpel.common.ui.CommonUIPlugin; import org.eclipse.bpel.common.ui.Messages; import org.eclipse.bpel.common.ui.Utils; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.action.IMenuManager; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.ui.IEditorActionBarContributor; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorReference; import org.eclipse.ui.IEditorSite; import org.eclipse.ui.internal.EditorActionBuilder; import org.eclipse.ui.internal.EditorSite; import org.eclipse.ui.internal.WorkbenchPage; import org.eclipse.ui.internal.registry.EditorDescriptor; /** * Handles embedded editor's contributions activation and deactivation. */ public class CompositeEditorManager { protected WorkbenchPage page; protected IEditorSite mainEditorSite; protected Map idToDescriptor; private static final String EXTPT_EMBEDDED_EDITORS = "embeddedEditors"; //$NON-NLS-1$ private static final String CHILD_EDITOR = "editor"; //$NON-NLS-1$ private static final String ATT_EDITOR_ID = "id"; //$NON-NLS-1$ private static final String ATT_EDITOR_CLASS = "class"; //$NON-NLS-1$ public CompositeEditorManager(IEditorSite mainEditorSite) { this.mainEditorSite = mainEditorSite; idToDescriptor = new HashMap(10); page = (WorkbenchPage) mainEditorSite.getPage(); } /** * Creates and initializes an IEditorPart given its id and input. */ public IEditorPart createEditor(String editorId, IEditorInput input) throws CoreException { IEditorPart editor = instantiateEditor(editorId); EditorSite site = createEditorSite(editorId, editor); editor.init(site, input); // Force menus to be created. IMenuManager menuManager = mainEditorSite.getActionBars().getMenuManager(); menuManager.setVisible(false); menuManager.setVisible(true); return editor; } /** * Instantiates an editor given its id. The editor id has to be declared * through the <code>embeddedEditors</code> extension point. * * @throws CoreException if the editorId is not found */ protected IEditorPart instantiateEditor(String editorId) throws CoreException { EditorDescriptor descriptor = (EditorDescriptor) idToDescriptor.get(editorId); if (descriptor == null) { descriptor = readDescriptor(editorId); if (descriptor == null) { IStatus status = new Status(IStatus.ERROR, CommonUIPlugin.PLUGIN_ID, ICompositeEditorConstants.COULD_NOT_INSTANTIATE_EDITOR, NLS.bind(Messages.CompositeEditorManager_Could_not_find_editor, (new Object[] { editorId })), null); throw new CoreException(status); } } return (IEditorPart) descriptor.getConfigurationElement().createExecutableExtension(ATT_EDITOR_CLASS); } /** * Creates an editor descriptor based on the information defined in the <code>embeddedEditors</code> * extension point for the given editorId. * * @return the editor descriptor or <code>null</code> if there none for the given editorId */ protected EditorDescriptor readDescriptor(String editorId) { IConfigurationElement[] elements = Utils.getConfigurationElements(EXTPT_EMBEDDED_EDITORS); for (int i = 0; i < elements.length; i++) { IConfigurationElement element = elements[i]; if (element.getName().equals(CHILD_EDITOR)) { String extensionId = element.getAttribute(ATT_EDITOR_ID); if (extensionId == null) { // the editor id is mandatory - log error String pluginId = element.getDeclaringExtension().getNamespace(); IStatus status = new Status(IStatus.ERROR, pluginId, ICompositeEditorConstants.MISSING_ATTRIBUTE, Messages.CompositeEditorManager_5, null); CommonUIPlugin.getDefault().getLog().log(status); } else if (editorId.equals(extensionId)) { // Use reflection to create and set state on an editor descriptor // This was done to avoid copying the class to this package try { Constructor constuctor = EditorDescriptor.class.getDeclaredConstructor(new Class[0]); constuctor.setAccessible(true); EditorDescriptor descriptor = (EditorDescriptor)constuctor.newInstance(new Object[0]); Method method = descriptor.getClass().getDeclaredMethod("setID", new Class[] {String.class}); method.setAccessible(true); method.invoke(descriptor, new Object[]{editorId}); method = descriptor.getClass().getDeclaredMethod("setConfigurationElement", new Class[] {IConfigurationElement.class}); method.setAccessible(true); method.invoke(descriptor, new Object[]{element}); idToDescriptor.put(editorId, descriptor); return descriptor; } catch (SecurityException e) { CommonUIPlugin.getDefault().createErrorStatus("Problem creating descriptor for " + editorId, e, true); } catch (IllegalArgumentException e) { CommonUIPlugin.getDefault().createErrorStatus("Problem creating descriptor for " + editorId, e, true); } catch (NoSuchMethodException e) { CommonUIPlugin.getDefault().createErrorStatus("Problem creating descriptor for " + editorId, e, true); } catch (InstantiationException e) { CommonUIPlugin.getDefault().createErrorStatus("Problem creating descriptor for " + editorId, e, true); } catch (IllegalAccessException e) { CommonUIPlugin.getDefault().createErrorStatus("Problem creating descriptor for " + editorId, e, true); } catch (InvocationTargetException e) { CommonUIPlugin.getDefault().createErrorStatus("Problem creating descriptor for " + editorId, e, true); } } } } return null; } /** * Creates and populates an editor site for the given editor. */ protected EditorSite createEditorSite(String editorId, IEditorPart editor) { EditorDescriptor descriptor = (EditorDescriptor) idToDescriptor.get(editorId); IEditorReference ref = new EditorReference(); EditorSite site = new CompositeEditorSite(mainEditorSite, ref, editor, page, descriptor); IEditorActionBarContributor contributor = descriptor.createActionBarContributor(); site.setActionBars(createEditorActionBars(descriptor, contributor, site)); return site; } /** * Creates the action bars for the given editor. It also searches for editor * contribution extensions. */ protected CompositeEditorActionBars createEditorActionBars(EditorDescriptor descriptor, IEditorActionBarContributor contributor, EditorSite site) { String type = String.valueOf(System.currentTimeMillis()); // IActionBars2 parentActionBars = (IActionBars2) mainEditorSite.getActionBars(); CompositeEditorActionBars actionBars = new CompositeEditorActionBars(page, site, type); if (contributor != null) { actionBars.setEditorContributor(contributor); contributor.init(actionBars, page); } // Read action extensions. EditorActionBuilder builder = new EditorActionBuilder(); IEditorActionBarContributor extension = builder.readActionExtensions(descriptor /*WDG , actionBars */); if (extension != null) { actionBars.setExtensionContributor(extension); extension.init(actionBars, page); } return actionBars; } /** * Activate contributions. */ public void activate(IEditorPart editor) { editor.setFocus(); IEditorSite site = editor.getEditorSite(); CompositeEditorActionBars actionBars = (CompositeEditorActionBars) site.getActionBars(); actionBars.partChanged(editor); actionBars.activate(true); ((CompositeEditorSite) site).activate(); } /** * Deactivate contributions. */ public void deactivate(IEditorPart editor) { if (editor != null) { CompositeEditorActionBars actionBars = (CompositeEditorActionBars) editor.getEditorSite().getActionBars(); actionBars.deactivate(true); IEditorSite site = editor.getEditorSite(); ((CompositeEditorSite) site).deactivate(); } } /** * Creates an embedded editor corresponding to the given editorId. * <p> * It is important to notice that the returned editor will never be * the workbench active part. * <p> * @param editorId the embedded editor id * @param editorComposite the editor's parent composite * @return IEditorPart the embedded editor instance * */ public IEditorPart createEditor(String editorId, IEditorInput input, Composite editorComposite) throws CoreException { final IEditorPart editor = createEditor(editorId, input); Composite composite = new Composite(editorComposite, SWT.NONE); composite.setLayout(new FillLayout()); editor.createPartControl(composite); // This is the fundamental part of our implementation. // Editors are activated when we get an Activate // event from the editor's composite. associate(editor, composite); return editor; } /** * Associates the control with the given editor. When the control * is activated all the editor contributions will be activated * as well. This is useful when the CompositeEditor is not only * composed by embedded editor but also by other controls. If no editor * is associated with these controls the available contributions * (menus, toolbars, status line, etc...) will be the contributions * for the last active editor and might cause confusion to the user. */ protected void associate(final IEditorPart editor, Control control) { control.addListener(SWT.Activate, new Listener() { public void handleEvent(Event event) { activate(editor); } }); control.addListener(SWT.Deactivate, new Listener() { public void handleEvent(Event event) { deactivate(editor); } }); } /** * Removes the given editor from this composite editor. If the given * editor is the current active editor the main editor will be activated * instead. The main editor cannot be disconnected by calling this * method. * * @exception CoreException if the editor cannot be disconnected. Reasons include: * <ul> * <li> The editor is the main editor.</li> * <li> The editor is the current active editor and the main editor was not defined.</li> * </ul> */ public void disposeEditor(IEditorPart editor) { CompositeEditorSite site = (CompositeEditorSite) editor.getSite(); CompositeEditorActionBars actionBars = (CompositeEditorActionBars) site.getActionBars(); actionBars.dispose(); site.dispose(); editor.dispose(); } }