Bug 1328855 - Clean up folder handling in FilterListDialog.js and fix filter list redraw. r=jorgk a=jorgk
authoraceman <acelists@atlas.sk>
Sun, 06 May 2018 14:43:00 +0200
changeset 31456 6510ef9822b3
parent 31455 1521f2ce1de5
child 31457 49d90f6c578a
push id383
push userclokep@gmail.com
push date2018-05-07 21:52 +0000
reviewersjorgk, jorgk
bugs1328855
Bug 1328855 - Clean up folder handling in FilterListDialog.js and fix filter list redraw. r=jorgk a=jorgk
mail/base/content/FilterListDialog.js
mail/base/content/FilterListDialog.xul
--- a/mail/base/content/FilterListDialog.js
+++ b/mail/base/content/FilterListDialog.js
@@ -5,19 +5,17 @@
 
 ChromeUtils.import("resource://gre/modules/PluralForm.jsm");
 ChromeUtils.import("resource:///modules/iteratorUtils.jsm");
 ChromeUtils.import("resource:///modules/mailServices.js");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 var gFilterListMsgWindow = null;
 var gCurrentFilterList;
-var gCurrentFolder;
-var gSelectedFolder = null;
-
+var gServerMenu = null;
 var gFilterListbox = null;
 var gEditButton = null;
 var gDeleteButton = null;
 var gCopyToNewButton = null;
 var gTopButton = null;
 var gUpButton = null;
 var gDownButton = null;
 var gBottomButton = null;
