Bug 546722 - show Favourite folders as a separate list in the folder picker. r=aceman,ui-r=bwinton
authorMihai <mihaicodrean@gmail.com>
Sat, 05 Jan 2019 09:25:00 +0100
changeset 33268 e63b335d0e43
parent 33267 0498136de604
child 33269 1968c2aef7ae
push id2368
push userclokep@gmail.com
push dateMon, 28 Jan 2019 21:12:50 +0000
treeherdercomm-beta@56d23c07d815 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersaceman, bwinton
bugs546722
Bug 546722 - show Favourite folders as a separate list in the folder picker. r=aceman,ui-r=bwinton
mail/base/content/mainNavigationToolbox.inc.xul
mail/base/content/mainPopupSet.inc.xul
mail/locales/en-US/chrome/messenger/messenger.dtd
mailnews/base/content/folderWidgets.xml
suite/locales/en-US/chrome/mailnews/messenger.dtd
--- a/mail/base/content/mainNavigationToolbox.inc.xul
+++ b/mail/base/content/mainNavigationToolbox.inc.xul
@@ -566,17 +566,20 @@
                 label="&folderMenu.label;"
                 accesskey="&folderMenu.accesskey;"
                 command="cmd_goFolder">
             <menupopup id="menu_GoFolderPopup"
                        type="folder"
                        showFileHereLabel="true"
                        showRecent="true"
                        recentLabel="&contextMoveCopyMsgRecentMenu.label;"
-                       recentAccessKey="&contextMoveCopyMsgRecentMenu.accesskey;"/>
+                       recentAccessKey="&contextMoveCopyMsgRecentMenu.accesskey;"
+                       showFavorites="true"
+                       favoritesLabel="&contextMoveCopyMsgFavoritesMenu.label;"
+                       favoritesAccessKey="&contextMoveCopyMsgFavoritesMenu.accesskey;"/>
           </menu>
           <menuseparator id="goFolderSeparator"/>
 
           <menu id="goRecentlyClosedTabs"
                 label="&goRecentlyClosedTabs.label;"
                 accesskey="&goRecentlyClosedTabs.accesskey;"
                 observes="cmd_undoCloseTab">
             <menupopup id="menu_GoRecentlyClosedTabsPopup"
@@ -758,27 +761,33 @@
             <menu id="moveMenu"
                   label="&moveMsgToMenu.label;"
                   accesskey="&moveMsgToMenu.accesskey;"
                   oncommand="MsgMoveMessage(event.target._folder)">
               <menupopup type="folder" mode="filing"
                          showFileHereLabel="true"
                          showRecent="true"
                          recentLabel="&moveCopyMsgRecentMenu.label;"
-                         recentAccessKey="&moveCopyMsgRecentMenu.accesskey;"/>
+                         recentAccessKey="&moveCopyMsgRecentMenu.accesskey;"
+                         showFavorites="true"
+                         favoritesLabel="&contextMoveCopyMsgFavoritesMenu.label;"
+                         favoritesAccessKey="&contextMoveCopyMsgFavoritesMenu.accesskey;"/>
             </menu>
             <menu id="copyMenu"
                   label="&copyMsgToMenu.label;"
                   accesskey="&copyMsgToMenu.accesskey;"
                   oncommand="MsgCopyMessage(event.target._folder)">
               <menupopup type="folder" mode="filing"
                          showFileHereLabel="true"
                          showRecent="true"
                          recentLabel="&moveCopyMsgRecentMenu.label;"
-                         recentAccessKey="&moveCopyMsgRecentMenu.accesskey;"/>
+                         recentAccessKey="&moveCopyMsgRecentMenu.accesskey;"
+                         showFavorites="true"
+                         favoritesLabel="&contextMoveCopyMsgFavoritesMenu.label;"
+                         favoritesAccessKey="&contextMoveCopyMsgFavoritesMenu.accesskey;"/>
             </menu>
             <menuitem id="moveToFolderAgain" key="key_moveToFolderAgain" command="cmd_moveToFolderAgain"
                       label="&moveToFolderAgain.label;" accesskey="&moveToFolderAgain.accesskey;"/>
             <menuseparator id="messageMenuAfterMoveCommandsSeparator"/>
             <menuitem id="createFilter" label="&createFilter.label;"
                       accesskey="&createFilter.accesskey;"
                       command="cmd_createFilterFromMenu"/>
         <menuseparator id="threadItemsSeparator"/>
