KickJava   Java API By Example, From Geeks To Geeks.

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


1 package net.suberic.pooka.gui;
2 import net.suberic.pooka.*;
3 import javax.mail.*;
4 import javax.mail.internet.MimeMessage JavaDoc;
5 import javax.mail.event.*;
6 import java.awt.*;
7 import java.awt.event.*;
8 import javax.swing.*;
9 import javax.swing.table.*;
10 import javax.swing.text.TextAction JavaDoc;
11 import java.util.*;
12 import net.suberic.util.gui.*;
13 import net.suberic.util.event.*;
14 import net.suberic.util.thread.*;
15 import net.suberic.util.swing.*;
16 import net.suberic.pooka.gui.dnd.FolderTransferHandler;
17
18 /**
19  * This is a JPanel which contains a JTable which displays the messages in
20  * the table.
21  *
22  * Note that this class does not actually do any real work. It does have
23  * Actions, but those are just passed on from the MessageProxy object in
24  * the table. You will need to have another component which implements
25  * FolderDisplayUI to use as the actual UI object for the Folder. That
26  * component can then use the FolderDisplayPanel to display the messages.
27  *
28  */

29
30 public class FolderDisplayPanel extends JPanel {
31   JTable messageTable = null;
32   JScrollPane scrollPane = null;
33   FolderInfo folderInfo = null;
34   boolean enabled = true;
35
36   boolean validated = false;
37   boolean useFolderColumnSizes = true;
38
39   public static String JavaDoc GLOBAL_COLUMN_PROPERTY_ROOT="PreviewFolderTable";
40
41   /**
42    * Creates an empty FolderDisplayPanel.
43    */

44   public FolderDisplayPanel() {
45     initWindow();
46     enabled=false;
47   }
48
49   /**
50    * Creates a FolderDisplayPanel for the given FolderInfo.
51    */

52   public FolderDisplayPanel(FolderInfo newFolderInfo) {
53     this(newFolderInfo, true);
54   }
55
56   /**
57    * Creates a FolderDisplayPanel for the given FolderInfo.
58    */

59   public FolderDisplayPanel(FolderInfo newFolderInfo, boolean pUseFolderColumnSizes) {
60     initWindow();
61     setFolderInfo(newFolderInfo);
62     addMessageTable();
63     useFolderColumnSizes = pUseFolderColumnSizes;
64   }
65
66   /**
67    * Initializes the window.
68    */

69
70   public void initWindow() {
71     scrollPane = new JScrollPane();
72     this.setLayout(new BorderLayout());
73     this.add("Center", scrollPane);
74
75     this.setPreferredSize(new Dimension(Integer.parseInt(Pooka.getProperty("folderWindow.height", "570")), Integer.parseInt(Pooka.getProperty("folderWindow.width","380"))));
76
77     // if the FolderDisplayPanel itself gets the focus, pass it on to
78
// the messageTable
79
this.addFocusListener(new FocusAdapter() {
80         public void focusGained(FocusEvent e) {
81           java.util.logging.Logger.getLogger("Pooka.debug.gui.focus").fine("folder display panel: gained focus.");
82
83           if (messageTable != null) {
84             messageTable.requestFocusInWindow();
85           }
86           Pooka.getMainPanel().refreshActiveMenus();
87           if (getFolderInfo() != null && getFolderInfo().hasNewMessages()) {
88             getFolderInfo().setNewMessages(false);
89             FolderNode fn = getFolderInfo().getFolderNode();
90             if (fn != null)
91               fn.getParentContainer().repaint();
92           }
93         }
94       });
95
96     JScrollBar jsb = scrollPane.getVerticalScrollBar();
97     if (jsb != null) {
98       jsb.addAdjustmentListener(new AdjustmentListener() {
99           public void adjustmentValueChanged(AdjustmentEvent e) {
100             if (getFolderInfo() != null && getFolderInfo().hasNewMessages()) {
101               getFolderInfo().setNewMessages(false);
102               FolderNode fn = getFolderInfo().getFolderNode();
103               if (fn != null)
104                 fn.getParentContainer().repaint();
105             }
106           }
107
108         });
109     }
110
111     Pooka.getHelpBroker().enableHelpKey(this, "ui.folderWindow", Pooka.getHelpBroker().getHelpSet());
112
113     setTransferHandler(new FolderTransferHandler());
114
115   }
116
117   /**
118    * Creates the JTable for the FolderInfo and adds it to the component.
119    */

120   public void addMessageTable() {
121     if (folderInfo != null) {
122       createMessageTable();
123       scrollPane.getViewport().add(messageTable);
124     }
125
126   }
127
128   /**
129    * This creates the messageTable.
130    */

131   public void createMessageTable() {
132     messageTable=new JTable(getFolderInfo().getFolderTableModel()) {
133         public String JavaDoc getToolTipText(MouseEvent event) {
134           int rowIndex = rowAtPoint(event.getPoint());
135           int columnIndex = columnAtPoint(event.getPoint());
136           Object JavaDoc value = getValueAt(rowIndex, columnIndex);
137           if (value != null) {
138             return value.toString();
139           } else {
140             return null;
141           }
142         }
143       };
144
145     if (!Pooka.getProperty("FolderTable.showLines", "true").equals("true")) {
146       messageTable.setShowVerticalLines(false);
147       messageTable.setShowHorizontalLines(false);
148     }
149
150     FolderTableModel ftm = getFolderInfo().getFolderTableModel();
151     for (int i = 0; i < messageTable.getColumnCount(); i++) {
152       if (useFolderColumnSizes) {
153         messageTable.getColumnModel().getColumn(i).setPreferredWidth(ftm.getColumnSize(i));
154       } else {
155         int colSize = 10;
156         try {
157           colSize = Integer.parseInt(Pooka.getProperty(GLOBAL_COLUMN_PROPERTY_ROOT + "." + ftm.getColumnId(i) + ".size", "10"));
158         } catch (Exception JavaDoc e) {
159           // just use the default.
160
}
161         messageTable.getColumnModel().getColumn(i).setPreferredWidth(colSize);
162       }
163     }
164
165     messageTable.setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN);
166
167     messageTable.setDefaultRenderer(Object JavaDoc.class, new FilterFolderCellRenderer());
168     messageTable.setDefaultRenderer(Number JavaDoc.class, new FilterFolderCellRenderer());
169
170     messageTable.setCellSelectionEnabled(false);
171     messageTable.setColumnSelectionAllowed(false);
172     messageTable.setRowSelectionAllowed(true);
173     addListeners();
174
175     messageTable.setTransferHandler(new FolderTransferHandler());
176
177     messageTable.setDragEnabled(true);
178
179   }
180
181   /**
182    * This removes the current message table.
183    */

