1999-06-25 06:47:28 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-file-style: "stroustrup" -*-
|
1999-03-05 23:51:41 +00:00
|
|
|
*
|
1999-11-06 03:43:54 +00:00
|
|
|
* The contents of this file are subject to the Netscape 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/NPL/
|
1999-03-05 23:51:41 +00:00
|
|
|
*
|
1999-11-06 03:43:54 +00:00
|
|
|
* 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.
|
1999-03-05 23:51:41 +00:00
|
|
|
*
|
1999-11-06 03:43:54 +00:00
|
|
|
* The Original Code is mozilla.org code.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is Netscape
|
1999-03-05 23:51:41 +00:00
|
|
|
* Communications Corporation. Portions created by Netscape are
|
1999-11-06 03:43:54 +00:00
|
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
|
|
* Rights Reserved.
|
|
|
|
*
|
2000-05-04 12:54:11 +00:00
|
|
|
* Original Author(s):
|
|
|
|
* Robert John Churchill <rjc@netscape.com>
|
|
|
|
* Chris Waterson <waterson@netscape.com>
|
|
|
|
*
|
1999-11-06 03:43:54 +00:00
|
|
|
* Contributor(s):
|
2000-05-06 00:01:01 +00:00
|
|
|
* Scott Putterman <putterman@netscape.com>
|
2000-05-04 12:54:11 +00:00
|
|
|
* Pierre Phaneuf <pp@ludusdesign.com>
|
2001-11-17 17:17:24 +00:00
|
|
|
* Chase Tingley <tingley@sundell.net>
|
2002-03-29 02:46:01 +00:00
|
|
|
* Joe Hewitt <hewitt@netscape.com>
|
2000-04-05 02:39:51 +00:00
|
|
|
*
|
|
|
|
* 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
|
1999-03-05 23:51:41 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
This file provides the implementation for the sort service manager.
|
|
|
|
*/
|
|
|
|
|
1999-03-07 09:44:38 +00:00
|
|
|
#include "nsCOMPtr.h"
|
|
|
|
#include "nsCRT.h"
|
|
|
|
#include "nsIAtom.h"
|
|
|
|
#include "nsIContent.h"
|
|
|
|
#include "nsIDOMElement.h"
|
|
|
|
#include "nsIDOMNode.h"
|
|
|
|
#include "nsIDocument.h"
|
|
|
|
#include "nsINameSpaceManager.h"
|
|
|
|
#include "nsIRDFCompositeDataSource.h"
|
|
|
|
#include "nsIRDFNode.h"
|
|
|
|
#include "nsIRDFObserver.h"
|
|
|
|
#include "nsIRDFService.h"
|
|
|
|
#include "nsIServiceManager.h"
|
|
|
|
#include "nsISupportsArray.h"
|
|
|
|
#include "nsIURL.h"
|
|
|
|
#include "nsRDFCID.h"
|
2001-02-22 03:01:34 +00:00
|
|
|
#include "nsXULContentUtils.h"
|
1999-03-07 09:44:38 +00:00
|
|
|
#include "nsString.h"
|
1999-03-29 19:52:54 +00:00
|
|
|
#include "nsXPIDLString.h"
|
2001-10-13 00:16:32 +00:00
|
|
|
#include "nsUnicharUtils.h"
|
1999-03-07 09:44:38 +00:00
|
|
|
#include "rdf.h"
|
2000-01-25 04:07:41 +00:00
|
|
|
#include "nsRDFSort.h"
|
1999-03-07 09:44:38 +00:00
|
|
|
#include "nsVoidArray.h"
|
1999-04-14 03:28:49 +00:00
|
|
|
#include "nsQuickSort.h"
|
1999-03-05 23:51:41 +00:00
|
|
|
#include "nsIXULSortService.h"
|
|
|
|
#include "prlog.h"
|
1999-05-17 22:43:47 +00:00
|
|
|
#include "nsICollation.h"
|
|
|
|
#include "nsCollationCID.h"
|
1999-03-05 23:51:41 +00:00
|
|
|
#include "nsLayoutCID.h"
|
1999-03-11 12:01:47 +00:00
|
|
|
#include "nsIDOMXULElement.h"
|
1999-07-17 21:36:17 +00:00
|
|
|
#include "nsILocale.h"
|
2000-03-20 22:48:39 +00:00
|
|
|
#include "nsILocaleService.h"
|
2001-11-17 17:17:24 +00:00
|
|
|
#include "nsIRDFContainerUtils.h"
|
|
|
|
#include "nsXULAtoms.h"
|
1999-07-17 21:36:17 +00:00
|
|
|
|
1999-03-05 23:51:41 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
1999-03-07 09:44:38 +00:00
|
|
|
static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
|
1999-05-17 22:43:47 +00:00
|
|
|
static NS_DEFINE_CID(kCollationFactoryCID, NS_COLLATIONFACTORY_CID);
|
1999-09-08 03:04:45 +00:00
|
|
|
static NS_DEFINE_CID(kRDFInMemoryDataSourceCID, NS_RDFINMEMORYDATASOURCE_CID);
|
2001-11-17 17:17:24 +00:00
|
|
|
static NS_DEFINE_CID(kRDFContainerUtilsCID, NS_RDFCONTAINERUTILS_CID);
|
1999-09-08 03:04:45 +00:00
|
|
|
|
1999-04-27 02:28:12 +00:00
|
|
|
DEFINE_RDF_VOCAB(NC_NAMESPACE_URI, NC, BookmarkSeparator);
|
1999-03-05 23:51:41 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
typedef struct _sortStruct {
|
|
|
|
PRBool firstFlag;
|
|
|
|
nsCOMPtr<nsIRDFResource> sortProperty, sortProperty2;
|
|
|
|
nsCOMPtr<nsIRDFResource> sortPropertyColl, sortPropertyColl2;
|
|
|
|
nsCOMPtr<nsIRDFResource> sortPropertySort, sortPropertySort2;
|
2000-01-13 10:16:32 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
PRBool cacheFirstHint;
|
|
|
|
nsCOMPtr<nsIRDFNode> cacheFirstNode;
|
|
|
|
PRBool cacheIsFirstNodeCollationKey;
|
2000-01-14 01:21:55 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
nsCOMPtr<nsIRDFCompositeDataSource> db;
|
|
|
|
nsCOMPtr<nsIRDFDataSource> mInner;
|
|
|
|
nsCOMPtr<nsIContent> parentContainer;
|
|
|
|
PRBool descendingSort;
|
|
|
|
PRBool naturalOrderSort;
|
|
|
|
PRBool inbetweenSeparatorSort;
|
2000-01-13 10:16:32 +00:00
|
|
|
|
1999-03-10 07:07:10 +00:00
|
|
|
} sortStruct, *sortPtr;
|
|
|
|
|
2000-02-15 05:05:29 +00:00
|
|
|
typedef struct {
|
2002-03-29 02:46:01 +00:00
|
|
|
nsIContent * content;
|
|
|
|
nsCOMPtr<nsIRDFResource> resource;
|
|
|
|
nsCOMPtr<nsIRDFNode> collationNode1;
|
|
|
|
nsCOMPtr<nsIRDFNode> collationNode2;
|
|
|
|
nsCOMPtr<nsIRDFNode> sortNode1;
|
|
|
|
nsCOMPtr<nsIRDFNode> sortNode2;
|
|
|
|
nsCOMPtr<nsIRDFNode> node1;
|
|
|
|
nsCOMPtr<nsIRDFNode> node2;
|
|
|
|
PRBool checkedCollation1;
|
|
|
|
PRBool checkedCollation2;
|
|
|
|
PRBool checkedSort1;
|
|
|
|
PRBool checkedSort2;
|
|
|
|
PRBool checkedNode1;
|
|
|
|
PRBool checkedNode2;
|
2000-02-15 05:05:29 +00:00
|
|
|
} contentSortInfo;
|
1999-03-10 07:07:10 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
int PR_CALLBACK inplaceSortCallback(const void *data1, const void *data2, void *privateData);
|
|
|
|
int PR_CALLBACK testSortCallback(const void * data1, const void *data2, void *privateData);
|
1999-03-10 07:07:10 +00:00
|
|
|
|
1999-03-05 23:51:41 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
// ServiceImpl
|
|
|
|
//
|
|
|
|
// This is the sort service.
|
|
|
|
//
|
|
|
|
class XULSortServiceImpl : public nsIXULSortService
|
|
|
|
{
|
|
|
|
protected:
|
2002-03-29 02:46:01 +00:00
|
|
|
XULSortServiceImpl(void);
|
|
|
|
virtual ~XULSortServiceImpl(void);
|
1999-03-05 23:51:41 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
static nsICollation *gCollation;
|
1999-08-30 10:05:40 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
friend nsresult NS_NewXULSortService(nsIXULSortService** mgr);
|
1999-03-05 23:51:41 +00:00
|
|
|
|
|
|
|
private:
|
2002-03-29 02:46:01 +00:00
|
|
|
static nsrefcnt gRefCnt;
|
|
|
|
static nsIAtom *kStaticHintAtom;
|
|
|
|
static nsIAtom *kStaticsSortLastHintAtom;
|
|
|
|
static nsIAtom *kResourceAtom;
|
|
|
|
static nsIAtom *kSortResourceAtom;
|
|
|
|
static nsIAtom *kSortResource2Atom;
|
|
|
|
static nsIAtom *kSortSeparatorsAtom;
|
|
|
|
static nsIAtom *kRDF_type;
|
|
|
|
|
|
|
|
static nsString *kTrueStr;
|
|
|
|
static nsString *kNaturalStr;
|
|
|
|
static nsString *kAscendingStr;
|
|
|
|
static nsString *kDescendingStr;
|
|
|
|
|
|
|
|
static nsIRDFService *gRDFService;
|
|
|
|
static nsIRDFContainerUtils *gRDFC;
|
|
|
|
|
|
|
|
nsresult FindDatabaseElement(nsIContent* aElement, nsIContent** aDatabaseElement);
|
|
|
|
nsresult FindSortableContainer(nsIContent *tree, nsIContent **treeBody);
|
2002-10-22 19:49:29 +00:00
|
|
|
nsresult SetSortHints(nsIContent *tree, const nsAString &sortResource, const nsAString &sortDirection, const nsAString &sortResource2, PRBool inbetweenSeparatorSort, PRBool found);
|
|
|
|
nsresult SetSortColumnHints(nsIContent *content, const nsAString &sortResource, const nsAString &sortDirection);
|
|
|
|
nsresult GetSortColumnInfo(nsIContent *tree, nsAString &sortResource, nsAString &sortDirection, nsAString &sortResource2, PRBool &inbetweenSeparatorSort);
|
2002-03-29 02:46:01 +00:00
|
|
|
|
|
|
|
nsresult SortContainer(nsIContent *container, sortPtr sortInfo, PRBool merelyInvertFlag);
|
|
|
|
nsresult InvertSortInfo(contentSortInfo **data, PRInt32 numItems);
|
|
|
|
|
|
|
|
static nsresult GetCachedTarget(sortPtr sortInfo, PRBool useCache, nsIRDFResource* aSource, nsIRDFResource *aProperty, PRBool aTruthValue, nsIRDFNode **aResult);
|
2000-02-15 05:05:29 +00:00
|
|
|
static nsresult GetTarget(contentSortInfo *contentSortInfo, sortPtr sortInfo, PRBool first, PRBool onlyCollationHint, PRBool truthValue,nsIRDFNode **target, PRBool &isCollationKey);
|
2002-03-29 02:46:01 +00:00
|
|
|
static nsresult GetResourceValue(nsIRDFResource *res1, sortPtr sortInfo, PRBool first, PRBool useCache, PRBool onlyCollationHint, nsIRDFNode **, PRBool &isCollationKey);
|
|
|
|
static nsresult GetResourceValue(contentSortInfo *contentSortInfo, sortPtr sortInfo, PRBool first, PRBool useCache, PRBool onlyCollationHint, nsIRDFNode **target, PRBool &isCollationKey);
|
|
|
|
static nsresult GetNodeValue(nsIContent *node1, sortPtr sortInfo, PRBool first, PRBool onlyCollationHint, nsIRDFNode **, PRBool &isCollationKey);
|
2000-02-15 05:05:29 +00:00
|
|
|
static nsresult GetNodeValue(contentSortInfo *info1, sortPtr sortInfo, PRBool first, PRBool onlyCollationHint, nsIRDFNode **theNode, PRBool &isCollationKey);
|
1999-05-13 08:25:12 +00:00
|
|
|
|
1999-03-05 23:51:41 +00:00
|
|
|
public:
|
2002-03-29 02:46:01 +00:00
|
|
|
// nsISupports
|
|
|
|
NS_DECL_ISUPPORTS
|
1999-05-13 08:25:12 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
// nsISortService
|
|
|
|
NS_DECL_NSIXULSORTSERVICE
|
1999-03-05 23:51:41 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
static nsresult InplaceSort(nsIContent *node1, nsIContent *node2, sortPtr sortInfo, PRInt32 & sortOrder);
|
|
|
|
static nsresult InplaceSort(contentSortInfo *info1, contentSortInfo *info2, sortPtr sortInfo, PRInt32 & sortOrder);
|
|
|
|
static nsresult CompareNodes(nsIRDFNode *cellNode1, PRBool isCollationKey1,
|
|
|
|
nsIRDFNode *cellNode2, PRBool isCollationKey2,
|
|
|
|
PRBool &bothValid, PRInt32 & sortOrder);
|
1999-03-05 23:51:41 +00:00
|
|
|
};
|
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
nsICollation *XULSortServiceImpl::gCollation = nsnull;
|
|
|
|
nsIRDFService *XULSortServiceImpl::gRDFService = nsnull;
|
|
|
|
nsIRDFContainerUtils *XULSortServiceImpl::gRDFC = nsnull;
|
1999-03-05 23:51:41 +00:00
|
|
|
nsrefcnt XULSortServiceImpl::gRefCnt = 0;
|
|
|
|
|
2000-05-06 00:01:01 +00:00
|
|
|
nsIAtom* XULSortServiceImpl::kStaticHintAtom;
|
|
|
|
nsIAtom* XULSortServiceImpl::kStaticsSortLastHintAtom;
|
1999-03-05 23:51:41 +00:00
|
|
|
nsIAtom* XULSortServiceImpl::kResourceAtom;
|
1999-11-14 11:10:34 +00:00
|
|
|
nsIAtom* XULSortServiceImpl::kSortResourceAtom;
|
|
|
|
nsIAtom* XULSortServiceImpl::kSortResource2Atom;
|
1999-11-23 01:02:55 +00:00
|
|
|
nsIAtom* XULSortServiceImpl::kSortSeparatorsAtom;
|
1999-04-27 02:28:12 +00:00
|
|
|
nsIAtom* XULSortServiceImpl::kRDF_type;
|
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
nsString* XULSortServiceImpl::kTrueStr = nsnull;
|
|
|
|
nsString* XULSortServiceImpl::kNaturalStr = nsnull;
|
|
|
|
nsString* XULSortServiceImpl::kAscendingStr = nsnull;
|
|
|
|
nsString* XULSortServiceImpl::kDescendingStr = nsnull;
|
1999-03-05 23:51:41 +00:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
XULSortServiceImpl::XULSortServiceImpl(void)
|
|
|
|
{
|
2002-03-29 02:46:01 +00:00
|
|
|
if (gRefCnt == 0) {
|
|
|
|
kStaticHintAtom = NS_NewAtom("staticHint");
|
|
|
|
kStaticsSortLastHintAtom = NS_NewAtom("sortStaticsLast");
|
|
|
|
kResourceAtom = NS_NewAtom("resource");
|
|
|
|
kSortResourceAtom = NS_NewAtom("sortResource");
|
|
|
|
kSortResource2Atom = NS_NewAtom("sortResource2");
|
|
|
|
kSortSeparatorsAtom = NS_NewAtom("sortSeparators");
|
|
|
|
kRDF_type = NS_NewAtom("type");
|
1999-03-05 23:51:41 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
kTrueStr = new nsString(NS_LITERAL_STRING("true"));
|
|
|
|
kNaturalStr = new nsString(NS_LITERAL_STRING("natural"));
|
|
|
|
kAscendingStr = new nsString(NS_LITERAL_STRING("ascending"));
|
|
|
|
kDescendingStr = new nsString(NS_LITERAL_STRING("descending"));
|
1999-11-23 01:51:46 +00:00
|
|
|
|
2002-12-11 14:24:49 +00:00
|
|
|
nsresult rv = CallGetService(kRDFServiceCID, &gRDFService);
|
2002-03-29 02:46:01 +00:00
|
|
|
if (NS_FAILED(rv))
|
|
|
|
NS_ERROR("couldn't create rdf service");
|
|
|
|
|
2002-12-11 14:24:49 +00:00
|
|
|
rv = CallGetService(kRDFContainerUtilsCID, &gRDFC);
|
2002-03-29 02:46:01 +00:00
|
|
|
if (NS_FAILED(rv))
|
|
|
|
NS_ERROR("couldn't create rdf container utils");
|
|
|
|
|
|
|
|
// get a locale service
|
|
|
|
nsCOMPtr<nsILocaleService> localeService = do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
nsCOMPtr<nsILocale> locale;
|
|
|
|
if (NS_SUCCEEDED(rv = localeService->GetApplicationLocale(getter_AddRefs(locale))) && (locale)) {
|
|
|
|
nsCOMPtr<nsICollationFactory> colFactory = do_CreateInstance(kCollationFactoryCID);
|
|
|
|
if (colFactory) {
|
|
|
|
if (NS_FAILED(rv = colFactory->CreateCollation(locale, &gCollation)))
|
|
|
|
NS_ERROR("couldn't create collation instance");
|
|
|
|
} else
|
|
|
|
NS_ERROR("couldn't create instance of collation factory");
|
|
|
|
} else
|
|
|
|
NS_ERROR("unable to get application locale");
|
|
|
|
} else
|
|
|
|
NS_ERROR("couldn't get locale factory");
|
|
|
|
}
|
1999-03-05 23:51:41 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
++gRefCnt;
|
|
|
|
}
|
1999-03-11 12:01:47 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
XULSortServiceImpl::~XULSortServiceImpl(void) {
|
1999-10-07 01:51:30 +00:00
|
|
|
#ifdef DEBUG_REFS
|
|
|
|
--gInstanceCount;
|
2000-10-28 22:17:53 +00:00
|
|
|
fprintf(stdout, "%d - RDF: XULSortServiceImpl\n", gInstanceCount);
|
1999-10-07 01:51:30 +00:00
|
|
|
#endif
|
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
--gRefCnt;
|
|
|
|
if (gRefCnt == 0) {
|
|
|
|
delete kTrueStr;
|
|
|
|
kTrueStr = nsnull;
|
|
|
|
delete kAscendingStr;
|
|
|
|
kAscendingStr = nsnull;
|
|
|
|
delete kDescendingStr;
|
|
|
|
kDescendingStr = nsnull;
|
|
|
|
delete kNaturalStr;
|
|
|
|
kNaturalStr = nsnull;
|
|
|
|
|
|
|
|
NS_IF_RELEASE(kStaticHintAtom);
|
|
|
|
NS_IF_RELEASE(kStaticsSortLastHintAtom);
|
|
|
|
NS_IF_RELEASE(kResourceAtom);
|
|
|
|
NS_IF_RELEASE(kSortResourceAtom);
|
|
|
|
NS_IF_RELEASE(kSortResource2Atom);
|
|
|
|
NS_IF_RELEASE(kSortSeparatorsAtom);
|
|
|
|
NS_IF_RELEASE(kRDF_type);
|
|
|
|
|
|
|
|
NS_IF_RELEASE(gCollation);
|
|
|
|
|
2002-12-11 14:24:49 +00:00
|
|
|
NS_IF_RELEASE(gRDFService);
|
|
|
|
NS_IF_RELEASE(gRDFC);
|
2002-03-29 02:46:01 +00:00
|
|
|
}
|
1999-03-05 23:51:41 +00:00
|
|
|
}
|
|
|
|
|
2000-11-17 20:54:21 +00:00
|
|
|
NS_IMPL_ISUPPORTS1(XULSortServiceImpl, nsIXULSortService)
|
1999-05-13 08:25:12 +00:00
|
|
|
|
1999-03-05 23:51:41 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
1999-11-14 11:10:34 +00:00
|
|
|
nsresult
|
2002-03-29 02:46:01 +00:00
|
|
|
XULSortServiceImpl::FindDatabaseElement(nsIContent *aElement, nsIContent **aDatabaseElement)
|
1999-11-14 11:10:34 +00:00
|
|
|
{
|
2002-03-29 02:46:01 +00:00
|
|
|
*aDatabaseElement = nsnull;
|
|
|
|
|
|
|
|
// so look from the current node upwards until we find a node with a database
|
|
|
|
nsCOMPtr<nsIContent> content(do_QueryInterface(aElement));
|
|
|
|
while (content) {
|
|
|
|
nsCOMPtr<nsIDOMXULElement> element = do_QueryInterface(content);
|
|
|
|
nsCOMPtr<nsIRDFCompositeDataSource> db;
|
|
|
|
element->GetDatabase(getter_AddRefs(db));
|
|
|
|
if (db) {
|
|
|
|
*aDatabaseElement = content;
|
|
|
|
NS_ADDREF(*aDatabaseElement);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> parent;
|
|
|
|
content->GetParent(*getter_AddRefs(parent));
|
|
|
|
content = parent;
|
|
|
|
}
|
1999-03-11 12:01:47 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
1999-03-05 23:51:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2002-03-29 02:46:01 +00:00
|
|
|
XULSortServiceImpl::FindSortableContainer(nsIContent *aRoot, nsIContent **aContainer)
|
1999-03-05 23:51:41 +00:00
|
|
|
{
|
2002-03-29 02:46:01 +00:00
|
|
|
nsresult rv;
|
1999-11-23 01:51:46 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
nsCOMPtr<nsIAtom> tag;
|
|
|
|
if (NS_FAILED(rv = aRoot->GetTag(*getter_AddRefs(tag)))) return rv;
|
1999-11-23 01:51:46 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
if (tag == nsXULAtoms::templateAtom) // ignore content within templates
|
|
|
|
return NS_OK;
|
1999-11-23 01:51:46 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
if (tag == nsXULAtoms::listbox || tag == nsXULAtoms::treechildren || tag == nsXULAtoms::menupopup)
|
|
|
|
{
|
|
|
|
*aContainer = aRoot;
|
|
|
|
NS_ADDREF(*aContainer);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
1999-03-07 09:44:38 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
nsCOMPtr<nsIContent> child;
|
|
|
|
PRInt32 childIndex = 0, numChildren = 0, nameSpaceID;
|
|
|
|
|
|
|
|
if (NS_FAILED(rv = aRoot->ChildCount(numChildren))) return rv;
|
|
|
|
for (childIndex = 0; childIndex < numChildren; childIndex++) {
|
|
|
|
if (NS_FAILED(rv = aRoot->ChildAt(childIndex, *getter_AddRefs(child)))) return rv;
|
|
|
|
if (NS_FAILED(rv = child->GetNameSpaceID(nameSpaceID))) return rv;
|
|
|
|
if (nameSpaceID == kNameSpaceID_XUL) {
|
|
|
|
rv = FindSortableContainer(child, aContainer);
|
|
|
|
if (*aContainer)
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
}
|
1999-03-11 12:01:47 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
1999-03-11 12:01:47 +00:00
|
|
|
|
1999-03-07 09:44:38 +00:00
|
|
|
nsresult
|
2002-10-22 19:49:29 +00:00
|
|
|
XULSortServiceImpl::SetSortHints(nsIContent *tree, const nsAString &sortResource,
|
|
|
|
const nsAString &sortDirection, const nsAString &sortResource2,
|
2002-03-29 02:46:01 +00:00
|
|
|
PRBool inbetweenSeparatorSort, PRBool found)
|
1999-03-07 09:44:38 +00:00
|
|
|
{
|
2002-03-29 02:46:01 +00:00
|
|
|
if (found) {
|
|
|
|
// set hints on tree root node
|
|
|
|
tree->SetAttr(kNameSpaceID_None, nsXULAtoms::sortActive, *kTrueStr, PR_FALSE);
|
|
|
|
tree->SetAttr(kNameSpaceID_None, nsXULAtoms::sortDirection, sortDirection, PR_FALSE);
|
|
|
|
tree->SetAttr(kNameSpaceID_None, kSortResourceAtom, sortResource, PR_FALSE);
|
|
|
|
|
|
|
|
if (!sortResource2.IsEmpty())
|
|
|
|
tree->SetAttr(kNameSpaceID_None, kSortResource2Atom, sortResource2, PR_FALSE);
|
|
|
|
else
|
|
|
|
tree->UnsetAttr(kNameSpaceID_None, kSortResource2Atom, PR_FALSE);
|
|
|
|
} else {
|
|
|
|
tree->UnsetAttr(kNameSpaceID_None, nsXULAtoms::sortActive, PR_FALSE);
|
|
|
|
tree->UnsetAttr(kNameSpaceID_None, nsXULAtoms::sortDirection, PR_FALSE);
|
|
|
|
tree->UnsetAttr(kNameSpaceID_None, kSortResourceAtom, PR_FALSE);
|
|
|
|
tree->UnsetAttr(kNameSpaceID_None, kSortResource2Atom, PR_FALSE);
|
|
|
|
}
|
1999-11-23 01:02:55 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
// optional hint
|
|
|
|
if (inbetweenSeparatorSort == PR_TRUE)
|
|
|
|
tree->SetAttr(kNameSpaceID_None, kSortSeparatorsAtom, *kTrueStr, PR_FALSE);
|
|
|
|
else
|
|
|
|
tree->UnsetAttr(kNameSpaceID_None, kSortSeparatorsAtom, PR_FALSE);
|
1999-11-23 01:02:55 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
SetSortColumnHints(tree, sortResource, sortDirection);
|
1999-11-23 01:02:55 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
return NS_OK;
|
1999-03-05 23:51:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2002-10-22 19:49:29 +00:00
|
|
|
XULSortServiceImpl::SetSortColumnHints(nsIContent *content, const nsAString &sortResource, const nsAString &sortDirection)
|
1999-03-05 23:51:41 +00:00
|
|
|
{
|
2002-03-29 02:46:01 +00:00
|
|
|
PRInt32 numChildren, childIndex, nameSpaceID;
|
|
|
|
nsCOMPtr<nsIContent> child;
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
if (NS_FAILED(rv = content->ChildCount(numChildren))) return rv;
|
|
|
|
|
|
|
|
for (childIndex = 0; childIndex < numChildren; ++childIndex) {
|
|
|
|
if (NS_FAILED(rv = content->ChildAt(childIndex, *getter_AddRefs(child)))) return rv;
|
|
|
|
if (NS_FAILED(rv = child->GetNameSpaceID(nameSpaceID))) return rv;
|
|
|
|
|
|
|
|
if (nameSpaceID == kNameSpaceID_XUL) {
|
|
|
|
nsCOMPtr<nsIAtom> tag;
|
|
|
|
if (NS_FAILED(rv = child->GetTag(*getter_AddRefs(tag)))) return rv;
|
|
|
|
|
|
|
|
if (tag == nsXULAtoms::treecols || tag == nsXULAtoms::listcols || tag == nsXULAtoms::listhead) {
|
|
|
|
rv = SetSortColumnHints(child, sortResource, sortDirection);
|
|
|
|
} else if (tag == nsXULAtoms::treecol ||
|
|
|
|
tag == nsXULAtoms::listcol || tag == nsXULAtoms::listheader) {
|
|
|
|
nsAutoString value;
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv = child->GetAttr(kNameSpaceID_None, kResourceAtom, value))
|
|
|
|
&& rv == NS_CONTENT_ATTR_HAS_VALUE)
|
|
|
|
{
|
|
|
|
if (value == sortResource) {
|
|
|
|
child->SetAttr(kNameSpaceID_None, nsXULAtoms::sortActive, *kTrueStr, PR_TRUE);
|
|
|
|
child->SetAttr(kNameSpaceID_None, nsXULAtoms::sortDirection, sortDirection, PR_TRUE);
|
|
|
|
// Note: don't break out of loop; want to set/unset attribs on ALL sort columns
|
|
|
|
} else {
|
|
|
|
child->UnsetAttr(kNameSpaceID_None, nsXULAtoms::sortActive, PR_TRUE);
|
|
|
|
child->UnsetAttr(kNameSpaceID_None, nsXULAtoms::sortDirection, PR_TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
1999-03-05 23:51:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2002-10-22 19:49:29 +00:00
|
|
|
XULSortServiceImpl::GetSortColumnInfo(nsIContent *tree, nsAString &sortResource,
|
|
|
|
nsAString &sortDirection, nsAString &sortResource2,
|
2002-03-29 02:46:01 +00:00
|
|
|
PRBool &inbetweenSeparatorSort)
|
1999-03-05 23:51:41 +00:00
|
|
|
{
|
2002-03-29 02:46:01 +00:00
|
|
|
nsresult rv = NS_ERROR_FAILURE;
|
|
|
|
inbetweenSeparatorSort = PR_FALSE;
|
1999-03-05 23:51:41 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
nsAutoString value;
|
|
|
|
if (NS_SUCCEEDED(rv = tree->GetAttr(kNameSpaceID_None, nsXULAtoms::sortActive, value))
|
|
|
|
&& (rv == NS_CONTENT_ATTR_HAS_VALUE))
|
|
|
|
{
|
|
|
|
if (value.EqualsIgnoreCase("true"))
|
|
|
|
{
|
|
|
|
if (NS_SUCCEEDED(rv = tree->GetAttr(kNameSpaceID_None, kSortResourceAtom, sortResource))
|
|
|
|
&& (rv == NS_CONTENT_ATTR_HAS_VALUE))
|
|
|
|
{
|
|
|
|
if (NS_SUCCEEDED(rv = tree->GetAttr(kNameSpaceID_None, nsXULAtoms::sortDirection, sortDirection))
|
|
|
|
&& (rv == NS_CONTENT_ATTR_HAS_VALUE))
|
|
|
|
{
|
|
|
|
rv = NS_OK;
|
|
|
|
|
|
|
|
// sort separator flag is optional
|
|
|
|
if (NS_SUCCEEDED(rv = tree->GetAttr(kNameSpaceID_None, kSortSeparatorsAtom,
|
|
|
|
value)) && (rv == NS_CONTENT_ATTR_HAS_VALUE))
|
|
|
|
{
|
|
|
|
if (value.EqualsIgnoreCase("true"))
|
|
|
|
{
|
|
|
|
inbetweenSeparatorSort = PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// secondary sort info is optional
|
|
|
|
if (NS_FAILED(rv = tree->GetAttr(kNameSpaceID_None, kSortResource2Atom, sortResource2))
|
|
|
|
|| (rv != NS_CONTENT_ATTR_HAS_VALUE))
|
|
|
|
{
|
|
|
|
sortResource2.Truncate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
1999-03-11 12:01:47 +00:00
|
|
|
|
1999-05-13 08:25:12 +00:00
|
|
|
nsresult
|
1999-07-07 05:32:07 +00:00
|
|
|
XULSortServiceImpl::CompareNodes(nsIRDFNode *cellNode1, PRBool isCollationKey1,
|
2002-03-29 02:46:01 +00:00
|
|
|
nsIRDFNode *cellNode2, PRBool isCollationKey2,
|
|
|
|
PRBool &bothValid, PRInt32 & sortOrder)
|
1999-03-07 09:44:38 +00:00
|
|
|
{
|
2002-01-30 22:37:17 +00:00
|
|
|
bothValid = PR_FALSE;
|
|
|
|
sortOrder = 0;
|
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
// First, check for blobs. This is the preferred way to do a raw key comparison.
|
2002-01-30 22:37:17 +00:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIRDFBlob> l = do_QueryInterface(cellNode1);
|
|
|
|
if (l)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIRDFBlob> r = do_QueryInterface(cellNode2);
|
|
|
|
if (r)
|
|
|
|
{
|
|
|
|
const PRUint8 *lkey, *rkey;
|
|
|
|
PRInt32 llen, rlen;
|
|
|
|
l->GetValue(&lkey);
|
|
|
|
l->GetLength(&llen);
|
|
|
|
r->GetValue(&rkey);
|
|
|
|
r->GetLength(&rlen);
|
|
|
|
bothValid = PR_TRUE;
|
|
|
|
if (gCollation)
|
|
|
|
return gCollation->CompareRawSortKey(lkey, llen, rkey, rlen, &sortOrder);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Next, literals. If isCollationKey1 and 2 are both set, do
|
|
|
|
// an unsafe raw comparison. (XXX Remove this code someday.)
|
2002-03-29 02:46:01 +00:00
|
|
|
{
|
2002-01-30 22:37:17 +00:00
|
|
|
nsCOMPtr<nsIRDFLiteral> l = do_QueryInterface(cellNode1);
|
|
|
|
if (l)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIRDFLiteral> r = do_QueryInterface(cellNode2);
|
|
|
|
if (r)
|
|
|
|
{
|
|
|
|
const PRUnichar *luni, *runi;
|
|
|
|
l->GetValueConst(&luni);
|
|
|
|
r->GetValueConst(&runi);
|
|
|
|
bothValid = PR_TRUE;
|
|
|
|
if (isCollationKey1 && isCollationKey2)
|
|
|
|
return gCollation->CompareRawSortKey(NS_REINTERPRET_CAST(const PRUint8*, luni),
|
|
|
|
nsCRT::strlen(luni)*sizeof(PRUnichar),
|
|
|
|
NS_REINTERPRET_CAST(const PRUint8*, runi),
|
|
|
|
nsCRT::strlen(runi)*sizeof(PRUnichar),
|
|
|
|
&sortOrder);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
nsresult rv = NS_ERROR_FAILURE;
|
|
|
|
nsDependentString lstr(luni), rstr(runi);
|
|
|
|
if (gCollation)
|
|
|
|
rv = gCollation->CompareString(kCollationCaseInSensitive, lstr, rstr, &sortOrder);
|
2002-03-29 02:46:01 +00:00
|
|
|
if (NS_FAILED(rv))
|
2002-01-30 22:37:17 +00:00
|
|
|
sortOrder = Compare(lstr, rstr, nsCaseInsensitiveStringComparator());
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Integers.
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIRDFInt> l = do_QueryInterface(cellNode1);
|
|
|
|
if (l)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIRDFInt> r = do_QueryInterface(cellNode2);
|
|
|
|
if (r)
|
|
|
|
{
|
|
|
|
PRInt32 lint, rint;
|
|
|
|
l->GetValue(&lint);
|
|
|
|
r->GetValue(&rint);
|
|
|
|
bothValid = PR_TRUE;
|
|
|
|
sortOrder = 0;
|
|
|
|
if (lint < rint)
|
|
|
|
sortOrder = -1;
|
|
|
|
else if (lint > rint)
|
|
|
|
sortOrder = 1;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Dates.
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIRDFDate> l = do_QueryInterface(cellNode1);
|
|
|
|
if (l)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIRDFDate> r = do_QueryInterface(cellNode2);
|
|
|
|
if (r)
|
|
|
|
{
|
|
|
|
PRInt64 ldate, rdate, delta;
|
|
|
|
l->GetValue(&ldate);
|
|
|
|
r->GetValue(&rdate);
|
|
|
|
bothValid = PR_TRUE;
|
|
|
|
LL_SUB(delta, ldate, rdate);
|
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
if (LL_IS_ZERO(delta))
|
2002-01-30 22:37:17 +00:00
|
|
|
sortOrder = 0;
|
|
|
|
else if (LL_GE_ZERO(delta))
|
|
|
|
sortOrder = 1;
|
2002-03-29 02:46:01 +00:00
|
|
|
else
|
2002-01-30 22:37:17 +00:00
|
|
|
sortOrder = -1;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Rats.
|
|
|
|
return NS_OK;
|
1999-07-07 05:32:07 +00:00
|
|
|
}
|
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
nsresult
|
|
|
|
XULSortServiceImpl::GetResourceValue(nsIRDFResource *res1, sortPtr sortInfo,
|
|
|
|
PRBool first, PRBool useCache,
|
|
|
|
PRBool onlyCollationHint, nsIRDFNode **target, PRBool &isCollationKey)
|
|
|
|
{
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
|
|
|
|
*target = nsnull;
|
|
|
|
isCollationKey = PR_FALSE;
|
|
|
|
|
|
|
|
if (res1 && !sortInfo->naturalOrderSort) {
|
|
|
|
nsCOMPtr<nsIRDFResource> modSortRes;
|
1999-07-07 05:32:07 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
// for any given property, first ask the graph for its value with "?collation=true" appended
|
|
|
|
// to indicate that if there is a collation key available for this value, we want it
|
|
|
|
|
|
|
|
modSortRes = (first) ? sortInfo->sortPropertyColl : sortInfo->sortPropertyColl2;
|
|
|
|
if (modSortRes) {
|
|
|
|
if (NS_SUCCEEDED(rv = GetCachedTarget(sortInfo, useCache, res1, modSortRes, PR_TRUE, target))
|
|
|
|
&& (rv != NS_RDF_NO_VALUE))
|
|
|
|
{
|
|
|
|
isCollationKey = PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!*target && !onlyCollationHint) {
|
|
|
|
// if no collation key, ask the graph for its value with "?sort=true" appended
|
|
|
|
// to indicate that if there is any distinction between its display value and sorting
|
|
|
|
// value, we want the sorting value (so that, for example, a mail datasource could strip
|
|
|
|
// off a "Re:" on a mail message subject)
|
|
|
|
modSortRes = first ? sortInfo->sortPropertySort : sortInfo->sortPropertySort2;
|
|
|
|
if (modSortRes)
|
|
|
|
rv = GetCachedTarget(sortInfo, useCache, res1, modSortRes, PR_TRUE, target);
|
|
|
|
}
|
|
|
|
if (!*target && !onlyCollationHint) {
|
|
|
|
// if no collation key and no special sorting value, just get the property value
|
|
|
|
modSortRes = first ? sortInfo->sortProperty : sortInfo->sortProperty2;
|
|
|
|
if (modSortRes)
|
|
|
|
rv = GetCachedTarget(sortInfo, useCache, res1, modSortRes, PR_TRUE, target);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
1999-07-07 05:32:07 +00:00
|
|
|
|
1999-09-08 03:04:45 +00:00
|
|
|
nsresult
|
2002-03-29 02:46:01 +00:00
|
|
|
XULSortServiceImpl::GetResourceValue(contentSortInfo *contentSortInfo, sortPtr sortInfo,
|
|
|
|
PRBool first, PRBool useCache,
|
|
|
|
PRBool onlyCollationHint, nsIRDFNode **target, PRBool &isCollationKey)
|
1999-09-08 03:04:45 +00:00
|
|
|
{
|
2002-03-29 02:46:01 +00:00
|
|
|
nsresult rv = NS_OK;
|
1999-09-07 07:27:49 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
*target = nsnull;
|
|
|
|
isCollationKey = PR_FALSE;
|
1999-09-07 07:27:49 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
nsIRDFResource *res1 = contentSortInfo->resource;
|
|
|
|
|
|
|
|
if (res1 && sortInfo->naturalOrderSort == PR_FALSE)
|
|
|
|
rv = GetTarget(contentSortInfo, sortInfo, first, onlyCollationHint, PR_TRUE, target, isCollationKey);
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
1999-09-07 07:27:49 +00:00
|
|
|
|
|
|
|
nsresult
|
2002-03-29 02:46:01 +00:00
|
|
|
XULSortServiceImpl::GetCachedTarget(sortPtr sortInfo, PRBool useCache, nsIRDFResource* aSource,
|
|
|
|
nsIRDFResource *aProperty, PRBool aTruthValue, nsIRDFNode **aResult)
|
1999-09-07 07:27:49 +00:00
|
|
|
{
|
2002-03-29 02:46:01 +00:00
|
|
|
nsresult rv;
|
|
|
|
*aResult = nsnull;
|
1999-05-18 06:19:04 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
if (!(sortInfo->mInner)) {
|
|
|
|
// if we don't have a mInner, create one
|
|
|
|
sortInfo->mInner = do_CreateInstance(kRDFInMemoryDataSourceCID, &rv);
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
}
|
2000-05-07 08:43:42 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
rv = NS_RDF_NO_VALUE;
|
|
|
|
if (sortInfo->mInner) {
|
|
|
|
if (useCache) {
|
|
|
|
// if we do have a mInner, look for the resource in it
|
|
|
|
rv = sortInfo->mInner->GetTarget(aSource, aProperty, aTruthValue, aResult);
|
|
|
|
} else if (sortInfo->db) {
|
|
|
|
// if we don't have a cached value, look it up in the document's DB
|
|
|
|
if (NS_SUCCEEDED(rv = (sortInfo->db)->GetTarget(aSource, aProperty, aTruthValue, aResult))
|
|
|
|
&& (rv != NS_RDF_NO_VALUE))
|
|
|
|
{
|
|
|
|
// and if we have a value, cache it away in our mInner also (ignore errors)
|
|
|
|
sortInfo->mInner->Assert(aSource, aProperty, *aResult, PR_TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
2000-05-07 08:43:42 +00:00
|
|
|
|
2000-02-15 05:05:29 +00:00
|
|
|
nsresult
|
2002-03-29 02:46:01 +00:00
|
|
|
XULSortServiceImpl::GetTarget(contentSortInfo *contentSortInfo, sortPtr sortInfo,
|
|
|
|
PRBool first, PRBool onlyCollationHint, PRBool truthValue,
|
|
|
|
nsIRDFNode **target, PRBool &isCollationKey)
|
2000-02-15 05:05:29 +00:00
|
|
|
{
|
2002-03-29 02:46:01 +00:00
|
|
|
nsresult rv;
|
|
|
|
nsIRDFResource *resource = contentSortInfo->resource;
|
|
|
|
|
|
|
|
if (first) {
|
|
|
|
if (contentSortInfo->collationNode1) {
|
|
|
|
*target = contentSortInfo->collationNode1;
|
|
|
|
NS_IF_ADDREF(*target);
|
|
|
|
} else if (!contentSortInfo->checkedCollation1
|
|
|
|
&& NS_SUCCEEDED(rv = (sortInfo->db)->GetTarget(resource, sortInfo->sortPropertyColl, truthValue, target)))
|
|
|
|
{
|
|
|
|
if (rv != NS_RDF_NO_VALUE)
|
|
|
|
contentSortInfo->collationNode1 = *target;
|
|
|
|
contentSortInfo->checkedCollation1 = PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*target) {
|
|
|
|
isCollationKey = PR_TRUE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2000-02-15 05:05:29 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
if (onlyCollationHint == PR_FALSE)
|
|
|
|
{
|
|
|
|
if(contentSortInfo->sortNode1) {
|
|
|
|
*target = contentSortInfo->sortNode1;
|
|
|
|
NS_IF_ADDREF(*target);
|
|
|
|
} else if (!contentSortInfo->checkedSort1
|
|
|
|
&& NS_SUCCEEDED(rv = (sortInfo->db)->GetTarget(resource, sortInfo->sortPropertySort, truthValue, target)))
|
|
|
|
{
|
|
|
|
if (rv != NS_RDF_NO_VALUE)
|
|
|
|
contentSortInfo->sortNode1 = *target;
|
|
|
|
contentSortInfo->checkedSort1 = PR_TRUE;
|
|
|
|
}
|
2000-05-07 08:43:42 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
if (*target)
|
|
|
|
return NS_OK;
|
2000-05-07 08:43:42 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
if (contentSortInfo->node1) {
|
|
|
|
*target = contentSortInfo->node1;
|
|
|
|
NS_IF_ADDREF(*target);
|
|
|
|
} else if (!contentSortInfo->checkedNode1
|
|
|
|
&& NS_SUCCEEDED(rv = (sortInfo->db)->GetTarget(resource, sortInfo->sortProperty, truthValue, target)))
|
|
|
|
{
|
|
|
|
if (rv != NS_RDF_NO_VALUE)
|
|
|
|
contentSortInfo->node1 = *target;
|
|
|
|
contentSortInfo->checkedNode1 = PR_TRUE;
|
|
|
|
}
|
2000-05-07 08:43:42 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
if (*target)
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (contentSortInfo->collationNode2) {
|
|
|
|
*target = contentSortInfo->collationNode2;
|
|
|
|
NS_IF_ADDREF(*target);
|
|
|
|
} else if (!contentSortInfo->checkedCollation2
|
|
|
|
&& NS_SUCCEEDED(rv = (sortInfo->db)->GetTarget(resource, sortInfo->sortPropertyColl2, truthValue, target)))
|
|
|
|
{
|
|
|
|
if (rv != NS_RDF_NO_VALUE)
|
|
|
|
contentSortInfo->collationNode2 = *target;
|
|
|
|
contentSortInfo->checkedCollation2 = PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*target) {
|
|
|
|
isCollationKey = PR_TRUE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2000-02-15 05:05:29 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
if (onlyCollationHint == PR_FALSE) {
|
|
|
|
if(contentSortInfo->sortNode2) {
|
|
|
|
*target = contentSortInfo->sortNode2;
|
|
|
|
NS_IF_ADDREF(*target);
|
|
|
|
} else if (!contentSortInfo->checkedSort2
|
|
|
|
&& NS_SUCCEEDED(rv = (sortInfo->db)->GetTarget(resource, sortInfo->sortPropertySort2, truthValue, target)))
|
|
|
|
{
|
|
|
|
if (rv != NS_RDF_NO_VALUE)
|
|
|
|
contentSortInfo->sortNode2 = *target;
|
|
|
|
contentSortInfo->checkedSort2 = PR_TRUE;
|
|
|
|
}
|
1999-05-18 06:19:04 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
if (*target)
|
|
|
|
return NS_OK;
|
2000-02-15 05:05:29 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
if (contentSortInfo->node2) {
|
|
|
|
*target = contentSortInfo->node2;
|
|
|
|
NS_IF_ADDREF(*target);
|
|
|
|
} else if (!contentSortInfo->checkedNode2
|
|
|
|
&& NS_SUCCEEDED(rv = (sortInfo->db)->GetTarget(resource, sortInfo->sortProperty2, truthValue, target)))
|
|
|
|
{
|
|
|
|
if (rv != NS_RDF_NO_VALUE)
|
|
|
|
contentSortInfo->node2 = *target;
|
|
|
|
contentSortInfo->checkedNode2 = PR_TRUE;
|
|
|
|
}
|
2000-02-15 05:05:29 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
if (*target)
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_RDF_NO_VALUE;
|
2000-02-15 05:05:29 +00:00
|
|
|
}
|
1999-05-18 06:19:04 +00:00
|
|
|
|
|
|
|
nsresult
|
2000-01-13 10:16:32 +00:00
|
|
|
XULSortServiceImpl::GetNodeValue(nsIContent *node1, sortPtr sortInfo, PRBool first,
|
2002-03-29 02:46:01 +00:00
|
|
|
PRBool onlyCollationHint, nsIRDFNode **theNode, PRBool &isCollationKey)
|
1999-05-18 06:19:04 +00:00
|
|
|
{
|
2002-03-29 02:46:01 +00:00
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIRDFResource> res1;
|
|
|
|
|
|
|
|
*theNode = nsnull;
|
|
|
|
isCollationKey = PR_FALSE;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMXULElement> dom1 = do_QueryInterface(node1);
|
|
|
|
if (dom1) {
|
|
|
|
if (NS_FAILED(rv = dom1->GetResource(getter_AddRefs(res1))))
|
|
|
|
res1 = nsnull;
|
|
|
|
// Note: don't check for res1 QI failure here. It only succeeds for RDF nodes,
|
|
|
|
// but for XUL nodes it will failure; in the failure case, the code below gets
|
|
|
|
// the cell's text value straight from the DOM
|
|
|
|
} else {
|
|
|
|
nsCOMPtr<nsIDOMElement> htmlDom = do_QueryInterface(node1);
|
|
|
|
if (htmlDom) {
|
|
|
|
nsAutoString htmlID;
|
|
|
|
if (NS_SUCCEEDED(rv = node1->GetAttr(kNameSpaceID_None, nsXULAtoms::id, htmlID))
|
|
|
|
&& (rv == NS_CONTENT_ATTR_HAS_VALUE))
|
|
|
|
{
|
2003-02-25 19:02:00 +00:00
|
|
|
if (NS_FAILED(rv = gRDFService->GetUnicodeResource(htmlID, getter_AddRefs(res1))))
|
2002-03-29 02:46:01 +00:00
|
|
|
res1 = nsnull;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((sortInfo->naturalOrderSort == PR_FALSE) && (sortInfo->sortProperty)) {
|
|
|
|
if (res1) {
|
|
|
|
rv = GetResourceValue(res1, sortInfo, first, PR_TRUE, onlyCollationHint, theNode, isCollationKey);
|
|
|
|
if ((rv == NS_RDF_NO_VALUE) || (!*theNode))
|
|
|
|
rv = GetResourceValue(res1, sortInfo, first, PR_FALSE, onlyCollationHint, theNode, isCollationKey);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
rv = NS_RDF_NO_VALUE;
|
1999-03-19 01:52:18 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
} else if ((sortInfo->naturalOrderSort == PR_TRUE) && (sortInfo->parentContainer)) {
|
|
|
|
nsAutoString cellPosVal1;
|
|
|
|
|
|
|
|
// check to see if this is a RDF_Seq
|
|
|
|
// Note: this code doesn't handle the aggregated Seq case especially well
|
|
|
|
if ((res1) && (sortInfo->db))
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIRDFResource> parentResource;
|
|
|
|
nsCOMPtr<nsIDOMXULElement> parentDOMNode = do_QueryInterface(sortInfo->parentContainer);
|
|
|
|
if (parentDOMNode)
|
|
|
|
{
|
|
|
|
if (NS_FAILED(rv = parentDOMNode->GetResource(getter_AddRefs(parentResource))))
|
|
|
|
{
|
|
|
|
parentResource = nsnull;
|
|
|
|
}
|
|
|
|
}
|
2000-05-07 08:43:42 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
if (parentResource)
|
|
|
|
{
|
|
|
|
PRInt32 index;
|
|
|
|
rv = gRDFC->IndexOf(sortInfo->db, parentResource,
|
|
|
|
res1, &index);
|
|
|
|
if (index != -1)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIRDFInt> intLit;
|
|
|
|
rv = gRDFService->GetIntLiteral(index, getter_AddRefs(intLit));
|
|
|
|
CallQueryInterface(intLit, theNode);
|
|
|
|
isCollationKey = PR_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return(rv);
|
|
|
|
}
|
2000-05-07 08:43:42 +00:00
|
|
|
|
2000-02-15 05:05:29 +00:00
|
|
|
nsresult
|
|
|
|
XULSortServiceImpl::GetNodeValue(contentSortInfo *info1, sortPtr sortInfo, PRBool first,
|
2002-03-29 02:46:01 +00:00
|
|
|
PRBool onlyCollationHint, nsIRDFNode **theNode,
|
|
|
|
PRBool &isCollationKey)
|
2000-02-15 05:05:29 +00:00
|
|
|
{
|
2002-03-29 02:46:01 +00:00
|
|
|
nsresult rv = NS_OK;
|
|
|
|
nsCOMPtr<nsIRDFResource> res1;
|
|
|
|
|
|
|
|
nsIContent *node1 = info1->content;
|
|
|
|
*theNode = nsnull;
|
|
|
|
isCollationKey = PR_FALSE;
|
|
|
|
|
|
|
|
// determine the rdf resource
|
|
|
|
nsCOMPtr<nsIDOMXULElement> dom1 = do_QueryInterface(node1);
|
|
|
|
if(dom1)
|
|
|
|
res1 = info1->resource;
|
|
|
|
else {
|
|
|
|
// If this isn't a XUL element, get its id and fetch the resource directly
|
|
|
|
nsCOMPtr<nsIDOMElement> htmlDom = do_QueryInterface(node1);
|
|
|
|
if (htmlDom) {
|
|
|
|
nsAutoString htmlID;
|
|
|
|
if (NS_SUCCEEDED(rv = node1->GetAttr(kNameSpaceID_None, nsXULAtoms::id, htmlID))
|
|
|
|
&& (rv == NS_CONTENT_ATTR_HAS_VALUE))
|
|
|
|
{
|
2003-02-25 19:02:00 +00:00
|
|
|
if (NS_FAILED(rv = gRDFService->GetUnicodeResource(htmlID, getter_AddRefs(res1))))
|
2002-03-29 02:46:01 +00:00
|
|
|
res1 = nsnull;
|
|
|
|
info1->resource = res1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((!sortInfo->naturalOrderSort) && (sortInfo->sortProperty)) {
|
|
|
|
if (res1) {
|
|
|
|
rv = GetResourceValue(info1, sortInfo, first, PR_TRUE, onlyCollationHint, theNode, isCollationKey);
|
|
|
|
if ((rv == NS_RDF_NO_VALUE) || (!*theNode)) {
|
|
|
|
rv = GetResourceValue(info1, sortInfo, first, PR_FALSE, onlyCollationHint, theNode, isCollationKey);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
rv = NS_RDF_NO_VALUE;
|
|
|
|
|
|
|
|
} else if ((sortInfo->naturalOrderSort == PR_TRUE) && (sortInfo->parentContainer)) {
|
|
|
|
nsAutoString cellPosVal1;
|
1999-03-19 01:52:18 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
// check to see if this is a RDF_Seq
|
|
|
|
// Note: this code doesn't handle the aggregated Seq case especially well
|
|
|
|
if ((res1) && (sortInfo->db))
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIRDFResource> parentResource;
|
|
|
|
nsCOMPtr<nsIDOMXULElement> parentDOMNode = do_QueryInterface(sortInfo->parentContainer);
|
|
|
|
if (parentDOMNode)
|
|
|
|
{
|
|
|
|
if (NS_FAILED(rv = parentDOMNode->GetResource(getter_AddRefs(parentResource))))
|
|
|
|
{
|
|
|
|
parentResource = nsnull;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (parentResource)
|
|
|
|
{
|
|
|
|
PRInt32 index;
|
|
|
|
rv = gRDFC->IndexOf(sortInfo->db, parentResource,
|
|
|
|
res1, &index);
|
|
|
|
if (index != -1)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIRDFInt> intLit;
|
|
|
|
rv = gRDFService->GetIntLiteral(index, getter_AddRefs(intLit));
|
|
|
|
CallQueryInterface(intLit, theNode);
|
|
|
|
isCollationKey = PR_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
// XXX Is this right?
|
|
|
|
rv = NS_ERROR_NULL_POINTER;
|
1999-03-19 01:52:18 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
return rv;
|
|
|
|
}
|
2000-05-07 08:43:42 +00:00
|
|
|
|
1999-05-13 08:25:12 +00:00
|
|
|
nsresult
|
1999-09-07 07:27:49 +00:00
|
|
|
XULSortServiceImpl::InplaceSort(nsIContent *node1, nsIContent *node2, sortPtr sortInfo, PRInt32 & sortOrder)
|
1999-03-05 23:51:41 +00:00
|
|
|
{
|
2002-03-29 02:46:01 +00:00
|
|
|
PRBool isCollationKey1 = PR_FALSE, isCollationKey2 = PR_FALSE;
|
|
|
|
nsresult rv;
|
1999-05-13 08:25:12 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
sortOrder = 0;
|
2000-05-07 08:43:42 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
nsCOMPtr<nsIRDFNode> cellNode1, cellNode2;
|
|
|
|
|
|
|
|
// rjc: in some cases, the first node is static while the second node changes
|
|
|
|
// per comparison; in these circumstances, we can cache the first node
|
|
|
|
if ((sortInfo->cacheFirstHint == PR_TRUE) && (sortInfo->cacheFirstNode))
|
|
|
|
{
|
|
|
|
cellNode1 = sortInfo->cacheFirstNode;
|
|
|
|
isCollationKey1 = sortInfo->cacheIsFirstNodeCollationKey;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GetNodeValue(node1, sortInfo, PR_TRUE, PR_FALSE, getter_AddRefs(cellNode1), isCollationKey1);
|
|
|
|
if (sortInfo->cacheFirstHint == PR_TRUE)
|
|
|
|
{
|
|
|
|
sortInfo->cacheFirstNode = cellNode1;
|
|
|
|
sortInfo->cacheIsFirstNodeCollationKey = isCollationKey1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
GetNodeValue(node2, sortInfo, PR_TRUE, isCollationKey1, getter_AddRefs(cellNode2), isCollationKey2);
|
|
|
|
|
|
|
|
PRBool bothValid = PR_FALSE;
|
|
|
|
rv = CompareNodes(cellNode1, isCollationKey1, cellNode2, isCollationKey2, bothValid, sortOrder);
|
|
|
|
|
|
|
|
if (sortOrder == 0)
|
|
|
|
{
|
|
|
|
// nodes appear to be equivalent, check for secondary sort criteria
|
|
|
|
if (sortInfo->sortProperty2 != nsnull)
|
|
|
|
{
|
|
|
|
cellNode1 = nsnull;
|
|
|
|
cellNode2 = nsnull;
|
|
|
|
isCollationKey1 = PR_FALSE;
|
|
|
|
isCollationKey2 = PR_FALSE;
|
|
|
|
|
|
|
|
GetNodeValue(node1, sortInfo, PR_FALSE, PR_FALSE, getter_AddRefs(cellNode1), isCollationKey1);
|
|
|
|
GetNodeValue(node2, sortInfo, PR_FALSE, isCollationKey1, getter_AddRefs(cellNode2), isCollationKey2);
|
|
|
|
|
|
|
|
bothValid = PR_FALSE;
|
|
|
|
rv = CompareNodes(cellNode1, isCollationKey1, cellNode2, isCollationKey2, bothValid, sortOrder);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((bothValid == PR_TRUE) && (sortInfo->descendingSort == PR_TRUE))
|
|
|
|
{
|
|
|
|
// descending sort is being imposed, so reverse the sort order
|
|
|
|
sortOrder = -sortOrder;
|
|
|
|
}
|
|
|
|
|
|
|
|
return(NS_OK);
|
|
|
|
}
|
2000-05-07 08:43:42 +00:00
|
|
|
|
2000-02-15 05:05:29 +00:00
|
|
|
nsresult
|
|
|
|
XULSortServiceImpl::InplaceSort(contentSortInfo *info1, contentSortInfo *info2, sortPtr sortInfo, PRInt32 & sortOrder)
|
|
|
|
{
|
2002-03-29 02:46:01 +00:00
|
|
|
PRBool isCollationKey1 = PR_FALSE, isCollationKey2 = PR_FALSE;
|
|
|
|
nsresult rv;
|
1999-05-13 08:25:12 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
sortOrder = 0;
|
1999-05-13 08:25:12 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
nsCOMPtr<nsIRDFNode> cellNode1, cellNode2;
|
|
|
|
|
|
|
|
// rjc: in some cases, the first node is static while the second node changes
|
|
|
|
// per comparison; in these circumstances, we can cache the first node
|
|
|
|
if ((sortInfo->cacheFirstHint == PR_TRUE) && (sortInfo->cacheFirstNode))
|
|
|
|
{
|
|
|
|
cellNode1 = sortInfo->cacheFirstNode;
|
|
|
|
isCollationKey1 = sortInfo->cacheIsFirstNodeCollationKey;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GetNodeValue(info1, sortInfo, PR_TRUE, PR_FALSE, getter_AddRefs(cellNode1), isCollationKey1);
|
|
|
|
if (sortInfo->cacheFirstHint == PR_TRUE)
|
|
|
|
{
|
|
|
|
sortInfo->cacheFirstNode = cellNode1;
|
|
|
|
sortInfo->cacheIsFirstNodeCollationKey = isCollationKey1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
GetNodeValue(info2, sortInfo, PR_TRUE, isCollationKey1, getter_AddRefs(cellNode2), isCollationKey2);
|
|
|
|
|
|
|
|
PRBool bothValid = PR_FALSE;
|
|
|
|
rv = CompareNodes(cellNode1, isCollationKey1, cellNode2, isCollationKey2, bothValid, sortOrder);
|
|
|
|
|
|
|
|
if (sortOrder == 0) {
|
|
|
|
// nodes appear to be equivalent, check for secondary sort criteria
|
|
|
|
if (sortInfo->sortProperty2 != nsnull) {
|
|
|
|
cellNode1 = nsnull;
|
|
|
|
cellNode2 = nsnull;
|
|
|
|
isCollationKey1 = PR_FALSE;
|
|
|
|
isCollationKey2 = PR_FALSE;
|
|
|
|
|
|
|
|
GetNodeValue(info1, sortInfo, PR_FALSE, PR_FALSE, getter_AddRefs(cellNode1), isCollationKey1);
|
|
|
|
GetNodeValue(info2, sortInfo, PR_FALSE, isCollationKey1, getter_AddRefs(cellNode2), isCollationKey2);
|
|
|
|
|
|
|
|
bothValid = PR_FALSE;
|
|
|
|
rv = CompareNodes(cellNode1, isCollationKey1, cellNode2, isCollationKey2, bothValid, sortOrder);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((bothValid == PR_TRUE) && (sortInfo->descendingSort == PR_TRUE))
|
|
|
|
{
|
|
|
|
// descending sort is being imposed, so reverse the sort order
|
|
|
|
sortOrder = -sortOrder;
|
|
|
|
}
|
|
|
|
|
|
|
|
return(NS_OK);
|
|
|
|
}
|
2000-05-07 08:43:42 +00:00
|
|
|
|
2000-05-12 22:23:36 +00:00
|
|
|
int PR_CALLBACK
|
1999-05-13 08:25:12 +00:00
|
|
|
inplaceSortCallback(const void *data1, const void *data2, void *privateData)
|
|
|
|
{
|
2002-03-29 02:46:01 +00:00
|
|
|
/// Note: inplaceSortCallback is a small C callback stub for NS_QuickSort
|
|
|
|
_sortStruct *sortInfo = (_sortStruct *)privateData;
|
|
|
|
nsIContent *node1 = *(nsIContent **)data1;
|
|
|
|
nsIContent *node2 = *(nsIContent **)data2;
|
|
|
|
PRInt32 sortOrder = 0;
|
1999-03-05 23:51:41 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
if (nsnull != sortInfo)
|
|
|
|
XULSortServiceImpl::InplaceSort(node1, node2, sortInfo, sortOrder);
|
2000-05-07 08:43:42 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
return sortOrder;
|
|
|
|
}
|
2000-05-07 08:43:42 +00:00
|
|
|
|
2000-05-12 22:23:36 +00:00
|
|
|
int PR_CALLBACK
|
2000-02-15 05:05:29 +00:00
|
|
|
testSortCallback(const void *data1, const void *data2, void *privateData)
|
|
|
|
{
|
2002-03-29 02:46:01 +00:00
|
|
|
/// Note: testSortCallback is a small C callback stub for NS_QuickSort
|
|
|
|
_sortStruct *sortInfo = (_sortStruct *)privateData;
|
|
|
|
contentSortInfo *info1 = *(contentSortInfo **)data1;
|
|
|
|
contentSortInfo *info2 = *(contentSortInfo **)data2;
|
|
|
|
PRInt32 sortOrder = 0;
|
2000-02-15 05:05:29 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
if (nsnull != sortInfo)
|
|
|
|
XULSortServiceImpl::InplaceSort(info1, info2, sortInfo, sortOrder);
|
2000-05-07 08:43:42 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
return sortOrder;
|
|
|
|
}
|
2000-05-07 08:43:42 +00:00
|
|
|
|
|
|
|
static contentSortInfo *
|
|
|
|
CreateContentSortInfo(nsIContent *content, nsIRDFResource * resource)
|
2000-02-15 05:05:29 +00:00
|
|
|
{
|
2002-03-29 02:46:01 +00:00
|
|
|
contentSortInfo * info = new contentSortInfo;
|
|
|
|
if (!info)
|
|
|
|
return nsnull;
|
2000-02-15 05:05:29 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
info->content = content;
|
|
|
|
NS_IF_ADDREF(info->content);
|
2000-02-15 05:05:29 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
info->resource = resource;
|
2000-02-15 05:05:29 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
info->checkedCollation1 = PR_FALSE;
|
|
|
|
info->checkedCollation2 = PR_FALSE;
|
|
|
|
info->checkedSort1 = PR_FALSE;
|
|
|
|
info->checkedSort2 = PR_FALSE;
|
|
|
|
info->checkedNode1 = PR_FALSE;
|
|
|
|
info->checkedNode2 = PR_FALSE;
|
1999-03-07 09:44:38 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
return info;
|
2000-02-15 05:05:29 +00:00
|
|
|
}
|
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
nsresult
|
|
|
|
XULSortServiceImpl::SortContainer(nsIContent *container, sortPtr sortInfo, PRBool merelyInvertFlag)
|
|
|
|
{
|
|
|
|
PRInt32 childIndex = 0, loop, numChildren = 0, numElements = 0, currentElement, nameSpaceID;
|
|
|
|
nsCOMPtr<nsIContent> child;
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
if (NS_FAILED(rv = container->ChildCount(numChildren))) return rv;
|
|
|
|
if (numChildren < 1) return NS_OK;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDocument> doc;
|
|
|
|
container->GetDocument(*getter_AddRefs(doc));
|
|
|
|
if (!doc) return NS_ERROR_UNEXPECTED;
|
|
|
|
|
|
|
|
// Note: This is a straight allocation (not a COMPtr) so we
|
|
|
|
// can't return out of this routine until/unless we free it!
|
|
|
|
contentSortInfo ** contentSortInfoArray = new contentSortInfo*[numChildren + 1];
|
|
|
|
if(!contentSortInfoArray) return(NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
|
|
|
// Note: walk backwards (and add nodes into the array backwards) because
|
|
|
|
// we also remove the nodes in this loop [via RemoveChildAt()] and if we
|
|
|
|
// were to do this in a forward-looking manner it would be harder
|
|
|
|
// (since we also skip over non XUL:treeitem nodes)
|
|
|
|
|
|
|
|
nsCOMPtr<nsIAtom> tag;
|
|
|
|
currentElement = numChildren;
|
|
|
|
for (childIndex = numChildren-1; childIndex >= 0; --childIndex) {
|
|
|
|
if (NS_FAILED(rv = container->ChildAt(childIndex, *getter_AddRefs(child)))) continue;
|
|
|
|
if (NS_FAILED(rv = child->GetNameSpaceID(nameSpaceID))) continue;
|
|
|
|
if (nameSpaceID == kNameSpaceID_XUL) {
|
|
|
|
if (NS_FAILED(rv = child->GetTag(*getter_AddRefs(tag)))) continue;
|
|
|
|
if (tag == nsXULAtoms::listitem || tag == nsXULAtoms::treeitem
|
|
|
|
|| tag == nsXULAtoms::menu || tag == nsXULAtoms::menuitem) {
|
|
|
|
--currentElement;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIRDFResource> resource;
|
|
|
|
nsXULContentUtils::GetElementResource(child, getter_AddRefs(resource));
|
|
|
|
contentSortInfo *contentInfo = CreateContentSortInfo(child, resource);
|
|
|
|
if(contentInfo)
|
|
|
|
contentSortInfoArray[currentElement] = contentInfo;
|
|
|
|
|
|
|
|
++numElements;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (numElements > 0) {
|
|
|
|
/* smart sorting (sort within separators) on name column */
|
|
|
|
if (sortInfo->inbetweenSeparatorSort) {
|
|
|
|
PRInt32 startIndex=currentElement;
|
|
|
|
nsAutoString type;
|
|
|
|
for (loop=currentElement; loop< currentElement + numElements; ++loop) {
|
|
|
|
if (NS_SUCCEEDED(rv = contentSortInfoArray[loop]->content->GetAttr(kNameSpaceID_RDF,
|
|
|
|
kRDF_type, type)) && (rv == NS_CONTENT_ATTR_HAS_VALUE))
|
|
|
|
{
|
|
|
|
if (type.EqualsWithConversion(kURINC_BookmarkSeparator)) {
|
|
|
|
if (loop > startIndex+1) {
|
|
|
|
if (merelyInvertFlag)
|
|
|
|
InvertSortInfo(&contentSortInfoArray[startIndex], loop-startIndex);
|
|
|
|
else
|
|
|
|
NS_QuickSort((void*)&contentSortInfoArray[startIndex], loop-startIndex,
|
|
|
|
sizeof(contentSortInfo*), testSortCallback, (void*)sortInfo);
|
|
|
|
startIndex = loop+1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (loop > startIndex+1) {
|
|
|
|
if (merelyInvertFlag)
|
|
|
|
InvertSortInfo(&contentSortInfoArray[startIndex], loop-startIndex);
|
|
|
|
else
|
|
|
|
NS_QuickSort((void*)&contentSortInfoArray[startIndex], loop-startIndex,
|
|
|
|
sizeof(contentSortInfo*), testSortCallback, (void*)sortInfo);
|
|
|
|
startIndex = loop+1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (merelyInvertFlag)
|
|
|
|
InvertSortInfo(&contentSortInfoArray[currentElement], numElements);
|
|
|
|
else
|
|
|
|
NS_QuickSort((void*)(&contentSortInfoArray[currentElement]), numElements,
|
|
|
|
sizeof(contentSortInfo*), testSortCallback, (void*)sortInfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (childIndex=numChildren-1; childIndex >= 0; childIndex--)
|
|
|
|
{
|
|
|
|
if (NS_FAILED(rv = container->ChildAt(childIndex, *getter_AddRefs(child)))) continue;
|
|
|
|
if (NS_FAILED(rv = child->GetNameSpaceID(nameSpaceID))) continue;
|
|
|
|
if (nameSpaceID == kNameSpaceID_XUL) {
|
|
|
|
if (NS_FAILED(rv = child->GetTag(*getter_AddRefs(tag)))) continue;
|
|
|
|
if (tag == nsXULAtoms::listitem || tag == nsXULAtoms::treeitem
|
|
|
|
|| tag == nsXULAtoms::menu || tag == nsXULAtoms::menuitem) {
|
|
|
|
// immediately remove the child node, and ignore any errors
|
|
|
|
container->RemoveChildAt(childIndex, PR_FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2000-05-06 00:01:01 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
// put the items back in sorted order
|
|
|
|
nsCOMPtr<nsIContent> parentNode;
|
|
|
|
nsAutoString value;
|
|
|
|
PRInt32 childPos = 0;
|
|
|
|
container->ChildCount(childPos);
|
|
|
|
for (loop=currentElement; loop < currentElement + numElements; loop++) {
|
|
|
|
contentSortInfo * contentSortInfo = contentSortInfoArray[loop];
|
|
|
|
parentNode = (nsIContent *)contentSortInfo->content;
|
|
|
|
nsIContent* kid = NS_STATIC_CAST(nsIContent*, parentNode);
|
|
|
|
container->InsertChildAt(kid, childPos++, PR_FALSE, PR_TRUE);
|
|
|
|
|
|
|
|
NS_RELEASE(contentSortInfo->content);
|
|
|
|
delete contentSortInfo;
|
|
|
|
|
|
|
|
// if it's a container, find its treechildren nodes, and sort those
|
|
|
|
if (NS_FAILED(rv = parentNode->GetAttr(kNameSpaceID_None, nsXULAtoms::container, value)) ||
|
|
|
|
(rv != NS_CONTENT_ATTR_HAS_VALUE) || (!value.EqualsIgnoreCase("true")))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (NS_FAILED(rv = parentNode->ChildCount(numChildren))) continue;
|
|
|
|
|
|
|
|
for (childIndex=0; childIndex<numChildren; childIndex++) {
|
|
|
|
if (NS_FAILED(rv = parentNode->ChildAt(childIndex, *getter_AddRefs(child))))
|
|
|
|
continue;
|
|
|
|
if (NS_FAILED(rv = child->GetNameSpaceID(nameSpaceID))) continue;
|
|
|
|
if (nameSpaceID != kNameSpaceID_XUL) continue;
|
|
|
|
|
|
|
|
if (NS_FAILED(rv = child->GetTag(*getter_AddRefs(tag)))) continue;
|
|
|
|
if (tag != nsXULAtoms::treechildren && tag != nsXULAtoms::menupopup) continue;
|
|
|
|
|
|
|
|
sortInfo->parentContainer = parentNode;
|
|
|
|
SortContainer(child, sortInfo, merelyInvertFlag);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
delete [] contentSortInfoArray;
|
|
|
|
contentSortInfoArray = nsnull;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2000-05-06 00:01:01 +00:00
|
|
|
|
2000-02-15 05:05:29 +00:00
|
|
|
nsresult
|
2002-03-29 02:46:01 +00:00
|
|
|
XULSortServiceImpl::InvertSortInfo(contentSortInfo **data, PRInt32 numItems)
|
2000-02-15 05:05:29 +00:00
|
|
|
{
|
2002-03-29 02:46:01 +00:00
|
|
|
if (numItems > 1) {
|
|
|
|
PRInt32 upPoint = (numItems + 1)/2, downPoint = (numItems - 2)/2;
|
|
|
|
PRInt32 half = numItems/2;
|
|
|
|
while (half-- > 0) {
|
|
|
|
contentSortInfo *temp = data[downPoint];
|
|
|
|
data[downPoint--] = data[upPoint];
|
|
|
|
data[upPoint++] = temp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NS_OK;
|
2000-02-15 05:05:29 +00:00
|
|
|
}
|
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
XULSortServiceImpl::InsertContainerNode(nsIRDFCompositeDataSource *db, nsRDFSortState *sortState,
|
|
|
|
nsIContent *root, nsIContent *trueParent, nsIContent *container,
|
|
|
|
nsIContent *node, PRBool aNotify)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
nsAutoString sortResource, sortDirection, sortResource2;
|
|
|
|
_sortStruct sortInfo;
|
|
|
|
|
|
|
|
// get composite db for tree
|
|
|
|
sortInfo.db = db;
|
|
|
|
sortInfo.parentContainer = trueParent;
|
|
|
|
sortInfo.sortProperty = nsnull;
|
|
|
|
sortInfo.sortProperty2 = nsnull;
|
|
|
|
sortInfo.inbetweenSeparatorSort = PR_FALSE;
|
|
|
|
sortInfo.cacheFirstHint = PR_TRUE;
|
|
|
|
|
2002-03-29 03:49:56 +00:00
|
|
|
if (sortState->mCache)
|
|
|
|
sortInfo.mInner = sortState->mCache;
|
|
|
|
else
|
|
|
|
sortInfo.mInner = nsnull;
|
2002-03-29 02:46:01 +00:00
|
|
|
|
|
|
|
if (container != sortState->lastContainer.get()) {
|
|
|
|
sortState->lastContainer = container;
|
|
|
|
sortState->lastWasFirst = PR_FALSE;
|
|
|
|
sortState->lastWasLast = PR_FALSE;
|
|
|
|
}
|
2000-05-07 08:43:42 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
PRBool sortInfoAvailable = PR_FALSE;
|
2000-05-07 08:43:42 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
// look for sorting info on root node
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv = root->GetAttr(kNameSpaceID_None, kSortResourceAtom, sortResource))
|
|
|
|
&& (rv == NS_CONTENT_ATTR_HAS_VALUE))
|
|
|
|
{
|
|
|
|
if (NS_SUCCEEDED(rv = root->GetAttr(kNameSpaceID_None, nsXULAtoms::sortDirection, sortDirection))
|
|
|
|
&& (rv == NS_CONTENT_ATTR_HAS_VALUE))
|
2000-08-08 05:50:10 +00:00
|
|
|
{
|
2002-03-29 02:46:01 +00:00
|
|
|
sortInfoAvailable = PR_TRUE;
|
|
|
|
|
|
|
|
if (NS_FAILED(rv = root->GetAttr(kNameSpaceID_None, kSortResource2Atom, sortResource2))
|
|
|
|
|| (rv != NS_CONTENT_ATTR_HAS_VALUE))
|
|
|
|
{
|
|
|
|
sortResource2.Truncate();
|
|
|
|
}
|
2000-08-08 05:50:10 +00:00
|
|
|
}
|
2002-03-29 02:46:01 +00:00
|
|
|
}
|
2000-08-08 05:50:10 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
if (sortInfoAvailable) {
|
|
|
|
if (sortState->sortResource.Equals(sortResource)
|
|
|
|
&& sortState->sortResource2.Equals(sortResource2))
|
|
|
|
{
|
|
|
|
sortInfo.sortProperty = sortState->sortProperty;
|
|
|
|
sortInfo.sortProperty2 = sortState->sortProperty2;
|
|
|
|
sortInfo.sortPropertyColl = sortState->sortPropertyColl;
|
|
|
|
sortInfo.sortPropertyColl2 = sortState->sortPropertyColl2;
|
|
|
|
sortInfo.sortPropertySort = sortState->sortPropertySort;
|
|
|
|
sortInfo.sortPropertySort2 = sortState->sortPropertySort2;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// either first time, or must have changing sorting info, so flush state cache
|
|
|
|
sortState->sortProperty = nsnull;
|
|
|
|
sortState->sortProperty2 = nsnull;
|
|
|
|
sortState->sortPropertyColl = nsnull;
|
|
|
|
sortState->sortPropertyColl2 = nsnull;
|
|
|
|
sortState->sortPropertySort = nsnull;
|
|
|
|
sortState->sortPropertySort2 = nsnull;
|
|
|
|
|
2003-02-25 19:02:00 +00:00
|
|
|
rv = gRDFService->GetUnicodeResource(sortResource, getter_AddRefs(sortInfo.sortProperty));
|
2002-03-29 02:46:01 +00:00
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
sortState->sortResource = sortResource;
|
|
|
|
sortState->sortProperty = sortInfo.sortProperty;
|
|
|
|
|
|
|
|
nsAutoString resourceUrl = sortResource;
|
|
|
|
resourceUrl.Append(NS_LITERAL_STRING("?collation=true"));
|
2003-02-25 19:02:00 +00:00
|
|
|
rv = gRDFService->GetUnicodeResource(resourceUrl, getter_AddRefs(sortInfo.sortPropertyColl));
|
2002-03-29 02:46:01 +00:00
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
sortState->sortPropertyColl = sortInfo.sortPropertyColl;
|
|
|
|
|
|
|
|
resourceUrl = sortResource;
|
|
|
|
resourceUrl.Append(NS_LITERAL_STRING("?sort=true"));
|
2003-02-25 19:02:00 +00:00
|
|
|
rv = gRDFService->GetUnicodeResource(resourceUrl, getter_AddRefs(sortInfo.sortPropertySort));
|
2002-03-29 02:46:01 +00:00
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
sortState->sortPropertySort = sortInfo.sortPropertySort;
|
|
|
|
|
|
|
|
if (!sortResource2.IsEmpty()) {
|
2003-02-25 19:02:00 +00:00
|
|
|
rv = gRDFService->GetUnicodeResource(sortResource2, getter_AddRefs(sortInfo.sortProperty2));
|
2002-03-29 02:46:01 +00:00
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
sortState->sortResource2 = sortResource2;
|
|
|
|
sortState->sortProperty2 = sortInfo.sortProperty2;
|
|
|
|
|
|
|
|
resourceUrl = sortResource2;
|
|
|
|
resourceUrl.Append(NS_LITERAL_STRING("?collation=true"));
|
2003-02-25 19:02:00 +00:00
|
|
|
rv = gRDFService->GetUnicodeResource(resourceUrl, getter_AddRefs(sortInfo.sortPropertyColl2));
|
2002-03-29 02:46:01 +00:00
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
sortState->sortPropertyColl2 = sortInfo.sortPropertyColl2;
|
|
|
|
|
|
|
|
resourceUrl = sortResource2;
|
|
|
|
resourceUrl.Append(NS_LITERAL_STRING("?sort=true"));
|
2003-02-25 19:02:00 +00:00
|
|
|
rv = gRDFService->GetUnicodeResource(resourceUrl, getter_AddRefs(sortInfo.sortPropertySort2));
|
2002-03-29 02:46:01 +00:00
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
sortState->sortPropertySort2 = sortInfo.sortPropertySort2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// either first time, or must have changing sorting info, so flush state cache
|
|
|
|
sortState->sortResource.Truncate();
|
|
|
|
sortState->sortResource2.Truncate();
|
|
|
|
|
|
|
|
sortState->sortProperty = nsnull;
|
|
|
|
sortState->sortProperty2 = nsnull;
|
|
|
|
sortState->sortPropertyColl = nsnull;
|
|
|
|
sortState->sortPropertyColl2 = nsnull;
|
|
|
|
sortState->sortPropertySort = nsnull;
|
|
|
|
sortState->sortPropertySort2 = nsnull;
|
|
|
|
}
|
2000-08-08 05:50:10 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
// set up sort order info
|
|
|
|
sortInfo.naturalOrderSort = PR_FALSE;
|
|
|
|
sortInfo.descendingSort = PR_FALSE;
|
|
|
|
if (sortDirection.Equals(*kDescendingStr))
|
|
|
|
sortInfo.descendingSort = PR_TRUE;
|
|
|
|
else if (!sortDirection.Equals(*kAscendingStr))
|
|
|
|
sortInfo.naturalOrderSort = PR_TRUE;
|
|
|
|
|
|
|
|
PRBool isContainerRDFSeq = PR_FALSE;
|
|
|
|
|
|
|
|
if (sortInfo.db && sortInfo.naturalOrderSort) {
|
|
|
|
// walk up the content model to find the REAL
|
|
|
|
// parent container to determine if its a RDF_Seq
|
|
|
|
nsCOMPtr<nsIContent> parent = do_QueryInterface(container, &rv);
|
|
|
|
nsCOMPtr<nsIContent> aContent;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDocument> doc;
|
|
|
|
if (NS_SUCCEEDED(rv) && parent) {
|
|
|
|
rv = parent->GetDocument(*getter_AddRefs(doc));
|
|
|
|
if (!doc)
|
|
|
|
parent = nsnull;
|
|
|
|
}
|
2000-08-08 05:50:10 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
if (parent) {
|
|
|
|
nsAutoString id;
|
|
|
|
nsCOMPtr<nsIAtom> tag;
|
1999-03-07 09:44:38 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
if (NS_FAILED(rv = trueParent->GetTag(*getter_AddRefs(tag))))
|
|
|
|
return rv;
|
1999-03-07 09:44:38 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
rv = trueParent->GetAttr(kNameSpaceID_None, nsXULAtoms::ref, id);
|
|
|
|
if (id.IsEmpty())
|
|
|
|
rv = trueParent->GetAttr(kNameSpaceID_None, nsXULAtoms::id, id);
|
1999-03-07 09:44:38 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
if (!id.IsEmpty()) {
|
|
|
|
nsCOMPtr<nsIRDFResource> containerRes;
|
|
|
|
rv = nsXULContentUtils::MakeElementResource(doc, id, getter_AddRefs(containerRes));
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
|
|
rv = gRDFC->IsSeq(sortInfo.db, containerRes, &isContainerRDFSeq);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1999-08-27 06:54:08 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
PRBool childAdded = PR_FALSE;
|
|
|
|
PRInt32 numChildren = 0;
|
|
|
|
if (NS_FAILED(rv = container->ChildCount(numChildren))) return rv;
|
1999-08-27 06:54:08 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
if ((sortInfo.naturalOrderSort == PR_FALSE) ||
|
|
|
|
((sortInfo.naturalOrderSort == PR_TRUE) &&
|
|
|
|
(isContainerRDFSeq == PR_TRUE)))
|
|
|
|
{
|
|
|
|
// because numChildren gets modified
|
|
|
|
PRInt32 realNumChildren = numChildren;
|
|
|
|
nsCOMPtr<nsIContent> child;
|
1999-08-27 06:54:08 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
// rjc says: determine where static XUL ends and generated XUL/RDF begins
|
|
|
|
PRInt32 staticCount = 0;
|
2000-08-08 05:50:10 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
nsAutoString staticValue;
|
|
|
|
if (NS_SUCCEEDED(rv = container->GetAttr(kNameSpaceID_None, kStaticHintAtom, staticValue))
|
|
|
|
&& (rv == NS_CONTENT_ATTR_HAS_VALUE))
|
|
|
|
{
|
|
|
|
// found "static" XUL element count hint
|
|
|
|
PRInt32 strErr=0;
|
|
|
|
staticCount = staticValue.ToInteger(&strErr);
|
|
|
|
if (strErr)
|
|
|
|
staticCount = 0;
|
|
|
|
} else {
|
|
|
|
// compute the "static" XUL element count
|
|
|
|
nsAutoString valueStr;
|
|
|
|
for (PRInt32 childLoop = 0; childLoop < numChildren; ++childLoop) {
|
|
|
|
container->ChildAt(childLoop, *getter_AddRefs(child));
|
|
|
|
if (!child) break;
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv = child->GetAttr(kNameSpaceID_None, nsXULAtoms::templateAtom, valueStr))
|
|
|
|
&& (rv == NS_CONTENT_ATTR_HAS_VALUE))
|
|
|
|
break;
|
|
|
|
else
|
|
|
|
++staticCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv = root->GetAttr(kNameSpaceID_None, kStaticsSortLastHintAtom, valueStr))
|
|
|
|
&& (rv == NS_CONTENT_ATTR_HAS_VALUE) && (valueStr.EqualsIgnoreCase("true")))
|
|
|
|
{
|
|
|
|
// indicate that static XUL comes after RDF-generated content by making negative
|
|
|
|
staticCount = -staticCount;
|
|
|
|
}
|
2000-08-08 05:50:10 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
// save the "static" XUL element count hint
|
|
|
|
valueStr.Truncate();
|
|
|
|
valueStr.AppendInt(staticCount);
|
|
|
|
container->SetAttr(kNameSpaceID_None, kStaticHintAtom, valueStr, PR_FALSE);
|
|
|
|
}
|
2000-08-08 05:50:10 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
if (staticCount <= 0) {
|
|
|
|
numChildren += staticCount;
|
|
|
|
staticCount = 0;
|
|
|
|
} else if (staticCount > 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 (sortState->lastWasFirst) {
|
|
|
|
container->ChildAt(staticCount, *getter_AddRefs(child));
|
|
|
|
temp = child.get();
|
|
|
|
direction = inplaceSortCallback(&node, &temp, &sortInfo);
|
|
|
|
if (direction < 0) {
|
|
|
|
container->InsertChildAt(node, staticCount, aNotify, PR_FALSE);
|
|
|
|
childAdded = PR_TRUE;
|
|
|
|
} else
|
|
|
|
sortState->lastWasFirst = PR_FALSE;
|
|
|
|
} else if (sortState->lastWasLast) {
|
|
|
|
container->ChildAt(realNumChildren-1, *getter_AddRefs(child));
|
|
|
|
temp = child.get();
|
|
|
|
direction = inplaceSortCallback(&node, &temp, &sortInfo);
|
|
|
|
if (direction > 0) {
|
|
|
|
container->InsertChildAt(node, realNumChildren, aNotify, PR_FALSE);
|
|
|
|
childAdded = PR_TRUE;
|
|
|
|
} else
|
|
|
|
sortState->lastWasLast = PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32 left = staticCount+1, right = realNumChildren, x;
|
|
|
|
while (!childAdded && right >= left) {
|
|
|
|
x = (left + right) / 2;
|
|
|
|
container->ChildAt(x-1, *getter_AddRefs(child));
|
|
|
|
temp = child.get();
|
|
|
|
|
|
|
|
// rjc says: since cacheFirstHint is PR_TRUE, the first node passed
|
|
|
|
// into inplaceSortCallback() must be the node that doesn't change
|
|
|
|
|
|
|
|
direction = inplaceSortCallback(&node, &temp, &sortInfo);
|
|
|
|
if (((x == left) && (direction < 0)) || (((x == right))
|
|
|
|
&& (direction >= 0)) || (left == right))
|
|
|
|
{
|
|
|
|
PRInt32 thePos = ((direction > 0) ? x : x-1);
|
|
|
|
container->InsertChildAt(node, thePos, aNotify, PR_FALSE);
|
|
|
|
childAdded = PR_TRUE;
|
|
|
|
|
|
|
|
sortState->lastWasFirst = (thePos == staticCount) ? PR_TRUE: PR_FALSE;
|
|
|
|
sortState->lastWasLast = (thePos >= realNumChildren) ? PR_TRUE: PR_FALSE;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (direction < 0)
|
|
|
|
right = x-1;
|
|
|
|
else
|
|
|
|
left = x+1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!childAdded)
|
|
|
|
container->InsertChildAt(node, numChildren, aNotify, PR_FALSE);
|
|
|
|
|
|
|
|
if (!sortState->mCache && sortInfo.mInner)
|
|
|
|
sortState->mCache = sortInfo.mInner;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2002-10-22 19:49:29 +00:00
|
|
|
XULSortServiceImpl::Sort(nsIDOMNode* node, const nsAString& sortResource, const nsAString& sortDirection)
|
2002-03-29 02:46:01 +00:00
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
_sortStruct sortInfo;
|
|
|
|
|
|
|
|
// get root content node
|
|
|
|
nsCOMPtr<nsIContent> contentNode = do_QueryInterface(node);
|
|
|
|
if (!contentNode) return NS_ERROR_FAILURE;
|
|
|
|
nsCOMPtr<nsIContent> dbNode;
|
|
|
|
if (NS_FAILED(rv = FindDatabaseElement(contentNode, getter_AddRefs(dbNode))))
|
|
|
|
return rv;
|
|
|
|
nsCOMPtr<nsIDOMXULElement> dbXULNode = do_QueryInterface(dbNode);
|
|
|
|
if (!dbXULNode) return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
// get composite db
|
|
|
|
sortInfo.db = nsnull;
|
|
|
|
sortInfo.mInner = nsnull;
|
|
|
|
sortInfo.parentContainer = dbNode;
|
|
|
|
sortInfo.inbetweenSeparatorSort = PR_FALSE;
|
|
|
|
sortInfo.cacheFirstHint = PR_FALSE;
|
|
|
|
|
|
|
|
// optimization - if we're about to merely invert the current sort
|
|
|
|
// then just reverse-index the current tree
|
|
|
|
PRBool invertTreeFlag = PR_FALSE;
|
|
|
|
nsAutoString value;
|
|
|
|
if (NS_SUCCEEDED(rv = dbNode->GetAttr(kNameSpaceID_None, nsXULAtoms::sortActive, value))
|
|
|
|
&& (rv == NS_CONTENT_ATTR_HAS_VALUE)
|
|
|
|
&& (value.EqualsIgnoreCase("true")))
|
|
|
|
{
|
|
|
|
if (NS_SUCCEEDED(rv = dbNode->GetAttr(kNameSpaceID_None, kSortResourceAtom, value))
|
|
|
|
&& (rv == NS_CONTENT_ATTR_HAS_VALUE)
|
|
|
|
&& (value.Equals(sortResource, nsCaseInsensitiveStringComparator())))
|
|
|
|
{
|
|
|
|
if (NS_SUCCEEDED(rv = dbNode->GetAttr(kNameSpaceID_None, nsXULAtoms::sortDirection, value))
|
|
|
|
&& (rv == NS_CONTENT_ATTR_HAS_VALUE))
|
|
|
|
{
|
|
|
|
if ((value.Equals(*kDescendingStr) && sortDirection.Equals(*kAscendingStr))
|
|
|
|
|| (value.Equals(*kAscendingStr) && sortDirection.Equals(*kDescendingStr)))
|
|
|
|
{
|
|
|
|
invertTreeFlag = PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1999-03-07 09:44:38 +00:00
|
|
|
|
2002-03-29 02:46:01 +00:00
|
|
|
// remove any sort hints on tree root node
|
|
|
|
dbNode->UnsetAttr(kNameSpaceID_None, nsXULAtoms::sortActive, PR_FALSE);
|
|
|
|
dbNode->UnsetAttr(kNameSpaceID_None, nsXULAtoms::sortDirection, PR_FALSE);
|
|
|
|
dbNode->UnsetAttr(kNameSpaceID_None, kSortSeparatorsAtom, PR_FALSE);
|
|
|
|
dbNode->UnsetAttr(kNameSpaceID_None, kSortResourceAtom, PR_FALSE);
|
|
|
|
dbNode->UnsetAttr(kNameSpaceID_None, kSortResource2Atom, PR_FALSE);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIRDFCompositeDataSource> cds;
|
|
|
|
if (NS_SUCCEEDED(rv = dbXULNode->GetDatabase(getter_AddRefs(cds))))
|
|
|
|
sortInfo.db = cds;
|
|
|
|
|
|
|
|
// determine new sort resource and direction to use
|
|
|
|
if (sortDirection.Equals(*kNaturalStr)) {
|
|
|
|
sortInfo.naturalOrderSort = PR_TRUE;
|
|
|
|
sortInfo.descendingSort = PR_FALSE;
|
|
|
|
} else {
|
|
|
|
sortInfo.naturalOrderSort = PR_FALSE;
|
|
|
|
if (sortDirection.Equals(*kAscendingStr))
|
|
|
|
sortInfo.descendingSort = PR_FALSE;
|
|
|
|
else if (sortDirection.Equals(*kDescendingStr))
|
|
|
|
sortInfo.descendingSort = PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// look for additional sort info from content
|
|
|
|
nsAutoString sortResource2, unused;
|
|
|
|
GetSortColumnInfo(contentNode, unused, unused, sortResource2, sortInfo.inbetweenSeparatorSort);
|
|
|
|
|
|
|
|
// build resource url for first sort resource
|
2003-02-25 19:02:00 +00:00
|
|
|
rv = gRDFService->GetUnicodeResource(sortResource, getter_AddRefs(sortInfo.sortProperty));
|
2002-03-29 02:46:01 +00:00
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
|
|
|
nsAutoString resourceUrl;
|
|
|
|
resourceUrl.Assign(sortResource);
|
|
|
|
resourceUrl.Append(NS_LITERAL_STRING("?collation=true"));
|
2003-02-25 19:02:00 +00:00
|
|
|
rv = gRDFService->GetUnicodeResource(resourceUrl, getter_AddRefs(sortInfo.sortPropertyColl));
|
2002-03-29 02:46:01 +00:00
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
|
|
|
resourceUrl.Assign(sortResource);
|
|
|
|
resourceUrl.Append(NS_LITERAL_STRING("?sort=true"));
|
2003-02-25 19:02:00 +00:00
|
|
|
rv = gRDFService->GetUnicodeResource(resourceUrl, getter_AddRefs(sortInfo.sortPropertySort));
|
2002-03-29 02:46:01 +00:00
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
|
|
|
// build resource url for second sort resource
|
|
|
|
if (!sortResource2.IsEmpty()) {
|
2003-02-25 19:02:00 +00:00
|
|
|
rv = gRDFService->GetUnicodeResource(sortResource2, getter_AddRefs(sortInfo.sortProperty2));
|
2002-03-29 02:46:01 +00:00
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
|
|
|
resourceUrl = sortResource2;
|
|
|
|
resourceUrl.Append(NS_LITERAL_STRING("?collation=true"));
|
2003-02-25 19:02:00 +00:00
|
|
|
rv = gRDFService->GetUnicodeResource(resourceUrl, getter_AddRefs(sortInfo.sortPropertyColl2));
|
2002-03-29 02:46:01 +00:00
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
|
|
|
resourceUrl = sortResource2;
|
|
|
|
resourceUrl.Append(NS_LITERAL_STRING("?sort=true"));
|
2003-02-25 19:02:00 +00:00
|
|
|
rv = gRDFService->GetUnicodeResource(resourceUrl, getter_AddRefs(sortInfo.sortPropertySort2));
|
2002-03-29 02:46:01 +00:00
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
// store sort info in attributes on content
|
|
|
|
SetSortHints(dbNode, sortResource, sortDirection, sortResource2, sortInfo.inbetweenSeparatorSort, PR_TRUE);
|
|
|
|
|
|
|
|
// start sorting the content depending on the tag
|
|
|
|
nsCOMPtr<nsIAtom> dbNodeTag;
|
|
|
|
dbNode->GetTag(*getter_AddRefs(dbNodeTag));
|
|
|
|
nsCOMPtr<nsIContent> container;
|
|
|
|
if (NS_FAILED(rv = FindSortableContainer(dbNode, getter_AddRefs(container)))) return rv;
|
|
|
|
SortContainer(container, &sortInfo, invertTreeFlag);
|
|
|
|
|
|
|
|
// Now remove the db node and re-insert it to force the frames to be rebuilt.
|
|
|
|
nsCOMPtr<nsIContent> containerParent;
|
|
|
|
if (NS_FAILED(rv = container->GetParent(*getter_AddRefs(containerParent)))) return rv;
|
|
|
|
PRInt32 containerIndex;
|
|
|
|
if (NS_FAILED(rv = containerParent->IndexOf(container, containerIndex))) return rv;
|
|
|
|
PRInt32 childCount;
|
|
|
|
if (NS_FAILED(rv = containerParent->ChildCount(childCount))) return rv;
|
|
|
|
if (NS_FAILED(rv = containerParent->RemoveChildAt(containerIndex, PR_TRUE))) return rv;
|
|
|
|
if (containerIndex+1 < childCount) {
|
|
|
|
if (NS_FAILED(rv = containerParent->InsertChildAt(container, containerIndex, PR_TRUE, PR_TRUE))) return rv;
|
|
|
|
} else {
|
|
|
|
if (NS_FAILED(rv = containerParent->AppendChildTo(container, PR_TRUE, PR_TRUE))) return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
1999-03-07 09:44:38 +00:00
|
|
|
|
1999-08-30 10:28:37 +00:00
|
|
|
nsresult
|
1999-03-05 23:51:41 +00:00
|
|
|
NS_NewXULSortService(nsIXULSortService** mgr)
|
|
|
|
{
|
2002-03-29 02:46:01 +00:00
|
|
|
XULSortServiceImpl *sortService = new XULSortServiceImpl();
|
|
|
|
if (!sortService)
|
|
|
|
return(NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
|
|
|
*mgr = sortService;
|
|
|
|
NS_ADDREF(*mgr);
|
|
|
|
return(NS_OK);
|
1999-03-05 23:51:41 +00:00
|
|
|
}
|