@@ -95,16 +93,17 @@ var filterEditorQuitObserver = {
 function onLoad()
 {
     gFilterListMsgWindow = Cc["@mozilla.org/messenger/msgwindow;1"]
                              .createInstance(Ci.nsIMsgWindow);
     gFilterListMsgWindow.domWindow = window;
     gFilterListMsgWindow.rootDocShell.appType = Ci.nsIDocShell.APP_TYPE_MAIL;
     gFilterListMsgWindow.statusFeedback = gStatusFeedback;
 
+    gServerMenu       = document.getElementById("serverMenu");
     gFilterListbox    = document.getElementById("filterList");
     gEditButton       = document.getElementById("editButton");
     gDeleteButton     = document.getElementById("deleteButton");
     gCopyToNewButton  = document.getElementById("copyToNewButton");
     gTopButton        = document.getElementById("reorderTopButton");
     gUpButton         = document.getElementById("reorderUpButton");
     gDownButton       = document.getElementById("reorderDownButton");
     gBottomButton     = document.getElementById("reorderBottomButton");
@@ -123,39 +122,42 @@ function onLoad()
 
 /**
  * Processes arguments sent to this dialog when opened or refreshed.
  *
  * @param aArguments  An object having members representing the arguments.
  *                    { arg1: value1, arg2: value2, ... }
  */
 function processWindowArguments(aArguments) {
-  // If a specific folder was requested, try to select it.
-  if (!gSelectedFolder ||
-      (("folder" in aArguments) && (aArguments.folder != gCurrentFolder)))
+  // If a specific folder was requested, try to select it
+  // if we don't already show its server.
+  if (!gServerMenu._folder ||
+      (("folder" in aArguments) &&
+      (aArguments.folder != gServerMenu._folder) &&
+      (aArguments.folder.rootFolder != gServerMenu._folder)))
   {
+    let wantedFolder;
     if ("folder" in aArguments)
-      gSelectedFolder = aArguments.folder;
+      wantedFolder = aArguments.folder;
 
     // Get the folder where filters should be defined, if that server
     // can accept filters.
-    let firstItem = getFilterFolderForSelection(gSelectedFolder);
+    let firstItem = getFilterFolderForSelection(wantedFolder);
 
     // If the selected server cannot have filters, get the default server
     // If the default server cannot have filters, check all accounts
     // and get a server that can have filters.
     if (!firstItem)
       firstItem = getServerThatCanHaveFilters().rootFolder;
 
     if (firstItem)
-      selectFolder(firstItem);
+      setFilterFolder(firstItem);
 
-    if (gSelectedFolder)
-      setRunFolder(gSelectedFolder);
-
+    if (wantedFolder)
+      setRunFolder(wantedFolder);
   } else {
     // If we didn't change folder still redraw the list
     // to show potential new filters if we were called for refresh.
     rebuildFilterList();
   }
 
   // If a specific filter was requested, try to select it.
   if ("filter" in aArguments)
@@ -173,91 +175,123 @@ function refresh(aArguments)
 {
   // As we really don't know what has changed, clear the search box
   // undonditionally so that the changed/added filters are surely visible.
   resetSearchBox();
 
   processWindowArguments(aArguments);
 }
 
-/**
- * Called when a user selects a folder in the list, so we can update the
- * filters that are displayed
- * note the function name 'onFilterFolderClick' is misleading, it would be
- * better named 'onServerSelect' => file follow up bug later.
- *
- * @param aFolder  the nsIMsgFolder that was selected
- */
-function onFilterFolderClick(aFolder)
-{
-    if (!aFolder || aFolder == gCurrentFolder)
-      return;
-
-    // Save the current filters to disk before switching because
-    // the dialog may be closed and we'll lose current filters.
-    gCurrentFilterList.saveToDefaultFile();
-
-    // Initial selected folder no longer applies, use getFirstFolder() logic,
-    // unless it's nntp where we can use the subscribed newsgroup.
-    gSelectedFolder = aFolder.server.type == "nntp" ? aFolder : null;
-
-    selectFolder(aFolder);
-}
-
 function CanRunFiltersAfterTheFact(aServer)
 {
   // filter after the fact is implement using search
   // so if you can't search, you can't filter after the fact
   return aServer.canSearchMessages;
 }
 
-// roots the tree at the specified folder
-function setFolder(msgFolder)
+/**
+ * Change the root server for which we are managing filters.
+ *
+ * @param msgFolder The nsIMsgFolder server containing filters
+ *                  (or a folder for NNTP server).
+ */
+function setFilterFolder(msgFolder)
 {
-   if (msgFolder == gCurrentFolder)
-     return;
+  if (!msgFolder || msgFolder == gServerMenu._folder)
+    return;
 
-   gCurrentFolder = msgFolder;
+  // Save the current filters to disk before switching because
+  // the dialog may be closed and we'll lose current filters.
+  if (gCurrentFilterList)
+    gCurrentFilterList.saveToDefaultFile();
+
+  // Setting this attribute should go away in bug 473009.
+  gServerMenu._folder = msgFolder;
+  // Calling this should go away in bug 802609.
+  gServerMenu.menupopup.selectFolder(msgFolder);
 
-   // Calling getFilterList will detect any errors in rules.dat,
-   // backup the file, and alert the user.
-   gCurrentFilterList = msgFolder.getEditableFilterList(gFilterListMsgWindow);
-   rebuildFilterList();
+  // Calling getEditableFilterList will detect any errors in msgFilterRules.dat,
+  // backup the file, and alert the user.
+  gCurrentFilterList = msgFolder.getEditableFilterList(gFilterListMsgWindow);
+  rebuildFilterList();
+
+  // Select the first item in the list, if there is one.
+  if (gFilterListbox.itemCount > 0)
+    gFilterListbox.selectItem(gFilterListbox.getItemAtIndex(0));
 
-   // Select the first item in the list, if there is one.
-   if (gFilterListbox.itemCount > 0)
-     gFilterListbox.selectItem(gFilterListbox.getItemAtIndex(0));
+  // This will get the deferred to account root folder, if server is deferred.
+  // We intentionally do this after setting the current server, as we want
+  // that to refer to the rootFolder for the actual server, not the
+  // deferred-to server, as current server is really a proxy for the
+  // server whose filters we are editing. But below here we are managing
+  // where the filters will get applied, which is on the deferred-to server.
+  msgFolder = msgFolder.server.rootMsgFolder;
+
+  // root the folder picker to this server
+  let runMenu = gRunFiltersFolder.menupopup;
+  runMenu._teardown();
+  runMenu._parentFolder = msgFolder;
+  runMenu._ensureInitialized();
+
+  let canFilterAfterTheFact = CanRunFiltersAfterTheFact(msgFolder.server);
+  gRunFiltersFolder.hidden = !canFilterAfterTheFact;
+  gRunFiltersButton.hidden = !canFilterAfterTheFact;
+  document.getElementById("folderPickerPrefix").hidden = !canFilterAfterTheFact;
 
-   // This will get the deferred to account root folder, if server is deferred.
-   // We intentionally do this after setting gCurrentFolder, as we want
-   // that to refer to the rootFolder for the actual server, not the
-   // deferred-to server, as gCurrentFolder is really a proxy for the
-   // server whose filters we are editing. But below here we are managing
-   // where the filters will get applied, which is on the deferred-to server.
-   msgFolder = msgFolder.server.rootMsgFolder;
-
-   // root the folder picker to this server
-   var runMenu = document.getElementById("runFiltersPopup");
-   runMenu._teardown();
-   runMenu._parentFolder = msgFolder;
-   runMenu._ensureInitialized();
+  if (canFilterAfterTheFact) {
+    let wantedFolder = null;
+    // For a given server folder, get the default run target folder or show
+    // "Choose Folder".
+    if (!msgFolder.isServer) {
+      wantedFolder = msgFolder;
+    } else {
+      try {
+        switch (msgFolder.server.type) {
+        case "nntp":
+          // For NNTP select the subscribed newsgroup.
+          wantedFolder = gServerMenu._folder;
+          break;
+        case "rss":
+          // Show "Choose Folder" for feeds.
+          wantedFolder = null;
+          break;
+        case "imap":
+        case "pop3":
+        case "none":
+          // Find Inbox for IMAP and POP or Local Folders,
+          // show "Choose Folder" if not found.
+          wantedFolder = msgFolder.rootFolder.getFolderWithFlags(Ci.nsMsgFolderFlags.Inbox);
+          break;
+        default:
+          // For other account types we don't know what's good to select,
+          // so show "Choose Folder".
+          wantedFolder = null;
+        }
+      } catch (e) {
+        Cu.reportError("Failed to select a suitable folder to run filters on: " + e);
+        wantedFolder = null;
+      }
+    }
 
-   let canFilterAfterTheFact = CanRunFiltersAfterTheFact(msgFolder.server);
-   gRunFiltersFolder.hidden = !canFilterAfterTheFact;
-   gRunFiltersButton.hidden = !canFilterAfterTheFact;
-   document.getElementById("folderPickerPrefix").hidden = !canFilterAfterTheFact;
+    // Select a useful first folder for the server.
+    setRunFolder(wantedFolder);
+  }
+}
 
-   if (canFilterAfterTheFact) {
-     // Get the first folder for this server. INBOX for IMAP and POP3 accounts
-     // and 1st news group for news. Disable the button for Choose Folder, if
-     // no folder is selected and the server is not imap/pop3/nntp.
-     gRunFiltersFolder.selectedIndex = 0;
-     runMenu.selectFolder(getFirstFolder(gSelectedFolder || msgFolder));
-     updateButtons();
-   }
+/**
+ * Select a folder on which filters are to be run.
+ *
+ * @param aFolder     nsIMsgFolder folder to select.
+ */
+function setRunFolder(aFolder) {
+  // Setting this attribute should go away in bug 473009.
+  gRunFiltersFolder._folder = aFolder;
+  // Calling this should go away in bug 802609.
+  gRunFiltersFolder.menupopup.selectFolder(gRunFiltersFolder._folder);
+  updateButtons();
 }
 
 /**
  * Toggle enabled state of a filter, in both the filter properties and the UI.
  *
  * @param aFilterItem  an item (row) of the filter list to be toggled
  */
 function toggleFilter(aFilterItem)
@@ -271,24 +305,16 @@ function toggleFilter(aFilterItem)
   filter.enabled = !filter.enabled;
 
   // Now update the checkbox
   aFilterItem.childNodes[1].setAttribute("enabled", filter.enabled);
   // For accessibility set the checked state on listitem
   aFilterItem.setAttribute("aria-checked", filter.enabled);
 }
 
-// update the server menulist
-function selectFolder(aFolder)
-{
-  var serverMenu = document.getElementById("serverMenuPopup");
-  serverMenu.selectFolder(aFolder);
-  setFolder(aFolder);
-}
-
 /**
  * Selects a specific filter in the filter list.
  * The listbox view is scrolled to the corresponding item.
  *
  * @param aFilter  The nsIMsgFilter to select.
  *
  * @return  true/false indicating whether the filter was found and selected.
  */
@@ -604,17 +630,19 @@ function runSelectedFilters()
 {
   // if run button has "stop" label, do stop.
   if (gRunFiltersButton.getAttribute("label") ==
       gRunFiltersButton.getAttribute("stoplabel")) {
     gFilterListMsgWindow.StopUrls();
     return;
   }
 
-  var folder = gRunFiltersFolder._folder || gRunFiltersFolder.selectedItem._folder;
+  let folder = gRunFiltersFolder._folder || gRunFiltersFolder.selectedItem._folder;
+  if (!folder)
+    return;
 
   let filterList = MailServices.filters.getTempFilterList(folder);
   let folders = Cc["@mozilla.org/array;1"]
                   .createInstance(Ci.nsIMutableArray);
   folders.appendElement(folder);
 
   // make sure the tmp filter list uses the real filter list log stream
   filterList.logStream = gCurrentFilterList.logStream;
@@ -794,17 +822,17 @@ function updateButtons()
 
     // "delete" only disabled when no filters are selected
     gDeleteButton.disabled = !numFiltersSelected;
 
     // we can run multiple filters on a folder
     // so only disable this UI if no filters are selected
     document.getElementById("folderPickerPrefix").disabled = !numFiltersSelected;
     gRunFiltersFolder.disabled = !numFiltersSelected;
-    gRunFiltersButton.disabled = !numFiltersSelected || !gRunFiltersFolder.value;
+    gRunFiltersButton.disabled = !numFiltersSelected || !gRunFiltersFolder._folder;
     // "up" and "top" enabled only if one filter is selected, and it's not the first
     // don't use gFilterListbox.currentIndex here, it's buggy when we've just changed the
     // children in the list (via rebuildFilterList)
     disabled = !(oneFilterSelected &&
                  gFilterListbox.getSelectedItem(0) != gFilterListbox.getItemAtIndex(0));
     gUpButton.disabled = disabled;
     gTopButton.disabled = disabled;
 
@@ -911,59 +939,16 @@ function onFilterListKeyPress(aEvent)
         break;
       default:
         gSearchBox.focus();
         gSearchBox.value = String.fromCharCode(aEvent.charCode);
     }
   }
 }
 
