Initial commit of everything.
55
trick_source/java/src/trick/Template.java
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* $Id: Template.java 1065 2010-09-09 19:49:28Z hchen $
|
||||
*
|
||||
*/
|
||||
|
||||
//========================================
|
||||
// Package
|
||||
//========================================
|
||||
package trick;
|
||||
|
||||
//========================================
|
||||
// Imports
|
||||
//========================================
|
||||
|
||||
/**
|
||||
* Template class.
|
||||
*
|
||||
* @since Trick 7.2.2
|
||||
*/
|
||||
public class Template {
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
|
||||
|
||||
//========================================
|
||||
// Private Data
|
||||
//========================================
|
||||
|
||||
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public Template()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Set/Get methods
|
||||
//========================================
|
||||
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
}
|
715
trick_source/java/src/trick/common/RunTimeTrickApplication.java
Normal file
@ -0,0 +1,715 @@
|
||||
package trick.common;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JRootPane;
|
||||
import javax.swing.JSeparator;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.border.TitledBorder;
|
||||
|
||||
import joptsimple.OptionParser;
|
||||
import joptsimple.OptionSet;
|
||||
import joptsimple.OptionSpec;
|
||||
|
||||
import org.jdesktop.swingx.JXButton;
|
||||
import org.jdesktop.swingx.JXLabel;
|
||||
import org.jdesktop.swingx.JXPanel;
|
||||
import org.jdesktop.swingx.JXTextField;
|
||||
|
||||
import trick.common.ui.panels.ConnectionStatusBar;
|
||||
import trick.common.utils.VariableServerConnection;
|
||||
|
||||
/**
|
||||
* Abstract base class for Trick run time GUIs, providing basic connection/disconnection functionality.
|
||||
*
|
||||
* @author Derek Bankieris
|
||||
* @since Trick 10
|
||||
*/
|
||||
public abstract class RunTimeTrickApplication extends TrickApplication {
|
||||
|
||||
/** enumeration for application behavior on disconnect */
|
||||
protected enum DisconnectBehavior {Close, Notify, Nothing}
|
||||
|
||||
/** indicates that the target simulation has been specified */
|
||||
protected boolean targetSpecified = false;
|
||||
|
||||
/** reconnect on lost connetions */
|
||||
protected boolean autoReconnect = false;
|
||||
|
||||
/** reconnecting state */
|
||||
private boolean reconnecting = false;
|
||||
|
||||
/** application behavior on disconnect */
|
||||
protected DisconnectBehavior disconnectBehavior = DisconnectBehavior.Notify;
|
||||
|
||||
/** handles the sending and receiving of commands to and from the Variable Server */
|
||||
protected VariableServerConnection variableServerConnection;
|
||||
|
||||
/** status bar displaying text fields for the host and port, and a connect/disconnect button */
|
||||
private ConnectionStatusBar connectionStatusBar;
|
||||
|
||||
/** represents the current connection status */
|
||||
private boolean connected = false;
|
||||
|
||||
/** update period in seconds */
|
||||
private double cyclePeriod;
|
||||
|
||||
/** minimum update period in seconds */
|
||||
private double minimumCyclePeriod;
|
||||
|
||||
/** the settings dialog */
|
||||
protected SettingsDialog settingsDialog;
|
||||
|
||||
/** property keys */
|
||||
protected static final String hostKey = "host";
|
||||
protected static final String portKey = "port";
|
||||
protected static final String autoReconnectKey = "autoReconnect";
|
||||
protected static final String disconnectBehaviorKey = "disconnectBehavior";
|
||||
protected static final String minimumCyclePeriodKey = "minCycle";
|
||||
protected static final String cyclePeriodKey = "cycle";
|
||||
protected static final String xKey = "x";
|
||||
protected static final String yKey = "y";
|
||||
protected static final String widthKey = "width";
|
||||
protected static final String heightKey = "height";
|
||||
|
||||
/** attempts to connect to the simulation specified by the current host name and port */
|
||||
protected void connect() throws IOException {
|
||||
if (!connected) {
|
||||
variableServerConnection = new VariableServerConnection(
|
||||
getHostName(), getPort());
|
||||
setConnectionState(true);
|
||||
}
|
||||
else {
|
||||
throw new IOException("Already connected.");
|
||||
}
|
||||
}
|
||||
|
||||
/** attempts to disconnect from the simulation */
|
||||
protected void disconnect() throws IOException {
|
||||
disconnect(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* attempts to disconnect from the simulation. If the disconnect behavior is
|
||||
* <code>DisconnectBehavior.Notify</code> and <code>exception</code> is not
|
||||
* <code>null</code>, it is displayed as the reason for the disconnection.
|
||||
*
|
||||
* @param exception (optional) the reason for the disconnection
|
||||
*/
|
||||
protected void disconnect(Exception exception) throws IOException {
|
||||
if (connected) {
|
||||
try {
|
||||
variableServerConnection.close();
|
||||
}
|
||||
finally {
|
||||
setConnectionState(false);
|
||||
switch (disconnectBehavior) {
|
||||
case Close:
|
||||
exit();
|
||||
break;
|
||||
case Notify:
|
||||
if (exception != null) {
|
||||
JOptionPane.showMessageDialog(getMainFrame(), exception,
|
||||
"Lost Connection", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (autoReconnect && exception != null) {
|
||||
reconnecting = true;
|
||||
connectionStatusBar.autoConnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new IOException("Not currently connected.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the connection state for both this application and the connection status bar
|
||||
*
|
||||
* @param connected the connection state
|
||||
*/
|
||||
protected void setConnectionState(boolean connected) {
|
||||
reconnecting = false;
|
||||
this.connected = connected;
|
||||
connectionStatusBar.setConnectionState(connected);
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the connection state
|
||||
*
|
||||
* @return the connection state
|
||||
*/
|
||||
protected boolean getConnectionState() {
|
||||
return connected;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the host name
|
||||
*
|
||||
* @return the host name
|
||||
*/
|
||||
protected String getHostName() {
|
||||
return connectionStatusBar.getHostName();
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the port
|
||||
*
|
||||
* @return the port
|
||||
*/
|
||||
protected int getPort() {
|
||||
return connectionStatusBar.getPort();
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the target simulation to which to connect
|
||||
*
|
||||
* @param hostName the name of the host machine
|
||||
* @param port the port on which to connect
|
||||
*/
|
||||
public void setTargetSimulation(String hostName, int port) {
|
||||
connectionStatusBar.setTarget(hostName, port);
|
||||
}
|
||||
|
||||
/** sends the cycle period to the Variable Server */
|
||||
protected void sendCyclePeriod() {
|
||||
if (connected) {
|
||||
try {
|
||||
variableServerConnection.setCycle(cyclePeriod);
|
||||
}
|
||||
catch (Exception exception) {
|
||||
try {
|
||||
disconnect(exception);
|
||||
}
|
||||
catch (Exception anotherException) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the period at which updates are received
|
||||
*
|
||||
* @param cyclePeriod the cycle period in seconds
|
||||
*/
|
||||
public void setCyclePeriod(double cyclePeriod) {
|
||||
this.cyclePeriod = cyclePeriod < minimumCyclePeriod ? minimumCyclePeriod : cyclePeriod;
|
||||
sendCyclePeriod();
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the period at which updates are received
|
||||
*
|
||||
* @return the cycle period in seconds
|
||||
*/
|
||||
public double getCyclePeriod() {
|
||||
return cyclePeriod;
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the minimum allowed period at which updates are received
|
||||
*
|
||||
* @param minimumCyclePeriod the minimum allowed cycle period in seconds
|
||||
*/
|
||||
public void setMinimumCyclePeriod(double minimumCyclePeriod) {
|
||||
this.minimumCyclePeriod = minimumCyclePeriod;
|
||||
if (cyclePeriod < minimumCyclePeriod) {
|
||||
setCyclePeriod(minimumCyclePeriod);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initialize(final String[] arguments) {
|
||||
super.initialize(arguments);
|
||||
|
||||
connectionStatusBar = new ConnectionStatusBar(
|
||||
new AbstractAction("Connect") {
|
||||
{
|
||||
putValue(SHORT_DESCRIPTION, "Connect to the simulation.");
|
||||
putValue(MNEMONIC_KEY, KeyEvent.VK_C);
|
||||
}
|
||||
public void actionPerformed(ActionEvent actionEvent) {
|
||||
try {
|
||||
setEnabled(false);
|
||||
connect();
|
||||
}
|
||||
catch (Exception exception) {
|
||||
if (reconnecting) {
|
||||
connectionStatusBar.autoConnect();
|
||||
}
|
||||
else {
|
||||
JOptionPane.showMessageDialog(getMainFrame(), exception,
|
||||
"Failed to Connect", JOptionPane.ERROR_MESSAGE);
|
||||
exception.printStackTrace(System.err);
|
||||
try {
|
||||
disconnect();
|
||||
}
|
||||
catch (IOException ioException) {}
|
||||
setEnabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new AbstractAction("Disconnect") {
|
||||
{
|
||||
putValue(SHORT_DESCRIPTION, "Disconnect from the simulation.");
|
||||
putValue(MNEMONIC_KEY, KeyEvent.VK_C);
|
||||
}
|
||||
public void actionPerformed(ActionEvent actionEvent) {
|
||||
try {
|
||||
setEnabled(false);
|
||||
disconnect();
|
||||
}
|
||||
catch (Exception exception) {
|
||||
JOptionPane.showMessageDialog(getMainFrame(), exception,
|
||||
"Error While Disconnecting", JOptionPane.ERROR_MESSAGE);
|
||||
exception.printStackTrace(System.err);
|
||||
setEnabled(true);
|
||||
}
|
||||
}
|
||||
},
|
||||
new AbstractAction("Stop") {
|
||||
{
|
||||
putValue(SHORT_DESCRIPTION, "Stop searching.");
|
||||
}
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent actionEvent) {
|
||||
connectionStatusBar.cancelAutoConnect();
|
||||
reconnecting = false;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
autoReconnect = Boolean.parseBoolean(
|
||||
trickProperties.getProperty(autoReconnectKey, Boolean.toString(autoReconnect)));
|
||||
|
||||
// Set up and parse all the options.
|
||||
try {
|
||||
parseArguments(arguments, new OptionParser());
|
||||
}
|
||||
catch (Exception exception) {
|
||||
System.out.println(exception);
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
// Restore previous settings.
|
||||
connectionStatusBar.setTarget(
|
||||
trickProperties.getProperty(hostKey, getHostName()),
|
||||
Integer.parseInt(trickProperties.getProperty(portKey, Integer.toString(getPort()))));
|
||||
|
||||
disconnectBehavior = Enum.valueOf(DisconnectBehavior.class,
|
||||
trickProperties.getProperty(disconnectBehaviorKey, disconnectBehavior.toString()));
|
||||
|
||||
setMinimumCyclePeriod(Double.parseDouble(trickProperties.getProperty(minimumCyclePeriodKey, "0.1")));
|
||||
setCyclePeriod(Double.parseDouble(trickProperties.getProperty(cyclePeriodKey, "0.5")));
|
||||
}
|
||||
|
||||
/**
|
||||
* parses the command line arguments
|
||||
*
|
||||
* @param arguments the arguments
|
||||
* @param optionParser the option parser to use
|
||||
*/
|
||||
protected void parseArguments(String[] arguments, OptionParser optionParser) {
|
||||
OptionSpec<String> hostSpec = optionParser.accepts(hostKey, "The name of the machine to connect to.")
|
||||
.withRequiredArg().ofType(String.class);
|
||||
|
||||
OptionSpec<Integer> portSpec = optionParser.accepts(portKey, "The port to connect to.")
|
||||
.withRequiredArg().ofType(Integer.class);
|
||||
|
||||
OptionSpec<Boolean> autoReconnectSpec = optionParser.accepts(autoReconnectKey, "Reestablish lost connections.")
|
||||
.withRequiredArg().ofType(Boolean.class);
|
||||
|
||||
String description = "[";
|
||||
for (DisconnectBehavior disconnectBehavior : DisconnectBehavior.values()) {
|
||||
description += disconnectBehavior + ", ";
|
||||
}
|
||||
description = description.substring(0, description.length() - 2) + "] The action to take on disconnect.";
|
||||
OptionSpec<DisconnectBehavior> disconnectBehaviorSpec = optionParser.accepts(disconnectBehaviorKey, description)
|
||||
.withRequiredArg().ofType(DisconnectBehavior.class);
|
||||
|
||||
OptionSpec<Double> minimumCyclePeriodSpec = optionParser.accepts(minimumCyclePeriodKey,
|
||||
"Minimum update cycle period (in seconds).").withRequiredArg().ofType(Double.class);
|
||||
|
||||
OptionSpec<Double> cyclePeriodSpec = optionParser.accepts(cyclePeriodKey,
|
||||
"Update cycle period (in seconds).").withRequiredArg().ofType(Double.class);
|
||||
|
||||
OptionSpec<Integer> xSpec = optionParser.accepts(xKey, "X position of the window.")
|
||||
.withRequiredArg().ofType(Integer.class);
|
||||
|
||||
OptionSpec<Integer> ySpec = optionParser.accepts(yKey, "Y position of the window.")
|
||||
.withRequiredArg().ofType(Integer.class);
|
||||
|
||||
OptionSpec<Integer> widthSpec = optionParser.accepts(widthKey,"Width of the window.")
|
||||
.withRequiredArg().ofType(Integer.class);
|
||||
|
||||
OptionSpec<Integer> heightSpec = optionParser.accepts(heightKey, "Height of the window.")
|
||||
.withRequiredArg().ofType(Integer.class);
|
||||
|
||||
optionParser.accepts("help", "Print this help message.");
|
||||
|
||||
OptionSet options = optionParser.parse(arguments);
|
||||
if (options.has("help") || !options.nonOptionArguments().isEmpty()) {
|
||||
try {
|
||||
System.out.println(
|
||||
"Options may be abbreviated and use a single hyphen if unambiguous.");
|
||||
optionParser.printHelpOn(System.out);
|
||||
}
|
||||
catch (IOException e) {}
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
if (options.has(autoReconnectKey)) {
|
||||
autoReconnect = options.valueOf(autoReconnectSpec);
|
||||
}
|
||||
|
||||
if (options.has(hostKey)) {
|
||||
trickProperties.setProperty(hostKey, options.valueOf(hostSpec).toString());
|
||||
targetSpecified = true;
|
||||
}
|
||||
|
||||
if (options.has(portKey)) {
|
||||
trickProperties.setProperty(portKey, (options.valueOf(portSpec).toString()));
|
||||
targetSpecified = true;
|
||||
}
|
||||
|
||||
if (options.has(disconnectBehaviorKey)) {
|
||||
trickProperties.setProperty(disconnectBehaviorKey, options.valueOf(disconnectBehaviorSpec).toString());
|
||||
}
|
||||
|
||||
if (options.has(minimumCyclePeriodKey)) {
|
||||
Double minimumCyclePeriod = options.valueOf(minimumCyclePeriodSpec);
|
||||
if (minimumCyclePeriod < 0) {
|
||||
System.out.println("Argument of option ['" + minimumCyclePeriodKey + "'] must be non-negative");
|
||||
System.exit(0);
|
||||
}
|
||||
trickProperties.setProperty(minimumCyclePeriodKey, minimumCyclePeriod.toString());
|
||||
}
|
||||
|
||||
if (options.has(cyclePeriodKey)) {
|
||||
Double cyclePeriod = options.valueOf(cyclePeriodSpec);
|
||||
if (cyclePeriod < 0) {
|
||||
System.out.println("Argument of option ['" + cyclePeriodKey + "'] must be non-negative");
|
||||
System.exit(0);
|
||||
}
|
||||
trickProperties.setProperty(cyclePeriodKey, cyclePeriod.toString());
|
||||
}
|
||||
|
||||
if (options.has(xKey)) {
|
||||
trickProperties.setProperty(xKey, (options.valueOf(xSpec).toString()));
|
||||
}
|
||||
|
||||
if (options.has(yKey)) {
|
||||
trickProperties.setProperty(yKey, (options.valueOf(ySpec).toString()));
|
||||
}
|
||||
|
||||
if (options.has(widthKey)) {
|
||||
trickProperties.setProperty(widthKey, (options.valueOf(widthSpec).toString()));
|
||||
}
|
||||
|
||||
if (options.has(heightKey)) {
|
||||
trickProperties.setProperty(heightKey, (options.valueOf(heightSpec).toString()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startup() {
|
||||
super.startup();
|
||||
settingsDialog = new SettingsDialog();
|
||||
getMainView().setStatusBar(createStatusBar());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void ready() {
|
||||
super.ready();
|
||||
if (targetSpecified) {
|
||||
connectionStatusBar.connectAction.actionPerformed(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JMenuBar createMenuBar() {
|
||||
JMenuBar menuBar = super.createMenuBar();
|
||||
JMenu menu = menuBar.getMenu(0);
|
||||
|
||||
// Remove look and feel menu item.
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
menu.remove(0);
|
||||
}
|
||||
|
||||
menu.add(new JSeparator(), 0);
|
||||
|
||||
menu.add(new JMenuItem(new AbstractAction("Settings") {
|
||||
{
|
||||
putValue(MNEMONIC_KEY, KeyEvent.VK_G);
|
||||
}
|
||||
public void actionPerformed(ActionEvent actionEvent) {
|
||||
settingsDialog.setVisible(true);
|
||||
}
|
||||
}), 0);
|
||||
|
||||
return menuBar;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JComponent createStatusBar() {
|
||||
return connectionStatusBar;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void shutdown() {
|
||||
try {
|
||||
String hostName = getHostName();
|
||||
int port = getPort();
|
||||
trickProperties.setProperty(hostKey, hostName);
|
||||
trickProperties.setProperty(portKey, Integer.toString(port));
|
||||
}
|
||||
catch (Exception exception) {}
|
||||
|
||||
trickProperties.setProperty(autoReconnectKey, Boolean.toString(autoReconnect));
|
||||
trickProperties.setProperty(disconnectBehaviorKey, disconnectBehavior.toString());
|
||||
trickProperties.setProperty(minimumCyclePeriodKey, Double.toString(minimumCyclePeriod));
|
||||
trickProperties.setProperty(cyclePeriodKey, Double.toString(cyclePeriod));
|
||||
|
||||
Rectangle bounds = getMainFrame().getBounds();
|
||||
trickProperties.setProperty(xKey, Integer.toString(bounds.x));
|
||||
trickProperties.setProperty(yKey, Integer.toString(bounds.y));
|
||||
trickProperties.setProperty(widthKey, Integer.toString(bounds.width));
|
||||
trickProperties.setProperty(heightKey, Integer.toString(bounds.height));
|
||||
|
||||
if (variableServerConnection != null) {
|
||||
try {
|
||||
variableServerConnection.close();
|
||||
}
|
||||
catch (IOException e) {}
|
||||
}
|
||||
super.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* dialog for modifying settings
|
||||
*/
|
||||
protected class SettingsDialog extends JDialog {
|
||||
|
||||
ArrayList<CommitChangesListener> commitChangesListeners = new ArrayList<CommitChangesListener>();
|
||||
ArrayList<BecomingVisibleListener> becomingVisibleListeners = new ArrayList<BecomingVisibleListener>();
|
||||
|
||||
/** weather or not to continuously attempt to reconnect after losing a connection */
|
||||
JCheckBox autoReconnectCheckBox = new JCheckBox("Automatically Reconnect") {{
|
||||
setToolTipText("Automatically attempt to reconnect after losing a connection.");
|
||||
}};
|
||||
|
||||
/** the behavior to take on disconnect */
|
||||
@SuppressWarnings("unchecked") // JComboBox is generic in Java 1.7+
|
||||
JComboBox disconnectBehaviorComboBox =
|
||||
new JComboBox(DisconnectBehavior.values()) {{
|
||||
setToolTipText("The behavior to take when the connection to the simulation is lost.");
|
||||
}};
|
||||
|
||||
/** text field for setting the cycle period */
|
||||
JXTextField cycleField = new JXTextField() {{
|
||||
setColumns(3);
|
||||
setHorizontalAlignment(TRAILING);
|
||||
setToolTipText("Update period in seconds.");
|
||||
}};
|
||||
|
||||
JXPanel mainPanel = new JXPanel(new GridBagLayout()) {{
|
||||
GridBagConstraints constraints = new GridBagConstraints() {{
|
||||
gridx = 0;
|
||||
fill = BOTH;
|
||||
}};
|
||||
|
||||
add(new JXPanel(new GridBagLayout()) {{
|
||||
setBorder(new TitledBorder("Application Behavior") {{
|
||||
setTitleJustification(CENTER);
|
||||
}});
|
||||
|
||||
GridBagConstraints constraints = new GridBagConstraints() {{
|
||||
gridy = 1;
|
||||
}};
|
||||
|
||||
add(new JXLabel("On Disconnect: "), constraints);
|
||||
add(disconnectBehaviorComboBox, constraints);
|
||||
constraints.gridx = constraints.gridy = 0;
|
||||
constraints.gridwidth = 2;
|
||||
add(autoReconnectCheckBox, constraints);
|
||||
}}, constraints);
|
||||
|
||||
add(new JXPanel() {{
|
||||
setBorder(new TitledBorder("Cycle Period") {{
|
||||
setTitleJustification(CENTER);
|
||||
}});
|
||||
add(cycleField);
|
||||
add(new JXLabel(" seconds"));
|
||||
}}, constraints);
|
||||
}};
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*/
|
||||
public SettingsDialog() {
|
||||
super(getMainFrame(), "Settings", true);
|
||||
|
||||
final AbstractAction okAction = new AbstractAction("OK") {
|
||||
{
|
||||
putValue(SHORT_DESCRIPTION, "Apply changes.");
|
||||
putValue(MNEMONIC_KEY, KeyEvent.VK_O);
|
||||
}
|
||||
public void actionPerformed(ActionEvent actionEvent) {
|
||||
for (CommitChangesListener commitChangesListener : commitChangesListeners) {
|
||||
if (!commitChangesListener.canCommitChanges()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
double period = Double.parseDouble(cycleField.getText());
|
||||
if (period < 0) {
|
||||
throw new NumberFormatException("Period must be non-negative.");
|
||||
}
|
||||
setCyclePeriod(period);
|
||||
}
|
||||
catch (NumberFormatException numberFormatException) {
|
||||
JOptionPane.showMessageDialog(getMainFrame(), numberFormatException,
|
||||
"Invalid Value", JOptionPane.ERROR_MESSAGE);
|
||||
cycleField.requestFocusInWindow();
|
||||
cycleField.selectAll();
|
||||
return;
|
||||
}
|
||||
|
||||
autoReconnect = autoReconnectCheckBox.isSelected();
|
||||
disconnectBehavior = (DisconnectBehavior)disconnectBehaviorComboBox.getSelectedItem();
|
||||
|
||||
for (CommitChangesListener commitChangesListener : commitChangesListeners) {
|
||||
commitChangesListener.commitChanges();
|
||||
}
|
||||
|
||||
setVisible(false);
|
||||
}
|
||||
};
|
||||
|
||||
final JXButton okButton = new JXButton(okAction);
|
||||
|
||||
final AbstractAction cancelAction = new AbstractAction("Cancel") {
|
||||
{
|
||||
putValue(SHORT_DESCRIPTION, "Discard changes.");
|
||||
putValue(MNEMONIC_KEY, KeyEvent.VK_C);
|
||||
}
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
setVisible(false);
|
||||
}
|
||||
};
|
||||
|
||||
setContentPane(new JXPanel(new BorderLayout()) {{
|
||||
add(mainPanel, BorderLayout.CENTER);
|
||||
|
||||
add(new JXPanel(new GridLayout(1, 4)) {{
|
||||
add(Box.createHorizontalGlue());
|
||||
add(okButton);
|
||||
add(new JXButton(cancelAction));
|
||||
add(Box.createHorizontalGlue());
|
||||
}}, BorderLayout.SOUTH);
|
||||
}});
|
||||
|
||||
JRootPane rootPane = getRootPane();
|
||||
|
||||
rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
|
||||
KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "SettingsDialog.cancel");
|
||||
rootPane.getActionMap().put("SettingsDialog.cancel", cancelAction);
|
||||
|
||||
rootPane.setDefaultButton(okButton);
|
||||
|
||||
pack();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(boolean visible) {
|
||||
if (visible) {
|
||||
autoReconnectCheckBox.setSelected(autoReconnect);
|
||||
disconnectBehaviorComboBox.setSelectedItem(disconnectBehavior);
|
||||
cycleField.setText(Double.toString(cyclePeriod));
|
||||
getRootPane().getDefaultButton().requestFocusInWindow();
|
||||
setLocationRelativeTo(getMainFrame());
|
||||
|
||||
for (BecomingVisibleListener becomingVisibleListener : becomingVisibleListeners) {
|
||||
becomingVisibleListener.becomingVisible();
|
||||
}
|
||||
}
|
||||
super.setVisible(visible);
|
||||
}
|
||||
|
||||
/**
|
||||
* adds <code>panel</code> to this dialog
|
||||
*
|
||||
* @param panel the panel to add
|
||||
*/
|
||||
public void addPanel(JPanel panel, GridBagConstraints constraints) {
|
||||
mainPanel.add(panel, constraints);
|
||||
pack();
|
||||
}
|
||||
|
||||
/**
|
||||
* registers <code>becomingVisibleListener</code> to be notified just
|
||||
* before this dialog becomes visible
|
||||
*
|
||||
* @param becomingVisibleListener the listener to be notified
|
||||
*/
|
||||
public void addBecomingVisibleListener(BecomingVisibleListener becomingVisibleListener) {
|
||||
becomingVisibleListeners.add(becomingVisibleListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* registers <code>commitChangesListener</code> to be notified when this
|
||||
* dialog's OK button is pressed
|
||||
*
|
||||
* @param commitChangesListener the listener to be notified
|
||||
*/
|
||||
public void addCommitChangesListener(CommitChangesListener commitChangesListener) {
|
||||
commitChangesListeners.add(commitChangesListener);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** a listener interface for when the settings dialog becomes visible */
|
||||
public interface BecomingVisibleListener {
|
||||
/** called just before the settings dialog becomes visible */
|
||||
public void becomingVisible();
|
||||
}
|
||||
|
||||
/** a listener interface for when the OK button on the settings dialog is pressed */
|
||||
public interface CommitChangesListener {
|
||||
/**
|
||||
* called just before changes are to be committed, allowing listeners to
|
||||
* veto the commit. If any listener returns <code>false<code>,
|
||||
* <code>commitChanges()</code> will not be called.
|
||||
*
|
||||
* @return whether or not to proceed with the commit
|
||||
*/
|
||||
public boolean canCommitChanges();
|
||||
|
||||
/** called after all listeners have approved the commit request */
|
||||
public void commitChanges();
|
||||
}
|
||||
|
||||
}
|
744
trick_source/java/src/trick/common/TrickApplication.java
Normal file
@ -0,0 +1,744 @@
|
||||
/*
|
||||
* $Id: TrickApplication.java 3785 2015-01-26 14:12:13Z alin $
|
||||
*
|
||||
*/
|
||||
|
||||
//========================================
|
||||
// Package
|
||||
//========================================
|
||||
package trick.common;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Component;
|
||||
import java.awt.Desktop;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.Insets;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.EventObject;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.swing.ActionMap;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.ButtonGroup;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBoxMenuItem;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.JRadioButtonMenuItem;
|
||||
import javax.swing.JSeparator;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.JToggleButton;
|
||||
import javax.swing.JToolBar;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
|
||||
import org.jdesktop.application.Action;
|
||||
import org.jdesktop.application.ResourceMap;
|
||||
import org.jdesktop.application.SingleFrameApplication;
|
||||
import org.jdesktop.application.View;
|
||||
import org.jdesktop.application.session.PropertySupport;
|
||||
|
||||
import trick.common.ui.UIUtils;
|
||||
|
||||
/**
|
||||
* The parent class which all other Trick Java GUI applications extend.
|
||||
* This intends to define common properties to all other Trick Java applications.
|
||||
* It is a subclass of {@link SingleFrameApplication}.
|
||||
*
|
||||
*
|
||||
* @author Hong Chen
|
||||
* @since Trick 10
|
||||
*/
|
||||
public abstract class TrickApplication extends SingleFrameApplication implements PropertySupport {
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
/** User settable properties, such as default directories, etc. */
|
||||
public Properties trickProperties;
|
||||
|
||||
/** The resource map for the application. */
|
||||
public ResourceMap resourceMap;
|
||||
|
||||
/** The action map for the application. */
|
||||
public ActionMap actionMap;
|
||||
|
||||
/** The exit listener for all applications */
|
||||
public ExitListener exitListener;
|
||||
|
||||
public static String DEFAULT_TIME_NAME = "sys.exec.out.time";
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
/** This application's name. */
|
||||
protected String applicationName;
|
||||
|
||||
/** The exit listener for all applications */
|
||||
protected JCheckBoxMenuItem confirmExitSelection;
|
||||
|
||||
/** The property directory for all applications ($HOME/.trick) */
|
||||
protected static String propDirectory;
|
||||
|
||||
/** The look and feel short name and its class name map */
|
||||
protected static Map<String, String> lafMap;
|
||||
|
||||
/** The look and feel short name list */
|
||||
protected static String[] lafShortNames;
|
||||
|
||||
|
||||
//========================================
|
||||
// Private Data
|
||||
//========================================
|
||||
private static int popupInvokerType;
|
||||
|
||||
// if we want to put the properties into a different location, change here.
|
||||
static {
|
||||
try {
|
||||
propDirectory = System.getProperty("user.home") + System.getProperty("file.separator") + ".trick";
|
||||
} catch (Exception e) {
|
||||
propDirectory = System.getenv("TRICK_USER_HOME") + System.getProperty("file.separator") + ".trick";
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
UIManager.LookAndFeelInfo looks[] = UIManager.getInstalledLookAndFeels();
|
||||
if (looks != null && looks.length > 0) {
|
||||
lafMap = new HashMap<String, String>();
|
||||
lafShortNames = new String[looks.length+1];
|
||||
for (int i = 0; i < looks.length; i++) {
|
||||
if (looks[i].getName().equals("GTK+")) {
|
||||
lafMap.put("GTK", looks[i].getClassName());
|
||||
lafShortNames[i] = "GTK";
|
||||
} else {
|
||||
lafMap.put(looks[i].getName(), looks[i].getClassName());
|
||||
lafShortNames[i] = looks[i].getName();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lafShortNames = new String[1];
|
||||
}
|
||||
lafShortNames[lafShortNames.length-1] = "Default";
|
||||
}
|
||||
|
||||
private JDialog aboutBox = null;
|
||||
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
|
||||
//========================================
|
||||
// Actions
|
||||
//========================================
|
||||
/**
|
||||
* closes the application. Called when the "Exit" menu item is clicked.
|
||||
*/
|
||||
@Action
|
||||
public void exitConfirmation() {
|
||||
if (confirmExitSelection.isSelected()) {
|
||||
addExitListener(exitListener);
|
||||
}
|
||||
else {
|
||||
removeExitListener(exitListener);
|
||||
}
|
||||
}
|
||||
|
||||
@Action
|
||||
public void helpContents() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the about box dialog.
|
||||
*/
|
||||
@Action
|
||||
public void showAboutBox() {
|
||||
if (aboutBox == null) {
|
||||
aboutBox = createAboutBox();
|
||||
}
|
||||
// all those components configured in this application resource
|
||||
// property file are injected through this call.
|
||||
show(aboutBox);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the about box dialog.
|
||||
*/
|
||||
@Action
|
||||
public void closeAboutBox() {
|
||||
if (aboutBox != null) {
|
||||
aboutBox.setVisible(false);
|
||||
aboutBox = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Action
|
||||
public void lookAndFeel() {
|
||||
if (lafMap == null) {
|
||||
JOptionPane.showMessageDialog(getMainFrame(),
|
||||
"Currently, the system doesn't have any Look and Feel installed!",
|
||||
"Look and Feel Not Found",
|
||||
JOptionPane.WARNING_MESSAGE);
|
||||
} else {
|
||||
int choice = -1;
|
||||
if (trickProperties.getProperty(applicationName + ".lookAndFeel") == null) {
|
||||
choice = JOptionPane.showOptionDialog(getMainFrame(), "Change default to:",
|
||||
"Change Look and Feel",
|
||||
JOptionPane.YES_NO_OPTION,
|
||||
JOptionPane.QUESTION_MESSAGE,
|
||||
null,
|
||||
lafShortNames,
|
||||
"Default");
|
||||
} else {
|
||||
String laf = UIManager.getLookAndFeel().getName();
|
||||
// due to the inconsistence between the name of LookAndFeel and UIManager.LookAndFeelInfo for GTK
|
||||
if (laf.startsWith("GTK")) {
|
||||
laf = "GTK";
|
||||
}
|
||||
choice = JOptionPane.showOptionDialog(getMainFrame(), "Change " + laf + " to:",
|
||||
"Change Look and Feel",
|
||||
JOptionPane.YES_NO_OPTION,
|
||||
JOptionPane.QUESTION_MESSAGE,
|
||||
null,
|
||||
lafShortNames,
|
||||
laf);
|
||||
}
|
||||
if (choice > -1 && choice < lafShortNames.length) {
|
||||
if (lafMap.get(lafShortNames[choice]) != null) {
|
||||
changeLookAndFeel(lafMap.get(lafShortNames[choice]));
|
||||
trickProperties.setProperty(applicationName + ".lookAndFeel", lafShortNames[choice]);
|
||||
} else {
|
||||
// if using default, the lookandfeel property doesn't need storing
|
||||
if (lafShortNames[choice].equals("Default")) {
|
||||
changeLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
trickProperties.remove(applicationName + ".lookAndFeel");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//========================================
|
||||
// Set/Get methods
|
||||
//========================================
|
||||
public static void setPopupInvoker(int type) {
|
||||
popupInvokerType = type;
|
||||
}
|
||||
|
||||
public static int getPopupInvoker() {
|
||||
return popupInvokerType;
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
@Override
|
||||
public Object getSessionState(Component component) {
|
||||
if (component instanceof JToggleButton) {
|
||||
return new Boolean(((JToggleButton)component).isSelected());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSessionState(Component component, Object state) {
|
||||
if (component instanceof JToggleButton && state instanceof Boolean) {
|
||||
((JToggleButton)component).setSelected(((Boolean)state).booleanValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for changing the look and feel for the application.
|
||||
*
|
||||
*/
|
||||
protected void changeLookAndFeel(String lafClassName) {
|
||||
if (lafClassName != null) {
|
||||
final String finalLafClassName = lafClassName;
|
||||
Runnable runnable = new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
UIManager.setLookAndFeel(finalLafClassName);
|
||||
SwingUtilities.updateComponentTreeUI(getMainFrame());
|
||||
} catch (Exception exception) {
|
||||
JOptionPane.showMessageDialog(getMainFrame(),
|
||||
"Can't change look and feel",
|
||||
"Invalid Look and Feel",
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
};
|
||||
SwingUtilities.invokeLater(runnable);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenates all of the strings in an array and each separated by the specified separator.
|
||||
*
|
||||
* @param arr The string array.
|
||||
* @param separator The separator for separating each string in the array.
|
||||
*
|
||||
* @return The concatenated string for the string array separated by the separator.
|
||||
*/
|
||||
public static String arrayToString(String[] arr, String separator) {
|
||||
StringBuffer result = new StringBuffer();
|
||||
if (arr.length > 0) {
|
||||
result.append(arr[0]);
|
||||
for (int i=1; i<arr.length; i++) {
|
||||
result.append(separator);
|
||||
result.append(arr[i]);
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Makes initialization as needed. This is called before startup().
|
||||
*
|
||||
* @see #startup
|
||||
*/
|
||||
@Override
|
||||
protected void initialize(String[] args) {
|
||||
// the name of this application
|
||||
applicationName = getContext().getApplicationClass().getSimpleName();
|
||||
|
||||
// set directory for session storage
|
||||
getContext().getLocalStorage().setDirectory(new File(propDirectory + System.getProperty("file.separator") + "." + applicationName));
|
||||
|
||||
// register property for JToggleButton class so that its state can be saved
|
||||
getContext().getSessionStorage().putProperty(JToggleButton.class, this);
|
||||
|
||||
actionMap = getContext().getActionMap();
|
||||
resourceMap = getContext().getResourceMap(getClass());
|
||||
|
||||
// Load any saved user settable properties from properties file
|
||||
trickProperties = new Properties();
|
||||
try {
|
||||
FileInputStream in = new FileInputStream(propDirectory + System.getProperty("file.separator") + applicationName + ".properties");
|
||||
trickProperties.load(in);
|
||||
in.close();
|
||||
}
|
||||
catch (IOException e) {}
|
||||
|
||||
exitListener = new ExitListener() {
|
||||
@Override
|
||||
public boolean canExit(EventObject e) {
|
||||
return (JOptionPane.showConfirmDialog(getMainFrame(), "Do you really want to exit?", "Confirm Exit",
|
||||
JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION);
|
||||
}
|
||||
@Override
|
||||
public void willExit(EventObject e) {}
|
||||
};
|
||||
|
||||
// Check look and feel property
|
||||
String laf = trickProperties.getProperty(applicationName + ".lookAndFeel");
|
||||
if (laf != null) {
|
||||
changeLookAndFeel(lafMap.get(laf));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts building GUI. This is called after initialize.
|
||||
* Once startup() is done, ready() is called.
|
||||
*
|
||||
* @see #initialize
|
||||
* @see #ready
|
||||
*/
|
||||
@Override
|
||||
protected void startup() {
|
||||
// Add this exit listener if the sub class likes the confirmation dialog
|
||||
String defaultValue = Boolean.toString(true);
|
||||
boolean savedExitProperty = new Boolean(trickProperties.getProperty(
|
||||
"confirmExit", defaultValue)).booleanValue();
|
||||
if (( savedExitProperty == true ) && (getExitListeners().length==0)) {
|
||||
// initialize gets called again if you reconnect, so don't add another exitlistener
|
||||
addExitListener(exitListener);
|
||||
}
|
||||
confirmExitSelection = createCheckBoxMenuItem("exitConfirmation", savedExitProperty);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void shutdown() {
|
||||
super.shutdown();
|
||||
boolean confirmExit = false;
|
||||
if (getExitListeners().length > 0) {
|
||||
confirmExit = true;
|
||||
}
|
||||
trickProperties.setProperty("confirmExit", Boolean.toString(confirmExit));
|
||||
|
||||
// Save any user settable properties to properties file in user's home directory in .trick dir
|
||||
try {
|
||||
FileOutputStream out = new FileOutputStream(propDirectory + System.getProperty("file.separator") + applicationName +".properties");
|
||||
trickProperties.store(out, "--- Trick User Properties ---");
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the main {@link JComponent} for the application main {@link View}.
|
||||
* Subclasses must override it.
|
||||
*
|
||||
* @return a {@link JComponent}.
|
||||
*/
|
||||
protected abstract JComponent createMainPanel();
|
||||
|
||||
|
||||
/**
|
||||
* Creates a {@link JMenuBar} for the application.
|
||||
* The default menu bar includes a File menu with an Exit menu item and a check box menu item allowing the user to
|
||||
* disable the exit confirmation prompt.
|
||||
*
|
||||
* @return a {@link JMenuBar}.
|
||||
*/
|
||||
protected JMenuBar createMenuBar() {
|
||||
JMenuBar menuBar = new JMenuBar();
|
||||
JMenu menu = new JMenu();
|
||||
menu.setName("fileMenu");
|
||||
menu.add(createMenuItem("lookAndFeel"));
|
||||
menu.add(new JSeparator());
|
||||
menu.add(confirmExitSelection);
|
||||
menu.add(createMenuItem("quit"));
|
||||
menuBar.add(menu);
|
||||
menuBar.add(Box.createHorizontalGlue());
|
||||
menuBar.add(UIUtils.getSmallTrickIconLabel());
|
||||
return menuBar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link JToolBar} for the application.
|
||||
* Subclasses need to override this if it needs to create a tool bar.
|
||||
*
|
||||
* @return a {@link JToolBar}.
|
||||
*/
|
||||
|
||||
protected JToolBar createToolBar() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a status bar for the application.
|
||||
* Subclasses need to override this if it needs to create a status bar.
|
||||
*
|
||||
* @return a {@link JComponent}.
|
||||
*/
|
||||
protected JComponent createStatusBar() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the action by its name.
|
||||
*
|
||||
* @param actionName The text name of the action.
|
||||
*
|
||||
* @return A {@link javax.swing.Action} of the specified action name.
|
||||
*/
|
||||
protected javax.swing.Action getAction(String actionName) {
|
||||
return getContext().getActionMap().get(actionName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a button based on the specified action name with showing
|
||||
* the text for the button optionally.
|
||||
*
|
||||
* @param actionName The name of the action.
|
||||
* @param showText <code>true</code> if text of the button needs showing,
|
||||
* <code>false</code> otherwise.
|
||||
*
|
||||
* @return An instance of {@link JButton}.
|
||||
*/
|
||||
protected JButton createButton(String actionName, boolean showText) {
|
||||
JButton button = new JButton();
|
||||
button.setVerticalTextPosition(JButton.BOTTOM);
|
||||
button.setHorizontalTextPosition(JButton.CENTER);
|
||||
button.setAction(getAction(actionName));
|
||||
button.setFocusable(false);
|
||||
if (!showText) {
|
||||
button.setText(null);
|
||||
// if button text is not showing, the mnemonic is not necessary either
|
||||
button.setMnemonic(-1);
|
||||
}
|
||||
return button;
|
||||
}
|
||||
|
||||
/**
|
||||
* Help method. Returns a JMenu named menuName that contains a JMenuItem
|
||||
* for each of the specified action names (see #getAction above).
|
||||
* Actions named "---" are turned into JSeparators.
|
||||
*
|
||||
* @param menuName The name for the {@link JMenu}.
|
||||
* @param actionNames An array of action names.
|
||||
*
|
||||
* @return A {@link JMenu} with specified name and action names for its menu items.
|
||||
*/
|
||||
protected JMenu createMenu(String menuName, String[] actionNames) {
|
||||
JMenu menu = new JMenu();
|
||||
menu.setName(menuName);
|
||||
buildMenu(menu, actionNames);
|
||||
return menu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds radio button menu items to a specified menu for the specified actions,
|
||||
* and always selects the first button in the group by default.
|
||||
*
|
||||
* @param menu An instance of {@link JMenu} which needs adding radio button menu itmes for.
|
||||
* @param actions A list of actions that are for menu items.
|
||||
*/
|
||||
protected JRadioButtonMenuItem[] addRadioButtonMenuItems(JMenu menu, String[] actions) {
|
||||
JRadioButtonMenuItem[] menuItems = new JRadioButtonMenuItem[actions.length];
|
||||
ButtonGroup group = new ButtonGroup();
|
||||
for (int i = 0; i < actions.length; i++) {
|
||||
menuItems[i] = new JRadioButtonMenuItem();
|
||||
group.add(menuItems[i]);
|
||||
menuItems[i].setAction(getAction(actions[i]));
|
||||
menuItems[i].setName(actions[i] + "MenuItem");
|
||||
if (i == 0) {
|
||||
menuItems[i].setSelected(true);
|
||||
}
|
||||
menu.add(menuItems[i]);
|
||||
}
|
||||
return menuItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a group of radio button menu items to a specified menu.
|
||||
*
|
||||
* @param menu An instance of {@link JMenu} which needs adding radio button menu items for.
|
||||
* @param items A group of radio button menu items that need adding to a menu.
|
||||
*/
|
||||
protected void addRadioButtonMenuItems(JMenu menu, JRadioButtonMenuItem[] items) {
|
||||
ButtonGroup group = new ButtonGroup();
|
||||
for (JRadioButtonMenuItem item : items) {
|
||||
group.add(item);
|
||||
menu.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Help method. Returns a JPopupMenu that contains a JMenuItem
|
||||
* for each of the specified action names (see #getAction above).
|
||||
* Actions named "---" are turned into JSeparators.
|
||||
*
|
||||
* @param actionNames An array of action names.
|
||||
*
|
||||
* @return A {@link JPopupMenu} with specified action names for its menu items.
|
||||
*/
|
||||
protected JPopupMenu createPopupMenu(String[] actionNames) {
|
||||
JPopupMenu menu = new JPopupMenu();
|
||||
buildMenu(menu, actionNames);
|
||||
return menu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for setting up the menu with specified action names.
|
||||
*/
|
||||
private void buildMenu(JComponent menu, String[] actionNames) {
|
||||
for (String actionName : actionNames) {
|
||||
if (actionName.equals("---")) {
|
||||
menu.add(new JSeparator());
|
||||
}
|
||||
else {
|
||||
menu.add(createMenuItem(actionName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a menu item via the specified action name
|
||||
*
|
||||
* @param actionName the name of the action
|
||||
*
|
||||
* @return the menu item
|
||||
*/
|
||||
protected JMenuItem createMenuItem(String actionName) {
|
||||
JMenuItem menuItem = new JMenuItem(getAction(actionName));
|
||||
menuItem.setName(actionName + "MenuItem");
|
||||
// Don't set it to null so that the icon specified with the action would be honored
|
||||
//menuItem.setIcon(null);
|
||||
return menuItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a checkbox menu item via the specified action name
|
||||
*
|
||||
* @param actionName the name of the action
|
||||
*
|
||||
* @return the checkbox menu item
|
||||
*/
|
||||
protected JCheckBoxMenuItem createCheckBoxMenuItem(String actionName, boolean b) {
|
||||
JCheckBoxMenuItem menuItem = new JCheckBoxMenuItem(getAction(actionName));
|
||||
menuItem.setName(actionName + "CheckBoxMenuItem");
|
||||
menuItem.setSelected(b);
|
||||
// Don't set it to null so that the icon specified with the action would be honored
|
||||
//menuItem.setIcon(null);
|
||||
return menuItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a simple about box {@link JDialog} that displays the standard
|
||||
* Application resources, like {@code Application.title} and
|
||||
* {@code Application.description}. The about box's labels and fields
|
||||
* are configured by resources that are injected when the about box
|
||||
* is shown. All {@code Application.version}, {@code Application.vender},
|
||||
* and {@code Application.homepage} are defiend in {@link TrickApplication}
|
||||
* resource property file from which any sub-class can inherit. All sub-class
|
||||
* needs to have its own {@code Application.id}, {@code Application.title}, and
|
||||
* {@code Application.description} to distinguish it from others.
|
||||
*/
|
||||
protected JDialog createAboutBox() {
|
||||
JPanel panel = new JPanel(new GridBagLayout());
|
||||
panel.setBorder(new EmptyBorder(0, 28, 16, 28)); // top, left, bottom, right
|
||||
JLabel titleLabel = new JLabel();
|
||||
titleLabel.setName("aboutTitleLabel");
|
||||
GridBagConstraints c = new GridBagConstraints();
|
||||
initGridBagConstraints(c);
|
||||
c.anchor = GridBagConstraints.WEST;
|
||||
c.gridwidth = GridBagConstraints.REMAINDER;
|
||||
c.fill = GridBagConstraints.HORIZONTAL;
|
||||
c.ipady = 32;
|
||||
c.weightx = 1.0;
|
||||
panel.add(titleLabel, c);
|
||||
String[] fields = {"description", "version", "vendor", "homepage"};
|
||||
for(String field : fields) {
|
||||
JLabel label = new JLabel();
|
||||
label.setName(field + "Label");
|
||||
JComponent textField = new JTextField();
|
||||
((JTextField)textField).setHorizontalAlignment(JTextField.RIGHT);
|
||||
textField.setName(field + "TextField");
|
||||
((JTextField)textField).setEditable(false);
|
||||
// if for homepage, using JButton instead of JTextField so that
|
||||
// the user can click the homepage link.
|
||||
if ("homepage".equals(field)) {
|
||||
// gets the text from the resource file for homepageTextField
|
||||
final String uriStr = resourceMap.getString("homepageTextField.text");
|
||||
textField = new JButton("<html><body><a href='" + uriStr + "'>" + uriStr + "</a></body></html>");
|
||||
try {
|
||||
final URI uri = new URI(uriStr);
|
||||
((JButton)textField).addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
open(uri);
|
||||
}
|
||||
});
|
||||
} catch (URISyntaxException ue) {
|
||||
((JButton)textField).setText(uriStr);
|
||||
}
|
||||
}
|
||||
|
||||
initGridBagConstraints(c);
|
||||
c.anchor = GridBagConstraints.BASELINE_TRAILING; //1.6 ONLY
|
||||
c.anchor = GridBagConstraints.EAST;
|
||||
panel.add(label, c);
|
||||
initGridBagConstraints(c);
|
||||
c.weightx = 1.0;
|
||||
c.gridwidth = GridBagConstraints.REMAINDER;
|
||||
c.fill = GridBagConstraints.HORIZONTAL;
|
||||
panel.add(textField, c);
|
||||
}
|
||||
JButton closeAboutButton = new JButton();
|
||||
closeAboutButton.setAction(getAction("closeAboutBox"));
|
||||
initGridBagConstraints(c);
|
||||
c.anchor = GridBagConstraints.EAST;
|
||||
c.gridx = 1;
|
||||
panel.add(closeAboutButton, c);
|
||||
JDialog dialog = new JDialog(getMainFrame());
|
||||
dialog.setName("aboutDialog");
|
||||
dialog.add(panel, BorderLayout.CENTER);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for launching the user-default browser to show the specified {@link URI}.
|
||||
*/
|
||||
private void open(URI uri) {
|
||||
if (Desktop.isDesktopSupported()) {
|
||||
Desktop desktop = Desktop.getDesktop();
|
||||
try {
|
||||
desktop.browse(uri);
|
||||
} catch (IOException e) {
|
||||
JOptionPane.showMessageDialog(getMainFrame(),
|
||||
"There is no registered application for opening \n" + uri.toString(),
|
||||
"Warning", JOptionPane.WARNING_MESSAGE);
|
||||
}
|
||||
} else {
|
||||
JOptionPane.showMessageDialog(getMainFrame(),
|
||||
"This desktop is not supported to open \n" + uri.toString(),
|
||||
"Warning", JOptionPane.WARNING_MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for same {@link GridBagConstraints} settings.
|
||||
*/
|
||||
private void initGridBagConstraints(GridBagConstraints c) {
|
||||
c.anchor = GridBagConstraints.CENTER;
|
||||
c.fill = GridBagConstraints.NONE;
|
||||
c.gridwidth = 1;
|
||||
c.gridheight = 1;
|
||||
c.gridx = GridBagConstraints.RELATIVE;
|
||||
c.gridy = GridBagConstraints.RELATIVE;
|
||||
c.insets = new Insets(0,0,0,0);
|
||||
c.ipadx = 4; // not the usual default
|
||||
c.ipady = 4; // not the usual default
|
||||
c.weightx = 0.0;
|
||||
c.weighty = 0.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a help menu item via action names related Java help set file name.
|
||||
*
|
||||
* @param menuName the name of the menu
|
||||
* @param actionNames all the action names for this help menu
|
||||
* @param helpSetName the Jave help set file name
|
||||
*
|
||||
* @return the help menu
|
||||
*
|
||||
*/
|
||||
protected JMenu createHelpMenu(String menuName, String[] actionNames, String helpSetName) {
|
||||
JMenu helpMenu = createMenu(menuName, actionNames);
|
||||
return helpMenu;
|
||||
}
|
||||
|
||||
/**
|
||||
* prepends <code>${TRICK_HOME}/bin</code> to <code>executable</code> and
|
||||
* runs the command in a new process with the given <code>arguments</code>.
|
||||
* Redirects the new process's standard and error outputs to the
|
||||
* corresponding parent steams.
|
||||
*
|
||||
* @param executable the trick application script to run
|
||||
* @param arguments the parameters to pass to the application
|
||||
*/
|
||||
protected static void launchTrickApplication(String executable, String arguments) {
|
||||
try {
|
||||
ProcessBuilder process = new ProcessBuilder(UIUtils.getTrickBin() +
|
||||
File.separator + executable, arguments);
|
||||
// TODO: Uncomment these when we move to Java 1.7 again
|
||||
//process.redirectOutput(ProcessBuilder.Redirect.INHERIT);
|
||||
//process.redirectError(ProcessBuilder.Redirect.INHERIT);
|
||||
process.start();
|
||||
} catch (IOException ioException) {
|
||||
ioException.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
#
|
||||
# $Id: RunTimeTrickApplication.properties 1752 2011-07-12 14:52:03Z dbankie $
|
||||
#
|
||||
|
||||
connect.Action.text = &Connect
|
||||
connect.Action.shortDescription = Connect to the simulation.
|
||||
|
||||
disconnect.Action.text = Dis&connect
|
||||
disconnect.Action.shortDescription = Disconnect from the simulation.
|
@ -0,0 +1,96 @@
|
||||
#
|
||||
# $Id: TrickApplication.properties 2126 2012-01-17 22:08:56Z dbankie $
|
||||
#
|
||||
# resources/TrickApplication.properties, property file for TrickApplication
|
||||
|
||||
Application.id = TrickApplication
|
||||
Application.title = [Application.title not specified]
|
||||
Application.version = 10.0
|
||||
Application.vendor = NASA
|
||||
Application.homepage = http://trick.jsc.nasa.gov/
|
||||
Application.description.short = [Application.description.short not specified]
|
||||
Application.description = [Application.description not specified]
|
||||
|
||||
Application.icon = trick_icon.png
|
||||
|
||||
trick.logo = trick.gif
|
||||
|
||||
|
||||
##Application.lookAndFeel = com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel
|
||||
##Application.lookAndFeel = javax.swing.plaf.nimbus.NimbusLookAndFeel
|
||||
##Application.lookAndFeel = javax.swing.plaf.metal.MetalLookAndFeel
|
||||
|
||||
## S_sie.resource
|
||||
sie.resource.file = S_sie.resource
|
||||
|
||||
## File menu - can be used/override in any subclass
|
||||
fileMenu.text = &File
|
||||
|
||||
exitConfirmation.Action.text = Show Exit Confirmation Prompt
|
||||
exitConfirmation.Action.shortDescription = Turn On/Off popup box that verifies \
|
||||
if the user really wants to close this application.
|
||||
|
||||
|
||||
## Help menu
|
||||
helpContents.Action.text = &Help Contents
|
||||
helpContents.Action.shortDescription = Show Help Contents
|
||||
|
||||
## About
|
||||
showAboutBox.Action.text = &About...
|
||||
showAboutBox.Action.shortDescription = Show the application's about box dialog
|
||||
|
||||
closeAboutBox.Action.text = OK
|
||||
closeAboutBox.Action.shortDescription = Close the about box dialog
|
||||
|
||||
# Resources for the AboutBox
|
||||
aboutDialog.title = About ${Application.id}
|
||||
|
||||
aboutTitleLabel.font = Lucida-BOLD-18
|
||||
aboutTitleLabel.text = ${Application.title}
|
||||
aboutTitleLabel.icon = trick_small.gif
|
||||
|
||||
descriptionLabel.text = Description:
|
||||
descriptionTextField.text = ${Application.description}
|
||||
|
||||
versionLabel.text = Version:
|
||||
versionTextField.text = ${Application.version}
|
||||
|
||||
vendorLabel.text = Vendor:
|
||||
vendorTextField.text = ${Application.vendor}
|
||||
|
||||
homepageLabel.text = Homepage:
|
||||
homepageTextField.text = ${Application.homepage}
|
||||
|
||||
## Look and Feel
|
||||
lookAndFeel.Action.text = &Look and Feel
|
||||
lookAndFeel.Action.ShortDescription = Change Look and Feel
|
||||
|
||||
## Specify certain action icons here so that they can be put in common
|
||||
## resources and shared by different applications
|
||||
## For TrickDPApplication
|
||||
# newSession action icon for TrickDPApplication
|
||||
newSession.Action.icon = filenew.gif
|
||||
# saveSession action icon for TrickDPApplication
|
||||
saveSession.Action.icon = filesave.gif
|
||||
# openSession action icon for TrickDPApplication
|
||||
openSession.Action.icon = fileopen.gif
|
||||
|
||||
## For TrickQPApplication
|
||||
# newDP action icon for TrickQPApplication
|
||||
newDP.Action.icon = filenew.gif
|
||||
# saveDP action icon for TrickQPApplication
|
||||
saveDP.Action.icon = filesave.gif
|
||||
# openDP action icon for TrickQPApplication
|
||||
openDP.Action.icon = fileopen.gif
|
||||
|
||||
## For DreApplication
|
||||
# openDR action icon for DreApplication
|
||||
openDR.Action.icon = fileopen.gif
|
||||
# saveDR action icon for DreApplication
|
||||
saveDR.Action.icon = filesave.gif
|
||||
|
||||
treeNodeClosed.icon = firefox_folder_closed.gif
|
||||
treeNodeOpen.icon = firefox_folder_open.gif
|
||||
treeNodeLeaf.icon = gnome-fs-regular.gif
|
||||
|
||||
|
BIN
trick_source/java/src/trick/common/resources/filenew.gif
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
trick_source/java/src/trick/common/resources/fileopen.gif
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
trick_source/java/src/trick/common/resources/filesave.gif
Normal file
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 608 B |
After Width: | Height: | Size: 610 B |
BIN
trick_source/java/src/trick/common/resources/page2.gif
Normal file
After Width: | Height: | Size: 66 B |
BIN
trick_source/java/src/trick/common/resources/plot.gif
Normal file
After Width: | Height: | Size: 360 B |
BIN
trick_source/java/src/trick/common/resources/program.gif
Normal file
After Width: | Height: | Size: 85 B |
BIN
trick_source/java/src/trick/common/resources/program_in.gif
Normal file
After Width: | Height: | Size: 110 B |
BIN
trick_source/java/src/trick/common/resources/program_out.gif
Normal file
After Width: | Height: | Size: 110 B |
BIN
trick_source/java/src/trick/common/resources/table_small.gif
Normal file
After Width: | Height: | Size: 67 B |
BIN
trick_source/java/src/trick/common/resources/toplevel.gif
Normal file
After Width: | Height: | Size: 158 B |
BIN
trick_source/java/src/trick/common/resources/trick.gif
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
trick_source/java/src/trick/common/resources/trick_icon.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
trick_source/java/src/trick/common/resources/trick_small.gif
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
trick_source/java/src/trick/common/resources/variable.gif
Normal file
After Width: | Height: | Size: 61 B |
BIN
trick_source/java/src/trick/common/resources/x_variable.gif
Normal file
After Width: | Height: | Size: 87 B |
BIN
trick_source/java/src/trick/common/resources/y_variable.gif
Normal file
After Width: | Height: | Size: 84 B |
156
trick_source/java/src/trick/common/ui/TrickFileFilter.java
Normal file
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* $Id: TrickFileFilter.java 3601 2014-07-23 21:13:49Z hchen3 $
|
||||
*
|
||||
*/
|
||||
|
||||
//========================================
|
||||
// Package
|
||||
//========================================
|
||||
package trick.common.ui;
|
||||
|
||||
//========================================
|
||||
// Imports
|
||||
//========================================
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
|
||||
|
||||
/**
|
||||
* A {@link FileFilter} that accepts specified file or directory name.
|
||||
*
|
||||
* @author Hong Chen
|
||||
* @since Trick 10
|
||||
*/
|
||||
public class TrickFileFilter implements java.io.FileFilter {
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
public final static int SIM_RUN = 1;
|
||||
public final static int SIM_DP = 2;
|
||||
public final static int LOG = 3;
|
||||
public final static int XML = 4;
|
||||
public final static int HEADER = 5;
|
||||
public final static int TRK = 6;
|
||||
public final static int CSV = 7;
|
||||
public final static int H5 = 8;
|
||||
// this includes all trick data record related files, .header, .trk, .csv and .h5
|
||||
public final static int TRICK_DATA_RECORD = 9;
|
||||
// for postscript files
|
||||
public final static int PS = 10;
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
|
||||
|
||||
//========================================
|
||||
// Private Data
|
||||
//========================================
|
||||
private int type;
|
||||
private String filenameMatch = null;
|
||||
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public TrickFileFilter(int type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Set/Get methods
|
||||
//========================================
|
||||
/**
|
||||
* Gets the type of this {@link TrickFileFilter}.
|
||||
*
|
||||
* @return The type of the filter.
|
||||
*/
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets file name mathing criteria for the filter.
|
||||
*
|
||||
* @param matching This filter cannot be accepted if {@link File} is a file and
|
||||
* its name doesn't contain the matching string.
|
||||
*/
|
||||
public void setFilenameMatch(String matching) {
|
||||
filenameMatch = matching;
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
/**
|
||||
* Required by {@link FileFilter}.
|
||||
*
|
||||
* @see javax.swing.filechooser.FileFilter#accept(java.io.File)
|
||||
*/
|
||||
public boolean accept(File f) {
|
||||
boolean ret;
|
||||
switch (type) {
|
||||
case SIM_RUN:
|
||||
// only directories are considered
|
||||
if (f.isFile()) {
|
||||
ret = false;
|
||||
}
|
||||
ret = f.getName().startsWith("SIM") || f.getName().startsWith("RUN") || f.getName().startsWith("SET") || f.getName().startsWith("MONTE_RUN");
|
||||
// ignore all RUN dirs under another RUN dirs unless these RUN dirs are under SIM_, SET_, or MONTE_RUN
|
||||
if (f.getName().startsWith("RUN") && f.getParentFile().getName().startsWith("RUN")) {
|
||||
ret = false;
|
||||
}
|
||||
break;
|
||||
case SIM_DP:
|
||||
ret = (f.isDirectory() && f.getName().startsWith("SIM"))
|
||||
|| (f.isFile() && f.getName().startsWith("DP"))
|
||||
|| (f.isDirectory() && f.getName().startsWith("SET"))
|
||||
|| (f.isDirectory() && f.getName().equals("DP_Product"))
|
||||
|| (f.isDirectory() && f.getName().equals("DP_Products"));
|
||||
break;
|
||||
case LOG:
|
||||
ret = f.isFile() && f.getName().toLowerCase().startsWith("log");
|
||||
break;
|
||||
case XML:
|
||||
ret = f.isFile() && f.getName().toLowerCase().endsWith(".xml");
|
||||
break;
|
||||
case HEADER:
|
||||
ret = f.isFile() && f.getName().toLowerCase().endsWith(".header");
|
||||
break;
|
||||
case TRK:
|
||||
ret = f.isFile() && f.getName().toLowerCase().endsWith(".trk");
|
||||
break;
|
||||
case CSV:
|
||||
ret = f.isFile() && f.getName().toLowerCase().endsWith(".csv");
|
||||
break;
|
||||
case H5:
|
||||
ret = f.isFile() && f.getName().toLowerCase().endsWith(".h5");
|
||||
break;
|
||||
case TRICK_DATA_RECORD:
|
||||
ret = f.isFile() &&
|
||||
(f.getName().toLowerCase().endsWith(".header") ||
|
||||
f.getName().toLowerCase().endsWith(".trk") ||
|
||||
f.getName().toLowerCase().endsWith(".csv") ||
|
||||
f.getName().toLowerCase().endsWith(".mat") ||
|
||||
f.getName().toLowerCase().endsWith(".h5")
|
||||
);
|
||||
break;
|
||||
case PS:
|
||||
ret = f.isFile() && f.getName().toLowerCase().endsWith(".ps");
|
||||
break;
|
||||
default:
|
||||
ret = true;
|
||||
}
|
||||
if (filenameMatch != null && filenameMatch.length() > 0) {
|
||||
// only check the additional match when is a file
|
||||
if (f.isFile()) {
|
||||
ret = ret && f.getName().contains(filenameMatch);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
864
trick_source/java/src/trick/common/ui/UIUtils.java
Normal file
@ -0,0 +1,864 @@
|
||||
/*
|
||||
* $Id: UIUtils.java 3771 2014-12-11 20:37:29Z hchen3 $
|
||||
*
|
||||
*/
|
||||
|
||||
//========================================
|
||||
// Package
|
||||
//========================================
|
||||
package trick.common.ui;
|
||||
|
||||
//========================================
|
||||
// Imports
|
||||
//========================================
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.HeadlessException;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.URL;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.swing.DefaultComboBoxModel;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.JTextPane;
|
||||
import javax.swing.ListSelectionModel;
|
||||
import javax.swing.filechooser.FileNameExtensionFilter;
|
||||
import javax.swing.text.Style;
|
||||
import javax.swing.text.StyleConstants;
|
||||
import javax.swing.text.StyleContext;
|
||||
import javax.swing.text.StyledDocument;
|
||||
|
||||
import org.jdesktop.swingx.JXLabel;
|
||||
import org.jdesktop.swingx.JXTitledPanel;
|
||||
|
||||
import trick.common.TrickApplication;
|
||||
import trick.common.utils.TrickColors;
|
||||
|
||||
|
||||
/**
|
||||
* Utilities class for UI.
|
||||
*
|
||||
* @author Hong Chen
|
||||
* @since Trick 7
|
||||
*/
|
||||
public class UIUtils {
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
public final static String DOCUMENT_STYLE_REGULAR = "regular";
|
||||
public final static String DOCUMENT_STYLE_REGULAR_ITALIC = "regularItalic";
|
||||
public final static String DOCUMENT_STYLE_REGULAR_BOLD_BLUE = "regularBoldBlue";
|
||||
public final static String DOCUMENT_STYLE_REGULAR_BOLD_BLUE_SHADE = "regularBoldBlueShade";
|
||||
public final static String DOCUMENT_STYLE_REGULAR_LARGE_BOLD_BLUE_SHADE = "regularLargeBoldBlueShade";
|
||||
public final static String DOCUMENT_STYLE_REGULAR_LARGE_BOLD_BLUE = "regularLargeBoldBlue";
|
||||
public final static String DOCUMENT_STYLE_REGULAR_SMALL = "regularSmall";
|
||||
|
||||
// For numbers that only needs to 2 fraction points.
|
||||
public static final NumberFormat TWO_FRACTION_FORMATTER = new DecimalFormat("0.00");
|
||||
|
||||
public final static int CANCEL_OPTION = 0;
|
||||
public final static int OK_OPTION = 1;
|
||||
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
|
||||
|
||||
//========================================
|
||||
// Private Data
|
||||
//========================================
|
||||
// for env variables
|
||||
private final static int HOME = 0;
|
||||
private final static int TRICK_HOME = 1;
|
||||
private final static int TRICK_USER_HOME = 2;
|
||||
private final static int TRICK_VER = 3;
|
||||
private final static int TRICK_HOST_CPU = 4;
|
||||
private final static int TRICK_LOGO = 5;
|
||||
|
||||
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
|
||||
|
||||
//========================================
|
||||
// Set/Get methods
|
||||
//========================================
|
||||
/**
|
||||
* Gets the value of HOME environment variable.
|
||||
*
|
||||
* @return The value of HOME.
|
||||
*/
|
||||
public static String getUserHome() {
|
||||
return getTrickEnv(HOME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of TRICK_USER_HOME environment variable.
|
||||
*
|
||||
* @return The value of TRICK_USER_HOME. If it is not defined, return
|
||||
* the value of HOME.
|
||||
*/
|
||||
public static String getTrickUserHome() {
|
||||
String ret = getTrickEnv(TRICK_USER_HOME);
|
||||
if (ret == null) {
|
||||
ret = getTrickEnv(HOME);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of TRICK_HOME environment variable.
|
||||
*
|
||||
* @return The value of TRICK_HOME. If it is not defined, return
|
||||
* the value of HOME.
|
||||
*/
|
||||
public static String getTrickHome() {
|
||||
String ret = getTrickEnv(TRICK_HOME);
|
||||
if (ret == null) {
|
||||
ret = getTrickEnv(HOME);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the text of $TRICK_HOME/bin.
|
||||
*
|
||||
* @return The text of $TRICK_HOME/bin. If it is not defined, return
|
||||
* the text of $HOME/bin.
|
||||
*/
|
||||
public static String getTrickBin() {
|
||||
String ret = getTrickEnv(TRICK_HOME) ;
|
||||
if (ret == null) {
|
||||
ret = getTrickEnv(HOME);
|
||||
}
|
||||
ret = ret + File.separator + "bin";
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of TRICK_VER environment variable.
|
||||
*
|
||||
* @return The value of TRICK_VER.
|
||||
*/
|
||||
public static String getTrickVersion() {
|
||||
return getTrickEnv(TRICK_VER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of TRICK_HOST_CPU environment variable.
|
||||
*
|
||||
* @return The value of TRICK_HOST_CPU.
|
||||
*/
|
||||
public static String getTrickHostCPU() {
|
||||
return getTrickEnv(TRICK_HOST_CPU);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of TRICK_LOGO environment variable.
|
||||
*
|
||||
* @return The value of TRICK_LOGO.
|
||||
*/
|
||||
public static String getTrickLogo() {
|
||||
return getTrickEnv(TRICK_LOGO);
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
/**
|
||||
* Helper method for getting Trick environment variable value.
|
||||
*
|
||||
* @param type The type of the variable.
|
||||
*
|
||||
* @return The environment variable value.
|
||||
*/
|
||||
private static String getTrickEnv(int type) {
|
||||
String value = null;
|
||||
switch (type) {
|
||||
case TRICK_HOME:
|
||||
value = System.getenv("TRICK_HOME");
|
||||
break;
|
||||
case TRICK_USER_HOME:
|
||||
value = System.getenv("TRICK_USER_HOME");
|
||||
break;
|
||||
case TRICK_VER:
|
||||
value = System.getenv("TRICK_VER");
|
||||
break;
|
||||
case HOME:
|
||||
value = System.getenv("HOME");
|
||||
break;
|
||||
case TRICK_HOST_CPU:
|
||||
value = System.getenv("TRICK_HOST_CPU");
|
||||
break;
|
||||
case TRICK_LOGO:
|
||||
value = System.getenv("TRICK_LOGO");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets html hex for a {@link Color}.
|
||||
*
|
||||
* @param c An instance of {@link Color} which the hex number is getting from.
|
||||
*
|
||||
* @return "#" followed by exactly 6 hex digits.
|
||||
*
|
||||
*/
|
||||
public final static String colorToHTMLHex(Color c) {
|
||||
String s = Integer.toHexString( c.getRGB() & 0xffffff );
|
||||
if ( s.length() < 6 ) { // pad on left with zeros
|
||||
s = "000000".substring( 0, 6 - s.length() ) + s;
|
||||
}
|
||||
return '#' + s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the color based on the 6-digit html hex string or color name.
|
||||
*
|
||||
* @param colorStrOrCode The 6-digit hex leading by "#" in string or a supported name of a color.
|
||||
*
|
||||
* @return An instance of {@link Color}.
|
||||
*/
|
||||
public final static Color getColorFromHTMLHex(String colorStrOrCode) {
|
||||
if (colorStrOrCode == null || "".equals(colorStrOrCode)) {
|
||||
return null;
|
||||
}
|
||||
Color c = null;
|
||||
try {
|
||||
c = Color.decode(colorStrOrCode);
|
||||
} catch (NumberFormatException nfe) {
|
||||
c = TrickColors.getColor(colorStrOrCode);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if a JComboBox contains an object.
|
||||
*/
|
||||
public static boolean comboBoxContains(DefaultComboBoxModel model, Object obj) {
|
||||
for (int i = 0; i < model.getSize(); i++) {
|
||||
if (obj.equals(model.getElementAt(i))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the mouse click is a right click.
|
||||
*
|
||||
* @param e a {@link MouseEvent} to test.
|
||||
*
|
||||
* @return <code>true</code> if right button was pressed, <code>false</code> otherwise.
|
||||
*/
|
||||
public static boolean isRightMouseClick(MouseEvent e) {
|
||||
boolean rval = false;
|
||||
|
||||
if( (e.getModifiers()&MouseEvent.BUTTON3_MASK)==MouseEvent.BUTTON3_MASK ) {
|
||||
rval = true;
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if the mouse click is double click.
|
||||
*
|
||||
* @param e a {@link MouseEvent} to test.
|
||||
*
|
||||
* @return <code>true</code> if is double-clicking, <code>false</code> otherwise.
|
||||
*/
|
||||
public static boolean isDoubleClick(MouseEvent e) {
|
||||
boolean rval = false;
|
||||
|
||||
if (e.getClickCount() == 2) {
|
||||
rval = true;
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if the specified directory has "log" files.
|
||||
*
|
||||
* @param dir A file directory.
|
||||
*
|
||||
* @return <code>true</code> if the specified directory has log files, <code>false</code> otherwise.
|
||||
*/
|
||||
public static boolean hasLogFile(File dir) {
|
||||
return hasSpecifiedFile(dir, TrickFileFilter.LOG);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if the specified directory has .header files.
|
||||
*
|
||||
* @param dir A file directory.
|
||||
*
|
||||
* @return <code>true</code> if the specified directory has .header files, <code>false</code> otherwise.
|
||||
*/
|
||||
public static boolean hasHeaderFile(File dir) {
|
||||
return hasSpecifiedFile(dir, TrickFileFilter.HEADER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if the specified directory has .trk files.
|
||||
*
|
||||
* @param dir A file directory.
|
||||
*
|
||||
* @return <code>true</code> if the specified directory has .trk files, <code>false</code> otherwise.
|
||||
*/
|
||||
public static boolean hasTRKFile(File dir) {
|
||||
return hasSpecifiedFile(dir, TrickFileFilter.TRK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if the specified directory has .csv files.
|
||||
*
|
||||
* @param dir A file directory.
|
||||
*
|
||||
* @return <code>true</code> if the specified directory has .csv files, <code>false</code> otherwise.
|
||||
*/
|
||||
public static boolean hasCSVFile(File dir) {
|
||||
return hasSpecifiedFile(dir, TrickFileFilter.CSV);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for checking to see if a particular directory has certain files.
|
||||
*
|
||||
* @param dir A directory.
|
||||
* @param type The Trick file type. See {@link TrickFileFilter} for all supported types.
|
||||
*
|
||||
* @return <code>true</code> if the specified directory has specified files, <code>false</code> otherwise.
|
||||
*/
|
||||
private static boolean hasSpecifiedFile(File dir, int type) {
|
||||
File[] tmp = dir.listFiles(new TrickFileFilter(type));
|
||||
if (tmp == null || tmp.length < 1) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a file's name without its extension. If no extension found, return
|
||||
* the original file name.
|
||||
*/
|
||||
public static String getFileNameWithoutExtension(File file) {
|
||||
String fileName = file.getName();
|
||||
int dotLoc = fileName.lastIndexOf('.');
|
||||
if (dotLoc > 0 && dotLoc <= fileName.length() - 2) {
|
||||
return fileName.substring(0, dotLoc);
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of abstract pathnames denoting the files that satisfy the specified filter.
|
||||
*
|
||||
* @param dir A directory.
|
||||
* @param type The Trick file type. See {@link TrickFileFilter} for all supported types.
|
||||
*
|
||||
* @return An array of abstract pathnames denoting the files, <code>null</code>
|
||||
* if the specified dir is null or is not a directory.
|
||||
*/
|
||||
public static File[] getListFiles(File dir, int type) {
|
||||
if (dir != null && dir.isDirectory()) {
|
||||
return dir.listFiles(new TrickFileFilter(type));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of {@link JXLabel} that displays trick small icon for different GUIs
|
||||
* with version information tool tip.
|
||||
*
|
||||
* @return An instance of {@link JXLabel} with its icon set to trick small icon and
|
||||
* tool tip set to the trick version.
|
||||
*/
|
||||
public static JXLabel getSmallTrickIconLabel() {
|
||||
JXLabel label = new JXLabel();
|
||||
String desc = "Trick Version " + getTrickVersion();
|
||||
label.setToolTipText(desc);
|
||||
|
||||
ImageIcon smallIcon = createImageIcon("trick_small.gif");
|
||||
if (smallIcon != null) {
|
||||
smallIcon.setDescription(desc);
|
||||
label.setIcon(smallIcon);
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search to see if an input string has the search string.
|
||||
* The search string can have "*". If there is no wildcard,
|
||||
* it simply checks if inputStr string contians the searchStr string.
|
||||
*
|
||||
* @param inputStr - the input search string.
|
||||
* @param searchStr - the search string which searching is based upon.
|
||||
*
|
||||
* @return - true if found, false otherwise.
|
||||
*/
|
||||
public static boolean searchWithWildcard(String inputStr, String searchStr) {
|
||||
StringBuffer patternBuf = new StringBuffer();
|
||||
if (searchStr.contains("*")) {
|
||||
String[] parts = searchStr.split("\\*");
|
||||
for (String part : parts) {
|
||||
patternBuf.append(".*(");
|
||||
patternBuf.append(part);
|
||||
patternBuf.append(")");
|
||||
}
|
||||
patternBuf.append(".*");
|
||||
|
||||
Pattern pattern = Pattern.compile(patternBuf.toString());
|
||||
Matcher matcher = pattern.matcher(inputStr);
|
||||
return matcher.find();
|
||||
} else {
|
||||
return (inputStr.contains(searchStr));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a directory only file chooser for a particular directory
|
||||
* with specified dialog title.
|
||||
*
|
||||
* @param chooserTitle The title for the dialog.
|
||||
* @param dir The directory for the file chooser.
|
||||
* @param parent The parent component for opening the file chooser.
|
||||
*
|
||||
* @return The selected directory.
|
||||
*/
|
||||
public static File chooseDir(String chooserTitle, String dir, Component parent) {
|
||||
JFileChooser chooser = new JFileChooser();
|
||||
if (dir == null) {
|
||||
chooser.setCurrentDirectory(new java.io.File("."));
|
||||
} else {
|
||||
File file = new java.io.File(dir);
|
||||
if (!file.exists()) {
|
||||
file = new java.io.File(".");
|
||||
}
|
||||
chooser.setCurrentDirectory(file);
|
||||
}
|
||||
chooser.setDialogTitle(chooserTitle);
|
||||
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
||||
|
||||
int chooserState = chooser.showDialog(parent, "Ok");
|
||||
if (chooserState == JFileChooser.APPROVE_OPTION) {
|
||||
return chooser.getSelectedFile();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a file chooser and returns the selected file if available.
|
||||
*
|
||||
* @param dir The directory from which a file will be selected.
|
||||
* @param fileName The initial file name that is prompted in the file field.
|
||||
* @param fileNameExtension The desired file extension.
|
||||
* @param parent The parent component that makes the call.
|
||||
*
|
||||
* @return An instance of {@link File} if the selection is successful, <code>null</code> otherwise.
|
||||
*/
|
||||
public static File chooseOpenFile(String dir, String fileName, String fileNameExtension, Component parent) {
|
||||
JFileChooser chooser = new JFileChooser();
|
||||
File selectedFile = null;
|
||||
|
||||
File fileDir = null;
|
||||
|
||||
// if dir is not specified or the dir doesn't exist, use the current directory
|
||||
if (dir == null) {
|
||||
fileDir = new File(".");
|
||||
} else {
|
||||
fileDir = new File(dir);
|
||||
}
|
||||
|
||||
if (!fileDir.exists()) {
|
||||
fileDir = new File(".");
|
||||
}
|
||||
|
||||
chooser.setCurrentDirectory(fileDir);
|
||||
|
||||
if (fileName != null) {
|
||||
chooser.setSelectedFile(new java.io.File(fileName));
|
||||
}
|
||||
|
||||
if (fileNameExtension != null) {
|
||||
chooser.setFileFilter(new FileNameExtensionFilter(fileNameExtension+" file", fileNameExtension));
|
||||
}
|
||||
chooser.setDialogTitle("Open File");
|
||||
|
||||
boolean isValid = true;
|
||||
do {
|
||||
int chooserState = chooser.showDialog(parent, "Ok");
|
||||
if (chooserState == JFileChooser.APPROVE_OPTION) {
|
||||
selectedFile = chooser.getSelectedFile();
|
||||
if (!selectedFile.exists()) {
|
||||
JOptionPane.showMessageDialog(parent,
|
||||
selectedFile.getName()+" does not exist. Please choose another file!",
|
||||
"File Not Found",
|
||||
JOptionPane.WARNING_MESSAGE);
|
||||
} else {
|
||||
isValid = false;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} while (isValid);
|
||||
|
||||
return selectedFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves text to a specified file.
|
||||
*
|
||||
* @param contents The text contents that need to be saved.
|
||||
* @param file The file which the text will be saved to.
|
||||
*/
|
||||
public static void saveTextFile(String contents, File file) {
|
||||
try {
|
||||
PrintWriter out = new PrintWriter(new FileWriter(file));
|
||||
out.print(contents);
|
||||
out.close();
|
||||
} catch (IOException ioe) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a file chooser and let the user to either choose or specify a file for saving purpose.
|
||||
*
|
||||
* @param dir The directory which the file chooser works from initially.
|
||||
* @param initialFile The file that is set initially.
|
||||
* @param fileNameExtension The desired file extension.
|
||||
* @param parent The parent component that wants to open the file chooser.
|
||||
*
|
||||
* @return The specified the file, <code>null</code> if canceled.
|
||||
*/
|
||||
public static File chooseSaveFile(String dir, String initialFile, String fileNameExtension, Component parent) {
|
||||
JFileChooser chooser = new JFileChooser();
|
||||
File selectedFile = null;
|
||||
String selectedFileName = null;
|
||||
|
||||
File fileDir = null;
|
||||
|
||||
// if dir is not specified or the dir doesn't exist, use the current directory
|
||||
if (dir == null) {
|
||||
fileDir = new File(".");
|
||||
} else {
|
||||
fileDir = new File(dir);
|
||||
}
|
||||
|
||||
if (!fileDir.exists()) {
|
||||
fileDir = new File(".");
|
||||
}
|
||||
|
||||
chooser.setCurrentDirectory(fileDir);
|
||||
|
||||
if (initialFile != null) {
|
||||
chooser.setSelectedFile(new java.io.File(initialFile));
|
||||
}
|
||||
if (fileNameExtension != null) {
|
||||
chooser.setFileFilter(new FileNameExtensionFilter(fileNameExtension + " file", fileNameExtension));
|
||||
}
|
||||
chooser.setDialogTitle("Save File");
|
||||
boolean isValid = true;
|
||||
do {
|
||||
int chooserState = chooser.showDialog(parent, "Ok");
|
||||
if (chooserState == JFileChooser.APPROVE_OPTION) {
|
||||
selectedFile = chooser.getSelectedFile();
|
||||
selectedFileName = selectedFile.getName();
|
||||
if (fileNameExtension != null) {
|
||||
// 1.append the specified file extension if there is no extension.
|
||||
// 2.append the desired extension if there is an extension which is not the same as specified
|
||||
if (selectedFileName.indexOf('.') == -1 ||
|
||||
(selectedFileName.indexOf('.') != -1 && !selectedFileName.endsWith(fileNameExtension))) {
|
||||
selectedFileName += "." + fileNameExtension;
|
||||
}
|
||||
selectedFile = new File(selectedFile.getParentFile(), selectedFileName);
|
||||
}
|
||||
if (selectedFile.exists()) {
|
||||
int choice = JOptionPane.showConfirmDialog(parent,
|
||||
selectedFileName + " already exists. Overwrite it?",
|
||||
"Overwrite File",
|
||||
JOptionPane.YES_NO_OPTION);
|
||||
// If "Yes" is selected
|
||||
if (choice == JOptionPane.YES_OPTION) {
|
||||
isValid = false;
|
||||
}
|
||||
} else {
|
||||
isValid = false;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} while (isValid);
|
||||
|
||||
return selectedFile;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shows a warning dialog with specified message and title.
|
||||
*
|
||||
* @param title The title for the dialog window.
|
||||
* @param msg The message text for the dialog window.
|
||||
* @param parent The parent component that wants to open the dialog.
|
||||
*
|
||||
* @return The selected choice.
|
||||
*/
|
||||
public static int showOkCancelDialog(String title, String msg, Component parent) {
|
||||
Object[] options = new Object[2];
|
||||
options[OK_OPTION] = "Ok";
|
||||
options[CANCEL_OPTION] = "Cancel";
|
||||
int choice = JOptionPane.showOptionDialog(parent,
|
||||
msg,
|
||||
title,
|
||||
JOptionPane.DEFAULT_OPTION,
|
||||
JOptionPane.WARNING_MESSAGE,
|
||||
null,
|
||||
options,
|
||||
options[CANCEL_OPTION]);
|
||||
return choice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a list input dialog. Forces to use a {@link JList} for user to input.
|
||||
*
|
||||
* JOptionPane.showInputDialog with the same arguments as this method uses
|
||||
* a component for user to input and it is upt to the UI to decide how best to represent the
|
||||
* <code>selectionValues</code>.
|
||||
* Normally, it's a {@link JComboBox} if less than 20 <code>selectionValues</code>,
|
||||
* {@link JList} if equal or greater than 20 <code>selectionValues</code>, or
|
||||
* {@link JTextField} if null <code>selectionValues</code>.
|
||||
*/
|
||||
public static Object showListInputDialog(Component parentComponent, Object message, String title, int messageType,
|
||||
Icon icon, Object[] selectionValues, Object initialSelectionValue)
|
||||
throws HeadlessException {
|
||||
JOptionPane pane = new JOptionPane();
|
||||
JList list = getSingleSelectionList(pane, selectionValues, initialSelectionValue);
|
||||
JScrollPane sp = new JScrollPane(list);
|
||||
list.ensureIndexIsVisible(list.getSelectedIndex());
|
||||
|
||||
pane.setMessage(new Object[] { message, sp});
|
||||
pane.setMessageType(JOptionPane.QUESTION_MESSAGE);
|
||||
pane.setOptionType(JOptionPane.OK_CANCEL_OPTION);
|
||||
|
||||
JDialog dialog = pane.createDialog(parentComponent, title);
|
||||
|
||||
dialog.setVisible(true);
|
||||
dialog.dispose();
|
||||
|
||||
Object value = pane.getInputValue();
|
||||
|
||||
// this choice is either JOptionPane.OK_OPTION or JOptionPane.CANCEL_OPTION,
|
||||
// if null, meaning the user closed the window without choosing anything
|
||||
Object choice = pane.getValue();
|
||||
|
||||
if (choice == null || ((Integer)choice).intValue() == JOptionPane.CANCEL_OPTION) {
|
||||
return initialSelectionValue;
|
||||
}
|
||||
|
||||
if (value == JOptionPane.UNINITIALIZED_VALUE) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method and only used by <code>showListInputDialog</code> method.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static JList getSingleSelectionList(final JOptionPane optionPane, Object[] values, Object initialValue) {
|
||||
JList list = new JList(values);
|
||||
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
if(initialValue != null) {
|
||||
list.setSelectedValue(initialValue, true);
|
||||
}
|
||||
|
||||
MouseListener mouseListener = new MouseAdapter() {
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
JList list = (JList)e.getSource();
|
||||
int index = list.locationToIndex(e.getPoint());
|
||||
optionPane.setInputValue(list.getModel().getElementAt(index));
|
||||
|
||||
if (isDoubleClick(e)) {
|
||||
// close the pane once the user selects a value by double-clicking
|
||||
optionPane.setValue(JOptionPane.CLOSED_OPTION);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
list.addMouseListener(mouseListener);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link ImageIcon} for the specified full file path or
|
||||
* a file in common/resources.
|
||||
*
|
||||
* @param fileName The name or the full path of the image file.
|
||||
*
|
||||
* @return an instance of {@link ImageIcon} for the specified image,
|
||||
* null if the image file can't be found.
|
||||
*/
|
||||
public static ImageIcon createImageIcon(String fileName) {
|
||||
ImageIcon imgIcon = null;
|
||||
|
||||
// if the fileName is a full path
|
||||
if (fileName.indexOf(System.getProperty("file.separator")) != -1) {
|
||||
imgIcon = new ImageIcon(fileName);
|
||||
} else {
|
||||
// if only a file name specified, try to find it at common resources folder
|
||||
URL imgURL = TrickApplication.class.getResource("resources" + System.getProperty("file.separator") + fileName);
|
||||
if (imgURL != null) {
|
||||
imgIcon = new ImageIcon(imgURL);
|
||||
}
|
||||
}
|
||||
|
||||
if (imgIcon == null) {
|
||||
System.err.println("Couldn't find file: " + fileName);
|
||||
}
|
||||
|
||||
return imgIcon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link InputStream} for the specified file path or a file
|
||||
* in common/resources.
|
||||
*
|
||||
* @param fileName The name of a file in common/resources or a full file path.
|
||||
*
|
||||
* @return an instance of {@link InputStream} for the specified file,
|
||||
* null if the specified file can't be found.
|
||||
*/
|
||||
public static InputStream getInputStreamForFile(String fileName) {
|
||||
try {
|
||||
InputStream ins = null;
|
||||
// if the fileName is a full path
|
||||
if (fileName.indexOf(System.getProperty("file.separator")) != -1) {
|
||||
ins = new FileInputStream(fileName);
|
||||
} else {
|
||||
// if only a file name, then find it at common resources area
|
||||
ins = TrickApplication.class.getResourceAsStream("resources" + System.getProperty("file.separator") + fileName);
|
||||
}
|
||||
return ins;
|
||||
} catch (NullPointerException npe) {
|
||||
return null;
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates titled panel with content view plus search capability if applicable.
|
||||
*
|
||||
* @param title The title of the panel.
|
||||
* @param contentComponent The searchable component for the content.
|
||||
* @param findPanel The panel for find/search function.
|
||||
* If <code>null</code>, then only a titled panel is created.
|
||||
*
|
||||
* @return A titled panel with find bar for search feature.
|
||||
*/
|
||||
public static JPanel createSearchableTitledPanel(String title,
|
||||
JComponent contentComponent,
|
||||
JPanel findPanel) {
|
||||
JXTitledPanel titledPanel = new JXTitledPanel();
|
||||
titledPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(""));
|
||||
titledPanel.setTitle(title);
|
||||
titledPanel.add(new JScrollPane(contentComponent), BorderLayout.CENTER);
|
||||
titledPanel.setMinimumSize(new Dimension(300, 250));
|
||||
if (findPanel != null) {
|
||||
titledPanel.add(findPanel, BorderLayout.SOUTH);
|
||||
}
|
||||
return titledPanel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JTextPane that displays detail information and the information
|
||||
* is StyledDocument.
|
||||
*
|
||||
* @return a JTextPane that has different document styles.
|
||||
*/
|
||||
public static JTextPane createReadingTextPane() {
|
||||
JTextPane textPane = new JTextPane();
|
||||
textPane.setEditable(false);
|
||||
textPane.setPreferredSize(new Dimension(400, 200));
|
||||
StyledDocument document = textPane.getStyledDocument();
|
||||
addStylesToDocument(document);
|
||||
return textPane;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds styles to a StyledDocument as specified doc.
|
||||
*
|
||||
* @param doc a StyledDocument to add styles to.
|
||||
*/
|
||||
private static void addStylesToDocument(StyledDocument doc) {
|
||||
//Initialize some styles.
|
||||
Style def = StyleContext.getDefaultStyleContext().getStyle(StyleContext.DEFAULT_STYLE);
|
||||
|
||||
Style regular = doc.addStyle(DOCUMENT_STYLE_REGULAR, def);
|
||||
StyleConstants.setFontFamily(def, "SansSerif");
|
||||
|
||||
|
||||
Style s = doc.addStyle(DOCUMENT_STYLE_REGULAR_ITALIC, regular);
|
||||
StyleConstants.setItalic(s, true);
|
||||
|
||||
s = doc.addStyle(DOCUMENT_STYLE_REGULAR_BOLD_BLUE, regular);
|
||||
StyleConstants.setBold(s, true);
|
||||
StyleConstants.setForeground(s, Color.blue);
|
||||
|
||||
s = doc.addStyle(DOCUMENT_STYLE_REGULAR_SMALL, regular);
|
||||
StyleConstants.setFontSize(s, 10);
|
||||
|
||||
s = doc.addStyle(DOCUMENT_STYLE_REGULAR_LARGE_BOLD_BLUE_SHADE, regular);
|
||||
StyleConstants.setFontSize(s, 14);
|
||||
StyleConstants.setBold(s, true);
|
||||
StyleConstants.setBackground(s, Color.lightGray);
|
||||
StyleConstants.setForeground(s, Color.blue);
|
||||
|
||||
s = doc.addStyle(DOCUMENT_STYLE_REGULAR_LARGE_BOLD_BLUE, regular);
|
||||
StyleConstants.setFontSize(s, 14);
|
||||
StyleConstants.setBold(s, true);
|
||||
StyleConstants.setForeground(s, Color.blue);
|
||||
|
||||
s = doc.addStyle(DOCUMENT_STYLE_REGULAR_BOLD_BLUE_SHADE, regular);
|
||||
StyleConstants.setBold(s, true);
|
||||
StyleConstants.setBackground(s, Color.lightGray);
|
||||
StyleConstants.setForeground(s, Color.blue);
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,139 @@
|
||||
/**
|
||||
* $Id: CommonTreeNode.java 2243 2012-03-14 21:15:29Z hchen3 $
|
||||
*
|
||||
*/
|
||||
|
||||
//========================================
|
||||
// Package
|
||||
//========================================
|
||||
package trick.common.ui.components;
|
||||
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.TreeNode;
|
||||
|
||||
|
||||
/**
|
||||
* This class that extends {@link DefaultMutableTreeNode}, which
|
||||
* has needed information associated with tree in Trick GUI.
|
||||
*
|
||||
* @author Hong Chen
|
||||
* @since Trick 7
|
||||
*/
|
||||
public class CommonTreeNode extends DefaultMutableTreeNode {
|
||||
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
public static final int NORMAL_NODE = 0;
|
||||
public static final int X_NODE = 1;
|
||||
public static final int Y_NODE = 2;
|
||||
public static final int Z_NODE = 3;
|
||||
public static final int PLOT_NODE = 4;
|
||||
public static final int CURVE_NODE = 5;
|
||||
public static final int VARCASE_NODE = 6;
|
||||
public static final int PAGE_NODE = 7;
|
||||
public static final int TABLE_NODE = 8;
|
||||
public static final int COLUMN_NODE = 9;
|
||||
public static final int VAR_NODE = 10;
|
||||
public static final int PROGRAM_NODE = 11;
|
||||
public static final int INPUT_NODE = 12;
|
||||
public static final int OUTPUT_NODE = 13;
|
||||
public static final int PLOTS_NODE = 14;
|
||||
public static final int TABLES_NODE = 15;
|
||||
public static final int PROGRAMS_NODE = 16;
|
||||
public static final int INPUT_VAR_NODE = 17;
|
||||
public static final int OUTPUT_VAR_NODE = 18;
|
||||
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
|
||||
|
||||
//========================================
|
||||
// Private Data
|
||||
//========================================
|
||||
private static final long serialVersionUID = 7211981327477779671L;
|
||||
|
||||
// By default, this tree node is a normal node.
|
||||
private int nodeType = 0;
|
||||
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public CommonTreeNode()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that takes argument {@link Object} for the tree node.
|
||||
*
|
||||
* @param obj An instance of {@link Object} that is used for the tree node.
|
||||
*/
|
||||
public CommonTreeNode(Object obj) {
|
||||
super(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that takes argument {@link Object} for the tree node.
|
||||
*
|
||||
* @param obj An instance of {@link Object} that is used for the tree node.
|
||||
* @param type The type of the node.
|
||||
*/
|
||||
public CommonTreeNode(Object obj, int type) {
|
||||
super(obj);
|
||||
nodeType = type;
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Set/Get methods
|
||||
//========================================
|
||||
/**
|
||||
* Sets the type for this node.
|
||||
*
|
||||
* @param type The type of the node.
|
||||
*/
|
||||
public void setNodeType(int type) {
|
||||
nodeType = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this node type.
|
||||
*
|
||||
* @return The type of the node.
|
||||
*/
|
||||
public int getNodeType() {
|
||||
return nodeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the path for this tree node in String format. Each tree node in
|
||||
* the path is separated by ".".
|
||||
*
|
||||
* @return a String that has all tree node names separated by ".".
|
||||
*
|
||||
*/
|
||||
public String getPathString() {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
TreeNode[] path = getPath();
|
||||
|
||||
if (path != null && path.length > 0) {
|
||||
for ( int j = 1; j < path.length; j ++ ) {
|
||||
buf.append(path[j].toString());
|
||||
if (j < path.length - 1) {
|
||||
buf.append(".");
|
||||
}
|
||||
}
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
}
|
@ -0,0 +1,268 @@
|
||||
/**
|
||||
* $Id: DoubleJSlider.java 1662 2011-05-31 13:15:17Z lin $
|
||||
*
|
||||
*/
|
||||
|
||||
//========================================
|
||||
// Package
|
||||
//========================================
|
||||
package trick.common.ui.components;
|
||||
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.event.MouseMotionListener;
|
||||
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.JSlider;
|
||||
import javax.swing.border.EtchedBorder;
|
||||
import javax.swing.border.TitledBorder;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import javax.swing.plaf.basic.BasicSliderUI;
|
||||
|
||||
/**
|
||||
* An extension of JSlider that uses double for its values.
|
||||
*
|
||||
* @since Trick 10
|
||||
*/
|
||||
public class DoubleJSlider extends JSlider implements ChangeListener{
|
||||
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
//public final static double DOUBLE_FACTOR = 100.0;
|
||||
public static double DOUBLE_FACTOR ;
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
|
||||
|
||||
//========================================
|
||||
// Private Data
|
||||
//========================================
|
||||
private static final long serialVersionUID = 8104332457463381081L;
|
||||
|
||||
/** This border show the current value of the slider as its title. */
|
||||
private TitledBorder border = new TitledBorder(new EtchedBorder());
|
||||
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
/**
|
||||
* Default constructor - initializes with 0.0,100.0,50.0
|
||||
*/
|
||||
public DoubleJSlider(){
|
||||
super();
|
||||
DOUBLE_FACTOR = 100.0 ;
|
||||
setDoubleMinimum(0.0);
|
||||
setDoubleMaximum(100.0);
|
||||
setDoubleValue(50.0);
|
||||
addChangeListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor with specified minimum, maximum and init value.
|
||||
*
|
||||
* @param min The minimum double value for the slider.
|
||||
* @param max The maximum double value for the slider.
|
||||
* @param val The init value for the slider.
|
||||
*/
|
||||
public DoubleJSlider(double min, double max, double val) {
|
||||
super();
|
||||
DOUBLE_FACTOR = 100.0 ;
|
||||
setUI(new DoubleJSliderUI(this));
|
||||
setBorder(border);
|
||||
setDoubleMinimum(min);
|
||||
setDoubleMaximum(max);
|
||||
setDoubleValue(val);
|
||||
setLabel("Current Value: " + val);
|
||||
addChangeListener(this);
|
||||
}
|
||||
|
||||
public DoubleJSlider(double min, double max, double val, double factor ) {
|
||||
super();
|
||||
DOUBLE_FACTOR = factor ;
|
||||
setUI(new DoubleJSliderUI(this));
|
||||
setBorder(border);
|
||||
setDoubleMinimum(min);
|
||||
setDoubleMaximum(max);
|
||||
setDoubleValue(val);
|
||||
setLabel("Current Value: " + val);
|
||||
addChangeListener(this);
|
||||
}
|
||||
/**
|
||||
* Sets the title for the slider.
|
||||
*
|
||||
* @param s The specified title for the slider.
|
||||
*/
|
||||
public void setLabel(String s) {
|
||||
border.setTitle(s);
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Set/Get methods
|
||||
//========================================
|
||||
/**
|
||||
* Returns the maximum value for the slider in double.
|
||||
*
|
||||
* @return The maximum value for the slider in double.
|
||||
*/
|
||||
public double getDoubleMaximum() {
|
||||
return( getMaximum()/DOUBLE_FACTOR );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minimum value for the slider in double.
|
||||
*
|
||||
* @return The minimum value for the slider in double.
|
||||
*/
|
||||
public double getDoubleMinimum() {
|
||||
return( getMinimum()/DOUBLE_FACTOR );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current value for the slider in double.
|
||||
*
|
||||
* @return The current value of the slider in double.
|
||||
*/
|
||||
public double getDoubleValue() {
|
||||
return( getValue()/DOUBLE_FACTOR );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets maximum value for the slider in double.
|
||||
*
|
||||
* @param max The value which needs to be set as maximum value for the slider.
|
||||
*/
|
||||
public void setDoubleMaximum(double max) {
|
||||
setMaximum((int)(max*DOUBLE_FACTOR));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets minimum value for the slider in double.
|
||||
*
|
||||
* @param min The value which needs to be set as minimum value for the slider.
|
||||
*/
|
||||
public void setDoubleMinimum(double min) {
|
||||
setMinimum((int)(min*DOUBLE_FACTOR));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets current value for the slider in double.
|
||||
*
|
||||
* @param val The value which needs to be set as current value for the slider.
|
||||
*/
|
||||
public void setDoubleValue(double val) {
|
||||
setValue((int)(val*DOUBLE_FACTOR));
|
||||
setToolTipText(Double.toString(val));
|
||||
}
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
/**
|
||||
* Required by ChangeListener.
|
||||
*/
|
||||
public void stateChanged(ChangeEvent e) {
|
||||
DoubleJSlider slider = (DoubleJSlider)e.getSource();
|
||||
if (!slider.getValueIsAdjusting()) {
|
||||
setToolTipText(Double.toString(slider.getDoubleValue()));
|
||||
slider.setLabel("Current Value: "+slider.getDoubleValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//========================================
|
||||
// Inner classes
|
||||
//========================================
|
||||
/**
|
||||
* The class for customized slider UI.
|
||||
*/
|
||||
class DoubleJSliderUI extends BasicSliderUI implements MouseMotionListener, MouseListener {
|
||||
final JPopupMenu pop = new JPopupMenu();
|
||||
JMenuItem item = new JMenuItem();
|
||||
|
||||
DoubleJSlider slider;
|
||||
|
||||
/**
|
||||
* Constructor with specifed slider.
|
||||
*
|
||||
* @param slider The specified {@link DoubleJSlider}.
|
||||
*/
|
||||
public DoubleJSliderUI(DoubleJSlider slider)
|
||||
{
|
||||
super(slider);
|
||||
slider.addMouseMotionListener(this);
|
||||
slider.addMouseListener(this);
|
||||
this.slider = slider;
|
||||
pop.add(item);
|
||||
pop.setDoubleBuffered(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the tip text while mouse moving.
|
||||
*
|
||||
* @param me The mouse event of slider moving.
|
||||
*/
|
||||
public void showToolTip(MouseEvent me) {
|
||||
item.setText(""+slider.getDoubleValue());
|
||||
|
||||
//limit the tooltip location relative to the slider
|
||||
Rectangle b = me.getComponent().getBounds();
|
||||
int x = me.getX();
|
||||
x = (x > (b.x + b.width / 2) ? (b.x + b.width / 2) : (x < (b.x - b.width / 2) ? (b.x - b.width / 2) : x));
|
||||
|
||||
pop.show( me.getComponent(), x - 5, -5 );
|
||||
|
||||
item.setArmed( false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Required by {@link MouseMotionListener}.
|
||||
*/
|
||||
public void mouseDragged(MouseEvent me) {
|
||||
showToolTip(me);
|
||||
}
|
||||
/**
|
||||
* Required by {@link MouseMotionListener}.
|
||||
*/
|
||||
public void mouseMoved(MouseEvent me) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Required by {@MouseListener}.
|
||||
*/
|
||||
public void mousePressed(MouseEvent me) {
|
||||
showToolTip(me);
|
||||
}
|
||||
/**
|
||||
* Required by {@MouseListener}.
|
||||
*/
|
||||
public void mouseClicked(MouseEvent me) {
|
||||
}
|
||||
/**
|
||||
* Required by {@MouseListener}.
|
||||
*/
|
||||
public void mouseReleased(MouseEvent me) {
|
||||
pop.setVisible(false);
|
||||
}
|
||||
/**
|
||||
* Required by {@MouseListener}.
|
||||
*/
|
||||
public void mouseEntered(MouseEvent me) {
|
||||
}
|
||||
/**
|
||||
* Required by {@MouseListener}.
|
||||
*/
|
||||
public void mouseExited(MouseEvent me) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,323 @@
|
||||
/*
|
||||
* $Id: FontChooser.java 2559 2012-09-05 16:25:43Z hchen3 $
|
||||
*
|
||||
*/
|
||||
|
||||
//========================================
|
||||
// Package
|
||||
//========================================
|
||||
package trick.common.ui.components;
|
||||
|
||||
//========================================
|
||||
// Imports
|
||||
//========================================
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.Frame;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.ListSelectionModel;
|
||||
import javax.swing.border.EtchedBorder;
|
||||
import javax.swing.border.LineBorder;
|
||||
import javax.swing.border.TitledBorder;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
|
||||
/**
|
||||
* Defines font chooser dialog.
|
||||
*
|
||||
* @author Hong Chen
|
||||
* @since Trick 10
|
||||
*/
|
||||
public class FontChooser extends JDialog implements ActionListener, ListSelectionListener {
|
||||
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
|
||||
|
||||
//========================================
|
||||
// Private Data
|
||||
//========================================
|
||||
|
||||
private static final long serialVersionUID = 5290768624262666696L;
|
||||
|
||||
private final static String OK_OPTION = "Ok";
|
||||
private final static String CANCEL_OPTION = "Cancel";
|
||||
private final static String BOLD_OPTION = "Bold";
|
||||
private final static String ITALIC_OPTION = "Italic";
|
||||
|
||||
private String[] fonts;
|
||||
private Integer[] sizes;
|
||||
private JList fontList;
|
||||
private JList sizeList;
|
||||
private JCheckBox boldBox;
|
||||
private JCheckBox italicBox;
|
||||
|
||||
private Font currentFont;
|
||||
|
||||
private JButton okButton;
|
||||
private JButton cancelButton;
|
||||
|
||||
private JLabel sampleLabel;
|
||||
|
||||
private int closeOption = JOptionPane.CLOSED_OPTION;
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
/**
|
||||
* Custructor with specified owner.
|
||||
*/
|
||||
private FontChooser(Frame parent, String title, Font font) {
|
||||
super(parent, title, true);
|
||||
fonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
|
||||
// the size list was obtained from tcl code, do we or can we support more?
|
||||
sizes = new Integer[]{4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24};
|
||||
buildGUI(parent);
|
||||
setLocationRelativeTo(parent);
|
||||
setCurrentFont(font);
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Set/Get methods
|
||||
//========================================
|
||||
/**
|
||||
* Sets the font for the dialog.
|
||||
*
|
||||
* @param font An instance of {@link Font} that needs to be set for the dialog.
|
||||
*/
|
||||
public void setCurrentFont(Font font) {
|
||||
currentFont = font;
|
||||
if (font != null) {
|
||||
fontList.setSelectedValue(font.getName(), true);
|
||||
sizeList.setSelectedValue(new Integer(font.getSize()), true);
|
||||
if (font.getStyle() == Font.PLAIN) {
|
||||
boldBox.setSelected(false);
|
||||
italicBox.setSelected(false);
|
||||
} else {
|
||||
if (font.getStyle() == (Font.BOLD | Font.ITALIC)) {
|
||||
boldBox.setSelected(true);
|
||||
italicBox.setSelected(true);
|
||||
} else {
|
||||
if (font.getStyle() == Font.BOLD) {
|
||||
boldBox.setSelected(true);
|
||||
} else if (font.getStyle() == Font.ITALIC) {
|
||||
italicBox.setSelected(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
sampleLabel.setFont(font);
|
||||
sampleLabel.setText(getCurrentFontText());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current font of the dialog.
|
||||
*
|
||||
* @return An instance of {@link Font}. <code>null</code> is returned if Ok is not selected.
|
||||
*/
|
||||
public Font getCurrentFont() {
|
||||
if (closeOption == JOptionPane.CLOSED_OPTION || closeOption == JOptionPane.CANCEL_OPTION) {
|
||||
return null;
|
||||
}
|
||||
return currentFont;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the currently selected font in text.
|
||||
*
|
||||
* @return The currently selected font in preferred text format.
|
||||
*/
|
||||
public String getCurrentFontText() {
|
||||
return currentFont.getFamily() + ":" + currentFont.getStyle() + ":" + currentFont.getSize();
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
/**
|
||||
* Handles clicks on the buttons or check box selections.
|
||||
*
|
||||
* Required by {@link ActionListener}.
|
||||
*/
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (OK_OPTION.equals(e.getActionCommand())) {
|
||||
updateFont();
|
||||
closeOption = JOptionPane.OK_OPTION;
|
||||
setVisible(false);
|
||||
dispose();
|
||||
} else if (CANCEL_OPTION.equals(e.getActionCommand())) {
|
||||
closeOption = JOptionPane.CANCEL_OPTION;
|
||||
setVisible(false);
|
||||
dispose();
|
||||
} else {
|
||||
updateFont();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles selections on the list.
|
||||
*
|
||||
* Required by {@link ListSelectionListener}.
|
||||
*/
|
||||
public void valueChanged(ListSelectionEvent e) {
|
||||
updateFont();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set up and show the font chooser dialog.
|
||||
*
|
||||
* @param parent The parent component for the dialog.
|
||||
* @param title The title of the dialog.
|
||||
* @param font The initial font.
|
||||
*/
|
||||
public static Font showDialog(Component parent, String title, Font font) {
|
||||
Frame frame = JOptionPane.getFrameForComponent(parent);
|
||||
FontChooser dialog = new FontChooser(frame, title, font);
|
||||
dialog.setVisible(true);
|
||||
return dialog.getCurrentFont();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for updating sample lable font for the purpose of showing
|
||||
* the selected font.
|
||||
*/
|
||||
private void updateFont() {
|
||||
// if during gui set up, don't need to update
|
||||
if (fontList == null || fontList.getSelectedValue() == null ||
|
||||
sizeList == null || sizeList.getSelectedValue() == null ||
|
||||
boldBox == null || italicBox == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int currentStyle = Font.PLAIN;
|
||||
if (boldBox.isSelected()) {
|
||||
currentStyle += Font.BOLD;
|
||||
}
|
||||
if (italicBox.isSelected()) {
|
||||
currentStyle += Font.ITALIC;
|
||||
}
|
||||
|
||||
currentFont = new Font(fontList.getSelectedValue().toString(), currentStyle, ((Integer)sizeList.getSelectedValue()).intValue());
|
||||
sampleLabel.setFont(currentFont);
|
||||
sampleLabel.setText(getCurrentFontText());
|
||||
sampleLabel.repaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for building the gui.
|
||||
*
|
||||
*/
|
||||
//for Java 7, the type of elements of JComboBox needs to be specified to avoid the warning and it's not supported in Java 6
|
||||
@SuppressWarnings("unchecked")
|
||||
private void buildGUI(Frame parent) {
|
||||
JPanel selectionPanel = new JPanel();
|
||||
fontList = new JList(fonts);
|
||||
fontList.getSelectionModel().addListSelectionListener(this);
|
||||
sizeList = new JList(sizes);
|
||||
sizeList.getSelectionModel().addListSelectionListener(this);
|
||||
JPanel fontPanel = getListPanel("Font", fontList);
|
||||
selectionPanel.add(fontPanel);
|
||||
JPanel sizePanel = getListPanel("Size", sizeList);
|
||||
selectionPanel.add(sizePanel);
|
||||
JPanel stylePanel = new JPanel();
|
||||
stylePanel.setLayout(new BoxLayout(stylePanel, BoxLayout.Y_AXIS));
|
||||
JLabel styleLabel = new JLabel("Style");
|
||||
boldBox = new JCheckBox(BOLD_OPTION);
|
||||
boldBox.addActionListener(this);
|
||||
italicBox = new JCheckBox(ITALIC_OPTION);
|
||||
italicBox.addActionListener(this);
|
||||
stylePanel.add(styleLabel);
|
||||
stylePanel.add(Box.createRigidArea(new Dimension(0,5)));
|
||||
stylePanel.add(boldBox);
|
||||
stylePanel.add(italicBox);
|
||||
stylePanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
|
||||
stylePanel.setPreferredSize(new Dimension(stylePanel.getPreferredSize().width, fontPanel.getPreferredSize().height));
|
||||
selectionPanel.add(stylePanel);
|
||||
selectionPanel.setMinimumSize(selectionPanel.getPreferredSize());
|
||||
|
||||
JPanel samplePanel = new JPanel(new BorderLayout());
|
||||
samplePanel.setBorder(new TitledBorder(new EtchedBorder(), "Preview"));
|
||||
|
||||
sampleLabel = new JLabel("", JLabel.CENTER);
|
||||
sampleLabel.setBackground(Color.white);
|
||||
sampleLabel.setBorder(new LineBorder(Color.black));
|
||||
sampleLabel.setOpaque(true);
|
||||
sampleLabel.setPreferredSize(new Dimension(120, 60));
|
||||
|
||||
samplePanel.add(sampleLabel, BorderLayout.CENTER);
|
||||
|
||||
JPanel buttonPanel = new JPanel();
|
||||
okButton = new JButton(OK_OPTION);
|
||||
okButton.addActionListener(this);
|
||||
cancelButton = new JButton(CANCEL_OPTION);
|
||||
cancelButton.addActionListener(this);
|
||||
buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
|
||||
buttonPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
|
||||
buttonPanel.add(Box.createHorizontalStrut(30));
|
||||
buttonPanel.add(okButton);
|
||||
buttonPanel.add(Box.createRigidArea(new Dimension(10, 0)));
|
||||
buttonPanel.add(cancelButton);
|
||||
|
||||
getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
|
||||
getContentPane().add(selectionPanel);
|
||||
getContentPane().add(Box.createVerticalStrut(15));
|
||||
getContentPane().add(samplePanel);
|
||||
getContentPane().add(buttonPanel);
|
||||
getContentPane().add(Box.createVerticalStrut(5));
|
||||
|
||||
pack();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a panel that contains a list and associated title.
|
||||
*
|
||||
* @param labelText The title label for the list.
|
||||
* @param list An instance of {@link JList}.
|
||||
*/
|
||||
private JPanel getListPanel(String labelText, JList list) {
|
||||
JPanel ret = new JPanel();
|
||||
list.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
|
||||
JScrollPane listScroller = new JScrollPane(list);
|
||||
listScroller.setAlignmentX(LEFT_ALIGNMENT);
|
||||
|
||||
JLabel label = new JLabel(labelText);
|
||||
ret.setLayout(new BoxLayout(ret, BoxLayout.Y_AXIS));
|
||||
label.setLabelFor(list);
|
||||
ret.add(label);
|
||||
ret.add(Box.createRigidArea(new Dimension(0,5)));
|
||||
ret.add(listScroller);
|
||||
ret.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
//========================================
|
||||
// Inner Classes
|
||||
//========================================
|
||||
|
||||
}
|
@ -0,0 +1,193 @@
|
||||
/**
|
||||
* $Id: NumberTextField.java 1488 2011-04-07 17:37:19Z hchen $
|
||||
*
|
||||
*/
|
||||
|
||||
//========================================
|
||||
// Package
|
||||
//========================================
|
||||
package trick.common.ui.components;
|
||||
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.text.AttributeSet;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.Document;
|
||||
import javax.swing.text.PlainDocument;
|
||||
|
||||
|
||||
/**
|
||||
* An extension of {@link JTextField} that only accepts numbers.
|
||||
*
|
||||
*
|
||||
* @since Trick 10
|
||||
*/
|
||||
public class NumberTextField extends JTextField {
|
||||
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
|
||||
|
||||
//========================================
|
||||
// Private Data
|
||||
//========================================
|
||||
private static final long serialVersionUID = -9181145899991928113L;
|
||||
|
||||
// By default, this text field is good for double unless intOnly is set to be true.
|
||||
// TODO: should support all Number types?
|
||||
private boolean intOnly = false;
|
||||
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public NumberTextField() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new empty text field only for integers.
|
||||
*
|
||||
* @param isIntOnly Whether this text field is only for integers.
|
||||
*/
|
||||
public NumberTextField(boolean isIntOnly) {
|
||||
this();
|
||||
intOnly = isIntOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new empty text field with the specified number of columns.
|
||||
*
|
||||
* @param columns The number of columns to use to calculate the preferred width.
|
||||
*/
|
||||
public NumberTextField(int columns) {
|
||||
super(columns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new text field with the specified text. If the text represents
|
||||
* an invalid double, only set text columns to a default number 5.
|
||||
*
|
||||
* @param text The text that represents a valid number to be displayed.
|
||||
*/
|
||||
public NumberTextField(String text) {
|
||||
super(text);
|
||||
if (getValue() == null) {
|
||||
setColumns(5);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new text field with the specified text. If the text represents
|
||||
* an invalid double, only set text clolumns to the specified number of columns.
|
||||
*
|
||||
* @param text The text that represents a valid number to be displayed.
|
||||
* @param columns The number of columns to use to calculate the preferred width.
|
||||
*/
|
||||
public NumberTextField(String text, int columns) {
|
||||
super(text, columns);
|
||||
}
|
||||
|
||||
|
||||
//========================================
|
||||
// Set/Get methods
|
||||
//========================================
|
||||
/**
|
||||
* Limits the text field only for integers.
|
||||
*/
|
||||
public void setIntOnly(boolean intOnly) {
|
||||
this.intOnly = intOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets value of the text field.
|
||||
*
|
||||
* @return the {@link Number} of this text field if it's valid.
|
||||
*/
|
||||
public Number getValue() {
|
||||
try {
|
||||
if (intOnly) {
|
||||
return Integer.valueOf(getText());
|
||||
}
|
||||
return Double.valueOf(getText());
|
||||
} catch (NumberFormatException e) {
|
||||
return null;
|
||||
} catch (NullPointerException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
/**
|
||||
* Uses the number document for this number text field.
|
||||
*/
|
||||
@Override
|
||||
protected Document createDefaultModel() {
|
||||
return new NumberTextDocument();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if any input is valid based on double data type.
|
||||
*
|
||||
* @return <code>true</code> if any input can be part of a number,
|
||||
* <code>false</code> otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
try {
|
||||
if (intOnly) {
|
||||
Integer.parseInt(getText());
|
||||
} else {
|
||||
Double.parseDouble(getText());
|
||||
}
|
||||
return true;
|
||||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
} catch (NullPointerException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//========================================
|
||||
// Inner classes
|
||||
//========================================
|
||||
/**
|
||||
* Class for valid number document.
|
||||
*/
|
||||
class NumberTextDocument extends PlainDocument {
|
||||
|
||||
|
||||
private static final long serialVersionUID = -6195020045069585237L;
|
||||
|
||||
@Override
|
||||
public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
|
||||
if (str == null) {
|
||||
return;
|
||||
}
|
||||
String oldString = getText(0, getLength());
|
||||
String newString = oldString.substring(0, offs) + str + oldString.substring(offs);
|
||||
try {
|
||||
if (intOnly) {
|
||||
Integer.parseInt(newString + "0");
|
||||
} else {
|
||||
Double.parseDouble(newString + "0");
|
||||
}
|
||||
super.insertString(offs, str, a);
|
||||
} catch (NumberFormatException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,192 @@
|
||||
/**
|
||||
* $Id: AnimationPlayer.java 1641 2011-05-24 19:25:12Z hchen $
|
||||
*
|
||||
*/
|
||||
|
||||
//========================================
|
||||
// Package
|
||||
//========================================
|
||||
package trick.common.ui.panels;
|
||||
|
||||
//========================================
|
||||
// Imports
|
||||
//========================================
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Image;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingWorker;
|
||||
|
||||
import trick.common.ui.UIUtils;
|
||||
|
||||
/**
|
||||
* An extension of JPanel that displays an animation image with the control capability.
|
||||
*
|
||||
* @since Trick 10
|
||||
*/
|
||||
public class AnimationPlayer extends JPanel {
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
|
||||
//========================================
|
||||
// Private Data
|
||||
//========================================
|
||||
private boolean paused;
|
||||
private boolean finished;
|
||||
private String animationFile;
|
||||
private JLabel animationLabel;
|
||||
private PlayAnimationTask animationTask;
|
||||
|
||||
|
||||
private static final long serialVersionUID = 3705588596523798631L;
|
||||
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public AnimationPlayer(String fileName) {
|
||||
animationFile = fileName;
|
||||
buildGUI();
|
||||
if (animationTask == null) {
|
||||
animationTask = new PlayAnimationTask();
|
||||
}
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Set/Get methods
|
||||
//========================================
|
||||
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
/**
|
||||
* Starts the animation task. This method has to be called
|
||||
* in order for the animation to be played.
|
||||
*/
|
||||
public void start() {
|
||||
if (animationTask == null) {
|
||||
animationTask = new PlayAnimationTask();
|
||||
}
|
||||
animationTask.execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses the animation play.
|
||||
*/
|
||||
public void pause() {
|
||||
paused = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes the animation play.
|
||||
*/
|
||||
public void resume() {
|
||||
paused = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the animation play.
|
||||
*/
|
||||
public void stop() {
|
||||
finished = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the player GUI.
|
||||
*/
|
||||
private void buildGUI() {
|
||||
setLayout(new BorderLayout());
|
||||
animationLabel = new JLabel();
|
||||
ImageIcon icon = UIUtils.createImageIcon(animationFile);
|
||||
// set proper initial size for the label
|
||||
if (icon != null) {
|
||||
animationLabel.setPreferredSize(new Dimension(icon.getIconWidth(), icon.getIconHeight()));
|
||||
}
|
||||
add(animationLabel, BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Inner Class
|
||||
//========================================
|
||||
/**
|
||||
* Inner class for playing an animation image.
|
||||
*/
|
||||
private class PlayAnimationTask extends SwingWorker<Void, Void> {
|
||||
ImageInputStream stream;
|
||||
|
||||
@Override
|
||||
public Void doInBackground() {
|
||||
|
||||
if (animationFile == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
InputStream input = UIUtils.getInputStreamForFile(animationFile);
|
||||
stream = ImageIO.createImageInputStream(input);
|
||||
Iterator readers = ImageIO.getImageReaders(stream);
|
||||
if (!readers.hasNext()) {
|
||||
throw new RuntimeException("no image reader found");
|
||||
}
|
||||
ImageReader reader = (ImageReader) readers.next();
|
||||
reader.setInput(stream); // don't omit this line!
|
||||
int n = reader.getNumImages(true); // don't use false!
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
BufferedImage image = reader.read(i);
|
||||
Image img = image;
|
||||
animationLabel.setIcon(new ImageIcon(img));
|
||||
do {
|
||||
try {
|
||||
Thread.sleep(150);
|
||||
} catch (InterruptedException ie) {
|
||||
}
|
||||
} while (paused);
|
||||
|
||||
if (finished) {
|
||||
break;
|
||||
} else {
|
||||
// rewind
|
||||
if (i == n-1) {
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (IOException ioe) {
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void done() {
|
||||
if (stream != null) {
|
||||
try {
|
||||
stream.close();
|
||||
} catch (IOException ioe) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,338 @@
|
||||
package trick.common.ui.panels;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.Insets;
|
||||
|
||||
import javax.swing.Action;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
|
||||
import org.jdesktop.swingx.JXButton;
|
||||
import org.jdesktop.swingx.JXLabel;
|
||||
import org.jdesktop.swingx.JXStatusBar;
|
||||
import org.jdesktop.swingx.plaf.basic.BasicStatusBarUI;
|
||||
|
||||
import trick.sniffer.SimulationInformation;
|
||||
import trick.sniffer.SimulationListener;
|
||||
import trick.sniffer.SimulationSniffer;
|
||||
|
||||
/**
|
||||
* provides a common GUI element for connecting to the Variable Server on a given host and port
|
||||
*
|
||||
* @author Derek Bankieris
|
||||
*/
|
||||
public class ConnectionStatusBar extends JXStatusBar {
|
||||
|
||||
/** label describing the connection state */
|
||||
protected JXLabel stateLabel = new JXLabel() {{
|
||||
setFont(getFont().deriveFont(Font.BOLD));
|
||||
}};
|
||||
|
||||
/** combo box which presents all the available sims on the network */
|
||||
@SuppressWarnings("unchecked")
|
||||
protected JComboBox simulationComboBox = new JComboBox() {
|
||||
|
||||
{
|
||||
setEditable(true);
|
||||
setSelectedItem(new SimulationInformation("localhost", "0"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addItem(Object object) {
|
||||
SimulationInformation simulationInformation = (SimulationInformation)object;
|
||||
for (int i = 0; i < getItemCount(); ++i) {
|
||||
if (simulationInformation.compareTo((SimulationInformation)getItemAt(i)) <= 0) {
|
||||
super.insertItemAt(simulationInformation, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
super.addItem(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelectedItem(Object object) {
|
||||
if (object instanceof SimulationInformation) {
|
||||
SimulationInformation simulationInformation =
|
||||
(SimulationInformation)object;
|
||||
super.setSelectedItem(simulationInformation.machine + ":" +
|
||||
simulationInformation.handshakePort);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/** toggles connection */
|
||||
protected JXButton connectionButton;
|
||||
|
||||
/** action to be performed when the button is pressed while disconnected */
|
||||
public final Action connectAction;
|
||||
|
||||
/** action to be performed when the button is pressed while connected */
|
||||
public final Action disconnectAction;
|
||||
|
||||
/** action to be performed when the button is pressed while auto-connecting */
|
||||
public final Action autoConnectingAction;
|
||||
|
||||
/** the connection state */
|
||||
private boolean connected = false;
|
||||
|
||||
/** the auto-connecting state */
|
||||
private boolean autoConnecting = false;
|
||||
|
||||
/** exception to be thrown in response to invalid host/port specification */
|
||||
protected IllegalArgumentException illegalArgumentException =
|
||||
new IllegalArgumentException("Connection specification must be of the form host:port");
|
||||
|
||||
/** the thread that listens on the multicast channel for simulations */
|
||||
private SimulationSniffer simulationSniffer = new SimulationSniffer() {{
|
||||
addSimulationListener(new SimulationListener() {
|
||||
|
||||
@Override
|
||||
public void simulationAdded(final SimulationInformation simulationInformation) {
|
||||
if (simulationInformation.getMajorVersionNumber() >= 10) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void run() {
|
||||
simulationComboBox.addItem(simulationInformation);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void simulationRemoved(final SimulationInformation simulationInformation) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
simulationComboBox.removeItem(simulationInformation);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionOccurred(Exception exception) {
|
||||
JOptionPane.showMessageDialog(ConnectionStatusBar.this, exception,
|
||||
"Simulation List Error", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
start();
|
||||
}};
|
||||
|
||||
/** a darker green */
|
||||
protected Color darkGreen = new Color(0, 150, 0);
|
||||
|
||||
/** a darker yellow */
|
||||
protected Color darkYellow = new Color(255, 165, 0);
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*
|
||||
* @param connectAction the action to execute when the button is pressed in
|
||||
* the disconnected state
|
||||
* @param disconnectAction the action to execute when the button is pressed
|
||||
* in the connected state
|
||||
* @param autoConnectingAction the action to execute when the button is pressed
|
||||
* in the auto-connecting state
|
||||
*/
|
||||
public ConnectionStatusBar(Action connectAction, Action disconnectAction, Action autoConnectingAction) {
|
||||
this.connectAction = connectAction;
|
||||
this.disconnectAction = disconnectAction;
|
||||
this.autoConnectingAction = autoConnectingAction;
|
||||
|
||||
simulationComboBox.getEditor().addActionListener(connectAction);
|
||||
|
||||
putClientProperty(BasicStatusBarUI.AUTO_ADD_SEPARATOR, false);
|
||||
setBorder(new EmptyBorder(5, 5, 3, 5));
|
||||
|
||||
add(stateLabel);
|
||||
|
||||
add(simulationComboBox, new JXStatusBar.Constraint(
|
||||
JXStatusBar.Constraint.ResizeBehavior.FILL, new Insets(0, 5, 0, 5)));
|
||||
|
||||
connectionButton = new JXButton(connectAction);
|
||||
add(connectionButton);
|
||||
|
||||
updateState();
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the host name
|
||||
*
|
||||
* @return the host name
|
||||
*/
|
||||
public String getHostName() {
|
||||
Object object = simulationComboBox.getEditor().getItem();
|
||||
|
||||
if (object instanceof SimulationInformation) {
|
||||
return ((SimulationInformation)object).machine;
|
||||
}
|
||||
|
||||
if (object instanceof String) {
|
||||
String string = (String)object;
|
||||
int index = string.lastIndexOf(":");
|
||||
if (index != -1) {
|
||||
return string.substring(0, index).trim();
|
||||
}
|
||||
else {
|
||||
throw illegalArgumentException;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the port
|
||||
*
|
||||
* @return the port
|
||||
*/
|
||||
public int getPort() {
|
||||
Object object = simulationComboBox.getEditor().getItem();
|
||||
|
||||
if (object instanceof SimulationInformation) {
|
||||
return Integer.parseInt(((SimulationInformation)object).handshakePort);
|
||||
}
|
||||
|
||||
if (object instanceof String) {
|
||||
String string = (String)object;
|
||||
int index = string.lastIndexOf(":");
|
||||
if (index != -1) {
|
||||
return Integer.parseInt(string.substring(index + 1).trim());
|
||||
}
|
||||
else {
|
||||
throw illegalArgumentException;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the target simulation
|
||||
*
|
||||
* @param hostName the name of the host machine
|
||||
* @param port the port of the host machine
|
||||
*/
|
||||
public void setTarget(String hostName, int port) {
|
||||
simulationComboBox.setSelectedItem(new SimulationInformation(
|
||||
hostName, Integer.toString(port)));
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the connection state
|
||||
*
|
||||
* @return the connection state
|
||||
*/
|
||||
public boolean getConnectionState() {
|
||||
return connected;
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the connection state, updating the display and action
|
||||
* enabled states appropriately
|
||||
*
|
||||
* @param connected the connection state
|
||||
*/
|
||||
public void setConnectionState(boolean connected) {
|
||||
if (this.connected != connected) {
|
||||
this.connected = connected;
|
||||
updateState();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* updates the display and action enabled states based on the connection state
|
||||
*/
|
||||
protected void updateState() {
|
||||
simulationSniffer.setPaused(connected);
|
||||
connectionButton.setAction(connected ? disconnectAction : connectAction);
|
||||
simulationComboBox.setEnabled(!connected);
|
||||
connectAction.setEnabled(!connected);
|
||||
disconnectAction.setEnabled(connected);
|
||||
if (connected) {
|
||||
stateLabel.setText("Connected To: ");
|
||||
stateLabel.setForeground(darkGreen);
|
||||
}
|
||||
else {
|
||||
stateLabel.setText("Not Connected ");
|
||||
stateLabel.setForeground(Color.red);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* continuously attempt to connect to the target simulation
|
||||
*/
|
||||
public void autoConnect() {
|
||||
if (!autoConnecting) {
|
||||
connected = false;
|
||||
simulationSniffer.setPaused(false);
|
||||
connectionButton.setAction(autoConnectingAction);
|
||||
simulationComboBox.setEnabled(false);
|
||||
connectAction.setEnabled(false);
|
||||
disconnectAction.setEnabled(false);
|
||||
stateLabel.setText("Searching For: ");
|
||||
stateLabel.setForeground(darkYellow);
|
||||
autoConnecting = true;
|
||||
|
||||
final String host = getHostName();
|
||||
final int port = getPort();
|
||||
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
while(autoConnecting) {
|
||||
try {
|
||||
sleep(1000);
|
||||
}
|
||||
catch (InterruptedException interruptedException) {}
|
||||
|
||||
for (SimulationInformation simulationInformation :
|
||||
simulationSniffer.getSimulationInformation()) {
|
||||
if (simulationInformation.machine.equals(host) &&
|
||||
simulationInformation.noHandshakePort.equals(Integer.toString(port)) &&
|
||||
simulationInformation.getMajorVersionNumber() >= 10) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (autoConnecting) {
|
||||
autoConnecting = false;
|
||||
connectAction.actionPerformed(null);
|
||||
}
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* stop continuously attempting to connect to the target simulation, if active
|
||||
*/
|
||||
public void cancelAutoConnect() {
|
||||
if (autoConnecting) {
|
||||
autoConnecting = false;
|
||||
updateState();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns whether or not this instance is currently attempting to
|
||||
* automatically connect to the target simulation
|
||||
*
|
||||
* @return <code>true</code> if auto-connect is currently in progress
|
||||
*/
|
||||
public boolean isAutoConnecting() {
|
||||
return autoConnecting;
|
||||
}
|
||||
|
||||
}
|
140
trick_source/java/src/trick/common/ui/panels/DataPanel.java
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* $Id: DataPanel.java 1065 2010-09-09 19:49:28Z hchen $
|
||||
*
|
||||
*/
|
||||
|
||||
//========================================
|
||||
// Package
|
||||
//========================================
|
||||
package trick.common.ui.panels;
|
||||
|
||||
//========================================
|
||||
//Imports
|
||||
//========================================
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
|
||||
|
||||
/**
|
||||
* A {@link JPanel} that is for displaying data.
|
||||
*
|
||||
* @since Trick 10
|
||||
*/
|
||||
public abstract class DataPanel extends JPanel {
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
public static final int SIM_RUN_TREE = 1;
|
||||
public static final int RUN_LIST = 2;
|
||||
public static final int SIM_DP_TREE = 3;
|
||||
public static final int DP_LIST = 4;
|
||||
public static final int VAR_LIST = 5;
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
/** The pop-up menu for the data panel. */
|
||||
protected JPopupMenu popup = null;
|
||||
|
||||
//========================================
|
||||
// Private Data
|
||||
//=======================================
|
||||
|
||||
private static final long serialVersionUID = -8211915811050384782L;
|
||||
|
||||
/** The panel could have more than one popup menu. */
|
||||
private JPopupMenu[] popupList;
|
||||
|
||||
/** The type of the panel so we know what kind of panel invokes the popup. */
|
||||
private int panelType;
|
||||
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public DataPanel() {
|
||||
popupList = new JPopupMenu[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* The constructor that specifies total number of popup menus for the panel.
|
||||
*
|
||||
* @param popupNum The total popup menus for the panel.
|
||||
*/
|
||||
public DataPanel(int popupNum) {
|
||||
if (popupNum > 0) {
|
||||
popupList = new JPopupMenu[popupNum];
|
||||
} else {
|
||||
popupList = new JPopupMenu[1];
|
||||
}
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Set/Get methods
|
||||
//========================================
|
||||
/**
|
||||
* Sets the panel type.
|
||||
*
|
||||
* @param type The type in integer for the panel.
|
||||
*/
|
||||
public void setType(int type) {
|
||||
panelType = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the panel type.
|
||||
*
|
||||
* @return The panel type in integer.
|
||||
*/
|
||||
public int getType() {
|
||||
return panelType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the total number of popup menus.
|
||||
*
|
||||
* @return The number of popup menus.
|
||||
*/
|
||||
public int getPopupNum() {
|
||||
if (popupList != null) {
|
||||
return popupList.length;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the popup menu with specified index number.
|
||||
*
|
||||
* @param popup An instance of {@link JPopupMenu}.
|
||||
* @param index The index number for the popup menu.
|
||||
*/
|
||||
public void setPopup(JPopupMenu popup, int index) {
|
||||
if (index < popupList.length) {
|
||||
popupList[index] = popup;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the popup menu at specified index number.
|
||||
*
|
||||
* @param index The index number of the popup menu.
|
||||
*
|
||||
* @return An instance of {@link JPopupMenu}.
|
||||
*/
|
||||
public JPopupMenu getPopup(int index) {
|
||||
if (index < popupList.length) {
|
||||
return popupList[index];
|
||||
}
|
||||
return popupList[0];
|
||||
}
|
||||
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
public abstract void removeSelectedData();
|
||||
}
|
372
trick_source/java/src/trick/common/ui/panels/DynamicTree.java
Normal file
@ -0,0 +1,372 @@
|
||||
/*
|
||||
* $Id: DynamicTree.java 3771 2014-12-11 20:37:29Z hchen3 $
|
||||
*
|
||||
*/
|
||||
|
||||
//========================================
|
||||
// Package
|
||||
//========================================
|
||||
package trick.common.ui.panels;
|
||||
|
||||
//========================================
|
||||
//Imports
|
||||
//========================================
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTree;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.DefaultTreeCellRenderer;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import org.jdesktop.swingx.JXTree;
|
||||
import org.jdesktop.swingx.decorator.ColorHighlighter;
|
||||
import org.jdesktop.swingx.decorator.HighlightPredicate;
|
||||
|
||||
import trick.common.ui.UIUtils;
|
||||
import trick.common.ui.components.CommonTreeNode;
|
||||
|
||||
|
||||
/**
|
||||
* A {@link JPanel} that displays a dynamic {@link JTree}.
|
||||
*
|
||||
* @author Hong Chen
|
||||
* @since Trick 10
|
||||
*/
|
||||
public class DynamicTree extends DataPanel {
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
/** An instance of JXTree. */
|
||||
protected JXTree tree;
|
||||
|
||||
/** The tree model for a JTree. */
|
||||
protected DefaultTreeModel treeModel;
|
||||
|
||||
/** The root for a JTree. */
|
||||
protected DefaultMutableTreeNode rootNode;
|
||||
|
||||
|
||||
//========================================
|
||||
// Private Data
|
||||
//========================================
|
||||
private static final long serialVersionUID = 7238523759496892652L;
|
||||
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public DynamicTree() {
|
||||
super();
|
||||
rootNode = new DefaultMutableTreeNode("Root Node");
|
||||
treeModel = new DefaultTreeModel(rootNode);
|
||||
tree = new JXTree(treeModel);
|
||||
tree.setRolloverEnabled(true);
|
||||
tree.addHighlighter(new ColorHighlighter(HighlightPredicate.ROLLOVER_ROW, null, Color.MAGENTA));
|
||||
tree.putClientProperty("JTree.lineStyle", "Angled");
|
||||
//tree.setEditable(true);
|
||||
//tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
|
||||
tree.setShowsRootHandles(true);
|
||||
tree.setRootVisible(false);
|
||||
tree.putClientProperty("JTree.lineStyle", "Horizontal");
|
||||
DynamicTreeCellRenderer renderer = new DynamicTreeCellRenderer();
|
||||
|
||||
tree.setCellRenderer(renderer);
|
||||
|
||||
setup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor with specified the number of pop up menu.
|
||||
*
|
||||
* @param popNum The number of pop up menu.
|
||||
*/
|
||||
public DynamicTree(int popNum) {
|
||||
super(popNum);
|
||||
rootNode = new DefaultMutableTreeNode("Root Node");
|
||||
treeModel = new DefaultTreeModel(rootNode);
|
||||
tree = new JXTree(treeModel);
|
||||
tree.setRolloverEnabled(true);
|
||||
tree.addHighlighter(new ColorHighlighter(HighlightPredicate.ROLLOVER_ROW, null, Color.MAGENTA));
|
||||
tree.putClientProperty("JTree.lineStyle", "Angled");
|
||||
//tree.setEditable(true);
|
||||
//tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
|
||||
tree.setShowsRootHandles(true);
|
||||
tree.setRootVisible(false);
|
||||
tree.putClientProperty("JTree.lineStyle", "Horizontal");
|
||||
DynamicTreeCellRenderer renderer = new DynamicTreeCellRenderer();
|
||||
|
||||
tree.setCellRenderer(renderer);
|
||||
|
||||
setup();
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Set/Get methods
|
||||
//========================================
|
||||
/**
|
||||
* Gets the instance of the {@link JXTree}.
|
||||
*
|
||||
* @return The instance of the tree.
|
||||
*/
|
||||
public JXTree getTree() {
|
||||
return tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the root of the tree.
|
||||
*
|
||||
* @return The root {@link DefaultMutableTreeNode} of the tree.
|
||||
*/
|
||||
public DefaultMutableTreeNode getRoot() {
|
||||
return rootNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default tree model for the tree.
|
||||
*
|
||||
* @return The instance of {@link DefaultTreeModel} for the tree.
|
||||
*/
|
||||
public DefaultTreeModel getDefaultModel() {
|
||||
return treeModel;
|
||||
}
|
||||
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
/**
|
||||
* Helper method.
|
||||
*/
|
||||
private void setup() {
|
||||
setLayout(new BorderLayout());
|
||||
JScrollPane scrollpane = new JScrollPane();
|
||||
scrollpane.getViewport().add(tree);
|
||||
|
||||
add(BorderLayout.CENTER, scrollpane);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all nodes except the root node.
|
||||
*/
|
||||
public void clear() {
|
||||
rootNode.removeAllChildren();
|
||||
treeModel.reload();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds a child node to a parent node.
|
||||
*
|
||||
* @param parent The parent {@link DefaultMutableTreeNode}.
|
||||
* @param child The child object.
|
||||
*/
|
||||
public DefaultMutableTreeNode addObject(DefaultMutableTreeNode parent, Object child) {
|
||||
return addObject(parent, child, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a child node object to a parent node by specifying if it should be visible.
|
||||
*
|
||||
* @param parent The parent {@link DefaultMutableTreeNode}.
|
||||
* @param child The child object.
|
||||
* @param shouldBeVisible <code>true</code> the node should be visible, <code>false</code> otherwise.
|
||||
*/
|
||||
public DefaultMutableTreeNode addObject(DefaultMutableTreeNode parent, Object child, boolean shouldBeVisible) {
|
||||
DefaultMutableTreeNode childNode = new DefaultMutableTreeNode(child);
|
||||
|
||||
if (parent == null) {
|
||||
parent = rootNode;
|
||||
}
|
||||
|
||||
//It is key to invoke this on the TreeModel, and NOT DefaultMutableTreeNode
|
||||
treeModel.insertNodeInto(childNode, parent, parent.getChildCount());
|
||||
|
||||
//Make sure the user can see the lovely new node.
|
||||
if (shouldBeVisible) {
|
||||
tree.scrollPathToVisible(new TreePath(childNode.getPath()));
|
||||
}
|
||||
return childNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a child node to a parent by specifying if it should be visible.
|
||||
*
|
||||
* @param parent The parent {@link DefaultMutableTreeNode}.
|
||||
* @param child The child {@link DefaultMutableTreeNode}.
|
||||
* @param shouldBeVisible <code>true</code> the node should be visible, <code>false</code> otherwise.
|
||||
*/
|
||||
public void addNode(DefaultMutableTreeNode parent, DefaultMutableTreeNode child, boolean shouldBeVisible) {
|
||||
if (parent == null) {
|
||||
parent = rootNode;
|
||||
}
|
||||
addNode(parent, child, parent.getChildCount(), shouldBeVisible);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a child node to a parent by specifying if it should be visible and its index location.
|
||||
*
|
||||
* @param parent The parent {@link DefaultMutableTreeNode}.
|
||||
* @param child The child {@link DefaultMutableTreeNode}.
|
||||
* @param index The child location index in parent children nodes.
|
||||
* @param shouldBeVisible <code>true</code> the node should be visible, <code>false</code> otherwise.
|
||||
*
|
||||
*/
|
||||
public void addNode(DefaultMutableTreeNode parent, DefaultMutableTreeNode child, int index, boolean shouldBeVisible) {
|
||||
|
||||
|
||||
if (index < 0 || index > parent.getChildCount()) {
|
||||
//It is key to invoke this on the TreeModel, and NOT DefaultMutableTreeNode
|
||||
treeModel.insertNodeInto(child, parent, parent.getChildCount());
|
||||
} else {
|
||||
treeModel.insertNodeInto(child, parent, index);
|
||||
}
|
||||
|
||||
//Make sure the user can see the lovely new node.
|
||||
if (shouldBeVisible) {
|
||||
tree.scrollPathToVisible(new TreePath(child.getPath()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all child node of a specified node.
|
||||
*
|
||||
* @param parent A parent {@link DefaultMutableTreeNode}.
|
||||
*
|
||||
* @return A list of {@link DefaultMutableTreeNode} of the specified parent node.
|
||||
*/
|
||||
public ArrayList<DefaultMutableTreeNode> getAllChildren(DefaultMutableTreeNode parent) {
|
||||
ArrayList<DefaultMutableTreeNode> childNodes = null;
|
||||
int count = parent.getChildCount();
|
||||
if (count > 0) {
|
||||
childNodes = new ArrayList<DefaultMutableTreeNode>();
|
||||
for (int i = 0; i < count; i++) {
|
||||
DefaultMutableTreeNode eachChild = (DefaultMutableTreeNode)treeModel.getChild(parent, i);
|
||||
childNodes.add(eachChild);
|
||||
}
|
||||
}
|
||||
return childNodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all selected nodes.
|
||||
*
|
||||
*/
|
||||
public ArrayList<DefaultMutableTreeNode> getSelectedNodes() {
|
||||
ArrayList<DefaultMutableTreeNode> selectedNodes = null;
|
||||
TreePath[] selectedPaths = tree.getSelectionPaths();
|
||||
|
||||
if (selectedPaths != null && selectedPaths.length > 0) {
|
||||
selectedNodes = new ArrayList<DefaultMutableTreeNode>();
|
||||
|
||||
for (int i = 0; i < selectedPaths.length; i ++) {
|
||||
if (selectedPaths[i].getLastPathComponent() instanceof DefaultMutableTreeNode) {
|
||||
DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode)selectedPaths[i].getLastPathComponent();
|
||||
selectedNodes.add(treeNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
return selectedNodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all selected tree nodes.
|
||||
*/
|
||||
@Override
|
||||
public void removeSelectedData() {
|
||||
// TODO:
|
||||
}
|
||||
|
||||
/**
|
||||
* Expands the specified tree node.
|
||||
*
|
||||
* @param node A {@link DefaultMutableTreeNode} that needs expanding.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void expandNode(DefaultMutableTreeNode node) {
|
||||
Enumeration children = node.depthFirstEnumeration();
|
||||
while (children.hasMoreElements()) {
|
||||
DefaultMutableTreeNode child = (DefaultMutableTreeNode)children.nextElement();
|
||||
if (child.isLeaf()) {
|
||||
tree.scrollPathToVisible(new TreePath(child.getPath()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//========================================
|
||||
// Inner classes
|
||||
//========================================
|
||||
/**
|
||||
* Class that extends {@link DefaultTreeCellRenderer}.
|
||||
*
|
||||
*/
|
||||
public class DynamicTreeCellRenderer extends DefaultTreeCellRenderer {
|
||||
|
||||
private static final long serialVersionUID = 6474954896113266472L;
|
||||
|
||||
/**
|
||||
* Configures the renderer based on the passed in components.
|
||||
*/
|
||||
@Override
|
||||
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel,
|
||||
boolean expanded, boolean leaf, int row, boolean hasFocus) {
|
||||
|
||||
super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
|
||||
|
||||
if (value instanceof CommonTreeNode) {
|
||||
CommonTreeNode node = (CommonTreeNode)value;
|
||||
switch (node.getNodeType()) {
|
||||
case CommonTreeNode.PAGE_NODE:
|
||||
setIcon(UIUtils.createImageIcon("page2.gif"));
|
||||
break;
|
||||
case CommonTreeNode.PLOT_NODE:
|
||||
case CommonTreeNode.CURVE_NODE:
|
||||
case CommonTreeNode.VARCASE_NODE:
|
||||
setIcon(UIUtils.createImageIcon("plot.gif"));
|
||||
break;
|
||||
case CommonTreeNode.X_NODE:
|
||||
setIcon(UIUtils.createImageIcon("x_variable.gif"));
|
||||
break;
|
||||
case CommonTreeNode.Y_NODE:
|
||||
setIcon(UIUtils.createImageIcon("y_variable.gif"));
|
||||
break;
|
||||
case CommonTreeNode.VAR_NODE:
|
||||
case CommonTreeNode.INPUT_VAR_NODE:
|
||||
case CommonTreeNode.OUTPUT_VAR_NODE:
|
||||
setIcon(UIUtils.createImageIcon("variable.gif"));
|
||||
break;
|
||||
case CommonTreeNode.TABLE_NODE:
|
||||
setIcon(UIUtils.createImageIcon("table_small.gif"));
|
||||
break;
|
||||
case CommonTreeNode.PROGRAM_NODE:
|
||||
setIcon(UIUtils.createImageIcon("program.gif"));
|
||||
break;
|
||||
case CommonTreeNode.INPUT_NODE:
|
||||
setIcon(UIUtils.createImageIcon("program_in.gif"));
|
||||
break;
|
||||
case CommonTreeNode.OUTPUT_NODE:
|
||||
setIcon(UIUtils.createImageIcon("program_out.gif"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
197
trick_source/java/src/trick/common/ui/panels/FindBar.java
Normal file
@ -0,0 +1,197 @@
|
||||
/*
|
||||
* $Id: FindBar.java 2559 2012-09-05 16:25:43Z hchen3 $
|
||||
*
|
||||
*/
|
||||
|
||||
//========================================
|
||||
// Package
|
||||
//========================================
|
||||
package trick.common.ui.panels;
|
||||
|
||||
//========================================
|
||||
//Imports
|
||||
//========================================
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.SwingConstants;
|
||||
|
||||
import org.jdesktop.swingx.AbstractPatternPanel;
|
||||
import org.jdesktop.swingx.JXFindBar;
|
||||
import org.jdesktop.swingx.JXFindPanel;
|
||||
import org.jdesktop.swingx.search.Searchable;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A {@link JXFindBar} that is for allowing users to input search text.
|
||||
*
|
||||
* @since Trick 10
|
||||
*/
|
||||
public class FindBar extends JXFindBar implements ActionListener{
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
|
||||
|
||||
//========================================
|
||||
// Private Data
|
||||
//=======================================
|
||||
|
||||
private static final long serialVersionUID = 9092192049485321408L;
|
||||
|
||||
/** The initial search text for this find bar */
|
||||
private String initialSearchText = null;
|
||||
|
||||
/** By default, this would not have search options as JXFindPanel, true otherwise. */
|
||||
private boolean hasOptions = false;
|
||||
|
||||
// TODO: add pattern support
|
||||
//private JCheckBox anchorCheck;
|
||||
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public FindBar() {
|
||||
super();
|
||||
setNotFoundForegroundColor();
|
||||
}
|
||||
|
||||
/**
|
||||
* The constructor that specifies total number of popup menus for the panel.
|
||||
*
|
||||
* @param searchable An instance of {@link Searchable} from a gui component which
|
||||
* this search bar is for.
|
||||
*/
|
||||
public FindBar(Searchable searchable) {
|
||||
super(searchable);
|
||||
setNotFoundForegroundColor();
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Set/Get methods
|
||||
//========================================
|
||||
/**
|
||||
* Gets to see if case sensitive is checked.
|
||||
*/
|
||||
public boolean isCaseSensitive() {
|
||||
return getPatternModel().isCaseSensitive();
|
||||
}
|
||||
/**
|
||||
* Sets whether to have the options as {@link JXFindPanel}.
|
||||
*/
|
||||
public void setOptions(boolean b) {
|
||||
hasOptions = b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the searchField that is defined in parent class {@link AbstractPatternPanel}
|
||||
* if there is initial search text is defined.
|
||||
*/
|
||||
public void updateSearchField(String searchText) {
|
||||
initialSearchText = searchText;
|
||||
if (searchField != null) {
|
||||
searchField.setText(searchText);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current search text shown in searchField.
|
||||
*/
|
||||
public String getSearchText() {
|
||||
if (searchField != null) {
|
||||
return searchField.getText();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for changing the forground color when the text is not found.
|
||||
* Since notFoundForegroundColor is proteced in {@link JXFindBar}, extending
|
||||
* it is the only way to be able to change it.
|
||||
*
|
||||
*/
|
||||
private void setNotFoundForegroundColor() {
|
||||
notFoundForegroundColor = Color.red;
|
||||
}
|
||||
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
@Override
|
||||
protected void build() {
|
||||
if (hasOptions) {
|
||||
buildBarWithOption();
|
||||
} else {
|
||||
buildBar();
|
||||
}
|
||||
if (initialSearchText != null) {
|
||||
updateSearchField(initialSearchText);
|
||||
}
|
||||
}
|
||||
|
||||
private void buildBar() {
|
||||
setLayout(new FlowLayout(SwingConstants.LEADING));
|
||||
add(searchLabel);
|
||||
add(new JLabel(":"));
|
||||
add(new JLabel(" "));
|
||||
add(searchField);
|
||||
add(findNext);
|
||||
add(findPrevious);
|
||||
}
|
||||
|
||||
private void buildBarWithOption() {
|
||||
//anchorCheck = new JCheckBox("Anchor");
|
||||
//anchorCheck.addActionListener(this);
|
||||
|
||||
wrapCheck = new JCheckBox();
|
||||
backCheck = new JCheckBox();
|
||||
Box lBox = new Box(BoxLayout.LINE_AXIS);
|
||||
//lBox.add(anchorCheck);
|
||||
lBox.add(matchCheck);
|
||||
lBox.add(wrapCheck);
|
||||
lBox.add(backCheck);
|
||||
lBox.setAlignmentY(Component.TOP_ALIGNMENT);
|
||||
|
||||
Box mBox = new Box(BoxLayout.LINE_AXIS);
|
||||
mBox.add(searchLabel);
|
||||
mBox.add(new JLabel(": "));
|
||||
mBox.add(searchField);
|
||||
mBox.add(findNext);
|
||||
mBox.add(findPrevious);
|
||||
mBox.setAlignmentY(Component.TOP_ALIGNMENT);
|
||||
|
||||
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
|
||||
|
||||
add(lBox);
|
||||
add(mBox);
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
/*if (e.getSource() == anchorCheck) {
|
||||
if (anchorCheck.isSelected()) {
|
||||
getPatternModel().setRegexCreatorKey(PatternModel.REGEX_ANCHORED);
|
||||
} else {
|
||||
getPatternModel().setMatchRule(PatternModel.REGEX_MATCH_RULES);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
311
trick_source/java/src/trick/common/ui/panels/ListPanel.java
Normal file
@ -0,0 +1,311 @@
|
||||
/*
|
||||
* $Id: ListPanel.java 2835 2013-03-04 15:06:44Z hchen3 $
|
||||
*
|
||||
*/
|
||||
|
||||
//========================================
|
||||
// Package
|
||||
//========================================
|
||||
package trick.common.ui.panels;
|
||||
|
||||
//========================================
|
||||
//Imports
|
||||
//========================================
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
|
||||
import javax.swing.AbstractListModel;
|
||||
import javax.swing.DefaultListModel;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.event.ListDataListener;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
|
||||
import org.jdesktop.swingx.JXList;
|
||||
import org.jdesktop.swingx.decorator.ColorHighlighter;
|
||||
import org.jdesktop.swingx.decorator.HighlightPredicate;
|
||||
|
||||
import trick.common.TrickApplication;
|
||||
import trick.common.ui.UIUtils;
|
||||
import trick.common.utils.SortedListModel;
|
||||
|
||||
|
||||
/**
|
||||
* A class that extends {@link DataPanel} for displaying a list of data using {@link JXList}.
|
||||
* All contents are unique.
|
||||
*
|
||||
* @author Hong Chen
|
||||
* @since Trick 10
|
||||
*/
|
||||
public class ListPanel extends DataPanel implements ListSelectionListener{
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
/** The model for the data list. */
|
||||
protected AbstractListModel dataListModel;
|
||||
|
||||
|
||||
//========================================
|
||||
// Private Data
|
||||
//========================================
|
||||
|
||||
private static final long serialVersionUID = 929091003093241018L;
|
||||
|
||||
/** An instance of JXList to represent a list of data shown on the panel. */
|
||||
private JXList dataList;
|
||||
|
||||
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public ListPanel() {
|
||||
super();
|
||||
dataListModel = new DefaultListModel();
|
||||
setup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor with specified list model.
|
||||
*/
|
||||
public ListPanel(AbstractListModel model) {
|
||||
super();
|
||||
dataListModel = model;
|
||||
setup();
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Set/Get methods
|
||||
//========================================
|
||||
/**
|
||||
* Gets the instance of the {@link JList}.
|
||||
*
|
||||
* @return The instance of the JList.
|
||||
*/
|
||||
public JList getJList() {
|
||||
return dataList;
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
/**
|
||||
* Sets up the list with a scroll pane.
|
||||
*/
|
||||
protected void setup() {
|
||||
if (dataListModel == null) {
|
||||
dataListModel = new DefaultListModel();
|
||||
}
|
||||
dataList = new JXList(dataListModel);
|
||||
|
||||
setLayout(new BorderLayout());
|
||||
|
||||
dataList.setRolloverEnabled(true);
|
||||
dataList.addHighlighter(new ColorHighlighter(HighlightPredicate.ROLLOVER_ROW, null, Color.MAGENTA));
|
||||
|
||||
// Put the JList into a JScrollPane.
|
||||
JScrollPane scrollpane = new JScrollPane(dataList);
|
||||
|
||||
dataList.addListSelectionListener(this);
|
||||
dataList.addMouseListener(new ListMouseListener());
|
||||
|
||||
add(BorderLayout.CENTER, scrollpane);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@link MouseListener} to the data list.
|
||||
*
|
||||
* @param listener An instance of {@link MouseListener} needs adding the list.
|
||||
*/
|
||||
public void addListMouseListener(MouseListener listener) {
|
||||
if (dataList != null) {
|
||||
dataList.addMouseListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds data array to the list.
|
||||
*
|
||||
* @param items An array of {@link Object} that need adding to the list.
|
||||
*/
|
||||
public void addData(Object[] items) {
|
||||
if (items == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < items.length; i++) {
|
||||
addData(items[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds one data to the list if it doesn't exist.
|
||||
*
|
||||
* @param item The {@link Object} that needs adding to the list.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void addData(Object item) {
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
if (dataListModel instanceof SortedListModel) {
|
||||
if (!((SortedListModel)dataListModel).contains(item)) {
|
||||
((SortedListModel)dataListModel).add(item);
|
||||
}
|
||||
} else {
|
||||
if (!((DefaultListModel)dataListModel).contains(item)) {
|
||||
((DefaultListModel)dataListModel).addElement(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all of the selected data from the list.
|
||||
*/
|
||||
public void removeSelectedData() {
|
||||
Object[] values = dataList.getSelectedValues();
|
||||
if (values != null) {
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
if (dataListModel instanceof SortedListModel) {
|
||||
((SortedListModel)dataListModel).removeElement(values[i]);
|
||||
} else {
|
||||
((DefaultListModel)dataListModel).removeElement(values[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all specified data from the list.
|
||||
*
|
||||
* @param dataArray The specified data array that need removing from the list.
|
||||
*/
|
||||
public void removeData(Object[] dataArray) {
|
||||
if (dataArray != null && dataArray.length > 0) {
|
||||
for (int i = 0; i < dataArray.length; i++) {
|
||||
removeData(dataArray[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes one data from the list.
|
||||
*
|
||||
* @param item The specified data that needs removing from the list.
|
||||
*/
|
||||
public void removeData(Object item) {
|
||||
if (item==null) {
|
||||
return;
|
||||
}
|
||||
if (dataListModel instanceof SortedListModel) {
|
||||
((SortedListModel)dataListModel).removeElement(item);
|
||||
} else {
|
||||
((DefaultListModel)dataListModel).removeElement(item);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all selected data from the list.
|
||||
*/
|
||||
public Object[] getSelectedData() {
|
||||
return dataList.getSelectedValues();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the first selected value, or <code>null</code> if the selection is empty.
|
||||
*/
|
||||
public Object getSelectedFirstData() {
|
||||
return dataList.getSelectedValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all data from the list.
|
||||
*/
|
||||
public Object[] getAllData() {
|
||||
if (dataListModel instanceof SortedListModel) {
|
||||
return ((SortedListModel)dataListModel).toArray();
|
||||
}
|
||||
return ((DefaultListModel)dataListModel).toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all data from the list.
|
||||
*/
|
||||
public void removeAllData() {
|
||||
if (dataListModel instanceof SortedListModel) {
|
||||
((SortedListModel)dataListModel).clear();
|
||||
} else {
|
||||
((DefaultListModel)dataListModel).clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Required by {@link ListSelectionListener} interface.
|
||||
*/
|
||||
public void valueChanged(ListSelectionEvent evt) {
|
||||
evt.getSource();
|
||||
}
|
||||
|
||||
public void addListDataListener(ListDataListener listener) {
|
||||
dataListModel.addListDataListener(listener);
|
||||
}
|
||||
|
||||
|
||||
//========================================
|
||||
// Inner classes
|
||||
//========================================
|
||||
/**
|
||||
* Using an inner class to define MouseListener to help organize code better.
|
||||
* The goal of this class is to handle mouse calls and forward them
|
||||
* to the interested parties.
|
||||
*/
|
||||
private class ListMouseListener extends MouseAdapter {
|
||||
|
||||
//========================================
|
||||
// MouseListener methods
|
||||
//========================================
|
||||
/**
|
||||
* Invoked when the mouse button has been clicked (pressed
|
||||
* and released) on a component.
|
||||
*
|
||||
* @param e MouseEvent sent from system.
|
||||
*/
|
||||
public void mouseClicked(MouseEvent e)
|
||||
{
|
||||
// there is nothing shown or the list is empty, return without doing anything.
|
||||
if (dataListModel.getSize() < 1) {
|
||||
return;
|
||||
}
|
||||
if( UIUtils.isRightMouseClick(e) ) {
|
||||
int index = dataList.locationToIndex(e.getPoint());
|
||||
if (index > -1) {
|
||||
int[] selectedIndices = dataList.getSelectedIndices();
|
||||
int[] extendedIndices = new int[selectedIndices.length+1];
|
||||
System.arraycopy(selectedIndices, 0, extendedIndices, 0, selectedIndices.length);
|
||||
// Adds the right-clicked one to the selected list
|
||||
extendedIndices[extendedIndices.length-1] = index;
|
||||
dataList.setSelectedIndices(extendedIndices);
|
||||
}
|
||||
if (getPopup(0) != null && !getPopup(0).isVisible()) {
|
||||
TrickApplication.setPopupInvoker(getType());
|
||||
getPopup(0).show(e.getComponent(), e.getX(), e.getY());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
//========================================
|
||||
// Package
|
||||
//========================================
|
||||
package trick.common.ui.panels;
|
||||
|
||||
//========================================
|
||||
// Package
|
||||
//========================================
|
||||
import java.net.URL;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
|
||||
import org.jdesktop.swingx.JXLabel;
|
||||
|
||||
import trick.common.TrickApplication;
|
||||
|
||||
public class SmallTrickIconLabel extends JXLabel {
|
||||
|
||||
private static final long serialVersionUID = -1272978741978959753L;
|
||||
|
||||
/**
|
||||
* creates a label displaying a small Trick icon with version information tool tip
|
||||
*/
|
||||
public SmallTrickIconLabel() {
|
||||
URL imageURL = TrickApplication.class.getResource("resources/trick_small.gif");
|
||||
if (imageURL != null) {
|
||||
String description = "Trick Version " + System.getenv("TRICK_VER");
|
||||
setIcon(new ImageIcon(imageURL, description));
|
||||
setToolTipText(description);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
335
trick_source/java/src/trick/common/utils/BinaryDataReader.java
Normal file
@ -0,0 +1,335 @@
|
||||
/*
|
||||
* $Id: BinaryDataReader.java 3544 2014-05-30 21:00:01Z hchen3 $
|
||||
*
|
||||
*/
|
||||
|
||||
//========================================
|
||||
// Package
|
||||
//========================================
|
||||
package trick.common.utils;
|
||||
|
||||
//========================================
|
||||
// Imports
|
||||
//========================================
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import trick.common.utils.LogVar.DisplayType;
|
||||
import trick.common.utils.LogVar.TrickType;
|
||||
import trick.dataproducts.trickqp.utils.ProductVar;
|
||||
|
||||
|
||||
/**
|
||||
* This data reader is for retrieving the recorded variable list out of Trick recorded binary data.
|
||||
*
|
||||
*
|
||||
* @since Trick 10
|
||||
*/
|
||||
public class BinaryDataReader extends DataReader {
|
||||
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Private Data
|
||||
//========================================
|
||||
private int numParams;
|
||||
private long headerBytes;
|
||||
private boolean isLittleEndian;
|
||||
|
||||
private FileInputStream fileInputStream;
|
||||
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
/**
|
||||
* Constructs a reader with specified file name.
|
||||
*
|
||||
* @param fileName The name of the file.
|
||||
*/
|
||||
public BinaryDataReader(String fileName) {
|
||||
super(fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a reader with specified file.
|
||||
*
|
||||
* @param file An instance of {@link File} for the reader to read.
|
||||
*/
|
||||
public BinaryDataReader(File file) {
|
||||
super(file);
|
||||
}
|
||||
|
||||
|
||||
//========================================
|
||||
// Set/Get methods
|
||||
//========================================
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
/**
|
||||
* Processes the recorded data. Required by {@link DataReader}.
|
||||
*/
|
||||
@Override
|
||||
protected void processHeader() throws FileNotFoundException, IOException {
|
||||
FileInputStream inFile = new FileInputStream(dataFile);
|
||||
|
||||
// 10 bytes are for endian spec
|
||||
String endianStr = readBytesToString(inFile, 10);
|
||||
headerBytes += 10;
|
||||
|
||||
if (endianStr.endsWith("-L")) {
|
||||
isLittleEndian = true;
|
||||
}
|
||||
|
||||
numParams = readBytesToInt(inFile, 4);
|
||||
headerBytes += 4;
|
||||
|
||||
// now go through the header for this data file
|
||||
for (int k = 0; k < numParams; k++) {
|
||||
// 4 bytes for the length of this param name
|
||||
int paramNameLen = readBytesToInt(inFile, 4);
|
||||
headerBytes += 4;
|
||||
|
||||
// paramNameLen bytes for the param name
|
||||
String paramName = readBytesToString(inFile, paramNameLen);
|
||||
headerBytes += paramNameLen;
|
||||
|
||||
LogVar varObj = new LogVar(paramName);
|
||||
|
||||
// 4 bytes for the length of the units
|
||||
int unitsLen = readBytesToInt(inFile, 4);
|
||||
headerBytes += 4;
|
||||
|
||||
// unitsLen bytes for the units
|
||||
// TODO: unit conversion for Trick-05*
|
||||
varObj.setUnits(readBytesToString(inFile, unitsLen));
|
||||
headerBytes += unitsLen;
|
||||
|
||||
// 4 bytes for the type id
|
||||
int typeId = readBytesToInt(inFile, 4);
|
||||
headerBytes += 4;
|
||||
|
||||
int size = readBytesToInt(inFile, 4);
|
||||
headerBytes += 4;
|
||||
|
||||
TrickType varType = TrickType.TRICK_DOUBLE;
|
||||
//varObj.setType(getType(typeId));
|
||||
if (typeId > -1 && typeId < TrickType.values().length) {
|
||||
varType = TrickType.values()[typeId];
|
||||
}
|
||||
varObj.setType(varType);
|
||||
varObj.setSize(size);
|
||||
|
||||
varObj.setDisplay(DisplayType.NORMAL);
|
||||
varObj.setLevel(0);
|
||||
varObj.setCount(1);
|
||||
varObj.setIsFromLog(true);
|
||||
varObj.setRunDir(dataFile.getParent());
|
||||
recordedVarList.add(varObj);
|
||||
}
|
||||
|
||||
if (inFile != null) {
|
||||
inFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for reading specified number of bytes from a binary file and convert it to an int.
|
||||
*/
|
||||
private int readBytesToInt(FileInputStream inFile, int numBytes) throws IOException {
|
||||
ByteBuffer byteBuf = readBytes(inFile, numBytes);
|
||||
|
||||
return byteBuf.getInt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for reading specified number of bytes from a binary file with correct format.
|
||||
*/
|
||||
private ByteBuffer readBytes(FileInputStream inFile, int numBytes) throws IOException {
|
||||
byte[] bytes = new byte[numBytes];
|
||||
inFile.read(bytes);
|
||||
ByteBuffer byteBuf = ByteBuffer.wrap(bytes);
|
||||
// Java native format is big endian, no need to set the order for bit endian.
|
||||
if (isLittleEndian) {
|
||||
byteBuf.order(ByteOrder.LITTLE_ENDIAN);
|
||||
}
|
||||
return byteBuf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for reading specified number bytes from a binary file and convert it to a string.
|
||||
*/
|
||||
private String readBytesToString(FileInputStream inFile, int numBytes) throws IOException {
|
||||
byte[] bytes = new byte[numBytes];
|
||||
inFile.read(bytes);
|
||||
return new String(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginRead(ProductVar var) throws IOException {
|
||||
super.beginRead(var);
|
||||
fileInputStream = new FileInputStream(dataFile);
|
||||
fileInputStream.skip(headerBytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getVarValue() throws IOException {
|
||||
double varData = Double.NaN;
|
||||
boolean isDone = false;
|
||||
|
||||
while (true) {
|
||||
boolean varFound = false;
|
||||
boolean timeFound = false;
|
||||
boolean goodTime = true;
|
||||
|
||||
for (int j = 0; j < numParams; j++) {
|
||||
LogVar thisVar = (LogVar)recordedVarList.get(j);
|
||||
byte[] bytes = new byte[thisVar.getSize()];
|
||||
if (fileInputStream.read(bytes) == -1) {
|
||||
isDone = true;
|
||||
break;
|
||||
}
|
||||
|
||||
ByteBuffer byteBuf = ByteBuffer.wrap(bytes);
|
||||
// Java native format is big endian, no need to set the order for bit endian.
|
||||
if (isLittleEndian) {
|
||||
byteBuf.order(ByteOrder.LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
if (j == timeIndex) {
|
||||
timeFound = true;
|
||||
theTimeValue = byteBuf.getDouble();
|
||||
goodTime = isTimeInRange(theTimeValue);
|
||||
}
|
||||
|
||||
if (j == theVarIndex) {
|
||||
if (timeIndex == theVarIndex) {
|
||||
varData = theTimeValue;
|
||||
} else {
|
||||
if (thisVar.getType() != null) {
|
||||
switch (thisVar.getType()) {
|
||||
//case TRICK_VOID:
|
||||
//case TRICK_CHARACTER:
|
||||
//case TRICK_UNSIGNED_CHARACTER:
|
||||
//case TRICK_STRING:
|
||||
case TRICK_SHORT:
|
||||
case TRICK_UNSIGNED_SHORT:
|
||||
varData = byteBuf.getShort();
|
||||
break;
|
||||
case TRICK_INTEGER:
|
||||
case TRICK_UNSIGNED_INTEGER:
|
||||
varData = byteBuf.getInt();
|
||||
break;
|
||||
case TRICK_LONG:
|
||||
case TRICK_UNSIGNED_LONG:
|
||||
case TRICK_LONG_LONG:
|
||||
case TRICK_UNSIGNED_LONG_LONG:
|
||||
varData = byteBuf.getLong();
|
||||
break;
|
||||
case TRICK_FLOAT:
|
||||
varData = byteBuf.getFloat();
|
||||
break;
|
||||
case TRICK_DOUBLE:
|
||||
varData = byteBuf.getDouble();
|
||||
break;
|
||||
case TRICK_BITFIELD:
|
||||
case TRICK_UNSIGNED_BITFIELD:
|
||||
if (thisVar.getSize() == 1) {
|
||||
varData = byteBuf.getChar();
|
||||
} else if (thisVar.getSize() == 2) {
|
||||
varData = byteBuf.getShort();
|
||||
} else if (thisVar.getSize() == 4) {
|
||||
varData = byteBuf.getInt();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
//case TRICK_FILE_PTR:
|
||||
//case TRICK_BOOLEAN:
|
||||
//case TRICK_WCHAR:
|
||||
//case TRICK_WSTRING:
|
||||
//case TRICK_VOID_PTR:
|
||||
//case TRICK_ENUMERATED:
|
||||
//case TRICK_STRUCTURED:
|
||||
//case TRICK_USER_DEFINED_TYPE:
|
||||
//case TRICK_NUMBER_OF_TYPES:
|
||||
}
|
||||
}
|
||||
}
|
||||
varFound = true;
|
||||
}
|
||||
|
||||
if (varFound && timeFound) {
|
||||
if (goodTime) {
|
||||
try {
|
||||
varData = applyVarProperties(varData);
|
||||
isDone = true;
|
||||
} catch (UnitType.IllegalUnitConversionException e) {
|
||||
System.out.println(e.getMessage());
|
||||
System.out.println(e.getCause());
|
||||
// set varFound false as no need to go through all log data
|
||||
// if unit conversion can't be performed for the variable
|
||||
varFound = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int needToSkipNum = Math.max(timeIndex, theVarIndex);
|
||||
for (int k = needToSkipNum + 1; k < recordedVarList.size(); k ++) {
|
||||
LogVar theVar = (LogVar)recordedVarList.get(k);
|
||||
fileInputStream.skip(theVar.getSize());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!varFound || isDone) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return varData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnd() {
|
||||
boolean ret = false;
|
||||
if (fileInputStream == null) {
|
||||
ret = true;
|
||||
}
|
||||
try {
|
||||
if (fileInputStream.available() < 1) {
|
||||
ret = true;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endRead() {
|
||||
if (fileInputStream != null) {
|
||||
try {
|
||||
fileInputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
189
trick_source/java/src/trick/common/utils/CSVDataReader.java
Normal file
@ -0,0 +1,189 @@
|
||||
/*
|
||||
* $Id: CSVDataReader.java 3536 2014-05-22 19:38:33Z hchen3 $
|
||||
*
|
||||
*/
|
||||
|
||||
//========================================
|
||||
// Package
|
||||
//========================================
|
||||
package trick.common.utils;
|
||||
|
||||
//========================================
|
||||
// Imports
|
||||
//========================================
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Scanner;
|
||||
|
||||
import trick.common.utils.LogVar.DisplayType;
|
||||
import trick.common.utils.UnitType.IllegalUnitConversionException;
|
||||
import trick.dataproducts.trickqp.utils.ProductVar;
|
||||
|
||||
|
||||
/**
|
||||
* This data reader is for retrieving the recorded variable list out of Trick recorded csv data.
|
||||
*
|
||||
*
|
||||
* @since Trick 10
|
||||
*/
|
||||
public class CSVDataReader extends DataReader {
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Private Data
|
||||
//========================================
|
||||
private BufferedReader bufferedDataReader = null;
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
/**
|
||||
* Constructs a reader with specified file name.
|
||||
*
|
||||
* @param fileName The name of the file.
|
||||
*/
|
||||
public CSVDataReader(String fileName) {
|
||||
super(fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a reader with specified file.
|
||||
*
|
||||
* @param file An instance of {@link File} for the reader to read.
|
||||
*/
|
||||
public CSVDataReader(File file) {
|
||||
super(file);
|
||||
}
|
||||
|
||||
|
||||
//========================================
|
||||
// Set/Get methods
|
||||
//========================================
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
/**
|
||||
* Processes the recorded data. Required by {@link DataReader}.
|
||||
*/
|
||||
@Override
|
||||
protected void processHeader() throws FileNotFoundException, IOException {
|
||||
Scanner scanner = new Scanner(dataFile);
|
||||
|
||||
try {
|
||||
String headerLine = scanner.nextLine();
|
||||
headerLine = headerLine.replaceAll("[{}]", "");
|
||||
String[] tokens = headerLine.split(",");
|
||||
|
||||
for (String eachToken : tokens) {
|
||||
String[] varPair = eachToken.split("\\s+");
|
||||
LogVar varObj = new LogVar(varPair[0]);
|
||||
if (varPair.length > 1) {
|
||||
varObj.setUnits(varPair[1]);
|
||||
}
|
||||
// TODO: type?
|
||||
varObj.setDisplay(DisplayType.NORMAL);
|
||||
varObj.setLevel(0);
|
||||
varObj.setCount(1);
|
||||
varObj.setIsFromLog(true);
|
||||
varObj.setRunDir(dataFile.getParent());
|
||||
recordedVarList.add(varObj);
|
||||
}
|
||||
}
|
||||
|
||||
finally {
|
||||
if (scanner != null) {
|
||||
scanner.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the process for getting variable value.
|
||||
*
|
||||
* @param var the variable name which need retrieving value for.
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public void beginRead(ProductVar var) throws IOException {
|
||||
super.beginRead(var);
|
||||
bufferedDataReader = new BufferedReader(new InputStreamReader(new FileInputStream(dataFile)));
|
||||
bufferedDataReader.readLine(); // ignore header
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends the process for getting value.
|
||||
*/
|
||||
@Override
|
||||
public void endRead() {
|
||||
if (bufferedDataReader != null) {
|
||||
try {
|
||||
bufferedDataReader.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getVarValue() throws IOException {
|
||||
|
||||
String oneLine = bufferedDataReader.readLine();
|
||||
|
||||
while (oneLine != null && !oneLine.isEmpty()) {
|
||||
String[] dataStrList = oneLine.split(",");
|
||||
// if time stamp is not recorded, no need to verify it
|
||||
if (timeIndex > -1) {
|
||||
theTimeValue = Double.parseDouble(dataStrList[timeIndex]);
|
||||
if (!isTimeInRange(theTimeValue)){
|
||||
oneLine = bufferedDataReader.readLine();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
double varData = Double.parseDouble(dataStrList[theVarIndex]);
|
||||
|
||||
try {
|
||||
varData = applyVarProperties(varData);
|
||||
} catch (IllegalUnitConversionException e) {
|
||||
break;
|
||||
}
|
||||
return varData;
|
||||
}
|
||||
return Double.NaN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnd() {
|
||||
boolean ret = false;
|
||||
if (bufferedDataReader == null) {
|
||||
ret = true;
|
||||
}
|
||||
try {
|
||||
if (bufferedDataReader.readLine() == null) {
|
||||
ret = true;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
339
trick_source/java/src/trick/common/utils/DataReader.java
Normal file
@ -0,0 +1,339 @@
|
||||
/*
|
||||
* $Id: DataReader.java 3536 2014-05-22 19:38:33Z hchen3 $
|
||||
*/
|
||||
|
||||
//========================================
|
||||
// Package
|
||||
//========================================
|
||||
package trick.common.utils;
|
||||
|
||||
//========================================
|
||||
// Imports
|
||||
//========================================
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import trick.common.TrickApplication;
|
||||
import trick.dataproducts.trickqp.utils.ProductVar;
|
||||
|
||||
|
||||
/**
|
||||
* This data reader is for reading recorded data from different type of files.
|
||||
*
|
||||
*
|
||||
* @since Trick 10
|
||||
*/
|
||||
public abstract class DataReader {
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
protected File dataFile;
|
||||
protected List<Object> recordedVarList;
|
||||
|
||||
protected double theTimeValue = Double.NaN;
|
||||
protected int theVarIndex = -1;
|
||||
protected ProductVar theVar;
|
||||
|
||||
protected Double tstart;
|
||||
protected Double tstop;
|
||||
protected Double frequency;
|
||||
// the index number of time name in the recordedVarList, by default, it's the 1st variable on the list
|
||||
protected int timeIndex = 0;
|
||||
|
||||
protected String timename = TrickApplication.DEFAULT_TIME_NAME;
|
||||
|
||||
//========================================
|
||||
// Private Data
|
||||
//========================================
|
||||
private static double EPSILON = 1e-9;
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
/**
|
||||
* Constructs the reader with specified file name.
|
||||
* Once the reader is created, its header is always
|
||||
* processed so that the recorded variable list is
|
||||
* ready to use.
|
||||
*
|
||||
* @param fileName The name of the file for the reader to read.
|
||||
*/
|
||||
public DataReader(String fileName) {
|
||||
this(new File(fileName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the reader with specified {@link File}.
|
||||
* Once the reader is created, its header is always
|
||||
* processed so that the recorded variable list is
|
||||
* ready to use.
|
||||
*
|
||||
* @param file An instance of {@link File} for the reader to read.
|
||||
*/
|
||||
public DataReader(File file) {
|
||||
dataFile = file;
|
||||
init();
|
||||
try {
|
||||
processHeader();
|
||||
} catch (FileNotFoundException e) {
|
||||
System.out.println("Error: " + file.getPath() + " can not be found!");
|
||||
} catch (IOException e) {
|
||||
System.out.println("I/O Exception: " + file.getPath());
|
||||
}
|
||||
timeIndex = locateVarIndex(timename);
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Set/Get methods
|
||||
//========================================
|
||||
/**
|
||||
* Gets the variable list that is recorded either from the header file or the data file.
|
||||
*
|
||||
* @return A {@link List} of variables that are recorded.
|
||||
*/
|
||||
public List<Object> getRecordedVarList() {
|
||||
return recordedVarList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the variable which the reader needs reading data for.
|
||||
*
|
||||
* @param var An instance of {@link ProductVar} for the variable.
|
||||
*/
|
||||
public void setVar(ProductVar var) {
|
||||
theVar = var;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the start time object for the XY data series.
|
||||
*
|
||||
* @param start The start time object.
|
||||
*/
|
||||
public void setTStart(Double start) {
|
||||
tstart = start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the stop time object for the XY data series.
|
||||
*
|
||||
* @param stop The stop time object;
|
||||
*/
|
||||
public void setTStop(Double stop) {
|
||||
tstop = stop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time name for this data reader.
|
||||
*
|
||||
* @param name The time name for the data reader.
|
||||
*/
|
||||
public void setTimename(String name) {
|
||||
// if name is null, name keeps its default that is DEFAULT_TIME_NAME(sys.exec.out.time)
|
||||
if (name != null && !name.equals(timename)) {
|
||||
timename = name;
|
||||
timeIndex = locateVarIndex(timename);
|
||||
// if can't find the specified timename, go back to the default one
|
||||
if (timeIndex == -1) {
|
||||
timename = TrickApplication.DEFAULT_TIME_NAME;
|
||||
timeIndex = locateVarIndex(timename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the log variable for the specified variable.
|
||||
*/
|
||||
public LogVar getLogVar(String varName) {
|
||||
LogVar logVar = null;
|
||||
if (recordedVarList != null) {
|
||||
for (Object thisVar : recordedVarList) {
|
||||
if (thisVar instanceof LogVar) {
|
||||
if (((LogVar)thisVar).getName().equals(varName)) {
|
||||
logVar = (LogVar)thisVar;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return logVar;
|
||||
}
|
||||
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
/**
|
||||
* Initialize.
|
||||
*/
|
||||
private void init() {
|
||||
recordedVarList = new ArrayList<Object>();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Starts the process for getting value.
|
||||
*
|
||||
* @param var the variable name which need retrieving value for.
|
||||
* @throws IOException
|
||||
*/
|
||||
public void beginRead(ProductVar var) throws IOException {
|
||||
theVarIndex = locateVarIndex(var.getName());
|
||||
theVar = var;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the variable value.
|
||||
*
|
||||
* @return The variable value.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public abstract double getVarValue() throws IOException;
|
||||
|
||||
/**
|
||||
* Ends the process for getting value.
|
||||
*/
|
||||
public abstract void endRead();
|
||||
|
||||
/**
|
||||
* Checks to see if this reader reaches its end.
|
||||
*
|
||||
* @return True if the reader reaches its end, false otherwise.
|
||||
*/
|
||||
public boolean isEnd() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index number of a variable in the list based on its name.
|
||||
*/
|
||||
public int locateVarIndex(String varName) {
|
||||
int idx = -1;
|
||||
for (int i = 0; i < recordedVarList.size(); i++) {
|
||||
LogVar thisVar = (LogVar)recordedVarList.get(i);
|
||||
|
||||
if (thisVar.getName().equals(varName)) {
|
||||
idx = i;
|
||||
}
|
||||
if (idx != -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if the time is in the range of specified tstart and tstop if applicable.
|
||||
* If the range is not specified, true is always returned.
|
||||
*
|
||||
* @see #tstart
|
||||
* @see #tstop
|
||||
*/
|
||||
public boolean isTimeInRange(double timeData) {
|
||||
boolean ret = true;
|
||||
if (tstart != null || tstop != null) {
|
||||
ret = false;
|
||||
if (tstart != null) {
|
||||
if (timeData >= tstart.doubleValue()) {
|
||||
ret = true;
|
||||
} else {
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
if (tstop != null) {
|
||||
if (timeData <= tstop.doubleValue()) {
|
||||
ret = ret && true;
|
||||
} else {
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the time stamp for the specified variable value retrieved.
|
||||
*/
|
||||
public double getTimeValue() {
|
||||
return theTimeValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract method for processing the data recording file.
|
||||
* This method needs to be called after a {@link DataReader} instance
|
||||
* is created in order for recordedVarList to be filled in.
|
||||
*/
|
||||
protected abstract void processHeader() throws FileNotFoundException, IOException;
|
||||
|
||||
/**
|
||||
* Checks to see if 2 doubles are almost equal with specified Epsilon.
|
||||
*/
|
||||
public static boolean nearlyEqual(double a, double b, double eps) {
|
||||
if (a == b) {
|
||||
return true;
|
||||
}
|
||||
return Math.abs(a - b) < eps * Math.max(Math.abs(a), Math.abs(b));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if 2 doubles are almost equal with the default Epsilon.
|
||||
*/
|
||||
public static boolean nearlyEqual(double a, double b) {
|
||||
return nearlyEqual(a, b, EPSILON);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the value of the variable properties such as scale, bias, and units.
|
||||
*/
|
||||
protected double applyVarProperties(double varData) throws UnitType.IllegalUnitConversionException {
|
||||
if (theVar.getScale() != null) {
|
||||
varData = theVar.getScale().doubleValue() * varData;
|
||||
}
|
||||
if (theVar.getBias() != null) {
|
||||
varData = varData + theVar.getBias().doubleValue();
|
||||
}
|
||||
|
||||
if (theVar.getUnits() != null) {
|
||||
varData = convertUnits(varData, getLogVar(theVar.getName()), theVar);
|
||||
}
|
||||
|
||||
return varData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts log variable value to product variable value based on their units.
|
||||
*
|
||||
* @throws UnitType.IllegalUnitConversionException if units conversion error.
|
||||
*/
|
||||
private double convertUnits(double fromValue, LogVar fromVar, ProductVar toVar) throws UnitType.IllegalUnitConversionException {
|
||||
double toValue = fromValue;
|
||||
String fromUnits = null;
|
||||
if (fromVar.getUnits() == null && toVar.getFromUnits() != null && !toVar.getFromUnits().isEmpty()) {
|
||||
fromUnits = toVar.getFromUnits();
|
||||
} else {
|
||||
fromUnits = fromVar.getUnits();
|
||||
}
|
||||
if (fromUnits != null && !fromUnits.equals(toVar.getUnits())) {
|
||||
try {
|
||||
toValue = UnitType.convertUnits(fromValue, fromVar.getUnits(), toVar.getUnits());
|
||||
} catch (UnitType.IllegalUnitConversionException e) {
|
||||
throw new UnitType.IllegalUnitConversionException("===" + fromVar.getName() + ": [" + fromVar.getUnits() + "]", toVar.getName() + ": [" + toVar.getUnits() + "]");
|
||||
}
|
||||
}
|
||||
return toValue;
|
||||
}
|
||||
}
|
85
trick_source/java/src/trick/common/utils/ErrorChecker.java
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* $Id: ErrorChecker.java 1306 2010-12-07 19:16:33Z hchen $
|
||||
*
|
||||
*/
|
||||
|
||||
//========================================
|
||||
// Package
|
||||
//========================================
|
||||
package trick.common.utils;
|
||||
|
||||
//========================================
|
||||
// Imports
|
||||
//========================================
|
||||
import org.xml.sax.SAXParseException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
|
||||
/**
|
||||
* Defines erro handler to deal with irregularities that come up
|
||||
* during the parsing of a XML document.
|
||||
*
|
||||
*
|
||||
* @since Trick 10
|
||||
*/
|
||||
public class ErrorChecker extends DefaultHandler{
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
|
||||
|
||||
//========================================
|
||||
// Private Data
|
||||
//========================================
|
||||
// Exception message
|
||||
private String exceptionMessage;
|
||||
|
||||
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
public ErrorChecker(){
|
||||
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Set/Get methods
|
||||
//========================================
|
||||
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
public void error(SAXParseException e) {
|
||||
exceptionMessage = "Parsing error: " + e.getMessage();
|
||||
//System.out.println(exceptionMessage);
|
||||
}
|
||||
|
||||
public void warning(SAXParseException e) {
|
||||
exceptionMessage = "Parsing error: " + e.getMessage();
|
||||
//System.out.println(exceptionMessage);
|
||||
}
|
||||
|
||||
public void fatalError(SAXParseException e) {
|
||||
exceptionMessage = "Parsing error: " + e.getMessage();
|
||||
//System.out.println(exceptionMessage);
|
||||
//System.out.println("Cannot continue.");
|
||||
//System.exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the exception message.
|
||||
*
|
||||
* @return a text message describing the exception.
|
||||
*/
|
||||
public String getExceptionMessage() {
|
||||
return exceptionMessage;
|
||||
}
|
||||
|
||||
}
|
168
trick_source/java/src/trick/common/utils/LogHeaderReader.java
Normal file
@ -0,0 +1,168 @@
|
||||
/*
|
||||
* $Id: LogHeaderReader.java 3544 2014-05-30 21:00:01Z hchen3 $
|
||||
*
|
||||
*/
|
||||
|
||||
//========================================
|
||||
// Package
|
||||
//========================================
|
||||
package trick.common.utils;
|
||||
|
||||
//========================================
|
||||
// Imports
|
||||
//========================================
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.Scanner;
|
||||
|
||||
import trick.common.utils.LogVar.DisplayType;
|
||||
|
||||
|
||||
/**
|
||||
* This data reader is for reading Trick log header data.
|
||||
*
|
||||
*
|
||||
* @since Trick 10
|
||||
*/
|
||||
public class LogHeaderReader extends DataReader{
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Private Data
|
||||
//========================================
|
||||
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
/**
|
||||
* Constructs a reader with specified file name.
|
||||
*
|
||||
* @param fileName The name of the file.
|
||||
*/
|
||||
public LogHeaderReader(String fileName) {
|
||||
super(fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a reader with specified file.
|
||||
*
|
||||
* @param file An instance of {@link File} for the reader to read.
|
||||
*/
|
||||
public LogHeaderReader(File file) {
|
||||
super(file);
|
||||
}
|
||||
|
||||
|
||||
//========================================
|
||||
// Set/Get methods
|
||||
//========================================
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
/**
|
||||
* Processes the recorded data. Required by {@link DataReader}.
|
||||
*/
|
||||
@Override
|
||||
protected void processHeader() throws FileNotFoundException, IOException {
|
||||
parseContents();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the contents from the file as a {@link List}.
|
||||
*
|
||||
* @return A {@link List} of data objects representing all needed data in the recorded file.
|
||||
*/
|
||||
private void parseContents() throws FileNotFoundException {
|
||||
Scanner scanner = new Scanner(dataFile);
|
||||
try {
|
||||
//first use a Scanner to get each line
|
||||
while ( scanner.hasNextLine() ){
|
||||
Object eachLine = processLine(scanner.nextLine());
|
||||
if (eachLine != null) {
|
||||
recordedVarList.add(eachLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
//ensure the underlying stream is always closed
|
||||
scanner.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a line of text. Required by {@link DataReader}.
|
||||
*
|
||||
* @return An object of {@link LogVar} to represent a line of recorded header data,
|
||||
* <code>null</code> if non-related data found in this line.
|
||||
*/
|
||||
private Object processLine(String theLine) {
|
||||
if (theLine.endsWith("ASCII")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
LogVar varObj = null;
|
||||
//use a second Scanner to parse the content of each line
|
||||
Scanner scanner = new Scanner(theLine);
|
||||
|
||||
// by default, the scanner uses whitespace for the delimiter
|
||||
// and this is what in recorded data
|
||||
if ( scanner.hasNext() ) {
|
||||
scanner.next(); // ignore the first item at each line
|
||||
String type = null;
|
||||
String units = null;
|
||||
String name = null;
|
||||
|
||||
if (scanner.hasNext()) {
|
||||
type = scanner.next();
|
||||
}
|
||||
if (scanner.hasNext()) {
|
||||
units = scanner.next();
|
||||
}
|
||||
if (scanner.hasNext()) {
|
||||
name = scanner.next();
|
||||
if ( ! type.equals("byte_order")) {
|
||||
varObj = new LogVar(name);
|
||||
varObj.setUnits(units);
|
||||
varObj.setRunDir(dataFile.getParent());
|
||||
varObj.setDisplay(DisplayType.NORMAL);
|
||||
varObj.setLevel(0);
|
||||
varObj.setCount(1);
|
||||
varObj.setIsFromLog(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
//no need for finally here, since String is source
|
||||
scanner.close();
|
||||
|
||||
return varObj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getVarValue() throws IOException {
|
||||
// there is no value in the header file
|
||||
return Double.NaN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endRead() {
|
||||
// do nothing
|
||||
}
|
||||
}
|
402
trick_source/java/src/trick/common/utils/LogVar.java
Normal file
@ -0,0 +1,402 @@
|
||||
/*
|
||||
* $Id: LogVar.java 3772 2015-01-06 18:23:32Z hchen3 $
|
||||
*
|
||||
*/
|
||||
|
||||
//========================================
|
||||
// Package
|
||||
//========================================
|
||||
package trick.common.utils;
|
||||
|
||||
//========================================
|
||||
// Imports
|
||||
//========================================
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
||||
/**
|
||||
* Defines each variable object for recorded data.
|
||||
*
|
||||
*
|
||||
* @since Trick 10
|
||||
*/
|
||||
public class LogVar implements Comparable<LogVar>, Serializable {
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
public enum DisplayType { NORMAL, EXPANDED, CONTRACTED, HIDDEN }
|
||||
|
||||
public static enum TrickType {
|
||||
TRICK_VOID,
|
||||
TRICK_CHARACTER,
|
||||
TRICK_UNSIGNED_CHARACTER,
|
||||
TRICK_STRING,
|
||||
TRICK_SHORT,
|
||||
TRICK_UNSIGNED_SHORT,
|
||||
TRICK_INTEGER,
|
||||
TRICK_UNSIGNED_INTEGER,
|
||||
TRICK_LONG,
|
||||
TRICK_UNSIGNED_LONG,
|
||||
TRICK_FLOAT,
|
||||
TRICK_DOUBLE,
|
||||
TRICK_BITFIELD,
|
||||
TRICK_UNSIGNED_BITFIELD,
|
||||
TRICK_LONG_LONG,
|
||||
TRICK_UNSIGNED_LONG_LONG,
|
||||
TRICK_FILE_PTR,
|
||||
TRICK_BOOLEAN,
|
||||
TRICK_WCHAR,
|
||||
TRICK_WSTRING,
|
||||
TRICK_VOID_PTR,
|
||||
TRICK_ENUMERATED,
|
||||
TRICK_STRUCTURED,
|
||||
TRICK_USER_DEFINED_TYPE,
|
||||
TRICK_NUMBER_OF_TYPES
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Private Data
|
||||
//========================================
|
||||
private static final long serialVersionUID = 1136627204616267499L;
|
||||
|
||||
|
||||
private String name;
|
||||
private String units;
|
||||
private String runDir; // for when run dir of this var is needed such as delta plot
|
||||
private TrickType type; // only needed when reading data out of a binary data file
|
||||
private int size; // needed when reading data out of a binary data file
|
||||
private DisplayType display; // tell how to display variable in list
|
||||
private int level; // number indicating what level of expansion this is for an arrayed variable
|
||||
private String sort_name; // name used for sorting in displayed varlist
|
||||
private int count; // count how many RUN dirs this variable is in
|
||||
|
||||
private boolean isFromLog; // flag to indicate if this var is really from the log file, not by gui creation
|
||||
|
||||
private DisplayType prevDisplay; // the place holder for previous display type of this variable, used if searching variable is performed
|
||||
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
/**
|
||||
* Constructor with specified variable name.
|
||||
*
|
||||
* @param name The name of the sim variable.
|
||||
*/
|
||||
public LogVar(String name) {
|
||||
this.name = name;
|
||||
this.setSortName(name);
|
||||
}
|
||||
/**
|
||||
* Copy constructor.
|
||||
*
|
||||
* @param obj The LogVar object to copy.
|
||||
*/
|
||||
public LogVar(Object obj) {
|
||||
if (! (obj instanceof LogVar)) {
|
||||
this.name = "";
|
||||
return;
|
||||
}
|
||||
LogVar source = (LogVar)obj;
|
||||
this.name = source.name;
|
||||
this.setSortName(source.name);
|
||||
this.units = source.units;
|
||||
this.runDir = source.runDir;
|
||||
this.type = source.type;
|
||||
this.display = source.display;
|
||||
this.level = source.level;
|
||||
this.count = source.count;
|
||||
}
|
||||
|
||||
|
||||
//========================================
|
||||
// Set/Get methods
|
||||
//========================================
|
||||
|
||||
/**
|
||||
* Sets the name for the variable.
|
||||
*
|
||||
* @param name The variable name.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
this.setSortName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the unit for the variable.
|
||||
*
|
||||
* @param units The variable unit.
|
||||
*/
|
||||
public void setUnits(String units) {
|
||||
this.units = units;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the run directory which the recorded data is in.
|
||||
*
|
||||
* @param dir The run directory.
|
||||
*/
|
||||
public void setRunDir(String dir) {
|
||||
runDir = dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the isFromLog flag.
|
||||
*/
|
||||
public void setIsFromLog(boolean b) {
|
||||
isFromLog = b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the variable data type.
|
||||
*
|
||||
* @param type The type of the variable.
|
||||
*/
|
||||
public void setType(TrickType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets how to display this variable in list.
|
||||
*
|
||||
* @param display true or false.
|
||||
*/
|
||||
public void setDisplay(DisplayType display) {
|
||||
this.display = display;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets expand level of this variable.
|
||||
*
|
||||
* @param level The expand level of the variable.
|
||||
*/
|
||||
public void setLevel(int level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the variable's sort name.
|
||||
* (if it's an expanded variable, name contains parent array name; any indices get leading zeros)
|
||||
*
|
||||
* @param name The sort name variable.
|
||||
*/
|
||||
public void setSortName(String name) {
|
||||
this.sort_name = name;
|
||||
// add leading zeros to all array indices (e.g. so x[10] does not come before x[2])
|
||||
// is this slow? seems to work ok
|
||||
String regex;
|
||||
Pattern p;
|
||||
Matcher m;
|
||||
regex = "\\[(\\d\\d\\d)\\]"; // [nnn] -> [0nnn]
|
||||
p = Pattern.compile(regex);
|
||||
m = p.matcher(this.sort_name);
|
||||
this.sort_name = m.replaceAll("\\[00$1\\]");
|
||||
regex = "\\[(\\d\\d)\\]"; // [nn] -> [00nn]
|
||||
p = Pattern.compile(regex);
|
||||
m = p.matcher(this.sort_name);
|
||||
this.sort_name = m.replaceAll("\\[00$1\\]");
|
||||
regex = "\\[(\\d)\\]"; // [n] -> [000n]
|
||||
p = Pattern.compile(regex);
|
||||
m = p.matcher(this.sort_name);
|
||||
this.sort_name = m.replaceAll("\\[000$1\\]");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets how many RUN dirs this variable belongs to.
|
||||
*
|
||||
* @param count The RUN dir count of the variable.
|
||||
*/
|
||||
public void setCount(int count) {
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the size of for this variable.
|
||||
*
|
||||
* @param size The size of this variable in bytes.
|
||||
*/
|
||||
public void setSize(int size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remembers the previous display type.
|
||||
*
|
||||
* @param prevDisplay The previous {@link LogVar.DisplayType} of this variable.
|
||||
*/
|
||||
public void setPrevDisplay(DisplayType prevDisplay) {
|
||||
this.prevDisplay = prevDisplay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the previous display type.
|
||||
*
|
||||
* @return The previous {@link LogVar.DisplayType} of this variable.
|
||||
*/
|
||||
public DisplayType getPrevDisplay() {
|
||||
return prevDisplay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the size of this variable.
|
||||
*
|
||||
* @return The size of this variable in bytes.
|
||||
*/
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the variable.
|
||||
*
|
||||
* @return The name of the variable.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the units of the variable.
|
||||
*
|
||||
* @return The units of the variable.
|
||||
*/
|
||||
public String getUnits() {
|
||||
return units;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of the variable
|
||||
*
|
||||
* @return The type of the variable.
|
||||
*/
|
||||
public TrickType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the run directory which the recorded data is in.
|
||||
*
|
||||
* @return The run directory.
|
||||
*/
|
||||
public String getRunDir() {
|
||||
return runDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the flag of isFromLog.
|
||||
*/
|
||||
public boolean getIsFromLog() {
|
||||
return isFromLog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if how th variable is to be displayed in list.
|
||||
*
|
||||
* @return true or false.
|
||||
*/
|
||||
public DisplayType getDisplay() {
|
||||
return display;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets expand level of this variable.
|
||||
*
|
||||
* @return The expand level of the variable.
|
||||
*/
|
||||
public int getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the variable's sort name.
|
||||
*
|
||||
* @return The sort name variable.
|
||||
*/
|
||||
public String getSortName() {
|
||||
return sort_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets how many RUN dirs this variable belongs to.
|
||||
*
|
||||
* @return The count of the variable.
|
||||
*/
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
/**
|
||||
* Overrides toString() method in Object class so that it returns the value
|
||||
* as desired instead of the value of
|
||||
* <blockquote>
|
||||
* <pre>
|
||||
* getClass().getName() + '@' + Integer.toHexString(hashCode())
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @return a string representation of the object.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return name + " (" + units + ")";
|
||||
}
|
||||
|
||||
/**
|
||||
* Required by Comparable interface. When two LogVar objects compare, only
|
||||
* name gets compared.
|
||||
*
|
||||
* @param o the object to be compared.
|
||||
* @return a negative integer, zero, or a positive integer as this object
|
||||
* is less than, equal to, or greater than the specified object.
|
||||
*/
|
||||
// this is what is used when sorting items in varlist
|
||||
public int compareTo(LogVar o) {
|
||||
if (name != null && o.name != null) {
|
||||
// sort name makes expanded variables be shown directly below their parent
|
||||
// also indices have leading zeros so components shown in numerical order
|
||||
String compare1 = sort_name;
|
||||
String compare2 = o.sort_name;
|
||||
return compare1.compareTo(compare2);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// must override equals so that calling contains for list of LogVars will work
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof LogVar)) {
|
||||
return false;
|
||||
}
|
||||
LogVar varObj = (LogVar) o;
|
||||
if (name != null && varObj.name != null) {
|
||||
return name.equals(varObj.name);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Serializable writeObject method - without this you get a NotSerializableException during drag/drop
|
||||
private void writeObject(
|
||||
ObjectOutputStream aOutputStream
|
||||
) throws IOException {
|
||||
//perform the default serialization for all non-transient, non-static fields
|
||||
aOutputStream.defaultWriteObject();
|
||||
}
|
||||
|
||||
}
|
222
trick_source/java/src/trick/common/utils/SortedListModel.java
Normal file
@ -0,0 +1,222 @@
|
||||
/*
|
||||
* $Id: SortedListModel.java 2266 2012-03-29 15:58:38Z hchen3 $
|
||||
*
|
||||
*/
|
||||
|
||||
//========================================
|
||||
// Package
|
||||
//========================================
|
||||
package trick.common.utils;
|
||||
|
||||
//========================================
|
||||
//Imports
|
||||
//========================================
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import javax.swing.AbstractListModel;
|
||||
|
||||
import org.jdesktop.swingx.JXList;
|
||||
|
||||
|
||||
/**
|
||||
* A class that extends {@link AbstractListModel} for providing a {@link JXList} with
|
||||
* sorted contents with uniqueness.
|
||||
*
|
||||
* @author Hong Chen
|
||||
* @since Trick 10
|
||||
*/
|
||||
public class SortedListModel extends AbstractListModel {
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
|
||||
|
||||
//========================================
|
||||
// Private Data
|
||||
//========================================
|
||||
|
||||
private static final long serialVersionUID = -4554077303172728923L;
|
||||
|
||||
/** For holding the data of the list. */
|
||||
private SortedSet<Object> set;
|
||||
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
/**
|
||||
* Constructs a SortedListModel.
|
||||
*/
|
||||
public SortedListModel() {
|
||||
set = new TreeSet<Object>();
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Set/Get methods
|
||||
//========================================
|
||||
/**
|
||||
* Gets the size of the list.
|
||||
*
|
||||
* @return The size of the list.
|
||||
*/
|
||||
public int getSize() {
|
||||
return set.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an element from the list based the index number.
|
||||
*
|
||||
* @param index The index number of the data from the list.
|
||||
*
|
||||
* @return An element at the specified index number from the list if possible, otherwise <code>null</code> is returned.
|
||||
*/
|
||||
public Object getElementAt(int index) {
|
||||
// in case, index is out of bound
|
||||
if (index < getSize()) {
|
||||
return set.toArray()[index];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets object from list with same name as the given element.
|
||||
*
|
||||
* @param element The element to get.
|
||||
*
|
||||
* @return The object with same name as element, or null if not in list.
|
||||
*/
|
||||
public Object getElement(Object element) {
|
||||
//if (set.contains(element)) {
|
||||
Object[] objs = set.toArray();
|
||||
String element_string;
|
||||
for (int ii=0; ii<objs.length; ii++) {
|
||||
if (element instanceof LogVar) {
|
||||
// ignore variable units
|
||||
element_string = ((LogVar)element).getName();
|
||||
} else {
|
||||
element_string = element.toString();
|
||||
}
|
||||
if (objs[ii].toString().startsWith(element_string)) {
|
||||
return objs[ii];
|
||||
}
|
||||
}
|
||||
//}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
/**
|
||||
* Returns the list as an array.
|
||||
*
|
||||
* @return The array of the data.
|
||||
*/
|
||||
public Object[] toArray() {
|
||||
return set.toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds one element to the list if it is not already present.
|
||||
*/
|
||||
public void add(Object element) {
|
||||
if (set.add(element)) {
|
||||
fireContentsChanged(this, 0, getSize());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all of the elements to the list.
|
||||
*/
|
||||
public void addAll(Object elements[]) {
|
||||
Collection<Object> c = Arrays.asList(elements);
|
||||
set.addAll(c);
|
||||
fireContentsChanged(this, 0, getSize());
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all of the elements from the list.
|
||||
*/
|
||||
public void clear() {
|
||||
set.clear();
|
||||
fireContentsChanged(this, 0, getSize());
|
||||
}
|
||||
/**
|
||||
* Redraw all elements of list -- need this when hiding rows.
|
||||
*/
|
||||
public void refresh() {
|
||||
fireContentsChanged(this, 0, getSize());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if the list contains the sepcified element.
|
||||
*
|
||||
* @param element Element whose presence in this list is to be tested.
|
||||
*
|
||||
* @return <code>true</code> if the list contains the specified element, <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean contains(Object element) {
|
||||
return set.contains(element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first element from the list.
|
||||
*
|
||||
* @return The first element of the list.
|
||||
*/
|
||||
public Object firstElement() {
|
||||
return set.first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the iterator over the elements in this list.
|
||||
*
|
||||
* @return An iterator over the elements in this list.
|
||||
*/
|
||||
public Iterator iterator() {
|
||||
return set.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last element from the list.
|
||||
*
|
||||
* @return The last element of the list.
|
||||
*/
|
||||
public Object lastElement() {
|
||||
return set.last();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified element from this list if it is present.
|
||||
*
|
||||
* @param element Element to be removed from this list, if present.
|
||||
*
|
||||
* @return <code>true</code> if this list contains the specified element, <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean removeElement(Object element) {
|
||||
if (getSize() < 0) {
|
||||
return false;
|
||||
}
|
||||
boolean removed = set.remove(element);
|
||||
if (removed) {
|
||||
fireContentsChanged(this, 0, getSize());
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Inner classes
|
||||
//========================================
|
||||
|
||||
|
||||
}
|
288
trick_source/java/src/trick/common/utils/TrickColors.java
Normal file
@ -0,0 +1,288 @@
|
||||
/*
|
||||
* $Id: TrickColors.java 3535 2014-05-22 19:25:51Z hchen3 $
|
||||
*
|
||||
*/
|
||||
|
||||
//========================================
|
||||
// Package
|
||||
//========================================
|
||||
package trick.common.utils;
|
||||
|
||||
//========================================
|
||||
//Imports
|
||||
//========================================
|
||||
import java.awt.Color;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Provides all colors supported for using its names.
|
||||
* Otherwise, the color code needs using.
|
||||
*
|
||||
* @author Hong Chen
|
||||
* @since Trick 13
|
||||
*/
|
||||
public class TrickColors {
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
|
||||
|
||||
//========================================
|
||||
// Private Data
|
||||
//========================================
|
||||
/** Map between color names and colors */
|
||||
private static Map<String, Color> name2color = new HashMap<String, Color>();
|
||||
|
||||
/** Map between colors and color names */
|
||||
private static Map<Color, String> color2name = new HashMap<Color, String>();
|
||||
|
||||
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
/**
|
||||
* Initialize colors map.
|
||||
*/
|
||||
private static void initColorsMap() {
|
||||
Field[] fields = TrickColors.class.getFields();
|
||||
for (Field field : fields) {
|
||||
if (field.getType().isAssignableFrom(Color.class)) {
|
||||
addColor(field.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to initialize the map.
|
||||
*/
|
||||
private static void addColor(String colorName, Color color) {
|
||||
name2color.put(colorName, color);
|
||||
color2name.put(color, colorName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to initialize the map.
|
||||
*/
|
||||
private static void addColor(String colorName) {
|
||||
addColor(colorName, getColorFromField(colorName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a color with the specified case-insensitive name.
|
||||
*/
|
||||
private static Color getColorFromField(String name) {
|
||||
try {
|
||||
Field colorField = TrickColors.class.getField(name.toLowerCase());
|
||||
return (Color) colorField.get(TrickColors.class);
|
||||
}
|
||||
catch (NoSuchFieldException exc) {
|
||||
}
|
||||
catch (SecurityException exc) {
|
||||
}
|
||||
catch (IllegalAccessException exc) {
|
||||
}
|
||||
catch (IllegalArgumentException exc) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a color with the specified case-insensitive name.
|
||||
*/
|
||||
public static String getName(Color color) {
|
||||
return color2name.get(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a color with the specified case-insensitive name.
|
||||
*/
|
||||
public static Color getColor(String name) {
|
||||
return name2color.get(name.toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a collection of all color names.
|
||||
*/
|
||||
public static Collection<String> colors() {
|
||||
return name2color.keySet();
|
||||
}
|
||||
|
||||
/** Transform a color string into a color object.
|
||||
*
|
||||
* @param s the color string
|
||||
* @return the color object
|
||||
*/
|
||||
public static Color decodeColor(String s) {
|
||||
if (s == null) {
|
||||
return null;
|
||||
}
|
||||
Color c;
|
||||
try {
|
||||
c = Color.decode(s);
|
||||
}
|
||||
catch (NumberFormatException exc) {
|
||||
c = TrickColors.getColor(s);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
public static final Color aliceblue = new Color(0xf0f8ff);
|
||||
public static final Color antiquewhite = new Color(0xfaebd7);
|
||||
public static final Color aqua = new Color(0x00ffff);
|
||||
public static final Color aquamarine = new Color(0x7fffd4);
|
||||
public static final Color azure = new Color(0xf0ffff);
|
||||
public static final Color beige = new Color(0xf5f5dc);
|
||||
public static final Color bisque = new Color(0xffe4c4);
|
||||
public static final Color black = new Color(0x000000);
|
||||
public static final Color blanchedalmond = new Color(0xffebcd);
|
||||
public static final Color blue = new Color(0x0000ff);
|
||||
public static final Color blueviolet = new Color(0x8a2be2);
|
||||
public static final Color brown = new Color(0xa52a2a);
|
||||
public static final Color burlywood = new Color(0xdeb887);
|
||||
public static final Color cadetblue = new Color(0x5f9ea0);
|
||||
public static final Color chartreuse = new Color(0x7fff00);
|
||||
public static final Color chocolate = new Color(0xd2691e);
|
||||
public static final Color coral = new Color(0xff7f50);
|
||||
public static final Color cornflowerblue = new Color(0x6495ed);
|
||||
public static final Color cornsilk = new Color(0xfff8dc);
|
||||
public static final Color crimson = new Color(0xdc143c);
|
||||
public static final Color cyan = new Color(0x00ffff);
|
||||
public static final Color darkblue = new Color(0x00008b);
|
||||
public static final Color darkcyan = new Color(0x008b8b);
|
||||
public static final Color darkgoldenrod = new Color(0xb8860b);
|
||||
public static final Color darkgray = new Color(0xa9a9a9);
|
||||
public static final Color darkgreen = new Color(0x006400);
|
||||
public static final Color darkkhaki = new Color(0xbdb76b);
|
||||
public static final Color darkmagenta = new Color(0x8b008b);
|
||||
public static final Color darkolivegreen = new Color(0x556b2f);
|
||||
public static final Color darkorange = new Color(0xff8c00);
|
||||
public static final Color darkorchid = new Color(0x9932cc);
|
||||
public static final Color darkred = new Color(0x8b0000);
|
||||
public static final Color darksalmon = new Color(0xe9967a);
|
||||
public static final Color darkseagreen = new Color(0x8fbc8f);
|
||||
public static final Color darkslateblue = new Color(0x483d8b);
|
||||
public static final Color darkslategray = new Color(0x2f4f4f);
|
||||
public static final Color darkturquoise = new Color(0x00ced1);
|
||||
public static final Color darkviolet = new Color(0x9400d3);
|
||||
public static final Color deeppink = new Color(0xff1493);
|
||||
public static final Color deepskyblue = new Color(0x00bfff);
|
||||
public static final Color dimgray = new Color(0x696969);
|
||||
public static final Color dodgerblue = new Color(0x1e90ff);
|
||||
public static final Color firebrick = new Color(0xb22222);
|
||||
public static final Color floralwhite = new Color(0xfffaf0);
|
||||
public static final Color forestgreen = new Color(0x228b22);
|
||||
public static final Color fuchsia = new Color(0xff00ff);
|
||||
public static final Color gainsboro = new Color(0xdcdcdc);
|
||||
public static final Color ghostwhite = new Color(0xf8f8ff);
|
||||
public static final Color gold = new Color(0xffd700);
|
||||
public static final Color goldenrod = new Color(0xdaa520);
|
||||
public static final Color gray = new Color(0x808080);
|
||||
public static final Color green = new Color(0x008000);
|
||||
public static final Color greenyellow = new Color(0xadff2f);
|
||||
public static final Color honeydew = new Color(0xf0fff0);
|
||||
public static final Color hotpink = new Color(0xff69b4);
|
||||
public static final Color indianred = new Color(0xcd5c5c);
|
||||
public static final Color indigo = new Color(0x4b0082);
|
||||
public static final Color ivory = new Color(0xfffff0);
|
||||
public static final Color khaki = new Color(0xf0e68c);
|
||||
public static final Color lavender = new Color(0xe6e6fa);
|
||||
public static final Color lavenderblush = new Color(0xfff0f5);
|
||||
public static final Color lawngreen = new Color(0x7cfc00);
|
||||
public static final Color lemonchiffon = new Color(0xfffacd);
|
||||
public static final Color lightblue = new Color(0xadd8e6);
|
||||
public static final Color lightcoral = new Color(0xf08080);
|
||||
public static final Color lightcyan = new Color(0xe0ffff);
|
||||
public static final Color lightgoldenrodyellow = new Color(0xfafad2);
|
||||
public static final Color lightgreen = new Color(0x90ee90);
|
||||
public static final Color lightgrey = new Color(0xd3d3d3);
|
||||
public static final Color lightpink = new Color(0xffb6c1);
|
||||
public static final Color lightsalmon = new Color(0xffa07a);
|
||||
public static final Color lightseagreen = new Color(0x20b2aa);
|
||||
public static final Color lightskyblue = new Color(0x87cefa);
|
||||
public static final Color lightslategray = new Color(0x778899);
|
||||
public static final Color lightsteelblue = new Color(0xb0c4de);
|
||||
public static final Color lightyellow = new Color(0xffffe0);
|
||||
public static final Color lime = new Color(0x00ff00);
|
||||
public static final Color limegreen = new Color(0x32cd32);
|
||||
public static final Color linen = new Color(0xfaf0e6);
|
||||
public static final Color magenta = new Color(0xff00ff);
|
||||
public static final Color maroon = new Color(0x800000);
|
||||
public static final Color mediumaquamarine = new Color(0x66cdaa);
|
||||
public static final Color mediumblue = new Color(0x0000cd);
|
||||
public static final Color mediumorchid = new Color(0xba55d3);
|
||||
public static final Color mediumpurple = new Color(0x9370db);
|
||||
public static final Color mediumseagreen = new Color(0x3cb371);
|
||||
public static final Color mediumslateblue = new Color(0x7b68ee);
|
||||
public static final Color mediumspringgreen = new Color(0x00fa9a);
|
||||
public static final Color mediumturquoise = new Color(0x48d1cc);
|
||||
public static final Color mediumvioletred = new Color(0xc71585);
|
||||
public static final Color midnightblue = new Color(0x191970);
|
||||
public static final Color mintcream = new Color(0xf5fffa);
|
||||
public static final Color mistyrose = new Color(0xffe4e1);
|
||||
public static final Color moccasin = new Color(0xffe4b5);
|
||||
public static final Color navajowhite = new Color(0xffdead);
|
||||
public static final Color navy = new Color(0x000080);
|
||||
public static final Color oldlace = new Color(0xfdf5e6);
|
||||
public static final Color olive = new Color(0x808000);
|
||||
public static final Color olivedrab = new Color(0x6b8e23);
|
||||
public static final Color orange = new Color(0xffa500);
|
||||
public static final Color orangered = new Color(0xff4500);
|
||||
public static final Color orchid = new Color(0xda70d6);
|
||||
public static final Color palegoldenrod = new Color(0xeee8aa);
|
||||
public static final Color palegreen = new Color(0x98fb98);
|
||||
public static final Color paleturquoise = new Color(0xafeeee);
|
||||
public static final Color palevioletred = new Color(0xdb7093);
|
||||
public static final Color papayawhip = new Color(0xffefd5);
|
||||
public static final Color peachpuff = new Color(0xffdab9);
|
||||
public static final Color peru = new Color(0xcd853f);
|
||||
public static final Color pink = new Color(0xffc0cb);
|
||||
public static final Color plum = new Color(0xdda0dd);
|
||||
public static final Color powderblue = new Color(0xb0e0e6);
|
||||
public static final Color purple = new Color(0x800080);
|
||||
public static final Color red = new Color(0xff0000);
|
||||
public static final Color rosybrown = new Color(0xbc8f8f);
|
||||
public static final Color royalblue = new Color(0x4169e1);
|
||||
public static final Color saddlebrown = new Color(0x8b4513);
|
||||
public static final Color salmon = new Color(0xfa8072);
|
||||
public static final Color sandybrown = new Color(0xf4a460);
|
||||
public static final Color seagreen = new Color(0x2e8b57);
|
||||
public static final Color seashell = new Color(0xfff5ee);
|
||||
public static final Color sienna = new Color(0xa0522d);
|
||||
public static final Color silver = new Color(0xc0c0c0);
|
||||
public static final Color skyblue = new Color(0x87ceeb);
|
||||
public static final Color slateblue = new Color(0x6a5acd);
|
||||
public static final Color slategray = new Color(0x708090);
|
||||
public static final Color snow = new Color(0xfffafa);
|
||||
public static final Color springgreen = new Color(0x00ff7f);
|
||||
public static final Color steelblue = new Color(0x4682b4);
|
||||
public static final Color tan = new Color(0xd2b48c);
|
||||
public static final Color teal = new Color(0x008080);
|
||||
public static final Color thistle = new Color(0xd8bfd8);
|
||||
public static final Color tomato = new Color(0xff6347);
|
||||
public static final Color turquoise = new Color(0x40e0d0);
|
||||
public static final Color violet = new Color(0xee82ee);
|
||||
public static final Color wheat = new Color(0xf5deb3);
|
||||
public static final Color white = new Color(0xffffff);
|
||||
public static final Color whitesmoke = new Color(0xf5f5f5);
|
||||
public static final Color yellow = new Color(0xffff00);
|
||||
public static final Color yellowgreen = new Color(0x9acd32);
|
||||
|
||||
static {
|
||||
initColorsMap();
|
||||
}
|
||||
}
|
@ -0,0 +1,228 @@
|
||||
/*
|
||||
* $Id: UnitInfixExpression.java 3288 2013-11-07 18:33:42Z hchen3 $
|
||||
*
|
||||
*/
|
||||
|
||||
//========================================
|
||||
// Package
|
||||
//========================================
|
||||
package trick.common.utils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
|
||||
public class UnitInfixExpression {
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
|
||||
public static final String OPERATORS="/*+-()123"; //ignore the "(" as an operator
|
||||
public static final Map<Character, Integer> OPERATOR_LEVELS = new HashMap<Character, Integer>();
|
||||
static {
|
||||
OPERATOR_LEVELS.put(')', 0);
|
||||
OPERATOR_LEVELS.put('1', 1);
|
||||
OPERATOR_LEVELS.put('2', 1);
|
||||
OPERATOR_LEVELS.put('3', 1);
|
||||
OPERATOR_LEVELS.put('*', 2);
|
||||
OPERATOR_LEVELS.put('/', 2);
|
||||
OPERATOR_LEVELS.put('+', 3);
|
||||
OPERATOR_LEVELS.put('-', 3);
|
||||
OPERATOR_LEVELS.put('(', 4);
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Private Data
|
||||
//========================================
|
||||
private String inputExpression = null;
|
||||
|
||||
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
public UnitInfixExpression(String expression) {
|
||||
inputExpression = expression;
|
||||
}
|
||||
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
/**
|
||||
* Returns a derived unit based on for the unit expression.
|
||||
*/
|
||||
public UnitType.Unit getUnit() {
|
||||
UnitType.Unit ret = null;
|
||||
|
||||
Stack<UnitType.Unit> unitStack = new Stack<UnitType.Unit>();
|
||||
Stack<Character> operationStack = new Stack<Character>();
|
||||
|
||||
StringBuffer unitBuf = new StringBuffer();
|
||||
|
||||
for (int i = 0; i < inputExpression.length(); i++ ) {
|
||||
char eachChar = inputExpression.charAt(i);
|
||||
|
||||
if (eachChar==' '){
|
||||
//ignore
|
||||
}
|
||||
else if (isValidOperator(eachChar)){
|
||||
if (!isLeftParen(eachChar) && unitBuf.length() > 0) {
|
||||
unitStack.push(UnitType.getPrimitiveUnit(unitBuf.toString()));
|
||||
unitBuf.setLength(0);
|
||||
}
|
||||
|
||||
if (operationStack.isEmpty() || isLeftParen(eachChar)){ //first item or left parenthesis
|
||||
operationStack.push(eachChar);
|
||||
}
|
||||
// if right parenthesis, evaluating the expression within the parenthesizes
|
||||
else if (isRightParen(eachChar)){
|
||||
evaluateUntilLeftParenthesis(unitStack, operationStack);
|
||||
|
||||
}
|
||||
//if the current operator has higher level than the first item in the stack, insert it
|
||||
else if (getHigherPrecedenceOperator(eachChar, operationStack.peek()) == eachChar){
|
||||
operationStack.push(eachChar);
|
||||
}
|
||||
//if the current operator has lower level, then the previous higher level of operation needs evaluating
|
||||
else{
|
||||
evaluateAndPushDerivedUnit(unitStack, operationStack);
|
||||
|
||||
//after evaluation of the higher pair, insert current operator
|
||||
operationStack.push(eachChar);
|
||||
}
|
||||
} else if (Character.isLetter(eachChar) || eachChar == '.' || eachChar == '-') { // if the character is a letter, appends to the unit string buffer
|
||||
unitBuf.append(eachChar);
|
||||
if ( i == inputExpression.length()-1){
|
||||
unitStack.push(UnitType.getPrimitiveUnit(unitBuf.toString())) ; //the last element
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//System.out.println("After all Unit Stack : "+unitStack);
|
||||
//System.out.println("After all Operation Stack : "+operationStack);
|
||||
|
||||
while (!operationStack.empty()){
|
||||
evaluateAndPushDerivedUnit(unitStack, operationStack);
|
||||
}
|
||||
|
||||
if (unitStack != null && unitStack.size() > 0) {
|
||||
return unitStack.pop();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to check if the specified character is a right parenthesis.
|
||||
*/
|
||||
private boolean isRightParen(Character operator) {
|
||||
|
||||
return operator == ')' ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to check if the specified character is a left parenthesis.
|
||||
*/
|
||||
private boolean isLeftParen(Character operator) {
|
||||
return operator == '(' ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for evaluating units and pushing the intermediate unit to the unit stack.
|
||||
*/
|
||||
private void evaluateAndPushDerivedUnit(Stack<UnitType.Unit> unitStack, Stack<Character> operationStack) {
|
||||
UnitType.Unit unit1 = null;
|
||||
UnitType.Unit unit2 = null;
|
||||
String derivedUnitName = "";
|
||||
UnitType.Unit derivedUnit = null;
|
||||
|
||||
Character operator = operationStack.pop();
|
||||
|
||||
switch (operator) {
|
||||
case '2':
|
||||
case '3':
|
||||
unit1 = unitStack.pop();
|
||||
derivedUnitName = unit1.abbreviation + operator;
|
||||
derivedUnit = new UnitType.Unit(derivedUnitName, derivedUnitName, false);
|
||||
derivedUnit.factor1 = unit1.factor1;
|
||||
if (operator == '2') {
|
||||
derivedUnit.factor1 = unit1.factor1 * unit1.factor1;
|
||||
derivedUnit.factor2 = unit1.factor2 * unit1.factor2;
|
||||
} else {
|
||||
derivedUnit.factor1 = unit1.factor1 * unit1.factor1 * unit1.factor1;
|
||||
derivedUnit.factor2 = unit1.factor2 * unit1.factor2 * unit1.factor2;
|
||||
}
|
||||
break;
|
||||
case '*':
|
||||
case '/':
|
||||
unit2 = unitStack.pop();
|
||||
unit1 = unitStack.pop();
|
||||
derivedUnitName = unit1.abbreviation + operator + unit2.abbreviation;
|
||||
derivedUnit = new UnitType.Unit(derivedUnitName, derivedUnitName, false);
|
||||
if (operator == '*' ) {
|
||||
derivedUnit.factor1 = unit1.factor1 * unit2.factor1;
|
||||
derivedUnit.factor2 = unit1.factor2 * unit2.factor2;
|
||||
} else {
|
||||
if (unit2.factor1 == 0.0) {
|
||||
derivedUnit.factor1 = unit1.factor1;
|
||||
} else {
|
||||
derivedUnit.factor1 = unit1.factor1 / unit2.factor1;
|
||||
}
|
||||
if (unit2.factor2 == 0.0) {
|
||||
derivedUnit.factor2 = unit1.factor2;
|
||||
} else {
|
||||
derivedUnit.factor2 = unit1.factor2 / unit2.factor2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (derivedUnit != null) {
|
||||
unitStack.push(derivedUnit);
|
||||
//System.out.println("derived unit " + derivedUnit.abbreviation + " factor1=" + derivedUnit.factor1 + "; factor2="+derivedUnit.factor2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for evaluating the expression until a left parenthesis.
|
||||
*/
|
||||
private void evaluateUntilLeftParenthesis(Stack<UnitType.Unit> unitStack, Stack<Character> operationStack) {
|
||||
|
||||
while (!operationStack.empty()){
|
||||
if (isLeftParen(operationStack.peek())){ //if the left parenthesis has been reached, then pop it up and exit
|
||||
operationStack.pop();
|
||||
break;
|
||||
}
|
||||
evaluateAndPushDerivedUnit(unitStack,operationStack);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to check if the specified character is a valid operator.
|
||||
*/
|
||||
private boolean isValidOperator(char input) {
|
||||
|
||||
if (OPERATORS.indexOf(input) != -1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for getting a higher level operator based on the predefined operator levels.
|
||||
*/
|
||||
private Character getHigherPrecedenceOperator(Character firstOperator, Character secondOperator){
|
||||
|
||||
return OPERATOR_LEVELS.get(firstOperator)<OPERATOR_LEVELS.get(secondOperator) ? firstOperator : secondOperator;
|
||||
|
||||
}
|
||||
|
||||
}
|
395
trick_source/java/src/trick/common/utils/UnitType.java
Normal file
@ -0,0 +1,395 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
//========================================
|
||||
// Package
|
||||
//========================================
|
||||
package trick.common.utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* enumerates the available categories of units. Each catagory contains the
|
||||
* specific units appropriate to its measure.
|
||||
*
|
||||
* @author Derek Bankieris
|
||||
*/
|
||||
public enum UnitType {
|
||||
|
||||
Angle(new ArrayList<Unit>() {{
|
||||
add(new Unit("radians", "r", false, 0.0, 1.0));
|
||||
add(new Unit("pico-radians", "pr", false, 0.0, 1.0 * PICO));
|
||||
add(new Unit("nano-radians", "nr", false, 0.0, 1.0 * NANO));
|
||||
add(new Unit("micro-radians", "ur", false, 0.0, 1.0 * MICRO));
|
||||
add(new Unit("milli-radians", "mr", false, 0.0, 1.0 * MILLI));
|
||||
add(new Unit("centi-radians", "cr", false, 0.0, 1.0 * CENTI));
|
||||
add(new Unit("deci-radians", "dr", false, 0.0, 1.0 * DECI));
|
||||
add(new Unit("degrees", "d", false, 0.0, 0.0174532925199433));
|
||||
add(new Unit("arc-seconds", "as", false, 0.0, 4.848136811095362e-06));
|
||||
add(new Unit("arc-minutes", "am", false, 0.0, 0.000290888208666));
|
||||
add(new Unit("revolutions", "rev", false, 0.0, 6.28318530717958647));
|
||||
}}),
|
||||
|
||||
Current(new ArrayList<Unit>() {{
|
||||
add(new Unit("amperes", "amp", true, 0.0, 1.0));
|
||||
}}),
|
||||
|
||||
Distance(new ArrayList<Unit>() {{
|
||||
add(new Unit("meters", "m", true, 0.0, 1.0));
|
||||
add(new Unit("inches", "in", false, 0.0, 0.0254));
|
||||
add(new Unit("feet", "ft", false, 0.0, 0.3048));
|
||||
add(new Unit("kilo-feet", "kft", false, 0.0, 0.3048 * KILO));
|
||||
add(new Unit("yards", "yd", false, 0.0, 0.9144));
|
||||
add(new Unit("miles", "mi", false, 0.0, 1609.344));
|
||||
add(new Unit("nautical-miles", "n.m.", false, 0.0, 1852.0));
|
||||
}}),
|
||||
|
||||
Energy(new ArrayList<Unit>() {{
|
||||
add(new Unit("joules", "J", true, 0.0, 1.0));
|
||||
add(new Unit("british-thermal-units", "BTU", false, 0.0, 1055.056));
|
||||
add(new Unit("tons-tnt", "TNT", false, 0.0, 4.184 * GIGA));
|
||||
}}),
|
||||
|
||||
Force(new ArrayList<Unit>() {{
|
||||
add(new Unit("newtons", "N", true, 0.0, 1.0));
|
||||
add(new Unit("ounces", "oz", false, 0.0, 0.27801385));
|
||||
add(new Unit("pounds-force", "lbf", false, 0.0, 4.4482216152605));
|
||||
}}),
|
||||
|
||||
Frequency(new ArrayList<Unit>() {{
|
||||
add(new Unit("hertz", "Hz", true, 0.0, 1.0));
|
||||
}}),
|
||||
|
||||
Gain(new ArrayList<Unit>() {{
|
||||
add(new Unit("decibels", "dB", false, 0.0, 1.0));
|
||||
}}),
|
||||
|
||||
Mass(new ArrayList<Unit>() {{
|
||||
add(new Unit("grams", "g", true, 0.0, MILLI));
|
||||
add(new Unit("metric-tons", "mt", false, 0.0, 1000.0));
|
||||
add(new Unit("slugs", "sl", false, 0.0, 14.5939029372064));
|
||||
add(new Unit("pounds-mass", "lbm", false, 0.0, 0.4535923697760192));
|
||||
}}),
|
||||
|
||||
Power(new ArrayList<Unit>() {{
|
||||
add(new Unit("watts", "W", true, 0.0, 1.0));
|
||||
add(new Unit("horse-power", "hp", false, 0.0, 745.69987));
|
||||
}}),
|
||||
|
||||
Pressure(new ArrayList<Unit>() {{
|
||||
add(new Unit("atmospheres", "atm", false, 0.0, 101325.00000));
|
||||
add(new Unit("pascals", "Pa", true, 0.0, 1.0));
|
||||
add(new Unit("milli-meters-mercury", "mmHg", false, 0.0, MILLI*133322.387415));
|
||||
add(new Unit("inches-mercury", "inHg", false, 0.0, 3386.389));
|
||||
add(new Unit("milli-meters-water", "mmWater", false, 0.0, MILLI*9806.65));
|
||||
add(new Unit("inches-water", "inWater", false, 0.0, 249.08891));
|
||||
}}),
|
||||
|
||||
Resistance(new ArrayList<Unit>() {{
|
||||
add(new Unit("ohms", "ohm", true, 0.0, 1.0));
|
||||
}}),
|
||||
|
||||
Temperature(new ArrayList<Unit>() {{
|
||||
add(new Unit("degrees-Celsius", "C", false, 0.0, 1.0));
|
||||
add(new Unit("degrees-Kelvin", "K", false, -273.15, 1.0));
|
||||
add(new Unit("degrees-Fahrenheit", "F", false, -17.777777777777778, 0.55555555555555556));
|
||||
add(new Unit("degrees-Rankine", "R", false, -273.15, 0.55555555555555556));
|
||||
}}),
|
||||
|
||||
Time(new ArrayList<Unit>() {{
|
||||
add(new Unit("seconds", "s", true, 0.0, 1.0));
|
||||
add(new Unit("minutes", "min", false, 0.0, 60.0));
|
||||
add(new Unit("hours", "hr", false, 0.0, 3600.0));
|
||||
add(new Unit("days", "day", false, 0.0, 86400.0));
|
||||
}}),
|
||||
|
||||
Unitless(new ArrayList<Unit>() {{
|
||||
add(new Unit("unitless", "--", false, 0.0, 1.0));
|
||||
add(new Unit("count", "cnt", false, 0.0, 1.0));
|
||||
add(new Unit("one", "one", false, 0.0, 1.0));
|
||||
add(new Unit("moles", "mol", false, 0.0, 6.02214179e+23));
|
||||
}}),
|
||||
|
||||
Voltage(new ArrayList<Unit>() {{
|
||||
add(new Unit("volts", "v", true, 0.0, 1.0));
|
||||
}}),
|
||||
|
||||
Volume(new ArrayList<Unit>() {{
|
||||
add(new Unit("liters", "l", true, 0.0, 1.0));
|
||||
add(new Unit("gallons", "gal", false, 0.0, 3.785412));
|
||||
add(new Unit("fluid-ounces", "floz", false, 0.0, 0.02957353));
|
||||
}});
|
||||
|
||||
public static final double PICO = 1e-12;
|
||||
public static final double NANO = 1e-09;
|
||||
public static final double MICRO = 1e-06;
|
||||
public static final double MILLI = 1e-03;
|
||||
public static final double CENTI = 1e-02;
|
||||
public static final double DECI = 1e-01;
|
||||
public static final double DECA = 1e+01;
|
||||
public static final double HECTO = 1e+2;
|
||||
public static final double KILO = 1e+3;
|
||||
public static final double MEGA = 1e+6;
|
||||
public static final double GIGA = 1e+9;
|
||||
public static final double TERA = 1e+12;
|
||||
|
||||
/** SI unit prefixes */
|
||||
private final Unit[] prefixes = {
|
||||
new Unit("pico-", "p", false, 0.0, PICO),
|
||||
new Unit("nana-", "n", false, 0.0, NANO),
|
||||
new Unit("micro-", "u", false, 0.0, MICRO),
|
||||
new Unit("milli-", "m", false, 0.0, MILLI),
|
||||
new Unit("centi-", "c", false, 0.0, CENTI),
|
||||
new Unit("deci-", "d", false, 0.0, DECI),
|
||||
new Unit("deca-", "da", false, 0.0, DECA),
|
||||
new Unit("hecto-", "h", false, 0.0, HECTO),
|
||||
new Unit("kilo-", "k", false, 0.0, KILO),
|
||||
new Unit("mega-", "M", false, 0.0, MEGA),
|
||||
new Unit("giga-", "G", false, 0.0, GIGA),
|
||||
new Unit("tera-", "T", false, 0.0, TERA)
|
||||
};
|
||||
|
||||
|
||||
public static final String OPERATORS="+-/*()^"; //ignore the "(" as an operator
|
||||
public static final Map<Character, Integer> OPERATOR_LEVELS = new HashMap<Character, Integer>();
|
||||
static {
|
||||
OPERATOR_LEVELS.put(')', 0);
|
||||
OPERATOR_LEVELS.put('^', 1);
|
||||
OPERATOR_LEVELS.put('*', 2);
|
||||
OPERATOR_LEVELS.put('/', 2);
|
||||
OPERATOR_LEVELS.put('+', 3);
|
||||
OPERATOR_LEVELS.put('-', 3);
|
||||
OPERATOR_LEVELS.put('(', 4);
|
||||
}
|
||||
|
||||
/** valid units for this type */
|
||||
private final ArrayList<Unit> units;
|
||||
|
||||
/**
|
||||
* constructs the type and adds prefixes to units that accept SI prefixes
|
||||
*
|
||||
* @param units the units appropriate to this type
|
||||
*/
|
||||
private UnitType(ArrayList<Unit> units) {
|
||||
this.units = units;
|
||||
ListIterator<Unit> iterator = units.listIterator();
|
||||
while (iterator.hasNext()) {
|
||||
Unit unit = iterator.next();
|
||||
if (unit.isPrefixable) {
|
||||
for (Unit prefix : prefixes) {
|
||||
iterator.add(new Unit(prefix.name + unit.name,
|
||||
prefix.abbreviation + unit.abbreviation, false, unit.factor1, prefix.factor2 * unit.factor2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gets all units appropriate for this <code>UnitType</code>
|
||||
*
|
||||
* @return the units available for this type
|
||||
*/
|
||||
public List<Unit> getAll() {
|
||||
return Collections.unmodifiableList(units);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the value of a specified units to the preferred units.
|
||||
*
|
||||
* @param fromValue
|
||||
* @param fromUnitStr
|
||||
* @param toUnitStr
|
||||
* @return new value based on the new units
|
||||
* @throws IllegalUnitConversionException
|
||||
*/
|
||||
public static double convertUnits(double fromValue, String fromUnitStr, String toUnitStr) throws IllegalUnitConversionException {
|
||||
Unit fromUnit = getExpressionUnit(fromUnitStr);
|
||||
Unit toUnit = getExpressionUnit(toUnitStr);
|
||||
|
||||
if (!isConvertible(fromUnitStr, toUnitStr)) {
|
||||
throw new IllegalUnitConversionException(fromUnitStr, toUnitStr);
|
||||
}
|
||||
|
||||
double derivedFactor1 = fromUnit.factor1 - toUnit.factor1 / toUnit.factor2;
|
||||
double derivedFactor2 = fromUnit.factor2 / toUnit.factor2;
|
||||
|
||||
return (fromValue * derivedFactor2 + derivedFactor1);
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the <code>UnitType</code> of which <code>abbreviation</code> is a
|
||||
* member. This method handles only simple units, not compound units
|
||||
* resulting from multiplication, division, or exponentiation.
|
||||
*
|
||||
* @return the corresponding type, or null if none exists
|
||||
*/
|
||||
public static UnitType getType(String abbreviation) {
|
||||
for (UnitType type : UnitType.values()) {
|
||||
for (Unit unit : type.getAll()) {
|
||||
if (unit.abbreviation.equals(abbreviation)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the primitive unit if it is a primitive units,
|
||||
* otherwise return a complex units that is made out of primitive units.
|
||||
*
|
||||
* @param expression
|
||||
* @return an instance of {@link Unit}
|
||||
*/
|
||||
public static Unit getExpressionUnit(String expression) {
|
||||
Unit ret = null;
|
||||
|
||||
ret = getPrimitiveUnit(expression);
|
||||
if (ret != null) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
UnitInfixExpression unitExpression = new UnitInfixExpression(expression);
|
||||
|
||||
ret = unitExpression.getUnit();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link Unit} based on its abbreviation.
|
||||
*
|
||||
* @param abbreviation the units abbreviation.
|
||||
* @return the corresponding Unit, or null if the abbreviation doesn't exist.
|
||||
*/
|
||||
public static Unit getPrimitiveUnit(String abbreviation) {
|
||||
Unit ret = null;
|
||||
for (UnitType type : UnitType.values()) {
|
||||
for (Unit unit : type.getAll()) {
|
||||
if (unit.abbreviation.equals(abbreviation)) {
|
||||
ret = unit;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets all valid unit alternatives for <code>expression</code>.
|
||||
* This method handles compound units resulting from multiplication,
|
||||
* division, or exponentiation.
|
||||
*/
|
||||
public static List<String> getAll(String expression) {
|
||||
ArrayList<String> results = new ArrayList<String>();
|
||||
Matcher matcher = Pattern.compile("([^\\d\\*/]+)(\\d*)").matcher(expression);
|
||||
if (matcher.find()) {
|
||||
UnitType type = UnitType.getType(matcher.group(1));
|
||||
if (type != null) {
|
||||
for (Unit unit : type.getAll()) {
|
||||
getAll(unit + matcher.group(2), expression.substring(matcher.end()), results);
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets all valid unit alternatives for <code>tail</code>, concatenating
|
||||
* each result to <code>head<code>, and appending each concatenation to
|
||||
* <code>results</code>. This method handles compound units resulting
|
||||
* from multiplication, division, or exponentiation.
|
||||
*
|
||||
* @param head the (already processed) head of the units expression
|
||||
* @param tail the (not yet processed) tai of the units expression
|
||||
* @param results the list to which to append results
|
||||
*/
|
||||
private static void getAll(String head, String tail, List<String> results) {
|
||||
Matcher matcher = Pattern.compile("(\\*|/)([^\\d\\*/]+)(\\d*)").matcher(tail);
|
||||
if (matcher.find()) {
|
||||
UnitType type = UnitType.getType(matcher.group(2));
|
||||
if (type != null) {
|
||||
for (Unit unit : type.getAll()) {
|
||||
getAll(head + matcher.group(1) + unit + matcher.group(3), tail.substring(matcher.end()), results);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
results.add(head);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if <code>fromUnits</code> can legally be converted to
|
||||
* </code>toUnits</code>. This method handles compound units resulting
|
||||
* from multiplication, division, or exponentiation.
|
||||
*
|
||||
* @param fromUnits the unit expression from which to convert
|
||||
* @param toUnits the unit expression to which to convert
|
||||
*
|
||||
* @return whether or not such a conversion is valid
|
||||
*/
|
||||
public static boolean isConvertible(String fromUnits, String toUnits) {
|
||||
return getAll(fromUnits).contains(toUnits);
|
||||
}
|
||||
|
||||
/**
|
||||
* represents a unit
|
||||
*/
|
||||
public static class Unit {
|
||||
|
||||
/** represents default units */
|
||||
public static final Unit DEFAULT_UNITS = new Unit("default", "xx", false);
|
||||
|
||||
/** the full name */
|
||||
public final String name;
|
||||
|
||||
/** the abbreviation to use following a value */
|
||||
public final String abbreviation;
|
||||
|
||||
public double factor1;
|
||||
public double factor2;
|
||||
|
||||
/** whether or not metric prefixes are valid */
|
||||
final boolean isPrefixable;
|
||||
|
||||
public Unit(String name, String abbreviation, boolean isPrefixable, double factor1, double factor2) {
|
||||
this(name, abbreviation, isPrefixable);
|
||||
this.factor1 = factor1;
|
||||
this.factor2 = factor2;
|
||||
}
|
||||
|
||||
/** constructor */
|
||||
public Unit(String name, String abbreviation, boolean isPrefixable) {
|
||||
this.name = name;
|
||||
this.abbreviation = abbreviation;
|
||||
this.isPrefixable = isPrefixable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return abbreviation;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception for handling illegal unit conversion.
|
||||
*/
|
||||
public static class IllegalUnitConversionException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 2800176399857985431L;
|
||||
|
||||
public IllegalUnitConversionException(String fromUnit, String toUnit) {
|
||||
super("Illegal Unit Conversion", new Throwable("Can't convert " + fromUnit + " -> " + toUnit));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,449 @@
|
||||
/*
|
||||
* $Id: VariableServerConnection.java 3760 2014-12-04 17:23:32Z dbankier $
|
||||
*/
|
||||
|
||||
package trick.common.utils;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
/**
|
||||
* a generic variable server client that provides for sending commands and
|
||||
* receiving responses. Currently only handles a subset of Trick types in binary
|
||||
* mode.
|
||||
*
|
||||
* @author Derek Bankieris
|
||||
*/
|
||||
public class VariableServerConnection {
|
||||
|
||||
/** maximum binary packet size sent by the Variable Server */
|
||||
public static final int maximumPacketSize = 8192;
|
||||
|
||||
/** Variable Server data mode */
|
||||
public enum DataMode {ASCII, BINARY, BINARY_NO_NAMES};
|
||||
|
||||
/** This really shouldn't be necessary. MTV needs to retrieve Variable Server data better. */
|
||||
public String results;
|
||||
|
||||
/** connection to the Variable Server */
|
||||
protected Socket socket;
|
||||
|
||||
/** Variable Server data mode */
|
||||
protected DataMode dataMode = DataMode.ASCII;
|
||||
|
||||
/** Variable Server synchronized mode */
|
||||
protected boolean sync = false;
|
||||
|
||||
/** tracks the paused status of the Variable Server */
|
||||
protected boolean isPaused = false;
|
||||
|
||||
/** receives commands from the Variable Server */
|
||||
protected BufferedReader inputStream;
|
||||
|
||||
/** sends commands to the Variable Server */
|
||||
protected DataOutputStream outputStream;
|
||||
|
||||
/**
|
||||
* attempts to connect to the Variable Server on the given host and port
|
||||
*
|
||||
* @param host Variable Server machine name
|
||||
* @param port Variable Server port number
|
||||
*/
|
||||
public VariableServerConnection(String host, int port) throws UnknownHostException, IOException, SecurityException {
|
||||
socket = new Socket(host, port);
|
||||
inputStream = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||
outputStream = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
|
||||
}
|
||||
|
||||
/**
|
||||
* sends the given command and any commands in the output stream's buffer
|
||||
* to the Variable Server. The command is written to the output stream,
|
||||
* and the buffer is flushed. A newline is automatically appended to the
|
||||
* given command.
|
||||
*
|
||||
* @param command the Variable Server command to be sent
|
||||
*/
|
||||
public void put(String command) throws IOException {
|
||||
outputStream.writeBytes(command + "\n");
|
||||
outputStream.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* writes the command to the output stream. A newline is
|
||||
* automatically appended. The buffer is not flushed.
|
||||
*
|
||||
* @param command the Variable Server command to be written
|
||||
*/
|
||||
public void write(String command) throws IOException {
|
||||
outputStream.writeBytes(command + "\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* flushes the buffer, sending any pending commands to the Variable
|
||||
* Server
|
||||
*/
|
||||
public void flush() throws IOException {
|
||||
outputStream.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* commands the Variable Server to send variable data in ASCII
|
||||
*/
|
||||
public void setAscii() throws IOException {
|
||||
if (dataMode != DataMode.ASCII) {
|
||||
put("trick.var_ascii()");
|
||||
dataMode = DataMode.ASCII;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* commands the Variable Server to send variable data in binary
|
||||
*/
|
||||
public void setBinary() throws IOException {
|
||||
if (dataMode != DataMode.BINARY) {
|
||||
put("trick.var_binary()");
|
||||
dataMode = DataMode.BINARY;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* commands the Variable Server to send variable data in binary and to
|
||||
* omit names
|
||||
*/
|
||||
public void setBinaryNoNames() throws IOException {
|
||||
if (dataMode != DataMode.BINARY_NO_NAMES) {
|
||||
put("trick.var_binary_nonames()");
|
||||
dataMode = DataMode.BINARY_NO_NAMES;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the Variable Server to synchronized mode
|
||||
*/
|
||||
public void setSync() throws IOException {
|
||||
if (!sync) {
|
||||
put("trick.var_sync(1)");
|
||||
sync = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* commands the Variable Server to stop sending data
|
||||
*/
|
||||
public void pause() throws IOException {
|
||||
put("trick.var_pause()");
|
||||
isPaused = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* commands the Variable Server to resume sending data
|
||||
*/
|
||||
public void unpause() throws IOException {
|
||||
put("trick.var_unpause()");
|
||||
isPaused = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the paused state of the Variable Server
|
||||
*
|
||||
* return whether or not the Variable Server is paused
|
||||
*/
|
||||
public boolean isPaused() {
|
||||
return isPaused;
|
||||
}
|
||||
|
||||
/**
|
||||
* adds the named variable to the Variable Server
|
||||
*
|
||||
* @param name the name of the variable to be added
|
||||
*/
|
||||
public void add(String name) throws IOException {
|
||||
put("trick.var_add(\"" + name + "\")");
|
||||
}
|
||||
|
||||
/**
|
||||
* adds the named variable to the Variable Server
|
||||
*
|
||||
* @param name the name of the variable to be added
|
||||
* @param units the units to use
|
||||
*/
|
||||
public void add(String name, String units) throws IOException {
|
||||
boolean invalidUnits = units == null || units.isEmpty();
|
||||
put("trick.var_add(\"" + name + (invalidUnits ? "" : "\", \"" + units) + "\")");
|
||||
}
|
||||
|
||||
/**
|
||||
* removes the named variable from the Variable Server
|
||||
*
|
||||
* @param name the name of the variable to be removeed
|
||||
*/
|
||||
public void remove(String name) throws IOException {
|
||||
put("trick.var_remove(\"" + name + "\")");
|
||||
}
|
||||
|
||||
/**
|
||||
* clears all variables from the Variable Server
|
||||
*/
|
||||
public void clear() throws IOException {
|
||||
put("trick.var_clear()");
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the period at which the Variable Server sends updates
|
||||
*
|
||||
* @param period the update period
|
||||
*/
|
||||
public void setCycle(double period) throws IOException {
|
||||
put("trick.var_cycle(" + period + ")");
|
||||
}
|
||||
|
||||
/**
|
||||
* requests a single update from the Variable Server
|
||||
*/
|
||||
public void poll() throws IOException {
|
||||
put("trick.var_send()");
|
||||
}
|
||||
|
||||
/**
|
||||
* attempts to resolve all invalid variables
|
||||
*/
|
||||
public void resolveInvalidReferences() throws IOException {
|
||||
put("trick.var_retry_bad_ref()");
|
||||
}
|
||||
|
||||
/**
|
||||
* sends a freeze command to the simulation
|
||||
*/
|
||||
public void freeze() throws IOException {
|
||||
put("trick.exec_freeze()");
|
||||
}
|
||||
|
||||
/**
|
||||
* sends a run command to the simulation
|
||||
*/
|
||||
public void run() throws IOException {
|
||||
put("trick.exec_run()");
|
||||
}
|
||||
|
||||
/**
|
||||
* sends an enable or disable real time command to the simulation
|
||||
*/
|
||||
public void setRealTimeEnabled(boolean enabled) throws IOException {
|
||||
put("trick.real_time_" + (enabled ? "enable" : "disable") + "()");
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the Variable Server's debug level
|
||||
*
|
||||
* @param level the debug level
|
||||
*/
|
||||
public void setDebugLevel(int level) throws IOException {
|
||||
put("trick.var_debug(" + level + ")");
|
||||
}
|
||||
|
||||
/**
|
||||
* sets this client's tag
|
||||
*
|
||||
* @param tag the tag that the Variable Server will associate with this client
|
||||
*/
|
||||
public void setClientTag(String tag) throws IOException {
|
||||
put("trick.var_set_client_tag(\"" + tag + "\")");
|
||||
}
|
||||
|
||||
// in binary mode, must convert C types (little endian) to java types (big endian)
|
||||
// return a java long (64bits) for bytes in buffer starting at i, size = 4 or 8
|
||||
/**
|
||||
* converts incoming binary data from little to big endian
|
||||
*/
|
||||
private long convertBinaryData(byte[] buffer, int index, int size) {
|
||||
long byte1, byte2, byte3, byte4, byte5, byte6, byte7, byte8;
|
||||
// int is size 4, longlong and double are size 8
|
||||
byte1 = (0xFF & ((int)buffer[index]));
|
||||
byte2 = (0xFF & ((int)buffer[index+1]));
|
||||
byte3 = (0xFF & ((int)buffer[index+2]));
|
||||
byte4 = (0xFF & ((int)buffer[index+3]));
|
||||
if (size==8) {
|
||||
byte5 = (0xFF & ((int)buffer[index+4]));
|
||||
byte6 = (0xFF & ((int)buffer[index+5]));
|
||||
byte7 = (0xFF & ((int)buffer[index+6]));
|
||||
byte8 = (0xFF & ((int)buffer[index+7]));
|
||||
// little -> big endian
|
||||
return (long) (byte8<<56 | byte7<<48 | byte6<<40 | byte5<<32 | byte4<<24 | byte3<<16 |
|
||||
byte2<<8 | byte1);
|
||||
} else {
|
||||
// little -> big endian
|
||||
return (long) (byte4<<24 | byte3<<16 | byte2<<8 | byte1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads characters into a portion of an array. This method will block until some input is available,
|
||||
* an I/O error occurs, or the end of the stream is reached.
|
||||
*
|
||||
* @param buffer destination buffer
|
||||
* @param index index within the buffer at which to start storing characters
|
||||
* @param maxCount maximum numbers of characters to read
|
||||
*
|
||||
* @return the number of characters read, or -1 if the end of the stream is reached
|
||||
*/
|
||||
public int read(char[] buffer, int index, int maxCount) throws IOException {
|
||||
return inputStream.read(buffer, index, maxCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* reads a line of data from the Variable Server. Values are tab-delimited.
|
||||
*
|
||||
* @return a tab-delimited line of data
|
||||
*/
|
||||
public String get() throws IOException {
|
||||
return get(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* reads the specified number of variables from the Variable Server. This
|
||||
* supports multiple binary packets.
|
||||
*
|
||||
* @return the tab-delimited data
|
||||
*/
|
||||
public String get(int num_variables) throws IOException {
|
||||
// num_variables (optional) is number of variables you expect to get (needed for binary multiple packet support)
|
||||
|
||||
int bytes_read, index, msg_size, len, type, size;
|
||||
int num_vars_processed, num_vars_in_msg;
|
||||
int ival;
|
||||
double dval;
|
||||
String name, typename, val;
|
||||
byte[] buffer = new byte[maximumPacketSize];
|
||||
String vals[] = new String[1000];
|
||||
int packet_count = 0;
|
||||
|
||||
if (dataMode == DataMode.ASCII) {
|
||||
results = inputStream.readLine();
|
||||
} else { // binary
|
||||
// handle multiple packets (continue reading if more variables and not eof of socket)
|
||||
num_vars_processed = 0;
|
||||
bytes_read = 0;
|
||||
results = "";
|
||||
while ((num_vars_processed < num_variables) && (bytes_read != -1)) {
|
||||
vals[packet_count] = "";
|
||||
// read binary header
|
||||
bytes_read = socket.getInputStream().read(buffer, 0, 12);
|
||||
if (bytes_read == -1) { // eof
|
||||
throw new IOException("Connection closed");
|
||||
}
|
||||
if ((int)buffer[0]==3) { // message indicator for send_event_data
|
||||
// simply a message header where msg_size=0 and num_vars_in_msg = number of event variables
|
||||
results += (int)convertBinaryData(buffer, 8, 4);
|
||||
return results;
|
||||
} else if ((int)buffer[0] != 0) {
|
||||
System.out.println("VarClient: Bad binary message indicator : " +(int)buffer[0]+ ".");
|
||||
return "";
|
||||
}
|
||||
msg_size = (int)convertBinaryData(buffer, 4, 4);
|
||||
//System.out.println("msg size=" + msg_size);
|
||||
num_vars_in_msg = (int)convertBinaryData(buffer, 8, 4);
|
||||
//System.out.println("numvars=" + num_vars_in_msg);
|
||||
if (num_variables==1) {
|
||||
// if user did not specify num_variables, get all vars in this message
|
||||
num_variables = num_vars_in_msg;
|
||||
}
|
||||
|
||||
// read binary data
|
||||
bytes_read = socket.getInputStream().read(buffer, 0, msg_size-8);
|
||||
//System.out.println("bytes_read=" + bytes_read);
|
||||
index = 0;
|
||||
while (index < bytes_read) {
|
||||
if (num_vars_processed > 0) {
|
||||
vals[packet_count] += "\t";
|
||||
}
|
||||
if (dataMode != DataMode.BINARY_NO_NAMES) {
|
||||
len = (int)convertBinaryData(buffer, index, 4);
|
||||
index += 4;
|
||||
name = new String(buffer, index, len);
|
||||
index += len;
|
||||
}
|
||||
type = (int)convertBinaryData(buffer, index, 4);
|
||||
index += 4;
|
||||
size = (int)convertBinaryData(buffer, index, 4);
|
||||
// Trick10 type of char* is CHAR, change it to CHARSTRING
|
||||
if ((type == 1) && (size > 1)) {
|
||||
type = 3 ;
|
||||
}
|
||||
//System.out.println("type=" + type + " size=" +size);
|
||||
|
||||
index += 4;
|
||||
switch (type) {
|
||||
case 1 : // CHAR
|
||||
case 17 : // BOOLEAN
|
||||
//typename = "CHAR";
|
||||
ival = (char)buffer[index];
|
||||
vals[packet_count] += ival;
|
||||
break;
|
||||
case 3 : // CHARSTRING
|
||||
//typename = "CHARSTRING";
|
||||
vals[packet_count] += new String(buffer, index, size-1); // do not include null terminator
|
||||
break;
|
||||
case 6 : // INT
|
||||
case 7 : // UNSIGNED INT
|
||||
case 21 : // ENUMERATED
|
||||
//typename = "INT";
|
||||
ival = (int)convertBinaryData(buffer, index, 4);
|
||||
vals[packet_count] += ival;
|
||||
break;
|
||||
case 11 : // DOUBLE
|
||||
//typename = "DOUBLE";
|
||||
dval = Double.longBitsToDouble(convertBinaryData(buffer, index, 8));
|
||||
vals[packet_count] += dval;
|
||||
break;
|
||||
case 14 : // LONGLONG
|
||||
//typename = "LONGLONG";
|
||||
dval = (double)convertBinaryData(buffer, index, 8);
|
||||
vals[packet_count] += dval;
|
||||
break;
|
||||
default :
|
||||
//typename = "???";
|
||||
System.out.println("VarClient: Unknown type " +type+ " in get().");
|
||||
break;
|
||||
}
|
||||
index += size;
|
||||
num_vars_processed++;
|
||||
} // while message data being parsed
|
||||
results += vals[packet_count];
|
||||
packet_count++;
|
||||
//System.out.println("pkt " +packet_count+ " : numvars_processed= "+num_vars_processed + " / " +num_variables);
|
||||
} // end while num_vars_processed < num_variables
|
||||
} // end binary
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* flushes any data that is still on the input stream
|
||||
*/
|
||||
public void flushInput() throws IOException {
|
||||
byte[] buffer = new byte[maximumPacketSize];
|
||||
int numAvailableBytes = socket.getInputStream().available();
|
||||
if (numAvailableBytes > 0) {
|
||||
int numBytesRead = socket.getInputStream().read(buffer, 0, numAvailableBytes);
|
||||
System.out.println("Flushed " + numBytesRead + " of " + numAvailableBytes +
|
||||
" available bytes.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* closes the connection to the Variable Server
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
try {
|
||||
put("trick.var_exit()");
|
||||
}
|
||||
finally {
|
||||
socket.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
237
trick_source/java/src/trick/common/utils/XMLCreator.java
Normal file
@ -0,0 +1,237 @@
|
||||
/*
|
||||
* $Id: XMLCreator.java 3375 2014-01-08 19:37:28Z hchen3 $
|
||||
*
|
||||
*/
|
||||
|
||||
//========================================
|
||||
// Package
|
||||
//========================================
|
||||
package trick.common.utils;
|
||||
|
||||
//========================================
|
||||
// Imports
|
||||
//========================================
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.OutputKeys;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Text;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This XML creator using Java API for XML Processing.
|
||||
*
|
||||
*
|
||||
* @since Trick 10
|
||||
*/
|
||||
public abstract class XMLCreator {
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
protected Document dom;
|
||||
protected Object rootObj;
|
||||
|
||||
//========================================
|
||||
// Private Data
|
||||
//========================================
|
||||
private String xmlFile;
|
||||
private String dtdFile;
|
||||
private String publicID;
|
||||
|
||||
private JFrame callerMainFrame;
|
||||
|
||||
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
public XMLCreator(){
|
||||
createDocument();
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Set/Get methods
|
||||
//========================================
|
||||
/**
|
||||
* Sets the XML file for parsing.
|
||||
*
|
||||
* @param xmlFile The XML file name.
|
||||
*/
|
||||
public void setXMLFile(String xmlFile) {
|
||||
this.xmlFile = xmlFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the root object of the XML.
|
||||
*
|
||||
* @param obj The root object.
|
||||
*/
|
||||
public void setRoot(Object obj) {
|
||||
rootObj = obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the DTD file for the XML.
|
||||
*
|
||||
* @param dtdFile The DTD file name for the XML.
|
||||
*/
|
||||
public void setDTDFile(String dtdFile){
|
||||
this.dtdFile = dtdFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the DTD public identifier.
|
||||
*
|
||||
* @param publicID The public identifier for the XML file.
|
||||
*/
|
||||
public void setPublicID(String publicID) {
|
||||
this.publicID = publicID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the frame that calls the XMLCreator to generate XML file.
|
||||
*/
|
||||
public void setCallerFrame(JFrame frame) {
|
||||
callerMainFrame = frame;
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
/**
|
||||
* Runs the XML creator to generate the XML file.
|
||||
*
|
||||
* @return True if the file is generated successfully, false otherwise.
|
||||
*/
|
||||
public boolean runCreator() {
|
||||
if (createDOMTree()) {
|
||||
printToFile();
|
||||
return true;
|
||||
} else {
|
||||
if (callerMainFrame != null) {
|
||||
JOptionPane.showMessageDialog(callerMainFrame,
|
||||
xmlFile + " could not be saved \n" + "because it doesn not have any plottable plot(s) or table(s) defined !",
|
||||
"File Not Created",
|
||||
JOptionPane.WARNING_MESSAGE);
|
||||
} else {
|
||||
System.out.println(xmlFile + " could not be saved because it doesn not have any plottable plot(s) or table(s) defined !");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Using JAXP in implementation independent manner create a document object
|
||||
* using which we create a xml tree in memory.
|
||||
*/
|
||||
private void createDocument() {
|
||||
//get an instance of factory
|
||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||
try {
|
||||
//get an instance of builder
|
||||
DocumentBuilder db = dbf.newDocumentBuilder();
|
||||
|
||||
//create an instance of DOM
|
||||
dom = db.newDocument();
|
||||
|
||||
} catch(ParserConfigurationException pce) {
|
||||
System.out.println("Error while trying to instantiate DocumentBuilder " + pce);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a child {@link Element} of the specified parent {@link Element}.
|
||||
*
|
||||
* @param parentElem The parent element which needs creating a child element for.
|
||||
* @param tagName The tag name of the child element.
|
||||
* @param tagText The text for the child element.
|
||||
*
|
||||
* @return A newly created element.
|
||||
*/
|
||||
protected Element createChildElement(Element parentElem, String tagName, String tagText) {
|
||||
if (tagText == null || "".equals(tagText.trim())) {
|
||||
return null;
|
||||
}
|
||||
Element childElem = dom.createElement(tagName);
|
||||
Text childText = dom.createTextNode(tagText);
|
||||
childElem.appendChild(childText);
|
||||
if (parentElem != null) {
|
||||
parentElem.appendChild(childElem);
|
||||
}
|
||||
return childElem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a child {@link Element} of the specified parent {@link Element}.
|
||||
*
|
||||
* @param parentElem The parent element which needs creating a child element for.
|
||||
* @param tagName The tag name of the child element.
|
||||
* @param tagObject The object for the child element.
|
||||
*
|
||||
* @return A newly created element.
|
||||
*/
|
||||
protected Element createChildElement(Element parentElem, String tagName, Object tagObject) {
|
||||
if (tagObject == null) {
|
||||
return null;
|
||||
}
|
||||
return createChildElement(parentElem, tagName, tagObject.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* This shall create the desired XML structure.
|
||||
*/
|
||||
protected abstract boolean createDOMTree();
|
||||
|
||||
|
||||
/**
|
||||
* Helper method which uses Java API for XML Processing
|
||||
* to print the XML document to file.
|
||||
*/
|
||||
private void printToFile(){
|
||||
try
|
||||
{
|
||||
Transformer tr = TransformerFactory.newInstance().newTransformer();
|
||||
tr.setOutputProperty(OutputKeys.INDENT, "yes");
|
||||
tr.setOutputProperty(OutputKeys.METHOD,"xml");
|
||||
tr.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
|
||||
tr.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1");
|
||||
tr.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, publicID);
|
||||
tr.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, dtdFile);
|
||||
|
||||
//to send the output to a file
|
||||
tr.transform( new DOMSource(dom),new StreamResult(new FileOutputStream(xmlFile)));
|
||||
|
||||
//to send the output to console
|
||||
//tr.transform( new DOMSource(dom),new StreamResult(System.out));
|
||||
|
||||
} catch(IOException ie) {
|
||||
ie.printStackTrace();
|
||||
} catch (TransformerException te) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
37
trick_source/java/src/trick/common/utils/vs/VSBoolean.java
Normal file
@ -0,0 +1,37 @@
|
||||
package trick.common.utils.vs;
|
||||
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
@XmlRootElement
|
||||
public class VSBoolean extends VSValue {
|
||||
|
||||
private static final long serialVersionUID = 3720173025885361193L;
|
||||
|
||||
public boolean value;
|
||||
|
||||
public VSBoolean() {}
|
||||
|
||||
public VSBoolean(boolean value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public boolean getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromVariableServer(String string) {
|
||||
value = Integer.parseInt(string.trim()) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toVariableServer() {
|
||||
return value ? "1" : "0";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Boolean.toString(value);
|
||||
}
|
||||
|
||||
}
|
39
trick_source/java/src/trick/common/utils/vs/VSByte.java
Normal file
@ -0,0 +1,39 @@
|
||||
package trick.common.utils.vs;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
@XmlRootElement
|
||||
public class VSByte extends VSValue {
|
||||
|
||||
private static final long serialVersionUID = 8405472938103497097L;
|
||||
|
||||
public byte value;
|
||||
|
||||
public VSByte() {}
|
||||
|
||||
public VSByte(byte value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public byte getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromVariableServer(String string) {
|
||||
value = new BigInteger(string.trim(), 10).byteValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toVariableServer() {
|
||||
return Byte.toString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Byte.toString(value);
|
||||
}
|
||||
|
||||
}
|
37
trick_source/java/src/trick/common/utils/vs/VSDouble.java
Normal file
@ -0,0 +1,37 @@
|
||||
package trick.common.utils.vs;
|
||||
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
@XmlRootElement
|
||||
public class VSDouble extends VSValue {
|
||||
|
||||
private static final long serialVersionUID = -2895628958106970334L;
|
||||
|
||||
public double value;
|
||||
|
||||
public VSDouble() {}
|
||||
|
||||
public VSDouble(double value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public double getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromVariableServer(String string) {
|
||||
value = Double.parseDouble(string.trim());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toVariableServer() {
|
||||
return Double.toString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Double.toString(value);
|
||||
}
|
||||
|
||||
}
|
37
trick_source/java/src/trick/common/utils/vs/VSFloat.java
Normal file
@ -0,0 +1,37 @@
|
||||
package trick.common.utils.vs;
|
||||
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
@XmlRootElement
|
||||
public class VSFloat extends VSValue {
|
||||
|
||||
private static final long serialVersionUID = -4629816234119061148L;
|
||||
|
||||
public float value;
|
||||
|
||||
public VSFloat() {}
|
||||
|
||||
public VSFloat(float value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public float getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromVariableServer(String string) {
|
||||
value = Float.parseFloat(string.trim());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toVariableServer() {
|
||||
return Float.toString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Float.toString(value);
|
||||
}
|
||||
|
||||
}
|
39
trick_source/java/src/trick/common/utils/vs/VSInteger.java
Normal file
@ -0,0 +1,39 @@
|
||||
package trick.common.utils.vs;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
@XmlRootElement
|
||||
public class VSInteger extends VSValue {
|
||||
|
||||
private static final long serialVersionUID = 1314788741378939173L;
|
||||
|
||||
public int value;
|
||||
|
||||
public VSInteger() {}
|
||||
|
||||
public VSInteger(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromVariableServer(String string) {
|
||||
value = new BigInteger(string.trim(), 10).intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toVariableServer() {
|
||||
return Integer.toString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Integer.toString(value);
|
||||
}
|
||||
|
||||
}
|
39
trick_source/java/src/trick/common/utils/vs/VSLong.java
Normal file
@ -0,0 +1,39 @@
|
||||
package trick.common.utils.vs;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
@XmlRootElement
|
||||
public class VSLong extends VSValue {
|
||||
|
||||
private static final long serialVersionUID = -7792501925528852232L;
|
||||
|
||||
public long value;
|
||||
|
||||
public VSLong() {}
|
||||
|
||||
public VSLong(long value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public long getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromVariableServer(String string) {
|
||||
value = new BigInteger(string.trim(), 10).longValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toVariableServer() {
|
||||
return Long.toString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Long.toString(value);
|
||||
}
|
||||
|
||||
}
|
39
trick_source/java/src/trick/common/utils/vs/VSShort.java
Normal file
@ -0,0 +1,39 @@
|
||||
package trick.common.utils.vs;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
@XmlRootElement
|
||||
public class VSShort extends VSValue {
|
||||
|
||||
private static final long serialVersionUID = 5431648313760456676L;
|
||||
|
||||
public short value;
|
||||
|
||||
public VSShort() {}
|
||||
|
||||
public VSShort(short value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public short getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromVariableServer(String string) {
|
||||
value = new BigInteger(string.trim(), 10).shortValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toVariableServer() {
|
||||
return Short.toString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Short.toString(value);
|
||||
}
|
||||
|
||||
}
|
37
trick_source/java/src/trick/common/utils/vs/VSString.java
Normal file
@ -0,0 +1,37 @@
|
||||
package trick.common.utils.vs;
|
||||
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
@XmlRootElement
|
||||
public class VSString extends VSValue {
|
||||
|
||||
private static final long serialVersionUID = 2238385297450301960L;
|
||||
|
||||
public String value;
|
||||
|
||||
public VSString() {}
|
||||
|
||||
public VSString(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromVariableServer(String string) {
|
||||
value = string;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toVariableServer() {
|
||||
return "\"" + value + "\"";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
15
trick_source/java/src/trick/common/utils/vs/VSValue.java
Normal file
@ -0,0 +1,15 @@
|
||||
package trick.common.utils.vs;
|
||||
|
||||
public abstract class VSValue implements VariableServerFluent, Cloneable {
|
||||
|
||||
@Override
|
||||
public VSValue clone() {
|
||||
try {
|
||||
return (VSValue)super.clone();
|
||||
}
|
||||
catch (CloneNotSupportedException cloneNotSupportedException) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
228
trick_source/java/src/trick/common/utils/vs/Variable.java
Normal file
@ -0,0 +1,228 @@
|
||||
package trick.common.utils.vs;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlElementRef;
|
||||
import javax.xml.bind.annotation.XmlElementRefs;
|
||||
|
||||
import trick.common.utils.VariableServerConnection;
|
||||
|
||||
/**
|
||||
* @author Derek Bankieris
|
||||
*
|
||||
* encapsulates the data necessary to represent a Variable Server variable
|
||||
*/
|
||||
public class Variable<T extends VariableServerFluent> implements Serializable, Cloneable {
|
||||
|
||||
private static final long serialVersionUID = 4529167759720494026L;
|
||||
|
||||
/** possible states */
|
||||
public enum State {Unknown, Invalid, Valid};
|
||||
|
||||
/** name */
|
||||
@XmlElement(required = true)
|
||||
public final String name;
|
||||
|
||||
/** value */
|
||||
@XmlElementRefs({
|
||||
@XmlElementRef(type=VSValue.class),
|
||||
@XmlElementRef(type=VSBoolean.class),
|
||||
@XmlElementRef(type=VSByte.class),
|
||||
@XmlElementRef(type=VSDouble.class),
|
||||
@XmlElementRef(type=VSFloat.class),
|
||||
@XmlElementRef(type=VSInteger.class),
|
||||
@XmlElementRef(type=VSLong.class),
|
||||
@XmlElementRef(type=VSShort.class),
|
||||
@XmlElementRef(type=VSString.class)
|
||||
})
|
||||
public final T value;
|
||||
|
||||
/** units */
|
||||
String units;
|
||||
|
||||
/** state */
|
||||
State state = State.Unknown;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*
|
||||
* @param name the name
|
||||
* @param value the initial value
|
||||
* @param units the initial units
|
||||
*/
|
||||
public Variable(String name, T value, String units) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
this.units = units;
|
||||
}
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*
|
||||
* @param name the name
|
||||
* @param value the initial value
|
||||
*/
|
||||
public Variable(String name, T value) {
|
||||
this(name, value, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* provided for JAXB compatibility
|
||||
*/
|
||||
private Variable() {
|
||||
name = null;
|
||||
value = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* sets this <code>Variable</code>'s value to <code>value</code>
|
||||
*
|
||||
* @param value the value to be set, expressed in Variable Server format
|
||||
*/
|
||||
public void setValue(String value) {
|
||||
if (value.equals("BAD_REF")) {
|
||||
state = State.Invalid;
|
||||
}
|
||||
else {
|
||||
this.value.fromVariableServer(value);
|
||||
state = State.Valid;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sets this <code>Variable</code>'s units to <code>units</code>
|
||||
*
|
||||
* @param units the units to be set
|
||||
*/
|
||||
public void setUnits(String units) {
|
||||
this.units = units;
|
||||
}
|
||||
|
||||
/**
|
||||
* commands the Variable Server to set the variable's value to <code>value</code>
|
||||
*
|
||||
* @param value the value to be sent
|
||||
*/
|
||||
public void sendValueToVariableServer(T value,
|
||||
VariableServerConnection variableServerConnection) throws IOException {
|
||||
boolean invalidUnits = units == null || units.isEmpty();
|
||||
variableServerConnection.put("trick.var_set(\"" +
|
||||
name + "\", " + value.toVariableServer() +
|
||||
(invalidUnits ? "" : ", \"" + units + "\"") + ")");
|
||||
}
|
||||
|
||||
/**
|
||||
* commands the Variable Server to set the variable's value to its current value
|
||||
*/
|
||||
public void sendValueToVariableServer(VariableServerConnection variableServerConnection)
|
||||
throws IOException {
|
||||
sendValueToVariableServer(value, variableServerConnection);
|
||||
}
|
||||
|
||||
/**
|
||||
* commands the Variable Server to set the variable's units to <code>units</code>
|
||||
*
|
||||
* @param units the units to be sent
|
||||
*/
|
||||
public void sendUnitsToVariableServer(String units,
|
||||
VariableServerConnection variableServerConnection) throws IOException {
|
||||
if (units != null && !units.isEmpty()) {
|
||||
variableServerConnection.put("trick.var_units(\"" + name + "\", \"" + units + "\")");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* commands the Variable Server to set the variable's units to its current units
|
||||
*/
|
||||
public void sendUnitsToVariableServer(VariableServerConnection variableServerConnection)
|
||||
throws IOException {
|
||||
sendUnitsToVariableServer(units, variableServerConnection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Equality among <code>Variable</code>s requires only that their names
|
||||
* be equal as implemented by <code>String.equals</code>.
|
||||
*
|
||||
* @param object the object to compare
|
||||
*
|
||||
* @return the equality of <code>object</code> to this <code>Variable</code>
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
return object != null && object instanceof Variable &&
|
||||
name.equals(((Variable)object).name);
|
||||
}
|
||||
|
||||
/**
|
||||
* a <code>Variable</code>'s hashcode is equal to the hashcode of its name
|
||||
*
|
||||
* @return a hashcode for this object
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return name.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the value
|
||||
*
|
||||
* @return the value
|
||||
*/
|
||||
public T getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the state
|
||||
*
|
||||
* @return the state
|
||||
*/
|
||||
public State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the name
|
||||
*
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the units
|
||||
*
|
||||
* @return the units
|
||||
*/
|
||||
@XmlElement(required = true)
|
||||
public String getUnits() {
|
||||
return units;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Variable<T> clone() {
|
||||
try {
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
new ObjectOutputStream(byteArrayOutputStream).writeObject(this);
|
||||
return (Variable<T>)new ObjectInputStream(new ByteArrayInputStream(
|
||||
byteArrayOutputStream.toByteArray())).readObject();
|
||||
}
|
||||
catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package trick.common.utils.vs;
|
||||
|
||||
/**
|
||||
* designates a class as being capable receiving variable events
|
||||
*
|
||||
* @author Derek Bankieris
|
||||
*/
|
||||
public interface VariableListener {
|
||||
|
||||
/** invoked after the variables have been updated */
|
||||
public void variablesUpdated();
|
||||
|
||||
/** invoked if an exception is thrown during variable tracking */
|
||||
public void variableUpdateFailed(Exception exception);
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package trick.common.utils.vs;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* designates a class as being compatible with Trick's Variable Server protocol
|
||||
*
|
||||
* @author Derek Bankieirs
|
||||
*/
|
||||
public interface VariableServerFluent extends Serializable {
|
||||
|
||||
/**
|
||||
* sets the state to reflect the value specified by the Variable Server <code>string</code>
|
||||
*
|
||||
* @param string the value from the Variable Server
|
||||
*/
|
||||
public void fromVariableServer(String string);
|
||||
|
||||
/**
|
||||
* returns the state formatted as a Variable Server string
|
||||
*
|
||||
* @return the state appropriately formatted for transmission to the Variable Server
|
||||
*/
|
||||
public String toVariableServer();
|
||||
|
||||
/**
|
||||
* returns a deep copy of this instance
|
||||
*
|
||||
* @return a deep copy of this instance
|
||||
*/
|
||||
public VariableServerFluent clone();
|
||||
|
||||
}
|
137
trick_source/java/src/trick/common/utils/vs/VariableTracker.java
Normal file
@ -0,0 +1,137 @@
|
||||
package trick.common.utils.vs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.swing.SwingWorker;
|
||||
|
||||
import trick.common.utils.VariableServerConnection;
|
||||
|
||||
/**
|
||||
* @author Derek Bankieris
|
||||
*/
|
||||
public class VariableTracker extends SwingWorker<Void, String[]> {
|
||||
|
||||
/** connection to the Variable Server */
|
||||
VariableServerConnection variableServerConnection;
|
||||
|
||||
/** variables being tracked */
|
||||
LinkedHashSet<Variable> variables = new LinkedHashSet<Variable>(10);
|
||||
|
||||
/** listeners to be informed of updates the the variables */
|
||||
ArrayList<VariableListener> variableListeners = new ArrayList<VariableListener>();
|
||||
|
||||
/** regular expression for finding units */
|
||||
Pattern pattern = Pattern.compile("^(.*?)\\s*(?:\\{(.*)\\})?$");
|
||||
|
||||
/**
|
||||
* sole constructor
|
||||
*
|
||||
* @param variableServerConnection connection to the Variable Server
|
||||
*/
|
||||
public VariableTracker(VariableServerConnection variableServerConnection) {
|
||||
this.variableServerConnection = variableServerConnection;
|
||||
}
|
||||
|
||||
/**
|
||||
* begin tracking <code>variable</code>
|
||||
*
|
||||
* @param variable the variable to track
|
||||
*/
|
||||
public void add(Variable variable) throws IOException {
|
||||
if (variables.add(variable)) {
|
||||
variableServerConnection.add(variable.name, variable.units);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* stops tracking <code>variable</code>
|
||||
*
|
||||
* @param variable the variable to stop tracking
|
||||
*/
|
||||
public void remove(Variable variable) throws IOException {
|
||||
variableServerConnection.remove(variable.getName());
|
||||
variables.remove(variable);
|
||||
}
|
||||
|
||||
/**
|
||||
* causes the <code>variableListener</code> to be notified of updates to the variables
|
||||
*
|
||||
* @param variableListener the listener to be notified
|
||||
*/
|
||||
public void addVariableListener(VariableListener variableListener) {
|
||||
variableListeners.add(variableListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* causes the <code>variableListener</code> to no longer be notified of updates to the variables
|
||||
*
|
||||
* @param variableListener the listener to be removed
|
||||
*/
|
||||
public void removeVariableListener(VariableListener variableListener) {
|
||||
variableListeners.remove(variableListener);
|
||||
}
|
||||
|
||||
/** Forever listen for incoming messages from the Variable Server. */
|
||||
@Override
|
||||
public Void doInBackground() throws IOException {
|
||||
while (true) {
|
||||
if (!isCancelled()) {
|
||||
String line = variableServerConnection.get();
|
||||
if (line == null) {
|
||||
throw new IOException("Reached end of stream.");
|
||||
}
|
||||
publish(line.split("\t", -1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* inform listeners that the variables have been updated
|
||||
*/
|
||||
@Override
|
||||
protected void process(List<String[]> valueList) {
|
||||
if (!isCancelled()) {
|
||||
String[] values = valueList.get(valueList.size() - 1);
|
||||
if (values.length == variables.size() + 1) {
|
||||
int i = 1;
|
||||
for (Variable variable : variables) {
|
||||
Matcher matcher = pattern.matcher(values[i]);
|
||||
matcher.find();
|
||||
variable.setValue(matcher.group(1));
|
||||
String units = matcher.group(2);
|
||||
if (units != null) {
|
||||
variable.setUnits(units);
|
||||
}
|
||||
++i;
|
||||
}
|
||||
for (VariableListener variableListener : variableListeners) {
|
||||
variableListener.variablesUpdated();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** executed on the Event Dispatch Thread after the doInBackground method is finished */
|
||||
@Override
|
||||
protected void done() {
|
||||
if (!isCancelled()) {
|
||||
try {
|
||||
// Check for any exception that occurred during execution by calling get().
|
||||
get();
|
||||
}
|
||||
catch (Exception exception) {
|
||||
for (VariableListener variableListener : variableListeners) {
|
||||
variableListener.variableUpdateFailed(exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,652 @@
|
||||
/*
|
||||
* $Id: DataProductsApplication.java 3761 2014-12-04 18:48:47Z hchen3 $
|
||||
*
|
||||
*/
|
||||
|
||||
//========================================
|
||||
// Package
|
||||
//========================================
|
||||
package trick.dataproducts;
|
||||
|
||||
//========================================
|
||||
// Imports
|
||||
//========================================
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.ComponentOrientation;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.FlowLayout;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
import javax.swing.Box;
|
||||
import javax.swing.ButtonGroup;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JRadioButtonMenuItem;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.JToggleButton;
|
||||
import javax.swing.SwingWorker;
|
||||
|
||||
import org.jdesktop.application.Action;
|
||||
import org.jdesktop.application.View;
|
||||
import org.jdesktop.swingx.JXMultiSplitPane;
|
||||
import org.jdesktop.swingx.MultiSplitLayout;
|
||||
|
||||
import trick.common.TrickApplication;
|
||||
import trick.common.ui.UIUtils;
|
||||
import trick.common.ui.components.NumberTextField;
|
||||
import trick.dataproducts.trickqp.TrickQPApplication;
|
||||
import trick.dataproducts.utils.Session;
|
||||
import trick.dataproducts.utils.SessionRun;
|
||||
import trick.dataproducts.utils.SessionXMLCreator;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Data Products Application that extends {@link TrickApplication}.
|
||||
*
|
||||
* @author Hong Chen
|
||||
* @since Trick 10
|
||||
*/
|
||||
public abstract class DataProductsApplication extends TrickApplication {
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
public JTextField versionField;
|
||||
public JTextField titleField;
|
||||
public NumberTextField startField;
|
||||
public NumberTextField stopField;
|
||||
public NumberTextField freqField;
|
||||
|
||||
public JTextArea statusArea;
|
||||
|
||||
public SessionRun runToConfigure;
|
||||
|
||||
public String sessionFile;
|
||||
|
||||
public File fileDevice;
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
protected JLabel versionLabel;
|
||||
protected JLabel titleLabel;
|
||||
protected JLabel startLabel;
|
||||
protected JLabel stopLabel;
|
||||
protected JLabel freqLabel;
|
||||
|
||||
// radio buttons for plot utility
|
||||
protected ButtonGroup radioButtonGroup;
|
||||
protected JRadioButtonMenuItem fermiRadioButton;
|
||||
protected JRadioButtonMenuItem javaRadioButton;
|
||||
protected JRadioButtonMenuItem gnuplotRadioButton;
|
||||
|
||||
protected JToggleButton gnuplotButton;
|
||||
|
||||
protected String plotDevice = Session.DEVICE_OPTIONS[Session.TERMINAL_DEVICE];
|
||||
protected String gnuplotTerminal = Session.GNUPLOT_TERMINAL_OPTIONS[Session.X11_GNUPLOT_TERMINAL];
|
||||
|
||||
|
||||
protected static String TEMP_DP_FILE = "/tmp/DP_" + System.getenv("USER") + ".xml";
|
||||
protected static String TEMP_SESSION_FILE = "/tmp/Session_" + System.getenv("USER") + ".xml";
|
||||
|
||||
|
||||
//========================================
|
||||
// Private Data
|
||||
//========================================
|
||||
private String plotCommand;
|
||||
|
||||
// Options are: "Simple", "Comparison", "Delta", "Contrast"
|
||||
private String preferredPresentation;
|
||||
|
||||
// Options are: "Plot", "Table".
|
||||
private String displayMode;
|
||||
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
|
||||
|
||||
//========================================
|
||||
// Set/Get methods
|
||||
//========================================
|
||||
/**
|
||||
* Sets the preferred presentation.
|
||||
*/
|
||||
public void setPreferredPresentation(String pt) {
|
||||
preferredPresentation = pt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the preferred presentation.
|
||||
*/
|
||||
public String getPreferredPresentation() {
|
||||
return preferredPresentation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets preferred display mode.
|
||||
*/
|
||||
public void setDisplayMode(String md) {
|
||||
displayMode = md;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets preferred display mode.
|
||||
*/
|
||||
public String getDisplayMode() {
|
||||
return displayMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the common bottom component if this is what you want.
|
||||
*
|
||||
* @return An instance of {@link JComponent}.
|
||||
*/
|
||||
protected JComponent getCommonBottom() {
|
||||
JPanel panel = new JPanel();
|
||||
panel.setPreferredSize(new Dimension(600, 180));
|
||||
|
||||
panel.setLayout(new BorderLayout());
|
||||
JPanel fieldsPanel = new JPanel();
|
||||
FlowLayout flowLayout = new FlowLayout();
|
||||
fieldsPanel.setLayout(flowLayout);
|
||||
flowLayout.setAlignment(FlowLayout.LEADING);
|
||||
fieldsPanel.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
|
||||
|
||||
if (DataProductsApplication.getInstance() instanceof TrickQPApplication) {
|
||||
titleLabel = new JLabel("Title:");
|
||||
titleField = new JTextField(15);
|
||||
fieldsPanel.add(titleLabel);
|
||||
fieldsPanel.add(titleField);
|
||||
fieldsPanel.add(Box.createHorizontalStrut(10));
|
||||
}
|
||||
|
||||
versionLabel = new JLabel("Version:");
|
||||
versionField = new JTextField("1.0", 2);
|
||||
fieldsPanel.add(versionLabel);
|
||||
fieldsPanel.add(versionField);
|
||||
fieldsPanel.add(Box.createHorizontalStrut(10));
|
||||
|
||||
startLabel = new JLabel("Start:");
|
||||
startField = new NumberTextField("-1.0e20", 5);
|
||||
fieldsPanel.add(startLabel);
|
||||
fieldsPanel.add(startField);
|
||||
fieldsPanel.add(Box.createHorizontalStrut(10));
|
||||
|
||||
stopLabel = new JLabel("Stop:");
|
||||
stopField = new NumberTextField("1.0e20", 5);
|
||||
fieldsPanel.add(stopLabel);
|
||||
fieldsPanel.add(stopField);
|
||||
fieldsPanel.add(Box.createHorizontalStrut(10));
|
||||
|
||||
freqLabel = new JLabel("Freq:");
|
||||
freqField = new NumberTextField("0.0", 5);
|
||||
fieldsPanel.add(freqLabel);
|
||||
fieldsPanel.add(freqField);
|
||||
fieldsPanel.add(Box.createHorizontalStrut(10));
|
||||
|
||||
panel.add(fieldsPanel, BorderLayout.NORTH);
|
||||
|
||||
statusArea = new JTextArea();
|
||||
statusArea.setBackground(new Color(65, 65, 65));
|
||||
statusArea.setForeground(Color.white);
|
||||
panel.add(new JScrollPane(statusArea), BorderLayout.CENTER);
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
@Action
|
||||
public void configureRunTimename() {
|
||||
String msgStr1 = "Please specify the time name for the selected run\n";
|
||||
String msgStr2 = "\n\n";
|
||||
|
||||
if (runToConfigure != null) {
|
||||
msgStr2 = runToConfigure.getDir() + msgStr2 ;
|
||||
//String timeName = resourceMap.getString("default.timename");
|
||||
String timeName = DEFAULT_TIME_NAME;
|
||||
if (runToConfigure.getTimename() != null) {
|
||||
timeName = runToConfigure.getTimename();
|
||||
}
|
||||
Object inputValue = JOptionPane.showInputDialog(getMainFrame(), msgStr1+msgStr2, timeName);
|
||||
if (inputValue != null) {
|
||||
runToConfigure.setTimename(inputValue.toString());
|
||||
}
|
||||
} else {
|
||||
JOptionPane.showMessageDialog(getMainFrame(), "Please select a Run first!", "No Run Selected", JOptionPane.WARNING_MESSAGE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@Action
|
||||
public void toggleGnuplot() {
|
||||
if (gnuplotButton.isSelected()) {
|
||||
gnuplotButton.setIcon(resourceMap.getIcon("gnuplot.on.icon"));
|
||||
gnuplotRadioButton.setSelected(true);
|
||||
getAction("selectGnuplotTerminal").setEnabled(true);
|
||||
} else {
|
||||
gnuplotButton.setIcon(resourceMap.getIcon("gnuplot.off.icon"));
|
||||
if (gnuplotRadioButton.isSelected()) {
|
||||
fermiRadioButton.setSelected(true);
|
||||
}
|
||||
getAction("selectGnuplotTerminal").setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Action
|
||||
public void selectFermi() {
|
||||
gnuplotButton.setSelected(false);
|
||||
getAction("selectGnuplotTerminal").setEnabled(false);
|
||||
toggleGnuplot();
|
||||
}
|
||||
|
||||
@Action
|
||||
public void selectGnuplot() {
|
||||
gnuplotButton.setSelected(true);
|
||||
getAction("selectGnuplotTerminal").setEnabled(true);
|
||||
toggleGnuplot();
|
||||
}
|
||||
|
||||
@Action
|
||||
public void selectJavaPlot() {
|
||||
gnuplotButton.setSelected(false);
|
||||
getAction("selectGnuplotTerminal").setEnabled(false);
|
||||
toggleGnuplot();
|
||||
}
|
||||
|
||||
@Action
|
||||
public void selectTerminalDevice() {
|
||||
setDevice(Session.TERMINAL_DEVICE);
|
||||
}
|
||||
|
||||
@Action
|
||||
public void selectPrinterDevice() {
|
||||
setDevice(Session.PRINTER_DEVICE);
|
||||
}
|
||||
|
||||
@Action
|
||||
public void selectGnuplotTerminal() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Action
|
||||
public void selectX11() {
|
||||
setGnuplotTerminal(Session.X11_GNUPLOT_TERMINAL);
|
||||
}
|
||||
|
||||
@Action
|
||||
public void selectPSColor() {
|
||||
setGnuplotTerminal(Session.PS_COLOR_GNUPLOT_TERMINAL);
|
||||
}
|
||||
|
||||
@Action
|
||||
public void selectPSBW() {
|
||||
setGnuplotTerminal(Session.PS_BW_GNUPLOT_TERMINAL);
|
||||
}
|
||||
|
||||
@Action
|
||||
public void selectPNG() {
|
||||
setGnuplotTerminal(Session.PNG_GNUPLOT_TERMINAL);
|
||||
}
|
||||
|
||||
@Action
|
||||
public void selectEPS() {
|
||||
setGnuplotTerminal(Session.EPS_GNUPLOT_TERMINAL);
|
||||
}
|
||||
|
||||
@Action
|
||||
public void selectAQUA() {
|
||||
setGnuplotTerminal(Session.AQUA_GNUPLOT_TERMINAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up the socket communication before exiting the application.
|
||||
*/
|
||||
@Override
|
||||
protected void shutdown() {
|
||||
super.shutdown();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Makes initialization as needed. This is called before startup().
|
||||
*
|
||||
* @see #startup
|
||||
*/
|
||||
@Override
|
||||
protected void initialize(String[] args) {
|
||||
super.initialize(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts things such as establishing socket communication, and starting monitor tasks.
|
||||
* This is called after startup.
|
||||
*
|
||||
* @see #initialize
|
||||
* @see #startup
|
||||
*/
|
||||
@Override
|
||||
protected void ready() {
|
||||
createActionController();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts building GUI. This is called after initialize.
|
||||
* Once startup() is done, ready() is called.
|
||||
*
|
||||
* @see #initialize
|
||||
* @see #ready
|
||||
*/
|
||||
@Override
|
||||
protected void startup() {
|
||||
super.startup();
|
||||
|
||||
gnuplotButton = new JToggleButton();
|
||||
gnuplotButton.setAction(getAction("toggleGnuplot"));
|
||||
gnuplotButton.setText(null);
|
||||
gnuplotButton.setFocusable(false);
|
||||
|
||||
fermiRadioButton = new JRadioButtonMenuItem();
|
||||
fermiRadioButton.setAction(getAction("selectFermi"));
|
||||
fermiRadioButton.setSelected(true);
|
||||
|
||||
javaRadioButton = new JRadioButtonMenuItem(getAction("selectJavaPlot"));
|
||||
|
||||
gnuplotRadioButton = new JRadioButtonMenuItem();
|
||||
gnuplotRadioButton.setAction(getAction("selectGnuplot"));
|
||||
|
||||
radioButtonGroup = new ButtonGroup();
|
||||
radioButtonGroup.add(fermiRadioButton);
|
||||
radioButtonGroup.add(javaRadioButton);
|
||||
radioButtonGroup.add(gnuplotRadioButton);
|
||||
|
||||
|
||||
View view = getMainView();
|
||||
view.setComponent(createMainPanel());
|
||||
view.setMenuBar(createMenuBar());
|
||||
view.setToolBar(createToolBar());
|
||||
|
||||
show(view);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates the main panel. This is required by TrickApplication.
|
||||
*
|
||||
* @return a {@link JComponent} as the main panel.
|
||||
*/
|
||||
@Override
|
||||
protected JComponent createMainPanel() {
|
||||
|
||||
JXMultiSplitPane msp = new JXMultiSplitPane();
|
||||
|
||||
String layoutDef =
|
||||
"(COLUMN " +
|
||||
"(ROW weight=0.8 " +
|
||||
"(COLUMN weight=0.44 (LEAF name=left.top weight=0.55) " +
|
||||
" (LEAF name=left.middle weight=0.45) " +
|
||||
") " +
|
||||
"(COLUMN weight=0.56 (LEAF name=right.top weight=0.55) " +
|
||||
" (LEAF name=right.middle weight=0.45) " +
|
||||
") " +
|
||||
")" +
|
||||
"(LEAF name=bottom weight=0.2) " +
|
||||
")";
|
||||
MultiSplitLayout.Node modelRoot = MultiSplitLayout.parseModel( layoutDef );
|
||||
|
||||
msp.getMultiSplitLayout().setModel( modelRoot );
|
||||
|
||||
msp.add( createLeftTop(), "left.top" );
|
||||
msp.add( createLeftMiddle(), "left.middle" );
|
||||
msp.add( createRightTop(), "right.top" );
|
||||
msp.add( createRightMiddle(), "right.middle");
|
||||
msp.add( createBottom(), "bottom" );
|
||||
|
||||
msp.validate();
|
||||
|
||||
return msp;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates the component for left top.
|
||||
*/
|
||||
protected abstract JComponent createLeftTop();
|
||||
|
||||
/**
|
||||
* Creates the component for left middle.
|
||||
*/
|
||||
protected abstract JComponent createLeftMiddle();
|
||||
|
||||
/**
|
||||
* Creates the component for right top.
|
||||
*/
|
||||
protected abstract JComponent createRightTop();
|
||||
|
||||
/**
|
||||
* Creates the component for right middle.
|
||||
*/
|
||||
protected abstract JComponent createRightMiddle();
|
||||
|
||||
/**
|
||||
* Creates the component for the bottom.
|
||||
*/
|
||||
protected abstract JComponent createBottom();
|
||||
|
||||
|
||||
/**
|
||||
* Helper method for setting gnuplot terminal.
|
||||
*
|
||||
* @param index One of these: Session.X11_GNUPLOT_TERMINAL,
|
||||
* Session.PS_COLOR_GNUPLOT_TERMINAL,
|
||||
* Session.PW_BW_GNUPLOT_TERMINAL,
|
||||
* Session.PNG_GNUPLOT_TERMINAL,
|
||||
* Session.EPS_GNUPLOT_TERMINAL,
|
||||
* Session.AQUA_GNUPLOT_TERMINAL.
|
||||
*/
|
||||
private void setGnuplotTerminal(int index) {
|
||||
if (index >= 0 && index<Session.GNUPLOT_TERMINAL_OPTIONS.length) {
|
||||
gnuplotTerminal = Session.GNUPLOT_TERMINAL_OPTIONS[index];
|
||||
} else {
|
||||
gnuplotTerminal = Session.GNUPLOT_TERMINAL_OPTIONS[Session.X11_GNUPLOT_TERMINAL];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for setting plot device.
|
||||
*
|
||||
* @param index One of these: Session.TERMINAL_DEVICE,
|
||||
* Session.PRINTER_DEVICE,
|
||||
* Session.FILE_DEVICE.
|
||||
*/
|
||||
private void setDevice(int index) {
|
||||
if (index >= 0 && index<Session.DEVICE_OPTIONS.length) {
|
||||
plotDevice = Session.DEVICE_OPTIONS[index];
|
||||
} else {
|
||||
plotDevice = Session.DEVICE_OPTIONS[Session.TERMINAL_DEVICE];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets all commond fields if available.
|
||||
*/
|
||||
public void resetCommonFields() {
|
||||
if (titleField != null) {
|
||||
titleField.setText("");
|
||||
}
|
||||
versionField.setText("1.0");
|
||||
startField.setText("-1.0e20");
|
||||
stopField.setText("1.0e20");
|
||||
freqField.setText("0.0");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the action controller for the application.
|
||||
*/
|
||||
protected abstract void createActionController();
|
||||
|
||||
|
||||
/**
|
||||
* Saves {@link Session} related data to a specified file.
|
||||
*
|
||||
* @param session An instance of {@link Session}.
|
||||
* @param fileName The name of a file.
|
||||
* @param runData A list for runs.
|
||||
* @param productFilesData A list of dp files.
|
||||
*/
|
||||
public void saveSessionToFile(Session session, String fileName, Object[] runData, Object[] productFilesData) {
|
||||
if (fileName == null) {
|
||||
// User clicked a plot button, so create temporary session file
|
||||
sessionFile = TEMP_SESSION_FILE;
|
||||
} else {
|
||||
sessionFile = fileName;
|
||||
}
|
||||
|
||||
SessionXMLCreator xmlCreator = new SessionXMLCreator();
|
||||
xmlCreator.setXMLFile(sessionFile);
|
||||
xmlCreator.setDTDFile("Session.dtd");
|
||||
xmlCreator.setPublicID("-//Tricklab//DTD Session V1.0//EN");
|
||||
|
||||
session.setVersion(versionField.getText());
|
||||
// session file doesn't have title, add this back if it needs it.
|
||||
//if (!titleField.getText().isEmpty()) {
|
||||
//session.setTitle(titleField.getText());
|
||||
//}
|
||||
session.setDevice(plotDevice);
|
||||
if (gnuplotButton.isSelected()) {
|
||||
session.setGnuplotTerminal(gnuplotTerminal);
|
||||
}
|
||||
|
||||
session.setTStart((Double)startField.getValue());
|
||||
session.setTStop((Double)stopField.getValue());
|
||||
session.setFrequency((Double)freqField.getValue());
|
||||
xmlCreator.setRoot(session);
|
||||
|
||||
for (int i = 0; i < runData.length; i++) {
|
||||
SessionRun sr = null;
|
||||
|
||||
if (runData[i] instanceof SessionRun) {
|
||||
sr = (SessionRun)runData[i];
|
||||
} else {
|
||||
sr = new SessionRun(runData[i].toString());
|
||||
}
|
||||
|
||||
session.addRun(sr);
|
||||
}
|
||||
for (int i = 0; i < productFilesData.length; i++) {
|
||||
session.addProductFile(productFilesData[i].toString());
|
||||
}
|
||||
xmlCreator.runCreator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Launches the external program for plotting.
|
||||
*
|
||||
* @param sessionFile The session used for plotting.
|
||||
*/
|
||||
public void launchPlotProgram(String sessionFile) {
|
||||
if (fermiRadioButton.isSelected()) {
|
||||
plotCommand = resourceMap.getString("fxplot.command");
|
||||
} else if (javaRadioButton.isSelected()) {
|
||||
plotCommand = resourceMap.getString("jxplot.command");
|
||||
} else if (gnuplotRadioButton.isSelected()) {
|
||||
plotCommand = resourceMap.getString("gxplot.command");
|
||||
}
|
||||
|
||||
plotCommand = UIUtils.getTrickBin() + File.separator + plotCommand;
|
||||
(new LaunchPlotProcessTask(plotCommand, sessionFile)).execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Launches a process with specified parameters.
|
||||
*
|
||||
* @param command The operating system program and arguments.
|
||||
*/
|
||||
public void launchPlotProcess(String... command) throws Exception{
|
||||
if (command == null || command.length < 0) {
|
||||
printStatusMessage("No plotting command specified!\n");
|
||||
return;
|
||||
}
|
||||
if (plotDevice.equals(Session.DEVICE_OPTIONS[Session.FILE_DEVICE])) {
|
||||
printStatusMessage("Generating postscript file(s) ...\n");
|
||||
} else {
|
||||
printStatusMessage("===>>>Launching " + command[0] + "<<<===\n");
|
||||
}
|
||||
ProcessBuilder pb = new ProcessBuilder(command);
|
||||
|
||||
captureProcessMessage(pb.start());
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirects runtime process messages from screen to GUI status area.
|
||||
*
|
||||
* @param runtimeProcess The runtime process from which screen messages is generated.
|
||||
*/
|
||||
public void captureProcessMessage(Process runtimeProcess) {
|
||||
try {
|
||||
if (runtimeProcess == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
BufferedReader stdInput = new BufferedReader(new InputStreamReader(runtimeProcess.getInputStream()));
|
||||
|
||||
BufferedReader stdError = new BufferedReader(new InputStreamReader(runtimeProcess.getErrorStream()));
|
||||
|
||||
String s = null;
|
||||
|
||||
// read the output from the command
|
||||
while ((s = stdInput.readLine()) != null) {
|
||||
printStatusMessage(s + "\n");
|
||||
}
|
||||
|
||||
// read any errors from the attempted command
|
||||
while ((s = stdError.readLine()) != null) {
|
||||
printStatusMessage(s + "\n");
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
printStatusMessage(ioe.getMessage() + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints status message to the status text area.
|
||||
*/
|
||||
public void printStatusMessage(String msg) {
|
||||
statusArea.append(msg);
|
||||
}
|
||||
|
||||
|
||||
private class LaunchPlotProcessTask extends SwingWorker<Void, Void> {
|
||||
private String[] processCommand;
|
||||
public LaunchPlotProcessTask(String... command) {
|
||||
this.processCommand = command;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void doInBackground() {
|
||||
try {
|
||||
launchPlotProcess(processCommand);
|
||||
} catch (Exception e) {
|
||||
printStatusMessage("Error launching plotting process!\n");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void done() {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,799 @@
|
||||
/*
|
||||
* $Id: JXPlotApplication.java 3795 2015-02-11 19:35:28Z alin $
|
||||
*/
|
||||
|
||||
package trick.dataproducts.plot;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.FieldPosition;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.swing.DefaultListModel;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JSeparator;
|
||||
import javax.swing.JToolBar;
|
||||
import javax.swing.ListModel;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import javax.swing.tree.TreePath;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.jdesktop.application.Action;
|
||||
import org.jdesktop.application.Application;
|
||||
import org.jdesktop.application.View;
|
||||
import org.jdesktop.swingx.JXMultiSplitPane;
|
||||
import org.jdesktop.swingx.JXTree;
|
||||
import org.jdesktop.swingx.MultiSplitLayout;
|
||||
import org.jfree.chart.axis.NumberAxis;
|
||||
import org.jfree.chart.plot.XYPlot;
|
||||
import org.jfree.chart.title.TextTitle;
|
||||
import org.jfree.data.xy.XYSeries;
|
||||
import org.jfree.data.xy.XYSeriesCollection;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import com.lowagie.text.Document;
|
||||
import com.lowagie.text.DocumentException;
|
||||
import com.lowagie.text.PageSize;
|
||||
import com.lowagie.text.pdf.DefaultFontMapper;
|
||||
import com.lowagie.text.pdf.PdfContentByte;
|
||||
import com.lowagie.text.pdf.PdfWriter;
|
||||
|
||||
import trick.common.TrickApplication;
|
||||
import trick.common.ui.UIUtils;
|
||||
import trick.dataproducts.plot.utils.PlotUtils;
|
||||
import trick.dataproducts.plot.utils.TrickChart;
|
||||
import trick.dataproducts.plot.utils.TrickChartFrame;
|
||||
import trick.dataproducts.plot.utils.TrickFrame;
|
||||
import trick.dataproducts.plot.utils.TrickTableFrame;
|
||||
import trick.dataproducts.plot.utils.TrickXYLineAndShapeRenderer;
|
||||
import trick.dataproducts.plot.utils.TrickXYPlot;
|
||||
import trick.dataproducts.plot.utils.TrickXYSeries;
|
||||
import trick.dataproducts.trickqp.utils.Product;
|
||||
import trick.dataproducts.trickqp.utils.ProductCurve;
|
||||
import trick.dataproducts.trickqp.utils.ProductDataPanel;
|
||||
import trick.dataproducts.trickqp.utils.ProductPage;
|
||||
import trick.dataproducts.trickqp.utils.ProductPlot;
|
||||
import trick.dataproducts.trickqp.utils.ProductTable;
|
||||
import trick.dataproducts.trickqp.utils.ProductVar;
|
||||
import trick.dataproducts.trickqp.utils.ProductVarcase;
|
||||
import trick.dataproducts.trickqp.utils.ProductDomParser;
|
||||
import trick.dataproducts.utils.Session;
|
||||
import trick.dataproducts.utils.SessionRun;
|
||||
import trick.dataproducts.utils.SessionDomParser;
|
||||
|
||||
/**
|
||||
* Plotting using Java.
|
||||
*
|
||||
* @author Hong Chen
|
||||
* @since Trick 13
|
||||
*/
|
||||
public class JXPlotApplication extends TrickApplication {
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
|
||||
|
||||
private JXTree productTree;
|
||||
private DefaultMutableTreeNode productTreeRoot;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private JList tableList;
|
||||
|
||||
private static int chartInitialLocX = 50;
|
||||
private static int chartInitialLocY = 50;
|
||||
private Session sessionObject;
|
||||
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
|
||||
|
||||
//========================================
|
||||
// Actions
|
||||
//========================================
|
||||
@Action
|
||||
public void saveAllToPDF() {
|
||||
File file = UIUtils.chooseSaveFile(null, "plot_", "pdf", getMainFrame());
|
||||
if (file == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
int dpFileCount = productTreeRoot.getChildCount();
|
||||
if (dpFileCount > 0) {
|
||||
Document document = new Document(PageSize.A4);
|
||||
PdfWriter writer = null;
|
||||
PdfContentByte pdfContent = null;
|
||||
try {
|
||||
writer = PdfWriter.getInstance(document, new FileOutputStream(file));
|
||||
document.open();
|
||||
// this object can be reused which is used to write each page to the same PDF file
|
||||
pdfContent = writer.getDirectContent();
|
||||
} catch (DocumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
for (int i = 0; i < dpFileCount; i++) {
|
||||
DefaultMutableTreeNode eachDPFile = (DefaultMutableTreeNode)productTree.getModel().getChild(productTreeRoot, i);
|
||||
int pageCount = eachDPFile.getChildCount();
|
||||
for (int j = 0; j < pageCount; j++) {
|
||||
DefaultMutableTreeNode eachPage = (DefaultMutableTreeNode)productTree.getModel().getChild(eachDPFile, j);
|
||||
if (eachPage.getUserObject() instanceof TrickChartFrame) {
|
||||
TrickChartFrame theFrame = (TrickChartFrame)eachPage.getUserObject();
|
||||
theFrame.writePDFPage(pdfContent, new DefaultFontMapper());
|
||||
}
|
||||
}
|
||||
}
|
||||
// document needs to be closed after the PDF file is saved
|
||||
if (document != null) {
|
||||
document.close();
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//========================================
|
||||
// Set/Get methods
|
||||
//========================================
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
/**
|
||||
* Main method for this application.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
Application.launch(JXPlotApplication.class, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes initialization as needed. This is called before startup().
|
||||
*
|
||||
* @see #startup
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@Override
|
||||
protected void initialize(String[] args) {
|
||||
super.initialize(args);
|
||||
|
||||
// TODO: make it as a tree
|
||||
final ListModel listModel = new DefaultListModel();
|
||||
tableList = new JList(listModel);
|
||||
tableList.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
int index = tableList.locationToIndex(e.getPoint());
|
||||
if (index != -1 && listModel.getElementAt(index) instanceof TrickFrame) {
|
||||
TrickFrame theFrame = (TrickFrame)listModel.getElementAt(index);
|
||||
if (!theFrame.isVisible()) {
|
||||
theFrame.setVisible(true);
|
||||
} else {
|
||||
theFrame.requestFocus();
|
||||
theFrame.toFront();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
productTreeRoot = new DefaultMutableTreeNode("Root");
|
||||
DefaultTreeModel treeModel = new DefaultTreeModel(productTreeRoot);
|
||||
productTree = new JXTree(treeModel);
|
||||
productTree.setRootVisible(false);
|
||||
productTree.setShowsRootHandles(true);
|
||||
productTree.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
TreePath clickedPath = null;
|
||||
DefaultMutableTreeNode clickedNode = null;
|
||||
|
||||
// when nothing is viewable, do nothing and return immediately
|
||||
if (productTree.getClosestPathForLocation(e.getX(), e.getY()) == null) {
|
||||
return;
|
||||
}
|
||||
clickedPath = productTree.getClosestPathForLocation(e.getX(), e.getY());
|
||||
if (clickedPath.getLastPathComponent() instanceof DefaultMutableTreeNode) {
|
||||
clickedNode = (DefaultMutableTreeNode)clickedPath.getLastPathComponent();
|
||||
}
|
||||
|
||||
if (clickedNode.getUserObject() instanceof TrickFrame) {
|
||||
TrickFrame theFrame = (TrickFrame)clickedNode.getUserObject();
|
||||
if (!theFrame.isVisible()) {
|
||||
theFrame.setVisible(true);
|
||||
} else {
|
||||
theFrame.requestFocus();
|
||||
theFrame.toFront();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (args.length > 0) {
|
||||
openSessionFile(args[0]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Opens a session file for plotting.
|
||||
*/
|
||||
private void openSessionFile(String sessionFile) {
|
||||
File file = new File(sessionFile);
|
||||
if (file != null) {
|
||||
try {
|
||||
sessionObject = SessionDomParser.parse(file);
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ParserConfigurationException e) {
|
||||
e.printStackTrace();
|
||||
} catch (SAXException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
for (String dpFile : sessionObject.getProductFiles()) {
|
||||
// if parsing is failed, stop!
|
||||
try {
|
||||
Product productObject = ProductDomParser.parse(new File(dpFile)) ;
|
||||
|
||||
if (productObject != null) {
|
||||
// if the mode is not defined or is set to PLOT_MODE, plot the data.
|
||||
if (sessionObject.getMode() == null || sessionObject.getMode().equals(Session.MODE_OPTIONS[Session.PLOT_MODE])) {
|
||||
DefaultMutableTreeNode dpFileNode = new DefaultMutableTreeNode(dpFile);
|
||||
productTreeRoot.add(dpFileNode);
|
||||
((DefaultTreeModel) productTree.getModel()).reload();
|
||||
// if there is any page
|
||||
if (productObject.getPageList() != null && productObject.getPageList().size() > 0) {
|
||||
for (ProductPage eachPage : productObject.getPageList()) {
|
||||
if (eachPage != null) {
|
||||
createAndShowCharts(dpFileNode, eachPage);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (sessionObject.getMode().equals(Session.MODE_OPTIONS[Session.TABLE_MODE])) {
|
||||
if (productObject.getTableList() != null && productObject.getTableList().size() > 0) {
|
||||
for (ProductTable eachTable : productObject.getTableList()) {
|
||||
createAndShowTable(tableList, productObject.getTitle(), eachTable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
System.out.println("\nERROR parsing " + dpFile + " !!!\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for creating table.
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes" })
|
||||
private void createAndShowTable(JList list, String title, ProductTable theTable) {
|
||||
showTable(theTable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for creating charts for a page.
|
||||
*/
|
||||
private void createAndShowCharts(DefaultMutableTreeNode dpFileNode, ProductPage thePage) {
|
||||
ArrayList<TrickChart> chartList = new ArrayList<TrickChart>();
|
||||
|
||||
if (sessionObject.getPresentation().equals(Session.PRESENTATION_OPTIONS[Session.SIMPLE_PRESENTATION])) {
|
||||
createChartsForSingle(thePage, chartList);
|
||||
} else if (sessionObject.getPresentation().equals(Session.PRESENTATION_OPTIONS[Session.COMPARISON_PRESENTATION])) {
|
||||
createChartsForComparison(thePage, chartList);
|
||||
} else if (sessionObject.getPresentation().equals(Session.PRESENTATION_OPTIONS[Session.DELTA_PRESENTATION])) {
|
||||
createChartsForDelta(thePage, chartList, false);
|
||||
} else if (sessionObject.getPresentation().equals(Session.PRESENTATION_OPTIONS[Session.CONTRAST_PRESENTATION])) {
|
||||
createChartsForContrast(thePage, chartList);
|
||||
}
|
||||
showPagePlots(dpFileNode, thePage, chartList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for creating all charts using contrast plotting for a particular {@link ProductPage}
|
||||
* and adding the charts to a list. Contrast plotting shows both comparison and delta plots on the
|
||||
* same page.
|
||||
*/
|
||||
private void createChartsForContrast(ProductPage thePage, ArrayList<TrickChart> chartList) {
|
||||
createChartsForComparison(thePage, chartList);
|
||||
createChartsForDelta(thePage, chartList, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for creating all charts using delta plotting for a particular {@link ProductPage}
|
||||
* and adding the charts to a list.
|
||||
*/
|
||||
private void createChartsForDelta(ProductPage thePage, ArrayList<TrickChart> chartList, boolean isContrast) {
|
||||
for (ProductPlot eachPlot : thePage.getPlotList()) {
|
||||
XYSeriesCollection dataset = null;
|
||||
int totalRuns = sessionObject.getRuns().size();
|
||||
if (totalRuns == 1) {
|
||||
dataset = new XYSeriesCollection();
|
||||
for (ProductCurve eachCurve : eachPlot.getCurveList()) {
|
||||
//dataset.addSeries(getXYSeriesForCurve(sessionObject.getRuns().get(0), thePage, eachPlot, eachCurve));
|
||||
addSeriesToDataset(dataset, getXYSeriesForCurve(sessionObject.getRuns().get(0), thePage, eachPlot, eachCurve));
|
||||
}
|
||||
createAndAddChart("(" + sessionObject.getRuns().get(0).getDirName() +")", chartList, thePage, eachPlot, dataset, false);
|
||||
} else {
|
||||
if (isContrast) {
|
||||
dataset = new XYSeriesCollection();
|
||||
}
|
||||
for (int i = 0; i < totalRuns - 1; i++) {
|
||||
for (int j = i + 1; j < totalRuns; j++) {
|
||||
if (!isContrast) {
|
||||
dataset = new XYSeriesCollection();
|
||||
}
|
||||
for (ProductCurve eachCurve : eachPlot.getCurveList()) {
|
||||
TrickXYSeries series1 = getXYSeriesForCurve(sessionObject.getRuns().get(i), thePage, eachPlot, eachCurve);
|
||||
TrickXYSeries series2 = getXYSeriesForCurve(sessionObject.getRuns().get(j), thePage, eachPlot, eachCurve);
|
||||
if (series1 == null || series2 == null) {
|
||||
continue;
|
||||
}
|
||||
int totalCount = series1.getItemCount() < series2.getItemCount() ? series1.getItemCount() : series2.getItemCount();
|
||||
|
||||
TrickXYSeries deltaSeries = new TrickXYSeries("DELTA: "
|
||||
+ series1.getDescription().substring(0, series1.getDescription().lastIndexOf("["))
|
||||
+ " ["
|
||||
+ sessionObject.getRuns().get(i).getDirName()
|
||||
+ " - "
|
||||
+ sessionObject.getRuns().get(j).getDirName() + "]", false, true);
|
||||
for (int k = 0; k < totalCount; k++) {
|
||||
deltaSeries.add(series1.getX(k).doubleValue(), series1.getY(k).doubleValue() - series2.getY(k).doubleValue());
|
||||
}
|
||||
//dataset.addSeries(deltaSeries);
|
||||
addSeriesToDataset(dataset, deltaSeries);
|
||||
deltaSeries.setXVar(series1.getXVar());
|
||||
deltaSeries.setYVar(series1.getYVar());
|
||||
}
|
||||
if (!isContrast) {
|
||||
createAndAddChart("(Difference)", chartList, thePage, eachPlot, dataset, isContrast);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isContrast) {
|
||||
createAndAddChart("(Difference)", chartList, thePage, eachPlot, dataset, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for creating all charts using comparison plotting for a particular {@link ProductPage}
|
||||
* and adding the charts to a list.
|
||||
*/
|
||||
private void createChartsForComparison(ProductPage thePage, ArrayList<TrickChart> chartList) {
|
||||
for (ProductPlot eachPlot : thePage.getPlotList()) {
|
||||
XYSeriesCollection dataset = getComparisonPlotDataset(thePage, eachPlot);
|
||||
createAndAddChart("(Compare)" , chartList, thePage, eachPlot, dataset, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for creating all charts using single plotting for a particular {@link ProductPage}
|
||||
* and adding the charts to a list.
|
||||
*/
|
||||
private void createChartsForSingle(ProductPage thePage, ArrayList<TrickChart> chartList) {
|
||||
for (ProductPlot eachPlot : thePage.getPlotList()) {
|
||||
for (SessionRun eachRun : sessionObject.getRuns()) {
|
||||
XYSeriesCollection dataset = getSinglePlotDataset(eachRun, thePage, eachPlot);
|
||||
createAndAddChart("("+eachRun.getDirName()+")", chartList, thePage, eachPlot, dataset, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a chart for the specified {@link XYSeriesCollection} and {@link ProductPlot} and then
|
||||
* adds to the list.
|
||||
*/
|
||||
private void createAndAddChart(String subTitle, ArrayList<TrickChart> chartList, ProductPage aPage, ProductPlot aPlot, XYSeriesCollection dataset, boolean isContrast) {
|
||||
XYPlot plot = createXYPlot(aPage, aPlot, dataset);
|
||||
|
||||
TrickChart chart = new TrickChart(aPlot.getTitle(), TrickChart.TRICK_DEFAULT_TITLE_FONT, plot, true);
|
||||
//TrickChartTheme chartTheme = new TrickChartTheme("TrickChart");
|
||||
|
||||
//chartTheme.apply(chart);
|
||||
configureChart(subTitle, chart, aPage, aPlot, isContrast);
|
||||
chartList.add(chart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for creating a {@link XYPlot} for the specified {@link ProductPlot}
|
||||
* and logged data.
|
||||
*/
|
||||
private XYPlot createXYPlot(ProductPage aPage, ProductPlot aPlot, XYSeriesCollection dataset) {
|
||||
DecimalFormat newFormat = new DecimalScientificFormat();
|
||||
|
||||
NumberAxis xAxis = new NumberAxis(null);
|
||||
xAxis.setNumberFormatOverride(newFormat);
|
||||
NumberAxis yAxis = new NumberAxis(null);
|
||||
yAxis.setNumberFormatOverride(newFormat);
|
||||
|
||||
TrickXYLineAndShapeRenderer renderer = new TrickXYLineAndShapeRenderer();
|
||||
return new TrickXYPlot(aPage, aPlot, dataset, xAxis, yAxis, renderer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the specified chart.
|
||||
*/
|
||||
private void configureChart(String subTitleText, TrickChart chart, ProductPage aPage, ProductPlot aPlot, boolean isContrast) {
|
||||
// TODO: will see if need to remove the legend for contrast plotting
|
||||
//if (isContrast) {
|
||||
// chart.removeLegend();
|
||||
//} else {
|
||||
if (aPlot.getForegroundColor() != null) {
|
||||
chart.getLegend().setItemPaint(aPlot.getForegroundColor());
|
||||
} else if (aPage.getForegroundColor() != null) {
|
||||
chart.getLegend().setItemPaint(aPage.getForegroundColor());
|
||||
}
|
||||
if (aPlot.getBackgroundColor() != null) {
|
||||
chart.getLegend().setBackgroundPaint(aPlot.getBackgroundColor());
|
||||
} else if (aPage.getBackgroundColor() != null) {
|
||||
chart.getLegend().setBackgroundPaint(aPage.getBackgroundColor());
|
||||
}
|
||||
//}
|
||||
|
||||
TextTitle subTitle = null;
|
||||
if (subTitleText != null && !subTitleText.isEmpty()) {
|
||||
subTitle = new TextTitle(subTitleText, TrickChart.TRICK_DEFAULT_SUBTITLE_FONT);
|
||||
}
|
||||
|
||||
// Font
|
||||
if (aPlot.getFont() != null && !(aPlot.getFont().isEmpty())) {
|
||||
Font plotFont = ProductDataPanel.getFontFromText(aPlot.getFont());
|
||||
chart.getTitle().setFont(plotFont);
|
||||
//if (!isContrast) {
|
||||
chart.getLegend().setItemFont(plotFont);
|
||||
//}
|
||||
if (subTitleText != null && !subTitleText.isEmpty()) {
|
||||
subTitle.setFont(plotFont);
|
||||
}
|
||||
}
|
||||
|
||||
if (subTitle != null) {
|
||||
chart.addSubtitle(subTitle);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows all plots on a page.
|
||||
*/
|
||||
private void showPagePlots(DefaultMutableTreeNode dpFileNode, ProductPage thePage, ArrayList<TrickChart> chartList) {
|
||||
if (chartList.size() > 0) {
|
||||
TrickChartFrame chartFrame = new TrickChartFrame(thePage.getTitle(), getMainFrame().getIconImage(), thePage, chartList);
|
||||
|
||||
dpFileNode.add(new DefaultMutableTreeNode(chartFrame));
|
||||
((DefaultTreeModel)productTree.getModel()).reload();
|
||||
|
||||
locateFrame(chartFrame);
|
||||
}
|
||||
}
|
||||
|
||||
private void locateFrame(TrickFrame frame) {
|
||||
frame.setLocation(chartInitialLocX, chartInitialLocY);
|
||||
chartInitialLocX += 30;
|
||||
chartInitialLocY += 30;
|
||||
frame.pack();
|
||||
frame.setVisible(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the table.
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private void showTable(ProductTable theTable) {
|
||||
if (theTable == null || theTable.getColumnList() == null || theTable.getColumnList().size() < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
TrickTableFrame tableFrame = new TrickTableFrame(theTable.getTitle(), getMainFrame().getIconImage(), sessionObject, theTable);
|
||||
tableFrame.setLocation(this.getMainFrame().getLocation());
|
||||
if (tableList.getModel() instanceof DefaultListModel) {
|
||||
DefaultListModel listModel = (DefaultListModel)tableList.getModel();
|
||||
listModel.addElement(tableFrame);
|
||||
}
|
||||
locateFrame(tableFrame);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the dataset for single plotting. Note that for single plotting,
|
||||
* data from different runs is showing on different plots.
|
||||
* @param page TODO
|
||||
*/
|
||||
private XYSeriesCollection getSinglePlotDataset(SessionRun theRun, ProductPage page, ProductPlot plot) {
|
||||
XYSeriesCollection dataset = new XYSeriesCollection();
|
||||
|
||||
for (ProductCurve eachCurve : plot.getCurveList()) {
|
||||
if (eachCurve != null && eachCurve.isValid()) {
|
||||
TrickXYSeries series = getXYSeriesForCurve(theRun, page, plot, eachCurve);
|
||||
if (series != null) {
|
||||
//dataset.addSeries(series);
|
||||
addSeriesToDataset(dataset, series);
|
||||
}
|
||||
}
|
||||
}
|
||||
return dataset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for getting {@link XYSeries} for the specified {@link ProductCurve}.
|
||||
* @param page TODO
|
||||
*/
|
||||
private TrickXYSeries getXYSeriesForCurve(SessionRun theRun, ProductPage page, ProductPlot plot, ProductCurve eachCurve) {
|
||||
TrickXYSeries series = null;
|
||||
ProductVar theXVar = null;
|
||||
ProductVar theYVar = null;
|
||||
|
||||
// a curve either has varcase or X & Y and doesn't have both at the same time
|
||||
if (eachCurve.hasVarcase()) {
|
||||
for (ProductVarcase eachVarcase : eachCurve.getVarcaseList()) {
|
||||
if (eachVarcase.isValid()) {
|
||||
theXVar = eachVarcase.getX();
|
||||
theYVar = eachVarcase.getY();
|
||||
|
||||
series = PlotUtils.getXYVarSeries(theRun, page, plot, theXVar, theYVar);
|
||||
|
||||
// if XYSeries for this varcase can be found, skip the rest. otherwise, keep checking the next varcase
|
||||
if (series != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
theXVar = eachCurve.getX();
|
||||
theYVar = eachCurve.getY();
|
||||
|
||||
series = PlotUtils.getXYVarSeries(theRun, page, plot, theXVar, theYVar);
|
||||
}
|
||||
return series;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper method for setting X and Y variable scales.
|
||||
* If the variable itself doesn't specify the scale, the plot scale is used if available.
|
||||
* If the variable does have the scale specified, the plot scale is ignored.
|
||||
*/
|
||||
/*private void setXYVarScale(ProductPlot plot, ProductVar theXVar, ProductVar theYVar) {
|
||||
if (theXVar.getScale() == null) {
|
||||
if (plot.getXScale() != null && !plot.getXScale().isEmpty()) {
|
||||
try {
|
||||
theXVar.setScale(Double.parseDouble(plot.getXScale()));
|
||||
} catch (Exception e) {
|
||||
// if there is an exception, just simply don't set the scale.
|
||||
}
|
||||
}
|
||||
}
|
||||
if (theYVar.getScale() == null) {
|
||||
if (plot.getYScale() != null && !plot.getYScale().isEmpty()) {
|
||||
try {
|
||||
theYVar.setScale(Double.parseDouble(plot.getYScale()));
|
||||
} catch (Exception e) {
|
||||
// if there is an exception, just simply don't set the scale.
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Gets the dataset for comparison plotting. Note that for comparison plotting,
|
||||
* data from different runs is showing on the same plot.
|
||||
* @param page TODO
|
||||
*/
|
||||
private XYSeriesCollection getComparisonPlotDataset(ProductPage page, ProductPlot plot) {
|
||||
XYSeriesCollection dataset = new XYSeriesCollection();
|
||||
for (ProductCurve eachCurve : plot.getCurveList()) {
|
||||
if (eachCurve != null) {
|
||||
for (SessionRun eachRun : sessionObject.getRuns()) {
|
||||
TrickXYSeries series = getXYSeriesForCurve(eachRun, page, plot, eachCurve);
|
||||
if (series != null) {
|
||||
addSeriesToDataset(dataset, series);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return dataset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for adding the data series index as the prefix for the key of a series
|
||||
* so that the key is guaranteed to be unique.
|
||||
*/
|
||||
private void addSeriesToDataset(XYSeriesCollection dataset, TrickXYSeries series) {
|
||||
String theKey = series.getKey().toString();
|
||||
theKey = "Series " + dataset.getSeriesCount() + ": " + theKey.toString();
|
||||
series.setKey(theKey);
|
||||
dataset.addSeries(series);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts building GUI. This is called after initialize.
|
||||
* Once startup() is done, ready() is called.
|
||||
*
|
||||
* @see #initialize
|
||||
* @see #ready
|
||||
*/
|
||||
@Override
|
||||
protected void startup() {
|
||||
super.startup();
|
||||
|
||||
View view = getMainView();
|
||||
view.setComponent(createMainPanel());
|
||||
view.setMenuBar(createMenuBar());
|
||||
//view.setToolBar(createToolBar());
|
||||
show(view);
|
||||
|
||||
//getMainFrame().setLocation(0, 0);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void ready() {
|
||||
super.ready();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void shutdown() {
|
||||
try {
|
||||
super.shutdown();
|
||||
} catch (Exception e) {
|
||||
// add this catch here in order not to show the warning
|
||||
// exception when try to exit the application while the
|
||||
// plotting frame is maximized. this is due to the problem
|
||||
// with storing session of the framework. here basically,
|
||||
// the plotting frame session is not saved which we don't
|
||||
// need it anyway.
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the main panel. This is required by TrickApplication.
|
||||
*
|
||||
* @return a {@link JComponent} as the main panel.
|
||||
*/
|
||||
@Override
|
||||
protected JComponent createMainPanel() {
|
||||
|
||||
JXMultiSplitPane msp = new JXMultiSplitPane();
|
||||
|
||||
String layoutDef =
|
||||
"(COLUMN (LEAF name=top weight=0.7)" +
|
||||
//" (LEAF name=middle weight=0.2)" +
|
||||
" (LEAF name=bottom weight=0.3)" +
|
||||
")";
|
||||
MultiSplitLayout.Node modelRoot = MultiSplitLayout.parseModel( layoutDef );
|
||||
|
||||
msp.getMultiSplitLayout().setModel( modelRoot );
|
||||
|
||||
|
||||
JPanel productsPanel = UIUtils.createSearchableTitledPanel("Products & Pages", productTree, null);
|
||||
productsPanel.setMinimumSize(new Dimension(250, 50));
|
||||
productsPanel.setPreferredSize(new Dimension(500, 150));
|
||||
|
||||
JPanel tablesPanel = UIUtils.createSearchableTitledPanel("Tables", tableList, null);
|
||||
tablesPanel.setMinimumSize(new Dimension(250, 50));
|
||||
//pagesPanel.setPreferredSize(new Dimension(400, 50));
|
||||
|
||||
msp.add(productsPanel, "top" );
|
||||
//msp.add(pagesPanel, "middle" );
|
||||
msp.add(tablesPanel, "bottom" );
|
||||
|
||||
return msp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create the JMenuBar for this application.
|
||||
*/
|
||||
@Override
|
||||
protected JMenuBar createMenuBar() {
|
||||
JMenuBar menuBar = super.createMenuBar();
|
||||
|
||||
JMenu menu = menuBar.getMenu(0);
|
||||
menu.add(new JSeparator(), 0);
|
||||
//menu.add(new JMenuItem(getAction("saveALLToPDF")), 0);
|
||||
menu.add(createMenuItem("saveAllToPDF"), 0);
|
||||
return menuBar;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates the tool bar for the application.
|
||||
*
|
||||
* @return a {@link JToolBar} for the application.
|
||||
*/
|
||||
@Override
|
||||
protected JToolBar createToolBar() {
|
||||
return new JToolBar();
|
||||
}
|
||||
|
||||
/*
|
||||
TODO: may want to add feature for righ_clicking a series to have
|
||||
a pop up menu for making it visible or invisible.
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
int series = -1;
|
||||
if (e.getActionCommand().equals("S1")) {
|
||||
series = 0;
|
||||
}
|
||||
else if (e.getActionCommand().equals("S2")) {
|
||||
series = 1;
|
||||
}
|
||||
else if (e.getActionCommand().equals("S3")) {
|
||||
series = 2;
|
||||
}
|
||||
if (series >= 0) {
|
||||
boolean visible = this.renderer.getItemVisible(series, 0);
|
||||
this.renderer.setSeriesVisible(series, new Boolean(!visible));
|
||||
}
|
||||
|
||||
}*/
|
||||
|
||||
//========================================
|
||||
// Inner classes
|
||||
//========================================
|
||||
public class DecimalScientificFormat extends DecimalFormat {
|
||||
|
||||
private static final long serialVersionUID = -7709354031636993724L;
|
||||
|
||||
private DecimalFormat normalFormat = new DecimalFormat("0.#####");
|
||||
|
||||
private DecimalFormat scientificFormat = new DecimalFormat("0.#####E0");
|
||||
|
||||
@Override
|
||||
public StringBuffer format(double number, StringBuffer result, FieldPosition fieldPosition) {
|
||||
String decimalFormat = normalFormat.format(number);
|
||||
String numberString = Double.toString(number);
|
||||
|
||||
boolean needScientificNotion = false;
|
||||
int dotLoc = numberString.indexOf(".");
|
||||
|
||||
if (numberString.indexOf("E") != -1) {
|
||||
needScientificNotion = true;
|
||||
} else if (dotLoc == -1) {
|
||||
if (numberString.length() > 5) {
|
||||
needScientificNotion = true;
|
||||
}
|
||||
} else {
|
||||
if (dotLoc >= 5) {
|
||||
needScientificNotion = true;
|
||||
} else if (numberString.length() - dotLoc >= 6) {
|
||||
needScientificNotion = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (number != 0.0 && needScientificNotion) {
|
||||
return scientificFormat.format(number, result, fieldPosition);
|
||||
} else {
|
||||
return result.append(decimalFormat);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
#
|
||||
# $Id: JXPlotApplication.properties 3531 2014-05-16 16:32:51Z hchen3 $
|
||||
#
|
||||
|
||||
Application.id = JXPlotApplication
|
||||
Application.title = Trick Plot
|
||||
|
||||
mainFrame.title = Trick Plot
|
||||
|
||||
saveAllToPDF.Action.text = &Make All to PDF
|
||||
saveAllToPDF.Action.shortDescription = Make a PDF of all plots of all pages
|
@ -0,0 +1,373 @@
|
||||
/*
|
||||
* $Id: PlotUtils.java 3795 2015-02-11 19:35:28Z alin $
|
||||
*/
|
||||
|
||||
package trick.dataproducts.plot.utils;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.Style;
|
||||
import javax.swing.text.StyleConstants;
|
||||
import javax.swing.text.StyleContext;
|
||||
import javax.swing.text.StyledDocument;
|
||||
|
||||
import org.jfree.data.xy.XYSeries;
|
||||
|
||||
import trick.common.ui.TrickFileFilter;
|
||||
import trick.common.ui.UIUtils;
|
||||
import trick.common.utils.BinaryDataReader;
|
||||
import trick.common.utils.CSVDataReader;
|
||||
import trick.common.utils.DataReader;
|
||||
import trick.dataproducts.trickqp.utils.ProductColumn;
|
||||
import trick.dataproducts.trickqp.utils.ProductPage;
|
||||
import trick.dataproducts.trickqp.utils.ProductPlot;
|
||||
import trick.dataproducts.trickqp.utils.ProductTable;
|
||||
import trick.dataproducts.trickqp.utils.ProductVar;
|
||||
import trick.dataproducts.utils.SessionRun;
|
||||
|
||||
/**
|
||||
* This data reader is for reading recorded data from different type of files.
|
||||
*
|
||||
* @author Hong Chen
|
||||
* @since Trick 13
|
||||
*/
|
||||
public class PlotUtils {
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Private Data
|
||||
//========================================
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
/**
|
||||
* Writes the logged data based on the {@link ProductTable} spec to the {@link StyledDocument}
|
||||
* for a specified {@link SessionRun}. The data is then displayed in the form of a table.
|
||||
* This is much faster than using Java table component for a large set of data.
|
||||
*
|
||||
* @param run The RUN_ directory that contains the logged data.
|
||||
* @param theTable The table spec.
|
||||
* @param doc The document that holds the logged data in order
|
||||
* for the data to be shown in the form of a table.
|
||||
*/
|
||||
public static void insertTableData(SessionRun run, ProductTable theTable, StyledDocument doc) {
|
||||
ArrayList<DataReader> varDataReaderList = null;
|
||||
File runDir = new File(run.getDir());
|
||||
if (runDir != null && runDir.exists()) {
|
||||
File[] files = UIUtils.getListFiles(runDir, TrickFileFilter.TRICK_DATA_RECORD);
|
||||
StringBuffer eachRow = new StringBuffer();
|
||||
|
||||
// do nothing if no data recording files found
|
||||
if (files == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// style for header
|
||||
StyleContext context = new StyleContext();
|
||||
Style headingStyle = context.getStyle(StyleContext.DEFAULT_STYLE);
|
||||
StyleConstants.setAlignment(headingStyle, StyleConstants.ALIGN_RIGHT);
|
||||
StyleConstants.setBold(headingStyle, true);
|
||||
StyleConstants.setFontSize(headingStyle, 14);
|
||||
StyleConstants.setSpaceAbove(headingStyle, 4);
|
||||
StyleConstants.setSpaceBelow(headingStyle, 4);
|
||||
|
||||
try {
|
||||
doc.insertString(doc.getLength(), "Title: " + theTable.getTitle() + "\n", headingStyle);
|
||||
doc.insertString(doc.getLength(), "Run: " + run.getDir() + "\n\n", headingStyle);
|
||||
} catch (BadLocationException ble) {
|
||||
ble.printStackTrace();
|
||||
}
|
||||
eachRow.setLength(0);
|
||||
|
||||
varDataReaderList = new ArrayList<DataReader>();
|
||||
|
||||
// build up the data reader list for reading the data and write the variable names on table
|
||||
// variable names row
|
||||
eachRow.append("Line#\t");
|
||||
for (ProductColumn theColumn : theTable.getColumnList()) {
|
||||
DataReader eachReader = getVarDataReader(runDir, theColumn.getVar());
|
||||
eachRow.append(theColumn.getVar().getShortName() + " {" + theColumn.getVar().getUnits() + "}" + "\t");
|
||||
|
||||
if (eachReader == null || eachReader.locateVarIndex(theColumn.getVar().getName()) == -1) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
eachReader.beginRead(theColumn.getVar());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
varDataReaderList.add(eachReader);
|
||||
}
|
||||
eachRow.append("\n");
|
||||
|
||||
if (varDataReaderList.size() < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
StyleConstants.setBackground(headingStyle, Color.lightGray);
|
||||
doc.insertString(doc.getLength(), eachRow.toString(), headingStyle);
|
||||
eachRow.setLength(0);
|
||||
} catch (BadLocationException ble) {
|
||||
ble.printStackTrace();
|
||||
}
|
||||
|
||||
double eachVarValue = Double.NaN;
|
||||
|
||||
// style for data
|
||||
context = new StyleContext();
|
||||
Style dataStyle = context.getStyle(StyleContext.DEFAULT_STYLE);
|
||||
StyleConstants.setAlignment(dataStyle, StyleConstants.ALIGN_RIGHT);
|
||||
StyleConstants.setBold(dataStyle, false);
|
||||
StyleConstants.setFontSize(dataStyle, 12);
|
||||
StyleConstants.setForeground(dataStyle, Color.BLUE);
|
||||
|
||||
int lineIndex = 0;
|
||||
|
||||
while (true) {
|
||||
eachRow.append(lineIndex + "\t");
|
||||
// get one value for each variable at a time
|
||||
for (DataReader eachReader : varDataReaderList) {
|
||||
try {
|
||||
eachVarValue = eachReader.getVarValue();
|
||||
|
||||
if (Double.isNaN(eachVarValue)) {
|
||||
break;
|
||||
}
|
||||
eachRow.append(eachVarValue + "\t");
|
||||
} catch (FileNotFoundException e) {
|
||||
System.err.println(e);
|
||||
} catch (IOException e) {
|
||||
System.err.println(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (Double.isNaN(eachVarValue)) {
|
||||
break;
|
||||
}
|
||||
eachRow.append("\n");
|
||||
try {
|
||||
if ((lineIndex & 1) == 0) {
|
||||
StyleConstants.setBackground(dataStyle, Color.white);
|
||||
} else {
|
||||
StyleConstants.setBackground(dataStyle, Color.lightGray);
|
||||
}
|
||||
doc.insertString(doc.getLength(), eachRow.toString(), dataStyle);
|
||||
eachRow.setLength(0);
|
||||
lineIndex++;
|
||||
} catch (BadLocationException ble) {
|
||||
ble.printStackTrace();
|
||||
}
|
||||
}
|
||||
// end data reader
|
||||
for (DataReader eachReader : varDataReaderList) {
|
||||
eachReader.endRead();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a {@link XYSeries} for x and y of the specified plot spec from the recorded data that is in a particular run directory.
|
||||
*
|
||||
* @param run A {@link SessionRun} instance.
|
||||
* @param plot A {@link ProductPlot} instance.
|
||||
* @param xVar The X variable.
|
||||
* @param yVar The Y variable.
|
||||
* @return An instance of {@link XYSeries}.
|
||||
*/
|
||||
public static TrickXYSeries getXYVarSeries(
|
||||
SessionRun run,
|
||||
ProductPage page,
|
||||
ProductPlot plot,
|
||||
ProductVar xVar,
|
||||
ProductVar yVar
|
||||
) {
|
||||
TrickXYSeries series = null;
|
||||
DataReader dataReaderX = null;
|
||||
DataReader dataReaderY = null;
|
||||
|
||||
File runDir = new File(run.getDir());
|
||||
if (runDir != null && runDir.exists()) {
|
||||
File[] files = UIUtils.getListFiles(runDir, TrickFileFilter.TRICK_DATA_RECORD);
|
||||
|
||||
// do nothing if no data recording files found
|
||||
if (files == null) {
|
||||
return series;
|
||||
}
|
||||
|
||||
dataReaderX = getVarDataReader(runDir, xVar);
|
||||
if (dataReaderX == null || dataReaderX.locateVarIndex(xVar.getName()) == -1) {
|
||||
return series;
|
||||
}
|
||||
dataReaderX.setTimename(run.getTimename());
|
||||
configureDataReader(page, plot, dataReaderX);
|
||||
|
||||
dataReaderY = getVarDataReader(runDir, yVar);
|
||||
if (dataReaderY == null || dataReaderY.locateVarIndex(yVar.getName()) == -1) {
|
||||
return series;
|
||||
}
|
||||
dataReaderY.setTimename(run.getTimename());
|
||||
configureDataReader(page, plot, dataReaderY);
|
||||
|
||||
try {
|
||||
String description = getSeriesDescription(runDir.getName(), xVar, yVar);
|
||||
series = new TrickXYSeries(description, false, true);
|
||||
series.setDescription(description);
|
||||
|
||||
dataReaderX.beginRead(xVar);
|
||||
dataReaderY.beginRead(yVar);
|
||||
|
||||
double xValue = dataReaderX.getVarValue();
|
||||
double yValue = dataReaderY.getVarValue();
|
||||
|
||||
while (!dataReaderX.isEnd() && Double.isNaN(xValue)) {
|
||||
xValue = dataReaderX.getVarValue();
|
||||
}
|
||||
|
||||
while (!dataReaderY.isEnd() && Double.isNaN(yValue)) {
|
||||
yValue = dataReaderY.getVarValue();
|
||||
}
|
||||
|
||||
// If either data reader doesn't have time data recorded, then time stamp is
|
||||
// not a concern. Simply just both x & y as they are.
|
||||
// If xVar reader's time stamp is bigger, reads more yVar till yVar reader's
|
||||
// time stamp almost equals to the xVar reader's time stamp and vice versa.
|
||||
// The xVar and yVar values are added to the series only if their time stamp
|
||||
// matches within 1e-9. TODO: Is 1e-9 good enough?
|
||||
while (!Double.isNaN(xValue) && !Double.isNaN(yValue)) {
|
||||
if (DataReader.nearlyEqual(dataReaderX.getTimeValue(), dataReaderY.getTimeValue()) ||
|
||||
Double.isNaN(dataReaderX.getTimeValue()) ||
|
||||
Double.isNaN(dataReaderY.getTimeValue())) {
|
||||
series.add(xValue, yValue);
|
||||
xValue = dataReaderX.getVarValue();
|
||||
yValue = dataReaderY.getVarValue();
|
||||
} else if (dataReaderX.getTimeValue() > dataReaderY.getTimeValue()) {
|
||||
yValue = dataReaderY.getVarValue();
|
||||
} else {
|
||||
xValue = dataReaderX.getVarValue();
|
||||
}
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
System.err.println(e);
|
||||
} catch (IOException e) {
|
||||
System.err.println(e);
|
||||
}
|
||||
|
||||
dataReaderX.endRead();
|
||||
dataReaderY.endRead();
|
||||
|
||||
if (series != null) {
|
||||
series.setXVar(xVar);
|
||||
series.setYVar(yVar);
|
||||
}
|
||||
}
|
||||
|
||||
return series;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the reader by applying {@link ProductPage} and {@link ProductPlot} specs.
|
||||
*/
|
||||
private static void configureDataReader(ProductPage page, ProductPlot plot, DataReader theReader) {
|
||||
if (page.getTStart() != null && plot.getTStart() != null) {
|
||||
if (page.getTStart().doubleValue() > plot.getTStart().doubleValue()) {
|
||||
theReader.setTStart(page.getTStart());
|
||||
} else {
|
||||
theReader.setTStart(plot.getTStart());
|
||||
}
|
||||
} else {
|
||||
if (page.getTStart() != null && plot.getTStart() == null) {
|
||||
theReader.setTStart(page.getTStart());
|
||||
} else if (page.getTStart() == null && plot.getTStart() != null) {
|
||||
theReader.setTStart(plot.getTStart());
|
||||
} else {
|
||||
theReader.setTStart(page.getTStart());
|
||||
}
|
||||
}
|
||||
|
||||
if (page.getTStop() != null && plot.getTStop() != null) {
|
||||
if (page.getTStop().doubleValue() < plot.getTStop().doubleValue()) {
|
||||
theReader.setTStop(page.getTStop());
|
||||
} else {
|
||||
theReader.setTStop(plot.getTStop());
|
||||
}
|
||||
} else {
|
||||
if (page.getTStop() != null && plot.getTStop() == null) {
|
||||
theReader.setTStop(page.getTStop());
|
||||
} else if (page.getTStop() == null && plot.getTStop() != null) {
|
||||
theReader.setTStop(plot.getTStop());
|
||||
} else {
|
||||
theReader.setTStop(page.getTStop());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for getting the corresponding reader for the specified variable.
|
||||
*
|
||||
* @param runDir The RUN_ dir that contains the recorded data.
|
||||
* @param var The {@link ProductVar} object which needs getting data for.
|
||||
*
|
||||
* @return An instance of {@link DataReader}.
|
||||
*/
|
||||
private static DataReader getVarDataReader(File runDir, ProductVar var) {
|
||||
DataReader theReader = null;
|
||||
File[] files = UIUtils.getListFiles(runDir, TrickFileFilter.TRICK_DATA_RECORD);
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
if (files[i].getPath().endsWith(".csv")) {
|
||||
theReader = new CSVDataReader(files[i].getPath());
|
||||
} else if (files[i].getPath().endsWith(".trk")) {
|
||||
theReader = new BinaryDataReader(files[i].getPath());
|
||||
} else if (files[i].getPath().endsWith(".h5")) {
|
||||
// TODO: set up data reader
|
||||
}
|
||||
if (theReader == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (theReader.locateVarIndex(var.getName()) != -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return theReader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes up the description for a series for the specified X & Y variables.
|
||||
*/
|
||||
private static String getSeriesDescription(String runDir, ProductVar xVar, ProductVar yVar) {
|
||||
// use variable name & units for label for plotting by default
|
||||
String xVarLabel = xVar.getName() + " (" + xVar.getUnits() + ")";
|
||||
String yVarLabel = yVar.getName() + " (" + yVar.getUnits() + ")";
|
||||
|
||||
// if label for the variable is specified, the specified label is used for plotting instead of its name&units
|
||||
if (xVar.getLabel() != null && !(xVar.getLabel().isEmpty())) {
|
||||
xVarLabel = xVar.getLabel();
|
||||
}
|
||||
|
||||
if (yVar.getLabel() != null && !(yVar.getLabel().isEmpty())) {
|
||||
yVarLabel = yVar.getLabel();
|
||||
}
|
||||
return yVarLabel + " VS. " + xVarLabel + " [" + runDir + "]";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* $Id: TrickChart.java 3795 2015-02-11 19:35:28Z alin $
|
||||
*/
|
||||
|
||||
package trick.dataproducts.plot.utils;
|
||||
|
||||
import java.awt.Font;
|
||||
|
||||
import org.jfree.chart.ChartFactory;
|
||||
import org.jfree.chart.JFreeChart;
|
||||
import org.jfree.chart.block.BlockBorder;
|
||||
import org.jfree.chart.plot.Plot;
|
||||
|
||||
public class TrickChart extends JFreeChart {
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
/** The default font for the primary title. */
|
||||
public static final Font TRICK_DEFAULT_TITLE_FONT = new Font("SansSerif", Font.BOLD, 12);
|
||||
|
||||
/** The default font for sub titles. */
|
||||
public static final Font TRICK_DEFAULT_SUBTITLE_FONT = new Font("SansSerif", Font.PLAIN, 12);
|
||||
|
||||
/** The default font for legend. */
|
||||
public static final Font TRICK_DEFAULT_LEGEND_FONT = new Font("SansSerif", Font.BOLD, 10);
|
||||
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Private Data
|
||||
//========================================
|
||||
private static final long serialVersionUID = -7190474578193337645L;
|
||||
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
/**
|
||||
* Creates a new chart based on the supplied plot. The chart will have
|
||||
* a legend added automatically, but no title (although you can easily add
|
||||
* one later).
|
||||
* <br><br>
|
||||
* Note that the {@link ChartFactory} class contains a range
|
||||
* of static methods that will return ready-made charts, and often this
|
||||
* is a more convenient way to create charts than using this constructor.
|
||||
*
|
||||
* @param plot the plot (<code>null</code> not permitted).
|
||||
*/
|
||||
public TrickChart(Plot plot) {
|
||||
super(plot);
|
||||
changeLegend();
|
||||
setAntiAlias(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new chart with the given title and plot. A default font
|
||||
* ({@link #DEFAULT_TITLE_FONT}) is used for the title, and the chart will
|
||||
* have a legend added automatically.
|
||||
* <br><br>
|
||||
* Note that the {@link ChartFactory} class contains a range
|
||||
* of static methods that will return ready-made charts, and often this
|
||||
* is a more convenient way to create charts than using this constructor.
|
||||
*
|
||||
* @param title the chart title (<code>null</code> permitted).
|
||||
* @param plot the plot (<code>null</code> not permitted).
|
||||
*/
|
||||
public TrickChart(String title, Plot plot) {
|
||||
super(title, plot);
|
||||
changeLegend();
|
||||
setAntiAlias(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new chart with the given title and plot. The
|
||||
* <code>createLegend</code> argument specifies whether or not a legend
|
||||
* should be added to the chart.
|
||||
* <br><br>
|
||||
* Note that the {@link ChartFactory} class contains a range
|
||||
* of static methods that will return ready-made charts, and often this
|
||||
* is a more convenient way to create charts than using this constructor.
|
||||
*
|
||||
* @param title the chart title (<code>null</code> permitted).
|
||||
* @param titleFont the font for displaying the chart title
|
||||
* (<code>null</code> permitted).
|
||||
* @param plot controller of the visual representation of the data
|
||||
* (<code>null</code> not permitted).
|
||||
* @param createLegend a flag indicating whether or not a legend should
|
||||
* be created for the chart.
|
||||
*/
|
||||
public TrickChart(String title, Font titleFont, Plot plot, boolean createLegend) {
|
||||
super(title, titleFont, plot, createLegend);
|
||||
if (createLegend) {
|
||||
changeLegend();
|
||||
}
|
||||
setAntiAlias(false);
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
private void changeLegend() {
|
||||
getLegend().setItemFont(TRICK_DEFAULT_LEGEND_FONT);
|
||||
getLegend().setFrame(BlockBorder.NONE);
|
||||
getLegend().setBackgroundPaint(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the title of this chart to represent the chart.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return getTitle().getText();
|
||||
}
|
||||
}
|
@ -0,0 +1,316 @@
|
||||
/*
|
||||
* $Id: TrickChartControlPanel.java 3795 2015-02-11 19:35:28Z alin $
|
||||
*/
|
||||
package trick.dataproducts.plot.utils;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.File;
|
||||
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JCheckBoxMenuItem;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.border.EtchedBorder;
|
||||
|
||||
import org.jfree.chart.ChartMouseEvent;
|
||||
import org.jfree.chart.ChartMouseListener;
|
||||
import org.jfree.chart.JFreeChart;
|
||||
import org.jfree.chart.annotations.XYPointerAnnotation;
|
||||
import org.jfree.chart.entity.XYItemEntity;
|
||||
import org.jfree.chart.event.ChartChangeEvent;
|
||||
import org.jfree.chart.event.ChartChangeListener;
|
||||
import org.jfree.chart.event.ChartProgressEvent;
|
||||
import org.jfree.chart.event.ChartProgressListener;
|
||||
import org.jfree.chart.panel.CrosshairOverlay;
|
||||
import org.jfree.chart.plot.Crosshair;
|
||||
import org.jfree.chart.plot.XYPlot;
|
||||
import org.jfree.chart.renderer.xy.XYItemRenderer;
|
||||
import org.jfree.data.xy.XYDataset;
|
||||
import org.jfree.ui.Layer;
|
||||
import org.jfree.ui.RectangleAnchor;
|
||||
import org.jfree.ui.TextAnchor;
|
||||
|
||||
|
||||
public class TrickChartControlPanel extends JPanel implements ChartChangeListener, ChartMouseListener, ChartProgressListener {
|
||||
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Private Data
|
||||
//========================================
|
||||
private JFreeChart trickChart;
|
||||
private TrickChartPanel chartPanel;
|
||||
private JPanel controlPanel;
|
||||
|
||||
private static final long serialVersionUID = -6328244469933876791L;
|
||||
|
||||
private JCheckBox showLegendCheck;
|
||||
private JCheckBox showGridCheck;
|
||||
private JCheckBox showCrosshairCheck;
|
||||
private JButton printButton;
|
||||
private JButton moreButton;
|
||||
private JCheckBoxMenuItem showControlCheck;
|
||||
|
||||
private int lastSelectedSeries = -1;
|
||||
|
||||
private Crosshair crosshairX;
|
||||
private Crosshair crosshairY;
|
||||
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
/**
|
||||
* Constructs a panel containing a chart and its control.
|
||||
* The <code>useBuffer</code> flag controls whether or not an
|
||||
* offscreen <code>BufferedImage</code> is maintained for the chart.
|
||||
* If the buffer is used, more memory is consumed, but panel repaints
|
||||
* will be a lot quicker in cases where the chart itself hasn't
|
||||
* changed (for example, when another frame is moved to reveal the panel).
|
||||
*
|
||||
* WARNING: If you set the <code>useBuffer</code>
|
||||
* flag to false, note that the mouse zooming rectangle will (in that case)
|
||||
* be drawn using XOR, and there is a SEVERE performance problem with that
|
||||
* on JRE6 on Windows.
|
||||
*
|
||||
* @param chart the chart.
|
||||
* @param useBuffer a flag controlling whether or not an off-screen buffer
|
||||
* is used (read the warning above before setting this
|
||||
* to <code>false</code>).
|
||||
*/
|
||||
public TrickChartControlPanel(JFreeChart chart, boolean useBuffer) {
|
||||
setLayout(new BorderLayout());
|
||||
setDoubleBuffered(true);
|
||||
|
||||
updateUI();
|
||||
trickChart = chart;
|
||||
trickChart.addChangeListener(this);
|
||||
trickChart.addProgressListener(this);
|
||||
|
||||
trickChart.getXYPlot().setRangeCrosshairLockedOnData(false);
|
||||
trickChart.getXYPlot().setDomainCrosshairLockedOnData(false);
|
||||
|
||||
chartPanel = new TrickChartPanel(chart, useBuffer);
|
||||
chartPanel.setDefaultDirectoryForSaveAs(new File("."));
|
||||
chartPanel.setMouseWheelEnabled(true);
|
||||
chartPanel.setAutoscrolls(true);
|
||||
chartPanel.addChartMouseListener(this);
|
||||
Border border = BorderFactory.createEtchedBorder(EtchedBorder.RAISED);
|
||||
chartPanel.setBorder(border);
|
||||
|
||||
CrosshairOverlay overlay = new CrosshairOverlay();
|
||||
crosshairX = new Crosshair(0.0);
|
||||
crosshairX.setVisible(false);
|
||||
crosshairX.setPaint(Color.red);
|
||||
crosshairY = new Crosshair(0.0);
|
||||
crosshairY.setVisible(false);
|
||||
crosshairY.setPaint(Color.blue);
|
||||
overlay.addDomainCrosshair(crosshairX);
|
||||
overlay.addRangeCrosshair(crosshairY);
|
||||
chartPanel.addOverlay(overlay);
|
||||
crosshairX.setLabelVisible(true);
|
||||
crosshairX.setLabelAnchor(RectangleAnchor.BOTTOM_RIGHT);
|
||||
crosshairX.setLabelBackgroundPaint(new Color(255, 255, 0, 100));
|
||||
crosshairY.setLabelVisible(true);
|
||||
crosshairY.setLabelBackgroundPaint(new Color(255, 255, 0, 100));
|
||||
|
||||
controlPanel = new JPanel();
|
||||
|
||||
setupControls();
|
||||
|
||||
controlPanel.add(showLegendCheck);
|
||||
controlPanel.add(showGridCheck);
|
||||
controlPanel.add(showCrosshairCheck);
|
||||
controlPanel.add(printButton);
|
||||
controlPanel.add(moreButton);
|
||||
|
||||
this.add(chartPanel, BorderLayout.CENTER);
|
||||
this.add(controlPanel, BorderLayout.SOUTH);
|
||||
|
||||
showControlCheck = new JCheckBoxMenuItem("Show Control", true);
|
||||
showControlCheck.addActionListener(new AbstractAction("Show Control") {
|
||||
|
||||
private static final long serialVersionUID = -2185831057523724894L;
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (showControlCheck.isSelected()) {
|
||||
controlPanel.setVisible(true);
|
||||
} else {
|
||||
controlPanel.setVisible(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
chartPanel.getPopupMenu().add(showControlCheck);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up all control gui components.
|
||||
*/
|
||||
private void setupControls() {
|
||||
// by default, legend is shown
|
||||
showLegendCheck = new JCheckBox("Show Legend", true);
|
||||
showLegendCheck.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (!showLegendCheck.isSelected()) {
|
||||
trickChart.getLegend().setVisible(false);
|
||||
} else {
|
||||
trickChart.getLegend().setVisible(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// depending on the DP_ file setting
|
||||
showGridCheck = new JCheckBox("Show Grid", false);
|
||||
if (trickChart.getXYPlot().isDomainGridlinesVisible()) {
|
||||
showGridCheck.setSelected(true);
|
||||
}
|
||||
showGridCheck.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (!showGridCheck.isSelected()) {
|
||||
trickChart.getXYPlot().setRangeGridlinesVisible(false);
|
||||
trickChart.getXYPlot().setDomainGridlinesVisible(false);
|
||||
} else {
|
||||
trickChart.getXYPlot().setRangeGridlinesVisible(true);
|
||||
trickChart.getXYPlot().setDomainGridlinesVisible(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// by default, crosshair is not shown
|
||||
showCrosshairCheck = new JCheckBox("Show Crosshair", false);
|
||||
showCrosshairCheck.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (!showCrosshairCheck.isSelected()) {
|
||||
crosshairX.setVisible(false);
|
||||
crosshairY.setVisible(false);
|
||||
} else {
|
||||
crosshairX.setVisible(true);
|
||||
crosshairY.setVisible(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
printButton = new JButton(new AbstractAction("Print...") {
|
||||
private static final long serialVersionUID = 4694651015847994699L;
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
chartPanel.createChartPrintJob();
|
||||
}
|
||||
});
|
||||
|
||||
moreButton = new JButton(new AbstractAction("More...") {
|
||||
private static final long serialVersionUID = 4106804422858015720L;
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
chartPanel.getPopupMenu().show((JButton)e.getSource(), 0, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instance of {@link JFreeChart} of this panel.
|
||||
*
|
||||
* @return the instance of {@link JFreeChart} which this panel holds.
|
||||
*/
|
||||
public JFreeChart getTheChart() {
|
||||
return trickChart;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void chartChanged(ChartChangeEvent event) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void chartMouseClicked(ChartMouseEvent event) {
|
||||
/*
|
||||
* TODO: complete it!
|
||||
MouseEvent me = event.getTrigger();
|
||||
if ((me.getModifiers() & MouseEvent.CTRL_MASK) > 0) {
|
||||
String response = JOptionPane.showInputDialog(this,
|
||||
"Formula:",
|
||||
"Curve Formula",
|
||||
JOptionPane.QUESTION_MESSAGE);
|
||||
if (response != null && !response.trim().isEmpty()) {
|
||||
// applyFormulaToPlot();
|
||||
}
|
||||
} else if ((me.getModifiers() & MouseEvent.SHIFT_MASK) > 0) {
|
||||
// manipulateCurve();
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@Override
|
||||
public void chartProgress(ChartProgressEvent event) {
|
||||
crosshairX.setValue(trickChart.getXYPlot().getDomainCrosshairValue());
|
||||
crosshairY.setValue(trickChart.getXYPlot().getRangeCrosshairValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void chartMouseMoved(ChartMouseEvent event) {
|
||||
XYPlot plot = event.getChart().getXYPlot();
|
||||
if (event.getEntity() instanceof XYItemEntity) {
|
||||
XYItemEntity e = (XYItemEntity) (event.getEntity());
|
||||
XYDataset dataset = e.getDataset();
|
||||
|
||||
for (int i = 0; i < plot.getDatasetCount(); i++) {
|
||||
XYDataset test = plot.getDataset(i);
|
||||
if (test == dataset) {
|
||||
XYItemRenderer r = plot.getRenderer(i);
|
||||
|
||||
if (r instanceof TrickXYLineAndShapeRenderer) {
|
||||
TrickXYLineAndShapeRenderer sel = (TrickXYLineAndShapeRenderer) r;
|
||||
if (lastSelectedSeries != -1) {
|
||||
r.removeAnnotations();
|
||||
}
|
||||
if (sel.isSelectionActive()) {
|
||||
sel.setSelectedSeries(-1);
|
||||
sel.setSelectedItem(-1);
|
||||
} else {
|
||||
sel.setSelectedSeries(e.getSeriesIndex());
|
||||
lastSelectedSeries = e.getSeriesIndex();
|
||||
XYPointerAnnotation annotation = new XYPointerAnnotation(
|
||||
"series " + e.getSeriesIndex(), test.getXValue(e.getSeriesIndex(), e.getItem()), test.getYValue(e.getSeriesIndex(), e.getItem()), -Math.PI / 4.0);
|
||||
annotation.setTextAnchor(TextAnchor.BOTTOM_LEFT);
|
||||
annotation.setPaint(sel.getSeriesPaint(e.getSeriesIndex()));
|
||||
annotation.setArrowPaint(sel.getSeriesPaint(e.getSeriesIndex()));
|
||||
plot.getRenderer().addAnnotation(annotation, Layer.BACKGROUND);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (lastSelectedSeries != -1) {
|
||||
plot.getRenderer().removeAnnotations();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Inner classes
|
||||
//========================================
|
||||
}
|
@ -0,0 +1,321 @@
|
||||
/*
|
||||
* $Id: TrickChartFrame.java 3531 2014-05-16 16:32:51Z hchen3 $
|
||||
*/
|
||||
package trick.dataproducts.plot.utils;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.HeadlessException;
|
||||
import java.awt.Image;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JSeparator;
|
||||
|
||||
import org.jfree.chart.ChartPanel;
|
||||
|
||||
import com.lowagie.text.Document;
|
||||
import com.lowagie.text.DocumentException;
|
||||
import com.lowagie.text.PageSize;
|
||||
import com.lowagie.text.pdf.BaseFont;
|
||||
import com.lowagie.text.pdf.DefaultFontMapper;
|
||||
import com.lowagie.text.pdf.FontMapper;
|
||||
import com.lowagie.text.pdf.PdfContentByte;
|
||||
import com.lowagie.text.pdf.PdfTemplate;
|
||||
import com.lowagie.text.pdf.PdfWriter;
|
||||
|
||||
import trick.common.TrickApplication;
|
||||
import trick.common.ui.UIUtils;
|
||||
import trick.dataproducts.trickqp.utils.ProductPage;
|
||||
|
||||
|
||||
public class TrickChartFrame extends TrickFrame {
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Private Data
|
||||
//========================================
|
||||
private static final long serialVersionUID = 1388143913508263815L;
|
||||
|
||||
private ArrayList<TrickChartControlPanel> allPanels;
|
||||
|
||||
private String pageTitle = "Page";
|
||||
|
||||
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
/**
|
||||
* Creates a new, initially invisible <code>Frame</code> with the
|
||||
* specified title and frame icon if necessary.
|
||||
* <p>
|
||||
* This constructor sets the component's locale property to the value
|
||||
* returned by <code>JComponent.getDefaultLocale</code>.
|
||||
*
|
||||
* @param title the title for the frame
|
||||
* @param iconImage the icon image for the frame and has to set it to null for Mac
|
||||
* @param thePage the {@link ProductPage} instance that contains page spec
|
||||
* @param chartList the list of charts that are in the specified the page
|
||||
*/
|
||||
public TrickChartFrame(String title, Image iconImage, ProductPage thePage, ArrayList<TrickChart> chartList) throws HeadlessException {
|
||||
super(title, iconImage);
|
||||
setMenuBar();
|
||||
if (fileMenu != null) {
|
||||
fileMenu.add(new SaveAction("Make PDF", new ImageIcon(TrickApplication.class.getResource("resources/filesave.gif")), "Save Page to PDF", KeyEvent.VK_S));
|
||||
|
||||
fileMenu.add(new JSeparator());
|
||||
JMenuItem closeMenuItem = new JMenuItem(new CloseAction("Close", "Close Plot", KeyEvent.VK_L));
|
||||
|
||||
fileMenu.add(closeMenuItem);
|
||||
}
|
||||
|
||||
if (thePage != null && thePage.getTitle() != null) {
|
||||
pageTitle = thePage.getTitle();
|
||||
}
|
||||
|
||||
setupChart(thePage, chartList);
|
||||
}
|
||||
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
/**
|
||||
* Helper method for setting up the plot.
|
||||
*/
|
||||
private void setupChart(ProductPage thePage, ArrayList<TrickChart> chartList) {
|
||||
|
||||
if (chartList == null || chartList.size() < 0) {
|
||||
return;
|
||||
}
|
||||
int chartSize = chartList.size();
|
||||
allPanels = new ArrayList<TrickChartControlPanel>(chartSize);
|
||||
JPanel framePanel = getPlotChartFramePanel(thePage, chartSize);
|
||||
|
||||
for (TrickChart eachChart : chartList) {
|
||||
TrickChartControlPanel eachPanel = new TrickChartControlPanel(eachChart, true);
|
||||
allPanels.add(eachPanel);
|
||||
framePanel.add(eachPanel);
|
||||
}
|
||||
setContentPane(framePanel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures a panel so that it is able to show specified number of charts.
|
||||
*/
|
||||
private JPanel getPlotChartFramePanel(ProductPage thePage, int subChartNumber) {
|
||||
JPanel framePanel = new JPanel();
|
||||
framePanel.setPreferredSize(new Dimension(ChartPanel.DEFAULT_WIDTH, ChartPanel.DEFAULT_HEIGHT+280));
|
||||
int numberVCells = 1;
|
||||
int numberHCells = 1;
|
||||
|
||||
if (thePage.getHcells() != null) {
|
||||
numberHCells = thePage.getHcells().intValue();
|
||||
}
|
||||
|
||||
if (thePage.getVcells() != null) {
|
||||
numberVCells = thePage.getVcells().intValue();
|
||||
}
|
||||
|
||||
if (subChartNumber > (numberHCells * numberVCells)) {
|
||||
if (subChartNumber < 9) {
|
||||
if (subChartNumber == 3) {
|
||||
numberHCells = 1;
|
||||
numberVCells = 3;
|
||||
} else if (subChartNumber == 1) {
|
||||
numberVCells = 1;
|
||||
numberHCells = 1;
|
||||
} else {
|
||||
numberVCells = 2;
|
||||
numberHCells = (subChartNumber / 2) + (subChartNumber % 2);
|
||||
}
|
||||
} else {
|
||||
while((numberHCells * numberVCells) < subChartNumber ) {
|
||||
if (numberHCells <= numberVCells) {
|
||||
numberHCells++;
|
||||
} else {
|
||||
numberVCells++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
framePanel.setLayout(new GridLayout(numberVCells, numberHCells));
|
||||
return framePanel;
|
||||
}
|
||||
|
||||
public String getChartTitle() {
|
||||
return pageTitle;
|
||||
}
|
||||
|
||||
public int getChartSize() {
|
||||
if (allPanels != null) {
|
||||
return allPanels.size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for saving all charts to a PDF file.
|
||||
* @throws IOException
|
||||
*/
|
||||
public void saveChartsAsPDF() throws IOException {
|
||||
File file = UIUtils.chooseSaveFile(null, "plot_", "pdf", this);
|
||||
if (file == null) {
|
||||
return;
|
||||
}
|
||||
Document document = new Document(PageSize.A4);
|
||||
PdfWriter writer = null;
|
||||
PdfContentByte pdfContent = null;
|
||||
try {
|
||||
writer = PdfWriter.getInstance(document, new FileOutputStream(file));
|
||||
document.open();
|
||||
pdfContent = writer.getDirectContent();
|
||||
} catch (DocumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
writePDFPage(pdfContent, new DefaultFontMapper());
|
||||
|
||||
if (document != null) {
|
||||
document.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes all plots shown to one page of PDF.
|
||||
*
|
||||
* @param pdfContent an object containing the user positioned text and graphic contents of a page.
|
||||
* @param mapper mapping between AWT fonts and PDF fonts.
|
||||
* @throws IOException
|
||||
*/
|
||||
public void writePDFPage(PdfContentByte pdfContent, FontMapper mapper) throws IOException {
|
||||
if (pdfContent == null) {
|
||||
return;
|
||||
}
|
||||
Document document = pdfContent.getPdfDocument();
|
||||
int chartLocOffset = 30;
|
||||
try {
|
||||
int pageWidth = (int)document.getPageSize().getWidth();
|
||||
int pageHeight = (int)document.getPageSize().getHeight();
|
||||
document.newPage();
|
||||
|
||||
BaseFont pageTitleFont = BaseFont.createFont(BaseFont.HELVETICA_BOLD, "Cp1252", false);
|
||||
|
||||
// show page title text
|
||||
pdfContent.beginText();
|
||||
pdfContent.setFontAndSize(pageTitleFont, 12);
|
||||
pdfContent.showTextAligned(PdfContentByte.ALIGN_CENTER, getChartTitle(), pageWidth / 2 , pageHeight - chartLocOffset / 2, 0);
|
||||
pdfContent.endText();
|
||||
|
||||
// draw all plots
|
||||
PdfTemplate pdfTemplate = pdfContent.createTemplate(pageWidth, pageHeight);
|
||||
Graphics2D g2 = pdfTemplate.createGraphics(pageWidth, pageHeight, mapper);
|
||||
int rows = 1;
|
||||
int columns = 1;
|
||||
|
||||
if (getContentPane().getLayout() instanceof GridLayout) {
|
||||
rows = ((GridLayout)getContentPane().getLayout()).getRows();
|
||||
columns = ((GridLayout)getContentPane().getLayout()).getColumns();
|
||||
}
|
||||
|
||||
int eachChartWidth = pageWidth;
|
||||
int eachChartHeight = pageHeight - chartLocOffset;
|
||||
if (columns != 0) {
|
||||
eachChartWidth = pageWidth / columns;
|
||||
}
|
||||
if (rows != 0) {
|
||||
eachChartHeight = (pageHeight - chartLocOffset) / rows;
|
||||
}
|
||||
|
||||
int xLoc = 0;
|
||||
int yLoc = chartLocOffset;
|
||||
for (int i = 0; i < rows; i++) {
|
||||
for (int j = 0; j < columns; j++) {
|
||||
int index = i * columns + j;
|
||||
if (index >= getChartSize()) {
|
||||
break;
|
||||
}
|
||||
TrickChartControlPanel eachPanel = (TrickChartControlPanel)getContentPane().getComponent(index);
|
||||
if (eachPanel.getTheChart() != null) {
|
||||
Rectangle2D r2D = new Rectangle2D.Double(xLoc, yLoc, eachChartWidth, eachChartHeight);
|
||||
eachPanel.getTheChart().draw(g2, r2D);
|
||||
}
|
||||
xLoc = xLoc + eachChartWidth;
|
||||
}
|
||||
xLoc = 0;
|
||||
yLoc = yLoc + eachChartHeight;
|
||||
|
||||
}
|
||||
g2.dispose();
|
||||
pdfContent.addTemplate(pdfTemplate, 0, 0);
|
||||
}
|
||||
catch (DocumentException de) {
|
||||
de.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets this frame invisible.
|
||||
*/
|
||||
private void closeChart() {
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Inner Classes
|
||||
//========================================
|
||||
public class SaveAction extends AbstractAction {
|
||||
|
||||
private static final long serialVersionUID = 5844945315420458601L;
|
||||
public SaveAction(String text, ImageIcon icon,
|
||||
String desc, Integer mnemonic) {
|
||||
super(text, icon);
|
||||
putValue(SHORT_DESCRIPTION, desc);
|
||||
putValue(MNEMONIC_KEY, mnemonic);
|
||||
}
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
saveChartsAsPDF();
|
||||
} catch (IOException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class CloseAction extends AbstractAction {
|
||||
|
||||
private static final long serialVersionUID = 3077821392818469620L;
|
||||
public CloseAction(String text, String desc, Integer mnemonic) {
|
||||
super(text);
|
||||
putValue(SHORT_DESCRIPTION, desc);
|
||||
putValue(MNEMONIC_KEY, mnemonic);
|
||||
}
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
closeChart();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package trick.dataproducts.plot.utils;
|
||||
|
||||
import javax.swing.JOptionPane;
|
||||
|
||||
import org.jfree.chart.ChartPanel;
|
||||
import org.jfree.chart.JFreeChart;
|
||||
|
||||
import trick.dataproducts.plot.utils.editor.TrickChartEditor;
|
||||
import trick.dataproducts.plot.utils.editor.TrickChartEditorManager;
|
||||
|
||||
public class TrickChartPanel extends ChartPanel {
|
||||
|
||||
|
||||
private static final long serialVersionUID = -507551123952070511L;
|
||||
|
||||
/**
|
||||
* Constructs a panel containing a chart. The <code>useBuffer</code> flag
|
||||
* controls whether or not an offscreen <code>BufferedImage</code> is
|
||||
* maintained for the chart. If the buffer is used, more memory is
|
||||
* consumed, but panel repaints will be a lot quicker in cases where the
|
||||
* chart itself hasn't changed (for example, when another frame is moved
|
||||
* to reveal the panel). WARNING: If you set the <code>useBuffer</code>
|
||||
* flag to false, note that the mouse zooming rectangle will (in that case)
|
||||
* be drawn using XOR, and there is a SEVERE performance problem with that
|
||||
* on JRE6 on Windows.
|
||||
*
|
||||
* @param chart the chart.
|
||||
* @param useBuffer a flag controlling whether or not an off-screen buffer
|
||||
* is used (read the warning above before setting this
|
||||
* to <code>false</code>).
|
||||
*/
|
||||
public TrickChartPanel(JFreeChart chart, boolean useBuffer) {
|
||||
super(chart, useBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a dialog that allows the user to edit the properties for the
|
||||
* current chart.
|
||||
*/
|
||||
@Override
|
||||
public void doEditChartProperties() {
|
||||
TrickChartEditor editor = TrickChartEditorManager.getChartEditor(getChart());
|
||||
int result = JOptionPane.showConfirmDialog(this, editor,
|
||||
localizationResources.getString("Chart_Properties"),
|
||||
JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
|
||||
if (result == JOptionPane.OK_OPTION) {
|
||||
editor.updateChart(getChart());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* $Id: TrickChartTheme.java 3107 2013-07-03 18:53:42Z hchen3 $
|
||||
*/
|
||||
|
||||
package trick.dataproducts.plot.utils;
|
||||
|
||||
import java.awt.Font;
|
||||
|
||||
import org.jfree.chart.StandardChartTheme;
|
||||
|
||||
public class TrickChartTheme extends StandardChartTheme {
|
||||
|
||||
private static final long serialVersionUID = 4199990670106681300L;
|
||||
|
||||
/**
|
||||
* Creates a new default instance.
|
||||
*
|
||||
* @param name the name of the theme (<code>null</code> not permitted).
|
||||
*/
|
||||
public TrickChartTheme(String name) {
|
||||
super(name);
|
||||
this.setExtraLargeFont(new Font("Tahoma", Font.BOLD, 14));
|
||||
this.setLargeFont(new Font("Tahoma", Font.BOLD, 12));
|
||||
}
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* $Id: TrickFrame.java 3795 2015-02-11 19:35:28Z alin $
|
||||
*/
|
||||
package trick.dataproducts.plot.utils;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.HeadlessException;
|
||||
import java.awt.Image;
|
||||
import java.awt.event.KeyEvent;
|
||||
|
||||
import javax.swing.Box;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.WindowConstants;
|
||||
|
||||
import trick.common.ui.UIUtils;
|
||||
|
||||
|
||||
public class TrickFrame extends JFrame {
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
protected JMenu fileMenu = null;
|
||||
|
||||
//========================================
|
||||
// Private Data
|
||||
//========================================
|
||||
|
||||
private static final long serialVersionUID = -2771397837741213286L;
|
||||
|
||||
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
/**
|
||||
* Creates a new, initially invisible <code>Frame</code> with the
|
||||
* specified title and frame icon if necessary.
|
||||
* <p>
|
||||
* This constructor sets the component's locale property to the value
|
||||
* returned by <code>JComponent.getDefaultLocale</code>.
|
||||
*
|
||||
* @param title the title for the frame
|
||||
* @param iconImage the icon image for the frame and has to set it to null for Mac
|
||||
*
|
||||
* @exception HeadlessException if GraphicsEnvironment.isHeadless()
|
||||
* returns true.
|
||||
* @see java.awt.GraphicsEnvironment#isHeadless
|
||||
* @see Component#setSize
|
||||
* @see Component#setVisible
|
||||
* @see JComponent#getDefaultLocale
|
||||
*/
|
||||
public TrickFrame(String title, Image iconImage) throws HeadlessException {
|
||||
super(title);
|
||||
setIconImage(iconImage);
|
||||
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
|
||||
|
||||
// Set chartFrame icon to null for Mac to avoid invalid context 0x0 error message
|
||||
String theOS = System.getProperty("os.name").toLowerCase();
|
||||
if (theOS.indexOf("mac") != -1) {
|
||||
setIconImage(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
/**
|
||||
* Helper method for setting up the menu bar if needed.
|
||||
*/
|
||||
protected void setMenuBar() {
|
||||
JMenuBar menuBar = new JMenuBar();
|
||||
fileMenu = new JMenu("File");
|
||||
fileMenu.setMnemonic(KeyEvent.VK_F);
|
||||
menuBar.add(fileMenu);
|
||||
menuBar.add(Box.createHorizontalGlue());
|
||||
menuBar.add(UIUtils.getSmallTrickIconLabel());
|
||||
setJMenuBar(menuBar);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getTitle();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,192 @@
|
||||
/*
|
||||
* $Id: TrickTableFrame.java 3496 2014-04-17 19:48:51Z hchen3 $
|
||||
*/
|
||||
package trick.dataproducts.plot.utils;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.HeadlessException;
|
||||
import java.awt.Image;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.io.File;
|
||||
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JSeparator;
|
||||
import javax.swing.JTabbedPane;
|
||||
import javax.swing.JTextPane;
|
||||
import javax.swing.JViewport;
|
||||
import javax.swing.text.AttributeSet;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.SimpleAttributeSet;
|
||||
import javax.swing.text.StyleConstants;
|
||||
import javax.swing.text.StyleContext;
|
||||
import javax.swing.text.TabSet;
|
||||
import javax.swing.text.TabStop;
|
||||
import javax.swing.text.html.HTMLDocument;
|
||||
|
||||
import trick.common.TrickApplication;
|
||||
import trick.common.ui.UIUtils;
|
||||
import trick.dataproducts.trickqp.utils.ProductTable;
|
||||
import trick.dataproducts.utils.Session;
|
||||
import trick.dataproducts.utils.SessionRun;
|
||||
|
||||
|
||||
public class TrickTableFrame extends TrickFrame {
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Private data
|
||||
//========================================
|
||||
|
||||
private static final long serialVersionUID = -3151139797020281386L;
|
||||
|
||||
/** The pane that holds tables. One tab for one RUN. */
|
||||
private JTabbedPane framePane;
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
/**
|
||||
* Creates a new, initially invisible <code>Frame</code> with the
|
||||
* specified title and frame icon image if necessary.
|
||||
* <p>
|
||||
* This constructor sets the component's locale property to the value
|
||||
* returned by <code>JComponent.getDefaultLocale</code>.
|
||||
*
|
||||
* @param title the title for the frame
|
||||
* @param sessionObject the {@link Session} object that contains where the table data is from
|
||||
* @param theTable the {@link ProductTable} instance that contains the table specs
|
||||
*
|
||||
*/
|
||||
public TrickTableFrame(String title, Image iconImage, Session sessionObject, ProductTable theTable) throws HeadlessException {
|
||||
super(title, iconImage);
|
||||
setMenuBar();
|
||||
if (fileMenu != null) {
|
||||
fileMenu.add(new SaveAction("Save", new ImageIcon(TrickApplication.class.getResource("resources/filesave.gif")), "Save Table", KeyEvent.VK_S));
|
||||
|
||||
fileMenu.add(new JSeparator());
|
||||
JMenuItem closeMenuItem = new JMenuItem(new CloseAction("Close", "Close Table", KeyEvent.VK_L));
|
||||
|
||||
fileMenu.add(closeMenuItem);
|
||||
}
|
||||
setupTable(sessionObject, theTable);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
/**
|
||||
* Helper method for setting up the table.
|
||||
*/
|
||||
private void setupTable(Session sessionObject, ProductTable theTable) {
|
||||
framePane = new JTabbedPane();
|
||||
framePane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
|
||||
|
||||
for (SessionRun eachRun : sessionObject.getRuns()) {
|
||||
JTextPane eachTablePane = new JTextPane();
|
||||
eachTablePane.setEditable(false);
|
||||
eachTablePane.setPreferredSize(new Dimension(400, 600));
|
||||
|
||||
// using HTMLDocument so that the table pane does not performing line wrapping
|
||||
eachTablePane.setContentType("text/html");
|
||||
HTMLDocument doc = (HTMLDocument)eachTablePane.getDocument();
|
||||
|
||||
// sets tabs setting for the table pane so that all values separated by tabs
|
||||
// can be aligned as table columns
|
||||
TabStop[] tabs = new TabStop[theTable.getColumnList().size()];
|
||||
int tabPixels = 200;
|
||||
for (int i = 0; i < theTable.getColumnList().size(); i++) {
|
||||
tabs[i] = new TabStop(tabPixels, TabStop.ALIGN_RIGHT, TabStop.LEAD_EQUALS);
|
||||
tabPixels += 200;
|
||||
}
|
||||
TabSet tabset = new TabSet(tabs);
|
||||
StyleContext context = StyleContext.getDefaultStyleContext();
|
||||
AttributeSet attrSet = context.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.TabSet, tabset);
|
||||
eachTablePane.setParagraphAttributes(attrSet, false);
|
||||
|
||||
PlotUtils.insertTableData(eachRun, theTable, doc);
|
||||
// scroll to top of the pane
|
||||
eachTablePane.setCaretPosition(0);
|
||||
framePane.add(eachRun.getDirName(), new JScrollPane(eachTablePane));
|
||||
}
|
||||
|
||||
add(framePane, BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for saving the table data to a text file.
|
||||
*/
|
||||
private void saveTable() {
|
||||
File file = UIUtils.chooseSaveFile(null, "table_", null, this);
|
||||
if (file != null) {
|
||||
JViewport viewPort = ((JScrollPane)framePane.getSelectedComponent()).getViewport();
|
||||
|
||||
JTextPane selectedPane = (JTextPane)viewPort.getView();
|
||||
try {
|
||||
UIUtils.saveTextFile(selectedPane.getDocument().getText(0, selectedPane.getDocument().getLength()), file);
|
||||
} catch (BadLocationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this frame invisible.
|
||||
*/
|
||||
private void closeTable() {
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Inner Classes
|
||||
//========================================
|
||||
public class SaveAction extends AbstractAction {
|
||||
|
||||
private static final long serialVersionUID = -2005694863569791565L;
|
||||
|
||||
public SaveAction(String text, ImageIcon icon,
|
||||
String desc, Integer mnemonic) {
|
||||
super(text, icon);
|
||||
putValue(SHORT_DESCRIPTION, desc);
|
||||
putValue(MNEMONIC_KEY, mnemonic);
|
||||
}
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
saveTable();
|
||||
}
|
||||
}
|
||||
|
||||
public class CloseAction extends AbstractAction {
|
||||
|
||||
private static final long serialVersionUID = 8766852963567400594L;
|
||||
|
||||
public CloseAction(String text, String desc, Integer mnemonic) {
|
||||
super(text);
|
||||
putValue(SHORT_DESCRIPTION, desc);
|
||||
putValue(MNEMONIC_KEY, mnemonic);
|
||||
}
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
closeTable();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* $Id: TrickXYLineAndShapeRenderer.java 3795 2015-02-11 19:35:28Z alin $
|
||||
*/
|
||||
package trick.dataproducts.plot.utils;
|
||||
|
||||
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
|
||||
|
||||
public class TrickXYLineAndShapeRenderer extends XYLineAndShapeRenderer {
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
|
||||
|
||||
//========================================
|
||||
// Private data
|
||||
//========================================
|
||||
|
||||
private static final long serialVersionUID = -7308381022424004094L;
|
||||
|
||||
private int selectedSeries = -1;
|
||||
private int selectedItem = -1;
|
||||
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
public TrickXYLineAndShapeRenderer() {
|
||||
super(true, false);
|
||||
setBaseShapesFilled(false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Set/Get methods
|
||||
//========================================
|
||||
public void setSelectedSeries(int series) {
|
||||
this.selectedSeries = series;
|
||||
}
|
||||
|
||||
public void setSelectedItem(int item) {
|
||||
this.selectedItem = item;
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
public boolean isSelectionActive() {
|
||||
return (selectedSeries > -1 && selectedItem > -1);
|
||||
}
|
||||
}
|
@ -0,0 +1,343 @@
|
||||
/*
|
||||
* $Id: TrickXYPlot.java 3795 2015-02-11 19:35:28Z alin $
|
||||
*/
|
||||
|
||||
package trick.dataproducts.plot.utils;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.Shape;
|
||||
import java.math.RoundingMode;
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import org.jfree.chart.axis.NumberAxis;
|
||||
import org.jfree.chart.labels.StandardXYToolTipGenerator;
|
||||
import org.jfree.chart.plot.PlotOrientation;
|
||||
import org.jfree.chart.plot.XYPlot;
|
||||
import org.jfree.data.xy.XYSeriesCollection;
|
||||
|
||||
import trick.dataproducts.trickqp.utils.ProductDataPanel;
|
||||
import trick.dataproducts.trickqp.utils.ProductPage;
|
||||
import trick.dataproducts.trickqp.utils.ProductPlot;
|
||||
import trick.dataproducts.trickqp.utils.ProductVar;
|
||||
|
||||
/**
|
||||
* Extends {@link XYPlot} so that Trick plotting specification can
|
||||
* be applied to the plot.
|
||||
*
|
||||
* @author Hong Chen
|
||||
*
|
||||
*/
|
||||
public class TrickXYPlot extends XYPlot {
|
||||
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Private Data
|
||||
//========================================
|
||||
|
||||
private static final long serialVersionUID = -3995993644038371850L;
|
||||
|
||||
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
/**
|
||||
* Creates a new plot with the specified dataset, axes and renderer
|
||||
* that is for a particular {@link ProductPage} and {@link ProductPlot}.
|
||||
*
|
||||
* @param aPage the {@link ProductPage} which the plot is with.
|
||||
* @param aPlot the {@link ProductPlot} spec plotting.
|
||||
* @param dataset the dataset (<code>null</code> permitted).
|
||||
* @param guiXAxis the domain axis (<code>null</code> permitted).
|
||||
* @param guiYAxis the range axis (<code>null</code> permitted).
|
||||
* @param renderer the renderer (<code>null</code> permitted).
|
||||
*/
|
||||
public TrickXYPlot(ProductPage aPage,
|
||||
ProductPlot aPlot,
|
||||
XYSeriesCollection dataset,
|
||||
NumberAxis guiXAxis,
|
||||
NumberAxis guiYAxis,
|
||||
TrickXYLineAndShapeRenderer renderer) {
|
||||
|
||||
super(dataset, guiXAxis, guiYAxis, renderer);
|
||||
|
||||
setAxisRange(dataset, guiXAxis, guiYAxis);
|
||||
|
||||
// the order of the following calls matters as the lower level of
|
||||
// specs would override the higher level of specs
|
||||
applyPageSpec(aPage, guiXAxis, guiYAxis);
|
||||
|
||||
applyPlotSpec(aPage, aPlot, dataset, guiXAxis, guiYAxis);
|
||||
|
||||
// TODO: applyXVarSpec
|
||||
|
||||
applyYVarSpec(dataset, renderer);
|
||||
|
||||
setOrientation(PlotOrientation.VERTICAL);
|
||||
renderer.setBaseToolTipGenerator(new StandardXYToolTipGenerator());
|
||||
}
|
||||
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
/**
|
||||
* Helper method for setting the range for both X and Y axis.
|
||||
* The min and max values are based on all series data.
|
||||
*/
|
||||
private void setAxisRange(XYSeriesCollection dataset, NumberAxis guiXAxis,
|
||||
NumberAxis guiYAxis) {
|
||||
if (dataset == null || dataset.getSeriesCount() < 1) {
|
||||
return;
|
||||
}
|
||||
double minX = dataset.getSeries(0).getMinX();
|
||||
double maxX = dataset.getSeries(0).getMaxX();
|
||||
double minY = dataset.getSeries(0).getMinY();
|
||||
double maxY = dataset.getSeries(0).getMaxY();
|
||||
|
||||
for (int i = 1; i < dataset.getSeriesCount(); i++) {
|
||||
minX = Math.min(minX, dataset.getSeries(i).getMinX());
|
||||
maxX = Math.max(maxX, dataset.getSeries(i).getMaxX());
|
||||
minY = Math.min(minY, dataset.getSeries(i).getMinY());
|
||||
maxY = Math.max(maxY, dataset.getSeries(i).getMaxY());
|
||||
}
|
||||
guiXAxis.setRange(minX, maxX);
|
||||
guiYAxis.setRange(minY, maxY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for applying page spec to gui.
|
||||
*/
|
||||
private void applyPageSpec(ProductPage aPage, NumberAxis guiXAxis, NumberAxis guiYAxis) {
|
||||
|
||||
if (aPage.getForegroundColor() != null) {
|
||||
guiXAxis.setTickLabelPaint(aPage.getForegroundColor());
|
||||
guiXAxis.setLabelPaint(aPage.getForegroundColor());
|
||||
guiYAxis.setTickLabelPaint(aPage.getForegroundColor());
|
||||
guiYAxis.setLabelPaint(aPage.getForegroundColor());
|
||||
}
|
||||
|
||||
if (aPage.getBackgroundColor() != null) {
|
||||
setBackgroundPaint(aPage.getBackgroundColor());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for applying plot spec to gui.
|
||||
*/
|
||||
private void applyPlotSpec(ProductPage aPage,
|
||||
ProductPlot aPlot,
|
||||
XYSeriesCollection dataset,
|
||||
NumberAxis guiXAxis,
|
||||
NumberAxis guiYAxis) {
|
||||
|
||||
applyPlotXAxisSpec(aPlot, dataset, guiXAxis);
|
||||
|
||||
applyPlotYAxisSpec(aPlot, dataset, guiYAxis);
|
||||
|
||||
// Plot Start and Stop
|
||||
|
||||
// Plot Foreground
|
||||
if (aPlot.getForegroundColor() != null) {
|
||||
guiXAxis.setTickLabelPaint(aPlot.getForegroundColor());
|
||||
guiXAxis.setLabelPaint(aPlot.getForegroundColor());
|
||||
guiYAxis.setTickLabelPaint(aPlot.getForegroundColor());
|
||||
guiYAxis.setLabelPaint(aPlot.getForegroundColor());
|
||||
}
|
||||
|
||||
// Plot Background
|
||||
if (aPlot.getBackgroundColor() != null) {
|
||||
setBackgroundPaint(aPlot.getBackgroundColor());
|
||||
}
|
||||
|
||||
// Plot Grid and Grid Color
|
||||
if (aPlot.getGrid().equalsIgnoreCase("Yes")) {
|
||||
setDomainGridlinesVisible(true);
|
||||
setRangeGridlinesVisible(true);
|
||||
if (aPlot.getGridColor() != null) {
|
||||
setDomainGridlinePaint(aPlot.getGridColor());
|
||||
setRangeGridlinePaint(aPlot.getGridColor());
|
||||
}
|
||||
|
||||
// use this stroke for both domain and range grid to make it more clear
|
||||
BasicStroke stroke = new BasicStroke(1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
|
||||
setDomainGridlineStroke(stroke);
|
||||
setRangeGridlineStroke(stroke);
|
||||
} else {
|
||||
setDomainGridlinesVisible(true);
|
||||
setRangeGridlinesVisible(true);
|
||||
}
|
||||
|
||||
// Plot Font
|
||||
if (aPlot.getFont() != null && !(aPlot.getFont().isEmpty())) {
|
||||
Font plotFont = ProductDataPanel.getFontFromText(aPlot.getFont());
|
||||
if (plotFont != null) {
|
||||
guiXAxis.setTickLabelFont(plotFont);
|
||||
guiXAxis.setLabelFont(plotFont);
|
||||
guiYAxis.setTickLabelFont(plotFont);
|
||||
guiYAxis.setLabelFont(plotFont);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for applying Y axis spec to gui.
|
||||
*/
|
||||
private void applyPlotYAxisSpec(ProductPlot aPlot,
|
||||
XYSeriesCollection dataset,
|
||||
NumberAxis guiYAxis) {
|
||||
// apply Plot Y Axis Label
|
||||
// if no label provided, the Y variable name is used if they are all the same within the collection
|
||||
if (aPlot.getYAxis() != null) {
|
||||
guiYAxis.setLabel(aPlot.getYAxis().getLabel());
|
||||
} else {
|
||||
ProductVar theYVar = getYVarFromSeriesCollection(dataset);
|
||||
if (theYVar != null) {
|
||||
guiYAxis.setLabel(theYVar.getName());
|
||||
guiYAxis.setFixedAutoRange(dataset.getSeries(0).getMaxY() - dataset.getSeries(0).getMinY());
|
||||
}
|
||||
}
|
||||
|
||||
// Y Axis Format
|
||||
if (aPlot.getYAxis() != null && aPlot.getYAxis().getFormat() != null && !aPlot.getYAxis().getFormat().isEmpty()) {
|
||||
try {
|
||||
DecimalFormat newFormat = new DecimalFormat(aPlot.getYAxis().getFormat());
|
||||
newFormat.setRoundingMode(RoundingMode.HALF_UP);
|
||||
guiYAxis.setNumberFormatOverride(newFormat);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
// do nothing if the provided format is invalid
|
||||
}
|
||||
}
|
||||
|
||||
if (aPlot.getYMin() != null && aPlot.getYMax() != null) {
|
||||
guiYAxis.setRange(aPlot.getYMin().doubleValue(), aPlot.getYMax().doubleValue());
|
||||
} else if (aPlot.getYMin() != null) {
|
||||
guiYAxis.setRange(aPlot.getYMin().doubleValue(), guiYAxis.getUpperBound());
|
||||
} else if (aPlot.getYMax() != null) {
|
||||
guiYAxis.setRange(guiYAxis.getLowerBound(), aPlot.getYMax().doubleValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for applying X axis spec to gui.
|
||||
*/
|
||||
private void applyPlotXAxisSpec(ProductPlot aPlot,
|
||||
XYSeriesCollection dataset,
|
||||
NumberAxis guiXAxis) {
|
||||
// apply Plot X Axis Label
|
||||
// if no label provided, the X variable name is used if they are all the same within the collection
|
||||
if (aPlot.getXAxis() != null) {
|
||||
guiXAxis.setLabel(aPlot.getXAxis().getLabel());
|
||||
} else {
|
||||
ProductVar theXVar = getXVarFromSeriesCollection(dataset);
|
||||
if (theXVar != null) {
|
||||
guiXAxis.setLabel(theXVar.getName());
|
||||
guiXAxis.setFixedAutoRange(dataset.getSeries(0).getMaxX() - dataset.getSeries(0).getMinX());
|
||||
}
|
||||
}
|
||||
|
||||
if (aPlot.getXMin() != null && aPlot.getXMax() != null) {
|
||||
guiXAxis.setRange(aPlot.getXMin().doubleValue(), aPlot.getXMax().doubleValue());
|
||||
} else if (aPlot.getXMin() != null) {
|
||||
guiXAxis.setRange(aPlot.getXMin().doubleValue(), guiXAxis.getUpperBound());
|
||||
} else if (aPlot.getXMax() != null) {
|
||||
guiXAxis.setRange(guiXAxis.getLowerBound(), aPlot.getXMax().doubleValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for applying Y variable spec to gui.
|
||||
*/
|
||||
private void applyYVarSpec(XYSeriesCollection dataset,
|
||||
TrickXYLineAndShapeRenderer renderer) {
|
||||
// Y Var Line Color, Line Style, Symbol Style, Symbol Size
|
||||
for (int i = 0; i < dataset.getSeriesCount(); i++) {
|
||||
TrickXYSeries xySeries = null;
|
||||
if (dataset.getSeries(i) instanceof TrickXYSeries) {
|
||||
xySeries = (TrickXYSeries)dataset.getSeries(i);
|
||||
// color
|
||||
Color lineColor = xySeries.getYVar().getLineColor();
|
||||
if (lineColor != null) {
|
||||
renderer.setSeriesPaint(i, lineColor);
|
||||
}
|
||||
// style
|
||||
ProductVar.LineStyle lineStyle = xySeries.getYVar().getLineStyle();
|
||||
if (lineStyle != null) {
|
||||
renderer.setSeriesStroke(i, lineStyle.getStroke());
|
||||
}
|
||||
// symbol
|
||||
ProductVar.SymbolStyle symbolStyle = xySeries.getYVar().getSymbolStyle();
|
||||
Shape symbolShape = xySeries.getYVar().getSymbolShape(symbolStyle);
|
||||
if (symbolShape != null) {
|
||||
renderer.setSeriesShapesVisible(i, true);
|
||||
renderer.setSeriesShape(i, symbolShape);
|
||||
renderer.setBaseShapesFilled(symbolStyle.isFilled());
|
||||
} else {
|
||||
renderer.setSeriesShapesVisible(i, false);
|
||||
renderer.setBaseShapesFilled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for getting the same X variable name from the specified {@link XYSeriesCollection}.
|
||||
*/
|
||||
private ProductVar getXVarFromSeriesCollection(XYSeriesCollection dataset) {
|
||||
ProductVar theXVar = null;
|
||||
|
||||
if (dataset.getSeriesCount() > 0) {
|
||||
if (dataset.getSeries(0) instanceof TrickXYSeries) {
|
||||
theXVar = ((TrickXYSeries)dataset.getSeries(0)).getXVar();
|
||||
for (int i = 1; i < dataset.getSeriesCount(); i++) {
|
||||
TrickXYSeries theXYSeries = null;
|
||||
if (dataset.getSeries(i) instanceof TrickXYSeries) {
|
||||
theXYSeries = (TrickXYSeries)dataset.getSeries(i);
|
||||
if (!(theXVar.getName().equals(theXYSeries.getXVar().getName()))) {
|
||||
theXVar = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return theXVar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for getting the same Y variable name from the specified {@link XYSeriesCollection}.
|
||||
*/
|
||||
private ProductVar getYVarFromSeriesCollection(XYSeriesCollection dataset) {
|
||||
ProductVar theYVar = null;
|
||||
if (dataset.getSeriesCount() > 0) {
|
||||
if (dataset.getSeries(0) instanceof TrickXYSeries) {
|
||||
theYVar = ((TrickXYSeries)dataset.getSeries(0)).getYVar();
|
||||
for (int i = 1; i < dataset.getSeriesCount(); i++) {
|
||||
TrickXYSeries theXYSeries = null;
|
||||
if (dataset.getSeries(i) instanceof TrickXYSeries) {
|
||||
theXYSeries = (TrickXYSeries)dataset.getSeries(i);
|
||||
if (!(theYVar.getName().equals(theXYSeries.getYVar().getName()))) {
|
||||
theYVar = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return theYVar;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* $Id: TrickXYSeries.java 3795 2015-02-11 19:35:28Z alin $
|
||||
*/
|
||||
package trick.dataproducts.plot.utils;
|
||||
|
||||
import org.jfree.data.xy.XYSeries;
|
||||
|
||||
import trick.dataproducts.trickqp.utils.ProductVar;
|
||||
|
||||
public class TrickXYSeries extends XYSeries {
|
||||
|
||||
|
||||
//========================================
|
||||
// Public data
|
||||
//========================================
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Protected data
|
||||
//========================================
|
||||
|
||||
|
||||
|
||||
//========================================
|
||||
// Private data
|
||||
//========================================
|
||||
|
||||
private static final long serialVersionUID = -4137551900938397559L;
|
||||
|
||||
private ProductVar xVar;
|
||||
private ProductVar yVar;
|
||||
|
||||
|
||||
//========================================
|
||||
// Constructors
|
||||
//========================================
|
||||
/**
|
||||
* Creates a new empty series. By default, items added to the series will
|
||||
* be sorted into ascending order by x-value, and duplicate x-values will
|
||||
* be allowed (these defaults can be modified with another constructor.
|
||||
*
|
||||
* @param key the series key (<code>null</code> not permitted).
|
||||
*/
|
||||
public TrickXYSeries(Comparable key) {
|
||||
super(key, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new empty series, with the auto-sort flag set as requested,
|
||||
* and duplicate values allowed.
|
||||
*
|
||||
* @param key the series key (<code>null</code> not permitted).
|
||||
* @param autoSort a flag that controls whether or not the items in the
|
||||
* series are sorted.
|
||||
*/
|
||||
public TrickXYSeries(Comparable key, boolean autoSort) {
|
||||
super(key, autoSort, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new xy-series that contains no data. You can specify
|
||||
* whether or not duplicate x-values are allowed for the series.
|
||||
*
|
||||
* @param key the series key (<code>null</code> not permitted).
|
||||
* @param autoSort a flag that controls whether or not the items in the
|
||||
* series are sorted.
|
||||
* @param allowDuplicateXValues a flag that controls whether duplicate
|
||||
* x-values are allowed.
|
||||
*/
|
||||
public TrickXYSeries(Comparable key, boolean autoSort, boolean allowDuplicateXValues) {
|
||||
super(key, autoSort, allowDuplicateXValues);
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Set/Get methods
|
||||
//========================================
|
||||
/**
|
||||
* Sets X variable to the specified {@link ProductVar}.
|
||||
*
|
||||
* @param x An instance of {@link ProductVar}.
|
||||
*/
|
||||
public void setXVar(ProductVar x) {
|
||||
xVar = x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets Y variable to the specified {@link ProductVar}.
|
||||
*
|
||||
* @param y An instance of {@link ProductVar}.
|
||||
*/
|
||||
public void setYVar(ProductVar y) {
|
||||
yVar = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets X variable.
|
||||
*
|
||||
* @return An instance of {@link ProductVar}.
|
||||
*/
|
||||
public ProductVar getXVar() {
|
||||
return xVar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets Y variable.
|
||||
*
|
||||
* @return An instance of {@link ProductVar}.
|
||||
*/
|
||||
public ProductVar getYVar() {
|
||||
return yVar;
|
||||
}
|
||||
|
||||
//========================================
|
||||
// Methods
|
||||
//========================================
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* $Id
|
||||
*/
|
||||
|
||||
package trick.dataproducts.plot.utils.editor;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.FocusEvent;
|
||||
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextField;
|
||||
|
||||
import org.jfree.chart.axis.Axis;
|
||||
import org.jfree.chart.axis.LogAxis;
|
||||
import org.jfree.chart.axis.NumberTickUnit;
|
||||
|
||||
/**
|
||||
* A panel for editing properties of a {@link LogAxis}.
|
||||
*/
|
||||
public class DefaultLogAxisEditor extends TrickValueAxisEditor {
|
||||
|
||||
|
||||
private static final long serialVersionUID = -5229846864465910050L;
|
||||
|
||||
private double manualTickUnitValue;
|
||||
|
||||
private JTextField manualTickUnit;
|
||||
|
||||
/**
|
||||
* Standard constructor: builds a property panel for the specified axis.
|
||||
*
|
||||
* @param axis the axis, which should be changed.
|
||||
*/
|
||||
public DefaultLogAxisEditor(LogAxis axis) {
|
||||
super(axis);
|
||||
this.manualTickUnitValue = axis.getTickUnit().getSize();
|
||||
manualTickUnit.setText(Double.toString(this.manualTickUnitValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a panel for editing the tick unit.
|
||||
*
|
||||
* @return A panel.
|
||||
*/
|
||||
@Override
|
||||
protected JPanel createTickUnitPanel() {
|
||||
JPanel tickUnitPanel = super.createTickUnitPanel();
|
||||
|
||||
tickUnitPanel.add(new JLabel(localizationResources.getString(
|
||||
"Manual_TickUnit_value")));
|
||||
this.manualTickUnit = new JTextField(Double.toString(
|
||||
this.manualTickUnitValue));
|
||||
this.manualTickUnit.setEnabled(!isAutoTickUnitSelection());
|
||||
this.manualTickUnit.setActionCommand("TickUnitValue");
|
||||
this.manualTickUnit.addActionListener(this);
|
||||
this.manualTickUnit.addFocusListener(this);
|
||||
tickUnitPanel.add(this.manualTickUnit);
|
||||
tickUnitPanel.add(new JPanel());
|
||||
|
||||
return tickUnitPanel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles actions from within the property panel.
|
||||
*
|
||||
* @param event an event.
|
||||
*/
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
String command = event.getActionCommand();
|
||||
if (command.equals("TickUnitValue")) {
|
||||
validateTickUnit();
|
||||
}
|
||||
else {
|
||||
// pass to the super-class for handling
|
||||
super.actionPerformed(event);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusLost(FocusEvent event) {
|
||||
super.focusLost(event);
|
||||
if (event.getSource() == this.manualTickUnit) {
|
||||
validateTickUnit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the auto-tick-unit setting.
|
||||
*/
|
||||
@Override
|
||||
public void toggleAutoTick() {
|
||||
super.toggleAutoTick();
|
||||
if (isAutoTickUnitSelection()) {
|
||||
this.manualTickUnit.setText(Double.toString(this.manualTickUnitValue));
|
||||
this.manualTickUnit.setEnabled(false);
|
||||
}
|
||||
else {
|
||||
this.manualTickUnit.setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the tick unit entered.
|
||||
*/
|
||||
public void validateTickUnit() {
|
||||
double newTickUnit;
|
||||
try {
|
||||
newTickUnit = Double.parseDouble(this.manualTickUnit.getText());
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
newTickUnit = this.manualTickUnitValue;
|
||||
}
|
||||
|
||||
if (newTickUnit > 0.0) {
|
||||
this.manualTickUnitValue = newTickUnit;
|
||||
}
|
||||
this.manualTickUnit.setText(Double.toString(this.manualTickUnitValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the properties of the specified axis to match the properties
|
||||
* defined on this panel.
|
||||
*
|
||||
* @param axis the axis.
|
||||
*/
|
||||
@Override
|
||||
public void setAxisProperties(Axis axis) {
|
||||
super.setAxisProperties(axis);
|
||||
LogAxis logAxis = (LogAxis) axis;
|
||||
if (!isAutoTickUnitSelection()) {
|
||||
logAxis.setTickUnit(new NumberTickUnit(manualTickUnitValue));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,488 @@
|
||||
/*
|
||||
* $Id
|
||||
*/
|
||||
|
||||
package trick.dataproducts.plot.utils.editor;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.Paint;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JColorChooser;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTabbedPane;
|
||||
import javax.swing.JTextField;
|
||||
|
||||
import org.jfree.chart.axis.Axis;
|
||||
import org.jfree.chart.axis.LogAxis;
|
||||
import org.jfree.chart.axis.NumberAxis;
|
||||
import org.jfree.chart.util.ResourceBundleWrapper;
|
||||
import org.jfree.layout.LCBLayout;
|
||||
import org.jfree.ui.FontChooserPanel;
|
||||
import org.jfree.ui.FontDisplayField;
|
||||
import org.jfree.ui.PaintSample;
|
||||
import org.jfree.ui.RectangleInsets;
|
||||
|
||||
/**
|
||||
* A panel for editing the properties of an axis.
|
||||
*/
|
||||
public class TrickAxisEditor extends JPanel implements ActionListener {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 5523403058732526022L;
|
||||
|
||||
/** The axis label. */
|
||||
private JTextField label;
|
||||
|
||||
/** The label font. */
|
||||
private Font labelFont;
|
||||
|
||||
/** The label paint. */
|
||||
private PaintSample labelPaintSample;
|
||||
|
||||
/** A field showing a description of the label font. */
|
||||
private JTextField labelFontField;
|
||||
|
||||
/** The font for displaying tick labels on the axis. */
|
||||
private Font tickLabelFont;
|
||||
|
||||
/**
|
||||
* A field containing a description of the font for displaying tick labels
|
||||
* on the axis.
|
||||
*/
|
||||
private JTextField tickLabelFontField;
|
||||
|
||||
/** The paint (color) for the tick labels. */
|
||||
private PaintSample tickLabelPaintSample;
|
||||
|
||||
/**
|
||||
* An empty sub-panel for extending the user interface to handle more
|
||||
* complex axes.
|
||||
*/
|
||||
private JPanel slot1;
|
||||
|
||||
/**
|
||||
* An empty sub-panel for extending the user interface to handle more
|
||||
* complex axes.
|
||||
*/
|
||||
private JPanel slot2;
|
||||
|
||||
/** A flag that indicates whether or not the tick labels are visible. */
|
||||
private JCheckBox showTickLabelsCheckBox;
|
||||
|
||||
/** A flag that indicates whether or not the tick marks are visible. */
|
||||
private JCheckBox showTickMarksCheckBox;
|
||||
|
||||
// /** Insets text field. */
|
||||
// private InsetsTextField tickLabelInsetsTextField;
|
||||
//
|
||||
// /** Label insets text field. */
|
||||
// private InsetsTextField labelInsetsTextField;
|
||||
|
||||
/** The tick label insets. */
|
||||
private RectangleInsets tickLabelInsets;
|
||||
|
||||
/** The label insets. */
|
||||
private RectangleInsets labelInsets;
|
||||
|
||||
/** A tabbed pane for... */
|
||||
private JTabbedPane otherTabs;
|
||||
|
||||
/** The resourceBundle for the localization. */
|
||||
protected static ResourceBundle localizationResources
|
||||
= ResourceBundleWrapper.getBundle(
|
||||
"org.jfree.chart.editor.LocalizationBundle");
|
||||
|
||||
/**
|
||||
* A static method that returns a panel that is appropriate for the axis
|
||||
* type.
|
||||
*
|
||||
* @param axis the axis whose properties are to be displayed/edited in
|
||||
* the panel.
|
||||
*
|
||||
* @return A panel or <code>null</code< if axis is <code>null</code>.
|
||||
*/
|
||||
public static TrickAxisEditor getInstance(Axis axis) {
|
||||
|
||||
if (axis != null) {
|
||||
// figure out what type of axis we have and instantiate the
|
||||
// appropriate panel
|
||||
if (axis instanceof NumberAxis) {
|
||||
return new TrickNumberAxisEditor((NumberAxis) axis);
|
||||
}
|
||||
if (axis instanceof LogAxis) {
|
||||
return new DefaultLogAxisEditor((LogAxis) axis);
|
||||
}
|
||||
else {
|
||||
return new TrickAxisEditor(axis);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard constructor: builds a panel for displaying/editing the
|
||||
* properties of the specified axis.
|
||||
*
|
||||
* @param axis the axis whose properties are to be displayed/edited in
|
||||
* the panel.
|
||||
*/
|
||||
public TrickAxisEditor(Axis axis) {
|
||||
|
||||
this.labelFont = axis.getLabelFont();
|
||||
this.labelPaintSample = new PaintSample(axis.getLabelPaint());
|
||||
this.tickLabelFont = axis.getTickLabelFont();
|
||||
this.tickLabelPaintSample = new PaintSample(axis.getTickLabelPaint());
|
||||
|
||||
// Insets values
|
||||
this.tickLabelInsets = axis.getTickLabelInsets();
|
||||
this.labelInsets = axis.getLabelInsets();
|
||||
|
||||
setLayout(new BorderLayout());
|
||||
|
||||
JPanel general = new JPanel(new BorderLayout());
|
||||
general.setBorder(
|
||||
BorderFactory.createTitledBorder(
|
||||
BorderFactory.createEtchedBorder(),
|
||||
localizationResources.getString("General")
|
||||
)
|
||||
);
|
||||
|
||||
JPanel interior = new JPanel(new LCBLayout(5));
|
||||
interior.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5));
|
||||
interior.add(new JLabel(localizationResources.getString("Label")));
|
||||
this.label = new JTextField(axis.getLabel());
|
||||
interior.add(this.label);
|
||||
interior.add(new JPanel());
|
||||
|
||||
interior.add(new JLabel(localizationResources.getString("Font")));
|
||||
this.labelFontField = new FontDisplayField(this.labelFont);
|
||||
interior.add(this.labelFontField);
|
||||
JButton b = new JButton(localizationResources.getString("Select..."));
|
||||
b.setActionCommand("SelectLabelFont");
|
||||
b.addActionListener(this);
|
||||
interior.add(b);
|
||||
|
||||
interior.add(new JLabel(localizationResources.getString("Paint")));
|
||||
interior.add(this.labelPaintSample);
|
||||
b = new JButton(localizationResources.getString("Select..."));
|
||||
b.setActionCommand("SelectLabelPaint");
|
||||
b.addActionListener(this);
|
||||
interior.add(b);
|
||||
|
||||
// interior.add(
|
||||
// new JLabel(localizationResources.getString("Label_Insets"))
|
||||
// );
|
||||
// b = new JButton(localizationResources.getString("Edit..."));
|
||||
// b.setActionCommand("LabelInsets");
|
||||
// b.addActionListener(this);
|
||||
// this.labelInsetsTextField = new InsetsTextField(this.labelInsets);
|
||||
// interior.add(this.labelInsetsTextField);
|
||||
// interior.add(b);
|
||||
//
|
||||
// interior.add(
|
||||
// new JLabel(localizationResources.getString("Tick_Label_Insets"))
|
||||
// );
|
||||
// b = new JButton(localizationResources.getString("Edit..."));
|
||||
// b.setActionCommand("TickLabelInsets");
|
||||
// b.addActionListener(this);
|
||||
// this.tickLabelInsetsTextField
|
||||
// = new InsetsTextField(this.tickLabelInsets);
|
||||
// interior.add(this.tickLabelInsetsTextField);
|
||||
// interior.add(b);
|
||||
|
||||
general.add(interior);
|
||||
|
||||
add(general, BorderLayout.NORTH);
|
||||
|
||||
this.slot1 = new JPanel(new BorderLayout());
|
||||
|
||||
JPanel other = new JPanel(new BorderLayout());
|
||||
other.setBorder(BorderFactory.createTitledBorder(
|
||||
BorderFactory.createEtchedBorder(),
|
||||
localizationResources.getString("Other")));
|
||||
|
||||
this.otherTabs = new JTabbedPane();
|
||||
this.otherTabs.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5));
|
||||
|
||||
JPanel ticks = new JPanel(new LCBLayout(3));
|
||||
ticks.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
|
||||
|
||||
this.showTickLabelsCheckBox = new JCheckBox(
|
||||
localizationResources.getString("Show_tick_labels"),
|
||||
axis.isTickLabelsVisible()
|
||||
);
|
||||
ticks.add(this.showTickLabelsCheckBox);
|
||||
ticks.add(new JPanel());
|
||||
ticks.add(new JPanel());
|
||||
|
||||
ticks.add(
|
||||
new JLabel(localizationResources.getString("Tick_label_font"))
|
||||
);
|
||||
this.tickLabelFontField = new FontDisplayField(this.tickLabelFont);
|
||||
ticks.add(this.tickLabelFontField);
|
||||
b = new JButton(localizationResources.getString("Select..."));
|
||||
b.setActionCommand("SelectTickLabelFont");
|
||||
b.addActionListener(this);
|
||||
ticks.add(b);
|
||||
|
||||
this.showTickMarksCheckBox = new JCheckBox(
|
||||
localizationResources.getString("Show_tick_marks"),
|
||||
axis.isTickMarksVisible()
|
||||
);
|
||||
ticks.add(this.showTickMarksCheckBox);
|
||||
ticks.add(new JPanel());
|
||||
ticks.add(new JPanel());
|
||||
|
||||
this.otherTabs.add(localizationResources.getString("Ticks"), ticks);
|
||||
|
||||
other.add(this.otherTabs);
|
||||
|
||||
this.slot1.add(other);
|
||||
|
||||
this.slot2 = new JPanel(new BorderLayout());
|
||||
this.slot2.add(this.slot1, BorderLayout.NORTH);
|
||||
add(this.slot2);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current axis label.
|
||||
*
|
||||
* @return The current axis label.
|
||||
*/
|
||||
public String getLabel() {
|
||||
return this.label.getText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current label font.
|
||||
*
|
||||
* @return The current label font.
|
||||
*/
|
||||
public Font getLabelFont() {
|
||||
return this.labelFont;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current label paint.
|
||||
*
|
||||
* @return The current label paint.
|
||||
*/
|
||||
public Paint getLabelPaint() {
|
||||
return this.labelPaintSample.getPaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a flag that indicates whether or not the tick labels are visible.
|
||||
*
|
||||
* @return <code>true</code> if ick mark labels are visible.
|
||||
*/
|
||||
public boolean isTickLabelsVisible() {
|
||||
return this.showTickLabelsCheckBox.isSelected();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the font used to draw the tick labels (if they are showing).
|
||||
*
|
||||
* @return The font used to draw the tick labels.
|
||||
*/
|
||||
public Font getTickLabelFont() {
|
||||
return this.tickLabelFont;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current tick label paint.
|
||||
*
|
||||
* @return The current tick label paint.
|
||||
*/
|
||||
public Paint getTickLabelPaint() {
|
||||
return this.tickLabelPaintSample.getPaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current value of the flag that determines whether or not
|
||||
* tick marks are visible.
|
||||
*
|
||||
* @return <code>true</code> if tick marks are visible.
|
||||
*/
|
||||
public boolean isTickMarksVisible() {
|
||||
return this.showTickMarksCheckBox.isSelected();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current tick label insets value
|
||||
*
|
||||
* @return The current tick label insets value.
|
||||
*/
|
||||
public RectangleInsets getTickLabelInsets() {
|
||||
return (this.tickLabelInsets == null)
|
||||
? new RectangleInsets(0, 0, 0, 0)
|
||||
: this.tickLabelInsets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current label insets value
|
||||
*
|
||||
* @return The current label insets value.
|
||||
*/
|
||||
public RectangleInsets getLabelInsets() {
|
||||
return (this.labelInsets == null)
|
||||
? new RectangleInsets(0, 0, 0, 0) : this.labelInsets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the tabbed pane.
|
||||
*
|
||||
* @return A reference to the tabbed pane.
|
||||
*/
|
||||
public JTabbedPane getOtherTabs() {
|
||||
return this.otherTabs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles user interaction with the property panel.
|
||||
*
|
||||
* @param event information about the event that triggered the call to
|
||||
* this method.
|
||||
*/
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
String command = event.getActionCommand();
|
||||
if (command.equals("SelectLabelFont")) {
|
||||
attemptLabelFontSelection();
|
||||
}
|
||||
else if (command.equals("SelectLabelPaint")) {
|
||||
attemptModifyLabelPaint();
|
||||
}
|
||||
else if (command.equals("SelectTickLabelFont")) {
|
||||
attemptTickLabelFontSelection();
|
||||
}
|
||||
// else if (command.equals("LabelInsets")) {
|
||||
// editLabelInsets();
|
||||
// }
|
||||
// else if (command.equals("TickLabelInsets")) {
|
||||
// editTickLabelInsets();
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* Presents a font selection dialog to the user.
|
||||
*/
|
||||
private void attemptLabelFontSelection() {
|
||||
|
||||
FontChooserPanel panel = new FontChooserPanel(this.labelFont);
|
||||
int result = JOptionPane.showConfirmDialog(this, panel,
|
||||
localizationResources.getString("Font_Selection"),
|
||||
JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
|
||||
|
||||
if (result == JOptionPane.OK_OPTION) {
|
||||
this.labelFont = panel.getSelectedFont();
|
||||
this.labelFontField.setText(
|
||||
this.labelFont.getFontName() + " " + this.labelFont.getSize()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows the user the opportunity to change the outline paint.
|
||||
*/
|
||||
private void attemptModifyLabelPaint() {
|
||||
Color initialColor = (labelPaintSample.getPaint() instanceof Color ? (Color)labelPaintSample.getPaint() : Color.blue);
|
||||
Color c = JColorChooser.showDialog(this, localizationResources.getString("Label_Color"), initialColor);
|
||||
if (c != null) {
|
||||
this.labelPaintSample.setPaint(c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Presents a tick label font selection dialog to the user.
|
||||
*/
|
||||
public void attemptTickLabelFontSelection() {
|
||||
|
||||
FontChooserPanel panel = new FontChooserPanel(this.tickLabelFont);
|
||||
int result = JOptionPane.showConfirmDialog(this, panel,
|
||||
localizationResources.getString("Font_Selection"),
|
||||
JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
|
||||
|
||||
if (result == JOptionPane.OK_OPTION) {
|
||||
this.tickLabelFont = panel.getSelectedFont();
|
||||
this.tickLabelFontField.setText(
|
||||
this.tickLabelFont.getFontName() + " "
|
||||
+ this.tickLabelFont.getSize()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Presents insets chooser panel allowing user to modify tick label's
|
||||
// * individual insets values. Updates the current insets text field if
|
||||
// * edit is accepted.
|
||||
// */
|
||||
// private void editTickLabelInsets() {
|
||||
// InsetsChooserPanel panel = new InsetsChooserPanel(
|
||||
// this.tickLabelInsets);
|
||||
// int result = JOptionPane.showConfirmDialog(
|
||||
// this, panel, localizationResources.getString("Edit_Insets"),
|
||||
// JOptionPane.PLAIN_MESSAGE
|
||||
// );
|
||||
//
|
||||
// if (result == JOptionPane.OK_OPTION) {
|
||||
// this.tickLabelInsets = panel.getInsets();
|
||||
// this.tickLabelInsetsTextField.setInsets(this.tickLabelInsets);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Presents insets chooser panel allowing user to modify label's
|
||||
// * individual insets values. Updates the current insets text field if edit
|
||||
// * is accepted.
|
||||
// */
|
||||
// private void editLabelInsets() {
|
||||
// InsetsChooserPanel panel = new InsetsChooserPanel(this.labelInsets);
|
||||
// int result = JOptionPane.showConfirmDialog(
|
||||
// this, panel, localizationResources.getString("Edit_Insets"),
|
||||
// JOptionPane.PLAIN_MESSAGE
|
||||
// );
|
||||
//
|
||||
// if (result == JOptionPane.OK_OPTION) {
|
||||
// this.labelInsets = panel.getInsets();
|
||||
// this.labelInsetsTextField.setInsets(this.labelInsets);
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* Sets the properties of the specified axis to match the properties
|
||||
* defined on this panel.
|
||||
*
|
||||
* @param axis the axis.
|
||||
*/
|
||||
public void setAxisProperties(Axis axis) {
|
||||
axis.setLabel(getLabel());
|
||||
axis.setLabelFont(getLabelFont());
|
||||
axis.setLabelPaint(getLabelPaint());
|
||||
axis.setTickMarksVisible(isTickMarksVisible());
|
||||
// axis.setTickMarkStroke(getTickMarkStroke());
|
||||
axis.setTickLabelsVisible(isTickLabelsVisible());
|
||||
axis.setTickLabelFont(getTickLabelFont());
|
||||
axis.setTickLabelPaint(getTickLabelPaint());
|
||||
axis.setTickLabelInsets(getTickLabelInsets());
|
||||
axis.setLabelInsets(getLabelInsets());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,301 @@
|
||||
/*
|
||||
* $Id: TrickChartEditor.java 3349 2013-12-17 15:05:20Z hchen3 $
|
||||
*/
|
||||
|
||||
package trick.dataproducts.plot.utils.editor;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.Paint;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JColorChooser;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTabbedPane;
|
||||
import javax.swing.JTextField;
|
||||
|
||||
import org.jfree.chart.JFreeChart;
|
||||
import org.jfree.chart.editor.ChartEditor;
|
||||
import org.jfree.chart.plot.Plot;
|
||||
import org.jfree.chart.plot.PolarPlot;
|
||||
import org.jfree.chart.title.Title;
|
||||
import org.jfree.chart.util.ResourceBundleWrapper;
|
||||
import org.jfree.layout.LCBLayout;
|
||||
import org.jfree.ui.PaintSample;
|
||||
import org.jfree.ui.StrokeChooserPanel;
|
||||
import org.jfree.ui.StrokeSample;
|
||||
|
||||
import trick.dataproducts.trickqp.utils.ProductVar;
|
||||
|
||||
/**
|
||||
* A panel for editing chart properties (includes subpanels for the title,
|
||||
* legend and plot).
|
||||
*/
|
||||
public class TrickChartEditor extends JPanel implements ActionListener, ChartEditor {
|
||||
|
||||
|
||||
private static final long serialVersionUID = -513746078897898843L;
|
||||
|
||||
/** A panel for displaying/editing the properties of the title. */
|
||||
private TrickTitleEditor titleEditor;
|
||||
|
||||
/** A panel for displaying/editing the properties of the plot. */
|
||||
private TrickPlotEditor plotEditor;
|
||||
|
||||
/**
|
||||
* A checkbox indicating whether or not the chart is drawn with
|
||||
* anti-aliasing.
|
||||
*/
|
||||
private JCheckBox antialias;
|
||||
|
||||
/** The chart background color. */
|
||||
private PaintSample background;
|
||||
|
||||
/** The chart plot series color. */
|
||||
private ArrayList<PaintSample> seriesPaintList;
|
||||
|
||||
/** The chart plot series color. */
|
||||
private ArrayList<StrokeSample> seriesStrokeList;
|
||||
|
||||
/** The resourceBundle for the localization. */
|
||||
protected static ResourceBundle localizationResources
|
||||
= ResourceBundleWrapper.getBundle(
|
||||
"org.jfree.chart.editor.LocalizationBundle");
|
||||
private static StrokeSample[] AVAILABLE_STROKE_SAMPLES = new StrokeSample[ProductVar.LineStyle.values().length];
|
||||
static {
|
||||
for (int i = 0; i < ProductVar.LineStyle.values().length; i++) {
|
||||
AVAILABLE_STROKE_SAMPLES[i] = new StrokeSample(ProductVar.LineStyle.values()[i].getStroke());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard constructor - the property panel is made up of a number of
|
||||
* sub-panels that are displayed in the tabbed pane.
|
||||
*
|
||||
* @param chart the chart, which properties should be changed.
|
||||
*/
|
||||
public TrickChartEditor(JFreeChart chart) {
|
||||
setLayout(new BorderLayout());
|
||||
|
||||
JPanel other = new JPanel(new BorderLayout());
|
||||
other.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
|
||||
|
||||
JPanel general = new JPanel(new BorderLayout());
|
||||
general.setBorder(BorderFactory.createTitledBorder(
|
||||
BorderFactory.createEtchedBorder(),
|
||||
localizationResources.getString("General")));
|
||||
|
||||
JPanel interior = new JPanel(new LCBLayout(4));
|
||||
interior.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5));
|
||||
|
||||
this.antialias = new JCheckBox(localizationResources.getString(
|
||||
"Draw_anti-aliased"));
|
||||
this.antialias.setSelected(chart.getAntiAlias());
|
||||
interior.add(this.antialias);
|
||||
interior.add(new JLabel(""));
|
||||
interior.add(new JLabel(""));
|
||||
interior.add(new JLabel(localizationResources.getString(
|
||||
"Background_paint")));
|
||||
this.background = new PaintSample(chart.getBackgroundPaint());
|
||||
interior.add(this.background);
|
||||
JButton button = new JButton(localizationResources.getString(
|
||||
"Select..."));
|
||||
button.setActionCommand("BackgroundPaint");
|
||||
button.addActionListener(this);
|
||||
interior.add(button);
|
||||
|
||||
interior.add(new JLabel(localizationResources.getString(
|
||||
"Series_Paint")));
|
||||
new JTextField(localizationResources.getString(
|
||||
"No_editor_implemented"));
|
||||
|
||||
int seriesCount = chart.getXYPlot().getSeriesCount();
|
||||
|
||||
JPanel seriesPaintPanel = new JPanel(new GridLayout(0, 3, 1, 1));
|
||||
seriesPaintList = new ArrayList<PaintSample>(seriesCount);
|
||||
|
||||
for (int i = 0; i < seriesCount; i++) {
|
||||
PaintSample aPaintSample = new PaintSample(chart.getXYPlot().getRenderer().getSeriesPaint(i));
|
||||
seriesPaintList.add(i, aPaintSample);
|
||||
seriesPaintPanel.add(seriesPaintList.get(i));
|
||||
aPaintSample.addMouseListener(new LocalMouseListener());
|
||||
}
|
||||
|
||||
interior.add(seriesPaintPanel);
|
||||
interior.add(new JLabel(""));
|
||||
|
||||
interior.add(new JLabel(localizationResources.getString(
|
||||
"Series_Stroke")));
|
||||
|
||||
JPanel seriesStrokePanel = new JPanel(new GridLayout(0, 3, 1, 1));
|
||||
seriesStrokeList = new ArrayList<StrokeSample>(seriesCount);
|
||||
|
||||
for (int i = 0; i < seriesCount; i++) {
|
||||
StrokeSample aStrokeSample = new StrokeSample(chart.getXYPlot().getRenderer().getSeriesStroke(i));
|
||||
seriesStrokeList.add(i, aStrokeSample);
|
||||
seriesStrokePanel.add(seriesStrokeList.get(i));
|
||||
aStrokeSample.addMouseListener(new LocalMouseListener());
|
||||
}
|
||||
|
||||
interior.add(seriesStrokePanel);
|
||||
interior.add(new JLabel(""));
|
||||
|
||||
general.add(interior, BorderLayout.NORTH);
|
||||
other.add(general, BorderLayout.NORTH);
|
||||
|
||||
JPanel parts = new JPanel(new BorderLayout());
|
||||
|
||||
Title title = chart.getTitle();
|
||||
Plot plot = chart.getPlot();
|
||||
|
||||
JTabbedPane tabs = new JTabbedPane();
|
||||
|
||||
this.titleEditor = new TrickTitleEditor(title);
|
||||
this.titleEditor.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
|
||||
tabs.addTab(localizationResources.getString("Title"), this.titleEditor);
|
||||
|
||||
if (plot instanceof PolarPlot) {
|
||||
this.plotEditor = new TrickPolarPlotEditor((PolarPlot) plot);
|
||||
}
|
||||
else {
|
||||
this.plotEditor = new TrickPlotEditor(plot);
|
||||
}
|
||||
this.plotEditor.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
|
||||
tabs.addTab(localizationResources.getString("Plot"), this.plotEditor);
|
||||
|
||||
tabs.add(localizationResources.getString("Other"), other);
|
||||
parts.add(tabs, BorderLayout.NORTH);
|
||||
add(parts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the title editor.
|
||||
*
|
||||
* @return A panel for editing the title.
|
||||
*/
|
||||
public TrickTitleEditor getTitleEditor() {
|
||||
return this.titleEditor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the plot property sub-panel.
|
||||
*
|
||||
* @return A panel for editing the plot properties.
|
||||
*/
|
||||
public TrickPlotEditor getPlotEditor() {
|
||||
return this.plotEditor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current setting of the anti-alias flag.
|
||||
*
|
||||
* @return <code>true</code> if anti-aliasing is enabled.
|
||||
*/
|
||||
public boolean getAntiAlias() {
|
||||
return this.antialias.isSelected();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current background paint.
|
||||
*
|
||||
* @return The current background paint.
|
||||
*/
|
||||
public Paint getBackgroundPaint() {
|
||||
return this.background.getPaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles user interactions with the panel.
|
||||
*
|
||||
* @param event a BackgroundPaint action.
|
||||
*/
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
String command = event.getActionCommand();
|
||||
if (command.equals("BackgroundPaint")) {
|
||||
attemptModifyBackgroundPaint();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows the user the opportunity to select a new background paint. Uses
|
||||
* JColorChooser, so we are only allowing a subset of all Paint objects to
|
||||
* be selected (fix later).
|
||||
*/
|
||||
private void attemptModifyBackgroundPaint() {
|
||||
Color initialColor = (background.getPaint() instanceof Color ? (Color)background.getPaint() : Color.blue);
|
||||
Color c = JColorChooser.showDialog(this, localizationResources.getString("Background_Color"), initialColor);
|
||||
if (c != null) {
|
||||
this.background.setPaint(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Updates the properties of a chart to match the properties defined on the
|
||||
* panel.
|
||||
*
|
||||
* @param chart the chart.
|
||||
*/
|
||||
public void updateChart(JFreeChart chart) {
|
||||
|
||||
this.titleEditor.setTitleProperties(chart);
|
||||
this.plotEditor.updatePlotProperties(chart.getPlot());
|
||||
|
||||
chart.setAntiAlias(getAntiAlias());
|
||||
chart.setBackgroundPaint(getBackgroundPaint());
|
||||
for (int i = 0; i < chart.getXYPlot().getSeriesCount(); i++) {
|
||||
chart.getXYPlot().getRenderer().setSeriesPaint(i, seriesPaintList.get(i).getPaint());
|
||||
chart.getXYPlot().getRenderer().setSeriesStroke(i, seriesStrokeList.get(i).getStroke());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow the user to change the outline stroke.
|
||||
*/
|
||||
private void attemptStrokeSelection(StrokeSample sample) {
|
||||
StrokeChooserPanel panel = new StrokeChooserPanel(
|
||||
sample, AVAILABLE_STROKE_SAMPLES);
|
||||
int result = JOptionPane.showConfirmDialog(this, panel,
|
||||
localizationResources.getString("Stroke_Selection"),
|
||||
JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
|
||||
|
||||
if (result == JOptionPane.OK_OPTION) {
|
||||
sample.setStroke(panel.getSelectedStroke());
|
||||
}
|
||||
}
|
||||
|
||||
public class LocalMouseListener extends MouseAdapter {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (!seriesPaintList.isEmpty()) {
|
||||
for (PaintSample theSample : seriesPaintList) {
|
||||
if (e.getSource().equals(theSample)) {
|
||||
Color initialColor = (theSample.getPaint() instanceof Color ? (Color)theSample.getPaint() : Color.blue);
|
||||
Color c = JColorChooser.showDialog(theSample, "Change Paint Color", initialColor);
|
||||
if (c != null) {
|
||||
theSample.setPaint(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!seriesStrokeList.isEmpty()) {
|
||||
for (StrokeSample theSample : seriesStrokeList) {
|
||||
if (e.getSource().equals(theSample)) {
|
||||
attemptStrokeSelection(theSample);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* $Id
|
||||
*/
|
||||
|
||||
package trick.dataproducts.plot.utils.editor;
|
||||
|
||||
import org.jfree.chart.JFreeChart;
|
||||
import org.jfree.chart.editor.ChartEditor;
|
||||
import org.jfree.chart.editor.ChartEditorFactory;
|
||||
|
||||
/**
|
||||
* A default implementation of the {@link ChartEditorFactory} interface.
|
||||
*/
|
||||
public class TrickChartEditorFactory implements ChartEditorFactory {
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*/
|
||||
public TrickChartEditorFactory() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new instance of a {@link ChartEditor}.
|
||||
*
|
||||
* @param chart the chart.
|
||||
*
|
||||
* @return A chart editor for the given chart.
|
||||
*/
|
||||
public TrickChartEditor createEditor(JFreeChart chart) {
|
||||
return new TrickChartEditor(chart);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* $Id
|
||||
*/
|
||||
|
||||
package trick.dataproducts.plot.utils.editor;
|
||||
|
||||
import org.jfree.chart.JFreeChart;
|
||||
import org.jfree.chart.editor.ChartEditor;
|
||||
import org.jfree.chart.util.ParamChecks;
|
||||
|
||||
/**
|
||||
* The central point for obtaining {@link ChartEditor} instances for editing
|
||||
* charts. Right now, the API is minimal - the plan is to extend this class
|
||||
* to provide customization options for chart editors (for example, make some
|
||||
* editor items read-only).
|
||||
*/
|
||||
public class TrickChartEditorManager {
|
||||
|
||||
/** This factory creates new {@link ChartEditor} instances as required. */
|
||||
static TrickChartEditorFactory factory = new TrickChartEditorFactory();
|
||||
|
||||
/**
|
||||
* Private constructor prevents instantiation.
|
||||
*/
|
||||
private TrickChartEditorManager() {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current factory.
|
||||
*
|
||||
* @return The current factory (never <code>null</code>).
|
||||
*/
|
||||
public static TrickChartEditorFactory getChartEditorFactory() {
|
||||
return factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the chart editor factory.
|
||||
*
|
||||
* @param f the new factory (<code>null</code> not permitted).
|
||||
*/
|
||||
public static void setChartEditorFactory(TrickChartEditorFactory f) {
|
||||
ParamChecks.nullNotPermitted(f, "f");
|
||||
factory = f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a component that can be used to edit the given chart.
|
||||
*
|
||||
* @param chart the chart.
|
||||
*
|
||||
* @return The chart editor.
|
||||
*/
|
||||
public static TrickChartEditor getChartEditor(JFreeChart chart) {
|
||||
return factory.createEditor(chart);
|
||||
}
|
||||
}
|
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* $Id
|
||||
*/
|
||||
|
||||
package trick.dataproducts.plot.utils.editor;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextField;
|
||||
|
||||
import org.jfree.chart.axis.Axis;
|
||||
import org.jfree.chart.axis.NumberAxis;
|
||||
import org.jfree.chart.axis.NumberTickUnit;
|
||||
import org.jfree.layout.LCBLayout;
|
||||
|
||||
/**
|
||||
* A panel for editing the properties of a value axis.
|
||||
*/
|
||||
public class TrickNumberAxisEditor extends TrickValueAxisEditor
|
||||
implements FocusListener {
|
||||
|
||||
|
||||
private static final long serialVersionUID = 651540823473853902L;
|
||||
|
||||
private double manualTickUnitValue;
|
||||
|
||||
private JTextField manualTickUnit;
|
||||
|
||||
|
||||
/**
|
||||
* Standard constructor: builds a property panel for the specified axis.
|
||||
*
|
||||
* @param axis the axis, which should be changed.
|
||||
*/
|
||||
public TrickNumberAxisEditor(NumberAxis axis) {
|
||||
|
||||
super(axis);
|
||||
|
||||
this.manualTickUnitValue = axis.getTickUnit().getSize();
|
||||
validateTickUnit();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JPanel createTickUnitPanel()
|
||||
{
|
||||
JPanel tickUnitPanel = new JPanel(new LCBLayout(3));
|
||||
tickUnitPanel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
|
||||
|
||||
tickUnitPanel.add(new JPanel());
|
||||
JCheckBox autoTickUnitSelectionCheckBox = new JCheckBox(
|
||||
localizationResources.getString("Auto-TickUnit_Selection"),
|
||||
isAutoTickUnitSelection());
|
||||
autoTickUnitSelectionCheckBox.setActionCommand("AutoTickOnOff");
|
||||
autoTickUnitSelectionCheckBox.addActionListener(this);
|
||||
setAutoTickUnitSelectionCheckBox(autoTickUnitSelectionCheckBox);
|
||||
tickUnitPanel.add(getAutoTickUnitSelectionCheckBox());
|
||||
tickUnitPanel.add(new JPanel());
|
||||
|
||||
tickUnitPanel.add(new JLabel(localizationResources.getString(
|
||||
"Manual_TickUnit_value")));
|
||||
this.manualTickUnit = new JTextField(Double.toString(
|
||||
this.manualTickUnitValue));
|
||||
this.manualTickUnit.setEnabled(!isAutoTickUnitSelection());
|
||||
this.manualTickUnit.setActionCommand("TickUnitValue");
|
||||
this.manualTickUnit.addActionListener(this);
|
||||
this.manualTickUnit.addFocusListener(this);
|
||||
tickUnitPanel.add(this.manualTickUnit);
|
||||
tickUnitPanel.add(new JPanel());
|
||||
|
||||
return tickUnitPanel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles actions from within the property panel.
|
||||
* @param event an event.
|
||||
*/
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
String command = event.getActionCommand();
|
||||
if (command.equals("TickUnitValue")) {
|
||||
validateTickUnit();
|
||||
}
|
||||
else {
|
||||
// pass to the super-class for handling
|
||||
super.actionPerformed(event);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusLost(FocusEvent event) {
|
||||
super.focusLost(event);
|
||||
if (event.getSource() == this.manualTickUnit) {
|
||||
validateTickUnit();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toggleAutoTick() {
|
||||
super.toggleAutoTick();
|
||||
if (isAutoTickUnitSelection()) {
|
||||
this.manualTickUnit.setText(Double.toString(this.manualTickUnitValue));
|
||||
this.manualTickUnit.setEnabled(false);
|
||||
}
|
||||
else {
|
||||
this.manualTickUnit.setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void validateTickUnit() {
|
||||
double newTickUnit;
|
||||
try {
|
||||
newTickUnit = Double.parseDouble(this.manualTickUnit.getText());
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
newTickUnit = this.manualTickUnitValue;
|
||||
}
|
||||
|
||||
if (newTickUnit > 0.0) {
|
||||
this.manualTickUnitValue = newTickUnit;
|
||||
}
|
||||
this.manualTickUnit.setText(Double.toString(this.manualTickUnitValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the properties of the specified axis to match the properties
|
||||
* defined on this panel.
|
||||
*
|
||||
* @param axis the axis.
|
||||
*/
|
||||
@Override
|
||||
public void setAxisProperties(Axis axis) {
|
||||
super.setAxisProperties(axis);
|
||||
NumberAxis numberAxis = (NumberAxis) axis;
|
||||
if (!isAutoTickUnitSelection()) {
|
||||
numberAxis.setTickUnit(new NumberTickUnit(manualTickUnitValue));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,629 @@
|
||||
/*
|
||||
* $Id
|
||||
*/
|
||||
|
||||
package trick.dataproducts.plot.utils.editor;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Paint;
|
||||
import java.awt.Stroke;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JColorChooser;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTabbedPane;
|
||||
|
||||
import org.jfree.chart.axis.Axis;
|
||||
import org.jfree.chart.plot.CategoryPlot;
|
||||
import org.jfree.chart.plot.Plot;
|
||||
import org.jfree.chart.plot.PlotOrientation;
|
||||
import org.jfree.chart.plot.PolarPlot;
|
||||
import org.jfree.chart.plot.XYPlot;
|
||||
import org.jfree.chart.renderer.category.CategoryItemRenderer;
|
||||
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
|
||||
import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
|
||||
import org.jfree.chart.renderer.xy.XYItemRenderer;
|
||||
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
|
||||
import org.jfree.chart.util.ResourceBundleWrapper;
|
||||
import org.jfree.layout.LCBLayout;
|
||||
import org.jfree.ui.PaintSample;
|
||||
import org.jfree.ui.RectangleInsets;
|
||||
import org.jfree.ui.StrokeChooserPanel;
|
||||
import org.jfree.ui.StrokeSample;
|
||||
import org.jfree.util.BooleanUtilities;
|
||||
|
||||
/**
|
||||
* A panel for editing the properties of a {@link Plot}.
|
||||
*/
|
||||
public class TrickPlotEditor extends JPanel implements ActionListener {
|
||||
|
||||
private static final long serialVersionUID = -6751169039890765522L;
|
||||
/** Orientation constants. */
|
||||
private final static String[] orientationNames = {"Vertical", "Horizontal"};
|
||||
private final static int ORIENTATION_VERTICAL = 0;
|
||||
private final static int ORIENTATION_HORIZONTAL = 1;
|
||||
|
||||
/** The paint (color) used to fill the background of the plot. */
|
||||
private PaintSample backgroundPaintSample;
|
||||
|
||||
/** The stroke used to draw the outline of the plot. */
|
||||
private StrokeSample outlineStrokeSample;
|
||||
|
||||
/** The paint (color) used to draw the outline of the plot. */
|
||||
private PaintSample outlinePaintSample;
|
||||
|
||||
/**
|
||||
* A panel used to display/edit the properties of the domain axis (if any).
|
||||
*/
|
||||
private TrickAxisEditor domainAxisPropertyPanel;
|
||||
|
||||
/**
|
||||
* A panel used to display/edit the properties of the range axis (if any).
|
||||
*/
|
||||
private TrickAxisEditor rangeAxisPropertyPanel;
|
||||
|
||||
/** An array of stroke samples to choose from. */
|
||||
private StrokeSample[] availableStrokeSamples;
|
||||
|
||||
/** The insets for the plot. */
|
||||
private RectangleInsets plotInsets;
|
||||
|
||||
/**
|
||||
* The orientation for the plot (for <tt>CategoryPlot</tt>s and
|
||||
* <tt>XYPlot</tt>s).
|
||||
*/
|
||||
private PlotOrientation plotOrientation;
|
||||
|
||||
/**
|
||||
* The orientation combo box (for <tt>CategoryPlot</tt>s and
|
||||
* <tt>XYPlot</tt>s).
|
||||
*/
|
||||
private JComboBox orientationCombo;
|
||||
|
||||
/** Whether or not to draw lines between each data point (for
|
||||
* <tt>LineAndShapeRenderer</tt>s and <tt>StandardXYItemRenderer</tt>s).
|
||||
*/
|
||||
private Boolean drawLines;
|
||||
|
||||
/**
|
||||
* The checkbox for whether or not to draw lines between each data point.
|
||||
*/
|
||||
private JCheckBox drawLinesCheckBox;
|
||||
|
||||
/** Whether or not to draw shapes at each data point (for
|
||||
* <tt>LineAndShapeRenderer</tt>s and <tt>StandardXYItemRenderer</tt>s).
|
||||
*/
|
||||
private Boolean drawShapes;
|
||||
|
||||
/**
|
||||
* The checkbox for whether or not to draw shapes at each data point.
|
||||
*/
|
||||
private JCheckBox drawShapesCheckBox;
|
||||
|
||||
/** The resourceBundle for the localization. */
|
||||
protected static ResourceBundle localizationResources
|
||||
= ResourceBundleWrapper.getBundle(
|
||||
"org.jfree.chart.editor.LocalizationBundle");
|
||||
|
||||
/**
|
||||
* Standard constructor - constructs a panel for editing the properties of
|
||||
* the specified plot.
|
||||
* <P>
|
||||
* In designing the panel, we need to be aware that subclasses of Plot will
|
||||
* need to implement subclasses of PlotPropertyEditPanel - so we need to
|
||||
* leave one or two 'slots' where the subclasses can extend the user
|
||||
* interface.
|
||||
*
|
||||
* @param plot the plot, which should be changed.
|
||||
*/
|
||||
public TrickPlotEditor(Plot plot) {
|
||||
JPanel panel = createPlotPanel(plot);
|
||||
add(panel);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
protected JPanel createPlotPanel(Plot plot) {
|
||||
this.plotInsets = plot.getInsets();
|
||||
this.backgroundPaintSample = new PaintSample(plot.getBackgroundPaint());
|
||||
this.outlineStrokeSample = new StrokeSample(plot.getOutlineStroke());
|
||||
this.outlinePaintSample = new PaintSample(plot.getOutlinePaint());
|
||||
if (plot instanceof CategoryPlot) {
|
||||
this.plotOrientation = ((CategoryPlot) plot).getOrientation();
|
||||
}
|
||||
else if (plot instanceof XYPlot) {
|
||||
this.plotOrientation = ((XYPlot) plot).getOrientation();
|
||||
}
|
||||
if (plot instanceof CategoryPlot) {
|
||||
CategoryItemRenderer renderer = ((CategoryPlot) plot).getRenderer();
|
||||
if (renderer instanceof LineAndShapeRenderer) {
|
||||
LineAndShapeRenderer r = (LineAndShapeRenderer) renderer;
|
||||
this.drawLines = BooleanUtilities.valueOf(
|
||||
r.getBaseLinesVisible());
|
||||
this.drawShapes = BooleanUtilities.valueOf(
|
||||
r.getBaseShapesVisible());
|
||||
}
|
||||
}
|
||||
else if (plot instanceof XYPlot) {
|
||||
XYItemRenderer renderer = ((XYPlot) plot).getRenderer();
|
||||
if (renderer instanceof StandardXYItemRenderer) {
|
||||
StandardXYItemRenderer r = (StandardXYItemRenderer) renderer;
|
||||
this.drawLines = BooleanUtilities.valueOf(r.getPlotLines());
|
||||
this.drawShapes = BooleanUtilities.valueOf(r.getBaseShapesVisible());
|
||||
} else if (renderer instanceof XYLineAndShapeRenderer) {
|
||||
XYLineAndShapeRenderer r = (XYLineAndShapeRenderer) renderer;
|
||||
this.drawLines = BooleanUtilities.valueOf(r.getBaseLinesVisible());
|
||||
this.drawShapes = BooleanUtilities.valueOf(r.getBaseShapesVisible());
|
||||
}
|
||||
}
|
||||
|
||||
setLayout(new BorderLayout());
|
||||
|
||||
this.availableStrokeSamples = new StrokeSample[4];
|
||||
this.availableStrokeSamples[0] = new StrokeSample(null);
|
||||
this.availableStrokeSamples[1] = new StrokeSample(
|
||||
new BasicStroke(1.0f));
|
||||
this.availableStrokeSamples[2] = new StrokeSample(
|
||||
new BasicStroke(2.0f));
|
||||
this.availableStrokeSamples[3] = new StrokeSample(
|
||||
new BasicStroke(3.0f));
|
||||
|
||||
// create a panel for the settings...
|
||||
JPanel panel = new JPanel(new BorderLayout());
|
||||
panel.setBorder(BorderFactory.createTitledBorder(
|
||||
BorderFactory.createEtchedBorder(), plot.getPlotType()
|
||||
+ localizationResources.getString(":")));
|
||||
|
||||
JPanel general = new JPanel(new BorderLayout());
|
||||
general.setBorder(BorderFactory.createTitledBorder(
|
||||
localizationResources.getString("General")));
|
||||
|
||||
JPanel interior = new JPanel(new LCBLayout(7));
|
||||
interior.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5));
|
||||
|
||||
// interior.add(new JLabel(localizationResources.getString("Insets")));
|
||||
// JButton button = new JButton(
|
||||
// localizationResources.getString("Edit...")
|
||||
// );
|
||||
// button.setActionCommand("Insets");
|
||||
// button.addActionListener(this);
|
||||
//
|
||||
// this.insetsTextField = new InsetsTextField(this.plotInsets);
|
||||
// this.insetsTextField.setEnabled(false);
|
||||
// interior.add(this.insetsTextField);
|
||||
// interior.add(button);
|
||||
|
||||
interior.add(new JLabel(localizationResources.getString(
|
||||
"Outline_stroke")));
|
||||
JButton button = new JButton(localizationResources.getString(
|
||||
"Select..."));
|
||||
button.setActionCommand("OutlineStroke");
|
||||
button.addActionListener(this);
|
||||
interior.add(this.outlineStrokeSample);
|
||||
interior.add(button);
|
||||
|
||||
interior.add(new JLabel(localizationResources.getString(
|
||||
"Outline_Paint")));
|
||||
button = new JButton(localizationResources.getString("Select..."));
|
||||
button.setActionCommand("OutlinePaint");
|
||||
button.addActionListener(this);
|
||||
interior.add(this.outlinePaintSample);
|
||||
interior.add(button);
|
||||
|
||||
interior.add(new JLabel(localizationResources.getString(
|
||||
"Background_paint")));
|
||||
button = new JButton(localizationResources.getString("Select..."));
|
||||
button.setActionCommand("BackgroundPaint");
|
||||
button.addActionListener(this);
|
||||
interior.add(this.backgroundPaintSample);
|
||||
interior.add(button);
|
||||
|
||||
if (this.plotOrientation != null) {
|
||||
boolean isVertical = this.plotOrientation.equals(
|
||||
PlotOrientation.VERTICAL);
|
||||
int index = isVertical ? ORIENTATION_VERTICAL
|
||||
: ORIENTATION_HORIZONTAL;
|
||||
interior.add(new JLabel(localizationResources.getString(
|
||||
"Orientation")));
|
||||
this.orientationCombo = new JComboBox(orientationNames);
|
||||
this.orientationCombo.setSelectedIndex(index);
|
||||
this.orientationCombo.setActionCommand("Orientation");
|
||||
this.orientationCombo.addActionListener(this);
|
||||
interior.add(new JPanel());
|
||||
interior.add(this.orientationCombo);
|
||||
}
|
||||
|
||||
if (this.drawLines != null) {
|
||||
interior.add(new JLabel(localizationResources.getString(
|
||||
"Draw_lines")));
|
||||
this.drawLinesCheckBox = new JCheckBox();
|
||||
this.drawLinesCheckBox.setSelected(this.drawLines.booleanValue());
|
||||
this.drawLinesCheckBox.setActionCommand("DrawLines");
|
||||
this.drawLinesCheckBox.addActionListener(this);
|
||||
interior.add(new JPanel());
|
||||
interior.add(this.drawLinesCheckBox);
|
||||
}
|
||||
|
||||
if (this.drawShapes != null) {
|
||||
interior.add(new JLabel(localizationResources.getString(
|
||||
"Draw_shapes")));
|
||||
this.drawShapesCheckBox = new JCheckBox();
|
||||
this.drawShapesCheckBox.setSelected(this.drawShapes.booleanValue());
|
||||
this.drawShapesCheckBox.setActionCommand("DrawShapes");
|
||||
this.drawShapesCheckBox.addActionListener(this);
|
||||
interior.add(new JPanel());
|
||||
interior.add(this.drawShapesCheckBox);
|
||||
}
|
||||
|
||||
general.add(interior, BorderLayout.NORTH);
|
||||
|
||||
JPanel appearance = new JPanel(new BorderLayout());
|
||||
appearance.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
|
||||
appearance.add(general, BorderLayout.NORTH);
|
||||
|
||||
JTabbedPane tabs = createPlotTabs(plot);
|
||||
tabs.add(localizationResources.getString("Appearance"), appearance);
|
||||
panel.add(tabs);
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
protected JTabbedPane createPlotTabs(Plot plot)
|
||||
{
|
||||
JTabbedPane tabs = new JTabbedPane();
|
||||
tabs.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5));
|
||||
|
||||
Axis domainAxis = null;
|
||||
if (plot instanceof CategoryPlot) {
|
||||
domainAxis = ((CategoryPlot) plot).getDomainAxis();
|
||||
}
|
||||
else if (plot instanceof XYPlot) {
|
||||
domainAxis = ((XYPlot) plot).getDomainAxis();
|
||||
}
|
||||
this.domainAxisPropertyPanel = TrickAxisEditor.getInstance(
|
||||
domainAxis);
|
||||
if (this.domainAxisPropertyPanel != null) {
|
||||
this.domainAxisPropertyPanel.setBorder(
|
||||
BorderFactory.createEmptyBorder(2, 2, 2, 2));
|
||||
tabs.add(localizationResources.getString("Domain_Axis"),
|
||||
this.domainAxisPropertyPanel);
|
||||
}
|
||||
|
||||
Axis rangeAxis = null;
|
||||
if (plot instanceof CategoryPlot) {
|
||||
rangeAxis = ((CategoryPlot) plot).getRangeAxis();
|
||||
}
|
||||
else if (plot instanceof XYPlot) {
|
||||
rangeAxis = ((XYPlot) plot).getRangeAxis();
|
||||
}
|
||||
else if (plot instanceof PolarPlot) {
|
||||
rangeAxis = ((PolarPlot) plot).getAxis();
|
||||
}
|
||||
|
||||
this.rangeAxisPropertyPanel = TrickAxisEditor.getInstance(rangeAxis);
|
||||
if (this.rangeAxisPropertyPanel != null) {
|
||||
this.rangeAxisPropertyPanel.setBorder(
|
||||
BorderFactory.createEmptyBorder(2, 2, 2, 2));
|
||||
tabs.add(localizationResources.getString("Range_Axis"),
|
||||
this.rangeAxisPropertyPanel);
|
||||
}
|
||||
|
||||
//dmo: added this panel for colorbar control. (start dmo additions)
|
||||
/*ColorBar colorBar = null;
|
||||
if (plot instanceof ContourPlot) {
|
||||
colorBar = ((ContourPlot) plot).getColorBar();
|
||||
}
|
||||
|
||||
this.colorBarAxisPropertyPanel = TrickColorBarEditor.getInstance(
|
||||
colorBar);
|
||||
if (this.colorBarAxisPropertyPanel != null) {
|
||||
this.colorBarAxisPropertyPanel.setBorder(
|
||||
BorderFactory.createEmptyBorder(2, 2, 2, 2));
|
||||
tabs.add(localizationResources.getString("Color_Bar"),
|
||||
this.colorBarAxisPropertyPanel);
|
||||
}
|
||||
//dmo: (end dmo additions)
|
||||
*/
|
||||
return tabs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current plot insets.
|
||||
*
|
||||
* @return The current plot insets.
|
||||
*/
|
||||
public RectangleInsets getPlotInsets() {
|
||||
if (this.plotInsets == null) {
|
||||
this.plotInsets = new RectangleInsets(0.0, 0.0, 0.0, 0.0);
|
||||
}
|
||||
return this.plotInsets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current background paint.
|
||||
*
|
||||
* @return The current background paint.
|
||||
*/
|
||||
public Paint getBackgroundPaint() {
|
||||
return this.backgroundPaintSample.getPaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current outline stroke.
|
||||
*
|
||||
* @return The current outline stroke (possibly <code>null</code>).
|
||||
*/
|
||||
public Stroke getOutlineStroke() {
|
||||
return this.outlineStrokeSample.getStroke();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current outline paint.
|
||||
*
|
||||
* @return The current outline paint.
|
||||
*/
|
||||
public Paint getOutlinePaint() {
|
||||
return this.outlinePaintSample.getPaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the panel for editing the properties of the
|
||||
* domain axis.
|
||||
*
|
||||
* @return A reference to a panel.
|
||||
*/
|
||||
public TrickAxisEditor getDomainAxisPropertyEditPanel() {
|
||||
return this.domainAxisPropertyPanel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the panel for editing the properties of the
|
||||
* range axis.
|
||||
*
|
||||
* @return A reference to a panel.
|
||||
*/
|
||||
public TrickAxisEditor getRangeAxisPropertyEditPanel() {
|
||||
return this.rangeAxisPropertyPanel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles user actions generated within the panel.
|
||||
* @param event the event
|
||||
*/
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
String command = event.getActionCommand();
|
||||
if (command.equals("BackgroundPaint")) {
|
||||
attemptBackgroundPaintSelection();
|
||||
}
|
||||
else if (command.equals("OutlineStroke")) {
|
||||
attemptOutlineStrokeSelection();
|
||||
}
|
||||
else if (command.equals("OutlinePaint")) {
|
||||
attemptOutlinePaintSelection();
|
||||
}
|
||||
// else if (command.equals("Insets")) {
|
||||
// editInsets();
|
||||
// }
|
||||
else if (command.equals("Orientation")) {
|
||||
attemptOrientationSelection();
|
||||
}
|
||||
else if (command.equals("DrawLines")) {
|
||||
attemptDrawLinesSelection();
|
||||
}
|
||||
else if (command.equals("DrawShapes")) {
|
||||
attemptDrawShapesSelection();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow the user to change the background paint.
|
||||
*/
|
||||
private void attemptBackgroundPaintSelection() {
|
||||
Color initialColor = (backgroundPaintSample.getPaint() instanceof Color ? (Color)backgroundPaintSample.getPaint() : Color.blue);
|
||||
Color c = JColorChooser.showDialog(this, localizationResources.getString("Background_Color"), initialColor);
|
||||
if (c != null) {
|
||||
this.backgroundPaintSample.setPaint(c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow the user to change the outline stroke.
|
||||
*/
|
||||
private void attemptOutlineStrokeSelection() {
|
||||
StrokeChooserPanel panel = new StrokeChooserPanel(
|
||||
this.outlineStrokeSample, this.availableStrokeSamples);
|
||||
int result = JOptionPane.showConfirmDialog(this, panel,
|
||||
localizationResources.getString("Stroke_Selection"),
|
||||
JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
|
||||
|
||||
if (result == JOptionPane.OK_OPTION) {
|
||||
this.outlineStrokeSample.setStroke(panel.getSelectedStroke());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow the user to change the outline paint. We use JColorChooser, so
|
||||
* the user can only choose colors (a subset of all possible paints).
|
||||
*/
|
||||
private void attemptOutlinePaintSelection() {
|
||||
Color initialColor = (outlinePaintSample.getPaint() instanceof Color ? (Color)outlinePaintSample.getPaint() : Color.blue);
|
||||
Color c= JColorChooser.showDialog(this, localizationResources.getString("Outline_Color"), initialColor);
|
||||
if (c != null) {
|
||||
this.outlinePaintSample.setPaint(c);
|
||||
}
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Allow the user to edit the individual insets' values.
|
||||
// */
|
||||
// private void editInsets() {
|
||||
// InsetsChooserPanel panel = new InsetsChooserPanel(this.plotInsets);
|
||||
// int result = JOptionPane.showConfirmDialog(
|
||||
// this, panel, localizationResources.getString("Edit_Insets"),
|
||||
// JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE
|
||||
// );
|
||||
//
|
||||
// if (result == JOptionPane.OK_OPTION) {
|
||||
// this.plotInsets = panel.getInsets();
|
||||
// this.insetsTextField.setInsets(this.plotInsets);
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
/**
|
||||
* Allow the user to modify the plot orientation if this is an editor for a
|
||||
* <tt>CategoryPlot</tt> or a <tt>XYPlot</tt>.
|
||||
*/
|
||||
private void attemptOrientationSelection() {
|
||||
|
||||
int index = this.orientationCombo.getSelectedIndex();
|
||||
|
||||
if (index == ORIENTATION_VERTICAL) {
|
||||
this.plotOrientation = PlotOrientation.VERTICAL;
|
||||
}
|
||||
else {
|
||||
this.plotOrientation = PlotOrientation.HORIZONTAL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow the user to modify whether or not lines are drawn between data
|
||||
* points by <tt>LineAndShapeRenderer</tt>s and
|
||||
* <tt>StandardXYItemRenderer</tt>s.
|
||||
*/
|
||||
private void attemptDrawLinesSelection() {
|
||||
this.drawLines = BooleanUtilities.valueOf(
|
||||
this.drawLinesCheckBox.isSelected());
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow the user to modify whether or not shapes are drawn at data points
|
||||
* by <tt>LineAndShapeRenderer</tt>s and <tt>StandardXYItemRenderer</tt>s.
|
||||
*/
|
||||
private void attemptDrawShapesSelection() {
|
||||
this.drawShapes = BooleanUtilities.valueOf(
|
||||
this.drawShapesCheckBox.isSelected());
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the plot properties to match the properties defined on the panel.
|
||||
*
|
||||
* @param plot The plot.
|
||||
*/
|
||||
public void updatePlotProperties(Plot plot) {
|
||||
|
||||
// set the plot properties...
|
||||
plot.setOutlinePaint(getOutlinePaint());
|
||||
plot.setOutlineStroke(getOutlineStroke());
|
||||
plot.setBackgroundPaint(getBackgroundPaint());
|
||||
plot.setInsets(getPlotInsets());
|
||||
|
||||
// then the axis properties...
|
||||
if (this.domainAxisPropertyPanel != null) {
|
||||
Axis domainAxis = null;
|
||||
if (plot instanceof CategoryPlot) {
|
||||
CategoryPlot p = (CategoryPlot) plot;
|
||||
domainAxis = p.getDomainAxis();
|
||||
}
|
||||
else if (plot instanceof XYPlot) {
|
||||
XYPlot p = (XYPlot) plot;
|
||||
domainAxis = p.getDomainAxis();
|
||||
}
|
||||
if (domainAxis != null) {
|
||||
this.domainAxisPropertyPanel.setAxisProperties(domainAxis);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.rangeAxisPropertyPanel != null) {
|
||||
Axis rangeAxis = null;
|
||||
if (plot instanceof CategoryPlot) {
|
||||
CategoryPlot p = (CategoryPlot) plot;
|
||||
rangeAxis = p.getRangeAxis();
|
||||
}
|
||||
else if (plot instanceof XYPlot) {
|
||||
XYPlot p = (XYPlot) plot;
|
||||
rangeAxis = p.getRangeAxis();
|
||||
}
|
||||
else if (plot instanceof PolarPlot) {
|
||||
PolarPlot p = (PolarPlot) plot;
|
||||
rangeAxis = p.getAxis();
|
||||
}
|
||||
if (rangeAxis != null) {
|
||||
this.rangeAxisPropertyPanel.setAxisProperties(rangeAxis);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.plotOrientation != null) {
|
||||
if (plot instanceof CategoryPlot) {
|
||||
CategoryPlot p = (CategoryPlot) plot;
|
||||
p.setOrientation(this.plotOrientation);
|
||||
}
|
||||
else if (plot instanceof XYPlot) {
|
||||
XYPlot p = (XYPlot) plot;
|
||||
p.setOrientation(this.plotOrientation);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.drawLines != null) {
|
||||
if (plot instanceof CategoryPlot) {
|
||||
CategoryPlot p = (CategoryPlot) plot;
|
||||
CategoryItemRenderer r = p.getRenderer();
|
||||
if (r instanceof LineAndShapeRenderer) {
|
||||
((LineAndShapeRenderer) r).setBaseLinesVisible(this.drawLines.booleanValue());
|
||||
}
|
||||
}
|
||||
else if (plot instanceof XYPlot) {
|
||||
XYPlot p = (XYPlot) plot;
|
||||
XYItemRenderer r = p.getRenderer();
|
||||
if (r instanceof StandardXYItemRenderer) {
|
||||
((StandardXYItemRenderer) r).setPlotLines(this.drawLines.booleanValue());
|
||||
} else if (r instanceof XYLineAndShapeRenderer) {
|
||||
((XYLineAndShapeRenderer) r).setBaseLinesVisible(this.drawLines.booleanValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.drawShapes != null) {
|
||||
if (plot instanceof CategoryPlot) {
|
||||
CategoryPlot p = (CategoryPlot) plot;
|
||||
CategoryItemRenderer r = p.getRenderer();
|
||||
if (r instanceof LineAndShapeRenderer) {
|
||||
((LineAndShapeRenderer) r).setBaseShapesVisible(this.drawShapes.booleanValue());
|
||||
}
|
||||
}
|
||||
else if (plot instanceof XYPlot) {
|
||||
XYPlot p = (XYPlot) plot;
|
||||
XYItemRenderer r = p.getRenderer();
|
||||
if (r instanceof StandardXYItemRenderer) {
|
||||
((StandardXYItemRenderer) r).setBaseShapesVisible(this.drawShapes.booleanValue());
|
||||
} else if (r instanceof XYLineAndShapeRenderer) {
|
||||
((XYLineAndShapeRenderer) r).setBaseShapesVisible(this.drawShapes.booleanValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
//dmo: added this panel for colorbar control. (start dmo additions)
|
||||
if (this.colorBarAxisPropertyPanel != null) {
|
||||
ColorBar colorBar = null;
|
||||
if (plot instanceof ContourPlot) {
|
||||
ContourPlot p = (ContourPlot) plot;
|
||||
colorBar = p.getColorBar();
|
||||
}
|
||||
if (colorBar != null) {
|
||||
this.colorBarAxisPropertyPanel.setAxisProperties(colorBar);
|
||||
}
|
||||
}
|
||||
//dmo: (end dmo additions)
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,179 @@
|
||||
/*
|
||||
* $Id
|
||||
*/
|
||||
|
||||
package trick.dataproducts.plot.utils.editor;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTabbedPane;
|
||||
import javax.swing.JTextField;
|
||||
|
||||
import org.jfree.chart.axis.NumberTickUnit;
|
||||
import org.jfree.chart.plot.Plot;
|
||||
import org.jfree.chart.plot.PolarPlot;
|
||||
import org.jfree.layout.LCBLayout;
|
||||
|
||||
/**
|
||||
* A panel for editing the properties of a {@link PolarPlot}.
|
||||
*/
|
||||
public class TrickPolarPlotEditor extends TrickPlotEditor
|
||||
implements FocusListener {
|
||||
|
||||
|
||||
private static final long serialVersionUID = 436737477629003049L;
|
||||
|
||||
/** A text field to enter a manual TickUnit. */
|
||||
private JTextField manualTickUnit;
|
||||
|
||||
/** A text field to enter the angleOffset. */
|
||||
private JTextField angleOffset;
|
||||
|
||||
/** The size for the manual TickUnit. */
|
||||
private double manualTickUnitValue;
|
||||
|
||||
/** The value for the plot's angle offset. */
|
||||
private double angleOffsetValue;
|
||||
|
||||
|
||||
/**
|
||||
* Standard constructor - constructs a panel for editing the properties of
|
||||
* the specified plot.
|
||||
*
|
||||
* @param plot the plot, which should be changed.
|
||||
*/
|
||||
public TrickPolarPlotEditor(PolarPlot plot) {
|
||||
super(plot);
|
||||
this.angleOffsetValue = plot.getAngleOffset();
|
||||
this.angleOffset.setText(Double.toString(this.angleOffsetValue));
|
||||
this.manualTickUnitValue = plot.getAngleTickUnit().getSize();
|
||||
this.manualTickUnit.setText(Double.toString(this.manualTickUnitValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a tabbed pane for editing the plot attributes.
|
||||
*
|
||||
* @param plot the plot.
|
||||
*
|
||||
* @return A tabbed pane.
|
||||
*/
|
||||
@Override
|
||||
protected JTabbedPane createPlotTabs(Plot plot) {
|
||||
JTabbedPane tabs = super.createPlotTabs(plot);
|
||||
// TODO find a better localization key
|
||||
tabs.insertTab(localizationResources.getString("General1"), null, createPlotPanel(), null, 0);
|
||||
tabs.setSelectedIndex(0);
|
||||
return tabs;
|
||||
}
|
||||
|
||||
private JPanel createPlotPanel() {
|
||||
JPanel plotPanel = new JPanel(new LCBLayout(3));
|
||||
plotPanel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
|
||||
|
||||
plotPanel.add(new JLabel(localizationResources.getString(
|
||||
"AngleOffset")));
|
||||
this.angleOffset = new JTextField(Double.toString(
|
||||
this.angleOffsetValue));
|
||||
this.angleOffset.setActionCommand("AngleOffsetValue");
|
||||
this.angleOffset.addActionListener(this);
|
||||
this.angleOffset.addFocusListener(this);
|
||||
plotPanel.add(this.angleOffset);
|
||||
plotPanel.add(new JPanel());
|
||||
|
||||
plotPanel.add(new JLabel(localizationResources.getString(
|
||||
"Manual_TickUnit_value")));
|
||||
this.manualTickUnit = new JTextField(Double.toString(
|
||||
this.manualTickUnitValue));
|
||||
this.manualTickUnit.setActionCommand("TickUnitValue");
|
||||
this.manualTickUnit.addActionListener(this);
|
||||
this.manualTickUnit.addFocusListener(this);
|
||||
plotPanel.add(this.manualTickUnit);
|
||||
plotPanel.add(new JPanel());
|
||||
|
||||
return plotPanel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing.
|
||||
*
|
||||
* @param event the event.
|
||||
*/
|
||||
public void focusGained(FocusEvent event) {
|
||||
// don't need to do anything
|
||||
}
|
||||
|
||||
/**
|
||||
* Revalidates minimum/maximum range.
|
||||
*
|
||||
* @param event the event.
|
||||
*/
|
||||
public void focusLost(FocusEvent event) {
|
||||
if (event.getSource() == this.angleOffset) {
|
||||
validateAngleOffset();
|
||||
}
|
||||
else if (event.getSource() == this.manualTickUnit) {
|
||||
validateTickUnit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles actions from within the property panel.
|
||||
* @param event an event.
|
||||
*/
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
String command = event.getActionCommand();
|
||||
if (command.equals("AngleOffsetValue")) {
|
||||
validateAngleOffset();
|
||||
}
|
||||
else if (command.equals("TickUnitValue")) {
|
||||
validateTickUnit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the angle offset entered by the user.
|
||||
*/
|
||||
public void validateAngleOffset() {
|
||||
double newOffset;
|
||||
try {
|
||||
newOffset = Double.parseDouble(this.angleOffset.getText());
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
newOffset = this.angleOffsetValue;
|
||||
}
|
||||
this.angleOffsetValue = newOffset;
|
||||
this.angleOffset.setText(Double.toString(this.angleOffsetValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the tick unit entered by the user.
|
||||
*/
|
||||
public void validateTickUnit() {
|
||||
double newTickUnit;
|
||||
try {
|
||||
newTickUnit = Double.parseDouble(this.manualTickUnit.getText());
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
newTickUnit = this.manualTickUnitValue;
|
||||
}
|
||||
|
||||
if (newTickUnit > 0.0 && newTickUnit < 360.0) {
|
||||
this.manualTickUnitValue = newTickUnit;
|
||||
}
|
||||
this.manualTickUnit.setText(Double.toString(this.manualTickUnitValue));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePlotProperties(Plot plot) {
|
||||
super.updatePlotProperties(plot);
|
||||
PolarPlot pp = (PolarPlot) plot;
|
||||
pp.setAngleTickUnit(new NumberTickUnit(this.manualTickUnitValue));
|
||||
pp.setAngleOffset(this.angleOffsetValue);
|
||||
}
|
||||
}
|
@ -0,0 +1,267 @@
|
||||
/*
|
||||
* $Id
|
||||
*/
|
||||
|
||||
package trick.dataproducts.plot.utils.editor;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.Paint;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JColorChooser;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextField;
|
||||
|
||||
import org.jfree.chart.JFreeChart;
|
||||
import org.jfree.chart.title.TextTitle;
|
||||
import org.jfree.chart.title.Title;
|
||||
import org.jfree.chart.util.ResourceBundleWrapper;
|
||||
import org.jfree.layout.LCBLayout;
|
||||
import org.jfree.ui.FontChooserPanel;
|
||||
import org.jfree.ui.FontDisplayField;
|
||||
import org.jfree.ui.PaintSample;
|
||||
|
||||
/**
|
||||
* A panel for editing the properties of a chart title.
|
||||
*/
|
||||
public class TrickTitleEditor extends JPanel implements ActionListener {
|
||||
|
||||
|
||||
private static final long serialVersionUID = 7434968517978830476L;
|
||||
|
||||
/** Whether or not to display the title on the chart. */
|
||||
private boolean showTitle;
|
||||
|
||||
/** The checkbox to indicate whether or not to display the title. */
|
||||
private JCheckBox showTitleCheckBox;
|
||||
|
||||
/** A field for displaying/editing the title text. */
|
||||
private JTextField titleField;
|
||||
|
||||
/** The font used to draw the title. */
|
||||
private Font titleFont;
|
||||
|
||||
/** A field for displaying a description of the title font. */
|
||||
private JTextField fontfield;
|
||||
|
||||
/** The button to use to select a new title font. */
|
||||
private JButton selectFontButton;
|
||||
|
||||
/** The paint (color) used to draw the title. */
|
||||
private PaintSample titlePaint;
|
||||
|
||||
/** The button to use to select a new paint (color) to draw the title. */
|
||||
private JButton selectPaintButton;
|
||||
|
||||
/** The resourceBundle for the localization. */
|
||||
protected static ResourceBundle localizationResources
|
||||
= ResourceBundleWrapper.getBundle(
|
||||
"org.jfree.chart.editor.LocalizationBundle");
|
||||
|
||||
/**
|
||||
* Standard constructor: builds a panel for displaying/editing the
|
||||
* properties of the specified title.
|
||||
*
|
||||
* @param title the title, which should be changed.
|
||||
*/
|
||||
public TrickTitleEditor(Title title) {
|
||||
|
||||
TextTitle t = (title != null ? (TextTitle) title
|
||||
: new TextTitle(localizationResources.getString("Title")));
|
||||
this.showTitle = (title != null);
|
||||
this.titleFont = t.getFont();
|
||||
this.titleField = new JTextField(t.getText());
|
||||
this.titlePaint = new PaintSample(t.getPaint());
|
||||
|
||||
setLayout(new BorderLayout());
|
||||
|
||||
JPanel general = new JPanel(new BorderLayout());
|
||||
general.setBorder(
|
||||
BorderFactory.createTitledBorder(
|
||||
BorderFactory.createEtchedBorder(),
|
||||
localizationResources.getString("General")
|
||||
)
|
||||
);
|
||||
|
||||
JPanel interior = new JPanel(new LCBLayout(4));
|
||||
interior.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5));
|
||||
|
||||
interior.add(new JLabel(localizationResources.getString("Show_Title")));
|
||||
this.showTitleCheckBox = new JCheckBox();
|
||||
this.showTitleCheckBox.setSelected(this.showTitle);
|
||||
this.showTitleCheckBox.setActionCommand("ShowTitle");
|
||||
this.showTitleCheckBox.addActionListener(this);
|
||||
interior.add(new JPanel());
|
||||
interior.add(this.showTitleCheckBox);
|
||||
|
||||
JLabel titleLabel = new JLabel(localizationResources.getString("Text"));
|
||||
interior.add(titleLabel);
|
||||
interior.add(this.titleField);
|
||||
interior.add(new JPanel());
|
||||
|
||||
JLabel fontLabel = new JLabel(localizationResources.getString("Font"));
|
||||
this.fontfield = new FontDisplayField(this.titleFont);
|
||||
this.selectFontButton = new JButton(
|
||||
localizationResources.getString("Select...")
|
||||
);
|
||||
this.selectFontButton.setActionCommand("SelectFont");
|
||||
this.selectFontButton.addActionListener(this);
|
||||
interior.add(fontLabel);
|
||||
interior.add(this.fontfield);
|
||||
interior.add(this.selectFontButton);
|
||||
|
||||
JLabel colorLabel = new JLabel(
|
||||
localizationResources.getString("Color")
|
||||
);
|
||||
this.selectPaintButton = new JButton(
|
||||
localizationResources.getString("Select...")
|
||||
);
|
||||
this.selectPaintButton.setActionCommand("SelectPaint");
|
||||
this.selectPaintButton.addActionListener(this);
|
||||
interior.add(colorLabel);
|
||||
interior.add(this.titlePaint);
|
||||
interior.add(this.selectPaintButton);
|
||||
|
||||
this.enableOrDisableControls();
|
||||
|
||||
general.add(interior);
|
||||
add(general, BorderLayout.NORTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the title text entered in the panel.
|
||||
*
|
||||
* @return The title text entered in the panel.
|
||||
*/
|
||||
public String getTitleText() {
|
||||
return this.titleField.getText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the font selected in the panel.
|
||||
*
|
||||
* @return The font selected in the panel.
|
||||
*/
|
||||
public Font getTitleFont() {
|
||||
return this.titleFont;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the paint selected in the panel.
|
||||
*
|
||||
* @return The paint selected in the panel.
|
||||
*/
|
||||
public Paint getTitlePaint() {
|
||||
return this.titlePaint.getPaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles button clicks by passing control to an appropriate handler
|
||||
* method.
|
||||
*
|
||||
* @param event the event
|
||||
*/
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
|
||||
String command = event.getActionCommand();
|
||||
|
||||
if (command.equals("SelectFont")) {
|
||||
attemptFontSelection();
|
||||
}
|
||||
else if (command.equals("SelectPaint")) {
|
||||
attemptPaintSelection();
|
||||
}
|
||||
else if (command.equals("ShowTitle")) {
|
||||
attemptModifyShowTitle();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Presents a font selection dialog to the user.
|
||||
*/
|
||||
public void attemptFontSelection() {
|
||||
|
||||
FontChooserPanel panel = new FontChooserPanel(this.titleFont);
|
||||
int result =
|
||||
JOptionPane.showConfirmDialog(
|
||||
this, panel, localizationResources.getString("Font_Selection"),
|
||||
JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE
|
||||
);
|
||||
|
||||
if (result == JOptionPane.OK_OPTION) {
|
||||
this.titleFont = panel.getSelectedFont();
|
||||
this.fontfield.setText(
|
||||
this.titleFont.getFontName() + " " + this.titleFont.getSize()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow the user the opportunity to select a Paint object. For now, we
|
||||
* just use the standard color chooser - all colors are Paint objects, but
|
||||
* not all Paint objects are colors (later we can implement a more general
|
||||
* Paint chooser).
|
||||
*/
|
||||
public void attemptPaintSelection() {
|
||||
Paint p = this.titlePaint.getPaint();
|
||||
Color defaultColor = (p instanceof Color ? (Color) p : Color.blue);
|
||||
Color c = JColorChooser.showDialog(
|
||||
this, localizationResources.getString("Title_Color"), defaultColor
|
||||
);
|
||||
if (c != null) {
|
||||
this.titlePaint.setPaint(c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow the user the opportunity to change whether the title is
|
||||
* displayed on the chart or not.
|
||||
*/
|
||||
private void attemptModifyShowTitle() {
|
||||
this.showTitle = this.showTitleCheckBox.isSelected();
|
||||
this.enableOrDisableControls();
|
||||
}
|
||||
|
||||
/**
|
||||
* If we are supposed to show the title, the controls are enabled.
|
||||
* If we are not supposed to show the title, the controls are disabled.
|
||||
*/
|
||||
private void enableOrDisableControls() {
|
||||
boolean enabled = (this.showTitle == true);
|
||||
this.titleField.setEnabled(enabled);
|
||||
this.selectFontButton.setEnabled(enabled);
|
||||
this.selectPaintButton.setEnabled(enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the properties of the specified title to match the properties
|
||||
* defined on this panel.
|
||||
*
|
||||
* @param chart the chart whose title is to be modified.
|
||||
*/
|
||||
public void setTitleProperties(JFreeChart chart) {
|
||||
if (this.showTitle) {
|
||||
TextTitle title = chart.getTitle();
|
||||
if (title == null) {
|
||||
title = new TextTitle();
|
||||
chart.setTitle(title);
|
||||
}
|
||||
title.setText(getTitleText());
|
||||
title.setFont(getTitleFont());
|
||||
title.setPaint(getTitlePaint());
|
||||
}
|
||||
else {
|
||||
chart.setTitle((TextTitle) null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,384 @@
|
||||
/*
|
||||
* $Id
|
||||
*/
|
||||
|
||||
package trick.dataproducts.plot.utils.editor;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JColorChooser;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTabbedPane;
|
||||
import javax.swing.JTextField;
|
||||
|
||||
import org.jfree.chart.axis.Axis;
|
||||
import org.jfree.chart.axis.ValueAxis;
|
||||
import org.jfree.chart.util.ResourceBundleWrapper;
|
||||
import org.jfree.layout.LCBLayout;
|
||||
import org.jfree.ui.PaintSample;
|
||||
import org.jfree.ui.StrokeChooserPanel;
|
||||
import org.jfree.ui.StrokeSample;
|
||||
|
||||
/**
|
||||
* A panel for editing properties of a {@link ValueAxis}.
|
||||
*/
|
||||
public class TrickValueAxisEditor extends TrickAxisEditor
|
||||
implements FocusListener {
|
||||
|
||||
|
||||
private static final long serialVersionUID = -8568989539318482713L;
|
||||
|
||||
/** A flag that indicates whether or not the axis range is determined
|
||||
* automatically.
|
||||
*/
|
||||
private boolean autoRange;
|
||||
|
||||
/** Flag if auto-tickunit-selection is enabled. */
|
||||
private boolean autoTickUnitSelection;
|
||||
|
||||
/** The lowest value in the axis range. */
|
||||
private double minimumValue;
|
||||
|
||||
/** The highest value in the axis range. */
|
||||
private double maximumValue;
|
||||
|
||||
/** A checkbox that indicates whether or not the axis range is determined
|
||||
* automatically.
|
||||
*/
|
||||
private JCheckBox autoRangeCheckBox;
|
||||
|
||||
/** A check-box enabling/disabling auto-tickunit-selection. */
|
||||
private JCheckBox autoTickUnitSelectionCheckBox;
|
||||
|
||||
/** A text field for entering the minimum value in the axis range. */
|
||||
private JTextField minimumRangeValue;
|
||||
|
||||
/** A text field for entering the maximum value in the axis range. */
|
||||
private JTextField maximumRangeValue;
|
||||
|
||||
/** The paint selected for drawing the gridlines. */
|
||||
private PaintSample gridPaintSample;
|
||||
|
||||
/** The stroke selected for drawing the gridlines. */
|
||||
private StrokeSample gridStrokeSample;
|
||||
|
||||
/** An array of stroke samples to choose from (since I haven't written a
|
||||
* decent StrokeChooser component yet).
|
||||
*/
|
||||
private StrokeSample[] availableStrokeSamples;
|
||||
|
||||
/** The resourceBundle for the localization. */
|
||||
protected static ResourceBundle localizationResources
|
||||
= ResourceBundleWrapper.getBundle(
|
||||
"org.jfree.chart.editor.LocalizationBundle");
|
||||
|
||||
/**
|
||||
* Standard constructor: builds a property panel for the specified axis.
|
||||
*
|
||||
* @param axis the axis, which should be changed.
|
||||
*/
|
||||
public TrickValueAxisEditor(ValueAxis axis) {
|
||||
|
||||
super(axis);
|
||||
|
||||
this.autoRange = axis.isAutoRange();
|
||||
this.minimumValue = axis.getLowerBound();
|
||||
this.maximumValue = axis.getUpperBound();
|
||||
this.autoTickUnitSelection = axis.isAutoTickUnitSelection();
|
||||
|
||||
this.gridPaintSample = new PaintSample(Color.blue);
|
||||
this.gridStrokeSample = new StrokeSample(new BasicStroke(1.0f));
|
||||
|
||||
this.availableStrokeSamples = new StrokeSample[3];
|
||||
this.availableStrokeSamples[0] = new StrokeSample(
|
||||
new BasicStroke(1.0f));
|
||||
this.availableStrokeSamples[1] = new StrokeSample(
|
||||
new BasicStroke(2.0f));
|
||||
this.availableStrokeSamples[2] = new StrokeSample(
|
||||
new BasicStroke(3.0f));
|
||||
|
||||
JTabbedPane other = getOtherTabs();
|
||||
|
||||
JPanel range = new JPanel(new LCBLayout(3));
|
||||
range.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
|
||||
|
||||
range.add(new JPanel());
|
||||
this.autoRangeCheckBox = new JCheckBox(localizationResources.getString(
|
||||
"Auto-adjust_range"), this.autoRange);
|
||||
this.autoRangeCheckBox.setActionCommand("AutoRangeOnOff");
|
||||
this.autoRangeCheckBox.addActionListener(this);
|
||||
range.add(this.autoRangeCheckBox);
|
||||
range.add(new JPanel());
|
||||
|
||||
range.add(new JLabel(localizationResources.getString(
|
||||
"Minimum_range_value")));
|
||||
this.minimumRangeValue = new JTextField(Double.toString(
|
||||
this.minimumValue));
|
||||
this.minimumRangeValue.setEnabled(!this.autoRange);
|
||||
this.minimumRangeValue.setActionCommand("MinimumRange");
|
||||
this.minimumRangeValue.addActionListener(this);
|
||||
this.minimumRangeValue.addFocusListener(this);
|
||||
range.add(this.minimumRangeValue);
|
||||
range.add(new JPanel());
|
||||
|
||||
range.add(new JLabel(localizationResources.getString(
|
||||
"Maximum_range_value")));
|
||||
this.maximumRangeValue = new JTextField(Double.toString(
|
||||
this.maximumValue));
|
||||
this.maximumRangeValue.setEnabled(!this.autoRange);
|
||||
this.maximumRangeValue.setActionCommand("MaximumRange");
|
||||
this.maximumRangeValue.addActionListener(this);
|
||||
this.maximumRangeValue.addFocusListener(this);
|
||||
range.add(this.maximumRangeValue);
|
||||
range.add(new JPanel());
|
||||
|
||||
other.add(localizationResources.getString("Range"), range);
|
||||
|
||||
other.add(localizationResources.getString("TickUnit"),
|
||||
createTickUnitPanel());
|
||||
}
|
||||
|
||||
protected JPanel createTickUnitPanel() {
|
||||
JPanel tickUnitPanel = new JPanel(new LCBLayout(3));
|
||||
tickUnitPanel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
|
||||
|
||||
tickUnitPanel.add(new JPanel());
|
||||
this.autoTickUnitSelectionCheckBox = new JCheckBox(
|
||||
localizationResources.getString("Auto-TickUnit_Selection"),
|
||||
this.autoTickUnitSelection);
|
||||
this.autoTickUnitSelectionCheckBox.setActionCommand("AutoTickOnOff");
|
||||
this.autoTickUnitSelectionCheckBox.addActionListener(this);
|
||||
tickUnitPanel.add(this.autoTickUnitSelectionCheckBox);
|
||||
tickUnitPanel.add(new JPanel());
|
||||
|
||||
return tickUnitPanel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for the {@link #autoTickUnitSelection} flag.
|
||||
*
|
||||
* @return The value of the flag for enabling auto-tickunit-selection.
|
||||
*/
|
||||
protected boolean isAutoTickUnitSelection() {
|
||||
return autoTickUnitSelection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the {@link #autoTickUnitSelection} flag.
|
||||
* @param autoTickUnitSelection The new value for auto-tickunit-selection.
|
||||
*/
|
||||
protected void setAutoTickUnitSelection(boolean autoTickUnitSelection) {
|
||||
this.autoTickUnitSelection = autoTickUnitSelection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the checkbox that enables/disables auto-tickunit-selection.
|
||||
*
|
||||
* @return The checkbox.
|
||||
*/
|
||||
protected JCheckBox getAutoTickUnitSelectionCheckBox() {
|
||||
return autoTickUnitSelectionCheckBox;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the checkbox that enables/disables auto-tickunit-selection.
|
||||
*
|
||||
* @param autoTickUnitSelectionCheckBox The checkbox.
|
||||
*/
|
||||
protected void setAutoTickUnitSelectionCheckBox(
|
||||
JCheckBox autoTickUnitSelectionCheckBox) {
|
||||
this.autoTickUnitSelectionCheckBox = autoTickUnitSelectionCheckBox;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current setting of the auto-range property.
|
||||
*
|
||||
* @return <code>true</code> if auto range is enabled.
|
||||
*/
|
||||
public boolean isAutoRange() {
|
||||
return this.autoRange;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current setting of the minimum value in the axis range.
|
||||
*
|
||||
* @return The current setting of the minimum value in the axis range.
|
||||
*/
|
||||
public double getMinimumValue() {
|
||||
return this.minimumValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current setting of the maximum value in the axis range.
|
||||
*
|
||||
* @return The current setting of the maximum value in the axis range.
|
||||
*/
|
||||
public double getMaximumValue() {
|
||||
return this.maximumValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles actions from within the property panel.
|
||||
* @param event an event.
|
||||
*/
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
String command = event.getActionCommand();
|
||||
if (command.equals("GridStroke")) {
|
||||
attemptGridStrokeSelection();
|
||||
}
|
||||
else if (command.equals("GridPaint")) {
|
||||
attemptGridPaintSelection();
|
||||
}
|
||||
else if (command.equals("AutoRangeOnOff")) {
|
||||
toggleAutoRange();
|
||||
}
|
||||
else if (command.equals("MinimumRange")) {
|
||||
validateMinimum();
|
||||
}
|
||||
else if (command.equals("MaximumRange")) {
|
||||
validateMaximum();
|
||||
}
|
||||
else if (command.equals("AutoTickOnOff")) {
|
||||
toggleAutoTick();
|
||||
}
|
||||
else {
|
||||
// pass to the super-class for handling
|
||||
super.actionPerformed(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a grid stroke selection.
|
||||
*/
|
||||
protected void attemptGridStrokeSelection() {
|
||||
StrokeChooserPanel panel = new StrokeChooserPanel(this.gridStrokeSample,
|
||||
this.availableStrokeSamples);
|
||||
int result = JOptionPane.showConfirmDialog(this, panel,
|
||||
localizationResources.getString("Stroke_Selection"),
|
||||
JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
|
||||
|
||||
if (result == JOptionPane.OK_OPTION) {
|
||||
this.gridStrokeSample.setStroke(panel.getSelectedStroke());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a grid paint selection.
|
||||
*/
|
||||
protected void attemptGridPaintSelection() {
|
||||
Color initialColor = (gridPaintSample.getPaint() instanceof Color ? (Color)gridPaintSample.getPaint() : Color.blue);
|
||||
Color c = JColorChooser.showDialog(this, localizationResources.getString("Grid_Color"), initialColor);
|
||||
if (c != null) {
|
||||
this.gridPaintSample.setPaint(c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing.
|
||||
*
|
||||
* @param event the event.
|
||||
*/
|
||||
public void focusGained(FocusEvent event) {
|
||||
// don't need to do anything
|
||||
}
|
||||
|
||||
/**
|
||||
* Revalidates minimum/maximum range.
|
||||
*
|
||||
* @param event the event.
|
||||
*/
|
||||
public void focusLost(FocusEvent event) {
|
||||
if (event.getSource() == this.minimumRangeValue) {
|
||||
validateMinimum();
|
||||
}
|
||||
else if (event.getSource() == this.maximumRangeValue) {
|
||||
validateMaximum();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the auto range setting.
|
||||
*/
|
||||
public void toggleAutoRange() {
|
||||
this.autoRange = this.autoRangeCheckBox.isSelected();
|
||||
if (this.autoRange) {
|
||||
this.minimumRangeValue.setText(Double.toString(this.minimumValue));
|
||||
this.minimumRangeValue.setEnabled(false);
|
||||
this.maximumRangeValue.setText(Double.toString(this.maximumValue));
|
||||
this.maximumRangeValue.setEnabled(false);
|
||||
}
|
||||
else {
|
||||
this.minimumRangeValue.setEnabled(true);
|
||||
this.maximumRangeValue.setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void toggleAutoTick() {
|
||||
this.autoTickUnitSelection = this.autoTickUnitSelectionCheckBox.isSelected();
|
||||
}
|
||||
|
||||
/**
|
||||
* Revalidate the range minimum.
|
||||
*/
|
||||
public void validateMinimum() {
|
||||
double newMin;
|
||||
try {
|
||||
newMin = Double.parseDouble(this.minimumRangeValue.getText());
|
||||
if (newMin >= this.maximumValue) {
|
||||
newMin = this.minimumValue;
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
newMin = this.minimumValue;
|
||||
}
|
||||
|
||||
this.minimumValue = newMin;
|
||||
this.minimumRangeValue.setText(Double.toString(this.minimumValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* Revalidate the range maximum.
|
||||
*/
|
||||
public void validateMaximum() {
|
||||
double newMax;
|
||||
try {
|
||||
newMax = Double.parseDouble(this.maximumRangeValue.getText());
|
||||
if (newMax <= this.minimumValue) {
|
||||
newMax = this.maximumValue;
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
newMax = this.maximumValue;
|
||||
}
|
||||
|
||||
this.maximumValue = newMax;
|
||||
this.maximumRangeValue.setText(Double.toString(this.maximumValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the properties of the specified axis to match the properties
|
||||
* defined on this panel.
|
||||
*
|
||||
* @param axis the axis.
|
||||
*/
|
||||
@Override
|
||||
public void setAxisProperties(Axis axis) {
|
||||
super.setAxisProperties(axis);
|
||||
ValueAxis valueAxis = (ValueAxis) axis;
|
||||
valueAxis.setAutoRange(this.autoRange);
|
||||
if (!this.autoRange) {
|
||||
valueAxis.setRange(this.minimumValue, this.maximumValue);
|
||||
}
|
||||
valueAxis.setAutoTickUnitSelection(this.autoTickUnitSelection);
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
# $Id: DataProductsApplication.properties 3259 2013-10-17 21:37:36Z hchen3 $
|
||||
# Resources file for DataProductsApplication class
|
||||
|
||||
Application.id = DataProductsApplication
|
||||
Application.title = Data Products
|
||||
|
||||
mainFrame.title = Data Products
|
||||
|
||||
|
||||
singlePlot.Action.text = &Single Plot...
|
||||
singlePlot.Action.shortDescription = Show Single Plot
|
||||
singlePlot.Action.icon = plot_single.gif
|
||||
|
||||
comparisonPlot.Action.text = &Comparison Plot...
|
||||
comparisonPlot.Action.shortDescription = Show Comparison Plot
|
||||
comparisonPlot.Action.icon = plot_coplot.gif
|
||||
|
||||
errorPlot.Action.text = &Error Plot...
|
||||
errorPlot.Action.shortDescription = Show Error Plot
|
||||
errorPlot.Action.icon = plot_error.gif
|
||||
|
||||
contrastPlot.Action.text = Co&ntrast Plot...
|
||||
contrastPlot.Action.shortDescription = Contrast Plot: Show Both Comparison and Error Plots
|
||||
contrastPlot.Action.icon = plot_contrast.gif
|
||||
|
||||
tabularData.Action.text = &Table...
|
||||
tabularData.Action.shortDescription = Show Tabular Data
|
||||
tabularData.Action.icon = table_callback1.gif
|
||||
|
||||
tabularErrorData.Action.text = Table Err&or...
|
||||
tabularErrorData.Action.shortDescription = Show Tabular Error Data
|
||||
tabularErrorData.Action.icon = table_error_callback.gif
|
||||
|
||||
removeSelectedNode.Action.text = Remove
|
||||
removeSelectedNode.Action.shortDescription = Remove the Selected Node
|
||||
|
||||
configureRunTimename.Action.text = Configure Time Name...
|
||||
configureRunTimename.Action.shortDescription = Configure the Time Name from Default sys.exec.out.time to a Different one
|
||||
|
||||
toggleGnuplot.Action.text = Gnuplot
|
||||
toggleGnuplot.Action.shortDescription = Check it if using Gnuplot
|
||||
toggleGnuplot.Action.icon = gnuplot_off.gif
|
||||
|
||||
selectFermi.Action.text = Fermi
|
||||
|
||||
selectGnuplot.Action.text = Gnuplot
|
||||
|
||||
selectJavaPlot.Action.text = Java
|
||||
|
||||
selectTerminalDevice.Action.text = Terminal
|
||||
selectPrinterDevice.Action.text = Printer
|
||||
selectFileDevice.Action.text = File ...
|
||||
|
||||
|
||||
selectGnuplotTerminal.Action.text = Gnuplot Terminal
|
||||
selectX11.Action.text = X11
|
||||
selectPSColor.Action.text = PS-Color
|
||||
selectPSBW.Action.text = PS-BW
|
||||
selectPNG.Action.text = PNG
|
||||
selectEPS.Action.text = EPS
|
||||
selectAQUA.Action.text = AQUA
|
||||
|
||||
gnuplot.on.icon = gnuplot_on.gif
|
||||
gnuplot.off.icon = gnuplot_off.gif
|
||||
|
||||
fxplot.command = fxplot
|
||||
gxplot.command = gxplot
|
||||
jxplot.command = jxplot
|
||||
|
||||
#default.timename = sys.exec.out.time
|
After Width: | Height: | Size: 668 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 404 B |
After Width: | Height: | Size: 751 B |
After Width: | Height: | Size: 289 B |
After Width: | Height: | Size: 469 B |
After Width: | Height: | Size: 326 B |
@ -0,0 +1,121 @@
|
||||
# $Id: TrickDPApplication.properties 2827 2013-02-27 19:44:59Z hchen3 $
|
||||
# Resources file for TrickDPApplication class
|
||||
|
||||
Application.id = trick_dp
|
||||
Application.title = Trick Data Products
|
||||
Application.description = Trick Data Products Application
|
||||
|
||||
|
||||
mainFrame.title = Trick DP
|
||||
|
||||
# Menu Bar
|
||||
sessionMenu.text = &Session
|
||||
simsRunsMenu.text = Sims/&Runs
|
||||
dataProductMenu.text = &Data Product
|
||||
settingsMenu.text = Se&ttings
|
||||
actionsMenu.text = &Actions
|
||||
helpMenu.text = &Help
|
||||
|
||||
|
||||
# Menu items
|
||||
## Session menu
|
||||
newSession.Action.text = &New...
|
||||
newSession.Action.shortDescription = Start a New Session
|
||||
|
||||
openSession.Action.text = &Open...
|
||||
openSession.Action.shortDescription = Open an Existing Session
|
||||
|
||||
##convertSession.Action.text = &Convert...
|
||||
##convertSession.Action.shortDescription = Convert Session File to XML Format
|
||||
|
||||
saveSession.Action.text = &Save...
|
||||
saveSession.Action.shortDescription = Save Current Session
|
||||
|
||||
refreshSession.Action.text = R&efresh...
|
||||
refreshSession.Action.shortDescription = Refresh Current Session
|
||||
|
||||
#propertiesSession.Action.text = &Properties...
|
||||
#propertiesSession.Action.shortDescription = Show Properties of Current Session
|
||||
|
||||
|
||||
## Sims/Runs menu
|
||||
importSimDir.Action.text = Import &Sim Dir...
|
||||
importSimDir.Action.shortDescription = Import Sim Directory to Current Session
|
||||
|
||||
addRunDir.Action.text = Add &Run Dir...
|
||||
addRunDir.Action.shortDescription = Add a Run Directory to Current Session
|
||||
|
||||
## Data Product menu
|
||||
addDP.Action.text = &Add DP...
|
||||
addDP.Action.shortDescription = Add a Data Product file to Current Session
|
||||
|
||||
editSelectedDP.Action.text = &Edit DP...
|
||||
editSelectedDP.Action.shortDescription = Open Quickplot to edit the Selected Data Product from DP Selections
|
||||
|
||||
editRightClickedDP.Action.text = &Edit DP...
|
||||
editRightClickedDP.Action.shortDescription = Open Quickplot to edit the Selected Data Product file
|
||||
|
||||
filterDP.Action.text = &Filter...
|
||||
filterDP.Action.shortDescription = Filter the Displayed Data Product files
|
||||
|
||||
|
||||
## Settings
|
||||
plotDestination.Action.text = &Destination
|
||||
plotDestination.Action.shortDescritpion = The Destination for Plotting
|
||||
|
||||
|
||||
## Actions menu
|
||||
gnuSinglePlot.Action.text = GNUplot Postscript Single Plot...
|
||||
gnuSinglePlot.Action.shortDescription = Show GNU Postscript Single Plot
|
||||
gnuSinglePlot.Action.icon = ps_single.gif
|
||||
|
||||
gnuComparisonPlot.Action.text = GNUplot Postscript Comparison Plot...
|
||||
gnuComparisonPlot.Action.shortDescription = Show GNU Postscript Comparison Plot
|
||||
gnuComparisonPlot.Action.icon = ps_coplot.gif
|
||||
|
||||
gnuErrorPlot.Action.text = GNUplot Postscript Error Plot...
|
||||
gnuErrorPlot.Action.shortDescription = Show GNU Postscript Error Plot
|
||||
gnuErrorPlot.Action.icon = ps_error.gif
|
||||
|
||||
quickPlot.Action.text = &Quickplot...
|
||||
quickPlot.Action.shortDescription = Quick Plot
|
||||
quickPlot.Action.icon = quickplot.gif
|
||||
|
||||
createPDF.Action.text = Create &PDF Booklet...
|
||||
createPDF.Action.shortDescription = Create PDF Booklet...
|
||||
createPDF.Action.icon = adobe_pdf.gif
|
||||
|
||||
|
||||
## Popup Menu for tree
|
||||
addRuns.Action.text = Add run(s)
|
||||
addRuns.Action.shortDescription = Selects run(s)
|
||||
|
||||
readDPList.Action.text = Read DP List
|
||||
readDPList.Action.shortDescription = Add DP List in Selected SIM Directory
|
||||
|
||||
openSelected.Action.text = Opentree
|
||||
openSelected.Action.shortDescription = Open Selected Tree Nodes
|
||||
|
||||
closeSelected.Action.text = Closetree
|
||||
closeSelected.Action.shortDescription = Close Selected Tree Nodes
|
||||
|
||||
removeSelectedNodes.Action.text = Remove
|
||||
removeSelectedNodes.Action.shortDescription = Remove Selected Node(s)
|
||||
|
||||
addDPs.Action.text = Add DPs
|
||||
addDPs.Action.shortDescription = Add Selected to DP List
|
||||
|
||||
## Popup Menu for list
|
||||
removeSelectedItems.Action.text = Remove
|
||||
removeSelectedItems.Action.shortDescription = Remove Selected List Item(s)
|
||||
|
||||
removeAllItems.Action.text = Remove All
|
||||
removeAllItems.Action.shortDescription = Remove All List Items
|
||||
|
||||
runSim.Action.text = Run Sim
|
||||
runSim.Action.shortDescription = Run Selected Sim
|
||||
|
||||
refreshSelected.Action.text = Refresh
|
||||
refreshSelected.Action.shortDescription = Refresh the Selected Nodes of the Tree
|
||||
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@ -0,0 +1,70 @@
|
||||
<?xml version='1.0' encoding='ISO-8859-1' ?>
|
||||
<!DOCTYPE helpset
|
||||
PUBLIC "-//Sun Microsystems Inc.//DTD JavaHelp HelpSet Version 2.0//EN"
|
||||
"http://java.sun.com/products/javahelp/helpset_2_0.dtd">
|
||||
|
||||
<helpset version="2.0">
|
||||
|
||||
<!-- title -->
|
||||
<title>Trick DP - Help</title>
|
||||
|
||||
<!-- maps -->
|
||||
<maps>
|
||||
<homeID>top</homeID>
|
||||
<mapref location="Map.jhm"/>
|
||||
</maps>
|
||||
|
||||
<!-- views -->
|
||||
<view>
|
||||
<name>TOC</name>
|
||||
<label>Table Of Contents</label>
|
||||
<type>javax.help.TOCView</type>
|
||||
<data>HelpTOC.xml</data>
|
||||
</view>
|
||||
|
||||
<!--view>
|
||||
<name>Index</name>
|
||||
<label>Index</label>
|
||||
<type>javax.help.IndexView</type>
|
||||
<data>HelpIndex.xml</data>
|
||||
</view-->
|
||||
|
||||
<view>
|
||||
<name>Search</name>
|
||||
<label>Search</label>
|
||||
<type>javax.help.SearchView</type>
|
||||
<data engine="com.sun.java.help.search.DefaultSearchEngine">
|
||||
JavaHelpSearch
|
||||
</data>
|
||||
</view>
|
||||
|
||||
<view>
|
||||
<name>Favorites</name>
|
||||
<label>Favorites</label>
|
||||
<type>javax.help.FavoritesView</type>
|
||||
</view>
|
||||
|
||||
<presentation default="true" displayviewimages="false">
|
||||
<name>main window</name>
|
||||
<size width="700" height="400" />
|
||||
<location x="200" y="200" />
|
||||
<title>Trick DP - Online Help</title>
|
||||
<image>trickicon</image>
|
||||
<toolbar>
|
||||
<helpaction>javax.help.BackAction</helpaction>
|
||||
<helpaction>javax.help.ForwardAction</helpaction>
|
||||
<helpaction>javax.help.SeparatorAction</helpaction>
|
||||
<helpaction>javax.help.HomeAction</helpaction>
|
||||
<helpaction>javax.help.ReloadAction</helpaction>
|
||||
<helpaction>javax.help.SeparatorAction</helpaction>
|
||||
<helpaction>javax.help.PrintAction</helpaction>
|
||||
<helpaction>javax.help.PrintSetupAction</helpaction>
|
||||
</toolbar>
|
||||
</presentation>
|
||||
<presentation>
|
||||
<name>main</name>
|
||||
<size width="400" height="400" />
|
||||
<location x="200" y="200" />
|
||||
<title>Trick DP - Online Help</title>
|
||||
</presentation>
|
||||
</helpset>
|
@ -0,0 +1,18 @@
|
||||
<?xml version='1.0' encoding='ISO-8859-1' ?>
|
||||
|
||||
<!DOCTYPE toc
|
||||
PUBLIC "-//Sun Microsystems Inc.//DTD JavaHelp TOC Version 2.0//EN"
|
||||
"http://java.sun.com/products/javahelp/toc_2_0.dtd">
|
||||
<toc version="2.0">
|
||||
<tocitem text="Trick DP" image="toplevelfolder">
|
||||
|
||||
<tocitem text="Introduction to Trick DP" target="trickdp.intro"/>
|
||||
<tocitem text="General Usage" target="trickdp.generalusage" />
|
||||
<tocitem text="How to Organize Data" target="trickdp.howtoorganize"/>
|
||||
<tocitem text="Importing Data" target="trickdp.importingdata"/>
|
||||
<tocitem text="Quickplot" target="trickdp.quickplot"/>
|
||||
<tocitem text="Using Gnuplot" target="trickdp.usinggnuplot"/>
|
||||
<tocitem text="FAQ" target="trickdp.faq"/>
|
||||
|
||||
</tocitem>
|
||||
</toc>
|