| /******************************************************************************* |
| * Copyright (c) 2006, 2015 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| * Nikolay Botev - bug 240651 |
| * Andrey Loskutov <loskutov@gmx.de> - Bug 459964 |
| * Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654 |
| *******************************************************************************/ |
| package org.eclipse.ui.internal; |
| |
| import java.io.IOException; |
| import java.io.StringReader; |
| import java.io.StringWriter; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Map; |
| import java.util.Set; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.core.runtime.IConfigurationElement; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.e4.core.contexts.IEclipseContext; |
| import org.eclipse.e4.ui.model.application.ui.basic.MPart; |
| import org.eclipse.e4.ui.workbench.IPresentationEngine; |
| import org.eclipse.jface.internal.provisional.action.ICoolBarManager2; |
| import org.eclipse.jface.preference.IPreferenceStore; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.ui.IEditorActionBarContributor; |
| import org.eclipse.ui.IEditorInput; |
| import org.eclipse.ui.IEditorPart; |
| import org.eclipse.ui.IEditorReference; |
| import org.eclipse.ui.IEditorRegistry; |
| import org.eclipse.ui.IElementFactory; |
| import org.eclipse.ui.IMemento; |
| import org.eclipse.ui.IPersistableEditor; |
| import org.eclipse.ui.IPersistableElement; |
| import org.eclipse.ui.IWorkbenchPage; |
| import org.eclipse.ui.IWorkbenchPart; |
| import org.eclipse.ui.IWorkbenchPart3; |
| import org.eclipse.ui.PartInitException; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.WorkbenchException; |
| import org.eclipse.ui.XMLMemento; |
| import org.eclipse.ui.internal.editorsupport.ComponentSupport; |
| import org.eclipse.ui.internal.part.NullEditorInput; |
| import org.eclipse.ui.internal.registry.EditorDescriptor; |
| import org.eclipse.ui.internal.registry.EditorRegistry; |
| import org.eclipse.ui.internal.util.Util; |
| |
| public class EditorReference extends WorkbenchPartReference implements IEditorReference { |
| |
| private IEditorInput input; |
| private EditorDescriptor descriptor; |
| private final String descriptorId; |
| private final IMemento editorState; |
| private final String factoryId; |
| |
| public EditorReference(IEclipseContext windowContext, IWorkbenchPage page, MPart part, IEditorInput input, |
| EditorDescriptor descriptor, IMemento editorState) { |
| super(windowContext, page, part); |
| this.input = input; |
| this.descriptor = descriptor; |
| this.editorState = editorState; |
| |
| String factory = null; |
| if (descriptor == null) { |
| String memento = getModel().getPersistedState().get(MEMENTO_KEY); |
| if (memento == null) { |
| descriptorId = EditorRegistry.EMPTY_EDITOR_ID; |
| } else { |
| XMLMemento createReadRoot; |
| try { |
| createReadRoot = XMLMemento.createReadRoot(new StringReader(memento)); |
| } catch (WorkbenchException e) { |
| WorkbenchPlugin.log(e); |
| descriptorId = EditorRegistry.EMPTY_EDITOR_ID; |
| factoryId = null; |
| return; |
| } |
| IEditorRegistry registry = getPage().getWorkbenchWindow().getWorkbench().getEditorRegistry(); |
| descriptorId = createReadRoot.getString(IWorkbenchConstants.TAG_ID); |
| this.descriptor = (EditorDescriptor) registry.findEditor(descriptorId); |
| |
| boolean pinnedVal = "true".equals(createReadRoot.getString(IWorkbenchConstants.TAG_PINNED)); //$NON-NLS-1$ |
| setPinned(pinnedVal); |
| |
| String ttip = createReadRoot.getString(IWorkbenchConstants.TAG_TOOLTIP); |
| part.getTransientData().put(IPresentationEngine.OVERRIDE_TITLE_TOOL_TIP_KEY, ttip); |
| |
| IMemento inputMem = createReadRoot.getChild(IWorkbenchConstants.TAG_INPUT); |
| if (inputMem != null) { |
| factory = inputMem.getString(IWorkbenchConstants.TAG_FACTORY_ID); |
| } |
| } |
| } else { |
| descriptorId = this.descriptor.getId(); |
| } |
| factoryId = factory; |
| } |
| |
| boolean persist() { |
| XMLMemento persistedState = (XMLMemento) getEditorState(); |
| if (persistedState == null) |
| return false; |
| |
| StringWriter writer = new StringWriter(); |
| try { |
| persistedState.save(writer); |
| getModel().getPersistedState().put(MEMENTO_KEY, writer.toString()); |
| } catch (IOException e) { |
| WorkbenchPlugin.log(e); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| IMemento getEditorState() { |
| IEditorPart editor = getEditor(false); |
| |
| // If the editor hasn't been rendered yet then see if we can grab the |
| // info from the model |
| if (editor == null && getModel() != null) { |
| String savedState = getModel().getPersistedState().get(MEMENTO_KEY); |
| if (savedState != null) { |
| StringReader sr = new StringReader(savedState); |
| try { |
| return XMLMemento.createReadRoot(sr); |
| } catch (WorkbenchException e) { |
| WorkbenchPlugin.log(e); |
| return null; |
| } |
| } |
| return null; |
| } |
| |
| IEditorInput input = editor.getEditorInput(); |
| if (input == null) { |
| return null; |
| } |
| |
| IPersistableElement persistable = input.getPersistable(); |
| if (persistable == null) { |
| return null; |
| } |
| |
| XMLMemento editorMem = XMLMemento.createWriteRoot(IWorkbenchConstants.TAG_EDITOR); |
| editorMem.putString(IWorkbenchConstants.TAG_ID, descriptor.getId()); |
| editorMem.putString(IWorkbenchConstants.TAG_TITLE, getTitle()); |
| editorMem.putString(IWorkbenchConstants.TAG_NAME, getName()); |
| editorMem.putString(IWorkbenchConstants.TAG_ID, getId()); |
| editorMem.putString(IWorkbenchConstants.TAG_TOOLTIP, getTitleToolTip()); |
| editorMem.putString(IWorkbenchConstants.TAG_PART_NAME, getPartName()); |
| |
| if (editor instanceof IWorkbenchPart3) { |
| Map<String, String> properties = ((IWorkbenchPart3) editor).getPartProperties(); |
| if (!properties.isEmpty()) { |
| IMemento propBag = editorMem.createChild(IWorkbenchConstants.TAG_PROPERTIES); |
| for (Map.Entry<String, String> entry : properties.entrySet()) { |
| IMemento p = propBag.createChild(IWorkbenchConstants.TAG_PROPERTY, entry.getKey()); |
| p.putTextData(entry.getValue()); |
| } |
| } |
| } |
| |
| if (isPinned()) { |
| editorMem.putString(IWorkbenchConstants.TAG_PINNED, "true"); //$NON-NLS-1$ |
| } |
| |
| IMemento inputMem = editorMem.createChild(IWorkbenchConstants.TAG_INPUT); |
| inputMem.putString(IWorkbenchConstants.TAG_FACTORY_ID, persistable.getFactoryId()); |
| persistable.saveState(inputMem); |
| |
| if (editor instanceof IPersistableEditor) { |
| IMemento editorStateMem = editorMem.createChild(IWorkbenchConstants.TAG_EDITOR_STATE); |
| ((IPersistableEditor) editor).saveState(editorStateMem); |
| } |
| |
| return editorMem; |
| } |
| |
| public EditorDescriptor getDescriptor() { |
| return descriptor; |
| } |
| |
| @Override |
| public String getId() { |
| // by default we delegate to the model part, which is not correct for |
| // editors |
| return descriptorId; |
| } |
| |
| @Override |
| public String getFactoryId() { |
| IEditorPart editor = getEditor(false); |
| if (editor == null) { |
| if (input == null) { |
| return factoryId; |
| } |
| |
| IPersistableElement persistable = input.getPersistable(); |
| return persistable == null ? null : persistable.getFactoryId(); |
| } |
| |
| IPersistableElement persistable = editor.getEditorInput().getPersistable(); |
| return persistable == null ? null : persistable.getFactoryId(); |
| } |
| |
| @Override |
| public String getName() { |
| IEditorPart editor = getEditor(false); |
| if (input == null) { |
| return editor == null ? getModel().getLocalizedLabel() : editor.getEditorInput().getName(); |
| } |
| return editor == null ? input.getName() : editor.getEditorInput().getName(); |
| } |
| |
| @Override |
| public String getTitle() { |
| String label = Util.safeString(getModel().getLocalizedLabel()); |
| if (label.isEmpty()) { |
| if (input == null) { |
| if (descriptor != null) { |
| return descriptor.getLabel(); |
| } |
| } else { |
| return Util.safeString(input.getName()); |
| } |
| } |
| return label; |
| } |
| |
| private IEditorInput restoreInput(IMemento editorMem) throws PartInitException { |
| return createInput(editorMem); |
| } |
| |
| public static IEditorInput createInput(IMemento editorMem) throws PartInitException { |
| String editorId = editorMem.getString(IWorkbenchConstants.TAG_ID); |
| |
| IMemento inputMem = editorMem.getChild(IWorkbenchConstants.TAG_INPUT); |
| |
| String editorName = null; |
| String factoryID = null; |
| if (inputMem != null) { |
| editorName = inputMem.getString(IWorkbenchConstants.TAG_PATH); |
| factoryID = inputMem.getString(IWorkbenchConstants.TAG_FACTORY_ID); |
| } |
| if (factoryID == null) { |
| throw new PartInitException( |
| NLS.bind(WorkbenchMessages.EditorManager_no_input_factory_ID, editorId, editorName)); |
| } |
| IAdaptable input = null; |
| IElementFactory factory = PlatformUI.getWorkbench().getElementFactory(factoryID); |
| if (factory == null) { |
| throw new PartInitException(NLS.bind(WorkbenchMessages.EditorManager_bad_element_factory, |
| new Object[] { factoryID, editorId, editorName })); |
| } |
| |
| // Get the input element. |
| input = factory.createElement(inputMem); |
| if (input == null) { |
| throw new PartInitException(NLS.bind(WorkbenchMessages.EditorManager_create_element_returned_null, |
| new Object[] { factoryID, editorId, editorName })); |
| } |
| if (!(input instanceof IEditorInput)) { |
| throw new PartInitException(NLS.bind(WorkbenchMessages.EditorManager_wrong_createElement_result, |
| new Object[] { factoryID, editorId, editorName })); |
| } |
| return (IEditorInput) input; |
| } |
| |
| @Override |
| public IEditorPart getEditor(boolean restore) { |
| return (IEditorPart) getPart(restore); |
| } |
| |
| @Override |
| public IEditorInput getEditorInput() throws PartInitException { |
| IEditorPart editor = getEditor(false); |
| if (editor != null) { |
| return editor.getEditorInput(); |
| } |
| |
| if (input == null) { |
| String memento = getModel().getPersistedState().get(MEMENTO_KEY); |
| if (memento == null) { |
| input = new NullEditorInput(); |
| } else { |
| try { |
| XMLMemento createReadRoot = XMLMemento.createReadRoot(new StringReader(memento)); |
| input = restoreInput(createReadRoot); |
| } catch (WorkbenchException e) { |
| throw new PartInitException(e.getStatus()); |
| } |
| } |
| } |
| return input; |
| } |
| |
| @Override |
| public IWorkbenchPart createPart() throws PartInitException { |
| try { |
| if (descriptor == null) { |
| return createErrorPart(); |
| } else if (descriptor.getId().equals(IEditorRegistry.SYSTEM_INPLACE_EDITOR_ID)) { |
| IEditorPart part = ComponentSupport.getSystemInPlaceEditor(); |
| if (part == null) { |
| throw new PartInitException(WorkbenchMessages.EditorManager_no_in_place_support); |
| } |
| return part; |
| } |
| return descriptor.createEditor(); |
| } catch (CoreException e) { |
| IStatus status = e.getStatus(); |
| throw new PartInitException( |
| new Status(IStatus.ERROR, WorkbenchPlugin.PI_WORKBENCH, status.getCode(), status.getMessage(), e)); |
| } |
| } |
| |
| @Override |
| IWorkbenchPart createErrorPart() { |
| IStatus status = new Status(IStatus.ERROR, WorkbenchPlugin.PI_WORKBENCH, |
| NLS.bind(WorkbenchMessages.EditorManager_missing_editor_descriptor, descriptorId), new Exception()); |
| IEditorRegistry registry = getPage().getWorkbenchWindow().getWorkbench().getEditorRegistry(); |
| descriptor = (EditorDescriptor) registry.findEditor(EditorRegistry.EMPTY_EDITOR_ID); |
| return createErrorPart(status); |
| } |
| |
| @Override |
| public IWorkbenchPart createErrorPart(IStatus status) { |
| return new ErrorEditorPart(status); |
| } |
| |
| @Override |
| public void initialize(IWorkbenchPart part) throws PartInitException { |
| IConfigurationElement element = descriptor.getConfigurationElement(); |
| EditorSite editorSite = new EditorSite(getModel(), part, this, element); |
| if (element == null) { |
| editorSite.setExtensionId(descriptor.getId()); |
| } |
| editorSite.setActionBars(createEditorActionBars((WorkbenchPage) getPage(), descriptor)); |
| IEditorPart editor = (IEditorPart) part; |
| try { |
| editor.init(editorSite, getEditorInput()); |
| } catch (PartInitException e) { |
| if (editor instanceof ErrorEditorPart) { |
| editor.init(editorSite, new NullEditorInput(this)); |
| } else { |
| throw e; |
| } |
| } |
| |
| if (editor.getSite() != editorSite || editor.getEditorSite() != editorSite) { |
| String id = descriptor == null ? getModel().getElementId() : descriptor.getId(); |
| throw new PartInitException(NLS.bind(WorkbenchMessages.EditorManager_siteIncorrect, id)); |
| } |
| |
| if (part instanceof IPersistableEditor) { |
| if (editorState != null) { |
| ((IPersistableEditor) part).restoreState(editorState); |
| } else if (useIPersistableEditor()) { |
| String mementoString = getModel().getPersistedState().get(MEMENTO_KEY); |
| if (mementoString != null) { |
| try { |
| IMemento createReadRoot = XMLMemento.createReadRoot(new StringReader(mementoString)); |
| IMemento editorStateMemento = createReadRoot.getChild(IWorkbenchConstants.TAG_EDITOR_STATE); |
| if (editorStateMemento != null) { |
| ((IPersistableEditor) part).restoreState(editorStateMemento); |
| } |
| } catch (WorkbenchException e) { |
| throw new PartInitException(e.getStatus()); |
| } |
| } |
| } |
| } |
| |
| legacyPart = part; |
| addPropertyListeners(); |
| } |
| |
| @Override |
| public PartSite getSite() { |
| if (legacyPart != null) { |
| return (PartSite) legacyPart.getSite(); |
| } |
| return null; |
| } |
| |
| private static HashMap<String, Set<EditorActionBars>> actionCache = new HashMap<>(); |
| |
| /* |
| * Creates the action bars for an editor. Editors of the same type should share |
| * a single editor action bar, so this implementation may return an existing |
| * action bar vector. |
| */ |
| private static EditorActionBars createEditorActionBars(WorkbenchPage page, EditorDescriptor desc) { |
| // Get the editor type. |
| String type = desc.getId(); |
| |
| // If an action bar already exists for this editor type return it. |
| Set<EditorActionBars> candidates = actionCache.get(type); |
| if (candidates != null) { |
| for (EditorActionBars candidate : candidates) { |
| if (candidate.getPage() == page) { |
| candidate.addRef(); |
| return candidate; |
| } |
| } |
| } |
| |
| // Create a new action bar set. |
| EditorActionBars actionBars = new EditorActionBars(page, page.getWorkbenchWindow(), type); |
| actionBars.addRef(); |
| if (candidates == null) { |
| candidates = new HashSet<>(3); |
| candidates.add(actionBars); |
| actionCache.put(type, candidates); |
| } else |
| candidates.add(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; |
| } |
| |
| public static void disposeEditorActionBars(EditorActionBars actionBars) { |
| actionBars.removeRef(); |
| if (actionBars.getRef() <= 0) { |
| String type = actionBars.getEditorType(); |
| Set<EditorActionBars> set = actionCache.get(type); |
| if (set != null) { |
| set.remove(actionBars); |
| } |
| // refresh the cool bar manager before disposing of a cool item |
| ICoolBarManager2 coolBar = (ICoolBarManager2) ((WorkbenchWindow) actionBars.getPage().getWorkbenchWindow()) |
| .getCoolBarManager2(); |
| if (coolBar != null) { |
| coolBar.refresh(); |
| } |
| actionBars.dispose(); |
| } |
| } |
| |
| private static boolean useIPersistableEditor() { |
| IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore(); |
| return store.getBoolean(IPreferenceConstants.USE_IPERSISTABLE_EDITORS); |
| } |
| } |