1
2
3
4
5 package spellcast.ui;
6
7 import java.awt.BorderLayout;
8 import java.awt.Container;
9 import java.awt.Dimension;
10 import java.awt.GridBagConstraints;
11 import java.awt.GridBagLayout;
12 import java.awt.Insets;
13 import java.awt.event.ActionEvent;
14 import java.awt.event.ActionListener;
15 import java.beans.PropertyChangeListener;
16 import java.io.BufferedReader;
17 import java.io.BufferedWriter;
18 import java.io.File;
19 import java.io.FileReader;
20 import java.io.FileWriter;
21 import java.io.LineNumberReader;
22 import java.util.ArrayList;
23 import java.util.Iterator;
24 import javax.swing.ComboBoxModel;
25 import javax.swing.DefaultComboBoxModel;
26 import javax.swing.DefaultListModel;
27 import javax.swing.JButton;
28 import javax.swing.JComboBox;
29 import javax.swing.JDialog;
30 import javax.swing.JFrame;
31 import javax.swing.JLabel;
32 import javax.swing.JList;
33 import javax.swing.JPanel;
34 import javax.swing.JScrollPane;
35 import javax.swing.JTextField;
36 import javax.swing.ListSelectionModel;
37 import javax.swing.WindowConstants;
38 import javax.swing.event.ListSelectionEvent;
39 import javax.swing.event.ListSelectionListener;
40 import javax.swing.event.SwingPropertyChangeSupport;
41 import org.apache.log4j.Logger;
42 import spellcast.beings.Gender;
43 import spellcast.util.TextUtil;
44
45 /***
46 * Display the profiles stored in <b>user.home</b>/.spellcast/Profiles.txt.
47 * New profiles can be added via the save button, or deleted by the delete button.
48 * When the user selects which profile to use it is written to <b>user.home</b>/.spellcast/Profiles-default.txt
49 * <p>
50 * Format of <b>user.home</b>/.spellcast/Profiles.txt:<br>
51 * This file contains wizard profiles, one per line.
52 * Each line is of the format <Gender String><space><Name>.
53 *
54 * @author Barrie Treloar
55 */
56 public class WizardProfiles extends JDialog implements UIProperties {
57 public static final File profilesFile =
58 new File(System.getProperty("user.home") + "/.spellcast/Profiles.txt");
59 public static final File defaultProfileFile =
60 new File(System.getProperty("user.home") + "/.spellcast/Default-Profile.txt");
61
62 /***
63 * The preffered size for the profile list. Since the list goes in the SOUTH
64 * section the height field is ignored.
65 */
66 private static final Dimension LIST_PREFERRED_SIZE = new Dimension(100, 100);
67
68 private GridBagLayout gridbag;
69
70 private JList profileList;
71 private DefaultListModel profileModel = new DefaultListModel();
72 private JTextField wizardName;
73 private JComboBox genders;
74 private ComboBoxModel genderModel =
75 new DefaultComboBoxModel(Gender.GENDERS_AS_STRINGS);
76 private SwingPropertyChangeSupport propertySupport;
77
78 private static final Logger logger = Logger.getLogger("client.ui");
79
80 public WizardProfiles() {
81 super((JFrame) null, "Spellcast: Wizard Profiles", true);
82 propertySupport = new SwingPropertyChangeSupport(this);
83 java.util.List profiles = loadProfiles();
84 if (profiles.size() == 0) {
85 setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
86 }
87 Iterator profileIterator = profiles.listIterator();
88 while (profileIterator.hasNext()) {
89 profileModel.addElement(profileIterator.next());
90 }
91
92 Container dialogPanel = getContentPane();
93
94 profileList = new JList(profileModel);
95 profileList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
96 profileList.setPreferredSize(LIST_PREFERRED_SIZE);
97 JScrollPane s =
98 new JScrollPane(
99 profileList,
100 JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
101 JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
102 dialogPanel.add(s, BorderLayout.WEST);
103
104 JPanel centerPanel = new JPanel();
105 gridbag = new GridBagLayout();
106 centerPanel.setLayout(gridbag);
107 GridBagConstraints c = new GridBagConstraints();
108
109 c.insets = new Insets(2, 2, 2, 2);
110
111 c.anchor = GridBagConstraints.WEST;
112 JLabel nameLabel = new JLabel("Name:");
113 gridbag.setConstraints(nameLabel, c);
114 centerPanel.add(nameLabel);
115
116 c.gridwidth = GridBagConstraints.REMAINDER;
117 wizardName = new JTextField(15);
118 gridbag.setConstraints(wizardName, c);
119 centerPanel.add(wizardName);
120 nameLabel.setLabelFor(wizardName);
121
122 c.gridwidth = 1;
123 JLabel genderLabel = new JLabel("Gender:");
124 gridbag.setConstraints(genderLabel, c);
125 centerPanel.add(genderLabel);
126
127 c.gridwidth = GridBagConstraints.REMAINDER;
128 genders = new JComboBox(genderModel);
129 genders.setEditable(false);
130 gridbag.setConstraints(genders, c);
131 centerPanel.add(genders);
132 genderLabel.setLabelFor(genders);
133
134 c.insets = new Insets(5, 2, 2, 2);
135 c.gridwidth = 1;
136 c.weightx = 1.0;
137 c.anchor = GridBagConstraints.EAST;
138 final JButton use = new JButton("Use");
139 use.setEnabled(false);
140 use.addActionListener(new ActionListener() {
141 public void actionPerformed(ActionEvent e) {
142 saveDefaultProfile((WizardProfile) profileList.getSelectedValue());
143 setVisible(false);
144 }
145 });
146 gridbag.setConstraints(use, c);
147 centerPanel.add(use);
148
149 c.weightx = 0.0;
150 c.anchor = GridBagConstraints.CENTER;
151 JButton save = new JButton("Save");
152 save.addActionListener(new ActionListener() {
153 public void actionPerformed(ActionEvent e) {
154 addProfile(wizardName.getText().trim(), (String) genders.getSelectedItem());
155 saveProfiles();
156 }
157 });
158 gridbag.setConstraints(save, c);
159 centerPanel.add(save);
160
161 JButton delete = new JButton("Delete");
162 delete.addActionListener(new ActionListener() {
163 public void actionPerformed(ActionEvent e) {
164 WizardProfile p = (WizardProfile) profileList.getSelectedValue();
165 if (p != null) {
166 profileModel.removeElement(p);
167 saveProfiles();
168 }
169 }
170 });
171 gridbag.setConstraints(delete, c);
172 centerPanel.add(delete);
173
174 c.gridwidth = GridBagConstraints.REMAINDER;
175 JButton clear = new JButton("Clear");
176 clear.addActionListener(new ActionListener() {
177 public void actionPerformed(ActionEvent e) {
178 wizardName.setText("");
179 }
180 });
181 gridbag.setConstraints(clear, c);
182 centerPanel.add(clear);
183
184 dialogPanel.add(centerPanel, BorderLayout.CENTER);
185
186 profileList.addListSelectionListener(new ListSelectionListener() {
187 public void valueChanged(ListSelectionEvent e) {
188 int index = profileList.getSelectedIndex();
189 if (index != -1) {
190 WizardProfile p = (WizardProfile) profileModel.elementAt(index);
191 wizardName.setText(p.wizardName);
192 genderModel.setSelectedItem(p.gender);
193 use.setEnabled(true);
194 }
195 else {
196 use.setEnabled(false);
197 }
198 }
199 });
200 profileList.setSelectedValue(loadDefaultProfile(), true);
201 pack();
202 }
203
204 public void addPropertyChangeListener(PropertyChangeListener listener) {
205 propertySupport.addPropertyChangeListener(listener);
206 }
207
208 public void removePropertyChangeListener(PropertyChangeListener listener) {
209 propertySupport.removePropertyChangeListener(listener);
210 }
211
212 /***
213 * Add the profile to the model.
214 * First checks to see if the wizard name already exists and if so just
215 * updates the profiles gender.
216 * If it doesn't exist in the model then add it.
217 */
218 private void addProfile(String wizardName, String gender) {
219 if (wizardName == null || wizardName.equals("")) {
220 return;
221 }
222
223 boolean found = false;
224 for (int i = 0; i < profileModel.size(); i++) {
225 WizardProfile p = (WizardProfile) profileModel.get(i);
226 if (p.wizardName.equals(wizardName)) {
227 found = true;
228 p.gender = gender;
229 }
230 }
231 if (!found) {
232 WizardProfile wp = new WizardProfile(wizardName, gender);
233 profileModel.addElement(wp);
234 profileList.setSelectedValue(wp, true);
235 }
236 }
237
238 /***
239 * Return a list of WizardProfiles. If there are no entries the list will be size == 0.
240 */
241 public static java.util.List loadProfiles() {
242 LineNumberReader r = null;
243 ArrayList result = new ArrayList(10);
244 try {
245 if (profilesFile.exists()) {
246 r = new LineNumberReader(new FileReader(profilesFile));
247 String line = null;
248 while ((line = r.readLine()) != null) {
249
250 String gender = TextUtil.getGender(line);
251 String wizardName = TextUtil.getWizardName(line);
252 if (Gender.getGender(gender) == null) {
253 logger.warn(
254 "Malformed line (" + r.getLineNumber() + ") expecting valid gender.");
255 }
256 else
257 if (wizardName == null || wizardName.equals("")) {
258 logger.warn(
259 "Malformed line (" + r.getLineNumber() + ") expecting valid wizard name.");
260 }
261 else {
262 result.add(new WizardProfile(wizardName, gender));
263 }
264 }
265 }
266 }
267 catch (Exception e) {
268 logger.error("Could not load Profiles.", e);
269 }
270 finally {
271 try {
272 if (r != null) {
273 r.close();
274 }
275 }
276 catch (Exception e) {
277 logger.error("Unexpected error in Reader.close().", e);
278 }
279 }
280 return result;
281 }
282
283 private void saveProfiles() {
284 BufferedWriter w = null;
285
286 try {
287
288 profilesFile.createNewFile();
289
290 if (profilesFile.exists()) {
291 w = new BufferedWriter(new FileWriter(profilesFile));
292 for (int i = 0; i < profileModel.size(); i++) {
293 WizardProfile p = (WizardProfile) profileModel.get(i);
294 w.write(p.gender);
295 w.write(" ");
296 w.write(p.wizardName);
297 w.newLine();
298 }
299 }
300 }
301 catch (Exception e) {
302 logger.error("Could not save Profiles.", e);
303 }
304 finally {
305 try {
306 if (w != null) {
307 w.flush();
308 w.close();
309 }
310 }
311 catch (Exception e) {
312 logger.error("Unexpected error in Writer.close().", e);
313 }
314 }
315 }
316
317 /***
318 * Return the default wizard profile, or null if it does not exist.
319 */
320 public static WizardProfile loadDefaultProfile() {
321 WizardProfile result = null;
322 BufferedReader r = null;
323 try {
324 if (defaultProfileFile.exists()) {
325 r = new BufferedReader(new FileReader(defaultProfileFile));
326 String line = r.readLine();
327 if (line != null) {
328
329 String gender = TextUtil.getGender(line);
330 String wizardName = TextUtil.getWizardName(line);
331 if (Gender.getGender(gender) == null) {
332 logger.warn("Malformed default profile. Expecting valid gender.");
333 }
334 else if (wizardName == null || wizardName.equals("")) {
335 logger.warn("Malformed default profile. Expecting valid wizard name.");
336 }
337 else {
338 result = new WizardProfile(wizardName, gender);
339 }
340 }
341 }
342 }
343 catch (Exception e) {
344 logger.error("Could not load default profile.", e);
345 }
346 finally {
347 try {
348 if (r != null) {
349 r.close();
350 }
351 }
352 catch (Exception e) {
353 logger.error("Unexpected error in Reader.close().", e);
354 }
355 }
356 return result;
357 }
358
359 /***
360 * Save the default profile
361 */
362 private void saveDefaultProfile(WizardProfile wp) {
363 BufferedWriter w = null;
364
365 if (wp == null) {
366 return;
367 }
368
369 try {
370
371 defaultProfileFile.createNewFile();
372
373 if (defaultProfileFile.exists()) {
374 w = new BufferedWriter(new FileWriter(defaultProfileFile));
375 w.write(wp.gender);
376 w.write(" ");
377 w.write(wp.wizardName);
378 w.newLine();
379 }
380 }
381 catch (Exception e) {
382 logger.error("Could not save Default Profiles.", e);
383 }
384 finally {
385 try {
386 if (w != null) {
387 w.flush();
388 w.close();
389 }
390 }
391 catch (Exception e) {
392 logger.error("Unexpected error in Writer.close().", e);
393 }
394 }
395 }
396
397 }