Bug 1636019 - Remove the remaining uses of nsIAbView, then remove it and nsAbView. r=mkmelin DONTBUILD
authorGeoff Lankow <geoff@darktrojan.net>
Thu, 07 May 2020 15:13:24 +1200
changeset 39088 a8bc54c5c7938de77fb02b35fd6d8aa19a369e41
parent 39087 2420430174e2f1e4a4e76d6af3a29f67258c564a
child 39089 01d4d3db44e6c509076df5fda8f37064d9652c78
push id402
push userclokep@gmail.com
push dateMon, 29 Jun 2020 20:48:04 +0000
reviewersmkmelin
bugs1636019
Bug 1636019 - Remove the remaining uses of nsIAbView, then remove it and nsAbView. r=mkmelin DONTBUILD
mail/base/content/mailCommands.js
mail/components/addrbook/content/abContactsPanel.xhtml
mail/components/addrbook/content/addressbook.xhtml
mail/components/addrbook/test/browser/browser_contact_tree.js
mail/components/addrbook/test/browser/browser_search.js
mail/locales/en-US/chrome/messenger/addressbook/abMainWindow.dtd
mailnews/addrbook/content/abResultsPane.js
mailnews/addrbook/content/abView.js
mailnews/addrbook/public/moz.build
mailnews/addrbook/public/nsAbBaseCID.h
mailnews/addrbook/public/nsIAbView.idl
mailnews/addrbook/src/moz.build
mailnews/addrbook/src/nsAbView.cpp
mailnews/addrbook/src/nsAbView.h
mailnews/addrbook/src/nsAddbookProtocolHandler.cpp
mailnews/build/nsMailModule.cpp
--- a/mail/base/content/mailCommands.js
+++ b/mail/base/content/mailCommands.js
@@ -167,36 +167,25 @@ function ComposeMessage(type, format, fo
   }
 
   // dump("\nComposeMessage from XUL: " + identity + "\n");
 
   switch (type) {
     case msgComposeType.New: // new message
       // dump("OpenComposeWindow with " + identity + "\n");
 
-      // If the addressbook sidebar panel is open and has focus, get
-      // the selected addresses from it.
-      if (
-        document.commandDispatcher.focusedWindow &&
-        document.commandDispatcher.focusedWindow.document.documentElement.hasAttribute(
-          "selectedaddresses"
-        )
-      ) {
-        NewMessageToSelectedAddresses(type, format, identity);
-      } else {
-        MailServices.compose.OpenComposeWindow(
-          null,
-          null,
-          null,
-          type,
-          format,
-          identity,
-          msgWindow
-        );
-      }
+      MailServices.compose.OpenComposeWindow(
+        null,
+        null,
+        null,
+        type,
+        format,
+        identity,
+        msgWindow
+      );
       return;
     case msgComposeType.NewsPost:
       // dump("OpenComposeWindow with " + identity + " and " + newsgroup + "\n");
       MailServices.compose.OpenComposeWindow(
         null,
         null,
         newsgroup,
         type,
@@ -272,45 +261,16 @@ function ComposeMessage(type, format, fo
             msgWindow
           );
         }
       }
   }
 }
 /* eslint-enable complexity */
 
