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