--- a/mail/base/content/mainPopupSet.inc.xul
+++ b/mail/base/content/mainPopupSet.inc.xul
@@ -994,26 +994,32 @@
                       label="&cancelNewsMsgCmd.label;"/>
             <menu id="appmenu_moveMenu"
                   label="&moveMsgToMenu.label;"
                   oncommand="MsgMoveMessage(event.target._folder)">
               <menupopup type="folder"
                          mode="filing"
                          showFileHereLabel="true"
                          showRecent="true"
-                         recentLabel="&moveCopyMsgRecentMenu.label;"/>
+                         recentLabel="&moveCopyMsgRecentMenu.label;"
+                         showFavorites="true"
+                         favoritesLabel="&contextMoveCopyMsgFavoritesMenu.label;"
+                         favoritesAccessKey="&contextMoveCopyMsgFavoritesMenu.accesskey;"/>
             </menu>
             <menu id="appmenu_copyMenu"
                   label="&copyMsgToMenu.label;"
                   oncommand="MsgCopyMessage(event.target._folder)">
               <menupopup type="folder"
                          mode="filing"
                          showFileHereLabel="true"
                          showRecent="true"
-                         recentLabel="&moveCopyMsgRecentMenu.label;"/>
+                         recentLabel="&moveCopyMsgRecentMenu.label;"
+                         showFavorites="true"
+                         favoritesLabel="&contextMoveCopyMsgFavoritesMenu.label;"
+                         favoritesAccessKey="&contextMoveCopyMsgFavoritesMenu.accesskey;"/>
             </menu>
             <menuitem id="appmenu_moveToFolderAgain"
                       command="cmd_moveToFolderAgain"
                       key="key_moveToFolderAgain"
                       label="&moveToFolderAgain.label;"/>
             <menuseparator id="appmenu_messageMenuAfterMoveCommandsSeparator"/>
             <menuitem id="appmenu_createFilter"
                       label="&createFilter.label;"
@@ -1463,29 +1469,35 @@
           accesskey="&contextMoveMsgMenu.accesskey;"
           oncommand="MsgMoveMessage(event.target._folder)">
       <menupopup id="mailContext-fileHereMenu"
                  type="folder"
                  mode="filing"
                  showFileHereLabel="true"
                  showRecent="true"
                  recentLabel="&contextMoveCopyMsgRecentMenu.label;"
-                 recentAccessKey="&contextMoveCopyMsgRecentMenu.accesskey;"/>
+                 recentAccessKey="&contextMoveCopyMsgRecentMenu.accesskey;"
+                 showFavorites="true"
+                 favoritesLabel="&contextMoveCopyMsgFavoritesMenu.label;"
+                 favoritesAccessKey="&contextMoveCopyMsgFavoritesMenu.accesskey;"/>
     </menu>
     <menu id="mailContext-copyMenu"
           label="&contextCopyMsgMenu.label;"
           accesskey="&contextCopyMsgMenu.accesskey;"
           oncommand="MsgCopyMessage(event.target._folder)">
       <menupopup id="mailContext-copyHereMenu"
                  type="folder"
                  mode="filing"
                  showFileHereLabel="true"
                  showRecent="true"
                  recentLabel="&contextMoveCopyMsgRecentMenu.label;"
-                 recentAccessKey="&contextMoveCopyMsgRecentMenu.accesskey;"/>
+                 recentAccessKey="&contextMoveCopyMsgRecentMenu.accesskey;"
+                 showFavorites="true"
+                 favoritesLabel="&contextMoveCopyMsgFavoritesMenu.label;"
+                 favoritesAccessKey="&contextMoveCopyMsgFavoritesMenu.accesskey;"/>
     </menu>
     <menuitem id="mailContext-moveToFolderAgain"
               command="cmd_moveToFolderAgain"
               label="&moveToFolderAgain.label;"
               accesskey="&moveToFolderAgain.accesskey;"/>
 
     <menuitem id="mailContext-delete"
               command="cmd_delete"/>
--- a/mail/locales/en-US/chrome/messenger/messenger.dtd
+++ b/mail/locales/en-US/chrome/messenger/messenger.dtd
@@ -787,16 +787,18 @@
 <!ENTITY contextForwardAsAttachmentItem.label "Attachment">
 <!ENTITY contextForwardAsAttachmentItem.accesskey "A">
 <!ENTITY contextMultiForwardAsAttachment.label "Forward as Attachments">
 <!ENTITY contextMultiForwardAsAttachment.accesskey "o">
 <!ENTITY contextMoveMsgMenu.label "Move To">
 <!ENTITY contextMoveMsgMenu.accesskey "M">
 <!ENTITY contextMoveCopyMsgRecentMenu.label "Recent">
 <!ENTITY contextMoveCopyMsgRecentMenu.accesskey "R">
