1794217
[gecko.git] / 
blob17942170ea421769766b587c04559a980344fa43
1 # -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 # The contents of this file are subject to the Netscape Public
3 # License Version 1.1 (the "License"); you may not use this file
4 # except in compliance with the License. You may obtain a copy of
5 # the License at http://www.mozilla.org/NPL/
7 # Software distributed under the License is distributed on an "AS
8 # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9 # implied. See the License for the specific language governing
10 # rights and limitations under the License.
12 # The Original Code is Mozilla Communicator client code, released
13 # March 31, 1998.
15 # The Initial Developer of the Original Code is Netscape
16 # Communications Corporation. Portions created by Netscape are
17 # Copyright (C) 1998-1999 Netscape Communications Corporation. All
18 # Rights Reserved.
20 # Contributors(s):
21 #   Jan Varga <varga@nixcorp.com>
22 #   HÃ¥kan Waara (hwaara@chello.se)
23 #   David Bienvenu (bienvenu@netscape.com)
25  * Command-specific code. This stuff should be called by the widgets
26  */
28 //NOTE: gMessengerBundle and gBrandBundle must be defined and set
29 //      for this Overlay to work properly
31 var gFolderJustSwitched = false;
32 var gBeforeFolderLoadTime;
33 var gRDFNamespace = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
35 /* keep in sync with nsMsgFolderFlags.h */
36 var MSG_FOLDER_FLAG_TRASH = 0x0100;
37 var MSG_FOLDER_FLAG_SENTMAIL = 0x0200;
38 var MSG_FOLDER_FLAG_DRAFTS = 0x0400;
39 var MSG_FOLDER_FLAG_QUEUE = 0x0800;
40 var MSG_FOLDER_FLAG_INBOX = 0x1000;
41 var MSG_FOLDER_FLAG_TEMPLATES = 0x400000;
42 var MSG_FOLDER_FLAG_JUNK = 0x40000000;
44 function OpenURL(url)
46   messenger.SetWindow(window, msgWindow);
47   messenger.OpenURL(url);
50 function GetMsgFolderFromResource(folderResource)
52   if (!folderResource)
53      return null;
55   var msgFolder = folderResource.QueryInterface(Components.interfaces.nsIMsgFolder);
56   if (msgFolder && (msgFolder.parent || msgFolder.isServer))
57     return msgFolder;
58   else
59     return null;
62 function GetServer(uri)
64     if (!uri) return null;
65     try {
66         var folder = GetMsgFolderFromUri(uri, true);
67         return folder.server;
68     }
69     catch (ex) {
70         dump("GetServer("+uri+") failed, ex="+ex+"\n");
71     }
72     return null;
75 function LoadMessageByUri(uri)
77   //dump("XXX LoadMessageByUri " + uri + " vs " + gCurrentDisplayedMessage + "\n");
78   if(uri != gCurrentDisplayedMessage)
79   {
80         dump("fix this, get the nsIMsgDBHdr and the nsIMsgFolder from the uri...\n");
82     var resource = RDF.GetResource(uri);
83     var message = resource.QueryInterface(Components.interfaces.nsIMessage);
84     if (message)
85       setTitleFromFolder(message.msgFolder, message.mimef2DecodedSubject);
87     var nsIMsgFolder = Components.interfaces.nsIMsgFolder;
88     if (message.msgFolder.server.downloadOnBiff)
89       message.msgFolder.biffState = nsIMsgFolder.nsMsgBiffState_NoMail;
92     gCurrentDisplayedMessage = uri;
93     gHaveLoadedMessage = true;
94     OpenURL(uri);
95   }
99 function setTitleFromFolder(msgfolder, subject)
101     var wintype = document.firstChild.getAttribute('windowtype');
102     var title; 
104     // If we are showing the mail:3pane. Never include the subject of the selected
105     // message in the title. ("Inbox for greenlantern@mozilla.org - Mozilla Thunderbird")
106     // If we are a stand alone message window, we should show the Subject
107     // and the product but not the account name: "Re: New window Title - Mozilla Thunderbird"
109     if (wintype == "mail:messageWindow")  
110       title = subject ? subject : "";
111     else if (msgfolder)
112     {
113       title = msgfolder.prettyName;
115       if (!msgfolder.isServer)
116       {
117         var server = msgfolder.server;
118         var middle;
119         var end;
120         if (server.type == "nntp") {
121             // <folder> on <hostname>
122             middle = gMessengerBundle.getString("titleNewsPreHost");
123             end = server.hostName;
124         } else {
125             var identity;
126             try {
127                 var identities = accountManager.GetIdentitiesForServer(server);
129                 identity = identities.QueryElementAt(0, Components.interfaces.nsIMsgIdentity);
130                 // <folder> for <email>
131                 middle = gMessengerBundle.getString("titleMailPreHost");
132                 end = identity.email;
133           } catch (ex) {}
134             }
135         if (middle) title += " " + middle;
136         if (end) title += " " + end;
137     }
138     }
140 #ifndef XP_MACOSX
141     title += " - " + gBrandBundle.getString("brandShortName");
142 #endif
143     window.title = title;
146 function UpdateMailToolbar(caller)
148   //dump("XXX update mail-toolbar " + caller + "\n");
149   document.commandDispatcher.updateCommands('mail-toolbar');
151   // hook for extra toolbar items
152   var observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
153   observerService.notifyObservers(window, "mail:updateToolbarItems", null);
156 function ChangeFolderByURI(uri, viewType, viewFlags, sortType, sortOrder)
158   //dump("In ChangeFolderByURI uri = " + uri + " sortType = " + sortType + "\n");
159   if (uri == gCurrentLoadingFolderURI)
160     return;
162   // hook for extra toolbar items
163   var observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
164   observerService.notifyObservers(window, "mail:setupToolbarItems", uri);
166   var resource = RDF.GetResource(uri);
167   var msgfolder =
168       resource.QueryInterface(Components.interfaces.nsIMsgFolder);
170   try {
171       setTitleFromFolder(msgfolder, null);
172   } catch (ex) {
173       dump("error setting title: " + ex + "\n");
174   }
176   //if it's a server, clear the threadpane and don't bother trying to load.
177   if(msgfolder.isServer) {
178     msgWindow.openFolder = null;
180     ClearThreadPane();
182     // Load AccountCentral page here.
183     ShowAccountCentral();
185     return;
186   }
187   else
188   {
189     if (msgfolder.server.displayStartupPage)
190     {
191       gDisplayStartupPage = true;
192       msgfolder.server.displayStartupPage = false;
193     }
194   }
196   // If the user clicks on msgfolder, time to display thread pane and message pane.
197   // Hide AccountCentral page
198   if (gAccountCentralLoaded)
199   {
200       HideAccountCentral();
201   }
203   if (gFakeAccountPageLoaded)
204   {
205       HideFakeAccountPage();
206   }
208   gCurrentLoadingFolderURI = uri;
209   gNextMessageAfterDelete = null; // forget what message to select, if any
211   gCurrentFolderToReroot = uri;
212   gCurrentLoadingFolderViewFlags = viewFlags;
213   gCurrentLoadingFolderViewType = viewType;
214   gCurrentLoadingFolderSortType = sortType;
215   gCurrentLoadingFolderSortOrder = sortOrder;
217   var showMessagesAfterLoading;
218   try {
219     var server = msgfolder.server;
220     if (gPrefBranch.getBoolPref("mail.password_protect_local_cache"))
221     {
222       showMessagesAfterLoading = server.passwordPromptRequired;
223       // servers w/o passwords (like local mail) will always be non-authenticated.
224       // So we need to use the account manager for that case.
225     }
226     else if (server.redirectorType) {
227       var prefString = server.type + "." + server.redirectorType + ".showMessagesAfterLoading";
228       showMessagesAfterLoading = gPrefBranch.getBoolPref(prefString);
229     }
230     else
231       showMessagesAfterLoading = false;
232   }
233   catch (ex) {
234     showMessagesAfterLoading = false;
235   }
237   if (msgfolder.manyHeadersToDownload || showMessagesAfterLoading)
238   {
239     gRerootOnFolderLoad = true;
240     try
241     {
242       ClearThreadPane();
243       SetBusyCursor(window, true);
244       msgfolder.startFolderLoading();
245       msgfolder.updateFolder(msgWindow);
246     }
247     catch(ex)
248     {
249           SetBusyCursor(window, false);
250           dump("Error loading with many headers to download: " + ex + "\n");
251     }
252   }
253   else
254   {
255     SetBusyCursor(window, true);
256     RerootFolder(uri, msgfolder, viewType, viewFlags, sortType, sortOrder);
257     gRerootOnFolderLoad = false;
258     msgfolder.startFolderLoading();
260     //Need to do this after rerooting folder.  Otherwise possibility of receiving folder loaded
261     //notification before folder has actually changed.
262     msgfolder.updateFolder(msgWindow);
263   }
266 function isNewsURI(uri)
268     if (!uri || uri[0] != 'n') {
269         return false;
270     }
271     else {
272         return ((uri.substring(0,6) == "news:/") || (uri.substring(0,14) == "news-message:/"));
273     }
276 function RerootFolder(uri, newFolder, viewType, viewFlags, sortType, sortOrder)
278   //dump("In reroot folder, sortType = " +  sortType + "\n");
280   // workaround for #39655
281   gFolderJustSwitched = true;
283   ClearThreadPaneSelection();
285   //Clear the new messages of the old folder
286   var oldFolder = msgWindow.openFolder;
287   if (oldFolder) {
288     if (oldFolder.hasNewMessages) {
289       oldFolder.clearNewMessages();
290     }
291   }
293   //Set the window's new open folder.
294   msgWindow.openFolder = newFolder;
296   //the new folder being selected should have its biff state get cleared.
297   if(newFolder)
298   {
299     newFolder.biffState =
300           Components.interfaces.nsIMsgFolder.nsMsgBiffState_NoMail;
301   }
303   //Clear out the thread pane so that we can sort it with the new sort id without taking any time.
304   // folder.setAttribute('ref', "");
306   // null this out, so we don't try sort.
307   if (gDBView) {
308     gDBView.close();
309     gDBView = null;
310   }
312   // cancel the pending mark as read timer
313   ClearPendingReadTimer();
315   // if this is the drafts, sent, or send later folder,
316   // we show "Recipient" instead of "Author"
317   SetSentFolderColumns(IsSpecialFolder(newFolder, MSG_FOLDER_FLAG_SENTMAIL | MSG_FOLDER_FLAG_DRAFTS | MSG_FOLDER_FLAG_QUEUE));
319   // now create the db view, which will sort it.
320   CreateDBView(newFolder, viewType, viewFlags, sortType, sortOrder);
321   if (oldFolder)
322   {
323     /*disable quick search clear button if we were in the search view on folder switching*/
324     disableQuickSearchClearButton();
326      /*we don't null out the db reference for inbox because inbox is like the "main" folder
327        and performance outweighs footprint */
328     if (!IsSpecialFolder(oldFolder, MSG_FOLDER_FLAG_INBOX))
329       if (oldFolder.URI != newFolder.URI)
330         oldFolder.setMsgDatabase(null);
331   }
332   // that should have initialized gDBView, now re-root the thread pane
333   RerootThreadPane();
335   SetUpToolbarButtons(uri);
337   UpdateStatusMessageCounts(newFolder);
338   
339   // hook for extra toolbar items
340   var observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
341   observerService.notifyObservers(window, "mail:updateToolbarItems", null);
344 function SwitchView(command)
346   // when switching thread views, we might be coming out of quick search
347   // or a message view.
348   // first set view picker to all
349   ViewMessagesBy("viewPickerAll");
351   // clear the QS text, if we need to
352   ClearQSIfNecessary();
353   
354   // now switch views
355   var oldSortType = gDBView ? gDBView.sortType : nsMsgViewSortType.byThread;
356   var oldSortOrder = gDBView ? gDBView.sortOrder : nsMsgViewSortOrder.ascending;
357   var viewFlags = gDBView ? gDBView.viewFlags : gCurViewFlags;
359   // close existing view.
360   if (gDBView) {
361     gDBView.close();
362     gDBView = null; 
363   }
365   switch(command)
366   {
367     case "cmd_viewUnreadMsgs":
369       viewFlags = viewFlags | nsMsgViewFlagsType.kUnreadOnly;
370       CreateDBView(msgWindow.openFolder, nsMsgViewType.eShowAllThreads, viewFlags,
371             oldSortType, oldSortOrder );
372     break;
373     case "cmd_viewAllMsgs":
374       viewFlags = viewFlags & ~nsMsgViewFlagsType.kUnreadOnly;
375       CreateDBView(msgWindow.openFolder, nsMsgViewType.eShowAllThreads, viewFlags,
376             oldSortType, oldSortOrder);
377     break;
378     case "cmd_viewThreadsWithUnread":
379       CreateDBView(msgWindow.openFolder, nsMsgViewType.eShowThreadsWithUnread, nsMsgViewFlagsType.kThreadedDisplay,
380             nsMsgViewSortType.byThread, oldSortOrder);
382     break;
383     case "cmd_viewWatchedThreadsWithUnread":
384       CreateDBView(msgWindow.openFolder, nsMsgViewType.eShowWatchedThreadsWithUnread, nsMsgViewFlagsType.kThreadedDisplay,
385             nsMsgViewSortType.byThread, oldSortOrder);
386    break;
387     case "cmd_viewIgnoredThreads":
388       if (viewFlags & nsMsgViewFlagsType.kShowIgnored)
389         viewFlags = viewFlags & ~nsMsgViewFlagsType.kShowIgnored;
390       else
391         viewFlags = viewFlags | nsMsgViewFlagsType.kShowIgnored;
392       CreateDBView(msgWindow.openFolder, nsMsgViewType.eShowAllThreads, viewFlags,
393             oldSortType, oldSortOrder);
394     break;
395   }
397   RerootThreadPane();
400 function SetSentFolderColumns(isSentFolder)
402   var tree = GetThreadTree();
404   var lastFolderSent = tree.getAttribute("lastfoldersent") == "true";
405   if (isSentFolder != lastFolderSent)
406   {
407     var senderColumn = document.getElementById("senderCol");
408     var recipientColumn = document.getElementById("recipientCol");
409     
410     var saveHidden = senderColumn.getAttribute("hidden");
411     senderColumn.setAttribute("hidden", senderColumn.getAttribute("swappedhidden"));
412     senderColumn.setAttribute("swappedhidden", saveHidden);
414     saveHidden = recipientColumn.getAttribute("hidden");
415     recipientColumn.setAttribute("hidden", recipientColumn.getAttribute("swappedhidden"));
416     recipientColumn.setAttribute("swappedhidden", saveHidden);
417   }
419   if(isSentFolder)
420     tree.setAttribute("lastfoldersent", "true");
421   else
422     tree.setAttribute("lastfoldersent", "false");
425 function SetNewsFolderColumns()
427   var sizeColumn = document.getElementById("sizeCol");
429   if (gDBView.usingLines) {
430      sizeColumn.setAttribute("label",gMessengerBundle.getString("linesColumnHeader"));
431   }
432   else {
433      sizeColumn.setAttribute("label", gMessengerBundle.getString("sizeColumnHeader"));
434   }
437 function UpdateStatusMessageCounts(folder)
439   var unreadElement = GetUnreadCountElement();
440   var totalElement = GetTotalCountElement();
441   if(folder && unreadElement && totalElement)
442   {
443     var numUnread =
444             gMessengerBundle.getFormattedString("unreadMsgStatus",
445                                                 [ folder.getNumUnread(false)]);
446     var numTotal =
447             gMessengerBundle.getFormattedString("totalMsgStatus",
448                                                 [folder.getTotalMessages(false)]);
450     unreadElement.setAttribute("label", numUnread);
451     totalElement.setAttribute("label", numTotal);
453   }
457 function ConvertColumnIDToSortType(columnID)
459   var sortKey;
461   switch (columnID) {
462     case "dateCol":
463       sortKey = nsMsgViewSortType.byDate;
464       break;
465     case "senderCol":
466         sortKey = nsMsgViewSortType.byAuthor;
467       break;
468     case "recipientCol":
469         sortKey = nsMsgViewSortType.byRecipient;
470       break;
471     case "subjectCol":
472       sortKey = nsMsgViewSortType.bySubject;
473       break;
474     case "locationCol":
475       sortKey = nsMsgViewSortType.byLocation;
476       break;
477     case "accountCol":
478       sortKey = nsMsgViewSortType.byAccount;
479       break;
480     case "unreadButtonColHeader":
481       sortKey = nsMsgViewSortType.byUnread;
482       break;
483     case "statusCol":
484       sortKey = nsMsgViewSortType.byStatus;
485       break;
486     case "sizeCol":
487       sortKey = nsMsgViewSortType.bySize;
488       break;
489     case "priorityCol":
490       sortKey = nsMsgViewSortType.byPriority;
491       break;
492     case "flaggedCol":
493       sortKey = nsMsgViewSortType.byFlagged;
494       break;
495     case "threadCol":
496       sortKey = nsMsgViewSortType.byThread;
497       break;
498     case "labelCol":
499       sortKey = nsMsgViewSortType.byLabel;
500       break;
501     case "junkStatusCol":
502       sortKey = nsMsgViewSortType.byJunkStatus;
503       break;
504     case "idCol":
505       sortKey = nsMsgViewSortType.byId;
506       break;
507     case "attachmentCol":
508             sortKey = nsMsgViewSortType.byAttachments;
509             break;
510     default:
511       dump("unsupported sort column: " + columnID + "\n");
512       sortKey = 0;
513       break;
514   }
515   return sortKey;
518 function ConvertSortTypeToColumnID(sortKey)
520   var columnID;
522   // hack to turn this into an integer, if it was a string
523   // it would be a string if it came from localStore.rdf
524   sortKey = sortKey - 0;
526   switch (sortKey) {
527     case nsMsgViewSortType.byDate:
528       columnID = "dateCol";
529       break;
530     case nsMsgViewSortType.byAuthor:
531       columnID = "senderCol";
532       break;
533     case nsMsgViewSortType.byRecipient:
534       columnID = "recipientCol";
535       break;
536     case nsMsgViewSortType.bySubject:
537       columnID = "subjectCol";
538       break;
539     case nsMsgViewSortType.byLocation:
540       columnID = "locationCol";
541       break;
542     case nsMsgViewSortType.byAccount:
543       columnID = "accountCol";
544       break;
545     case nsMsgViewSortType.byUnread:
546       columnID = "unreadButtonColHeader";
547       break;
548     case nsMsgViewSortType.byStatus:
549       columnID = "statusCol";
550       break;
551     case nsMsgViewSortType.byLabel:
552       columnID = "labelCol";
553       break;
554     case nsMsgViewSortType.bySize:
555       columnID = "sizeCol";
556       break;
557     case nsMsgViewSortType.byPriority:
558       columnID = "priorityCol";
559       break;
560     case nsMsgViewSortType.byFlagged:
561       columnID = "flaggedCol";
562       break;
563     case nsMsgViewSortType.byThread:
564       columnID = "threadCol";
565       break;
566     case nsMsgViewSortType.byId:
567       // there is no orderReceivedCol, so return null
568       columnID = null;
569       break;
570     case nsMsgViewSortType.byJunkStatus:
571       columnID = "junkStatusCol";
572       break;
573           case nsMsgViewSortType.byAttachments:
574             columnID = "attachmentCol";
575             break;
576     default:
577       dump("unsupported sort key: " + sortKey + "\n");
578       columnID = null;
579       break;
580   }
581   return columnID;
584 var nsMsgViewSortType = Components.interfaces.nsMsgViewSortType;
585 var nsMsgViewSortOrder = Components.interfaces.nsMsgViewSortOrder;
586 var nsMsgViewFlagsType = Components.interfaces.nsMsgViewFlagsType;
587 var nsMsgViewCommandType = Components.interfaces.nsMsgViewCommandType;
588 var nsMsgViewType = Components.interfaces.nsMsgViewType;
589 var nsMsgNavigationType = Components.interfaces.nsMsgNavigationType;
591 var gDBView = null;
592 var gCurViewFlags;
593 var gCurSortType;
595 // CreateDBView is called when we have a thread pane. CreateBareDBView is called when there is no
596 // tree associated with the view. CreateDBView will call into CreateBareDBView...
598 function CreateBareDBView(originalView, msgFolder, viewType, viewFlags, sortType, sortOrder)
600   var dbviewContractId = "@mozilla.org/messenger/msgdbview;1?type=";
601   // hack to turn this into an integer, if it was a string
602   // it would be a string if it came from localStore.rdf
603   viewType = viewType - 0;
605   switch (viewType) {
606       case nsMsgViewType.eShowQuickSearchResults:
607           dbviewContractId += "quicksearch";
608           break;
609       case nsMsgViewType.eShowThreadsWithUnread:
610           dbviewContractId += "threadswithunread";
611           break;
612       case nsMsgViewType.eShowWatchedThreadsWithUnread:
613           dbviewContractId += "watchedthreadswithunread";
614           break;
615       case nsMsgViewType.eShowAllThreads:
616       default:
617           dbviewContractId += "threaded";
618           break;
619   }
621   if (!originalView)
622     gDBView = Components.classes[dbviewContractId].createInstance(Components.interfaces.nsIMsgDBView);
624   gCurViewFlags = viewFlags;
625   var count = new Object;
626   if (!gThreadPaneCommandUpdater)
627     gThreadPaneCommandUpdater = new nsMsgDBViewCommandUpdater();
629   gCurSortType = sortType;
631   if (!originalView) {
632     gDBView.init(messenger, msgWindow, gThreadPaneCommandUpdater);
634     gDBView.open(msgFolder, gCurSortType, sortOrder, viewFlags, count);
635   } 
636   else {
637     gDBView = originalView.cloneDBView(messenger, msgWindow, gThreadPaneCommandUpdater);
638   }
641 function CreateDBView(msgFolder, viewType, viewFlags, sortType, sortOrder)
643   // call the inner create method
644   CreateBareDBView(null, msgFolder, viewType, viewFlags, sortType, sortOrder);
646   // now do tree specific work
648   // based on the collapsed state of the thread pane/message pane splitter,
649   // suppress message display if appropriate.
650   gDBView.suppressMsgDisplay = IsMessagePaneCollapsed();
652   UpdateSortIndicators(gCurSortType, sortOrder);
655 //------------------------------------------------------------
656 // Sets the column header sort icon based on the requested
657 // column and direction.
659 // Notes:
660 // (1) This function relies on the first part of the
661 //     <treecell id> matching the <treecol id>.  The treecell
662 //     id must have a "Header" suffix.
663 // (2) By changing the "sortDirection" attribute, a different
664 //     CSS style will be used, thus changing the icon based on
665 //     the "sortDirection" parameter.
666 //------------------------------------------------------------
667 function UpdateSortIndicator(column,sortDirection)
669   // this is obsolete
672 function GetSelectedFolderResource()
674     var folderTree = GetFolderTree();
675     var startIndex = {};
676     var endIndex = {};
677     folderTree.view.selection.getRangeAt(0, startIndex, endIndex);
678     return GetFolderResource(folderTree, startIndex.value);
681 function ChangeMessagePaneVisibility(now_hidden)
683   // we also have to hide the File/Attachments menuitem
684   node = document.getElementById("fileAttachmentMenu");
685   if (node)
686     node.hidden = now_hidden;
688   if (gDBView) {
689     // the collapsed state is the state after we released the mouse 
690     // so we take it as it is
691     gDBView.suppressMsgDisplay = now_hidden;
692   }
693   var event = document.createEvent('Events');
694   if (now_hidden) {
695     event.initEvent('messagepane-hide', false, true);
696   }
697   else {
698     event.initEvent('messagepane-unhide', false, true);
699   }
700   document.getElementById("messengerWindow").dispatchEvent(event);
703 function OnMouseUpThreadAndMessagePaneSplitter()
705   // the collapsed state is the state after we released the mouse 
706   // so we take it as it is
707   ChangeMessagePaneVisibility(IsMessagePaneCollapsed());
710 function FolderPaneSelectionChange()
712     var folderTree = GetFolderTree();
713     var folderSelection = folderTree.view.selection;
715     // This prevents a folder from being loaded in the case that the user
716     // has right-clicked on a folder different from the one that was
717     // originally highlighted.  On a right-click, the highlight (selection)
718     // of a row will be different from the value of currentIndex, thus if
719     // the currentIndex is not selected, it means the user right-clicked
720     // and we don't want to load the contents of the folder.
721     if (!folderSelection.isSelected(folderSelection.currentIndex))
722       return;
724     if(gTimelineEnabled) {
725       gTimelineService.startTimer("FolderLoading");
726       gTimelineService.enter("FolderLoading has Started");
727     }
729     if (folderSelection.count == 1)
730     {
731         var startIndex = {};
732         var endIndex = {};
733         folderSelection.getRangeAt(0, startIndex, endIndex);
734         var folderResource = GetFolderResource(folderTree, startIndex.value);
735         var msgFolder = folderResource.QueryInterface(Components.interfaces.nsIMsgFolder);
736         if (msgFolder == msgWindow.openFolder)
737             return;
738         else
739         {
740             var sortType = 0;
741             var sortOrder = 0;
742             var viewFlags = 0;
743             var viewType = 0;
745             // don't get the db if this folder is a server
746             // we're going to be display account central
747             if (!(msgFolder.isServer)) 
748             {
749               try 
750               {
751                 var msgDatabase = msgFolder.getMsgDatabase(msgWindow);
752                 if (msgDatabase)
753                 {
754                   var dbFolderInfo = msgDatabase.dBFolderInfo;
755                   sortType = dbFolderInfo.sortType;
756                   sortOrder = dbFolderInfo.sortOrder;
757                   viewFlags = dbFolderInfo.viewFlags;
758                   viewType = dbFolderInfo.viewType;
759                   msgDatabase = null;
760                   dbFolderInfo = null;
761                 }
762               }
763               catch (ex)
764               {
765                 dump("failed to get view & sort values.  ex = " + ex +"\n");
766               }
767             }
768             if (gDBView && gDBView.viewType == nsMsgViewType.eShowQuickSearchResults)
769             {
770               if (gPreQuickSearchView) //close cached view before quick search
771               {
772                 gPreQuickSearchView.close();
773                 gPreQuickSearchView = null;  
774               }
775               var searchInput = document.getElementById("searchInput");  //reset the search input on folder switch
776               if (searchInput) 
777                 searchInput.value = "";
778             }
779             ClearMessagePane();
781             if (gSearchEmailAddress || gDefaultSearchViewTerms)
782               viewType = nsMsgViewType.eShowQuickSearchResults;
783             else if (viewType == nsMsgViewType.eShowQuickSearchResults)
784               viewType = nsMsgViewType.eShowAllThreads;  //override viewType - we don't want to start w/ quick search
785             ChangeFolderByURI(folderResource.Value, viewType, viewFlags, sortType, sortOrder);
786         }
787     }
788     else
789     {
790         msgWindow.openFolder = null;
791         ClearThreadPane();
792     }
794     if (gAccountCentralLoaded)
795       UpdateMailToolbar("gAccountCentralLoaded");
796     else if (gFakeAccountPageLoaded)
797       UpdateMailToolbar("gFakeAccountPageLoaded");
799     if (gDisplayStartupPage)
800     {
801         loadStartPage();
802         gDisplayStartupPage = false;
803         UpdateMailToolbar("gDisplayStartupPage");
804     }    
807 function ClearThreadPane()
809   if (gDBView) {
810     gDBView.close();
811     gDBView = null; 
812   }
815 function IsSpecialFolder(msgFolder, flags)
817     if (!msgFolder) {
818         return false;
819     }
820     else if ((msgFolder.flags & flags) == 0) {
821           var parentMsgFolder = msgFolder.parentMsgFolder;
823       if(!parentMsgFolder) {
824          return false;
825       }
827       return IsSpecialFolder(parentMsgFolder, flags);
828     }
829     else {
830         // the user can set their INBOX to be their SENT folder.
831         // in that case, we want this folder to act like an INBOX, 
832         // and not a SENT folder
833         if ((flags & MSG_FOLDER_FLAG_SENTMAIL) && (msgFolder.flags & MSG_FOLDER_FLAG_INBOX)) {
834           return false;
835         }
836         else {
837           return true;
838         }
839     }
842 function SelectNextMessage(nextMessage)
844     dump("XXX implement SelectNextMessage()\n");
847 function GetSelectTrashUri(folder)
849     if (!folder) return null;
850     var uri = folder.getAttribute('id');
851     var resource = RDF.GetResource(uri);
852     var msgFolder =
853         resource.QueryInterface(Components.interfaces.nsIMsgFolder);
854     if (msgFolder)
855     {
856         var rootFolder = msgFolder.rootFolder;
857         var numFolder;
858         var out = new Object();
859         var trashFolder = rootFolder.getFoldersWithFlag(MSG_FOLDER_FLAG_TRASH, 1, out);
860         numFolder = out.value;
861         if (trashFolder) {
862             return trashFolder.URI;
863         }
864     }
865     return null;
868 function Undo()
870     messenger.Undo(msgWindow);
873 function Redo()
875     messenger.Redo(msgWindow);
877 var mailOfflineObserver = {
878   observe: function(subject, topic, state) {
879     // sanity checks
880     if (topic != "network:offline-status-changed") return;
881     MailOfflineStateChanged(state == "offline");
882   }
885 function AddMailOfflineObserver() 
887   var observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService); 
888   observerService.addObserver(mailOfflineObserver, "network:offline-status-changed", false);
891 function RemoveMailOfflineObserver()
893   var observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService); 
894   observerService.removeObserver(mailOfflineObserver,"network:offline-status-changed");