package uk.ac.lkl.migen.system;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import java.util.MissingResourceException;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import org.restlet.Client;
import org.restlet.data.Method;
import org.restlet.data.Protocol;
import org.restlet.data.Reference;
import org.restlet.data.Request;
import org.restlet.data.Response;
import org.restlet.data.Status;
import org.restlet.resource.Representation;
import uk.ac.lkl.common.util.LoggingUtilities;
import uk.ac.lkl.common.util.RobotUtilities;
import uk.ac.lkl.common.util.SubversionUtilities;
import uk.ac.lkl.common.util.config.ConfigurationException;
import uk.ac.lkl.common.util.config.ConfigurationOutOfSyncException;
import uk.ac.lkl.common.util.datafile.AbstractDataFileManager;
import uk.ac.lkl.common.util.datafile.BasicDataFileManager;
import uk.ac.lkl.common.util.datafile.DataFile;
import uk.ac.lkl.common.util.datafile.SettableDataFileManager;
import uk.ac.lkl.common.util.restlet.RestletException;
import uk.ac.lkl.common.util.value.IntegerValue;
import uk.ac.lkl.migen.system.expresser.LoggerConfigurator;
import uk.ac.lkl.migen.system.expresser.model.AvailableTileColors;
import uk.ac.lkl.migen.system.expresser.model.ExpresserModel;
import uk.ac.lkl.migen.system.expresser.model.event.CreationEventManager;
import uk.ac.lkl.migen.system.expresser.model.exception.ColorSpecificationException;
import uk.ac.lkl.migen.system.expresser.ui.ActivityMaker;
import uk.ac.lkl.migen.system.expresser.ui.BlockShapeCanvasPanel;
import uk.ac.lkl.migen.system.expresser.ui.ExpresserModelPanel;
import uk.ac.lkl.migen.system.expresser.ui.MasterSlaveUniverseMicroworldPanel;
import uk.ac.lkl.migen.system.expresser.ui.MultiUniverseTabbedPanel;
import uk.ac.lkl.migen.system.expresser.ui.ObjectCanvasFrame;
import uk.ac.lkl.migen.system.expresser.ui.ObjectSetCanvas;
import uk.ac.lkl.migen.system.expresser.ui.ecollaborator.ActivityDocument;
import uk.ac.lkl.migen.system.expresser.ui.ecollaborator.ActivityDocumentXMLString;
import uk.ac.lkl.migen.system.expresser.ui.event.ClientCreationEventListener;
import uk.ac.lkl.migen.system.server.Gender;
import uk.ac.lkl.migen.system.server.MiGenServerCommunicator;
import uk.ac.lkl.migen.system.server.OfflineUser;
import uk.ac.lkl.migen.system.server.User;
import uk.ac.lkl.migen.system.server.UserSet;
import uk.ac.lkl.migen.woztools.intervention.InterventionDisplayerImpl;
/**
* The main point of entry for the stand-alone version of the eXpresser.
*
* @author $Author: sergut $
* @version $Revision: 9203 $
* @version $Date: 2011-04-21 16:34:45 -0700 (Thu, 21 Apr 2011) $
*/
public class ExpresserLauncher extends MiGenLauncher {
// to provide access when closing the window
private static InterventionDisplayerImpl wizardOfOzFeedbackServer = null;
private static MultiUniverseTabbedPanel modelCopyTabbedPane;
private static ObjectCanvasFrame<IntegerValue> mainExpresserFrame;
private static boolean rearrangingPanels = false;
// hack: so can share between methods -- need to clean up this class a lot!!
private static SettableDataFileManager taskConfigsFileManager = null;
private static BasicDataFileManager tasksFileManager = null;
private static BasicDataFileManager messagesFileManager = null;
private static boolean savedActivityDocumentLoadPending;
private static Runnable repaintRunnable = new Runnable() {
public void run() {
if (mainExpresserFrame != null) {
mainExpresserFrame.repaint();
}
repaintPending = false;
}};
private static boolean repaintPending = false;
private static UserSet userSet = null;
private static List<User> allUsers = new ArrayList<User>();
private static long startTime = 0;
private static HomepageFrame homepageFrame = null;
private static SetupFrame setupFrame = null;
private static String configFilename = null;
public static void main(String[] args) throws RestletException, ConfigurationException {
if (args.length > 1)
usage();
configFilename = (args.length == 1) ? args[0] : "migen.ini";
try {
init();
initialiseFileManagers();
processConfiguration(configFilename);
Boolean enableServer = MiGenConfiguration.isConnectedToServer();
if (enableServer) {
createServerCommunicator(args);
}
String userName = MiGenConfiguration.getUserName();
initialiseUserSet(userName);
launchStartFrame();
} catch (ConfigurationOutOfSyncException e) {
errorShutdown(e, e.getMessage(), ExitStatus.CONFIGURATION_SYNC);
} catch (ConfigurationException e) {
errorShutdown(e, "Invalid configuration: " + e.getMessage(), ExitStatus.CONFIG_ERROR);
} catch (MissingResourceException e) {
errorShutdown(e, "Missing resource", ExitStatus.NO_MESSAGE_BUNDLE_FOUND);
} catch (RestletException e) {
errorShutdown(e, "Server Unavailable", ExitStatus.CONNECTION_ERROR);
}
}
private static void usage() {
System.out.println("USAGE: ExpresserLauncher [<file.ini>]");
shutdown(ExitStatus.WRONG_CMD_LINE_ARG);
}
// convenience for clarity
private static void errorShutdown(Exception e, String msg, ExitStatus exitStatus) {
e.printStackTrace();
JOptionPane.showMessageDialog(null, msg, "System Error", JOptionPane.ERROR_MESSAGE);
shutdown(exitStatus);
}
private static void createServerCommunicator(String[] args) throws RestletException, ConfigurationException {
if (MiGenContext.isServerCommunicatorEnabled())
return;
String serverName = MiGenConfiguration.getServerName();
if (serverName == null)
throw new ConfigurationException("No server defined.");
int serverPort = MiGenConfiguration.getServerPort();
MiGenServerCommunicator serverCommunicator = new MiGenServerCommunicator(serverName, serverPort);
MiGenContext.setServerCommunicator(serverCommunicator);
checkServerStatus(serverName, serverPort);
}
private static boolean isServerCommunicatorEnabled(MiGenServerCommunicator serverCommunicator) {
if (serverCommunicator == null)
return false;
return serverCommunicator.isEnabled();
}
private static void launchStartFrame() {
printTime("Start");
Integer choice = null;
if (MiGenConfiguration.isUsingHomePageOnly()) {
choice = 1;
} else if (MiGenConfiguration.isUsingSetupFrameOnly()) {
choice = 0;
}
if (choice == null) {
// old interface
File file = new File("ChooseStartFrame");
if (file.exists()) {
choice = JOptionPane.showOptionDialog(
null,
"Please choose start frame:", "Start Frame Chooser",
JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
null, new String[] { "Setup", "Homepage" }, "Setup");
if (choice == JOptionPane.CLOSED_OPTION) {
shutdown(ExitStatus.NO_ERROR);
}
}
}
if (choice == null)
launchHomepageFrame();
else if (choice == 0)
launchSetupFrame();
else if (choice == 1)
launchHomepageFrame();
}
public static void printTime(String message) {
if (startTime == 0) {
return; // don't want to instrument this run
}
long now = System.currentTimeMillis();
if (startTime < 0) {
startTime = now;
}
System.out.println(">>>Time is " + (now-startTime )*.001 + " seconds. " + message);
}
// todo: put this somewhere more central and check name of entity layer
private static void checkServerStatus(String server, int port) throws RestletException {
Client client = new Client(Protocol.HTTP);
Reference reference = new Reference("http://" + server + ":" + port);
Request request = new Request(Method.GET, reference);
Response response = client.handle(request);
Status status = response.getStatus();
if (status.isError())
throw new RestletException("Server is not available");
Representation representation = response.getEntity();
try {
String responseText = representation.getText();
System.out.println(status.getName() + "\n" + responseText);
} catch (IOException e) {
throw new RestletException("Unable to get server check response text");
}
}
private static void launchSetupFrame() {
List<AbstractDataFileManager<?>> dataFileManagers = initialiseFileManagers();
setupFrame = new SetupFrame(dataFileManagers);
setupFrame.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
DataFile currentTaskConfigFile = taskConfigsFileManager.getCurrentFile();
startTask(currentTaskConfigFile);
}});
setupFrame.setVisible(true);
}
private static void launchHomepageFrame() {
homepageFrame = new HomepageFrame();
homepageFrame.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
printTime("Home Page button pressed.");
ConfigHandle selectedTaskConfigHandle = homepageFrame.getSelectedConfigHandle();
DataFile taskConfigFile = selectedTaskConfigHandle.getDataFile();
JList savedActivityDocumentsList = homepageFrame.getSavedDocumentsList();
if (savedActivityDocumentsList != null) {
Object selectedValue = savedActivityDocumentsList.getSelectedValue();
if (selectedValue != null) {
SavedActivityDocumentHandle handle = (SavedActivityDocumentHandle) selectedValue;
final ExpresserModel modelHandle = handle.getModelHandle();
if (modelHandle != null) {
savedActivityDocumentLoadPending = true;
if (startTask(taskConfigFile)) {
Runnable loadSavedDocument = new Runnable() {
@Override
public void run() {
MiGenServerCommunicator serverCommunicator = MiGenContext.getServerCommunicator();
ActivityDocumentXMLString activityDocumentXMLString;
activityDocumentXMLString = serverCommunicator.getActivityDocumentXMLString(userSet, modelHandle);
if (activityDocumentXMLString != null) {
ActivityDocument activityDocument = activityDocumentXMLString.getActivityDocument();
activityDocument.installActivityDocument(true);
}
}
};
SwingUtilities.invokeLater(loadSavedDocument);
} else {
homepageFrame.setVisible(true);
}
} else {
savedActivityDocumentLoadPending = false;
if (!startTask(taskConfigFile)) {
homepageFrame.setVisible(true);
}
}
}
} else {
startTask(taskConfigFile);
}
}}
);
homepageFrame.setVisible(true);
}
public static List<AbstractDataFileManager<?>> initialiseFileManagers() {
if (taskConfigsFileManager == null) {
taskConfigsFileManager =
new SettableDataFileManager("Configs", "data", "configs", "txt");
}
if (tasksFileManager == null) {
tasksFileManager =
new BasicDataFileManager("Pre-Saved Models", "data", "tasks", "xml");
}
if (messagesFileManager == null) {
messagesFileManager =
new BasicDataFileManager("Messages", "data", "messages", "properties");
}
List<AbstractDataFileManager<?>> dataFileManagers = new ArrayList<AbstractDataFileManager<?>>();
dataFileManagers.add(taskConfigsFileManager);
dataFileManagers.add(tasksFileManager);
dataFileManagers.add(messagesFileManager);
return dataFileManagers;
}
private static boolean startTask(DataFile taskConfigFile) {
printTime("startTask called");
try {
MiGenConfiguration.resetToSystemDefault();
processConfiguration(configFilename);
processConfiguration(taskConfigFile);
} catch (ConfigurationException e) {
e.printStackTrace();
JOptionPane.showMessageDialog(
null,
"Error in activity configuration file: " + e.getMessage(),
"Activity Configuration Error",
JOptionPane.ERROR_MESSAGE);
return false;
}
setJavaAWTToolkitDesktopProperty("DnD.gestureMotionThreshold", MiGenConfiguration.getPixelsToStartDrag());
initialiseUserSet(null);
String errorFileName = MiGenConfiguration.getErrorFileName();
MiGenServerCommunicator serverCommunicator = MiGenContext.getServerCommunicator();
CreationEventManager.addCreationEventListener(new ClientCreationEventListener(serverCommunicator, getUserSet()));
UserSet userSet = getUserSet();
/*
* FIXME: This is a hack to connect eGen to the DB while ActivityMaker
* is being used.
*/
ActivityMaker.setUserSet(userSet);
/* ************************************* */
if (errorFileName != null && !errorFileName.isEmpty()) {
try {
String fullFileName =
errorFileName + "_"
+ LoggingUtilities.getUserName() + "_"
+ LoggingUtilities.formatTime() + "_"
+ SubversionUtilities.getCoreVersion().replace(":", "-")
+ ".log";
FileOutputStream os = new FileOutputStream(
new File("log", fullFileName));
FileOutputStream os2 = new FileOutputStream(
new File("log", "out_" + LoggingUtilities.getUserName()
+ "_" + LoggingUtilities.formatTime() + "_"
+ SubversionUtilities.getCoreVersion().replace(":", "-")
+ ".log"));
PrintStream ps = new PrintStream(os);
PrintStream ps2 = new PrintStream(os2);
System.setErr(ps);
System.setOut(ps2);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
try {
AvailableTileColors.initialiseDefaultColors();
} catch (ColorSpecificationException e) {
e.printStackTrace();
}
launchMainExpresserInterface(userSet);
// hack maybe need to configure this
sendStartKeys();
return true;
}
/**
* initialises allUsers
* @throws RestletException
*/
private static void initialiseUserSet(String defaultName) {
MiGenServerCommunicator serverCommunicator = MiGenContext.getServerCommunicator();
if (allUsers.isEmpty()) {
if (MiGenContext.isServerCommunicatorEnabled()) {
User user = createOnlineUser(serverCommunicator, defaultName);
if (user != null && !allUsers.contains(user)) {
allUsers.add(user);
}
} else {
allUsers.add(new OfflineUser());
}
}
userSet = getUserSet(serverCommunicator, allUsers);
if (userSet == null) {
userSet = createUserSet(serverCommunicator, allUsers);
}
System.out.println("UserSet: " + userSet);
printTime("User set computed");
}
/**
* Attempts to get a User instance with the given username from the server.
*
* Note that if the communicator is disabled, this method returns null
* immediately.
*
* This method also returns null if the user is not found on the list of
* users on the server.
*
* This method is very inefficient in principle since it gets the entire
* list of users and iterates through them. This is best done through the
* appropriate query on the server. This improvement will come ASAP. In the
* meantime, this workaround is robust and since the number of users we will
* have is low, does not have a huge impact on efficiency.
*
* @param serverCommunicator
* @param username
* @return
*/
public static User getUser(MiGenServerCommunicator serverCommunicator, String username) {
if (!isServerCommunicatorEnabled(serverCommunicator))
return null;
List<User> users = serverCommunicator.getUserList();
for (User user : users) {
if (user.getUsername().equals(username))
return user;
}
return null;
}
/**
* Creates a User instance and posts it on the server (if enabled).
*
* If the communicator is disabled, this method creates a User instance with
* the given username and dummy firstname/lastname and returns this instance
* immediately. If the communicator is enabled, the user is added to the set
* of users known to the system after requesting that they enter their name.
*
* Note that the Gender and BirthDate of the user is hard-wired here (!).
* This is a temporary hack that will do for now.
*
* @param serverCommunicator
* @param username
* @return
*/
public static User createUser(MiGenServerCommunicator serverCommunicator, String username) {
if (!isServerCommunicatorEnabled(serverCommunicator))
return createOfflineUser(username);
return createOnlineUser(serverCommunicator);
}
private static User createOfflineUser(String username) {
return new User(username, username, "", Gender.MALE);
}
private static User createOnlineUser(MiGenServerCommunicator serverCommunicator) {
return createOnlineUser(serverCommunicator, null);
}
private static User createOnlineUser(MiGenServerCommunicator serverCommunicator, String defaultUserName) {
String[] nameParts;
if (defaultUserName == null || defaultUserName.length() == 0) {
nameParts = inputName();
if (nameParts == null) {
return null;
}
} else {
nameParts = defaultUserName.split(" +");
}
String firstName = nameParts[0];
String lastName = nameParts[1];
// TODO: see discussion of Issue 1043
String userName = generateUserName(firstName, lastName);
User user = new User(userName, firstName, lastName, Gender.MALE);
User existingUser = getUser(serverCommunicator, userName);
if (existingUser == null) {
int response = JOptionPane.showConfirmDialog(mainExpresserFrame, firstName + " " + lastName + " is not registered. Register now?", "New user?", JOptionPane.YES_NO_OPTION);
if (response == JOptionPane.YES_OPTION) {
serverCommunicator.addUser(user);
return user;
} else {
return createOnlineUser(serverCommunicator);
}
} else {
return existingUser;
}
}
public static String generateUserName(String firstName, String lastName) {
return firstName.substring(0,1) + lastName.charAt(0) + (firstName + lastName).hashCode();
}
private static String[] inputName() {
boolean nameOk = false;
String[] parts = null;
do {
String name = JOptionPane.showInputDialog("Please enter your first name and last name: ");
if (name != null) {
parts = name.split(" +");
if (parts.length == 2) {
nameOk = true;
}
} else {
// user cancelled the log in
// Does this make sense if cancelling the addition of user to form a group?
return null;
}
} while (!nameOk);
parts[0] = cannonicaliseName(parts[0]);
parts[1] = cannonicaliseName(parts[1]);
if (parts[0].isEmpty() || parts[1].isEmpty() ) {
return inputName();
}
return parts;
}
private static String cannonicaliseName(String name) {
name = name.replaceAll("\\W", "");
name = name.toLowerCase();
name = Character.toUpperCase(name.charAt(0)) + name.substring(1);
return name;
}
public static void addUserToUserSet() throws RestletException {
if (!MiGenContext.isServerCommunicatorEnabled())
return;
MiGenServerCommunicator serverCommunicator = MiGenContext.getServerCommunicator();
User newUser = createOnlineUser(serverCommunicator);
while (newUser == null && allUsers.isEmpty()) {
newUser = createOnlineUser(serverCommunicator);
}
if (newUser != null && !allUsers.contains(newUser)) {
allUsers.add(newUser);
userSet = null; // force re-computation
}
if (homepageFrame != null) {
homepageFrame.updateUserLoggedInMessage();
homepageFrame.updateSavedModelList();
} else if (setupFrame != null) {
setupFrame.updateUserLoggedInMessage();
}
}
public static void removeAllUsers() {
allUsers.clear();
}
/**
* Attempts to get the appropriate UserSet from the server if enabled.
*
* If the communicator is not enabled, this method returns null.
*
* Otherwise, it gets all the UserSets and iterates through them looking for
* one that consists of just the specified user. If found, this is returned.
* If not found, null is returned.
*
* @param serverCommunicator
* @param user
* @return
*/
// Deprecated since only checks first user in a set
// and supplanted by the more general following version that accepts a list of users
@Deprecated
public static UserSet getUserSet(MiGenServerCommunicator serverCommunicator, User user) {
if (!isServerCommunicatorEnabled(serverCommunicator))
return null;
List<UserSet> userSets = serverCommunicator.getUserSetList();
for (UserSet userSet : userSets) {
if (userSet.size() == 1 && userSet.getUser(0).equals(user))
return userSet;
}
return null;
}
public static UserSet getUserSet(MiGenServerCommunicator serverCommunicator, List<User> users) {
if (!isServerCommunicatorEnabled(serverCommunicator))
return null;
int userCount = users.size();
List<UserSet> userSets = serverCommunicator.getUserSetList();
for (UserSet userSet : userSets) {
if (userSet.size() == userCount) {
List<User> usersFromServer = userSet.getUsers();
boolean mismatch = false;
for (User user : usersFromServer) {
if (!users.contains(user)) {
mismatch = true;
break;
}
}
if (!mismatch) {
return userSet;
}
}
}
return null;
}
/**
* Creates a UserSet instance and posts it on the server (if applicable).
*
* If the communicator is disabled, this method simply creates a UserSet
* consisting solely of the given User instance and returns. Otherwise, it
* attempts to post this to the server.
*
* @param serverCommunicator
* @param user
* @return
*/
@Deprecated
// Deprecated since it uses the single user rather than a list
public static UserSet createUserSet(MiGenServerCommunicator serverCommunicator, User user) {
UserSet userSet = new UserSet(allUsers);
if (!isServerCommunicatorEnabled(serverCommunicator))
return userSet;
serverCommunicator.addUserSet(userSet);
return userSet;
}
/**
* Creates a UserSet instance and posts it on the server (if applicable).
*
* If the communicator is disabled, this method simply creates a UserSet
* consisting of all of the given User instances and returns. Otherwise, it
* attempts to post this to the server.
*
* @param serverCommunicator
* @param users
* @return
*/
public static UserSet createUserSet(MiGenServerCommunicator serverCommunicator, List<User> users) {
UserSet userSet = new UserSet(users);
if (isServerCommunicatorEnabled(serverCommunicator))
serverCommunicator.addUserSet(userSet);
return userSet;
}
// FIXME: @Hack(who = "MM", why = "AmeryHillJune09", issues = 0)
private static void sendStartKeys() {
// start external programs by simulating key presses
// TODO: use config to define these
String[] onStartKeys = { "VK_CONTROL", "VK_SHIFT", "VK_F9" }; // Key
RobotUtilities.sendKeysCombo(onStartKeys);
}
public static void setJavaAWTToolkitDesktopProperty(String key, Object value) {
// a hack to work around the fact that
// java.awt.Toolkit.setDesktopProperty is protected
// based on http://www.jroller.com/tackline/entry/xp_pl_f_on_linux
java.awt.Toolkit toolkit = java.awt.Toolkit.getDefaultToolkit();
java.lang.reflect.Method setter;
try {
setter = java.awt.Toolkit.class.getDeclaredMethod("setDesktopProperty", String.class, Object.class);
setter.setAccessible(true); // Say please.
setter.invoke(toolkit, key, value);
} catch (Exception e) {
e.printStackTrace();
}
}
private static void launchMainExpresserInterface(UserSet student) {
printTime("Before launchInterface");
String studentName = userSet.getNamesAsString();
LoggerConfigurator.setName(studentName);
LoggerConfigurator.configureMainLogger(studentName);
modelCopyTabbedPane = new MultiUniverseTabbedPanel();
mainExpresserFrame = new ObjectCanvasFrame<IntegerValue>(modelCopyTabbedPane, studentName);
prepareMainExpresserInterface(mainExpresserFrame);
final String modelFileName = MiGenConfiguration.getInitialModelFileName();
if (modelFileName != null && modelFileName.length() != 0) {
Runnable loadInitialModel = new Runnable() {
public void run() {
ExpresserModelPanel selectedModelPanel = modelCopyTabbedPane.getSelectedModelPanel();
ObjectSetCanvas canvas = selectedModelPanel.getCanvas();
canvas.loadXMLDocument(new File(modelFileName));
}};
SwingUtilities.invokeLater(loadInitialModel);
}
printTime("Before createKaleidoscopeCommonFormatLogger");
modelCopyTabbedPane.createKaleidoscopeCommonFormatLogger();
printTime("After createKaleidoscopeCommonFormatLogger");
/* ************************************* */
}
private static void prepareMainExpresserInterface(final ObjectCanvasFrame<IntegerValue> frame) {
frame.setVisible(true);
if (MiGenConfiguration.isRunWozServer()) {
frame.setTitlePostfix("-help");
}
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
closeExpresserInterface();
}});
}
public static MultiUniverseTabbedPanel getModelCopyTabbedPanel() {
return modelCopyTabbedPane;
}
public static BlockShapeCanvasPanel getSelectedMasterPanel() {
return getSelectedPanel();
}
public static BlockShapeCanvasPanel getSelectedPanel() {
if (modelCopyTabbedPane == null) {
// probably not fully initialised yet or not in eXpresser
return null;
}
ExpresserModelPanel selectedModelPanel = modelCopyTabbedPane.getSelectedModelPanel();
if (selectedModelPanel instanceof MasterSlaveUniverseMicroworldPanel) {
MasterSlaveUniverseMicroworldPanel masterSlaveUniverseMicroworldPanel = (MasterSlaveUniverseMicroworldPanel) selectedModelPanel;
return masterSlaveUniverseMicroworldPanel.getMasterPanel();
} else {
return null;
}
}
public static void setCurrentModelDirty() {
if (modelCopyTabbedPane == null) {
return;
}
ExpresserModel model = modelCopyTabbedPane.getModelAt(modelCopyTabbedPane.getSelectedIndex());
if (model != null) {
model.setDirtyModel(true);
}
}
public static void autoSaveCurrentModel() {
if (modelCopyTabbedPane == null) {
return;
}
ExpresserModel model = modelCopyTabbedPane.getModelAt(modelCopyTabbedPane.getSelectedIndex());
if (model != null) {
model.setAutoSaveModel(true);
}
}
public static void setCurrentPanelDirty() {
if (modelCopyTabbedPane == null) {
return;
}
ExpresserModel model = modelCopyTabbedPane.getModelAt(modelCopyTabbedPane.getSelectedIndex());
if (model != null) {
model.setDirtyPanel(true);
}
}
public static ExpresserModel getModelOfSelectedTab() {
if (modelCopyTabbedPane == null) {
return null;
}
return modelCopyTabbedPane.getModelAt(modelCopyTabbedPane.getSelectedIndex());
}
public static ObjectCanvasFrame<IntegerValue> getFrame() {
return mainExpresserFrame;
}
// Why is this necessary? - SG - Dec 2010
// KK: A little experimenting and it seems that if the caller instead called validate() on
// the appropriate Swing component then this would not have been necessary.
// This is non-issue in the web version so will not fix this
public static void repaint() {
if (!repaintPending && mainExpresserFrame != null) {
repaintPending = true;
EventQueue.invokeLater(repaintRunnable);
}
}
public static void add(Component component) {
// used to give drag feedback
Container contentPane = mainExpresserFrame.getContentPane();
// we want this to be invisible to the layout manager
// since it is used only for drag feedback
// and the side effects on the layout manager
// caused Issue 615
LayoutManager layout = contentPane.getLayout();
contentPane.setLayout(null);
contentPane.add(component);
contentPane.setComponentZOrder(component, 0);
contentPane.setLayout(layout);
}
public static void remove(Component component) {
Container contentPane = mainExpresserFrame.getContentPane();
contentPane.remove(component);
}
public static Container getContentPane() {
if (mainExpresserFrame == null) {
return null;
} else {
return mainExpresserFrame.getContentPane();
}
}
public static boolean isRemovalFinal(Container container) {
return !rearrangingPanels && container != getContentPane();
}
public static boolean isRearrangingPanels() {
return rearrangingPanels;
}
public static void setRearrangingPanels(boolean rearrangingPanels) {
ExpresserLauncher.rearrangingPanels = rearrangingPanels;
}
public static UserSet getUserSet() {
return getUserSet(true);
}
public static UserSet getUserSet(boolean okToCreate) {
if (userSet == null && okToCreate) {
initialiseUserSet(null);
}
return userSet;
}
/**
*
* All exit paths should call this method instead of System.exit() to
* ensure that everything is in order before closing the application.
*
* @param exitStatus the exit status to be returned to the operating system.
*/
public static void shutdown(ExitStatus exitStatus) {
System.exit(exitStatus.toInt());
}
public static void closeExpresserInterface() {
System.out.print("eXpresser activity closing...");
MiGenSession.closeCurrentSession();
if (mainExpresserFrame != null) {
mainExpresserFrame.setVisible(false); // show that eXpresser it is closed
// save the current activity document
ActivityDocument activityDocument = mainExpresserFrame.getActivityDocument();
if (activityDocument != null && MiGenContext.isServerCommunicatorEnabled()) {
MiGenServerCommunicator serverCommunicator = MiGenContext.getServerCommunicator();
activityDocument.saveToServer(serverCommunicator, ActivityDocument.ACTIVITY_DOCUMENT_SAVED_BECAUSE_SHUTDOWN, null);
}
}
if (wizardOfOzFeedbackServer != null)
wizardOfOzFeedbackServer.shutdown();
if (modelCopyTabbedPane != null) {
modelCopyTabbedPane.saveKaleidoscopeCommonFormatLog();
}
// when this is called from shutdown should the following be called depending upon the ExitStatus?
if (homepageFrame != null) {
homepageFrame.setVisible(true);
homepageFrame.updateSavedModelList();
}
waitWhileRequestQueueIsEmptied();
System.out.println("*** eXpresser activity closed ***");
}
private static void waitWhileRequestQueueIsEmptied() {
JFrame waitFrame = new JFrame("Please wait...");
JTextField waitText = new JTextField("Please wait while eXpresser shuts down...");
waitText.setFont(new Font(Font.SERIF, Font.PLAIN, 16));
waitText.setForeground(Color.BLACK);
waitText.setEditable(false);
waitFrame.add(waitText);
waitFrame.pack();
mainExpresserFrame = null;
waitFrame.setLocationRelativeTo(null);
System.out.println("Waiting for the request queue to empty...");
while (!isQueueEmpty()) {
waitFrame.setVisible(true);
waitFrame.repaint();
try {
Thread.sleep(1000);
System.out.println("Still waiting...");
} catch (InterruptedException e) {
System.out.println("Waked up but still waiting...");
}
}
System.out.println("Request queue empty.");
waitFrame.setVisible(false);
}
private static boolean isQueueEmpty() {
if (!MiGenContext.isServerCommunicatorEnabled())
return true;
return MiGenContext.getServerCommunicator().isQueueEmpty();
}
public static String getUserNames() {
return getUserNames(", ");
}
public static String getUserNames(String separator) {
UserSet currentUserSet = new UserSet(allUsers);
return currentUserSet.getNamesAsString(separator);
}
public static boolean isSavedActivityDocumentLoadPending() {
return savedActivityDocumentLoadPending;
}
public static void setUserSet(UserSet userSet) {
ExpresserLauncher.userSet = userSet;
}
}
|