зеркало из https://github.com/mozilla/pjs.git
Bug 379745, add some additional template sort hint options to sort case-insensitive, sort by integers, and skip natural sort order, r=neil,sr=sicking
This commit is contained in:
Родитель
ce7169288e
Коммит
2a82f1fe95
|
@ -845,6 +845,7 @@ GK_ATOM(sort, "sort")
|
|||
GK_ATOM(sortActive, "sortActive")
|
||||
GK_ATOM(sortDirection, "sortDirection")
|
||||
GK_ATOM(sorted, "sorted")
|
||||
GK_ATOM(sorthints, "sorthints")
|
||||
GK_ATOM(sortLocked, "sortLocked")
|
||||
GK_ATOM(sortResource, "sortResource")
|
||||
GK_ATOM(sortResource2, "sortResource2")
|
||||
|
|
|
@ -45,6 +45,9 @@ interface nsIDOMNode;
|
|||
[scriptable, uuid(F29270C8-3BE5-4046-9B57-945A84DFF132)]
|
||||
interface nsIXULSortService : nsISupports
|
||||
{
|
||||
const unsigned long SORT_COMPARECASE = 0x0001;
|
||||
const unsigned long SORT_INTEGER = 0x0100;
|
||||
|
||||
/**
|
||||
* Sort the contents of the widget containing <code>aNode</code>
|
||||
* using <code>aSortKey</code> as the comparison key, and
|
||||
|
@ -52,14 +55,17 @@ interface nsIXULSortService : nsISupports
|
|||
*
|
||||
* @param aNode A node in the XUL widget whose children are to be sorted.
|
||||
* @param aSortKey The value to be used as the comparison key.
|
||||
* @param aSortDirection May be either <b>natural</b> to return
|
||||
* the contents to their natural (unsorted) order,
|
||||
* <b>ascending</b> to sort the contents in ascending order, or
|
||||
* <b>descending</b> to sort the contents in descending order.
|
||||
* @param aSortHints One or more hints as to how to sort:
|
||||
*
|
||||
* ascending: to sort the contents in ascending order
|
||||
* descending: to sort the contents in descending order
|
||||
* comparecase: perform case sensitive comparisons
|
||||
* integer: treat values as integers, non-integers are compared as strings
|
||||
* twostate: don't allow the natural (unordered state)
|
||||
*/
|
||||
void sort(in nsIDOMNode aNode,
|
||||
in AString aSortKey,
|
||||
in AString aSortDirection);
|
||||
in AString aSortHints);
|
||||
};
|
||||
|
||||
%{C++
|
||||
|
|
|
@ -107,7 +107,7 @@ interface nsIXULTemplateBuilder;
|
|||
* nsIRDFDataSource or a DOM node, and will always be the same one in between
|
||||
* calls to initializeForBuilding and done.
|
||||
*/
|
||||
[scriptable, uuid(970f1c36-5d2e-4cbc-a1cf-e3327b50df71)]
|
||||
[scriptable, uuid(C257573F-444F-468A-BA27-DE979DC55FE4)]
|
||||
interface nsIXULTemplateQueryProcessor : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -291,6 +291,8 @@ interface nsIXULTemplateQueryProcessor : nsISupports
|
|||
* sorted in a natural order, for instance, based on the order the data in
|
||||
* stored in the datasource.
|
||||
*
|
||||
* The sort hints are the flags in nsIXULSortService.
|
||||
*
|
||||
* This method must only be called with results that were created by this
|
||||
* query processor.
|
||||
*
|
||||
|
@ -302,5 +304,6 @@ interface nsIXULTemplateQueryProcessor : nsISupports
|
|||
*/
|
||||
PRInt32 compareResults(in nsIXULTemplateResult aLeft,
|
||||
in nsIXULTemplateResult aRight,
|
||||
in nsIAtom aVar);
|
||||
in nsIAtom aVar,
|
||||
in unsigned long aSortHints);
|
||||
};
|
||||
|
|
|
@ -1839,7 +1839,8 @@ nsXULContentBuilder::CompareResultToNode(nsIXULTemplateResult* aResult,
|
|||
if (mSortState.direction == nsSortState_natural) {
|
||||
// sort in natural order
|
||||
nsresult rv = mQueryProcessor->CompareResults(aResult, match->mResult,
|
||||
nsnull, aSortOrder);
|
||||
nsnull, mSortState.sortHints,
|
||||
aSortOrder);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
else {
|
||||
|
@ -1848,7 +1849,8 @@ nsXULContentBuilder::CompareResultToNode(nsIXULTemplateResult* aResult,
|
|||
PRInt32 length = mSortState.sortKeys.Count();
|
||||
for (PRInt32 t = 0; t < length; t++) {
|
||||
nsresult rv = mQueryProcessor->CompareResults(aResult, match->mResult,
|
||||
mSortState.sortKeys[t], aSortOrder);
|
||||
mSortState.sortKeys[t],
|
||||
mSortState.sortHints, aSortOrder);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (*aSortOrder)
|
||||
|
@ -1872,9 +1874,12 @@ nsXULContentBuilder::InsertSortedNode(nsIContent* aContainer,
|
|||
nsresult rv;
|
||||
|
||||
if (!mSortState.initialized) {
|
||||
nsAutoString sort, sortDirection;
|
||||
nsAutoString sort, sortDirection, sortHints;
|
||||
mRoot->GetAttr(kNameSpaceID_None, nsGkAtoms::sort, sort);
|
||||
mRoot->GetAttr(kNameSpaceID_None, nsGkAtoms::sortDirection, sortDirection);
|
||||
mRoot->GetAttr(kNameSpaceID_None, nsGkAtoms::sorthints, sortHints);
|
||||
sortDirection.AppendLiteral(" ");
|
||||
sortDirection += sortHints;
|
||||
rv = XULSortServiceImpl::InitializeSortState(mRoot, aContainer,
|
||||
sort, sortDirection, &mSortState);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
|
|
@ -72,6 +72,8 @@
|
|||
#include "nsIDOMXULElement.h"
|
||||
#include "nsIXULTemplateBuilder.h"
|
||||
#include "nsTemplateMatch.h"
|
||||
#include "nsICollation.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS1(XULSortServiceImpl, nsIXULSortService)
|
||||
|
||||
|
@ -156,7 +158,7 @@ XULSortServiceImpl::GetItemsToSort(nsIContent *aContainer,
|
|||
if (builder) {
|
||||
nsresult rv = builder->GetQueryProcessor(getter_AddRefs(aSortState->processor));
|
||||
if (NS_FAILED(rv) || !aSortState->processor)
|
||||
return rv;
|
||||
return rv;
|
||||
|
||||
return GetTemplateItemsToSort(aContainer, builder, aSortState, aSortItems);
|
||||
}
|
||||
|
@ -174,7 +176,7 @@ XULSortServiceImpl::GetItemsToSort(nsIContent *aContainer,
|
|||
return NS_OK;
|
||||
|
||||
aContainer = treechildren;
|
||||
}
|
||||
}
|
||||
|
||||
PRUint32 count = aContainer->GetChildCount();
|
||||
for (PRUint32 c = 0; c < count; c++) {
|
||||
|
@ -185,9 +187,9 @@ XULSortServiceImpl::GetItemsToSort(nsIContent *aContainer,
|
|||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
cinfo->content = child;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
@ -214,7 +216,7 @@ XULSortServiceImpl::GetTemplateItemsToSort(nsIContent* aContainer,
|
|||
|
||||
cinfo->content = child;
|
||||
cinfo->result = result;
|
||||
}
|
||||
}
|
||||
else if (aContainer->Tag() != nsGkAtoms::_template) {
|
||||
rv = GetTemplateItemsToSort(child, aBuilder, aSortState, aSortItems);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -237,7 +239,7 @@ testSortCallback(const void *data1, const void *data2, void *privateData)
|
|||
if (sortState->direction == nsSortState_natural && sortState->processor) {
|
||||
// sort in natural order
|
||||
sortState->processor->CompareResults(left->result, right->result,
|
||||
nsnull, &sortOrder);
|
||||
nsnull, sortState->sortHints, &sortOrder);
|
||||
}
|
||||
else {
|
||||
PRInt32 length = sortState->sortKeys.Count();
|
||||
|
@ -245,21 +247,19 @@ testSortCallback(const void *data1, const void *data2, void *privateData)
|
|||
// for templates, use the query processor to do sorting
|
||||
if (sortState->processor) {
|
||||
sortState->processor->CompareResults(left->result, right->result,
|
||||
sortState->sortKeys[t], &sortOrder);
|
||||
sortState->sortKeys[t],
|
||||
sortState->sortHints, &sortOrder);
|
||||
if (sortOrder)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// no template, so just compare attributes. Ignore namespaces for now.
|
||||
nsAutoString leftstr, rightstr;
|
||||
left->content->GetAttr(kNameSpaceID_None, sortState->sortKeys[t], leftstr);
|
||||
right->content->GetAttr(kNameSpaceID_None, sortState->sortKeys[t], rightstr);
|
||||
|
||||
if (!leftstr.Equals(rightstr)) {
|
||||
sortOrder = (leftstr > rightstr) ? 1 : -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
sortOrder = XULSortServiceImpl::CompareValues(leftstr, rightstr, sortState->sortHints);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -297,18 +297,18 @@ XULSortServiceImpl::SortContainer(nsIContent *aContainer, nsSortState* aSortStat
|
|||
sizeof(contentSortInfo), testSortCallback, (void*)aSortState);
|
||||
|
||||
startIndex = i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (i > startIndex + 1) {
|
||||
if (aSortState->invertSort)
|
||||
InvertSortInfo(items, startIndex, i - startIndex);
|
||||
else
|
||||
else
|
||||
NS_QuickSort((void *)(items.Elements() + startIndex), i - startIndex,
|
||||
sizeof(contentSortInfo), testSortCallback, (void*)aSortState);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
} else {
|
||||
// if the items are just being inverted, that is, just switching between
|
||||
// ascending and descending, just reverse the list.
|
||||
if (aSortState->invertSort)
|
||||
|
@ -330,8 +330,8 @@ XULSortServiceImpl::SortContainer(nsIContent *aContainer, nsSortState* aSortStat
|
|||
items[i].parent = parent;
|
||||
PRInt32 index = parent->IndexOf(child);
|
||||
parent->RemoveChildAt(index, PR_TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now add the items back in sorted order
|
||||
for (i = 0; i < numResults; i++)
|
||||
|
@ -384,7 +384,7 @@ nsresult
|
|||
XULSortServiceImpl::InitializeSortState(nsIContent* aRootElement,
|
||||
nsIContent* aContainer,
|
||||
const nsAString& aSortKey,
|
||||
const nsAString& aSortDirection,
|
||||
const nsAString& aSortHints,
|
||||
nsSortState* aSortState)
|
||||
{
|
||||
// used as an optimization for the content builder
|
||||
|
@ -428,17 +428,33 @@ XULSortServiceImpl::InitializeSortState(nsIContent* aRootElement,
|
|||
}
|
||||
|
||||
aSortState->sort.Assign(sort);
|
||||
aSortState->direction = nsSortState_natural;
|
||||
|
||||
PRBool noNaturalState = PR_FALSE;
|
||||
nsWhitespaceTokenizer tokenizer(aSortHints);
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
const nsDependentSubstring& token(tokenizer.nextToken());
|
||||
if (token.EqualsLiteral("comparecase"))
|
||||
aSortState->sortHints |= nsIXULSortService::SORT_COMPARECASE;
|
||||
else if (token.EqualsLiteral("integer"))
|
||||
aSortState->sortHints |= nsIXULSortService::SORT_INTEGER;
|
||||
else if (token.EqualsLiteral("descending"))
|
||||
aSortState->direction = nsSortState_descending;
|
||||
else if (token.EqualsLiteral("ascending"))
|
||||
aSortState->direction = nsSortState_ascending;
|
||||
else if (token.EqualsLiteral("twostate"))
|
||||
noNaturalState = PR_TRUE;
|
||||
}
|
||||
|
||||
// if the twostate flag was set, the natural order is skipped and only
|
||||
// ascending and descending are allowed
|
||||
if (aSortState->direction == nsSortState_natural && noNaturalState) {
|
||||
aSortState->direction = nsSortState_ascending;
|
||||
}
|
||||
|
||||
// set up sort order info
|
||||
if (aSortDirection.EqualsLiteral("descending"))
|
||||
aSortState->direction = nsSortState_descending;
|
||||
else if (aSortDirection.EqualsLiteral("ascending"))
|
||||
aSortState->direction = nsSortState_ascending;
|
||||
else
|
||||
aSortState->direction = nsSortState_natural;
|
||||
|
||||
aSortState->invertSort = PR_FALSE;
|
||||
|
||||
|
||||
nsAutoString existingsort;
|
||||
aRootElement->GetAttr(kNameSpaceID_None, nsGkAtoms::sort, existingsort);
|
||||
nsAutoString existingsortDirection;
|
||||
|
@ -449,14 +465,14 @@ XULSortServiceImpl::InitializeSortState(nsIContent* aRootElement,
|
|||
if (aSortState->direction == nsSortState_descending) {
|
||||
if (existingsortDirection.EqualsLiteral("ascending"))
|
||||
aSortState->invertSort = PR_TRUE;
|
||||
}
|
||||
}
|
||||
else if (aSortState->direction == nsSortState_ascending &&
|
||||
existingsortDirection.EqualsLiteral("descending")) {
|
||||
existingsortDirection.EqualsLiteral("descending")) {
|
||||
aSortState->invertSort = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// sort items between separatore independently
|
||||
// sort items between separators independently
|
||||
aSortState->inbetweenSeparatorSort =
|
||||
aRootElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::sortSeparators,
|
||||
nsGkAtoms::_true, eCaseMatters);
|
||||
|
@ -471,10 +487,42 @@ XULSortServiceImpl::InitializeSortState(nsIContent* aRootElement,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
PRInt32
|
||||
XULSortServiceImpl::CompareValues(const nsAString& aLeft,
|
||||
const nsAString& aRight,
|
||||
PRUint32 aSortHints)
|
||||
{
|
||||
if (aSortHints & SORT_INTEGER) {
|
||||
PRInt32 err;
|
||||
PRInt32 leftint = nsDependentString(aLeft).ToInteger(&err);
|
||||
if (NS_SUCCEEDED(err)) {
|
||||
PRInt32 rightint = nsDependentString(aRight).ToInteger(&err);
|
||||
if (NS_SUCCEEDED(err)) {
|
||||
return leftint - rightint;
|
||||
}
|
||||
}
|
||||
// if they aren't integers, just fall through and compare strings
|
||||
}
|
||||
|
||||
if (aSortHints & SORT_COMPARECASE) {
|
||||
return ::Compare(aLeft, aRight);
|
||||
}
|
||||
|
||||
nsICollation* collation = nsXULContentUtils::GetCollation();
|
||||
if (collation) {
|
||||
PRInt32 result;
|
||||
collation->CompareString(nsICollation::kCollationCaseInSensitive,
|
||||
aLeft, aRight, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
return ::Compare(aLeft, aRight, nsCaseInsensitiveStringComparator());
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
XULSortServiceImpl::Sort(nsIDOMNode* aNode,
|
||||
const nsAString& aSortKey,
|
||||
const nsAString& aSortDirection)
|
||||
const nsAString& aSortHints)
|
||||
{
|
||||
// get root content node
|
||||
nsCOMPtr<nsIContent> sortNode = do_QueryInterface(aNode);
|
||||
|
@ -483,7 +531,7 @@ XULSortServiceImpl::Sort(nsIDOMNode* aNode,
|
|||
|
||||
nsSortState sortState;
|
||||
nsresult rv = InitializeSortState(sortNode, sortNode,
|
||||
aSortKey, aSortDirection, &sortState);
|
||||
aSortKey, aSortHints, &sortState);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// store sort info in attributes on content
|
||||
|
|
|
@ -80,6 +80,8 @@ struct nsSortState
|
|||
PRBool sortStaticsLast;
|
||||
PRBool isContainerRDFSeq;
|
||||
|
||||
PRUint32 sortHints;
|
||||
|
||||
nsSortState_direction direction;
|
||||
nsAutoString sort;
|
||||
nsCOMArray<nsIAtom> sortKeys;
|
||||
|
@ -89,7 +91,8 @@ struct nsSortState
|
|||
PRBool lastWasFirst, lastWasLast;
|
||||
|
||||
nsSortState()
|
||||
: initialized(PR_FALSE)
|
||||
: initialized(PR_FALSE),
|
||||
sortHints(0)
|
||||
{
|
||||
}
|
||||
void Traverse(nsCycleCollectionTraversalCallback &cb) const
|
||||
|
@ -203,4 +206,12 @@ public:
|
|||
const nsAString& aSortKey,
|
||||
const nsAString& aSortDirection,
|
||||
nsSortState* aSortState);
|
||||
|
||||
/**
|
||||
* Compares aLeft and aRight and returns < 0, 0, or > 0. The sort
|
||||
* hints are checked for case matching and integer sorting.
|
||||
*/
|
||||
static PRInt32 CompareValues(const nsAString& aLeft,
|
||||
const nsAString& aRight,
|
||||
PRUint32 aSortHints);
|
||||
};
|
||||
|
|
|
@ -55,7 +55,6 @@
|
|||
#include "nsGkAtoms.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIXULDocument.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsAttrName.h"
|
||||
#include "rdf.h"
|
||||
#include "nsArrayUtils.h"
|
||||
|
@ -71,6 +70,7 @@
|
|||
#include "nsXULTemplateResultRDF.h"
|
||||
#include "nsXULTemplateResultSetRDF.h"
|
||||
#include "nsXULTemplateQueryProcessorRDF.h"
|
||||
#include "nsXULSortService.h"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
|
@ -654,6 +654,7 @@ NS_IMETHODIMP
|
|||
nsXULTemplateQueryProcessorRDF::CompareResults(nsIXULTemplateResult* aLeft,
|
||||
nsIXULTemplateResult* aRight,
|
||||
nsIAtom* aVar,
|
||||
PRUint32 aSortHints,
|
||||
PRInt32* aResult)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aLeft);
|
||||
|
@ -704,7 +705,7 @@ nsXULTemplateQueryProcessorRDF::CompareResults(nsIXULTemplateResult* aLeft,
|
|||
else {
|
||||
// get the values for the sort key from the results
|
||||
aLeft->GetBindingObjectFor(aVar, getter_AddRefs(leftNode));
|
||||
aRight->GetBindingObjectFor(aVar, getter_AddRefs(rightNode));
|
||||
aRight->GetBindingObjectFor(aVar, getter_AddRefs(rightNode));
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -717,18 +718,12 @@ nsXULTemplateQueryProcessorRDF::CompareResults(nsIXULTemplateResult* aLeft,
|
|||
l->GetValueConst(&lstr);
|
||||
r->GetValueConst(&rstr);
|
||||
|
||||
nsICollation* collation = nsXULContentUtils::GetCollation();
|
||||
if (collation) {
|
||||
collation->CompareString(nsICollation::kCollationCaseInSensitive,
|
||||
nsDependentString(lstr),
|
||||
nsDependentString(rstr),
|
||||
aResult);
|
||||
}
|
||||
else
|
||||
*aResult = ::Compare(nsDependentString(lstr),
|
||||
nsDependentString(rstr),
|
||||
nsCaseInsensitiveStringComparator());
|
||||
*aResult = XULSortServiceImpl::CompareValues(
|
||||
nsDependentString(lstr),
|
||||
nsDependentString(rstr), aSortHints);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -752,6 +747,8 @@ nsXULTemplateQueryProcessorRDF::CompareResults(nsIXULTemplateResult* aLeft,
|
|||
else
|
||||
*aResult = -1;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -767,6 +764,8 @@ nsXULTemplateQueryProcessorRDF::CompareResults(nsIXULTemplateResult* aLeft,
|
|||
|
||||
*aResult = lval - rval;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
#include "nsXULTemplateBuilder.h"
|
||||
#include "nsXULTemplateResultStorage.h"
|
||||
#include "nsXULContentUtils.h"
|
||||
#include "nsXULSortService.h"
|
||||
|
||||
#include "mozIStorageService.h"
|
||||
|
||||
|
@ -468,6 +469,7 @@ NS_IMETHODIMP
|
|||
nsXULTemplateQueryProcessorStorage::CompareResults(nsIXULTemplateResult* aLeft,
|
||||
nsIXULTemplateResult* aRight,
|
||||
nsIAtom* aVar,
|
||||
PRUint32 aSortHints,
|
||||
PRInt32* aResult)
|
||||
{
|
||||
*aResult = 0;
|
||||
|
@ -524,14 +526,12 @@ nsXULTemplateQueryProcessorStorage::CompareResults(nsIXULTemplateResult* aLeft,
|
|||
// Values are not integers or floats, so we just compare them as simple strings
|
||||
nsAutoString leftVal;
|
||||
if (aLeft)
|
||||
aLeft->GetBindingFor(aVar, leftVal);
|
||||
aLeft->GetBindingFor(aVar, leftVal);
|
||||
|
||||
nsAutoString rightVal;
|
||||
if (aRight)
|
||||
aRight->GetBindingFor(aVar, rightVal);
|
||||
aRight->GetBindingFor(aVar, rightVal);
|
||||
|
||||
*aResult = Compare(nsDependentString(leftVal),
|
||||
nsDependentString(rightVal),
|
||||
nsCaseInsensitiveStringComparator());
|
||||
*aResult = XULSortServiceImpl::CompareValues(leftVal, rightVal, aSortHints);
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
#include "nsXULTemplateBuilder.h"
|
||||
#include "nsXULTemplateQueryProcessorXML.h"
|
||||
#include "nsXULTemplateResultXML.h"
|
||||
#include "nsXULSortService.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsXMLQuery, nsXMLQuery)
|
||||
|
||||
|
@ -428,27 +429,22 @@ NS_IMETHODIMP
|
|||
nsXULTemplateQueryProcessorXML::CompareResults(nsIXULTemplateResult* aLeft,
|
||||
nsIXULTemplateResult* aRight,
|
||||
nsIAtom* aVar,
|
||||
PRUint32 aSortHints,
|
||||
PRInt32* aResult)
|
||||
{
|
||||
*aResult = 0;
|
||||
if (!aVar)
|
||||
return NS_OK;
|
||||
|
||||
// XXXndeakin - bug 379745
|
||||
// it would be good for this to handle other types such as integers,
|
||||
// so that sorting can be optimized for different types.
|
||||
return NS_OK;
|
||||
|
||||
nsAutoString leftVal;
|
||||
if (aLeft)
|
||||
aLeft->GetBindingFor(aVar, leftVal);
|
||||
aLeft->GetBindingFor(aVar, leftVal);
|
||||
|
||||
nsAutoString rightVal;
|
||||
if (aRight)
|
||||
aRight->GetBindingFor(aVar, rightVal);
|
||||
aRight->GetBindingFor(aVar, rightVal);
|
||||
|
||||
// currently templates always sort case-insensitive
|
||||
*aResult = ::Compare(leftVal, rightVal,
|
||||
nsCaseInsensitiveStringComparator());
|
||||
*aResult = XULSortServiceImpl::CompareValues(leftVal, rightVal, aSortHints);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -59,10 +59,12 @@
|
|||
#include "nsGkAtoms.h"
|
||||
#include "nsXULContentUtils.h"
|
||||
#include "nsXULTemplateBuilder.h"
|
||||
#include "nsIXULSortService.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsINameSpaceManager.h"
|
||||
#include "nsIDOMClassInfo.h"
|
||||
#include "nsWhitespaceTokenizer.h"
|
||||
|
||||
// For security check
|
||||
#include "nsIDocument.h"
|
||||
|
@ -262,6 +264,11 @@ protected:
|
|||
*/
|
||||
Direction mSortDirection;
|
||||
|
||||
/*
|
||||
* Sort hints (compare case, etc)
|
||||
*/
|
||||
PRUint32 mSortHints;
|
||||
|
||||
/**
|
||||
* The builder observers.
|
||||
*/
|
||||
|
@ -308,7 +315,7 @@ NS_INTERFACE_MAP_END_INHERITING(nsXULTemplateBuilder)
|
|||
|
||||
|
||||
nsXULTreeBuilder::nsXULTreeBuilder()
|
||||
: mSortDirection(eDirection_Natural)
|
||||
: mSortDirection(eDirection_Natural), mSortHints(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -395,6 +402,21 @@ nsXULTreeBuilder::Sort(nsIDOMElement* aElement)
|
|||
// Grab the new sort variable
|
||||
mSortVariable = do_GetAtom(sort);
|
||||
|
||||
nsAutoString hints;
|
||||
header->GetAttr(kNameSpaceID_None, nsGkAtoms::sorthints, hints);
|
||||
|
||||
PRBool hasNaturalState = PR_TRUE;
|
||||
nsWhitespaceTokenizer tokenizer(hints);
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
const nsDependentSubstring& token(tokenizer.nextToken());
|
||||
if (token.EqualsLiteral("comparecase"))
|
||||
mSortHints |= nsIXULSortService::SORT_COMPARECASE;
|
||||
else if (token.EqualsLiteral("integer"))
|
||||
mSortHints |= nsIXULSortService::SORT_INTEGER;
|
||||
else if (token.EqualsLiteral("twostate"))
|
||||
hasNaturalState = PR_FALSE;
|
||||
}
|
||||
|
||||
// Cycle the sort direction
|
||||
nsAutoString dir;
|
||||
header->GetAttr(kNameSpaceID_None, nsGkAtoms::sortDirection, dir);
|
||||
|
@ -403,7 +425,7 @@ nsXULTreeBuilder::Sort(nsIDOMElement* aElement)
|
|||
dir.AssignLiteral("descending");
|
||||
mSortDirection = eDirection_Descending;
|
||||
}
|
||||
else if (dir.EqualsLiteral("descending")) {
|
||||
else if (hasNaturalState && dir.EqualsLiteral("descending")) {
|
||||
dir.AssignLiteral("natural");
|
||||
mSortDirection = eDirection_Natural;
|
||||
}
|
||||
|
@ -1865,7 +1887,7 @@ nsXULTreeBuilder::CompareResults(nsIXULTemplateResult* aLeft, nsIXULTemplateResu
|
|||
}
|
||||
|
||||
PRInt32 sortorder;
|
||||
mQueryProcessor->CompareResults(aLeft, aRight, mSortVariable, &sortorder);
|
||||
mQueryProcessor->CompareResults(aLeft, aRight, mSortVariable, mSortHints, &sortorder);
|
||||
|
||||
if (sortorder)
|
||||
sortorder = sortorder * mSortDirection;
|
||||
|
|
|
@ -49,6 +49,7 @@ _TEST_FILES = \
|
|||
test_bug441785.xul \
|
||||
bug441785-1.rdf \
|
||||
bug441785-2.rdf \
|
||||
test_sortservice.xul \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -140,6 +140,7 @@ _TEST_FILES = \
|
|||
test_tmpl_simplesyntaxfilter.xul \
|
||||
test_tmpl_sortascendingquerysyntax.xul \
|
||||
test_tmpl_sortdescendingquerysyntax.xul \
|
||||
test_tmpl_sortascendinginteger.xul \
|
||||
test_tmpl_sortunknownascendingquerysyntax.xul \
|
||||
test_tmpl_sortresourceascendingquerysyntax.xul \
|
||||
test_tmpl_sortresourcedescendingquerysyntax.xul \
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
|
||||
|
||||
<!--
|
||||
sort ascending - integers
|
||||
-->
|
||||
|
||||
<window title="XUL Template Tests" width="500" height="600"
|
||||
onload="test_template();"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
|
||||
|
||||
<script src="templates_shared.js"/>
|
||||
|
||||
<script>
|
||||
<![CDATA[
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var testid ="sort ascending - integers";
|
||||
var queryType = "rdf";
|
||||
var isTreeBuilder = false;
|
||||
var needsOpen = false;
|
||||
var notWorkingYet = false;
|
||||
var notWorkingYetDynamic = false;
|
||||
var expectedOutput =
|
||||
<output>
|
||||
<label id="http://www.some-fictitious-zoo.com/mammals/ninebandedarmadillo" value="Nine-banded Armadillo"/>
|
||||
<label id="http://www.some-fictitious-zoo.com/mammals/aardvark" value="aardvark"/>
|
||||
<label id="http://www.some-fictitious-zoo.com/mammals/hippopotamus" value="HIPPOPOTAMUS"/>
|
||||
<label id="http://www.some-fictitious-zoo.com/mammals/lion" value="Lion"/>
|
||||
<label step="-1" id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/>
|
||||
<label id="http://www.some-fictitious-zoo.com/mammals/gorilla" value="Gorilla"/>
|
||||
<label step="1" id="http://www.some-fictitious-zoo.com/mammals/llama" value="LLAMA"/>
|
||||
<label id="http://www.some-fictitious-zoo.com/mammals/africanelephant" value="African Elephant"/>
|
||||
<label id="http://www.some-fictitious-zoo.com/mammals/polarbear" value="Polar Bear"/>
|
||||
</output>;
|
||||
|
||||
var changes = [
|
||||
// step 1
|
||||
function(targetds, root) {
|
||||
var subject = RDF.GetResource(ZOO_NS + 'mammals/llama');
|
||||
var predicate = RDF.GetResource(ZOO_NS + 'rdf#specimensAsString');
|
||||
var oldval = targetds.GetTarget(subject, predicate, true);
|
||||
targetds.Change(subject, predicate, oldval, RDF.GetLiteral('12'), true);
|
||||
}
|
||||
];
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" id="root" datasources="animals.rdf"
|
||||
ref="http://www.some-fictitious-zoo.com/mammals" sort="?specimens ?name" sortDirection="ascending" sorthints="integer">
|
||||
<template id="template">
|
||||
<query id="query">
|
||||
<content uri="?uri"/>
|
||||
<member container="?uri" child="?animal"/>
|
||||
<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/>
|
||||
<triple subject="?animal" predicate="http://www.some-fictitious-zoo.com/rdf#specimensAsString" object="?specimens"/>
|
||||
</query>
|
||||
<action id="action">
|
||||
<label uri="?animal" value="?name"/>
|
||||
</action>
|
||||
</template>
|
||||
</vbox>
|
||||
|
||||
</window>
|
|
@ -0,0 +1,73 @@
|
|||
<?xml version="1.0" ?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<vbox id="box"/>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>
|
||||
|
||||
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
|
||||
<script type="application/x-javascript">
|
||||
<![CDATA[
|
||||
|
||||
var tests = [
|
||||
[["One", "Two", "Three", "Four"], "", ["Four One Three Two"]],
|
||||
[["One", "Two", "Three", "Four"], "integer", ["Four One Three Two"]],
|
||||
[["One", "Two", "Three", "Four"], "descending", ["Two Three One Four"]],
|
||||
[["One", "Two", "Three", "Four"], "descending integer", ["Two Three One Four"]],
|
||||
[["One", "Two", "Three", "Four"], "integer cat descending", ["Two Three One Four"]],
|
||||
[["1", "13", "2", "7", "12", "240", "2", "170", "222", "98"], "", ["1 12 13 170 2 2 222 240 7 98"]],
|
||||
[["1", "13", "2", "7", "12", "240", "2", "170", "222", "98"], "integer", ["1 2 2 7 12 13 98 170 222 240"]],
|
||||
[["1", "13", "2", "7", "12", "240", "2", "170", "222", "98"], "ascending integer", ["1 2 2 7 12 13 98 170 222 240"]],
|
||||
[["1", "13", "2", "7", "12", "240", "2", "170", "222", "98"], "integer descending", ["240 222 170 98 13 12 7 2 2 1"]],
|
||||
[["Cat", "cat", "Candy", "candy"], "comparecase", ["Candy Cat candy cat"]],
|
||||
[["1", "102", "22", "One", "40", "Two"], "integer", ["1 22 40 102 One Two"]],
|
||||
];
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function doTests()
|
||||
{
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
|
||||
var box = document.getElementById("box");
|
||||
|
||||
const sortService = Components.classes["@mozilla.org/xul/xul-sort-service;1"].
|
||||
getService(Components.interfaces.nsIXULSortService);
|
||||
|
||||
for (let t = 0; t < tests.length; t++) {
|
||||
var test = tests[t];
|
||||
|
||||
for (let e = 0; e < test[0].length; e++) {
|
||||
var label = document.createElement("label");
|
||||
label.setAttribute("value", test[0][e]);
|
||||
box.appendChild(label);
|
||||
}
|
||||
|
||||
sortService.sort(box, "value", test[1]);
|
||||
|
||||
var actual = "";
|
||||
for (let e = 0; e < box.childNodes.length; e++) {
|
||||
if (actual)
|
||||
actual += " ";
|
||||
actual += box.childNodes[e].getAttribute("value");
|
||||
}
|
||||
is(actual, test[2], "sorted step " + (t + 1));
|
||||
|
||||
while(box.hasChildNodes())
|
||||
box.removeChild(box.firstChild);
|
||||
box.removeAttribute("sortDirection");
|
||||
}
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
window.addEventListener("load", doTests, false);
|
||||
|
||||
]]>
|
||||
</script>
|
||||
</window>
|
|
@ -635,6 +635,11 @@ nsTreeContentView::CycleHeader(nsITreeColumn* aCol)
|
|||
default: sortdirection.AssignLiteral("ascending"); break;
|
||||
}
|
||||
|
||||
nsAutoString hints;
|
||||
column->GetAttr(kNameSpaceID_None, nsGkAtoms::sorthints, hints);
|
||||
sortdirection.AppendLiteral(" ");
|
||||
sortdirection += hints;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> rootnode = do_QueryInterface(mRoot);
|
||||
xs->Sort(rootnode, sort, sortdirection);
|
||||
}
|
||||
|
|
|
@ -1031,6 +1031,20 @@ function testtag_tree_TreeView_rows_sort(tree, testid, rowInfo)
|
|||
// Check we have gone back to natural sorting.
|
||||
is(columnElement.getAttribute("sortDirection"), "",
|
||||
"cycleHeader column sortDirection");
|
||||
|
||||
columnElement.setAttribute("sorthints", "twostate");
|
||||
view.cycleHeader(column);
|
||||
is(tree.getAttribute("sortDirection"), "ascending", "cycleHeader sortDirection ascending twostate");
|
||||
view.cycleHeader(column);
|
||||
is(tree.getAttribute("sortDirection"), "descending", "cycleHeader sortDirection ascending twostate");
|
||||
view.cycleHeader(column);
|
||||
is(tree.getAttribute("sortDirection"), "ascending", "cycleHeader sortDirection ascending twostate again");
|
||||
columnElement.removeAttribute("sorthints");
|
||||
view.cycleHeader(column);
|
||||
view.cycleHeader(column);
|
||||
|
||||
is(columnElement.getAttribute("sortDirection"), "",
|
||||
"cycleHeader column sortDirection reset");
|
||||
}
|
||||
|
||||
// checks if the current and selected rows are correct
|
||||
|
|
Загрузка…
Ссылка в новой задаче