184   public void removeMessageTable() {
185     if (messageTable != null) {
186       scrollPane.getViewport().remove(messageTable);
187       if (getFolderInfo() != null)
188         getFolderInfo().getFolderTableModel().removeTableModelListener(messageTable);
189       messageTable = null;
190     }
191   }
192
193   /**
194    * This removes rows from the FolderTableModel. This is the preferred
195    * way to remove rows from the FolderTableModel.
196    *
197    * Called from within the FolderThread.
198    */

199   public void removeRows(java.util.List JavaDoc removedProxies) {
200     //This is here so that we can select the next row and remove the
201
//removed rows together in one call to the AWTEventThread.
202
final java.util.List JavaDoc removedProxiesTmp = removedProxies;
203
204     try {
205       SwingUtilities.invokeAndWait(new Runnable JavaDoc() {
206           public void run() {
207             moveSelectionOnRemoval(removedProxiesTmp);
208
209             getFolderTableModel().removeRows(removedProxiesTmp);
210           }
211         });
212     } catch (Exception JavaDoc e) {
213     }
214   }
215
216   /**
217    * This checks to see if the message which has been removed is
218    * currently selected. If so, we unselect it and select the next
219    * row.
220    */

221   public void moveSelectionOnRemoval(MessageChangedEvent e) {
222     try {
223       // don't bother if we're just going to autoexpunge it...
224
if ((!Pooka.getProperty("Pooka.autoExpunge", "true").equalsIgnoreCase("true")) && e.getMessageChangeType() == MessageChangedEvent.FLAGS_CHANGED && (e.getMessage().isExpunged() || e.getMessage().getFlags().contains(Flags.Flag.DELETED))) {
225         final Message JavaDoc changedMessage = e.getMessage();
226         SwingUtilities.invokeLater(new Runnable JavaDoc() {
227             public void run() {
228               MessageProxy selectedProxy = getSelectedMessage();
229
230               if ( selectedProxy != null && (! (selectedProxy instanceof MultiMessageProxy)) && selectedProxy.getMessageInfo().getMessage().equals(changedMessage)) {
231                 selectNextMessage();
232               }
233             }
234           });
235       }
236     } catch (MessagingException me) {
237     }
238   }
239
240   /**
241    * This checks to see if the message which has been removed is
242    * currently selected. If so, we unselect it and select the next
243    * row.
244    */

