View Javadoc

1   /*
2    *  UnBBayes
3    *  Copyright (C) 2002, 2008 Universidade de Brasilia - http://www.unb.br
4    *
5    *  This file is part of UnBBayes.
6    *
7    *  UnBBayes is free software: you can redistribute it and/or modify
8    *  it under the terms of the GNU General Public License as published by
9    *  the Free Software Foundation, either version 3 of the License, or
10   *  (at your option) any later version.
11   *
12   *  UnBBayes is distributed in the hope that it will be useful,
13   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   *  GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License
18   *  along with UnBBayes.  If not, see <http://www.gnu.org/licenses/>.
19   *
20   */
21  package unbbayes.gui.table;
22  
23  import java.awt.Component;
24  import java.awt.Toolkit;
25  import java.awt.event.ActionEvent;
26  import java.awt.event.KeyEvent;
27  import java.text.NumberFormat;
28  import java.text.ParseException;
29  
30  import javax.swing.AbstractAction;
31  import javax.swing.DefaultCellEditor;
32  import javax.swing.JFormattedTextField;
33  import javax.swing.JOptionPane;
34  import javax.swing.JTable;
35  import javax.swing.JTextField;
36  import javax.swing.KeyStroke;
37  import javax.swing.SwingUtilities;
38  import javax.swing.text.DefaultFormatterFactory;
39  import javax.swing.text.NumberFormatter;
40  
41  /**
42   * Implements a cell editor that uses a formatted text field to edit float/double
43   * values.
44   */
45  public class NumberEditor extends DefaultCellEditor {
46  
47  	private static final long serialVersionUID = 1L;
48  
49  	JFormattedTextField ftf;
50  
51  	NumberFormat numberFormat;
52  
53  	public NumberEditor() {
54  		super(new JFormattedTextField());
55  		ftf = (JFormattedTextField) getComponent();
56  
57  		// Set up the editor for the integer cells.
58  		numberFormat = NumberFormat.getNumberInstance();
59  		numberFormat.setMinimumFractionDigits(2);
60  		numberFormat.setMaximumFractionDigits(2);
61  		numberFormat.setMinimumIntegerDigits(1);
62  		NumberFormatter numberFormatter = new NumberFormatter(numberFormat);
63  		numberFormatter.setFormat(numberFormat);
64  
65  		ftf.setFormatterFactory(new DefaultFormatterFactory(numberFormatter));
66  		ftf.setHorizontalAlignment(JTextField.TRAILING);
67  		ftf.setFocusLostBehavior(JFormattedTextField.PERSIST);
68  
69  		// React when the user presses Enter while the editor is
70  		// active. (Tab is handled as specified by
71  		// JFormattedTextField's focusLostBehavior property.)
72  		ftf.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0),
73  				"check");
74  		ftf.getActionMap().put("check", new AbstractAction() {
75  			public void actionPerformed(ActionEvent e) {
76  				if (!ftf.isEditValid()) { // The text is invalid.
77  					if (userSaysRevert()) { // reverted
78  						ftf.postActionEvent(); // inform the editor
79  					}
80  				} else
81  					try { // The text is valid,
82  						ftf.commitEdit(); // so use it.
83  						ftf.postActionEvent(); // stop editing
84  					} catch (java.text.ParseException exc) {
85  					}
86  			}
87  		});
88  	}
89  
90  	// Override to invoke setValue on the formatted text field.
91  	public Component getTableCellEditorComponent(JTable table,
92  			Object value, boolean isSelected, int row, int column) {
93  		JFormattedTextField ftf = (JFormattedTextField) super
94  				.getTableCellEditorComponent(table, value, isSelected, row,
95  						column);
96  		ftf.setValue(value);
97  		return ftf;
98  	}
99  
100 	// Override to ensure that the value remains an Integer.
101 	public Object getCellEditorValue() {
102 		JFormattedTextField ftf = (JFormattedTextField) getComponent();
103 		Object o = ftf.getValue();
104 		if (o instanceof Float || o instanceof Double) {
105 			return o;
106 		} else if (o instanceof Number) {
107 			return new Float(((Number) o).floatValue());
108 		} else {
109 			try {
110 				return numberFormat.parseObject(o.toString());
111 			} catch (ParseException exc) {
112 				System.err.println("getCellEditorValue: can't parse o: "
113 						+ o);
114 				return null;
115 			}
116 		}
117 	}
118 
119 	// Override to check whether the edit is valid,
120 	// setting the value if it is and complaining if
121 	// it isn't. If it's OK for the editor to go
122 	// away, we need to invoke the superclass's version
123 	// of this method so that everything gets cleaned up.
124 	public boolean stopCellEditing() {
125 		JFormattedTextField ftf = (JFormattedTextField) getComponent();
126 		if (ftf.isEditValid()) {
127 			try {
128 				ftf.commitEdit();
129 			} catch (java.text.ParseException exc) {
130 			}
131 
132 		} else { // text is invalid
133 			if (!userSaysRevert()) { // user wants to edit
134 				return false; // don't let the editor go away
135 			}
136 		}
137 		return super.stopCellEditing();
138 	}
139 
140 	/**
141 	 * Lets the user know that the text they entered is bad. Returns true if
142 	 * the user elects to revert to the last good value. Otherwise, returns
143 	 * false, indicating that the user wants to continue editing.
144 	 */
145 	protected boolean userSaysRevert() {
146 		Toolkit.getDefaultToolkit().beep();
147 		ftf.selectAll();
148 		Object[] options = { "Edit", "Revert" };
149 		int answer = JOptionPane.showOptionDialog(SwingUtilities
150 				.getWindowAncestor(ftf),
151 				"The value must be a number.\n"
152 						+ "You can either continue editing "
153 						+ "or revert to the last valid value.",
154 				"Invalid Text Entered", JOptionPane.YES_NO_OPTION,
155 				JOptionPane.ERROR_MESSAGE, null, options, options[1]);
156 
157 		if (answer == 1) { // Revert!
158 			ftf.setValue(ftf.getValue());
159 			return true;
160 		}
161 		return false;
162 	}
163 }