diff --git a/src/eva2/gui/Main.java b/src/eva2/gui/Main.java index beae0f8c..24feaf0b 100644 --- a/src/eva2/gui/Main.java +++ b/src/eva2/gui/Main.java @@ -1,557 +1,17 @@ package eva2.gui; import eva2.EvAInfo; -import eva2.optimization.OptimizationParameters; -import eva2.optimization.OptimizationStateListener; -import eva2.optimization.InterfaceOptimizationParameters; -import eva2.optimization.modules.*; -import eva2.optimization.statistics.AbstractStatistics; -import eva2.optimization.statistics.InterfaceStatisticsListener; -import eva2.optimization.statistics.InterfaceStatisticsParameters; -import eva2.tools.BasicResourceLoader; -import eva2.tools.EVAERROR; -import eva2.tools.ReflectPackage; import eva2.tools.StringTools; -import eva2.util.ClassPreloader; -import eva2.util.EvAComAdapter; -import javax.help.HelpSet; -import javax.help.JHelpContentViewer; -import javax.help.JHelpNavigator; -import javax.swing.*; -import java.awt.*; -import java.awt.event.*; -import java.net.URL; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; /** - * + * Main method, creates and sets up MainFrame */ -public class Main extends JFrame implements OptimizationStateListener { - - /** - * Generated serial version identifier. - */ - private static final long serialVersionUID = 8232856334379977970L; - private final int splashScreenTime; - private boolean clientInited = false; - private JDesktopPane desktopPane; - private JPanel configurationPane; - private Runnable initRunnable = null; - - private transient JProgressBar progressBar; - - // Option - private ExtAction actPreferences; - private ExtAction actQuit; - +public class Main { private static final Logger LOGGER = Logger.getLogger(Main.class.getName()); - // Configurable module: - private ModuleAdapter currentModuleAdapter = null; - - // Help: - private ExtAction actHelp; - private ExtAction actAbout; - private ExtAction actLicense; - - // if not null, the module is loaded automatically and no other can be selected - private String useDefaultModule = null; //"Genetic_Optimization"; - - - // measuring optimization runtime - private long startTime = 0; - private boolean withGUI = true; - private boolean withTreeView = false; - private EvATabbedFrameMaker frameMaker = null; - private Window parentWindow; - - private java.util.List superListenerList = null; - - private EvAComAdapter comAdapter; - - - public void addOptimizationStateListener(OptimizationStateListener l) { - if (superListenerList == null) { - superListenerList = new ArrayList<>(); - } - superListenerList.add(l); - } - - public boolean removeOptimizationStateListener(OptimizationStateListener l) { - return superListenerList != null && superListenerList.remove(l); - } - - /** - * Constructor of GUI of EvA2. Works as client for the EvA2 server. Note - * that the Main initialized multi-threaded for efficiency. Use {@link #awaitClientInitialized()} } - * to await full initialization if necessary. - */ - public Main() { - this(null, false, false); - } - - /** - * A constructor. Splash screen is optional, Gui is activated, no parent - * window. Note that the Main initialized multi-threaded for - * efficiency. Use {@link #awaitClientInitialized()} to await full - * initialization if necessary. - * - * @param paramsFile - * @param autorun - * @param nosplash - */ - public Main(final String paramsFile, boolean autorun, boolean nosplash) { - this(null, paramsFile, null, autorun, nosplash, false, false); - } - - /** - * A constructor with optional spash screen. Note that the Main is - * initialized multi-threaded for efficiency. Use {@link #awaitClientInitialized()} - * to await full initialization if necessary. - * - * @param autorun - * @param nosplash - * @see #Main(String, boolean, boolean) - */ - public Main(boolean autorun, boolean nosplash) { - this(null, autorun, nosplash); - } - - /** - * A constructor with optional splash screen. Note that the Main - * initialized multi-threaded for efficiency. Use {@link #awaitClientInitialized()} - * to await full initialization if necessary. - * - * @param paramsFile - * @param autorun - * @param noSplash - * @param noGui - * @see #Main(boolean, boolean) - */ - public Main(String paramsFile, boolean autorun, boolean noSplash, boolean noGui, boolean withTreeView) { - this(null, paramsFile, null, autorun, noSplash, noGui, withTreeView); - } - - /** - * A constructor with optional splash screen. Note that the Main - * initialized multi-threaded for efficiency. Use {@link #awaitClientInitialized()} - * to await full initialization if necessary. - * - * @param optimizationParameters - * @param autorun - * @param noSplash - * @param noGui - * @see #Main(String, boolean, boolean) - */ - public Main(InterfaceOptimizationParameters optimizationParameters, boolean autorun, boolean noSplash, boolean noGui) { - this(null, null, optimizationParameters, autorun, noSplash, noGui, false); - } - - /** - * Do not use the tree view by default. - * - * @param parent - * @param paramsFile - * @param goParams - * @param autorun - * @param noSplash - * @param noGui - */ - public Main(final Window parent, final String paramsFile, final InterfaceOptimizationParameters goParams, final boolean autorun, final boolean noSplash, final boolean noGui) { - this(parent, paramsFile, goParams, autorun, noSplash, noGui, false); - } - - /** - * Main constructor of the EvA2 client GUI. Works as standalone version - * locally or as client for the EvA2 server. GO parameters may be loaded - * from a file (paramsFile) or given directly as a java instance. Both may - * be null to start with standard parameters. If both are non null, the java - * instance has the higher priority. Note that the Main initialized - * multi-threaded for efficiency. Use {@link #awaitClientInitialized()} to - * await full initialization if necessary. - * - * @param parent - * @param paramsFile - * @param autorun - * @param noSplash - * @param noGui - */ - public Main(final Window parent, final String paramsFile, final InterfaceOptimizationParameters goParams, final boolean autorun, final boolean noSplash, final boolean noGui, final boolean showTreeView) { - clientInited = false; - final eva2.gui.SplashScreen splashScreen = new eva2.gui.SplashScreen(EvAInfo.splashLocation); - - // preload some classes (into system cache) in a parallel thread - preloadClasses(); - - withGUI = !noGui; - withTreeView = showTreeView; - // activate the splash screen (show later using SwingUtilities) - if (!noSplash && withGUI) { - try { - splashScreen.splash(); - } catch (HeadlessException e) { - LOGGER.severe("Error: no xserver present - deactivating GUI."); - withGUI = false; - } - } - - this.comAdapter = EvAComAdapter.getInstance(); - splashScreenTime = 2500; - initRunnable = new Runnable() { - - @Override - public void run() { - synchronized (this) { - long startTime = System.currentTimeMillis(); - init(paramsFile, goParams, parent); // this takes a bit - - long wait = System.currentTimeMillis() - startTime; - LOGGER.info("Loaded EvA2 in " + wait + "ms."); - System.out.print(wait); - if (!autorun) { - if (!noSplash) { - try { - // if splashScreenTime has not passed, sleep some more - if (wait < splashScreenTime) { - Thread.sleep(splashScreenTime - wait); - } - } catch (Exception ignored) { - } - } - } else { - if (!withGUI && (currentModuleAdapter instanceof GenericModuleAdapter)) { - // do not save new parameters for an autorun without GUI - they weren't changed manually anyways. - ((GenericModuleAdapter) currentModuleAdapter).getStatistics().setSaveParams(false); - LOGGER.info("Autorun without GUI - not saving statistics parameters..."); - } - if (withGUI) { - frameMaker.onUserStart(); - } else { - currentModuleAdapter.startOptimization(); - } - } - // close splash screen - if (!noSplash && withGUI) { - splashScreen.dispose(); - } - clientInited = true; - notifyAll(); - } - } - }; - SwingUtilities.invokeLater(initRunnable); - } - - private void initLookAndFeel() { - // The native L&F on Linux looks horrible - don't set it. - if (System.getProperty("os.name").equals("Linux")) { - return; - } - - // Properties for Mac OS X support. - if ((System.getProperty("mrj.version") != null) - || (System.getProperty("os.name").toLowerCase().contains("mac"))) { - /* - * Note: the xDock name property must be set before parsing - * command-line arguments! See above! - */ - System.setProperty("com.apple.mrj.application.apple.menu.about.name", EvAInfo.productName); - - System.setProperty("apple.awt.graphics.EnableQ2DX", "true"); - System.setProperty("apple.laf.useScreenMenuBar", "true"); - System.setProperty("com.apple.macos.smallTabs", "true"); - System.setProperty("com.apple.macos.useScreenMenuBar", "true"); - - System.setProperty("com.apple.mrj.application.growbox.intrudes", "false"); - System.setProperty("com.apple.mrj.application.live-resize", "true"); - try { - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { - LOGGER.log(Level.INFO, "Could not set Look&Feel", ex); - } - } else { - /* Set Look and Feel */ - try { - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - //UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); - } catch (Exception ex) { - LOGGER.log(Level.INFO, "Could not set Look&Feel", ex); - } - } - } - - /** - * Since the constructor runs multi-threaded for efficiency, this method may - * be called to await the full initialization of a client instance. As soon - * as it returns, the Main GUI is fully initialized. - */ - public void awaitClientInitialized() { - if (initRunnable != null) { - synchronized (initRunnable) { - if (!clientInited) { - try { - initRunnable.wait(); - initRunnable = null; - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - } - } - - private void preloadClasses() { - ClassPreloader cp = new ClassPreloader("eva2.optimization.strategies.InterfaceOptimizer", "eva2.problems.InterfaceOptimizationProblem", "eva2.optimization.operator.terminators.InterfaceTerminator"); - new Thread(cp).start(); - } - - /** - * Try to start the optimization with current parameters on the loaded - * module. Return true on success, otherwise false. - * - * @return - */ - public boolean startOptimization() { - if (currentModuleAdapter != null) { - currentModuleAdapter.startOptimization(); - return true; - } else { - return false; - } - } - - - /** - * Set UI Font for all controls. - * - * @param fontResource The FontUIResource for the controls - */ - private static void setUIFont(javax.swing.plaf.FontUIResource fontResource) { - Enumeration keys = UIManager.getDefaults().keys(); - while (keys.hasMoreElements()) { - Object key = keys.nextElement(); - Object value = UIManager.get(key); - if (value != null && value instanceof javax.swing.plaf.FontUIResource) { - UIManager.put(key, fontResource); - } - } - } - - /** - * Tries to load OptimizationParameters from given file if not null. - */ - private void init(String paramsFile, InterfaceOptimizationParameters optimizationParameters, final Window parent) { - useDefaultModule = EvAInfo.propDefaultModule(); - this.parentWindow = parent; - - setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); - - setUIFont(new javax.swing.plaf.FontUIResource(Font.SANS_SERIF, 0, 11)); - - if (useDefaultModule != null) { - useDefaultModule = useDefaultModule.trim(); - if (useDefaultModule.length() < 1) { - useDefaultModule = null; - } - } - - if (withGUI) { - // Initialize look and feel for EvA2 - initLookAndFeel(); - - GridBagConstraints gbConstraints = new GridBagConstraints(); - - /* Create main frame with GridBagLayout */ - setTitle(EvAInfo.productName); - setLayout(new GridBagLayout()); - setMinimumSize(new Dimension(1024, 800)); - - /* Creates the desktopPane for Plot/Text Output */ - desktopPane = new JExtDesktopPane(); - JEFrameRegister.getInstance().setDesktopPane(desktopPane); - /* Creates desktopPane ToolBar to show tiling buttons */ - JExtDesktopPaneToolBar desktopToolBar = new JExtDesktopPaneToolBar((JExtDesktopPane) desktopPane); - - /* Pane to hold ToolBar + DesktopPane */ - JPanel desktopPanel = new JPanel(new GridBagLayout()); - GridBagConstraints desktopConst = new GridBagConstraints(); - desktopConst.gridx = 0; - desktopConst.gridy = 0; - desktopConst.fill = GridBagConstraints.HORIZONTAL; - desktopConst.weightx = 1.0; - desktopPanel.add(desktopToolBar, desktopConst); - desktopConst.gridy = 1; - desktopConst.fill = GridBagConstraints.BOTH; - desktopConst.weighty = 1.0; - desktopPanel.add(desktopPane, desktopConst); - - BasicResourceLoader loader = BasicResourceLoader.getInstance(); - byte[] bytes = loader.getBytesFromResourceLocation(EvAInfo.iconLocation, true); - // TODO: use setIconImages (for better support of multiple icons when changing programs etc.) - setIconImage(Toolkit.getDefaultToolkit().createImage(bytes)); - - LoggingPanel logPanel = new LoggingPanel(); - logPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); - - createActions(); - - setSize(1024, 800); - Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); - setLocation((screenSize.width - this.getWidth()) / 2, (int) ((screenSize.height - this.getHeight()) / 2.5)); - - /* Create a new ConfigurationPanel (left side) */ - configurationPane = new JPanel(new GridBagLayout()); - gbConstraints.ipadx = 5; - gbConstraints.weightx = 0.0; - gbConstraints.weighty = 1.0; - /* Set configurationPane at 0,1 */ - gbConstraints.gridx = 0; - gbConstraints.gridy = 1; - gbConstraints.fill = GridBagConstraints.VERTICAL; - gbConstraints.gridwidth = GridBagConstraints.RELATIVE; - gbConstraints.gridheight = GridBagConstraints.RELATIVE; - add(configurationPane, gbConstraints); - - /* SplitPane for desktopPanel and loggingPanel */ - JSplitPane horizontalSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true); - horizontalSplit.setTopComponent(desktopPanel); - horizontalSplit.setBottomComponent(logPanel); - horizontalSplit.setDividerSize(8); - horizontalSplit.setOneTouchExpandable(true); - horizontalSplit.setResizeWeight(1.0); - horizontalSplit.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY, 1)); - horizontalSplit.setContinuousLayout(true); - - horizontalSplit.setDividerLocation(0.25); - /* Add horizontal split pane at 1,1 */ - gbConstraints.gridx = 1; - gbConstraints.gridy = 1; - gbConstraints.fill = GridBagConstraints.BOTH; - gbConstraints.gridwidth = GridBagConstraints.REMAINDER; - gbConstraints.gridheight = GridBagConstraints.RELATIVE; - add(horizontalSplit, gbConstraints); - - /* StatusBar of the main frame */ - JPanel statusBar = new JPanel(new FlowLayout(FlowLayout.RIGHT)); - JPanel statusBarControls = new JPanel(); - statusBarControls.setLayout(new BoxLayout(statusBarControls, BoxLayout.LINE_AXIS)); - - statusBarControls.add(Box.createHorizontalGlue()); - - /* Set default logging level to INFO */ - Logger.getLogger("eva2").setLevel(Level.INFO); - /* Logging settings drop down */ - LoggingLevelLabel loggingOption = new LoggingLevelLabel(); - - statusBarControls.add(loggingOption); - - statusBarControls.add(Box.createHorizontalStrut(5)); - statusBarControls.add(new JSeparator(JSeparator.VERTICAL)); - statusBarControls.add(Box.createHorizontalStrut(5)); - - /* Create ProgressBar and add it to the status bar */ - statusBarControls.add(new JLabel("Progress")); - statusBarControls.add(Box.createHorizontalStrut(5)); - - progressBar = new JProgressBar(); - progressBar.setValue(0); - progressBar.setStringPainted(true); - statusBarControls.add(progressBar); - - statusBarControls.add(Box.createHorizontalStrut(5)); - statusBarControls.add(new JSeparator(JSeparator.VERTICAL)); - statusBarControls.add(Box.createHorizontalStrut(5)); - /* Create ProgressBar and add it to the status bar */ - statusBarControls.add(new JLabel("CPU")); - statusBarControls.add(Box.createHorizontalStrut(5)); - statusBarControls.add(new CPUPanel(100)); - - statusBar.add(statusBarControls); - - gbConstraints.gridx = 0; - gbConstraints.gridy = 2; - gbConstraints.gridwidth = 2; - gbConstraints.weighty = 0.0; - gbConstraints.fill = GridBagConstraints.HORIZONTAL; - gbConstraints.anchor = GridBagConstraints.PAGE_END; - add(statusBar, gbConstraints); - } - - if (useDefaultModule != null) { - /* - * if optimizationParameters are not defined and a params file is defined - * try to load parameters from file - */ - if (optimizationParameters == null && (paramsFile != null && (paramsFile.length() > 0))) { - optimizationParameters = OptimizationParameters.getInstance(paramsFile, false); - } - loadSpecificModule(useDefaultModule, optimizationParameters);//loadSpecificModule - } - - if (withGUI) { - buildMenu(); - addWindowListener(new WindowAdapter() { - - @Override - public void windowClosing(final WindowEvent event) { - int result = JOptionPane.showConfirmDialog( - Main.this, - "Do you really want to exit EvA2?", - "Exit Application", - JOptionPane.YES_NO_OPTION); - if (result == JOptionPane.YES_OPTION) { - Main.this.close(); - } - } - }); - - LOGGER.log(Level.INFO, "Working directory is: {0}", System.getProperty("user.dir")); - LOGGER.log(Level.FINE, "Class path is: {0}", System.getProperty("java.class.path", ".")); - - if (!(configurationPane.isVisible())) { - configurationPane.setVisible(true); - } - - setVisible(true); - - // if this message is omitted, the stupid scroll pane runs to - // the end of the last line which is ugly for a long class path - LOGGER.info("EvA2 ready"); - } - } - - /** - * Closes EvA2 workbench. Will not kill the JVM iff - * the MATLAB environment variable has been set. - */ - public void close() { - LOGGER.info("Closing EvA2 Client. Bye!"); - Set keys = System.getenv().keySet(); - if (keys.contains("MATLAB")) { - LOGGER.info("EvA2 workbench has been started from Matlab: not killing JVM"); - } else { - if (parentWindow == null) { - System.exit(1); - } else { - this.setVisible(false); - this.dispose(); - } - } - } - - /** - * Refresh the parameter panels (if settings have been changed outside of - * the GUI which should be updated in the GUI. - */ - public void refreshMainPanels() { - frameMaker.refreshPanels(); - } - /** * The one and only main of the client program. Possible arguments: * --autorun: immediately starts the optimization (with parameters loaded @@ -562,9 +22,27 @@ public class Main extends JFrame implements OptimizationStateListener { * @param args command line parameters */ public static void main(String[] args) { + // Properties for Mac OS X support. + if ((System.getProperty("mrj.version") != null) + || (System.getProperty("os.name").toLowerCase().contains("mac"))) { + /* + * Note: the xDock name property must be set before parsing + * command-line arguments! See above! + */ + System.setProperty("com.apple.mrj.application.apple.menu.about.name", EvAInfo.productName); + System.setProperty("apple.awt.application.name", EvAInfo.productName); + System.setProperty("apple.awt.graphics.EnableQ2DX", "true"); + System.setProperty("apple.laf.useScreenMenuBar", "true"); + System.setProperty("com.apple.macos.smallTabs", "true"); + System.setProperty("com.apple.macos.useScreenMenuBar", "true"); + + System.setProperty("com.apple.mrj.application.growbox.intrudes", "false"); + System.setProperty("com.apple.mrj.application.live-resize", "true"); + } + /* Available command-line parameters */ String[] keys = new String[]{ - "--help", "--autorun", "--nosplash", "--nogui", "--params", "--treeView" + "--help", "--autorun", "--nosplash", "--nogui", "--params", "--treeView" }; /* Number of arguments per parameter */ int[] arities = new int[]{0, 0, 0, 0, 1, 0}; @@ -596,42 +74,10 @@ public class Main extends JFrame implements OptimizationStateListener { boolean treeView = (values[5] != null); String paramsFile = StringTools.checkSingleStringArg(keys[4], values[4], arities[4] - 1); - new Main(paramsFile, autorun, nosplash, nogui, treeView); + new MainFrame(paramsFile, autorun, nosplash, nogui, treeView); } } - /** - * Initialize the client GUI with given parameters and set listeners. This - * will return as soon as the GUI is visible and ready. - * - * @param goParams optimization parameters - * @param statisticsListener statistics listener receiving data during - * optimization - * @param windowListener additional window listener for client frame - */ - public static Main initClientGUI(OptimizationParameters goParams, - InterfaceStatisticsListener statisticsListener, - WindowListener windowListener, final Window parent) { - Main evaClient; - - evaClient = new Main(parent, null, goParams, - false, true, false, false); // initializes GUI in the background - // important: wait for GUI initialization before accessing any internal - // settings: - evaClient.awaitClientInitialized(); // this returns as soon as the - // GUI is ready - evaClient.addWindowListener(windowListener); - // modify initial settings and activate output of all data: - evaClient.getStatistics().getStatisticsParameters().setOutputAllFieldsAsText(true); - // add a data listener instance: - evaClient.getStatistics().addDataListener(statisticsListener); - - // GUI update due to the changes made through the API - evaClient.refreshMainPanels(); - - return evaClient; - } - /** * This method returns a readable usage string. * @@ -660,309 +106,4 @@ public class Main extends JFrame implements OptimizationStateListener { return sbuf.toString(); } - - /** - * - */ - private void createActions() { - - actAbout = new ExtAction("&About", "Product Information") { - - @Override - public void actionPerformed(final ActionEvent event) { - LOGGER.info(event.getActionCommand()); - showAboutDialog(); - } - }; - actLicense = new ExtAction("&License", "View License") { - - @Override - public void actionPerformed(final ActionEvent event) { - LOGGER.info(event.getActionCommand()); - showLicense(); - } - }; - - actQuit = new ExtAction("&Quit", "Quit EvA2 workbench", - KeyStroke.getKeyStroke(KeyEvent.VK_Q, InputEvent.CTRL_MASK)) { - - @Override - public void actionPerformed(final ActionEvent event) { - int result = JOptionPane.showConfirmDialog( - Main.this, - "Do you really want to exit EvA2?", - "Exit Application", - JOptionPane.YES_NO_OPTION); - if (result == JOptionPane.YES_OPTION) { - Main.this.close(); - } - } - }; - - actPreferences = new ExtAction("&Preferences", "Show preferences dialog", - KeyStroke.getKeyStroke(KeyEvent.VK_P, InputEvent.CTRL_MASK)) { - - @Override - public void actionPerformed(final ActionEvent event) { - // ToDo - } - }; - - actHelp = new ExtAction("&Help", "Show help contents", - KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0)) { - - @Override - public void actionPerformed(final ActionEvent event) { - // ToDo - String helpHS = "EvA2Help/EvA2Help.hs"; - ClassLoader cl = Main.class.getClassLoader(); - JHelpContentViewer helpPane; - try { - URL hsURL = HelpSet.findHelpSet(cl, helpHS); - HelpSet helpSet = new HelpSet(null, hsURL); - // Trigger the help viewer: - helpPane = new JHelpContentViewer(helpSet); - JHelpNavigator helpNavigator = (JHelpNavigator) helpSet.getNavigatorView("TOC").createNavigator(helpPane.getModel()); - JEFrame helpFrame = new JEFrame("Help contents"); - JSplitPane helpSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, helpNavigator, helpPane); - helpFrame.add(helpSplit); - helpFrame.setVisible(true); - helpFrame.setMaximum(true); - } catch (Exception ee) { - // Say what the exception really is - LOGGER.log(Level.WARNING, "Could not open application help", ee); - } - } - }; - } - - /** - * Create the main menu and add actions. - */ - private void buildMenu() { - JMenuBar menuBar = new JMenuBar(); - setJMenuBar(menuBar); - - JExtMenu menuHelp = new JExtMenu("&Help"); - menuHelp.add(actHelp); - menuHelp.addSeparator(); - menuHelp.add(actAbout); - menuHelp.add(actLicense); - - JExtMenu menuOptions = new JExtMenu("&Options"); - menuOptions.add(actPreferences); - menuOptions.addSeparator(); - menuOptions.add(actQuit); - - menuBar.add(menuOptions); - menuBar.add(((JExtDesktopPane) desktopPane).getWindowMenu()); - menuBar.add(menuHelp); - } - - /** - * Retrieve the optimization parameters of a loaded module. Return null if no module is - * loaded. - * - * @return - */ - public InterfaceOptimizationParameters getOptimizationParameters() { - if (currentModuleAdapter != null) { - if (currentModuleAdapter instanceof AbstractModuleAdapter) { - return ((AbstractModuleAdapter) currentModuleAdapter).getOptimizationParameters(); - } - } - return null; - } - - public AbstractStatistics getStatistics() { - return ((GenericModuleAdapter) currentModuleAdapter).getStatistics(); - } - - public InterfaceStatisticsParameters getStatisticsParameter() { - return ((GenericModuleAdapter) currentModuleAdapter).getStatistics().getStatisticsParameters(); - } - - private void loadSpecificModule(String selectedModule, InterfaceOptimizationParameters optimizationParameters) { - ModuleAdapter newModuleAdapter = null; - // - try { - InterfaceOptimizationParameters params = optimizationParameters; - if (optimizationParameters == null) { - params = OptimizationParameters.getInstance(); - } - newModuleAdapter = new GOModuleAdapter(selectedModule, params, withGUI ? null : "EvA2"); - //newModuleAdapter = comAdapter.getModuleAdapter(selectedModule, optimizationParameters, withGUI ? null : "EvA2"); - } catch (Exception e) { - LOGGER.log(Level.SEVERE, "Error loading module.", e); - EVAERROR.EXIT("Error while comAdapter.GetModuleAdapter Host: " + e.getMessage()); - } - if (newModuleAdapter == null) { - // When launching a Java Web Start application, baseDir will always be null! - URL baseDir = getClass().getClassLoader().getResource(""); - String cp = System.getProperty("java.class.path", "."); - String dir = (baseDir == null) ? System.getProperty("user.dir") : baseDir.getPath(); - - if (!cp.contains(dir)) { - // this was added due to matlab not adding base dir to base path... - System.err.println("classpath does not contain base directory!"); - System.err.println("adding base dir and trying again..."); - System.setProperty("java.class.path", cp + System.getProperty("path.separator") + dir); - ReflectPackage.resetDynCP(); - comAdapter.updateLocalMainAdapter(); - loadSpecificModule(selectedModule, optimizationParameters); // end recursive call! handle with care! - } - } else { - newModuleAdapter.addOptimizationStateListener(this); - try { - if (withGUI) { - // this (or rather: EvAModuleButtonPanelMaker) is where the start button etc come from! - frameMaker = newModuleAdapter.getModuleFrame(); - - /* This is the left TabPane on the main frame */ - JPanel moduleContainer = frameMaker.makePanel(); - - configurationPane.setVisible(false); - configurationPane.removeAll(); - - GridBagConstraints gbConstraints = new GridBagConstraints(); - - /* ToDo: Find a way to properly add the TreeView to the GOPanel */ - if (withTreeView && (newModuleAdapter instanceof AbstractModuleAdapter)) { - JComponent tree = null; - tree = getEvATreeView(frameMaker.getGOPanel(), "OptimizationParameters", ((AbstractModuleAdapter) newModuleAdapter).getOptimizationParameters()); - gbConstraints.gridx = 0; - gbConstraints.gridy = 0; - gbConstraints.fill = GridBagConstraints.BOTH; - gbConstraints.weightx = 1.0; - gbConstraints.weighty = 1.0; - configurationPane.add(tree, gbConstraints); - } - - - gbConstraints.weightx = 1.0; - gbConstraints.weighty = 0.0; - gbConstraints.gridx = 0; - gbConstraints.gridy = 0; - gbConstraints.gridwidth = 2; - gbConstraints.fill = GridBagConstraints.HORIZONTAL; - gbConstraints.anchor = GridBagConstraints.PAGE_START; - add(frameMaker.getToolBar(), gbConstraints); - - GridBagConstraints gbConstraints2 = new GridBagConstraints(); - gbConstraints2.gridx = 0; - gbConstraints2.gridy = 0; - gbConstraints2.fill = GridBagConstraints.VERTICAL; - gbConstraints2.weighty = 1.0; - configurationPane.add(moduleContainer, gbConstraints2); - configurationPane.validate(); - } - - - } catch (Exception e) { - LOGGER.log(Level.SEVERE, "Error while newModuleAdapter.getModuleFrame(): " + e.getMessage(), e); - EVAERROR.EXIT("Error while newModuleAdapter.getModuleFrame(): " + e.getMessage()); - } - - currentModuleAdapter = newModuleAdapter; - } - } - - /** - * Create a tree view of an object based on EvATreeNode. It is encapsulated - * in a JScrollPane. - * - * @param goPanel - * @param title - * @param object - * @return - * @see eva2.gui.EvATreeNode - */ - public JComponent getEvATreeView(JParaPanel goPanel, String title, Object object) { - EvATreeNode root = new EvATreeNode(title, object); // the root of the tree - JTree jtree = new JTree(root); - JScrollPane treeView = new JScrollPane(jtree); - - EvATreeSelectionListener treeListener = new EvATreeSelectionListener(root, goPanel.getEditor(), jtree); - // hooks itself up as the tree listener. It reacts both to changes in the selection - // state of the tree (to update the parameter panel) and to changes in the - // parameters to update the tree - return treeView; - } - - private void showAboutDialog() { - AboutDialog aboutDialog = new AboutDialog(this); - aboutDialog.setLocationRelativeTo(this); - aboutDialog.setVisible(true); - aboutDialog.setModalityType(Dialog.ModalityType.APPLICATION_MODAL); - } - - private void showLicense() { - HtmlDemo lgpl = new HtmlDemo(EvAInfo.LGPLFile); - HtmlDemo gpl = new HtmlDemo(EvAInfo.GPLFile); - gpl.show(); - lgpl.show(); - } - - @Override - public void performedRestart(String infoString) { - if (superListenerList != null) { - for (OptimizationStateListener l : superListenerList) { - l.performedRestart(infoString); - } - } - LOGGER.log(Level.INFO, "Restarted processing {0}", infoString); - startTime = System.currentTimeMillis(); - } - - @Override - public void performedStart(String infoString) { - if (superListenerList != null) { - for (OptimizationStateListener l : superListenerList) { - l.performedStart(infoString); - } - } - LOGGER.log(Level.INFO, "Started processing {0}", infoString); - startTime = System.currentTimeMillis(); - } - - @Override - public void performedStop() { - if (superListenerList != null) { - for (OptimizationStateListener l : superListenerList) { - l.performedStop(); - } - } - long t = (System.currentTimeMillis() - startTime); - LOGGER.info(String.format("Stopped after %1$d.%2$tL s", (t / 1000), (t % 1000))); - if (!withGUI) { - System.exit(0); - } - } - - /** - * When the worker needs to update the GUI we do so by queuing a Runnable - * for the event dispatching thread with SwingUtilities.invokeLater(). In - * this case we're just changing the progress bars value. - */ - @Override - public void updateProgress(final int percent, String msg) { - if (superListenerList != null) { - for (OptimizationStateListener l : superListenerList) { - l.updateProgress(percent, msg); - } - } - if (msg != null) { - LOGGER.info(msg); - } - if (this.progressBar != null) { - Runnable doSetProgressBarValue = new Runnable() { - - @Override - public void run() { - progressBar.setValue(percent); - } - }; - SwingUtilities.invokeLater(doSetProgressBarValue); - } - } } diff --git a/src/eva2/gui/MainFrame.java b/src/eva2/gui/MainFrame.java new file mode 100644 index 00000000..410660a8 --- /dev/null +++ b/src/eva2/gui/MainFrame.java @@ -0,0 +1,877 @@ +package eva2.gui; + +import eva2.EvAInfo; +import eva2.optimization.OptimizationParameters; +import eva2.optimization.OptimizationStateListener; +import eva2.optimization.InterfaceOptimizationParameters; +import eva2.optimization.modules.*; +import eva2.optimization.statistics.AbstractStatistics; +import eva2.optimization.statistics.InterfaceStatisticsListener; +import eva2.optimization.statistics.InterfaceStatisticsParameters; +import eva2.tools.BasicResourceLoader; +import eva2.tools.EVAERROR; +import eva2.tools.ReflectPackage; +import eva2.util.ClassPreloader; +import eva2.util.EvAComAdapter; + +import javax.help.HelpSet; +import javax.help.JHelpContentViewer; +import javax.help.JHelpNavigator; +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; +import java.net.URL; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + */ +public class MainFrame extends JFrame implements OptimizationStateListener { + + /** + * Generated serial version identifier. + */ + private static final long serialVersionUID = 8232856334379977970L; + private final int splashScreenTime; + private boolean clientInitialized = false; + private JDesktopPane desktopPane; + private JPanel configurationPane; + private Runnable initRunnable = null; + + private transient JProgressBar progressBar; + + // Option + private ExtAction actPreferences; + private ExtAction actQuit; + + private static final Logger LOGGER = Logger.getLogger(MainFrame.class.getName()); + + // Configurable module: + private ModuleAdapter currentModuleAdapter = null; + + // Help: + private ExtAction actHelp; + private ExtAction actAbout; + private ExtAction actLicense; + + // if not null, the module is loaded automatically and no other can be selected + private String useDefaultModule = null; //"Genetic_Optimization"; + + + // measuring optimization runtime + private long startTime = 0; + private boolean withGUI = true; + private boolean withTreeView = false; + private EvATabbedFrameMaker frameMaker = null; + private Window parentWindow; + + private java.util.List superListenerList = null; + + private EvAComAdapter comAdapter; + + + public void addOptimizationStateListener(OptimizationStateListener l) { + if (superListenerList == null) { + superListenerList = new ArrayList<>(); + } + superListenerList.add(l); + } + + public boolean removeOptimizationStateListener(OptimizationStateListener l) { + return superListenerList != null && superListenerList.remove(l); + } + + /** + * Constructor of GUI of EvA2. Works as client for the EvA2 server. Note + * that the Main initialized multi-threaded for efficiency. Use {@link #awaitClientInitialized()} } + * to await full initialization if necessary. + */ + public MainFrame() { + this(null, false, false); + } + + /** + * A constructor. Splash screen is optional, Gui is activated, no parent + * window. Note that the Main initialized multi-threaded for + * efficiency. Use {@link #awaitClientInitialized()} to await full + * initialization if necessary. + * + * @param paramsFile + * @param autorun + * @param nosplash + */ + public MainFrame(final String paramsFile, boolean autorun, boolean nosplash) { + this(null, paramsFile, null, autorun, nosplash, false, false); + } + + /** + * A constructor with optional spash screen. Note that the Main is + * initialized multi-threaded for efficiency. Use {@link #awaitClientInitialized()} + * to await full initialization if necessary. + * + * @param autorun + * @param nosplash + * @see #MainFrame(String, boolean, boolean) + */ + public MainFrame(boolean autorun, boolean nosplash) { + this(null, autorun, nosplash); + } + + /** + * A constructor with optional splash screen. Note that the Main + * initialized multi-threaded for efficiency. Use {@link #awaitClientInitialized()} + * to await full initialization if necessary. + * + * @param paramsFile + * @param autorun + * @param noSplash + * @param noGui + * @see #MainFrame(boolean, boolean) + */ + public MainFrame(String paramsFile, boolean autorun, boolean noSplash, boolean noGui, boolean withTreeView) { + this(null, paramsFile, null, autorun, noSplash, noGui, withTreeView); + } + + /** + * A constructor with optional splash screen. Note that the Main + * initialized multi-threaded for efficiency. Use {@link #awaitClientInitialized()} + * to await full initialization if necessary. + * + * @param optimizationParameters + * @param autorun + * @param noSplash + * @param noGui + * @see #MainFrame(String, boolean, boolean) + */ + public MainFrame(InterfaceOptimizationParameters optimizationParameters, boolean autorun, boolean noSplash, boolean noGui) { + this(null, null, optimizationParameters, autorun, noSplash, noGui, false); + } + + /** + * Do not use the tree view by default. + * + * @param parent + * @param paramsFile + * @param goParams + * @param autorun + * @param noSplash + * @param noGui + */ + public MainFrame(final Window parent, final String paramsFile, final InterfaceOptimizationParameters goParams, final boolean autorun, final boolean noSplash, final boolean noGui) { + this(parent, paramsFile, goParams, autorun, noSplash, noGui, false); + } + + /** + * Main constructor of the EvA2 client GUI. Works as standalone version + * locally or as client for the EvA2 server. GO parameters may be loaded + * from a file (paramsFile) or given directly as a java instance. Both may + * be null to start with standard parameters. If both are non null, the java + * instance has the higher priority. Note that the Main initialized + * multi-threaded for efficiency. Use {@link #awaitClientInitialized()} to + * await full initialization if necessary. + * + * @param parent + * @param paramsFile + * @param autorun + * @param noSplash + * @param noGui + */ + public MainFrame(final Window parent, final String paramsFile, final InterfaceOptimizationParameters optimizationParameters, final boolean autorun, final boolean noSplash, final boolean noGui, final boolean showTreeView) { + clientInitialized = false; + final eva2.gui.SplashScreen splashScreen = new eva2.gui.SplashScreen(EvAInfo.splashLocation); + + // preload some classes (into system cache) in a parallel thread + preloadClasses(); + + withGUI = !noGui; + withTreeView = showTreeView; + // activate the splash screen (show later using SwingUtilities) + if (!noSplash && withGUI) { + try { + splashScreen.splash(); + } catch (HeadlessException e) { + LOGGER.severe("Error: no xserver present - deactivating GUI."); + withGUI = false; + } + } + + this.comAdapter = EvAComAdapter.getInstance(); + splashScreenTime = 2500; + initRunnable = new Runnable() { + + @Override + public void run() { + synchronized (this) { + long startTime = System.currentTimeMillis(); + init(paramsFile, optimizationParameters, parent); // this takes a bit + + long wait = System.currentTimeMillis() - startTime; + LOGGER.info("Loaded EvA2 in " + wait + "ms."); + System.out.print(wait); + if (!autorun) { + if (!noSplash) { + try { + // if splashScreenTime has not passed, sleep some more + if (wait < splashScreenTime) { + Thread.sleep(splashScreenTime - wait); + } + } catch (Exception ignored) { + } + } + } else { + if (!withGUI && (currentModuleAdapter instanceof GenericModuleAdapter)) { + // do not save new parameters for an autorun without GUI - they weren't changed manually anyways. + ((GenericModuleAdapter) currentModuleAdapter).getStatistics().setSaveParams(false); + LOGGER.info("Autorun without GUI - not saving statistics parameters..."); + } + if (withGUI) { + frameMaker.onUserStart(); + } else { + currentModuleAdapter.startOptimization(); + } + } + // close splash screen + if (!noSplash && withGUI) { + splashScreen.dispose(); + } + clientInitialized = true; + notifyAll(); + } + } + }; + SwingUtilities.invokeLater(initRunnable); + } + + private void initLookAndFeel() { + // The native L&F on Linux looks horrible - don't set it. + if (System.getProperty("os.name").equals("Linux")) { + return; + } + + // Properties for Mac OS X support. + if ((System.getProperty("mrj.version") != null) + || (System.getProperty("os.name").toLowerCase().contains("mac"))) { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { + LOGGER.log(Level.INFO, "Could not set Look&Feel", ex); + } + } else { + /* Set Look and Feel */ + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + //UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); + } catch (Exception ex) { + LOGGER.log(Level.INFO, "Could not set Look&Feel", ex); + } + } + } + + /** + * Since the constructor runs multi-threaded for efficiency, this method may + * be called to await the full initialization of a client instance. As soon + * as it returns, the Main GUI is fully initialized. + */ + public void awaitClientInitialized() { + if (initRunnable != null) { + synchronized (initRunnable) { + if (!clientInitialized) { + try { + initRunnable.wait(); + initRunnable = null; + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + } + + private void preloadClasses() { + ClassPreloader cp = new ClassPreloader("eva2.optimization.strategies.InterfaceOptimizer", "eva2.problems.InterfaceOptimizationProblem", "eva2.optimization.operator.terminators.InterfaceTerminator"); + new Thread(cp).start(); + } + + /** + * Try to start the optimization with current parameters on the loaded + * module. Return true on success, otherwise false. + * + * @return + */ + public boolean startOptimization() { + if (currentModuleAdapter != null) { + currentModuleAdapter.startOptimization(); + return true; + } else { + return false; + } + } + + + /** + * Set UI Font for all controls. + * + * @param fontResource The FontUIResource for the controls + */ + private static void setUIFont(javax.swing.plaf.FontUIResource fontResource) { + Enumeration keys = UIManager.getDefaults().keys(); + while (keys.hasMoreElements()) { + Object key = keys.nextElement(); + Object value = UIManager.get(key); + if (value != null && value instanceof javax.swing.plaf.FontUIResource) { + UIManager.put(key, fontResource); + } + } + } + + /** + * Tries to load OptimizationParameters from given file if not null. + */ + private void init(String paramsFile, InterfaceOptimizationParameters optimizationParameters, final Window parent) { + useDefaultModule = EvAInfo.propDefaultModule(); + this.parentWindow = parent; + + setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + + setUIFont(new javax.swing.plaf.FontUIResource(Font.SANS_SERIF, 0, 11)); + + if (useDefaultModule != null) { + useDefaultModule = useDefaultModule.trim(); + if (useDefaultModule.length() < 1) { + useDefaultModule = null; + } + } + + if (withGUI) { + // Initialize look and feel for EvA2 + initLookAndFeel(); + + GridBagConstraints gbConstraints = new GridBagConstraints(); + + /* Create main frame with GridBagLayout */ + setTitle(EvAInfo.productName); + setLayout(new GridBagLayout()); + setMinimumSize(new Dimension(1024, 800)); + + /* Creates the desktopPane for Plot/Text Output */ + desktopPane = new JExtDesktopPane(); + JEFrameRegister.getInstance().setDesktopPane(desktopPane); + /* Creates desktopPane ToolBar to show tiling buttons */ + JExtDesktopPaneToolBar desktopToolBar = new JExtDesktopPaneToolBar((JExtDesktopPane) desktopPane); + + /* Pane to hold ToolBar + DesktopPane */ + JPanel desktopPanel = new JPanel(new GridBagLayout()); + GridBagConstraints desktopConst = new GridBagConstraints(); + desktopConst.gridx = 0; + desktopConst.gridy = 0; + desktopConst.fill = GridBagConstraints.HORIZONTAL; + desktopConst.weightx = 1.0; + desktopPanel.add(desktopToolBar, desktopConst); + desktopConst.gridy = 1; + desktopConst.fill = GridBagConstraints.BOTH; + desktopConst.weighty = 1.0; + desktopPanel.add(desktopPane, desktopConst); + + BasicResourceLoader loader = BasicResourceLoader.getInstance(); + byte[] bytes = loader.getBytesFromResourceLocation(EvAInfo.iconLocation, true); + // TODO: use setIconImages (for better support of multiple icons when changing programs etc.) + setIconImage(Toolkit.getDefaultToolkit().createImage(bytes)); + + LoggingPanel logPanel = new LoggingPanel(); + logPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + + createActions(); + + setSize(1024, 800); + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + setLocation((screenSize.width - this.getWidth()) / 2, (int) ((screenSize.height - this.getHeight()) / 2.5)); + + /* Create a new ConfigurationPanel (left side) */ + configurationPane = new JPanel(new GridBagLayout()); + gbConstraints.ipadx = 5; + gbConstraints.weightx = 0.0; + gbConstraints.weighty = 1.0; + /* Set configurationPane at 0,1 */ + gbConstraints.gridx = 0; + gbConstraints.gridy = 1; + gbConstraints.fill = GridBagConstraints.VERTICAL; + gbConstraints.gridwidth = GridBagConstraints.RELATIVE; + gbConstraints.gridheight = GridBagConstraints.RELATIVE; + add(configurationPane, gbConstraints); + + /* SplitPane for desktopPanel and loggingPanel */ + JSplitPane horizontalSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true); + horizontalSplit.setTopComponent(desktopPanel); + horizontalSplit.setBottomComponent(logPanel); + horizontalSplit.setDividerSize(8); + horizontalSplit.setOneTouchExpandable(true); + horizontalSplit.setResizeWeight(1.0); + horizontalSplit.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY, 1)); + horizontalSplit.setContinuousLayout(true); + + horizontalSplit.setDividerLocation(0.25); + /* Add horizontal split pane at 1,1 */ + gbConstraints.gridx = 1; + gbConstraints.gridy = 1; + gbConstraints.fill = GridBagConstraints.BOTH; + gbConstraints.gridwidth = GridBagConstraints.REMAINDER; + gbConstraints.gridheight = GridBagConstraints.RELATIVE; + add(horizontalSplit, gbConstraints); + + /* StatusBar of the main frame */ + JPanel statusBar = new JPanel(new FlowLayout(FlowLayout.RIGHT)); + JPanel statusBarControls = new JPanel(); + statusBarControls.setLayout(new BoxLayout(statusBarControls, BoxLayout.LINE_AXIS)); + + statusBarControls.add(Box.createHorizontalGlue()); + + /* Set default logging level to INFO */ + Logger.getLogger("eva2").setLevel(Level.INFO); + /* Logging settings drop down */ + LoggingLevelLabel loggingOption = new LoggingLevelLabel(); + + statusBarControls.add(loggingOption); + + statusBarControls.add(Box.createHorizontalStrut(5)); + statusBarControls.add(new JSeparator(JSeparator.VERTICAL)); + statusBarControls.add(Box.createHorizontalStrut(5)); + + /* Create ProgressBar and add it to the status bar */ + statusBarControls.add(new JLabel("Progress")); + statusBarControls.add(Box.createHorizontalStrut(5)); + + progressBar = new JProgressBar(); + progressBar.setValue(0); + progressBar.setStringPainted(true); + statusBarControls.add(progressBar); + + statusBarControls.add(Box.createHorizontalStrut(5)); + statusBarControls.add(new JSeparator(JSeparator.VERTICAL)); + statusBarControls.add(Box.createHorizontalStrut(5)); + /* Create ProgressBar and add it to the status bar */ + statusBarControls.add(new JLabel("CPU")); + statusBarControls.add(Box.createHorizontalStrut(5)); + statusBarControls.add(new CPUPanel(100)); + + statusBar.add(statusBarControls); + + gbConstraints.gridx = 0; + gbConstraints.gridy = 2; + gbConstraints.gridwidth = 2; + gbConstraints.weighty = 0.0; + gbConstraints.fill = GridBagConstraints.HORIZONTAL; + gbConstraints.anchor = GridBagConstraints.PAGE_END; + add(statusBar, gbConstraints); + } + + if (useDefaultModule != null) { + /* + * if optimizationParameters are not defined and a params file is defined + * try to load parameters from file + */ + if (optimizationParameters == null && (paramsFile != null && (paramsFile.length() > 0))) { + optimizationParameters = OptimizationParameters.getInstance(paramsFile, false); + } + loadSpecificModule(useDefaultModule, optimizationParameters);//loadSpecificModule + } + + if (withGUI) { + buildMenu(); + addWindowListener(new WindowAdapter() { + + @Override + public void windowClosing(final WindowEvent event) { + int result = JOptionPane.showConfirmDialog( + MainFrame.this, + "Do you really want to exit EvA2?", + "Exit Application", + JOptionPane.YES_NO_OPTION); + if (result == JOptionPane.YES_OPTION) { + MainFrame.this.close(); + } + } + }); + + LOGGER.log(Level.INFO, "Working directory is: {0}", System.getProperty("user.dir")); + LOGGER.log(Level.FINE, "Class path is: {0}", System.getProperty("java.class.path", ".")); + + if (!(configurationPane.isVisible())) { + configurationPane.setVisible(true); + } + + setVisible(true); + + // if this message is omitted, the stupid scroll pane runs to + // the end of the last line which is ugly for a long class path + LOGGER.info("EvA2 ready"); + } + } + + /** + * Closes EvA2 workbench. Will not kill the JVM iff + * the MATLAB environment variable has been set. + */ + public void close() { + LOGGER.info("Closing EvA2 Client. Bye!"); + Set keys = System.getenv().keySet(); + if (keys.contains("MATLAB")) { + LOGGER.info("EvA2 workbench has been started from Matlab: not killing JVM"); + } else { + if (parentWindow == null) { + System.exit(1); + } else { + this.setVisible(false); + this.dispose(); + } + } + } + + /** + * Refresh the parameter panels (if settings have been changed outside of + * the GUI which should be updated in the GUI. + */ + public void refreshMainPanels() { + frameMaker.refreshPanels(); + } + + /** + * Initialize the client GUI with given parameters and set listeners. This + * will return as soon as the GUI is visible and ready. + * + * @param goParams optimization parameters + * @param statisticsListener statistics listener receiving data during + * optimization + * @param windowListener additional window listener for client frame + */ + public static MainFrame initClientGUI(OptimizationParameters goParams, + InterfaceStatisticsListener statisticsListener, + WindowListener windowListener, final Window parent) { + MainFrame evaClient; + + evaClient = new MainFrame(parent, null, goParams, + false, true, false, false); // initializes GUI in the background + // important: wait for GUI initialization before accessing any internal + // settings: + evaClient.awaitClientInitialized(); // this returns as soon as the + // GUI is ready + evaClient.addWindowListener(windowListener); + // modify initial settings and activate output of all data: + evaClient.getStatistics().getStatisticsParameters().setOutputAllFieldsAsText(true); + // add a data listener instance: + evaClient.getStatistics().addDataListener(statisticsListener); + + // GUI update due to the changes made through the API + evaClient.refreshMainPanels(); + + return evaClient; + } + + /** + * + */ + private void createActions() { + + actAbout = new ExtAction("&About", "Product Information") { + + @Override + public void actionPerformed(final ActionEvent event) { + LOGGER.info(event.getActionCommand()); + showAboutDialog(); + } + }; + actLicense = new ExtAction("&License", "View License") { + + @Override + public void actionPerformed(final ActionEvent event) { + LOGGER.info(event.getActionCommand()); + showLicense(); + } + }; + + actQuit = new ExtAction("&Quit", "Quit EvA2 workbench", + KeyStroke.getKeyStroke(KeyEvent.VK_Q, InputEvent.CTRL_MASK)) { + + @Override + public void actionPerformed(final ActionEvent event) { + int result = JOptionPane.showConfirmDialog( + MainFrame.this, + "Do you really want to exit EvA2?", + "Exit Application", + JOptionPane.YES_NO_OPTION); + if (result == JOptionPane.YES_OPTION) { + MainFrame.this.close(); + } + } + }; + + actPreferences = new ExtAction("&Preferences", "Show preferences dialog", + KeyStroke.getKeyStroke(KeyEvent.VK_P, InputEvent.CTRL_MASK)) { + + @Override + public void actionPerformed(final ActionEvent event) { + // ToDo + } + }; + + actHelp = new ExtAction("&Help", "Show help contents", + KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0)) { + + @Override + public void actionPerformed(final ActionEvent event) { + // ToDo + String helpHS = "EvA2Help/EvA2Help.hs"; + ClassLoader cl = MainFrame.class.getClassLoader(); + JHelpContentViewer helpPane; + try { + URL hsURL = HelpSet.findHelpSet(cl, helpHS); + HelpSet helpSet = new HelpSet(null, hsURL); + // Trigger the help viewer: + helpPane = new JHelpContentViewer(helpSet); + JHelpNavigator helpNavigator = (JHelpNavigator) helpSet.getNavigatorView("TOC").createNavigator(helpPane.getModel()); + JEFrame helpFrame = new JEFrame("Help contents"); + JSplitPane helpSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, helpNavigator, helpPane); + helpFrame.add(helpSplit); + helpFrame.setVisible(true); + helpFrame.setMaximum(true); + } catch (Exception ee) { + // Say what the exception really is + LOGGER.log(Level.WARNING, "Could not open application help", ee); + } + } + }; + } + + /** + * Create the main menu and add actions. + */ + private void buildMenu() { + JMenuBar menuBar = new JMenuBar(); + setJMenuBar(menuBar); + + JExtMenu menuHelp = new JExtMenu("&Help"); + menuHelp.add(actHelp); + menuHelp.addSeparator(); + menuHelp.add(actAbout); + menuHelp.add(actLicense); + + JExtMenu menuOptions = new JExtMenu("&Options"); + menuOptions.add(actPreferences); + menuOptions.addSeparator(); + menuOptions.add(actQuit); + + menuBar.add(menuOptions); + menuBar.add(((JExtDesktopPane) desktopPane).getWindowMenu()); + menuBar.add(menuHelp); + } + + /** + * Retrieve the optimization parameters of a loaded module. Return null if no module is + * loaded. + * + * @return + */ + public InterfaceOptimizationParameters getOptimizationParameters() { + if (currentModuleAdapter != null) { + if (currentModuleAdapter instanceof AbstractModuleAdapter) { + return ((AbstractModuleAdapter) currentModuleAdapter).getOptimizationParameters(); + } + } + return null; + } + + public AbstractStatistics getStatistics() { + return ((GenericModuleAdapter) currentModuleAdapter).getStatistics(); + } + + public InterfaceStatisticsParameters getStatisticsParameter() { + return ((GenericModuleAdapter) currentModuleAdapter).getStatistics().getStatisticsParameters(); + } + + private void loadSpecificModule(String selectedModule, InterfaceOptimizationParameters optimizationParameters) { + ModuleAdapter newModuleAdapter = null; + // + try { + InterfaceOptimizationParameters params = optimizationParameters; + if (optimizationParameters == null) { + params = OptimizationParameters.getInstance(); + } + newModuleAdapter = new GOModuleAdapter(selectedModule, params, withGUI ? null : "EvA2"); + //newModuleAdapter = comAdapter.getModuleAdapter(selectedModule, optimizationParameters, withGUI ? null : "EvA2"); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, "Error loading module.", e); + EVAERROR.EXIT("Error while comAdapter.GetModuleAdapter Host: " + e.getMessage()); + } + if (newModuleAdapter == null) { + // When launching a Java Web Start application, baseDir will always be null! + URL baseDir = getClass().getClassLoader().getResource(""); + String cp = System.getProperty("java.class.path", "."); + String dir = (baseDir == null) ? System.getProperty("user.dir") : baseDir.getPath(); + + if (!cp.contains(dir)) { + // this was added due to matlab not adding base dir to base path... + System.err.println("classpath does not contain base directory!"); + System.err.println("adding base dir and trying again..."); + System.setProperty("java.class.path", cp + System.getProperty("path.separator") + dir); + ReflectPackage.resetDynCP(); + comAdapter.updateLocalMainAdapter(); + loadSpecificModule(selectedModule, optimizationParameters); // end recursive call! handle with care! + } + } else { + newModuleAdapter.addOptimizationStateListener(this); + try { + if (withGUI) { + // this (or rather: EvAModuleButtonPanelMaker) is where the start button etc come from! + frameMaker = newModuleAdapter.getModuleFrame(); + + /* This is the left TabPane on the main frame */ + JPanel moduleContainer = frameMaker.makePanel(); + + configurationPane.setVisible(false); + configurationPane.removeAll(); + + GridBagConstraints gbConstraints = new GridBagConstraints(); + + /* ToDo: Find a way to properly add the TreeView to the GOPanel */ + if (withTreeView && (newModuleAdapter instanceof AbstractModuleAdapter)) { + JComponent tree = null; + tree = getEvATreeView(frameMaker.getGOPanel(), "OptimizationParameters", ((AbstractModuleAdapter) newModuleAdapter).getOptimizationParameters()); + gbConstraints.gridx = 0; + gbConstraints.gridy = 0; + gbConstraints.fill = GridBagConstraints.BOTH; + gbConstraints.weightx = 1.0; + gbConstraints.weighty = 1.0; + configurationPane.add(tree, gbConstraints); + } + + + gbConstraints.weightx = 1.0; + gbConstraints.weighty = 0.0; + gbConstraints.gridx = 0; + gbConstraints.gridy = 0; + gbConstraints.gridwidth = 2; + gbConstraints.fill = GridBagConstraints.HORIZONTAL; + gbConstraints.anchor = GridBagConstraints.PAGE_START; + add(frameMaker.getToolBar(), gbConstraints); + + GridBagConstraints gbConstraints2 = new GridBagConstraints(); + gbConstraints2.gridx = 0; + gbConstraints2.gridy = 0; + gbConstraints2.fill = GridBagConstraints.VERTICAL; + gbConstraints2.weighty = 1.0; + configurationPane.add(moduleContainer, gbConstraints2); + configurationPane.validate(); + } + + + } catch (Exception e) { + LOGGER.log(Level.SEVERE, "Error while newModuleAdapter.getModuleFrame(): " + e.getMessage(), e); + EVAERROR.EXIT("Error while newModuleAdapter.getModuleFrame(): " + e.getMessage()); + } + + currentModuleAdapter = newModuleAdapter; + } + } + + /** + * Create a tree view of an object based on EvATreeNode. It is encapsulated + * in a JScrollPane. + * + * @param goPanel + * @param title + * @param object + * @return + * @see eva2.gui.EvATreeNode + */ + public JComponent getEvATreeView(JParaPanel goPanel, String title, Object object) { + EvATreeNode root = new EvATreeNode(title, object); // the root of the tree + JTree jtree = new JTree(root); + JScrollPane treeView = new JScrollPane(jtree); + + EvATreeSelectionListener treeListener = new EvATreeSelectionListener(root, goPanel.getEditor(), jtree); + // hooks itself up as the tree listener. It reacts both to changes in the selection + // state of the tree (to update the parameter panel) and to changes in the + // parameters to update the tree + return treeView; + } + + private void showAboutDialog() { + AboutDialog aboutDialog = new AboutDialog(this); + aboutDialog.setLocationRelativeTo(this); + aboutDialog.setVisible(true); + aboutDialog.setModalityType(Dialog.ModalityType.APPLICATION_MODAL); + } + + private void showLicense() { + HtmlDemo lgpl = new HtmlDemo(EvAInfo.LGPLFile); + HtmlDemo gpl = new HtmlDemo(EvAInfo.GPLFile); + gpl.show(); + lgpl.show(); + } + + @Override + public void performedRestart(String infoString) { + if (superListenerList != null) { + for (OptimizationStateListener l : superListenerList) { + l.performedRestart(infoString); + } + } + LOGGER.log(Level.INFO, "Restarted processing {0}", infoString); + startTime = System.currentTimeMillis(); + } + + @Override + public void performedStart(String infoString) { + if (superListenerList != null) { + for (OptimizationStateListener l : superListenerList) { + l.performedStart(infoString); + } + } + LOGGER.log(Level.INFO, "Started processing {0}", infoString); + startTime = System.currentTimeMillis(); + } + + @Override + public void performedStop() { + if (superListenerList != null) { + for (OptimizationStateListener l : superListenerList) { + l.performedStop(); + } + } + long t = (System.currentTimeMillis() - startTime); + LOGGER.info(String.format("Stopped after %1$d.%2$tL s", (t / 1000), (t % 1000))); + if (!withGUI) { + System.exit(0); + } + } + + /** + * When the worker needs to update the GUI we do so by queuing a Runnable + * for the event dispatching thread with SwingUtilities.invokeLater(). In + * this case we're just changing the progress bars value. + */ + @Override + public void updateProgress(final int percent, String msg) { + if (superListenerList != null) { + for (OptimizationStateListener l : superListenerList) { + l.updateProgress(percent, msg); + } + } + if (msg != null) { + LOGGER.info(msg); + } + if (this.progressBar != null) { + Runnable doSetProgressBarValue = new Runnable() { + + @Override + public void run() { + progressBar.setValue(percent); + } + }; + SwingUtilities.invokeLater(doSetProgressBarValue); + } + } +} diff --git a/src/eva2/problems/ERPStarter.java b/src/eva2/problems/ERPStarter.java index 0f081222..7ef320f3 100644 --- a/src/eva2/problems/ERPStarter.java +++ b/src/eva2/problems/ERPStarter.java @@ -3,7 +3,7 @@ package eva2.problems; import eva2.OptimizerFactory; import eva2.OptimizerRunnable; import eva2.gui.BeanInspector; -import eva2.gui.Main; +import eva2.gui.MainFrame; import eva2.optimization.individuals.AbstractEAIndividual; import eva2.optimization.OptimizationParameters; import eva2.optimization.operator.crossover.CrossoverESDefault; @@ -87,7 +87,7 @@ public class ERPStarter { // Instantiate optimization OptimizationParameters params = new OptimizationParameters(opt, erp, new EvaluationTerminator(maxEvals)); if (startGUI) { - Main.initClientGUI(params, null, null, null); + MainFrame.initClientGUI(params, null, null, null); } else { OptimizerRunnable rnbl = new OptimizerRunnable(params, new StatisticsStandalone(outputFilePrefix, 1, InterfaceStatisticsParameters.OutputVerbosity.ALL, true), false); // actually start the optimization