245   public void moveSelectionOnRemoval(MessageCountEvent e) {
246     final Message JavaDoc[] removedMsgs = e.getMessages();
247
248     SwingUtilities.invokeLater(new Runnable JavaDoc() {
249         public void run() {
250           MessageProxy selectedProxy = getSelectedMessage();
251           if (selectedProxy != null) {
252             boolean found = false;
253             Message JavaDoc currentMsg = selectedProxy.getMessageInfo().getMessage();
254             for (int i = 0; (currentMsg != null && found == false && i < removedMsgs.length); i++) {
255               if (currentMsg.equals(removedMsgs[i])) {
256                 found = true;
257               }
258             }
259
260             if (found) {
261               selectNextMessage();
262             }
263           }
264         }
265       });
266
267   }
268
269   /**
270    * This checks to see if the message which has been removed is
271    * currently selected. If so, we unselect it and select the next
272    * row.
273    *
274    * Should be called on the AWTEventThread while the FolderThread
275    * is locked.
276    */

277   void moveSelectionOnRemoval(java.util.List JavaDoc removedProxies) {
278     MessageProxy selectedProxy = getSelectedMessage();
279     if (selectedProxy != null) {
280       boolean selectNextMessage = false;
281       if (selectedProxy instanceof MultiMessageProxy) {
282         MultiMessageInfo mmi = (MultiMessageInfo) selectedProxy.getMessageInfo();
283         int messageCount = mmi.getMessageCount();
284         selectNextMessage = true;
285         for (int i = 0; selectNextMessage && i < messageCount; i++) {
286           MessageProxy currentProxy = mmi.getMessageInfo(i).getMessageProxy();
287           if (! removedProxies.contains(currentProxy))
288             selectNextMessage=false;
289         }
290
291       } else {
292         if (removedProxies.contains(selectedProxy)) {
293           selectNextMessage = true;
294         }
295
296       }
297
298       if (selectNextMessage) {
299         int currentlySelected = messageTable.getSelectedRow();
300         int nextValue = getNextSelectableMessage(currentlySelected, removedProxies);
301         if (nextValue >= messageTable.getRowCount()) {
302           // in that case, check for a selectable message before this one.
303
nextValue = getPreviousSelectableMessage(nextValue, removedProxies);
304         }
305
306         if (nextValue < 0) {
307           // if we're removing all of the messages, then we should just
308
// be able to unselect everything.
309
int[] rowSelection = messageTable.getSelectedRows();
310           messageTable.removeRowSelectionInterval(rowSelection[0], rowSelection[rowSelection.length - 1]);
311         } else {
312           selectMessage(nextValue);
313         }
314       }
315     }
316   }
317
318   /**
319    * This recreates the message table with a new FolderTableModel.
320    */

321   public void resetFolderTableModel(FolderTableModel newModel) {
322     if (messageTable != null) {
323       FolderTableModel oldFtm = (FolderTableModel) messageTable.getModel();
324       oldFtm.removeTableModelListener(messageTable);
325       //newModel.addTableModelListener(messageTable);
326
messageTable.setModel(newModel);
327     }
328   }
329
330   /**
331    * This adds all the listeners to the current FolderDisplayPanel.
332    */

