001    /*
002     Copyright (C) 2003 Adam Olsen
003     This program is free software; you can redistribute it and/or modify
004     it under the terms of the GNU General Public License as published by
005     the Free Software Foundation; either version 1, or (at your option)
006     any later version.
007     This program is distributed in the hope that it will be useful,
008     but WITHOUT ANY WARRANTY; without even the implied warranty of
009     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
010     GNU General Public License for more details.
011     You should have received a copy of the GNU General Public License
012     along with this program; if not, write to the Free Software
013     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
014     */
015    package com.valhalla.jbother;
016    
017    //includes
018    import java.awt.Color;
019    import java.awt.GridLayout;
020    import java.awt.event.MouseAdapter;
021    import java.awt.event.MouseEvent;
022    import java.util.Enumeration;
023    import java.util.Hashtable;
024    import java.util.Iterator;
025    import java.util.Locale;
026    import java.util.ResourceBundle;
027    import java.util.TreeMap;
028    
029    import javax.swing.JPanel;
030    import javax.swing.JScrollPane;
031    import javax.swing.JTree;
032    import javax.swing.SwingUtilities;
033    import javax.swing.ToolTipManager;
034    import javax.swing.event.TreeExpansionEvent;
035    import javax.swing.event.TreeExpansionListener;
036    import javax.swing.tree.TreePath;
037    import javax.swing.tree.TreeSelectionModel;
038    
039    import org.dotuseful.ui.tree.AutomatedTreeModel;
040    import org.dotuseful.ui.tree.AutomatedTreeNode;
041    import org.jivesoftware.smack.Roster;
042    import org.jivesoftware.smack.RosterEntry;
043    import org.jivesoftware.smack.XMPPConnection;
044    import org.jivesoftware.smack.packet.Presence;
045    
046    import com.valhalla.jbother.jabber.BuddyGroup;
047    import com.valhalla.jbother.jabber.BuddyStatus;
048    import com.valhalla.jbother.menus.BuddyListPopupMenu;
049    import com.valhalla.jbother.menus.BuddyListTransportMenu;
050    import com.valhalla.jbother.menus.GroupPopupMenu;
051    import com.valhalla.settings.Settings;
052    
053    /**
054     * BuddyListTree is the part of the buddy list dialog that draws the buddies and
055     * their groups from your Jabber roster. It also displays different pictures for
056     * different statuses.
057     *
058     * @author Adam Olsen
059     * @created March 2, 2005
060     * @version 1.0
061     */
062    public class BuddyListTree extends JPanel {
063        private ResourceBundle resources = ResourceBundle.getBundle(
064                "JBotherBundle", Locale.getDefault());
065    
066        private XMPPConnection connection;
067    
068        private Roster roster;
069    
070        private AutomatedTreeNode root = new AutomatedTreeNode("Buddies");
071    
072        private AutomatedTreeModel model = new AutomatedTreeModel(root);
073    
074        private JTree tree = new JTree(model);
075    
076        private JScrollPane scrollPane = new JScrollPane(tree);
077    
078        private BuddyListPopupMenu buddyPopupMenu = new BuddyListPopupMenu();
079    
080        private GroupPopupMenu groupPopupMenu = new GroupPopupMenu();
081    
082        private BuddyListTransportMenu buddyTransportMenu = new BuddyListTransportMenu();
083    
084        private boolean showOfflineBuddies = Settings.getInstance().getBoolean(
085                "showOfflineBuddies");
086    
087        private boolean showUnfiledBuddies = Settings.getInstance().getBoolean(
088                "showUnfiledBuddies");
089    
090        private boolean showAgentBuddies = Settings.getInstance().getBoolean(
091                "showAgentBuddies");
092    
093        private boolean sortByStatus = Settings.getInstance().getBoolean(
094                "sortByStatus");
095    
096        private boolean showAwayBuddies = !Settings.getInstance().getBoolean("dontShowAwayBuddies");
097    
098        private BuddyListRenderer renderer = new BuddyListRenderer();
099    
100        protected Hashtable totalEntriesPerGroup = new Hashtable();
101    
102        protected Hashtable onlineEntriesPerGroup = new Hashtable();
103    
104        protected Hashtable groups = new Hashtable();
105    
106        private BuddyListExpansionListener expandListener = new BuddyListExpansionListener();
107    
108        private TreeMap buddyGroups = new TreeMap();
109    
110        // to sort the buddy groups
111    
112        /**
113         * Sets up the tree
114         */
115        public BuddyListTree() {
116            setLayout(new GridLayout(0, 1));
117            setBackground(Color.WHITE);
118    
119            tree.setCellRenderer(renderer);
120            tree.setRootVisible(false);
121            tree.setRowHeight(0);
122            tree.setShowsRootHandles(true);
123            tree.getSelectionModel().setSelectionMode(
124                    TreeSelectionModel.SINGLE_TREE_SELECTION);
125            tree.addMouseListener(new PopupMouseListener());
126            tree.addTreeExpansionListener(expandListener);
127    
128            ToolTipManager.sharedInstance().registerComponent(tree);
129            add(scrollPane);
130        }
131    
132        public void updateUI() {
133            super.updateUI();
134            if (buddyPopupMenu != null) {
135                buddyPopupMenu = new BuddyListPopupMenu();
136                groupPopupMenu = new GroupPopupMenu();
137            }
138        }
139    
140        /**
141         * Gets the popMenu attribute of the BuddyListTree object
142         *
143         * @return The popMenu value
144         */
145        public BuddyListPopupMenu getPopMenu() {
146            return buddyPopupMenu;
147        }
148    
149        /**
150         * Gets the groupPopMenu attribute of the BuddyListTree object
151         *
152         * @return The popMenu value
153         */
154        public GroupPopupMenu getGroupMenu() {
155            return groupPopupMenu;
156        }
157    
158        /**
159         * Returns the JTree
160         *
161         * @return the actual JTree swing component
162         */
163        public JTree getTree() {
164            return this.tree;
165        }
166    
167        /**
168         * Sets the JTree's XMPPConnection
169         *
170         * @param connection
171         *            the current connection
172         */
173        public void setConnection(XMPPConnection connection) {
174            this.connection = connection;
175            if (connection == null) {
176                return;
177            }
178            this.roster = ConnectorThread.getInstance().getRoster();
179        }
180    
181        /**
182         * Sets whether or not to show the offline buddies
183         *
184         * @param show
185         *            true to show the offline buddies
186         */
187        public void setShowOfflineBuddies(boolean show) {
188            this.showOfflineBuddies = show;
189            Settings.getInstance().setBoolean("showOfflineBuddies", show);
190    
191            reloadBuddies();
192        }
193    
194        public void setShowAwayBuddies(boolean show) {
195            this.showAwayBuddies = show;
196            Settings.getInstance().setBoolean("doneShowAwayBuddies", !show);
197            reloadBuddies();
198        }
199    
200        /**
201         * Sets whether or not to show the unfiled buddies
202         *
203         * @param show
204         *            true to show unfiled buddies
205         */
206        public void setShowUnfiledBuddies(boolean show) {
207            this.showUnfiledBuddies = show;
208            Settings.getInstance().setBoolean("showUnfiledBuddies", show);
209            reloadBuddies();
210        }
211    
212        /**
213         * Sets whether or not to show agents/transports
214         *
215         * @param show
216         *            true to show agents and transports
217         */
218        public void setShowAgentBuddies(boolean show) {
219            this.showAgentBuddies = show;
220            Settings.getInstance().setBoolean("showAgentBuddies", show);
221            reloadBuddies();
222        }
223    
224        /**
225         * set to true if you want to sort your buddies by status
226         *
227         * @param show
228         *            true to sort by status
229         */
230        public void setSortByStatus(boolean show) {
231            this.sortByStatus = show;
232            Settings.getInstance().setBoolean("sortByStatus", show);
233            reloadBuddies();
234        }
235    
236        /**
237         * @return true if sort by status is set
238         */
239        public boolean getSortByStatus() {
240            return this.sortByStatus;
241        }
242    
243        /**
244         * To listen to when a group gets expanded. Saves it in the settings for
245         * session restoration
246         *
247         * @author Adam Olsen
248         * @created March 2, 2005
249         * @version 1.0
250         */
251        static class BuddyListExpansionListener implements TreeExpansionListener {
252            /**
253             * Listens for a tree collapse event
254             *
255             * @param e
256             *            Description of the Parameter
257             */
258            public void treeCollapsed(TreeExpansionEvent e) {
259                TreePath path = e.getPath();
260                AutomatedTreeNode node = (AutomatedTreeNode) path
261                        .getLastPathComponent();
262    
263                if (node.getUserObject() instanceof BuddyGroup) {
264                    Settings.getInstance().setProperty(
265                            "groupExpandStatus_"
266                                    + ((BuddyGroup) node.getUserObject())
267                                            .getGroupName(), "collapsed");
268                }
269            }
270    
271            /**
272             * Listens for a tree expand event
273             *
274             * @param e
275             *            Description of the Parameter
276             */
277            public void treeExpanded(TreeExpansionEvent e) {
278                TreePath path = e.getPath();
279                AutomatedTreeNode node = (AutomatedTreeNode) path
280                        .getLastPathComponent();
281    
282                if (node.getUserObject() instanceof BuddyGroup) {
283                    Settings.getInstance().remove(
284                            "groupExpandStatus_"
285                                    + ((BuddyGroup) node.getUserObject())
286                                            .getGroupName());
287                }
288            }
289        }
290    
291        /**
292         * Redraws the JTree
293         */
294        public void reloadBuddies() {
295            reloadBuddies(false);
296        }
297    
298        /**
299         * Shows all the current offline buddies
300         */
301        public void loadOfflineBuddies() {
302            reloadBuddies(true);
303        }
304    
305        /**
306         * Redraws the JTree
307         *
308         * @param loadOffline
309         *            whether or not to just load the offline buddies
310         */
311        public void reloadBuddies(final boolean loadOffline) {
312            showOfflineBuddies = Settings.getInstance().getBoolean(
313                    "showOfflineBuddies");
314            SwingUtilities.invokeLater(new Runnable() {
315                public void run() {
316                    if (connection == null) {
317                        return;
318                    }
319                    if (roster == null) {
320                        roster = ConnectorThread.getInstance().getRoster();
321                        roster.reload();
322                    }
323    
324                    if (!loadOffline) {
325                        clearBuddies();
326                    }
327    
328                    // loop through all the RosterEntries and see if they need to be
329                    // added to the
330                    // BuddyList tree
331                    Iterator it = roster.getEntries();
332                    while (it.hasNext()) {
333                        RosterEntry entry = (RosterEntry) it.next();
334                        BuddyStatus buddy = BuddyList.getInstance().getBuddyStatus(
335                                entry.getUser());
336    
337                        checkAddEntry(buddy);
338    
339                    }
340    
341                    tree.repaint();
342                    tree.validate();
343                }
344            });
345        }
346    
347        /**
348         * Clears all the buddies from the JTree
349         */
350        public void clearBuddies() {
351            com.valhalla.Logger.debug("Clearing Buddies");
352            // clear the JTree and the BuddyGroups TreeMap
353            root.removeAllChildren();
354            buddyGroups.clear();
355            totalEntriesPerGroup.clear();
356        }
357    
358        /**
359         * We store all of the Group names in a TreeMap so that we can get the sort
360         * index when inserting the TreeNode for this group into the root node
361         *
362         * @param group
363         *            the name of the group
364         * @return The groupIndex value
365         */
366        private int getGroupIndex(String group) {
367            //synchronized (buddyGroups) {
368                if (buddyGroups.containsKey(group)) {
369                    return -1;
370                }
371                // we want General Contacts and Agents/Transports to always
372                // sort at the bottom
373                if (group.equals(resources.getString("contactsGroup"))) {
374                    group = "zzz Contacts";
375                } else if (group.equals(resources.getString("transportsGroup"))) {
376                    group = "zzzz Agents/Transports";
377                }
378    
379                buddyGroups.put(group, new TreeMap());
380    
381                int count = 0;
382    
383                // find the index of the newly sorted group
384                Iterator i = buddyGroups.keySet().iterator();
385                while (i.hasNext()) {
386                    String key = (String) i.next();
387                    if (key.equals(group)) {
388                        break;
389                    }
390                    count++;
391                }
392    
393                return count;
394            //}
395        }
396    
397        /**
398         * Finds out the sort index of this particular buddy
399         *
400         * @param group
401         *            the group the buddy is in
402         * @param buddy
403         *            the buddy to find the index of
404         * @return The buddyIndex value
405         */
406        private int getBuddyIndex(String group, BuddyStatus buddy) {
407            //synchronized (buddyGroups) {
408                if (group.equals(resources.getString("contactsGroup"))) {
409                    group = "zzz Contacts";
410                } else if (group.equals(resources.getString("transportsGroup"))) {
411                    group = "zzzz Agents/Transports";
412                } else if (group.equals(resources.getString("notInRoster"))) {
413                    group = "zzzz Not In Roster";
414                }
415    
416                String name = buddy.getName();
417                if (name == null) {
418                    name = buddy.getUser();
419                }
420                name = name.toLowerCase() + buddy.getUser().toLowerCase();
421    
422                if (sortByStatus) {
423                    // sort by status
424                    Presence.Mode mode = buddy.getPresence(buddy
425                            .getHighestResource());
426                    if (mode == null) {
427                        name = "zzz9555 " + name;
428                    } else if (mode == Presence.Mode.AVAILABLE) {
429                        name = "aa " + name;
430                    } else if (mode == Presence.Mode.CHAT) {
431                        name = "zzz9111 " + name;
432                    } else if (mode == Presence.Mode.AWAY) {
433                        name = "zzz9222 " + name;
434                    } else if (mode == Presence.Mode.EXTENDED_AWAY) {
435                        name = "zzz9333 " + name;
436                    } else if (mode == Presence.Mode.DO_NOT_DISTURB) {
437                        name = "zzz9444 " + name;
438                    }
439    
440                    if (buddy.size() <= 0) {
441                        name = "zzz9555 " + name;
442                    }
443                }
444    
445                if (buddyGroups.get(group) == null) {
446                    buddyGroups.put(group, new TreeMap());
447                }
448    
449                ((TreeMap) buddyGroups.get(group)).put(name, buddy.getUser());
450    
451                int count = 0;
452    
453                Iterator i = ((TreeMap) buddyGroups.get(group)).keySet().iterator();
454                while (i.hasNext()) {
455                    String key = (String) i.next();
456                    if (key.equals(name)) {
457                        break;
458                    }
459                    count++;
460                }
461                return count;
462            //}
463        }
464    
465        /**
466         * Checks to see if the group is already in the tree, and returns the index
467         * of it
468         *
469         * @param group
470         *            the group to check
471         * @return Description of the Return Value
472         */
473        public AutomatedTreeNode checkGroup(BuddyGroup group) {
474            boolean check = false;
475            AutomatedTreeNode node = new AutomatedTreeNode(group);
476    
477            Enumeration children = root.children();
478    
479            // find out if the group alread exists
480            whileLoop: while (children.hasMoreElements()) {
481                AutomatedTreeNode theNode = (AutomatedTreeNode) children
482                        .nextElement();
483                BuddyGroup g = (BuddyGroup) theNode.getUserObject();
484                if (g.getGroupName().equals(group.getGroupName())) {
485                    node = theNode;
486                    check = true;
487                    break whileLoop;
488                }
489            }
490    
491            if (root.isNodeChild(node)) {
492                return node;
493            }
494    
495            final String tempGroup = group.getGroupName();
496            final AutomatedTreeNode tempNode = node;
497    
498            if (!check) {
499                int num = getGroupIndex(tempGroup);
500                if (num >= 0) {
501                    root.insert(tempNode, num);
502                }
503            }
504    
505            group.setNode(node);
506    
507            return node;
508    
509        }
510    
511        private BuddyGroup getGroupObject(String name) {
512            String temp = name.replaceAll(" ([^)]*)$", "");
513    
514            if (!showUnfiledBuddies
515                    && temp.equals(resources.getString("contactsGroup"))) {
516                return null;
517            }
518            if (!showAgentBuddies
519                    && temp.equals(resources.getString("transportsGroup"))) {
520                return null;
521            }
522            BuddyGroup group = (BuddyGroup) groups.get(name);
523            if (group == null)
524                group = new BuddyGroup(name);
525            groups.put(name, group);
526            return group;
527        }
528    
529        /**
530         * finds out if the buddy should be displayed in the BuddyListTree. If so
531         * the buddy is added to the tree
532         *
533         * @param buddy
534         *            the buddy to add
535         */
536        public void checkAddEntry(final BuddyStatus buddy) {
537            if (buddy == null) {
538                return;
539            }
540    
541            boolean add = false;
542    
543            // if we are set to show the offline buddies then add the buddy to the
544            // tree
545            if (showOfflineBuddies) {
546                add = true;
547            } else {
548                // otherwise we have to find out if the buddy is online before we
549                // add it
550                if (buddy.size() > 0) {
551                    add = true;
552                }
553            }
554    
555            if(!showAwayBuddies)
556            {
557                Presence.Mode mode = buddy.getPresence(buddy.getHighestResource());
558                if( mode != null && mode != Presence.Mode.AVAILABLE ) add = false;
559            }
560    
561            if (buddy.getRemoved()) {
562                add = false;
563            }
564    
565            String tempGroup = buddy.getTempGroup();
566            if (tempGroup == null) {
567                tempGroup = buddy.getGroup();
568            }
569    
570            final String group = tempGroup;
571    
572            if( buddy.getRosterEntry() == null ) add = false;
573    
574            BuddyGroup gObj = getGroupObject(group);
575            if (gObj == null)
576                return;
577    
578            gObj.addBuddy(buddy);
579    
580            if (add) {
581                final AutomatedTreeNode node = checkGroup(gObj);
582                node.setUserObject(gObj);
583    
584                // find the group that the buddy belongs to
585                int index = getBuddyIndex(gObj.getGroupName(), buddy);
586    
587                if (!isInTree(buddy)) {
588                    node.insert(new AutomatedTreeNode(buddy), index);
589                }
590    
591                TreePath parent = new TreePath(root);
592                tree.expandPath(parent);
593    
594                // find out if we need to expand this group
595                String property = Settings.getInstance().getProperty(
596                        "groupExpandStatus_" + group);
597                if (property == null || !property.equals("collapsed")) {
598                    tree.expandPath(parent.pathByAddingChild(node));
599                }
600            }
601    
602        }
603    
604        /**
605         * Returns whether or not the buddy is in the tree
606         *
607         * @param buddy
608         *            the buddy to check
609         * @return true if the buddy is in the tree
610         */
611        public boolean isInTree(BuddyStatus buddy) {
612            String group = buddy.getGroup();
613    
614            // loop through all the groups until we find the group that this
615            // buddy belongs to
616            Enumeration children = root.children();
617            while (children.hasMoreElements()) {
618                AutomatedTreeNode node = (AutomatedTreeNode) children.nextElement();
619    
620                // once we find it's group, loop through all the buddies in that
621                // group
622                if (((BuddyGroup) node.getUserObject()).getGroupName()
623                        .equals(group)) {
624                    Enumeration leafs = node.children();
625                    while (leafs.hasMoreElements()) {
626                        AutomatedTreeNode leaf = (AutomatedTreeNode) leafs
627                                .nextElement();
628                        if (leaf.getUserObject() == buddy) {
629                            return true;
630                        }
631                    }
632                }
633            }
634    
635            return false;
636        }
637    
638        /**
639         * Adds a buddy to the tree - if it's not already in the tree
640         *
641         * @param buddy
642         *            the buddy to add
643         */
644        public void addBuddy(final BuddyStatus buddy) {
645            checkAddEntry(buddy);
646    
647            validate();
648            repaint();
649        }
650    
651        /**
652         * Removes the buddy from the tree
653         *
654         * @param buddy
655         *            the buddy to remove
656         * @param group
657         *            the group the buddy is in
658         */
659        public void removeBuddy(final BuddyStatus buddy, final String group,
660                final boolean removeFromGroup) {
661            // loop through all the groups until we find the group that this
662            // buddy belongs to
663            Enumeration children = root.children();
664            while (children.hasMoreElements()) {
665                AutomatedTreeNode node = (AutomatedTreeNode) children.nextElement();
666    
667                // once we find it's group, loop through all the buddies in that
668                // group
669                if (((BuddyGroup) node.getUserObject()).getGroupName()
670                        .equals(group)) {
671                    Enumeration leafs = node.children();
672                    while (leafs.hasMoreElements()) {
673                        AutomatedTreeNode leaf = (AutomatedTreeNode) leafs
674                                .nextElement();
675                        Object check = leaf.getUserObject();
676                        if (check instanceof BuddyStatus) {
677                            BuddyStatus temp = (BuddyStatus) check;
678    
679                            if (temp.getUser().equals(buddy.getUser())) {
680                                // once we find the buddy, remove it
681                                removeBuddyNode(node, leaf);
682                                if (removeFromGroup) {
683                                    BuddyGroup g = getGroupObject(group);
684                                    g.removeBuddy(buddy);
685                                }
686                            }
687                        }
688                    }
689                }
690            }
691    
692        }
693    
694        /**
695         * removes this buddy from the JTree. If this was the last buddy in the
696         * group then remove the group from being displayed
697         *
698         * @param node
699         *            the group node
700         * @param leaf
701         *            the leaf node
702         */
703        private void removeBuddyNode(final AutomatedTreeNode node,
704                final AutomatedTreeNode leaf) {
705            String group = ((BuddyGroup) node.getUserObject()).getGroupName();
706    
707            if (group == null || group.equals(resources.getString("contactsGroup"))) {
708                group = "zzz Contacts";
709            } else if (group.equals(resources.getString("transportsGroup"))) {
710                group = "zzzz Agents/Transports";
711            }
712    
713            BuddyStatus buddy = (BuddyStatus) leaf.getUserObject();
714    
715            String name = buddy.getName();
716            if (name == null) {
717                name = buddy.getUser();
718            }
719            String jid = buddy.getUser();
720    
721           // synchronized (buddyGroups) {
722                TreeMap buddies = ((TreeMap) buddyGroups.get(group));
723                Iterator i = buddies.keySet().iterator();
724                while (i.hasNext()) {
725                    String key = (String) i.next();
726                    if (buddies.get(key).equals(jid)) {
727                        ((TreeMap) buddyGroups.get(group)).remove(key);
728                        break;
729                    }
730                }
731    
732           // }
733    
734            node.remove(leaf);
735            if (node.getChildCount() <= 0) {
736                buddyGroups.remove(group);
737                root.remove(node);
738            }
739    
740            tree.repaint();
741        }
742    
743        /**
744         * Starts a conversation if someone double double clicks on a buddy
745         */
746        public void initiateConversation(BuddyStatus buddy) {
747            if (buddy == null) {
748                if (tree.getSelectionPath() == null) {
749                    return;
750                }
751    
752                TreePath path = tree.getSelectionPath();
753                AutomatedTreeNode node = (AutomatedTreeNode) path
754                        .getLastPathComponent();
755                if (model.isLeaf(node)) {
756                    try {
757                        buddy = (BuddyStatus) node.getUserObject();
758                    } catch (ClassCastException ex) {
759                        return;
760                    }
761                }
762            }
763    
764            if (buddy == null)
765                return;
766    
767            if (buddy.getConversation() == null) {
768                ChatPanel conver = new ChatPanel(buddy);
769                buddy.setConversation(conver);
770    
771                MessageDelegator.getInstance().showPanel(buddy.getConversation());
772                MessageDelegator.getInstance().frontFrame(buddy.getConversation());
773            } else {
774                MessageDelegator.getInstance().showPanel(buddy.getConversation());
775                MessageDelegator.getInstance().frontFrame(buddy.getConversation());
776            }
777    
778            buddy.getConversation().stopTimer();
779        }
780    
781        /**
782         * Listens for mouse events in the tree
783         *
784         * @author Adam Olsen
785         * @created March 2, 2005
786         * @version 1.0
787         */
788        class PopupMouseListener extends MouseAdapter {
789            /**
790             * Description of the Method
791             *
792             * @param e
793             *            Description of the Parameter
794             */
795            public void mousePressed(MouseEvent e) {
796                checkPop(e);
797            }
798    
799            /**
800             * Description of the Method
801             *
802             * @param e
803             *            Description of the Parameter
804             */
805            public void mouseReleased(MouseEvent e) {
806                checkPop(e);
807            }
808    
809            /**
810             * Description of the Method
811             *
812             * @param e
813             *            Description of the Parameter
814             */
815            public void mouseClicked(MouseEvent e) {
816                checkPop(e);
817                try {
818                    JTree tree = (JTree) e.getComponent();
819                } catch (ClassCastException ex) {
820                    return;
821                }
822    
823                if (e.getClickCount() >= 2) {
824                    e.consume();
825                    initiateConversation(null);
826                }
827            }
828    
829            /**
830             * Checks if we need to display the buddy list popup menu Shows it if
831             * needs be
832             *
833             * @param e
834             *            Description of the Parameter
835             */
836            public void checkPop(MouseEvent e) {
837                BuddyStatus buddy = null;
838    
839                if (e.isPopupTrigger()) {
840                    try {
841    
842                        JTree tree = (JTree) e.getComponent();
843    
844                        TreePath path = tree.getPathForLocation(e.getX(), e.getY());
845                        if (path == null) {
846                            throw new ClassCastException();
847                        }
848    
849                        tree.setSelectionPath(path);
850    
851                        AutomatedTreeNode node = (AutomatedTreeNode) path
852                                .getLastPathComponent();
853                        Object selectedUserObject = node.getUserObject();
854                        if (selectedUserObject.getClass().equals(BuddyStatus.class)) {
855                            buddy = (BuddyStatus) node.getUserObject();
856                            buddyPopupMenu.showMenu(e.getComponent(), e.getX(), e
857                                    .getY(), buddy);
858                        } else if (selectedUserObject.getClass().equals(
859                                BuddyGroup.class)) {
860                            // buddies that are not in any group are put in
861                            // "Contacts" group by JBother
862                            // if we need to send a message to them, we need to
863                            // extract them from the tree
864                            // because there is no way to do it from the roster
865                            Enumeration iChildren = node.children();
866                            String usersList = new String();
867                            while (iChildren.hasMoreElements())
868                            {
869                                AutomatedTreeNode o = (AutomatedTreeNode) iChildren
870                                        .nextElement();
871                                BuddyStatus buddyStatus = (BuddyStatus) o
872                                        .getUserObject();
873                                usersList += buddyStatus.getUser() + MessagePanel.RECIPIENTS_DELIMITER + " ";
874                            }
875                            // get rid of 'unneeded delimiter + space' string at the end
876                            usersList = usersList.substring(0, usersList.length() -
877                              (MessagePanel.RECIPIENTS_DELIMITER.length() + 1));
878                            groupPopupMenu.showMenu(e.getComponent(), e.getX(), e
879                                    .getY(), usersList,
880                                    (BuddyGroup) selectedUserObject);
881                        }
882                        buddy = (BuddyStatus) node.getUserObject();
883    
884                        if (buddy.getUser().indexOf("@") == -1) {
885                            buddyTransportMenu.showMenu(e.getComponent(), e.getX(),
886                                    e.getY(), buddy);
887                        } else {
888                            buddyPopupMenu.showMenu(e.getComponent(), e.getX(), e
889                                    .getY(), buddy);
890                        }
891                    } catch (ClassCastException ex) {
892                        /*
893                         * is not a buddy, so don't display the menu
894                         */
895                    }
896                }
897            }
898        }
899    }