001 /*
002 Copyright (C) 2003 Adam Olsen This program is free software; you can
003 redistribute it and/or modify it under the terms of the GNU General Public
004 License as published by the Free Software Foundation; either version 1, or
005 (at your option) any later version. This program is distributed in the hope
006 that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
007 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
008 General Public License for more details. You should have received a copy of
009 the GNU General Public License along with this program; if not, write to the
010 Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
011 */
012 package com.valhalla.jbother;
013
014 import java.awt.*;
015 import java.awt.event.*;
016 import java.io.*;
017 import java.util.*;
018
019 import javax.swing.*;
020 import com.valhalla.settings.*;
021
022 import org.jivesoftware.smack.packet.Presence;
023
024 /**
025 * @author Anrdey Zakirov
026 * @created April 12, 2005
027 * @version 0.2
028 * @since April 10, 2005
029 */
030
031 public class StatusDialog extends JDialog
032 {
033 private ResourceBundle resources = ResourceBundle.getBundle(
034 "JBotherBundle", Locale.getDefault());
035
036 private JPanel main;
037
038 private JButton okButton = new JButton(resources.getString("okButton"));
039
040 private JButton changeNameButton = new JButton("Rename");
041
042 private JButton deleteButton = new JButton("Delete");
043
044 private JButton cancelButton = new JButton(resources.getString("cancelButton"));
045
046 private JList statusList = new JList();
047 private StatusListModel model = new StatusListModel();
048
049 private JTextArea itemText = new JTextArea(5, 10);
050
051 private JScrollPane itemScroll = new JScrollPane(itemText);
052
053 private Presence.Mode mode = null;
054
055 private StatusMessageProperties statusProps;
056
057 private Hashtable modeHash = new Hashtable();
058
059 private String modeString;
060
061 private String modeLocaleString;
062
063 private String modeDescription;
064
065 private JTextField priorityBox = new JTextField(5);
066
067 /**
068 *Constructor for the StatusDialog object
069 *
070 * @param mode Description of the Parameter
071 */
072 public StatusDialog(Presence.Mode mode)
073 {
074
075 super(BuddyList.getInstance().getContainerFrame(), "", true);
076 statusProps = new StatusMessageProperties();
077
078 statusList.setModel(model);
079
080 this.mode = mode;
081 main = (JPanel) getContentPane();
082 main.setBorder(BorderFactory.createTitledBorder(resources.getString("enterStatusMessage")));
083 String currentMessage = BuddyList.getInstance()
084 .getCurrentStatusString();
085 GridBagLayout grid = new GridBagLayout();
086 GridBagConstraints c = new GridBagConstraints();
087 main.setLayout(grid);
088
089 c.fill = GridBagConstraints.HORIZONTAL;
090 c.gridx = 0;
091 c.gridy = 0;
092 c.weighty = 0;
093 c.weightx = 1.0;
094
095 grid.setConstraints(statusList, c);
096
097 modeString = mode.toString();
098
099 modeLocaleString = resources.getString(modeString);
100 itemText.setWrapStyleWord( true );
101 itemText.setLineWrap( true );
102
103 modeDescription = resources.getString(modeString + ".description");
104
105 this.setTitle(resources.getString(mode.toString()));
106
107 if(!statusProps.containsKey(modeString + "." + modeLocaleString))
108 {
109 statusProps.put(modeString + "." + modeLocaleString, modeDescription);
110 }
111
112 StatusMessageProperties statusProps1 = (StatusMessageProperties) statusProps.clone();
113
114 String item = null;
115 String key = null;
116 String key2 = null;
117 boolean justChecked = false;
118 while(statusProps1.keys().hasMoreElements())
119 {
120 item = null;
121 key = (String) statusProps1.keys().nextElement();
122 item = (String) statusProps1.get(key);
123 if(key.startsWith(mode.toString()) == true)
124 {
125 key2 = key.substring(modeString.length() + 1, key.length());
126 if(modeHash.containsKey(key2) == false)
127 {
128 model.addItem(key2);
129 modeHash.put(key2, item);
130 if(currentMessage.matches(item))
131 {
132 justChecked = true;
133 statusList.setSelectedValue(key2, true);
134 itemText.setText(item);
135 }
136
137 }
138 }
139 statusProps1.remove(key);
140 }
141
142 if(!justChecked)
143 {
144 statusList.setSelectedIndex(0);
145 itemText.setText((String) modeHash.get((String) statusList.getSelectedValue()));
146 }
147
148 JPanel status = new JPanel();
149 status.setLayout(new BorderLayout(5, 5));
150 status.add(new JScrollPane(statusList), BorderLayout.CENTER);
151 JPanel buttonPanel = new JPanel();
152 buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.Y_AXIS));
153
154 changeNameButton.setMaximumSize(new Dimension(100, 100));
155 deleteButton.setMaximumSize(new Dimension(100, 100));
156
157 buttonPanel.add(changeNameButton);
158 buttonPanel.add(deleteButton);
159 buttonPanel.add(Box.createVerticalGlue());
160 status.add(buttonPanel, BorderLayout.EAST);
161
162 status.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
163 c.gridy++;
164 grid.setConstraints(status, c);
165
166 main.add(status);
167
168 JPanel items = new JPanel();
169 items.setLayout(new BorderLayout());
170 JLabel newLabel = new JLabel(resources.getString("createNewStatusMessage"));
171 newLabel.setBorder( BorderFactory.createEmptyBorder(0,0,5,0));
172 items.add(newLabel,BorderLayout.NORTH);
173 items.add(itemScroll,BorderLayout.CENTER);
174 items.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
175 c.gridy++;
176 grid.setConstraints(items, c);
177 main.add(items);
178
179 JPanel buttons = new JPanel();
180 buttons.setLayout(new BoxLayout(buttons, BoxLayout.X_AXIS));
181 buttons.add(Box.createHorizontalGlue());
182 buttons.add(okButton);
183 buttons.add(cancelButton);
184 buttons.add(Box.createHorizontalGlue());
185 buttons.setBorder(BorderFactory.createEmptyBorder(5, 5, 2, 5));
186 getRootPane().setDefaultButton(okButton);
187
188 c.weightx = 0;
189 c.fill = GridBagConstraints.NONE;
190 String p = Settings.getInstance().getProperty("priority", "5");
191
192 JPanel priority = new JPanel();
193 priorityBox.setText(p);
194 priority.setLayout( new BoxLayout(priority,BoxLayout.X_AXIS));
195 priority.add(Box.createHorizontalGlue());
196 priority.add(new JLabel(resources.getString("priority")+": "));
197 priority.add(priorityBox);
198 priority.add(Box.createHorizontalGlue());
199 c.gridy++;
200 grid.setConstraints(priority, c);
201 main.add(priority);
202
203 c.weightx = 1;
204 c.gridy++;
205 grid.setConstraints(buttons, c);
206 main.add(buttons);
207
208 addListeners();
209 pack();
210 setLocationRelativeTo(null);
211
212 addWindowListener(
213 new WindowAdapter()
214 {
215 public void windowClosing(WindowEvent e)
216 {
217 cancelHandler();
218 }
219 });
220
221 Dimension dim = getSize();
222 setSize(350, (int) dim.getHeight());
223 setResizable(false);
224
225 setVisible(true);
226 }
227
228 /**
229 * Adds a feature to the Listeners attribute of the StatusDialog object
230 */
231 private void addListeners()
232 {
233 statusList.addMouseListener(new MouseClickListener());
234 okButton.addActionListener(new OKDialogListener());
235 cancelButton.addActionListener(new CancelDialogListener());
236 changeNameButton.addActionListener(new ChangeNameDialogListener());
237 deleteButton.addActionListener(new DeleteDialogListener());
238 }
239
240 class MouseClickListener extends MouseAdapter {
241 public void mouseClicked(MouseEvent e) {
242
243 if( e.getClickCount() >= 2 ) okHandler();
244 else statusHandler();
245 }
246 }
247
248 /**
249 * Description of the Class
250 *
251 * @author synic
252 * @created April 12, 2005
253 */
254 class OKDialogListener implements ActionListener
255 {
256 /**
257 * Description of the Method
258 *
259 * @param e Description of the Parameter
260 */
261 public void actionPerformed(ActionEvent e)
262 {
263 okHandler();
264 }
265 }
266
267 /**
268 * Description of the Class
269 *
270 * @author synic
271 * @created April 12, 2005
272 */
273 class CancelDialogListener implements ActionListener
274 {
275 /**
276 * Description of the Method
277 *
278 * @param e Description of the Parameter
279 */
280 public void actionPerformed(ActionEvent e)
281 {
282 cancelHandler();
283 }
284 }
285
286 /**
287 * Description of the Class
288 *
289 * @author synic
290 * @created April 12, 2005
291 */
292 class DeleteDialogListener implements ActionListener
293 {
294 /**
295 * Description of the Method
296 *
297 * @param e Description of the Parameter
298 */
299 public void actionPerformed(ActionEvent e)
300 {
301 deleteHandler();
302 }
303 }
304
305 /**
306 * Description of the Class
307 *
308 * @author synic
309 * @created April 12, 2005
310 */
311 class ChangeNameDialogListener implements ActionListener
312 {
313 /**
314 * Description of the Method
315 *
316 * @param e Description of the Parameter
317 */
318 public void actionPerformed(ActionEvent e)
319 {
320 changeNameHandler();
321 }
322 }
323
324 /**
325 * Description of the Method
326 */
327 private void okHandler()
328 {
329 String statusText = itemText.getText();
330 if(!statusProps.containsValue(statusText))
331 {
332 if(statusProps.addMessage(statusText))
333 {
334 statusProps.saveToFile();
335 }
336 }
337
338 Settings.getInstance().setProperty("priority", priorityBox.getText());
339
340 BuddyList.getInstance().setStatus(mode, statusText, false);
341 dispose();
342 }
343
344 /**
345 * Description of the Method
346 */
347 private void cancelHandler()
348 {
349 BuddyList.getInstance().getStatusMenu().setModeChecked(
350 BuddyList.getInstance().getCurrentPresenceMode());
351 dispose();
352 }
353
354 /**
355 * Description of the Method
356 */
357 private void deleteHandler()
358 {
359 if(model.getSize() < 2)
360 {
361 JOptionPane.showMessageDialog(null, "This is the last entry. Make another to remove it.");
362 return;
363 }
364 int i = JOptionPane.showConfirmDialog(null, "Do you really want to remove this presence message?", "", 0, 1);
365 if(i == 0)
366 {
367 i = statusList.getSelectedIndex();
368 String temp = (String) statusList.getSelectedValue();
369 statusProps.remove(mode + "." + temp);
370 if(i > 0)
371 {
372 statusList.setSelectedIndex(i - 1);
373 }
374 else
375 {
376 statusList.setSelectedIndex(i + 1);
377 }
378 model.removeItem(temp);
379 statusProps.saveToFile();
380 statusHandler();
381 }
382 }
383
384 /**
385 * Description of the Method
386 */
387 private void changeNameHandler()
388 {
389 String key;
390 while(true)
391 {
392 key = JOptionPane.showInputDialog("Please enter this status name:");
393 if(key.equals("") == true)
394 {
395 JOptionPane.showMessageDialog(null, "Presence name must be not blank! Please, enter name.");
396 }
397 else if((statusProps.containsKey(modeString + "." + key) == false))
398 {
399 break;
400 }
401 else
402 {
403 JOptionPane.showMessageDialog(null, "This name is already taken! Pease, choose other name.");
404 }
405 }
406
407 if(key.equals(null) == false)
408 {
409
410 String selected = (String) statusList.getSelectedValue();
411 String message = (String) statusProps.get(mode + "." + selected);
412 statusProps.remove(mode + "." + selected);
413 statusProps.put(mode + "." + key, message);
414 model.removeItem(selected);
415 model.addItem(key);
416 statusList.setSelectedValue(key, true);
417 statusProps.saveToFile();
418 }
419
420 }
421
422
423 /**
424 * Description of the Method
425 */
426 private void statusHandler()
427 {
428 itemText.setText((String) statusProps.get(modeString + "." + (String) statusList.getSelectedValue()));
429 }
430
431 /**
432 * The model that represents the list of buddies in the room
433 *
434 * @author Adam Olsen
435 * @created April 12, 2005
436 * @version 1.0
437 */
438 class StatusListModel extends AbstractListModel
439 {
440 private Vector statuses = new Vector();
441
442 /**
443 * @return the number of elements in the list
444 */
445 public int getSize()
446 {
447 return statuses.size();
448 }
449
450 /**
451 * @param row the element you want to get
452 * @return the Object at <tt>row</tt>
453 */
454 public Object getElementAt(int row)
455 {
456 return statuses.get(row);
457 }
458
459 /**
460 * @param status The feature to be added to the Item attribute
461 */
462 public void addItem(String status)
463 {
464 statuses.add(status);
465 fireChanged();
466 }
467
468 /**
469 * Removes a buddy from the list
470 *
471 * @param status Description of the Parameter
472 */
473 public void removeItem(String status)
474 {
475 statuses.remove(status);
476 fireChanged();
477 }
478
479 /**
480 * Fires a change of the list
481 */
482 private void fireChanged()
483 {
484 SwingUtilities.invokeLater(
485 new Runnable()
486 {
487 public void run()
488 {
489 fireContentsChanged(StatusListModel.this, 0, statuses.size());
490 statusList.validate();
491 }
492 });
493 }
494 }
495
496 /**
497 * Description of the Class
498 *
499 * @author synic
500 * @created April 12, 2005
501 */
502 private class StatusMessageProperties extends Properties
503 {
504
505 private File propDir;
506
507 private File propFile;
508
509 private int tempIndex = 0;
510
511 /**
512 *Constructor for the StatusMessageProperties object
513 */
514 public StatusMessageProperties()
515 {
516 this(JBother.profileDir, "statusmessages.properties");
517 }
518
519 /**
520 *Constructor for the StatusMessageProperties object
521 *
522 * @param propDir Description of the Parameter
523 * @param propFile Description of the Parameter
524 */
525 private StatusMessageProperties(String propDir, String propFile)
526 {
527
528 this.propDir = new File(propDir);
529 this.propFile = new File(propDir, propFile);
530 loadFromFile();
531
532 }
533
534 /**
535 * Description of the Method
536 */
537 public void loadFromFile()
538 {
539
540 if(!propDir.isDirectory())
541 {
542
543 if(!propDir.isDirectory() && !propDir.mkdirs())
544 {
545 com.valhalla.Logger.debug("Could not create directory for StatusMessageProperties file! ("
546 + propDir.getName() + ")");
547 }
548
549 }
550
551 if(propFile.isFile())
552 {
553 try
554 {
555 InputStream is = new FileInputStream(propFile);
556 load(is);
557 is.close();
558 }
559 catch(Exception e)
560 {
561 com.valhalla.Logger.debug("Could not load away message properties file");
562 com.valhalla.Logger.debug(e.getMessage());
563 }
564 }
565
566 }
567
568 /**
569 * Adds a feature to the Message attribute of the StatusMessageProperties object
570 *
571 * @param message The feature to be added to the Message attribute
572 * @return Description of the Return Value
573 */
574 public boolean addMessage(String message)
575 {
576 String key;
577 while(true)
578 {
579 key = JOptionPane.showInputDialog("Please enter this status name:");
580 if(key.equals("") == true)
581 {
582 JOptionPane.showMessageDialog(null, "Presence name must be not blank! Please, enter name.");
583 }
584 else if((statusProps.containsKey(modeString + "." + key) == false))
585 {
586 break;
587 }
588 else
589 {
590 JOptionPane.showMessageDialog(null, "This name is already taken! Pease, choose other name.");
591 }
592 }
593
594 if(key.equals(null) == false)
595 {
596 model.addItem(key);
597 itemText.setText(message);
598 statusProps.put(mode + "." + key, message);
599 return true;
600 }
601 return false;
602 }
603
604 /**
605 * Description of the Method
606 */
607 public void saveToFile()
608 {
609
610 StatusMessageProperties propCopy = (StatusMessageProperties) clone();
611 clear();
612 int i = 0;
613 for(Enumeration e = propCopy.propertyNames(); e.hasMoreElements(); i++)
614 {
615 String propName = (String) e.nextElement();
616 setProperty(propName, propCopy.getProperty(propName));
617 }
618 if(propDir.isDirectory())
619 {
620 try
621 {
622 OutputStream os = new FileOutputStream(propFile);
623 store(os, "StatusMessages");
624 os.close();
625 }
626 catch(Exception e)
627 {
628 com.valhalla.Logger.debug("Could not save away message properties file");
629 com.valhalla.Logger.debug(e.getMessage());
630 }
631 }
632
633 }
634
635 }
636
637 }
638