333   public void addListeners() {
334     // add a mouse listener
335

336     messageTable.addMouseListener(new MouseAdapter() {
337         public void mouseClicked(MouseEvent e) {
338           if (e.getClickCount() == 2) {
339             int rowIndex = getMessageTable().rowAtPoint(e.getPoint());
340             if (rowIndex != -1) {
341               getMessageTable().setRowSelectionInterval(rowIndex, rowIndex);
342               MessageProxy selectedMessage = getSelectedMessage();
343               String JavaDoc actionCommand = Pooka.getProperty("MessagePanel.2xClickAction", "file-open");
344               if (selectedMessage != null) {
345                 Action JavaDoc clickAction = selectedMessage.getAction(actionCommand);
346                 if (clickAction != null && isEnabled()) {
347                   clickAction.actionPerformed (new ActionEvent(this, ActionEvent.ACTION_PERFORMED, actionCommand));
348
349                 }
350               }
351             }
352           }
353         }
354
355         public void mousePressed(MouseEvent e) {
356           if (e.isPopupTrigger()) {
357             // see if anything is selected
358
int rowIndex = getMessageTable().rowAtPoint(e.getPoint());
359             int columnIndex = getMessageTable().columnAtPoint(e.getPoint());
360             if (rowIndex == -1 || !getMessageTable().isRowSelected(rowIndex) ) {
361               getMessageTable().setRowSelectionInterval(rowIndex, rowIndex);
362             }
363
364             MessageProxy selectedMessage = getSelectedMessage();
365             if (selectedMessage != null && isEnabled()) {
366               Object JavaDoc o = getMessageTable().getValueAt(rowIndex, columnIndex);
367               if (o != null && o instanceof BooleanIcon) {
368                 BooleanIcon bi = (BooleanIcon) o;
369                 if (bi.getIconId().equalsIgnoreCase("attachments") && bi.iconValue()) {
370                   selectedMessage.showAttachmentPopupMenu(getMessageTable(), e);
371                 } else {
372                   selectedMessage.showPopupMenu(getMessageTable(), e);
373
374                 }
375               } else {
376                 selectedMessage.showPopupMenu(getMessageTable(), e);
377               }
378             }
379           }
380         }
381
382         public void mouseReleased(MouseEvent e) {
383           if (e.isPopupTrigger()) {
384             // see if anything is selected
385
int rowIndex = getMessageTable().rowAtPoint(e.getPoint());
386             int columnIndex = getMessageTable().columnAtPoint(e.getPoint());
387             if (rowIndex == -1 || !getMessageTable().isRowSelected(rowIndex) ) {
388               getMessageTable().setRowSelectionInterval(rowIndex, rowIndex);
389             }
390
391             MessageProxy selectedMessage = getSelectedMessage();
392             if (selectedMessage != null && isEnabled())
393               if (columnIndex == 2)
394                 selectedMessage.showAttachmentPopupMenu(getMessageTable(), e);
395               else
396                 selectedMessage.showPopupMenu(getMessageTable(), e);
397           }
398         }
399       });
400
401     messageTable.getSelectionModel().addListSelectionListener(new SelectionListener());
402
403     // add sorting by header.
404

405     messageTable.getTableHeader().addMouseListener(new MouseAdapter() {
406         public void mousePressed(MouseEvent e) {
407           // show a wait cursor if we're not done loading the messages yet.
408
boolean allLoaded = true;
409           java.util.List JavaDoc data = ((FolderTableModel)messageTable.getModel()).getAllProxies();
410           java.util.Iterator JavaDoc it = data.iterator();
411           while (allLoaded && it.hasNext()) {
412             MessageProxy current = (MessageProxy) it.next();
413             if (! current.isLoaded())
414               allLoaded = false;
415           }
416
417           if (! allLoaded) {
418             messageTable.getTableHeader().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
419           }
420
421         }
422
423         public void mouseReleased(MouseEvent e) {
424           // clear the wait cursor, if any.
425
messageTable.getTableHeader().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
426         }
427
428         public void mouseClicked(MouseEvent e) {
429           TableColumnModel columnModel = messageTable.getColumnModel();
430           int viewColumn = columnModel.getColumnIndexAtX(e.getX());
431           int column = messageTable.convertColumnIndexToModel(viewColumn);
432           if (e.getClickCount() == 1 && column != -1) {
433             // check to make sure that all messages are loaded.
434
boolean allLoaded = true;
435             java.util.List JavaDoc data = ((FolderTableModel)messageTable.getModel()).getAllProxies();
436             java.util.Iterator JavaDoc it = data.iterator();
437             while (allLoaded && it.hasNext()) {
438               MessageProxy current = (MessageProxy) it.next();
439               if (! current.isLoaded())
440                 allLoaded = false;
441             }
442
443             if (allLoaded) {
444               java.util.logging.Logger.getLogger("Pooka.debug").fine("Sorting ...");
445
446               int shiftPressed = e.getModifiers()&InputEvent.SHIFT_MASK;
447               boolean ascending = (shiftPressed == 0);
448
449               MessageProxy selectedMessage = null;
450
451               int rowsSelected = messageTable.getSelectedRowCount();
452
453               if (rowsSelected == 1)
454                 selectedMessage = getFolderInfo().getMessageProxy(messageTable.getSelectedRow());
455               else if (rowsSelected > 1)
456                 selectedMessage = getFolderInfo().getMessageProxy(messageTable.getSelectedRows()[0]);
457
458               if (! ascending) {
459                 ((FolderTableModel)messageTable.getModel()).sortByColumn(column, ascending);
460               } else {
461                 ((FolderTableModel)messageTable.getModel()).sortByColumn(column );
462               }
463
464               if (selectedMessage != null) {
465                 int selectedIndex = ((FolderTableModel)messageTable.getModel()).getRowForMessage(selectedMessage);
466                 messageTable.setRowSelectionInterval(selectedIndex, selectedIndex);
467                 makeSelectionVisible(selectedIndex);
468               }
469             }
470           }
471         }
472       });
473
474     messageTable.registerKeyboardAction(new ActionListener() {
475         public void actionPerformed(ActionEvent e) {
476           FolderDisplayUI fdui = getFolderInfo().getFolderDisplayUI();
477           if (fdui != null) {
478             fdui.selectNextMessage();
479           }
480         }
481       }, KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_DOWN, 0), JComponent.WHEN_FOCUSED);
482
483     messageTable.registerKeyboardAction(new ActionListener() {
484         public void actionPerformed(ActionEvent e) {
485           FolderDisplayUI fdui = getFolderInfo().getFolderDisplayUI();
486           if (fdui != null) {
487             fdui.selectPreviousMessage();
488           }
489         }
490       }, KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_UP, 0), JComponent.WHEN_FOCUSED);
491
492     messageTable.registerKeyboardAction(new ActionListener() {
493         public void actionPerformed(ActionEvent e) {
494           MessageProxy selectedMessage = getSelectedMessage();
495           if (selectedMessage != null) {
496             Action JavaDoc defaultOpenAction = selectedMessage.getAction("file-default-open");
497             if (defaultOpenAction != null) {
498               defaultOpenAction.actionPerformed(e);
499             } else {
500               Pooka.getUIFactory().doDefaultOpen(selectedMessage);
501             }
502           }
503         }
504       }, KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_ENTER, 0), JComponent.WHEN_FOCUSED);
505
506     messageTable.registerKeyboardAction(new ActionListener() {
507         public void actionPerformed(ActionEvent e) {
508           MessageProxy selectedMessage = getSelectedMessage();
509           if (selectedMessage != null) {
510             Action JavaDoc defaultOpenAction = selectedMessage.getAction("file-default-open");
511             if (defaultOpenAction != null) {
512               defaultOpenAction.actionPerformed(e);
513             } else {
514               Pooka.getUIFactory().doDefaultOpen(selectedMessage);
515             }
516           }
517         }
518       }, KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_SPACE, 0), JComponent.WHEN_FOCUSED);
519
520     messageTable.registerKeyboardAction(new ActionListener() {
521         public void actionPerformed(ActionEvent e) {
522           selectNextUnreadMessage();
523         }
524       }, KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_TAB, 0), JComponent.WHEN_FOCUSED);
525
526     messageTable.registerKeyboardAction(new ActionListener() {
527         public void actionPerformed(ActionEvent e) {
528           selectPreviousUnreadMessage();
529         }
530       }, KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_TAB, java.awt.Event.SHIFT_MASK), JComponent.WHEN_FOCUSED);
531
532   }
533
534   /**
535    * This finds the first unread message (if any) and sets that message
536    * to selected, and returns that index.
537    */

