| /******************************************************************************* |
| * Copyright (c) 2008, 2009 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.e4.compatibility; |
| |
| import java.util.HashMap; |
| import java.util.Map; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IConfigurationElement; |
| import org.eclipse.e4.core.contexts.IEclipseContext; |
| import org.eclipse.e4.extensions.ExtensionUtils; |
| import org.eclipse.e4.extensions.ModelEditorReference; |
| import org.eclipse.e4.ui.internal.workbench.Trackable; |
| import org.eclipse.e4.ui.internal.workbench.swt.AbstractPartRenderer; |
| import org.eclipse.e4.ui.model.application.ui.basic.MPart; |
| import org.eclipse.e4.ui.widgets.CTabFolder; |
| import org.eclipse.e4.ui.widgets.CTabItem; |
| import org.eclipse.swt.events.DisposeEvent; |
| import org.eclipse.swt.events.DisposeListener; |
| import org.eclipse.swt.layout.FillLayout; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.ui.IEditorActionBarContributor; |
| import org.eclipse.ui.IEditorInput; |
| import org.eclipse.ui.IEditorPart; |
| import org.eclipse.ui.IPropertyListener; |
| import org.eclipse.ui.IViewPart; |
| import org.eclipse.ui.IWorkbenchPart; |
| import org.eclipse.ui.IWorkbenchWindow; |
| import org.eclipse.ui.SubActionBars; |
| import org.eclipse.ui.internal.EditorActionBars; |
| import org.eclipse.ui.internal.EditorActionBuilder; |
| import org.eclipse.ui.internal.EditorSite; |
| import org.eclipse.ui.internal.ViewSite; |
| import org.eclipse.ui.internal.WorkbenchPage; |
| import org.eclipse.ui.internal.registry.EditorDescriptor; |
| import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants; |
| |
| /** |
| * This class is an implementation of an MPart that can be used to host a 3.x |
| * EditorPart into an Eclipse 4.0 application. |
| * |
| * @since 4.0 |
| * |
| */ |
| public class LegacyEditor { |
| public final static String LEGACY_VIEW_URI = "bundleclass://org.eclipse.ui.workbench/org.eclipse.e4.compatibility.LegacyEditor"; //$NON-NLS-1$ |
| |
| private static final String IS_DIRTY = "isDirty"; //$NON-NLS-1$ |
| private static final String EDITOR_DISPOSED = "editorDisposed"; //$NON-NLS-1$ |
| |
| private MPart editorPart; |
| private IEditorPart editorWBPart; |
| |
| private Map<IEditorPart, Trackable> trackables = new HashMap<IEditorPart, Trackable>(); |
| |
| /** |
| * Create and initialize a 3.x editor from an e4 contribution |
| * |
| * @param parent |
| * The SWT parent for the editor |
| * @param context |
| * The context under which this part is being created |
| * @param part |
| * The MPart representing the editor |
| */ |
| public LegacyEditor(final Composite parent, IEclipseContext context, |
| final MPart part) { |
| editorPart = part; |
| |
| IConfigurationElement editorElement = findEditorConfig(part.getId()); |
| |
| EditorDescriptor desc = new EditorDescriptor(part.getId(), |
| editorElement); |
| |
| parent.setLayout(new FillLayout()); |
| |
| // Convert the relative path into a bundle URI |
| String imagePath = editorElement.getAttribute("icon"); //$NON-NLS-1$ |
| String imageURI = imagePath; |
| if (!imagePath.startsWith("platform:")) { //$NON-NLS-1$ |
| imagePath = imagePath.replace("$nl$", ""); //$NON-NLS-1$//$NON-NLS-2$ |
| if (imagePath.charAt(0) != '/') { |
| imagePath = '/' + imagePath; |
| } |
| String bundleId = editorElement.getContributor().getName(); |
| imageURI = "platform:/plugin/" + bundleId + imagePath; //$NON-NLS-1$ |
| } |
| |
| part.setIconURI(imageURI); |
| |
| try { |
| editorWBPart = desc.createEditor(); |
| } catch (CoreException e) { |
| e.printStackTrace(); |
| } |
| |
| if (editorWBPart == null) |
| return; |
| |
| try { |
| final IEclipseContext localContext = part.getContext(); |
| IEclipseContext parentContext = (IEclipseContext) localContext |
| .get(IContextConstants.PARENT); |
| |
| localContext.set(IContextConstants.DEBUG_STRING, "Legacy Editor(" //$NON-NLS-1$ |
| + desc.getLabel() + ")"); //$NON-NLS-1$ |
| parentContext.set(IContextConstants.ACTIVE_CHILD, localContext); |
| |
| part.setObject(editorWBPart); |
| // Assign a 'site' for the newly instantiated part |
| WorkbenchPage page = (WorkbenchPage) localContext |
| .get(WorkbenchPage.class.getName()); |
| ModelEditorReference ref = new ModelEditorReference(part, page); |
| EditorSite site = new EditorSite(ref, editorWBPart, page); |
| EditorActionBars bars = getEditorActionBars(desc, page, |
| page.getWorkbenchWindow(), part.getId()); |
| site.setActionBars(bars); |
| site.setConfigurationElement(editorElement); |
| editorWBPart.init(site, (IEditorInput) localContext |
| .get(IEditorInput.class.getName())); |
| |
| editorWBPart.createPartControl(parent); |
| localContext.set(MPart.class.getName(), part); |
| |
| // HACK!! presumes it's the -last- child of the parent |
| if (parent.getChildren().length > 0) { |
| Control newCtrl = parent.getChildren()[parent.getChildren().length - 1]; |
| newCtrl.addDisposeListener(new DisposeListener() { |
| public void widgetDisposed(DisposeEvent e) { |
| disposeEditor(editorPart); |
| } |
| }); |
| } |
| |
| // Manage the 'dirty' state |
| final IEditorPart implementation = editorWBPart; |
| localContext.set(IS_DIRTY, implementation.isDirty()); |
| localContext.set(EDITOR_DISPOSED, Boolean.FALSE); |
| |
| Trackable updateDirty = new Trackable(localContext) { |
| private CTabItem findItemForPart(CTabFolder ctf) { |
| CTabItem[] items = ctf.getItems(); |
| for (int i = 0; i < items.length; i++) { |
| if (items[i].getData(AbstractPartRenderer.OWNING_ME) == part) { |
| return items[i]; |
| } |
| } |
| |
| return null; |
| } |
| |
| public void run() { |
| if (!participating) { |
| return; |
| } |
| trackingContext.get(EDITOR_DISPOSED); |
| boolean dirty = (Boolean) trackingContext.get(IS_DIRTY); |
| if (parent instanceof CTabFolder) { |
| CTabFolder ctf = (CTabFolder) parent; |
| CTabItem partItem = findItemForPart(ctf); |
| if (partItem == null) |
| return; |
| |
| String itemText = partItem.getText(); |
| if (dirty && itemText.indexOf('*') != 0) { |
| itemText = '*' + itemText; |
| } else if (itemText.indexOf('*') == 0) { |
| itemText = itemText.substring(1); |
| } |
| partItem.setText(itemText); |
| } |
| } |
| }; |
| trackables.put(implementation, updateDirty); |
| localContext.runAndTrack(updateDirty); |
| editorWBPart.addPropertyListener(new IPropertyListener() { |
| public void propertyChanged(Object source, int propId) { |
| localContext.set(IS_DIRTY, implementation.isDirty()); |
| } |
| }); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| } |
| } |
| |
| protected void disposeEditor(MPart part) { |
| Object obj = part.getObject(); |
| if (!(obj instanceof IWorkbenchPart)) |
| return; |
| |
| if (obj instanceof IEditorPart) { |
| Activator.trace(Policy.DEBUG_RENDERER, |
| "Disposing tracker for " + obj, null); //$NON-NLS-1$ |
| Trackable t = trackables.remove(obj); |
| t.participating = false; |
| part.getContext().set(EDITOR_DISPOSED, Boolean.TRUE); |
| } |
| ((IWorkbenchPart) obj).dispose(); |
| if (obj instanceof IEditorPart) { |
| EditorSite site = (EditorSite) ((IEditorPart) obj).getEditorSite(); |
| disposeEditorActionBars((EditorActionBars) site.getActionBars()); |
| site.dispose(); |
| } else if (obj instanceof IViewPart) { |
| ViewSite site = (ViewSite) ((IViewPart) obj).getViewSite(); |
| SubActionBars bars = (SubActionBars) site.getActionBars(); |
| bars.dispose(); |
| site.dispose(); |
| } |
| part.setObject(null); |
| } |
| |
| Map<String, EditorActionBars> actionCache = new HashMap<String, EditorActionBars>(); |
| |
| private EditorActionBars getEditorActionBars(EditorDescriptor desc, |
| WorkbenchPage page, IWorkbenchWindow workbenchWindow, String type) { |
| // Get the editor type. |
| |
| // If an action bar already exists for this editor type return it. |
| EditorActionBars actionBars = actionCache.get(type); |
| if (actionBars != null) { |
| actionBars.addRef(); |
| return actionBars; |
| } |
| |
| // Create a new action bar set. |
| actionBars = new EditorActionBars(page, workbenchWindow, type); |
| actionBars.addRef(); |
| actionCache.put(type, actionBars); |
| |
| // Read base contributor. |
| IEditorActionBarContributor contr = desc.createActionBarContributor(); |
| if (contr != null) { |
| actionBars.setEditorContributor(contr); |
| contr.init(actionBars, page); |
| } |
| |
| // Read action extensions. |
| EditorActionBuilder builder = new EditorActionBuilder(); |
| contr = builder.readActionExtensions(desc); |
| if (contr != null) { |
| actionBars.setExtensionContributor(contr); |
| contr.init(actionBars, page); |
| } |
| |
| // Return action bars. |
| return actionBars; |
| } |
| |
| private void disposeEditorActionBars(EditorActionBars actionBars) { |
| actionBars.removeRef(); |
| if (actionBars.getRef() <= 0) { |
| String type = actionBars.getEditorType(); |
| actionCache.remove(type); |
| actionBars.dispose(); |
| } |
| } |
| |
| private IConfigurationElement findEditorConfig(String id) { |
| IConfigurationElement[] editors = ExtensionUtils |
| .getExtensions(IWorkbenchRegistryConstants.PL_EDITOR); |
| IConfigurationElement editorContribution = ExtensionUtils |
| .findExtension(editors, id); |
| return editorContribution; |
| } |
| |
| /** |
| * @return The client implementation of their 3.x part |
| */ |
| public IEditorPart getEditorWBPart() { |
| return editorWBPart; |
| } |
| } |