/*
* Open Source Physics software is free software as described near the bottom of this code file.
*
* For additional information and documentation on Open Source Physics please see:
* <http://www.opensourcephysics.org/>
*/
package org.opensourcephysics.controls;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.util.Locale;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ButtonGroup;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.KeyStroke;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.opensourcephysics.display.DisplayRes;
import org.opensourcephysics.display.GUIUtils;
import org.opensourcephysics.display.OSPFrame;
import org.opensourcephysics.display.OSPRuntime;
import org.opensourcephysics.display.PrintUtils;
import org.opensourcephysics.tools.FontSizer;
import org.opensourcephysics.tools.ToolsRes;
/**
* A frame with menu items for saving and loading control parameters
*
* @author Wolfgang Christian
* @version 1.0
*/
abstract public class ControlFrame extends OSPFrame implements Control {
final static int MENU_SHORTCUT_KEY_MASK = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
protected Object model; // the object that will be controlled
protected JMenuItem[] languageItems;
protected JMenu languageMenu;
protected JMenu fileMenu;
protected JMenu editMenu;
protected JMenu displayMenu;
protected JMenuItem readItem, clearItem, printFrameItem, saveFrameAsEPSItem;
protected JMenuItem saveAsItem;
protected JMenuItem copyItem;
protected JMenuItem inspectItem;
protected JMenuItem logToFileItem;
protected JMenuItem sizeUpItem;
protected JMenuItem sizeDownItem;
protected OSPApplication ospApp;
protected XMLControlElement xmlDefault;
protected ControlFrame(String title) {
super(title);
createMenuBar();
setName("controlFrame"); //$NON-NLS-1$
}
private void createMenuBar() {
JMenuBar menuBar = new JMenuBar();
if(!OSPRuntime.appletMode) {
setJMenuBar(menuBar);
}
fileMenu = new JMenu(ControlsRes.getString("ControlFrame.File")); //$NON-NLS-1$
editMenu = new JMenu(ControlsRes.getString("ControlFrame.Edit")); //$NON-NLS-1$
menuBar.add(fileMenu);
menuBar.add(editMenu);
readItem = new JMenuItem(ControlsRes.getString("ControlFrame.Load_XML")); //$NON-NLS-1$
saveAsItem = new JMenuItem(ControlsRes.getString("ControlFrame.Save_XML")); //$NON-NLS-1$
inspectItem = new JMenuItem(ControlsRes.getString("ControlFrame.Inspect_XML")); //$NON-NLS-1$
clearItem = new JMenuItem(ControlsRes.getString("ControlFrame.Clear_XML")); //$NON-NLS-1$
clearItem.setEnabled(false);
copyItem = new JMenuItem(ControlsRes.getString("ControlFrame.Copy")); //$NON-NLS-1$
printFrameItem = new JMenuItem(DisplayRes.getString("DrawingFrame.PrintFrame_menu_item")); //$NON-NLS-1$
saveFrameAsEPSItem = new JMenuItem(DisplayRes.getString("DrawingFrame.SaveFrameAsEPS_menu_item")); //$NON-NLS-1$
JMenu printMenu = new JMenu(DisplayRes.getString("DrawingFrame.Print_menu_title")); //$NON-NLS-1$
if(OSPRuntime.applet==null) {
fileMenu.add(readItem);
}
if(OSPRuntime.applet==null) {
fileMenu.add(saveAsItem);
}
fileMenu.add(inspectItem);
fileMenu.add(clearItem);
if(OSPRuntime.applet==null) {
fileMenu.add(printMenu);
}
printMenu.add(printFrameItem);
printMenu.add(saveFrameAsEPSItem);
editMenu.add(copyItem);
copyItem.setAccelerator(KeyStroke.getKeyStroke('C', MENU_SHORTCUT_KEY_MASK));
copyItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
copy();
}
});
saveAsItem.setAccelerator(KeyStroke.getKeyStroke('S', MENU_SHORTCUT_KEY_MASK));
saveAsItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
saveXML();
}
});
inspectItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
inspectXML(); // cannot use a static method here because of run-time binding
}
});
readItem.setAccelerator(KeyStroke.getKeyStroke('L', MENU_SHORTCUT_KEY_MASK));
readItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// readParameters(); // cannot use a static method here because of run-time binding
loadXML((String) null);
}
});
clearItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if((xmlDefault==null)||(model==null)) {
return;
}
xmlDefault = null;
clearItem.setEnabled(false);
if(model instanceof Calculation) {
((Calculation) model).resetCalculation();
((Calculation) model).calculate();
} else if(model instanceof Animation) {
((Animation) model).stopAnimation();
((Animation) model).resetAnimation();
((Animation) model).initializeAnimation();
}
GUIUtils.repaintOSPFrames();
}
});
// print item
printFrameItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
PrintUtils.printComponent(ControlFrame.this);
}
});
// save as EPS item
saveFrameAsEPSItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
PrintUtils.saveComponentAsEPS(ControlFrame.this);
} catch(IOException ex) {}
}
});
// display menu
loadDisplayMenu();
// help menu
JMenu helpMenu = new JMenu(ControlsRes.getString("ControlFrame.Help")); //$NON-NLS-1$
menuBar.add(helpMenu);
JMenuItem aboutItem = new JMenuItem(ControlsRes.getString("ControlFrame.About")); //$NON-NLS-1$
aboutItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
OSPRuntime.showAboutDialog(ControlFrame.this);
}
});
helpMenu.add(aboutItem);
JMenuItem sysItem = new JMenuItem(ControlsRes.getString("ControlFrame.System")); //$NON-NLS-1$
sysItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ControlUtils.showSystemProperties(true);
}
});
helpMenu.add(sysItem);
JMenuItem showItem = new JMenuItem(ControlsRes.getString("ControlFrame.Display_All_Frames")); //$NON-NLS-1$
showItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
org.opensourcephysics.display.GUIUtils.showDrawingAndTableFrames();
}
});
helpMenu.add(showItem);
helpMenu.addSeparator();
JMenuItem logItem = new JMenuItem(ControlsRes.getString("ControlFrame.Message_Log")); //$NON-NLS-1$
logItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
OSPLog.showLog();
}
});
if(OSPRuntime.applet==null) {
helpMenu.add(logItem);
}
logToFileItem = new JCheckBoxMenuItem(ControlsRes.getString("ControlFrame.Log_to_File")); //$NON-NLS-1$
logToFileItem.setSelected(false);
logToFileItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JCheckBoxMenuItem item = (JCheckBoxMenuItem) e.getSource();
if(OSPRuntime.appletMode||(OSPRuntime.applet!=null)) {
return; // applets cannot log to file
}
OSPLog.getOSPLog().setLogToFile(item.isSelected());
}
});
helpMenu.add(logToFileItem);
validate();
}
/**
* Adds a Display menu to the menu bar. Overrides OSPFrame method.
*
* @return the display menu
*/
protected JMenu loadDisplayMenu() {
JMenuBar menuBar = getJMenuBar();
if(menuBar==null) {
return null;
}
displayMenu = super.loadDisplayMenu();
if(displayMenu==null) {
displayMenu = new JMenu();
displayMenu.setText(ControlsRes.getString("ControlFrame.Display")); //$NON-NLS-1$
menuBar.add(displayMenu);
}
// language menu
languageMenu = new JMenu();
languageMenu.setText(ControlsRes.getString("ControlFrame.Language")); //$NON-NLS-1$
Action languageAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
String language = e.getActionCommand();
OSPLog.finest("setting language to "+language); //$NON-NLS-1$
Locale[] locales = OSPRuntime.getInstalledLocales();
for(int i = 0; i<locales.length; i++) {
if(language.equals(locales[i].getDisplayName())) {
ToolsRes.setLocale(locales[i]);
return;
}
}
}
};
Locale[] locales = OSPRuntime.getInstalledLocales();
ButtonGroup languageGroup = new ButtonGroup();
languageItems = new JMenuItem[locales.length];
for(int i = 0; i<locales.length; i++) {
languageItems[i] = new JRadioButtonMenuItem(locales[i].getDisplayName(locales[i]));
languageItems[i].setActionCommand(locales[i].getDisplayName());
languageItems[i].addActionListener(languageAction);
languageMenu.add(languageItems[i]);
languageGroup.add(languageItems[i]);
}
for(int i = 0; i<locales.length; i++) {
if(locales[i].getLanguage().equals(ToolsRes.getLanguage())) {
languageItems[i].setSelected(true);
}
}
if(OSPRuntime.isAuthorMode()||!OSPRuntime.isLauncherMode()) {
displayMenu.add(languageMenu); // add the menu if program is stand-alone or if user is authoring.
}
//font menu
JMenu fontMenu = new JMenu(DisplayRes.getString("DrawingFrame.Font_menu_title")); //$NON-NLS-1$
displayMenu.add(fontMenu);
JMenuItem sizeUpItem = new JMenuItem(ControlsRes.getString("ControlFrame.Increase_Font_Size")); //$NON-NLS-1$
sizeUpItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
FontSizer.levelUp();
}
});
fontMenu.add(sizeUpItem);
final JMenuItem sizeDownItem = new JMenuItem(ControlsRes.getString("ControlFrame.Decrease_Font_Size")); //$NON-NLS-1$
sizeDownItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
FontSizer.levelDown();
}
});
fontMenu.add(sizeDownItem);
fontMenu.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
sizeDownItem.setEnabled(FontSizer.getLevel()>0);
}
});
return displayMenu;
}
/**
* Refreshes the user interface in response to display changes such as Language.
*/
protected void refreshGUI() {
super.refreshGUI();
createMenuBar();
}
/** Saves a file containing the control parameters to the disk. */
public void save() {
ControlUtils.saveToFile(this, ControlFrame.this);
}
/** Loads a file containing the control parameters from the disk. */
public void readParameters() {
ControlUtils.loadParameters(this, ControlFrame.this);
}
/** Copies the data in the table to the system clipboard */
public void copy() {
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
StringSelection stringSelection = new StringSelection(this.toString());
clipboard.setContents(stringSelection, stringSelection);
}
public void saveXML() {
JFileChooser chooser = OSPRuntime.getChooser();
if(chooser==null) {
return;
}
String oldTitle = chooser.getDialogTitle();
chooser.setDialogTitle(ControlsRes.getString("ControlFrame.Save_XML_Data")); //$NON-NLS-1$
int result = chooser.showSaveDialog(null);
chooser.setDialogTitle(oldTitle);
if(result==JFileChooser.APPROVE_OPTION) {
File file = chooser.getSelectedFile();
// check to see if file already exists
if(file.exists()) {
int selected = JOptionPane.showConfirmDialog(null, ControlsRes.getString("ControlFrame.Replace_existing")+file.getName() //$NON-NLS-1$
+ControlsRes.getString("ControlFrame.question_mark"), ControlsRes.getString("ControlFrame.Replace_File"), //$NON-NLS-1$ //$NON-NLS-2$
JOptionPane.YES_NO_CANCEL_OPTION);
if(selected!=JOptionPane.YES_OPTION) {
return;
}
}
OSPRuntime.chooserDir = chooser.getCurrentDirectory().toString();
String fileName = file.getAbsolutePath();
// String fileName = XML.getRelativePath(file.getAbsolutePath());
if((fileName==null)||fileName.trim().equals("")) { //$NON-NLS-1$
return;
}
int i = fileName.toLowerCase().lastIndexOf(".xml"); //$NON-NLS-1$
if(i!=fileName.length()-4) {
fileName += ".xml"; //$NON-NLS-1$
}
XMLControl xml = new XMLControlElement(getOSPApp());
xml.write(fileName);
}
}
public void loadXML(String[] args) {
if(args!=null) {
for(int i = 0; i<args.length; i++) {
loadXML(args[i]);
}
}
}
/**
* Loads xml data into the model.
*
* @param xml
* @param compatibleModel true if model is known to be compatible with the app
*/
public void loadXML(XMLControlElement xml, boolean compatibleModel) {
if(xml==null) {
OSPLog.finer("XML data not found in ControlFrame loadXML method."); //$NON-NLS-1$
return;
}
// load xml into app if xml object class is an OSPApplication
// if(xml.getObjectClass().isAssignableFrom(OSPApplication.class)) {
if(OSPApplication.class.isAssignableFrom(xml.getObjectClass())) {
ospApp = getOSPApp();
ospApp.compatibleModel = compatibleModel;
xml.loadObject(getOSPApp());
ospApp.compatibleModel = false;
if(model.getClass()==ospApp.getLoadedModelClass()) { // classes match so we have a new default
xmlDefault = xml;
clearItem.setEnabled(true);
} else if(ospApp.getLoadedModelClass()!=null) { // a model was imported; create xml from current model
xmlDefault = new XMLControlElement(getOSPApp());
clearItem.setEnabled(true);
} else { // model is null
xmlDefault = null;
clearItem.setEnabled(false);
JOptionPane.showMessageDialog(this, "Model specified in file not found.", //$NON-NLS-1$
"Data not loaded.", JOptionPane.WARNING_MESSAGE); //$NON-NLS-1$
}
} else {
JOptionPane.showMessageDialog(this, "Data for: "+xml.getObjectClass()+".", //$NON-NLS-1$ //$NON-NLS-2$
"OSP Application data not found.", JOptionPane.WARNING_MESSAGE); //$NON-NLS-1$
}
}
public void loadXML(String fileName) {
if((fileName==null)||fileName.trim().equals("")) { //$NON-NLS-1$
loadXML();
return;
}
loadXML(new XMLControlElement(fileName), false);
}
public void loadXML() {
JFileChooser chooser = OSPRuntime.getChooser();
if(chooser==null) {
return;
}
String oldTitle = chooser.getDialogTitle();
chooser.setDialogTitle(ControlsRes.getString("ControlFrame.Load_XML_Data")); //$NON-NLS-1$
int result = chooser.showOpenDialog(null);
chooser.setDialogTitle(oldTitle);
if(result==JFileChooser.APPROVE_OPTION) {
OSPRuntime.chooserDir = chooser.getCurrentDirectory().toString();
String fileName = chooser.getSelectedFile().getAbsolutePath();
loadXML(new XMLControlElement(fileName), false);
}
}
public void inspectXML() {
// display a TreePanel in a modal dialog
XMLControl xml = new XMLControlElement(getOSPApp());
XMLTreePanel treePanel = new XMLTreePanel(xml);
JDialog dialog = new JDialog((java.awt.Frame) null, true);
dialog.setContentPane(treePanel);
dialog.setSize(new Dimension(600, 300));
dialog.setVisible(true);
}
/**
* Gets the OSP Application that is controlled by this frame.
* @return
*/
public OSPApplication getOSPApp() {
if(ospApp==null) {
ospApp = new OSPApplication(this, model);
}
return ospApp;
}
}
/*
* Open Source Physics software is free software; you can redistribute
* it and/or modify it under the terms of the GNU General Public License (GPL) as
* published by the Free Software Foundation; either version 2 of the License,
* or(at your option) any later version.
*
* Code that uses any portion of the code in the org.opensourcephysics package
* or any subpackage (subdirectory) of this package must must also be be released
* under the GNU GPL license.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA
* or view the license online at http://www.gnu.org/copyleft/gpl.html
*
* Copyright (c) 2007 The Open Source Physics project
* http://www.opensourcephysics.org
*/