538   public void selectFirstUnread() {
539
540     // sigh.
541
getFolderInfo().getFolderThread().addToQueue(new javax.swing.AbstractAction JavaDoc() {
542         public void actionPerformed(java.awt.event.ActionEvent JavaDoc ae) {
543           final int firstUnread = getFolderInfo().getFirstUnreadMessage();
544           SwingUtilities.invokeLater(new Runnable JavaDoc() {
545               public void run() {
546                 int useFirstUnread = firstUnread;
547                 if (useFirstUnread < 0 || useFirstUnread > messageTable.getRowCount()) {
548                   useFirstUnread = messageTable.getRowCount() - 1;
549                 } else {
550                   messageTable.setRowSelectionInterval(useFirstUnread, useFirstUnread);
551                 }
552                 makeSelectionVisible(useFirstUnread);
553               }
554             });
555         }
556       }, new java.awt.event.ActionEvent JavaDoc(this, 0, "folder-select-first-unread"));
557
558   }
559
560   /**
561    * This scrolls the given row number to visible.
562    */

563   public void makeSelectionVisible(int rowNumber) {
564     messageTable.scrollRectToVisible(messageTable.getCellRect(rowNumber, 1, true));
565
566   }
567
568
569   /**
570    * This selects the next message. If no message is selected, then
571    * the first message is selected.
572    */

