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
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/
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
15 * The Original Code is Mozilla Communicator client code.
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.
23 * Chris Waterson <waterson@netscape.com>
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.
37 * ***** END LICENSE BLOCK ***** */
40 #include "nsTreeRows.h"
43 nsTreeRows::EnsureSubtreeFor(Subtree
* aParent
,
46 Subtree
* subtree
= GetSubtreeFor(aParent
, aChildIndex
);
49 subtree
= aParent
->mRows
[aChildIndex
].mSubtree
= new Subtree(aParent
);
50 InvalidateCachedRow();
57 nsTreeRows::GetSubtreeFor(const Subtree
* aParent
,
59 PRInt32
* aSubtreeSize
)
61 NS_PRECONDITION(aParent
, "no parent");
62 NS_PRECONDITION(aChildIndex
>= 0, "bad child index");
64 Subtree
* result
= nsnull
;
66 if (aChildIndex
< aParent
->mCount
)
67 result
= aParent
->mRows
[aChildIndex
].mSubtree
;
70 *aSubtreeSize
= result
? result
->mSubtreeSize
: 0;
76 nsTreeRows::RemoveSubtreeFor(Subtree
* aParent
, PRInt32 aChildIndex
)
78 NS_PRECONDITION(aParent
, "no parent");
79 NS_PRECONDITION(aChildIndex
>= 0 && aChildIndex
< aParent
->mCount
, "bad child index");
81 Row
& row
= aParent
->mRows
[aChildIndex
];
84 PRInt32 subtreeSize
= row
.mSubtree
->GetSubtreeSize();
87 row
.mSubtree
= nsnull
;
89 for (Subtree
* subtree
= aParent
; subtree
!= nsnull
; subtree
= subtree
->mParent
)
90 subtree
->mSubtreeSize
-= subtreeSize
;
93 InvalidateCachedRow();
100 result
.Append(&mRoot
, 0);
101 result
.SetRowIndex(0);
110 // Build up a path along the rightmost edge of the tree
111 Subtree
* current
= &mRoot
;
112 PRInt32 count
= current
->Count();
114 PRInt32 last
= count
- 1;
115 result
.Append(current
, last
);
116 current
= count
? GetSubtreeFor(current
, last
) : nsnull
;
117 } while (current
&& ((count
= current
->Count()) != 0));
119 // Now, at the bottom rightmost leaf, advance us one off the end.
120 result
.GetTop().mChildIndex
++;
122 // Our row index will be the size of the root subree, plus one.
123 result
.SetRowIndex(mRoot
.GetSubtreeSize() + 1);
129 nsTreeRows::operator[](PRInt32 aRow
)
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 PRInt32 last
= mLastRow
.GetRowIndex();
138 else if (last
+ 1 == aRow
)
140 else if (last
- 1 == aRow
)
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
150 Subtree
* current
= &mRoot
;
153 result
.SetRowIndex(aRow
);
157 Subtree
* subtree
= GetSubtreeFor(current
, index
, &subtreeSize
);
159 if (subtreeSize
>= aRow
) {
160 result
.Append(current
, index
);
167 aRow
-= subtreeSize
+ 1;
176 nsTreeRows::FindByResource(nsIRDFResource
* aResource
)
178 // XXX Mmm, scan through the rows one-by-one...
179 iterator last
= Last();
183 nsAutoString resourceid
;
184 PRBool stringmode
= PR_FALSE
;
186 for (iter
= First(); iter
!= last
; ++iter
) {
188 nsCOMPtr
<nsIRDFResource
> findres
;
189 rv
= iter
->mMatch
->mResult
->GetResource(getter_AddRefs(findres
));
190 if (NS_FAILED(rv
)) return last
;
192 if (findres
== aResource
)
197 aResource
->GetValueConst(&uri
);
198 CopyUTF8toUTF16(uri
, resourceid
);
200 // set stringmode and fall through
201 stringmode
= PR_TRUE
;
205 // additional check because previous block could change stringmode
208 rv
= iter
->mMatch
->mResult
->GetId(findid
);
209 if (NS_FAILED(rv
)) return last
;
211 if (resourceid
.Equals(findid
))
220 nsTreeRows::Find(nsIXULTemplateResult
*aResult
)
222 // XXX Mmm, scan through the rows one-by-one...
223 iterator last
= Last();
226 for (iter
= First(); iter
!= last
; ++iter
) {
227 if (aResult
== iter
->mMatch
->mResult
)
238 InvalidateCachedRow();
241 //----------------------------------------------------------------------
243 // nsTreeRows::Subtree
246 nsTreeRows::Subtree::~Subtree()
252 nsTreeRows::Subtree::Clear()
254 for (PRInt32 i
= mCount
- 1; i
>= 0; --i
)
255 delete mRows
[i
].mSubtree
;
260 mCount
= mCapacity
= mSubtreeSize
= 0;
264 nsTreeRows::Subtree::InsertRowAt(nsTemplateMatch
* aMatch
, PRInt32 aIndex
)
266 if (mCount
>= mCapacity
|| aIndex
>= mCapacity
) {
267 PRInt32 newCapacity
= NS_MAX(mCapacity
* 2, aIndex
+ 1);
268 Row
* newRows
= new Row
[newCapacity
];
272 for (PRInt32 i
= mCount
- 1; i
>= 0; --i
)
273 newRows
[i
] = mRows
[i
];
278 mCapacity
= newCapacity
;
281 for (PRInt32 i
= mCount
- 1; i
>= aIndex
; --i
)
282 mRows
[i
+ 1] = mRows
[i
];
284 mRows
[aIndex
].mMatch
= aMatch
;
285 mRows
[aIndex
].mContainerType
= eContainerType_Unknown
;
286 mRows
[aIndex
].mContainerState
= eContainerState_Unknown
;
287 mRows
[aIndex
].mContainerFill
= eContainerFill_Unknown
;
288 mRows
[aIndex
].mSubtree
= nsnull
;
291 // Now build an iterator that points to the newly inserted element.
292 PRInt32 rowIndex
= 0;
294 result
.Push(this, aIndex
);
296 for ( ; --aIndex
>= 0; ++rowIndex
) {
297 // Account for open subtrees in the absolute row index.
298 const Subtree
*subtree
= mRows
[aIndex
].mSubtree
;
300 rowIndex
+= subtree
->mSubtreeSize
;
303 Subtree
*subtree
= this;
305 // Note that the subtree's size has expanded.
306 ++subtree
->mSubtreeSize
;
308 Subtree
*parent
= subtree
->mParent
;
312 // Account for open subtrees in the absolute row index.
313 PRInt32 count
= parent
->Count();
314 for (aIndex
= 0; aIndex
< count
; ++aIndex
, ++rowIndex
) {
315 const Subtree
*child
= (*parent
)[aIndex
].mSubtree
;
316 if (subtree
== child
)
320 rowIndex
+= child
->mSubtreeSize
;
323 NS_ASSERTION(aIndex
< count
, "couldn't find subtree in parent");
325 result
.Push(parent
, aIndex
);
327 ++rowIndex
; // One for the parent row.
330 result
.SetRowIndex(rowIndex
);
335 nsTreeRows::Subtree::RemoveRowAt(PRInt32 aIndex
)
337 NS_PRECONDITION(aIndex
>= 0 && aIndex
< Count(), "bad index");
338 if (aIndex
< 0 || aIndex
>= Count())
341 // How big is the subtree we're going to be removing?
342 PRInt32 subtreeSize
= mRows
[aIndex
].mSubtree
343 ? mRows
[aIndex
].mSubtree
->GetSubtreeSize()
348 delete mRows
[aIndex
].mSubtree
;
350 for (PRInt32 i
= aIndex
+ 1; i
< mCount
; ++i
)
351 mRows
[i
- 1] = mRows
[i
];
355 for (Subtree
* subtree
= this; subtree
!= nsnull
; subtree
= subtree
->mParent
)
356 subtree
->mSubtreeSize
-= subtreeSize
;
359 //----------------------------------------------------------------------
361 // nsTreeRows::iterator
364 nsTreeRows::iterator::iterator(const iterator
& aIterator
)
365 : mRowIndex(aIterator
.mRowIndex
),
366 mLink(aIterator
.mLink
)
370 nsTreeRows::iterator
&
371 nsTreeRows::iterator::operator=(const iterator
& aIterator
)
373 mRowIndex
= aIterator
.mRowIndex
;
374 mLink
= aIterator
.mLink
;
379 nsTreeRows::iterator::Append(Subtree
* aParent
, PRInt32 aChildIndex
)
381 Link
*link
= mLink
.AppendElement();
383 link
->mParent
= aParent
;
384 link
->mChildIndex
= aChildIndex
;
387 NS_ERROR("out of memory");
391 nsTreeRows::iterator::Push(Subtree
*aParent
, PRInt32 aChildIndex
)
393 Link
*link
= mLink
.InsertElementAt(0);
395 link
->mParent
= aParent
;
396 link
->mChildIndex
= aChildIndex
;
399 NS_ERROR("out of memory");
403 nsTreeRows::iterator::operator==(const iterator
& aIterator
) const
405 if (GetDepth() != aIterator
.GetDepth())
411 return GetTop() == aIterator
.GetTop();
415 nsTreeRows::iterator::Next()
417 NS_PRECONDITION(GetDepth() > 0, "cannot increment an uninitialized iterator");
419 // Increment the absolute row index
422 Link
& top
= GetTop();
424 // Is there a child subtree? If so, descend into the child
426 Subtree
* subtree
= top
.GetRow().mSubtree
;
428 if (subtree
&& subtree
->Count()) {
433 // Have we exhausted the current subtree?
434 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.
439 for (unfinished
= GetDepth() - 2; unfinished
>= 0; --unfinished
) {
440 const Link
& link
= mLink
[unfinished
];
441 if (link
.mChildIndex
< link
.mParent
->Count() - 1)
445 // If there are no unfinished subtrees in the stack, then this
446 // iterator is exhausted. Leave it in the same state that
448 if (unfinished
< 0) {
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 mLink
.SetLength(unfinished
+ 1);
458 // Advance to the next child in this subtree
459 ++(GetTop().mChildIndex
);
463 nsTreeRows::iterator::Prev()
465 NS_PRECONDITION(GetDepth() > 0, "cannot increment an uninitialized iterator");
467 // Decrement the absolute row index
470 // Move to the previous child in this subtree
471 --(GetTop().mChildIndex
);
473 // Have we exhausted the current subtree?
474 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.
479 for (unfinished
= GetDepth() - 2; unfinished
>= 0; --unfinished
) {
480 const Link
& link
= mLink
[unfinished
];
481 if (link
.mChildIndex
>= 0)
485 // If there are no unfinished subtrees in the stack, then this
486 // iterator is exhausted. Leave it in the same state that
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 mLink
.SetLength(unfinished
+ 1);
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 Subtree
* parent
= GetTop().GetParent();
501 PRInt32 index
= GetTop().GetChildIndex();
503 Subtree
* subtree
= (*parent
)[index
].mSubtree
;
505 if (subtree
&& subtree
->Count()) {
507 index
= subtree
->Count() - 1;
508 Append(subtree
, index
);
511 subtree
= (*parent
)[index
].mSubtree
;
512 } while (subtree
&& subtree
->Count());