Dactyloidae/mailnews/base/util/folderUtils.jsm
Matt A. Tobin d97bcfb97a Follow up to 39be34c06 - The check sound be if not ordered
FINE! I'll go to bed already...
2020-07-31 08:06:52 +08:00

245 lines
8 KiB
JavaScript

/* 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/. */
/**
* This file contains helper methods for dealing with nsIMsgFolders.
*/
this.EXPORTED_SYMBOLS = ["getFolderProperties", "getSpecialFolderString",
"getFolderFromUri", "allAccountsSorted",
"getMostRecentFolders", "folderNameCompare"];
Components.utils.import("resource:///modules/mailServices.js");
Components.utils.import("resource:///modules/iteratorUtils.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
/**
* Returns a string representation of a folder's "special" type.
*
* @param aFolder the nsIMsgFolder whose special type should be returned
*/
function getSpecialFolderString(aFolder) {
const nsMsgFolderFlags = Components.interfaces.nsMsgFolderFlags;
let flags = aFolder.flags;
if (flags & nsMsgFolderFlags.Inbox)
return "Inbox";
if (flags & nsMsgFolderFlags.Trash)
return "Trash";
if (flags & nsMsgFolderFlags.Queue)
return "Outbox";
if (flags & nsMsgFolderFlags.SentMail)
return "Sent";
if (flags & nsMsgFolderFlags.Drafts)
return "Drafts";
if (flags & nsMsgFolderFlags.Templates)
return "Templates";
if (flags & nsMsgFolderFlags.Junk)
return "Junk";
if (flags & nsMsgFolderFlags.Archive)
return "Archive";
if (flags & nsMsgFolderFlags.Virtual)
return "Virtual";
return "none";
}
/**
* This function is meant to be used with trees. It returns the property list
* for all of the common properties that css styling is based off of.
*
* @param nsIMsgFolder aFolder the folder whose properties should be returned
* as a string
* @param bool aOpen true if the folder is open/expanded
*
* @return A string of the property names, delimited by space.
*/
function getFolderProperties(aFolder, aOpen) {
const nsIMsgFolder = Components.interfaces.nsIMsgFolder;
let properties = [];
properties.push("folderNameCol");
properties.push("serverType-" + aFolder.server.type);
// set the SpecialFolder attribute
properties.push("specialFolder-" + getSpecialFolderString(aFolder));
// Now set the biffState
switch (aFolder.biffState) {
case nsIMsgFolder.nsMsgBiffState_NewMail:
properties.push("biffState-NewMail");
break;
case nsIMsgFolder.nsMsgBiffState_NoMail:
properties.push("biffState-NoMail");
break;
default:
properties.push("biffState-UnknownMail");
}
properties.push("isSecure-" + aFolder.server.isSecure);
// A folder has new messages, or a closed folder or any subfolder has new messages.
if (aFolder.hasNewMessages ||
(!aOpen && aFolder.hasSubFolders && aFolder.hasFolderOrSubfolderNewMessages))
properties.push("newMessages-true");
if (aFolder.isServer) {
properties.push("isServer-true");
}
else
{
// We only set this if we're not a server
let shallowUnread = aFolder.getNumUnread(false);
if (shallowUnread > 0) {
properties.push("hasUnreadMessages-true");
}
else
{
// Make sure that shallowUnread isn't negative
shallowUnread = 0;
}
let deepUnread = aFolder.getNumUnread(true);
if (deepUnread - shallowUnread > 0)
properties.push("subfoldersHaveUnreadMessages-true");
}
properties.push("noSelect-" + aFolder.noSelect);
properties.push("imapShared-" + aFolder.imapShared);
return properties.join(" ");
}
/**
* Returns a folder for a particular uri
*
* @param aUri the rdf uri of the folder to return
*/
function getFolderFromUri(aUri) {
const Cc = Components.classes;
const Ci = Components.interfaces;
return Cc["@mozilla.org/mail/folder-lookup;1"].
getService(Ci.nsIFolderLookupService).getFolderById(aUri);
}
/**
* Returns the sort order value based on the server type to be used for sorting.
* The servers (accounts) go in the following order:
* (0) default account, (1) other mail accounts, (2) Local Folders,
* (3) IM accounts, (4) RSS, (5) News, (9) others (no server)
* This ordering is encoded in the .sortOrder property of each server type.
*
* @param aServer the server object to be tested
*/
function getServerSortOrder(aServer) {
// If there is no server sort this object to the end.
if (!aServer)
return 999999999;
// Otherwise get the server sort order from the Account manager.
return MailServices.accounts.getSortOrder(aServer);
}
/**
* Compares the passed in accounts according to their precedence.
*/
function compareAccounts(aAccount1, aAccount2) {
return getServerSortOrder(aAccount1.incomingServer)
- getServerSortOrder(aAccount2.incomingServer);
}
/**
* Returns a list of accounts sorted by server type.
*
* @param aExcludeIMAccounts Remove IM accounts from the list?
*/
function allAccountsSorted(aExcludeIMAccounts) {
// Get the account list, and add the proper items.
let accountList = toArray(fixIterator(MailServices.accounts.accounts,
Components.interfaces.nsIMsgAccount));
// This is a HACK to work around bug 41133. If we have one of the
// dummy "news" accounts there, that account won't have an
// incomingServer attached to it, and everything will blow up.
accountList = accountList.filter(function hasServer(a) {
return a.incomingServer;
});
// Remove IM servers.
if (aExcludeIMAccounts) {
accountList = accountList.filter(function(a) {
return a.incomingServer.type != "im";
});
}
// Sort the accounts else will respect the order in mail.accountmanager.accounts
if (!Services.prefs.getBoolPref("mail.accountmanager.accounts.ordered", false)) {
accountList = accountList.sort(compareAccounts);
}
// Set "Local Folders" as always the first displayed account
if (Services.prefs.getBoolPref("mail.accountmanager.localfolderfirst", false)) {
accountList.unshift(accountList.splice(accountList.findIndex(item => item.key === "account1"), 1)[0]);
}
return accountList;
}
/**
* Returns the most recently used/modified folders from the passed in list.
*
* @param aFolderList The array of nsIMsgFolders to search for recent folders.
* @param aMaxHits How many folders to return.
* @param aTimeProperty Which folder time property to use.
* Use "MRMTime" for most recently modified time.
* Use "MRUTime" for most recently used time.
*/
function getMostRecentFolders(aFolderList, aMaxHits, aTimeProperty) {
let recentFolders = [];
/**
* This sub-function will add a folder to the recentFolders array if it
* is among the aMaxHits most recent. If we exceed aMaxHits folders,
* it will pop the oldest folder, ensuring that we end up with the
* right number.
*
* @param aFolder The folder to check for recency.
*/
let oldestTime = 0;
function addIfRecent(aFolder) {
let time = 0;
try {
time = Number(aFolder.getStringProperty(aTimeProperty)) || 0;
} catch(e) {}
if (time <= oldestTime)
return;
if (recentFolders.length == aMaxHits) {
recentFolders.sort(function sort_folders_by_time(a, b) {
return a.time < b.time; });
recentFolders.pop();
oldestTime = recentFolders[recentFolders.length - 1].time;
}
recentFolders.push({ folder: aFolder, time: time });
}
for (let folder of aFolderList) {
addIfRecent(folder);
}
return recentFolders.map(function (f) { return f.folder; });
}
/**
* A locale dependent comparison function to produce a case-insensitive sort order
* used to sort folder names.
* Returns positive number if aString1 > aString2, negative number if aString1 > aString2,
* otherwise 0.
*
* @param aString1 first string to compare
* @param aString2 second string to compare
*/
function folderNameCompare(aString1, aString2) {
// TODO: improve this as described in bug 992651.
return aString1.toLocaleLowerCase()
.localeCompare(aString2.toLocaleLowerCase());
}