/*
* 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.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Iterator;
import javax.swing.JButton;
import javax.swing.SwingUtilities;
import org.opensourcephysics.display.GUIUtils;
/**
* A GUI consisting of an input text area, a message area, and various buttons
* to initialize and control an Animation.
*
* @author Wolfgang Christian
* @author Joshua Gould
* @version 1.0
*/
public class AnimationControl extends OSPControl {
String resetToolTipText = ControlsRes.ANIMATION_RESET_TIP;
String initToolTipText = ControlsRes.ANIMATION_INIT_TIP;
String startToolTipText = ControlsRes.ANIMATION_START_TIP;
String stopToolTipText = ControlsRes.ANIMATION_STOP_TIP;
String newToolTipText = ControlsRes.ANIMATION_NEW_TIP;
String stepToolTipText = ControlsRes.ANIMATION_STEP_TIP;
String initText = ControlsRes.ANIMATION_INIT;
String startText = ControlsRes.ANIMATION_START;
String stopText = ControlsRes.ANIMATION_STOP;
String resetText = ControlsRes.ANIMATION_RESET;
String newText = ControlsRes.ANIMATION_NEW;
boolean stepModeEditing = true; // enables input editing while single stepping
JButton startBtn = new JButton(ControlsRes.ANIMATION_INIT); // changes to start, stop
JButton stepBtn = new JButton(ControlsRes.ANIMATION_STEP);
JButton resetBtn = new JButton(ControlsRes.ANIMATION_RESET); // changes to new
/**
* AnimationControl constructor.
*
* @param animation the animation for this AnimationControl
*/
public AnimationControl(Animation animation) {
super(animation);
if(model!=null) {
String name = model.getClass().getName();
setTitle(name.substring(1+name.lastIndexOf("."))+" Controller"); //$NON-NLS-1$ //$NON-NLS-2$
}
startBtn.addActionListener(new StartBtnListener());
startBtn.setToolTipText(initToolTipText);
stepBtn.addActionListener(new StepBtnListener());
stepBtn.setToolTipText(stepToolTipText);
resetBtn.addActionListener(new ResetBtnListener());
resetBtn.setToolTipText(resetToolTipText);
stepBtn.setEnabled(false);
buttonPanel.add(startBtn);
buttonPanel.add(stepBtn);
buttonPanel.add(resetBtn);
validate();
pack();
}
/**
* Refreshes the user interface in response to display changes such as Language.
*/
protected void refreshGUI() {
super.refreshGUI();
resetToolTipText = ControlsRes.ANIMATION_RESET_TIP;
initToolTipText = ControlsRes.ANIMATION_INIT_TIP;
startToolTipText = ControlsRes.ANIMATION_START_TIP;
stopToolTipText = ControlsRes.ANIMATION_STOP_TIP;
newToolTipText = ControlsRes.ANIMATION_NEW_TIP;
stepToolTipText = ControlsRes.ANIMATION_STEP_TIP;
if(stepBtn==null) {
return;
}
stepBtn.setText(ControlsRes.ANIMATION_STEP);
stepBtn.setToolTipText(stepToolTipText);
if(startBtn.getText().equals(startText)) {
startBtn.setText(ControlsRes.ANIMATION_START);
startBtn.setToolTipText(startToolTipText);
} else if(startBtn.getText().equals(stopText)) {
startBtn.setText(ControlsRes.ANIMATION_STOP);
startBtn.setToolTipText(stopToolTipText);
} else {
startBtn.setText(ControlsRes.ANIMATION_INIT);
startBtn.setToolTipText(initToolTipText);
}
if(resetBtn.getText().equals(newText)) {
resetBtn.setText(ControlsRes.ANIMATION_NEW);
resetBtn.setToolTipText(newToolTipText);
} else {
resetBtn.setText(ControlsRes.ANIMATION_RESET);
resetBtn.setToolTipText(resetToolTipText);
}
initText = ControlsRes.ANIMATION_INIT;
startText = ControlsRes.ANIMATION_START;
resetText = ControlsRes.ANIMATION_RESET;
stopText = ControlsRes.ANIMATION_STOP;
newText = ControlsRes.ANIMATION_NEW;
}
/**
* Disposes all resources.
*/
public void dispose() {
if(model instanceof AbstractAnimation) {
// stops the animation
((AbstractAnimation) model).animationThread = null;
}
super.dispose();
}
/**
* Signals the control that the animation has completed.
* The control should reset itself in preparation for a new
* animation. The given message is printed in the message area.
*
* @param message
*/
public void calculationDone(final String message) {
// always update a Swing component from the event thread
if(model instanceof Animation) {
((Animation) model).stopAnimation();
}
Runnable doNow = new Runnable() {
public void run() {
startBtnActionPerformed(new ActionEvent(this, 0, stopText));
resetBtnActionPerformed(new ActionEvent(this, 0, newText));
resetBtn.setEnabled(true);
org.opensourcephysics.display.GUIUtils.enableMenubars(true);
if(message!=null) {
println(message);
}
}
};
try {
if(SwingUtilities.isEventDispatchThread()) {
doNow.run();
} else { // paint within the event thread
SwingUtilities.invokeAndWait(doNow);
}
} catch(java.lang.reflect.InvocationTargetException ex1) {}
catch(InterruptedException ex1) {}
}
/**
* Method startBtnActionPerformed
*
* @param e
*/
void startBtnActionPerformed(ActionEvent e) {
// table.getDefaultEditor(Object.class).stopCellEditing();
if(e.getActionCommand().equals(initText)) {
stepBtn.setEnabled(true);
startBtn.setText(startText);
startBtn.setToolTipText(startToolTipText);
resetBtn.setText(newText);
resetBtn.setToolTipText(newToolTipText);
resetBtn.setEnabled(true);
readItem.setEnabled(stepModeEditing);
table.setEnabled(stepModeEditing);
messageTextArea.setEditable(false);
GUIUtils.clearDrawingFrameData(false);
if(model==null) {
println("This AnimationControl's model is null."); //$NON-NLS-1$
} else {
((Animation) model).initializeAnimation();
}
org.opensourcephysics.display.GUIUtils.showDrawingAndTableFrames();
} else if(e.getActionCommand().equals(startText)) {
setCustomButtonsEnabled(false);
startBtn.setText(stopText);
startBtn.setToolTipText(stopToolTipText);
stepBtn.setEnabled(false);
resetBtn.setEnabled(false);
readItem.setEnabled(false);
table.setEnabled(false);
org.opensourcephysics.display.GUIUtils.enableMenubars(false);
((Animation) model).startAnimation();
} else { // action command = Stop
startBtn.setText(startText);
setCustomButtonsEnabled(true);
startBtn.setToolTipText(startToolTipText);
stepBtn.setEnabled(true);
resetBtn.setEnabled(true);
org.opensourcephysics.display.GUIUtils.enableMenubars(true);
readItem.setEnabled(stepModeEditing);
table.setEnabled(stepModeEditing);
((Animation) model).stopAnimation();
}
}
/**
* Method resetBtnActionPerformed
*
* @param e
*/
void resetBtnActionPerformed(ActionEvent e) {
if(e.getActionCommand().equals(resetText)) {
GUIUtils.clearDrawingFrameData(true);
if(model==null) {
println("This AnimationControl's model is null."); //$NON-NLS-1$
return;
}
((Animation) model).resetAnimation();
if(xmlDefault!=null) {
xmlDefault.loadObject(getOSPApp(), true, true);
}
table.refresh();
} else { // action command = New
startBtn.setText(initText);
startBtn.setToolTipText(initToolTipText);
resetBtn.setText(resetText);
resetBtn.setToolTipText(resetToolTipText);
stepBtn.setEnabled(false);
readItem.setEnabled(true);
table.setEnabled(true);
messageTextArea.setEditable(true);
setCustomButtonsEnabled(true);
}
}
/**
* Method stepBtnActionPerformed
*
* @param e
*/
void stepBtnActionPerformed(ActionEvent e) {
((Animation) model).stepAnimation();
}
private void setCustomButtonsEnabled(boolean enabled) {
if(customButtons!=null) {
for(Iterator<JButton> it = customButtons.iterator(); it.hasNext(); ) {
(it.next()).setEnabled(enabled);
}
}
}
/**
* Class StartBtnListener
*/
class StartBtnListener implements ActionListener {
/**
* Method actionPerformed
*
* @param e
*/
public void actionPerformed(ActionEvent e) {
startBtnActionPerformed(e);
}
}
/**
* Class ResetBtnListener
*/
class ResetBtnListener implements ActionListener {
/**
* Method actionPerformed
*
* @param e
*/
public void actionPerformed(ActionEvent e) {
resetBtnActionPerformed(e);
}
}
/**
* Class StepBtnListener
*/
class StepBtnListener implements ActionListener {
/**
* Method actionPerformed
*
* @param e
*/
public void actionPerformed(ActionEvent e) {
stepBtnActionPerformed(e);
}
}
/**
* Returns an XML.ObjectLoader to save and load data for this object.
*
* @return the object loader
*/
public static XML.ObjectLoader getLoader() {
return new AnimationControlLoader();
}
/**
* A class to save and load data for OSPControls.
*/
static class AnimationControlLoader extends OSPControlLoader {
/**
* Saves object data to an XMLControl.
*
* @param control the control to save to
* @param obj the object to save
*/
public void saveObject(XMLControl control, Object obj) {
AnimationControl ac = (AnimationControl) obj;
if(ac.startBtn.getText().equals(ac.stopText)) {
ac.startBtn.doClick(); // stop the animation if it is running
}
control.setValue("initialize_mode", ac.startBtn.getText().equals(ac.initText)); //$NON-NLS-1$
super.saveObject(control, obj);
}
/**
* Creates an object using data from an XMLControl.
*
* @param control the control
* @return the newly created object
*/
public Object createObject(XMLControl control) {
return new AnimationControl(null);
}
/**
* Loads an object with data from an XMLControl.
*
* @param control the control
* @param obj the object
* @return the loaded object
*/
public Object loadObject(XMLControl control, Object obj) {
AnimationControl ac = (AnimationControl) obj;
if(ac.startBtn.getText().equals(ac.stopText)) {
ac.startBtn.doClick(); // stop the animation if it is running
}
boolean initMode = control.getBoolean("initialize_mode"); //$NON-NLS-1$
control.setValue("initialize_mode", null); // don't show this internal parameter //$NON-NLS-1$
super.loadObject(control, obj); // load the control's parameters and the model
// put the animation into the initialize state if it was in this state when it was stopped
if(initMode) {
control.setValue("initialize_mode", true); //$NON-NLS-1$
}
if(initMode&&ac.startBtn.getText().equals(ac.startText)) {
ac.resetBtn.doClick();
}
if(!initMode&&ac.startBtn.getText().equals(ac.initText)) {
ac.startBtn.doClick();
}
ac.clearMessages();
return obj;
}
}
/**
* Creates an animation control and establishes communication between the control and the model.
*
* @param model Animation
* @return AnimationControl
*/
public static AnimationControl createApp(Animation model) {
AnimationControl control = new AnimationControl(model);
model.setControl(control);
return control;
}
/**
* Creates a animation control and establishes communication between the control and the model.
* Initial parameters are set using the xml data.
*
* @param model Animation
* @param xml String[]
* @return AnimationControl
*/
public static AnimationControl createApp(Animation model, String[] xml) {
AnimationControl control = createApp(model);
control.loadXML(xml);
return control;
}
}
/*
* 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
*/