573   public int selectNextMessage() {
574     int selectedRow = messageTable.getSelectedRow();
575     int nextSelectable = getNextSelectableMessage(selectedRow, null);
576     return selectMessage(nextSelectable);
577   }
578
579   /**
580    * This selects the next unread message. If no message is selected, then
581    * the first unread message is selected. If no unread messages exist, this
582    * does nothing.
583    */

584   public int selectNextUnreadMessage() {
585     int selectedRow = messageTable.getSelectedRow();
586     int nextSelectable = getNextSelectableMessage(selectedRow, null, true);
587     return selectMessage(nextSelectable);
588   }
589
590
591   /**
592    * Determines which message is the next selectable message. If no
593    * messages past this one are selectable (i.e. not deleted or about to
594    * be deleted), returns messageTable.getRowCount() (i.e. an unused
595    * row.
596    *
597    * Since we're polling flags on the Messages, this probably should be
598    * called on the FolderThread. The change of selection itself, of course,
599    * should be done on the AWTEventThread.
600    */

601   public int getNextSelectableMessage(int selectedRow, java.util.List JavaDoc removedProxies) {
602     return getNextSelectableMessage(selectedRow, removedProxies, false);
603   }
604
605   /**
606    * Determines which message is the next selectable message. If no
607    * messages past this one are selectable (i.e. not deleted or about to
608    * be deleted), returns messageTable.getRowCount() (i.e. an unused
609    * row.
610    *
611    * Since we're polling flags on the Messages, this probably should be
612    * called on the FolderThread. The change of selection itself, of course,
613    * should be done on the AWTEventThread.
614    */

615   public int getNextSelectableMessage(int selectedRow, java.util.List JavaDoc removedProxies, boolean unread) {
616     int newRow = selectedRow + 1;
617     boolean done = false;
618     while (! done && newRow < messageTable.getRowCount() ) {
619       MessageProxy mp = getFolderInfo().getMessageProxy(newRow);
620       try {
621         //if ((removedProxies != null && removedProxies.contains(mp)) || mp.getMessageInfo().getFlags().contains(Flags.Flag.DELETED) || (unread && mp.getMessageInfo().getFlags().contains(Flags.Flag.SEEN))) {
622
if ((removedProxies != null && removedProxies.contains(mp)) || mp.isDeleted() || (unread && mp.isSeen())) {
623           newRow ++;
624         } else {
625           done = true;
626         }
627       } catch (MessagingException me) {
628         newRow ++;
629       }
630     }
631
632     return newRow;
633   }
634
635
636   /**
637    * This selects the previous message. If no message is selected, then
638    * the last message is selected.
639    */

640   public int selectPreviousMessage() {
641     int[] rowsSelected = messageTable.getSelectedRows();
642     int selectedRow = 0;
643     if (rowsSelected.length > 0)
644       selectedRow = rowsSelected[0];
645     else
646       selectedRow = messageTable.getRowCount();
647
648     int previousSelectable = getPreviousSelectableMessage(selectedRow, null, false);
649     return selectMessage(previousSelectable);
650   }
651
652   /**
653    * This selects the previous unread message. If no message is selected, then
654    * the first message is selected.
655    */

656   public int selectPreviousUnreadMessage() {
657     int[] rowsSelected = messageTable.getSelectedRows();
658     int selectedRow = 0;
659     if (rowsSelected.length > 0)
660       selectedRow = rowsSelected[0];
661     else
662       selectedRow = messageTable.getRowCount();
663
664     int previousSelectable = getPreviousSelectableMessage(selectedRow, null, true);
665     return selectMessage(previousSelectable);
666   }
667
668   /**
669    * Determines which message is the previous selectable message. If no
670    * messages before this one are selectable (i.e. not deleted or about to
671    * be deleted), returns -1.
672    *
673    * Since we're polling flags on the Messages, this probably should be
674    * called on the FolderThread. The change of selection itself, of course,
675    * should be done on the AWTEventThread.
676    */

