/*
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:
*
* TopFrame.XMLFILE for module configuration
* app.properties with the VERSION string
*
*
* @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.