-function onTargetSelect(event) {
-  setRunFolder(event.target._folder);
-}
-
-function setRunFolder(aFolder) {
-  gRunFiltersFolder._folder = aFolder;
-  gRunFiltersFolder.menupopup.selectFolder(gRunFiltersFolder._folder);
-  updateButtons();
-}
-
-/**
- * For a given server folder, get the default run target selected folder or show
- * Choose Folder.
- */
-function getFirstFolder(msgFolder)
-{
-  // Sanity check.
-  if (!msgFolder.isServer)
-    return msgFolder;
-
-  try {
-    // Choose Folder for feeds.
-    if (msgFolder.server.type == "rss")
-      return null;
-
-    if (msgFolder.server.type != "nntp")
-    {
-      // Find Inbox for imap and pop; show Choose Folder if not found or
-      // Local Folders or any other account type.
-      const nsMsgFolderFlags = Ci.nsMsgFolderFlags;
-      // If inbox does not exist then return null.
-      return msgFolder.getFolderWithFlags(nsMsgFolderFlags.Inbox);
-    }
-
-    // For news, this is the account folder.
-    return msgFolder;
-  }
-  catch (ex) {
-    dump(ex + "\n");
-  }
-  return msgFolder;
-}
-
 /**
  * Decides if the given filter matches the given keyword.
  *
  * @param  aFilter   nsIMsgFilter to check
  * @param  aKeyword  the string to find in the filter name
  *
  * @return  True if the filter name contains the searched keyword.
             Otherwise false. In the future this may be extended to match
--- a/mail/base/content/FilterListDialog.xul
+++ b/mail/base/content/FilterListDialog.xul
@@ -38,17 +38,17 @@
 
     <menulist id="serverMenu"
               class="folderMenuItem">
       <menupopup id="serverMenuPopup" type="folder" mode="filters"
                  class="menulist-menupopup"
                  expandFolders="nntp"
                  showFileHereLabel="true"
                  showAccountsFileHere="true"
-                 oncommand="onFilterFolderClick(event.target._folder);"/>
+                 oncommand="setFilterFolder(event.target._folder);"/>
     </menulist>
     <textbox id="searchBox"
              class="searchBox"
              flex="1"
              type="search"
              oncommand="rebuildFilterList();"
              emptytext="&searchBox.emptyText;"
              isempty="true"/>
@@ -142,17 +142,17 @@
             <menulist id="runFiltersFolder" disabled="true" flex="1"
                       class="folderMenuItem"
                       displayformat="verbose">
               <menupopup id="runFiltersPopup"
                          class="menulist-menupopup"
                          type="folder"
                          showFileHereLabel="true"
                          showAccountsFileHere="false"
-                         oncommand="onTargetSelect(event);"/>
+                         oncommand="setRunFolder(event.target._folder);"/>
             </menulist>
           <button id="runFiltersButton"
                   label="&runFilters.label;"
                   accesskey="&runFilters.accesskey;"
                   runlabel="&runFilters.label;"
                   runaccesskey="&runFilters.accesskey;"
                   stoplabel="&stopFilters.label;"
                   stopaccesskey="&stopFilters.accesskey;"