677   public int getPreviousSelectableMessage(int selectedRow, java.util.List JavaDoc removedProxies) {
678     return getPreviousSelectableMessage(selectedRow, removedProxies, false);
679   }
680
681   /**
682    * Determines which message is the previous selectable message. If no
683    * messages before this one are selectable (i.e. not deleted or about to
684    * be deleted), returns -1.
685    *
686    * Since we're polling flags on the Messages, this probably should be
687    * called on the FolderThread. The change of selection itself, of course,
688    * should be done on the AWTEventThread.
689    */

690   public int getPreviousSelectableMessage(int selectedRow, java.util.List JavaDoc removedProxies, boolean unread) {
691     int newRow = selectedRow - 1;
692     boolean done = false;
693     while (! done && newRow >= 0 ) {
694       MessageProxy mp = getFolderInfo().getMessageProxy(newRow);
695       try {
696         //if ((removedProxies != null && removedProxies.contains(mp)) || mp.getMessageInfo().getFlags().contains(Flags.Flag.DELETED) || (unread && mp.getMessageInfo().getFlags().contains(Flags.Flag.SEEN))) {
697
if ((removedProxies != null && removedProxies.contains(mp)) || mp.isDeleted() || (unread && mp.isSeen())) {
698           newRow--;
699         } else {
700           done = true;
701         }
702       } catch (MessagingException me) {
703         newRow--;
704       }
705     }
706
707     return newRow;
708
709   }
710
711   /**
712    * Selects all of the messages in the FolderTable.
713    */

714   public void selectAll() {
715     messageTable.selectAll();
716   }
717
718   /**
719    * This selects the message at the given row, and also scrolls the
720    * MessageTable to make the given row visible.
721    *
722    * If the number entered is below the range of available messages, then
723    * the first message is selected. If the number entered is above that
724    * range, then the last message is selected. If the MessageTable
725    * contains no messages, nothing happens.
726    *
727    * @return the index of the newly selected row.
728    */

729   public int selectMessage(int messageNumber) {
730     int rowCount = messageTable.getRowCount();
731
732     if (rowCount > 0) {
733       int numberToSet = messageNumber;
734
735       if (messageNumber < 0) {
736         numberToSet = 0;
737       } else if (messageNumber >= rowCount) {
738         numberToSet = rowCount - 1;
739       }
740       messageTable.setRowSelectionInterval(numberToSet, numberToSet);
741       makeSelectionVisible(numberToSet);
742       return numberToSet;
743     } else {
744       return -1;
745     }
746   }
747
748   /**
749    * This method takes the currently selected row(s) and returns the
750    * appropriate MessageProxy object.
751    *
752    * If no rows are selected, null is returned.
753    */

754   public MessageProxy getSelectedMessage() {
755     if (messageTable != null) {
756       int rowsSelected = messageTable.getSelectedRowCount();
757
758       if (rowsSelected == 1)
759         return getFolderInfo().getMessageProxy(messageTable.getSelectedRow());
760       else if (rowsSelected < 1)
761         return null;
762       else {
763         int[] selectedRows = messageTable.getSelectedRows();
764         MessageProxy[] msgSelected= new MessageProxy[selectedRows.length];
765         for (int i = 0; i < selectedRows.length; i++)
766           msgSelected[i] = getFolderInfo().getMessageProxy(selectedRows[i]);
767         return new MultiMessageProxy(selectedRows, msgSelected, this.getFolderInfo());
768       }
769     } else {
770       return null;
771     }
772   }
773
774   /**
775    * This updates the entry for the given message, if that message is
776    * visible.
777    */

778   public void repaintMessage(MessageProxy mp) {
779     int row = getFolderTableModel().getRowForMessage(mp);
780     if (row >=0) {
781       getFolderTableModel().fireTableRowsUpdated(row, row);
782     }
783   }
784
785   /**
786    * Saves state for this display panel.
787    */

788   public void saveTableSettings() {
789     if (getFolderInfo() != null) {
790       String JavaDoc key = getFolderInfo().getFolderProperty();
791       // save the column information.
792
FolderTableModel ftm = getFolderTableModel();
793       for (int i = 0; i < ftm.getColumnCount(); i++) {
794         Pooka.setProperty(key + ".columnsize." + ftm.getColumnId(i) + ".value", Integer.toString(messageTable.getColumnModel().getColumn(i).getWidth()));
795
796       }
797     }
798   }
799
800   /**
801    * This resets the size to that of the parent component.
802    */

