Bug 386159 - Menu-view performance improvements. r=dietrich, a=mconnor.
authormozilla.mano@sent.com
Thu, 28 Jun 2007 13:33:21 -0700
changeset 2938 13792949ca982cef3eedf91687ed56e6b433c301
parent 2937 1607d7ed23b9efb446b0e7c1df2a622a20677756
child 2939 ef4619f2814ccb8e2d4f8fb08f3d4582ba68c4c2
push idunknown
push userunknown
push dateunknown
reviewersdietrich, mconnor
bugs386159
milestone1.9a6pre
Bug 386159 - Menu-view performance improvements. r=dietrich, a=mconnor.
browser/components/places/content/menu.xml
browser/components/places/content/toolbar.xml
--- a/browser/components/places/content/menu.xml
+++ b/browser/components/places/content/menu.xml
@@ -82,23 +82,27 @@
           }
         ]]></body>
       </method>
 
       <property name="controller"
                 readonly="true"
                 onget="return this._controller;"/>
 
+      <field name="_built">false</field>
+
       <method name="onPopupShowing">
         <body><![CDATA[
         if (!this._resultNode)
           this._init();
 
         if (!this._resultNode.containerOpen)
           this._resultNode.containerOpen = true;
+        if (!this._built)
+          this._rebuild();
 
         if (this.popupShowingCallback)
           this.popupShowingCallback();
         ]]></body>
       </method>
       
       <field name="_selection">null</field>
       
@@ -319,16 +323,17 @@
               var label = PlacesUtils.getString("bookmarksMenuEmptyFolder");
               const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
               var element = document.createElementNS(XULNS, "menuitem");
               element.setAttribute("label", label);
               element.setAttribute("disabled", true);
               this.appendChild(element);
             }
           }
+          this._built = true;
         ]]></body>
       </method>
 
       <!-- nsINavHistoryResultViewer -->
       <field name="_viewer"><![CDATA[({
         _self: this,
 
         _forwardToChildView:
@@ -339,41 +344,50 @@
               childView[aFunction].apply(childView, aArguments);
               return;
             }
           }
           throw("Container view not found");
         },
 
         itemInserted: function PMV_itemInserted(aParentNode, aNode, aIndex) {
+          if (!this._self._built)
+            return;
+
           if (aParentNode == this._self.getResultNode()) {
             var index = this._self._startMarker + 1 + aIndex;
             var before = this._self.childNodes[index] || null;
             this._self.insertNewItem(aNode, before);
           }
           else
             this._forwardToChildView(aParentNode, "itemInserted", arguments);
         },
 
         itemRemoved: function PMV_itemRemoved(aParentNode, aNode, aIndex) {
+          if (!this._self._built)
+            return;
+
           if (aParentNode == this._self.getResultNode()) {
             var children = this._self.childNodes;
             
             for (var i = 0; i < children.length; i++) {
               if (children[i].node == aNode) {
                 this._self.removeItem(children[i]);
                 return;
               }
             }
           }
           else
             this._forwardToChildView(aParentNode, "itemRemoved", arguments);
         },
 
         itemChanged: function PMV_itemChanged(aNode) {
+          if (!this._self._built)
+            return;
+
           // this check can be removed once we fix bug #382397
           var parentNode = aNode.parent;
           if (!parentNode)
             return;
 
           if (parentNode != this._self.getResultNode()) {
             this._forwardToChildView(parentNode, "itemChanged", arguments);
             return;
@@ -420,16 +434,19 @@
             menuitem.removeAttribute("image");
 
           if (menuitem.getAttribute("label") != title)
             menuitem.setAttribute("label", title);
         },
 
         itemReplaced:
         function PMV_itemReplaced(aParentNode, aOldNode, aNewNode, aIndex) {
+          if (!this._self._built)
+            return;
+
           if (aParentNode == this._self.getResultNode()) {
             var children = this._self.childNodes;
             for (var i = 0; i < children.length; i++) {
               if (children[i].node == aOldNode) {
                 var next = children[i].nextSibling;
                 this._self.removeItem(children[i]);
                 this._self.insertNewItem(aNewNode, next);
                 return;
@@ -444,16 +461,19 @@
           this.invalidateContainer(aNode);
         },
 
         containerClosed: function PMV_containerClosed(aNode) {
           this.invalidateContainer(aNode);
         },
 
         invalidateContainer: function PMV_invalidateContainer(aContainer) {
+          if (!this._self._built)
+            return;
+
           function isChildOf(node, container) {
             var parent = node.parent;
             while (parent) {
               if (parent == container)
                 return true;
               parent = parent.parent;
             }
             return false;
@@ -466,25 +486,25 @@
             if (node == aContainer)
               viewerToRebuild = this._self._containerNodesMap[i].domNode._viewer;
             if (isChildOf(node, aContainer))
               this._self._containerNodesMap.splice(i,1);
           }
         
           if (aContainer.containerOpen) {
             if (viewerToRebuild)
-              viewerToRebuild._self._rebuild();
+              viewerToRebuild._built = false;
             else
-              this._self._rebuild();
+              this._self._built = false;
           }
         },
 
         invalidateAll: function PMV_invalidateAll() {
           this._self._containerNodesMap.splice(0);
-          this._self._rebuild();
+          this._self._built = false;
         },
 
         sortingChanged: function PMV_sortingChanged(aSortingMode) {
         }
       })]]></field>
 
       <!-- Sometimes calling hidePopup() on a menu can leave submenus
            open.  This calls hidePopup() on the menu and recursively
@@ -892,18 +912,22 @@
         if (event.target == this)
           this.onPopupShowing();
       </handler>
 
       <handler event="popuphidden">
         if (event.target != this)
           return;
 
-        // UI performance: keep the resultnode open so we don't rebuild its
-        // contents whenever the popup is reopened.
+        // UI performance: folder queries are cheap, keep the resultnode open
+        // so we don't rebuild its contents whenever the popup is reopened.
+        if (!PlacesUtils.nodeIsFolder(this._resultNode)) {
+          this._resultNode.containerOpen = false;
+          this._built = false;
+        }
 
         // The autoopened attribute is set for folders which have been
         // automatically opened when dragged over.  Turn off this attribute
         // when the folder closes because it is no longer applicable.
         this.removeAttribute("autoopened");
       </handler>
 
       <!-- Set selected node on DOMMenuItemActive/contextmenu events
--- a/browser/components/places/content/toolbar.xml
+++ b/browser/components/places/content/toolbar.xml
@@ -633,20 +633,20 @@
           for (var i=0; i < this._self._containerNodesMap.length; i++) {
             var node = this._self._containerNodesMap[i].resultNode;
             
             if (node == aContainer)
               viewerToRebuild = this._self._containerNodesMap[i].domNode._viewer;
             if (isChildOf(node, aContainer))
               this._self._containerNodesMap.splice(i,1);
           }
-        
+
           if (aContainer.containerOpen) {
             if (viewerToRebuild)
-              viewerToRebuild._self._rebuild();
+              viewerToRebuild._self._built = false;
             else
               this._self._rebuild();
           }
         },
 
         invalidateAll: function TV_V_invalidateAll() {
           this._self._containerNodesMap.splice(0);
           this._self._rebuild();