Bug 71530. Put the wraps on the RDF outliner for now. Implement 'natural order' sorting. Also, fix off-by-one in the enumerator. r=ben, sr=hyatt

This commit is contained in:
waterson%netscape.com 2001-03-28 22:42:49 +00:00
parent c3df8d612a
commit c2f73cbddd
8 changed files with 236 additions and 32 deletions

View File

@ -345,8 +345,10 @@ nsOutlinerRows::iterator::Next()
// If there are no unfinished subtrees in the stack, then this // If there are no unfinished subtrees in the stack, then this
// iterator is exhausted. Leave it in the same state that // iterator is exhausted. Leave it in the same state that
// Last() does. // Last() does.
if (unfinished < 0) if (unfinished < 0) {
top.mChildIndex++;
return; return;
}
// Otherwise, we ran off the end of one of the inner // Otherwise, we ran off the end of one of the inner
// subtrees. Pop up to the next unfinished level in the stack. // subtrees. Pop up to the next unfinished level in the stack.

View File

@ -345,8 +345,10 @@ nsOutlinerRows::iterator::Next()
// If there are no unfinished subtrees in the stack, then this // If there are no unfinished subtrees in the stack, then this
// iterator is exhausted. Leave it in the same state that // iterator is exhausted. Leave it in the same state that
// Last() does. // Last() does.
if (unfinished < 0) if (unfinished < 0) {
top.mChildIndex++;
return; return;
}
// Otherwise, we ran off the end of one of the inner // Otherwise, we ran off the end of one of the inner
// subtrees. Pop up to the next unfinished level in the stack. // subtrees. Pop up to the next unfinished level in the stack.

View File

