diff options
Diffstat (limited to 'comm/suite/mailnews/content/commandglue.js')
-rw-r--r-- | comm/suite/mailnews/content/commandglue.js | 989 |
1 files changed, 989 insertions, 0 deletions
diff --git a/comm/suite/mailnews/content/commandglue.js b/comm/suite/mailnews/content/commandglue.js new file mode 100644 index 0000000000..a9a9332c64 --- /dev/null +++ b/comm/suite/mailnews/content/commandglue.js @@ -0,0 +1,989 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * Command-specific code. This stuff should be called by the widgets + */ + +var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); +const { MailUtils } = ChromeUtils.import("resource:///modules/MailUtils.js"); +var { MailServices } = ChromeUtils.import( + "resource:///modules/MailServices.jsm" +); + +//NOTE: gMessengerBundle and gBrandBundle must be defined and set +// for this Overlay to work properly + +var gFolderJustSwitched = false; +var gBeforeFolderLoadTime; +var gVirtualFolderTerms; +var gXFVirtualFolderTerms; +var gCurrentVirtualFolderUri; +var gPrevFolderFlags; +var gPrevSelectedFolder; +var gMsgFolderSelected; + +function setTitleFromFolder(msgfolder, subject) +{ + var title = subject || ""; + + if (msgfolder) + { + if (title) + title += " - "; + + title += msgfolder.prettyName; + + if (!msgfolder.isServer) + { + var server = msgfolder.server; + var middle; + var end; + if (server.type == "nntp") { + // <folder> on <hostname> + middle = gMessengerBundle.getString("titleNewsPreHost"); + end = server.hostName; + } else { + // <folder> for <accountname> + middle = gMessengerBundle.getString("titleMailPreHost"); + end = server.prettyName; + } + if (middle) title += " " + middle; + if (end) title += " " + end; + } + } + + if (AppConstants.platform != "macosx") { + title += " - " + gBrandBundle.getString("brandShortName"); + } + + document.title = title; + + // Notify the current tab, it might want to update also. + var tabmail = GetTabMail(); + if (tabmail) + { + tabmail.saveCurrentTabState(); // gDBView may have changed! + tabmail.setTabTitle(); + } +} + +function UpdateMailToolbar(caller) +{ + //dump("XXX update mail-toolbar " + caller + "\n"); + document.commandDispatcher.updateCommands('mail-toolbar'); + + // hook for extra toolbar items + Services.obs.notifyObservers(window, "mail:updateToolbarItems"); +} + +/** + * @param folder - If viewFolder is a single folder saved + - search, this folder is the scope of the + - saved search, the real, underlying folder. + - Otherwise, it's the same as the viewFolder. + * @param viewFolder - nsIMsgFolder selected in the folder pane. + - Will be the same as folder, except if + - it's a single folder saved search. + * @param viewType - nsMsgViewType (see nsIMsgDBView.idl) + * @param viewFlags - nsMsgViewFlagsType (see nsIMsgDBView.idl) + * @param sortType - nsMsgViewSortType (see nsIMsgDBView.idl) + * @param sortOrder - nsMsgViewSortOrder (see nsIMsgDBView.idl) + **/ +function ChangeFolder(folder, viewFolder, viewType, viewFlags, sortType, sortOrder) +{ + if (folder.URI == gCurrentLoadingFolderURI) + return; + + SetUpToolbarButtons(folder.URI); + + // hook for extra toolbar items + Services.obs.notifyObservers(window, "mail:setupToolbarItems", folder.URI); + + try { + setTitleFromFolder(viewFolder, null); + } catch (ex) { + dump("error setting title: " + ex + "\n"); + } + + //if it's a server, clear the threadpane and don't bother trying to load. + if (folder.isServer) { + msgWindow.openFolder = null; + + ClearThreadPane(); + + // Load AccountCentral page here. + ShowAccountCentral(folder); + + return; + } + else + { + if (folder.server.displayStartupPage) + { + gDisplayStartupPage = true; + folder.server.displayStartupPage = false; + } + } + + // If the user clicks on folder, time to display thread pane and message pane. + ShowThreadPane(); + + gCurrentLoadingFolderURI = folder.URI; + gNextMessageAfterDelete = null; // forget what message to select, if any + + gCurrentFolderToReroot = folder.URI; + gCurrentLoadingFolderViewFlags = viewFlags; + gCurrentLoadingFolderViewType = viewType; + gCurrentLoadingFolderSortType = sortType; + gCurrentLoadingFolderSortOrder = sortOrder; + + var showMessagesAfterLoading; + try { + let server = folder.server; + if (Services.prefs.getBoolPref("mail.password_protect_local_cache")) + { + showMessagesAfterLoading = server.passwordPromptRequired; + // servers w/o passwords (like local mail) will always be non-authenticated. + // So we need to use the account manager for that case. + } + else + showMessagesAfterLoading = false; + } + catch (ex) { + showMessagesAfterLoading = false; + } + + if (viewType != nsMsgViewType.eShowVirtualFolderResults && + (folder.manyHeadersToDownload || showMessagesAfterLoading)) + { + gRerootOnFolderLoad = true; + try + { + ClearThreadPane(); + SetBusyCursor(window, true); + folder.startFolderLoading(); + folder.updateFolder(msgWindow); + } + catch(ex) + { + SetBusyCursor(window, false); + dump("Error loading with many headers to download: " + ex + "\n"); + } + } + else + { + if (viewType != nsMsgViewType.eShowVirtualFolderResults) + SetBusyCursor(window, true); + RerootFolder(folder.URI, folder, viewType, viewFlags, sortType, sortOrder); + gRerootOnFolderLoad = false; + folder.startFolderLoading(); + + //Need to do this after rerooting folder. Otherwise possibility of receiving folder loaded + //notification before folder has actually changed. + if (viewType != nsMsgViewType.eShowVirtualFolderResults) + folder.updateFolder(msgWindow); + } +} + +function isNewsURI(uri) +{ + return ((/^news-message:/.test(uri)) || (/^news:/.test(uri))); +} + +function RerootFolder(uri, newFolder, viewType, viewFlags, sortType, sortOrder) +{ + viewDebug("In reroot folder, sortType = " + sortType + "viewType = " + viewType + "\n"); + if (sortType == 0) + { + try + { + var dbFolderInfo = newFolder.msgDatabase.dBFolderInfo; + sortType = dbFolderInfo.sortType; + sortOrder = dbFolderInfo.sortOrder; + viewFlags = dbFolderInfo.viewFlags; + viewType = dbFolderInfo.viewType; + dbFolderInfo = null; + } + catch(ex) + { + dump("invalid db in RerootFolder: " + ex + "\n"); + } + } + + // workaround for #39655 + gFolderJustSwitched = true; + + ClearThreadPaneSelection(); + + //Clear the new messages of the old folder + var oldFolder = gPrevSelectedFolder; + if (oldFolder) { + oldFolder.clearNewMessages(); + oldFolder.hasNewMessages = false; + } + + //Set the window's new open folder. + msgWindow.openFolder = newFolder; + + //the new folder being selected should have its biff state get cleared. + if(newFolder) + { + newFolder.biffState = + Ci.nsIMsgFolder.nsMsgBiffState_NoMail; + } + + //Clear out the thread pane so that we can sort it with the new sort id without taking any time. + // folder.setAttribute('ref', ""); + + // null this out, so we don't try sort. + if (gDBView) { + gDBView.close(); + gDBView = null; + } + + // cancel the pending mark as read timer + ClearPendingReadTimer(); + + // If this is the sent, drafts, templates, or send later folder, + // we show "Recipient" instead of "Author". + let outgoingFlags = Ci.nsMsgFolderFlags.SentMail | + Ci.nsMsgFolderFlags.Drafts | + Ci.nsMsgFolderFlags.Templates | + Ci.nsMsgFolderFlags.Queue; + SetSentFolderColumns(newFolder.isSpecialFolder(outgoingFlags, true)); + ShowLocationColumn(viewType == nsMsgViewType.eShowVirtualFolderResults); + // Only show 'Received' column for e-mails. For newsgroup messages, the 'Date' header is as reliable as an e-mail's + // 'Received' header, as it is replaced with the news server's (more reliable) date. + UpdateReceivedColumn(newFolder); + + // now create the db view, which will sort it. + CreateDBView(newFolder, viewType, viewFlags, sortType, sortOrder); + if (oldFolder) + { + /*disable quick search clear button if we were in the search view on folder switching*/ + disableQuickSearchClearButton(); + + /*we don't null out the db reference for inbox because inbox is like the "main" folder + and performance outweighs footprint */ + if (!oldFolder.isSpecialFolder(Ci.nsMsgFolderFlags.Inbox, false)) + if (oldFolder.URI != newFolder.URI) + oldFolder.msgDatabase = null; + } + // that should have initialized gDBView, now re-root the thread pane + RerootThreadPane(); + + UpdateStatusMessageCounts(gMsgFolderSelected); + + UpdateMailToolbar("reroot folder in 3 pane"); + // hook for extra toolbar items + Services.obs.notifyObservers(window, "mail:updateToolbarItems"); + // this is to kick off cross-folder searches for virtual folders. + if (gSearchSession && !gVirtualFolderTerms) // another var might be better... + { + viewDebug("doing a xf folder search in rerootFolder\n"); + gCurrentLoadingFolderURI = ""; + ViewChangeByFolder(newFolder); + gPreQuickSearchView = null; // don't remember the cross folder search + ScrollToMessageAfterFolderLoad(newFolder); + } +} + +function SwitchView(command) +{ + // when switching thread views, we might be coming out of quick search + // or a message view. + // first set view picker to all + ViewChangeByValue(kViewItemAll); + + // clear the QS text, if we need to + ClearQSIfNecessary(); + + // now switch views + var oldSortType = gDBView ? gDBView.sortType : nsMsgViewSortType.byThread; + var oldSortOrder = gDBView ? gDBView.sortOrder : nsMsgViewSortOrder.ascending; + var viewFlags = gDBView ? gDBView.viewFlags : gCurViewFlags; + + // close existing view. + if (gDBView) { + gDBView.close(); + gDBView = null; + } + + switch(command) + { + // "All" threads and "Unread" threads don't change threading state + case "cmd_viewAllMsgs": + viewFlags = viewFlags & ~nsMsgViewFlagsType.kUnreadOnly; + CreateDBView(msgWindow.openFolder, nsMsgViewType.eShowAllThreads, viewFlags, + oldSortType, oldSortOrder); + break; + case "cmd_viewUnreadMsgs": + viewFlags = viewFlags | nsMsgViewFlagsType.kUnreadOnly; + CreateDBView(msgWindow.openFolder, nsMsgViewType.eShowAllThreads, viewFlags, + oldSortType, oldSortOrder ); + break; + // "Threads with Unread" and "Watched Threads with Unread" force threading + case "cmd_viewThreadsWithUnread": + CreateDBView(msgWindow.openFolder, nsMsgViewType.eShowThreadsWithUnread, nsMsgViewFlagsType.kThreadedDisplay, + oldSortType, oldSortOrder); + break; + case "cmd_viewWatchedThreadsWithUnread": + CreateDBView(msgWindow.openFolder, nsMsgViewType.eShowWatchedThreadsWithUnread, nsMsgViewFlagsType.kThreadedDisplay, + oldSortType, oldSortOrder); + break; + // "Ignored Threads" toggles 'ignored' inclusion -- + // but it also resets 'With Unread' views to 'All' + case "cmd_viewIgnoredThreads": + if (viewFlags & nsMsgViewFlagsType.kShowIgnored) + viewFlags = viewFlags & ~nsMsgViewFlagsType.kShowIgnored; + else + viewFlags = viewFlags | nsMsgViewFlagsType.kShowIgnored; + CreateDBView(msgWindow.openFolder, nsMsgViewType.eShowAllThreads, viewFlags, + oldSortType, oldSortOrder); + break; + } + + RerootThreadPane(); + + // this is to kick off cross-folder searches for virtual folders. + if (gSearchSession && !gVirtualFolderTerms) // another var might be better... + { + gDBView.searchSession = gSearchSession; + gSearchSession.search(msgWindow); + } +} + +function SetSentFolderColumns(isSentFolder) +{ + var tree = GetThreadTree(); + var searchBox = document.getElementById("searchInput"); + + var lastFolderSent = tree.getAttribute("lastfoldersent") == "true"; + if (isSentFolder != lastFolderSent) + { + var senderColumn = document.getElementById("senderCol"); + var recipientColumn = document.getElementById("recipientCol"); + + var saveHidden = senderColumn.getAttribute("hidden"); + senderColumn.setAttribute("hidden", senderColumn.getAttribute("swappedhidden")); + senderColumn.setAttribute("swappedhidden", saveHidden); + + saveHidden = recipientColumn.getAttribute("hidden"); + recipientColumn.setAttribute("hidden", recipientColumn.getAttribute("swappedhidden")); + recipientColumn.setAttribute("swappedhidden", saveHidden); + } + + tree.setAttribute("lastfoldersent", isSentFolder ? "true" : "false"); +} + +function ShowLocationColumn(show) +{ + var col = document.getElementById("locationCol"); + if (col) { + if (show) { + col.removeAttribute("hidden"); + col.removeAttribute("ignoreincolumnpicker"); + } + else { + col.setAttribute("hidden","true"); + col.setAttribute("ignoreincolumnpicker","true"); + } + } +} + +function UpdateReceivedColumn(newFolder) +{ + // Only show 'Received' column for e-mails. For newsgroup messages, the 'Date' header is as reliable as an e-mail's + // 'Received' header, as it is replaced with the news server's (more reliable) date. + var receivedColumn = document.getElementById("receivedCol"); + + var newFolderShowsRcvd = (newFolder.flags & Ci.nsMsgFolderFlags.Mail) && + !(newFolder.flags & (Ci.nsMsgFolderFlags.Queue | + Ci.nsMsgFolderFlags.Templates | + Ci.nsMsgFolderFlags.Drafts | + Ci.nsMsgFolderFlags.SentMail)); + + var tempHidden = receivedColumn.getAttribute("temphidden") == "true"; + var isHidden = receivedColumn.getAttribute("hidden") == "true"; + + if (!newFolderShowsRcvd && !isHidden) + { + // Record state & hide + receivedColumn.setAttribute("temphidden", "true"); + receivedColumn.setAttribute("hidden", "true"); + } + else if (newFolderShowsRcvd && tempHidden && isHidden) + { + receivedColumn.setAttribute("hidden", "false"); + } + + if (newFolderShowsRcvd) + { + receivedColumn.removeAttribute("ignoreincolumnpicker"); + receivedColumn.removeAttribute("temphidden"); + } + else + receivedColumn.setAttribute("ignoreincolumnpicker", "true"); +} + + +function SetNewsFolderColumns() +{ + var sizeColumn = document.getElementById("sizeCol"); + + if (gDBView.usingLines) { + sizeColumn.setAttribute("tooltiptext",gMessengerBundle.getString("linesColumnTooltip2")); + sizeColumn.setAttribute("label",gMessengerBundle.getString("linesColumnHeader")); + } + else { + sizeColumn.setAttribute("tooltiptext", gMessengerBundle.getString("sizeColumnTooltip2")); + sizeColumn.setAttribute("label", gMessengerBundle.getString("sizeColumnHeader")); + } +} + +function UpdateStatusMessageCounts(folder) +{ + var unreadElement = GetUnreadCountElement(); + var totalElement = GetTotalCountElement(); + if(folder && unreadElement && totalElement) + { + var numSelected = GetNumSelectedMessages(); + + var numUnread = (numSelected > 1) ? + gMessengerBundle.getFormattedString("selectedMsgStatus", + [numSelected]) : + gMessengerBundle.getFormattedString("unreadMsgStatus", + [ folder.getNumUnread(false)]); + var numTotal = + gMessengerBundle.getFormattedString("totalMsgStatus", + [folder.getTotalMessages(false)]); + + unreadElement.setAttribute("label", numUnread); + totalElement.setAttribute("label", numTotal); + unreadElement.hidden = false; + totalElement.hidden = false; + + } + +} + +function ConvertSortTypeToColumnID(sortKey) +{ + var columnID; + + // Hack to turn this into an integer, if it was a string. + // It would be a string if it came from xulstore.json + sortKey = sortKey - 0; + + switch (sortKey) { + // In the case of None, we default to the date column + // This appears to be the case in such instances as + // Global search, so don't complain about it. + case nsMsgViewSortType.byNone: + case nsMsgViewSortType.byDate: + columnID = "dateCol"; + break; + case nsMsgViewSortType.byReceived: + columnID = "receivedCol"; + break; + case nsMsgViewSortType.byAuthor: + columnID = "senderCol"; + break; + case nsMsgViewSortType.byRecipient: + columnID = "recipientCol"; + break; + case nsMsgViewSortType.bySubject: + columnID = "subjectCol"; + break; + case nsMsgViewSortType.byLocation: + columnID = "locationCol"; + break; + case nsMsgViewSortType.byAccount: + columnID = "accountCol"; + break; + case nsMsgViewSortType.byUnread: + columnID = "unreadButtonColHeader"; + break; + case nsMsgViewSortType.byStatus: + columnID = "statusCol"; + break; + case nsMsgViewSortType.byTags: + columnID = "tagsCol"; + break; + case nsMsgViewSortType.bySize: + columnID = "sizeCol"; + break; + case nsMsgViewSortType.byPriority: + columnID = "priorityCol"; + break; + case nsMsgViewSortType.byFlagged: + columnID = "flaggedCol"; + break; + case nsMsgViewSortType.byThread: + columnID = "threadCol"; + break; + case nsMsgViewSortType.byId: + columnID = "idCol"; + break; + case nsMsgViewSortType.byJunkStatus: + columnID = "junkStatusCol"; + break; + case nsMsgViewSortType.byAttachments: + columnID = "attachmentCol"; + break; + case nsMsgViewSortType.byCustom: + columnID = gDBView.db.dBFolderInfo.getProperty("customSortCol"); + if (!columnID) { + dump("ConvertSortTypeToColumnID: custom sort key but columnID not found\n"); + columnID = "dateCol"; + } + break; + default: + dump("unsupported sort key: " + sortKey + "\n"); + columnID = null; + break; + } + return columnID; +} + +var nsMsgViewSortType = Ci.nsMsgViewSortType; +var nsMsgViewSortOrder = Ci.nsMsgViewSortOrder; +var nsMsgViewFlagsType = Ci.nsMsgViewFlagsType; +var nsMsgViewCommandType = Ci.nsMsgViewCommandType; +var nsMsgViewType = Ci.nsMsgViewType; +var nsMsgNavigationType = Ci.nsMsgNavigationType; + +var gDBView = null; +var gCurViewFlags; +var gCurSortType; + +// CreateDBView is called when we have a thread pane. CreateBareDBView is called when there is no +// tree associated with the view. CreateDBView will call into CreateBareDBView... + +function CreateBareDBView(originalView, msgFolder, viewType, viewFlags, sortType, sortOrder) +{ + var dbviewContractId = "@mozilla.org/messenger/msgdbview;1?type="; + // hack to turn this into an integer, if it was a string + // it would be a string if it came from xulstore.json + viewType = viewType - 0; + + switch (viewType) { + case nsMsgViewType.eShowQuickSearchResults: + dbviewContractId += "quicksearch"; + break; + case nsMsgViewType.eShowSearch: + dbviewContractId += "search"; + break; + case nsMsgViewType.eShowThreadsWithUnread: + dbviewContractId += "threadswithunread"; + break; + case nsMsgViewType.eShowWatchedThreadsWithUnread: + dbviewContractId += "watchedthreadswithunread"; + break; + case nsMsgViewType.eShowVirtualFolderResults: + dbviewContractId += "xfvf"; + break; + case nsMsgViewType.eShowAllThreads: + default: + if (viewFlags & nsMsgViewFlagsType.kGroupBySort) + dbviewContractId += "group"; + else + dbviewContractId += "threaded"; + break; + } + +// dump ("contract id = " + dbviewContractId + "original view = " + originalView + "\n"); + if (!originalView) + gDBView = Cc[dbviewContractId].createInstance(Ci.nsIMsgDBView); + + gCurViewFlags = viewFlags; + var count = new Object; + if (!gThreadPaneCommandUpdater) + gThreadPaneCommandUpdater = new nsMsgDBViewCommandUpdater(); + + gCurSortType = sortType; + + if (!originalView) { + gDBView.init(messenger, msgWindow, gThreadPaneCommandUpdater); + gDBView.open(msgFolder, gCurSortType, sortOrder, viewFlags, count); + if (viewType == nsMsgViewType.eShowVirtualFolderResults) + { + // the view is a listener on the search results + gViewSearchListener = gDBView.QueryInterface(Ci.nsIMsgSearchNotify); + gSearchSession.registerListener(gViewSearchListener); + } + } + else { + gDBView = originalView.cloneDBView(messenger, msgWindow, gThreadPaneCommandUpdater); + } +} + +function CreateDBView(msgFolder, viewType, viewFlags, sortType, sortOrder) +{ + // call the inner create method + CreateBareDBView(null, msgFolder, viewType, viewFlags, sortType, sortOrder); + + // now do tree specific work + + // based on the collapsed state of the thread pane/message pane splitter, + // suppress message display if appropriate. + gDBView.suppressMsgDisplay = IsMessagePaneCollapsed(); + + UpdateSortIndicators(gCurSortType, sortOrder); + Services.obs.notifyObservers(msgFolder, "MsgCreateDBView", viewType + ":" + viewFlags); +} + +function FolderPaneSelectionChange() +{ + let folders = GetSelectedMsgFolders(); + if (folders.length) { + let locationItem = document.getElementById("locationFolders"); + if (locationItem && + locationItem.parentNode.parentNode.localName != "toolbarpalette") { + let msgFolder = folders[0]; + locationItem.setAttribute("label", msgFolder.prettyName); + document.getElementById("folderLocationPopup") + ._setCssSelectors(msgFolder, locationItem); + } + } + + let folderSelection = gFolderTreeView.selection; + + // This prevents a folder from being loaded in the case that the user + // has right-clicked on a folder different from the one that was + // originally highlighted. On a right-click, the highlight (selection) + // of a row will be different from the value of currentIndex, thus if + // the currentIndex is not selected, it means the user right-clicked + // and we don't want to load the contents of the folder. + if (!folderSelection.isSelected(folderSelection.currentIndex)) + return; + + gVirtualFolderTerms = null; + gXFVirtualFolderTerms = null; + + if (folders.length == 1) + { + let msgFolder = folders[0]; + let uriToLoad = msgFolder.URI; + + if (msgFolder == gMsgFolderSelected) + return; + // If msgFolder turns out to be a single folder saved search, not a virtual folder, + // realFolder will get set to the underlying folder the saved search is based on. + let realFolder = msgFolder; + gPrevSelectedFolder = gMsgFolderSelected; + gMsgFolderSelected = msgFolder; + var folderFlags = msgFolder.flags; + const kVirtual = Ci.nsMsgFolderFlags.Virtual; + // if this is same folder, and we're not showing a virtual folder + // then do nothing. + if (msgFolder == msgWindow.openFolder && + !(folderFlags & kVirtual) && !(gPrevFolderFlags & kVirtual)) + return; + + OnLeavingFolder(gPrevSelectedFolder); // mark all read in last folder + var sortType = 0; + var sortOrder = 0; + var viewFlags = 0; + var viewType = 0; + gDefaultSearchViewTerms = null; + gVirtualFolderTerms = null; + gXFVirtualFolderTerms = null; + gPrevFolderFlags = folderFlags; + gCurrentVirtualFolderUri = null; + // don't get the db if this folder is a server + // we're going to be display account central + if (!(msgFolder.isServer)) + { + try + { + var msgDatabase = msgFolder.msgDatabase; + if (msgDatabase) + { + gSearchSession = null; + var dbFolderInfo = msgDatabase.dBFolderInfo; + sortType = dbFolderInfo.sortType; + sortOrder = dbFolderInfo.sortOrder; + viewType = dbFolderInfo.viewType; + viewFlags = dbFolderInfo.viewFlags; + if (folderFlags & kVirtual) + { + viewType = nsMsgViewType.eShowQuickSearchResults; + var searchTermString = dbFolderInfo.getCharProperty("searchStr"); + // trick the view code into updating the real folder... + gCurrentVirtualFolderUri = uriToLoad; + var srchFolderUri = dbFolderInfo.getCharProperty("searchFolderUri"); + var srchFolderUriArray = srchFolderUri.split('|'); + var searchOnline = dbFolderInfo.getBooleanProperty("searchOnline", false); + // cross folder search + var filterList = MailServices.filters.getTempFilterList(msgFolder); + var tempFilter = filterList.createFilter("temp"); + filterList.parseCondition(tempFilter, searchTermString); + if (srchFolderUriArray.length > 1) + { + viewType = nsMsgViewType.eShowVirtualFolderResults; + gXFVirtualFolderTerms = CreateGroupedSearchTerms(tempFilter.searchTerms); + setupXFVirtualFolderSearch(srchFolderUriArray, gXFVirtualFolderTerms, searchOnline); + // need to set things up so that reroot folder issues the search + } + else + { + uriToLoad = srchFolderUri; + // we need to load the db for the actual folder so that many hdrs to download + // will return false... + realFolder = MailUtils.getFolderForURI(uriToLoad); + msgDatabase = realFolder.msgDatabase; +// dump("search term string = " + searchTermString + "\n"); + + gVirtualFolderTerms = CreateGroupedSearchTerms(tempFilter.searchTerms); + } + } + msgDatabase = null; + dbFolderInfo = null; + } + } + catch (ex) + { + dump("failed to get view & sort values. ex = " + ex +"\n"); + } + } + // clear cached view if we have no db or a pending quick search + if (!gDBView || gDBView.viewType == nsMsgViewType.eShowQuickSearchResults) + { + if (gPreQuickSearchView) //close cached view before quick search + { + gPreQuickSearchView.close(); + gPreQuickSearchView = null; + } + var searchInput = document.getElementById("searchInput"); //reset the search input on folder switch + if (searchInput) + searchInput.value = ""; + } + ClearMessagePane(); + + if (gXFVirtualFolderTerms) + viewType = nsMsgViewType.eShowVirtualFolderResults; + else if (gSearchEmailAddress || gVirtualFolderTerms) + viewType = nsMsgViewType.eShowQuickSearchResults; + else if (viewType == nsMsgViewType.eShowQuickSearchResults) + viewType = nsMsgViewType.eShowAllThreads; //override viewType - we don't want to start w/ quick search + ChangeFolder(realFolder, msgFolder, viewType, viewFlags, sortType, sortOrder); + if (gVirtualFolderTerms) + gDBView.viewFolder = msgFolder; + + let tabmail = GetTabMail(); + if (tabmail) + { + tabmail.saveCurrentTabState(); // gDBView may have changed! + tabmail.setTabTitle(); + } + } + else + { + msgWindow.openFolder = null; + ClearThreadPane(); + } + + if (gAccountCentralLoaded) + UpdateMailToolbar("gAccountCentralLoaded"); + + if (gDisplayStartupPage) + { + loadStartPage(); + gDisplayStartupPage = false; + UpdateMailToolbar("gDisplayStartupPage"); + } +} + +function ClearThreadPane() +{ + if (gDBView) { + gDBView.close(); + gDBView = null; + } +} + +var mailOfflineObserver = { + observe: function(subject, topic, state) { + // sanity checks + if (topic != "network:offline-status-changed") return; + MailOfflineStateChanged(state == "offline"); + } +} + +function AddMailOfflineObserver() +{ + Services.obs.addObserver(mailOfflineObserver, "network:offline-status-changed"); +} + +function RemoveMailOfflineObserver() +{ + Services.obs.removeObserver(mailOfflineObserver, "network:offline-status-changed"); +} + +function getSearchTermString(searchTerms) +{ + var searchIndex; + var condition = ""; + var count = searchTerms.length; + for (searchIndex = 0; searchIndex < count; ) + { + var term = searchTerms[searchIndex++]; + + if (condition.length > 1) + condition += ' '; + + if (term.matchAll) + { + condition = "ALL"; + break; + } + condition += (term.booleanAnd) ? "AND (" : "OR ("; + condition += term.termAsString + ')'; + } + return condition; +} + +function CreateVirtualFolder(newName, parentFolder, searchFolderURIs, searchTerms, searchOnline) +{ + // ### need to make sure view/folder doesn't exist. + if (searchFolderURIs && (searchFolderURIs != "") && newName && (newName != "")) + { + var newFolder; + try + { + if (parentFolder instanceof(Ci.nsIMsgLocalMailFolder)) + newFolder = parentFolder.createLocalSubfolder(newName); + else + newFolder = parentFolder.addSubfolder(newName); + newFolder.setFlag(Ci.nsMsgFolderFlags.Virtual); + var vfdb = newFolder.msgDatabase; + var searchTermString = getSearchTermString(searchTerms); + var dbFolderInfo = vfdb.dBFolderInfo; + // set the view string as a property of the db folder info + // set the original folder name as well. + dbFolderInfo.setCharProperty("searchStr", searchTermString); + dbFolderInfo.setCharProperty("searchFolderUri", searchFolderURIs); + dbFolderInfo.setBooleanProperty("searchOnline", searchOnline); + vfdb.summaryValid = true; + vfdb.Close(true); + parentFolder.notifyFolderAdded(newFolder); + MailServices.accounts.saveVirtualFolders(); + } + catch(e) + { + throw(e); // so that the dialog does not automatically close + dump ("Exception : creating virtual folder \n"); + } + } + else + { + dump("no name or nothing selected\n"); + } +} + +var searchSessionContractID = "@mozilla.org/messenger/searchSession;1"; +var gSearchSession; + +var nsMsgSearchScope = Ci.nsMsgSearchScope; + +var gMessengerBundle = null; + +var gViewSearchListener; + +function GetScopeForFolder(folder) +{ + return folder.server.searchScope; +} + +function setupXFVirtualFolderSearch(folderUrisToSearch, searchTerms, searchOnline) +{ + var count = new Object; + var i; + + gSearchSession = Cc[searchSessionContractID] + .createInstance(Ci.nsIMsgSearchSession); + + for (i in folderUrisToSearch) + { + let realFolder = MailUtils.getFolderForURI(folderUrisToSearch[i]); + if (!realFolder.isServer) + gSearchSession.addScopeTerm(!searchOnline ? nsMsgSearchScope.offlineMail : GetScopeForFolder(realFolder), realFolder); + } + + for (let term of searchTerms) { + gSearchSession.appendTerm(term); + } +} + +/** + * Uses an array of search terms to produce a new list usable from quick search. + * + * @param searchTermsArray A nsIArray of terms to copy. + * + * @return nsIMutableArray of search terms + */ +function CreateGroupedSearchTerms(searchTermsArray) +{ + + var searchSession = gSearchSession || + Cc[searchSessionContractID].createInstance(Ci.nsIMsgSearchSession); + + // Create a temporary nsIMutableArray to store our search terms + // since we will be modifying the terms so they work with quick search. + var searchTermsArrayForQS = Cc["@mozilla.org/array;1"] + .createInstance(Ci.nsIMutableArray); + + var numEntries = searchTermsArray.length; + for (let i = 0; i < numEntries; i++) { + let searchTerm = searchTermsArray[i]; + + // clone the term, since we might be modifying it + var searchTermForQS = searchSession.createTerm(); + searchTermForQS.value = searchTerm.value; + searchTermForQS.attrib = searchTerm.attrib; + searchTermForQS.arbitraryHeader = searchTerm.arbitraryHeader + searchTermForQS.hdrProperty = searchTerm.hdrProperty; + searchTermForQS.customId = searchTerm.customId + searchTermForQS.op = searchTerm.op; + + // mark the first node as a group + if (i == 0) + searchTermForQS.beginsGrouping = true; + else if (i == numEntries - 1) + searchTermForQS.endsGrouping = true; + + // turn the first term to true to work with quick search... + searchTermForQS.booleanAnd = i ? searchTerm.booleanAnd : true; + + searchTermsArrayForQS.appendElement(searchTermForQS); + } + return searchTermsArrayForQS; +} + +function OnLeavingFolder(aFolder) +{ + try + { + // Mark all messages of aFolder as read: + // We can't use the command controller, because it is already tuned in to the + // new folder, so we just mimic its behaviour wrt goDoCommand('cmd_markAllRead'). + if (gDBView && Services.prefs.getBoolPref("mailnews.mark_message_read." + aFolder.server.type)) + { + gDBView.doCommand(nsMsgViewCommandType.markAllRead); + } + } + catch(e){/* ignore */} +} + +var gViewDebug = false; + +function viewDebug(str) +{ + if (gViewDebug) + dump(str); +} + |