/******************************************************************************* * Copyright (c) 2012 Association for Decentralized Information Management in * Industry THTH ry. * 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: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.modeling.ui.diagramEditor.e4; import java.lang.reflect.Constructor; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExecutableExtension; import org.eclipse.core.runtime.Platform; import org.eclipse.e4.ui.model.application.ui.basic.MPart; import org.eclipse.e4.ui.workbench.modeling.EPartService; import org.eclipse.e4.ui.workbench.modeling.IPartListener; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; import org.eclipse.ui.PartInitException; import org.osgi.framework.Bundle; import org.simantics.db.Resource; import org.simantics.modeling.ui.diagramEditor.DisposingPolicy; import org.simantics.modeling.ui.diagramEditor.e4.DiagramViewer.DiagramViewerHost; import org.simantics.ui.workbench.e4.E4ResourceEditorBase; import org.simantics.utils.ui.ErrorLogger; /** * A class for diagram editor parts that contains logic for destruction and * (re)initialization of the actual diagram viewer and its controls during the * life cycle of this editor part. * *

* To use this class in an editor part extension, define the following in the * class attribute of the extension: * *

 * class="org.simantics.modeling.ui.diagramEditor.DiagramEditor:viewer=%VIEWER%"
 * 
* * where %VIEWER% is the name of the class that either is or * extends {@link org.simantics.modeling.ui.diagramEditor.DiagramViewer}. The * viewer argument tells {@link DiagramEditor} where to find the * initializer for the diagram editor controls. The initializer must have a * default constructor. * *

* This class is not intended to be extended by clients. Customizations should * be performed through the viewer class. * * @author Tuukka Lehtonen * @author Antti Villberg */ public class DiagramEditor extends E4ResourceEditorBase implements DiagramViewerHost, IExecutableExtension, IPartListener { /** * The {@value #ARG_VIEWER} argument for this editor part class tells the * name of the class to use for initializing the diagram viewer, i.e. * {@link #viewer}. The class is instantiated through reflection using the * class loader of the bundle named {@link #viewerContributor}. * * @see #setInitializationData(IConfigurationElement, String, Object) */ public static final String ARG_VIEWER = "viewer"; //$NON-NLS-1$ private Composite parent; private String viewerContributor; private String viewerClassName; // private ResourceEditorSupport support; private DiagramViewer viewer; /** * Reads the class arguments from the string in the data argument. * * @see org.eclipse.ui.part.EditorPart#setInitializationData(org.eclipse.core.runtime.IConfigurationElement, * java.lang.String, java.lang.Object) * @see #createViewer() */ @Override public void setInitializationData(IConfigurationElement cfig, String propertyName, Object data) { // super.setInitializationData(cfig, propertyName, data); if (data instanceof String) { viewerContributor = cfig.getContributor().getName(); String[] parameters = ((String) data).split(";"); //$NON-NLS-1$ for (String parameter : parameters) { String[] keyValue = parameter.split("="); //$NON-NLS-1$ if (keyValue.length > 2) { ErrorLogger.defaultLogWarning(NLS.bind(Messages.DiagramEditor_InvalidParameter, parameter, data), null); continue; } String key = keyValue[0]; String value = keyValue.length > 1 ? keyValue[1] : ""; //$NON-NLS-1$ if (ARG_VIEWER.equals(key)) { viewerClassName = value; } } } } protected DiagramViewer createViewer() throws PartInitException { if (viewerClassName == null) throw new PartInitException( "DiagramViewer contributor class was not specified in editor extension's class attribute viewer-argument. contributor is '" //$NON-NLS-1$ + viewerContributor + "'"); //$NON-NLS-1$ try { Bundle b = Platform.getBundle(viewerContributor); if (b == null) throw new PartInitException("DiagramViewer '" + viewerClassName + "' contributor bundle '" //$NON-NLS-1$ //$NON-NLS-2$ + viewerContributor + "' was not found in the platform."); //$NON-NLS-1$ Class clazz = b.loadClass(viewerClassName); if (!DiagramViewer.class.isAssignableFrom(clazz)) throw new PartInitException("DiagramViewer class '" + viewerClassName + "' is not assignable to " //$NON-NLS-1$ //$NON-NLS-2$ + DiagramViewer.class + "."); //$NON-NLS-1$ Constructor ctor = clazz.getConstructor(); return (DiagramViewer) ctor.newInstance(); } catch (Exception e) { throw new PartInitException("Failed to instantiate DiagramViewer implementation '" + viewerClassName //$NON-NLS-1$ + "' from bundle '" + viewerContributor + "'. See exception for details.", e); //$NON-NLS-1$ //$NON-NLS-2$ } } public DiagramViewer getViewer() { return viewer; } public Resource getRuntimeResource() { DiagramViewer viewer = this.viewer; return viewer != null ? viewer.getRuntime() : null; } // public Resource getInputResource() { // DiagramViewer viewer = this.viewer; // return viewer != null ? viewer.getInputResource() : null; // } @Override public void initImpl(MPart part) { super.initImpl(part); try { viewer = createViewer(); } catch (PartInitException e) { // TODO Auto-generated catch block e.printStackTrace(); } // #TODO Finish this when we are going to use full E4 workbench // viewer.init(this, getResourceInput()); EPartService partService = part.getContext().get(EPartService.class); partService.addPartListener(this); } @Override public void createPartControl(Composite parent) { this.parent = parent; initializeViewer(); } private void initializeViewer() { parent.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_WHITE)); viewer.createPartControl(parent); // It is possible that something goes wrong and the parent gets disposed already if(parent.isDisposed()) return; parent.layout(true); } @Override public void setFocus() { if (viewer != null) viewer.setFocus(); } @SuppressWarnings("rawtypes") public Object getAdapter(Class adapter) { if (adapter == DiagramViewer.class) return viewer; if (viewer != null) { Object result = viewer.getAdapter(adapter); if (result != null) return result; } return null; } @Override public void dispose() { EPartService partService = getPart().getContext().get(EPartService.class); partService.removePartListener(this); DISPOSING_POLICY.removeDisposer(disposer); tryDisposeViewer(); } public void doSetPartName(String name) { getPart().setLabel(name); } public void doSetTitleToolTip(String tooltip) { getPart().setTooltip(tooltip); } private static final DisposingPolicy DISPOSING_POLICY = new DisposingPolicy(); private Runnable disposer = new Runnable() { @Override public void run() { tryDisposeViewer(); } }; private void tryDisposeViewer() { if (viewer != null) { Composite viewerComposite = viewer.getComposite(); viewer.dispose(); viewer = null; if (viewerComposite != null) { viewerComposite.dispose(); } } } @Override public void partVisible(MPart part) { if (getPart().equals(part)) { DISPOSING_POLICY.removeDisposer(disposer); if (viewer == null) { try { viewer = createViewer(); // #TODO Finish this when we are going to use full E4 workbench // viewer.init(DiagramEditor.this, getResourceInput()); initializeViewer(); } catch (PartInitException e) { // This should never happen! ErrorLogger.defaultLogError(e); } } } } @Override public void partHidden(MPart part) { if (getPart().equals(part)) { DISPOSING_POLICY.addDisposer(disposer); } } @Override public void partDeactivated(MPart part) { } @Override public void partBroughtToTop(MPart part) { } @Override public void partActivated(MPart part) { } }