/* ========================
* JSynoptic : a free Synoptic editor
* ========================
*
* Project Info: http://jsynoptic.sourceforge.net/index.html
*
* This program is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* (C) Copyright 2001-2003, by :
* Corporate:
* Astrium SAS
* EADS CRC
* Individual:
* Nicolas Brodu
*
* $Id: ExpressionPanel.java,v 1.5 2008/07/22 10:25:36 ogor Exp $
*
* Changes
* -------
* 20-Jan-2004 : Creation date (NB);
*
*/
package jsynoptic.ui;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Collection;
import java.util.Iterator;
import java.util.ResourceBundle;
import java.util.Set;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import jsynoptic.base.Plugin;
import jsynoptic.data.ExpressionDataSource;
import jsynoptic.data.VariableAssociation;
import jsynoptic.parser.ExpressionNode;
import jsynoptic.parser.ExpressionParser;
import jsynoptic.parser.ParseException;
import simtools.data.DataInfo;
import simtools.data.DataSource;
import simtools.data.DataSourcePool;
import simtools.ui.GridBagPanel;
import simtools.ui.ResourceFinder;
import simtools.ui.SourceTree;
/**
* @author nbrodu
*
* To change the template for this generated type comment go to
* Window - Preferences - Java - Code Generation - Code and Comments
*/
public class ExpressionPanel extends GridBagPanel {
protected JTextField tfNewSourceName, tfExpression;
protected JButton addExp;//, delExp;
protected JComboBox cbxPredefined;
public static ResourceBundle resources = ResourceFinder.get(ExpressionPanel.class);
protected SourceTree sourceTree;
protected JTabbedPane tabbedPane;
/**
*
*/
public ExpressionPanel(SourceTree sourceTree) {
super(resources.getString("computedSources"));
this.sourceTree = sourceTree;
addOnCurrentRow(new JLabel(resources.getString("nameOfComputedSource")));
addOnCurrentRow(tfNewSourceName = new JTextField(), 4, true, false, true);
tabbedPane = new JTabbedPane(JTabbedPane.TOP, JTabbedPane.SCROLL_TAB_LAYOUT);
GridBagPanel predefinedSources = new GridBagPanel();
predefinedSources.addOnCurrentRow(cbxPredefined = new JComboBox(), 5, true, false, true);
tabbedPane.add(predefinedSources, resources.getString("predefinedSources"));
GridBagPanel mathExpression= new GridBagPanel();
mathExpression.addOnCurrentRow(tfExpression = new JTextField(), 5, true, false, true);
tabbedPane.add(mathExpression, resources.getString("mathExpression"));
tabbedPane.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
switch(tabbedPane.getSelectedIndex()) {
case 0:
addExp.setText(resources.getString("addTemplate"));
break;
case 1:
addExp.setText(resources.getString("addExp"));
break;
default:
}
updateAddExpState();
}
});
addOnCurrentRow(tabbedPane, 5, true, false, true);
addOnCurrentRow(addExp = new JButton(resources.getString("addTemplate")),2);
// get the source templates from the plugins
for (Iterator it = Run.plugins.iterator(); it.hasNext();) {
Plugin p = (Plugin)it.next();
if (p==null) continue;
String[] templates = p.getSources();
if (templates==null) continue;
for (int i=0; i<templates.length; ++i) {
// Insert at the right place
int j=0;
for (; j<cbxPredefined.getItemCount(); ++j) {
if (cbxPredefined.getItemAt(j).toString().compareTo(templates[i])>0) break;
}
cbxPredefined.insertItemAt(new SourceTemplate(templates[i],p),j);
}
}
if (cbxPredefined.getItemCount()>0) cbxPredefined.setSelectedIndex(0);
// When user validates the expression (press enter), call add/modify button
tfExpression.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (addExp.isEnabled()) addExp.doClick();
}
});
addExp.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String name = tfNewSourceName.getText();
if (tabbedPane.getSelectedIndex()==-1) return; // shall not happen
// Check for use of template
if (tabbedPane.getSelectedIndex()==0) {
Object o = cbxPredefined.getSelectedItem();
if (o==null) return;
if (!(o instanceof SourceTemplate)) return;
SourceTemplate t = (SourceTemplate)o;
// Ask the plugin to create the source
DataSource ds = t.plugin.createSource(t.template, name);
if (ds==null) return;
// Add the source to the panel
DataSourcePool.global.addDataSource(ds);
ExpressionPanel.this.sourceTree.setSelectedValue(ds);
return;
}
String exp = tfExpression.getText();
if ((name == null) || name.equals("")) {
JOptionPane.showMessageDialog(JSynoptic.gui.getOwner(),resources.getString("PleaseEnterNewSourceName"),resources.getString("Error"),JOptionPane.ERROR_MESSAGE);
return;
}
if ((exp == null) || exp.equals("")) {
JOptionPane.showMessageDialog(JSynoptic.gui.getOwner(),resources.getString("PleaseEnterAMathematicalExpression"),resources.getString("Error"),JOptionPane.ERROR_MESSAGE);
return;
}
ExpressionNode node = null;
try {
ExpressionParser ep = new ExpressionParser(exp);
// Add the data sources as variables
// start by looping through collections
Set collections = DataSourcePool.global.dataSourceCollections();
for (Iterator it = collections.iterator(); it.hasNext(); ) {
Collection c = (Collection)it.next();
for (Iterator it2 = c.iterator(); it2.hasNext();) addVariable(ep, it2.next());
}
// also add sources
Set sources = DataSourcePool.global.dataSources();
for (Iterator it = sources.iterator(); it.hasNext();) addVariable(ep, it.next());
// Add known plugins => may bring in more mathematical functions
for (Iterator it = Run.plugins.iterator(); it.hasNext();) ep.addClass(it.next().getClass());
node = ep.parse();
} catch (ParseException pe) {
// Also catches duplicate variable names
JOptionPane.showMessageDialog(JSynoptic.gui.getOwner(),pe.getLocalizedMessage(),resources.getString("InvalidExpression"),JOptionPane.ERROR_MESSAGE);
return;
} catch (Error err) {
JOptionPane.showMessageDialog(JSynoptic.gui.getOwner(),err.getLocalizedMessage(),resources.getString("InvalidExpression"),JOptionPane.ERROR_MESSAGE);
return;
}
// Now we have a correct node, ready to evaluate()
// Create a data source
boolean newSource = true;
// Check if the source exists, and in this case change the expression on the fly
for (Iterator it = DataSourcePool.global.dataSources().iterator(); it.hasNext(); ) {
Object o = it.next();
if (!(o instanceof ExpressionDataSource)) continue;
ExpressionDataSource ds = (ExpressionDataSource)o;
if (name.equals(DataInfo.getLabel(ds)) || name.equals(DataInfo.getAlias(ds))) {
ds.changeExpression(exp, node);
newSource = false;
ExpressionPanel.this.sourceTree.setSelectedValue(ds);
TreeNode tn = (TreeNode)(ExpressionPanel.this.sourceTree.getSelectionPath().getLastPathComponent());
((DefaultTreeModel)(ExpressionPanel.this.sourceTree.getModel())).nodeChanged(tn);
break;
}
}
if (newSource) {
ExpressionDataSource eds = new ExpressionDataSource(new DataInfo(name, name, exp), node);
DataSourcePool.global.addDataSource(eds);
ExpressionPanel.this.sourceTree.setSelectedValue(eds);
}
}
private void addVariable(ExpressionParser ep, Object object) {
if (object==null) return;
if (!(object instanceof DataSource)) return;
String alias = DataInfo.getAlias(object);
if (alias!=null) ep.addVariable(new VariableAssociation((DataSource)object, alias));
else ep.addVariable(new VariableAssociation((DataSource)object, DataInfo.getLabel(object)));
}
});
/* delExp.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Object o = ExpressionPanel.this.sourceTree.getSelectedSourceOrCollection();
if ((o==null) || (!(o instanceof ExpressionDataSource))) {
JOptionPane.showMessageDialog(JSynoptic.gui,resources.getString("PleaseSelectAnExpression"),resources.getString("CannotRemoveExpression"),JOptionPane.ERROR_MESSAGE);
return;
}
DataSourcePool.global.removeDataSource((ExpressionDataSource)o);
}
});
*/
// Now set the correct button states
sourceTree.addTreeSelectionListener(new TreeSelectionListener() {
public void valueChanged(TreeSelectionEvent e) {
Object o = ExpressionPanel.this.sourceTree.getSelectedSourceOrCollection();
if ((o!=null) && (o instanceof ExpressionDataSource)) {
//delExp.setEnabled(true);
tfNewSourceName.setText(DataInfo.getLabel(o));
tfExpression.setText(DataInfo.getComment(o));
tabbedPane.setSelectedIndex(1);
}
else {
tfNewSourceName.setText("");
tfExpression.setText("");
//delExp.setEnabled(false);
}
}
});
//delExp.setEnabled(false); // wait for a selection in the source tree
tfNewSourceName.getDocument().addDocumentListener(new DocumentListener() {
public void changedUpdate(DocumentEvent e) {
updateAddExpState();
}
public void insertUpdate(DocumentEvent e) {
updateAddExpState();
}
public void removeUpdate(DocumentEvent e) {
updateAddExpState();
}
} );
tfExpression.getDocument().addDocumentListener(new DocumentListener() {
public void changedUpdate(DocumentEvent e) {
updateAddExpState();
}
public void insertUpdate(DocumentEvent e) {
updateAddExpState();
}
public void removeUpdate(DocumentEvent e) {
updateAddExpState();
}
} );
updateAddExpState();
}
/**
*
*/
protected void updateAddExpState() {
String name = tfNewSourceName.getText();
String exp = tfExpression.getText();
if ((name == null) || name.equals("")) {
addExp.setEnabled(false);
return;
}
if (tabbedPane.getSelectedIndex()==0) {
addExp.setEnabled(true);
return;
}
if ((exp == null) || exp.equals("")) {
addExp.setEnabled(false);
return;
}
addExp.setEnabled(true);
}
protected static class SourceTemplate {
public String template;
public Plugin plugin;
public String toString() {
return template;
}
public SourceTemplate(String template, Plugin plugin) {
this.template = template;
this.plugin = plugin;
}
}
}