Bug 377577 Allow templates to generate arbitrarily nested treeitems r=Enn sr=roc
authorneil@parkwaycc.co.uk
Thu, 19 Apr 2007 12:27:11 -0700
changeset 654 f0f2a3ebf0b00b4035a67c690eb113a09e0e1fb2
parent 653 836a81e2537f7d6f2a988cfb53d26aaaa00f0c56
child 655 aeceb84ea620b98cd8bc6321efe6664b0062882b
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersEnn, roc
bugs377577
milestone1.9a4pre
Bug 377577 Allow templates to generate arbitrarily nested treeitems r=Enn sr=roc
content/xul/templates/src/nsTreeRows.cpp
content/xul/templates/src/nsTreeRows.h
--- a/content/xul/templates/src/nsTreeRows.cpp
+++ b/content/xul/templates/src/nsTreeRows.cpp
@@ -112,17 +112,17 @@ nsTreeRows::Last()
     PRInt32 count = current->Count();
     do  {
         PRInt32 last = count - 1;
         result.Append(current, last);
         current = count ? GetSubtreeFor(current, last) : nsnull;
     } while (current && ((count = current->Count()) != 0));
 
     // Now, at the bottom rightmost leaf, advance us one off the end.
-    result.mLink[result.mTop].mChildIndex++;
+    result.GetTop().mChildIndex++;
 
     // Our row index will be the size of the root subree, plus one.
     result.SetRowIndex(mRoot.GetSubtreeSize() + 1);
 
     return result;
 }
 
 nsTreeRows::iterator
@@ -357,160 +357,153 @@ nsTreeRows::Subtree::RemoveRowAt(PRInt32
 }
 
 //----------------------------------------------------------------------
 //
 // nsTreeRows::iterator
 //
 
 nsTreeRows::iterator::iterator(const iterator& aIterator)
