/*******************************************************************************
* Copyright (c) 2007, 2014 compeople AG 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:
* compeople AG - initial API and implementation
*******************************************************************************/
package org.eclipse.riena.navigation.ui.swt.application;
import org.osgi.service.log.LogService;
import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.equinox.app.IApplication;
import org.eclipse.equinox.app.IApplicationContext;
import org.eclipse.jface.databinding.swt.SWTObservables;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.application.ActionBarAdvisor;
import org.eclipse.ui.application.IActionBarConfigurer;
import org.eclipse.ui.application.WorkbenchAdvisor;
import org.eclipse.ui.internal.Workbench;
import org.eclipse.riena.core.Log4r;
import org.eclipse.riena.core.util.ReflectionFailure;
import org.eclipse.riena.core.util.ReflectionUtils;
import org.eclipse.riena.core.wire.InjectExtension;
import org.eclipse.riena.core.wire.Wire;
import org.eclipse.riena.internal.navigation.ui.swt.Activator;
import org.eclipse.riena.internal.navigation.ui.swt.IAdvisorHelper;
import org.eclipse.riena.internal.ui.swt.utils.RcpUtilities;
import org.eclipse.riena.navigation.IApplicationNode;
import org.eclipse.riena.navigation.listener.ApplicationNodeListener;
import org.eclipse.riena.navigation.ui.application.AbstractApplication;
import org.eclipse.riena.navigation.ui.controllers.ApplicationController;
import org.eclipse.riena.navigation.ui.login.ILoginDialogView;
import org.eclipse.riena.navigation.ui.swt.application.LoginNonActivityTimer.ILoginExecutor;
import org.eclipse.riena.navigation.ui.swt.facades.NavigationFacade;
import org.eclipse.riena.navigation.ui.swt.login.ILoginSplashViewExtension;
import org.eclipse.riena.navigation.ui.swt.splashHandlers.AbstractLoginSplashHandler;
import org.eclipse.riena.ui.swt.facades.SWTFacade;
import org.eclipse.riena.ui.swt.utils.ImageStore;
/**
* Creates and starts an empty swt application Subclass to create own model or controller.
*/
public class SwtApplication extends AbstractApplication {
protected ILoginSplashViewExtension loginSplashViewExtension;
// private LoginNonActivityTimer loginNonActivityTimer;
@Override
protected void initializeUI() {
PlatformUI.createDisplay();
}
@Override
public Object createView(final IApplicationContext context, final IApplicationNode pNode) {
final Display display = Display.getCurrent();
try {
final WorkbenchAdvisor advisor = NavigationFacade.getDefault().createWorkbenchAdvisor(createApplicationController(pNode), new AdvisorHelper());
initializeLoginNonActivityTimer(display, pNode, context);
final int returnCode = PlatformUI.createAndRunWorkbench(display, advisor);
if (returnCode == PlatformUI.RETURN_RESTART) {
return IApplication.EXIT_RESTART;
}
return IApplication.EXIT_OK;
} finally {
display.dispose();
}
}
/**
* Creates an action bar advisor for a window.
* <p>
* Subclasses may override.
*
* @return an AdvisorBarAdvisor; never null
* @since 1.2
*/
public ActionBarAdvisor createActionBarAdvisor(final IActionBarConfigurer configurer) {
return new ActionBarAdvisor(configurer);
}
/**
* Return the default keyboard scheme for this applications.
* <p>
* Subclasses defining their own scheme using the '...' extension point, should override this method and return the appropriate id.
* <p>
* When defining your own scheme, you can specify '...' as the parent scheme, to inherit the default Riena keybindings. If you wish to start with a blank
* scheme, leave the parent attribute empty.
* <p>
* Example:
*
* <pre>
* <extension
* point="org.eclipse.ui.bindings">
* <scheme
* id="org.eclipse.riena.example.client.scheme"
* name="Riena Client Key Bindings"
* parentId="org.eclipse.riena.ui.defaultBindings">
* </scheme>
* <key
* commandId="org.eclipse.riena.example.client.exitCommand"
* contextId="org.eclipse.ui.contexts.window"
* schemeId="org.eclipse.riena.example.client.scheme"
* sequence="F10">
* </key>
* </extension>
* </pre>
*
* @return the identifer of a valid scheme as String; never null.
*/
protected String getKeyScheme() {
return "org.eclipse.riena.ui.defaultBindings"; //$NON-NLS-1$
}
public void stop() {
final IWorkbench workbench = PlatformUI.getWorkbench();
if (workbench == null) {
return;
}
final Display display = workbench.getDisplay();
display.syncExec(new Runnable() {
public void run() {
if (!display.isDisposed()) {
workbench.close();
}
}
});
}
/*
* keep public, called via reflection
*/
@InjectExtension
public void update(final ILoginSplashViewExtension[] data) {
if (data.length > 0) {
loginSplashViewExtension = data[0];
}
}
protected ApplicationController createApplicationController(final IApplicationNode pModel) {
return new ApplicationController(pModel);
}
protected void prePerformLogin(final IApplicationContext context) {
if (RcpUtilities.getWorkbenchShell() != null) {
// To minimize the workbench and show the login dialog later, the workbench has be made first invisible and then minimized.
RcpUtilities.getWorkbenchShell().setVisible(false);
RcpUtilities.getWorkbenchShell().setMinimized(true);
// Make workbench visible to be shown as minimized in the (windows) task bar.
RcpUtilities.getWorkbenchShell().setVisible(true);
}
}
protected void postPerformLogin(final IApplicationContext context, final Object result) {
if (!EXIT_OK.equals(result)) {
PlatformUI.getWorkbench().close();
} else {
RcpUtilities.getWorkbenchShell().setMinimized(false);
// loginNonActivityTimer.schedule();
}
}
@Override
protected Integer doPerformLogin(final IApplicationContext context) {
final Realm realm = SWTObservables.getRealm(getDisplay());
// TODO Is really necessary that the loginDialogViewExtension is used here. Should not it be done it the super class??
final ILoginDialogView loginDialogView = loginDialogViewExtension.createViewClass();
do {
Realm.runWithDefault(realm, new Runnable() {
public void run() {
loginDialogView.build();
}
});
} while (EXIT_RESTART.equals(loginDialogView.getResult()));
return loginDialogView.getResult();
}
@Override
protected Integer doPerformSplashLogin(final IApplicationContext context) {
final Shell shell = new Shell(getDisplay(), SWT.NO_TRIM | SWT.APPLICATION_MODAL);
initilizeShellBackgroundImage(shell, getBackgroundImagePath(context));
final AbstractLoginSplashHandler loginSplashHandler = getLoginSplashHandler();
loginSplashHandler.init(shell);
shell.open();
while (!shell.isDisposed()) {
if (!getDisplay().readAndDispatch()) {
getDisplay().sleep();
}
}
return loginSplashHandler.getResult();
}
@Override
protected boolean isSplashLogin(final IApplicationContext context) {
return loginSplashViewExtension != null && getLoginSplashHandler() != null;
}
@Override
protected boolean isDialogLogin(final IApplicationContext context) {
return super.isDialogLogin(context) && loginSplashViewExtension == null;
}
@Override
protected void initializeLoginViewDefinition() {
super.initializeLoginViewDefinition();
initializeLoginSplashViewDefinition();
}
// helping methods
//////////////////
private String getBackgroundImagePath(final IApplicationContext context) {
return "splash.bmp"; //$NON-NLS-1$
}
private Display getDisplay() {
if (PlatformUI.isWorkbenchRunning()) {
return PlatformUI.getWorkbench().getDisplay();
} else {
return PlatformUI.createDisplay();
}
}
private AbstractLoginSplashHandler getLoginSplashHandler() {
AbstractLoginSplashHandler result = null;
if (PlatformUI.isWorkbenchRunning() && !SWTFacade.isRAP()) { // RAP does not have a splash
// Use the splash handler of the workbench both for the login and for
// a later re-login after inactivity timeout. Unfortunately it is not
// accessible and an enhancement request to change that was rejected:
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=260736.
try {
final Object loginSplashHandler = ReflectionUtils.invokeHidden(Workbench.class, "getSplash"); //$NON-NLS-1$
if (loginSplashHandler instanceof AbstractLoginSplashHandler) {
result = (AbstractLoginSplashHandler) loginSplashHandler;
}
} catch (final ReflectionFailure refFail) {
Log4r.getLogger(SwtApplication.class).log(LogService.LOG_ERROR, "Workbench.getSplash()", refFail); //$NON-NLS-1$
}
}
return result;
}
private void initializeLoginNonActivityTimer(final Display display, final IApplicationNode pNode, final IApplicationContext context) {
pNode.addListener(new ApplicationNodeListener() {
@Override
public void afterActivated(final IApplicationNode source) {
final ILoginExecutor<Integer> loginExecutor = new ILoginExecutor<Integer>() {
public void prePerformLogin() throws Exception {
SwtApplication.this.prePerformLogin(context);
}
public void postPerformLogin(final Integer result) throws Exception {
SwtApplication.this.postPerformLogin(context, result);
}
public Integer performLogin() {
try {
return SwtApplication.this.performLogin(context);
} catch (final Exception e) {
throw new RuntimeException(e);
}
}
public int getNonActivityDuration() {
if (isSplashLogin(context)) {
return loginSplashViewExtension.getNonActivityDuration();
}
if (isDialogLogin(context)) {
return loginDialogViewExtension.getNonActivityDuration();
}
return 0;
}
};
if (isSplashLogin(context)) {
startNonActivityTimer(display, loginExecutor);
} else if (isDialogLogin(context)) {
// TODO See todo in method doPerformLogin(IApplicationContext context)
startNonActivityTimer(display, loginExecutor);
}
}
});
}
private boolean startNonActivityTimer(final Display display, final ILoginExecutor<Integer> loginExecutor) {
if (loginDialogViewExtension.getNonActivityDuration() > 0) {
new LoginNonActivityTimer(display, loginExecutor, loginSplashViewExtension.getNonActivityDuration()).schedule();
return true;
} else {
return false;
}
}
private void initializeLoginSplashViewDefinition() {
Wire.instance(this).andStart(Activator.getDefault().getContext());
}
private void initilizeShellBackgroundImage(final Shell shell, final String imageName) {
final Image bi = ImageStore.getInstance().getImage(imageName);
shell.setSize(bi.getBounds().width, bi.getBounds().height);
shell.setBackgroundImage(bi);
}
// helping classes
//////////////////
private final class AdvisorHelper implements IAdvisorHelper {
public ActionBarAdvisor createActionBarAdvisor(final IActionBarConfigurer configurer) {
return SwtApplication.this.createActionBarAdvisor(configurer);
}
public String getKeyScheme() {
return SwtApplication.this.getKeyScheme();
}
}
// private static final class EventListener implements Listener {
// private boolean activity;
// private long activityTime;
//
// private EventListener() {
// activity = false;
// activityTime = -1;
// }
//
// public void handleEvent(final Event event) {
// activity = true;
// activityTime = System.currentTimeMillis();
// }
// }
// private final class LoginNonActivityTimer implements Runnable {
// private final Display display;
// private final IApplicationContext context;
// private EventListener eventListener;
// private final int nonActivityDuration;
//
// private LoginNonActivityTimer(final Display display, final IApplicationContext context,
// final int nonActivityDuration) {
// super();
//
// this.display = display;
// this.context = context;
// this.nonActivityDuration = nonActivityDuration;
// initializeEventListener();
// }
//
// public void run() {
// try {
// if (eventListener.activity) {
// schedule();
// return;
// }
//
// prePerformLogin(context);
// postPerformLogin(context, performLogin(context));
// } catch (final Exception e) {
// throw new ExceptionFailure(e.getLocalizedMessage(), e);
// }
// }
//
// private void initializeEventListener() {
// eventListener = new EventListener();
// display.addFilter(SWT.KeyDown, eventListener);
// display.addFilter(SWT.KeyUp, eventListener);
// display.addFilter(SWT.MouseDoubleClick, eventListener);
// display.addFilter(SWT.MouseDown, eventListener);
// display.addFilter(SWT.MouseUp, eventListener);
// display.addFilter(SWT.Traverse, eventListener);
// final SWTFacade facade = SWTFacade.getDefault();
// facade.addFilterMouseExit(display, eventListener);
// facade.addFilterMouseMove(display, eventListener);
// facade.addFilterMouseWheel(display, eventListener);
// }
//
// private void schedule() {
// initializeForSchedule();
// display.timerExec(getTimerDelay(), this);
// }
//
// private void initializeForSchedule() {
// if (eventListener.activityTime == -1) {// initialize on first schedule
// eventListener.activityTime = System.currentTimeMillis();
// }
// eventListener.activity = false;
// }
//
// private int getTimerDelay() {
// return nonActivityDuration - (int) (System.currentTimeMillis() - eventListener.activityTime);
// }
// }
}