123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483 |
- /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
- /* 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/. */
- #include "nsString.h"
- #include "nsTreeRows.h"
- #include <algorithm>
- nsTreeRows::Subtree*
- nsTreeRows::EnsureSubtreeFor(Subtree* aParent,
- int32_t aChildIndex)
- {
- Subtree* subtree = GetSubtreeFor(aParent, aChildIndex);
- if (! subtree) {
- subtree = aParent->mRows[aChildIndex].mSubtree = new Subtree(aParent);
- InvalidateCachedRow();
- }
- return subtree;
- }
- nsTreeRows::Subtree*
- nsTreeRows::GetSubtreeFor(const Subtree* aParent,
- int32_t aChildIndex,
- int32_t* aSubtreeSize)
- {
- NS_PRECONDITION(aParent, "no parent");
- NS_PRECONDITION(aChildIndex >= 0, "bad child index");
- Subtree* result = nullptr;
- if (aChildIndex < aParent->mCount)
- result = aParent->mRows[aChildIndex].mSubtree;
- if (aSubtreeSize)
- *aSubtreeSize = result ? result->mSubtreeSize : 0;
- return result;
- }
- void
- nsTreeRows::RemoveSubtreeFor(Subtree* aParent, int32_t aChildIndex)
- {
- NS_PRECONDITION(aParent, "no parent");
- NS_PRECONDITION(aChildIndex >= 0 && aChildIndex < aParent->mCount, "bad child index");
- Row& row = aParent->mRows[aChildIndex];
- if (row.mSubtree) {
- int32_t subtreeSize = row.mSubtree->GetSubtreeSize();
- delete row.mSubtree;
- row.mSubtree = nullptr;
- for (Subtree* subtree = aParent; subtree != nullptr; subtree = subtree->mParent)
- subtree->mSubtreeSize -= subtreeSize;
- }
- InvalidateCachedRow();
- }
- nsTreeRows::iterator
- nsTreeRows::First()
- {
- iterator result;
- result.Append(&mRoot, 0);
- result.SetRowIndex(0);
- return result;
- }
- nsTreeRows::iterator
- nsTreeRows::Last()
- {
- iterator result;
- // Build up a path along the rightmost edge of the tree
- Subtree* current = &mRoot;
- int32_t count = current->Count();
- do {
- int32_t last = count - 1;
- result.Append(current, last);
- current = count ? GetSubtreeFor(current, last) : nullptr;
- } while (current && ((count = current->Count()) != 0));
- // Now, at the bottom rightmost leaf, advance us one off the end.
- 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
- nsTreeRows::operator[](int32_t aRow)
- {
- // See if we're just lucky, and end up with something
- // nearby. (This tends to happen a lot due to the way that we get
- // asked for rows n' stuff.)
- int32_t last = mLastRow.GetRowIndex();
- if (last != -1) {
- if (aRow == last)
- return mLastRow;
- else if (last + 1 == aRow)
- return ++mLastRow;
- else if (last - 1 == aRow)
- return --mLastRow;
- }
- // Nope. Construct a path to the specified index. This is a little
- // bit better than O(n), because we can skip over subtrees. (So it
- // ends up being approximately linear in the subtree size, instead
- // of the entire view size. But, most of the time, big views are
- // flat. Oh well.)
- iterator result;
- Subtree* current = &mRoot;
- int32_t index = 0;
- result.SetRowIndex(aRow);
- do {
- int32_t subtreeSize;
- Subtree* subtree = GetSubtreeFor(current, index, &subtreeSize);
- if (subtreeSize >= aRow) {
- result.Append(current, index);
- current = subtree;
- index = 0;
- --aRow;
- }
- else {
- ++index;
- aRow -= subtreeSize + 1;
- }
- } while (aRow >= 0);
- mLastRow = result;
- return result;
- }
- nsTreeRows::iterator
- nsTreeRows::FindByResource(nsIRDFResource* aResource)
- {
- // XXX Mmm, scan through the rows one-by-one...
- iterator last = Last();
- iterator iter;
- nsresult rv;
- nsAutoString resourceid;
- bool stringmode = false;
- for (iter = First(); iter != last; ++iter) {
- if (!stringmode) {
- nsCOMPtr<nsIRDFResource> findres;
- rv = iter->mMatch->mResult->GetResource(getter_AddRefs(findres));
- if (NS_FAILED(rv)) return last;
- if (findres == aResource)
- break;
- if (! findres) {
- const char *uri;
- aResource->GetValueConst(&uri);
- CopyUTF8toUTF16(uri, resourceid);
- // set stringmode and fall through
- stringmode = true;
- }
- }
- // additional check because previous block could change stringmode
- if (stringmode) {
- nsAutoString findid;
- rv = iter->mMatch->mResult->GetId(findid);
- if (NS_FAILED(rv)) return last;
- if (resourceid.Equals(findid))
- break;
- }
- }
- return iter;
- }
- nsTreeRows::iterator
- nsTreeRows::Find(nsIXULTemplateResult *aResult)
- {
- // XXX Mmm, scan through the rows one-by-one...
- iterator last = Last();
- iterator iter;
- for (iter = First(); iter != last; ++iter) {
- if (aResult == iter->mMatch->mResult)
- break;
- }
- return iter;
- }
- void
- nsTreeRows::Clear()
- {
- mRoot.Clear();
- InvalidateCachedRow();
- }
- //----------------------------------------------------------------------
- //
- // nsTreeRows::Subtree
- //
- nsTreeRows::Subtree::~Subtree()
- {
- Clear();
- }
- void
- nsTreeRows::Subtree::Clear()
- {
- for (int32_t i = mCount - 1; i >= 0; --i)
- delete mRows[i].mSubtree;
- delete[] mRows;
- mRows = nullptr;
- mCount = mCapacity = mSubtreeSize = 0;
- }
- nsTreeRows::iterator
- nsTreeRows::Subtree::InsertRowAt(nsTemplateMatch* aMatch, int32_t aIndex)
- {
- if (mCount >= mCapacity || aIndex >= mCapacity) {
- int32_t newCapacity = std::max(mCapacity * 2, aIndex + 1);
- Row* newRows = new Row[newCapacity];
- if (! newRows)
- return iterator();
- for (int32_t i = mCount - 1; i >= 0; --i)
- newRows[i] = mRows[i];
- delete[] mRows;
- mRows = newRows;
- mCapacity = newCapacity;
- }
- for (int32_t i = mCount - 1; i >= aIndex; --i)
- mRows[i + 1] = mRows[i];
- mRows[aIndex].mMatch = aMatch;
- mRows[aIndex].mContainerType = eContainerType_Unknown;
- mRows[aIndex].mContainerState = eContainerState_Unknown;
- mRows[aIndex].mContainerFill = eContainerFill_Unknown;
- mRows[aIndex].mSubtree = nullptr;
- ++mCount;
- // Now build an iterator that points to the newly inserted element.
- int32_t rowIndex = 0;
- iterator result;
- result.Push(this, aIndex);
- for ( ; --aIndex >= 0; ++rowIndex) {
- // Account for open subtrees in the absolute row index.
- const Subtree *subtree = mRows[aIndex].mSubtree;
- if (subtree)
- rowIndex += subtree->mSubtreeSize;
- }
- Subtree *subtree = this;
- do {
- // Note that the subtree's size has expanded.
- ++subtree->mSubtreeSize;
- Subtree *parent = subtree->mParent;
- if (! parent)
- break;
- // Account for open subtrees in the absolute row index.
- int32_t count = parent->Count();
- for (aIndex = 0; aIndex < count; ++aIndex, ++rowIndex) {
- const Subtree *child = (*parent)[aIndex].mSubtree;
- if (subtree == child)
- break;
- if (child)
- rowIndex += child->mSubtreeSize;
- }
- NS_ASSERTION(aIndex < count, "couldn't find subtree in parent");
- result.Push(parent, aIndex);
- subtree = parent;
- ++rowIndex; // One for the parent row.
- } while (1);
- result.SetRowIndex(rowIndex);
- return result;
- }
- void
- nsTreeRows::Subtree::RemoveRowAt(int32_t aIndex)
- {
- NS_PRECONDITION(aIndex >= 0 && aIndex < Count(), "bad index");
- if (aIndex < 0 || aIndex >= Count())
- return;
- // How big is the subtree we're going to be removing?
- int32_t subtreeSize = mRows[aIndex].mSubtree
- ? mRows[aIndex].mSubtree->GetSubtreeSize()
- : 0;
- ++subtreeSize;
- delete mRows[aIndex].mSubtree;
- for (int32_t i = aIndex + 1; i < mCount; ++i)
- mRows[i - 1] = mRows[i];
- --mCount;
- for (Subtree* subtree = this; subtree != nullptr; subtree = subtree->mParent)
- subtree->mSubtreeSize -= subtreeSize;
- }
- //----------------------------------------------------------------------
- //
- // nsTreeRows::iterator
- //
- nsTreeRows::iterator::iterator(const iterator& aIterator)
- : mRowIndex(aIterator.mRowIndex),
- mLink(aIterator.mLink)
- {
- }
- nsTreeRows::iterator&
- nsTreeRows::iterator::operator=(const iterator& aIterator)
- {
- mRowIndex = aIterator.mRowIndex;
- mLink = aIterator.mLink;
- return *this;
- }
- void
- nsTreeRows::iterator::Append(Subtree* aParent, int32_t aChildIndex)
- {
- Link *link = mLink.AppendElement();
- if (link) {
- link->mParent = aParent;
- link->mChildIndex = aChildIndex;
- }
- else
- NS_ERROR("out of memory");
- }
- void
- nsTreeRows::iterator::Push(Subtree *aParent, int32_t aChildIndex)
- {
- Link *link = mLink.InsertElementAt(0);
- if (link) {
- link->mParent = aParent;
- link->mChildIndex = aChildIndex;
- }
- else
- NS_ERROR("out of memory");
- }
- bool
- nsTreeRows::iterator::operator==(const iterator& aIterator) const
- {
- if (GetDepth() != aIterator.GetDepth())
- return false;
- if (GetDepth() == 0)
- return true;
- return GetTop() == aIterator.GetTop();
- }
- void
- nsTreeRows::iterator::Next()
- {
- NS_PRECONDITION(GetDepth() > 0, "cannot increment an uninitialized iterator");
- // Increment the absolute row index
- ++mRowIndex;
- 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.
- int32_t 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.
- mLink.SetLength(unfinished + 1);
- }
- // Advance to the next child in this subtree
- ++(GetTop().mChildIndex);
- }
- void
- nsTreeRows::iterator::Prev()
- {
- NS_PRECONDITION(GetDepth() > 0, "cannot increment an uninitialized iterator");
- // Decrement the absolute row index
- --mRowIndex;
- // Move to the previous child in this subtree
- --(GetTop().mChildIndex);
- // Have we exhausted the current subtree?
- 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.
- int32_t 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.
- 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 = GetTop().GetParent();
- int32_t index = GetTop().GetChildIndex();
- Subtree* subtree = (*parent)[index].mSubtree;
- if (subtree && subtree->Count()) {
- do {
- index = subtree->Count() - 1;
- Append(subtree, index);
- parent = subtree;
- subtree = (*parent)[index].mSubtree;
- } while (subtree && subtree->Count());
- }
- }
|