KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > SnowMailClient > model > MailFolder


1 package SnowMailClient.model;
2
3
4 import SnowMailClient.SnowMailClientApp;
5 import SnowMailClient.model.folders.*;
6 import SnowMailClient.model.events.*;
7 import snow.utils.storage.*;
8 import SnowMailClient.utils.*;
9 import snow.utils.gui.*;
10
11 import snow.sortabletable.*;
12 import SnowMailClient.Language.Language;
13
14
15 import java.util.*;
16 import java.util.regex.*;
17 import java.text.*;
18 import javax.swing.table.*;
19 import javax.swing.SwingUtilities JavaDoc;
20 import java.awt.EventQueue JavaDoc;
21
22
23 /** Model of a mail folder, is stored in the directory tree maintained from storagetreemodel
24     + this is a table model,
25     + one can listen for changes (that forward all messages events !)
26 */

27 public final class MailFolder extends FineGrainTableModel
28                         implements Vectorizable, MailMessageChangeListener//, Iterable<MailMessage>
29
{
30   private final AppProperties properties = new AppProperties();
31   private final Vector<MailMessage> messages = new Vector<MailMessage>();
32   private static final String JavaDoc[] COLUMN_NAMES = new String JavaDoc[]{
33      Language.translate("From"),
34      Language.translate("To"),
35      Language.translate("Subject"),
36      Language.translate("Date"),
37      Language.translate("Size"),
38      Language.translate("SPAM")
39   };
40
41
42   int[] COLUMN_PREFERED_SIZES = new int[] { 12, 12, 12, 6, 6, 4 };
43   public int getPreferredColumnWidth(int column)
44   {
45     if(column>=0 && column<COLUMN_PREFERED_SIZES.length) return COLUMN_PREFERED_SIZES[column];
46     return -1;
47   }
48
49
50   // tells where is it...
51
FolderTreeNode node;
52
53   // is used to decide if store is necessary ...
54
private boolean contentHasChanged = false;
55
56   private SimpleDateFormat dateFormat = new SimpleDateFormat("dd MMM yy HH':'mm", Language.getInstance().getLocale());
57
58
59   private int sortedColumnInView = 3; // default sorted by date !!
60
private boolean ascendingSortOrder = true;
61
62   public MailFolder(FolderTreeNode node)
63   {
64     this.node = node;
65   } // Constructor
66

67
68   public String JavaDoc getFolderName()
69   {
70     return node.getFolderName();
71   }
72
73   public void addMessage(final MailMessage m)
74   {
75     if(!SwingUtilities.isEventDispatchThread())
76     {
77        new Throwable JavaDoc("Must be EDT").printStackTrace();
78     }
79
80     fireTableModelWillChange();
81     messages.addElement(m);
82     m.addChangeListener(this);
83     contentHasChanged = true;
84     fireTableDataChanged();
85     fireTableModelHasChanged();
86
87     this.notifyMailFolderListener_of_FolderSizeChanged();
88   }
89
90
91   public void removeMessage(final MailMessage m)
92   {
93     if(!SwingUtilities.isEventDispatchThread())
94     {
95        new Throwable JavaDoc("Must be EDT").printStackTrace();
96     }
97
98     fireTableModelWillChange();
99     messages.removeElement(m);
100     m.removeChangeListener(this);
101     contentHasChanged = true;
102     fireTableDataChanged();
103     fireTableModelHasChanged();
104
105     this.notifyMailFolderListener_of_FolderSizeChanged();
106   }
107
108
109   public MailMessage getMessageAt(int i)
110   {
111      return messages.elementAt(i);
112   }
113
114   /** new mails (unread) or just composed
115   */

116   public int getNumberOfNewMails()
117   {
118      int n=0;
119      for(MailMessage mess: messages)
120      {
121         if(mess.getIsNew()) n+=1;
122      }
123      return n;
124   }
125
126
127   // Iterator (for the foreach loop)
128
//
129

130   /*
131   public Iterator<MailMessage> iterator()
132   {
133     return new Iterator<MailMessage>()
134     {
135         int i=0;
136         public boolean hasNext() { return i<messages.size(); }
137         public MailMessage next() { return messages.elementAt(i++); }
138         public void remove() { throw new UnsupportedOperationException(); }
139     };
140   }*/

141
142
143   /** use this to iterate with a foreach loop. This is a copy of the references.
144       Can be used to safely remove elements ! call this class remove message.
145       the remove on the vector will have NO effect !
146   */

147   public Vector<MailMessage> getAllMessages()
148   {
149     Vector<MailMessage> vm = new Vector<MailMessage>();
150     vm.addAll(messages);
151     return vm;
152   }
153
154
155   // Table
156
//
157

158   public int getRowCount() { return messages.size(); }
159   public int getColumnCount() { return COLUMN_NAMES.length; }
160   public Object JavaDoc getValueAt(int row, int column)
161   {
162     MailMessage mess = messages.elementAt(row);
163     if(column==0)
164     {
165       Address from = mess.getFromAddress();
166       return from.getMailAddress();
167     }
168     else if(column==1)
169     {
170       return mess.getToAddressesText();
171     }
172     else if(column==2)
173     {
174       return mess.getSubject();
175     }
176     else if(column==3)
177     {
178       long time = mess.getParsedMessageTime();
179       if(time==0)
180       {
181         return mess.getDateFieldFormHeader();
182       }
183       else
184       {
185         return dateFormat.format(new Date(time));
186       }
187     }
188     else if(column==4)
189     {
190       return MailMessageUtils.formatSize(mess.getSize());
191     }
192     else if(column==5)
193     {
194       //double spam = mess.getSPAMProbability();
195
//return ""; // the renderer does the work !!
196
//if(mess.getIsSPAM()) return "S";
197
//else if(mess.getIsHAM()) return "H";
198
//else return "";
199
return "";
200     }
201
202     return "?";
203   }
204
205
206   public String JavaDoc getColumnName(int col)
207   {
208     return COLUMN_NAMES[col];
209   }
210
211   public boolean hitForTextSearch(int row, String JavaDoc txt, Pattern p)
212   {
213     // look in the table strings
214
boolean foundInTable = super.hitForTextSearch(row, txt, p);
215     if(foundInTable==true) return true;
216
217     // look in the message
218
MailMessage mess = messages.elementAt(row);
219     return mess.searchText(txt.toUpperCase());
220   }
221
222   public int compareForColumnSort(int pos1, int pos2, int col)
223   {
224      MailMessage mess1 = messages.elementAt(pos1);
225      MailMessage mess2 = messages.elementAt(pos2);
226
227      if(col==3) // Dates
228
{
229        return this.compareDoubles(mess1.getParsedMessageTime(), mess2.getParsedMessageTime());
230      }
231
232      if(col==4) // Sizes
233
{
234        return this.compareInts(mess1.getSize(), mess2.getSize());
235      }
236
237      if(col==5) // Spam prob
238
{
239
240        if(mess1.getIsSPAM() && !mess2.getIsSPAM()) return -1;
241        if(!mess1.getIsSPAM() && mess2.getIsSPAM()) return 1;
242        // TODO: also look HAMs flags ??
243

244        int cd = this.compareDoubles(mess1.getSPAMProbability(), mess2.getSPAMProbability());
245        return cd;
246      }
247
248      // for the other cols, use string compare
249
String JavaDoc val1 = (String JavaDoc) getValueAt(pos1, col);
250      String JavaDoc val2 = (String JavaDoc) getValueAt(pos2, col);
251      return val1.compareTo(val2);
252   }
253
254   /** Cause a save, later
255     @param notify if listeners should be notified. If true, the view will refresh...
256
257     Called from this and the foldertreenode to force a save later...
258   */

259   public void setContentHasChanged(boolean notify)
260   {
261     //System.out.println("Folder content changed, notify="+notify);
262

263     contentHasChanged = true;
264     if(notify)
265     {
266       this.notifyMailFolderListener_of_ContentEdited(null);
267     }
268   }
269
270   public void setContentWasStored()
271   {
272     contentHasChanged = false;
273     this.notifyMailFolderListener_of_FolderStored();
274   }
275
276   public boolean hasContentChanged()
277   {
278     return contentHasChanged;
279   }
280
281
282   public void saveSortedColumnFromView( int sortedColumnInView,
283                                          boolean ascendingSortOrder )
284   {
285     this.sortedColumnInView = sortedColumnInView;
286     this.ascendingSortOrder = ascendingSortOrder;
287
288   }
289
290   public int getSortedColumn()
291   {
292     return sortedColumnInView;
293   }
294
295   public boolean getIsSortingAscendingOrder()
296   {
297     return ascendingSortOrder;
298   }
299
300   // Vectorizable
301
//
302
public Vector<Object JavaDoc> getVectorRepresentation() throws VectorizeException
303   {
304     Vector<Object JavaDoc> rep = new Vector<Object JavaDoc>();
305     rep.addElement(1); // 0
306
rep.addElement(properties.getVectorRepresentation()); // 1
307

308     Vector<Object JavaDoc> messagesVec = new Vector<Object JavaDoc>();
309     rep.addElement(messagesVec); // 2
310
for(MailMessage m: messages)
311     {
312        messagesVec.addElement( m.getVectorRepresentation() );
313     }
314     rep.addElement(this.sortedColumnInView); // 3
315
rep.addElement(this.ascendingSortOrder); // 4
316
return rep;
317   }
318
319 @SuppressWarnings JavaDoc("unchecked")
320   public void createFromVectorRepresentation(Vector<Object JavaDoc> v) throws VectorizeException
321   {
322     int version = (Integer JavaDoc) v.elementAt(0); // 0
323
if(version==1)
324     {
325       properties.createFromVectorRepresentation((Vector) v.elementAt(1)); // 1
326

327       Vector<Vector> messVec = (Vector<Vector>) v.elementAt(2); // 2
328
messages.removeAllElements();
329       for(Vector mv: messVec)
330       {
331          try
332          {
333            MailMessage mess = new MailMessage();
334            mess.createFromVectorRepresentation(mv );
335            messages.addElement(mess);
336            mess.addChangeListener(this);
337          }
338          catch(Exception JavaDoc e)
339          {
340            System.out.println("Cannot read a mail in folder "+this.getFolderName()+" "+e.getMessage());
341            //e.printStackTrace();
342
}
343       }
344       if(v.size()>3)
345       {
346         this.sortedColumnInView = (Integer JavaDoc) v.elementAt(3);
347         this.ascendingSortOrder = (Boolean JavaDoc) v.elementAt(4);
348       }
349
350     }
351     else
352     {
353       throw new VectorizeException(Language.translate("bad version %", ""+version));
354     }
355   }
356
357   // Selection
358
//
359
public void setRowSelection(int row, boolean isSelected)
360   {
361     messages.elementAt(row).selectedInView = isSelected;
362   }
363
364   public boolean isRowSelected(int row)
365   {
366     return messages.elementAt(row).selectedInView;
367   }
368
369   public void setSelectedMessage(MailMessage mess)
370   {
371     if(mess==null) return;
372     for(MailMessage mi : messages)
373     {
374        mi.selectedInView = (mi==mess);
375     }
376   }
377
378
379   /** When one of the mails of this folder has changed.
380       Edit Cases:
381       1) in_edition: the message is being edited (key was pressed in the message textpane),
382          this must just set the folder flag to "changed".
383       2) the header or the message changed =>
384          refresh the view.
385   */

386   public void mailMessageChanged(MailMessage source, MailMessageChangeType type, String JavaDoc detail)
387   {
388     if(type == MailMessageChangeType.IN_EDITION)
389     {
390       //System.out.println("Message in edition");
391
this.setContentHasChanged(false);
392     }
393     else
394     {
395       // type is one of {MESSAGE, HEADER, PROPERTY, ATTACHMENT}
396

397       //System.out.println("Message changed: "+type+", detail="+detail+", SRC="+source.getSubject());
398
this.setContentHasChanged(true);
399     }
400   }
401
402
403   // Listeners
404
//
405
Vector<MailFolderListener> mailFolderListener = new Vector<MailFolderListener>();
406
407   /** this listen to all mails changes in this folder
408   */

409   public void addMailFolderListener(MailFolderListener mfn)
410   {
411     mailFolderListener.addElement(mfn);
412   }
413
414
415   public void removeMailFolderListener(MailFolderListener mfn)
416   {
417     mailFolderListener.removeElement(mfn);
418   }
419
420   /** either added/removed mails
421   */

422   public void notifyMailFolderListener_of_FolderSizeChanged()
423   {
424      // do a copy of the listeners to decouple them from the vector
425
// because they may perform operation on the vector in the notify loop (remove listener)
426
// and caus concurrent modification exceptions
427
MailFolderListener[] mfl = null;
428      synchronized(mailFolderListener)
429      {
430        mfl = mailFolderListener.toArray(new MailFolderListener[mailFolderListener.size()]);
431      }
432
433      for(MailFolderListener mfn : mfl)
434      {
435        mfn.folderSizeChanged();
436      }
437      // ## DO BETTER !
438
if(SnowMailClientApp.getInstance().getFoldersView()!=null)
439      {
440        SnowMailClientApp.getInstance().getFoldersView().repaint();
441      }
442   }
443
444   public void notifyMailFolderListener_of_FolderStored()
445   {
446      // do a copy of the listeners to decouple them from the vector
447
// because they may perform operation on the vector in the notify loop (remove listener)
448
// and caus concurrent modification exceptions
449
MailFolderListener[] mfl = null;
450      synchronized(mailFolderListener)
451      {
452        mfl = mailFolderListener.toArray(new MailFolderListener[mailFolderListener.size()]);
453      }
454
455      for(MailFolderListener mfn : mfl)
456      {
457        mfn.folderStored();
458      }
459
460      if(SnowMailClientApp.getInstance().getFoldersView()!=null)
461      {
462        SnowMailClientApp.getInstance().getFoldersView().repaint();
463      }
464   }
465
466   public void notifyMailFolderListener_of_ContentEdited(MailMessageChangeListener.MailMessageChangeType change)
467   {
468      // do a copy of the listeners to decouple them from the vector
469
// because they may perform operation on the vector in the notify loop (remove listener)
470
// and caus concurrent modification exceptions
471
MailFolderListener[] mfl = null;
472      synchronized(mailFolderListener)
473      {
474        mfl = mailFolderListener.toArray(new MailFolderListener[mailFolderListener.size()]);
475      }
476
477      for(MailFolderListener mfn : mfl)
478      {
479        mfn.folderContentEdited(change);
480      }
481      SnowMailClientApp.getInstance().getFoldersView().repaint();
482   }
483
484   public void notifyMailFolderListener_of_FolderClosed()
485   {
486      // do a copy of the listeners to decouple them from the vector
487
// because they may perform operation on the vector in the notify loop (remove listener)
488
// and caus concurrent modification exceptions
489
MailFolderListener[] mfl = null;
490      synchronized(mailFolderListener)
491      {
492        mfl = mailFolderListener.toArray(new MailFolderListener[mailFolderListener.size()]);
493      }
494
495      for(MailFolderListener mfn : mfl)
496      {
497        mfn.folderClosed();
498      }
499      SnowMailClientApp.getInstance().getFoldersView().repaint();
500   }
501
502
503
504 } // MailFolder
Popular Tags