Bug 1637668 - Follow up improvements to Folder Pane icons colour customization. r=mkmelin a=wsmwk
authorAlessandro Castellani <alessandro@thunderbird.net>
Sun, 07 Jun 2020 13:37:40 +0300
changeset 39403 c8d94a2edc42e0e8d552f2a71b2cde469dc10f87
parent 39402 d2d84ac207536f6f672b861964909d1c70d46da0
child 39404 dae8830af25a8a0a0879e5e5a82a4128999a2be6
push id402
push userclokep@gmail.com
push dateMon, 29 Jun 2020 20:48:04 +0000
reviewersmkmelin, wsmwk
bugs1637668
Bug 1637668 - Follow up improvements to Folder Pane icons colour customization. r=mkmelin a=wsmwk
mail/base/content/folderPane.js
mail/base/content/messenger.xhtml
mailnews/base/content/msgSelectOfflineFolders.xhtml
mailnews/base/content/virtualFolderListEdit.xhtml
--- a/mail/base/content/folderPane.js
+++ b/mail/base/content/folderPane.js
@@ -145,18 +145,20 @@ var gFolderTreeView = {
 
   /**
    * Called when the window is initially loaded. This function initializes the
    * folder-pane to the view last shown before the application was closed.
    */
   load(aTree, aJSONFile) {
     this._treeElement = aTree;
     this.messengerBundle = document.getElementById("bundle_messenger");
-    this.inlineStyle = document.getElementById("inlineStyle");
-    this.previewStyle = document.getElementById("previewStyle");
+    this.folderColorStyle = document.getElementById("folderColorsStyle");
+    this.folderColorPreview = document.getElementById(
+      "folderColorsStylePreview"
+    );
 
     // The folder pane can be used for other trees which may not have these
     // elements. Collapse them if no account is currently available.
     let hasAccounts = MailServices.accounts.accounts.length > 0;
     if (document.getElementById("folderpane_splitter")) {
       document.getElementById("folderpane_splitter").collapsed = !hasAccounts;
     }
     if (document.getElementById("folderPaneBox")) {
@@ -1566,20 +1568,29 @@ var gFolderTreeView = {
       // So fallback on old trick of going backwards from the end, which
       // doesn't care when you add things at the end.
       for (let i = tree._rowMap.length - 1; i >= 0; i--) {
         let row = tree._rowMap[i];
         if (row.level != curLevel) {
           continue;
         }
 
+        // Restore the custom color of the fodler icon.
+        tree.setFolderCustomColor(row._folder);
+
         // The initial state of all rows is closed, so toggle those we want open.
         if (!map || map.includes(row.id)) {
           tree._toggleRow(i, false);
           goOn = true;
+        } else {
+          // Loop through the children of this closed folder to check for
+          // custom colors. Bug 1641950
+          for (let child of Array.from(row.children)) {
+            tree.setFolderCustomColor(child._folder);
+          }
         }
       }
 
       // If we opened up any new kids, we need to check their level as well.
       curLevel++;
       if (goOn) {
         openLevel();
       }
@@ -1681,42 +1692,16 @@ var gFolderTreeView = {
     for (let folder of selectedFolders) {
       if (folder) {
         let index = this.getIndexOfFolder(folder);
         if (index != null) {
           this.selection.toggleSelect(index);
         }
       }
     }
-
-    // Restore custom icon colors.
-    for (let i = 0; i < this._rowMap.length; i++) {
-      let folder = this._rowMap[i]._folder;
-      let msgDatabase;
-      try {
-        // This will throw an exception if the .msf file is missing,
-        // out of date (e.g., the local folder has changed), or corrupted.
-        msgDatabase = folder.msgDatabase;
-      } catch (e) {}
-
-      if (msgDatabase) {
-        // Get the previously stored color from the Folder Database.
-        let iconColor = folder.msgDatabase.dBFolderInfo.getCharProperty(
-          "folderIconColor"
-        );
-        // Store the color in the cache property so we can use this for
-        // properties changes and updates.
-        gFolderTreeView.setFolderCacheProperty(
-          this._rowMap[i]._folder,
-          "folderIconColor",
-          iconColor
-        );
-        this.appendColor(iconColor);
-      }
-    }
   },
 
   _sortedAccounts() {
     let accounts = allAccountsSorted(true);
 
     // Don't show deferred pop accounts.
     accounts = accounts.filter(function(a) {
       let server = a.incomingServer;
@@ -2616,29 +2601,77 @@ var gFolderTreeView = {
   OnItemEvent(aFolder, aEvent) {
     let index = this.getIndexOfFolder(aFolder);
     if (index != null) {
       this._tree.invalidateRow(index);
     }
   },
 
   /**
+   * Apply custom icon colors if a cached property is not already present.
+   *
+   * @param {ftvItem} folder - The folder attached to this row in the tree.
+   */
+  setFolderCustomColor(folder) {
+    // Interrupt if the folder already has an icon color cached property.
+    if (gFolderTreeView.getFolderCacheProperty(folder, "folderIconColor")) {
+      return;
+    }
+
+    let msgDatabase;
+    try {
+      // This will throw an exception if the .msf file is missing,
+      // out of date (e.g., the local folder has changed), or corrupted.
+      msgDatabase = folder.msgDatabase;
+    } catch (e) {}
+
+    // Interrupt if no folder database is available.
+    if (!msgDatabase) {
+      return;
+    }
+
+    // Get the previously stored color from the Folder Database.
+    let iconColor = msgDatabase.dBFolderInfo.getCharProperty("folderIconColor");
+
+    // Store the color in the cache property so we can use this for
+    // properties changes and updates.
+    gFolderTreeView.setFolderCacheProperty(
+      folder,
+      "folderIconColor",
+      iconColor
+    );
+    this.appendColor(iconColor);
+
+    // Null out to avoid memory bloat.
+    if (
+      !MailServices.mailSession.IsFolderOpenInWindow(folder) &&
+      !(folder.flags & (Ci.nsMsgFolderFlags.Trash | Ci.nsMsgFolderFlags.Inbox))
+    ) {
+      folder.msgDatabase = null;
+    }
+  },
+
+  /**
    * Append inline CSS style for those icons where a custom color was defined.
    *
    * @param {string} iconColor - The hash color.
    */
   appendColor(iconColor) {
-    if (!this.inlineStyle || !iconColor) {
+    if (!this.folderColorStyle || !iconColor) {
       return;
     }
 
-    let selector = `customColor-${iconColor.replace("#", "")}`;
-
-    // Append the inline CSS styling.
-    this.inlineStyle.textContent += `treechildren::-moz-tree-image(folderNameCol, ${selector}) {fill: ${iconColor};}`;
+    // Append the new CSS styling.
+    this.folderColorStyle.sheet.insertRule(
+      `treechildren::-moz-tree-image(folderNameCol, customColor-${iconColor.replace(
+        "#",
+        ""
+      )}) {fill: ${iconColor};}`,
+      this.folderColorStyle.sheet.cssRules.length
+    );
   },
 };
 
 /**
  * The ftvItem object represents a single row in the tree view. Because I'm lazy
  * I'm just going to define the expected interface here.  You are free to return
  * an alternative object, provided that it matches this interface:
  *
@@ -3384,59 +3417,59 @@ var gFolderTreeController = {
   /**
    * Update the inline preview style in the messagener.xhtml file to show
    * users a preview of the defined color.
    *
    * @param {ftvItem} folder - The folder where the color is defined.
    * @param {string} newColor - The new hash color to preview.
    */
   previewSelectedColor(folder, newColor) {
-    // If the color is null, it measn we're resetting to the default value.
+    // If the color is null, it means we're resetting to the default value.
     if (!newColor) {
       gFolderTreeView.setFolderCacheProperty(folder, "folderIconColor", "");
 
       // Clear the preview CSS.
-      gFolderTreeView.previewStyle.textContent = "";
+      gFolderTreeView.folderColorPreview.textContent = "";
 
       // Force the folder update to see the new color.
       gFolderTreeView._tree.invalidateRow(
         gFolderTreeView.getIndexOfFolder(folder)
       );
       return;
     }
 
     // Add the new color property.
     gFolderTreeView.setFolderCacheProperty(folder, "folderIconColor", newColor);
 
     let selector = `customColor-${newColor.replace("#", "")}`;
     // Add the inline CSS styling.
-    gFolderTreeView.previewStyle.textContent = `treechildren::-moz-tree-image(folderNameCol, ${selector}) {fill: ${newColor};}`;
+    gFolderTreeView.folderColorPreview.textContent = `treechildren::-moz-tree-image(folderNameCol, ${selector}) {fill: ${newColor};}`;
 
     // Force the folder update to set the new color.
     gFolderTreeView._tree.invalidateRow(
       gFolderTreeView.getIndexOfFolder(folder)
     );
   },
 
   /**
    * Clear the preview style and add the new selected color to the persistent
    * inline style in the messenger.xhtml file.
    *
    * @param {ftvItem} folder - The folder where the new color was defined.
    */
   updateColor(folder) {
     // Clear the preview CSS.
-    gFolderTreeView.previewStyle.textContent = "";
+    gFolderTreeView.folderColorPreview.textContent = "";
 
     let newColor = gFolderTreeView.getFolderCacheProperty(
       folder,
       "folderIconColor"
     );
 
-    // Append new incline color if defined.
+    // Append new inline color if defined.
     gFolderTreeView.appendColor(newColor);
 
     // Store the new color in the Folder database.
     folder.msgDatabase.dBFolderInfo.setCharProperty(
       "folderIconColor",
       newColor
     );
 
--- a/mail/base/content/messenger.xhtml
+++ b/mail/base/content/messenger.xhtml
@@ -39,20 +39,16 @@
 
 <?xml-stylesheet href="chrome://calendar/skin/calendar-views.css" type="text/css"?>
 <?xml-stylesheet href="chrome://calendar/skin/shared/calendar-alarms.css" type="text/css"?>
 <?xml-stylesheet href="chrome://calendar/skin/shared/widgets/minimonth.css" type="text/css"?>
 <?xml-stylesheet href="chrome://calendar/skin/widgets/calendar-widgets.css" type="text/css"?>
 
 <?xml-stylesheet href="chrome://calendar/skin/lightning-toolbar.css" type="text/css"?>
 
-<!-- NEEDED FOR FOLDER COLOR CUSTOMIZATION -->
-<?xml-stylesheet href="#inlineStyle" type="text/css"?>
-<?xml-stylesheet href="#previewStyle" type="text/css"?>
-
 # All DTD information is stored in a separate file so that it can be shared by
 # hiddenWindowMac.xhtml.
 <!DOCTYPE window [
 #include messenger-doctype.inc.dtd
 ]>
 
 <!--
   - The 'what you think of when you think of thunderbird' window;
@@ -251,19 +247,18 @@
 <script src="chrome://calendar/content/calendar-menus.js"/>
 
 <!-- NEEDED FOR CALENDAR VIEWS -->
 <script src="chrome://calendar/content/calendar-event-gripbar.js"/>
 
 <!-- NEEDED FOR MIGRATION CHECK AT INSTALL -->
 <script src="chrome://calendar/content/calendar-migration.js"/>
 
-<!-- NEEDED FOR FOLDER COLOR CUSTOMIZATION -->
-<html:style type="text/css" id="inlineStyle"></html:style>
-<html:style type="text/css" id="previewStyle"></html:style>
+<html:style id="folderColorsStyle" type="text/css"></html:style>
+<html:style id="folderColorsStylePreview" type="text/css"></html:style>
 
 <commandset id="mailCommands">
 #include mainCommandSet.inc.xhtml
   <commandset id="mailSearchMenuItems"/>
   <commandset id="globalEditMenuItems"
               commandupdater="true"
               events="create-menu-edit"
               oncommandupdate="goUpdateGlobalEditMenuItems()"/>
--- a/mailnews/base/content/msgSelectOfflineFolders.xhtml
+++ b/mailnews/base/content/msgSelectOfflineFolders.xhtml
@@ -1,34 +1,31 @@
 <?xml version="1.0"?>
 <!-- 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/. -->
 
 <?xml-stylesheet href="chrome://messenger/skin/msgSelectOffline.css" type="text/css"?>
-<!-- NEEDED FOR FOLDER COLOR CUSTOMIZATION -->
-<?xml-stylesheet href="#inlineStyle" type="text/css"?>
 
 <!DOCTYPE window SYSTEM "chrome://messenger/locale/msgSynchronize.dtd" >
 
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
         windowtype="mailnews:selectOffline"
         title="&MsgSelect.label;"
         width="450" height="400"
         persist="width height"
         onload="gSelectOffline.load();">
 <dialog id="select-offline">
   <stringbundle id="bundle_messenger" src="chrome://messenger/locale/messenger.properties"/>
   <stringbundle id="bundle_brand" src="chrome://branding/locale/brand.properties"/>
 
   <script src="chrome://messenger/content/msgSelectOfflineFolders.js"/>
   <script src="chrome://messenger/content/folderPane.js"/>
 
-  <!-- NEEDED FOR FOLDER COLOR CUSTOMIZATION -->
-  <html:style type="text/css" id="inlineStyle"></html:style>
+  <html:style id="folderColorsStyle" type="text/css"></html:style>
 
   <label class="desc" control="synchronizeTree">&MsgSelectDesc.label;</label>
 
   <tree id="synchronizeTree"
         flex="1"
         hidecolumnpicker="true"
         seltype="multiple"
         disableKeyNavigation="true"
--- a/mailnews/base/content/virtualFolderListEdit.xhtml
+++ b/mailnews/base/content/virtualFolderListEdit.xhtml
@@ -1,32 +1,29 @@
 <?xml version="1.0"?>
 <!-- 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/.
    -->
 
 <?xml-stylesheet href="chrome://messenger/skin/mailWindow1.css" type="text/css"?>
-<!-- NEEDED FOR FOLDER COLOR CUSTOMIZATION -->
-<?xml-stylesheet href="#inlineStyle" type="text/css"?>
 
 <!DOCTYPE window SYSTEM "chrome://messenger/locale/virtualFolderListDialog.dtd">
 
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
         title="&virtualFolderListTitle.title;"
         windowtype="mailnews:virtualFolderList"
         style="width: 27em; height: 25em;"
         persist="width height screenX screenY"
         onload="gSelectVirtual.load();">
 <dialog id="searchFolderWindow">
   <script src="chrome://messenger/content/virtualFolderListEdit.js"/>
   <script src="chrome://messenger/content/folderPane.js"/>
 
-  <!-- NEEDED FOR FOLDER COLOR CUSTOMIZATION -->
-  <html:style type="text/css" id="inlineStyle"></html:style>
+  <html:style id="folderColorsStyle" type="text/css"></html:style>
 
   <stringbundle id="bundle_messenger" src="chrome://messenger/locale/messenger.properties"/>
 
   <label control="folderPickerTree">&virtualFolderDesc.label;</label>
 
     <tree id="folderPickerTree"
           flex="1"
           hidecolumnpicker="true"