/*
* org.openmicroscopy.shoola.env.ui.SplashScreenManager
*
*------------------------------------------------------------------------------
* Copyright (C) 2006-2014 University of Dundee. All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*------------------------------------------------------------------------------
*/
package org.openmicroscopy.shoola.env.ui;
//Java imports
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.WindowEvent;
import java.awt.event.WindowFocusListener;
import java.awt.event.WindowStateListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.Icon;
import javax.swing.JFrame;
//Third-party libraries
//Application-internal dependencies
import org.openmicroscopy.shoola.env.Container;
import org.openmicroscopy.shoola.env.LookupNames;
import org.openmicroscopy.shoola.env.config.OMEROInfo;
import org.openmicroscopy.shoola.env.config.Registry;
import org.openmicroscopy.shoola.env.data.login.UserCredentials;
import org.openmicroscopy.shoola.util.CommonsLangUtils;
import org.openmicroscopy.shoola.util.image.geom.Factory;
import org.openmicroscopy.shoola.util.ui.UIUtilities;
import org.openmicroscopy.shoola.util.ui.login.LoginCredentials;
import org.openmicroscopy.shoola.util.ui.login.ScreenLogin;
import org.openmicroscopy.shoola.util.ui.login.ScreenLogo;
/**
* Manages the splash screen input, data and update.
* Plays both the role of Controller and Model within the splash screen
* component.
* <p>Provides clients with the splash screen component's functionality
* as specified by the the {@link SplashScreen} interface. However, clients
* never get an instance of this class. The reason is that this component is
* meant to be used during the initialization procedure, which runs within its
* own thread this component's event handling happens within the
* <i>Swing</i> dispatching thread instead. In order to separate threading
* issues from the actual component's functionality, we use Active Object: this
* class plays the role of the Servant and a proxy ({@link SplashScreenProxy})
* is actually returned to clients by the {@link UIFactory}.</p>
*
* @author Jean-Marie Burel
* <a href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a>
* @author <br>Andrea Falconi
* <a href="mailto:a.falconi@dundee.ac.uk">
* a.falconi@dundee.ac.uk</a>
* @version 2.2
* <small>
* (<b>Internal version:</b> $Revision$ $Date$)
* </small>
* @since OME2.2
*/
class SplashScreenManager
implements PropertyChangeListener, WindowFocusListener, WindowStateListener
{
/** The component's UI. */
private ScreenLogin view;
/** Tells whether or not the splash screen window is open. */
private boolean isOpen;
/** Filled in with the user's login when available. */
private SplashScreenFuture userCredentials;
/** The current number of tasks to be executed. */
private int totalTasks;
/** The current number of tasks that have been executed. */
private int doneTasks;
/** Reference to the singleton {@link Container}. */
private Container container;
/** Reference to the component. */
private SplashScreen component;
/**
* The credentials stored if the login button is pressed before the
* end of the initialization sequence.
*/
private LoginCredentials lc;
/**
* Attempts to log onto <code>OMERO</code>.
*
* @param lc The user's credentials.
*/
private void login(LoginCredentials lc)
{
if (doneTasks != totalTasks) {
this.lc = lc;
return;
}
try {
UserCredentials uc = new UserCredentials(lc.getUserName(),
lc.getPassword(), lc.getHostName(), lc.getSpeedLevel());
uc.setPort(lc.getPort());
uc.setEncrypted(lc.isEncrypted());
uc.setGroup(lc.getGroup());
userCredentials.set(uc);
this.lc = null;
} catch (Exception e) {
UserNotifier un = UIFactory.makeUserNotifier(container);
un.notifyError("Login Incomplete", e.getMessage());
view.setControlsEnabled(true);
updateView();
}
}
/**
* Sets the state of the specified window.
*
* @param f The window to handle.
* @param state The state to set.
*/
private void setWindowState(JFrame f, int state)
{
if (f == null) return;
f.removeWindowStateListener(this);
f.setState(state);
f.addWindowStateListener(this);
}
/** Sets the views on top. */
private void updateView()
{
if (view != null) {
view.setAlwaysOnTop(true);
view.requestFocusOnField();
}
}
/**
* Initializes the view.
*
* @param splashscreen The splash-screen
*/
private void initializedView(Icon splashscreen)
{
if (view != null) return;
Image img = IconManager.getOMEImageIcon();
Object version = container.getRegistry().lookup(LookupNames.VERSION);
String v = "";
if (version != null && version instanceof String)
v = (String) version;
OMEROInfo info =
(OMEROInfo) container.getRegistry().lookup(LookupNames.OMERODS);
int p = -1;
String port = ""+ info.getPortSSL();
String host = info.getHostName();
boolean configurable = info.isHostNameConfigurable();
//check if we have jnlp option
String jnlpHost = System.getProperty("jnlp.omero.host");
if (CommonsLangUtils.isNotBlank(jnlpHost)) {
host = jnlpHost;
configurable = false;
}
String jnlpPort = System.getProperty("jnlp.omero.port");
if (CommonsLangUtils.isNotBlank(jnlpPort)) {
port = jnlpPort;
p = Integer.parseInt(port);
configurable = false;
}
String jnlpSession = System.getProperty("jnlp.omero.sessionid");
boolean serverAvailable = connectToServer();
if (CommonsLangUtils.isNotBlank(jnlpSession)) {
serverAvailable = false;
}
view = new ScreenLogin(Container.TITLE, splashscreen, img, v, port,
host, serverAvailable);
view.setEncryptionConfiguration(info.isEncrypted(),
info.isEncryptedConfigurable());
view.setHostNameConfiguration(host, configurable, p);
view.showConnectionSpeed(true);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension d = view.getPreferredSize();
view.setBounds((screenSize.width-d.width)/2,
(screenSize.height-d.height)/2, d.width, d.height);
view.addPropertyChangeListener(this);
view.addWindowStateListener(this);
view.addWindowFocusListener(this);
}
/**
* Returns <code>true</code> if the client connects to a server,
* <code>false</code> otherwise.
*
* @return See above.
*/
private boolean connectToServer()
{
Integer v = (Integer) container.getRegistry().lookup(
LookupNames.ENTRY_POINT);
if (v != null) {
return v.intValue() == LookupNames.INSIGHT_ENTRY ||
v.intValue() == LookupNames.IMPORTER_ENTRY;
}
return false;
}
/**
* Creates the splash screen component.
* Creates a new instance of this manager and links them as needed.
*
* @param component Reference to the {@link SplashScreen}.
* @param c Reference to the singleton {@link Container}.
*/
SplashScreenManager(SplashScreen component, Container c)
{
container = c;
this.component = component;
Registry reg = c.getRegistry();
String n = (String) reg.lookup(LookupNames.SPLASH_SCREEN_LOGO);
String f = container.getConfigFileRelative(null);
Icon splashscreen = Factory.createIcon(n, f);
if (splashscreen == null) {
Integer v = (Integer) container.getRegistry().lookup(
LookupNames.ENTRY_POINT);
if (v != null) {
switch (v.intValue()) {
case LookupNames.IMPORTER_ENTRY:
splashscreen = IconManager.getImporterSplashScreen();
break;
default:
splashscreen = IconManager.getSplashScreen();
}
}
}
isOpen = false;
doneTasks = 0;
initializedView(splashscreen);
}
/**
* Implemented as specified by {@link SplashScreen}.
* @see SplashScreen#open()
*/
void open()
{
//close() has already been called.
view.setVisible(true);
view.setStatusVisible(true, false);
isOpen = true;
UIUtilities.applyGnome3Workaround(view);
container.getRegistry().bind(LookupNames.LOGIN_SPLASHSCREEN,
Boolean.valueOf(true));
}
/**
* Implemented as specified by {@link SplashScreen}.
* @see SplashScreen#close()
*/
void close()
{
//close() has already been called.
if (view == null) return;
Boolean b = (Boolean) container.getRegistry().lookup(
LookupNames.SESSION_KEY);
if (b != null && b.booleanValue()) {
view.setUserName("");
}
view.close();
view = null;
isOpen = false;
container.getRegistry().bind(LookupNames.LOGIN_SPLASHSCREEN,
Boolean.valueOf(false));
}
/**
* Sets the total number of initialization tasks that have to be
* performed.
*
* @param value The total number of tasks.
* @see SplashScreen#setTotalTasks(int)
*/
void setTotalTasks(int value)
{
if (!isOpen) return;
totalTasks = value;
//NB: Increment to show that the execution process is finished
// i.e. all tasks executed.
totalTasks++;
view.initProgressBar(value);
}
/**
* Updates the display to the current state of the initialization
* procedure.
*
* @param task The name of the initialization task that is about to
* be executed.
* @see SplashScreen#updateProgress(String)
*/
void updateProgress(String task)
{
if (!isOpen) return;
int n = doneTasks++;
view.setStatus(task, n);
if (doneTasks == totalTasks) {
view.setStatusVisible(false, lc == null);
if (lc == null) view.requestFocusOnField();
if (!connectToServer()) {
view.setVisible(false);
}
}
}
/**
* Registers a request to fill in the given <code>future</code> with
* the user's credentials when available.
*
* @param future The Future to collect the credentials.
* @param init Flag to control if it's the first attempt.
*/
void collectUserCredentials(SplashScreenFuture future, boolean init)
{
userCredentials = future;
if (lc != null) {
login(lc);
return;
}
if (view != null) view.setControlsEnabled(true);
if (!init) {
if (view != null) view.cleanField(ScreenLogin.PASSWORD_FIELD);
updateView();
}
}
/**
* Registers a request to fill in the given <code>future</code> with
* the user's credentials when available.
*
* @param future The Future to collect the credentials.
*/
void collectUserCredentialsInit(SplashScreenFuture future)
{
userCredentials = future;
if (view != null) view.setControlsEnabled(true);
}
/** Fails to log in. */
void onLoginFailure()
{
if (view != null) view.onLoginFailure();
updateView();
}
/**
* Reacts to property changes fired by the {@link ScreenLogin} and
* {@link ScreenLogo}.
* @see PropertyChangeListener#propertyChange(PropertyChangeEvent)
*/
public void propertyChange(PropertyChangeEvent evt)
{
String name = evt.getPropertyName();
if (ScreenLogin.LOGIN_PROPERTY.equals(name)) {
LoginCredentials lc = (LoginCredentials) evt.getNewValue();
this.lc = lc;
if (userCredentials != null && lc != null) login(lc);
} else if (ScreenLogin.QUIT_PROPERTY.equals(name)) {
container.exit();
component.close();
} else if (ScreenLogin.TO_FRONT_PROPERTY.equals(name) ||
ScreenLogo.MOVE_FRONT_PROPERTY.equals(name)) {
updateView();
}
}
/**
* Reacts to state changes fired by the {@link ScreenLogin}.
* @see WindowStateListener#windowStateChanged(WindowEvent)
*/
public void windowStateChanged(WindowEvent e)
{
Object src = e.getSource();
int state = e.getNewState();
if (src instanceof ScreenLogin) setWindowState(view, state);
if (view != null) view.setAlwaysOnTop(state == JFrame.NORMAL);
}
/**
* Resets the flag when one of the windows loses focus.
* @see WindowFocusListener#windowLostFocus(WindowEvent)
*/
public void windowLostFocus(WindowEvent e)
{
if (e.getOppositeWindow() == null) {
if (view != null) view.setAlwaysOnTop(false);
}
}
/**
* Required by the {@link WindowFocusListener} I/F but no-operation
* implementation in our case.
* @see WindowFocusListener#windowGainedFocus(WindowEvent)
*/
public void windowGainedFocus(WindowEvent e) {}
}