/******************************************************************************* * 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); // } // } }