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;
+}