803   public void resize() {
804     this.setSize(getParent().getSize());
805   }
806
807   // Accessor methods.
808

809   public JTable getMessageTable() {
810     return messageTable;
811   }
812
813   /**
814    * This sets the FolderInfo.
815    */

816   public void setFolderInfo(FolderInfo newValue) {
817     folderInfo=newValue;
818   }
819
820   public FolderInfo getFolderInfo() {
821     return folderInfo;
822   }
823
824   /**
825    * Returns the FolderTableModel for this FolderDisplayPanel.
826    */

827   public FolderTableModel getFolderTableModel() {
828     if (getFolderInfo() != null)
829       return getFolderInfo().getFolderTableModel();
830     else
831       return null;
832   }
833
834   /**
835    * gets the actions handled both by the FolderDisplayPanel and the
836    * selected Message(s).
837    */

838
839   public class SelectionListener implements javax.swing.event.ListSelectionListener JavaDoc {
840     SelectionListener() {
841     }
842
843     public void valueChanged(javax.swing.event.ListSelectionEvent JavaDoc e) {
844       Pooka.getMainPanel().refreshActiveMenus();
845       getFolderInfo().setNewMessages(false);
846       FolderNode fn = getFolderInfo().getFolderNode();
847       if (fn != null)
848         fn.getParentContainer().repaint();
849     }
850   }
851
852   /**
853    * This registers the Keyboard action not only for the FolderDisplayPanel
854    * itself, but also for pretty much all of its children, also. This
855    * is to work around something which I think is a bug in jdk 1.2.
856    * (this is not really necessary in jdk 1.3.)
857    *
858    * Overrides JComponent.registerKeyboardAction(ActionListener anAction,
859    * String aCommand, KeyStroke aKeyStroke, int aCondition)
860    */

861
862   public void registerKeyboardAction(ActionListener anAction,
863                                      String JavaDoc aCommand, KeyStroke aKeyStroke,
864                                      int aCondition) {
865     super.registerKeyboardAction(anAction, aCommand, aKeyStroke, aCondition);
866
867     if (messageTable != null)
868       messageTable.registerKeyboardAction(anAction, aCommand, aKeyStroke, aCondition);
869   }
870
871   /**
872    * This unregisters the Keyboard action not only for the FolderDisplayPanel
873    * itself, but also for pretty much all of its children, also. This
874    * is to work around something which I think is a bug in jdk 1.2.
875    * (this is not really necessary in jdk 1.3.)
876    *
877    * Overrides JComponent.unregisterKeyboardAction(KeyStroke aKeyStroke)
878    */

879
880   public void unregisterKeyboardAction(KeyStroke aKeyStroke) {
881     super.unregisterKeyboardAction(aKeyStroke);
882
883     messageTable.unregisterKeyboardAction(aKeyStroke);
884   }
885
886   /**
887    * Returns whether or not this window is enabled. This should be true
888    * just about all of the time. The only time it won't be true is if
889    * the Folder is closed or disconnected, and the mail store isn't set
890    * up to work in disconnected mode.
891    */

892   public boolean isEnabled() {
893     return enabled;
894   }
895
896   /**
897    * This sets whether or not the window is enabled. This should only
898    * be set to false when the Folder is no longer available.
899    */

900   public void setEnabled(boolean newValue) {
901     enabled = newValue;
902   }
903
904   public Action JavaDoc[] getActions() {
905     if (isEnabled()) {
906       Action JavaDoc[] returnValue = null;
907       MessageProxy m = getSelectedMessage();
908
909       if (m != null)
910         returnValue = m.getActions();
911
912       if (folderInfo.getActions() != null) {
913         if (returnValue != null) {
914           returnValue = TextAction.augmentList(folderInfo.getActions(), returnValue);
915         } else {
916           returnValue = folderInfo.getActions();
917         }
918       }
919
920       if (messageTable != null) {
921         Action JavaDoc[] defaultActions = new Action JavaDoc[] {
922           FolderTransferHandler.getCutAction(messageTable),
923           FolderTransferHandler.getCopyAction(messageTable),
924           FolderTransferHandler.getPasteAction(messageTable)
925         };
926         if (returnValue != null) {
927           returnValue = TextAction.augmentList(defaultActions, returnValue);
928         } else {
929           returnValue = defaultActions;
930         }
931       }
932
933       return returnValue;
934     } else {
935       return null;
936     }
937   }
938 }
939
Popular Tags