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 }