content/xul/templates/src/nsXULSortService.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
michael@0 5 *
michael@0 6 * This Original Code has been modified by IBM Corporation.
michael@0 7 * Modifications made by IBM described herein are
michael@0 8 * Copyright (c) International Business Machines
michael@0 9 * Corporation, 2000
michael@0 10 *
michael@0 11 * Modifications to Mozilla code or documentation
michael@0 12 * identified per MPL Section 3.3
michael@0 13 *
michael@0 14 * Date Modified by Description of modification
michael@0 15 * 03/27/2000 IBM Corp. Added PR_CALLBACK for Optlink
michael@0 16 * use in OS2
michael@0 17 */
michael@0 18
michael@0 19 /*
michael@0 20 This file provides the implementation for the sort service manager.
michael@0 21 */
michael@0 22
michael@0 23 #include "nsCOMPtr.h"
michael@0 24 #include "nsIContent.h"
michael@0 25 #include "nsIDOMElement.h"
michael@0 26 #include "nsIDOMNode.h"
michael@0 27 #include "nsIServiceManager.h"
michael@0 28 #include "nsGkAtoms.h"
michael@0 29 #include "nsNameSpaceManager.h"
michael@0 30 #include "nsXULContentUtils.h"
michael@0 31 #include "nsString.h"
michael@0 32 #include "nsQuickSort.h"
michael@0 33 #include "nsWhitespaceTokenizer.h"
michael@0 34 #include "nsXULSortService.h"
michael@0 35 #include "nsIDOMXULElement.h"
michael@0 36 #include "nsIXULTemplateBuilder.h"
michael@0 37 #include "nsTemplateMatch.h"
michael@0 38 #include "nsICollation.h"
michael@0 39 #include "nsUnicharUtils.h"
michael@0 40
michael@0 41 NS_IMPL_ISUPPORTS(XULSortServiceImpl, nsIXULSortService)
michael@0 42
michael@0 43 void
michael@0 44 XULSortServiceImpl::SetSortHints(nsIContent *aNode, nsSortState* aSortState)
michael@0 45 {
michael@0 46 // set sort and sortDirection attributes when is sort is done
michael@0 47 aNode->SetAttr(kNameSpaceID_None, nsGkAtoms::sort,
michael@0 48 aSortState->sort, true);
michael@0 49
michael@0 50 nsAutoString direction;
michael@0 51 if (aSortState->direction == nsSortState_descending)
michael@0 52 direction.AssignLiteral("descending");
michael@0 53 else if (aSortState->direction == nsSortState_ascending)
michael@0 54 direction.AssignLiteral("ascending");
michael@0 55 aNode->SetAttr(kNameSpaceID_None, nsGkAtoms::sortDirection,
michael@0 56 direction, true);
michael@0 57
michael@0 58 // for trees, also set the sort info on the currently sorted column
michael@0 59 if (aNode->NodeInfo()->Equals(nsGkAtoms::tree, kNameSpaceID_XUL)) {
michael@0 60 if (aSortState->sortKeys.Count() >= 1) {
michael@0 61 nsAutoString sortkey;
michael@0 62 aSortState->sortKeys[0]->ToString(sortkey);
michael@0 63 SetSortColumnHints(aNode, sortkey, direction);
michael@0 64 }
michael@0 65 }
michael@0 66 }
michael@0 67
michael@0 68 void
michael@0 69 XULSortServiceImpl::SetSortColumnHints(nsIContent *content,
michael@0 70 const nsAString &sortResource,
michael@0 71 const nsAString &sortDirection)
michael@0 72 {
michael@0 73 // set sort info on current column. This ensures that the
michael@0 74 // column header sort indicator is updated properly.
michael@0 75 for (nsIContent* child = content->GetFirstChild();
michael@0 76 child;
michael@0 77 child = child->GetNextSibling()) {
michael@0 78 if (child->IsXUL()) {
michael@0 79 nsIAtom *tag = child->Tag();
michael@0 80
michael@0 81 if (tag == nsGkAtoms::treecols) {
michael@0 82 SetSortColumnHints(child, sortResource, sortDirection);
michael@0 83 } else if (tag == nsGkAtoms::treecol) {
michael@0 84 nsAutoString value;
michael@0 85 child->GetAttr(kNameSpaceID_None, nsGkAtoms::sort, value);
michael@0 86 // also check the resource attribute for older code
michael@0 87 if (value.IsEmpty())
michael@0 88 child->GetAttr(kNameSpaceID_None, nsGkAtoms::resource, value);
michael@0 89 if (value == sortResource) {
michael@0 90 child->SetAttr(kNameSpaceID_None, nsGkAtoms::sortActive,
michael@0 91 NS_LITERAL_STRING("true"), true);
michael@0 92 child->SetAttr(kNameSpaceID_None, nsGkAtoms::sortDirection,
michael@0 93 sortDirection, true);
michael@0 94 // Note: don't break out of loop; want to set/unset
michael@0 95 // attribs on ALL sort columns
michael@0 96 } else if (!value.IsEmpty()) {
michael@0 97 child->UnsetAttr(kNameSpaceID_None, nsGkAtoms::sortActive,
michael@0 98 true);
michael@0 99 child->UnsetAttr(kNameSpaceID_None, nsGkAtoms::sortDirection,
michael@0 100 true);
michael@0 101 }
michael@0 102 }
michael@0 103 }
michael@0 104 }
michael@0 105 }
michael@0 106
michael@0 107 nsresult
michael@0 108 XULSortServiceImpl::GetItemsToSort(nsIContent *aContainer,
michael@0 109 nsSortState* aSortState,
michael@0 110 nsTArray<contentSortInfo>& aSortItems)
michael@0 111 {
michael@0 112 // if there is a template attached to the sort node, use the builder to get
michael@0 113 // the items to be sorted
michael@0 114 nsCOMPtr<nsIDOMXULElement> element = do_QueryInterface(aContainer);
michael@0 115 if (element) {
michael@0 116 nsCOMPtr<nsIXULTemplateBuilder> builder;
michael@0 117 element->GetBuilder(getter_AddRefs(builder));
michael@0 118
michael@0 119 if (builder) {
michael@0 120 nsresult rv = builder->GetQueryProcessor(getter_AddRefs(aSortState->processor));
michael@0 121 if (NS_FAILED(rv) || !aSortState->processor)
michael@0 122 return rv;
michael@0 123
michael@0 124 return GetTemplateItemsToSort(aContainer, builder, aSortState, aSortItems);
michael@0 125 }
michael@0 126 }
michael@0 127
michael@0 128 // if there is no template builder, just get the children. For trees,
michael@0 129 // get the treechildren element as use that as the parent
michael@0 130 nsCOMPtr<nsIContent> treechildren;
michael@0 131 if (aContainer->NodeInfo()->Equals(nsGkAtoms::tree, kNameSpaceID_XUL)) {
michael@0 132 nsXULContentUtils::FindChildByTag(aContainer,
michael@0 133 kNameSpaceID_XUL,
michael@0 134 nsGkAtoms::treechildren,
michael@0 135 getter_AddRefs(treechildren));
michael@0 136 if (!treechildren)
michael@0 137 return NS_OK;
michael@0 138
michael@0 139 aContainer = treechildren;
michael@0 140 }
michael@0 141
michael@0 142 for (nsIContent* child = aContainer->GetFirstChild();
michael@0 143 child;
michael@0 144 child = child->GetNextSibling()) {
michael@0 145 contentSortInfo* cinfo = aSortItems.AppendElement();
michael@0 146 if (!cinfo)
michael@0 147 return NS_ERROR_OUT_OF_MEMORY;
michael@0 148
michael@0 149 cinfo->content = child;
michael@0 150 }
michael@0 151
michael@0 152 return NS_OK;
michael@0 153 }
michael@0 154
michael@0 155
michael@0 156 nsresult
michael@0 157 XULSortServiceImpl::GetTemplateItemsToSort(nsIContent* aContainer,
michael@0 158 nsIXULTemplateBuilder* aBuilder,
michael@0 159 nsSortState* aSortState,
michael@0 160 nsTArray<contentSortInfo>& aSortItems)
michael@0 161 {
michael@0 162 for (nsIContent* child = aContainer->GetFirstChild();
michael@0 163 child;
michael@0 164 child = child->GetNextSibling()) {
michael@0 165
michael@0 166 nsCOMPtr<nsIDOMElement> childnode = do_QueryInterface(child);
michael@0 167
michael@0 168 nsCOMPtr<nsIXULTemplateResult> result;
michael@0 169 nsresult rv = aBuilder->GetResultForContent(childnode, getter_AddRefs(result));
michael@0 170 NS_ENSURE_SUCCESS(rv, rv);
michael@0 171
michael@0 172 if (result) {
michael@0 173 contentSortInfo* cinfo = aSortItems.AppendElement();
michael@0 174 if (!cinfo)
michael@0 175 return NS_ERROR_OUT_OF_MEMORY;
michael@0 176
michael@0 177 cinfo->content = child;
michael@0 178 cinfo->result = result;
michael@0 179 }
michael@0 180 else if (aContainer->Tag() != nsGkAtoms::_template) {
michael@0 181 rv = GetTemplateItemsToSort(child, aBuilder, aSortState, aSortItems);
michael@0 182 NS_ENSURE_SUCCESS(rv, rv);
michael@0 183 }
michael@0 184 }
michael@0 185
michael@0 186 return NS_OK;
michael@0 187 }
michael@0 188
michael@0 189 int
michael@0 190 testSortCallback(const void *data1, const void *data2, void *privateData)
michael@0 191 {
michael@0 192 /// Note: testSortCallback is a small C callback stub for NS_QuickSort
michael@0 193 contentSortInfo *left = (contentSortInfo *)data1;
michael@0 194 contentSortInfo *right = (contentSortInfo *)data2;
michael@0 195 nsSortState* sortState = (nsSortState *)privateData;
michael@0 196
michael@0 197 int32_t sortOrder = 0;
michael@0 198
michael@0 199 if (sortState->direction == nsSortState_natural && sortState->processor) {
michael@0 200 // sort in natural order
michael@0 201 sortState->processor->CompareResults(left->result, right->result,
michael@0 202 nullptr, sortState->sortHints, &sortOrder);
michael@0 203 }
michael@0 204 else {
michael@0 205 int32_t length = sortState->sortKeys.Count();
michael@0 206 for (int32_t t = 0; t < length; t++) {
michael@0 207 // for templates, use the query processor to do sorting
michael@0 208 if (sortState->processor) {
michael@0 209 sortState->processor->CompareResults(left->result, right->result,
michael@0 210 sortState->sortKeys[t],
michael@0 211 sortState->sortHints, &sortOrder);
michael@0 212 if (sortOrder)
michael@0 213 break;
michael@0 214 }
michael@0 215 else {
michael@0 216 // no template, so just compare attributes. Ignore namespaces for now.
michael@0 217 nsAutoString leftstr, rightstr;
michael@0 218 left->content->GetAttr(kNameSpaceID_None, sortState->sortKeys[t], leftstr);
michael@0 219 right->content->GetAttr(kNameSpaceID_None, sortState->sortKeys[t], rightstr);
michael@0 220
michael@0 221 sortOrder = XULSortServiceImpl::CompareValues(leftstr, rightstr, sortState->sortHints);
michael@0 222 }
michael@0 223 }
michael@0 224 }
michael@0 225
michael@0 226 if (sortState->direction == nsSortState_descending)
michael@0 227 sortOrder = -sortOrder;
michael@0 228
michael@0 229 return sortOrder;
michael@0 230 }
michael@0 231
michael@0 232 nsresult
michael@0 233 XULSortServiceImpl::SortContainer(nsIContent *aContainer, nsSortState* aSortState)
michael@0 234 {
michael@0 235 nsTArray<contentSortInfo> items;
michael@0 236 nsresult rv = GetItemsToSort(aContainer, aSortState, items);
michael@0 237 NS_ENSURE_SUCCESS(rv, rv);
michael@0 238
michael@0 239 uint32_t numResults = items.Length();
michael@0 240 if (!numResults)
michael@0 241 return NS_OK;
michael@0 242
michael@0 243 uint32_t i;
michael@0 244
michael@0 245 // inbetweenSeparatorSort sorts the items between separators independently
michael@0 246 if (aSortState->inbetweenSeparatorSort) {
michael@0 247 uint32_t startIndex = 0;
michael@0 248 for (i = 0; i < numResults; i++) {
michael@0 249 if (i > startIndex + 1) {
michael@0 250 nsAutoString type;
michael@0 251 items[i].result->GetType(type);
michael@0 252 if (type.EqualsLiteral("separator")) {
michael@0 253 if (aSortState->invertSort)
michael@0 254 InvertSortInfo(items, startIndex, i - startIndex);
michael@0 255 else
michael@0 256 NS_QuickSort((void *)(items.Elements() + startIndex), i - startIndex,
michael@0 257 sizeof(contentSortInfo), testSortCallback, (void*)aSortState);
michael@0 258
michael@0 259 startIndex = i + 1;
michael@0 260 }
michael@0 261 }
michael@0 262 }
michael@0 263
michael@0 264 if (i > startIndex + 1) {
michael@0 265 if (aSortState->invertSort)
michael@0 266 InvertSortInfo(items, startIndex, i - startIndex);
michael@0 267 else
michael@0 268 NS_QuickSort((void *)(items.Elements() + startIndex), i - startIndex,
michael@0 269 sizeof(contentSortInfo), testSortCallback, (void*)aSortState);
michael@0 270 }
michael@0 271 } else {
michael@0 272 // if the items are just being inverted, that is, just switching between
michael@0 273 // ascending and descending, just reverse the list.
michael@0 274 if (aSortState->invertSort)
michael@0 275 InvertSortInfo(items, 0, numResults);
michael@0 276 else
michael@0 277 NS_QuickSort((void *)items.Elements(), numResults,
michael@0 278 sizeof(contentSortInfo), testSortCallback, (void*)aSortState);
michael@0 279 }
michael@0 280
michael@0 281 // first remove the items from the old positions
michael@0 282 for (i = 0; i < numResults; i++) {
michael@0 283 nsIContent* child = items[i].content;
michael@0 284 nsIContent* parent = child->GetParent();
michael@0 285
michael@0 286 if (parent) {
michael@0 287 // remember the parent so that it can be reinserted back
michael@0 288 // into the same parent. This is necessary as multiple rules
michael@0 289 // may generate results which get placed in different locations.
michael@0 290 items[i].parent = parent;
michael@0 291 int32_t index = parent->IndexOf(child);
michael@0 292 parent->RemoveChildAt(index, true);
michael@0 293 }
michael@0 294 }
michael@0 295
michael@0 296 // now add the items back in sorted order
michael@0 297 for (i = 0; i < numResults; i++)
michael@0 298 {
michael@0 299 nsIContent* child = items[i].content;
michael@0 300 nsIContent* parent = items[i].parent;
michael@0 301 if (parent) {
michael@0 302 parent->AppendChildTo(child, true);
michael@0 303
michael@0 304 // if it's a container in a tree or menu, find its children,
michael@0 305 // and sort those also
michael@0 306 if (!child->AttrValueIs(kNameSpaceID_None, nsGkAtoms::container,
michael@0 307 nsGkAtoms::_true, eCaseMatters))
michael@0 308 continue;
michael@0 309
michael@0 310 for (nsIContent* grandchild = child->GetFirstChild();
michael@0 311 grandchild;
michael@0 312 grandchild = grandchild->GetNextSibling()) {
michael@0 313 nsINodeInfo *ni = grandchild->NodeInfo();
michael@0 314 nsIAtom *localName = ni->NameAtom();
michael@0 315 if (ni->NamespaceID() == kNameSpaceID_XUL &&
michael@0 316 (localName == nsGkAtoms::treechildren ||
michael@0 317 localName == nsGkAtoms::menupopup)) {
michael@0 318 SortContainer(grandchild, aSortState);
michael@0 319 }
michael@0 320 }
michael@0 321 }
michael@0 322 }
michael@0 323
michael@0 324 return NS_OK;
michael@0 325 }
michael@0 326
michael@0 327 nsresult
michael@0 328 XULSortServiceImpl::InvertSortInfo(nsTArray<contentSortInfo>& aData,
michael@0 329 int32_t aStart, int32_t aNumItems)
michael@0 330 {
michael@0 331 if (aNumItems > 1) {
michael@0 332 // reverse the items in the array starting from aStart
michael@0 333 int32_t upPoint = (aNumItems + 1) / 2 + aStart;
michael@0 334 int32_t downPoint = (aNumItems - 2) / 2 + aStart;
michael@0 335 int32_t half = aNumItems / 2;
michael@0 336 while (half-- > 0) {
michael@0 337 aData[downPoint--].swap(aData[upPoint++]);
michael@0 338 }
michael@0 339 }
michael@0 340 return NS_OK;
michael@0 341 }
michael@0 342
michael@0 343 nsresult
michael@0 344 XULSortServiceImpl::InitializeSortState(nsIContent* aRootElement,
michael@0 345 nsIContent* aContainer,
michael@0 346 const nsAString& aSortKey,
michael@0 347 const nsAString& aSortHints,
michael@0 348 nsSortState* aSortState)
michael@0 349 {
michael@0 350 // used as an optimization for the content builder
michael@0 351 if (aContainer != aSortState->lastContainer.get()) {
michael@0 352 aSortState->lastContainer = aContainer;
michael@0 353 aSortState->lastWasFirst = false;
michael@0 354 aSortState->lastWasLast = false;
michael@0 355 }
michael@0 356
michael@0 357 // The attributes allowed are either:
michael@0 358 // sort="key1 key2 ..."
michael@0 359 // or sortResource="key1" sortResource2="key2"
michael@0 360 // The latter is for backwards compatibility, and is equivalent to concatenating
michael@0 361 // both values in the sort attribute
michael@0 362 nsAutoString sort(aSortKey);
michael@0 363 aSortState->sortKeys.Clear();
michael@0 364 if (sort.IsEmpty()) {
michael@0 365 nsAutoString sortResource, sortResource2;
michael@0 366 aRootElement->GetAttr(kNameSpaceID_None, nsGkAtoms::sortResource, sortResource);
michael@0 367 if (!sortResource.IsEmpty()) {
michael@0 368 nsCOMPtr<nsIAtom> sortkeyatom = do_GetAtom(sortResource);
michael@0 369 aSortState->sortKeys.AppendObject(sortkeyatom);
michael@0 370 sort.Append(sortResource);
michael@0 371
michael@0 372 aRootElement->GetAttr(kNameSpaceID_None, nsGkAtoms::sortResource2, sortResource2);
michael@0 373 if (!sortResource2.IsEmpty()) {
michael@0 374 nsCOMPtr<nsIAtom> sortkeyatom2 = do_GetAtom(sortResource2);
michael@0 375 aSortState->sortKeys.AppendObject(sortkeyatom2);
michael@0 376 sort.AppendLiteral(" ");
michael@0 377 sort.Append(sortResource2);
michael@0 378 }
michael@0 379 }
michael@0 380 }
michael@0 381 else {
michael@0 382 nsWhitespaceTokenizer tokenizer(sort);
michael@0 383 while (tokenizer.hasMoreTokens()) {
michael@0 384 nsCOMPtr<nsIAtom> keyatom = do_GetAtom(tokenizer.nextToken());
michael@0 385 NS_ENSURE_TRUE(keyatom, NS_ERROR_OUT_OF_MEMORY);
michael@0 386 aSortState->sortKeys.AppendObject(keyatom);
michael@0 387 }
michael@0 388 }
michael@0 389
michael@0 390 aSortState->sort.Assign(sort);
michael@0 391 aSortState->direction = nsSortState_natural;
michael@0 392
michael@0 393 bool noNaturalState = false;
michael@0 394 nsWhitespaceTokenizer tokenizer(aSortHints);
michael@0 395 while (tokenizer.hasMoreTokens()) {
michael@0 396 const nsDependentSubstring& token(tokenizer.nextToken());
michael@0 397 if (token.EqualsLiteral("comparecase"))
michael@0 398 aSortState->sortHints |= nsIXULSortService::SORT_COMPARECASE;
michael@0 399 else if (token.EqualsLiteral("integer"))
michael@0 400 aSortState->sortHints |= nsIXULSortService::SORT_INTEGER;
michael@0 401 else if (token.EqualsLiteral("descending"))
michael@0 402 aSortState->direction = nsSortState_descending;
michael@0 403 else if (token.EqualsLiteral("ascending"))
michael@0 404 aSortState->direction = nsSortState_ascending;
michael@0 405 else if (token.EqualsLiteral("twostate"))
michael@0 406 noNaturalState = true;
michael@0 407 }
michael@0 408
michael@0 409 // if the twostate flag was set, the natural order is skipped and only
michael@0 410 // ascending and descending are allowed
michael@0 411 if (aSortState->direction == nsSortState_natural && noNaturalState) {
michael@0 412 aSortState->direction = nsSortState_ascending;
michael@0 413 }
michael@0 414
michael@0 415 // set up sort order info
michael@0 416 aSortState->invertSort = false;
michael@0 417
michael@0 418 nsAutoString existingsort;
michael@0 419 aRootElement->GetAttr(kNameSpaceID_None, nsGkAtoms::sort, existingsort);
michael@0 420 nsAutoString existingsortDirection;
michael@0 421 aRootElement->GetAttr(kNameSpaceID_None, nsGkAtoms::sortDirection, existingsortDirection);
michael@0 422
michael@0 423 // if just switching direction, set the invertSort flag
michael@0 424 if (sort.Equals(existingsort)) {
michael@0 425 if (aSortState->direction == nsSortState_descending) {
michael@0 426 if (existingsortDirection.EqualsLiteral("ascending"))
michael@0 427 aSortState->invertSort = true;
michael@0 428 }
michael@0 429 else if (aSortState->direction == nsSortState_ascending &&
michael@0 430 existingsortDirection.EqualsLiteral("descending")) {
michael@0 431 aSortState->invertSort = true;
michael@0 432 }
michael@0 433 }
michael@0 434
michael@0 435 // sort items between separators independently
michael@0 436 aSortState->inbetweenSeparatorSort =
michael@0 437 aRootElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::sortSeparators,
michael@0 438 nsGkAtoms::_true, eCaseMatters);
michael@0 439
michael@0 440 // sort static content (non template generated nodes) after generated content
michael@0 441 aSortState->sortStaticsLast = aRootElement->AttrValueIs(kNameSpaceID_None,
michael@0 442 nsGkAtoms::sortStaticsLast,
michael@0 443 nsGkAtoms::_true, eCaseMatters);
michael@0 444
michael@0 445 aSortState->initialized = true;
michael@0 446
michael@0 447 return NS_OK;
michael@0 448 }
michael@0 449
michael@0 450 int32_t
michael@0 451 XULSortServiceImpl::CompareValues(const nsAString& aLeft,
michael@0 452 const nsAString& aRight,
michael@0 453 uint32_t aSortHints)
michael@0 454 {
michael@0 455 if (aSortHints & SORT_INTEGER) {
michael@0 456 nsresult err;
michael@0 457 int32_t leftint = PromiseFlatString(aLeft).ToInteger(&err);
michael@0 458 if (NS_SUCCEEDED(err)) {
michael@0 459 int32_t rightint = PromiseFlatString(aRight).ToInteger(&err);
michael@0 460 if (NS_SUCCEEDED(err)) {
michael@0 461 return leftint - rightint;
michael@0 462 }
michael@0 463 }
michael@0 464 // if they aren't integers, just fall through and compare strings
michael@0 465 }
michael@0 466
michael@0 467 if (aSortHints & SORT_COMPARECASE) {
michael@0 468 return ::Compare(aLeft, aRight);
michael@0 469 }
michael@0 470
michael@0 471 nsICollation* collation = nsXULContentUtils::GetCollation();
michael@0 472 if (collation) {
michael@0 473 int32_t result;
michael@0 474 collation->CompareString(nsICollation::kCollationCaseInSensitive,
michael@0 475 aLeft, aRight, &result);
michael@0 476 return result;
michael@0 477 }
michael@0 478
michael@0 479 return ::Compare(aLeft, aRight, nsCaseInsensitiveStringComparator());
michael@0 480 }
michael@0 481
michael@0 482 NS_IMETHODIMP
michael@0 483 XULSortServiceImpl::Sort(nsIDOMNode* aNode,
michael@0 484 const nsAString& aSortKey,
michael@0 485 const nsAString& aSortHints)
michael@0 486 {
michael@0 487 // get root content node
michael@0 488 nsCOMPtr<nsIContent> sortNode = do_QueryInterface(aNode);
michael@0 489 if (!sortNode)
michael@0 490 return NS_ERROR_FAILURE;
michael@0 491
michael@0 492 nsSortState sortState;
michael@0 493 nsresult rv = InitializeSortState(sortNode, sortNode,
michael@0 494 aSortKey, aSortHints, &sortState);
michael@0 495 NS_ENSURE_SUCCESS(rv, rv);
michael@0 496
michael@0 497 // store sort info in attributes on content
michael@0 498 SetSortHints(sortNode, &sortState);
michael@0 499 rv = SortContainer(sortNode, &sortState);
michael@0 500
michael@0 501 sortState.processor = nullptr; // don't hang on to this reference
michael@0 502 return rv;
michael@0 503 }
michael@0 504
michael@0 505 nsresult
michael@0 506 NS_NewXULSortService(nsIXULSortService** sortService)
michael@0 507 {
michael@0 508 *sortService = new XULSortServiceImpl();
michael@0 509 if (!*sortService)
michael@0 510 return NS_ERROR_OUT_OF_MEMORY;
michael@0 511
michael@0 512 NS_ADDREF(*sortService);
michael@0 513 return NS_OK;
michael@0 514 }

mercurial