зеркало из 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 ***** */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
#include "nsIRDFCompositeDataSource.idl"
|
||||
#include "nsIRDFResource.idl"
|
||||
|
||||
%{C++
|
||||
class nsRDFSortState;
|
||||
%}
|
||||
|
||||
[ptr] native nsRDFSortState(nsRDFSortState);
|
||||
|
||||
interface nsIContent;
|
||||
interface nsIDOMNode;
|
||||
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
/**
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @param aNode A node in the XUL widget whose children are to be
|
||||
* sorted. <code>sort</code> will traverse upwards to find the
|
||||
* 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 aNode A node in the XUL widget whose children are to be sorted.
|
||||
* @param aSortKey The value to be used as the comparison key.
|
||||
* @param aSortDirection May be either <b>natural</b> to return
|
||||
* the contents to their natural (unsorted) order,
|
||||
* <b>ascending</b> to sort the contents in ascending order, or
|
||||
* <b>descending</b> to sort the contents in descending order.
|
||||
*/
|
||||
void sort(in nsIDOMNode aNode,
|
||||
in AString aSortResource,
|
||||
in AString aSortKey,
|
||||
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++
|
||||
|
|
|
@ -159,7 +159,7 @@ interface nsIXULTemplateQueryProcessor;
|
|||
*
|
||||
* 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
|
||||
{
|
||||
/**
|
||||
|
@ -181,6 +181,11 @@ interface nsIXULTemplateBuilder : nsISupports
|
|||
*/
|
||||
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
|
||||
* will be removed first. The query processor's done() method will be
|
||||
|
@ -269,6 +274,14 @@ interface nsIXULTemplateBuilder : nsISupports
|
|||
*/
|
||||
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
|
||||
* 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
|
||||
* 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
|
||||
* query processor.
|
||||
*
|
||||
|
|
|
@ -55,7 +55,7 @@ interface nsIRDFResource;
|
|||
* particular variable may be retrieved using the getBindingFor and
|
||||
* getBindingObjectFor methods.
|
||||
*/
|
||||
[scriptable, uuid(d035f34f-d8ee-444a-bd46-41163f54ed25)]
|
||||
[scriptable, uuid(ebea0230-36fa-41b7-8e31-760806057965)]
|
||||
interface nsIXULTemplateResult : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -92,6 +92,13 @@ interface nsIXULTemplateResult : nsISupports
|
|||
*/
|
||||
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
|
||||
* result. This string will be used in the action body from a template as
|
||||
|
|
|
@ -48,12 +48,11 @@
|
|||
#include "nsIServiceManager.h"
|
||||
#include "nsITextContent.h"
|
||||
#include "nsIXULDocument.h"
|
||||
#include "nsIXULSortService.h"
|
||||
|
||||
#include "nsContentSupportMap.h"
|
||||
#include "nsRDFConMemberTestNode.h"
|
||||
#include "nsRDFPropertyTestNode.h"
|
||||
#include "nsRDFSort.h"
|
||||
#include "nsXULSortService.h"
|
||||
#include "nsTemplateRule.h"
|
||||
#include "nsTemplateMap.h"
|
||||
#include "nsVoidArray.h"
|
||||
|
@ -74,10 +73,6 @@
|
|||
#include "pldhash.h"
|
||||
#include "rdf.h"
|
||||
|
||||
//----------------------------------------------------------------------0
|
||||
|
||||
static NS_DEFINE_CID(kXULSortServiceCID, NS_XULSORTSERVICE_CID);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
// Return values for EnsureElementHasGenericChild()
|
||||
|
@ -141,6 +136,9 @@ public:
|
|||
nsIAtom* aTag,
|
||||
PRBool* aGenerated);
|
||||
|
||||
NS_IMETHOD GetResultForContent(nsIDOMElement* aContent,
|
||||
nsIXULTemplateResult** aResult);
|
||||
|
||||
// nsIDocumentObserver interface
|
||||
virtual void AttributeChanged(nsIDocument* aDocument,
|
||||
nsIContent* aContent,
|
||||
|
@ -155,8 +153,6 @@ protected:
|
|||
NS_NewXULContentBuilder(nsISupports* aOuter, REFNSIID aIID, void** aResult);
|
||||
|
||||
nsXULContentBuilder();
|
||||
virtual ~nsXULContentBuilder();
|
||||
nsresult InitGlobals();
|
||||
|
||||
virtual void Uninit(PRBool aIsFinal);
|
||||
|
||||
|
@ -413,6 +409,26 @@ protected:
|
|||
virtual nsresult
|
||||
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
|
||||
* that they support.
|
||||
|
@ -428,16 +444,9 @@ protected:
|
|||
/**
|
||||
* Information about the currently active sort
|
||||
*/
|
||||
nsRDFSortState sortState;
|
||||
|
||||
// pseudo-constants
|
||||
static PRInt32 gRefCnt;
|
||||
static nsIXULSortService* gXULSortService;
|
||||
nsSortState mSortState;
|
||||
};
|
||||
|
||||
PRInt32 nsXULContentBuilder::gRefCnt;
|
||||
nsIXULSortService* nsXULContentBuilder::gXULSortService;
|
||||
|
||||
NS_IMETHODIMP
|
||||
NS_NewXULContentBuilder(nsISupports* aOuter, REFNSIID aIID, void** aResult)
|
||||
{
|
||||
|
@ -463,25 +472,7 @@ NS_NewXULContentBuilder(nsISupports* aOuter, REFNSIID aIID, void** aResult)
|
|||
|
||||
nsXULContentBuilder::nsXULContentBuilder()
|
||||
{
|
||||
}
|
||||
|
||||
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();
|
||||
mSortState.initialized = PR_FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -497,6 +488,8 @@ nsXULContentBuilder::Uninit(PRBool aIsFinal)
|
|||
mContentSupportMap.Clear();
|
||||
mTemplateMap.Clear();
|
||||
|
||||
mSortState.initialized = PR_FALSE;
|
||||
|
||||
nsXULTemplateBuilder::Uninit(aIsFinal);
|
||||
}
|
||||
|
||||
|
@ -868,12 +861,8 @@ nsXULContentBuilder::BuildContentFromTemplate(nsIContent *aTemplateNode,
|
|||
if (! isUnique) {
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
|
||||
if (gXULSortService && isGenerationElement) {
|
||||
rv = gXULSortService->InsertContainerNode(mCompDB, &sortState,
|
||||
mRoot, aResourceNode,
|
||||
aRealNode, realKid,
|
||||
aNotify);
|
||||
}
|
||||
if (isGenerationElement)
|
||||
rv = InsertSortedNode(aRealNode, realKid, aChild, aNotify);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
rv = aRealNode->AppendChildTo(realKid, aNotify);
|
||||
|
@ -1740,6 +1729,29 @@ nsXULContentBuilder::HasGeneratedContent(nsIRDFResource* aResource,
|
|||
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
|
||||
|
@ -1765,6 +1777,13 @@ nsXULContentBuilder::AttributeChanged(nsIDocument* aDocument,
|
|||
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.
|
||||
nsXULTemplateBuilder::AttributeChanged(aDocument, aContent, aNameSpaceID,
|
||||
aAttribute, aModType);
|
||||
|
@ -1785,7 +1804,6 @@ nsXULContentBuilder::NodeWillBeDestroyed(const nsINode* aNode)
|
|||
// nsXULTemplateBuilder methods
|
||||
//
|
||||
|
||||
|
||||
PRBool
|
||||
nsXULContentBuilder::GetInsertionLocations(nsIXULTemplateResult* aResult,
|
||||
nsISupportsArray** aLocations)
|
||||
|
@ -2077,3 +2095,202 @@ nsXULContentBuilder::RebuildAll()
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULTemplateBuilder::GetQueryProcessor(nsIXULTemplateQueryProcessor** aResult)
|
||||
{
|
||||
NS_IF_ADDREF(*aResult = mQueryProcessor.get());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULTemplateBuilder::AddRuleFilter(nsIDOMNode* aRule, nsIXULTemplateRuleFilter* aFilter)
|
||||
{
|
||||
|
@ -834,6 +841,14 @@ nsXULTemplateBuilder::GetResultForId(const nsAString& aId,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULTemplateBuilder::GetResultForContent(nsIDOMElement* aContent,
|
||||
nsIXULTemplateResult** aResult)
|
||||
{
|
||||
*aResult = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULTemplateBuilder::AddListener(nsIXULBuilderListener* aListener)
|
||||
{
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
#include "nsIXULDocument.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsAttrName.h"
|
||||
#include "rdf.h"
|
||||
|
||||
#include "nsContentTestNode.h"
|
||||
#include "nsRDFConInstanceTestNode.h"
|
||||
|
@ -78,7 +79,8 @@ static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
|
|||
nsrefcnt nsXULTemplateQueryProcessorRDF::gRefCnt = 0;
|
||||
nsIRDFService* nsXULTemplateQueryProcessorRDF::gRDFService;
|
||||
nsIRDFContainerUtils* nsXULTemplateQueryProcessorRDF::gRDFContainerUtils;
|
||||
|
||||
nsIRDFResource* nsXULTemplateQueryProcessorRDF::kNC_BookmarkSeparator;
|
||||
nsIRDFResource* nsXULTemplateQueryProcessorRDF::kRDF_type;
|
||||
|
||||
NS_IMPL_ISUPPORTS2(nsXULTemplateQueryProcessorRDF,
|
||||
nsIXULTemplateQueryProcessor,
|
||||
|
@ -100,6 +102,8 @@ nsXULTemplateQueryProcessorRDF::~nsXULTemplateQueryProcessorRDF(void)
|
|||
if (--gRefCnt == 0) {
|
||||
NS_IF_RELEASE(gRDFService);
|
||||
NS_IF_RELEASE(gRDFContainerUtils);
|
||||
NS_IF_RELEASE(kNC_BookmarkSeparator);
|
||||
NS_IF_RELEASE(kRDF_type);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -122,6 +126,18 @@ nsXULTemplateQueryProcessorRDF::InitGlobals()
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -190,6 +206,7 @@ nsXULTemplateQueryProcessorRDF::Done()
|
|||
|
||||
mDB = nsnull;
|
||||
mBuilder = nsnull;
|
||||
mRefVariable = nsnull;
|
||||
mLastRef = nsnull;
|
||||
|
||||
mGenerationStarted = PR_FALSE;
|
||||
|
@ -228,6 +245,8 @@ nsXULTemplateQueryProcessorRDF::CompileQuery(nsIXULTemplateBuilder* aBuilder,
|
|||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
query->mRefVariable = aRefVariable;
|
||||
if (!mRefVariable)
|
||||
mRefVariable = aRefVariable;
|
||||
|
||||
if (!aMemberVariable)
|
||||
query->mMemberVariable = do_GetAtom("?");
|
||||
|
@ -428,7 +447,8 @@ nsXULTemplateQueryProcessorRDF::AddBinding(nsIDOMNode* aRuleNode,
|
|||
return bindings->AddBinding(aVar, aRef, property);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsXULTemplateQueryProcessorRDF::TranslateRef(nsISupports* aDatasource,
|
||||
NS_IMETHODIMP
|
||||
nsXULTemplateQueryProcessorRDF::TranslateRef(nsISupports* aDatasource,
|
||||
const nsAString& aRefString,
|
||||
nsIXULTemplateResult** aRef)
|
||||
{
|
||||
|
@ -450,18 +470,63 @@ NS_IMETHODIMP nsXULTemplateQueryProcessorRDF::TranslateRef(nsISupports* aDatasou
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsXULTemplateQueryProcessorRDF::CompareResults(nsIXULTemplateResult* aLeft,
|
||||
NS_IMETHODIMP
|
||||
nsXULTemplateQueryProcessorRDF::CompareResults(nsIXULTemplateResult* aLeft,
|
||||
nsIXULTemplateResult* aRight,
|
||||
nsIAtom* aVar,
|
||||
PRInt32* aResult)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aLeft);
|
||||
NS_ENSURE_ARG_POINTER(aRight);
|
||||
|
||||
*aResult = 0;
|
||||
|
||||
nsCOMPtr<nsISupports> leftNode;
|
||||
aLeft->GetBindingObjectFor(aVar, getter_AddRefs(leftNode));
|
||||
// for natural order sorting, use the index in the RDF container for the
|
||||
// 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));
|
||||
}
|
||||
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
@ -940,6 +1006,13 @@ nsXULTemplateQueryProcessorRDF::CheckEmpty(nsIRDFResource* aResource,
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
PRBool* aIsEmpty);
|
||||
|
||||
/**
|
||||
* Check if a resource is a separator
|
||||
*/
|
||||
nsresult
|
||||
CheckIsSeparator(nsIRDFResource* aResource, PRBool* aIsSeparator);
|
||||
|
||||
/*
|
||||
* Compute the containment properties which are additional arcs which
|
||||
* indicate that a node is a container, in additional to the RDF container
|
||||
|
@ -266,6 +272,23 @@ public:
|
|||
*/
|
||||
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; }
|
||||
|
||||
nsIXULTemplateBuilder* GetBuilder() { return mBuilder; }
|
||||
|
@ -315,6 +338,9 @@ protected:
|
|||
// fixed size allocator used to allocate rule network structures
|
||||
nsFixedSizeAllocator mPool;
|
||||
|
||||
// the reference variable
|
||||
nsCOMPtr<nsIAtom> mRefVariable;
|
||||
|
||||
// the last ref that was calculated, used for simple rules
|
||||
nsCOMPtr<nsIXULTemplateResult> mLastRef;
|
||||
|
||||
|
@ -364,6 +390,8 @@ protected:
|
|||
public:
|
||||
static nsIRDFService* gRDFService;
|
||||
static nsIRDFContainerUtils* gRDFContainerUtils;
|
||||
static nsIRDFResource* kNC_BookmarkSeparator;
|
||||
static nsIRDFResource* kRDF_type;
|
||||
|
||||
nsFixedSizeAllocator& GetPool() { return mPool; }
|
||||
};
|
||||
|
|
|
@ -119,6 +119,24 @@ nsXULTemplateResultRDF::GetResource(nsIRDFResource** aResource)
|
|||
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
|
||||
nsXULTemplateResultRDF::GetBindingFor(nsIAtom* aVar, nsAString& aValue)
|
||||
{
|
||||
|
|
|
@ -95,13 +95,6 @@ protected:
|
|||
NS_NewXULTreeBuilder(nsISupports* aOuter, REFNSIID aIID, void** aResult);
|
||||
|
||||
nsXULTreeBuilder();
|
||||
virtual ~nsXULTreeBuilder();
|
||||
|
||||
/**
|
||||
* Initialize the template builder
|
||||
*/
|
||||
nsresult
|
||||
InitGlobals();
|
||||
|
||||
/**
|
||||
* Uninitialize the template builder
|
||||
|
@ -274,15 +267,7 @@ protected:
|
|||
* The builder observers.
|
||||
*/
|
||||
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
|
||||
nsXULTreeBuilder::Uninit(PRBool aIsFinal)
|
||||
{
|
||||
|
@ -632,10 +590,11 @@ nsXULTreeBuilder::IsSeparator(PRInt32 aIndex, PRBool* aResult)
|
|||
if (aIndex < 0 || aIndex >= mRows.Count())
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
nsCOMPtr<nsIRDFResource> resource;
|
||||
GetResourceFor(aIndex, getter_AddRefs(resource));
|
||||
nsAutoString type;
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "nsIDOMClassInfo.h"
|
||||
#include "nsIEventStateManager.h"
|
||||
#include "nsINodeInfo.h"
|
||||
#include "nsIXULSortService.h"
|
||||
|
||||
// A content model view implementation for the tree.
|
||||
|
||||
|
@ -597,6 +598,37 @@ nsTreeContentView::ToggleOpenState(PRInt32 aIndex)
|
|||
NS_IMETHODIMP
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче