/*******************************************************************************
* Copyright (c) 2008, 2016 BestSolution.at 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:
* Tom Schindl <tom.schindl@bestsolution.at> - initial API and implementation
* IBM Corporation - initial API and implementation
* Christian Georgi (SAP) - Bug 432480
* Lars Vogel <Lars.Vogel@vogella.com> - Bug 472654, 393171, 508450
******************************************************************************/
package org.eclipse.e4.ui.internal.workbench;
import java.net.URI;
import java.util.Hashtable;
import java.util.List;
import java.util.UUID;
import org.eclipse.e4.core.commands.ExpressionContext;
import org.eclipse.e4.core.contexts.ContextInjectionFactory;
import org.eclipse.e4.core.contexts.EclipseContextFactory;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.core.services.contributions.IContributionFactory;
import org.eclipse.e4.core.services.log.Logger;
import org.eclipse.e4.ui.model.application.MApplication;
import org.eclipse.e4.ui.model.application.MApplicationElement;
import org.eclipse.e4.ui.model.application.ui.MContext;
import org.eclipse.e4.ui.workbench.IPresentationEngine;
import org.eclipse.e4.ui.workbench.IWorkbench;
import org.eclipse.e4.ui.workbench.UIEvents;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.osgi.service.datalocation.Location;
import org.osgi.framework.ServiceRegistration;
/**
* Default implementation of {@link IWorkbench}
*/
public class E4Workbench implements IWorkbench {
/**
* The argument for the locale active shell <br>
* <br>
* Value is: <code>localActiveShell</code>
*/
public static final String LOCAL_ACTIVE_SHELL = "localActiveShell"; //$NON-NLS-1$
/**
* The argument for the {@link URI} of the initial workbench model <br>
* <br>
* Value is: <code>initialWorkbenchModelURI</code>
*/
public static final String INITIAL_WORKBENCH_MODEL_URI = "initialWorkbenchModelURI"; //$NON-NLS-1$
/**
* The argument for the {@link Location} of the running instance <br>
* <br>
* Value is: <code>instanceLocation</code>
*/
public static final String INSTANCE_LOCATION = "instanceLocation"; //$NON-NLS-1$
/**
* The argument for the renderer factory to use <br>
* <br>
* Value is: <code>rendererFactoryUri</code>
*/
public static final String RENDERER_FACTORY_URI = "rendererFactoryUri"; //$NON-NLS-1$
/**
* The argument for setting RTL mode <br>
* <br>
* Value is: <code>dir</code>
*/
public static final String RTL_MODE = "dir"; //$NON-NLS-1$
/**
* The argument for the perspective to activate <br>
* <br>
* Value is: <code>perspectiveId</code>
*/
public static final String FORCED_PERSPECTIVE_ID = "forcedPerspetiveId"; //$NON-NLS-1$
public static final String NO_SAVED_MODEL_FOUND = "NO_SAVED_MODEL_FOUND"; //$NON-NLS-1$
/**
* The argument for the whether to forcefully show the location in the window title (set on the
* command line)<br>
* <br>
* Value is: <code>forcedShowLocation</code>
*/
public static final String FORCED_SHOW_LOCATION = "forcedShowLocation"; //$NON-NLS-1$
private final String id;
private ServiceRegistration<?> osgiRegistration;
IEclipseContext appContext;
IPresentationEngine renderer;
MApplication appModel = null;
private UIEventPublisher uiEventPublisher;
private boolean restart;
/**
* @return the {@link IEclipseContext} for the main application
*/
public IEclipseContext getContext() {
return appContext;
}
/**
* Constructor
*
* @param uiRoot
* the root UI element
* @param applicationContext
* the root context
*/
public E4Workbench(MApplicationElement uiRoot, IEclipseContext applicationContext) {
id = createId();
appContext = applicationContext;
appContext.set(IWorkbench.class.getName(), this);
if (uiRoot instanceof MApplication) {
appModel = (MApplication) uiRoot;
}
if (uiRoot instanceof MApplication) {
init((MApplication) uiRoot);
}
uiEventPublisher = new UIEventPublisher(appContext);
appContext.set(UIEventPublisher.class, uiEventPublisher);
((Notifier) uiRoot).eAdapters().add(uiEventPublisher);
Hashtable<String, Object> properties = new Hashtable<>();
properties.put("id", getId()); //$NON-NLS-1$
osgiRegistration = Activator.getDefault().getContext()
.registerService(IWorkbench.class.getName(), this, properties);
ContextInjectionFactory.make(PartOnTopManager.class, appContext);
}
@Override
public final String getId() {
return id;
}
protected String createId() {
return UUID.randomUUID().toString();
}
/**
* @param uiRoot
*/
public void createAndRunUI(MApplicationElement uiRoot) {
// Has someone already created one ?
instantiateRenderer();
if (renderer != null) {
renderer.run(uiRoot, appContext);
}
}
/**
*
*/
public void instantiateRenderer() {
renderer = appContext.get(IPresentationEngine.class);
if (renderer == null) {
String presentationURI = (String) appContext.get(IWorkbench.PRESENTATION_URI_ARG);
if (presentationURI != null) {
IContributionFactory factory = appContext.get(IContributionFactory.class);
renderer = (IPresentationEngine) factory.create(presentationURI, appContext);
appContext.set(IPresentationEngine.class, renderer);
}
if (renderer == null) {
Logger logger = appContext.get(Logger.class);
logger.error("Failed to create the presentation engine for URI: " + presentationURI); //$NON-NLS-1$
}
}
}
private void init(MApplication appElement) {
if (Policy.DEBUG_WORKBENCH) {
Activator.trace(Policy.DEBUG_WORKBENCH_FLAG, "init() workbench", null); //$NON-NLS-1$
}
IEclipseContext context = appElement.getContext();
if (context != null) {
context.set(ExpressionContext.ALLOW_ACTIVATION, Boolean.TRUE);
}
}
@Override
public boolean close() {
// Fire an E4 lifecycle notification
UIEvents.publishEvent(UIEvents.UILifeCycle.APP_SHUTDOWN_STARTED, appModel);
if (renderer != null) {
renderer.stop();
}
if (uiEventPublisher != null && appModel != null) {
((Notifier) appModel).eAdapters().remove(uiEventPublisher);
uiEventPublisher = null;
}
if (osgiRegistration != null) {
osgiRegistration.unregister();
osgiRegistration = null;
}
return true;
}
@Override
public boolean restart() {
this.restart = true;
return close();
}
/**
* @return <code>true</code> when the workbench should be restarted
*/
public boolean isRestart() {
return restart;
}
/**
* @return a context that can be used to lookup OSGi services
*/
public static IEclipseContext getServiceContext() {
return EclipseContextFactory.getServiceContext(Activator.getDefault().getContext());
}
@Override
public MApplication getApplication() {
return appModel;
}
/**
* Create the context chain. It both creates the chain for the current model, and adds eAdapters
* so it can add new contexts when new model items are added.
*
* @param parentContext
* The parent context
* @param contextModel
* needs a context created
* @return a chained {@link IEclipseContext}
*/
public static IEclipseContext initializeContext(IEclipseContext parentContext,
MContext contextModel) {
final IEclipseContext context;
if (contextModel.getContext() != null) {
context = contextModel.getContext();
} else {
context = parentContext.createChild("PartContext(" + contextModel + ')'); //$NON-NLS-1$
}
if (Policy.DEBUG_CONTEXTS) {
Activator.trace(Policy.DEBUG_CONTEXTS_FLAG, "initializeContext(" //$NON-NLS-1$
+ parentContext.toString() + ", " + contextModel + ")", null); //$NON-NLS-1$ //$NON-NLS-2$
}
// fill in the interfaces, so MContributedPart.class.getName() will
// return the model element, for example.
ContributionsAnalyzer.populateModelInterfaces(contextModel, context, contextModel
.getClass().getInterfaces());
// declares modifiable variables from the model
List<String> containedProperties = contextModel.getVariables();
for (String name : containedProperties) {
context.declareModifiable(name);
}
contextModel.setContext(context);
return context;
}
}