-function NewMessageToSelectedAddresses(type, format, identity) {
-  var abSidebarPanel = document.commandDispatcher.focusedWindow;
-  var abResultsTree = abSidebarPanel.document.getElementById("abResultsTree");
-  var abView = abResultsTree.view;
-  abView = abView.QueryInterface(Ci.nsIAbView);
-  var addresses = abView.selectedAddresses;
-  var params = Cc[
-    "@mozilla.org/messengercompose/composeparams;1"
-  ].createInstance(Ci.nsIMsgComposeParams);
-  if (params) {
-    params.type = type;
-    params.format = format;
-    params.identity = identity;
-    var composeFields = Cc[
-      "@mozilla.org/messengercompose/composefields;1"
-    ].createInstance(Ci.nsIMsgCompFields);
-    if (composeFields) {
-      let addressList = [];
-      const nsISupportsString = Ci.nsISupportsString;
-      for (let i = 0; i < addresses.length; i++) {
-        addressList.push(addresses.queryElementAt(i, nsISupportsString).data);
-      }
-      composeFields.to = addressList.join(",");
-      params.composeFields = composeFields;
-      MailServices.compose.OpenComposeWindowWithParams(null, params);
-    }
-  }
-}
-
 function Subscribe(preselectedMsgFolder) {
   window.openDialog(
     "chrome://messenger/content/subscribe.xhtml",
     "subscribe",
     "chrome,modal,titlebar,resizable=yes",
     {
       folder: preselectedMsgFolder,
       okCallback: SubscribeOKCallback,
--- a/mail/components/addrbook/content/abContactsPanel.xhtml
+++ b/mail/components/addrbook/content/abContactsPanel.xhtml
@@ -12,18 +12,17 @@
 %abResultsPaneDTD;
 <!ENTITY % abContactsPanelDTD SYSTEM "chrome://messenger/locale/addressbook/abContactsPanel.dtd" >
 %abContactsPanelDTD;
 ]>
 
 <window id="abContactsPanel"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
         onload="AbPanelLoad();"
-        onunload="AbPanelUnload();"
-        selectedaddresses="true">
+        onunload="AbPanelUnload();">
 
   <stringbundle id="bundle_addressBook" src="chrome://messenger/locale/addressbook/addressBook.properties"/>
 
   <script src="chrome://global/content/globalOverlay.js"/>
   <script src="chrome://global/content/editMenuOverlay.js"/>
   <script src="chrome://communicator/content/utilityOverlay.js"/>
   <script src="chrome://messenger/content/addressbook/addressbook.js"/>
   <script src="chrome://messenger/content/addressbook/abDragDrop.js"/>
--- a/mail/components/addrbook/content/addressbook.xhtml
+++ b/mail/components/addrbook/content/addressbook.xhtml
@@ -430,21 +430,16 @@
             <menuitem id="menu_search_addresses"
                       label="&searchAddressesCmd.label;"
                       accesskey="&searchAddressesCmd.accesskey;"
                       key="key_searchAddresses"
                       oncommand="onAdvancedAbSearch();"
                       class="menuitem-iconic"/>
 
             <menuseparator/>
-            <!-- LOCALIZATION NOTE: set "hideSwapFnLnUI" to false in .dtd to enable the UI -->
-            <menuitem label="&swapFirstNameLastNameCmd.label;"
-                      accesskey="&swapFirstNameLastNameCmd.accesskey;"
-                      hidden="&hideSwapFnLnUI;"
-                      oncommand="AbSwapFirstNameLastName()"/>
             <menuitem id="menu_properties"
                       key="key_properties"
                       command="cmd_properties"
                       label="&propertiesContext.label;"
                       accesskey="&propertiesContext.accesskey;"
                       valueGeneric="&propertiesMenu.label;"
                       valueGenericAccessKey="&propertiesMenu.accesskey;"
                       valueAddressBook="&abPropertiesMenu.label;"
--- a/mail/components/addrbook/test/browser/browser_contact_tree.js
+++ b/mail/components/addrbook/test/browser/browser_contact_tree.js
@@ -93,31 +93,30 @@ add_task(async () => {
   function deleteRowWithPrompt(row) {
     let promptPromise = BrowserTestUtils.promiseAlertDialogOpen("accept");
     mailTestUtils.treeClick(EventUtils, abWindow, abContactTree, row, 0, {});
     EventUtils.synthesizeKey("VK_DELETE", {}, abWindow);
     return promptPromise;
   }
 
   function checkRows(...expectedCards) {
-    abContactTree.view.QueryInterface(Ci.nsIAbView);
     Assert.equal(
-      abContactTree.view.rowCount,
+      abWindow.gAbView.rowCount,
       expectedCards.length,
       "rowCount correct"
     );
     for (let i = 0; i < expectedCards.length; i++) {
       if (expectedCards[i].isMailList) {
         Assert.equal(
-          abContactTree.view.getCardFromRow(i).displayName,
+          abWindow.gAbView.getCardFromRow(i).displayName,
           expectedCards[i].dirName
         );
       } else {
         Assert.equal(
-          abContactTree.view.getCardFromRow(i).displayName,
+          abWindow.gAbView.getCardFromRow(i).displayName,
           expectedCards[i].displayName
         );
       }
     }
   }
 
   let bookA = createAddressBook("book A");
   let contactA1 = bookA.addCard(createContact("contact", "A1"));
--- a/mail/components/addrbook/test/browser/browser_search.js
+++ b/mail/components/addrbook/test/browser/browser_search.js
@@ -27,18 +27,17 @@ add_task(async () => {
       }
     });
   }
 
   function checkRows(...expectedCards) {
     is(resultsTree.view.rowCount, expectedCards.length, "rowCount correct");
     for (let i = 0; i < expectedCards.length; i++) {
       is(
-        resultsTree.view.QueryInterface(Ci.nsIAbView).getCardFromRow(i)
-          .displayName,
+        abWindow.gAbView.getCardFromRow(i).displayName,
         expectedCards[i].displayName,
         `row ${i} has the right contact`
       );
     }
   }
 
   let personalBook = MailServices.ab.getDirectoryFromId("ldap_2.servers.pab");
   let historyBook = MailServices.ab.getDirectoryFromId(
--- a/mail/locales/en-US/chrome/messenger/addressbook/abMainWindow.dtd
+++ b/mail/locales/en-US/chrome/messenger/addressbook/abMainWindow.dtd
@@ -47,21 +47,16 @@
 <!ENTITY deleteCmd.label                                "Delete">
 <!ENTITY deleteAbCmd.label                              "Delete Address Book">
 <!ENTITY deleteContactCmd.label                         "Delete Contact">
 <!ENTITY deleteContactsCmd.label                        "Delete Contacts">
 <!ENTITY deleteListCmd.label                            "Delete List">
 <!ENTITY deleteListsCmd.label                           "Delete Lists">
 <!ENTITY deleteItemsCmd.label                           "Delete Items">
 <!ENTITY searchAddressesCmd.key                         "f">
-<!ENTITY swapFirstNameLastNameCmd.label                 "Swap First/Last Name">
-<!ENTITY swapFirstNameLastNameCmd.accesskey             "w">
-<!-- LOCALIZATION NOTE (hideSwapFnLnUI) : DONT_TRANSLATE -->
-<!-- Swap FN/LN UI  Set to "false" to show swap fn/ln UI -->
-<!ENTITY hideSwapFnLnUI "true">
 <!ENTITY propertiesMenu.label                           "Properties">
 <!ENTITY propertiesMenu.accesskey                       "i">
 <!ENTITY propertiesCmd.key                              "i">
 <!ENTITY abPropertiesMenu.label                         "Address Book Properties">
 <!ENTITY abPropertiesMenu.accesskey                     "i">
 <!ENTITY contactPropertiesMenu.label                    "Contact Properties">
 <!ENTITY contactPropertiesMenu.accesskey                "i">
 <!ENTITY mailingListPropertiesMenu.label                "Mailing List Properties">
--- a/mailnews/addrbook/content/abResultsPane.js
+++ b/mailnews/addrbook/content/abResultsPane.js
@@ -31,28 +31,29 @@
 var kNothingSelected = 0;
 var kListsAndCards = 1;
 var kMultipleListsOnly = 2;
 var kSingleListOnly = 3;
 var kCardsOnly = 4;
 
 // Global Variables
 
-// gAbView holds an object with an nsIAbView interface
-var gAbView = null;
 // Holds a reference to the "abResultsTree" document element. Initially
 // set up by SetAbView.
 var gAbResultsTree = null;
+// gAbView is the current value of gAbResultsTree.view, without passing
+// through XPCOM, so we can access extra functions if necessary.
+var gAbView = null;
 
 function SetAbView(aURI, aSearchQuery) {
   // If we don't have a URI, just clear the view and leave everything else
   // alone.
   if (!aURI) {
     if (gAbView) {
-      gAbView.clearView();
+      CloseAbView();
     }
     return;
   }
 
   // If we do have a URI, we want to allow updating the review even if the
   // URI is the same, as the search results may be different.
 
   var sortColumn = kDefaultSortColumn;
@@ -266,22 +267,16 @@ function GetSelectedRows() {
       }
       selectedRows += j;
     }
   }
 
   return selectedRows;
 }
 
-function AbSwapFirstNameLastName() {
-  if (gAbView) {
-    gAbView.swapFirstNameLastName();
-  }
-}
-
 function AbEditSelectedCard() {
   AbEditCard(GetSelectedCard());
 }
 
 function AbResultsPaneOnClick(event) {
   // we only care about button 0 (left click) events
   if (event.button != 0) {
     return;
--- a/mailnews/addrbook/content/abView.js
+++ b/mailnews/addrbook/content/abView.js
@@ -25,54 +25,38 @@ function ABView(directory, searchQuery, 
       this.listener.onCountChanged(this.rowCount);
     }
   }
   this.sortBy(sortColumn, sortDirection);
 }
 ABView.prototype = {
   QueryInterface: ChromeUtils.generateQI([
     Ci.nsITreeView,
-    Ci.nsIAbView,
     Ci.nsIAbDirSearchListener,
     Ci.nsIObserver,
     Ci.nsISupportsWeakReference,
   ]),
 
+  directory: null,
+  listener: null,
   _notifications: [
     "addrbook-contact-created",
     "addrbook-contact-deleted",
     "addrbook-list-member-added",
     "addrbook-list-member-removed",
   ],
 
-  // nsITreeView
-
-  selectionChanged() {
-    if (this.listener) {
-      this.listener.onSelectionChanged();
-    }
-  },
-  setTree(tree) {
-    this.tree = tree;
-    for (let topic of this._notifications) {
-      if (tree) {
-        Services.obs.addObserver(this, topic, true);
-      } else {
-        Services.obs.removeObserver(this, topic);
-      }
-    }
-  },
-
-  // nsIAbView
+  sortColumn: "",
+  sortDirection: "",
 
   deleteSelectedCards() {
     let directoryMap = new Map();
     for (let i = 0; i < this.selection.getRangeCount(); i++) {
-      let start = {},
-        finish = {};
+      let start = {};
+      let finish = {};
       this.selection.getRangeAt(i, start, finish);
       for (let j = start.value; j <= finish.value; j++) {
         let card = this.getCardFromRow(j);
         let directoryId = card.directoryId.split("&")[0];
         let cardSet = directoryMap.get(directoryId);
         if (!cardSet) {
           cardSet = new Set();
           directoryMap.set(directoryId, cardSet);
@@ -92,23 +76,19 @@ ABView.prototype = {
 
       cardSet = [...cardSet];
       directory.deleteCards(cardSet.filter(card => !card.isMailList));
       for (let card of cardSet.filter(card => card.isMailList)) {
         MailServices.ab.deleteAddressBook(card.mailListURI);
       }
     }
   },
-
   getCardFromRow(row) {
     return this._rowMap[row] ? this._rowMap[row].card : null;
   },
-
-  sortColumn: "",
-  sortDirection: "",
   sortBy(sortColumn, sortDirection, resort) {
     if (sortColumn == this.sortColumn && !resort) {
       if (sortDirection == this.sortDirection) {
         return;
       }
       this._rowMap.reverse();
     } else {
       this._rowMap.sort((a, b) => {
@@ -123,16 +103,34 @@ ABView.prototype = {
 
     if (this.tree) {
       this.tree.invalidate();
     }
     this.sortColumn = sortColumn;
     this.sortDirection = sortDirection;
   },
 
+  // nsITreeView
+
+  selectionChanged() {
+    if (this.listener) {
+      this.listener.onSelectionChanged();
+    }
+  },
+  setTree(tree) {
+    this.tree = tree;
+    for (let topic of this._notifications) {
+      if (tree) {
+        Services.obs.addObserver(this, topic, true);
+      } else {
+        Services.obs.removeObserver(this, topic);
+      }
+    }
+  },
+
   // nsIAbDirSearchListener
 
   onSearchFoundCard(card) {
     this._rowMap.push(new abViewCard(card));
   },
   onSearchFinished(result, errorMsg) {
     this.sortBy(this.sortColumn, this.sortDirection, true);
     if (this.listener) {
--- a/mailnews/addrbook/public/moz.build
+++ b/mailnews/addrbook/public/moz.build
@@ -11,17 +11,16 @@ XPIDL_SOURCES += [
     'nsIAbDirectory.idl',
     'nsIAbDirectoryQuery.idl',
     'nsIAbDirectoryQueryProxy.idl',
     'nsIAbDirSearchListener.idl',
     'nsIAbLDAPAttributeMap.idl',
     'nsIAbLDIFService.idl',
     'nsIAbListener.idl',
     'nsIAbManager.idl',
-    'nsIAbView.idl',
     'nsIAddbookUrl.idl',
     'nsIAddrDatabase.idl',
     'nsIMsgVCardService.idl',
 ]
 
 if CONFIG['MOZ_LDAP_XPCOM']:
     XPIDL_SOURCES += [
         'nsIAbLDAPCard.idl',
--- a/mailnews/addrbook/public/nsAbBaseCID.h
+++ b/mailnews/addrbook/public/nsAbBaseCID.h
@@ -327,26 +327,16 @@
     0x63e11d52, 0x3c9b, 0x11d6, {                   \
       0xb7, 0xb9, 0x0, 0xb0, 0xd0, 0x6e, 0x5f, 0x27 \
     }                                               \
   }
 
 #define NS_ABLDAP_PROCESSCHANGELOGDATA_CONTRACTID \
   "@mozilla.org/addressbook/ldap-process-changelog-data;1"
 
-// nsABView
-#define NS_ABVIEW_CID                                \
-  {                                                  \
-    0xc5eb5d6a, 0x1dd1, 0x11b2, {                    \
-      0xa0, 0x25, 0x94, 0xd1, 0x18, 0x1f, 0xc5, 0x9c \
-    }                                                \
-  }
-
-#define NS_ABVIEW_CONTRACTID "@mozilla.org/addressbook/abview;1"
-
 #ifdef XP_MACOSX
 //
 // nsAbOSXDirectory
 //
 #  define NS_ABOSXDIRECTORY_PREFIX "moz-abosxdirectory"
 #  define NS_ABOSXCARD_PREFIX "moz-abosxcard"
 
 #  define NS_ABOSXDIRECTORY_CONTRACTID \
deleted file mode 100644
--- a/mailnews/addrbook/public/nsIAbView.idl
+++ /dev/null
@@ -1,109 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */
-
-#include "nsISupports.idl"
-
-interface nsIAbCard;
-interface nsIAbDirectory;
-interface nsIArray;
-
-/// Define a class using this interface to listen to updates from nsIAbView.
-[scriptable, uuid(79ad5d6e-1dd2-11b2-addd-f547dab50d75)]
-interface nsIAbViewListener : nsISupports
-{
-  /// Called when the selection is changed in the tree
-  void onSelectionChanged();
-
-  /// Called when the total count of cards is changed.
-  void onCountChanged(in long total);
-};
-
-/**
- * This interface and its associated nsAbView object provides an interface
- * to allow a tree to be associated with an address book, and the results
- * to be displayed in that tree.
- *
- * If you wish for the tree to display the results of a different address
- * book, then call setView again. There is no need to delete and recreate the
- * nsAbView object. If you wish to clear the view, then just call clearView.
- */
-[scriptable, uuid(45e2fa9f-0b59-4090-a2fa-fb7042cf64a2)]
-interface nsIAbView : nsISupports
-{
-  /**
-   * Sets up the nsIAbView to look at the specified directory. This may be
-   * called multiple times.
-   *
-   * @param aDirectory      The directory to search, this may be a directory
-   *                        with a query string.
-   * @param aViewListener   An optional listener.
-   * @param aSortColumn     The column to sort by. See the xul element with
-   *                        id abResultsTreeCols for possible values.
-   * @param aSortDirection  The sort direction to use ("ascending"/"descending")
-   * @return                The actual sortColumn (various switching of apps
-   *                        could cause the persisted sortColumn to be bogus).
-   */
-  AString setView(in nsIAbDirectory aAddressBook,
-                  in nsIAbViewListener aAbViewListener,
-                  in AString aSortColumn,
-                  in AString aSortDirection);
-
-  /**
-   * Clears the view and releases any locally held copies of the address book
-   * directory. This should be called when the view is no longer required, e.g.
-   * on unload.
-   */
-  void clearView();
-
-  /**
-   * Sorts the tree by the specified parameters.
-   *
-   * @param aSortColumn     The column to sort by. See the xul element with
-   *                        id abResultsTreeCols for possible values.
-   * @param aSortDirection  The sort direction to use ("ascending"/"descending")
-   * @param aResort         The function DOES optimize for the case when sortColumn
-   *                        and sortDirection is identical since the last call.
-   *                        If an unconditional resort is needed, set this to true.
-   */
-  void sortBy(in wstring aSortColumn, in wstring aSortDirection,
-              [optional] in boolean aResort);
-
-  /// Returns the current sort column
-  readonly attribute AString sortColumn;
-
-  /// Returns the current sort direction
-  readonly attribute AString sortDirection;
-
-  /**
-   * Returns the current directory that this view is hooked up to. May be
-   * null if no directory has been set.
-   */
-  readonly attribute nsIAbDirectory directory;
-
-  /**
-   * Returns the card associated with the given row.
-   *
-   * @param aRow  The row from which to return the card.
-   * @return      A card associated with the row, or null if row is not valid.
-   */
-  nsIAbCard getCardFromRow(in long aRow);
-
-  /// Selects all rows in the view.
-  void selectAll();
-
-  /// Deletes all the selected cards (no prompts are given).
-  void deleteSelectedCards();
-
-  /**
-   * Swaps the first and last name order, and updates the appropriate
-   * preference.
-   */
-  void swapFirstNameLastName();
-
-  /**
-   *  Returns an array of the currently selected addresses.
-   */
-  readonly attribute nsIArray selectedAddresses;
-};
--- a/mailnews/addrbook/src/moz.build
+++ b/mailnews/addrbook/src/moz.build
@@ -14,17 +14,16 @@ SOURCES += [
     'nsAbBooleanExpression.cpp',
     'nsAbCardProperty.cpp',
     'nsAbContentHandler.cpp',
     'nsAbDirectoryQuery.cpp',
     'nsAbDirectoryQueryProxy.cpp',
     'nsAbDirProperty.cpp',
     'nsAbLDIFService.cpp',
     'nsAbQueryStringToExpression.cpp',
-    'nsAbView.cpp',
     'nsAddbookProtocolHandler.cpp',
     'nsAddbookUrl.cpp',
     'nsAddrDatabase.cpp',
     'nsMsgVCardService.cpp',
     'nsVCard.cpp',
     'nsVCardObj.cpp',
 ]
 
deleted file mode 100644
--- a/mailnews/addrbook/src/nsAbView.cpp
+++ /dev/null
@@ -1,1313 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */
-
-#include "mozilla/DebugOnly.h"
-
-#include "nsAbView.h"
-#include "nsISupports.h"
-#include "nsCOMPtr.h"
-#include "nsIAbCard.h"
-#include "prmem.h"
-#include "nsCollationCID.h"
-#include "nsIAbManager.h"
-#include "nsAbBaseCID.h"
-#include "nsXPCOM.h"
-#include "nsTreeColumns.h"
-#include "nsCRTGlue.h"
-#include "nsIMutableArray.h"
-#include "nsIPrefService.h"
-#include "nsIPrefBranch.h"
-#include "nsIStringBundle.h"
-#include "nsIPrefLocalizedString.h"
-#include "nsArrayUtils.h"
-#include "nsIAddrDatabase.h"  // for kPhoneticNameColumn
-#include "nsMsgUtils.h"
-#include "mozilla/Services.h"
-#include "mozilla/dom/DataTransfer.h"
-
-using namespace mozilla;
-
-#define CARD_NOT_FOUND -1
-#define ALL_ROWS -1
-
-#define PREF_MAIL_ADDR_BOOK_LASTNAMEFIRST "mail.addr_book.lastnamefirst"
-#define PREF_MAIL_ADDR_BOOK_DISPLAYNAME_AUTOGENERATION \
-  "mail.addr_book.displayName.autoGeneration"
-#define PREF_MAIL_ADDR_BOOK_DISPLAYNAME_LASTNAMEFIRST \
-  "mail.addr_book.displayName.lastnamefirst"
-
-// Also, our default primary sort
-#define GENERATED_NAME_COLUMN_ID "GeneratedName"
-
-NS_IMPL_ISUPPORTS(nsAbView, nsIAbView, nsITreeView, nsIAbListener, nsIObserver)
-
-nsAbView::nsAbView()
-    : mInitialized(false),
-      mIsAllDirectoryRootView(false),
-      mSuppressSelectionChange(false),
-      mSuppressCountChange(false),
-      mGeneratedNameFormat(0) {}
-
-nsAbView::~nsAbView() {
-  if (mInitialized) {
-    NS_ASSERTION(NS_SUCCEEDED(ClearView()), "failed to close view");
-  }
-}
-
-NS_IMETHODIMP nsAbView::ClearView() {
-  mDirectory = nullptr;
-  mAbViewListener = nullptr;
-  if (mTree) {
-    IgnoredErrorResult rv2;
-    mTree->SetView(nullptr, mozilla::dom::CallerType::System, rv2);
-  }
-  mTree = nullptr;
-  mTreeSelection = nullptr;
-
-  if (mInitialized) {
-    nsresult rv;
-    mInitialized = false;
-    nsCOMPtr<nsIPrefBranch> pbi(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = pbi->RemoveObserver(PREF_MAIL_ADDR_BOOK_LASTNAMEFIRST, this);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    nsCOMPtr<nsIAbManager> abManager(
-        do_GetService(NS_ABMANAGER_CONTRACTID, &rv));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = abManager->RemoveAddressBookListener(this);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  int32_t i = mCards.Length();
-  while (i-- > 0)
-    NS_ASSERTION(NS_SUCCEEDED(RemoveCardAt(i)), "remove card failed");
-
-  return NS_OK;
-}
-
-nsresult nsAbView::RemoveCardAt(int32_t row) {
-  nsresult rv;
-
-  AbCard *abcard = mCards.ElementAt(row);
-  mCards.RemoveElementAt(row);
-  delete abcard;
-
-  // This needs to happen after we remove the card, as RowCountChanged() will
-  // call GetRowCount()
-  if (mTree) {
-    mTree->RowCountChanged(row, -1);
-  }
-
-  if (mAbViewListener && !mSuppressCountChange) {
-    rv = mAbViewListener->OnCountChanged(mCards.Length());
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-  return NS_OK;
-}
-
-nsresult nsAbView::SetGeneratedNameFormatFromPrefs() {
-  nsresult rv;
-  nsCOMPtr<nsIPrefBranch> prefBranchInt(
-      do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return prefBranchInt->GetIntPref(PREF_MAIL_ADDR_BOOK_LASTNAMEFIRST,
-                                   &mGeneratedNameFormat);
-}
-
-nsresult nsAbView::Initialize() {
-  if (mInitialized) return NS_OK;
-
-  mInitialized = true;
-
-  nsresult rv;
-  nsCOMPtr<nsIAbManager> abManager(do_GetService(NS_ABMANAGER_CONTRACTID, &rv));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = abManager->AddAddressBookListener(this, nsIAbListener::all);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIPrefBranch> pbi(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = pbi->AddObserver(PREF_MAIL_ADDR_BOOK_LASTNAMEFIRST, this, false);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (!mABBundle) {
-    nsCOMPtr<nsIStringBundleService> stringBundleService =
-        mozilla::services::GetStringBundleService();
-    NS_ENSURE_TRUE(stringBundleService, NS_ERROR_UNEXPECTED);
-
-    rv = stringBundleService->CreateBundle(
-        "chrome://messenger/locale/addressbook/addressBook.properties",
-        getter_AddRefs(mABBundle));
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  return SetGeneratedNameFormatFromPrefs();
-}
-
-NS_IMETHODIMP nsAbView::SetView(nsIAbDirectory *aAddressBook,
-                                nsIAbViewListener *aAbViewListener,
-                                const nsAString &aSortColumn,
-                                const nsAString &aSortDirection,
-                                nsAString &aResult) {
-  // Ensure we are initialized
-  nsresult rv = Initialize();
-
-  mAbViewListener = nullptr;
-  if (mTree) {
-    // Try and speed deletion of old cards by disconnecting the tree from us.
-    mTreeSelection->ClearSelection();
-    IgnoredErrorResult rv2;
-    mTree->SetView(nullptr, mozilla::dom::CallerType::System, rv2);
-  }
-
-  // Clear out old cards
-  int32_t i = mCards.Length();
-  while (i-- > 0) {
-    rv = RemoveCardAt(i);
-    NS_ASSERTION(NS_SUCCEEDED(rv), "remove card failed");
-  }
-
-  // We replace all cards so any sorting is no longer valid.
-  mSortColumn.AssignLiteral("");
-  mSortDirection.AssignLiteral("");
-
-  if (aAddressBook) {
-    nsCString uri;
-    aAddressBook->GetURI(uri);
-
-    mIsAllDirectoryRootView = false;
-    mDirectory = aAddressBook;
-    rv = EnumerateCards();
-    NS_ENSURE_SUCCESS(rv, rv);
-  } else {
-    mIsAllDirectoryRootView = true;
-
-    nsCOMPtr<nsIAbManager> abManager(
-        do_GetService(NS_ABMANAGER_CONTRACTID, &rv));
-    NS_ENSURE_SUCCESS(rv, rv);
-    nsCOMPtr<nsISimpleEnumerator> enumerator;
-    rv = abManager->GetDirectories(getter_AddRefs(enumerator));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    bool hasMore = false;
-    nsCOMPtr<nsISupports> support;
-    nsCOMPtr<nsIAbDirectory> directory;
-    while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMore)) && hasMore) {
-      rv = enumerator->GetNext(getter_AddRefs(support));
-      NS_ENSURE_SUCCESS(rv, rv);
-      directory = do_QueryInterface(support, &rv);
-
-      // If, for some reason, we are unable to get a directory, we continue.
-      if (NS_FAILED(rv)) continue;
-
-      mDirectory = directory;
-      rv = EnumerateCards();
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-  }
-
-  NS_NAMED_LITERAL_STRING(generatedNameColumnId, GENERATED_NAME_COLUMN_ID);
-
-  // See if the persisted sortColumn is valid.
-  // It may not be, if you migrated from older versions, or switched between
-  // a mozilla build and a commercial build, which have different columns.
-  nsAutoString actualSortColumn;
-  if (!generatedNameColumnId.Equals(aSortColumn) && mCards.Length()) {
-    nsIAbCard *card = mCards.ElementAt(0)->card;
-    nsString value;
-    // XXX todo
-    // Need to check if _Generic is valid.  GetCardValue() will always return
-    // NS_OK for _Generic We're going to have to ask mDirectory if it is. It
-    // might not be.  example:  _ScreenName is valid in Netscape, but not
-    // Mozilla.
-    rv = GetCardValue(card, aSortColumn, value);
-    if (NS_FAILED(rv))
-      actualSortColumn = generatedNameColumnId;
-    else
-      actualSortColumn = aSortColumn;
-  } else
-    actualSortColumn = aSortColumn;
-
-  rv = SortBy(actualSortColumn.get(), PromiseFlatString(aSortDirection).get(),
-              false);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  mAbViewListener = aAbViewListener;
-  if (mAbViewListener && !mSuppressCountChange) {
-    rv = mAbViewListener->OnCountChanged(mCards.Length());
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  aResult = actualSortColumn;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbView::GetDirectory(nsIAbDirectory **aDirectory) {
-  NS_ENSURE_ARG_POINTER(aDirectory);
-  NS_IF_ADDREF(*aDirectory = mDirectory);
-  return NS_OK;
-}
-
-nsresult nsAbView::EnumerateCards() {
-  nsresult rv;
-  nsCOMPtr<nsISimpleEnumerator> cardsEnumerator;
-  nsCOMPtr<nsIAbCard> card;
-
-  if (!mDirectory) return NS_ERROR_UNEXPECTED;
-
-  rv = mDirectory->GetChildCards(getter_AddRefs(cardsEnumerator));
-  if (NS_SUCCEEDED(rv) && cardsEnumerator) {
-    nsCOMPtr<nsISupports> item;
-    bool more;
-    while (NS_SUCCEEDED(cardsEnumerator->HasMoreElements(&more)) && more) {
-      rv = cardsEnumerator->GetNext(getter_AddRefs(item));
-      if (NS_SUCCEEDED(rv)) {
-        nsCOMPtr<nsIAbCard> card = do_QueryInterface(item);
-        AbCard *abcard = new AbCard(card);
-
-        // XXX todo
-        // Would it be better to do an insertion sort, than append and sort?
-        // XXX todo
-        // If we knew how many cards there was going to be
-        // we could allocate an array of the size,
-        // instead of growing and copying as we append.
-        mCards.AppendElement(abcard);
-      }
-    }
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbView::GetRowCount(int32_t *aRowCount) {
-  *aRowCount = mCards.Length();
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbView::GetSelection(nsITreeSelection **aSelection) {
-  NS_IF_ADDREF(*aSelection = mTreeSelection);
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbView::SetSelection(nsITreeSelection *aSelection) {
-  mTreeSelection = aSelection;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbView::GetRowProperties(int32_t index, nsAString &properties) {
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbView::GetCellProperties(int32_t row, nsTreeColumn *col,
-                                          nsAString &properties) {
-  NS_ENSURE_TRUE(row >= 0, NS_ERROR_UNEXPECTED);
-
-  if (mCards.Length() <= (size_t)row) return NS_OK;
-
-  const nsAString &colID = col->GetId();
-  // "G" == "GeneratedName"
-  if (colID.IsEmpty() || colID.First() != 'G') return NS_OK;
-
-  nsIAbCard *card = mCards.ElementAt(row)->card;
-
-  bool isMailList;
-  nsresult rv = card->GetIsMailList(&isMailList);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (isMailList) properties.AssignLiteral("MailList");
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbView::GetColumnProperties(nsTreeColumn *col,
-                                            nsAString &properties) {
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbView::IsContainer(int32_t index, bool *_retval) {
-  *_retval = false;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbView::IsContainerOpen(int32_t index, bool *_retval) {
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP nsAbView::IsContainerEmpty(int32_t index, bool *_retval) {
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP nsAbView::IsSeparator(int32_t index, bool *_retval) {
-  *_retval = false;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbView::IsSorted(bool *_retval) {
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP nsAbView::CanDrop(int32_t index, int32_t orientation,
-                                mozilla::dom::DataTransfer *dataTransfer,
-                                bool *_retval) {
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP nsAbView::Drop(int32_t row, int32_t orientation,
-                             mozilla::dom::DataTransfer *dataTransfer) {
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP nsAbView::GetParentIndex(int32_t rowIndex, int32_t *_retval) {
-  *_retval = -1;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbView::HasNextSibling(int32_t rowIndex, int32_t afterIndex,
-                                       bool *_retval) {
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP nsAbView::GetLevel(int32_t index, int32_t *_retval) {
-  *_retval = 0;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbView::GetImageSrc(int32_t row, nsTreeColumn *col,
-                                    nsAString &_retval) {
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbView::GetCellValue(int32_t row, nsTreeColumn *col,
-                                     nsAString &_retval) {
-  return NS_OK;
-}
-
-nsresult nsAbView::GetCardValue(nsIAbCard *card, const nsAString &colID,
-                                nsAString &_retval) {
-  if (colID.EqualsLiteral("addrbook")) {
-    nsCString dirID;
-    nsresult rv = card->GetDirectoryId(dirID);
-    if (NS_SUCCEEDED(rv))
-      CopyUTF8toUTF16(Substring(dirID, dirID.FindChar('&') + 1), _retval);
-
-    return rv;
-  }
-
-  // "G" == "GeneratedName", "_P" == "_PhoneticName"
-  // else, standard column (like PrimaryEmail and _AimScreenName)
-  if (colID[0] == char16_t('G'))
-    return card->GenerateName(mGeneratedNameFormat, mABBundle, _retval);
-
-  if (colID[0] == char16_t('_') && colID[1] == char16_t('P'))
-    // Use LN/FN order for the phonetic name
-    return card->GeneratePhoneticName(true, _retval);
-
-  if (colID.EqualsLiteral("ChatName")) return card->GenerateChatName(_retval);
-
-  nsresult rv =
-      card->GetPropertyAsAString(NS_ConvertUTF16toUTF8(colID).get(), _retval);
-  if (rv == NS_ERROR_NOT_AVAILABLE) {
-    rv = NS_OK;
-    _retval.Truncate();
-  }
-  return rv;
-}
-
-nsresult nsAbView::RefreshTree() {
-  nsresult rv;
-
-  // The PREF_MAIL_ADDR_BOOK_LASTNAMEFIRST pref affects how the GeneratedName
-  // column looks. so if the GeneratedName is our primary or secondary sort, we
-  // need to resort. the same applies for kPhoneticNameColumn
-  //
-  // XXX optimize me
-  // PrimaryEmail is always the secondary sort, unless it is currently the
-  // primary sort.  So, if PrimaryEmail is the primary sort,
-  // GeneratedName might be the secondary sort.
-  //
-  // One day, we can get fancy and remember what the secondary sort is.
-  // We do that, we can fix this code. At best, it will turn a sort into a
-  // invalidate.
-  //
-  // If neither the primary nor the secondary sorts are GeneratedName (or
-  // kPhoneticNameColumn), all we have to do is invalidate (to show the new
-  // GeneratedNames), but the sort will not change.
-  if (mSortColumn.EqualsLiteral(GENERATED_NAME_COLUMN_ID) ||
-      mSortColumn.EqualsLiteral(kPriEmailProperty) ||
-      mSortColumn.EqualsLiteral(kPhoneticNameColumn)) {
-    rv = SortBy(mSortColumn.get(), mSortDirection.get(), true);
-  } else {
-    rv = InvalidateTree(ALL_ROWS);
-
-    // Although the selection hasn't changed, the card that is selected may need
-    // to be displayed differently, therefore pretend that the selection has
-    // changed to force that update.
-    SelectionChangedXPCOM();
-  }
-
-  return rv;
-}
-
-NS_IMETHODIMP nsAbView::GetCellText(int32_t row, nsTreeColumn *col,
-                                    nsAString &_retval) {
-  NS_ENSURE_TRUE(row >= 0 && (size_t)row < mCards.Length(),
-                 NS_ERROR_UNEXPECTED);
-
-  nsIAbCard *card = mCards.ElementAt(row)->card;
-  const nsAString &colID = col->GetId();
-  return GetCardValue(card, colID, _retval);
-}
-
-NS_IMETHODIMP nsAbView::SetTree(mozilla::dom::XULTreeElement *tree) {
-  mTree = tree;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbView::ToggleOpenState(int32_t index) {
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP nsAbView::CycleHeader(nsTreeColumn *col) { return NS_OK; }
-
-nsresult nsAbView::InvalidateTree(int32_t row) {
-  if (!mTree) return NS_OK;
-
-  if (row == ALL_ROWS)
-    mTree->Invalidate();
-  else
-    mTree->InvalidateRow(row);
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbView::SelectionChangedXPCOM() {
-  if (mAbViewListener && !mSuppressSelectionChange) {
-    nsresult rv = mAbViewListener->OnSelectionChanged();
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbView::CycleCell(int32_t row, nsTreeColumn *col) {
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP nsAbView::IsEditable(int32_t row, nsTreeColumn *col,
-                                   bool *_retval) {
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP nsAbView::SetCellValue(int32_t row, nsTreeColumn *col,
-                                     const nsAString &value) {
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP nsAbView::SetCellText(int32_t row, nsTreeColumn *col,
-                                    const nsAString &value) {
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP nsAbView::GetCardFromRow(int32_t row, nsIAbCard **aCard) {
-  *aCard = nullptr;
-  NS_ENSURE_TRUE(row >= 0, NS_ERROR_UNEXPECTED);
-  if (mCards.Length() <= (size_t)row) {
-    return NS_OK;
-  }
-
-  AbCard *a = mCards.ElementAt(row);
-  if (!a) return NS_OK;
-
-  NS_IF_ADDREF(*aCard = a->card);
-  return NS_OK;
-}
-
-#define DESCENDING_SORT_FACTOR -1
-#define ASCENDING_SORT_FACTOR 1
-
-typedef struct SortClosure {
-  const char16_t *colID;
-  int32_t factor;
-  nsAbView *abView;
-} SortClosure;
-
-static int inplaceSortCallback(const AbCard *card1, const AbCard *card2,
-                               SortClosure *closure) {
-  int32_t sortValue;
-
-  // If we are sorting the "PrimaryEmail", swap the collation keys, as the
-  // secondary is always the PrimaryEmail. Use the last primary key as the
-  // secondary key.
-  //
-  // "Pr" to distinguish "PrimaryEmail" from "PagerNumber"
-  if (closure->colID[0] == char16_t('P') &&
-      closure->colID[1] == char16_t('r')) {
-    sortValue = closure->abView->CompareCollationKeys(
-        card1->secondaryCollationKey, card2->secondaryCollationKey);
-    if (sortValue)
-      return sortValue * closure->factor;
-    else
-      return closure->abView->CompareCollationKeys(card1->primaryCollationKey,
-                                                   card2->primaryCollationKey) *
-             (closure->factor);
-  } else {
-    sortValue = closure->abView->CompareCollationKeys(
-        card1->primaryCollationKey, card2->primaryCollationKey);
-    if (sortValue)
-      return sortValue * (closure->factor);
-    else
-      return closure->abView->CompareCollationKeys(
-                 card1->secondaryCollationKey, card2->secondaryCollationKey) *
-             (closure->factor);
-  }
-}
-
-static void SetSortClosure(const char16_t *sortColumn,
-                           const char16_t *sortDirection, nsAbView *abView,
-                           SortClosure *closure) {
-  closure->colID = sortColumn;
-
-  if (sortDirection && !NS_strcmp(sortDirection, u"descending"))
-    closure->factor = DESCENDING_SORT_FACTOR;
-  else
-    closure->factor = ASCENDING_SORT_FACTOR;
-
-  closure->abView = abView;
-  return;
-}
-
-class CardComparator {
- public:
-  void SetClosure(SortClosure *closure) { m_closure = closure; };
-
-  bool Equals(const AbCard *a, const AbCard *b) const {
-    return inplaceSortCallback(a, b, m_closure) == 0;
-  }
-  bool LessThan(const AbCard *a, const AbCard *b) const {
-    return inplaceSortCallback(a, b, m_closure) < 0;
-  }
-
- private:
-  SortClosure *m_closure;
-};
-
-NS_IMETHODIMP nsAbView::SortBy(const char16_t *colID, const char16_t *sortDir,
-                               bool aResort = false) {
-  nsresult rv;
-
-  int32_t count = mCards.Length();
-
-  nsAutoString sortColumn;
-  if (!colID)
-    sortColumn =
-        NS_LITERAL_STRING(GENERATED_NAME_COLUMN_ID);  // default sort column
-  else
-    sortColumn = colID;
-
-  nsAutoString sortDirection;
-  if (!sortDir)
-    sortDirection = NS_LITERAL_STRING("ascending");  // default direction
-  else
-    sortDirection = sortDir;
-
-  if (mSortColumn.Equals(sortColumn) && !aResort) {
-    if (mSortDirection.Equals(sortDir)) {
-      // If sortColumn and sortDirection are identical since the last call, do
-      // nothing.
-      return NS_OK;
-    } else {
-      // If we are sorting by how we are already sorted,
-      // and just the sort direction changes, just reverse.
-      int32_t halfPoint = count / 2;
-      for (int32_t i = 0; i < halfPoint; i++) {
-        // Swap the elements.
-        AbCard *ptr1 = mCards.ElementAt(i);
-        AbCard *ptr2 = mCards.ElementAt(count - i - 1);
-        mCards.ReplaceElementAt(i, ptr2);
-        mCards.ReplaceElementAt(count - i - 1, ptr1);
-      }
-      mSortDirection = sortDir;
-    }
-  } else {
-    // Generate collation keys
-    for (int32_t i = 0; i < count; i++) {
-      AbCard *abcard = mCards.ElementAt(i);
-
-      rv = GenerateCollationKeysForCard(sortColumn, abcard);
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-
-    // We need to do full sort.
-    SortClosure closure;
-    SetSortClosure(sortColumn.get(), sortDirection.get(), this, &closure);
-
-    nsCOMPtr<nsIMutableArray> selectedCards =
-        do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = GetSelectedCards(selectedCards);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    nsCOMPtr<nsIAbCard> indexCard;
-
-    if (mTreeSelection) {
-      int32_t currentIndex = -1;
-
-      rv = mTreeSelection->GetCurrentIndex(&currentIndex);
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      if (currentIndex != -1) {
-        rv = GetCardFromRow(currentIndex, getter_AddRefs(indexCard));
-        NS_ENSURE_SUCCESS(rv, rv);
-      }
-    }
-
-    CardComparator cardComparator;
-    cardComparator.SetClosure(&closure);
-    mCards.Sort(cardComparator);
-
-    rv = ReselectCards(selectedCards, indexCard);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    mSortColumn = sortColumn;
-    mSortDirection = sortDirection;
-  }
-
-  rv = InvalidateTree(ALL_ROWS);
-  NS_ENSURE_SUCCESS(rv, rv);
-  return rv;
-}
-
-int32_t nsAbView::CompareCollationKeys(const nsTArray<uint8_t> &key1,
-                                       const nsTArray<uint8_t> &key2) {
-  NS_ASSERTION(mCollationKeyGenerator, "no key generator");
-  if (!mCollationKeyGenerator) return 0;
-
-  int32_t result;
-
-  nsresult rv = mCollationKeyGenerator->CompareRawSortKey(key1, key2, &result);
-  NS_ASSERTION(NS_SUCCEEDED(rv), "key compare failed");
-  if (NS_FAILED(rv)) result = 0;
-  return result;
-}
-
-nsresult nsAbView::GenerateCollationKeysForCard(const nsAString &colID,
-                                                AbCard *abcard) {
-  nsresult rv;
-  nsString value;
-
-  if (!mCollationKeyGenerator) {
-    nsCOMPtr<nsICollationFactory> factory =
-        do_CreateInstance(NS_COLLATIONFACTORY_CONTRACTID, &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = factory->CreateCollation(getter_AddRefs(mCollationKeyGenerator));
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  rv = GetCardValue(abcard->card, colID, value);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = mCollationKeyGenerator->AllocateRawSortKey(
-      nsICollation::kCollationCaseInSensitive, value,
-      abcard->primaryCollationKey);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Hardcode email to be our secondary key. As we are doing this, just call
-  // the card's GetCardValue direct, rather than our own function which will
-  // end up doing the same as then we can save a bit of time.
-  rv = abcard->card->GetPrimaryEmail(value);
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = mCollationKeyGenerator->AllocateRawSortKey(
-      nsICollation::kCollationCaseInSensitive, value,
-      abcard->secondaryCollationKey);
-  NS_ENSURE_SUCCESS(rv, rv);
-  return rv;
-}
-
-// A helper method currently returns true if the directory is an LDAP.
-// We can tweak this to return true for all Remote Address Books where the
-// search is asynchronous.
-bool isDirectoryRemote(nsCOMPtr<nsIAbDirectory> aDir) {
-  nsCString uri;
-  aDir->GetURI(uri);
-  return (uri.Find("moz-abldapdirectory") != kNotFound);
-}
-
-// A helper method to get the query string for nsIAbDirectory.
-nsCString getQuery(nsCOMPtr<nsIAbDirectory> aDir) {
-  nsCString uri;
-  aDir->GetURI(uri);
-  int32_t searchBegin = uri.FindChar('?');
-  if (searchBegin == kNotFound) return EmptyCString();
-
-  return nsCString(Substring(uri, searchBegin));
-}
-
-NS_IMETHODIMP nsAbView::OnItemAdded(nsISupports *parentDir, nsISupports *item) {
-  if (!parentDir) return NS_OK;
-  if (!mDirectory)  // No address book selected.
-    return NS_OK;
-
-  nsresult rv;
-  nsCOMPtr<nsIAbDirectory> directory = do_QueryInterface(parentDir, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  bool isRemote = isDirectoryRemote(directory);
-  // If the search is performed on All Address books, its possible that the LDAP
-  // results start coming when mDirectory has changed (LDAP search works in an
-  // asynchronous manner).
-  // Since the listeners are being added to all nsAbView instances, we need to
-  // make sure that all the views aren't updated by the listeners.
-  bool isDirectoryQuery = false;
-  bool isMDirectoryQuery = false;
-  // See if current parent directory to which the item is added is a query
-  // directory.
-  directory->GetIsQuery(&isDirectoryQuery);
-  // Get the query string for the directory in Advanced AB Search window.
-  nsCString directoryQuery(getQuery(directory));
-  // See if the selected directory in Address book main window is a query
-  // directory.
-  mDirectory->GetIsQuery(&isMDirectoryQuery);
-  // Get the query string for the selected directory in the main AB window.
-  nsCString mDirectoryQuery(getQuery(mDirectory));
-  if ((mIsAllDirectoryRootView && isRemote && isDirectoryQuery &&
-       isMDirectoryQuery && directoryQuery.Equals(mDirectoryQuery)) ||
-      directory.get() == mDirectory.get()) {
-    nsCOMPtr<nsIAbCard> addedCard = do_QueryInterface(item);
-    if (addedCard) {
-      AbCard *abcard = new AbCard(addedCard);
-      rv = GenerateCollationKeysForCard(mSortColumn, abcard);
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      int32_t index;
-      rv = AddCard(abcard, false /* select card */, &index);
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-  }
-  return rv;
-}
-
-NS_IMETHODIMP nsAbView::Observe(nsISupports *aSubject, const char *aTopic,
-                                const char16_t *someData) {
-  if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
-    if (nsDependentString(someData).EqualsLiteral(
-            PREF_MAIL_ADDR_BOOK_LASTNAMEFIRST)) {
-      nsresult rv = SetGeneratedNameFormatFromPrefs();
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      rv = RefreshTree();
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-  }
-  return NS_OK;
-}
-
-// Adds a card into our internal mCards array.
-// mCards takes ownership of abcard.
-nsresult nsAbView::AddCard(AbCard *abcard, bool selectCardAfterAdding,
-                           int32_t *index) {
-  nsresult rv = NS_OK;
-  NS_ENSURE_ARG_POINTER(abcard);
-
-  *index = FindIndexForInsert(abcard);
-  mCards.InsertElementAt(*index, abcard);
-
-  // This needs to happen after we insert the card, as RowCountChanged() will
-  // call GetRowCount()
-  if (mTree) mTree->RowCountChanged(*index, 1);
-
-  // Checking for mTree here works around core bug 399227
-  if (selectCardAfterAdding && mTreeSelection && mTree) {
-    mTreeSelection->SetCurrentIndex(*index);
-    mTreeSelection->RangedSelect(*index, *index, false /* augment */);
-  }
-
-  if (mAbViewListener && !mSuppressCountChange) {
-    rv = mAbViewListener->OnCountChanged(mCards.Length());
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  return rv;
-}
-
-int32_t nsAbView::FindIndexForInsert(AbCard *abcard) {
-  int32_t count = mCards.Length();
-  int32_t i;
-
-  SortClosure closure;
-  SetSortClosure(mSortColumn.get(), mSortDirection.get(), this, &closure);
-
-  // XXX todo
-  // Make this a binary search
-  for (i = 0; i < count; i++) {
-    int32_t value = inplaceSortCallback(abcard, mCards.ElementAt(i), &closure);
-    // XXX Fix me, this is not right for both ascending and descending
-    if (value <= 0) break;
-  }
-  return i;
-}
-
-NS_IMETHODIMP nsAbView::OnItemRemoved(nsISupports *parentDir,
-                                      nsISupports *item) {
-  if (!parentDir) return NS_OK;
-
-  nsresult rv;
-
-  nsCOMPtr<nsIAbDirectory> directory = do_QueryInterface(parentDir, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (directory.get() == mDirectory.get())
-    return RemoveCardAndSelectNextCard(item);
-
-  // The pointers aren't the same, are the URI strings similar? This is most
-  // likely the case if the current directory is a search on a directory.
-  nsCString currentURI;
-  rv = mDirectory->GetURI(currentURI);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // If it is a search, it will have something like ?(or(PrimaryEmail...
-  // on the end of the string, so remove that before comparing
-  int32_t pos = currentURI.FindChar('?');
-  if (pos != -1) currentURI.SetLength(pos);
-
-  nsCString notifiedURI;
-  rv = directory->GetURI(notifiedURI);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (currentURI.Equals(notifiedURI)) return RemoveCardAndSelectNextCard(item);
-
-  return NS_OK;
-}
-
-nsresult nsAbView::RemoveCardAndSelectNextCard(nsISupports *item) {
-  nsresult rv = NS_OK;
-  nsCOMPtr<nsIAbCard> card = do_QueryInterface(item);
-  if (card) {
-    int32_t index = FindIndexForCard(card);
-    if (index != CARD_NOT_FOUND) {
-      bool selectNextCard = false;
-      if (mTreeSelection) {
-        int32_t selectedIndex;
-        // XXX todo
-        // Make sure it works if nothing selected
-        mTreeSelection->GetCurrentIndex(&selectedIndex);
-        if (index == selectedIndex) selectNextCard = true;
-      }
-
-      rv = RemoveCardAt(index);
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      if (selectNextCard) {
-        int32_t count = mCards.Length();
-        if (count && mTreeSelection) {
-          // If we deleted the last card, adjust so we select the new "last"
-          // card
-          if (index >= (count - 1)) {
-            index = count - 1;
-          }
-          mTreeSelection->SetCurrentIndex(index);
-          mTreeSelection->RangedSelect(index, index, false /* augment */);
-        }
-      }
-    }
-  }
-  return rv;
-}
-
-int32_t nsAbView::FindIndexForCard(nsIAbCard *card) {
-  int32_t count = mCards.Length();
-  int32_t i;
-
-  // You can't implement the binary search here, as all you have is the
-  // nsIAbCard you might be here because one of the card properties has changed,
-  // and that property could be the collation key.
-  for (i = 0; i < count; i++) {
-    AbCard *abcard = mCards.ElementAt(i);
-    bool equals;
-    nsresult rv = card->Equals(abcard->card, &equals);
-    if (NS_SUCCEEDED(rv) && equals) {
-      return i;
-    }
-  }
-  return CARD_NOT_FOUND;
-}
-
-NS_IMETHODIMP nsAbView::OnItemPropertyChanged(nsISupports *item,
-                                              const char *property,
-                                              const nsAString &oldValue,
-                                              const nsAString &newValue) {
-  nsresult rv;
-
-  nsCOMPtr<nsIAbCard> card = do_QueryInterface(item);
-  if (!card) return NS_OK;
-
-  int32_t index = FindIndexForCard(card);
-  if (index == -1) return NS_OK;
-
-  AbCard *oldCard = mCards.ElementAt(index);
-  AbCard *newCard = new AbCard(card);
-
-  rv = GenerateCollationKeysForCard(mSortColumn, newCard);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  bool cardWasSelected = false;
-
-  if (mTreeSelection) {
-    rv = mTreeSelection->IsSelected(index, &cardWasSelected);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  if (!CompareCollationKeys(newCard->primaryCollationKey,
-                            oldCard->primaryCollationKey) &&
-      CompareCollationKeys(newCard->secondaryCollationKey,
-                           oldCard->secondaryCollationKey)) {
-    // No need to remove and add, since the collation keys haven't changed.
-    // Since they haven't changed, the card will sort to the same place.
-    // We just need to clean up what we allocated.
-    delete newCard;
-
-    // Still need to invalidate, as the other columns may have changed.
-    rv = InvalidateTree(index);
-    NS_ENSURE_SUCCESS(rv, rv);
-  } else {
-    mSuppressSelectionChange = true;
-    mSuppressCountChange = true;
-
-    // Remove the old card.
-    rv = RemoveCardAt(index);
-    NS_ASSERTION(NS_SUCCEEDED(rv), "remove card failed");
-
-    // Add the card we created, and select it (to restore selection) if it was
-    // selected.
-    rv = AddCard(newCard, cardWasSelected /* select card */, &index);
-    NS_ASSERTION(NS_SUCCEEDED(rv), "add card failed");
-
-    mSuppressSelectionChange = false;
-    mSuppressCountChange = false;
-
-    // Ensure restored selection is visible
-    if (cardWasSelected && mTree) mTree->EnsureRowIsVisible(index);
-  }
-
-  // Although the selection hasn't changed, the card that is selected may need
-  // to be displayed differently, therefore pretend that the selection has
-  // changed to force that update.
-  if (cardWasSelected) SelectionChangedXPCOM();
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbView::SelectAll() {
-  if (mTreeSelection && mTree) {
-    mTreeSelection->SelectAll();
-    mTree->Invalidate();
-  }
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbView::GetSortDirection(nsAString &aDirection) {
-  aDirection = mSortDirection;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbView::GetSortColumn(nsAString &aColumn) {
-  aColumn = mSortColumn;
-  return NS_OK;
-}
-
-nsresult nsAbView::ReselectCards(nsIArray *aCards, nsIAbCard *aIndexCard) {
-  uint32_t count;
-  uint32_t i;
-
-  if (!mTreeSelection || !aCards) return NS_OK;
-
-  nsresult rv = mTreeSelection->ClearSelection();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = aCards->GetLength(&count);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // If we don't have any cards selected, nothing else to do.
-  if (!count) return NS_OK;
-
-  for (i = 0; i < count; i++) {
-    nsCOMPtr<nsIAbCard> card = do_QueryElementAt(aCards, i);
-    if (card) {
-      int32_t index = FindIndexForCard(card);
-      if (index != CARD_NOT_FOUND) {
-        mTreeSelection->RangedSelect(index, index, true /* augment */);
-      }
-    }
-  }
-
-  // Reset the index card, and ensure it is visible.
-  if (aIndexCard) {
-    int32_t currentIndex = FindIndexForCard(aIndexCard);
-    rv = mTreeSelection->SetCurrentIndex(currentIndex);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    if (mTree) {
-      mTree->EnsureRowIsVisible(currentIndex);
-    }
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbView::DeleteSelectedCards() {
-  nsresult rv;
-  nsCOMPtr<nsIMutableArray> cardsToDelete =
-      do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = GetSelectedCards(cardsToDelete);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // mDirectory should not be null
-  // Bullet proof (and assert) to help figure out bug #127748
-  NS_ENSURE_TRUE(mDirectory, NS_ERROR_UNEXPECTED);
-
-  rv = mDirectory->DeleteCards(cardsToDelete);
-  NS_ENSURE_SUCCESS(rv, rv);
-  return rv;
-}
-
-nsresult nsAbView::GetSelectedCards(nsCOMPtr<nsIMutableArray> &aSelectedCards) {
-  if (!mTreeSelection) return NS_OK;
-
-  int32_t selectionCount;
-  nsresult rv = mTreeSelection->GetRangeCount(&selectionCount);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (!selectionCount) return NS_OK;
-
-  for (int32_t i = 0; i < selectionCount; i++) {
-    int32_t startRange;
-    int32_t endRange;
-    rv = mTreeSelection->GetRangeAt(i, &startRange, &endRange);
-    NS_ENSURE_SUCCESS(rv, NS_OK);
-    int32_t totalCards = mCards.Length();
-    if (startRange >= 0 && startRange < totalCards) {
-      for (int32_t rangeIndex = startRange;
-           rangeIndex <= endRange && rangeIndex < totalCards; rangeIndex++) {
-        nsCOMPtr<nsIAbCard> abCard;
-        rv = GetCardFromRow(rangeIndex, getter_AddRefs(abCard));
-        NS_ENSURE_SUCCESS(rv, rv);
-
-        rv = aSelectedCards->AppendElement(abCard);
-        NS_ENSURE_SUCCESS(rv, rv);
-      }
-    }
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbView::SwapFirstNameLastName() {
-  if (!mTreeSelection) return NS_OK;
-
-  int32_t selectionCount;
-  nsresult rv = mTreeSelection->GetRangeCount(&selectionCount);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (!selectionCount) return NS_OK;
-
-  // Prepare for displayname generation
-  // No cache for pref and bundle since the swap operation is not executed
-  // frequently
-  bool displayNameAutoGeneration;
-  bool displayNameLastnamefirst = false;
-
-  nsCOMPtr<nsIPrefBranch> pPrefBranchInt(
-      do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = pPrefBranchInt->GetBoolPref(
-      PREF_MAIL_ADDR_BOOK_DISPLAYNAME_AUTOGENERATION,
-      &displayNameAutoGeneration);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIStringBundle> bundle;
-  if (displayNameAutoGeneration) {
-    nsCOMPtr<nsIPrefLocalizedString> pls;
-    rv = pPrefBranchInt->GetComplexValue(
-        PREF_MAIL_ADDR_BOOK_DISPLAYNAME_LASTNAMEFIRST,
-        NS_GET_IID(nsIPrefLocalizedString), getter_AddRefs(pls));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    nsString str;
-    pls->ToString(getter_Copies(str));
-    displayNameLastnamefirst = str.EqualsLiteral("true");
-    nsCOMPtr<nsIStringBundleService> bundleService =
-        mozilla::services::GetStringBundleService();
-    NS_ENSURE_TRUE(bundleService, NS_ERROR_UNEXPECTED);
-
-    rv = bundleService->CreateBundle(
-        "chrome://messenger/locale/addressbook/addressBook.properties",
-        getter_AddRefs(bundle));
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  for (int32_t i = 0; i < selectionCount; i++) {
-    int32_t startRange;
-    int32_t endRange;
-    rv = mTreeSelection->GetRangeAt(i, &startRange, &endRange);
-    NS_ENSURE_SUCCESS(rv, NS_OK);
-    int32_t totalCards = mCards.Length();
-    if (startRange >= 0 && startRange < totalCards) {
-      for (int32_t rangeIndex = startRange;
-           rangeIndex <= endRange && rangeIndex < totalCards; rangeIndex++) {
-        nsCOMPtr<nsIAbCard> abCard;
-        rv = GetCardFromRow(rangeIndex, getter_AddRefs(abCard));
-        NS_ENSURE_SUCCESS(rv, rv);
-
-        // Swap FN/LN
-        nsAutoString fn, ln;
-        abCard->GetFirstName(fn);
-        abCard->GetLastName(ln);
-        if (!fn.IsEmpty() || !ln.IsEmpty()) {
-          abCard->SetFirstName(ln);
-          abCard->SetLastName(fn);
-
-          // Generate display name using the new order
-          if (displayNameAutoGeneration && !fn.IsEmpty() && !ln.IsEmpty()) {
-            nsString dnLnFn;
-            nsString dnFnLn;
-            AutoTArray<nsString, 2> nameString;
-            const char *formatString;
-
-            // The format should stays the same before/after we swap the names
-            formatString = displayNameLastnamefirst ? "lastFirstFormat"
-                                                    : "firstLastFormat";
-
-            // Generate both ln/fn and fn/ln combination since we need both
-            // later to check to see if the current display name was edited note
-            // that fn/ln still hold the values before the swap
-            nameString.AppendElement(ln);
-            nameString.AppendElement(fn);
-            rv = bundle->FormatStringFromName(formatString, nameString, dnLnFn);
-            NS_ENSURE_SUCCESS(rv, rv);
-            nameString[0] = fn;
-            nameString[1] = ln;
-            rv = bundle->FormatStringFromName(formatString, nameString, dnFnLn);
-            NS_ENSURE_SUCCESS(rv, rv);
-
-            // Get the current display name
-            nsAutoString dn;
-            rv = abCard->GetDisplayName(dn);
-            NS_ENSURE_SUCCESS(rv, rv);
-
-            // Swap the display name if not edited
-            if (displayNameLastnamefirst) {
-              if (dn.Equals(dnLnFn)) abCard->SetDisplayName(dnFnLn);
-            } else {
-              if (dn.Equals(dnFnLn)) abCard->SetDisplayName(dnLnFn);
-            }
-          }
-
-          // Swap phonetic names
-          rv = abCard->GetPropertyAsAString(kPhoneticFirstNameProperty, fn);
-          NS_ENSURE_SUCCESS(rv, rv);
-          rv = abCard->GetPropertyAsAString(kPhoneticLastNameProperty, ln);
-          NS_ENSURE_SUCCESS(rv, rv);
-          if (!fn.IsEmpty() || !ln.IsEmpty()) {
-            abCard->SetPropertyAsAString(kPhoneticFirstNameProperty, ln);
-            abCard->SetPropertyAsAString(kPhoneticLastNameProperty, fn);
-          }
-        }
-      }
-    }
-  }
-  // Update the tree
-  // Re-sort if either generated or phonetic name is primary or secondary sort,
-  // otherwise invalidate to reflect the change
-  rv = RefreshTree();
-
-  return rv;
-}
-
-NS_IMETHODIMP nsAbView::GetSelectedAddresses(nsIArray **_retval) {
-  NS_ENSURE_ARG_POINTER(_retval);
-
-  nsresult rv;
-  nsCOMPtr<nsIMutableArray> selectedCards =
-      do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = GetSelectedCards(selectedCards);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIMutableArray> addresses =
-      do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-  uint32_t count;
-  selectedCards->GetLength(&count);
-
-  for (uint32_t i = 0; i < count; i++) {
-    nsCOMPtr<nsIAbCard> card(do_QueryElementAt(selectedCards, i, &rv));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    bool isMailList;
-    card->GetIsMailList(&isMailList);
-    nsAutoString primaryEmail;
-    if (isMailList) {
-      nsCOMPtr<nsIAbManager> abManager(
-          do_GetService(NS_ABMANAGER_CONTRACTID, &rv));
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      nsCString mailListURI;
-      rv = card->GetMailListURI(getter_Copies(mailListURI));
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      nsCOMPtr<nsIAbDirectory> mailList;
-      rv = abManager->GetDirectory(mailListURI, getter_AddRefs(mailList));
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      nsCOMPtr<nsISimpleEnumerator> mailListAddresses;
-      rv = mailList->GetChildCards(getter_AddRefs(mailListAddresses));
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      bool hasMore = false;
-      nsCOMPtr<nsISupports> support;
-      nsCOMPtr<nsIAbCard> mailListCard;
-      while (NS_SUCCEEDED(mailListAddresses->HasMoreElements(&hasMore)) &&
-             hasMore) {
-        rv = mailListAddresses->GetNext(getter_AddRefs(support));
-        NS_ENSURE_SUCCESS(rv, rv);
-        mailListCard = do_QueryInterface(support, &rv);
-        NS_ENSURE_SUCCESS(rv, rv);
-
-        rv = mailListCard->GetPrimaryEmail(primaryEmail);
-        NS_ENSURE_SUCCESS(rv, rv);
-
-        if (!primaryEmail.IsEmpty()) {
-          nsCOMPtr<nsISupportsString> supportsEmail(
-              do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID));
-          supportsEmail->SetData(primaryEmail);
-          addresses->AppendElement(supportsEmail);
-        }
-      }
-    } else {
-      rv = card->GetPrimaryEmail(primaryEmail);
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      if (!primaryEmail.IsEmpty()) {
-        nsCOMPtr<nsISupportsString> supportsEmail(
-            do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID));
-        supportsEmail->SetData(primaryEmail);
-        addresses->AppendElement(supportsEmail);
-      }
-    }
-  }
-
-  addresses.forget(_retval);
-
-  return NS_OK;
-}
deleted file mode 100644
--- a/mailnews/addrbook/src/nsAbView.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */
-
-#ifndef _nsAbView_H_
-#define _nsAbView_H_
-
-#include "nsISupports.h"
-#include "nsString.h"
-#include "nsIAbView.h"
-#include "nsITreeView.h"
-#include "mozilla/dom/XULTreeElement.h"
-#include "nsITreeSelection.h"
-#include "nsTArray.h"
-#include "nsIAbDirectory.h"
-#include "nsICollation.h"
-#include "nsIAbListener.h"
-#include "nsIObserver.h"
-#include "nsServiceManagerUtils.h"
-#include "nsComponentManagerUtils.h"
-#include "nsMemory.h"
-#include "nsIStringBundle.h"
-
-typedef struct AbCard {
-  explicit AbCard(nsIAbCard *c) : card(c) {}
-  nsCOMPtr<nsIAbCard> card;
-  nsTArray<uint8_t> primaryCollationKey;
-  nsTArray<uint8_t> secondaryCollationKey;
-} AbCard;
-
-class nsAbView : public nsIAbView,
-                 public nsITreeView,
-                 public nsIAbListener,
-                 public nsIObserver {
- public:
-  nsAbView();
-
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIABVIEW
-  NS_DECL_NSITREEVIEW
-  NS_DECL_NSIABLISTENER
-  NS_DECL_NSIOBSERVER
-
-  int32_t CompareCollationKeys(const nsTArray<uint8_t> &key1,
-                               const nsTArray<uint8_t> &key2);
-
- private:
-  virtual ~nsAbView();
-  nsresult Initialize();
-  int32_t FindIndexForInsert(AbCard *abcard);
-  int32_t FindIndexForCard(nsIAbCard *card);
-  nsresult GenerateCollationKeysForCard(const nsAString &colID, AbCard *abcard);
-  nsresult InvalidateTree(int32_t row);
-  nsresult RemoveCardAt(int32_t row);
-  nsresult AddCard(AbCard *abcard, bool selectCardAfterAdding, int32_t *index);
-  nsresult RemoveCardAndSelectNextCard(nsISupports *item);
-  nsresult EnumerateCards();
-  nsresult SetGeneratedNameFormatFromPrefs();
-  nsresult GetSelectedCards(nsCOMPtr<nsIMutableArray> &aSelectedCards);
-  nsresult ReselectCards(nsIArray *aCards, nsIAbCard *aIndexCard);
-  nsresult GetCardValue(nsIAbCard *card, const nsAString &colID,
-                        nsAString &_retval);
-  nsresult RefreshTree();
-
-  RefPtr<mozilla::dom::XULTreeElement> mTree;
-  nsCOMPtr<nsITreeSelection> mTreeSelection;
-  nsCOMPtr<nsIAbDirectory> mDirectory;
-  nsTArray<AbCard *> mCards;
-  nsString mSortColumn;
-  nsString mSortDirection;
-  nsCOMPtr<nsICollation> mCollationKeyGenerator;
-  nsCOMPtr<nsIAbViewListener> mAbViewListener;
-  nsCOMPtr<nsIStringBundle> mABBundle;
-
-  bool mInitialized;
-  bool mIsAllDirectoryRootView;
-  bool mSuppressSelectionChange;
-  bool mSuppressCountChange;
-  int32_t mGeneratedNameFormat;
-};
-
-#endif /* _nsAbView_H_ */
--- a/mailnews/addrbook/src/nsAddbookProtocolHandler.cpp
+++ b/mailnews/addrbook/src/nsAddbookProtocolHandler.cpp
@@ -12,25 +12,25 @@
 #include "nsCOMPtr.h"
 #include "nsAbBaseCID.h"
 #include "nsNetUtil.h"
 #include "nsStringStream.h"
 #include "nsIAbCard.h"
 #include "nsIAbDirectory.h"
 #include "nsIAbManager.h"
 #include "prmem.h"
-#include "nsIAbView.h"
-#include "nsITreeView.h"
 #include "nsIStringBundle.h"
 #include "mozilla/Services.h"
 #include "nsIAsyncInputStream.h"
 #include "nsIAsyncOutputStream.h"
 #include "nsIPipe.h"
 #include "nsIPrincipal.h"
 #include "nsIInputStream.h"
+#include "nsCollationCID.h"
+#include "nsICollation.h"
 
 nsAddbookProtocolHandler::nsAddbookProtocolHandler() {
   mAddbookOperation = nsIAddbookUrlOperation::InvalidUrl;
 }
 
 nsAddbookProtocolHandler::~nsAddbookProtocolHandler() {}
 
 NS_IMPL_ISUPPORTS(nsAddbookProtocolHandler, nsIProtocolHandler)
@@ -222,16 +222,72 @@ nsresult nsAddbookProtocolHandler::Gener
   }
 
   rv = BuildDirectoryXML(directory, aOutput);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
+typedef struct CardEnclosure {
+  nsCOMPtr<nsIAbCard> card;
+  nsString generatedName;
+} CardEnclosure;
+
+class CardComparator {
+ private:
+  nsCOMPtr<nsICollation> mCollation;
+
+  int cmp(CardEnclosure a, CardEnclosure b) const {
+    int32_t result;
+    mCollation->CompareString(nsICollation::kCollationCaseInSensitive,
+                              a.generatedName, b.generatedName, &result);
+    return result;
+  }
+
+ public:
+  CardComparator() {
+    nsCOMPtr<nsICollationFactory> factory =
+        do_CreateInstance(NS_COLLATIONFACTORY_CONTRACTID);
+    factory->CreateCollation(getter_AddRefs(mCollation));
+  }
+
+  bool Equals(CardEnclosure a, CardEnclosure b) const { return cmp(a, b) == 0; }
+  bool LessThan(CardEnclosure a, CardEnclosure b) const {
+    return cmp(a, b) < 0;
+  }
+};
+
+nsresult EnumerateCards(nsIAbDirectory *aDirectory,
+                        nsTArray<CardEnclosure> &aCards,
+                        nsIStringBundle *aBundle) {
+  if (!aDirectory) return NS_ERROR_UNEXPECTED;
+
+  nsCOMPtr<nsISimpleEnumerator> cardsEnumerator;
+  nsCOMPtr<nsIAbCard> card;
+
+  nsresult rv = aDirectory->GetChildCards(getter_AddRefs(cardsEnumerator));
+  if (NS_SUCCEEDED(rv) && cardsEnumerator) {
+    nsCOMPtr<nsISupports> item;
+    bool more;
+    while (NS_SUCCEEDED(cardsEnumerator->HasMoreElements(&more)) && more) {
+      rv = cardsEnumerator->GetNext(getter_AddRefs(item));
+      if (NS_SUCCEEDED(rv)) {
+        nsCOMPtr<nsIAbCard> card = do_QueryInterface(item);
+        CardEnclosure enclosure = CardEnclosure();
+        enclosure.card = card;
+        card->GenerateName(0, aBundle, enclosure.generatedName);
+        aCards.AppendElement(enclosure);
+      }
+    }
+  }
+
+  return NS_OK;
+}
+
 nsresult nsAddbookProtocolHandler::BuildDirectoryXML(nsIAbDirectory *aDirectory,
                                                      nsString &aOutput) {
   nsresult rv;
 
   aOutput.AppendLiteral(
       "<?xml version=\"1.0\"?>\n"
       "<?xml-stylesheet type=\"text/css\" "
       "href=\"chrome://messagebody/content/addressbook/print.css\"?>\n"
@@ -251,42 +307,55 @@ nsresult nsAddbookProtocolHandler::Build
       if (NS_SUCCEEDED(rv)) {
         aOutput.AppendLiteral("<title xmlns=\"http://www.w3.org/1999/xhtml\">");
         aOutput.Append(addrBook);
         aOutput.AppendLiteral("</title>\n");
       }
     }
   }
 
-  // create a view and init it with the generated name sort order. Then, iterate
-  // over the view, getting the card for each row, and printing them.
-  nsString sortColumn;
-  nsCOMPtr<nsIAbView> view =
-      do_CreateInstance("@mozilla.org/addressbook/abview;1", &rv);
-
-  view->SetView(aDirectory, nullptr, NS_LITERAL_STRING("GeneratedName"),
-                NS_LITERAL_STRING("ascending"), sortColumn);
+  nsTArray<CardEnclosure> cards;
+  if (aDirectory) {
+    EnumerateCards(aDirectory, cards, bundle);
+  } else {
+    nsCOMPtr<nsIAbManager> abManager(
+        do_GetService(NS_ABMANAGER_CONTRACTID, &rv));
+    NS_ENSURE_SUCCESS(rv, rv);
+    nsCOMPtr<nsISimpleEnumerator> enumerator;
+    rv = abManager->GetDirectories(getter_AddRefs(enumerator));
+    NS_ENSURE_SUCCESS(rv, rv);
 
-  int32_t numRows;
-  nsCOMPtr<nsITreeView> treeView = do_QueryInterface(view, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-  treeView->GetRowCount(&numRows);
+    bool hasMore = false;
+    nsCOMPtr<nsISupports> support;
+    nsCOMPtr<nsIAbDirectory> directory;
+    while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMore)) && hasMore) {
+      rv = enumerator->GetNext(getter_AddRefs(support));
+      NS_ENSURE_SUCCESS(rv, rv);
+      directory = do_QueryInterface(support, &rv);
+
+      // If, for some reason, we are unable to get a directory, we continue.
+      if (NS_FAILED(rv)) continue;
 
-  for (int32_t row = 0; row < numRows; row++) {
-    nsCOMPtr<nsIAbCard> card;
-    view->GetCardFromRow(row, getter_AddRefs(card));
+      rv = EnumerateCards(directory, cards, bundle);
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+  }
 
+  CardComparator cardComparator = CardComparator();
+  cards.Sort(cardComparator);
+
+  for (CardEnclosure enclosure : cards) {
     bool isMailList;
-    if (NS_FAILED(card->GetIsMailList(&isMailList)) || isMailList) {
+    if (NS_FAILED(enclosure.card->GetIsMailList(&isMailList)) || isMailList) {
       continue;
     }
 
     nsCString xmlSubstr;
 
-    rv = card->TranslateTo(NS_LITERAL_CSTRING("xml"), xmlSubstr);
+    rv = enclosure.card->TranslateTo(NS_LITERAL_CSTRING("xml"), xmlSubstr);
     NS_ENSURE_SUCCESS(rv, rv);
 
     aOutput.AppendLiteral("<separator/>");
     aOutput.Append(NS_ConvertUTF8toUTF16(xmlSubstr));
     aOutput.AppendLiteral("<separator/>");
   }
 
   aOutput.AppendLiteral("</directory>\n");
--- a/mailnews/build/nsMailModule.cpp
+++ b/mailnews/build/nsMailModule.cpp
@@ -116,17 +116,16 @@
 #include "nsAbDirProperty.h"
 #include "nsAbAddressCollector.h"
 #include "nsAddbookProtocolHandler.h"
 #include "nsAddbookUrl.h"
 
 #include "nsAbDirectoryQuery.h"
 #include "nsAbBooleanExpression.h"
 #include "nsAbDirectoryQueryProxy.h"
-#include "nsAbView.h"
 #include "nsMsgVCardService.h"
 #include "nsAbLDIFService.h"
 
 #if defined(MOZ_LDAP_XPCOM)
 #  include "nsAbLDAPDirectory.h"
 #  include "nsAbLDAPDirectoryQuery.h"
 #  include "nsAbLDAPCard.h"
 #  include "nsAbLDAPReplicationService.h"
@@ -455,17 +454,16 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsAbLDAPR
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsAbLDAPProcessReplicationData)
 // XXX These files are not being built as they don't work. Bug 311632 should
 // fix them.
 // NS_GENERIC_FACTORY_CONSTRUCTOR(nsAbLDAPChangeLogQuery)
 // NS_GENERIC_FACTORY_CONSTRUCTOR(nsAbLDAPProcessChangeLogData)
 #endif
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsAbDirectoryQueryProxy)
-NS_GENERIC_FACTORY_CONSTRUCTOR(nsAbView)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsMsgVCardService)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsAbLDIFService)
 
 #ifdef XP_MACOSX
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsAbOSXDirectory)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsAbOSXCard)
 #endif
 
@@ -492,17 +490,16 @@ NS_DEFINE_NAMED_CID(NS_ABLDAP_REPLICATIO
 NS_DEFINE_NAMED_CID(NS_ABLDAP_REPLICATIONQUERY_CID);
 NS_DEFINE_NAMED_CID(NS_ABLDAP_PROCESSREPLICATIONDATA_CID);
 #endif
 NS_DEFINE_NAMED_CID(NS_ABDIRECTORYQUERYPROXY_CID);
 #ifdef XP_MACOSX
 NS_DEFINE_NAMED_CID(NS_ABOSXDIRECTORY_CID);
 NS_DEFINE_NAMED_CID(NS_ABOSXCARD_CID);
 #endif
-NS_DEFINE_NAMED_CID(NS_ABVIEW_CID);
 NS_DEFINE_NAMED_CID(NS_MSGVCARDSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_ABLDIFSERVICE_CID);
 
 ////////////////////////////////////////////////////////////////////////////////
 // bayesian spam filter factories
 ////////////////////////////////////////////////////////////////////////////////
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsBayesianFilter, Init)
 
@@ -913,17 +910,16 @@ const mozilla::Module::CIDEntry kMailNew
      nsAbLDAPProcessReplicationDataConstructor},
 #endif
     {&kNS_ABDIRECTORYQUERYPROXY_CID, false, NULL,
      nsAbDirectoryQueryProxyConstructor},
 #ifdef XP_MACOSX
     {&kNS_ABOSXDIRECTORY_CID, false, NULL, nsAbOSXDirectoryConstructor},
     {&kNS_ABOSXCARD_CID, false, NULL, nsAbOSXCardConstructor},
 #endif
-    {&kNS_ABVIEW_CID, false, NULL, nsAbViewConstructor},
     {&kNS_MSGVCARDSERVICE_CID, false, NULL, nsMsgVCardServiceConstructor},
     {&kNS_ABLDIFSERVICE_CID, false, NULL, nsAbLDIFServiceConstructor},
     // Bayesian Filter Entries
     {&kNS_BAYESIANFILTER_CID, false, NULL, nsBayesianFilterConstructor},
     // Compose Entries
     {&kNS_MSGCOMPOSE_CID, false, NULL, nsMsgComposeConstructor},
     {&kNS_MSGCOMPOSESERVICE_CID, false, NULL, nsMsgComposeServiceConstructor},
     {&kNS_MSGCOMPOSECONTENTHANDLER_CID, false, NULL,
@@ -1146,17 +1142,16 @@ const mozilla::Module::ContractIDEntry k
      &kNS_ABLDAP_PROCESSREPLICATIONDATA_CID},
 #endif
 
     {NS_ABDIRECTORYQUERYPROXY_CONTRACTID, &kNS_ABDIRECTORYQUERYPROXY_CID},
 #ifdef XP_MACOSX
     {NS_ABOSXDIRECTORY_CONTRACTID, &kNS_ABOSXDIRECTORY_CID},
     {NS_ABOSXCARD_CONTRACTID, &kNS_ABOSXCARD_CID},
 #endif
-    {NS_ABVIEW_CONTRACTID, &kNS_ABVIEW_CID},
     {NS_MSGVCARDSERVICE_CONTRACTID, &kNS_MSGVCARDSERVICE_CID},
     {NS_ABLDIFSERVICE_CONTRACTID, &kNS_ABLDIFSERVICE_CID},
     // Bayesian Filter Entries
     {NS_BAYESIANFILTER_CONTRACTID, &kNS_BAYESIANFILTER_CID},
     // Compose Entries
     {NS_MSGCOMPOSE_CONTRACTID, &kNS_MSGCOMPOSE_CID},
     {NS_MSGCOMPOSESERVICE_CONTRACTID, &kNS_MSGCOMPOSESERVICE_CID},
     {NS_MSGCOMPOSESTARTUPHANDLER_CONTRACTID, &kNS_MSGCOMPOSESERVICE_CID},