KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > suberic > pooka > gui > FolderNode


1 package net.suberic.pooka.gui;
2 import javax.swing.*;
3 import java.awt.Cursor JavaDoc;
4 import java.awt.event.ActionEvent JavaDoc;
5 import javax.swing.tree.*;
6 import javax.mail.Store JavaDoc;
7 import javax.mail.Folder JavaDoc;
8 import javax.mail.MessagingException JavaDoc;
9 import java.util.*;
10 import net.suberic.pooka.*;
11 import net.suberic.util.thread.*;
12 import javax.mail.FolderNotFoundException JavaDoc;
13 import net.suberic.pooka.FolderInfo;
14 import javax.mail.event.*;
15
16 public class FolderNode extends MailTreeNode implements MessageChangedListener, UserProfileContainer, ConnectionListener {
17
18   protected FolderInfo folderInfo = null;
19   protected boolean hasLoaded = false;
20
21
22   /**
23    * creates a tree node that points to a folder
24    *
25    * @param newFolderthe store for this node
26    * @param newParent the parent component
27    */

28   public FolderNode(FolderInfo newFolderInfo, JComponent newParent) {
29     super(newFolderInfo, newParent);
30     folderInfo = newFolderInfo;
31
32     folderInfo.setFolderNode(this);
33
34     commands = new Hashtable();
35
36     defaultActions = new Action[] {
37       new ActionWrapper(new OpenAction(), folderInfo.getFolderThread()),
38       new ActionWrapper(new ReconnectAction(), folderInfo.getFolderThread()),
39       new ActionWrapper(new CloseAction(), folderInfo.getFolderThread()),
40       new UnsubscribeAction(),
41       new NewFolderAction(),
42       new DeleteAction()
43     };
44
45     Action[] actions = defaultActions;
46
47     if (actions != null) {
48       for (int i = 0; i < actions.length; i++) {
49         Action a = actions[i];
50         commands.put(a.getValue(Action.NAME), a);
51       }
52     }
53
54     folderInfo.addMessageCountListener(new MessageCountAdapter() {
55         public void messagesAdded(MessageCountEvent e) {
56           if ( folderInfo.notifyNewMessagesMain()) {
57             Pooka.getUIFactory().getMessageNotificationManager().notifyNewMessagesReceived(e, getFolderInfo().getFolderID());
58           }
59           updateNode();
60         }
61
62         public void messagesRemoved(MessageCountEvent e) {
63           updateNode();
64
65         }
66       });
67
68     folderInfo.addMessageChangedListener(this);
69     folderInfo.addConnectionListener(this);
70     loadChildren();
71
72   }
73
74
75   /**
76    * a Folder is a leaf if it cannot contain sub folders
77    */

78   public boolean isLeaf() {
79     if (getChildCount() < 1)
80       return true;
81     else
82       return false;
83   }
84
85   /**
86    * returns the folder for this node
87    */

88   public Folder JavaDoc getFolder() {
89     return folderInfo.getFolder();
90   }
91
92   /**
93    * This loads (or reloads) the children of the FolderNode from
94    * the list of Children on the FolderInfo.
95    *
96    * Runs on the event dispatch thread, but is safe to be called from anywhere.
97    */

98   public void loadChildren() {
99     Runnable JavaDoc runMe = new Runnable JavaDoc() {
100         public void run() {
101           doLoadChildren();
102         }
103       };
104
105     if (SwingUtilities.isEventDispatchThread())
106       doLoadChildren();
107     else {
108       try {
109         SwingUtilities.invokeAndWait(runMe);
110       } catch (Exception JavaDoc ie) {
111       }
112     }
113   }
114
115   /**
116    * Does the actual work for loading the children. performed on the swing
117    * gui thread.
118    */

119   private void doLoadChildren() {
120     Enumeration origChildren = super.children();
121     Vector origChildrenVector = new Vector();
122     while (origChildren.hasMoreElements())
123       origChildrenVector.add(origChildren.nextElement());
124
125     Vector folderChildren = getFolderInfo().getChildren();
126
127     if (folderChildren != null) {
128       for (int i = 0; i < folderChildren.size(); i++) {
129         FolderNode node = popChild(((FolderInfo)folderChildren.elementAt(i)).getFolderName(), origChildrenVector);
130         if (node == null) {
131           node = new FolderNode((FolderInfo)folderChildren.elementAt(i), getParentContainer());
132           // we used insert here, since add() would mak
133
// another recursive call to getChildCount();
134
insert(node, 0);
135         }
136       }
137
138     }
139
140     removeChildren(origChildrenVector);
141
142     hasLoaded=true;
143
144     //((javax.swing.tree.DefaultTreeModel)(((FolderPanel)getParentContainer()).getFolderTree().getModel())).nodeStructureChanged(this);
145
}
146
147   /**
148    * This goes through the Vector of FolderNodes provided and
149    * returns the FolderNode for the given childName, if one exists.
150    * It will also remove the Found FolderNode from the childrenList
151    * Vector.
152    *
153    * If a FolderNode that corresponds with the given childName does
154    * not exist, this returns null.
155    *
156    */

157   public FolderNode popChild(String JavaDoc childName, Vector childrenList) {
158     if (children != null) {
159       for (int i = 0; i < childrenList.size(); i++)
160         if (((FolderNode)childrenList.elementAt(i)).getFolderInfo().getFolderName().equals(childName)) {
161           FolderNode fn = (FolderNode)childrenList.elementAt(i);
162           childrenList.remove(fn);
163           return fn;
164         }
165     }
166
167     // no match.
168
return null;
169   }
170
171   /**
172    * This creates the current PopupMenu if there is not one. It then
173    * will configure the PopupMenu with the current actions.
174    *
175    * Overrides MailTreeNode.configurePopupMenu();
176    */

177
178   public void configurePopupMenu() {
179     if (popupMenu == null) {
180       popupMenu = new net.suberic.util.gui.ConfigurablePopupMenu();
181       if (getFolderInfo().isTrashFolder())
182         popupMenu.configureComponent("TrashFolderNode.popupMenu", Pooka.getResources());
183       else if (getFolderInfo().isOutboxFolder())
184         popupMenu.configureComponent("OutboxFolderNode.popupMenu", Pooka.getResources());
185       else if (getFolderInfo() instanceof net.suberic.pooka.cache.CachingFolderInfo && ! ((net.suberic.pooka.cache.CachingFolderInfo) getFolderInfo()).getCacheHeadersOnly())
186         popupMenu.configureComponent("CachingFolderNode.popupMenu", Pooka.getResources());
187       else
188         popupMenu.configureComponent("FolderNode.popupMenu", Pooka.getResources());
189
190       updatePopupTheme();
191
192     }
193
194     popupMenu.setActive(getActions());
195   }
196
197   /**
198    * This removes all the items in removeList from the list of this
199    * node's children.
200    */

201   public void removeChildren(Vector removeList) {
202     for (int i = 0; i < removeList.size(); i++) {
203       if (removeList.elementAt(i) instanceof javax.swing.tree.MutableTreeNode JavaDoc)
204         this.remove((javax.swing.tree.MutableTreeNode JavaDoc)removeList.elementAt(i));
205     }
206   }
207
208   /**
209    * This makes the FolderNode visible in its parent JTree.
210    */

211   public void makeVisible() {
212     javax.swing.SwingUtilities.invokeLater(new Runnable JavaDoc() {
213         public void run() {
214           javax.swing.JTree JavaDoc folderTree = ((FolderPanel)getParentContainer()).getFolderTree();
215           TreeNode[] nodeList = ((DefaultTreeModel)folderTree.getModel()).getPathToRoot(FolderNode.this);
216           TreePath path = new TreePath(nodeList);
217           folderTree.makeVisible(path);
218         }
219       });
220   }
221
222   public void messageChanged(MessageChangedEvent mce) {
223     updateNode();
224   }
225
226   public void closed(ConnectionEvent e) {
227     updateNode();
228   }
229
230   public void opened(ConnectionEvent e) {
231     updateNode();
232   }
233
234   public void disconnected(ConnectionEvent e) {
235     updateNode();
236   }
237
238
239   int lastFolderStatus = -1;
240   boolean lastUnread = false;
241   boolean lastNewMessages = false;
242
243   /**
244    * Checks to see if the Folder's status has changed from the last time
245    * we redrew this node. If it has, then we redraw the node.
246    */

247   public void updateNode() {
248     javax.swing.SwingUtilities.invokeLater(new Runnable JavaDoc() {
249         public void run() {
250           FolderInfo fi = getFolderInfo();
251           if (fi != null) {
252             int currentStatus = fi.getStatus();
253             boolean hasUnread = fi.hasUnread();
254             boolean hasNewMessages = fi.hasNewMessages();
255
256             if (currentStatus != lastFolderStatus || hasUnread != lastUnread || hasNewMessages != lastNewMessages) {
257               lastFolderStatus = currentStatus;
258               lastUnread = hasUnread;
259               lastNewMessages = hasNewMessages;
260               //getParentContainer().repaint();
261
javax.swing.JTree JavaDoc folderTree = ((FolderPanel)getParentContainer()).getFolderTree();
262               ((DefaultTreeModel)folderTree.getModel()).nodeChanged(FolderNode.this);
263             }
264           }
265         }
266       });
267   }
268
269   /**
270    * This opens up a dialog asking if the user wants to unsubsribe to
271    * the current Folder. If the user chooses 'yes', then
272    * getFolderInfo().unsubscribe() is called.
273    */

274   public void unsubscribeFolder() {
275     String JavaDoc message;
276     if (isLeaf())
277       message = Pooka.getProperty("Folder.unsubscribeConfirm", "Do you really want to unsubscribe from the following folder?");
278     else
279       message = Pooka.getProperty("Folder.unsubscribeConfirm.notLeaf", "Do you really want to unsubscribe from \nthis folder and all its children?");
280
281     int response = Pooka.getUIFactory().showConfirmDialog(message + "\n" + getFolderInfo().getFolderName(), Pooka.getProperty("Folder.unsubscribeConfirm.title", "Unsubscribe from Folder"), JOptionPane.YES_NO_OPTION);
282
283     if (response == JOptionPane.YES_OPTION) {
284       getFolderInfo().getFolderThread().addToQueue(new javax.swing.AbstractAction JavaDoc() {
285           public void actionPerformed(java.awt.event.ActionEvent JavaDoc e) {
286             getFolderInfo().unsubscribe();
287           }
288         } , new java.awt.event.ActionEvent JavaDoc(this, 0, "folder-unsubscribe"));
289     }
290   }
291
292   /**
293    * This opens up a dialog asking if the user wants to delete
294    * the current Folder. If the user chooses 'yes', then
295    * getFolderInfo().delete() is called.
296    */

297   public void deleteFolder() {
298     String JavaDoc message;
299     if (isLeaf())
300       message = Pooka.getProperty("Folder.deleteConfirm", "Do you really want to delete from the following folder?");
301     else
302       message = Pooka.getProperty("Folder.deleteConfirm.notLeaf", "Do you really want to delete \nthis folder and all its children?");
303
304     int response = Pooka.getUIFactory().showConfirmDialog(message + "\n" + getFolderInfo().getFolderName(), Pooka.getProperty("Folder.deleteConfirm.title", "Delete Folder"), JOptionPane.YES_NO_OPTION);
305
306     if (response == JOptionPane.YES_OPTION) {
307       message = Pooka.getProperty("Folder.deleteConfirm.secondMessage", "Are you sure? This will permanently remove the folder and all of its messages");
308       int responseTwo = Pooka.getUIFactory().showConfirmDialog(message, Pooka.getProperty("Folder.deleteConfirm.secondMessage.title", "Are you sure?"), JOptionPane.YES_NO_OPTION);
309       if (responseTwo == JOptionPane.YES_OPTION) {
310
311         getFolderInfo().getFolderThread().addToQueue(new javax.swing.AbstractAction JavaDoc() {
312             public void actionPerformed(java.awt.event.ActionEvent JavaDoc e) {
313               try {
314                 getFolderInfo().delete();
315               } catch(MessagingException JavaDoc me) {
316                 final Exception JavaDoc fme = me;
317                 SwingUtilities.invokeLater(new Runnable JavaDoc() {
318                     public void run() {
319                       Pooka.getUIFactory().showError("Error deleting folder: ", fme);
320                     }
321                   });
322               }
323             }
324           } , new java.awt.event.ActionEvent JavaDoc(this, 0, "folder-delete"));
325       }
326     }
327   }
328
329   /**
330    * This opens up a dialog asking if the user wants to subscribe to a
331    * subfolder.
332    */

333   public void newFolder() {
334     if ((getFolderInfo().getType() & Folder.HOLDS_FOLDERS) != 0) {
335       String JavaDoc message = Pooka.getProperty("Folder.newFolder", "Subscribe/create new subfolder of") + " " + getFolderInfo().getFolderName();
336
337       JLabel messageLabel = new JLabel(message);
338
339       JPanel typePanel = new JPanel();
340       typePanel.setBorder(BorderFactory.createEtchedBorder());
341
342       JRadioButton messagesButton = new JRadioButton(Pooka.getProperty("Folder.new.messages.label", "Contains Messages"), true);
343       JRadioButton foldersButton = new JRadioButton(Pooka.getProperty("Folder.new.folders.label", "Contains Folders"));
344
345       ButtonGroup bg = new ButtonGroup();
346       bg.add(messagesButton);
347       bg.add(foldersButton);
348
349       typePanel.add(messagesButton);
350       typePanel.add(foldersButton);
351
352       Object JavaDoc[] inputPanels = new Object JavaDoc[] {
353         messageLabel,
354         typePanel
355       };
356
357       final String JavaDoc response = Pooka.getUIFactory().showInputDialog(inputPanels, Pooka.getProperty("Folder.new.title", "Create new Folder"));
358
359       int type = javax.mail.Folder.HOLDS_MESSAGES;
360       if (foldersButton.isSelected()) {
361         type = javax.mail.Folder.HOLDS_FOLDERS;
362       }
363
364       final int finalType = type;
365
366       if (response != null && response.length() > 0) {
367         getFolderInfo().getFolderThread().addToQueue(new javax.swing.AbstractAction JavaDoc() {
368             public void actionPerformed(java.awt.event.ActionEvent JavaDoc e) {
369               try {
370                 getFolderInfo().createSubFolder(response, finalType);
371               } catch (MessagingException JavaDoc me) {
372                 final Exception JavaDoc fme = me;
373                 SwingUtilities.invokeLater(new Runnable JavaDoc() {
374                     public void run() {
375                       Pooka.getUIFactory().showError(fme.getMessage());
376                     }
377                   });
378
379                 me.printStackTrace();
380               }
381             }
382           } , new java.awt.event.ActionEvent JavaDoc(this, 0, "folder-new"));
383       }
384     }
385   }
386
387   /**
388    * Opens the folder.
389    */

390   public void openFolder(boolean pReconnect) {
391     openFolder(pReconnect, true);
392   }
393
394   /**
395    * Opens the folder.
396    */

397   public void openFolder(boolean pReconnect, boolean pSelectFolder) {
398
399     try {
400       getFolderInfo().loadAllMessages();
401
402       if (! getFolderInfo().isSortaOpen() || (pReconnect && ! getFolderInfo().isConnected())) {
403         getFolderInfo().openFolder(javax.mail.Folder.READ_WRITE, pReconnect);
404       }
405
406       int firstUnread = -1;
407       int messageCount = -1;
408
409       final int folderType = getFolderInfo().getType();
410
411       if (getFolderInfo().isSortaOpen() && (folderType & Folder.HOLDS_MESSAGES) != 0 && getFolderInfo().getFolderDisplayUI() == null) {
412         firstUnread = getFolderInfo().getFirstUnreadMessage();
413         messageCount = getFolderInfo().getMessageCount();
414       }
415
416       final int finalFirstUnread = firstUnread;
417       final int finalMessageCount = messageCount;
418       final boolean fSelectFolder = pSelectFolder;
419
420       SwingUtilities.invokeLater(new Runnable JavaDoc() {
421           public void run() {
422
423             if ((folderType & Folder.HOLDS_MESSAGES) != 0) {
424               if (getFolderInfo().getFolderDisplayUI() != null) {
425                 getFolderInfo().getFolderDisplayUI().openFolderDisplay(fSelectFolder);
426               } else {
427                 getFolderInfo().setFolderDisplayUI(Pooka.getUIFactory().createFolderDisplayUI(getFolderInfo()));
428                 if (Pooka.getProperty("Pooka.autoSelectFirstUnread", "true").equalsIgnoreCase("true")) {
429                   if (finalFirstUnread >= 0)
430                     getFolderInfo().getFolderDisplayUI().selectMessage(finalFirstUnread);
431                   else
432                     getFolderInfo().getFolderDisplayUI().selectMessage(finalMessageCount);
433                 } else {
434                   if (finalFirstUnread >= 0)
435                     getFolderInfo().getFolderDisplayUI().makeSelectionVisible(finalFirstUnread);
436                   else
437                     getFolderInfo().getFolderDisplayUI().makeSelectionVisible(finalMessageCount);
438
439                 }
440                 getFolderInfo().getFolderDisplayUI().openFolderDisplay(fSelectFolder);
441               }
442
443             }
444             if ((folderType & Folder.HOLDS_FOLDERS) != 0) {
445               javax.swing.JTree JavaDoc folderTree = ((FolderPanel)getParentContainer()).getFolderTree();
446               folderTree.expandPath(folderTree.getSelectionPath());
447             }
448           }
449         });
450     } catch (MessagingException JavaDoc me) {
451       final MessagingException JavaDoc newMe = me;
452       SwingUtilities.invokeLater(new Runnable JavaDoc() {
453           public void run() {
454             Pooka.getUIFactory().showError(Pooka.getProperty("error.Folder.openFailed", "Failed to open folder") + " " + getFolderInfo().getFolderID(), newMe);
455           }
456         });
457     }
458
459   }
460
461   /**
462    * Returns the FolderID of the FolderInfo that's defining this FolderNode.
463    */

464   public String JavaDoc getFolderID() {
465     return getFolderInfo().getFolderID();
466   }
467
468   /**
469    * Returns the FolderInfo that's defining this FolderNode.
470    */

471   public FolderInfo getFolderInfo() {
472     return folderInfo;
473   }
474
475   /**
476    * override toString() since we only want to display a folder's
477    * name, and not the full path of the folder
478    */

479   public String JavaDoc toString() {
480     if (getFolderInfo() != null) {
481       String JavaDoc folderName = getFolderInfo().getFolderName();
482       if (getFolderInfo().hasUnread()) {
483         return folderName + " (" + getFolderInfo().getUnreadCount() + ")";
484       } else {
485         return folderName;
486       }
487     } else {
488       return "no folder name";
489     }
490   }
491
492
493   //As specified by interface net.suberic.pooka.UserProfileContainer
494
public UserProfile getDefaultProfile() {
495     if (getFolderInfo() != null)
496       return getFolderInfo().getDefaultProfile();
497     else
498       return null;
499   }
500
501   public Action[] getActions() {
502     if (getFolderInfo().getActions() != null)
503       return javax.swing.text.TextAction.augmentList(getFolderInfo().getActions(), defaultActions);
504     else
505       return defaultActions;
506   }
507
508   public Action[] defaultActions;
509
510   class OpenAction extends AbstractAction {
511
512     OpenAction() {
513       super("file-open");
514     }
515
516     OpenAction(String JavaDoc nm) {
517       super(nm);
518     }
519
520     public void actionPerformed(ActionEvent JavaDoc e) {
521       SwingUtilities.invokeLater(new Runnable JavaDoc() {
522           public void run() {
523             ((FolderPanel)getParentContainer()).getMainPanel().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
524           }
525         });
526
527       openFolder(false);
528
529       SwingUtilities.invokeLater(new Runnable JavaDoc() {
530           public void run() {
531             ((FolderPanel)getParentContainer()).getMainPanel().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
532           }
533         });
534     }
535
536   }
537
538   class ReconnectAction extends AbstractAction {
539
540     ReconnectAction() {
541       super("folder-connect");
542     }
543
544     ReconnectAction(String JavaDoc nm) {
545       super(nm);
546     }
547
548     public void actionPerformed(ActionEvent JavaDoc e) {
549       SwingUtilities.invokeLater(new Runnable JavaDoc() {
550           public void run() {
551             ((FolderPanel)getParentContainer()).getMainPanel().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
552           }
553         });
554
555       openFolder(true);
556
557       SwingUtilities.invokeLater(new Runnable JavaDoc() {
558           public void run() {
559             ((FolderPanel)getParentContainer()).getMainPanel().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
560           }
561         });
562     }
563
564   }
565
566   class UnsubscribeAction extends AbstractAction {
567
568     UnsubscribeAction() {
569       super("folder-unsubscribe");
570     }
571
572     public void actionPerformed(ActionEvent JavaDoc e) {
573       unsubscribeFolder();
574     }
575
576   }
577
578   class DeleteAction extends AbstractAction {
579
580     DeleteAction() {
581       super("folder-delete");
582     }
583
584     public void actionPerformed(ActionEvent JavaDoc e) {
585       deleteFolder();
586     }
587
588   }
589
590   class NewFolderAction extends AbstractAction {
591
592     NewFolderAction() {
593       super("folder-new");
594     }
595
596     public void actionPerformed(ActionEvent JavaDoc e) {
597       newFolder();
598     }
599
600   }
601
602   class CloseAction extends AbstractAction {
603
604     CloseAction() {
605       super("folder-close");
606     }
607
608     public void actionPerformed(ActionEvent JavaDoc e) {
609       try {
610         getFolderInfo().closeFolder(false);
611       } catch (Exception JavaDoc ex) {
612         System.out.println("caught exception: " + ex.getMessage());
613       }
614     }
615
616   }
617 }
618
619
Popular Tags