+<!ENTITY contextMoveCopyMsgFavoritesMenu.label "Favorites">
+<!ENTITY contextMoveCopyMsgFavoritesMenu.accesskey "F">
 <!ENTITY contextCopyMsgMenu.label "Copy To">
 <!ENTITY contextCopyMsgMenu.accesskey "C">
 <!ENTITY contextKillThreadMenu.label "Ignore Thread">
 <!ENTITY contextKillSubthreadMenu.accesskey "b">
 <!ENTITY contextKillThreadMenu.accesskey "I">
 <!ENTITY contextKillSubthreadMenu.label "Ignore Subthread">
 <!ENTITY contextWatchThreadMenu.label "Watch Thread">
 <!-- LOCALIZATION NOTE (contextWatchThreadMenu.accesskey):
--- a/mailnews/base/content/folderWidgets.xml
+++ b/mailnews/base/content/folderWidgets.xml
@@ -226,16 +226,23 @@
             this._menu._teardown();
         },
 
         //xxx I stole this listener list from nsMsgFolderDatasource.cpp, but
         //    someone should really document what events are fired when, so that
         //    we make sure we're updating at the right times.
         OnItemPropertyChanged: function(aItem, aProperty, aOld, aNew) {},
         OnItemIntPropertyChanged: function(aItem, aProperty, aOld, aNew) {
+          if (aItem instanceof Ci.nsIMsgFolder) {
+            if (aProperty == "FolderFlag" &&
+                ((aOld & Ci.nsMsgFolderFlags.Favorite) !=
+                 (aNew & Ci.nsMsgFolderFlags.Favorite))) {
+               setTimeout(this._clearMenu, 0, this._menu);
+            }
+          }
           var child = this._getChildForItem(aItem);
           if (child)
             this._menu._setCssSelectors(child._folder, child);
         },
         OnItemBoolPropertyChanged: function(aItem, aProperty, aOld, aNew) {
           var child = this._getChildForItem(aItem);
           if (child)
             this._menu._setCssSelectors(child._folder, child);
@@ -416,20 +423,33 @@
               sep.setAttribute("generated", "true");
               this.appendChild(sep);
             }
           }
 
           let globalInboxFolder = null;
           // See if this is the toplevel menu (usually with accounts).
           if (!this._parentFolder) {
+            let addSeparator = false;
             // Some menus want a "Recent" option, but that should only be on our
             // top-level menu
-            if (this.getAttribute("showRecent") == "true")
+            if (this.getAttribute("showRecent") == "true") {
               this._buildRecentMenu();
+              addSeparator = true;
+            }
+            if (this.getAttribute("showFavorites") == "true") {
+              this._buildFavoritesMenu();
+              addSeparator = true;
+            }
+            if (addSeparator) {
+              // If we added Recent and/or Favorites, separate them from the rest of the items.
+              let sep = document.createElement("menuseparator");
+              sep.setAttribute("generated", "true");
+              this.appendChild(sep);
+            }
             // If we are showing the accounts for deferring, move Local Folders to the top.
             if (mode == "deferred") {
               globalInboxFolder = this.MailServices.accounts.localFoldersServer
                                                             .rootFolder;
               let localFoldersIndex = folders.indexOf(globalInboxFolder);
               if (localFoldersIndex != -1) {
                 folders.splice(localFoldersIndex, 1);
                 folders.unshift(globalInboxFolder);
@@ -636,20 +656,91 @@
             this._setCssSelectors(folderItem.folder, node);
             node.setAttribute("generated", "true");
             popup.appendChild(node);
           }
           menu.setAttribute("generated", "true");
           this.appendChild(menu);
           if (!recentFolders.length)
             menu.setAttribute("disabled", "true");
+        ]]></body>
+      </method>
 
