/*
* mongobrowser - a webstart gui application for viewing,
* editing and administering a Mongo Database
* Copyright 2009-2011 MeBigFatGuy.com
* Copyright 2009-2011 Dave Brosius
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations
* under the License.
*/
package com.mebigfatguy.mongobrowser.dialogs;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
import com.mebigfatguy.mongobrowser.MongoBundle;
import com.mebigfatguy.mongobrowser.SwingUtils;
import com.mebigfatguy.pickcal.PickCalDialog;
import com.mongodb.BasicDBObject;
/**
* a dialog for collecting key/value pairs for a mongo object property
*/
public class KeyValueDialog extends JDialog {
private static final long serialVersionUID = 4909101478144542212L;
private JTextField keyField;
private JComboBox valueTypeBox;
private JTextField valueField;
private JButton okButton;
private JButton cancelButton;
private final DateMouseListener dateMouseListener;
private boolean ok = false;
/**
* constructs a dialog to collect a key value for a mongo object's property
*/
public KeyValueDialog() {
this(null, null);
}
/**
* constructs a dialog to collect a key value for a mongo object's property
*/
public KeyValueDialog(String key, Object value) {
setTitle(MongoBundle.getString(MongoBundle.Key.NewKeyValue));
initComponents();
initListeners();
dateMouseListener = new DateMouseListener();
if (key != null) {
keyField.setText(key);
keyField.setEnabled(false);
installValue(value);
}
pack();
}
/**
* adds and lays out the components in the dialog
*/
private void initComponents() {
Container cp = getContentPane();
cp.setLayout(new BorderLayout(4, 4));
cp.add(createFormPanel(), BorderLayout.CENTER);
cp.add(createCtrlPanel(), BorderLayout.SOUTH);
}
/**
* creates the panel for collecting the key and value
*
* @return a panel holding the input fields
*/
private JPanel createFormPanel() {
JPanel p = new JPanel();
p.setLayout(new FormLayout("6dlu, pref, 5dlu, 200px, 5dlu, pref, 6dlu", "6dlu, pref, 2dlu, pref, 6dlu"));
CellConstraints cc = new CellConstraints();
JLabel keyLabel = new JLabel(MongoBundle.getString(MongoBundle.Key.Key));
p.add(keyLabel, cc.xy(2, 2));
keyField = new JTextField();
p.add(keyField, cc.xy(4, 2));
keyLabel.setLabelFor(keyField);
JLabel valueLabel = new JLabel(MongoBundle.getString(MongoBundle.Key.Value));
p.add(valueLabel, cc.xy(2, 4));
valueField = new JTextField();
p.add(valueField, cc.xy(4, 4));
valueTypeBox = new JComboBox();
DefaultComboBoxModel model = (DefaultComboBoxModel) valueTypeBox.getModel();
model.addElement(new IntegerValueType());
model.addElement(new DoubleValueType());
model.addElement(new FloatValueType());
model.addElement(new StringValueType());
model.addElement(new DateValueType());
model.addElement(new ObjectValueType());
valueTypeBox.setSelectedIndex(3);
p.add(valueTypeBox, cc.xy(6, 4));
valueLabel.setLabelFor(valueField);
return p;
}
/**
* creates a panel holding the ok and cancel buttons
*
* @return the ok/cancel button panel
*/
private JPanel createCtrlPanel() {
JPanel p = new JPanel();
p.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0));
p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
p.add(Box.createHorizontalGlue());
okButton = new JButton(MongoBundle.getString(MongoBundle.Key.OK));
p.add(okButton);
p.add(Box.createHorizontalStrut(10));
cancelButton = new JButton(MongoBundle.getString(MongoBundle.Key.Cancel));
p.add(cancelButton);
p.add(Box.createHorizontalStrut(10));
SwingUtils.sizeUniformly(okButton, cancelButton);
return p;
}
/**
* installs the listeners
*/
private void initListeners() {
okButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent ae) {
ok = true;
dispose();
}
});
cancelButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent ae) {
dispose();
}
});
valueTypeBox.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent ie) {
if (ie.getStateChange() == ItemEvent.SELECTED) {
ValueType vt = (ValueType) ie.getItem();
vt.installDocument(valueField);
if (vt instanceof DateValueType) {
valueField.setEditable(false);
valueField.addMouseListener(dateMouseListener);
} else {
valueField.setEditable(true);
valueField.removeMouseListener(dateMouseListener);
}
}
}
});
getRootPane().setDefaultButton(okButton);
}
/**
* did the user click ok
*
* @return if the user clicked ok
*/
public boolean isOK() {
return ok;
}
/**
* gets the key value from the form
*
* @return the key value
*/
public String getKey() {
return keyField.getText();
}
/**
* gets the typed value from the dialog
*
* @return the typed value
*/
public Object getValue() {
return ((ValueType) valueTypeBox.getSelectedItem()).getValue(valueField);
}
/**
* updates the key value dialog based on the value, this is kind of crufty,
* would be nicer to handle the popup a better way
*
* @param value
* the value to set
*/
private void installValue(Object value) {
if (value != null) {
DefaultComboBoxModel model = (DefaultComboBoxModel) valueTypeBox.getModel();
if (value instanceof Integer) {
valueTypeBox.setSelectedIndex(0);
ValueType vt = (ValueType) model.getElementAt(0);
vt.installDocument(valueField);
valueField.setText(String.valueOf(value));
} else if (value instanceof Double) {
valueTypeBox.setSelectedIndex(1);
ValueType vt = (ValueType) model.getElementAt(1);
vt.installDocument(valueField);
valueField.setText(String.valueOf(value));
} else if (value instanceof Float) {
valueTypeBox.setSelectedIndex(2);
ValueType vt = (ValueType) model.getElementAt(2);
vt.installDocument(valueField);
valueField.setText(String.valueOf(value));
} else if (value instanceof String) {
valueTypeBox.setSelectedIndex(3);
ValueType vt = (ValueType) model.getElementAt(3);
vt.installDocument(valueField);
valueField.setText((String) value);
} else if (value instanceof Date) {
valueTypeBox.setSelectedIndex(4);
ValueType vt = (ValueType) model.getElementAt(4);
vt.installDocument(valueField);
valueField.setEditable(false);
SimpleDateFormat sdf = new SimpleDateFormat(MongoBundle.getString(MongoBundle.Key.DateFormat));
valueField.setText(sdf.format((Date) value));
}
}
}
/**
* interface for items that are put into the Value type combobox
*/
interface ValueType {
/**
* switch the JTextField's model based on the type of value
*
* @param field
* the component who's document should be modified
*/
void installDocument(JTextField field);
/**
* get the value object of the field, based on the type of this value
*
* @param field
* the component to get the value from
* @return a value object
*/
Object getValue(JTextField field);
}
/**
* a value type representing an Integer object
*/
static class IntegerValueType implements ValueType {
/**
* installs an IntegerDocument as the field's model
*
* @param field
* the text edit field to install the model
*/
@Override
public void installDocument(JTextField field) {
try {
String val = field.getText();
field.setText("");
field.setDocument(new IntegerDocument());
field.getDocument().insertString(0, val, null);
field.setEnabled(true);
} catch (BadLocationException ble) {
}
}
/**
* get the field's values as an Integer
*
* @param field
* the component that holds the integer value
* @return an Integer that is the value of the text field
*/
@Override
public Object getValue(JTextField field) {
return Integer.valueOf(field.getText());
}
/**
* returns the display value shown in the combo box
*
* @return the string 'Integer'
*/
@Override
public String toString() {
return MongoBundle.getString(MongoBundle.Key.Integer);
}
}
/**
* a value type representing an Double object
*/
static class DoubleValueType implements ValueType {
/**
* installs an DoubleDocument as the field's model
*
* @param field
* the text edit field to install the model
*/
@Override
public void installDocument(JTextField field) {
try {
String val = field.getText();
field.setText("");
field.setDocument(new DoubleDocument());
field.getDocument().insertString(0, val, null);
field.setEnabled(true);
} catch (BadLocationException ble) {
}
}
/**
* get the field's values as an Double
*
* @param field
* the component that holds the double value
* @return an Double that is the value of the text field
*/
@Override
public Object getValue(JTextField field) {
return Double.valueOf(field.getText());
}
/**
* returns the display value shown in the combo box
*
* @return the string 'Double'
*/
@Override
public String toString() {
return MongoBundle.getString(MongoBundle.Key.Double);
}
}
/**
* a value type representing an Float object
*/
static class FloatValueType implements ValueType {
/**
* installs an FloatDocument as the field's model
*
* @param field
* the text edit field to install the model
*/
@Override
public void installDocument(JTextField field) {
try {
String val = field.getText();
field.setText("");
field.setDocument(new FloatDocument());
field.getDocument().insertString(0, val, null);
field.setEnabled(true);
} catch (BadLocationException ble) {
}
}
/**
* get the field's values as an Float
*
* @param field
* the component that holds the float value
* @return an Float that is the value of the text field
*/
@Override
public Object getValue(JTextField field) {
return Float.valueOf(field.getText());
}
/**
* returns the display value shown in the combo box
*
* @return the string 'Float'
*/
@Override
public String toString() {
return MongoBundle.getString(MongoBundle.Key.Float);
}
}
/**
* a value type representing an String object
*/
static class StringValueType implements ValueType {
/**
* installs an PlainDocument as the field's model
*
* @param field
* the text edit field to install the model
*/
@Override
public void installDocument(JTextField field) {
try {
String val = field.getText();
field.setText("");
field.setDocument(new PlainDocument());
field.getDocument().insertString(0, val, null);
field.setEnabled(true);
} catch (BadLocationException ble) {
}
}
/**
* get the field's values as an String
*
* @param field
* the component that holds the string value
* @return an String that is the value of the text field
*/
@Override
public Object getValue(JTextField field) {
return field.getText();
}
/**
* returns the display value shown in the combo box
*
* @return the string 'String'
*/
@Override
public String toString() {
return MongoBundle.getString(MongoBundle.Key.String);
}
}
/**
* a value type representing a Date object
*/
static class DateValueType implements ValueType {
/**
* installs an PlainDocument as the field's model
*
* @param field
* the text edit field to install the model
*/
@Override
public void installDocument(JTextField field) {
try {
String val = field.getText();
field.setText("");
field.setDocument(new DateDocument());
field.getDocument().insertString(0, val, null);
field.setEnabled(true);
} catch (BadLocationException ble) {
}
}
/**
* get the field's values as an String
*
* @param field
* the component that holds the string value
* @return an Date that is the value of the text field
*/
@Override
public Object getValue(JTextField field) {
Pattern p = Pattern.compile(MongoBundle.getString(MongoBundle.Key.DateRegex));
Calendar c = Calendar.getInstance();
Matcher m = p.matcher(field.getText());
if (m.matches() || m.hitEnd()) {
c.clear();
int groupCounts = m.groupCount();
if (groupCounts > 0) {
String[] monthVals = MongoBundle.getString(MongoBundle.Key.MonthValues).split(",");
String month = m.group(1);
for (String mv : monthVals) {
if (month.startsWith(mv)) {
c.set(Calendar.MONTH, Integer.parseInt(mv.split(":")[1]));
}
}
if (groupCounts > 1) {
c.set(Calendar.DAY_OF_MONTH, Integer.parseInt(m.group(2)));
if (groupCounts > 2) {
c.set(Calendar.YEAR, Integer.parseInt(m.group(3)));
if (groupCounts > 3) {
String[] time = m.group(4).split(":");
if (time.length > 0) {
c.set(Calendar.HOUR_OF_DAY, Integer.parseInt(time[0]));
if (time.length > 1) {
c.set(Calendar.MINUTE, Integer.parseInt(time[1]));
if (time.length > 2) {
c.set(Calendar.SECOND, Integer.parseInt(time[2]));
}
}
}
}
}
}
}
}
return c.getTime();
}
/**
* returns the display value shown in the combo box
*
* @return the string 'String'
*/
@Override
public String toString() {
return MongoBundle.getString(MongoBundle.Key.Date);
}
}
/**
* a value type representing an BasicDBObject object
*/
static class ObjectValueType implements ValueType {
/**
* installs an PlainDocument as the field's model and disables the field
*
* @param field
* the text edit field to install the model
*/
@Override
public void installDocument(JTextField field) {
field.setText("");
field.setDocument(new PlainDocument());
field.setEnabled(false);
}
/**
* get the field's values as an BasicDBObject
*
* @param field
* the component that holds the string value
* @return an String that is the value of the text field
*/
@Override
public Object getValue(JTextField field) {
return new BasicDBObject();
}
/**
* returns the display value shown in the combo box
*
* @return the string 'Object'
*/
@Override
public String toString() {
return MongoBundle.getString(MongoBundle.Key.Object);
}
}
class DateMouseListener extends MouseAdapter {
@Override
public void mouseClicked(MouseEvent e) {
SimpleDateFormat sdf = new SimpleDateFormat(MongoBundle.getString(MongoBundle.Key.DateFormat));
PickCalDialog pick = new PickCalDialog();
try {
pick.setDate(sdf.parse(valueField.getText()));
} catch (ParseException pe) {
}
pick.setModal(true);
pick.setLocationRelativeTo(KeyValueDialog.this);
pick.setVisible(true);
if (pick.isOK()) {
Date pickedDate = pick.getDate();
valueField.setText(sdf.format(pickedDate));
}
}
}
}