LCOV - code coverage report
Current view: directory - content/xul/templates/src - nsTreeRows.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 232 0 0.0 %
Date: 2012-06-02 Functions: 20 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is Mozilla Communicator client code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Chris Waterson <waterson@netscape.com>
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      27                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include "nsString.h"
      40                 : #include "nsTreeRows.h"
      41                 : 
      42                 : nsTreeRows::Subtree*
      43               0 : nsTreeRows::EnsureSubtreeFor(Subtree* aParent,
      44                 :                              PRInt32 aChildIndex)
      45                 : {
      46               0 :     Subtree* subtree = GetSubtreeFor(aParent, aChildIndex);
      47                 : 
      48               0 :     if (! subtree) {
      49               0 :         subtree = aParent->mRows[aChildIndex].mSubtree = new Subtree(aParent);
      50               0 :         InvalidateCachedRow();
      51                 :     }
      52                 : 
      53               0 :     return subtree;
      54                 : }
      55                 : 
      56                 : nsTreeRows::Subtree*
      57               0 : nsTreeRows::GetSubtreeFor(const Subtree* aParent,
      58                 :                               PRInt32 aChildIndex,
      59                 :                               PRInt32* aSubtreeSize)
      60                 : {
      61               0 :     NS_PRECONDITION(aParent, "no parent");
      62               0 :     NS_PRECONDITION(aChildIndex >= 0, "bad child index");
      63                 : 
      64               0 :     Subtree* result = nsnull;
      65                 : 
      66               0 :     if (aChildIndex < aParent->mCount)
      67               0 :         result = aParent->mRows[aChildIndex].mSubtree;
      68                 : 
      69               0 :     if (aSubtreeSize)
      70               0 :         *aSubtreeSize = result ? result->mSubtreeSize : 0;
      71                 : 
      72               0 :     return result;
      73                 : }
      74                 : 
      75                 : void
      76               0 : nsTreeRows::RemoveSubtreeFor(Subtree* aParent, PRInt32 aChildIndex)
      77                 : {
      78               0 :     NS_PRECONDITION(aParent, "no parent");
      79               0 :     NS_PRECONDITION(aChildIndex >= 0 && aChildIndex < aParent->mCount, "bad child index");
      80                 : 
      81               0 :     Row& row = aParent->mRows[aChildIndex];
      82                 : 
      83               0 :     if (row.mSubtree) {
      84               0 :         PRInt32 subtreeSize = row.mSubtree->GetSubtreeSize();
      85                 : 
      86               0 :         delete row.mSubtree;
      87               0 :         row.mSubtree = nsnull;
      88                 : 
      89               0 :         for (Subtree* subtree = aParent; subtree != nsnull; subtree = subtree->mParent)
      90               0 :             subtree->mSubtreeSize -= subtreeSize;
      91                 :     }
      92                 : 
      93               0 :     InvalidateCachedRow();
      94               0 : }
      95                 : 
      96                 : nsTreeRows::iterator
      97               0 : nsTreeRows::First()
      98                 : {
      99               0 :     iterator result;
     100               0 :     result.Append(&mRoot, 0);
     101               0 :     result.SetRowIndex(0);
     102                 :     return result;
     103                 : }
     104                 : 
     105                 : nsTreeRows::iterator
     106               0 : nsTreeRows::Last()
     107                 : {
     108               0 :     iterator result;
     109                 : 
     110                 :     // Build up a path along the rightmost edge of the tree
     111               0 :     Subtree* current = &mRoot;
     112               0 :     PRInt32 count = current->Count();
     113               0 :     do  {
     114               0 :         PRInt32 last = count - 1;
     115               0 :         result.Append(current, last);
     116               0 :         current = count ? GetSubtreeFor(current, last) : nsnull;
     117                 :     } while (current && ((count = current->Count()) != 0));
     118                 : 
     119                 :     // Now, at the bottom rightmost leaf, advance us one off the end.
     120               0 :     result.GetTop().mChildIndex++;
     121                 : 
     122                 :     // Our row index will be the size of the root subree, plus one.
     123               0 :     result.SetRowIndex(mRoot.GetSubtreeSize() + 1);
     124                 : 
     125                 :     return result;
     126                 : }
     127                 : 
     128                 : nsTreeRows::iterator
     129               0 : nsTreeRows::operator[](PRInt32 aRow)
     130                 : {
     131                 :     // See if we're just lucky, and end up with something
     132                 :     // nearby. (This tends to happen a lot due to the way that we get
     133                 :     // asked for rows n' stuff.)
     134               0 :     PRInt32 last = mLastRow.GetRowIndex();
     135               0 :     if (last != -1) {
     136               0 :         if (aRow == last)
     137               0 :             return mLastRow;
     138               0 :         else if (last + 1 == aRow)
     139               0 :             return ++mLastRow;
     140               0 :         else if (last - 1 == aRow)
     141               0 :             return --mLastRow;
     142                 :     }
     143                 : 
     144                 :     // Nope. Construct a path to the specified index. This is a little
     145                 :     // bit better than O(n), because we can skip over subtrees. (So it
     146                 :     // ends up being approximately linear in the subtree size, instead
     147                 :     // of the entire view size. But, most of the time, big views are
     148                 :     // flat. Oh well.)
     149               0 :     iterator result;
     150               0 :     Subtree* current = &mRoot;
     151                 : 
     152               0 :     PRInt32 index = 0;
     153               0 :     result.SetRowIndex(aRow);
     154                 : 
     155               0 :     do {
     156                 :         PRInt32 subtreeSize;
     157               0 :         Subtree* subtree = GetSubtreeFor(current, index, &subtreeSize);
     158                 : 
     159               0 :         if (subtreeSize >= aRow) {
     160               0 :             result.Append(current, index);
     161               0 :             current = subtree;
     162               0 :             index = 0;
     163               0 :             --aRow;
     164                 :         }
     165                 :         else {
     166               0 :             ++index;
     167               0 :             aRow -= subtreeSize + 1;
     168                 :         }
     169                 :     } while (aRow >= 0);
     170                 : 
     171               0 :     mLastRow = result;
     172               0 :     return result;
     173                 : }
     174                 : 
     175                 : nsTreeRows::iterator
     176               0 : nsTreeRows::FindByResource(nsIRDFResource* aResource)
     177                 : {
     178                 :     // XXX Mmm, scan through the rows one-by-one...
     179               0 :     iterator last = Last();
     180               0 :     iterator iter;
     181                 : 
     182                 :     nsresult rv;
     183               0 :     nsAutoString resourceid;
     184               0 :     bool stringmode = false;
     185                 : 
     186               0 :     for (iter = First(); iter != last; ++iter) {
     187               0 :         if (!stringmode) {
     188               0 :             nsCOMPtr<nsIRDFResource> findres;
     189               0 :             rv = iter->mMatch->mResult->GetResource(getter_AddRefs(findres));
     190               0 :             if (NS_FAILED(rv)) return last;
     191                 : 
     192               0 :             if (findres == aResource)
     193                 :                 break;
     194                 : 
     195               0 :             if (! findres) {
     196                 :                 const char *uri;
     197               0 :                 aResource->GetValueConst(&uri);
     198               0 :                 CopyUTF8toUTF16(uri, resourceid);
     199                 : 
     200                 :                 // set stringmode and fall through
     201               0 :                 stringmode = true;
     202                 :             }
     203                 :         }
     204                 : 
     205                 :         // additional check because previous block could change stringmode
     206               0 :         if (stringmode) {
     207               0 :             nsAutoString findid;
     208               0 :             rv = iter->mMatch->mResult->GetId(findid);
     209               0 :             if (NS_FAILED(rv)) return last;
     210                 : 
     211               0 :             if (resourceid.Equals(findid))
     212                 :                 break;
     213                 :         }
     214                 :     }
     215                 : 
     216               0 :     return iter;
     217                 : }
     218                 : 
     219                 : nsTreeRows::iterator
     220               0 : nsTreeRows::Find(nsIXULTemplateResult *aResult)
     221                 : {
     222                 :     // XXX Mmm, scan through the rows one-by-one...
     223               0 :     iterator last = Last();
     224               0 :     iterator iter;
     225                 : 
     226               0 :     for (iter = First(); iter != last; ++iter) {
     227               0 :         if (aResult == iter->mMatch->mResult)
     228               0 :           break;
     229                 :     }
     230                 : 
     231                 :     return iter;
     232                 : }
     233                 : 
     234                 : void
     235               0 : nsTreeRows::Clear()
     236                 : {
     237               0 :     mRoot.Clear();
     238               0 :     InvalidateCachedRow();
     239               0 : }
     240                 : 
     241                 : //----------------------------------------------------------------------
     242                 : //
     243                 : // nsTreeRows::Subtree
     244                 : //
     245                 : 
     246               0 : nsTreeRows::Subtree::~Subtree()
     247                 : {
     248               0 :     Clear();
     249               0 : }
     250                 : 
     251                 : void
     252               0 : nsTreeRows::Subtree::Clear()
     253                 : {
     254               0 :     for (PRInt32 i = mCount - 1; i >= 0; --i)
     255               0 :         delete mRows[i].mSubtree;
     256                 : 
     257               0 :     delete[] mRows;
     258                 : 
     259               0 :     mRows = nsnull;
     260               0 :     mCount = mCapacity = mSubtreeSize = 0;
     261               0 : }
     262                 : 
     263                 : nsTreeRows::iterator
     264               0 : nsTreeRows::Subtree::InsertRowAt(nsTemplateMatch* aMatch, PRInt32 aIndex)
     265                 : {
     266               0 :     if (mCount >= mCapacity || aIndex >= mCapacity) {
     267               0 :         PRInt32 newCapacity = NS_MAX(mCapacity * 2, aIndex + 1);
     268               0 :         Row* newRows = new Row[newCapacity];
     269               0 :         if (! newRows)
     270               0 :             return iterator();
     271                 : 
     272               0 :         for (PRInt32 i = mCount - 1; i >= 0; --i)
     273               0 :             newRows[i] = mRows[i];
     274                 : 
     275               0 :         delete[] mRows;
     276                 : 
     277               0 :         mRows = newRows;
     278               0 :         mCapacity = newCapacity;
     279                 :     }
     280                 : 
     281               0 :     for (PRInt32 i = mCount - 1; i >= aIndex; --i)
     282               0 :         mRows[i + 1] = mRows[i];
     283                 : 
     284               0 :     mRows[aIndex].mMatch = aMatch;
     285               0 :     mRows[aIndex].mContainerType = eContainerType_Unknown;
     286               0 :     mRows[aIndex].mContainerState = eContainerState_Unknown;
     287               0 :     mRows[aIndex].mContainerFill = eContainerFill_Unknown;
     288               0 :     mRows[aIndex].mSubtree = nsnull;
     289               0 :     ++mCount;
     290                 : 
     291                 :     // Now build an iterator that points to the newly inserted element.
     292               0 :     PRInt32 rowIndex = 0;
     293               0 :     iterator result;
     294               0 :     result.Push(this, aIndex);
     295                 : 
     296               0 :     for ( ; --aIndex >= 0; ++rowIndex) {
     297                 :         // Account for open subtrees in the absolute row index.
     298               0 :         const Subtree *subtree = mRows[aIndex].mSubtree;
     299               0 :         if (subtree)
     300               0 :             rowIndex += subtree->mSubtreeSize;
     301                 :     }
     302                 : 
     303               0 :     Subtree *subtree = this;
     304               0 :     do {
     305                 :         // Note that the subtree's size has expanded.
     306               0 :         ++subtree->mSubtreeSize;
     307                 : 
     308               0 :         Subtree *parent = subtree->mParent;
     309               0 :         if (! parent)
     310                 :             break;
     311                 : 
     312                 :         // Account for open subtrees in the absolute row index.
     313               0 :         PRInt32 count = parent->Count();
     314               0 :         for (aIndex = 0; aIndex < count; ++aIndex, ++rowIndex) {
     315               0 :             const Subtree *child = (*parent)[aIndex].mSubtree;
     316               0 :             if (subtree == child)
     317               0 :                 break;
     318                 : 
     319               0 :             if (child)
     320               0 :                 rowIndex += child->mSubtreeSize;
     321                 :         }
     322                 : 
     323               0 :         NS_ASSERTION(aIndex < count, "couldn't find subtree in parent");
     324                 : 
     325               0 :         result.Push(parent, aIndex);
     326               0 :         subtree = parent;
     327               0 :         ++rowIndex; // One for the parent row.
     328                 :     } while (1);
     329                 : 
     330               0 :     result.SetRowIndex(rowIndex);
     331               0 :     return result;
     332                 : }
     333                 : 
     334                 : void
     335               0 : nsTreeRows::Subtree::RemoveRowAt(PRInt32 aIndex)
     336                 : {
     337               0 :     NS_PRECONDITION(aIndex >= 0 && aIndex < Count(), "bad index");
     338               0 :     if (aIndex < 0 || aIndex >= Count())
     339               0 :         return;
     340                 : 
     341                 :     // How big is the subtree we're going to be removing?
     342               0 :     PRInt32 subtreeSize = mRows[aIndex].mSubtree
     343               0 :         ? mRows[aIndex].mSubtree->GetSubtreeSize()
     344               0 :         : 0;
     345                 : 
     346               0 :     ++subtreeSize;
     347                 : 
     348               0 :     delete mRows[aIndex].mSubtree;
     349                 : 
     350               0 :     for (PRInt32 i = aIndex + 1; i < mCount; ++i)
     351               0 :         mRows[i - 1] = mRows[i];
     352                 : 
     353               0 :     --mCount;
     354                 : 
     355               0 :     for (Subtree* subtree = this; subtree != nsnull; subtree = subtree->mParent)
     356               0 :         subtree->mSubtreeSize -= subtreeSize;
     357                 : }
     358                 : 
     359                 : //----------------------------------------------------------------------
     360                 : //
     361                 : // nsTreeRows::iterator
     362                 : //
     363                 : 
     364               0 : nsTreeRows::iterator::iterator(const iterator& aIterator)
     365                 :     : mRowIndex(aIterator.mRowIndex),
     366               0 :       mLink(aIterator.mLink)
     367                 : {
     368               0 : }
     369                 : 
     370                 : nsTreeRows::iterator&
     371               0 : nsTreeRows::iterator::operator=(const iterator& aIterator)
     372                 : {
     373               0 :     mRowIndex = aIterator.mRowIndex;
     374               0 :     mLink = aIterator.mLink;
     375               0 :     return *this;
     376                 : }
     377                 : 
     378                 : void
     379               0 : nsTreeRows::iterator::Append(Subtree* aParent, PRInt32 aChildIndex)
     380                 : {
     381               0 :     Link *link = mLink.AppendElement();
     382               0 :     if (link) {
     383               0 :         link->mParent     = aParent;
     384               0 :         link->mChildIndex = aChildIndex;
     385                 :     }
     386                 :     else
     387               0 :         NS_ERROR("out of memory");
     388               0 : }
     389                 : 
     390                 : void
     391               0 : nsTreeRows::iterator::Push(Subtree *aParent, PRInt32 aChildIndex)
     392                 : {
     393               0 :     Link *link = mLink.InsertElementAt(0);
     394               0 :     if (link) {
     395               0 :         link->mParent     = aParent;
     396               0 :         link->mChildIndex = aChildIndex;
     397                 :     }
     398                 :     else
     399               0 :         NS_ERROR("out of memory");
     400               0 : }
     401                 : 
     402                 : bool
     403               0 : nsTreeRows::iterator::operator==(const iterator& aIterator) const
     404                 : {
     405               0 :     if (GetDepth() != aIterator.GetDepth())
     406               0 :         return false;
     407                 : 
     408               0 :     if (GetDepth() == 0)
     409               0 :         return true;
     410                 : 
     411               0 :     return GetTop() == aIterator.GetTop();
     412                 : }
     413                 : 
     414                 : void
     415               0 : nsTreeRows::iterator::Next()
     416                 : {
     417               0 :     NS_PRECONDITION(GetDepth() > 0, "cannot increment an uninitialized iterator");
     418                 : 
     419                 :     // Increment the absolute row index
     420               0 :     ++mRowIndex;
     421                 : 
     422               0 :     Link& top = GetTop();
     423                 : 
     424                 :     // Is there a child subtree? If so, descend into the child
     425                 :     // subtree.
     426               0 :     Subtree* subtree = top.GetRow().mSubtree;
     427                 : 
     428               0 :     if (subtree && subtree->Count()) {
     429               0 :         Append(subtree, 0);
     430               0 :         return;
     431                 :     }
     432                 : 
     433                 :     // Have we exhausted the current subtree?
     434               0 :     if (top.mChildIndex >= top.mParent->Count() - 1) {
     435                 :         // Yep. See if we've just iterated path the last element in
     436                 :         // the tree, period. Walk back up the stack, looking for any
     437                 :         // unfinished subtrees.
     438                 :         PRInt32 unfinished;
     439               0 :         for (unfinished = GetDepth() - 2; unfinished >= 0; --unfinished) {
     440               0 :             const Link& link = mLink[unfinished];
     441               0 :             if (link.mChildIndex < link.mParent->Count() - 1)
     442               0 :                 break;
     443                 :         }
     444                 : 
     445                 :         // If there are no unfinished subtrees in the stack, then this
     446                 :         // iterator is exhausted. Leave it in the same state that
     447                 :         // Last() does.
     448               0 :         if (unfinished < 0) {
     449               0 :             top.mChildIndex++;
     450               0 :             return;
     451                 :         }
     452                 : 
     453                 :         // Otherwise, we ran off the end of one of the inner
     454                 :         // subtrees. Pop up to the next unfinished level in the stack.
     455               0 :         mLink.SetLength(unfinished + 1);
     456                 :     }
     457                 : 
     458                 :     // Advance to the next child in this subtree
     459               0 :     ++(GetTop().mChildIndex);
     460                 : }
     461                 : 
     462                 : void
     463               0 : nsTreeRows::iterator::Prev()
     464                 : {
     465               0 :     NS_PRECONDITION(GetDepth() > 0, "cannot increment an uninitialized iterator");
     466                 : 
     467                 :     // Decrement the absolute row index
     468               0 :     --mRowIndex;
     469                 : 
     470                 :     // Move to the previous child in this subtree
     471               0 :     --(GetTop().mChildIndex);
     472                 : 
     473                 :     // Have we exhausted the current subtree?
     474               0 :     if (GetTop().mChildIndex < 0) {
     475                 :         // Yep. See if we've just iterated back to the first element
     476                 :         // in the tree, period. Walk back up the stack, looking for
     477                 :         // any unfinished subtrees.
     478                 :         PRInt32 unfinished;
     479               0 :         for (unfinished = GetDepth() - 2; unfinished >= 0; --unfinished) {
     480               0 :             const Link& link = mLink[unfinished];
     481               0 :             if (link.mChildIndex >= 0)
     482               0 :                 break;
     483                 :         }
     484                 : 
     485                 :         // If there are no unfinished subtrees in the stack, then this
     486                 :         // iterator is exhausted. Leave it in the same state that
     487                 :         // First() does.
     488               0 :         if (unfinished < 0)
     489               0 :             return;
     490                 : 
     491                 :         // Otherwise, we ran off the end of one of the inner
     492                 :         // subtrees. Pop up to the next unfinished level in the stack.
     493               0 :         mLink.SetLength(unfinished + 1);
     494               0 :         return;
     495                 :     }
     496                 : 
     497                 :     // Is there a child subtree immediately prior to our current
     498                 :     // position? If so, descend into it, grovelling down to the
     499                 :     // deepest, rightmost left edge.
     500               0 :     Subtree* parent = GetTop().GetParent();
     501               0 :     PRInt32 index = GetTop().GetChildIndex();
     502                 : 
     503               0 :     Subtree* subtree = (*parent)[index].mSubtree;
     504                 : 
     505               0 :     if (subtree && subtree->Count()) {
     506               0 :         do {
     507               0 :             index = subtree->Count() - 1;
     508               0 :             Append(subtree, index);
     509                 : 
     510               0 :             parent = subtree;
     511               0 :             subtree = (*parent)[index].mSubtree;
     512               0 :         } while (subtree && subtree->Count());
     513                 :     }
     514                 : }

Generated by: LCOV version 1.7