-          var sep = document.createElement("menuseparator");
-          sep.setAttribute("generated", "true");
-          this.appendChild(sep);
+      <!--
+         - Builds a submenu with all of the favorite folders in it, to
+         - allow for easy access.
+        -->
+      <method name="_buildFavoritesMenu">
+        <body><![CDATA[
+          // Iterate through all folders in all accounts, and find the
+          // favorite ones.
+          let allFolders = this.toArray(
+            this.fixIterator(this.MailServices.accounts.allFolders, Ci.nsIMsgFolder));
+
+          let favoriteFolders = allFolders.filter(f => f.canFileMessages &&
+                                                       f.getFlag(Ci.nsMsgFolderFlags.Favorite));
+
+          // Cache the pretty names so that they do not need to be fetched
+          // _MAXFAVORITES^2 times later.
+          favoriteFolders = favoriteFolders.map(
+            function (f) { return { folder: f, name: f.prettyName } });
+
+          // Because we're scanning across multiple accounts, we can end up with
+          // several folders with the same name. Find those dupes.
+          let dupeNames = new Set();
+          for (let i = 0; i < favoriteFolders.length; i++) {
+            for (let j = i + 1; j < favoriteFolders.length; j++) {
+              if (favoriteFolders[i].name == favoriteFolders[j].name)
+                dupeNames.add(favoriteFolders[i].name);
+            }
+          }
+
+          for (let folderItem of favoriteFolders) {
+            // If this folder name appears multiple times in the favorites list,
+            // append the server name to disambiguate.
+            // TODO:
+            // - maybe this could use verboseFolderFormat from messenger.properties
+            //   instead of hardcoded " - ".
+            // - disambiguate folders with same name in same account
+            //   (in different subtrees).
+            let label = folderItem.name;
+            if (dupeNames.has(label))
+              label += " - " + folderItem.folder.server.prettyName;
+
+            folderItem.label = label;
+          }
+
+          // Make sure the entries are sorted alphabetically.
+          favoriteFolders.sort((a, b) => this.folderNameCompare(a.label, b.label));
+
+          // Now create the Favorites folder and its children
+          var menu = document.createElement("menu");
+          menu.setAttribute("label", this.getAttribute("favoritesLabel"));
+          menu.setAttribute("accesskey", this.getAttribute("favoritesAccessKey"));
+          var popup = document.createElement("menupopup");
+          popup.setAttribute("class", this.getAttribute("class"));
+          popup.setAttribute("generated", "true");
+          menu.appendChild(popup);
+
+          // Create entries for each of the favorite folders.
+          for (let folderItem of favoriteFolders) {
+            let node = document.createElement("menuitem");
+
+            node.setAttribute("label", folderItem.label);
+            node._folder = folderItem.folder;
+
+            node.setAttribute("class", "folderMenuItem menuitem-iconic");
+            this._setCssSelectors(folderItem.folder, node);
+            node.setAttribute("generated", "true");
+            popup.appendChild(node);
+          }
+          menu.setAttribute("generated", "true");
+          this.appendChild(menu);
+          if (!favoriteFolders.length)
+            menu.setAttribute("disabled", "true");
         ]]></body>
       </method>
 
       <!--
          - This function adds attributes on menu/menuitems to make it easier for
          - css to style them.
          -
          - @param aFolder    the folder that corresponds to the menu/menuitem
--- a/suite/locales/en-US/chrome/mailnews/messenger.dtd
+++ b/suite/locales/en-US/chrome/mailnews/messenger.dtd
@@ -478,16 +478,18 @@
 <!ENTITY contextArchive.label "Archive">
 <!ENTITY contextArchive.accesskey "A">
 <!ENTITY contextMoveMsgMenu.label "Move To">
 <!ENTITY contextMoveMsgMenu.accesskey "M">
 <!ENTITY contextCopyMsgMenu.label "Copy To">
 <!ENTITY contextCopyMsgMenu.accesskey "C">
 <!ENTITY contextMoveCopyMsgRecentMenu.label "Recent">
 <!ENTITY contextMoveCopyMsgRecentMenu.accesskey "R">
+<!ENTITY contextMoveCopyMsgFavoritesMenu.label "Favorites">
+<!ENTITY contextMoveCopyMsgFavoritesMenu.accesskey "F">
 <!ENTITY contextSaveAs.label "Save As…">
 <!ENTITY contextSaveAs.accesskey "S">
 <!ENTITY contextPrint.label "Print…">
 <!ENTITY contextPrint.accesskey "P">
 <!ENTITY contextPrintPreview.label "Print Preview">
 <!ENTITY contextPrintPreview.accesskey "v">
 
 <!-- Folder Pane Context Menu -->