diff --git a/content/xul/templates/src/nsOutlinerRows.cpp b/content/xul/templates/src/nsOutlinerRows.cpp index a7c29e3d639..f6cee2c971b 100644 --- a/content/xul/templates/src/nsOutlinerRows.cpp +++ b/content/xul/templates/src/nsOutlinerRows.cpp @@ -345,8 +345,10 @@ nsOutlinerRows::iterator::Next() // If there are no unfinished subtrees in the stack, then this // iterator is exhausted. Leave it in the same state that // Last() does. - if (unfinished < 0) + if (unfinished < 0) { + top.mChildIndex++; return; + } // Otherwise, we ran off the end of one of the inner // subtrees. Pop up to the next unfinished level in the stack. diff --git a/content/xul/templates/src/nsTreeRows.cpp b/content/xul/templates/src/nsTreeRows.cpp index a7c29e3d639..f6cee2c971b 100644 --- a/content/xul/templates/src/nsTreeRows.cpp +++ b/content/xul/templates/src/nsTreeRows.cpp @@ -345,8 +345,10 @@ nsOutlinerRows::iterator::Next() // If there are no unfinished subtrees in the stack, then this // iterator is exhausted. Leave it in the same state that // Last() does. - if (unfinished < 0) + if (unfinished < 0) { + top.mChildIndex++; return; + } // Otherwise, we ran off the end of one of the inner // subtrees. Pop up to the next unfinished level in the stack. diff --git a/content/xul/templates/src/nsXULOutlinerBuilder.cpp b/content/xul/templates/src/nsXULOutlinerBuilder.cpp index ffe645f9baf..ee2e63acfa5 100644 --- a/content/xul/templates/src/nsXULOutlinerBuilder.cpp +++ b/content/xul/templates/src/nsXULOutlinerBuilder.cpp @@ -236,7 +236,7 @@ protected: enum Direction { eDirection_Descending = -1, - eDirection_None = 0, + eDirection_Natural = 0, eDirection_Ascending = +1 }; @@ -282,7 +282,7 @@ NS_IMPL_ISUPPORTS_INHERITED2(nsXULOutlinerBuilder, nsXULTemplateBuilder, nsXULOutlinerBuilder::nsXULOutlinerBuilder() : mSortVariable(0), - mSortDirection(eDirection_None) + mSortDirection(eDirection_Natural) { } @@ -611,7 +611,7 @@ nsXULOutlinerBuilder::CycleHeader(const PRUnichar* aColID, nsIDOMElement* aEleme } else if (dir == NS_LITERAL_STRING("descending")) { dir = NS_LITERAL_STRING("natural"); - mSortDirection = eDirection_None; + mSortDirection = eDirection_Natural; } else { dir = NS_LITERAL_STRING("ascending"); @@ -796,7 +796,7 @@ nsXULOutlinerBuilder::ReplaceMatch(nsIRDFResource* aMember, // By default, place the new element at the end of the container PRInt32 index = parent->Count(); - if (mSortVariable && mSortDirection != eDirection_None) { + if (mSortVariable) { // Figure out where to put the new element by doing an // insertion sort. PRInt32 left = 0; @@ -892,7 +892,7 @@ nsXULOutlinerBuilder::GetSortVariables(VariableSet& aVariables) child->GetAttribute(kNameSpaceID_None, nsXULAtoms::sortDirection, dir); if (dir == NS_LITERAL_STRING("none")) - mSortDirection = eDirection_None; + mSortDirection = eDirection_Natural; else if (dir == NS_LITERAL_STRING("descending")) mSortDirection = eDirection_Descending; else @@ -1241,7 +1241,7 @@ nsXULOutlinerBuilder::OpenSubtreeOf(nsOutlinerRows::Subtree* aSubtree, } // Sort the container. - if (mSortVariable && mSortDirection != eDirection_None) { + if (mSortVariable) { NS_QuickSort(mRows.GetRowsFor(aSubtree), aSubtree->Count(), sizeof(nsOutlinerRows::Row), @@ -1350,6 +1350,60 @@ nsXULOutlinerBuilder::CompareMatches(nsTemplateMatch* aLeft, nsTemplateMatch* aR { PRInt32 result = 0; + if (mSortDirection == eDirection_Natural) { + // If the sort order is ``natural'', then see if the container + // is an RDF sequence. If so, we'll try to use the ordinal + // properties to determine order. + // + // XXX the problem with this is, it doesn't always get the + // *real* container; e.g., + // + // + // + // + // + // + // + // In this case mContainerVar is bound to ?uri, not + // ?subheadings. (The ``container'' in the template sense != + // container in the RDF sense.) + Value val; + aLeft->GetAssignmentFor(mConflictSet, mContainerVar, &val); + + nsIRDFResource* container = VALUE_TO_IRDFRESOURCE(val); + + PRBool isSequence = PR_FALSE; + gRDFContainerUtils->IsSeq(mDB, container, &isSequence); + if (! isSequence) + // If it's not an RDF container, then there's no natural + // order. + return 0; + + // Determine the indices of the left and right elements in the + // container. + Value left; + aLeft->GetAssignmentFor(mConflictSet, mMemberVar, &left); + + PRInt32 lindex; + gRDFContainerUtils->IndexOf(mDB, container, VALUE_TO_IRDFNODE(left), &lindex); + if (lindex < 0) + return 0; + + Value right; + aRight->GetAssignmentFor(mConflictSet, mMemberVar, &right); + + PRInt32 rindex; + gRDFContainerUtils->IndexOf(mDB, container, VALUE_TO_IRDFNODE(right), &rindex); + if (rindex < 0) + return 0; + + return rindex - lindex; + } + + // If we get here, then an ascending or descending sort order is + // imposed. Value leftValue; aLeft->GetAssignmentFor(mConflictSet, mSortVariable, &leftValue); nsIRDFNode* leftNode = VALUE_TO_IRDFNODE(leftValue); diff --git a/content/xul/templates/src/nsXULTemplateBuilder.cpp b/content/xul/templates/src/nsXULTemplateBuilder.cpp index ab4d28a7894..aa8f6e76a8f 100644 --- a/content/xul/templates/src/nsXULTemplateBuilder.cpp +++ b/content/xul/templates/src/nsXULTemplateBuilder.cpp @@ -125,6 +125,7 @@ nsrefcnt nsXULTemplateBuilder::gRefCnt = 0; PRInt32 nsXULTemplateBuilder::kNameSpaceID_RDF; PRInt32 nsXULTemplateBuilder::kNameSpaceID_XUL; nsIRDFService* nsXULTemplateBuilder::gRDFService; +nsIRDFContainerUtils* nsXULTemplateBuilder::gRDFContainerUtils; nsINameSpaceManager* nsXULTemplateBuilder::gNameSpaceManager; nsIScriptSecurityManager* nsXULTemplateBuilder::gScriptSecurityManager; nsIPrincipal* nsXULTemplateBuilder::gSystemPrincipal; @@ -133,9 +134,6 @@ nsIPrincipal* nsXULTemplateBuilder::gSystemPrincipal; PRLogModuleInfo* gXULTemplateLog; #endif -static nsIRDFContainerUtils* gRDFContainerUtils; - - //---------------------------------------------------------------------- // // nsXULTempalteBuilder methods diff --git a/content/xul/templates/src/nsXULTemplateBuilder.h b/content/xul/templates/src/nsXULTemplateBuilder.h index 67d17d36b60..0144ee9ca9b 100644 --- a/content/xul/templates/src/nsXULTemplateBuilder.h +++ b/content/xul/templates/src/nsXULTemplateBuilder.h @@ -33,6 +33,7 @@ #include "nsISecurityCheckedComponent.h" #include "nsIRDFCompositeDataSource.h" #include "nsIRDFContainer.h" +#include "nsIRDFContainerUtils.h" #include "nsIRDFDataSource.h" #include "nsIRDFObserver.h" #include "nsIRDFService.h" @@ -374,6 +375,7 @@ protected: // pseudo-constants static nsrefcnt gRefCnt; static nsIRDFService* gRDFService; + static nsIRDFContainerUtils* gRDFContainerUtils; static nsINameSpaceManager* gNameSpaceManager; static nsIScriptSecurityManager* gScriptSecurityManager; static nsIPrincipal* gSystemPrincipal; diff --git a/content/xul/templates/src/nsXULTreeBuilder.cpp b/content/xul/templates/src/nsXULTreeBuilder.cpp index ffe645f9baf..ee2e63acfa5 100644 --- a/content/xul/templates/src/nsXULTreeBuilder.cpp +++ b/content/xul/templates/src/nsXULTreeBuilder.cpp @@ -236,7 +236,7 @@ protected: enum Direction { eDirection_Descending = -1, - eDirection_None = 0, + eDirection_Natural = 0, eDirection_Ascending = +1 }; @@ -282,7 +282,7 @@ NS_IMPL_ISUPPORTS_INHERITED2(nsXULOutlinerBuilder, nsXULTemplateBuilder, nsXULOutlinerBuilder::nsXULOutlinerBuilder() : mSortVariable(0), - mSortDirection(eDirection_None) + mSortDirection(eDirection_Natural) { } @@ -611,7 +611,7 @@ nsXULOutlinerBuilder::CycleHeader(const PRUnichar* aColID, nsIDOMElement* aEleme } else if (dir == NS_LITERAL_STRING("descending")) { dir = NS_LITERAL_STRING("natural"); - mSortDirection = eDirection_None; + mSortDirection = eDirection_Natural; } else { dir = NS_LITERAL_STRING("ascending"); @@ -796,7 +796,7 @@ nsXULOutlinerBuilder::ReplaceMatch(nsIRDFResource* aMember, // By default, place the new element at the end of the container PRInt32 index = parent->Count(); - if (mSortVariable && mSortDirection != eDirection_None) { + if (mSortVariable) { // Figure out where to put the new element by doing an // insertion sort. PRInt32 left = 0; @@ -892,7 +892,7 @@ nsXULOutlinerBuilder::GetSortVariables(VariableSet& aVariables) child->GetAttribute(kNameSpaceID_None, nsXULAtoms::sortDirection, dir); if (dir == NS_LITERAL_STRING("none")) - mSortDirection = eDirection_None; + mSortDirection = eDirection_Natural; else if (dir == NS_LITERAL_STRING("descending")) mSortDirection = eDirection_Descending; else @@ -1241,7 +1241,7 @@ nsXULOutlinerBuilder::OpenSubtreeOf(nsOutlinerRows::Subtree* aSubtree, } // Sort the container. - if (mSortVariable && mSortDirection != eDirection_None) { + if (mSortVariable) { NS_QuickSort(mRows.GetRowsFor(aSubtree), aSubtree->Count(), sizeof(nsOutlinerRows::Row), @@ -1350,6 +1350,60 @@ nsXULOutlinerBuilder::CompareMatches(nsTemplateMatch* aLeft, nsTemplateMatch* aR { PRInt32 result = 0; + if (mSortDirection == eDirection_Natural) { + // If the sort order is ``natural'', then see if the container + // is an RDF sequence. If so, we'll try to use the ordinal + // properties to determine order. + // + // XXX the problem with this is, it doesn't always get the + // *real* container; e.g., + // + // + // + // + // + // + // + // In this case mContainerVar is bound to ?uri, not + // ?subheadings. (The ``container'' in the template sense != + // container in the RDF sense.) + Value val; + aLeft->GetAssignmentFor(mConflictSet, mContainerVar, &val); + + nsIRDFResource* container = VALUE_TO_IRDFRESOURCE(val); + + PRBool isSequence = PR_FALSE; + gRDFContainerUtils->IsSeq(mDB, container, &isSequence); + if (! isSequence) + // If it's not an RDF container, then there's no natural + // order. + return 0; + + // Determine the indices of the left and right elements in the + // container. + Value left; + aLeft->GetAssignmentFor(mConflictSet, mMemberVar, &left); + + PRInt32 lindex; + gRDFContainerUtils->IndexOf(mDB, container, VALUE_TO_IRDFNODE(left), &lindex); + if (lindex < 0) + return 0; + + Value right; + aRight->GetAssignmentFor(mConflictSet, mMemberVar, &right); + + PRInt32 rindex; + gRDFContainerUtils->IndexOf(mDB, container, VALUE_TO_IRDFNODE(right), &rindex); + if (rindex < 0) + return 0; + + return rindex - lindex; + } + + // If we get here, then an ascending or descending sort order is + // imposed. Value leftValue; aLeft->GetAssignmentFor(mConflictSet, mSortVariable, &leftValue); nsIRDFNode* leftNode = VALUE_TO_IRDFNODE(leftValue); diff --git a/rdf/base/idl/nsIRDFContainerUtils.idl b/rdf/base/idl/nsIRDFContainerUtils.idl index c24bdda5427..209e121306b 100644 --- a/rdf/base/idl/nsIRDFContainerUtils.idl +++ b/rdf/base/idl/nsIRDFContainerUtils.idl @@ -28,41 +28,69 @@ // Container utilities [scriptable, uuid(D4214E91-FB94-11D2-BDD8-00104BDE6048)] interface nsIRDFContainerUtils : nsISupports { - // Returns 'true' if the property is an RDF ordinal property. + /** + * Returns 'true' if the property is an RDF ordinal property. + */ boolean IsOrdinalProperty(in nsIRDFResource aProperty); - // Convert the specified index to an ordinal property. + /** + * Convert the specified index to an ordinal property. + */ nsIRDFResource IndexToOrdinalResource(in long aIndex); - // Convert the specified ordinal property into an index + /** + * Convert the specified ordinal property into an index + */ long OrdinalResourceToIndex(in nsIRDFResource aOrdinal); - // Return 'true' if the specified resource is a container + /** + * Return 'true' if the specified resource is a container + */ boolean IsContainer(in nsIRDFDataSource aDataSource, in nsIRDFResource aResource); - // Return 'true' if the specified resource is a container and it is empty + /** + * Return 'true' if the specified resource is a container and it is empty + */ boolean IsEmpty(in nsIRDFDataSource aDataSource, in nsIRDFResource aResource); - // Return 'true' if the specified resource is a bag + /** + * Return 'true' if the specified resource is a bag + */ boolean IsBag(in nsIRDFDataSource aDataSource, in nsIRDFResource aResource); - // Return 'true' if the specified resource is a sequence + /** + * Return 'true' if the specified resource is a sequence + */ boolean IsSeq(in nsIRDFDataSource aDataSource, in nsIRDFResource aResource); - // Return 'true' if the specified resource is an alternation + /** + * Return 'true' if the specified resource is an alternation + */ boolean IsAlt(in nsIRDFDataSource aDataSource, in nsIRDFResource aResource); - // Decorates the specified resource appropriately to make it - // usable as an empty bag in the specified data source. + /** + * Decorates the specified resource appropriately to make it + * usable as an empty bag in the specified data source. + */ nsIRDFContainer MakeBag(in nsIRDFDataSource aDataSource, in nsIRDFResource aResource); - // Decorates the specified resource appropriately to make it - // usable as an empty sequence in the specified data source. + /** + * Decorates the specified resource appropriately to make it + * usable as an empty sequence in the specified data source. + */ nsIRDFContainer MakeSeq(in nsIRDFDataSource aDataSource, in nsIRDFResource aResource); - // Decorates the specified resource appropriately to make it - // usable as an empty alternation in the specified data source. + /** + * Decorates the specified resource appropriately to make it + * usable as an empty alternation in the specified data source. + */ nsIRDFContainer MakeAlt(in nsIRDFDataSource aDataSource, in nsIRDFResource aResource); + + /** + * Retrieve the index of element in the container. Returns -1 if + * the element is not in the container. + */ + long indexOf(in nsIRDFDataSource aDataSource, in nsIRDFResource aContainer, in nsIRDFNode aElement); }; %{C++ diff --git a/rdf/base/src/nsRDFContainerUtils.cpp b/rdf/base/src/nsRDFContainerUtils.cpp index d74a178b982..2e111805f3c 100644 --- a/rdf/base/src/nsRDFContainerUtils.cpp +++ b/rdf/base/src/nsRDFContainerUtils.cpp @@ -170,7 +170,7 @@ RDFContainerUtilsImpl::OrdinalResourceToIndex(nsIRDFResource *aOrdinal, PRInt32 const char *ordinalStr; if (NS_FAILED(aOrdinal->GetValueConst( &ordinalStr ))) - return PR_FALSE; + return NS_ERROR_FAILURE; const char* s = ordinalStr; if (PL_strncmp(s, kRDFNameSpaceURI, sizeof(kRDFNameSpaceURI) - 1) != 0) { @@ -469,3 +469,67 @@ RDFContainerUtilsImpl::IsA(nsIRDFDataSource* aDataSource, nsIRDFResource* aResou return result; } + +NS_IMETHODIMP +RDFContainerUtilsImpl::IndexOf(nsIRDFDataSource* aDataSource, nsIRDFResource* aContainer, nsIRDFNode* aElement, PRInt32* aIndex) +{ + // Assume we can't find it. + *aIndex = -1; + + // We'll assume that fan-out is much higher than fan-in, so grovel + // through the inbound arcs, look for an ordinal resource, and + // decode it. + nsCOMPtr arcsIn; + aDataSource->ArcLabelsIn(aElement, getter_AddRefs(arcsIn)); + if (! arcsIn) + return NS_OK; + + while (1) { + PRBool hasMoreArcs = PR_FALSE; + arcsIn->HasMoreElements(&hasMoreArcs); + if (! hasMoreArcs) + break; + + nsCOMPtr isupports; + arcsIn->GetNext(getter_AddRefs(isupports)); + if (! isupports) + break; + + nsCOMPtr property = + do_QueryInterface(isupports); + + if (! property) + continue; + + PRBool isOrdinal; + IsOrdinalProperty(property, &isOrdinal); + if (! isOrdinal) + continue; + + nsCOMPtr sources; + aDataSource->GetSources(property, aElement, PR_TRUE, getter_AddRefs(sources)); + if (! sources) + continue; + + while (1) { + PRBool hasMoreSources = PR_FALSE; + sources->HasMoreElements(&hasMoreSources); + if (! hasMoreSources) + continue; + + nsCOMPtr isupports2; + sources->GetNext(getter_AddRefs(isupports2)); + if (! isupports2) + break; + + nsCOMPtr source = + do_QueryInterface(isupports2); + + if (source == aContainer) + // Found it. + return OrdinalResourceToIndex(property, aIndex); + } + } + + return NS_OK; +}