-    : mTop(aIterator.mTop),
-      mRowIndex(aIterator.mRowIndex)
+    : mRowIndex(aIterator.mRowIndex),
+      mLink(aIterator.mLink)
 {
-    for (PRInt32 i = mTop; i >= 0; --i)
-        mLink[i] = aIterator.mLink[i];
 }
 
 nsTreeRows::iterator&
 nsTreeRows::iterator::operator=(const iterator& aIterator)
 {
-    mTop = aIterator.mTop;
     mRowIndex = aIterator.mRowIndex;
-    for (PRInt32 i = mTop; i >= 0; --i)
-        mLink[i] = aIterator.mLink[i];
+    mLink = aIterator.mLink;
     return *this;
 }
 
 void
 nsTreeRows::iterator::Append(Subtree* aParent, PRInt32 aChildIndex)
 {
-    if (mTop < kMaxDepth - 1) {
-        ++mTop;
-        mLink[mTop].mParent     = aParent;
-        mLink[mTop].mChildIndex = aChildIndex;
+    Link *link = mLink.AppendElement();
+    if (link) {
+        link->mParent     = aParent;
+        link->mChildIndex = aChildIndex;
     }
     else
-        NS_ERROR("overflow");
+        NS_ERROR("out of memory");
 }
 
 void
 nsTreeRows::iterator::Push(Subtree *aParent, PRInt32 aChildIndex)
 {
-    if (mTop < kMaxDepth - 1) {
-        for (PRInt32 i = mTop; i >= 0; --i)
-            mLink[i + 1] = mLink[i];
-
-        mLink[0].mParent     = aParent;
-        mLink[0].mChildIndex = aChildIndex;
-        ++mTop;
+    Link *link = mLink.InsertElementAt(0);
+    if (link) {
+        link->mParent     = aParent;
+        link->mChildIndex = aChildIndex;
     }
     else
-        NS_ERROR("overflow");
+        NS_ERROR("out of memory");
 }
 
 PRBool
 nsTreeRows::iterator::operator==(const iterator& aIterator) const
 {
-    if (mTop != aIterator.mTop)
+    if (GetDepth() != aIterator.GetDepth())
         return PR_FALSE;
 
-    if (mTop == -1)
+    if (GetDepth() == 0)
         return PR_TRUE;
 
-    return PRBool(mLink[mTop] == aIterator.mLink[mTop]);
+    return GetTop() == aIterator.GetTop();
 }
 
 void
 nsTreeRows::iterator::Next()
 {
-    NS_PRECONDITION(mTop >= 0, "cannot increment an uninitialized iterator");
+    NS_PRECONDITION(GetDepth() > 0, "cannot increment an uninitialized iterator");
 
     // Increment the absolute row index
     ++mRowIndex;
 
-    Link& top = mLink[mTop];
+    Link& top = GetTop();
 
     // Is there a child subtree? If so, descend into the child
     // subtree.
     Subtree* subtree = top.GetRow().mSubtree;
 
     if (subtree && subtree->Count()) {
         Append(subtree, 0);
         return;
     }
 
     // Have we exhausted the current subtree?
     if (top.mChildIndex >= top.mParent->Count() - 1) {
         // Yep. See if we've just iterated path the last element in
         // the tree, period. Walk back up the stack, looking for any
         // unfinished subtrees.
         PRInt32 unfinished;
-        for (unfinished = mTop - 1; unfinished >= 0; --unfinished) {
+        for (unfinished = GetDepth() - 2; unfinished >= 0; --unfinished) {
             const Link& link = mLink[unfinished];
             if (link.mChildIndex < link.mParent->Count() - 1)
                 break;
         }
 
         // If there are no unfinished subtrees in the stack, then this
         // iterator is exhausted. Leave it in the same state that
         // Last() does.
         if (unfinished < 0) {
             top.mChildIndex++;
             return;
         }
 
         // Otherwise, we ran off the end of one of the inner
         // subtrees. Pop up to the next unfinished level in the stack.
-        mTop = unfinished;
+        mLink.SetLength(unfinished + 1);
     }
 
     // Advance to the next child in this subtree
-    ++(mLink[mTop].mChildIndex);
+    ++(GetTop().mChildIndex);
 }
 
 void
 nsTreeRows::iterator::Prev()
 {
-    NS_PRECONDITION(mTop >= 0, "cannot increment an uninitialized iterator");
+    NS_PRECONDITION(GetDepth() > 0, "cannot increment an uninitialized iterator");
 
     // Decrement the absolute row index
     --mRowIndex;
 
     // Move to the previous child in this subtree
-    --(mLink[mTop].mChildIndex);
+    --(GetTop().mChildIndex);
 
     // Have we exhausted the current subtree?
-    if (mLink[mTop].mChildIndex < 0) {
+    if (GetTop().mChildIndex < 0) {
         // Yep. See if we've just iterated back to the first element
         // in the tree, period. Walk back up the stack, looking for
         // any unfinished subtrees.
         PRInt32 unfinished;
-        for (unfinished = mTop - 1; unfinished >= 0; --unfinished) {
+        for (unfinished = GetDepth() - 2; unfinished >= 0; --unfinished) {
             const Link& link = mLink[unfinished];
             if (link.mChildIndex >= 0)
                 break;
         }
 
         // If there are no unfinished subtrees in the stack, then this
         // iterator is exhausted. Leave it in the same state that
         // First() does.
         if (unfinished < 0)
             return;
 
         // Otherwise, we ran off the end of one of the inner
         // subtrees. Pop up to the next unfinished level in the stack.
-        mTop = unfinished;
+        mLink.SetLength(unfinished + 1);
         return;
     }
 
     // Is there a child subtree immediately prior to our current
     // position? If so, descend into it, grovelling down to the
     // deepest, rightmost left edge.
-    Subtree* parent = mLink[mTop].GetParent();
-    PRInt32 index = mLink[mTop].GetChildIndex();
+    Subtree* parent = GetTop().GetParent();
+    PRInt32 index = GetTop().GetChildIndex();
 
     Subtree* subtree = (*parent)[index].mSubtree;
 
     if (subtree && subtree->Count()) {
         do {
             index = subtree->Count() - 1;
             Append(subtree, index);
 
--- a/content/xul/templates/src/nsTreeRows.h
+++ b/content/xul/templates/src/nsTreeRows.h
@@ -35,16 +35,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsTreeRows_h__
 #define nsTreeRows_h__
 
 #include "nsCOMPtr.h"
+#include "nsTArray.h"
 #include "pldhash.h"
 #include "nsIXULTemplateResult.h"
 #include "nsTemplateMatch.h"
 #include "nsIRDFResource.h"
 
 
 /**
  * This class maintains the state of the XUL tree builder's
@@ -181,18 +182,16 @@ public:
         /**
          * Remove an immediate child row from the specified index.
          */
         void RemoveRowAt(PRInt32 aChildIndex);
     };
 
     friend class Subtree;
 
-    enum { kMaxDepth = 32 };
-
 protected:
     /**
      * A link in the path through the view's tree.
      */
     struct Link {
         Subtree* mParent;
         PRInt32  mChildIndex;
 
@@ -217,19 +216,18 @@ protected:
     };
 
 public:
     /**
      * An iterator that can be used to traverse the tree view.
      */
     class iterator {
     protected:
-        PRInt32 mTop;
         PRInt32 mRowIndex;
-        Link    mLink[kMaxDepth];
+        nsAutoTArray<Link, 8> mLink;
 
         void Next();
         void Prev();
 
         friend class Subtree; // so InsertRowAt can initialize us
         friend class nsTreeRows; // so nsTreeRows can initialize us
 
         /**
@@ -242,68 +240,71 @@ public:
          */
         void Push(Subtree *aParent, PRInt32 aChildIndex);
 
         /**
          * Used by operator[]() and InsertRowAt() to initialize an iterator.
          */
         void SetRowIndex(PRInt32 aRowIndex) { mRowIndex = aRowIndex; }
 
+        /**
+         * Handy accessors to the top element.
+         */
+        Link& GetTop() { return mLink[mLink.Length() - 1]; }
+        const Link& GetTop() const { return mLink[mLink.Length() - 1]; }
+
     public:
-        iterator() : mTop(-1), mRowIndex(-1) {}
+        iterator() : mRowIndex(-1) {}
 
         iterator(const iterator& aIterator);
         iterator& operator=(const iterator& aIterator);
 
         PRBool operator==(const iterator& aIterator) const;
 
         PRBool operator!=(const iterator& aIterator) const {
             return !aIterator.operator==(*this); }
 
-        const Row& operator*() const { return mLink[mTop].GetRow(); }
-        Row& operator*() { return mLink[mTop].GetRow(); }
+        const Row& operator*() const { return GetTop().GetRow(); }
+        Row& operator*() { return GetTop().GetRow(); }
 
-        const Row* operator->() const { return &(mLink[mTop].GetRow()); }
-        Row* operator->() { return &(mLink[mTop].GetRow()); }
+        const Row* operator->() const { return &(GetTop().GetRow()); }
+        Row* operator->() { return &(GetTop().GetRow()); }
 
         iterator& operator++() { Next(); return *this; }
         iterator operator++(int) { iterator temp(*this); Next(); return temp; }
         iterator& operator--() { Prev(); return *this; }
         iterator operator--(int) { iterator temp(*this); Prev(); return temp; }
 
         /**
          * Return the current parent link
          */
-        Subtree* GetParent() {
-            return mLink[mTop].GetParent(); }
+        Subtree* GetParent() { return GetTop().GetParent(); }
 
-        const Subtree* GetParent() const {
-            return mLink[mTop].GetParent(); }
+        const Subtree* GetParent() const { return GetTop().GetParent(); }
 
         /**
          * Return the current child index
          */
-        PRInt32 GetChildIndex() const {
-            return mLink[mTop].GetChildIndex(); }
+        PRInt32 GetChildIndex() const { return GetTop().GetChildIndex(); }
 
         /**
          * Return the depth of the path the iterator is maintaining
          * into the tree.
          */
-        PRInt32 GetDepth() const { return mTop + 1; }
+        PRInt32 GetDepth() const { return mLink.Length(); }
 
         /**
          * Return the current row index of the iterator
          */
         PRInt32 GetRowIndex() const { return mRowIndex; }
 
         /**
          * Pop the iterator up a level.
          */
-        iterator& Pop() { --mTop; return *this; }
+        iterator& Pop() { mLink.SetLength(GetDepth() - 1); return *this; }
     };
 
     /**
      * Retrieve the first element in the view
      */
     iterator First();
 
     /**