Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "nsXULTreeBuilder.h"
7 : #include "nscore.h"
8 : #include "nsError.h"
9 : #include "nsIContent.h"
10 : #include "mozilla/dom/NodeInfo.h"
11 : #include "nsIDOMElement.h"
12 : #include "nsIBoxObject.h"
13 : #include "nsITreeBoxObject.h"
14 : #include "nsITreeSelection.h"
15 : #include "nsITreeColumns.h"
16 : #include "nsTreeUtils.h"
17 : #include "nsIServiceManager.h"
18 : #include "nsReadableUtils.h"
19 : #include "nsQuickSort.h"
20 : #include "nsTemplateRule.h"
21 : #include "nsTemplateMatch.h"
22 : #include "nsTreeColumns.h"
23 : #include "nsGkAtoms.h"
24 : #include "nsXULContentUtils.h"
25 : #include "nsIXULSortService.h"
26 : #include "nsTArray.h"
27 : #include "nsUnicharUtils.h"
28 : #include "nsNameSpaceManager.h"
29 : #include "nsWhitespaceTokenizer.h"
30 : #include "nsTreeContentView.h"
31 : #include "nsIXULStore.h"
32 : #include "mozilla/BinarySearch.h"
33 : #include "mozilla/dom/DataTransfer.h"
34 : #include "mozilla/dom/TreeBoxObject.h"
35 : #include "mozilla/dom/XULTemplateBuilderBinding.h"
36 :
37 : // For security check
38 : #include "nsIDocument.h"
39 :
40 0 : NS_IMPL_ADDREF_INHERITED(nsXULTreeBuilder, nsXULTemplateBuilder)
41 0 : NS_IMPL_RELEASE_INHERITED(nsXULTreeBuilder, nsXULTemplateBuilder)
42 :
43 0 : NS_IMPL_CYCLE_COLLECTION_INHERITED(nsXULTreeBuilder, nsXULTemplateBuilder,
44 : mBoxObject,
45 : mSelection,
46 : mPersistStateStore,
47 : mLocalStore,
48 : mObservers)
49 :
50 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXULTreeBuilder)
51 0 : NS_INTERFACE_MAP_ENTRY(nsIXULTreeBuilder)
52 0 : NS_INTERFACE_MAP_ENTRY(nsITreeView)
53 0 : NS_INTERFACE_MAP_END_INHERITING(nsXULTemplateBuilder)
54 :
55 :
56 0 : nsXULTreeBuilder::nsXULTreeBuilder(Element* aElement)
57 : : nsXULTemplateBuilder(aElement),
58 0 : mSortDirection(eDirection_Natural), mSortHints(0)
59 : {
60 0 : }
61 :
62 0 : nsXULTreeBuilder::~nsXULTreeBuilder()
63 : {
64 0 : }
65 :
66 : JSObject*
67 0 : nsXULTreeBuilder::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
68 : {
69 0 : return XULTreeBuilderBinding::Wrap(aCx, this, aGivenProto);
70 : }
71 :
72 : void
73 0 : nsXULTreeBuilder::Uninit(bool aIsFinal)
74 : {
75 0 : int32_t count = mRows.Count();
76 0 : mRows.Clear();
77 :
78 0 : if (mBoxObject) {
79 0 : mBoxObject->BeginUpdateBatch();
80 0 : mBoxObject->RowCountChanged(0, -count);
81 0 : if (mBoxObject) {
82 0 : mBoxObject->EndUpdateBatch();
83 : }
84 : }
85 :
86 0 : nsXULTemplateBuilder::Uninit(aIsFinal);
87 0 : }
88 :
89 :
90 : //----------------------------------------------------------------------
91 : //
92 : // nsIXULTreeBuilder methods
93 : //
94 :
95 : already_AddRefed<nsIRDFResource>
96 0 : nsXULTreeBuilder::GetResourceAtIndex(int32_t aRowIndex, ErrorResult& aError)
97 : {
98 0 : if (!IsValidRowIndex(aRowIndex)) {
99 0 : aError.Throw(NS_ERROR_INVALID_ARG);
100 0 : return nullptr;
101 : }
102 :
103 0 : nsCOMPtr<nsIRDFResource> result;
104 0 : aError = GetResourceFor(aRowIndex, getter_AddRefs(result));
105 0 : return result.forget();
106 : }
107 :
108 : NS_IMETHODIMP
109 0 : nsXULTreeBuilder::GetResourceAtIndex(int32_t aRowIndex, nsIRDFResource** aResult)
110 : {
111 0 : ErrorResult rv;
112 0 : *aResult = GetResourceAtIndex(aRowIndex, rv).take();
113 0 : return rv.StealNSResult();
114 : }
115 :
116 : int32_t
117 0 : nsXULTreeBuilder::GetIndexOfResource(nsIRDFResource* aResource,
118 : ErrorResult& aError)
119 : {
120 0 : nsTreeRows::iterator iter = mRows.FindByResource(aResource);
121 0 : return iter == mRows.Last() ? -1 : iter.GetRowIndex();
122 : }
123 :
124 : NS_IMETHODIMP
125 0 : nsXULTreeBuilder::GetIndexOfResource(nsIRDFResource* aResource, int32_t* aResult)
126 : {
127 0 : NS_ENSURE_ARG_POINTER(aResource);
128 :
129 0 : ErrorResult rv;
130 0 : *aResult = GetIndexOfResource(aResource, rv);
131 0 : return rv.StealNSResult();
132 : }
133 :
134 : void
135 0 : nsXULTreeBuilder::AddObserver(XULTreeBuilderObserver& aObserver)
136 : {
137 : CallbackObjectHolder<XULTreeBuilderObserver, nsIXULTreeBuilderObserver>
138 0 : holder(&aObserver);
139 0 : mObservers.AppendElement(holder.ToXPCOMCallback());
140 0 : }
141 :
142 : NS_IMETHODIMP
143 0 : nsXULTreeBuilder::AddObserver(nsIXULTreeBuilderObserver* aObserver)
144 : {
145 0 : mObservers.AppendElement(aObserver);
146 0 : return NS_OK;
147 : }
148 :
149 : void
150 0 : nsXULTreeBuilder::RemoveObserver(XULTreeBuilderObserver& aObserver)
151 : {
152 : CallbackObjectHolder<XULTreeBuilderObserver, nsIXULTreeBuilderObserver>
153 0 : holder(&aObserver);
154 0 : nsCOMPtr<nsIXULTreeBuilderObserver> observer(holder.ToXPCOMCallback());
155 0 : mObservers.RemoveElement(observer);
156 0 : }
157 :
158 : NS_IMETHODIMP
159 0 : nsXULTreeBuilder::RemoveObserver(nsIXULTreeBuilderObserver* aObserver)
160 : {
161 0 : mObservers.RemoveElement(aObserver);
162 0 : return NS_OK;
163 : }
164 :
165 : void
166 0 : nsXULTreeBuilder::Sort(Element& aElement)
167 : {
168 0 : if (aElement.AttrValueIs(kNameSpaceID_None, nsGkAtoms::sortLocked,
169 : nsGkAtoms::_true, eCaseMatters)) {
170 0 : return;
171 : }
172 :
173 0 : nsAutoString sort;
174 0 : aElement.GetAttr(kNameSpaceID_None, nsGkAtoms::sort, sort);
175 :
176 0 : if (sort.IsEmpty()) {
177 0 : return;
178 : }
179 :
180 : // Grab the new sort variable
181 0 : mSortVariable = NS_Atomize(sort);
182 :
183 0 : nsAutoString hints;
184 0 : aElement.GetAttr(kNameSpaceID_None, nsGkAtoms::sorthints, hints);
185 :
186 0 : bool hasNaturalState = true;
187 0 : nsWhitespaceTokenizer tokenizer(hints);
188 0 : while (tokenizer.hasMoreTokens()) {
189 0 : const nsDependentSubstring& token(tokenizer.nextToken());
190 0 : if (token.EqualsLiteral("comparecase"))
191 0 : mSortHints |= nsIXULSortService::SORT_COMPARECASE;
192 0 : else if (token.EqualsLiteral("integer"))
193 0 : mSortHints |= nsIXULSortService::SORT_INTEGER;
194 0 : else if (token.EqualsLiteral("twostate"))
195 0 : hasNaturalState = false;
196 : }
197 :
198 : // Cycle the sort direction
199 0 : nsAutoString dir;
200 0 : aElement.GetAttr(kNameSpaceID_None, nsGkAtoms::sortDirection, dir);
201 :
202 0 : if (dir.EqualsLiteral("ascending")) {
203 0 : dir.AssignLiteral("descending");
204 0 : mSortDirection = eDirection_Descending;
205 : }
206 0 : else if (hasNaturalState && dir.EqualsLiteral("descending")) {
207 0 : dir.AssignLiteral("natural");
208 0 : mSortDirection = eDirection_Natural;
209 : }
210 : else {
211 0 : dir.AssignLiteral("ascending");
212 0 : mSortDirection = eDirection_Ascending;
213 : }
214 :
215 : // Sort it.
216 0 : SortSubtree(mRows.GetRoot());
217 0 : mRows.InvalidateCachedRow();
218 0 : if (mBoxObject)
219 0 : mBoxObject->Invalidate();
220 :
221 0 : nsTreeUtils::UpdateSortIndicators(&aElement, dir);
222 : }
223 :
224 : NS_IMETHODIMP
225 0 : nsXULTreeBuilder::Sort(nsIDOMElement* aElement)
226 : {
227 0 : nsCOMPtr<Element> header = do_QueryInterface(aElement);
228 0 : if (!header) {
229 0 : return NS_ERROR_FAILURE;
230 : }
231 0 : Sort(*header);
232 0 : return NS_OK;
233 : }
234 :
235 : //----------------------------------------------------------------------
236 : //
237 : // nsITreeView methods
238 : //
239 :
240 : NS_IMETHODIMP
241 0 : nsXULTreeBuilder::GetRowCount(int32_t* aRowCount)
242 : {
243 0 : *aRowCount = RowCount();
244 0 : return NS_OK;
245 : }
246 :
247 : NS_IMETHODIMP
248 0 : nsXULTreeBuilder::GetSelection(nsITreeSelection** aSelection)
249 : {
250 0 : NS_IF_ADDREF(*aSelection = GetSelection());
251 0 : return NS_OK;
252 : }
253 :
254 : void
255 0 : nsXULTreeBuilder::SetSelection(nsITreeSelection* aSelection,
256 : ErrorResult& aError)
257 : {
258 0 : if (aSelection && !nsTreeContentView::CanTrustTreeSelection(aSelection)) {
259 0 : aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
260 0 : return;
261 : }
262 :
263 0 : mSelection = aSelection;
264 : }
265 :
266 : NS_IMETHODIMP
267 0 : nsXULTreeBuilder::SetSelection(nsITreeSelection* aSelection)
268 : {
269 0 : ErrorResult rv;
270 0 : SetSelection(aSelection, rv);
271 0 : return rv.StealNSResult();
272 : }
273 :
274 : void
275 0 : nsXULTreeBuilder::GetRowProperties(int32_t aRow, nsAString& aProperties,
276 : ErrorResult& aError)
277 : {
278 0 : if (!IsValidRowIndex(aRow)) {
279 0 : aError.Throw(NS_ERROR_INVALID_ARG);
280 0 : return;
281 : }
282 :
283 0 : nsCOMPtr<nsIContent> row;
284 0 : GetTemplateActionRowFor(aRow, getter_AddRefs(row));
285 0 : if (row) {
286 0 : nsAutoString raw;
287 0 : row->GetAttr(kNameSpaceID_None, nsGkAtoms::properties, raw);
288 :
289 0 : if (!raw.IsEmpty()) {
290 0 : SubstituteText(mRows[aRow]->mMatch->mResult, raw, aProperties);
291 : }
292 : }
293 : }
294 :
295 : NS_IMETHODIMP
296 0 : nsXULTreeBuilder::GetRowProperties(int32_t aIndex, nsAString& aProps)
297 : {
298 0 : ErrorResult rv;
299 0 : GetRowProperties(aIndex, aProps, rv);
300 0 : return rv.StealNSResult();
301 : }
302 :
303 : void
304 0 : nsXULTreeBuilder::GetCellProperties(int32_t aRow, nsTreeColumn& aColumn,
305 : nsAString& aProperties, ErrorResult& aError)
306 : {
307 0 : if (!IsValidRowIndex(aRow)) {
308 0 : aError.Throw(NS_ERROR_INVALID_ARG);
309 0 : return;
310 : }
311 :
312 0 : nsIContent* cell = GetTemplateActionCellFor(aRow, aColumn);
313 0 : if (cell) {
314 0 : nsAutoString raw;
315 0 : cell->GetAttr(kNameSpaceID_None, nsGkAtoms::properties, raw);
316 :
317 0 : if (!raw.IsEmpty()) {
318 0 : SubstituteText(mRows[aRow]->mMatch->mResult, raw, aProperties);
319 : }
320 : }
321 : }
322 :
323 : NS_IMETHODIMP
324 0 : nsXULTreeBuilder::GetCellProperties(int32_t aRow, nsITreeColumn* aCol,
325 : nsAString& aProps)
326 : {
327 0 : RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
328 0 : NS_ENSURE_ARG(col);
329 :
330 0 : ErrorResult rv;
331 0 : GetCellProperties(aRow, *col, aProps, rv);
332 0 : return rv.StealNSResult();
333 : }
334 :
335 : NS_IMETHODIMP
336 0 : nsXULTreeBuilder::GetColumnProperties(nsITreeColumn* aCol, nsAString& aProps)
337 : {
338 0 : NS_ENSURE_ARG_POINTER(aCol);
339 : // XXX sortactive fu
340 0 : return NS_OK;
341 : }
342 :
343 : bool
344 0 : nsXULTreeBuilder::IsContainer(int32_t aRow, ErrorResult& aError)
345 : {
346 0 : if (!IsValidRowIndex(aRow)) {
347 0 : aError.Throw(NS_ERROR_INVALID_ARG);
348 0 : return false;
349 : }
350 :
351 0 : nsTreeRows::iterator iter = mRows[aRow];
352 :
353 : bool isContainer;
354 0 : iter->mMatch->mResult->GetIsContainer(&isContainer);
355 :
356 0 : iter->mContainerType = isContainer
357 0 : ? nsTreeRows::eContainerType_Container
358 : : nsTreeRows::eContainerType_Noncontainer;
359 :
360 0 : return iter->mContainerType == nsTreeRows::eContainerType_Container;
361 : }
362 :
363 : NS_IMETHODIMP
364 0 : nsXULTreeBuilder::IsContainer(int32_t aIndex, bool* aResult)
365 : {
366 0 : ErrorResult rv;
367 0 : *aResult = IsContainer(aIndex, rv);
368 0 : return rv.StealNSResult();
369 : }
370 :
371 : bool
372 0 : nsXULTreeBuilder::IsContainerOpen(int32_t aRow, ErrorResult& aError)
373 : {
374 0 : if (!IsValidRowIndex(aRow)) {
375 0 : aError.Throw(NS_ERROR_INVALID_ARG);
376 0 : return false;
377 : }
378 :
379 0 : nsTreeRows::iterator iter = mRows[aRow];
380 :
381 0 : if (iter->mContainerState == nsTreeRows::eContainerState_Unknown) {
382 0 : bool isOpen = IsContainerOpen(iter->mMatch->mResult);
383 :
384 0 : iter->mContainerState = isOpen
385 0 : ? nsTreeRows::eContainerState_Open
386 : : nsTreeRows::eContainerState_Closed;
387 : }
388 :
389 0 : return iter->mContainerState == nsTreeRows::eContainerState_Open;
390 : }
391 :
392 : NS_IMETHODIMP
393 0 : nsXULTreeBuilder::IsContainerOpen(int32_t aIndex, bool* aOpen)
394 : {
395 0 : ErrorResult rv;
396 0 : *aOpen = IsContainerOpen(aIndex, rv);
397 0 : return rv.StealNSResult();
398 : }
399 :
400 : bool
401 0 : nsXULTreeBuilder::IsContainerEmpty(int32_t aRow, ErrorResult& aError)
402 : {
403 0 : if (!IsValidRowIndex(aRow)) {
404 0 : aError.Throw(NS_ERROR_INVALID_ARG);
405 0 : return false;
406 : }
407 :
408 0 : nsTreeRows::iterator iter = mRows[aRow];
409 0 : NS_ASSERTION(iter->mContainerType == nsTreeRows::eContainerType_Container,
410 : "asking for empty state on non-container");
411 :
412 : // if recursion is disabled, pretend that the container is empty. This
413 : // ensures that folders are still displayed as such, yet won't display
414 : // their children
415 0 : if ((mFlags & eDontRecurse) && (iter->mMatch->mResult != mRootResult)) {
416 0 : return true;
417 : }
418 :
419 0 : if (iter->mContainerFill == nsTreeRows::eContainerFill_Unknown) {
420 : bool isEmpty;
421 0 : iter->mMatch->mResult->GetIsEmpty(&isEmpty);
422 :
423 0 : iter->mContainerFill = isEmpty
424 0 : ? nsTreeRows::eContainerFill_Empty
425 : : nsTreeRows::eContainerFill_Nonempty;
426 : }
427 :
428 0 : return iter->mContainerFill == nsTreeRows::eContainerFill_Empty;
429 : }
430 :
431 : NS_IMETHODIMP
432 0 : nsXULTreeBuilder::IsContainerEmpty(int32_t aIndex, bool* aResult)
433 : {
434 0 : ErrorResult rv;
435 0 : *aResult = IsContainerEmpty(aIndex, rv);
436 0 : return rv.StealNSResult();
437 : }
438 :
439 : bool
440 0 : nsXULTreeBuilder::IsSeparator(int32_t aRow, ErrorResult& aError)
441 : {
442 0 : if (!IsValidRowIndex(aRow)) {
443 0 : aError.Throw(NS_ERROR_INVALID_ARG);
444 0 : return false;
445 : }
446 :
447 0 : nsAutoString type;
448 0 : nsTreeRows::Row& row = *(mRows[aRow]);
449 0 : row.mMatch->mResult->GetType(type);
450 :
451 0 : return type.EqualsLiteral("separator");
452 : }
453 :
454 : NS_IMETHODIMP
455 0 : nsXULTreeBuilder::IsSeparator(int32_t aIndex, bool* aResult)
456 : {
457 0 : ErrorResult rv;
458 0 : *aResult = IsSeparator(aIndex, rv);
459 0 : return rv.StealNSResult();
460 : }
461 :
462 : int32_t
463 0 : nsXULTreeBuilder::GetParentIndex(int32_t aRow, ErrorResult& aError)
464 : {
465 0 : if (!IsValidRowIndex(aRow)) {
466 0 : aError.Throw(NS_ERROR_INVALID_ARG);
467 0 : return -1;
468 : }
469 :
470 : // Construct a path to the row
471 0 : nsTreeRows::iterator iter = mRows[aRow];
472 :
473 : // The parent of the row will be at the top of the path
474 0 : nsTreeRows::Subtree* parent = iter.GetParent();
475 :
476 : // Now walk through our previous siblings, subtracting off each
477 : // one's subtree size
478 0 : int32_t index = iter.GetChildIndex();
479 0 : while (--index >= 0)
480 0 : aRow -= mRows.GetSubtreeSizeFor(parent, index) + 1;
481 :
482 : // Now the parent's index will be the first row's index, less one.
483 0 : return aRow - 1;
484 : }
485 :
486 : NS_IMETHODIMP
487 0 : nsXULTreeBuilder::GetParentIndex(int32_t aRowIndex, int32_t* aResult)
488 : {
489 0 : ErrorResult rv;
490 0 : *aResult = GetParentIndex(aRowIndex, rv);
491 0 : return rv.StealNSResult();
492 : }
493 :
494 : bool
495 0 : nsXULTreeBuilder::HasNextSibling(int32_t aRow, int32_t aAfterIndex,
496 : ErrorResult& aError)
497 : {
498 0 : if (!IsValidRowIndex(aRow)) {
499 0 : aError.Throw(NS_ERROR_INVALID_ARG);
500 0 : return false;
501 : }
502 :
503 : // Construct a path to the row
504 0 : nsTreeRows::iterator iter = mRows[aRow];
505 :
506 : // The parent of the row will be at the top of the path
507 0 : nsTreeRows::Subtree* parent = iter.GetParent();
508 :
509 : // We have a next sibling if the child is not the last in the
510 : // subtree.
511 0 : return iter.GetChildIndex() != parent->Count() - 1;
512 : }
513 :
514 : NS_IMETHODIMP
515 0 : nsXULTreeBuilder::HasNextSibling(int32_t aRowIndex, int32_t aAfterIndex, bool* aResult)
516 : {
517 0 : ErrorResult rv;
518 0 : *aResult = HasNextSibling(aRowIndex, aAfterIndex, rv);
519 0 : return rv.StealNSResult();
520 : }
521 :
522 : int32_t
523 0 : nsXULTreeBuilder::GetLevel(int32_t aRow, ErrorResult& aError)
524 : {
525 0 : if (!IsValidRowIndex(aRow)) {
526 0 : aError.Throw(NS_ERROR_INVALID_ARG);
527 0 : return -1;
528 : }
529 :
530 : // Construct a path to the row; the ``level'' is the path length
531 : // less one.
532 0 : nsTreeRows::iterator iter = mRows[aRow];
533 0 : return iter.GetDepth() - 1;
534 : }
535 :
536 : NS_IMETHODIMP
537 0 : nsXULTreeBuilder::GetLevel(int32_t aRowIndex, int32_t* aResult)
538 : {
539 0 : ErrorResult rv;
540 0 : *aResult = GetLevel(aRowIndex, rv);
541 0 : return rv.StealNSResult();
542 : }
543 :
544 : void
545 0 : nsXULTreeBuilder::GetImageSrc(int32_t aRow, nsTreeColumn& aColumn,
546 : nsAString& aSrc, ErrorResult& aError)
547 : {
548 0 : if (!IsValidRowIndex(aRow)) {
549 0 : aError.Throw(NS_ERROR_INVALID_ARG);
550 0 : return;
551 : }
552 :
553 : // Find the <cell> that corresponds to the column we want.
554 0 : nsIContent* cell = GetTemplateActionCellFor(aRow, aColumn);
555 0 : if (cell) {
556 0 : nsAutoString raw;
557 0 : cell->GetAttr(kNameSpaceID_None, nsGkAtoms::src, raw);
558 :
559 0 : SubstituteText(mRows[aRow]->mMatch->mResult, raw, aSrc);
560 : } else {
561 0 : aSrc.Truncate();
562 : }
563 : }
564 :
565 : NS_IMETHODIMP
566 0 : nsXULTreeBuilder::GetImageSrc(int32_t aRow, nsITreeColumn* aCol, nsAString& aResult)
567 : {
568 0 : RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
569 0 : NS_ENSURE_ARG(col);
570 :
571 0 : ErrorResult rv;
572 0 : GetImageSrc(aRow, *col, aResult, rv);
573 0 : return rv.StealNSResult();
574 : }
575 :
576 : int32_t
577 0 : nsXULTreeBuilder::GetProgressMode(int32_t aRow, nsTreeColumn& aColumn,
578 : ErrorResult& aError)
579 : {
580 0 : if (!IsValidRowIndex(aRow)) {
581 0 : aError.Throw(NS_ERROR_INVALID_ARG);
582 0 : return -1;
583 : }
584 :
585 : // Find the <cell> that corresponds to the column we want.
586 0 : nsIContent* cell = GetTemplateActionCellFor(aRow, aColumn);
587 0 : if (cell) {
588 0 : nsAutoString raw;
589 0 : cell->GetAttr(kNameSpaceID_None, nsGkAtoms::mode, raw);
590 :
591 0 : nsAutoString mode;
592 0 : SubstituteText(mRows[aRow]->mMatch->mResult, raw, mode);
593 :
594 0 : if (mode.EqualsLiteral("normal")) {
595 0 : return nsITreeView::PROGRESS_NORMAL;
596 : }
597 :
598 0 : if (mode.EqualsLiteral("undetermined")) {
599 0 : return nsITreeView::PROGRESS_UNDETERMINED;
600 : }
601 : }
602 :
603 0 : return nsITreeView::PROGRESS_NONE;
604 : }
605 :
606 : NS_IMETHODIMP
607 0 : nsXULTreeBuilder::GetProgressMode(int32_t aRow, nsITreeColumn* aCol, int32_t* aResult)
608 : {
609 0 : RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
610 0 : NS_ENSURE_ARG(col);
611 :
612 0 : ErrorResult rv;
613 0 : *aResult = GetProgressMode(aRow, *col, rv);
614 0 : return rv.StealNSResult();
615 : }
616 :
617 : void
618 0 : nsXULTreeBuilder::GetCellValue(int32_t aRow, nsTreeColumn& aColumn,
619 : nsAString& aValue, ErrorResult& aError)
620 : {
621 0 : if (!IsValidRowIndex(aRow)) {
622 0 : aError.Throw(NS_ERROR_INVALID_ARG);
623 0 : return;
624 : }
625 :
626 : // Find the <cell> that corresponds to the column we want.
627 0 : nsIContent* cell = GetTemplateActionCellFor(aRow, aColumn);
628 0 : if (cell) {
629 0 : nsAutoString raw;
630 0 : cell->GetAttr(kNameSpaceID_None, nsGkAtoms::value, raw);
631 :
632 0 : SubstituteText(mRows[aRow]->mMatch->mResult, raw, aValue);
633 : } else {
634 0 : aValue.Truncate();
635 : }
636 : }
637 :
638 : NS_IMETHODIMP
639 0 : nsXULTreeBuilder::GetCellValue(int32_t aRow, nsITreeColumn* aCol, nsAString& aResult)
640 : {
641 0 : RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
642 0 : NS_ENSURE_ARG(col);
643 :
644 0 : ErrorResult rv;
645 0 : GetCellValue(aRow, *col, aResult, rv);
646 0 : return rv.StealNSResult();
647 : }
648 :
649 : void
650 0 : nsXULTreeBuilder::GetCellText(int32_t aRow, nsTreeColumn& aColumn,
651 : nsAString& aText, ErrorResult& aError)
652 : {
653 0 : if (!IsValidRowIndex(aRow)) {
654 0 : aError.Throw(NS_ERROR_INVALID_ARG);
655 0 : return;
656 : }
657 :
658 : // Find the <cell> that corresponds to the column we want.
659 0 : nsIContent* cell = GetTemplateActionCellFor(aRow, aColumn);
660 0 : if (cell) {
661 0 : nsAutoString raw;
662 0 : cell->GetAttr(kNameSpaceID_None, nsGkAtoms::label, raw);
663 :
664 0 : SubstituteText(mRows[aRow]->mMatch->mResult, raw, aText);
665 : } else {
666 0 : aText.Truncate();
667 : }
668 : }
669 :
670 : NS_IMETHODIMP
671 0 : nsXULTreeBuilder::GetCellText(int32_t aRow, nsITreeColumn* aCol, nsAString& aResult)
672 : {
673 0 : RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
674 0 : NS_ENSURE_ARG(col);
675 :
676 0 : ErrorResult rv;
677 0 : GetCellText(aRow, *col, aResult, rv);
678 0 : return rv.StealNSResult();
679 : }
680 :
681 : void
682 0 : nsXULTreeBuilder::SetTree(TreeBoxObject* aTree, ErrorResult& aError)
683 : {
684 0 : aError = SetTree(aTree);
685 0 : }
686 :
687 : NS_IMETHODIMP
688 0 : nsXULTreeBuilder::SetTree(nsITreeBoxObject* aTree)
689 : {
690 0 : mBoxObject = aTree;
691 :
692 : // If this is teardown time, then we're done.
693 0 : if (!mBoxObject) {
694 0 : Uninit(false);
695 0 : return NS_OK;
696 : }
697 0 : NS_ENSURE_TRUE(mRoot, NS_ERROR_NOT_INITIALIZED);
698 :
699 : // Only use the XUL store if the root's principal is trusted.
700 0 : bool isTrusted = false;
701 0 : nsresult rv = IsSystemPrincipal(mRoot->NodePrincipal(), &isTrusted);
702 0 : if (NS_SUCCEEDED(rv) && isTrusted) {
703 0 : mLocalStore = do_GetService("@mozilla.org/xul/xulstore;1");
704 0 : if(NS_WARN_IF(!mLocalStore)){
705 0 : return NS_ERROR_NOT_INITIALIZED;
706 : }
707 : }
708 :
709 0 : Rebuild();
710 :
711 0 : EnsureSortVariables();
712 0 : if (mSortVariable)
713 0 : SortSubtree(mRows.GetRoot());
714 :
715 0 : return NS_OK;
716 : }
717 :
718 : void
719 0 : nsXULTreeBuilder::ToggleOpenState(int32_t aRow, ErrorResult& aError)
720 : {
721 0 : if (!IsValidRowIndex(aRow)) {
722 0 : aError.Throw(NS_ERROR_INVALID_ARG);
723 0 : return;
724 : }
725 :
726 0 : nsIXULTemplateResult* result = mRows[aRow]->mMatch->mResult;
727 0 : if (!result) {
728 0 : aError.Throw(NS_ERROR_FAILURE);
729 0 : return;
730 : }
731 :
732 0 : if (mFlags & eDontRecurse) {
733 0 : return;
734 : }
735 :
736 0 : if (result && result != mRootResult) {
737 : // don't open containers if child processing isn't allowed
738 : bool mayProcessChildren;
739 0 : aError = result->GetMayProcessChildren(&mayProcessChildren);
740 0 : if (aError.Failed() || !mayProcessChildren) {
741 0 : return;
742 : }
743 : }
744 :
745 0 : uint32_t count = mObservers.Length();
746 0 : for (uint32_t i = 0; i < count; ++i) {
747 0 : nsCOMPtr<nsIXULTreeBuilderObserver> observer = mObservers.SafeElementAt(i);
748 0 : if (observer)
749 0 : observer->OnToggleOpenState(aRow);
750 : }
751 :
752 0 : if (mLocalStore && mRoot) {
753 : bool isOpen;
754 0 : IsContainerOpen(aRow, &isOpen);
755 :
756 0 : nsIDocument* doc = mRoot->GetComposedDoc();
757 0 : if (!doc) {
758 0 : aError.Throw(NS_ERROR_FAILURE);
759 0 : return;
760 : }
761 :
762 0 : nsIURI* docURI = doc->GetDocumentURI();
763 0 : nsTreeRows::Row& row = *(mRows[aRow]);
764 0 : nsAutoString nodeid;
765 0 : aError = row.mMatch->mResult->GetId(nodeid);
766 0 : if (aError.Failed()) {
767 0 : return;
768 : }
769 :
770 0 : nsAutoCString utf8uri;
771 0 : aError = docURI->GetSpec(utf8uri);
772 0 : if (NS_WARN_IF(aError.Failed())) {
773 0 : return;
774 : }
775 0 : NS_ConvertUTF8toUTF16 uri(utf8uri);
776 :
777 0 : if (isOpen) {
778 0 : mLocalStore->RemoveValue(uri, nodeid, NS_LITERAL_STRING("open"));
779 0 : CloseContainer(aRow);
780 : } else {
781 0 : mLocalStore->SetValue(uri, nodeid, NS_LITERAL_STRING("open"),
782 0 : NS_LITERAL_STRING("true"));
783 :
784 0 : OpenContainer(aRow, result);
785 : }
786 : }
787 : }
788 :
789 : NS_IMETHODIMP
790 0 : nsXULTreeBuilder::ToggleOpenState(int32_t aIndex)
791 : {
792 0 : ErrorResult rv;
793 0 : ToggleOpenState(aIndex, rv);
794 0 : return rv.StealNSResult();
795 : }
796 :
797 : void
798 0 : nsXULTreeBuilder::CycleHeader(nsTreeColumn& aColumn, ErrorResult& aError)
799 : {
800 0 : nsCOMPtr<nsIDOMElement> element;
801 0 : aColumn.GetElement(getter_AddRefs(element));
802 :
803 0 : nsAutoString id;
804 0 : aColumn.GetId(id);
805 :
806 0 : uint32_t count = mObservers.Length();
807 0 : for (uint32_t i = 0; i < count; ++i) {
808 0 : nsCOMPtr<nsIXULTreeBuilderObserver> observer = mObservers.SafeElementAt(i);
809 0 : if (observer)
810 0 : observer->OnCycleHeader(id.get(), element);
811 : }
812 :
813 0 : aError = Sort(element);
814 0 : }
815 :
816 : NS_IMETHODIMP
817 0 : nsXULTreeBuilder::CycleHeader(nsITreeColumn* aCol)
818 : {
819 0 : RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
820 0 : NS_ENSURE_ARG(col);
821 :
822 0 : ErrorResult rv;
823 0 : CycleHeader(*col, rv);
824 0 : return rv.StealNSResult();
825 : }
826 :
827 : NS_IMETHODIMP
828 0 : nsXULTreeBuilder::SelectionChanged()
829 : {
830 0 : uint32_t count = mObservers.Length();
831 0 : for (uint32_t i = 0; i < count; ++i) {
832 0 : nsCOMPtr<nsIXULTreeBuilderObserver> observer = mObservers.SafeElementAt(i);
833 0 : if (observer)
834 0 : observer->OnSelectionChanged();
835 : }
836 :
837 0 : return NS_OK;
838 : }
839 :
840 : void
841 0 : nsXULTreeBuilder::CycleCell(int32_t aRow, nsTreeColumn& aColumn)
842 : {
843 0 : nsAutoString id;
844 0 : aColumn.GetId(id);
845 :
846 0 : uint32_t count = mObservers.Length();
847 0 : for (uint32_t i = 0; i < count; ++i) {
848 0 : nsCOMPtr<nsIXULTreeBuilderObserver> observer = mObservers.SafeElementAt(i);
849 0 : if (observer)
850 0 : observer->OnCycleCell(aRow, id.get());
851 : }
852 0 : }
853 :
854 : NS_IMETHODIMP
855 0 : nsXULTreeBuilder::CycleCell(int32_t aRow, nsITreeColumn* aCol)
856 : {
857 0 : RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
858 0 : NS_ENSURE_ARG(col);
859 :
860 0 : CycleCell(aRow, *col);
861 0 : return NS_OK;
862 : }
863 :
864 : bool
865 0 : nsXULTreeBuilder::IsEditable(int32_t aRow, nsTreeColumn& aColumn,
866 : ErrorResult& aError)
867 : {
868 0 : if (!IsValidRowIndex(aRow)) {
869 0 : aError.Throw(NS_ERROR_INVALID_ARG);
870 0 : return false;
871 : }
872 :
873 : // Find the <cell> that corresponds to the column we want.
874 0 : nsIContent* cell = GetTemplateActionCellFor(aRow, aColumn);
875 0 : if (!cell) {
876 0 : return true;
877 : }
878 :
879 0 : nsAutoString raw;
880 0 : cell->GetAttr(kNameSpaceID_None, nsGkAtoms::editable, raw);
881 :
882 0 : nsAutoString editable;
883 0 : SubstituteText(mRows[aRow]->mMatch->mResult, raw, editable);
884 :
885 0 : return !editable.EqualsLiteral("false");
886 : }
887 :
888 : NS_IMETHODIMP
889 0 : nsXULTreeBuilder::IsEditable(int32_t aRow, nsITreeColumn* aCol, bool* _retval)
890 : {
891 0 : RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
892 0 : NS_ENSURE_ARG(col);
893 :
894 0 : ErrorResult rv;
895 0 : *_retval = IsEditable(aRow, *col, rv);
896 0 : return rv.StealNSResult();
897 : }
898 :
899 : bool
900 0 : nsXULTreeBuilder::IsSelectable(int32_t aRow, nsTreeColumn& aColumn,
901 : ErrorResult& aError)
902 : {
903 0 : if (!IsValidRowIndex(aRow)) {
904 0 : aError.Throw(NS_ERROR_INVALID_ARG);
905 0 : return false;
906 : }
907 :
908 : // Find the <cell> that corresponds to the column we want.
909 0 : nsIContent* cell = GetTemplateActionCellFor(aRow, aColumn);
910 0 : if (!cell) {
911 0 : return true;
912 : }
913 :
914 0 : nsAutoString raw;
915 0 : cell->GetAttr(kNameSpaceID_None, nsGkAtoms::selectable, raw);
916 :
917 0 : nsAutoString selectable;
918 0 : SubstituteText(mRows[aRow]->mMatch->mResult, raw, selectable);
919 :
920 0 : return !selectable.EqualsLiteral("false");
921 : }
922 :
923 : NS_IMETHODIMP
924 0 : nsXULTreeBuilder::IsSelectable(int32_t aRow, nsITreeColumn* aCol, bool* _retval)
925 : {
926 0 : RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
927 0 : NS_ENSURE_ARG(col);
928 :
929 0 : ErrorResult rv;
930 0 : *_retval = IsSelectable(aRow, *col, rv);
931 0 : return rv.StealNSResult();
932 : }
933 :
934 : NS_IMETHODIMP
935 0 : nsXULTreeBuilder::SetCellValue(int32_t aRow, nsITreeColumn* aCol, const nsAString& aValue)
936 : {
937 0 : NS_ENSURE_ARG_POINTER(aCol);
938 0 : return NS_OK;
939 : }
940 :
941 : NS_IMETHODIMP
942 0 : nsXULTreeBuilder::SetCellText(int32_t aRow, nsITreeColumn* aCol, const nsAString& aValue)
943 : {
944 0 : NS_ENSURE_ARG_POINTER(aCol);
945 0 : return NS_OK;
946 : }
947 :
948 : void
949 0 : nsXULTreeBuilder::PerformAction(const nsAString& aAction)
950 : {
951 0 : uint32_t count = mObservers.Length();
952 0 : for (uint32_t i = 0; i < count; ++i) {
953 0 : nsCOMPtr<nsIXULTreeBuilderObserver> observer = mObservers.SafeElementAt(i);
954 0 : if (observer) {
955 0 : observer->OnPerformAction(PromiseFlatString(aAction).get());
956 : }
957 : }
958 0 : }
959 :
960 : NS_IMETHODIMP
961 0 : nsXULTreeBuilder::PerformAction(const char16_t* aAction)
962 : {
963 0 : PerformAction(aAction ? nsDependentString(aAction) : EmptyString());
964 :
965 0 : return NS_OK;
966 : }
967 :
968 : void
969 0 : nsXULTreeBuilder::PerformActionOnRow(const nsAString& aAction, int32_t aRow)
970 : {
971 0 : uint32_t count = mObservers.Length();
972 0 : for (uint32_t i = 0; i < count; ++i) {
973 0 : nsCOMPtr<nsIXULTreeBuilderObserver> observer = mObservers.SafeElementAt(i);
974 0 : if (observer) {
975 0 : observer->OnPerformActionOnRow(PromiseFlatString(aAction).get(), aRow);
976 : }
977 : }
978 0 : }
979 :
980 : NS_IMETHODIMP
981 0 : nsXULTreeBuilder::PerformActionOnRow(const char16_t* aAction, int32_t aRow)
982 : {
983 0 : PerformActionOnRow(aAction ? nsDependentString(aAction) : EmptyString(), aRow);
984 :
985 0 : return NS_OK;
986 : }
987 :
988 : void
989 0 : nsXULTreeBuilder::PerformActionOnCell(const nsAString& aAction, int32_t aRow,
990 : nsTreeColumn& aColumn)
991 : {
992 0 : nsAutoString id;
993 0 : aColumn.GetId(id);
994 :
995 0 : uint32_t count = mObservers.Length();
996 0 : for (uint32_t i = 0; i < count; ++i) {
997 0 : nsCOMPtr<nsIXULTreeBuilderObserver> observer = mObservers.SafeElementAt(i);
998 0 : if (observer) {
999 0 : observer->OnPerformActionOnCell(PromiseFlatString(aAction).get(), aRow, id.get());
1000 : }
1001 : }
1002 0 : }
1003 :
1004 : NS_IMETHODIMP
1005 0 : nsXULTreeBuilder::PerformActionOnCell(const char16_t* aAction, int32_t aRow, nsITreeColumn* aCol)
1006 : {
1007 0 : RefPtr<nsTreeColumn> col = nsTreeColumn::From(aCol);
1008 0 : NS_ENSURE_ARG(col);
1009 :
1010 0 : PerformActionOnCell(aAction ? nsDependentString(aAction) : EmptyString(), aRow, *col);
1011 :
1012 0 : return NS_OK;
1013 : }
1014 :
1015 :
1016 : void
1017 0 : nsXULTreeBuilder::NodeWillBeDestroyed(const nsINode* aNode)
1018 : {
1019 0 : nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
1020 0 : mObservers.Clear();
1021 :
1022 0 : nsXULTemplateBuilder::NodeWillBeDestroyed(aNode);
1023 0 : }
1024 :
1025 : bool
1026 0 : nsXULTreeBuilder::HasGeneratedContent(nsIRDFResource* aResource,
1027 : const nsAString& aTag,
1028 : ErrorResult& aError)
1029 : {
1030 0 : if (!aResource) {
1031 0 : aError.Throw(NS_ERROR_INVALID_POINTER);
1032 0 : return false;
1033 : }
1034 :
1035 0 : if (!mRootResult) {
1036 0 : return false;
1037 : }
1038 :
1039 0 : nsCOMPtr<nsIRDFResource> rootresource;
1040 0 : aError = mRootResult->GetResource(getter_AddRefs(rootresource));
1041 0 : if (aError.Failed()) {
1042 0 : return false;
1043 : }
1044 :
1045 0 : return aResource == rootresource ||
1046 0 : mRows.FindByResource(aResource) != mRows.Last();
1047 : }
1048 :
1049 : bool
1050 0 : nsXULTreeBuilder::GetInsertionLocations(nsIXULTemplateResult* aResult,
1051 : nsCOMArray<nsIContent>** aLocations)
1052 : {
1053 0 : *aLocations = nullptr;
1054 :
1055 : // Get the reference point and check if it is an open container. Rows
1056 : // should not be generated otherwise.
1057 :
1058 0 : nsAutoString ref;
1059 0 : nsresult rv = aResult->GetBindingFor(mRefVariable, ref);
1060 0 : if (NS_FAILED(rv) || ref.IsEmpty())
1061 0 : return false;
1062 :
1063 0 : nsCOMPtr<nsIRDFResource> container;
1064 0 : rv = gRDFService->GetUnicodeResource(ref, getter_AddRefs(container));
1065 0 : if (NS_FAILED(rv))
1066 0 : return false;
1067 :
1068 : // Can always insert into the root resource
1069 0 : if (container == mRows.GetRootResource())
1070 0 : return true;
1071 :
1072 0 : nsTreeRows::iterator iter = mRows.FindByResource(container);
1073 0 : if (iter == mRows.Last())
1074 0 : return false;
1075 :
1076 0 : return (iter->mContainerState == nsTreeRows::eContainerState_Open);
1077 : }
1078 :
1079 : struct ResultComparator
1080 : {
1081 : nsXULTreeBuilder* const mTreebuilder;
1082 : nsIXULTemplateResult* const mResult;
1083 0 : ResultComparator(nsXULTreeBuilder* aTreebuilder, nsIXULTemplateResult* aResult)
1084 0 : : mTreebuilder(aTreebuilder), mResult(aResult) {}
1085 0 : int operator()(const nsTreeRows::Row& aSubtree) const {
1086 0 : return mTreebuilder->CompareResults(mResult, aSubtree.mMatch->mResult);
1087 : }
1088 : };
1089 :
1090 : nsresult
1091 0 : nsXULTreeBuilder::ReplaceMatch(nsIXULTemplateResult* aOldResult,
1092 : nsTemplateMatch* aNewMatch,
1093 : nsTemplateRule* aNewMatchRule,
1094 : void *aLocation)
1095 : {
1096 0 : if (! mBoxObject)
1097 0 : return NS_OK;
1098 :
1099 0 : if (aOldResult) {
1100 : // Grovel through the rows looking for oldresult.
1101 0 : nsTreeRows::iterator iter = mRows.Find(aOldResult);
1102 :
1103 0 : NS_ASSERTION(iter != mRows.Last(), "couldn't find row");
1104 0 : if (iter == mRows.Last())
1105 0 : return NS_ERROR_FAILURE;
1106 :
1107 : // Remove the rows from the view
1108 0 : int32_t row = iter.GetRowIndex();
1109 :
1110 : // If the row contains children, remove the matches from the
1111 : // children so that they can be regenerated again if the element
1112 : // gets added back.
1113 0 : int32_t delta = mRows.GetSubtreeSizeFor(iter);
1114 0 : if (delta)
1115 0 : RemoveMatchesFor(*(iter->mSubtree));
1116 :
1117 0 : if (mRows.RemoveRowAt(iter) == 0 && iter.GetRowIndex() >= 0) {
1118 :
1119 : // In this case iter now points to its parent
1120 : // Invalidate the row's cached fill state
1121 0 : iter->mContainerFill = nsTreeRows::eContainerFill_Unknown;
1122 :
1123 0 : nsCOMPtr<nsITreeColumns> cols;
1124 0 : mBoxObject->GetColumns(getter_AddRefs(cols));
1125 0 : if (cols) {
1126 0 : nsCOMPtr<nsITreeColumn> primaryCol;
1127 0 : cols->GetPrimaryColumn(getter_AddRefs(primaryCol));
1128 0 : if (primaryCol)
1129 0 : mBoxObject->InvalidateCell(iter.GetRowIndex(), primaryCol);
1130 : }
1131 : }
1132 :
1133 : // Notify the box object
1134 0 : mBoxObject->RowCountChanged(row, -delta - 1);
1135 : }
1136 :
1137 0 : if (aNewMatch && aNewMatch->mResult) {
1138 : // Insertion.
1139 0 : int32_t row = -1;
1140 0 : nsTreeRows::Subtree* parent = nullptr;
1141 0 : nsIXULTemplateResult* result = aNewMatch->mResult;
1142 :
1143 0 : nsAutoString ref;
1144 0 : nsresult rv = result->GetBindingFor(mRefVariable, ref);
1145 0 : if (NS_FAILED(rv) || ref.IsEmpty())
1146 0 : return rv;
1147 :
1148 0 : nsCOMPtr<nsIRDFResource> container;
1149 0 : rv = gRDFService->GetUnicodeResource(ref, getter_AddRefs(container));
1150 0 : if (NS_FAILED(rv))
1151 0 : return rv;
1152 :
1153 0 : if (container != mRows.GetRootResource()) {
1154 0 : nsTreeRows::iterator iter = mRows.FindByResource(container);
1155 0 : row = iter.GetRowIndex();
1156 :
1157 0 : NS_ASSERTION(iter != mRows.Last(), "couldn't find container row");
1158 0 : if (iter == mRows.Last())
1159 0 : return NS_ERROR_FAILURE;
1160 :
1161 : // Use the persist store to remember if the container
1162 : // is open or closed.
1163 0 : bool open = false;
1164 0 : IsContainerOpen(row, &open);
1165 :
1166 : // If it's open, make sure that we've got a subtree structure ready.
1167 0 : if (open)
1168 0 : parent = mRows.EnsureSubtreeFor(iter);
1169 :
1170 : // We know something has just been inserted into the
1171 : // container, so whether its open or closed, make sure
1172 : // that we've got our tree row's state correct.
1173 0 : if ((iter->mContainerType != nsTreeRows::eContainerType_Container) ||
1174 0 : (iter->mContainerFill != nsTreeRows::eContainerFill_Nonempty)) {
1175 0 : iter->mContainerType = nsTreeRows::eContainerType_Container;
1176 0 : iter->mContainerFill = nsTreeRows::eContainerFill_Nonempty;
1177 0 : mBoxObject->InvalidateRow(iter.GetRowIndex());
1178 : }
1179 : }
1180 : else {
1181 0 : parent = mRows.GetRoot();
1182 : }
1183 :
1184 0 : if (parent) {
1185 : // If we get here, then we're inserting into an open
1186 : // container. By default, place the new element at the
1187 : // end of the container
1188 0 : size_t index = parent->Count();
1189 :
1190 0 : if (mSortVariable) {
1191 : // Figure out where to put the new element through
1192 : // binary search.
1193 0 : mozilla::BinarySearchIf(*parent, 0, parent->Count(),
1194 0 : ResultComparator(this, result), &index);
1195 : }
1196 :
1197 : nsTreeRows::iterator iter =
1198 0 : mRows.InsertRowAt(aNewMatch, parent, index);
1199 :
1200 0 : mBoxObject->RowCountChanged(iter.GetRowIndex(), +1);
1201 :
1202 : // See if this newly added row is open; in which case,
1203 : // recursively add its children to the tree, too.
1204 :
1205 0 : if (mFlags & eDontRecurse)
1206 0 : return NS_OK;
1207 :
1208 0 : if (result != mRootResult) {
1209 : // don't open containers if child processing isn't allowed
1210 : bool mayProcessChildren;
1211 0 : nsresult rv = result->GetMayProcessChildren(&mayProcessChildren);
1212 0 : if (NS_FAILED(rv) || ! mayProcessChildren) return NS_OK;
1213 : }
1214 :
1215 0 : if (IsContainerOpen(result)) {
1216 0 : OpenContainer(iter.GetRowIndex(), result);
1217 : }
1218 : }
1219 : }
1220 :
1221 0 : return NS_OK;
1222 : }
1223 :
1224 : nsresult
1225 0 : nsXULTreeBuilder::SynchronizeResult(nsIXULTemplateResult* aResult)
1226 : {
1227 0 : if (mBoxObject) {
1228 : // XXX we could be more conservative and just invalidate the cells
1229 : // that got whacked...
1230 :
1231 0 : nsTreeRows::iterator iter = mRows.Find(aResult);
1232 :
1233 0 : NS_ASSERTION(iter != mRows.Last(), "couldn't find row");
1234 0 : if (iter == mRows.Last())
1235 0 : return NS_ERROR_FAILURE;
1236 :
1237 0 : int32_t row = iter.GetRowIndex();
1238 0 : if (row >= 0)
1239 0 : mBoxObject->InvalidateRow(row);
1240 :
1241 0 : MOZ_LOG(gXULTemplateLog, LogLevel::Debug,
1242 : ("xultemplate[%p] => row %d", this, row));
1243 : }
1244 :
1245 0 : return NS_OK;
1246 : }
1247 :
1248 : //----------------------------------------------------------------------
1249 :
1250 : nsresult
1251 0 : nsXULTreeBuilder::EnsureSortVariables()
1252 : {
1253 : // Grovel through <treecols> kids to find the <treecol>
1254 : // with the sort attributes.
1255 0 : nsCOMPtr<nsIContent> treecols;
1256 :
1257 0 : nsXULContentUtils::FindChildByTag(mRoot, kNameSpaceID_XUL,
1258 : nsGkAtoms::treecols,
1259 0 : getter_AddRefs(treecols));
1260 :
1261 0 : if (!treecols)
1262 0 : return NS_OK;
1263 :
1264 0 : for (nsIContent* child = treecols->GetFirstChild();
1265 0 : child;
1266 0 : child = child->GetNextSibling()) {
1267 :
1268 0 : if (child->NodeInfo()->Equals(nsGkAtoms::treecol,
1269 : kNameSpaceID_XUL)) {
1270 0 : if (child->AttrValueIs(kNameSpaceID_None, nsGkAtoms::sortActive,
1271 : nsGkAtoms::_true, eCaseMatters)) {
1272 0 : nsAutoString sort;
1273 0 : child->GetAttr(kNameSpaceID_None, nsGkAtoms::sort, sort);
1274 0 : if (! sort.IsEmpty()) {
1275 0 : mSortVariable = NS_Atomize(sort);
1276 :
1277 : static nsIContent::AttrValuesArray strings[] =
1278 : {&nsGkAtoms::ascending, &nsGkAtoms::descending, nullptr};
1279 0 : switch (child->FindAttrValueIn(kNameSpaceID_None,
1280 : nsGkAtoms::sortDirection,
1281 0 : strings, eCaseMatters)) {
1282 0 : case 0: mSortDirection = eDirection_Ascending; break;
1283 0 : case 1: mSortDirection = eDirection_Descending; break;
1284 0 : default: mSortDirection = eDirection_Natural; break;
1285 : }
1286 : }
1287 0 : break;
1288 : }
1289 : }
1290 : }
1291 :
1292 0 : return NS_OK;
1293 : }
1294 :
1295 : nsresult
1296 0 : nsXULTreeBuilder::RebuildAll()
1297 : {
1298 0 : NS_ENSURE_TRUE(mRoot, NS_ERROR_NOT_INITIALIZED);
1299 :
1300 0 : nsCOMPtr<nsIDocument> doc = mRoot->GetComposedDoc();
1301 :
1302 : // Bail out early if we are being torn down.
1303 0 : if (!doc)
1304 0 : return NS_OK;
1305 :
1306 0 : if (! mQueryProcessor)
1307 0 : return NS_OK;
1308 :
1309 0 : if (mBoxObject) {
1310 0 : mBoxObject->BeginUpdateBatch();
1311 : }
1312 :
1313 0 : if (mQueriesCompiled) {
1314 0 : Uninit(false);
1315 : }
1316 0 : else if (mBoxObject) {
1317 0 : int32_t count = mRows.Count();
1318 0 : mRows.Clear();
1319 0 : mBoxObject->RowCountChanged(0, -count);
1320 : }
1321 :
1322 0 : nsresult rv = CompileQueries();
1323 0 : if (NS_SUCCEEDED(rv) && mQuerySets.Length() > 0) {
1324 : // Seed the rule network with assignments for the tree row variable
1325 0 : nsAutoString ref;
1326 0 : mRoot->GetAttr(kNameSpaceID_None, nsGkAtoms::ref, ref);
1327 0 : if (!ref.IsEmpty()) {
1328 0 : rv = mQueryProcessor->TranslateRef(mDataSource, ref,
1329 0 : getter_AddRefs(mRootResult));
1330 0 : if (NS_SUCCEEDED(rv) && mRootResult) {
1331 0 : OpenContainer(-1, mRootResult);
1332 :
1333 0 : nsCOMPtr<nsIRDFResource> rootResource;
1334 0 : GetResultResource(mRootResult, getter_AddRefs(rootResource));
1335 :
1336 0 : mRows.SetRootResource(rootResource);
1337 : }
1338 : }
1339 : }
1340 :
1341 0 : if (mBoxObject) {
1342 0 : mBoxObject->EndUpdateBatch();
1343 : }
1344 :
1345 0 : return rv;
1346 : }
1347 :
1348 : nsresult
1349 0 : nsXULTreeBuilder::GetTemplateActionRowFor(int32_t aRow, nsIContent** aResult)
1350 : {
1351 : // Get the template in the DOM from which we're supposed to
1352 : // generate text
1353 0 : nsTreeRows::Row& row = *(mRows[aRow]);
1354 :
1355 : // The match stores the indices of the rule and query to use. Use these
1356 : // to look up the right nsTemplateRule and use that rule's action to get
1357 : // the treerow in the template.
1358 0 : int16_t ruleindex = row.mMatch->RuleIndex();
1359 0 : if (ruleindex >= 0) {
1360 0 : nsTemplateQuerySet* qs = mQuerySets[row.mMatch->QuerySetPriority()];
1361 0 : nsTemplateRule* rule = qs->GetRuleAt(ruleindex);
1362 0 : if (rule) {
1363 0 : nsCOMPtr<nsIContent> children;
1364 0 : nsXULContentUtils::FindChildByTag(rule->GetAction(), kNameSpaceID_XUL,
1365 : nsGkAtoms::treechildren,
1366 0 : getter_AddRefs(children));
1367 0 : if (children) {
1368 0 : nsCOMPtr<nsIContent> item;
1369 0 : nsXULContentUtils::FindChildByTag(children, kNameSpaceID_XUL,
1370 : nsGkAtoms::treeitem,
1371 0 : getter_AddRefs(item));
1372 0 : if (item)
1373 0 : return nsXULContentUtils::FindChildByTag(item,
1374 : kNameSpaceID_XUL,
1375 : nsGkAtoms::treerow,
1376 0 : aResult);
1377 : }
1378 : }
1379 : }
1380 :
1381 0 : *aResult = nullptr;
1382 0 : return NS_OK;
1383 : }
1384 :
1385 : nsIContent*
1386 0 : nsXULTreeBuilder::GetTemplateActionCellFor(int32_t aRow, nsTreeColumn& aCol)
1387 : {
1388 0 : nsCOMPtr<nsIContent> row;
1389 0 : GetTemplateActionRowFor(aRow, getter_AddRefs(row));
1390 0 : if (!row) {
1391 0 : return nullptr;
1392 : }
1393 :
1394 0 : nsCOMPtr<nsIAtom> colAtom(aCol.GetAtom());
1395 0 : int32_t colIndex(aCol.GetIndex());
1396 :
1397 0 : nsIContent* result = nullptr;
1398 0 : uint32_t j = 0;
1399 0 : for (nsIContent* child = row->GetFirstChild();
1400 0 : child;
1401 0 : child = child->GetNextSibling()) {
1402 0 : if (child->NodeInfo()->Equals(nsGkAtoms::treecell, kNameSpaceID_XUL)) {
1403 0 : if (colAtom &&
1404 0 : child->AttrValueIs(kNameSpaceID_None, nsGkAtoms::ref, colAtom,
1405 0 : eCaseMatters)) {
1406 0 : return child;
1407 : }
1408 :
1409 0 : if (j == (uint32_t)colIndex) {
1410 0 : result = child;
1411 : }
1412 0 : ++j;
1413 : }
1414 : }
1415 0 : return result;
1416 : }
1417 :
1418 : nsresult
1419 0 : nsXULTreeBuilder::GetResourceFor(int32_t aRow, nsIRDFResource** aResource)
1420 : {
1421 0 : nsTreeRows::Row& row = *(mRows[aRow]);
1422 0 : return GetResultResource(row.mMatch->mResult, aResource);
1423 : }
1424 :
1425 : nsresult
1426 0 : nsXULTreeBuilder::OpenContainer(int32_t aIndex, nsIXULTemplateResult* aResult)
1427 : {
1428 : // A row index of -1 in this case means ``open tree body''
1429 0 : NS_ASSERTION(aIndex >= -1 && aIndex < mRows.Count(), "bad row");
1430 0 : if (aIndex < -1 || aIndex >= mRows.Count())
1431 0 : return NS_ERROR_INVALID_ARG;
1432 :
1433 : nsTreeRows::Subtree* container;
1434 :
1435 0 : if (aIndex >= 0) {
1436 0 : nsTreeRows::iterator iter = mRows[aIndex];
1437 0 : container = mRows.EnsureSubtreeFor(iter.GetParent(),
1438 0 : iter.GetChildIndex());
1439 :
1440 0 : iter->mContainerState = nsTreeRows::eContainerState_Open;
1441 : }
1442 : else
1443 0 : container = mRows.GetRoot();
1444 :
1445 0 : if (! container)
1446 0 : return NS_ERROR_OUT_OF_MEMORY;
1447 :
1448 : int32_t count;
1449 0 : OpenSubtreeOf(container, aIndex, aResult, &count);
1450 :
1451 : // Notify the box object
1452 0 : if (mBoxObject) {
1453 0 : if (aIndex >= 0)
1454 0 : mBoxObject->InvalidateRow(aIndex);
1455 :
1456 0 : if (count)
1457 0 : mBoxObject->RowCountChanged(aIndex + 1, count);
1458 : }
1459 :
1460 0 : return NS_OK;
1461 : }
1462 :
1463 : nsresult
1464 0 : nsXULTreeBuilder::OpenSubtreeOf(nsTreeRows::Subtree* aSubtree,
1465 : int32_t aIndex,
1466 : nsIXULTemplateResult *aResult,
1467 : int32_t* aDelta)
1468 : {
1469 0 : AutoTArray<int32_t, 8> open;
1470 0 : int32_t count = 0;
1471 :
1472 0 : int32_t rulecount = mQuerySets.Length();
1473 :
1474 0 : for (int32_t r = 0; r < rulecount; r++) {
1475 0 : nsTemplateQuerySet* queryset = mQuerySets[r];
1476 0 : OpenSubtreeForQuerySet(aSubtree, aIndex, aResult, queryset, &count, open);
1477 : }
1478 :
1479 : // Now recursively deal with any open sub-containers that just got
1480 : // inserted. We need to do this back-to-front to avoid skewing offsets.
1481 0 : for (int32_t i = open.Length() - 1; i >= 0; --i) {
1482 0 : int32_t index = open[i];
1483 :
1484 : nsTreeRows::Subtree* child =
1485 0 : mRows.EnsureSubtreeFor(aSubtree, index);
1486 :
1487 0 : nsIXULTemplateResult* result = (*aSubtree)[index].mMatch->mResult;
1488 :
1489 : int32_t delta;
1490 0 : OpenSubtreeOf(child, aIndex + index, result, &delta);
1491 0 : count += delta;
1492 : }
1493 :
1494 : // Sort the container.
1495 0 : if (mSortVariable) {
1496 0 : NS_QuickSort(mRows.GetRowsFor(aSubtree),
1497 0 : aSubtree->Count(),
1498 : sizeof(nsTreeRows::Row),
1499 : Compare,
1500 0 : this);
1501 : }
1502 :
1503 0 : *aDelta = count;
1504 0 : return NS_OK;
1505 : }
1506 :
1507 : nsresult
1508 0 : nsXULTreeBuilder::OpenSubtreeForQuerySet(nsTreeRows::Subtree* aSubtree,
1509 : int32_t aIndex,
1510 : nsIXULTemplateResult* aResult,
1511 : nsTemplateQuerySet* aQuerySet,
1512 : int32_t* aDelta,
1513 : nsTArray<int32_t>& open)
1514 : {
1515 0 : int32_t count = *aDelta;
1516 :
1517 0 : nsCOMPtr<nsISimpleEnumerator> results;
1518 0 : nsresult rv = mQueryProcessor->GenerateResults(mDataSource, aResult,
1519 : aQuerySet->mCompiledQuery,
1520 0 : getter_AddRefs(results));
1521 0 : if (NS_FAILED(rv))
1522 0 : return rv;
1523 :
1524 : bool hasMoreResults;
1525 0 : rv = results->HasMoreElements(&hasMoreResults);
1526 :
1527 0 : for (; NS_SUCCEEDED(rv) && hasMoreResults;
1528 0 : rv = results->HasMoreElements(&hasMoreResults)) {
1529 0 : nsCOMPtr<nsISupports> nr;
1530 0 : rv = results->GetNext(getter_AddRefs(nr));
1531 0 : if (NS_FAILED(rv))
1532 0 : return rv;
1533 :
1534 0 : nsCOMPtr<nsIXULTemplateResult> nextresult = do_QueryInterface(nr);
1535 0 : if (!nextresult)
1536 0 : return NS_ERROR_UNEXPECTED;
1537 :
1538 0 : nsCOMPtr<nsIRDFResource> resultid;
1539 0 : rv = GetResultResource(nextresult, getter_AddRefs(resultid));
1540 0 : if (NS_FAILED(rv))
1541 0 : return rv;
1542 :
1543 0 : if (! resultid)
1544 0 : continue;
1545 :
1546 : // check if there is already an existing match. If so, a previous
1547 : // query already generated content so the match is just added to the
1548 : // end of the set of matches.
1549 :
1550 0 : bool generateContent = true;
1551 :
1552 0 : nsTemplateMatch* prevmatch = nullptr;
1553 0 : nsTemplateMatch* existingmatch = nullptr;
1554 0 : if (mMatchMap.Get(resultid, &existingmatch)){
1555 : // check if there is an existing match that matched a rule
1556 0 : while (existingmatch) {
1557 0 : if (existingmatch->IsActive())
1558 0 : generateContent = false;
1559 0 : prevmatch = existingmatch;
1560 0 : existingmatch = existingmatch->mNext;
1561 : }
1562 : }
1563 :
1564 : nsTemplateMatch *newmatch =
1565 0 : nsTemplateMatch::Create(aQuerySet->Priority(), nextresult, nullptr);
1566 0 : if (!newmatch)
1567 0 : return NS_ERROR_OUT_OF_MEMORY;
1568 :
1569 0 : if (generateContent) {
1570 : // Don't allow cyclic graphs to get our knickers in a knot.
1571 0 : bool cyclic = false;
1572 :
1573 0 : if (aIndex >= 0) {
1574 0 : for (nsTreeRows::iterator iter = mRows[aIndex]; iter.GetDepth() > 0; iter.Pop()) {
1575 0 : nsCOMPtr<nsIRDFResource> parentid;
1576 0 : rv = GetResultResource(iter->mMatch->mResult, getter_AddRefs(parentid));
1577 0 : if (NS_FAILED(rv)) {
1578 0 : nsTemplateMatch::Destroy(newmatch, false);
1579 0 : return rv;
1580 : }
1581 :
1582 0 : if (resultid == parentid) {
1583 0 : cyclic = true;
1584 0 : break;
1585 : }
1586 : }
1587 : }
1588 :
1589 0 : if (cyclic) {
1590 0 : NS_WARNING("tree cannot handle cyclic graphs");
1591 0 : nsTemplateMatch::Destroy(newmatch, false);
1592 0 : continue;
1593 : }
1594 :
1595 : int16_t ruleindex;
1596 0 : nsTemplateRule* matchedrule = nullptr;
1597 0 : rv = DetermineMatchedRule(nullptr, nextresult, aQuerySet,
1598 0 : &matchedrule, &ruleindex);
1599 0 : if (NS_FAILED(rv)) {
1600 0 : nsTemplateMatch::Destroy(newmatch, false);
1601 0 : return rv;
1602 : }
1603 :
1604 0 : if (matchedrule) {
1605 0 : rv = newmatch->RuleMatched(aQuerySet, matchedrule, ruleindex,
1606 0 : nextresult);
1607 0 : if (NS_FAILED(rv)) {
1608 0 : nsTemplateMatch::Destroy(newmatch, false);
1609 0 : return rv;
1610 : }
1611 :
1612 : // Remember that this match applied to this row
1613 0 : mRows.InsertRowAt(newmatch, aSubtree, count);
1614 :
1615 : // If this is open, then remember it so we can recursively add
1616 : // *its* rows to the tree.
1617 0 : if (IsContainerOpen(nextresult)) {
1618 0 : if (open.AppendElement(count) == nullptr)
1619 0 : return NS_ERROR_OUT_OF_MEMORY;
1620 : }
1621 :
1622 0 : ++count;
1623 : }
1624 :
1625 0 : if (mFlags & eLoggingEnabled)
1626 0 : OutputMatchToLog(resultid, newmatch, true);
1627 :
1628 : }
1629 :
1630 0 : if (prevmatch) {
1631 0 : prevmatch->mNext = newmatch;
1632 : }
1633 : else {
1634 0 : mMatchMap.Put(resultid, newmatch);
1635 : }
1636 : }
1637 :
1638 0 : *aDelta = count;
1639 0 : return rv;
1640 : }
1641 :
1642 : nsresult
1643 0 : nsXULTreeBuilder::CloseContainer(int32_t aIndex)
1644 : {
1645 0 : NS_ASSERTION(aIndex >= 0 && aIndex < mRows.Count(), "bad row");
1646 0 : if (aIndex < 0 || aIndex >= mRows.Count())
1647 0 : return NS_ERROR_INVALID_ARG;
1648 :
1649 0 : nsTreeRows::iterator iter = mRows[aIndex];
1650 :
1651 0 : if (iter->mSubtree)
1652 0 : RemoveMatchesFor(*iter->mSubtree);
1653 :
1654 :
1655 0 : int32_t count = mRows.GetSubtreeSizeFor(iter);
1656 0 : mRows.RemoveSubtreeFor(iter);
1657 :
1658 0 : iter->mContainerState = nsTreeRows::eContainerState_Closed;
1659 :
1660 0 : if (mBoxObject) {
1661 0 : mBoxObject->InvalidateRow(aIndex);
1662 :
1663 0 : if (count)
1664 0 : mBoxObject->RowCountChanged(aIndex + 1, -count);
1665 : }
1666 :
1667 0 : return NS_OK;
1668 : }
1669 :
1670 : nsresult
1671 0 : nsXULTreeBuilder::RemoveMatchesFor(nsTreeRows::Subtree& subtree)
1672 : {
1673 0 : for (int32_t i = subtree.Count() - 1; i >= 0; --i) {
1674 0 : nsTreeRows::Row& row = subtree[i];
1675 :
1676 0 : nsTemplateMatch* match = row.mMatch;
1677 :
1678 0 : nsCOMPtr<nsIRDFResource> id;
1679 0 : nsresult rv = GetResultResource(match->mResult, getter_AddRefs(id));
1680 0 : if (NS_FAILED(rv))
1681 0 : return rv;
1682 :
1683 : nsTemplateMatch* existingmatch;
1684 0 : if (mMatchMap.Get(id, &existingmatch)) {
1685 0 : while (existingmatch) {
1686 0 : nsTemplateMatch* nextmatch = existingmatch->mNext;
1687 0 : nsTemplateMatch::Destroy(existingmatch, true);
1688 0 : existingmatch = nextmatch;
1689 : }
1690 :
1691 0 : mMatchMap.Remove(id);
1692 : }
1693 :
1694 0 : if ((row.mContainerState == nsTreeRows::eContainerState_Open) && row.mSubtree)
1695 0 : RemoveMatchesFor(*(row.mSubtree));
1696 : }
1697 :
1698 0 : return NS_OK;
1699 : }
1700 :
1701 :
1702 : bool
1703 0 : nsXULTreeBuilder::IsContainerOpen(nsIXULTemplateResult *aResult)
1704 : {
1705 : // items are never open if recursion is disabled
1706 0 : if ((mFlags & eDontRecurse) && aResult != mRootResult) {
1707 0 : return false;
1708 : }
1709 :
1710 0 : if (!mLocalStore) {
1711 0 : return false;
1712 : }
1713 :
1714 0 : nsIDocument* doc = mRoot->GetComposedDoc();
1715 0 : if (!doc) {
1716 0 : return false;
1717 : }
1718 :
1719 0 : nsIURI* docURI = doc->GetDocumentURI();
1720 :
1721 0 : nsAutoString nodeid;
1722 0 : nsresult rv = aResult->GetId(nodeid);
1723 0 : if (NS_FAILED(rv)) {
1724 0 : return false;
1725 : }
1726 :
1727 0 : nsAutoCString utf8uri;
1728 0 : rv = docURI->GetSpec(utf8uri);
1729 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
1730 0 : return false;
1731 : }
1732 0 : NS_ConvertUTF8toUTF16 uri(utf8uri);
1733 :
1734 0 : nsAutoString val;
1735 0 : mLocalStore->GetValue(uri, nodeid, NS_LITERAL_STRING("open"), val);
1736 0 : return val.EqualsLiteral("true");
1737 : }
1738 :
1739 : int
1740 0 : nsXULTreeBuilder::Compare(const void* aLeft, const void* aRight, void* aClosure)
1741 : {
1742 0 : nsXULTreeBuilder* self = static_cast<nsXULTreeBuilder*>(aClosure);
1743 :
1744 : nsTreeRows::Row* left = static_cast<nsTreeRows::Row*>
1745 0 : (const_cast<void*>(aLeft));
1746 :
1747 : nsTreeRows::Row* right = static_cast<nsTreeRows::Row*>
1748 0 : (const_cast<void*>(aRight));
1749 :
1750 0 : return self->CompareResults(left->mMatch->mResult, right->mMatch->mResult);
1751 : }
1752 :
1753 : int32_t
1754 0 : nsXULTreeBuilder::CompareResults(nsIXULTemplateResult* aLeft, nsIXULTemplateResult* aRight)
1755 : {
1756 : // this is an extra check done for RDF queries such that results appear in
1757 : // the order they appear in their containing Seq
1758 0 : if (mSortDirection == eDirection_Natural && mDB) {
1759 : // If the sort order is ``natural'', then see if the container
1760 : // is an RDF sequence. If so, we'll try to use the ordinal
1761 : // properties to determine order.
1762 : //
1763 : // XXX the problem with this is, it doesn't always get the
1764 : // *real* container; e.g.,
1765 : //
1766 : // <treerow uri="?uri" />
1767 : //
1768 : // <triple subject="?uri"
1769 : // predicate="http://home.netscape.com/NC-rdf#subheadings"
1770 : // object="?subheadings" />
1771 : //
1772 : // <member container="?subheadings" child="?subheading" />
1773 : //
1774 : // In this case mRefVariable is bound to ?uri, not
1775 : // ?subheadings. (The ``container'' in the template sense !=
1776 : // container in the RDF sense.)
1777 :
1778 0 : nsCOMPtr<nsISupports> ref;
1779 0 : nsresult rv = aLeft->GetBindingObjectFor(mRefVariable, getter_AddRefs(ref));
1780 0 : if (NS_FAILED(rv))
1781 0 : return 0;
1782 :
1783 0 : nsCOMPtr<nsIRDFResource> container = do_QueryInterface(ref);
1784 0 : if (container) {
1785 0 : bool isSequence = false;
1786 0 : gRDFContainerUtils->IsSeq(mDB, container, &isSequence);
1787 0 : if (isSequence) {
1788 : // Determine the indices of the left and right elements
1789 : // in the container.
1790 0 : int32_t lindex = 0, rindex = 0;
1791 :
1792 0 : nsCOMPtr<nsIRDFResource> leftitem;
1793 0 : aLeft->GetResource(getter_AddRefs(leftitem));
1794 0 : if (leftitem) {
1795 0 : gRDFContainerUtils->IndexOf(mDB, container, leftitem, &lindex);
1796 0 : if (lindex < 0)
1797 0 : return 0;
1798 : }
1799 :
1800 0 : nsCOMPtr<nsIRDFResource> rightitem;
1801 0 : aRight->GetResource(getter_AddRefs(rightitem));
1802 0 : if (rightitem) {
1803 0 : gRDFContainerUtils->IndexOf(mDB, container, rightitem, &rindex);
1804 0 : if (rindex < 0)
1805 0 : return 0;
1806 : }
1807 :
1808 0 : return lindex - rindex;
1809 : }
1810 : }
1811 : }
1812 :
1813 : int32_t sortorder;
1814 0 : if (!mQueryProcessor)
1815 0 : return 0;
1816 :
1817 0 : mQueryProcessor->CompareResults(aLeft, aRight, mSortVariable, mSortHints, &sortorder);
1818 :
1819 0 : if (sortorder)
1820 0 : sortorder = sortorder * mSortDirection;
1821 0 : return sortorder;
1822 : }
1823 :
1824 : nsresult
1825 0 : nsXULTreeBuilder::SortSubtree(nsTreeRows::Subtree* aSubtree)
1826 : {
1827 0 : NS_QuickSort(mRows.GetRowsFor(aSubtree),
1828 0 : aSubtree->Count(),
1829 : sizeof(nsTreeRows::Row),
1830 : Compare,
1831 0 : this);
1832 :
1833 0 : for (int32_t i = aSubtree->Count() - 1; i >= 0; --i) {
1834 0 : nsTreeRows::Subtree* child = (*aSubtree)[i].mSubtree;
1835 0 : if (child)
1836 0 : SortSubtree(child);
1837 : }
1838 :
1839 0 : return NS_OK;
1840 : }
1841 :
1842 : bool
1843 0 : nsXULTreeBuilder::CanDrop(int32_t aRow, int32_t aOrientation,
1844 : DataTransfer* aDataTransfer, ErrorResult& aError)
1845 : {
1846 0 : uint32_t count = mObservers.Length();
1847 0 : for (uint32_t i = 0; i < count; ++i) {
1848 0 : nsCOMPtr<nsIXULTreeBuilderObserver> observer = mObservers.SafeElementAt(i);
1849 0 : if (observer) {
1850 0 : bool canDrop = false;
1851 0 : observer->CanDrop(aRow, aOrientation, aDataTransfer, &canDrop);
1852 0 : if (canDrop) {
1853 0 : return true;
1854 : }
1855 : }
1856 : }
1857 :
1858 0 : return false;
1859 : }
1860 :
1861 : NS_IMETHODIMP
1862 0 : nsXULTreeBuilder::CanDrop(int32_t index, int32_t orientation,
1863 : nsIDOMDataTransfer* dataTransfer, bool *_retval)
1864 : {
1865 0 : ErrorResult rv;
1866 0 : *_retval = CanDrop(index, orientation, DataTransfer::Cast(dataTransfer),
1867 : rv);
1868 0 : return rv.StealNSResult();
1869 : }
1870 :
1871 : void
1872 0 : nsXULTreeBuilder::Drop(int32_t aRow, int32_t aOrientation,
1873 : DataTransfer* aDataTransfer, ErrorResult& aError)
1874 : {
1875 0 : uint32_t count = mObservers.Length();
1876 0 : for (uint32_t i = 0; i < count; ++i) {
1877 0 : nsCOMPtr<nsIXULTreeBuilderObserver> observer = mObservers.SafeElementAt(i);
1878 0 : if (observer) {
1879 0 : bool canDrop = false;
1880 0 : observer->CanDrop(aRow, aOrientation, aDataTransfer, &canDrop);
1881 0 : if (canDrop)
1882 0 : observer->OnDrop(aRow, aOrientation, aDataTransfer);
1883 : }
1884 : }
1885 0 : }
1886 :
1887 : NS_IMETHODIMP
1888 0 : nsXULTreeBuilder::Drop(int32_t row, int32_t orient, nsIDOMDataTransfer* dataTransfer)
1889 : {
1890 0 : ErrorResult rv;
1891 0 : Drop(row, orient, DataTransfer::Cast(dataTransfer), rv);
1892 0 : return rv.StealNSResult();
1893 : }
1894 :
1895 : NS_IMETHODIMP
1896 0 : nsXULTreeBuilder::IsSorted(bool *_retval)
1897 : {
1898 0 : *_retval = (mSortVariable != nullptr);
1899 0 : return NS_OK;
1900 : }
1901 :
1902 : bool
1903 0 : nsXULTreeBuilder::IsValidRowIndex(int32_t aRowIndex)
1904 : {
1905 0 : return aRowIndex >= 0 && aRowIndex < int32_t(mRows.Count());
1906 : }
|