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 : }
|