зеркало из https://github.com/mozilla/pjs.git
bug 335122, rework XUL sort service, r=jan, sr=sicking
This commit is contained in:
Родитель
458f4bdc89
Коммит
7dad4afe63
|
@ -36,57 +36,30 @@
|
||||||
* ***** END LICENSE BLOCK ***** */
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
#include "nsISupports.idl"
|
#include "nsISupports.idl"
|
||||||
#include "nsIRDFCompositeDataSource.idl"
|
|
||||||
#include "nsIRDFResource.idl"
|
|
||||||
|
|
||||||
%{C++
|
|
||||||
class nsRDFSortState;
|
|
||||||
%}
|
|
||||||
|
|
||||||
[ptr] native nsRDFSortState(nsRDFSortState);
|
|
||||||
|
|
||||||
interface nsIContent;
|
|
||||||
interface nsIDOMNode;
|
interface nsIDOMNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A service used to sort the contents of a XUL widget.
|
* A service used to sort the contents of a XUL widget.
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(BFD05261-834C-11d2-8EAC-00805F29F371)]
|
[scriptable, uuid(F29270C8-3BE5-4046-9B57-945A84DFF132)]
|
||||||
interface nsIXULSortService : nsISupports
|
interface nsIXULSortService : nsISupports
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* Sort the contents of the widget containing <code>aNode</code>
|
* Sort the contents of the widget containing <code>aNode</code>
|
||||||
* using <code>aSortResource</code> as the comparison key, and
|
* using <code>aSortKey</code> as the comparison key, and
|
||||||
* <code>aSortDirection</code> as the direction.
|
* <code>aSortDirection</code> as the direction.
|
||||||
*
|
*
|
||||||
* @param aNode A node in the XUL widget whose children are to be
|
* @param aNode A node in the XUL widget whose children are to be sorted.
|
||||||
* sorted. <code>sort</code> will traverse upwards to find the
|
* @param aSortKey The value to be used as the comparison key.
|
||||||
* root node at which to begin the actualy sorting. For optimal
|
|
||||||
* results, pass in the root of the widget.
|
|
||||||
*
|
|
||||||
* @param aSortResource The RDF resource to be used as
|
|
||||||
* the comparison key.
|
|
||||||
*
|
|
||||||
* @param aSortDirection May be either <b>natural</b> to return
|
* @param aSortDirection May be either <b>natural</b> to return
|
||||||
* the contents to their natural (unsorted) order,
|
* the contents to their natural (unsorted) order,
|
||||||
* <b>ascending</b> to sort the contents in ascending order, or
|
* <b>ascending</b> to sort the contents in ascending order, or
|
||||||
* <b>descending</b> to sort the contents in descending order.
|
* <b>descending</b> to sort the contents in descending order.
|
||||||
*/
|
*/
|
||||||
void sort(in nsIDOMNode aNode,
|
void sort(in nsIDOMNode aNode,
|
||||||
in AString aSortResource,
|
in AString aSortKey,
|
||||||
in AString aSortDirection);
|
in AString aSortDirection);
|
||||||
|
|
||||||
/**
|
|
||||||
* Used internally for insertion sorting.
|
|
||||||
*/
|
|
||||||
[noscript] void insertContainerNode(in nsIRDFCompositeDataSource db,
|
|
||||||
in nsRDFSortState sortStatePtr,
|
|
||||||
in nsIContent root,
|
|
||||||
in nsIContent trueParent,
|
|
||||||
in nsIContent container,
|
|
||||||
in nsIContent node,
|
|
||||||
in boolean aNotify);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
%{C++
|
%{C++
|
||||||
|
|
|
@ -159,7 +159,7 @@ interface nsIXULTemplateQueryProcessor;
|
||||||
*
|
*
|
||||||
* See http://wiki.mozilla.org/XUL:Templates_Plan for details about templates.
|
* See http://wiki.mozilla.org/XUL:Templates_Plan for details about templates.
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(e025ef24-d508-11d9-9633-cd2d4a843228)]
|
[scriptable, uuid(fd8fe8a1-5dc3-4830-84b7-f75baccb4a9b)]
|
||||||
interface nsIXULTemplateBuilder : nsISupports
|
interface nsIXULTemplateBuilder : nsISupports
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -181,6 +181,11 @@ interface nsIXULTemplateBuilder : nsISupports
|
||||||
*/
|
*/
|
||||||
readonly attribute nsIXULTemplateResult rootResult;
|
readonly attribute nsIXULTemplateResult rootResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The query processor used to generate results.
|
||||||
|
*/
|
||||||
|
[noscript] readonly attribute nsIXULTemplateQueryProcessor queryProcessor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Force the template builder to rebuild its content. All existing content
|
* Force the template builder to rebuild its content. All existing content
|
||||||
* will be removed first. The query processor's done() method will be
|
* will be removed first. The query processor's done() method will be
|
||||||
|
@ -269,6 +274,14 @@ interface nsIXULTemplateBuilder : nsISupports
|
||||||
*/
|
*/
|
||||||
nsIXULTemplateResult getResultForId(in AString aId);
|
nsIXULTemplateResult getResultForId(in AString aId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the result corresponding to a generated element, or null is
|
||||||
|
* there isn't one.
|
||||||
|
*
|
||||||
|
* @param aContent element to result the result of
|
||||||
|
*/
|
||||||
|
nsIXULTemplateResult getResultForContent(in nsIDOMElement aElement);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the node has content generated for it. This method is
|
* Returns true if the node has content generated for it. This method is
|
||||||
* intended to be called only by the RDF query processor. If aTag is set,
|
* intended to be called only by the RDF query processor. If aTag is set,
|
||||||
|
|
|
@ -250,6 +250,10 @@ interface nsIXULTemplateQueryProcessor : nsISupports
|
||||||
* The comparison should only consider the values for the specified
|
* The comparison should only consider the values for the specified
|
||||||
* variable.
|
* variable.
|
||||||
*
|
*
|
||||||
|
* If the comparison variable is null, the results may be
|
||||||
|
* sorted in a natural order, for instance, based on the order the data in
|
||||||
|
* stored in the datasource.
|
||||||
|
*
|
||||||
* This method must only be called with results that were created by this
|
* This method must only be called with results that were created by this
|
||||||
* query processor.
|
* query processor.
|
||||||
*
|
*
|
||||||
|
|
|
@ -55,7 +55,7 @@ interface nsIRDFResource;
|
||||||
* particular variable may be retrieved using the getBindingFor and
|
* particular variable may be retrieved using the getBindingFor and
|
||||||
* getBindingObjectFor methods.
|
* getBindingObjectFor methods.
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(d035f34f-d8ee-444a-bd46-41163f54ed25)]
|
[scriptable, uuid(ebea0230-36fa-41b7-8e31-760806057965)]
|
||||||
interface nsIXULTemplateResult : nsISupports
|
interface nsIXULTemplateResult : nsISupports
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -92,6 +92,13 @@ interface nsIXULTemplateResult : nsISupports
|
||||||
*/
|
*/
|
||||||
readonly attribute nsIRDFResource resource;
|
readonly attribute nsIRDFResource resource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the object. The predefined value 'separator' may be used
|
||||||
|
* for separators. Other values may be used for application specific
|
||||||
|
* purposes.
|
||||||
|
*/
|
||||||
|
readonly attribute AString type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the string representation of the value of a variable for this
|
* Get the string representation of the value of a variable for this
|
||||||
* result. This string will be used in the action body from a template as
|
* result. This string will be used in the action body from a template as
|
||||||
|
|
|
@ -48,12 +48,11 @@
|
||||||
#include "nsIServiceManager.h"
|
#include "nsIServiceManager.h"
|
||||||
#include "nsITextContent.h"
|
#include "nsITextContent.h"
|
||||||
#include "nsIXULDocument.h"
|
#include "nsIXULDocument.h"
|
||||||
#include "nsIXULSortService.h"
|
|
||||||
|
|
||||||
#include "nsContentSupportMap.h"
|
#include "nsContentSupportMap.h"
|
||||||
#include "nsRDFConMemberTestNode.h"
|
#include "nsRDFConMemberTestNode.h"
|
||||||
#include "nsRDFPropertyTestNode.h"
|
#include "nsRDFPropertyTestNode.h"
|
||||||
#include "nsRDFSort.h"
|
#include "nsXULSortService.h"
|
||||||
#include "nsTemplateRule.h"
|
#include "nsTemplateRule.h"
|
||||||
#include "nsTemplateMap.h"
|
#include "nsTemplateMap.h"
|
||||||
#include "nsVoidArray.h"
|
#include "nsVoidArray.h"
|
||||||
|
@ -74,10 +73,6 @@
|
||||||
#include "pldhash.h"
|
#include "pldhash.h"
|
||||||
#include "rdf.h"
|
#include "rdf.h"
|
||||||
|
|
||||||
//----------------------------------------------------------------------0
|
|
||||||
|
|
||||||
static NS_DEFINE_CID(kXULSortServiceCID, NS_XULSORTSERVICE_CID);
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// Return values for EnsureElementHasGenericChild()
|
// Return values for EnsureElementHasGenericChild()
|
||||||
|
@ -141,6 +136,9 @@ public:
|
||||||
nsIAtom* aTag,
|
nsIAtom* aTag,
|
||||||
PRBool* aGenerated);
|
PRBool* aGenerated);
|
||||||
|
|
||||||
|
NS_IMETHOD GetResultForContent(nsIDOMElement* aContent,
|
||||||
|
nsIXULTemplateResult** aResult);
|
||||||
|
|
||||||
// nsIDocumentObserver interface
|
// nsIDocumentObserver interface
|
||||||
virtual void AttributeChanged(nsIDocument* aDocument,
|
virtual void AttributeChanged(nsIDocument* aDocument,
|
||||||
nsIContent* aContent,
|
nsIContent* aContent,
|
||||||
|
@ -155,8 +153,6 @@ protected:
|
||||||
NS_NewXULContentBuilder(nsISupports* aOuter, REFNSIID aIID, void** aResult);
|
NS_NewXULContentBuilder(nsISupports* aOuter, REFNSIID aIID, void** aResult);
|
||||||
|
|
||||||
nsXULContentBuilder();
|
nsXULContentBuilder();
|
||||||
virtual ~nsXULContentBuilder();
|
|
||||||
nsresult InitGlobals();
|
|
||||||
|
|
||||||
virtual void Uninit(PRBool aIsFinal);
|
virtual void Uninit(PRBool aIsFinal);
|
||||||
|
|
||||||
|
@ -413,6 +409,26 @@ protected:
|
||||||
virtual nsresult
|
virtual nsresult
|
||||||
SynchronizeResult(nsIXULTemplateResult* aResult);
|
SynchronizeResult(nsIXULTemplateResult* aResult);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare a result to a content node. If the generated content for the
|
||||||
|
* result should come before aContent, set aSortOrder to -1. If it should
|
||||||
|
* come after, set sortOrder to 1. If both are equal, set to 0.
|
||||||
|
*/
|
||||||
|
nsresult
|
||||||
|
CompareResultToNode(nsIXULTemplateResult* aResult, nsIContent* aContent,
|
||||||
|
PRInt32* aSortOrder);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert a generated node into the container where it should go according
|
||||||
|
* to the current sort. aNode is the generated content node and aResult is
|
||||||
|
* the result for the generated node.
|
||||||
|
*/
|
||||||
|
nsresult
|
||||||
|
InsertSortedNode(nsIContent* aContainer,
|
||||||
|
nsIContent* aNode,
|
||||||
|
nsIXULTemplateResult* aResult,
|
||||||
|
PRBool aNotify);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maintains a mapping between elements in the DOM and the matches
|
* Maintains a mapping between elements in the DOM and the matches
|
||||||
* that they support.
|
* that they support.
|
||||||
|
@ -428,16 +444,9 @@ protected:
|
||||||
/**
|
/**
|
||||||
* Information about the currently active sort
|
* Information about the currently active sort
|
||||||
*/
|
*/
|
||||||
nsRDFSortState sortState;
|
nsSortState mSortState;
|
||||||
|
|
||||||
// pseudo-constants
|
|
||||||
static PRInt32 gRefCnt;
|
|
||||||
static nsIXULSortService* gXULSortService;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
PRInt32 nsXULContentBuilder::gRefCnt;
|
|
||||||
nsIXULSortService* nsXULContentBuilder::gXULSortService;
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
NS_NewXULContentBuilder(nsISupports* aOuter, REFNSIID aIID, void** aResult)
|
NS_NewXULContentBuilder(nsISupports* aOuter, REFNSIID aIID, void** aResult)
|
||||||
{
|
{
|
||||||
|
@ -463,25 +472,7 @@ NS_NewXULContentBuilder(nsISupports* aOuter, REFNSIID aIID, void** aResult)
|
||||||
|
|
||||||
nsXULContentBuilder::nsXULContentBuilder()
|
nsXULContentBuilder::nsXULContentBuilder()
|
||||||
{
|
{
|
||||||
}
|
mSortState.initialized = PR_FALSE;
|
||||||
|
|
||||||
nsXULContentBuilder::~nsXULContentBuilder()
|
|
||||||
{
|
|
||||||
if (--gRefCnt == 0) {
|
|
||||||
NS_IF_RELEASE(gXULSortService);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
|
||||||
nsXULContentBuilder::InitGlobals()
|
|
||||||
{
|
|
||||||
if (gRefCnt++ == 0) {
|
|
||||||
nsresult rv = CallGetService(kXULSortServiceCID, &gXULSortService);
|
|
||||||
if (NS_FAILED(rv))
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nsXULTemplateBuilder::InitGlobals();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -497,6 +488,8 @@ nsXULContentBuilder::Uninit(PRBool aIsFinal)
|
||||||
mContentSupportMap.Clear();
|
mContentSupportMap.Clear();
|
||||||
mTemplateMap.Clear();
|
mTemplateMap.Clear();
|
||||||
|
|
||||||
|
mSortState.initialized = PR_FALSE;
|
||||||
|
|
||||||
nsXULTemplateBuilder::Uninit(aIsFinal);
|
nsXULTemplateBuilder::Uninit(aIsFinal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -868,12 +861,8 @@ nsXULContentBuilder::BuildContentFromTemplate(nsIContent *aTemplateNode,
|
||||||
if (! isUnique) {
|
if (! isUnique) {
|
||||||
rv = NS_ERROR_UNEXPECTED;
|
rv = NS_ERROR_UNEXPECTED;
|
||||||
|
|
||||||
if (gXULSortService && isGenerationElement) {
|
if (isGenerationElement)
|
||||||
rv = gXULSortService->InsertContainerNode(mCompDB, &sortState,
|
rv = InsertSortedNode(aRealNode, realKid, aChild, aNotify);
|
||||||
mRoot, aResourceNode,
|
|
||||||
aRealNode, realKid,
|
|
||||||
aNotify);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
rv = aRealNode->AppendChildTo(realKid, aNotify);
|
rv = aRealNode->AppendChildTo(realKid, aNotify);
|
||||||
|
@ -1740,6 +1729,29 @@ nsXULContentBuilder::HasGeneratedContent(nsIRDFResource* aResource,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsXULContentBuilder::GetResultForContent(nsIDOMElement* aElement,
|
||||||
|
nsIXULTemplateResult** aResult)
|
||||||
|
{
|
||||||
|
NS_ENSURE_ARG_POINTER(aElement);
|
||||||
|
NS_ENSURE_ARG_POINTER(aResult);
|
||||||
|
|
||||||
|
nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
|
||||||
|
if (content == mRoot) {
|
||||||
|
*aResult = mRootResult;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
nsTemplateMatch *match = nsnull;
|
||||||
|
if (mContentSupportMap.Get(content, &match))
|
||||||
|
*aResult = match->mResult;
|
||||||
|
else
|
||||||
|
*aResult = nsnull;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IF_ADDREF(*aResult);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// nsIDocumentObserver methods
|
// nsIDocumentObserver methods
|
||||||
|
@ -1765,6 +1777,13 @@ nsXULContentBuilder::AttributeChanged(nsIDocument* aDocument,
|
||||||
CloseContainer(aContent);
|
CloseContainer(aContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((aNameSpaceID == kNameSpaceID_XUL) &&
|
||||||
|
((aAttribute == nsXULAtoms::sort) ||
|
||||||
|
(aAttribute == nsXULAtoms::sortDirection) ||
|
||||||
|
(aAttribute == nsXULAtoms::sortResource) ||
|
||||||
|
(aAttribute == nsXULAtoms::sortResource2)))
|
||||||
|
mSortState.initialized = PR_FALSE;
|
||||||
|
|
||||||
// Pass along to the generic template builder.
|
// Pass along to the generic template builder.
|
||||||
nsXULTemplateBuilder::AttributeChanged(aDocument, aContent, aNameSpaceID,
|
nsXULTemplateBuilder::AttributeChanged(aDocument, aContent, aNameSpaceID,
|
||||||
aAttribute, aModType);
|
aAttribute, aModType);
|
||||||
|
@ -1785,7 +1804,6 @@ nsXULContentBuilder::NodeWillBeDestroyed(const nsINode* aNode)
|
||||||
// nsXULTemplateBuilder methods
|
// nsXULTemplateBuilder methods
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
PRBool
|
PRBool
|
||||||
nsXULContentBuilder::GetInsertionLocations(nsIXULTemplateResult* aResult,
|
nsXULContentBuilder::GetInsertionLocations(nsIXULTemplateResult* aResult,
|
||||||
nsISupportsArray** aLocations)
|
nsISupportsArray** aLocations)
|
||||||
|
@ -2077,3 +2095,202 @@ nsXULContentBuilder::RebuildAll()
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**** Sorting Methods ****/
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsXULContentBuilder::CompareResultToNode(nsIXULTemplateResult* aResult,
|
||||||
|
nsIContent* aContent,
|
||||||
|
PRInt32* aSortOrder)
|
||||||
|
{
|
||||||
|
NS_ASSERTION(aSortOrder, "CompareResultToNode: null out param aSortOrder");
|
||||||
|
|
||||||
|
*aSortOrder = 0;
|
||||||
|
|
||||||
|
nsTemplateMatch *match = nsnull;
|
||||||
|
if (!mContentSupportMap.Get(aContent, &match)) {
|
||||||
|
*aSortOrder = mSortState.sortStaticsLast ? -1 : 1;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mQueryProcessor)
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
if (mSortState.direction == nsSortState_natural) {
|
||||||
|
// sort in natural order
|
||||||
|
nsresult rv = mQueryProcessor->CompareResults(aResult, match->mResult,
|
||||||
|
nsnull, aSortOrder);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// iterate over each sort key and compare. If the nodes are equal,
|
||||||
|
// continue to compare using the next sort key. If not equal, stop.
|
||||||
|
PRInt32 length = mSortState.sortKeys.Count();
|
||||||
|
for (PRInt32 t = 0; t < length; t++) {
|
||||||
|
nsresult rv = mQueryProcessor->CompareResults(aResult, match->mResult,
|
||||||
|
mSortState.sortKeys[t], aSortOrder);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
if (*aSortOrder)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// flip the sort order if performing a descending sorting
|
||||||
|
if (mSortState.direction == nsSortState_descending)
|
||||||
|
*aSortOrder = -*aSortOrder;
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsXULContentBuilder::InsertSortedNode(nsIContent* aContainer,
|
||||||
|
nsIContent* aNode,
|
||||||
|
nsIXULTemplateResult* aResult,
|
||||||
|
PRBool aNotify)
|
||||||
|
{
|
||||||
|
nsresult rv;
|
||||||
|
|
||||||
|
if (!mSortState.initialized) {
|
||||||
|
nsAutoString sort, sortDirection;
|
||||||
|
mRoot->GetAttr(kNameSpaceID_None, nsGkAtoms::sort, sort);
|
||||||
|
mRoot->GetAttr(kNameSpaceID_None, nsGkAtoms::sortDirection, sortDirection);
|
||||||
|
rv = XULSortServiceImpl::InitializeSortState(mRoot, aContainer,
|
||||||
|
sort, sortDirection, &mSortState);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
// when doing a natural sort, items will typically be sorted according to
|
||||||
|
// the order they appear in the datasource. For RDF, cache whether the
|
||||||
|
// reference parent is an RDF Seq. That way, the items can be sorted in the
|
||||||
|
// order they are in the Seq.
|
||||||
|
mSortState.isContainerRDFSeq = PR_FALSE;
|
||||||
|
if (mSortState.direction == nsSortState_natural) {
|
||||||
|
nsCOMPtr<nsISupports> ref;
|
||||||
|
nsresult rv = aResult->GetBindingObjectFor(mRefVariable, getter_AddRefs(ref));
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
nsCOMPtr<nsIRDFResource> container = do_QueryInterface(ref);
|
||||||
|
|
||||||
|
if (container) {
|
||||||
|
rv = gRDFContainerUtils->IsSeq(mDB, container, &mSortState.isContainerRDFSeq);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PRBool childAdded = PR_FALSE;
|
||||||
|
PRUint32 numChildren = aContainer->GetChildCount();
|
||||||
|
|
||||||
|
if (mSortState.direction != nsSortState_natural ||
|
||||||
|
(mSortState.direction == nsSortState_natural && mSortState.isContainerRDFSeq))
|
||||||
|
{
|
||||||
|
// because numChildren gets modified
|
||||||
|
PRInt32 realNumChildren = numChildren;
|
||||||
|
nsIContent *child = nsnull;
|
||||||
|
|
||||||
|
// rjc says: determine where static XUL ends and generated XUL/RDF begins
|
||||||
|
PRInt32 staticCount = 0;
|
||||||
|
|
||||||
|
nsAutoString staticValue;
|
||||||
|
aContainer->GetAttr(kNameSpaceID_None, nsXULAtoms::staticHint, staticValue);
|
||||||
|
if (!staticValue.IsEmpty())
|
||||||
|
{
|
||||||
|
// found "static" XUL element count hint
|
||||||
|
PRInt32 strErr = 0;
|
||||||
|
staticCount = staticValue.ToInteger(&strErr);
|
||||||
|
if (strErr)
|
||||||
|
staticCount = 0;
|
||||||
|
} else {
|
||||||
|
// compute the "static" XUL element count
|
||||||
|
for (PRUint32 childLoop = 0; childLoop < numChildren; ++childLoop) {
|
||||||
|
child = aContainer->GetChildAt(childLoop);
|
||||||
|
if (nsContentUtils::HasNonEmptyAttr(child, kNameSpaceID_None,
|
||||||
|
nsXULAtoms::_template))
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
++staticCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mSortState.sortStaticsLast) {
|
||||||
|
// indicate that static XUL comes after RDF-generated content by
|
||||||
|
// making negative
|
||||||
|
staticCount = -staticCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// save the "static" XUL element count hint
|
||||||
|
nsAutoString valueStr;
|
||||||
|
valueStr.AppendInt(staticCount);
|
||||||
|
aContainer->SetAttr(kNameSpaceID_None, nsXULAtoms::staticHint, valueStr, PR_FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (staticCount <= 0) {
|
||||||
|
numChildren += staticCount;
|
||||||
|
staticCount = 0;
|
||||||
|
} else if (staticCount > (PRInt32)numChildren) {
|
||||||
|
staticCount = numChildren;
|
||||||
|
numChildren -= staticCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// figure out where to insert the node when a sort order is being imposed
|
||||||
|
if (numChildren > 0) {
|
||||||
|
nsIContent *temp;
|
||||||
|
PRInt32 direction;
|
||||||
|
|
||||||
|
// rjc says: The following is an implementation of a fairly optimal
|
||||||
|
// binary search insertion sort... with interpolation at either end-point.
|
||||||
|
|
||||||
|
if (mSortState.lastWasFirst) {
|
||||||
|
child = aContainer->GetChildAt(staticCount);
|
||||||
|
temp = child;
|
||||||
|
rv = CompareResultToNode(aResult, temp, &direction);
|
||||||
|
if (direction < 0) {
|
||||||
|
aContainer->InsertChildAt(aNode, staticCount, aNotify);
|
||||||
|
childAdded = PR_TRUE;
|
||||||
|
} else
|
||||||
|
mSortState.lastWasFirst = PR_FALSE;
|
||||||
|
} else if (mSortState.lastWasLast) {
|
||||||
|
child = aContainer->GetChildAt(realNumChildren - 1);
|
||||||
|
temp = child;
|
||||||
|
rv = CompareResultToNode(aResult, temp, &direction);
|
||||||
|
if (direction > 0) {
|
||||||
|
aContainer->InsertChildAt(aNode, realNumChildren, aNotify);
|
||||||
|
childAdded = PR_TRUE;
|
||||||
|
} else
|
||||||
|
mSortState.lastWasLast = PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRInt32 left = staticCount + 1, right = realNumChildren, x;
|
||||||
|
while (!childAdded && right >= left) {
|
||||||
|
x = (left + right) / 2;
|
||||||
|
child = aContainer->GetChildAt(x - 1);
|
||||||
|
temp = child;
|
||||||
|
|
||||||
|
rv = CompareResultToNode(aResult, temp, &direction);
|
||||||
|
if ((x == left && direction < 0) ||
|
||||||
|
(x == right && direction >= 0) ||
|
||||||
|
left == right)
|
||||||
|
{
|
||||||
|
PRInt32 thePos = (direction > 0 ? x : x - 1);
|
||||||
|
aContainer->InsertChildAt(aNode, thePos, aNotify);
|
||||||
|
childAdded = PR_TRUE;
|
||||||
|
|
||||||
|
mSortState.lastWasFirst = (thePos == staticCount);
|
||||||
|
mSortState.lastWasLast = (thePos >= realNumChildren);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (direction < 0)
|
||||||
|
right = x - 1;
|
||||||
|
else
|
||||||
|
left = x + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the child hasn't been inserted yet, just add it at the end. Note
|
||||||
|
// that an append isn't done as there may be static content afterwards.
|
||||||
|
if (!childAdded)
|
||||||
|
aContainer->InsertChildAt(aNode, numChildren, aNotify);
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,199 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* ***** BEGIN LICENSE BLOCK *****
|
||||||
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
* http://www.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing rights and limitations under the
|
||||||
|
* License.
|
||||||
|
*
|
||||||
|
* The Original Code is mozilla.org code.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is
|
||||||
|
* Netscape Communications Corporation.
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Scott Putterman <putterman@netscape.com>
|
||||||
|
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||||
|
* Chase Tingley <tingley@sundell.net>
|
||||||
|
* Neil Deakin <enndeakin@sympatico.ca>
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||||
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
* of those above. If you wish to allow use of your version of this file only
|
||||||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
* use your version of this file under the terms of the MPL, indicate your
|
||||||
|
* decision by deleting the provisions above and replace them with the notice
|
||||||
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||||
|
* the provisions above, a recipient may use your version of this file under
|
||||||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
*
|
||||||
|
* ***** END LICENSE BLOCK *****
|
||||||
|
*
|
||||||
|
* This Original Code has been modified by IBM Corporation.
|
||||||
|
* Modifications made by IBM described herein are
|
||||||
|
* Copyright (c) International Business Machines
|
||||||
|
* Corporation, 2000
|
||||||
|
*
|
||||||
|
* Modifications to Mozilla code or documentation
|
||||||
|
* identified per MPL Section 3.3
|
||||||
|
*
|
||||||
|
* Date Modified by Description of modification
|
||||||
|
* 03/27/2000 IBM Corp. Added PR_CALLBACK for Optlink
|
||||||
|
* use in OS2
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
This sort service is used to sort template built content or content by attribute.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "nsCOMPtr.h"
|
||||||
|
#include "nsCOMArray.h"
|
||||||
|
#include "nsTArray.h"
|
||||||
|
#include "nsIContent.h"
|
||||||
|
#include "nsIXULTemplateResult.h"
|
||||||
|
#include "nsIXULTemplateQueryProcessor.h"
|
||||||
|
#include "nsIXULSortService.h"
|
||||||
|
|
||||||
|
enum nsSortState_direction {
|
||||||
|
nsSortState_descending,
|
||||||
|
nsSortState_ascending,
|
||||||
|
nsSortState_natural
|
||||||
|
};
|
||||||
|
|
||||||
|
// the sort state holds info about the current sort
|
||||||
|
struct nsSortState
|
||||||
|
{
|
||||||
|
PRBool initialized;
|
||||||
|
PRBool invertSort;
|
||||||
|
PRBool inbetweenSeparatorSort;
|
||||||
|
PRBool sortStaticsLast;
|
||||||
|
PRBool isContainerRDFSeq;
|
||||||
|
|
||||||
|
nsSortState_direction direction;
|
||||||
|
nsAutoString sort;
|
||||||
|
nsCOMArray<nsIAtom> sortKeys;
|
||||||
|
|
||||||
|
nsCOMPtr<nsIXULTemplateQueryProcessor> processor;
|
||||||
|
nsCOMPtr<nsIContent> lastContainer;
|
||||||
|
PRBool lastWasFirst, lastWasLast;
|
||||||
|
|
||||||
|
nsSortState()
|
||||||
|
: initialized(PR_FALSE)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// information about a particular item to be sorted
|
||||||
|
struct contentSortInfo {
|
||||||
|
nsCOMPtr<nsIContent> content;
|
||||||
|
nsCOMPtr<nsIContent> parent;
|
||||||
|
nsCOMPtr<nsIXULTemplateResult> result;
|
||||||
|
|
||||||
|
contentSortInfo(nsIContent* aContent,
|
||||||
|
nsIXULTemplateResult* aResult)
|
||||||
|
: content(aContent), result(aResult)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
// ServiceImpl
|
||||||
|
//
|
||||||
|
// This is the sort service.
|
||||||
|
//
|
||||||
|
class XULSortServiceImpl : public nsIXULSortService
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
XULSortServiceImpl(void) {};
|
||||||
|
virtual ~XULSortServiceImpl(void) {};
|
||||||
|
|
||||||
|
friend nsresult NS_NewXULSortService(nsIXULSortService** mgr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
public:
|
||||||
|
// nsISupports
|
||||||
|
NS_DECL_ISUPPORTS
|
||||||
|
|
||||||
|
// nsISortService
|
||||||
|
NS_DECL_NSIXULSORTSERVICE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set sort and sortDirection attributes when a sort is done.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
SetSortHints(nsIContent *aNode, nsSortState* aSortState);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set sortActive and sortDirection attributes on a tree column when a sort
|
||||||
|
* is done. The column to change is the one with a sort attribute that
|
||||||
|
* matches the sort key. The sort attributes are removed from the other
|
||||||
|
* columns.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
SetSortColumnHints(nsIContent *content,
|
||||||
|
const nsAString &sortResource,
|
||||||
|
const nsAString &sortDirection);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the list of items which need to be sorted. This is determined
|
||||||
|
* in the following way:
|
||||||
|
* - for elements that have a content builder, get its list of generated
|
||||||
|
* results
|
||||||
|
* - otherwise, for trees, get the child treeitems
|
||||||
|
* - otherwise, get the direct children
|
||||||
|
*/
|
||||||
|
nsresult
|
||||||
|
GetItemsToSort(nsIContent *aContainer,
|
||||||
|
nsSortState* aSortState,
|
||||||
|
nsTArray<contentSortInfo *>& aSortItems);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list of items to sort for template built content
|
||||||
|
*/
|
||||||
|
nsresult
|
||||||
|
GetTemplateItemsToSort(nsIContent* aContainer,
|
||||||
|
nsIXULTemplateBuilder* aBuilder,
|
||||||
|
nsSortState* aSortState,
|
||||||
|
nsTArray<contentSortInfo *>& aSortItems);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort a container using the supplied sort state details.
|
||||||
|
*/
|
||||||
|
nsresult
|
||||||
|
SortContainer(nsIContent *aContainer, nsSortState* aSortState);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a list of sortable items, reverse the list. This is done
|
||||||
|
* when simply changing the sort direction for the same key.
|
||||||
|
*/
|
||||||
|
nsresult
|
||||||
|
InvertSortInfo(nsTArray<contentSortInfo *>* aData,
|
||||||
|
PRInt32 aStart, PRInt32 aNumItems);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize sort information from attributes specified on the container,
|
||||||
|
* the sort key and sort direction.
|
||||||
|
*
|
||||||
|
* @param aRootElement the element that contains sort attributes
|
||||||
|
* @param aContainer the container to sort, usually equal to aRootElement
|
||||||
|
* @param aSortKey space separated list of sort keys
|
||||||
|
* @param aSortDirection direction to sort in
|
||||||
|
* @param aSortState structure filled in with sort data
|
||||||
|
*/
|
||||||
|
static nsresult
|
||||||
|
InitializeSortState(nsIContent* aRootElement,
|
||||||
|
nsIContent* aContainer,
|
||||||
|
const nsAString& aSortKey,
|
||||||
|
const nsAString& aSortDirection,
|
||||||
|
nsSortState* aSortState);
|
||||||
|
};
|
|
@ -260,6 +260,13 @@ nsXULTemplateBuilder::GetDatabase(nsIRDFCompositeDataSource** aResult)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsXULTemplateBuilder::GetQueryProcessor(nsIXULTemplateQueryProcessor** aResult)
|
||||||
|
{
|
||||||
|
NS_IF_ADDREF(*aResult = mQueryProcessor.get());
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsXULTemplateBuilder::AddRuleFilter(nsIDOMNode* aRule, nsIXULTemplateRuleFilter* aFilter)
|
nsXULTemplateBuilder::AddRuleFilter(nsIDOMNode* aRule, nsIXULTemplateRuleFilter* aFilter)
|
||||||
{
|
{
|
||||||
|
@ -834,6 +841,14 @@ nsXULTemplateBuilder::GetResultForId(const nsAString& aId,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsXULTemplateBuilder::GetResultForContent(nsIDOMElement* aContent,
|
||||||
|
nsIXULTemplateResult** aResult)
|
||||||
|
{
|
||||||
|
*aResult = nsnull;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsXULTemplateBuilder::AddListener(nsIXULBuilderListener* aListener)
|
nsXULTemplateBuilder::AddListener(nsIXULBuilderListener* aListener)
|
||||||
{
|
{
|
||||||
|
|
|
@ -55,6 +55,7 @@
|
||||||
#include "nsIXULDocument.h"
|
#include "nsIXULDocument.h"
|
||||||
#include "nsUnicharUtils.h"
|
#include "nsUnicharUtils.h"
|
||||||
#include "nsAttrName.h"
|
#include "nsAttrName.h"
|
||||||
|
#include "rdf.h"
|
||||||
|
|
||||||
#include "nsContentTestNode.h"
|
#include "nsContentTestNode.h"
|
||||||
#include "nsRDFConInstanceTestNode.h"
|
#include "nsRDFConInstanceTestNode.h"
|
||||||
|
@ -78,7 +79,8 @@ static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
|
||||||
nsrefcnt nsXULTemplateQueryProcessorRDF::gRefCnt = 0;
|
nsrefcnt nsXULTemplateQueryProcessorRDF::gRefCnt = 0;
|
||||||
nsIRDFService* nsXULTemplateQueryProcessorRDF::gRDFService;
|
nsIRDFService* nsXULTemplateQueryProcessorRDF::gRDFService;
|
||||||
nsIRDFContainerUtils* nsXULTemplateQueryProcessorRDF::gRDFContainerUtils;
|
nsIRDFContainerUtils* nsXULTemplateQueryProcessorRDF::gRDFContainerUtils;
|
||||||
|
nsIRDFResource* nsXULTemplateQueryProcessorRDF::kNC_BookmarkSeparator;
|
||||||
|
nsIRDFResource* nsXULTemplateQueryProcessorRDF::kRDF_type;
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS2(nsXULTemplateQueryProcessorRDF,
|
NS_IMPL_ISUPPORTS2(nsXULTemplateQueryProcessorRDF,
|
||||||
nsIXULTemplateQueryProcessor,
|
nsIXULTemplateQueryProcessor,
|
||||||
|
@ -100,6 +102,8 @@ nsXULTemplateQueryProcessorRDF::~nsXULTemplateQueryProcessorRDF(void)
|
||||||
if (--gRefCnt == 0) {
|
if (--gRefCnt == 0) {
|
||||||
NS_IF_RELEASE(gRDFService);
|
NS_IF_RELEASE(gRDFService);
|
||||||
NS_IF_RELEASE(gRDFContainerUtils);
|
NS_IF_RELEASE(gRDFContainerUtils);
|
||||||
|
NS_IF_RELEASE(kNC_BookmarkSeparator);
|
||||||
|
NS_IF_RELEASE(kRDF_type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,6 +126,18 @@ nsXULTemplateQueryProcessorRDF::InitGlobals()
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!kNC_BookmarkSeparator) {
|
||||||
|
gRDFService->GetResource(
|
||||||
|
NS_LITERAL_CSTRING(NC_NAMESPACE_URI "BookmarkSeparator"),
|
||||||
|
&kNC_BookmarkSeparator);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!kRDF_type) {
|
||||||
|
gRDFService->GetResource(
|
||||||
|
NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "type"),
|
||||||
|
&kRDF_type);
|
||||||
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,6 +206,7 @@ nsXULTemplateQueryProcessorRDF::Done()
|
||||||
|
|
||||||
mDB = nsnull;
|
mDB = nsnull;
|
||||||
mBuilder = nsnull;
|
mBuilder = nsnull;
|
||||||
|
mRefVariable = nsnull;
|
||||||
mLastRef = nsnull;
|
mLastRef = nsnull;
|
||||||
|
|
||||||
mGenerationStarted = PR_FALSE;
|
mGenerationStarted = PR_FALSE;
|
||||||
|
@ -228,8 +245,10 @@ nsXULTemplateQueryProcessorRDF::CompileQuery(nsIXULTemplateBuilder* aBuilder,
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
query->mRefVariable = aRefVariable;
|
query->mRefVariable = aRefVariable;
|
||||||
|
if (!mRefVariable)
|
||||||
|
mRefVariable = aRefVariable;
|
||||||
|
|
||||||
if (! aMemberVariable)
|
if (!aMemberVariable)
|
||||||
query->mMemberVariable = do_GetAtom("?");
|
query->mMemberVariable = do_GetAtom("?");
|
||||||
else
|
else
|
||||||
query->mMemberVariable = aMemberVariable;
|
query->mMemberVariable = aMemberVariable;
|
||||||
|
@ -428,7 +447,8 @@ nsXULTemplateQueryProcessorRDF::AddBinding(nsIDOMNode* aRuleNode,
|
||||||
return bindings->AddBinding(aVar, aRef, property);
|
return bindings->AddBinding(aVar, aRef, property);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP nsXULTemplateQueryProcessorRDF::TranslateRef(nsISupports* aDatasource,
|
NS_IMETHODIMP
|
||||||
|
nsXULTemplateQueryProcessorRDF::TranslateRef(nsISupports* aDatasource,
|
||||||
const nsAString& aRefString,
|
const nsAString& aRefString,
|
||||||
nsIXULTemplateResult** aRef)
|
nsIXULTemplateResult** aRef)
|
||||||
{
|
{
|
||||||
|
@ -450,18 +470,63 @@ NS_IMETHODIMP nsXULTemplateQueryProcessorRDF::TranslateRef(nsISupports* aDatasou
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP nsXULTemplateQueryProcessorRDF::CompareResults(nsIXULTemplateResult* aLeft,
|
NS_IMETHODIMP
|
||||||
|
nsXULTemplateQueryProcessorRDF::CompareResults(nsIXULTemplateResult* aLeft,
|
||||||
nsIXULTemplateResult* aRight,
|
nsIXULTemplateResult* aRight,
|
||||||
nsIAtom* aVar,
|
nsIAtom* aVar,
|
||||||
PRInt32* aResult)
|
PRInt32* aResult)
|
||||||
{
|
{
|
||||||
|
NS_ENSURE_ARG_POINTER(aLeft);
|
||||||
|
NS_ENSURE_ARG_POINTER(aRight);
|
||||||
|
|
||||||
*aResult = 0;
|
*aResult = 0;
|
||||||
|
|
||||||
nsCOMPtr<nsISupports> leftNode;
|
// for natural order sorting, use the index in the RDF container for the
|
||||||
aLeft->GetBindingObjectFor(aVar, getter_AddRefs(leftNode));
|
// order. If there is no container, just sort them arbitrarily.
|
||||||
|
if (!aVar) {
|
||||||
|
// if a result has a negative index, just sort it first
|
||||||
|
PRInt32 leftindex = GetContainerIndexOf(aLeft);
|
||||||
|
PRInt32 rightindex = GetContainerIndexOf(aRight);
|
||||||
|
*aResult = leftindex == rightindex ? 0 :
|
||||||
|
leftindex > rightindex ? 1 :
|
||||||
|
-1;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsISupports> rightNode;
|
nsAutoString sortkey;
|
||||||
|
aVar->ToString(sortkey);
|
||||||
|
|
||||||
|
nsCOMPtr<nsISupports> leftNode, rightNode;
|
||||||
|
|
||||||
|
if (!sortkey.IsEmpty() && sortkey[0] != '?' &&
|
||||||
|
!StringBeginsWith(sortkey, NS_LITERAL_STRING("rdf:")) &&
|
||||||
|
mDB) {
|
||||||
|
// if the sort key is not a template variable, it should be an RDF
|
||||||
|
// predicate. Get the targets and compare those instead.
|
||||||
|
nsCOMPtr<nsIRDFResource> predicate;
|
||||||
|
nsresult rv = gRDFService->GetUnicodeResource(sortkey, getter_AddRefs(predicate));
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
// create a predicate with '?sort=true' appended. This special
|
||||||
|
// predicate may be used to have a different sort value than the
|
||||||
|
// displayed value
|
||||||
|
sortkey.AppendLiteral("?sort=true");
|
||||||
|
|
||||||
|
nsCOMPtr<nsIRDFResource> sortPredicate;
|
||||||
|
rv = gRDFService->GetUnicodeResource(sortkey, getter_AddRefs(sortPredicate));
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
rv = GetSortValue(aLeft, predicate, sortPredicate, getter_AddRefs(leftNode));
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
rv = GetSortValue(aRight, predicate, sortPredicate, getter_AddRefs(rightNode));
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
}
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// Literals?
|
// Literals?
|
||||||
|
@ -546,6 +611,7 @@ NS_IMETHODIMP nsXULTemplateQueryProcessorRDF::CompareResults(nsIXULTemplateResul
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if the results are none of the above, just pretend that they are equal
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -940,6 +1006,13 @@ nsXULTemplateQueryProcessorRDF::CheckEmpty(nsIRDFResource* aResource,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsXULTemplateQueryProcessorRDF::CheckIsSeparator(nsIRDFResource* aResource,
|
||||||
|
PRBool* aIsSeparator)
|
||||||
|
{
|
||||||
|
return mDB->HasAssertion(aResource, kRDF_type, kNC_BookmarkSeparator,
|
||||||
|
PR_TRUE, aIsSeparator);
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -1640,3 +1713,68 @@ nsXULTemplateQueryProcessorRDF::RetractElement(const MemoryElement& aMemoryEleme
|
||||||
mMemoryElementToResultMap.Remove(hash);
|
mMemoryElementToResultMap.Remove(hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRInt32
|
||||||
|
nsXULTemplateQueryProcessorRDF::GetContainerIndexOf(nsIXULTemplateResult* aResult)
|
||||||
|
{
|
||||||
|
// get the reference variable and look up the container in the result
|
||||||
|
nsCOMPtr<nsISupports> ref;
|
||||||
|
nsresult rv = aResult->GetBindingObjectFor(mRefVariable,
|
||||||
|
getter_AddRefs(ref));
|
||||||
|
if (NS_FAILED(rv))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
nsCOMPtr<nsIRDFResource> container = do_QueryInterface(ref);
|
||||||
|
if (container) {
|
||||||
|
// if the container is an RDF Seq, return the index of the result
|
||||||
|
// in the container.
|
||||||
|
PRBool isSequence = PR_FALSE;
|
||||||
|
gRDFContainerUtils->IsSeq(mDB, container, &isSequence);
|
||||||
|
if (isSequence) {
|
||||||
|
nsCOMPtr<nsIRDFResource> resource;
|
||||||
|
aResult->GetResource(getter_AddRefs(resource));
|
||||||
|
if (resource) {
|
||||||
|
PRInt32 index;
|
||||||
|
gRDFContainerUtils->IndexOf(mDB, container, resource, &index);
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the container isn't a Seq, or the result isn't in the container,
|
||||||
|
// return -1 indicating no index.
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsXULTemplateQueryProcessorRDF::GetSortValue(nsIXULTemplateResult* aResult,
|
||||||
|
nsIRDFResource* aPredicate,
|
||||||
|
nsIRDFResource* aSortPredicate,
|
||||||
|
nsISupports** aResultNode)
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIRDFResource> source;
|
||||||
|
nsresult rv = aResult->GetResource(getter_AddRefs(source));
|
||||||
|
if (NS_FAILED(rv))
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
nsCOMPtr<nsIRDFNode> value;
|
||||||
|
if (source) {
|
||||||
|
// first check predicate?sort=true so that datasources may use a
|
||||||
|
// custom value for sorting
|
||||||
|
rv = mDB->GetTarget(source, aSortPredicate, PR_TRUE,
|
||||||
|
getter_AddRefs(value));
|
||||||
|
if (NS_FAILED(rv))
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
if (!value) {
|
||||||
|
rv = mDB->GetTarget(source, aPredicate, PR_TRUE,
|
||||||
|
getter_AddRefs(value));
|
||||||
|
if (NS_FAILED(rv))
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*aResultNode = value;
|
||||||
|
NS_IF_ADDREF(*aResultNode);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
|
@ -140,6 +140,12 @@ public:
|
||||||
CheckEmpty(nsIRDFResource* aTargetResource,
|
CheckEmpty(nsIRDFResource* aTargetResource,
|
||||||
PRBool* aIsEmpty);
|
PRBool* aIsEmpty);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a resource is a separator
|
||||||
|
*/
|
||||||
|
nsresult
|
||||||
|
CheckIsSeparator(nsIRDFResource* aResource, PRBool* aIsSeparator);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compute the containment properties which are additional arcs which
|
* Compute the containment properties which are additional arcs which
|
||||||
* indicate that a node is a container, in additional to the RDF container
|
* indicate that a node is a container, in additional to the RDF container
|
||||||
|
@ -266,6 +272,23 @@ public:
|
||||||
*/
|
*/
|
||||||
void RetractElement(const MemoryElement& aMemoryElement);
|
void RetractElement(const MemoryElement& aMemoryElement);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the index of a result's resource in its RDF container
|
||||||
|
*/
|
||||||
|
PRInt32
|
||||||
|
GetContainerIndexOf(nsIXULTemplateResult* aResult);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a result and a predicate to sort on, get the target value of
|
||||||
|
* the triple to use for sorting. The sort predicate is the predicate
|
||||||
|
* with '?sort=true' appended.
|
||||||
|
*/
|
||||||
|
nsresult
|
||||||
|
GetSortValue(nsIXULTemplateResult* aResult,
|
||||||
|
nsIRDFResource* aPredicate,
|
||||||
|
nsIRDFResource* aSortPredicate,
|
||||||
|
nsISupports** aResultNode);
|
||||||
|
|
||||||
nsIRDFDataSource* GetDataSource() { return mDB; }
|
nsIRDFDataSource* GetDataSource() { return mDB; }
|
||||||
|
|
||||||
nsIXULTemplateBuilder* GetBuilder() { return mBuilder; }
|
nsIXULTemplateBuilder* GetBuilder() { return mBuilder; }
|
||||||
|
@ -315,6 +338,9 @@ protected:
|
||||||
// fixed size allocator used to allocate rule network structures
|
// fixed size allocator used to allocate rule network structures
|
||||||
nsFixedSizeAllocator mPool;
|
nsFixedSizeAllocator mPool;
|
||||||
|
|
||||||
|
// the reference variable
|
||||||
|
nsCOMPtr<nsIAtom> mRefVariable;
|
||||||
|
|
||||||
// the last ref that was calculated, used for simple rules
|
// the last ref that was calculated, used for simple rules
|
||||||
nsCOMPtr<nsIXULTemplateResult> mLastRef;
|
nsCOMPtr<nsIXULTemplateResult> mLastRef;
|
||||||
|
|
||||||
|
@ -364,6 +390,8 @@ protected:
|
||||||
public:
|
public:
|
||||||
static nsIRDFService* gRDFService;
|
static nsIRDFService* gRDFService;
|
||||||
static nsIRDFContainerUtils* gRDFContainerUtils;
|
static nsIRDFContainerUtils* gRDFContainerUtils;
|
||||||
|
static nsIRDFResource* kNC_BookmarkSeparator;
|
||||||
|
static nsIRDFResource* kRDF_type;
|
||||||
|
|
||||||
nsFixedSizeAllocator& GetPool() { return mPool; }
|
nsFixedSizeAllocator& GetPool() { return mPool; }
|
||||||
};
|
};
|
||||||
|
|
|
@ -119,6 +119,24 @@ nsXULTemplateResultRDF::GetResource(nsIRDFResource** aResource)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsXULTemplateResultRDF::GetType(nsAString& aType)
|
||||||
|
{
|
||||||
|
aType.Truncate();
|
||||||
|
|
||||||
|
nsresult rv = NS_OK;
|
||||||
|
|
||||||
|
nsXULTemplateQueryProcessorRDF* processor = GetProcessor();
|
||||||
|
if (processor) {
|
||||||
|
PRBool found;
|
||||||
|
rv = processor->CheckIsSeparator(mNode, &found);
|
||||||
|
if (NS_SUCCEEDED(rv) && found)
|
||||||
|
aType.AssignLiteral("separator");
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsXULTemplateResultRDF::GetBindingFor(nsIAtom* aVar, nsAString& aValue)
|
nsXULTemplateResultRDF::GetBindingFor(nsIAtom* aVar, nsAString& aValue)
|
||||||
{
|
{
|
||||||
|
|
|
@ -95,13 +95,6 @@ protected:
|
||||||
NS_NewXULTreeBuilder(nsISupports* aOuter, REFNSIID aIID, void** aResult);
|
NS_NewXULTreeBuilder(nsISupports* aOuter, REFNSIID aIID, void** aResult);
|
||||||
|
|
||||||
nsXULTreeBuilder();
|
nsXULTreeBuilder();
|
||||||
virtual ~nsXULTreeBuilder();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the template builder
|
|
||||||
*/
|
|
||||||
nsresult
|
|
||||||
InitGlobals();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uninitialize the template builder
|
* Uninitialize the template builder
|
||||||
|
@ -274,15 +267,7 @@ protected:
|
||||||
* The builder observers.
|
* The builder observers.
|
||||||
*/
|
*/
|
||||||
nsCOMPtr<nsISupportsArray> mObservers;
|
nsCOMPtr<nsISupportsArray> mObservers;
|
||||||
|
|
||||||
// pseudo-constants
|
|
||||||
static PRInt32 gRefCnt;
|
|
||||||
static nsIRDFResource* kRDF_type;
|
|
||||||
static nsIRDFResource* kNC_BookmarkSeparator;
|
|
||||||
};
|
};
|
||||||
PRInt32 nsXULTreeBuilder::gRefCnt = 0;
|
|
||||||
nsIRDFResource* nsXULTreeBuilder::kRDF_type;
|
|
||||||
nsIRDFResource* nsXULTreeBuilder::kNC_BookmarkSeparator;
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -327,33 +312,6 @@ nsXULTreeBuilder::nsXULTreeBuilder()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
|
||||||
nsXULTreeBuilder::InitGlobals()
|
|
||||||
{
|
|
||||||
nsresult rv = nsXULTemplateBuilder::InitGlobals();
|
|
||||||
if (NS_FAILED(rv))
|
|
||||||
return rv;
|
|
||||||
|
|
||||||
if (gRefCnt++ == 0) {
|
|
||||||
gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "type"), &kRDF_type);
|
|
||||||
gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "BookmarkSeparator"),
|
|
||||||
&kNC_BookmarkSeparator);
|
|
||||||
}
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsXULTreeBuilder::~nsXULTreeBuilder()
|
|
||||||
{
|
|
||||||
if (--gRefCnt == 0) {
|
|
||||||
NS_IF_RELEASE(kRDF_type);
|
|
||||||
NS_IF_RELEASE(kNC_BookmarkSeparator);
|
|
||||||
}
|
|
||||||
|
|
||||||
Uninit(PR_TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
nsXULTreeBuilder::Uninit(PRBool aIsFinal)
|
nsXULTreeBuilder::Uninit(PRBool aIsFinal)
|
||||||
{
|
{
|
||||||
|
@ -632,10 +590,11 @@ nsXULTreeBuilder::IsSeparator(PRInt32 aIndex, PRBool* aResult)
|
||||||
if (aIndex < 0 || aIndex >= mRows.Count())
|
if (aIndex < 0 || aIndex >= mRows.Count())
|
||||||
return NS_ERROR_INVALID_ARG;
|
return NS_ERROR_INVALID_ARG;
|
||||||
|
|
||||||
nsCOMPtr<nsIRDFResource> resource;
|
nsAutoString type;
|
||||||
GetResourceFor(aIndex, getter_AddRefs(resource));
|
nsTreeRows::Row& row = *(mRows[aIndex]);
|
||||||
|
row.mMatch->mResult->GetType(type);
|
||||||
|
|
||||||
mDB->HasAssertion(resource, kRDF_type, kNC_BookmarkSeparator, PR_TRUE, aResult);
|
*aResult = type.EqualsLiteral("separator");
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
#include "nsIDOMClassInfo.h"
|
#include "nsIDOMClassInfo.h"
|
||||||
#include "nsIEventStateManager.h"
|
#include "nsIEventStateManager.h"
|
||||||
#include "nsINodeInfo.h"
|
#include "nsINodeInfo.h"
|
||||||
|
#include "nsIXULSortService.h"
|
||||||
|
|
||||||
// A content model view implementation for the tree.
|
// A content model view implementation for the tree.
|
||||||
|
|
||||||
|
@ -597,6 +598,37 @@ nsTreeContentView::ToggleOpenState(PRInt32 aIndex)
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsTreeContentView::CycleHeader(nsITreeColumn* aCol)
|
nsTreeContentView::CycleHeader(nsITreeColumn* aCol)
|
||||||
{
|
{
|
||||||
|
NS_ENSURE_ARG_POINTER(aCol);
|
||||||
|
|
||||||
|
if (!mRoot)
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
nsCOMPtr<nsIDOMElement> element;
|
||||||
|
aCol->GetElement(getter_AddRefs(element));
|
||||||
|
if (element) {
|
||||||
|
nsCOMPtr<nsIContent> column = do_QueryInterface(element);
|
||||||
|
nsAutoString sort;
|
||||||
|
column->GetAttr(kNameSpaceID_None, nsXULAtoms::sort, sort);
|
||||||
|
if (!sort.IsEmpty()) {
|
||||||
|
nsCOMPtr<nsIXULSortService> xs = do_GetService("@mozilla.org/xul/xul-sort-service;1");
|
||||||
|
if (xs) {
|
||||||
|
nsAutoString sortdirection;
|
||||||
|
static nsIContent::AttrValuesArray strings[] =
|
||||||
|
{&nsXULAtoms::ascending, &nsXULAtoms::descending, nsnull};
|
||||||
|
switch (column->FindAttrValueIn(kNameSpaceID_None,
|
||||||
|
nsXULAtoms::sortDirection,
|
||||||
|
strings, eCaseMatters)) {
|
||||||
|
case 0: sortdirection.AssignLiteral("descending"); break;
|
||||||
|
case 1: sortdirection.AssignLiteral("natural"); break;
|
||||||
|
default: sortdirection.AssignLiteral("ascending"); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIDOMNode> rootnode = do_QueryInterface(mRoot);
|
||||||
|
xs->Sort(rootnode, sort, sortdirection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче