1   /**
2    * Distribution License:
3    * JSword is free software; you can redistribute it and/or modify it under
4    * the terms of the GNU Lesser General Public License, version 2.1 as published by
5    * the Free Software Foundation. This program is distributed in the hope
6    * that it will be useful, but WITHOUT ANY WARRANTY; without even the
7    * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8    * See the GNU Lesser General Public License for more details.
9    *
10   * The License is available on the internet at:
11   *       http://www.gnu.org/copyleft/lgpl.html
12   * or by writing to:
13   *      Free Software Foundation, Inc.
14   *      59 Temple Place - Suite 330
15   *      Boston, MA 02111-1307, USA
16   *
17   * Copyright: 2005
18   *     The copyright to this program is held by it's authors.
19   *
20   * ID: $Id: StringArrayField.java 2104 2011-03-07 18:54:34Z dmsmith $
21   */
22  package org.crosswire.common.config.swing;
23  
24  import java.awt.BorderLayout;
25  import java.awt.FlowLayout;
26  import java.awt.Font;
27  import java.awt.GridBagConstraints;
28  import java.awt.GridBagLayout;
29  import java.awt.Insets;
30  import java.io.IOException;
31  import java.io.ObjectInputStream;
32  
33  import javax.swing.BorderFactory;
34  import javax.swing.DefaultComboBoxModel;
35  import javax.swing.JButton;
36  import javax.swing.JComponent;
37  import javax.swing.JLabel;
38  import javax.swing.JList;
39  import javax.swing.JOptionPane;
40  import javax.swing.JPanel;
41  import javax.swing.JScrollPane;
42  import javax.swing.JTextField;
43  import javax.swing.ListSelectionModel;
44  import javax.swing.border.Border;
45  
46  import org.crosswire.common.config.Choice;
47  import org.crosswire.common.swing.ActionFactory;
48  import org.crosswire.common.swing.CWMsg;
49  import org.crosswire.common.swing.CWOptionPane;
50  import org.crosswire.common.swing.CWScrollPane;
51  import org.crosswire.common.swing.GuiUtil;
52  import org.crosswire.common.swing.CWOtherMsg;
53  import org.crosswire.common.util.Convert;
54  
55  /**
56   * A StringArrayField allows editing of an array of Strings in a JList. It
57   * allows the user to specify additional classes that extend the functionality
58   * of the program.
59   * 
60   * @see gnu.lgpl.License for license details.<br>
61   *      The copyright to this program is held by it's authors.
62   * @author Joe Walker [joe at eireneh dot com]
63   */
64  public class StringArrayField extends JPanel implements Field {
65      /**
66       * Create a PropertyHashtableField for editing String arrays.
67       */
68      public StringArrayField() {
69          actions = new ActionFactory(this);
70  
71          list_model = new DefaultComboBoxModel();
72          list = new JList(list_model);
73  
74          JPanel buttons = new JPanel(new FlowLayout());
75  
76          list.setFont(new Font("Monospaced", Font.PLAIN, 12));
77          list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
78  
79          JScrollPane scroll = new CWScrollPane(list);
80  
81          // TRANSLATOR: This is the text on an "Add" button.
82          buttons.add(new JButton(actions.addAction("Add", CWMsg.gettext("Add"))));
83          // TRANSLATOR: This is the text on a "Remove" button.
84          buttons.add(new JButton(actions.addAction("Remove", CWMsg.gettext("Remove"))));
85          // TRANSLATOR: This is the text on an "Update" button.
86          buttons.add(new JButton(actions.addAction("Update", CWMsg.gettext("Update"))));
87  
88          Border title = BorderFactory.createTitledBorder(CWOtherMsg.lookupText("Component Editor"));
89          Border pad = BorderFactory.createEmptyBorder(5, 5, 5, 5);
90          setBorder(BorderFactory.createCompoundBorder(title, pad));
91  
92          setLayout(new BorderLayout());
93          add(scroll, BorderLayout.CENTER);
94          add(buttons, BorderLayout.PAGE_END);
95          GuiUtil.applyDefaultOrientation(this);
96      }
97  
98      /*
99       * (non-Javadoc)
100      * 
101      * @see
102      * org.crosswire.common.config.swing.Field#setChoice(org.crosswire.common
103      * .config.Choice)
104      */
105     public void setChoice(Choice param) {
106     }
107 
108     /*
109      * (non-Javadoc)
110      * 
111      * @see org.crosswire.common.config.swing.Field#getValue()
112      */
113     public String getValue() {
114         return Convert.stringArray2String(getArray(), SEPARATOR);
115     }
116 
117     /**
118      * Return the actual Hashtable being edited
119      * 
120      * @return The current value
121      */
122     public String[] getArray() {
123         String[] retcode = new String[list_model.getSize()];
124         for (int i = 0; i < retcode.length; i++) {
125             retcode[i] = (String) list_model.getElementAt(i);
126         }
127 
128         return retcode;
129     }
130 
131     /*
132      * (non-Javadoc)
133      * 
134      * @see org.crosswire.common.config.swing.Field#setValue(java.lang.String)
135      */
136     public void setValue(String value) {
137         setArray(Convert.string2StringArray(value, SEPARATOR));
138     }
139 
140     /**
141      * Set the current value using a hashtable
142      * 
143      * @param value
144      *            The new text
145      */
146     public void setArray(String[] value) {
147         list_model = new DefaultComboBoxModel(value.clone());
148         list.setModel(list_model);
149     }
150 
151     /*
152      * (non-Javadoc)
153      * 
154      * @see org.crosswire.common.config.swing.Field#getComponent()
155      */
156     public JComponent getComponent() {
157         return this;
158     }
159 
160     /**
161      * Pop up a dialog to allow editing of a new value
162      */
163     public void doAddEntry() {
164         InputPane input = new InputPane();
165 
166         if (CWOptionPane.showConfirmDialog(this, input, CWOtherMsg.lookupText("New Class"), JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION) {
167             String new_name = input.name_field.getText();
168 
169             list_model.addElement(new_name);
170         }
171     }
172 
173     /**
174      * Pop up a dialog to allow editing of a current value
175      */
176     public void doUpdateEntry() {
177         InputPane input = new InputPane();
178         input.name_field.setText(currentValue());
179 
180         if (CWOptionPane.showConfirmDialog(this, input, CWOtherMsg.lookupText("Edit Class"), JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION) {
181             String new_name = input.name_field.getText();
182 
183             list_model.removeElement(currentValue());
184             list_model.addElement(new_name);
185         }
186     }
187 
188     /**
189      * Delete the current value in the hashtable
190      */
191     public void doRemoveEntry() {
192         list_model.removeElement(currentValue());
193     }
194 
195     /**
196      * What is the currently selected value?
197      * 
198      * @return The currently selected value
199      */
200     private String currentValue() {
201         return (String) list_model.getElementAt(list.getSelectedIndex());
202     }
203 
204     /**
205      * Serialization support.
206      * 
207      * @param is
208      * @throws IOException
209      * @throws ClassNotFoundException
210      */
211     private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException {
212         actions = new ActionFactory(this);
213         is.defaultReadObject();
214     }
215 
216     /**
217      * The panel for a JOptionPane that allows editing a name/class combination.
218      */
219     public static class InputPane extends JPanel {
220         /**
221          * Simple ctor
222          */
223         public InputPane() {
224             super(new GridBagLayout());
225 
226             GridBagConstraints c = new GridBagConstraints();
227             c.anchor = GridBagConstraints.LINE_END;
228             c.insets = new Insets(0, 5, 0, 5);
229 
230             c.gridwidth = GridBagConstraints.RELATIVE; // next-to-last
231             c.fill = GridBagConstraints.NONE; // reset to default
232             c.weightx = 0.0; // reset to default
233             add(new JLabel(CWOtherMsg.lookupText("Name") + ':'), c);
234 
235             c.gridwidth = GridBagConstraints.REMAINDER; // end row
236             c.fill = GridBagConstraints.HORIZONTAL;
237             c.weightx = 1.0;
238             add(name_field, c);
239 
240             setBorder(BorderFactory.createEmptyBorder(10, 5, 10, 5));
241         }
242 
243         /**
244          * To edit a name (hashtable key)
245          */
246         protected JTextField name_field = new JTextField();
247 
248         /**
249          * Serialization ID
250          */
251         private static final long serialVersionUID = 3256444715753878326L;
252     }
253 
254     /**
255      * What character do we use to separate strings?
256      */
257     private static final String SEPARATOR = "#";
258 
259     private transient ActionFactory actions;
260 
261     /**
262      * The TableModel that points the JTable at the Hashtable
263      */
264     private DefaultComboBoxModel list_model;
265 
266     /**
267      * The Table - displays the Hashtble
268      */
269     private JList list;
270 
271     /**
272      * Serialization ID
273      */
274     private static final long serialVersionUID = 3256444715753878326L;
275 }
276