/*
 This file is part of the software framework JStatCom, 
 a library for building applications for data based analysis.

 Copyright (C) 2000-2005  Markus Kraetzig

 This library is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License as
 published by the Free Software Foundation; either version 2.1 of the
 License, or (at your option) any later version.

 This library 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
 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 USA
 */

package com.jstatcom.component;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyVetoException;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.ResourceBundle;
import java.util.Vector;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JDesktopPane;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.WindowConstants;

import javolution37.javolution.xml.ObjectReader;
import javolution37.javolution.xml.XmlElement;
import javolution37.javolution.xml.XmlFormat;

import org.apache.log4j.Logger;

import EDU.oswego.cs.dl.util.concurrent.Callable;
import EDU.oswego.cs.dl.util.concurrent.QueuedExecutor;
import EDU.oswego.cs.dl.util.concurrent.TimedCallable;
import EDU.oswego.cs.dl.util.concurrent.misc.SwingWorker;

import com.jstatcom.engine.DefaultPCallControl;
import com.jstatcom.engine.Engine;
import com.jstatcom.engine.EngineTypes;
import com.jstatcom.io.AbstractImportPanel;
import com.jstatcom.io.FileSupport;
import com.jstatcom.io.ImportDataFrame;
import com.jstatcom.io.RedirectOutput;
import com.jstatcom.io.RedirectReceiver;
import com.jstatcom.io.TSImportPanel;
import com.jstatcom.model.JSCConstants;
import com.jstatcom.model.JSCInt;
import com.jstatcom.model.JSCNArray;
import com.jstatcom.model.control.SymbolFrame;
import com.jstatcom.project.ModuleTreeNode;
import com.jstatcom.project.OutputFrame;
import com.jstatcom.project.OutputList;
import com.jstatcom.project.ProjectDataManager;
import com.jstatcom.project.ProjectManager;
import com.jstatcom.project.ProjectStateHandler;
import com.jstatcom.project.ProjectTree;
import com.jstatcom.project.SettingsManager;
import com.jstatcom.ts.TSCalcFrame;
import com.jstatcom.ts.TSHolder;
import com.jstatcom.util.FArg;

