// ParameterDialog.java
package net.sf.gogui.gui;
import java.awt.Component;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import static java.lang.Math.max;
import java.text.MessageFormat;
import java.util.ArrayList;
import javax.swing.Box;
import javax.swing.JDialog;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import static javax.swing.JOptionPane.OK_CANCEL_OPTION;
import static javax.swing.JOptionPane.PLAIN_MESSAGE;
import static javax.swing.JOptionPane.UNINITIALIZED_VALUE;
import static javax.swing.JOptionPane.VALUE_PROPERTY;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import net.sf.gogui.gtp.AnalyzeUtil;
import net.sf.gogui.gtp.GtpError;
import net.sf.gogui.gtp.ParameterType;
import static net.sf.gogui.gui.GuiUtil.SMALL_PAD;
import static net.sf.gogui.gui.I18n.i18n;
import net.sf.gogui.util.ObjectUtil;
import net.sf.gogui.util.StringUtil;
/** Dialog for editing parameters in response to an analyze command of type
<i>param</i>. */
public class ParameterDialog
{
public static void editParameters(final String paramCommand, Frame owner,
String title, String response,
final GuiGtpClient gtp,
final MessageDialogs messageDialogs)
{
final ArrayList<Parameter> parameters = parseResponse(response);
Component mainComponent = createMainComponent(parameters);
final Object options[] = { i18n("LB_OK"), i18n("LB_CANCEL") };
final JOptionPane optionPane =
new JOptionPane(mainComponent, PLAIN_MESSAGE, OK_CANCEL_OPTION,
null, options, options[0]);
final JDialog dialog = new JDialog(owner, title, true);
dialog.setContentPane(optionPane);
optionPane.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent event) {
String prop = event.getPropertyName();
if (dialog.isVisible() && event.getSource() == optionPane
&& prop.equals(VALUE_PROPERTY))
{
Object value = optionPane.getValue();
if (ObjectUtil.equals(value, UNINITIALIZED_VALUE))
return;
if (ObjectUtil.equals(value, options[0]))
{
for (int i = 0; i < parameters.size(); ++i)
{
Parameter parameter = parameters.get(i);
if (! parameter.isChanged())
continue;
try
{
String command =
getNewValueCommand(paramCommand,
parameter);
gtp.send(command);
}
catch (GtpError e)
{
showError(dialog, messageDialogs,
parameter, e);
optionPane.setValue(UNINITIALIZED_VALUE);
return;
}
}
}
dialog.setVisible(false);
}
}
});
dialog.pack();
dialog.setLocationByPlatform(true);
dialog.addWindowListener(new WindowAdapter() {
public void windowOpened(WindowEvent e) {
// JDK 1.5 docs require to invoke selectInitialValue after
// the window is made visible
optionPane.selectInitialValue();
} });
dialog.setVisible(true);
}
/** Length of a textfield for editing string parameters. */
private static final int TEXTFIELD_LEN = 13;
private static final int MAX_PARAM_PER_COLUMN = 15;
private abstract static class Parameter
{
public Parameter(String key, String value)
{
m_key = key;
m_value = value;
m_label = StringUtil.capitalize(key.replace('_', ' '));
}
public String getKey()
{
return m_key;
}
public String getLabel()
{
return m_label;
}
public String getValue()
{
return m_value;
}
public abstract String getNewValue();
public abstract boolean isChanged();
public abstract void createComponents(int gridy, JPanel panel,
GridBagLayout gridbag);
private final String m_key;
private final String m_label;
private final String m_value;
}
private static class BoolParameter
extends Parameter
{
public BoolParameter(String key, String value)
{
super(key, value);
try
{
m_initialValue = (Integer.parseInt(value) != 0);
}
catch (NumberFormatException e)
{
m_initialValue = false;
}
}
public String getNewValue()
{
if (m_checkBox.isSelected())
return "1";
return "0";
}
public boolean isChanged()
{
return (m_checkBox.isSelected() != m_initialValue);
}
public void createComponents(int gridy, JPanel panel,
GridBagLayout gridbag)
{
m_checkBox = new JCheckBox(getLabel(), m_initialValue);
GridBagConstraints constraints = new GridBagConstraints();
constraints.gridx = 0;
constraints.gridy = gridy;
constraints.gridwidth = GridBagConstraints.REMAINDER;
constraints.weightx = 1.0;
constraints.anchor = GridBagConstraints.WEST;
gridbag.setConstraints(m_checkBox, constraints);
panel.add(m_checkBox);
}
private boolean m_initialValue;
private JCheckBox m_checkBox;
}
private static class ListParameter
extends Parameter
{
public ListParameter(String type, String key, String value)
{
super(key, value);
String[] args = type.split("/");
assert args[0].equals("list");
m_items = new String[args.length - 1];
m_labels = new String[args.length - 1];
int initialIndex = 0;
int maxLength = 0;
for (int i = 1; i < args.length; ++i)
{
String item = args[i];
if (item.equals(value))
initialIndex = i - 1;
maxLength = max(item.length(), maxLength);
m_items[i - 1] = item;
m_labels[i - 1] =
StringUtil.capitalize(item.replace('_', ' '));
}
m_initialIndex = initialIndex;
}
public String getNewValue()
{
return m_items[m_comboBox.getSelectedIndex()];
}
public boolean isChanged()
{
return (m_comboBox.getSelectedIndex() != m_initialIndex);
}
public void createComponents(int gridy, JPanel panel,
GridBagLayout gridbag)
{
JLabel label = new JLabel(getLabel() + ":");
GridBagConstraints constraints = new GridBagConstraints();
constraints.gridx = 0;
constraints.gridy = gridy;
constraints.weightx = 1.0;
constraints.ipadx = SMALL_PAD;
constraints.insets = new Insets(SMALL_PAD, 0, 0, 0);
constraints.anchor = GridBagConstraints.EAST;
gridbag.setConstraints(label, constraints);
panel.add(label);
m_comboBox = new JComboBox(m_labels);
m_comboBox.setSelectedIndex(m_initialIndex);
constraints = new GridBagConstraints();
constraints.gridx = 1;
constraints.gridy = gridy;
constraints.weightx = 1.0;
constraints.insets = new Insets(SMALL_PAD, 0, 0, 0);
constraints.anchor = GridBagConstraints.WEST;
gridbag.setConstraints(m_comboBox, constraints);
panel.add(m_comboBox);
}
private final int m_initialIndex;
private final String[] m_items;
private final String[] m_labels;
private JComboBox m_comboBox;
}
private static class StringParameter
extends Parameter
{
public StringParameter(String key, String value)
{
super(key, value);
}
public String getNewValue()
{
return m_textField.getText().trim();
}
public boolean isChanged()
{
return ! getNewValue().equals(getValue());
}
public void createComponents(int gridy, JPanel panel,
GridBagLayout gridbag)
{
JLabel label = new JLabel(getLabel() + ":");
GridBagConstraints constraints = new GridBagConstraints();
constraints.gridx = 0;
constraints.gridy = gridy;
constraints.weightx = 1.0;
constraints.ipadx = SMALL_PAD;
constraints.insets = new Insets(SMALL_PAD, 0, 0, 0);
constraints.anchor = GridBagConstraints.EAST;
gridbag.setConstraints(label, constraints);
panel.add(label);
m_textField = new JTextField(TEXTFIELD_LEN);
m_textField.setText(getValue());
constraints = new GridBagConstraints();
constraints.gridx = 1;
constraints.gridy = gridy;
constraints.weightx = 1.0;
constraints.insets = new Insets(SMALL_PAD, 0, 0, 0);
constraints.anchor = GridBagConstraints.WEST;
gridbag.setConstraints(m_textField, constraints);
panel.add(m_textField);
}
private JTextField m_textField;
}
private static ArrayList<Parameter> parseResponse(String response)
{
ArrayList<Parameter> parameters = new ArrayList<Parameter>();
BufferedReader reader =
new BufferedReader(new StringReader(response));
while (true)
{
String line = null;
try
{
line = reader.readLine();
}
catch (IOException e)
{
}
if (line == null)
break;
AnalyzeUtil.Result result = AnalyzeUtil.parseParameterLine(line);
if (result == null)
continue;
if (result.m_type == ParameterType.BOOL)
parameters.add(new BoolParameter(result.m_key,
result.m_value));
else if (result.m_type == ParameterType.LIST)
parameters.add(new ListParameter(result.m_typeInfo,
result.m_key,
result.m_value));
else
// Treat unknown types as string for compatibiliy with future
// types
parameters.add(new StringParameter(result.m_key,
result.m_value));
}
return parameters;
}
private static Component
createMainComponent(ArrayList<Parameter> parameters)
{
int numberParameters = parameters.size();
Box outerBox = Box.createHorizontalBox();
int i = 0;
int numberColumns = 0;
JPanel panel = null;
GridBagLayout gridbag = null;
int gridy = 0;
int paramPerColumn =
(numberParameters + 1)
/ (numberParameters / MAX_PARAM_PER_COLUMN + 1);
while (i < numberParameters)
{
if (i % paramPerColumn == 0)
{
if (panel != null)
{
if (numberColumns > 0)
{
outerBox.add(GuiUtil.createFiller());
outerBox.add(new JSeparator(SwingConstants.VERTICAL));
outerBox.add(GuiUtil.createFiller());
}
outerBox.add(panel);
++numberColumns;
}
gridbag = new GridBagLayout();
panel = new JPanel(gridbag);
gridy = 0;
}
parameters.get(i).createComponents(gridy, panel, gridbag);
++gridy;
++i;
}
if (panel != null)
{
if (numberColumns > 0)
{
outerBox.add(GuiUtil.createFiller());
outerBox.add(new JSeparator(SwingConstants.VERTICAL));
outerBox.add(GuiUtil.createFiller());
}
outerBox.add(panel);
}
return outerBox;
}
private static String getNewValueCommand(String paramCommand,
Parameter parameter)
{
String key = parameter.getKey();
String value = parameter.getNewValue();
return AnalyzeUtil.getParameterCommand(paramCommand, key, value);
}
private static void showError(JDialog owner, MessageDialogs messageDialogs,
Parameter parameter, GtpError e)
{
String mainMessage =
MessageFormat.format(i18n("MSG_PARAMDIALOG_COULD_NOT_CHANGE"),
parameter.getLabel());
String optionalMessage = StringUtil.capitalize(e.getMessage());
messageDialogs.showError(owner, mainMessage, optionalMessage);
}
}