Bug 1669871 - Pre-sort the list of address books returned by nsIAbManager.directories. r=mkmelin a=wsmwk
authorGeoff Lankow <geoff@darktrojan.net>
Thu, 08 Oct 2020 22:06:22 +0000
changeset 40839 7f504c66bf54275a9686e1b670256b38c793452b
parent 40838 855800ef6150bb9e7c789ad4c46af9b9cdcd57c5
child 40840 2fe6caa558e42024c1a902345837ebd8bc3f0fe3
push id406
push userthunderbird@calypsoblue.org
push dateMon, 19 Oct 2020 19:46:44 +0000
reviewersmkmelin, wsmwk
bugs1669871
Bug 1669871 - Pre-sort the list of address books returned by nsIAbManager.directories. r=mkmelin a=wsmwk Differential Revision: https://phabricator.services.mozilla.com/D92865
mailnews/addrbook/modules/AddrBookManager.jsm
--- a/mailnews/addrbook/modules/AddrBookManager.jsm
+++ b/mailnews/addrbook/modules/AddrBookManager.jsm
@@ -43,16 +43,37 @@ let store = null;
 let types = ["jsaddrbook", "jscarddav", "moz-abldapdirectory"];
 if (AppConstants.platform == "macosx") {
   types.push("moz-abosxdirectory");
 } else if (AppConstants.platform == "win") {
   types.push("moz-aboutlookdirectory");
 }
 
 /**
+ * A pre-sorted list of directories in the right order, to be returned by
+ * AddrBookManager.directories. That function is called a lot, and there's
+ * no need to sort the list every time.
+ *
+ * Call updateSortedDirectoryList after `store` changes and before any
+ * notifications happen.
+ */
+let sortedDirectoryList = [];
+function updateSortedDirectoryList() {
+  sortedDirectoryList = [...store.values()];
+  sortedDirectoryList.sort((a, b) => {
+    let aPosition = a.dirPrefId ? a.getIntValue("position", 0) : 0;
+    let bPosition = b.dirPrefId ? b.getIntValue("position", 0) : 0;
+    if (aPosition != bPosition) {
+      return aPosition - bPosition;
+    }
+    return a.URI < b.URI ? -1 : 1;
+  });
+}
+
+/**
  * Initialise an address book directory by URI.
  *
  * @param {string} uri - URI for the directory.
  * @param {boolean} shouldStore - Whether to keep a reference to this address
  *   book in the store.
  * @returns {nsIAbDirectory}
  */
 function createDirectoryObject(uri, shouldStore = false) {
@@ -148,16 +169,18 @@ function ensureInitialized() {
             }
             break;
         }
       }
     } catch (ex) {
       Cu.reportError(ex);
     }
   }
+
+  updateSortedDirectoryList();
 }
 
 Services.obs.addObserver(() => {
   // Clear the store. The next call to ensureInitialized will recreate it.
   store = null;
 }, "addrbook-reload");
 
 /**
@@ -171,26 +194,17 @@ AddrBookManager.prototype = {
     "nsICommandLineHandler",
   ]),
   classID: Components.ID("{224d3ef9-d81c-4d94-8826-a79a5835af93}"),
 
   /* nsIAbManager */
 
   get directories() {
     ensureInitialized();
-    let dirs = [...store.values()];
-    dirs.sort((a, b) => {
-      let aPosition = a.dirPrefId ? a.getIntValue("position", 0) : 0;
-      let bPosition = b.dirPrefId ? b.getIntValue("position", 0) : 0;
-      if (aPosition != bPosition) {
-        return aPosition - bPosition;
-      }
-      return a.URI < b.URI ? -1 : 1;
-    });
-    return dirs;
+    return sortedDirectoryList.slice();
   },
   getDirectory(uri) {
     if (uri.startsWith("moz-abdirectory://")) {
       throw new Components.Exception(
         "The root address book no longer exists",
         Cr.NS_ERROR_FAILURE
       );
     }
@@ -285,16 +299,17 @@ AddrBookManager.prototype = {
 
         ensureUniquePrefName();
         Services.prefs.setStringPref(`${prefName}.description`, dirName);
         Services.prefs.setStringPref(`${prefName}.filename`, file.leafName);
         Services.prefs.setStringPref(`${prefName}.uri`, uri);
 
         uri = `moz-abldapdirectory://${prefName}`;
         let dir = createDirectoryObject(uri, true);
+        updateSortedDirectoryList();
         Services.obs.notifyObservers(dir, "addrbook-directory-created");
         break;
       }
       case Ci.nsIAbManager.MAPI_DIRECTORY_TYPE: {
         if (AppConstants.platform == "macosx") {
           uri = "moz-abosxdirectory:///";
           if (store.has(uri)) {
             throw Components.Exception(
@@ -336,23 +351,25 @@ AddrBookManager.prototype = {
         Services.prefs.setStringPref(
           `${prefName}.description`,
           "chrome://messenger/locale/addressbook/addressBook.properties"
         );
         Services.prefs.setStringPref(`${prefName}.uri`, uri);
 
         if (AppConstants.platform == "macosx") {
           let dir = createDirectoryObject(uri, true);
+          updateSortedDirectoryList();
           Services.obs.notifyObservers(dir, "addrbook-directory-created");
         } else if (AppConstants.platform == "win") {
           let outlookInterface = Cc[
             "@mozilla.org/addressbook/outlookinterface;1"
           ].getService(Ci.nsIAbOutlookInterface);
           for (let folderURI of outlookInterface.getFolderURIs(uri)) {
             let dir = createDirectoryObject(folderURI, true);
+            updateSortedDirectoryList();
             Services.obs.notifyObservers(dir, "addrbook-directory-created");
           }
         }
         break;
       }
       case Ci.nsIAbManager.JS_DIRECTORY_TYPE:
       case Ci.nsIAbManager.CARDDAV_DIRECTORY_TYPE: {
         let file = Services.dirsvc.get("ProfD", Ci.nsIFile);
@@ -365,16 +382,17 @@ AddrBookManager.prototype = {
         Services.prefs.setStringPref(`${prefName}.filename`, file.leafName);
 
         let scheme =
           type == Ci.nsIAbManager.JS_DIRECTORY_TYPE
             ? "jsaddrbook"
             : "jscarddav";
         uri = `${scheme}://${file.leafName}`;
         let dir = createDirectoryObject(uri, true);
+        updateSortedDirectoryList();
         Services.obs.notifyObservers(dir, "addrbook-directory-created");
         break;
       }
       default:
         throw Components.Exception(
           `Unexpected directory type: ${type}`,
           Cr.NS_ERROR_UNEXPECTED
         );
@@ -429,16 +447,17 @@ AddrBookManager.prototype = {
         Services.prefs.clearUserPref(`${prefName}.carddav.url`);
       }
       Services.prefs.clearUserPref(`${prefName}.dirType`);
     }
     Services.prefs.clearUserPref(`${prefName}.filename`);
     Services.prefs.clearUserPref(`${prefName}.uid`);
     Services.prefs.clearUserPref(`${prefName}.uri`);
     store.delete(uri);
+    updateSortedDirectoryList();
 
     // Clear this reference to the deleted address book.
     if (Services.prefs.getStringPref("mail.collect_addressbook") == uri) {
       Services.prefs.clearUserPref("mail.collect_addressbook");
     }
 
     if (fileName) {
       let file = Services.dirsvc.get("ProfD", Ci.nsIFile);