/* ==============================================
* Simtools : The tools library used in JSynoptic
* ==============================================
*
* Project Info: http://jsynoptic.sourceforge.net/index.html
*
* This library is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* (C) Copyright 2003, by :
* Corporate:
* Astrium SAS
* EADS CRC
* Individual:
* Nicolas Brodu
*
* $Id: AutomatonActionMapper.java,v 1.5 2006/11/23 17:20:57 ogor Exp $
*
* Changes
* -------
* 28-Nov-03 : Creation (NB)
*
*/
package jsynoptic.builtin;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Iterator;
import java.util.ResourceBundle;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.ButtonGroup;
import javax.swing.DefaultCellEditor;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JColorChooser;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.TableCellRenderer;
import simtools.ui.ActionRadioButton;
import simtools.ui.CustomizedLocale;
import simtools.ui.GenericMapper;
import simtools.ui.NumberField;
import simtools.ui.ResourceFinder;
/**
* This class maps data sources and index to images.
* The mapping is user defined, and based for example on the value of the data source
* For example, green value < 10, red above. Useful for making plots with "alarm" colors
*
* The data source shall not be saved into the object. Rather, this class goal is to implement
* a mapping independent of the data source given.
* The same is true for the images
*
*/
public class AutomatonActionMapper extends GenericMapper {
static final long serialVersionUID = -2604553969207409594L;
public static ResourceBundle resources = ResourceFinder.get(AutomatonActionMapper.class);
public AutomatonActionMapper() {
super();
}
public AutomatonActionMapper(String name) {
super(name);
}
/*
* The editor button that brings up the dialog.
* We extend DefaultCellEditor for convenience,
* even though it mean we have to create a dummy
* check box. Another approach would be to copy
* the implementation of TableCellEditor methods
* from the source code for DefaultCellEditor.
*/
protected static class AutomatonActionEditor extends DefaultCellEditor {
public AutomatonActionList currentActions;
public AutomatonActionEditor(JButton b) {
super(new JCheckBox()); //Unfortunately, the constructor
//expects a check box, combo box,
//or text field.
editorComponent = b;
setClickCountToStart(2); //This is usually 1 or 2.
//Must do this so that editing stops when appropriate.
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
fireEditingStopped();
}
});
}
protected void fireEditingStopped() {
super.fireEditingStopped();
}
public Object getCellEditorValue() {
return currentActions;
}
public Component getTableCellEditorComponent(JTable table,
Object value,
boolean isSelected,
int row,
int column) {
((JButton)editorComponent).setText(value.toString());
currentActions = (AutomatonActionList)value;
return editorComponent;
}
public Panel createPanel() {
return new Panel();
}
public class Panel extends JPanel {
JTextField tfName;
JComboBox cbxAction;
private JComboBox cbxformat;
private JTextField tfFixedText;
private ActionRadioButton rbFixedText;
private JRadioButton rbUseSource;
private JLabel lformatdigits;
AutomatonActionList actionList;
private NumberField nfformat;
AutomatonAction currentAction;
private JRadioButton rbWrap;
private JRadioButton rbExtend;
private JRadioButton rbDoNothing;
private JButton bchoosecolor;
private DefaultListModel listModel;
private JButton bMoveBefore;
private JButton bMoveAfter;
private JButton bRemove;
private JButton bAdd;
private JPanel optionPanel;
private JList list;
protected Color lastColor = Color.red;
protected Integer lastMoveOp = AutomatonAction.OPTION_DO_NOTHING;
protected String lastString = resources.getString("LoremIpsum");
protected boolean inAction = false;
public void setActionProperties() {
// No re-entry to avoid problems, not synchronized because not necessary
if (inAction) return;
inAction = true;
CardLayout cl = (CardLayout)(optionPanel.getLayout());
switch (currentAction.action) {
case AutomatonAction.MOVE_UP:
case AutomatonAction.MOVE_RIGHT:
case AutomatonAction.MOVE_DOWN:
case AutomatonAction.MOVE_LEFT:
cl.show(optionPanel, "move");
if ((currentAction.option==null) || (!(currentAction.option instanceof Integer)))
currentAction.option = lastMoveOp;
lastMoveOp = (Integer)currentAction.option;
if (currentAction.option.equals(AutomatonAction.OPTION_WRAP)) {
rbWrap.setSelected(true);
}
else if (currentAction.option.equals(AutomatonAction.OPTION_EXTEND)) {
rbExtend.setSelected(true);
}
else rbDoNothing.setSelected(true);
break;
case AutomatonAction.SET_BACKGROUND_COLOR:
case AutomatonAction.SET_FRAME_COLOR:
case AutomatonAction.SET_TEXT_COLOR:
cl.show(optionPanel, "color");
if ((currentAction.option==null) || (!(currentAction.option instanceof Color)))
currentAction.option = lastColor;
lastColor = (Color)currentAction.option;
bchoosecolor.setBackground(lastColor);
break;
case AutomatonAction.SET_TEXT:
if ((currentAction.option==null) || (!(currentAction.option instanceof Object[])) || (((Object[])currentAction.option).length==0) || (!(((Object[])currentAction.option)[0] instanceof Integer)) ) {
currentAction.option = new Object[] {new Integer(0)};
}
int format = ((Integer)((Object[])currentAction.option)[0]).intValue();
if (format==6) {
if ((((Object[])currentAction.option).length<2) || (!(((Object[])currentAction.option)[1] instanceof String))) {
currentAction.option = new Object[] { ((Object[])currentAction.option)[6], lastString };
}
lastString = (String)((Object[])currentAction.option)[1];
rbFixedText.setSelected(true);
if (!tfFixedText.getText().equals(lastString) )
tfFixedText.setText(lastString);
tfFixedText.setEnabled(true);
cbxformat.setEnabled(false);
nfformat.setEnabled(false);
lformatdigits.setEnabled(false);
} else {
rbUseSource.setSelected(true);
tfFixedText.setEnabled(false);
cbxformat.setEnabled(true);
cbxformat.setSelectedIndex(format);
if ((format==1) || (format==2)) {
if ((((Object[])currentAction.option).length<2) || (!(((Object[])currentAction.option)[1] instanceof NumberFormat))) {
currentAction.option = new Object[] { ((Object[])currentAction.option)[0], NumberFormat.getNumberInstance(CustomizedLocale.get()) };
if ((format==2) && (((Object[])currentAction.option)[1] instanceof DecimalFormat)) {
((DecimalFormat)((Object[])currentAction.option)[1]).applyPattern("0.000E0");
}
}
nfformat.setEnabled(true);
lformatdigits.setEnabled(true);
if (((Object[])currentAction.option)[1] instanceof DecimalFormat) {
DecimalFormat df = ((DecimalFormat)((Object[])currentAction.option)[1]);
if (format==1) nfformat.setValue(df.getMaximumFractionDigits());
else {
String pattern = df.toPattern();
int l =0;
l = pattern.indexOf('E') - pattern.indexOf('.');
if (l>0) l--; // number of characters between . and E
nfformat.setValue(l);
}
}
} else {
nfformat.setEnabled(false);
lformatdigits.setEnabled(false);
}
}
cl.show(optionPanel, "text");
break;
}
cbxAction.setSelectedIndex(currentAction.action);
if (list!=null) list.repaint();
inAction = false;
}
public Panel() {
// Create our own copy to work on
actionList = (AutomatonActionList)currentActions.clone();
if (actionList.size()>0) currentAction = actionList.getAction(0);
else currentAction = createNewAction();
setLayout(new BorderLayout());
Box box = Box.createHorizontalBox();
box.add(new JLabel(resources.getString("Name")));
box.add(Box.createHorizontalGlue());
box.add(tfName = new JTextField(actionList.getName()));
add(box, BorderLayout.NORTH);
Box definitionBox = Box.createHorizontalBox();
Box actionBox = Box.createVerticalBox();
actionBox.setBorder(BorderFactory.createTitledBorder(resources.getString("ActionDefinition")));
actionBox.add(cbxAction = new JComboBox());
for (int i=0; i<AutomatonAction.NUMBER_OF_POSSIBLE_ACTIONS; ++i) {
cbxAction.addItem(AutomatonAction.toString(i));
}
cbxAction.setEditable(false);
cbxAction.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
currentAction.action = cbxAction.getSelectedIndex();
setActionProperties();
}
});
optionPanel = new JPanel(new CardLayout());
// ---------- Text options -----------
Box options = Box.createVerticalBox();
options.add(Box.createVerticalGlue());
box = Box.createHorizontalBox();
box.add(rbFixedText = new ActionRadioButton(resources.getString("FixedText")) {
public void stateChanged(ChangeEvent e) {
if (rbFixedText.isSelected()) currentAction.option = new Object[] {new Integer(6), tfFixedText.getText()};
else currentAction.option = new Object[] {new Integer(cbxformat.getSelectedIndex())};
setActionProperties();
}
});
box.add(Box.createHorizontalGlue());
box.add(tfFixedText = new JTextField());
tfFixedText.getDocument().addDocumentListener(new DocumentListener() {
public void insertUpdate(DocumentEvent e) {
currentAction.option = new Object[] {new Integer(6), tfFixedText.getText()};
setActionProperties();
}
public void removeUpdate(DocumentEvent e) {
currentAction.option = new Object[] {new Integer(6), tfFixedText.getText()};
setActionProperties();
}
public void changedUpdate(DocumentEvent e) {
currentAction.option = new Object[] {new Integer(6), tfFixedText.getText()};
setActionProperties();
}
});
options.add(box);
box = Box.createHorizontalBox();
box.add(rbUseSource = new JRadioButton(resources.getString("UseDataSourceValueAs")));
box.add(Box.createHorizontalGlue());
box.add(cbxformat = new JComboBox());
cbxformat.addItem(resources.getString("String"));
cbxformat.addItem(resources.getString("Decimal"));
cbxformat.addItem(resources.getString("Scientific"));
cbxformat.addItem(resources.getString("Hexadecimal"));
cbxformat.addItem(resources.getString("Octal"));
cbxformat.addItem(resources.getString("Binary"));
cbxformat.setEditable(false);
options.add(box);
ButtonGroup bg = new ButtonGroup();
bg.add(rbFixedText);
bg.add(rbUseSource);
box = Box.createHorizontalBox();
box.add(lformatdigits = new JLabel(resources.getString("DecimalDigits")));
box.add(Box.createHorizontalGlue());
box.add(nfformat = new NumberField(3,3));
nfformat.setColumns(3);
nfformat.setHorizontalAlignment(JTextField.RIGHT);
cbxformat.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
currentAction.option = new Object[] { new Integer(cbxformat.getSelectedIndex()) };
setActionProperties();
}
});
options.add(box);
JPanel textOptions = new JPanel(new BorderLayout());
textOptions.add(options, BorderLayout.NORTH);
optionPanel.add(textOptions, "text");
// ---------- Move options -----------
options = Box.createVerticalBox();
options.add(Box.createVerticalGlue());
Box descPanel = Box.createHorizontalBox();
descPanel.add(new JLabel(resources.getString("WhenReachingAnArrayEdge")));
descPanel.add(Box.createHorizontalGlue());
options.add(descPanel);
descPanel = Box.createHorizontalBox();
descPanel.add(rbDoNothing = new JRadioButton(resources.getString("DoNothing")));
descPanel.add(Box.createHorizontalGlue());
options.add(descPanel);
descPanel = Box.createHorizontalBox();
descPanel.add(rbWrap = new JRadioButton(resources.getString("WrapToOtherSide")));
descPanel.add(Box.createHorizontalGlue());
options.add(descPanel);
descPanel = Box.createHorizontalBox();
descPanel.add(rbExtend = new JRadioButton(resources.getString("ExtendArray")));
descPanel.add(Box.createHorizontalGlue());
options.add(descPanel);
options.add(Box.createVerticalGlue());
rbDoNothing.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
if (rbDoNothing.isSelected()) {
currentAction.option = AutomatonAction.OPTION_DO_NOTHING;
setActionProperties();
}
}
});
rbWrap.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
if (rbWrap.isSelected()) {
currentAction.option = AutomatonAction.OPTION_WRAP;
setActionProperties();
}
}
});
rbExtend.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
if (rbExtend.isSelected()) {
currentAction.option = AutomatonAction.OPTION_EXTEND;
setActionProperties();
}
}
});
bg = new ButtonGroup();
bg.add(rbDoNothing);
bg.add(rbWrap);
bg.add(rbExtend);
JPanel moveOptions = new JPanel(new BorderLayout());
moveOptions.add(options, BorderLayout.CENTER);
optionPanel.add(moveOptions, "move");
// ---------- Color options -----------
box = Box.createHorizontalBox();
box.add(new JLabel(resources.getString("ChooseColor")));
box.add(Box.createHorizontalGlue());
box.add(bchoosecolor = new JButton(" "));
bchoosecolor.setFocusPainted(false);
JPanel colorOptions = new JPanel(new BorderLayout());
colorOptions.add(box, BorderLayout.CENTER);
optionPanel.add(colorOptions, "color");
setActionProperties();
actionBox.add(optionPanel);
definitionBox.add(actionBox);
bchoosecolor.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Color c = JColorChooser.showDialog(bchoosecolor, resources.getString("ChooseColor"),bchoosecolor.getBackground());
if (c!=null) {
currentAction.option = c;
setActionProperties();
}
}
});
// Now define the action list
JPanel listPanel = new JPanel(new BorderLayout());
listPanel.setBorder(BorderFactory.createTitledBorder(resources.getString("ActionList")));
listModel = new DefaultListModel();
for (Iterator it = actionList.iterator(); it.hasNext(); ) listModel.addElement(it.next());
list = new JList(listModel);
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
listPanel.add(new JScrollPane(list), BorderLayout.CENTER);
definitionBox.add(listPanel);
if (listModel.size()>0) list.setSelectedIndex(0);
// Set the buttons
box = Box.createVerticalBox();
box.add(Box.createVerticalGlue());
JPanel buttonGrid = new JPanel(new GridLayout(4,1));
buttonGrid.add(bAdd = new JButton(resources.getString("Add")));
buttonGrid.add(bRemove = new JButton(resources.getString("Remove")));
buttonGrid.add(bMoveBefore = new JButton(resources.getString("MoveBefore")));
buttonGrid.add(bMoveAfter = new JButton(resources.getString("MoveAfter")));
box.add(buttonGrid);
box.add(Box.createVerticalGlue());
definitionBox.add(box);
add(definitionBox, BorderLayout.CENTER);
setListButtonState();
list.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
int sel = list.getSelectedIndex();
if (sel==-1) currentAction = createNewAction();
else currentAction = actionList.getAction(list.getSelectedIndex());
setListButtonState();
setActionProperties();
}
});
bAdd.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
AutomatonAction action;
if (listModel.contains(currentAction)) action = createNewAction();
else action = currentAction;
listModel.addElement(action);
actionList.add(action);
list.setSelectedValue(action,true);
setListButtonState();
}
});
bRemove.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int sel = list.getSelectedIndex();
if (sel==-1) return;
listModel.remove(sel);
actionList.remove(sel);
if (sel<listModel.size()) {
list.setSelectedIndex(sel);
currentAction = actionList.getAction(sel);
} else {
list.setSelectedIndex(-1);
currentAction = createNewAction();
}
setListButtonState();
setActionProperties();
}
});
bMoveBefore.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int sel = list.getSelectedIndex();
if (sel<=0) return; // should not happen, button disabled.
// Exchange elements
Object tmp = actionList.get(sel);
actionList.set(sel, actionList.get(sel-1));
actionList.set(sel-1, tmp);
listModel.clear(); // warning: listeners side effect forces clear() instead of exchange
for (Iterator it = actionList.iterator(); it.hasNext(); ) listModel.addElement(it.next());
list.setSelectedIndex(sel-1);
setListButtonState();
}
});
bMoveAfter.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int sel = list.getSelectedIndex();
if ((sel<0) || (sel>=listModel.size()-1)) return; // should not happen, button disabled.
// Exchange elements
Object tmp = actionList.get(sel);
actionList.set(sel, actionList.get(sel+1));
actionList.set(sel+1, tmp);
listModel.clear(); // warning: listeners side effect forces clear() instead of exchange
for (Iterator it = actionList.iterator(); it.hasNext(); ) listModel.addElement(it.next());
list.setSelectedIndex(sel+1);
setListButtonState();
}
});
}
void setListButtonState() {
int sel = list.getSelectedIndex();
bMoveBefore.setEnabled(sel>0);
bMoveAfter.setEnabled((sel>=0) && (sel<listModel.size()-1));
bRemove.setEnabled(sel!=-1);
}
void updateProperties() {
actionList.setName(tfName.getText());
currentActions = actionList;
}
}
}
protected static class AutomatonActionRenderer extends JLabel
implements TableCellRenderer {
public Component getTableCellRendererComponent(
JTable table, Object o,
boolean isSelected, boolean hasFocus,
int row, int column) {
setText(o==null ? resources.getString("NoAction") : o.toString());
return this;
}
}
public MapperTableModel createModel() {
return new AutomatonActionMapperTableModel();
}
protected class AutomatonActionMappingTable extends ExpressionMappingTable {
/**
* @param dialog
*/
public AutomatonActionMappingTable(JDialog owner) {
super(owner);
setPreferredScrollableViewportSize(new Dimension(300, 150));
getColumnModel().getColumn(0).setPreferredWidth(100);
getColumnModel().getColumn(1).setPreferredWidth(200);
}
/** Sets up the renderer to a color renderer
* @see simtools.ui.GenericMapper.ExpressionMappingTable#setUpRenderer()
*/
protected void setUpRenderer() {
setDefaultRenderer(AutomatonAction.class,new AutomatonActionRenderer());
}
/** Sets up the editor to a color editor
* @see simtools.ui.GenericMapper.ExpressionMappingTable#setUpEditor()
*/
protected void setUpEditor() {
//First, set up the button that brings up the dialog.
final JButton button = new JButton("");
//Now create an editor to encapsulate the button, and
//set it up as the editor for all Color cells.
final AutomatonActionEditor actionEditor = new AutomatonActionEditor(button);
setDefaultEditor(AutomatonAction.class, actionEditor);
//Here's the code that brings up the dialog.
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//Set up the action dialog
AutomatonActionEditor.Panel panel = actionEditor.createPanel();
int result = JOptionPane.showConfirmDialog(null, panel,
resources.getString("Properties"), JOptionPane.OK_CANCEL_OPTION,
JOptionPane.PLAIN_MESSAGE);
if (result == JOptionPane.OK_OPTION) {
panel.updateProperties();
}
}
});
}
}
public static AutomatonAction createNewAction() {
return new AutomatonAction(AutomatonAction.SET_BACKGROUND_COLOR, Color.red);
}
protected class AutomatonActionMapperTableModel extends MapperTableModel {
public Class getColumnClass(int c) {
if (c==1) return AutomatonAction.class;
return super.getColumnClass(c);
}
public String getColumnName(int col) {
if (col==1) return resources.getString("Actions");
return super.getColumnName(col);
}
public boolean isCellEditable(int row, int col) {
if (col==1) return true;
return super.isCellEditable(row, col);
}
}
protected ExpressionMappingTable createTable(JDialog parent) {
return new AutomatonActionMappingTable(parent);
}
protected Object createNewValue() {
AutomatonActionList ret = new AutomatonActionList(resources.getString("RedBackground"));
ret.add(createNewAction());
return ret;
}
public static void main(String[] args) {
// GenericMapper cm = new GenericMapper();
AutomatonActionMapper cm = new AutomatonActionMapper();
cm.editDialog(null);
System.exit(0);
}
}