/**
 * A configurable frame that can be used as a main frame for applications based
 * on JStatCom. It provides a default implementation which can be adjusted by
 * overwriting template methods and by specifying an XML file for adding
 * additional modules.
 * 

* The files for storing configuration data are: *

* * @author Markus Kraetzig */ public class TopFrame extends JFrame { private static final Logger log = Logger.getLogger(TopFrame.class); // init with default private static AppSettings appSettings = new AppSettings(); public static AppSettings getApplicationSettings() { if (appSettings == null) return new AppSettings(); return appSettings; } private AppSettingsDialog settingsDialog = null; /** * Holds the os.name property in upper case. */ protected String osName = System.getProperty("os.name").toUpperCase(); private JInternalFrame currentTopFrame = null; private final QueuedExecutor executorThread = new QueuedExecutor(); private JPanel leftPanel = null; /** * Gets title of the currently displayed top-level module frame. * * @return top-level frame title, or "" if none is displayed */ public String getTopModuleByName() { if (currentTopFrame == null) return null; return currentTopFrame.getTitle(); } /** * Filename for storing the module configuration as XML. */ public static final String XMLFILE = "modules.xml"; /** * Holds the xml representation for all modules. * * @author Markus Kraetzig */ public static class XMLRep { public final List moduleList; public final String name; /** * XML format field for (de)serialization. */ public static final XmlFormat XMLRep_XML = new XmlFormat( XMLRep.class) { public void format(XMLRep data, XmlElement xml) { xml.setAttribute("name", data.name); for (Iterator iter = data.moduleList.iterator(); iter.hasNext();) { Module element = (Module) iter.next(); xml.add(element); } } public XMLRep parse(XmlElement xml) { String nam = xml.getAttribute("name") + ""; List modules = new ArrayList(); while (xml.hasNext()) { Module mod = (Module) xml.getNext(); if (mod != null) modules.add(mod); } return new XMLRep(nam, modules); } }; public XMLRep(String name, List moduleList) { this.name = name; this.moduleList = moduleList; } }; /** * Version string and other props are taken from resource file * app.properties. */ public static String VERSION = "1.0"; public static String TITLE = "JStatCom"; public static String ABOUTIMAGE = "/images/splashdefault.gif"; public static String ABOUTINFO = "www.jstatcom.com"; public static String LICENSE = "license.html"; public static String ICON = "/images/jstatcom.gif"; private static ResourceBundle resjm = null; static { try { resjm = ResourceBundle.getBundle("app"); VERSION = resjm.getString("VERSION"); TITLE = resjm.getString("TITLE"); ABOUTIMAGE = resjm.getString("ABOUTIMAGE"); ABOUTINFO = resjm.getString("ABOUTINFO"); LICENSE = resjm.getString("LICENSE"); ICON = resjm.getString("ICON"); } catch (Throwable ex) { log.error("Resource app.properties not found", ex); } } /** * Swing Worker for background ARCH creation. */ private static class Worker extends SwingWorker { protected Class classToBuild; protected Method method; /** * Creates a worker thread that build an object from the class defined * by className. * * @param className, * class must exist * @throws RuntimeException * if Class.forName(className) fails */ public Worker(String className, String methodName) { super(); if (className == null) classToBuild = null; else { try { classToBuild = Class.forName(className); } catch (ClassNotFoundException ex) { throw new RuntimeException(ex); } if (classToBuild != null && methodName != null && methodName.length() > 0) try { method = classToBuild.getMethod(methodName, new Class[0]); } catch (NoSuchMethodException ex) { throw new RuntimeException(ex); } } } /** * Gets the constructed object or an instance of Exception * if an error happened. Clients should check this and handle the * exception. * * @return the constructed object or a Exception */ public Object construct() { try { if (classToBuild == null) return null; if (method != null) { Object rt = method.invoke(this, new Object[0]); return rt; } return classToBuild.newInstance(); } catch (Throwable ex) { return ex; } } } private JToggleButton outputToggleB = null; private boolean systemExitWhenClosing = true; private boolean confirmClose = true; private List alreadyShownFrames = new Vector(); private List moduleFrames = new Vector(); private LogFrame logger = null; private JDialog aboutBox = null; private JInternalFrame tsCalc = null; private JToolBar toolBar = null; private JSplitPane splitPane = null; private JFrame symbolFrame = null; private JFrame outputFrame = null; private ImportDataFrame importFrame = null; private AbstractImportPanel importPanel = null; /** * Splash screen that is initialized with startSplash. Can * be referenced to set progress notification. */ protected SplashScreen splashScreen = null; private JDesktopPane desktopPane = null; private JMenuBar menuBar = null; private JPanel statusBar = null; private JMenu fileMenu = null; private JMenu modulesMenu = null; private JMenu toolsMenu = null; private JMenu controlMenu = null; private JMenu helpMenu = null; /** * Calls this("JStatCom - Top Frame", true, true). */ public TopFrame() { this(TITLE, true, true); } /** * Calls this(title, true, true). * * @param title * the title of the application */ public TopFrame(String title) { this(title, true, true); } /** * Creates a TopFrame with its closing behaviour defined by * the arguments. * * @param title * the title of the application * @param isConfirmClose * if true then a confirm dialog is shown before * closing * @param isSystemExitOnClose * if true then System.exit is called on close and * all engine instances are shutdown, otherwise only * dispose is called */ public TopFrame(String title, boolean isConfirmClose, boolean isSystemExitOnClose) { super(title); systemExitWhenClosing = isSystemExitOnClose; confirmClose = isConfirmClose; // add windowListener setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { TopFrame topFrame = (TopFrame) e.getComponent(); if (appSettings.getExitDialog().intVal() != 0 && confirmClose) { if (JOptionPane.showConfirmDialog(topFrame, "Quit?", topFrame.getTitle(), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.NO_OPTION) { return; } } try { // make sure that the application finishes in any case SettingsManager.getInstance().saveSettings(); if (appSettings.getSaveLastState().intVal() != 0) SettingsManager.getInstance().saveLastState(); } catch (Throwable t) { log.error("Error saving settings", t); } testForExit(); dispose(); } private void testForExit() { if (systemExitWhenClosing) { try { // shutdown all engines for (Iterator iter = EngineTypes.engineIterator(); iter .hasNext();) { final Engine element = (Engine) iter.next(); Callable call = new Callable() { public Object call() { element.shutdown(); return null; } }; new TimedCallable(call, 1000).call(); } } catch (Throwable ex) { log.error("Error shutting down engines", ex); } System.exit(0); } } }); } /** * Gets the calculator. * * @return TS calculator frame */ protected JInternalFrame getTSCalcFrame() { if (tsCalc == null) { try { tsCalc = new TSCalcFrame(); } catch (Throwable ex) { log.error("Error creating TSCalcFrame", ex); } } return tsCalc; } /** * Gets the tool bar. * * @return tool bar */ public JToolBar getToolBar() { if (toolBar == null) { try { toolBar = new JToolBar(); toolBar.setSize(200, 20); toolBar.setFloatable(false); toolBar.setRollover(true); } catch (Throwable ex) { log.error("Error creating toolbar", ex); } } return toolBar; } /** * Manages dragging and dropping of data and project files to a component. * Used for the scrollpane holding the project tree. * * @param comp * component for which to enable data transfer support */ private void installDragAndDropListener(Component comp) { new FileDrop(comp, javax.swing.BorderFactory.createMatteBorder(2, 2, 2, 2, Color.GREEN), true, new FileDrop.Listener() { public void filesDropped(java.io.File[] files) { // handle file drop String fName = ""; TopFrame.this.setCursor(new Cursor(Cursor.WAIT_CURSOR)); try { if (files != null && files.length > 0) { fName = files[0].getAbsolutePath(); if (fName.endsWith(".jsc") || fName.endsWith(".JSC")) ProjectManager.getInstance().deSerializeProject( files[0]); else { if (getImportFrame().importData(files[0])) handleView(getImportFrame()); } } } catch (Throwable t) { StdMessages .error( "The file \"" + fName + "\" could not be handled.\nPlease see the log for details.", "File Read Error"); log.error("Error in file drag'n drop", t); } finally { TopFrame.this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); } } // end filesDropped }); // end FileDrop.Listener } /** * Initialized the toggle button that switches the output history on and off * * @return toggle button */ private JToggleButton getOutputToggleButton() { if (outputToggleB == null) { outputToggleB = new JToggleButton("Output History On"); URL urlon = getClass().getResource("/images/outcontrol.gif"); URL urloff = getClass().getResource("/images/outcontroloff.gif"); ImageIcon on = null; ImageIcon off = null; if (urlon != null) on = new ImageIcon(urlon); if (urloff != null) off = new ImageIcon(urloff); final ImageIcon onFin = on; final ImageIcon offFin = off; outputToggleB.setIcon(on); outputToggleB.setSelected(true); outputToggleB.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { if (outputToggleB.isSelected()) { outputToggleB.setText("Output History On"); outputToggleB.setIcon(onFin); getOutputControlFrame().setTitle( "Output Control [History On]"); getOutputControlFrame().setIconImage(onFin.getImage()); OutputList.getInstance().setOutputHistory(true); } else { outputToggleB.setText("Output History Off"); outputToggleB.setIcon(offFin); getOutputControlFrame().setTitle( "Output Control [History Off]"); getOutputControlFrame().setIconImage(offFin.getImage()); OutputList.getInstance().setOutputHistory(false); } } }); } return outputToggleB; } /** * Gets the split pane. * * @return tool bar */ private JSplitPane getSplitPane() { if (splitPane == null) { try { splitPane = new JSplitPane(); splitPane.setRightComponent(getTopFrameDesktop()); JScrollPane scrollPane = new JScrollPane(ProjectTree .getInstance()); leftPanel = new JPanel(new BorderLayout()); leftPanel.add(scrollPane, BorderLayout.CENTER); leftPanel.add(getOutputToggleButton(), BorderLayout.NORTH); installDragAndDropListener(scrollPane); scrollPane.setPreferredSize(new Dimension(150, 100)); splitPane.setLeftComponent(leftPanel); } catch (Throwable ex) { log.error("Error creating splitpane", ex); } } return splitPane; } /** * Gets the output control frame. * * @return output control frame */ protected JFrame getOutputControlFrame() { if (outputFrame == null) { try { outputFrame = new OutputFrame(); outputFrame.setLocationRelativeTo(this); } catch (Throwable ex) { log.error("Error creating output control", ex); } } return outputFrame; } /** * Gets the symbol control frame. * * @return symbol control frame */ protected JFrame getSymbolControlFrame() { if (symbolFrame == null) { try { symbolFrame = new SymbolFrame(); symbolFrame.setLocationRelativeTo(this); } catch (Throwable ex) { log.error("Error creating symbol frame", ex); } } return symbolFrame; } /** * Gets the desktop pane. * * @return initialized JDesktopPane */ public final JDesktopPane getTopFrameDesktop() { if (desktopPane == null) { try { desktopPane = new JDesktopPane(); } catch (Throwable ex) { log.error("Error creating desktop", ex); } } return desktopPane; } /** * Gets the menu bar. * * @return initialized JMenuBar */ public final JMenuBar getTopFrameMenuBar() { if (menuBar == null) { menuBar = new JMenuBar(); } return menuBar; } /** * Gets the dialog that is used as about box. * * @return initialized JDialog */ protected JDialog getTopFrameAboutBox() { if (aboutBox == null) { try { aboutBox = new TopFrameAboutBox(this, "About " + TITLE, VERSION, ABOUTINFO, ABOUTIMAGE, LICENSE); } catch (Throwable ex) { log.error("Error creating about box", ex); } } return aboutBox; } /** * Gets the logging component that implements * com.jstatcom.io.Logger. * * @return logger instance */ protected RedirectReceiver getLogFrame() { if (logger == null) try { logger = new LogFrame(); } catch (Throwable ex) { log.error("Error creating logger", ex); } return logger; } /** * Gets an instance of AbstractImportPanel. If another * import panel should be used, then this method must be overriden to return * a different handler component. The default panel is * TSImportPanel. * * @return initialized AbstractImportPanel */ protected AbstractImportPanel getImportPanel() { if (importPanel == null) { try { importPanel = new TSImportPanel(); } catch (Throwable ex) { log.error("Error creating import panel", ex); } } return importPanel; } /** * Gets the import data frame. It uses the panel from * getImportPanel. * * @return panel to be used as status bar */ protected ImportDataFrame getImportFrame() { if (importFrame == null) { try { importFrame = new ImportDataFrame(); importFrame.setImportPanel(getImportPanel()); } catch (Throwable ex) { log.error("Error creating import frame", ex); } } return importFrame; } /** * Skeleton method to call template methods in the following order: *
    *
  • setLookAndFeel *
  • startSplash *
  • adjustFrameSizeandLocation *
  • initLog *
  • addMenuBar *
  • addToolBar *
  • addStatusBar *
  • setModulesFromXML *
  • extra *
* If this method is overwritten, then no components will be added to this * frame. To adjust the behaviour subclasses should overwrite the template * methods. */ public void skeleton() { try { // set default path, should be changed to read in stored // settings String file = new File(".").getAbsolutePath(); // truncate ., will be overridden by settings FileSupport.getInstance().setDefaultPath( file.substring(0, file.length() - 1)); getContentPane().add(getSplitPane(), BorderLayout.CENTER); TopFrameReference.setTopFrameRef(this); setSize(1000, 800); URL url = getClass().getResource(ICON); if (url != null) setIconImage(new ImageIcon(url).getImage()); setLookAndFeel(); startSplash(); adjustFrameSizeandLocation(); initLog(); addMenuBar(); addToolBar(); addStatusBar(); extra(); ProjectManager.getInstance().setTopFrame(TopFrame.this); SettingsManager.getInstance().restoreSettings(); // project and data management // after frame is visible setModulesFromXML(); try { executorThread.execute(new Runnable() { public void run() { SwingUtilities.invokeLater(new Runnable() { public void run() { ProjectDataManager.getInstance().register( TSHolder.getInstance()); if (appSettings.getSaveLastState().intVal() != 0) SettingsManager.getInstance() .restoreLastState(); } }); } }); } catch (Throwable ex) { log.error("Error executing restore thread", ex); } } catch (Throwable ex) { log.error("Error restoring settings", ex); } finally { if (splashScreen != null) splashScreen.showStatus("Completed", 100); // handleView(getImportFrame()); if (splashScreen != null) splashScreen.setVisible(false); setVisible(true); } } /** * Template method that is called by skeleton method to set the Look and * Feel for this application. Default implementation sets system specific * L&F. */ protected void setLookAndFeel() { try { final Font f = new Font("dialog", Font.PLAIN, 11); /* * if (osName.indexOf("WIN") > -1) * UIManager.setLookAndFeel(UIManager * .getSystemLookAndFeelClassName()); */ UIManager.put("Button.font", f); UIManager.put("CheckBox.font", f); UIManager.put("CheckBoxMenuItem.font", f); UIManager.put("ColorChooser.font", f); UIManager.put("ComboBox.font", f); UIManager.put("EditorPane.font", f); UIManager.put("FormattedTextField.font", f); UIManager.put("Label.font", f); UIManager.put("List.font", f); UIManager.put("Menu.font", f); UIManager.put("MenuBar.font", f); UIManager.put("MenuItem.font", f); UIManager.put("MenuItem.acceleratorFont", new Font("dialog", Font.PLAIN, 10)); UIManager.put("OptionPane.font", f); UIManager.put("Panel.font", f); UIManager.put("PasswordField.font", f); UIManager.put("PopupMenu.font", f); UIManager.put("ProgressBar.font", f); UIManager.put("RadioButton.font", f); UIManager.put("RadioButtonMenuItem.font", f); UIManager.put("ScrollPane.font", f); UIManager.put("Spinner.font", f); UIManager.put("TabbedPane.font", f); UIManager.put("Table.font", f); UIManager.put("TableHeader.font", f); UIManager.put("TextArea.font", f); UIManager.put("TextField.font", f); UIManager.put("TextPane.font", f); UIManager.put("TitledBorder.font", f); UIManager.put("ToggleButton.font", f); UIManager.put("ToolBar.font", f); UIManager.put("ToolTip.font", f); UIManager.put("Tree.font", f); UIManager.put("Viewport.font", f); } catch (Throwable ex) { log.error("Error configuring UI", ex); } } /** * Template method that gets the splash image. * * @return string default: "/images/splashdefault.gif" */ protected String getSplashImage() { return ABOUTIMAGE; } /** * Template method that is called by skeleton method to start splash screen. * It calls getVersion and getSplashImage. */ protected void startSplash() { try { URL url = getClass().getResource(getSplashImage()); Icon icon = null; if (url != null) icon = new ImageIcon(url); else log.error("About image \"" + getSplashImage() + "\" could not be found."); splashScreen = new SplashScreen(icon, "Starting Up", "version " + VERSION); splashScreen.setVisible(true); } catch (Throwable ex) { log.error("Error creating splash screen", ex); } } /** * Template method that sets the frame size and location to a reasonable * default depending on the screen size. The default size is 820 x 600. */ protected void adjustFrameSizeandLocation() { Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); Dimension frameSize = getSize(); if (frameSize.height > screenSize.height) frameSize.height = screenSize.height; if (frameSize.width > screenSize.width) frameSize.width = screenSize.width; setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2); } /** * Template method that starts redirecting output to a log frame and prints * system information. It also sets the DEBUG flag from the * system property. */ protected void initLog() { try { RedirectOutput.start(getLogFrame()); SimpleDateFormat formater = new SimpleDateFormat(); log.info(FArg.sprintf("%-20s%s", new FArg("log time:").add(formater .format(new Date())))); log.info(FArg.sprintf("%-20s%s", new FArg("program version:") .add(VERSION))); Properties sysprops = System.getProperties(); String debug = sysprops.getProperty("DEBUG", "false"); log.info(FArg .sprintf("%-20s%s", new FArg("debug mode:").add(debug))); if (debug.equalsIgnoreCase("true")) JSCConstants.DEBUG = true; log.info(FArg.sprintf("%-20s%s", new FArg("java vm version:") .add(sysprops.getProperty("java.vm.version")))); log.info(FArg.sprintf("%-20s%s", new FArg("os name:").add(sysprops .getProperty("os.name")))); log.info(FArg.sprintf("%-20s%s", new FArg("os version:") .add(sysprops.getProperty("os.version")))); } catch (Throwable ex) { log.error("Error initializing log", ex); } } /** * Sets up the file menu with the default items. Items are set up as * AbstractAction instances. * * @return a default file menu instance */ protected JMenu getFileMenu() { if (fileMenu != null) return fileMenu; try { fileMenu = new JMenu("File"); Icon icon = null; URL url = null; final TopFrame frame = this; // open project action AbstractAction openProjectAction = ProjectManager.getInstance() .getDeSerializationAction(); openProjectAction .putValue(Action.SHORT_DESCRIPTION, "Open Project"); fileMenu.add(openProjectAction); getToolBar().add(openProjectAction); // save as project action AbstractAction saveAsProjectAction = ProjectManager.getInstance() .getSerializationAction(); saveAsProjectAction.putValue(Action.ACCELERATOR_KEY, KeyStroke .getKeyStroke("control S")); saveAsProjectAction.putValue(Action.SHORT_DESCRIPTION, "Save Project As"); fileMenu.add(saveAsProjectAction); getToolBar().add(saveAsProjectAction); fileMenu.addSeparator(); getToolBar().addSeparator(); // import action url = getClass().getResource("/images/import.gif"); if (url != null) icon = new ImageIcon(url); AbstractAction importAction = new AbstractAction("Import Data", icon) { public void actionPerformed(ActionEvent evt) { handleView(getImportFrame()); getImportFrame().importData(); } }; importAction.putValue(Action.ACCELERATOR_KEY, KeyStroke .getKeyStroke("control F")); importAction.putValue(Action.SHORT_DESCRIPTION, "Import Data"); fileMenu.add(importAction); getToolBar().add(importAction); getToolBar().addSeparator(); url = getClass().getResource("/images/settings.gif"); if (url != null) icon = new ImageIcon(url); AbstractAction settingsAction = new AbstractAction("Preferences", icon) { public void actionPerformed(ActionEvent evt) { getSettingsDialog().setAppSettings(appSettings); getSettingsDialog().setVisible(true); appSettings = getSettingsDialog().getAppSettings(); setAppSettings(appSettings); } }; fileMenu.addSeparator(); fileMenu.add(settingsAction); // separator fileMenu.addSeparator(); // exit action url = getClass().getResource("/images/exit.gif"); if (url != null) icon = new ImageIcon(url); AbstractAction exitAction = new AbstractAction("Exit Program", icon) { public void actionPerformed(ActionEvent evt) { processWindowEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING)); } }; fileMenu.add(exitAction); } catch (Throwable ex) { log.error("Error creating file menu", ex); } return fileMenu; } /** * Sets up the model menu. It cannot be overwritten, because * setModulesFromXML depends on it. * * @return a menu instance */ final JMenu getModuleMenu() { if (modulesMenu != null) return modulesMenu; modulesMenu = new JMenu("Modules"); return modulesMenu; } /** * Sets up the window menu. * * @return a menu instance */ public JMenu getToolsMenu() { if (toolsMenu != null) return toolsMenu; try { URL url = null; Icon icon = null; toolsMenu = new JMenu("Tools"); // TSCalc action url = getClass().getResource("/images/tscalc.gif"); if (url != null) icon = new ImageIcon(url); AbstractAction tsCalcAction = new AbstractAction("TS Calculator", icon) { public void actionPerformed(ActionEvent evt) { handleView(getTSCalcFrame()); if (!alreadyShownFrames.contains(getTSCalcFrame())) { alreadyShownFrames.add(getTSCalcFrame()); try { getTSCalcFrame().setMaximum(true); } catch (Throwable ex) { // nothing to do here } } } }; tsCalcAction.putValue(Action.ACCELERATOR_KEY, KeyStroke .getKeyStroke("control D")); tsCalcAction.putValue(Action.SHORT_DESCRIPTION, "Displays Time Series Calculator"); toolsMenu.add(tsCalcAction); getToolBar().add(tsCalcAction); getToolBar().addSeparator(); } catch (Throwable ex) { log.error("Error creating tools menu", ex); } return toolsMenu; } /** * Sets up the control menu. * * @return a menu instance */ protected JMenu getControlMenu() { if (controlMenu != null) return controlMenu; try { URL url = null; Icon icon = null; controlMenu = new JMenu("Control"); // symbol control if (getSymbolControlFrame().getIconImage() != null) icon = new ImageIcon(getSymbolControlFrame().getIconImage()); AbstractAction symbolAction = new AbstractAction("Symbol Control", icon) { public void actionPerformed(ActionEvent evt) { getSymbolControlFrame().setVisible(true); } }; symbolAction.putValue(Action.SHORT_DESCRIPTION, "Symbol Control"); controlMenu.add(symbolAction); getToolBar().add(symbolAction); // output control icon = null; URL urlon = getClass().getResource("/images/outcontrol.gif"); if (urlon != null) icon = new ImageIcon(urlon); AbstractAction outputAction = new AbstractAction("Output Control", icon) { public void actionPerformed(ActionEvent evt) { getOutputControlFrame().setVisible(true); } }; outputAction.putValue(Action.SHORT_DESCRIPTION, "Output Control"); controlMenu.add(outputAction); getToolBar().add(outputAction); getToolBar().addSeparator(); // separator controlMenu.addSeparator(); // show logs action url = getClass().getResource("/images/log.gif"); if (url != null) icon = new ImageIcon(url); AbstractAction logAction = new AbstractAction("Show Logs", icon) { public void actionPerformed(ActionEvent evt) { getLogFrame().setVisible(true); } }; controlMenu.add(logAction); } catch (Throwable ex) { log.error("Error creating control menu", ex); } return controlMenu; } /** * Sets up the control menu. * * @return a menu instance */ protected JMenu getHelpMenu() { if (helpMenu != null) return helpMenu; try { URL url = null; Icon icon = null; helpMenu = new JMenu("Help"); // help url = getClass().getResource("/images/help.gif"); if (url != null) icon = new ImageIcon(url); AbstractAction helpAction = JHelpAction.getShowHelpInstance( "Help System", icon); helpAction .putValue(Action.SHORT_DESCRIPTION, "Invokes Help System"); helpMenu.add(helpAction); getToolBar().add(helpAction); // direct help url = getClass().getResource("/images/onItem.gif"); if (url != null) icon = new ImageIcon(url); AbstractAction trackAction = JHelpAction.getTrackInstance( "Direct Help", icon); trackAction.putValue(Action.SHORT_DESCRIPTION, "Context Sensitive Help"); helpMenu.add(trackAction); helpMenu.addSeparator(); getToolBar().add(trackAction); // about action url = getClass().getResource("/images/about.gif"); if (url != null) icon = new ImageIcon(url); AbstractAction aboutAction = new AbstractAction("About " + TITLE, icon) { public void actionPerformed(ActionEvent evt) { getTopFrameAboutBox().setVisible(true); } }; helpMenu.add(aboutAction); } catch (Throwable ex) { log.error("Error creating help menu", ex); } return helpMenu; } /** * Gets the status bar. The default returns * DefaultPCallControl.getInstance. * * @return panel to be used as status bar */ protected JPanel getStatusBar() { if (statusBar == null) { try { statusBar = DefaultPCallControl.getInstance(); statusBar.setPreferredSize(new Dimension(200, 25)); } catch (Throwable ex) { log.error("Error creating status bar", ex); } } return statusBar; } /** * Template method that sets up and adds the menu bar. It can be overwritten * to set up different menus. The menu bar can be referenced via * getTopFrameMenuBar. There is a separate method for each * menu that can be overwritten. If a menu method returns null, * then this menu will be ignored. */ protected void addMenuBar() { if (getTopFrameMenuBar() != null) setJMenuBar(getTopFrameMenuBar()); if (getFileMenu() != null) getTopFrameMenuBar().add(getFileMenu()); if (getModuleMenu() != null) getTopFrameMenuBar().add(getModuleMenu()); if (getToolsMenu() != null) getTopFrameMenuBar().add(getToolsMenu()); if (getControlMenu() != null) getTopFrameMenuBar().add(getControlMenu()); if (getHelpMenu() != null) getTopFrameMenuBar().add(getHelpMenu()); } /** * Empty default implementation that is called by skeleton * before this frame is shown. * */ protected void extra() { } /** * Template method that sets up and adds the menu bar. It can be overwritten * to set up different menus. The menu bar can be referenced via * getStatusBar. */ protected void addStatusBar() { if (getStatusBar() != null) getContentPane().add(getStatusBar(), BorderLayout.SOUTH); } /** * Template method that adds the tool bar. The tool bar can be referenced * via getToolBar. */ protected void addToolBar() { if (getToolBar() != null) getContentPane().add(getToolBar(), BorderLayout.NORTH); } /** * Starts the application. * * @param args * an array of command-line arguments */ public static void main(String[] args) { try { TopFrame topFrame = new TopFrame(); // call skeleton topFrame.skeleton(); } catch (Throwable exception) { log.error("Error in main()", exception); } } /** * Shows internal frame and brings it to top if closed or iconified. * * @param internalFrame */ public final void handleView(JInternalFrame internalFrame) { if (internalFrame.getDesktopPane() == null) { getTopFrameDesktop().add(internalFrame); } try { boolean wasMax = internalFrame.isMaximum(); Dimension dim = internalFrame.getSize(); Point point = internalFrame.getLocation(); internalFrame.setClosed(false); internalFrame.setIcon(false); // force to bring it on top internalFrame.setMaximum(!wasMax); internalFrame.setMaximum(wasMax); if (!wasMax) { internalFrame.setSize(dim); internalFrame.setLocation(point); } } catch (PropertyVetoException ex) { log.error("Error handling a view", ex); } if (moduleFrames.contains(internalFrame)) currentTopFrame = internalFrame; internalFrame.setVisible(true); } /** * Sets the modules defined in the XML file TopFrame.XMLFILE. * All modules must be instances of JInternalFrame. The * method also sets up the help menu. */ protected final void setModulesFromXML() { URL url = getClass().getResource("/" + XMLFILE); if (url == null) return; TopFrame.XMLRep newRep = null; // get module representation from XML file ObjectReader constructor = new ObjectReader(); try { newRep = (TopFrame.XMLRep) constructor.read(url.openStream()); } catch (Throwable ex) { log.error("Module initialization from \"" + url + "\" failed.", ex); return; } // check representation if (newRep == null || newRep.moduleList == null || newRep.moduleList.size() == 0) { log.error("No modules defined in \"" + url + "\"."); return; } // manage modules and helpsets List helpSetList = new ArrayList(); int num = newRep.moduleList.size(); for (int i = 0; i < num; i++) { final Module module_i = (Module) newRep.moduleList.get(i); if (module_i != null) { // helpset if (module_i.helpSetName != null && !helpSetList.contains(module_i.helpSetName)) helpSetList.add(module_i.helpSetName); // handle classname attribute if (module_i.className != null) try { if (splashScreen != null) splashScreen.showStatus(module_i.className, 100 / num * (i + 1)); final JMenuItem menu_i = new JMenuItem( module_i.className); menu_i.setEnabled(false); getModuleMenu().add(menu_i); Worker worker_i = new Worker(module_i.className, module_i.methodName) { Logger lg = Logger.getLogger(this.getClass()); public void finished() { final Object obj; try { obj = get(); } catch (Throwable ex) { lg.error("Error in finished of worker: " + module_i.className + ":" + module_i.methodName, ex); return; } // everything ok if (obj instanceof JInternalFrame) { final JInternalFrame frame = (JInternalFrame) obj; AbstractAction action = new AbstractAction( frame.getTitle(), frame .getFrameIcon()) { public void actionPerformed( ActionEvent evt) { handleView(frame); if (!alreadyShownFrames .contains(frame)) { alreadyShownFrames.add(frame); try { frame.setMaximum(true); } catch (Throwable ex) { lg .error( "Error in setMaximum", ex); } } } }; menu_i.setAction(action); ProjectTree.getInstance().addModuleNode( new ModuleTreeNode(action)); moduleFrames.add(frame); handleView(frame); if (!alreadyShownFrames.contains(frame)) { alreadyShownFrames.add(frame); try { frame.setMaximum(true); } catch (Throwable ex) { lg.error("Error in setMaximum", ex); } } // registers module with project manager if (frame instanceof ProjectStateHandler) ProjectManager .getInstance() .addProjectStateHandler( (ProjectStateHandler) frame); return; } // there is a pending exception from creation if (obj instanceof Throwable) { lg.error("Creation of \"" + classToBuild + "\" failed.", (Throwable) obj); } else { // created object is not a // JInternalFrame lg.error("\"" + classToBuild + "\" is not a JInternalFrame."); } } }; // queue executorThread.execute(worker_i); } catch (Throwable ex) { log.error("Module \"" + module_i.className + "\" at position [" + (i + 1) + "] in \"" + url + "\" could not be set.", ex); } } } JHelpAction.startHelpWorker(helpSetList); } /** * Sets the module frame that should be displayed via its title. If there is * no module frame with moduleTitle, nothing happens. * * @param moduleTitle * the title of the module frame to set * @throws IllegalArgumentException * if (moduleTitle == null) */ public void setTopModuleByName(String moduleTitle) { if (moduleTitle == null) throw new IllegalArgumentException("Argument was null."); for (int i = 0; i < moduleFrames.size(); i++) { Object o = moduleFrames.get(i); if (o instanceof JInternalFrame) { JInternalFrame frame = (JInternalFrame) o; if (moduleTitle.equals(frame.getTitle())) { handleView(frame); return; } } } } /** * Sets the appearance of this frame according to the settings argument. * Nothing happens if the argument is null. * * @param settings * holds the parameters determining the appearance of this frame */ public void setTopFrameSettings(TopFrameSettings settings) { if (settings == null) return; int[][] bounds = settings.getFrameBounds().intArray(); if (bounds.length == 4) { Rectangle rec = new Rectangle(bounds[0][0], bounds[1][0], bounds[2][0], bounds[3][0]); setBounds(rec); } int loc = settings.getSplitLocation().intVal(); getSplitPane().setDividerLocation(loc); int isToggle = settings.getIsOutputOn().intVal(); if (isToggle != 0 != getOutputToggleButton().isSelected()) getOutputToggleButton().doClick(); } /** * Sets the user properties from a settings parameter. * * @param settings * holds the property parameters */ public void setAppSettings(AppSettings settings) { if (settings == null) return; appSettings = settings; // whether symbol control should allow users to change values if (getSymbolControlFrame() instanceof SymbolFrame) ((SymbolFrame) getSymbolControlFrame()).setDataEditable(appSettings .getSControlEdit().intVal() != 0); if (leftPanel != null) if (appSettings.getShowExplorer().intVal() != 0) { leftPanel.setVisible(true); getSplitPane().setDividerSize(10); if (getSplitPane().getDividerLocation() < 10) getSplitPane().setDividerLocation(180); } else { leftPanel.setVisible(false); getSplitPane().setDividerSize(0); } } /** * Gets the settings instance according to the current appearance of this * frame. * * @return settings instance */ public TopFrameSettings getTopFrameSettings() { TopFrameSettings settings = new TopFrameSettings(); Rectangle rec = getBounds(); JSCNArray bounds = new JSCNArray("bounds", new double[] { rec.getX(), rec.getY(), rec.getWidth(), rec.getHeight() }); settings.setFrameBounds(bounds); int divider = getSplitPane().getDividerLocation(); JSCInt div = new JSCInt("split", divider); settings.setSplitLocation(div); JSCInt output = new JSCInt("output", getOutputToggleButton() .isSelected()); settings.setIsOutputOn(output); return settings; } /** * Gets the settings instance according to the user properties. * * @return settings instance */ public AppSettings getAppSettings() { return appSettings; } /** * @return */ private AppSettingsDialog getSettingsDialog() { if (settingsDialog == null) { settingsDialog = new AppSettingsDialog(this); settingsDialog.setLocationRelativeTo(this); } return settingsDialog; } }

Ads help maintain this website.