@ -236,7 +236,7 @@ protected:
enum Direction { enum Direction {
eDirection_Descending = -1, eDirection_Descending = -1,
eDirection_None = 0, eDirection_Natural = 0,
eDirection_Ascending = +1 eDirection_Ascending = +1
}; };
@ -282,7 +282,7 @@ NS_IMPL_ISUPPORTS_INHERITED2(nsXULOutlinerBuilder, nsXULTemplateBuilder,
nsXULOutlinerBuilder::nsXULOutlinerBuilder() nsXULOutlinerBuilder::nsXULOutlinerBuilder()
: mSortVariable(0), : 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")) { else if (dir == NS_LITERAL_STRING("descending")) {
dir = NS_LITERAL_STRING("natural"); dir = NS_LITERAL_STRING("natural");
mSortDirection = eDirection_None; mSortDirection = eDirection_Natural;
} }
else { else {
dir = NS_LITERAL_STRING("ascending"); 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 // By default, place the new element at the end of the container
PRInt32 index = parent->Count(); PRInt32 index = parent->Count();
if (mSortVariable && mSortDirection != eDirection_None) { if (mSortVariable) {
// Figure out where to put the new element by doing an // Figure out where to put the new element by doing an
// insertion sort. // insertion sort.
PRInt32 left = 0; PRInt32 left = 0;
@ -892,7 +892,7 @@ nsXULOutlinerBuilder::GetSortVariables(VariableSet& aVariables)
child->GetAttribute(kNameSpaceID_None, nsXULAtoms::sortDirection, dir); child->GetAttribute(kNameSpaceID_None, nsXULAtoms::sortDirection, dir);
if (dir == NS_LITERAL_STRING("none")) if (dir == NS_LITERAL_STRING("none"))
mSortDirection = eDirection_None; mSortDirection = eDirection_Natural;
else if (dir == NS_LITERAL_STRING("descending")) else if (dir == NS_LITERAL_STRING("descending"))
mSortDirection = eDirection_Descending; mSortDirection = eDirection_Descending;
else else
@ -1241,7 +1241,7 @@ nsXULOutlinerBuilder::OpenSubtreeOf(nsOutlinerRows::Subtree* aSubtree,
} }
// Sort the container. // Sort the container.
if (mSortVariable && mSortDirection != eDirection_None) { if (mSortVariable) {
NS_QuickSort(mRows.GetRowsFor(aSubtree), NS_QuickSort(mRows.GetRowsFor(aSubtree),
aSubtree->Count(), aSubtree->Count(),
sizeof(nsOutlinerRows::Row), sizeof(nsOutlinerRows::Row),
@ -1350,6 +1350,60 @@ nsXULOutlinerBuilder::CompareMatches(nsTemplateMatch* aLeft, nsTemplateMatch* aR
{ {
PRInt32 result = 0; 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.,
//
// <outlinerrow uri="?uri" />
//
// <triple subject="?uri"
// predicate="http://home.netscape.com/NC-rdf#subheadings"
// object="?subheadings" />
//
// <member container="?subheadings" child="?subheading" />
//
// 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; Value leftValue;
aLeft->GetAssignmentFor(mConflictSet, mSortVariable, &leftValue); aLeft->GetAssignmentFor(mConflictSet, mSortVariable, &leftValue);
nsIRDFNode* leftNode = VALUE_TO_IRDFNODE(leftValue); nsIRDFNode* leftNode = VALUE_TO_IRDFNODE(leftValue);

View File

@ -125,6 +125,7 @@ nsrefcnt nsXULTemplateBuilder::gRefCnt = 0;
PRInt32 nsXULTemplateBuilder::kNameSpaceID_RDF; PRInt32 nsXULTemplateBuilder::kNameSpaceID_RDF;
PRInt32 nsXULTemplateBuilder::kNameSpaceID_XUL; PRInt32 nsXULTemplateBuilder::kNameSpaceID_XUL;
nsIRDFService* nsXULTemplateBuilder::gRDFService; nsIRDFService* nsXULTemplateBuilder::gRDFService;
nsIRDFContainerUtils* nsXULTemplateBuilder::gRDFContainerUtils;
nsINameSpaceManager* nsXULTemplateBuilder::gNameSpaceManager; nsINameSpaceManager* nsXULTemplateBuilder::gNameSpaceManager;
nsIScriptSecurityManager* nsXULTemplateBuilder::gScriptSecurityManager; nsIScriptSecurityManager* nsXULTemplateBuilder::gScriptSecurityManager;
nsIPrincipal* nsXULTemplateBuilder::gSystemPrincipal; nsIPrincipal* nsXULTemplateBuilder::gSystemPrincipal;
@ -133,9 +134,6 @@ nsIPrincipal* nsXULTemplateBuilder::gSystemPrincipal;
PRLogModuleInfo* gXULTemplateLog; PRLogModuleInfo* gXULTemplateLog;
#endif #endif
static nsIRDFContainerUtils* gRDFContainerUtils;
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// //
// nsXULTempalteBuilder methods // nsXULTempalteBuilder methods

View File

@ -33,6 +33,7 @@
#include "nsISecurityCheckedComponent.h" #include "nsISecurityCheckedComponent.h"
#include "nsIRDFCompositeDataSource.h" #include "nsIRDFCompositeDataSource.h"
#include "nsIRDFContainer.h" #include "nsIRDFContainer.h"
#include "nsIRDFContainerUtils.h"
#include "nsIRDFDataSource.h" #include "nsIRDFDataSource.h"
#include "nsIRDFObserver.h" #include "nsIRDFObserver.h"
#include "nsIRDFService.h" #include "nsIRDFService.h"
@ -374,6 +375,7 @@ protected:
// pseudo-constants // pseudo-constants
static nsrefcnt gRefCnt; static nsrefcnt gRefCnt;
static nsIRDFService* gRDFService; static nsIRDFService* gRDFService;
static nsIRDFContainerUtils* gRDFContainerUtils;
static nsINameSpaceManager* gNameSpaceManager; static nsINameSpaceManager* gNameSpaceManager;
static nsIScriptSecurityManager* gScriptSecurityManager; static nsIScriptSecurityManager* gScriptSecurityManager;
static nsIPrincipal* gSystemPrincipal; static nsIPrincipal* gSystemPrincipal;

View File

@ -236,7 +236,7 @@ protected:
enum Direction { enum Direction {
eDirection_Descending = -1, eDirection_Descending = -1,
eDirection_None = 0, eDirection_Natural = 0,
eDirection_Ascending = +1 eDirection_Ascending = +1
}; };
@ -282,7 +282,7 @@ NS_IMPL_ISUPPORTS_INHERITED2(nsXULOutlinerBuilder, nsXULTemplateBuilder,
nsXULOutlinerBuilder::nsXULOutlinerBuilder() nsXULOutlinerBuilder::nsXULOutlinerBuilder()
: mSortVariable(0), : 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")) { else if (dir == NS_LITERAL_STRING("descending")) {
dir = NS_LITERAL_STRING("natural"); dir = NS_LITERAL_STRING("natural");
mSortDirection = eDirection_None; mSortDirection = eDirection_Natural;
} }
else { else {
dir = NS_LITERAL_STRING("ascending"); 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 // By default, place the new element at the end of the container
PRInt32 index = parent->Count(); PRInt32 index = parent->Count();
if (mSortVariable && mSortDirection != eDirection_None) { if (mSortVariable) {
// Figure out where to put the new element by doing an // Figure out where to put the new element by doing an
// insertion sort. // insertion sort.
PRInt32 left = 0; PRInt32 left = 0;
@ -892,7 +892,7 @@ nsXULOutlinerBuilder::GetSortVariables(VariableSet& aVariables)
child->GetAttribute(kNameSpaceID_None, nsXULAtoms::sortDirection, dir); child->GetAttribute(kNameSpaceID_None, nsXULAtoms::sortDirection, dir);
if (dir == NS_LITERAL_STRING("none")) if (dir == NS_LITERAL_STRING("none"))
mSortDirection = eDirection_None; mSortDirection = eDirection_Natural;
else if (dir == NS_LITERAL_STRING("descending")) else if (dir == NS_LITERAL_STRING("descending"))
mSortDirection = eDirection_Descending; mSortDirection = eDirection_Descending;
else else
@ -1241,7 +1241,7 @@ nsXULOutlinerBuilder::OpenSubtreeOf(nsOutlinerRows::Subtree* aSubtree,
} }
// Sort the container. // Sort the container.
if (mSortVariable && mSortDirection != eDirection_None) { if (mSortVariable) {
NS_QuickSort(mRows.GetRowsFor(aSubtree), NS_QuickSort(mRows.GetRowsFor(aSubtree),
aSubtree->Count(), aSubtree->Count(),
sizeof(nsOutlinerRows::Row), sizeof(nsOutlinerRows::Row),
@ -1350,6 +1350,60 @@ nsXULOutlinerBuilder::CompareMatches(nsTemplateMatch* aLeft, nsTemplateMatch* aR
{ {
PRInt32 result = 0; 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.,
//
// <outlinerrow uri="?uri" />
//
// <triple subject="?uri"
// predicate="http://home.netscape.com/NC-rdf#subheadings"
// object="?subheadings" />
//
// <member container="?subheadings" child="?subheading" />
//
// 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; Value leftValue;
aLeft->GetAssignmentFor(mConflictSet, mSortVariable, &leftValue); aLeft->GetAssignmentFor(mConflictSet, mSortVariable, &leftValue);
nsIRDFNode* leftNode = VALUE_TO_IRDFNODE(leftValue); nsIRDFNode* leftNode = VALUE_TO_IRDFNODE(leftValue);

View File

@ -28,41 +28,69 @@
// Container utilities // Container utilities
[scriptable, uuid(D4214E91-FB94-11D2-BDD8-00104BDE6048)] [scriptable, uuid(D4214E91-FB94-11D2-BDD8-00104BDE6048)]
interface nsIRDFContainerUtils : nsISupports { 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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++ %{C++

View File

@ -170,7 +170,7 @@ RDFContainerUtilsImpl::OrdinalResourceToIndex(nsIRDFResource *aOrdinal, PRInt32
const char *ordinalStr; const char *ordinalStr;
if (NS_FAILED(aOrdinal->GetValueConst( &ordinalStr ))) if (NS_FAILED(aOrdinal->GetValueConst( &ordinalStr )))
return PR_FALSE; return NS_ERROR_FAILURE;
const char* s = ordinalStr; const char* s = ordinalStr;
if (PL_strncmp(s, kRDFNameSpaceURI, sizeof(kRDFNameSpaceURI) - 1) != 0) { if (PL_strncmp(s, kRDFNameSpaceURI, sizeof(kRDFNameSpaceURI) - 1) != 0) {
@ -469,3 +469,67 @@ RDFContainerUtilsImpl::IsA(nsIRDFDataSource* aDataSource, nsIRDFResource* aResou
return result; 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<nsISimpleEnumerator> 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<nsISupports> isupports;
arcsIn->GetNext(getter_AddRefs(isupports));
if (! isupports)
break;
nsCOMPtr<nsIRDFResource> property =
do_QueryInterface(isupports);
if (! property)
continue;
PRBool isOrdinal;
IsOrdinalProperty(property, &isOrdinal);
if (! isOrdinal)
continue;
nsCOMPtr<nsISimpleEnumerator> 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<nsISupports> isupports2;
sources->GetNext(getter_AddRefs(isupports2));
if (! isupports2)
break;
nsCOMPtr<nsIRDFResource> source =
do_QueryInterface(isupports2);
if (source == aContainer)
// Found it.
return OrdinalResourceToIndex(property, aIndex);
}
}
return NS_OK;
}