mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 06:11:37 +00:00
Bug 71530. Implement RDF outliner; preflight new files. r=ben/hyatt
This commit is contained in:
parent
21a52124e0
commit
a89ccc86d7
56
content/xul/templates/src/nsClusterKey.cpp
Normal file
56
content/xul/templates/src/nsClusterKey.cpp
Normal file
@ -0,0 +1,56 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#include "nsClusterKey.h"
|
||||
#include "nsTemplateRule.h"
|
||||
|
||||
nsClusterKey::nsClusterKey(const Instantiation& aInstantiation, const nsTemplateRule* aRule)
|
||||
{
|
||||
PRBool hasassignment;
|
||||
|
||||
mContainerVariable = aRule->GetContainerVariable();
|
||||
hasassignment = aInstantiation.mAssignments.GetAssignmentFor(mContainerVariable, &mContainerValue);
|
||||
NS_ASSERTION(hasassignment, "no assignment for container variable");
|
||||
|
||||
mMemberVariable = aRule->GetMemberVariable();
|
||||
hasassignment = aInstantiation.mAssignments.GetAssignmentFor(mMemberVariable, &mMemberValue);
|
||||
NS_ASSERTION(hasassignment, "no assignment for member variable");
|
||||
|
||||
MOZ_COUNT_CTOR(nsClusterKey);
|
||||
}
|
||||
|
||||
|
||||
PLHashNumber PR_CALLBACK
|
||||
nsClusterKey::HashClusterKey(const void* aKey)
|
||||
{
|
||||
const nsClusterKey* key = NS_STATIC_CAST(const nsClusterKey*, aKey);
|
||||
return key->Hash();
|
||||
}
|
||||
|
||||
PRIntn PR_CALLBACK
|
||||
nsClusterKey::CompareClusterKeys(const void* aLeft, const void* aRight)
|
||||
{
|
||||
const nsClusterKey* left = NS_STATIC_CAST(const nsClusterKey*, aLeft);
|
||||
const nsClusterKey* right = NS_STATIC_CAST(const nsClusterKey*, aRight);
|
||||
return *left == *right;
|
||||
}
|
121
content/xul/templates/src/nsClusterKey.h
Normal file
121
content/xul/templates/src/nsClusterKey.h
Normal file
@ -0,0 +1,121 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#ifndef nsClusterKey_h__
|
||||
#define nsClusterKey_h__
|
||||
|
||||
#include "prtypes.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsRuleNetwork.h"
|
||||
class nsTemplateRule;
|
||||
|
||||
/**
|
||||
* A match "cluster" is a group of matches that all share the same
|
||||
* values for their "container" (or parent) and "member" (or child)
|
||||
* variables.
|
||||
*
|
||||
* Only one match in a cluster can be "active": the active match is
|
||||
* the match that is used to generate content for the content model.
|
||||
* The matches in a cluster "compete" amongst each other;
|
||||
* specifically, the match that corresponds to the rule that is
|
||||
* declared first wins, and becomes active.
|
||||
*
|
||||
* The nsClusterKey is a hashtable key into the set of matches that are
|
||||
* currently competing: it consists of the container variable, its
|
||||
* value, the member variable, and its value.
|
||||
*/
|
||||
class nsClusterKey {
|
||||
public:
|
||||
nsClusterKey() { MOZ_COUNT_CTOR(nsClusterKey); }
|
||||
|
||||
/**
|
||||
* Construct a nsClusterKey from an instantiation and a rule. This
|
||||
* will use the rule to identify the container and member variables,
|
||||
* and then pull out their assignments from the instantiation.
|
||||
* @param aInstantiation the instantiation to use to determine
|
||||
* variable values
|
||||
* @param aRule the rule to use to determine the member and container
|
||||
* variables.
|
||||
*/
|
||||
nsClusterKey(const Instantiation& aInstantiation, const nsTemplateRule* aRule);
|
||||
|
||||
nsClusterKey(PRInt32 aContainerVariable,
|
||||
const Value& aContainerValue,
|
||||
PRInt32 aMemberVariable,
|
||||
const Value& aMemberValue)
|
||||
: mContainerVariable(aContainerVariable),
|
||||
mContainerValue(aContainerValue),
|
||||
mMemberVariable(aMemberVariable),
|
||||
mMemberValue(aMemberValue) {
|
||||
MOZ_COUNT_CTOR(nsClusterKey); }
|
||||
|
||||
nsClusterKey(const nsClusterKey& aKey)
|
||||
: mContainerVariable(aKey.mContainerVariable),
|
||||
mContainerValue(aKey.mContainerValue),
|
||||
mMemberVariable(aKey.mMemberVariable),
|
||||
mMemberValue(aKey.mMemberValue) {
|
||||
MOZ_COUNT_CTOR(nsClusterKey); }
|
||||
|
||||
~nsClusterKey() { MOZ_COUNT_DTOR(nsClusterKey); }
|
||||
|
||||
nsClusterKey& operator=(const nsClusterKey& aKey) {
|
||||
mContainerVariable = aKey.mContainerVariable;
|
||||
mContainerValue = aKey.mContainerValue;
|
||||
mMemberVariable = aKey.mMemberVariable;
|
||||
mMemberValue = aKey.mMemberValue;
|
||||
return *this; }
|
||||
|
||||
PRBool operator==(const nsClusterKey& aKey) const {
|
||||
return Equals(aKey); }
|
||||
|
||||
PRBool operator!=(const nsClusterKey& aKey) const {
|
||||
return !Equals(aKey); }
|
||||
|
||||
PRInt32 mContainerVariable;
|
||||
Value mContainerValue;
|
||||
PRInt32 mMemberVariable;
|
||||
Value mMemberValue;
|
||||
|
||||
PLHashNumber Hash() const {
|
||||
PLHashNumber temp1;
|
||||
temp1 = mContainerValue.Hash();
|
||||
temp1 &= 0xffff;
|
||||
temp1 |= PLHashNumber(mContainerVariable) << 16;
|
||||
PLHashNumber temp2;
|
||||
temp2 = mMemberValue.Hash();
|
||||
temp2 &= 0xffff;
|
||||
temp2 |= PLHashNumber(mMemberVariable) << 16;
|
||||
return temp1 ^ temp2; }
|
||||
|
||||
static PLHashNumber PR_CALLBACK HashClusterKey(const void* aKey);
|
||||
static PRIntn PR_CALLBACK CompareClusterKeys(const void* aLeft, const void* aRight);
|
||||
|
||||
protected:
|
||||
PRBool Equals(const nsClusterKey& aKey) const {
|
||||
return mContainerVariable == aKey.mContainerVariable &&
|
||||
mContainerValue == aKey.mContainerValue &&
|
||||
mMemberVariable == aKey.mMemberVariable &&
|
||||
mMemberValue == aKey.mMemberValue; }
|
||||
};
|
||||
|
||||
#endif // nsClusterKey_h__
|
89
content/xul/templates/src/nsClusterKeySet.cpp
Normal file
89
content/xul/templates/src/nsClusterKeySet.cpp
Normal file
@ -0,0 +1,89 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#include "nsClusterKeySet.h"
|
||||
|
||||
PLHashAllocOps nsClusterKeySet::gAllocOps = {
|
||||
AllocTable, FreeTable, AllocEntry, FreeEntry };
|
||||
|
||||
|
||||
nsClusterKeySet::nsClusterKeySet()
|
||||
: mTable(nsnull)
|
||||
{
|
||||
mHead.mPrev = mHead.mNext = &mHead;
|
||||
|
||||
static const size_t kBucketSizes[] = { sizeof(Entry) };
|
||||
static const PRInt32 kNumBuckets = sizeof(kBucketSizes) / sizeof(size_t);
|
||||
static const PRInt32 kInitialEntries = 8;
|
||||
|
||||
// Per news://news.mozilla.org/39BEC105.5090206%40netscape.com
|
||||
static const PRInt32 kInitialPoolSize = 256;
|
||||
|
||||
mPool.Init("nsClusterKeySet", kBucketSizes, kNumBuckets, kInitialPoolSize);
|
||||
|
||||
mTable = PL_NewHashTable(kInitialEntries, nsClusterKey::HashClusterKey, nsClusterKey::CompareClusterKeys,
|
||||
PL_CompareValues, &gAllocOps, &mPool);
|
||||
|
||||
MOZ_COUNT_CTOR(nsClusterKeySet);
|
||||
}
|
||||
|
||||
|
||||
nsClusterKeySet::~nsClusterKeySet()
|
||||
{
|
||||
PL_HashTableDestroy(mTable);
|
||||
MOZ_COUNT_DTOR(nsClusterKeySet);
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsClusterKeySet::Contains(const nsClusterKey& aKey)
|
||||
{
|
||||
return nsnull != PL_HashTableLookup(mTable, &aKey);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsClusterKeySet::Add(const nsClusterKey& aKey)
|
||||
{
|
||||
PLHashNumber hash = aKey.Hash();
|
||||
PLHashEntry** hep = PL_HashTableRawLookup(mTable, hash, &aKey);
|
||||
|
||||
if (hep && *hep)
|
||||
return NS_OK; // already had it.
|
||||
|
||||
PLHashEntry* he = PL_HashTableRawAdd(mTable, hep, hash, &aKey, nsnull);
|
||||
if (! he)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
Entry* entry = NS_REINTERPRET_CAST(Entry*, he);
|
||||
|
||||
// XXX yes, I am evil. Fixup the key in the hashentry to point to
|
||||
// the value it contains, rather than the one on the stack.
|
||||
entry->mHashEntry.key = &entry->mKey;
|
||||
|
||||
// thread
|
||||
mHead.mPrev->mNext = entry;
|
||||
entry->mPrev = mHead.mPrev;
|
||||
entry->mNext = &mHead;
|
||||
mHead.mPrev = entry;
|
||||
|
||||
return NS_OK;
|
||||
}
|
131
content/xul/templates/src/nsClusterKeySet.h
Normal file
131
content/xul/templates/src/nsClusterKeySet.h
Normal file
@ -0,0 +1,131 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#ifndef nsClusterKeySet_h__
|
||||
#define nsClusterKeySet_h__
|
||||
|
||||
#include "nsClusterKey.h"
|
||||
#include "nsFixedSizeAllocator.h"
|
||||
|
||||
/**
|
||||
* A collection of nsClusterKey objects.
|
||||
*/
|
||||
class nsClusterKeySet {
|
||||
public:
|
||||
class ConstIterator;
|
||||
friend class ConstIterator;
|
||||
|
||||
protected:
|
||||
class Entry {
|
||||
public:
|
||||
static void* operator new(size_t aSize, nsFixedSizeAllocator& aAllocator) {
|
||||
return aAllocator.Alloc(aSize); }
|
||||
|
||||
static void operator delete(void* aPtr, size_t aSize) {
|
||||
nsFixedSizeAllocator::Free(aPtr, aSize); }
|
||||
|
||||
Entry() { MOZ_COUNT_CTOR(nsClusterKeySet::Entry); }
|
||||
|
||||
Entry(const nsClusterKey& aKey) : mKey(aKey) {
|
||||
MOZ_COUNT_CTOR(nsClusterKeySet::Entry); }
|
||||
|
||||
~Entry() { MOZ_COUNT_DTOR(nsClusterKeySet::Entry); }
|
||||
|
||||
PLHashEntry mHashEntry;
|
||||
nsClusterKey mKey;
|
||||
Entry* mPrev;
|
||||
Entry* mNext;
|
||||
};
|
||||
|
||||
PLHashTable* mTable;
|
||||
Entry mHead;
|
||||
|
||||
nsFixedSizeAllocator mPool;
|
||||
|
||||
public:
|
||||
nsClusterKeySet();
|
||||
~nsClusterKeySet();
|
||||
|
||||
class ConstIterator {
|
||||
protected:
|
||||
Entry* mCurrent;
|
||||
|
||||
public:
|
||||
ConstIterator(Entry* aEntry) : mCurrent(aEntry) {}
|
||||
|
||||
ConstIterator(const ConstIterator& aConstIterator)
|
||||
: mCurrent(aConstIterator.mCurrent) {}
|
||||
|
||||
ConstIterator& operator=(const ConstIterator& aConstIterator) {
|
||||
mCurrent = aConstIterator.mCurrent;
|
||||
return *this; }
|
||||
|
||||
ConstIterator& operator++() {
|
||||
mCurrent = mCurrent->mNext;
|
||||
return *this; }
|
||||
|
||||
ConstIterator operator++(int) {
|
||||
ConstIterator result(*this);
|
||||
mCurrent = mCurrent->mNext;
|
||||
return result; }
|
||||
|
||||
const nsClusterKey& operator*() const {
|
||||
return mCurrent->mKey; }
|
||||
|
||||
const nsClusterKey* operator->() const {
|
||||
return &mCurrent->mKey; }
|
||||
|
||||
PRBool operator==(const ConstIterator& aConstIterator) const {
|
||||
return mCurrent == aConstIterator.mCurrent; }
|
||||
|
||||
PRBool operator!=(const ConstIterator& aConstIterator) const {
|
||||
return mCurrent != aConstIterator.mCurrent; }
|
||||
};
|
||||
|
||||
ConstIterator First() const { return ConstIterator(mHead.mNext); }
|
||||
ConstIterator Last() const { return ConstIterator(NS_CONST_CAST(Entry*, &mHead)); }
|
||||
|
||||
PRBool Contains(const nsClusterKey& aKey);
|
||||
nsresult Add(const nsClusterKey& aKey);
|
||||
|
||||
protected:
|
||||
static PLHashAllocOps gAllocOps;
|
||||
|
||||
static void* PR_CALLBACK AllocTable(void* aPool, PRSize aSize) {
|
||||
return new char[aSize]; }
|
||||
|
||||
static void PR_CALLBACK FreeTable(void* aPool, void* aItem) {
|
||||
delete[] NS_STATIC_CAST(char*, aItem); }
|
||||
|
||||
static PLHashEntry* PR_CALLBACK AllocEntry(void* aPool, const void* aKey) {
|
||||
nsFixedSizeAllocator* pool = NS_STATIC_CAST(nsFixedSizeAllocator*, aPool);
|
||||
const nsClusterKey* key = NS_STATIC_CAST(const nsClusterKey*, aKey);
|
||||
Entry* entry = new (*pool) Entry(*key);
|
||||
return NS_REINTERPRET_CAST(PLHashEntry*, entry); }
|
||||
|
||||
static void PR_CALLBACK FreeEntry(void* aPool, PLHashEntry* aEntry, PRUintn aFlag) {
|
||||
if (aFlag == HT_FREE_ENTRY)
|
||||
delete NS_REINTERPRET_CAST(Entry*, aEntry); }
|
||||
};
|
||||
|
||||
#endif // nsClusterKeySet_h__
|
360
content/xul/templates/src/nsConflictSet.cpp
Normal file
360
content/xul/templates/src/nsConflictSet.cpp
Normal file
@ -0,0 +1,360 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#include "nsConflictSet.h"
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
PRLogModule* nsConflictSet::gLog;
|
||||
#endif
|
||||
|
||||
// Allocation operations for the cluster table
|
||||
PLHashAllocOps nsConflictSet::gClusterAllocOps = {
|
||||
AllocClusterTable, FreeClusterTable, AllocClusterEntry, FreeClusterEntry };
|
||||
|
||||
// Allocation operations for the support table
|
||||
PLHashAllocOps nsConflictSet::gSupportAllocOps = {
|
||||
AllocSupportTable, FreeSupportTable, AllocSupportEntry, FreeSupportEntry };
|
||||
|
||||
// Allocation operations for the binding table
|
||||
PLHashAllocOps nsConflictSet::gBindingAllocOps = {
|
||||
AllocBindingTable, FreeBindingTable, AllocBindingEntry, FreeBindingEntry };
|
||||
|
||||
|
||||
nsresult
|
||||
nsConflictSet::Init()
|
||||
{
|
||||
#ifdef PR_LOGGING
|
||||
if (! gLog)
|
||||
gLog = PR_NewLogModule("nsConflictSet");
|
||||
#endif
|
||||
|
||||
static const size_t kBucketSizes[] = {
|
||||
sizeof(ClusterEntry),
|
||||
sizeof(SupportEntry),
|
||||
sizeof(BindingEntry),
|
||||
nsTemplateMatchSet::kEntrySize,
|
||||
nsTemplateMatchSet::kIndexSize
|
||||
};
|
||||
|
||||
static const PRInt32 kNumBuckets = sizeof(kBucketSizes) / sizeof(size_t);
|
||||
|
||||
static const PRInt32 kNumResourceElements = 64;
|
||||
|
||||
// Per news://news.mozilla.org/39BEC105.5090206%40netscape.com
|
||||
static const PRInt32 kInitialSize = 256;
|
||||
|
||||
mPool.Init("nsConflictSet", kBucketSizes, kNumBuckets, kInitialSize);
|
||||
|
||||
mClusters =
|
||||
PL_NewHashTable(kNumResourceElements /* XXXwaterson we need a way to give a hint? */,
|
||||
nsClusterKey::HashClusterKey,
|
||||
nsClusterKey::CompareClusterKeys,
|
||||
PL_CompareValues,
|
||||
&gClusterAllocOps,
|
||||
&mPool);
|
||||
|
||||
mSupport =
|
||||
PL_NewHashTable(kNumResourceElements, /* XXXwaterson need hint */
|
||||
HashMemoryElement,
|
||||
CompareMemoryElements,
|
||||
PL_CompareValues,
|
||||
&gSupportAllocOps,
|
||||
&mPool);
|
||||
|
||||
mBindingDependencies =
|
||||
PL_NewHashTable(kNumResourceElements /* XXX arbitrary */,
|
||||
HashBindingElement,
|
||||
CompareBindingElements,
|
||||
PL_CompareValues,
|
||||
&gBindingAllocOps,
|
||||
&mPool);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsConflictSet::Destroy()
|
||||
{
|
||||
PL_HashTableDestroy(mSupport);
|
||||
PL_HashTableDestroy(mClusters);
|
||||
PL_HashTableDestroy(mBindingDependencies);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsConflictSet::Add(nsTemplateMatch* aMatch)
|
||||
{
|
||||
// Add a match to the conflict set. This involves adding it to
|
||||
// the cluster table, the support table, and the binding table.
|
||||
|
||||
// add the match to a table indexed by instantiation key
|
||||
{
|
||||
nsClusterKey key(aMatch->mInstantiation, aMatch->mRule);
|
||||
|
||||
PLHashNumber hash = key.Hash();
|
||||
PLHashEntry** hep = PL_HashTableRawLookup(mClusters, hash, &key);
|
||||
|
||||
nsTemplateMatchSet* set;
|
||||
|
||||
if (hep && *hep) {
|
||||
set = NS_STATIC_CAST(nsTemplateMatchSet*, (*hep)->value);
|
||||
}
|
||||
else {
|
||||
PLHashEntry* he = PL_HashTableRawAdd(mClusters, hep, hash, &key, nsnull);
|
||||
if (! he)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
ClusterEntry* entry = NS_REINTERPRET_CAST(ClusterEntry*, he);
|
||||
|
||||
// Fixup the key in the hashentry to point to the value
|
||||
// that the specially-allocated entry contains (rather
|
||||
// than the value on the stack). Do the same for its
|
||||
// value.
|
||||
entry->mHashEntry.key = &entry->mKey;
|
||||
entry->mHashEntry.value = &entry->mMatchSet;
|
||||
|
||||
set = &entry->mMatchSet;
|
||||
}
|
||||
|
||||
if (! set->Contains(*aMatch)) {
|
||||
set->Add(mPool, aMatch);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Add the match to a table indexed by supporting MemoryElement
|
||||
{
|
||||
MemoryElementSet::ConstIterator last = aMatch->mInstantiation.mSupport.Last();
|
||||
for (MemoryElementSet::ConstIterator element = aMatch->mInstantiation.mSupport.First(); element != last; ++element) {
|
||||
PLHashNumber hash = element->Hash();
|
||||
PLHashEntry** hep = PL_HashTableRawLookup(mSupport, hash, element.operator->());
|
||||
|
||||
nsTemplateMatchSet* set;
|
||||
|
||||
if (hep && *hep) {
|
||||
set = NS_STATIC_CAST(nsTemplateMatchSet*, (*hep)->value);
|
||||
}
|
||||
else {
|
||||
PLHashEntry* he = PL_HashTableRawAdd(mSupport, hep, hash, element.operator->(), nsnull);
|
||||
|
||||
SupportEntry* entry = NS_REINTERPRET_CAST(SupportEntry*, he);
|
||||
if (! entry)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// Fixup the key and value.
|
||||
entry->mHashEntry.key = entry->mElement;
|
||||
entry->mHashEntry.value = &entry->mMatchSet;
|
||||
|
||||
set = &entry->mMatchSet;
|
||||
}
|
||||
|
||||
if (! set->Contains(*aMatch)) {
|
||||
set->Add(mPool, aMatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add the match to a table indexed by bound MemoryElement
|
||||
nsResourceSet::ConstIterator last = aMatch->mBindingDependencies.Last();
|
||||
for (nsResourceSet::ConstIterator dep = aMatch->mBindingDependencies.First(); dep != last; ++dep)
|
||||
AddBindingDependency(aMatch, *dep);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsConflictSet::GetMatchesForClusterKey(const nsClusterKey& aKey, const nsTemplateMatchSet** aMatchSet)
|
||||
{
|
||||
// Retrieve all the matches in a cluster
|
||||
*aMatchSet = NS_STATIC_CAST(nsTemplateMatchSet*, PL_HashTableLookup(mClusters, &aKey));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsConflictSet::GetMatchesWithBindingDependency(nsIRDFResource* aResource, const nsTemplateMatchSet** aMatchSet)
|
||||
{
|
||||
// Retrieve all the matches whose bindings depend on the specified resource
|
||||
*aMatchSet = NS_STATIC_CAST(nsTemplateMatchSet*, PL_HashTableLookup(mBindingDependencies, aResource));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsConflictSet::Remove(const MemoryElement& aMemoryElement,
|
||||
nsTemplateMatchSet& aNewMatches,
|
||||
nsTemplateMatchSet& aRetractedMatches)
|
||||
{
|
||||
// Use the memory-element-to-match map to figure out what matches
|
||||
// will be affected.
|
||||
PLHashEntry** hep = PL_HashTableRawLookup(mSupport, aMemoryElement.Hash(), &aMemoryElement);
|
||||
|
||||
if (!hep || !*hep)
|
||||
return;
|
||||
|
||||
// 'set' gets the set of all matches containing the first binding.
|
||||
nsTemplateMatchSet* set = NS_STATIC_CAST(nsTemplateMatchSet*, (*hep)->value);
|
||||
|
||||
// We'll iterate through these matches, only paying attention to
|
||||
// matches that strictly contain the MemoryElement we're about to
|
||||
// remove.
|
||||
for (nsTemplateMatchSet::Iterator match = set->First(); match != set->Last(); ++match) {
|
||||
// Note the retraction, so we can compute new matches, later.
|
||||
aRetractedMatches.Add(mPool, match.operator->());
|
||||
|
||||
// Keep the bindings table in sync, as well. Since this match
|
||||
// is getting nuked, we need to nuke its bindings as well.
|
||||
nsResourceSet::ConstIterator last = match->mBindingDependencies.Last();
|
||||
for (nsResourceSet::ConstIterator dep = match->mBindingDependencies.First(); dep != last; ++dep)
|
||||
RemoveBindingDependency(match.operator->(), *dep);
|
||||
}
|
||||
|
||||
// Unhash it
|
||||
PL_HashTableRawRemove(mSupport, hep, *hep);
|
||||
|
||||
// Update the key-to-match map, and see if any new rules have been
|
||||
// fired as a result of the retraction.
|
||||
ComputeNewMatches(aNewMatches, aRetractedMatches);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsConflictSet::AddBindingDependency(nsTemplateMatch* aMatch, nsIRDFResource* aResource)
|
||||
{
|
||||
// Note a match's dependency on a source resource
|
||||
PLHashNumber hash = HashBindingElement(aResource);
|
||||
PLHashEntry** hep = PL_HashTableRawLookup(mBindingDependencies, hash, aResource);
|
||||
|
||||
nsTemplateMatchSet* set;
|
||||
|
||||
if (hep && *hep) {
|
||||
set = NS_STATIC_CAST(nsTemplateMatchSet*, (*hep)->value);
|
||||
}
|
||||
else {
|
||||
PLHashEntry* he = PL_HashTableRawAdd(mBindingDependencies, hep, hash, aResource, nsnull);
|
||||
|
||||
BindingEntry* entry = NS_REINTERPRET_CAST(BindingEntry*, he);
|
||||
if (! entry)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// Fixup the value.
|
||||
entry->mHashEntry.value = set = &entry->mMatchSet;
|
||||
|
||||
}
|
||||
|
||||
if (! set->Contains(*aMatch)) {
|
||||
set->Add(mPool, aMatch);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsConflictSet::RemoveBindingDependency(nsTemplateMatch* aMatch, nsIRDFResource* aResource)
|
||||
{
|
||||
// Remove a match's dependency on a source resource
|
||||
PLHashNumber hash = HashBindingElement(aResource);
|
||||
PLHashEntry** hep = PL_HashTableRawLookup(mBindingDependencies, hash, aResource);
|
||||
|
||||
if (hep && *hep) {
|
||||
nsTemplateMatchSet* set = NS_STATIC_CAST(nsTemplateMatchSet*, (*hep)->value);
|
||||
|
||||
set->Remove(aMatch);
|
||||
|
||||
if (set->Empty()) {
|
||||
PL_HashTableRawRemove(mBindingDependencies, hep, *hep);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsConflictSet::ComputeNewMatches(nsTemplateMatchSet& aNewMatches, nsTemplateMatchSet& aRetractedMatches)
|
||||
{
|
||||
// Given a set of just-retracted matches, compute the set of new
|
||||
// matches that have been revealed, updating the key-to-match map
|
||||
// as we go.
|
||||
nsTemplateMatchSet::ConstIterator last = aRetractedMatches.Last();
|
||||
for (nsTemplateMatchSet::ConstIterator retraction = aRetractedMatches.First(); retraction != last; ++retraction) {
|
||||
nsClusterKey key(retraction->mInstantiation, retraction->mRule);
|
||||
PLHashEntry** hep = PL_HashTableRawLookup(mClusters, key.Hash(), &key);
|
||||
|
||||
// XXXwaterson I'd managed to convince myself that this was really
|
||||
// okay, but now I can't remember why.
|
||||
//NS_ASSERTION(hep && *hep, "mClusters corrupted");
|
||||
if (!hep || !*hep)
|
||||
continue;
|
||||
|
||||
nsTemplateMatchSet* set = NS_STATIC_CAST(nsTemplateMatchSet*, (*hep)->value);
|
||||
|
||||
for (nsTemplateMatchSet::Iterator match = set->First(); match != set->Last(); ++match) {
|
||||
if (match->mRule == retraction->mRule) {
|
||||
set->Erase(match--);
|
||||
|
||||
// See if we've revealed another rule that's applicable
|
||||
nsTemplateMatch* newmatch =
|
||||
set->FindMatchWithHighestPriority();
|
||||
|
||||
if (newmatch)
|
||||
aNewMatches.Add(mPool, newmatch);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (set->Empty()) {
|
||||
PL_HashTableRawRemove(mClusters, hep, *hep);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsConflictSet::Clear()
|
||||
{
|
||||
Destroy();
|
||||
Init();
|
||||
}
|
||||
|
||||
PLHashNumber PR_CALLBACK
|
||||
nsConflictSet::HashMemoryElement(const void* aMemoryElement)
|
||||
{
|
||||
const MemoryElement* element =
|
||||
NS_STATIC_CAST(const MemoryElement*, aMemoryElement);
|
||||
|
||||
return element->Hash();
|
||||
}
|
||||
|
||||
PRIntn PR_CALLBACK
|
||||
nsConflictSet::CompareMemoryElements(const void* aLeft, const void* aRight)
|
||||
{
|
||||
const MemoryElement* left =
|
||||
NS_STATIC_CAST(const MemoryElement*, aLeft);
|
||||
|
||||
const MemoryElement* right =
|
||||
NS_STATIC_CAST(const MemoryElement*, aRight);
|
||||
|
||||
return *left == *right;
|
||||
}
|
272
content/xul/templates/src/nsConflictSet.h
Normal file
272
content/xul/templates/src/nsConflictSet.h
Normal file
@ -0,0 +1,272 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#ifndef nsConflictSet_h__
|
||||
#define nsConflictSet_h__
|
||||
|
||||
#include "plhash.h"
|
||||
#include "nsTemplateMatch.h"
|
||||
#include "nsTemplateMatchSet.h"
|
||||
#include "nsClusterKey.h"
|
||||
#include "nsIRDFResource.h"
|
||||
|
||||
/**
|
||||
* Maintains the set of active matches, and the stuff that the
|
||||
* matches depend on.
|
||||
*/
|
||||
class nsConflictSet
|
||||
{
|
||||
public:
|
||||
nsConflictSet()
|
||||
: mClusters(nsnull),
|
||||
mSupport(nsnull),
|
||||
mBindingDependencies(nsnull) { Init(); }
|
||||
|
||||
~nsConflictSet() { Destroy(); }
|
||||
|
||||
/**
|
||||
* Add a match to the conflict set.
|
||||
* @param aMatch the match to add to the conflict set
|
||||
* @return NS_OK if no errors occurred
|
||||
*/
|
||||
nsresult Add(nsTemplateMatch* aMatch);
|
||||
|
||||
/**
|
||||
* Given a cluster key, which is a container-member pair, return the
|
||||
* set of matches that are currently "active" for that cluster. (The
|
||||
* caller can the select among the active rules to determine which
|
||||
* should actually be applied.)
|
||||
* @param aKey the cluster key to search for
|
||||
* @param aMatchSet the set of matches that are currently active
|
||||
* for the key.
|
||||
*/
|
||||
void GetMatchesForClusterKey(const nsClusterKey& aKey, const nsTemplateMatchSet** aMatchSet);
|
||||
|
||||
/**
|
||||
* Given a "source" in the RDF graph, return the set of matches
|
||||
* that currently depend on the source in some way.
|
||||
* @param aSource an RDF resource that is a "source" in the graph.
|
||||
* @param aMatchSet the set of matches that depend on aSource.
|
||||
*/
|
||||
void GetMatchesWithBindingDependency(nsIRDFResource* aSource, const nsTemplateMatchSet** aMatchSet);
|
||||
|
||||
/**
|
||||
* Remove a memory element from the conflict set. This may
|
||||
* potentially retract matches that depended on the memory
|
||||
* element, as well as trigger previously masked matches that are
|
||||
* now "revealed".
|
||||
* @param aMemoryElement the memory element that is being removed.
|
||||
* @param aNewMatches new matches that have been revealed.
|
||||
* @param aRetractedMatches matches whose validity depended
|
||||
* on aMemoryElement and have been retracted.
|
||||
*/
|
||||
void Remove(const MemoryElement& aMemoryElement,
|
||||
nsTemplateMatchSet& aNewMatches,
|
||||
nsTemplateMatchSet& aRetractedMatches);
|
||||
|
||||
nsresult AddBindingDependency(nsTemplateMatch* aMatch, nsIRDFResource* aResource);
|
||||
|
||||
nsresult RemoveBindingDependency(nsTemplateMatch* aMatch, nsIRDFResource* aResource);
|
||||
|
||||
/**
|
||||
* Remove all match support information currently stored in the conflict
|
||||
* set, and re-initialize the set.
|
||||
*/
|
||||
void Clear();
|
||||
|
||||
/**
|
||||
* Get the fixed-size arena allocator used by the conflict set
|
||||
* @return the fixed-size arena allocator used by the conflict set
|
||||
*/
|
||||
nsFixedSizeAllocator& GetPool() { return mPool; }
|
||||
|
||||
protected:
|
||||
nsresult Init();
|
||||
nsresult Destroy();
|
||||
|
||||
nsresult ComputeNewMatches(nsTemplateMatchSet& aNewMatches, nsTemplateMatchSet& aRetractedMatches);
|
||||
|
||||
/**
|
||||
* "Clusters" of matched rules for the same <content, member>
|
||||
* pair. This table makes it O(1) to lookup all of the matches
|
||||
* that are active for a cluster, so determining which is active
|
||||
* is efficient.
|
||||
*/
|
||||
PLHashTable* mClusters;
|
||||
|
||||
class ClusterEntry {
|
||||
public:
|
||||
static void* operator new(size_t aSize, nsFixedSizeAllocator& aAllocator) {
|
||||
return aAllocator.Alloc(aSize); }
|
||||
|
||||
static void operator delete(void* aPtr, size_t aSize) {
|
||||
nsFixedSizeAllocator::Free(aPtr, aSize); }
|
||||
|
||||
ClusterEntry() { MOZ_COUNT_CTOR(nsConflictSet::ClusterEntry); }
|
||||
~ClusterEntry() { MOZ_COUNT_DTOR(nsConflictSet::ClusterEntry); }
|
||||
|
||||
PLHashEntry mHashEntry;
|
||||
nsClusterKey mKey;
|
||||
nsTemplateMatchSet mMatchSet;
|
||||
};
|
||||
|
||||
static PLHashAllocOps gClusterAllocOps;
|
||||
|
||||
static void* PR_CALLBACK AllocClusterTable(void* aPool, PRSize aSize) {
|
||||
return new char[aSize]; }
|
||||
|
||||
static void PR_CALLBACK FreeClusterTable(void* aPool, void* aItem) {
|
||||
delete[] NS_STATIC_CAST(char*, aItem); }
|
||||
|
||||
static PLHashEntry* PR_CALLBACK AllocClusterEntry(void* aPool, const void* aKey) {
|
||||
nsFixedSizeAllocator* pool = NS_STATIC_CAST(nsFixedSizeAllocator*, aPool);
|
||||
|
||||
ClusterEntry* entry = new (*pool) ClusterEntry();
|
||||
if (! entry)
|
||||
return nsnull;
|
||||
|
||||
entry->mKey = *NS_STATIC_CAST(const nsClusterKey*, aKey);
|
||||
return NS_REINTERPRET_CAST(PLHashEntry*, entry); }
|
||||
|
||||
static void PR_CALLBACK FreeClusterEntry(void* aPool, PLHashEntry* aHashEntry, PRUintn aFlag) {
|
||||
if (aFlag == HT_FREE_ENTRY)
|
||||
delete NS_REINTERPRET_CAST(ClusterEntry*, aHashEntry); }
|
||||
|
||||
/**
|
||||
* Maps a MemoryElement to the nsTemplateMatch objects that it
|
||||
* supports. This map allows us to efficiently remove rules from
|
||||
* the conflict set when a MemoryElement is removed.
|
||||
*/
|
||||
PLHashTable* mSupport;
|
||||
|
||||
class SupportEntry {
|
||||
public:
|
||||
static void* operator new(size_t aSize, nsFixedSizeAllocator& aAllocator) {
|
||||
return aAllocator.Alloc(aSize); }
|
||||
|
||||
static void operator delete(void* aPtr, size_t aSize) {
|
||||
nsFixedSizeAllocator::Free(aPtr, aSize); }
|
||||
|
||||
SupportEntry() : mElement(nsnull)
|
||||
{ MOZ_COUNT_CTOR(nsConflictSet::SupportEntry); }
|
||||
|
||||
~SupportEntry() {
|
||||
delete mElement;
|
||||
MOZ_COUNT_DTOR(nsConflictSet::SupportEntry); }
|
||||
|
||||
PLHashEntry mHashEntry;
|
||||
MemoryElement* mElement;
|
||||
nsTemplateMatchSet mMatchSet;
|
||||
};
|
||||
|
||||
static PLHashAllocOps gSupportAllocOps;
|
||||
|
||||
static void* PR_CALLBACK AllocSupportTable(void* aPool, PRSize aSize) {
|
||||
return new char[aSize]; }
|
||||
|
||||
static void PR_CALLBACK FreeSupportTable(void* aPool, void* aItem) {
|
||||
delete[] NS_STATIC_CAST(char*, aItem); }
|
||||
|
||||
static PLHashEntry* PR_CALLBACK AllocSupportEntry(void* aPool, const void* aKey) {
|
||||
nsFixedSizeAllocator* pool = NS_STATIC_CAST(nsFixedSizeAllocator*, aPool);
|
||||
|
||||
SupportEntry* entry = new (*pool) SupportEntry();
|
||||
if (! entry)
|
||||
return nsnull;
|
||||
|
||||
const MemoryElement* element = NS_STATIC_CAST(const MemoryElement*, aKey);
|
||||
entry->mElement = element->Clone(aPool);
|
||||
|
||||
return NS_REINTERPRET_CAST(PLHashEntry*, entry); }
|
||||
|
||||
static void PR_CALLBACK FreeSupportEntry(void* aPool, PLHashEntry* aHashEntry, PRUintn aFlag) {
|
||||
if (aFlag == HT_FREE_ENTRY)
|
||||
delete NS_REINTERPRET_CAST(SupportEntry*, aHashEntry); }
|
||||
|
||||
static PLHashNumber PR_CALLBACK HashMemoryElement(const void* aBinding);
|
||||
static PRIntn PR_CALLBACK CompareMemoryElements(const void* aLeft, const void* aRight);
|
||||
|
||||
|
||||
/**
|
||||
* Maps a MemoryElement to the nsTemplateMatch objects whose bindings it
|
||||
* participates in. This makes it possible to efficiently update a
|
||||
* match when a binding changes.
|
||||
*/
|
||||
PLHashTable* mBindingDependencies;
|
||||
|
||||
class BindingEntry {
|
||||
public:
|
||||
static void* operator new(size_t aSize, nsFixedSizeAllocator& aAllocator) {
|
||||
return aAllocator.Alloc(aSize); }
|
||||
|
||||
static void operator delete(void* aPtr, size_t aSize) {
|
||||
nsFixedSizeAllocator::Free(aPtr, aSize); }
|
||||
|
||||
BindingEntry()
|
||||
{ MOZ_COUNT_CTOR(nsConflictSet::BindingEntry); }
|
||||
|
||||
~BindingEntry()
|
||||
{ MOZ_COUNT_DTOR(nsConflictSet::BindingEntry); }
|
||||
|
||||
PLHashEntry mHashEntry;
|
||||
nsTemplateMatchSet mMatchSet;
|
||||
};
|
||||
|
||||
static PLHashAllocOps gBindingAllocOps;
|
||||
|
||||
static void* PR_CALLBACK AllocBindingTable(void* aPool, PRSize aSize) {
|
||||
return new char[aSize]; }
|
||||
|
||||
static void PR_CALLBACK FreeBindingTable(void* aPool, void* aItem) {
|
||||
delete[] NS_STATIC_CAST(char*, aItem); }
|
||||
|
||||
static PLHashEntry* PR_CALLBACK AllocBindingEntry(void* aPool, const void* aKey) {
|
||||
nsFixedSizeAllocator* pool = NS_STATIC_CAST(nsFixedSizeAllocator*, aPool);
|
||||
|
||||
BindingEntry* entry = new (*pool) BindingEntry();
|
||||
if (! entry)
|
||||
return nsnull;
|
||||
|
||||
nsIRDFResource* key = NS_STATIC_CAST(nsIRDFResource*, NS_CONST_CAST(void*, aKey));
|
||||
NS_ADDREF(key);
|
||||
|
||||
return NS_REINTERPRET_CAST(PLHashEntry*, entry); }
|
||||
|
||||
static void PR_CALLBACK FreeBindingEntry(void* aPool, PLHashEntry* aHashEntry, PRUintn aFlag) {
|
||||
if (aFlag == HT_FREE_ENTRY) {
|
||||
nsIRDFResource* key = NS_STATIC_CAST(nsIRDFResource*, NS_CONST_CAST(void*, aHashEntry->key));
|
||||
NS_RELEASE(key);
|
||||
delete NS_REINTERPRET_CAST(BindingEntry*, aHashEntry);
|
||||
} }
|
||||
|
||||
static PLHashNumber PR_CALLBACK HashBindingElement(const void* aSupport) {
|
||||
return PLHashNumber(aSupport) >> 3; }
|
||||
|
||||
static PRIntn PR_CALLBACK CompareBindingElements(const void* aLeft, const void* aRight) {
|
||||
return aLeft == aRight; }
|
||||
|
||||
// The pool from whence all our slop will be allocated
|
||||
nsFixedSizeAllocator mPool;
|
||||
};
|
||||
|
||||
#endif // nsConflictSet_h__
|
113
content/xul/templates/src/nsContentSupportMap.cpp
Normal file
113
content/xul/templates/src/nsContentSupportMap.cpp
Normal file
@ -0,0 +1,113 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#include "nsContentSupportMap.h"
|
||||
#include "nsIXULContent.h"
|
||||
|
||||
PLHashAllocOps nsContentSupportMap::gAllocOps = {
|
||||
AllocTable, FreeTable, AllocEntry, FreeEntry };
|
||||
|
||||
void
|
||||
nsContentSupportMap::Init()
|
||||
{
|
||||
static const size_t kBucketSizes[] = { sizeof(Entry) };
|
||||
static const PRInt32 kNumBuckets = sizeof(kBucketSizes) / sizeof(size_t);
|
||||
|
||||
// Per news://news.mozilla.org/39BEC105.5090206%40netscape.com
|
||||
static const PRInt32 kInitialSize = 256;
|
||||
|
||||
mPool.Init("nsContentSupportMap", kBucketSizes, kNumBuckets, kInitialSize);
|
||||
|
||||
static const PRInt32 kInitialEntries = 8; // XXX arbitrary
|
||||
|
||||
mMap = PL_NewHashTable(kInitialEntries,
|
||||
HashPointer,
|
||||
PL_CompareValues,
|
||||
PL_CompareValues,
|
||||
&gAllocOps,
|
||||
&mPool);
|
||||
}
|
||||
|
||||
void
|
||||
nsContentSupportMap::Finish()
|
||||
{
|
||||
PL_HashTableDestroy(mMap);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsContentSupportMap::Put(nsIContent* aElement, nsTemplateMatch* aMatch)
|
||||
{
|
||||
PLHashEntry* he = PL_HashTableAdd(mMap, aElement, nsnull);
|
||||
if (! he)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// "Fix up" the entry's value to refer to the mMatch that's built
|
||||
// in to the Entry object.
|
||||
Entry* entry = NS_REINTERPRET_CAST(Entry*, he);
|
||||
entry->mHashEntry.value = &entry->mMatch;
|
||||
entry->mMatch = aMatch;
|
||||
aMatch->AddRef();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsContentSupportMap::Remove(nsIContent* aElement)
|
||||
{
|
||||
PL_HashTableRemove(mMap, aElement);
|
||||
|
||||
PRInt32 count;
|
||||
|
||||
// If possible, use the special nsIXULContent interface to "peek"
|
||||
// at the child count without accidentally creating children as a
|
||||
// side effect, since we're about to rip 'em outta the map anyway.
|
||||
nsCOMPtr<nsIXULContent> xulcontent = do_QueryInterface(aElement);
|
||||
if (xulcontent) {
|
||||
xulcontent->PeekChildCount(count);
|
||||
}
|
||||
else {
|
||||
aElement->ChildCount(count);
|
||||
}
|
||||
|
||||
for (PRInt32 i = 0; i < count; ++i) {
|
||||
nsCOMPtr<nsIContent> child;
|
||||
aElement->ChildAt(i, *getter_AddRefs(child));
|
||||
|
||||
Remove(child);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
PRBool
|
||||
nsContentSupportMap::Get(nsIContent* aElement, nsTemplateMatch** aMatch)
|
||||
{
|
||||
nsTemplateMatch** match = NS_STATIC_CAST(nsTemplateMatch**, PL_HashTableLookup(mMap, aElement));
|
||||
if (! match)
|
||||
return PR_FALSE;
|
||||
|
||||
*aMatch = *match;
|
||||
return PR_TRUE;
|
||||
}
|
99
content/xul/templates/src/nsContentSupportMap.h
Normal file
99
content/xul/templates/src/nsContentSupportMap.h
Normal file
@ -0,0 +1,99 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#ifndef nsContentSupportMap_h__
|
||||
#define nsContentSupportMap_h__
|
||||
|
||||
#include "plhash.h"
|
||||
#include "nsFixedSizeAllocator.h"
|
||||
#include "nsTemplateMatch.h"
|
||||
|
||||
/**
|
||||
* The nsContentSupportMap maintains a mapping from a "resource element"
|
||||
* in the content tree to the nsTemplateMatch that was used to instantiate it. This
|
||||
* is necessary to allow the XUL content to be built lazily. Specifically,
|
||||
* when building "resumes" on a partially-built content element, the builder
|
||||
* will walk upwards in the content tree to find the first element with an
|
||||
* 'id' attribute. This element is assumed to be the "resource element",
|
||||
* and allows the content builder to access the nsTemplateMatch (variable assignments
|
||||
* and rule information).
|
||||
*/
|
||||
class nsContentSupportMap {
|
||||
public:
|
||||
nsContentSupportMap() { Init(); }
|
||||
~nsContentSupportMap() { Finish(); }
|
||||
|
||||
nsresult Put(nsIContent* aElement, nsTemplateMatch* aMatch);
|
||||
PRBool Get(nsIContent* aElement, nsTemplateMatch** aMatch);
|
||||
nsresult Remove(nsIContent* aElement);
|
||||
void Clear() { Finish(); Init(); }
|
||||
|
||||
protected:
|
||||
PLHashTable* mMap;
|
||||
nsFixedSizeAllocator mPool;
|
||||
|
||||
void Init();
|
||||
void Finish();
|
||||
|
||||
struct Entry {
|
||||
PLHashEntry mHashEntry;
|
||||
nsTemplateMatch* mMatch;
|
||||
};
|
||||
|
||||
static PLHashAllocOps gAllocOps;
|
||||
|
||||
static void* PR_CALLBACK
|
||||
AllocTable(void* aPool, PRSize aSize) {
|
||||
return new char[aSize]; };
|
||||
|
||||
static void PR_CALLBACK
|
||||
FreeTable(void* aPool, void* aItem) {
|
||||
delete[] NS_STATIC_CAST(char*, aItem); }
|
||||
|
||||
static PLHashEntry* PR_CALLBACK
|
||||
AllocEntry(void* aPool, const void* aKey) {
|
||||
nsFixedSizeAllocator* pool = NS_STATIC_CAST(nsFixedSizeAllocator*, aPool);
|
||||
|
||||
Entry* entry = NS_STATIC_CAST(Entry*, pool->Alloc(sizeof(Entry)));
|
||||
if (! entry)
|
||||
return nsnull;
|
||||
|
||||
return NS_REINTERPRET_CAST(PLHashEntry*, entry); }
|
||||
|
||||
static void PR_CALLBACK
|
||||
FreeEntry(void* aPool, PLHashEntry* aEntry, PRUintn aFlag) {
|
||||
if (aFlag == HT_FREE_ENTRY) {
|
||||
Entry* entry = NS_REINTERPRET_CAST(Entry*, aEntry);
|
||||
|
||||
if (entry->mMatch)
|
||||
entry->mMatch->Release();
|
||||
|
||||
nsFixedSizeAllocator::Free(entry, sizeof(Entry));
|
||||
} }
|
||||
|
||||
static PLHashNumber PR_CALLBACK
|
||||
HashPointer(const void* aKey) {
|
||||
return PLHashNumber(aKey) >> 3; }
|
||||
};
|
||||
|
||||
#endif
|
88
content/xul/templates/src/nsContentTagTestNode.cpp
Normal file
88
content/xul/templates/src/nsContentTagTestNode.cpp
Normal file
@ -0,0 +1,88 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#include "nsContentTagTestNode.h"
|
||||
#include "nsISupportsArray.h"
|
||||
|
||||
#include "prlog.h"
|
||||
#ifdef PR_LOGGING
|
||||
extern PRLogModuleInfo* gXULTemplateLog;
|
||||
#endif
|
||||
|
||||
nsContentTagTestNode::nsContentTagTestNode(InnerNode* aParent,
|
||||
nsConflictSet& aConflictSet,
|
||||
PRInt32 aContentVariable,
|
||||
nsIAtom* aTag)
|
||||
: TestNode(aParent),
|
||||
mConflictSet(aConflictSet),
|
||||
mContentVariable(aContentVariable),
|
||||
mTag(aTag)
|
||||
{
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
nsAutoString tag = NS_LITERAL_STRING("(none)");
|
||||
if (mTag)
|
||||
mTag->ToString(tag);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("nsContentTagTestNode[%p]: parent=%p content-var=%d tag=%s",
|
||||
this, aParent, aContentVariable, NS_ConvertUCS2toUTF8(tag).get()));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsContentTagTestNode::FilterInstantiations(InstantiationSet& aInstantiations, void* aClosure) const
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsISupportsArray> elements;
|
||||
rv = NS_NewISupportsArray(getter_AddRefs(elements));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
InstantiationSet::Iterator last = aInstantiations.Last();
|
||||
for (InstantiationSet::Iterator inst = aInstantiations.First(); inst != last; ++inst) {
|
||||
Value value;
|
||||
if (! inst->mAssignments.GetAssignmentFor(mContentVariable, &value)) {
|
||||
NS_ERROR("cannot handle open-ended tag name query");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
rv = VALUE_TO_ICONTENT(value)->GetTag(*getter_AddRefs(tag));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (tag != mTag) {
|
||||
aInstantiations.Erase(inst--);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsContentTagTestNode::GetAncestorVariables(VariableSet& aVariables) const
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
48
content/xul/templates/src/nsContentTagTestNode.h
Normal file
48
content/xul/templates/src/nsContentTagTestNode.h
Normal file
@ -0,0 +1,48 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#ifndef nsContentTagTestNode_h__
|
||||
#define nsContentTagTestNode_h__
|
||||
|
||||
#include "nsRuleNetwork.h"
|
||||
class nsConflictSet;
|
||||
|
||||
class nsContentTagTestNode : public TestNode
|
||||
{
|
||||
public:
|
||||
nsContentTagTestNode(InnerNode* aParent,
|
||||
nsConflictSet& aConflictSet,
|
||||
PRInt32 aContentVariable,
|
||||
nsIAtom* aTag);
|
||||
|
||||
virtual nsresult FilterInstantiations(InstantiationSet& aInstantiations, void* aClosure) const;
|
||||
|
||||
virtual nsresult GetAncestorVariables(VariableSet& aVariables) const;
|
||||
|
||||
protected:
|
||||
nsConflictSet& mConflictSet;
|
||||
PRInt32 mContentVariable;
|
||||
nsCOMPtr<nsIAtom> mTag;
|
||||
};
|
||||
|
||||
#endif // nsContentTagTestNode_h__
|
240
content/xul/templates/src/nsContentTestNode.cpp
Normal file
240
content/xul/templates/src/nsContentTestNode.cpp
Normal file
@ -0,0 +1,240 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#include "nsConflictSet.h"
|
||||
#include "nsContentTestNode.h"
|
||||
#include "nsISupportsArray.h"
|
||||
#include "nsIXULDocument.h"
|
||||
#include "nsIRDFResource.h"
|
||||
#include "nsXULContentUtils.h"
|
||||
|
||||
#include "prlog.h"
|
||||
#ifdef PR_LOGGING
|
||||
extern PRLogModuleInfo* gXULTemplateLog;
|
||||
#endif
|
||||
|
||||
PRBool
|
||||
IsElementContainedBy(nsIContent* aElement, nsIContent* aContainer)
|
||||
{
|
||||
// Make sure that we're actually creating content for the tree
|
||||
// content model that we've been assigned to deal with.
|
||||
|
||||
// Walk up the parent chain from us to the root and
|
||||
// see what we find.
|
||||
if (aElement == aContainer)
|
||||
return PR_TRUE;
|
||||
|
||||
// walk up the tree until you find rootAtom
|
||||
nsCOMPtr<nsIContent> element(do_QueryInterface(aElement));
|
||||
nsCOMPtr<nsIContent> parent;
|
||||
element->GetParent(*getter_AddRefs(parent));
|
||||
element = parent;
|
||||
|
||||
while (element) {
|
||||
if (element.get() == aContainer)
|
||||
return PR_TRUE;
|
||||
|
||||
element->GetParent(*getter_AddRefs(parent));
|
||||
element = parent;
|
||||
}
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsContentTestNode::nsContentTestNode(InnerNode* aParent,
|
||||
nsConflictSet& aConflictSet,
|
||||
nsIXULDocument* aDocument,
|
||||
nsIContent* aRoot,
|
||||
PRInt32 aContentVariable,
|
||||
PRInt32 aIdVariable,
|
||||
nsIAtom* aTag)
|
||||
: TestNode(aParent),
|
||||
mConflictSet(aConflictSet),
|
||||
mDocument(aDocument),
|
||||
mRoot(aRoot),
|
||||
mContentVariable(aContentVariable),
|
||||
mIdVariable(aIdVariable),
|
||||
mTag(aTag)
|
||||
{
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
nsAutoString tag = NS_LITERAL_STRING("(none)");
|
||||
if (mTag)
|
||||
mTag->ToString(tag);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("nsContentTestNode[%p]: parent=%p content-var=%d id-var=%d tag=%s",
|
||||
this, aParent, mContentVariable, mIdVariable,
|
||||
NS_ConvertUCS2toUTF8(tag).get()));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsContentTestNode::FilterInstantiations(InstantiationSet& aInstantiations, void* aClosure) const
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsISupportsArray> elements;
|
||||
rv = NS_NewISupportsArray(getter_AddRefs(elements));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
InstantiationSet::Iterator last = aInstantiations.Last();
|
||||
for (InstantiationSet::Iterator inst = aInstantiations.First(); inst != last; ++inst) {
|
||||
Value contentValue;
|
||||
PRBool hasContentBinding = inst->mAssignments.GetAssignmentFor(mContentVariable, &contentValue);
|
||||
|
||||
Value idValue;
|
||||
PRBool hasIdBinding = inst->mAssignments.GetAssignmentFor(mIdVariable, &idValue);
|
||||
|
||||
if (hasContentBinding && hasIdBinding) {
|
||||
// both are bound, consistency check
|
||||
PRBool consistent = PR_TRUE;
|
||||
|
||||
nsIContent* content = VALUE_TO_ICONTENT(contentValue);
|
||||
|
||||
if (mTag) {
|
||||
// If we're supposed to be checking the tag, do it now.
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
content->GetTag(*getter_AddRefs(tag));
|
||||
|
||||
if (tag != mTag)
|
||||
consistent = PR_FALSE;
|
||||
}
|
||||
|
||||
if (consistent) {
|
||||
nsCOMPtr<nsIRDFResource> resource;
|
||||
nsXULContentUtils::GetElementRefResource(content, getter_AddRefs(resource));
|
||||
|
||||
if (resource.get() != VALUE_TO_IRDFRESOURCE(idValue))
|
||||
consistent = PR_FALSE;
|
||||
}
|
||||
|
||||
if (consistent) {
|
||||
Element* element = new (mConflictSet.GetPool())
|
||||
Element(VALUE_TO_ICONTENT(contentValue));
|
||||
|
||||
if (! element)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
inst->AddSupportingElement(element);
|
||||
}
|
||||
else {
|
||||
aInstantiations.Erase(inst--);
|
||||
}
|
||||
}
|
||||
else if (hasContentBinding) {
|
||||
// the content node is bound, get its id
|
||||
PRBool consistent = PR_TRUE;
|
||||
|
||||
nsIContent* content = VALUE_TO_ICONTENT(contentValue);
|
||||
|
||||
if (mTag) {
|
||||
// If we're supposed to be checking the tag, do it now.
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
content->GetTag(*getter_AddRefs(tag));
|
||||
|
||||
if (tag != mTag)
|
||||
consistent = PR_FALSE;
|
||||
}
|
||||
|
||||
if (consistent) {
|
||||
nsCOMPtr<nsIRDFResource> resource;
|
||||
nsXULContentUtils::GetElementRefResource(content, getter_AddRefs(resource));
|
||||
|
||||
if (resource) {
|
||||
Instantiation newinst = *inst;
|
||||
newinst.AddAssignment(mIdVariable, Value(resource.get()));
|
||||
|
||||
Element* element = new (mConflictSet.GetPool())
|
||||
Element(content);
|
||||
|
||||
if (! element)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
newinst.AddSupportingElement(element);
|
||||
|
||||
aInstantiations.Insert(inst, newinst);
|
||||
}
|
||||
}
|
||||
|
||||
aInstantiations.Erase(inst--);
|
||||
}
|
||||
else if (hasIdBinding) {
|
||||
// the 'id' is bound, find elements in the content tree that match
|
||||
const char* uri;
|
||||
rv = VALUE_TO_IRDFRESOURCE(idValue)->GetValueConst(&uri);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = mDocument->GetElementsForID(NS_ConvertUTF8toUCS2(uri), elements);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
PRUint32 count;
|
||||
rv = elements->Count(&count);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
for (PRInt32 j = PRInt32(count) - 1; j >= 0; --j) {
|
||||
nsISupports* isupports = elements->ElementAt(j);
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(isupports);
|
||||
NS_IF_RELEASE(isupports);
|
||||
|
||||
if (IsElementContainedBy(content, mRoot)) {
|
||||
if (mTag) {
|
||||
// If we've got a tag, check it to ensure
|
||||
// we're consistent.
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
content->GetTag(*getter_AddRefs(tag));
|
||||
|
||||
if (tag != mTag)
|
||||
continue;
|
||||
}
|
||||
|
||||
Instantiation newinst = *inst;
|
||||
newinst.AddAssignment(mContentVariable, Value(content.get()));
|
||||
|
||||
Element* element = new (mConflictSet.GetPool()) Element(content);
|
||||
|
||||
if (! element)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
newinst.AddSupportingElement(element);
|
||||
|
||||
aInstantiations.Insert(inst, newinst);
|
||||
}
|
||||
}
|
||||
|
||||
aInstantiations.Erase(inst--);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsContentTestNode::GetAncestorVariables(VariableSet& aVariables) const
|
||||
{
|
||||
aVariables.Add(mContentVariable);
|
||||
aVariables.Add(mIdVariable);
|
||||
|
||||
return TestNode::GetAncestorVariables(aVariables);
|
||||
}
|
||||
|
97
content/xul/templates/src/nsContentTestNode.h
Normal file
97
content/xul/templates/src/nsContentTestNode.h
Normal file
@ -0,0 +1,97 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#ifndef nsContentTestNode_h__
|
||||
#define nsContentTestNode_h__
|
||||
|
||||
#include "nsRuleNetwork.h"
|
||||
#include "nsFixedSizeAllocator.h"
|
||||
class nsIXULDocument;
|
||||
class nsConflictSet;
|
||||
|
||||
class nsContentTestNode : public TestNode
|
||||
{
|
||||
public:
|
||||
nsContentTestNode(InnerNode* aParent,
|
||||
nsConflictSet& aConflictSet,
|
||||
nsIXULDocument* aDocument,
|
||||
nsIContent* aRoot,
|
||||
PRInt32 aContentVariable,
|
||||
PRInt32 aIdVariable,
|
||||
nsIAtom* aTag);
|
||||
|
||||
virtual nsresult
|
||||
FilterInstantiations(InstantiationSet& aInstantiations, void* aClosure) const;
|
||||
|
||||
virtual nsresult
|
||||
GetAncestorVariables(VariableSet& aVariables) const;
|
||||
|
||||
class Element : public MemoryElement {
|
||||
public:
|
||||
static void* operator new(size_t aSize, nsFixedSizeAllocator& aAllocator) {
|
||||
return aAllocator.Alloc(aSize); }
|
||||
|
||||
static void operator delete(void* aPtr, size_t aSize) {
|
||||
nsFixedSizeAllocator::Free(aPtr, aSize); }
|
||||
|
||||
Element(nsIContent* aContent)
|
||||
: mContent(aContent) {
|
||||
MOZ_COUNT_CTOR(nsContentTestNode::Element); }
|
||||
|
||||
virtual ~Element() { MOZ_COUNT_DTOR(nsContentTestNode::Element); }
|
||||
|
||||
virtual const char* Type() const {
|
||||
return "nsContentTestNode::Element"; }
|
||||
|
||||
virtual PLHashNumber Hash() const {
|
||||
return PLHashNumber(mContent.get()) >> 2; }
|
||||
|
||||
virtual PRBool Equals(const MemoryElement& aElement) const {
|
||||
if (aElement.Type() == Type()) {
|
||||
const Element& element = NS_STATIC_CAST(const Element&, aElement);
|
||||
return mContent == element.mContent;
|
||||
}
|
||||
return PR_FALSE; }
|
||||
|
||||
virtual MemoryElement* Clone(void* aPool) const {
|
||||
return new (*NS_STATIC_CAST(nsFixedSizeAllocator*, aPool))
|
||||
Element(mContent); }
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIContent> mContent;
|
||||
};
|
||||
|
||||
protected:
|
||||
nsConflictSet& mConflictSet;
|
||||
nsIXULDocument* mDocument; // [WEAK] because we know the document will outlive us
|
||||
nsCOMPtr<nsIContent> mRoot;
|
||||
PRInt32 mContentVariable;
|
||||
PRInt32 mIdVariable;
|
||||
nsCOMPtr<nsIAtom> mTag;
|
||||
};
|
||||
|
||||
extern PRBool
|
||||
IsElementContainedBy(nsIContent* aElement, nsIContent* aContainer);
|
||||
|
||||
#endif // nsContentTestNode_h__
|
||||
|
81
content/xul/templates/src/nsInstantiationNode.cpp
Normal file
81
content/xul/templates/src/nsInstantiationNode.cpp
Normal file
@ -0,0 +1,81 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#include "nsInstantiationNode.h"
|
||||
#include "nsTemplateRule.h"
|
||||
#include "nsClusterKeySet.h"
|
||||
#include "nsConflictSet.h"
|
||||
|
||||
#include "prlog.h"
|
||||
#ifdef PR_LOGGING
|
||||
extern PRLogModuleInfo* gXULTemplateLog;
|
||||
#endif
|
||||
|
||||
nsInstantiationNode::nsInstantiationNode(nsConflictSet& aConflictSet,
|
||||
nsTemplateRule* aRule,
|
||||
nsIRDFDataSource* aDataSource)
|
||||
: mConflictSet(aConflictSet),
|
||||
mRule(aRule)
|
||||
{
|
||||
#ifdef PR_LOGGING
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("nsInstantiationNode[%p] rule=%p", this, aRule));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
nsInstantiationNode::~nsInstantiationNode()
|
||||
{
|
||||
delete mRule;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsInstantiationNode::Propogate(const InstantiationSet& aInstantiations, void* aClosure)
|
||||
{
|
||||
// If we get here, we've matched the rule associated with this
|
||||
// node. Extend it with any <bindings> that we might have, add it
|
||||
// to the conflict set, and the set of new <content, member>
|
||||
// pairs.
|
||||
nsClusterKeySet* newkeys = NS_STATIC_CAST(nsClusterKeySet*, aClosure);
|
||||
|
||||
InstantiationSet::ConstIterator last = aInstantiations.Last();
|
||||
for (InstantiationSet::ConstIterator inst = aInstantiations.First(); inst != last; ++inst) {
|
||||
nsAssignmentSet assignments = inst->mAssignments;
|
||||
|
||||
nsTemplateMatch* match = new (mConflictSet.GetPool()) nsTemplateMatch(mRule, *inst, assignments);
|
||||
if (! match)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
mRule->InitBindings(mConflictSet, match);
|
||||
|
||||
mConflictSet.Add(match);
|
||||
|
||||
// Give back our "local" reference. The conflict set will have
|
||||
// taken what it needs.
|
||||
match->Release();
|
||||
|
||||
newkeys->Add(nsClusterKey(*inst, mRule));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
59
content/xul/templates/src/nsInstantiationNode.h
Normal file
59
content/xul/templates/src/nsInstantiationNode.h
Normal file
@ -0,0 +1,59 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#ifndef nsInstantiationNode_h__
|
||||
#define nsInstantiationNode_h__
|
||||
|
||||
#include "nsRuleNetwork.h"
|
||||
class nsIRDFDataSource;
|
||||
class nsConflictSet;
|
||||
class nsTemplateRule;
|
||||
|
||||
/**
|
||||
* A leaf-level node in the rule network. If any instantiations
|
||||
* propogate to this node, then we know we've matched a rule.
|
||||
*/
|
||||
class nsInstantiationNode : public ReteNode
|
||||
{
|
||||
public:
|
||||
nsInstantiationNode(nsConflictSet& aConflictSet,
|
||||
nsTemplateRule* aRule,
|
||||
nsIRDFDataSource* aDataSource);
|
||||
|
||||
~nsInstantiationNode();
|
||||
|
||||
// "downward" propogations
|
||||
virtual nsresult Propogate(const InstantiationSet& aInstantiations, void* aClosure);
|
||||
|
||||
protected:
|
||||
nsConflictSet& mConflictSet;
|
||||
|
||||
/**
|
||||
* The rule that the node instantiates. The instantiation node
|
||||
* assumes ownership of the rule in its ctor, and will destroy
|
||||
* the rule in its dtor.
|
||||
*/
|
||||
nsTemplateRule* mRule;
|
||||
};
|
||||
|
||||
#endif // nsInstantiationNode_h__
|
102
content/xul/templates/src/nsOutlinerRowTestNode.cpp
Normal file
102
content/xul/templates/src/nsOutlinerRowTestNode.cpp
Normal file
@ -0,0 +1,102 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#include "nsOutlinerRowTestNode.h"
|
||||
#include "nsOutlinerRows.h"
|
||||
#include "nsIRDFResource.h"
|
||||
#include "nsXULContentUtils.h"
|
||||
#include "nsConflictSet.h"
|
||||
|
||||
#include "prlog.h"
|
||||
#ifdef PR_LOGGING
|
||||
extern PRLogModuleInfo* gXULTemplateLog;
|
||||
#endif
|
||||
|
||||
nsOutlinerRowTestNode::nsOutlinerRowTestNode(InnerNode* aParent,
|
||||
nsConflictSet& aConflictSet,
|
||||
nsOutlinerRows& aRows,
|
||||
PRInt32 aIdVariable)
|
||||
: TestNode(aParent),
|
||||
mConflictSet(aConflictSet),
|
||||
mRows(aRows),
|
||||
mIdVariable(aIdVariable)
|
||||
{
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("nsOutlinerRowTestNode[%p]: parent=%p id-var=%d",
|
||||
this, aParent, aIdVariable));
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsOutlinerRowTestNode::FilterInstantiations(InstantiationSet& aInstantiations, void* aClosure) const
|
||||
{
|
||||
InstantiationSet::Iterator last = aInstantiations.Last();
|
||||
for (InstantiationSet::Iterator inst = aInstantiations.First(); inst != last; ++inst) {
|
||||
Value idValue;
|
||||
PRBool hasIdBinding =
|
||||
inst->mAssignments.GetAssignmentFor(mIdVariable, &idValue);
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
const char* id = "(unbound)";
|
||||
if (hasIdBinding)
|
||||
VALUE_TO_IRDFRESOURCE(idValue)->GetValueConst(&id);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("nsOutlinerRowTestNode[%p]: FilterInstantiations() id=[%s]",
|
||||
this, id));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (hasIdBinding) {
|
||||
nsIRDFResource* container = VALUE_TO_IRDFRESOURCE(idValue);
|
||||
|
||||
// Is the row in the outliner?
|
||||
if ((container == mRows.GetRootResource()) ||
|
||||
(mRows.Find(mConflictSet, container) != mRows.Last())) {
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG, (" => passed"));
|
||||
Element* element = new (mConflictSet.GetPool())
|
||||
Element(container);
|
||||
|
||||
if (! element)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
inst->AddSupportingElement(element);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG, (" => failed"));
|
||||
aInstantiations.Erase(inst--);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsOutlinerRowTestNode::GetAncestorVariables(VariableSet& aVariables) const
|
||||
{
|
||||
aVariables.Add(mIdVariable);
|
||||
return TestNode::GetAncestorVariables(aVariables);
|
||||
}
|
90
content/xul/templates/src/nsOutlinerRowTestNode.h
Normal file
90
content/xul/templates/src/nsOutlinerRowTestNode.h
Normal file
@ -0,0 +1,90 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#ifndef nsOutlinerRowTestNode_h__
|
||||
#define nsOutlinerRowTestNode_h__
|
||||
|
||||
#include "nsFixedSizeAllocator.h"
|
||||
#include "nsRuleNetwork.h"
|
||||
#include "nsIRDFResource.h"
|
||||
class nsConflictSet;
|
||||
class nsOutlinerRows;
|
||||
|
||||
class nsOutlinerRowTestNode : public TestNode
|
||||
{
|
||||
public:
|
||||
enum { kRoot = -1 };
|
||||
|
||||
nsOutlinerRowTestNode(InnerNode* aParent,
|
||||
nsConflictSet& aConflictSet,
|
||||
nsOutlinerRows& aRows,
|
||||
PRInt32 aIdVariable);
|
||||
|
||||
virtual nsresult
|
||||
FilterInstantiations(InstantiationSet& aInstantiations, void* aClosure) const;
|
||||
|
||||
virtual nsresult
|
||||
GetAncestorVariables(VariableSet& aVariables) const;
|
||||
|
||||
class Element : public MemoryElement {
|
||||
public:
|
||||
static void* operator new(size_t aSize, nsFixedSizeAllocator& aAllocator) {
|
||||
return aAllocator.Alloc(aSize); }
|
||||
|
||||
static void operator delete(void* aPtr, size_t aSize) {
|
||||
nsFixedSizeAllocator::Free(aPtr, aSize); }
|
||||
|
||||
Element(nsIRDFResource* aResource)
|
||||
: mResource(aResource) {
|
||||
MOZ_COUNT_CTOR(nsOutlinerRowTestNode::Element); }
|
||||
|
||||
virtual ~Element() { MOZ_COUNT_DTOR(nsOutlinerRowTestNode::Element); }
|
||||
|
||||
virtual const char* Type() const {
|
||||
return "nsOutlinerRowTestNode::Element"; }
|
||||
|
||||
virtual PLHashNumber Hash() const {
|
||||
return PLHashNumber(mResource.get()) >> 2; }
|
||||
|
||||
virtual PRBool Equals(const MemoryElement& aElement) const {
|
||||
if (aElement.Type() == Type()) {
|
||||
const Element& element = NS_STATIC_CAST(const Element&, aElement);
|
||||
return mResource == element.mResource;
|
||||
}
|
||||
return PR_FALSE; }
|
||||
|
||||
virtual MemoryElement* Clone(void* aPool) const {
|
||||
return new (*NS_STATIC_CAST(nsFixedSizeAllocator*, aPool))
|
||||
Element(mResource); }
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIRDFResource> mResource;
|
||||
};
|
||||
|
||||
protected:
|
||||
nsConflictSet& mConflictSet;
|
||||
nsOutlinerRows& mRows;
|
||||
PRInt32 mIdVariable;
|
||||
};
|
||||
|
||||
#endif // nsOutlinerRowTestNode_h__
|
412
content/xul/templates/src/nsOutlinerRows.cpp
Normal file
412
content/xul/templates/src/nsOutlinerRows.cpp
Normal file
@ -0,0 +1,412 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#include "nsOutlinerRows.h"
|
||||
#include "nsTemplateMatch.h"
|
||||
#include "nsTemplateRule.h"
|
||||
|
||||
nsOutlinerRows::Subtree*
|
||||
nsOutlinerRows::EnsureSubtreeFor(Subtree* aParent,
|
||||
PRInt32 aChildIndex)
|
||||
{
|
||||
Subtree* subtree = GetSubtreeFor(aParent, aChildIndex);
|
||||
|
||||
if (! subtree) {
|
||||
subtree = aParent->mRows[aChildIndex].mSubtree = new Subtree(aParent);
|
||||
InvalidateCachedRow();
|
||||
}
|
||||
|
||||
return subtree;
|
||||
}
|
||||
|
||||
nsOutlinerRows::Subtree*
|
||||
nsOutlinerRows::GetSubtreeFor(const Subtree* aParent,
|
||||
PRInt32 aChildIndex,
|
||||
PRInt32* aSubtreeSize)
|
||||
{
|
||||
NS_PRECONDITION(aParent, "no parent");
|
||||
NS_PRECONDITION(aChildIndex >= 0, "bad child index");
|
||||
|
||||
Subtree* result = nsnull;
|
||||
|
||||
if (aChildIndex < aParent->mCount)
|
||||
result = aParent->mRows[aChildIndex].mSubtree;
|
||||
|
||||
if (aSubtreeSize)
|
||||
*aSubtreeSize = result ? result->mSubtreeSize : 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
nsOutlinerRows::RemoveSubtreeFor(Subtree* aParent, PRInt32 aChildIndex)
|
||||
{
|
||||
NS_PRECONDITION(aParent, "no parent");
|
||||
NS_PRECONDITION(aChildIndex >= 0 && aChildIndex < aParent->mCount, "bad child index");
|
||||
|
||||
Row& row = aParent->mRows[aChildIndex];
|
||||
|
||||
if (row.mSubtree) {
|
||||
PRInt32 subtreeSize = row.mSubtree->GetSubtreeSize();
|
||||
|
||||
delete row.mSubtree;
|
||||
row.mSubtree = nsnull;
|
||||
|
||||
for (Subtree* subtree = aParent; subtree != nsnull; subtree = subtree->mParent)
|
||||
subtree->mSubtreeSize -= subtreeSize;
|
||||
}
|
||||
|
||||
InvalidateCachedRow();
|
||||
}
|
||||
|
||||
nsOutlinerRows::iterator
|
||||
nsOutlinerRows::First()
|
||||
{
|
||||
iterator result;
|
||||
Subtree* current = &mRoot;
|
||||
while (current && current->Count()) {
|
||||
result.Push(current, 0);
|
||||
current = GetSubtreeFor(current, 0);
|
||||
}
|
||||
result.SetRowIndex(0);
|
||||
return result;
|
||||
}
|
||||
|
||||
nsOutlinerRows::iterator
|
||||
nsOutlinerRows::Last()
|
||||
{
|
||||
iterator result;
|
||||
|
||||
// Build up a path along the rightmost edge of the tree
|
||||
Subtree* current = &mRoot;
|
||||
while (current && current->Count()) {
|
||||
result.Push(current, current->Count() - 1);
|
||||
current = GetSubtreeFor(current, current->Count() - 1);
|
||||
}
|
||||
|
||||
// Now, at the bottom rightmost leaf, advance us one off the end.
|
||||
result.mLink[result.mTop].mChildIndex++;
|
||||
|
||||
// Our row index will be the size of the root subree, plus one.
|
||||
result.SetRowIndex(mRoot.GetSubtreeSize() + 1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
nsOutlinerRows::iterator
|
||||
nsOutlinerRows::operator[](PRInt32 aRow)
|
||||
{
|
||||
// See if we're just lucky, and end up with something
|
||||
// nearby. (This tends to happen a lot due to the way that we get
|
||||
// asked for rows n' stuff.)
|
||||
PRInt32 last = mLastRow.GetRowIndex();
|
||||
if (last != -1) {
|
||||
if (aRow == last)
|
||||
return mLastRow;
|
||||
else if (last + 1 == aRow)
|
||||
return ++mLastRow;
|
||||
else if (last - 1 == aRow)
|
||||
return --mLastRow;
|
||||
}
|
||||
|
||||
// Nope. Construct a path to the specified index. This is a little
|
||||
// bit better than O(n), because we can skip over subtrees. (So it
|
||||
// ends up being approximately linear in the subtree size, instead
|
||||
// of the entire view size. But, most of the time, big views are
|
||||
// flat. Oh well.)
|
||||
iterator result;
|
||||
Subtree* current = &mRoot;
|
||||
|
||||
PRInt32 index = 0;
|
||||
result.SetRowIndex(aRow);
|
||||
|
||||
do {
|
||||
PRInt32 subtreeSize;
|
||||
Subtree* subtree = GetSubtreeFor(current, index, &subtreeSize);
|
||||
|
||||
if (subtreeSize >= aRow) {
|
||||
result.Push(current, index);
|
||||
current = subtree;
|
||||
index = 0;
|
||||
--aRow;
|
||||
}
|
||||
else {
|
||||
++index;
|
||||
aRow -= subtreeSize + 1;
|
||||
}
|
||||
} while (aRow >= 0);
|
||||
|
||||
mLastRow = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
nsOutlinerRows::iterator
|
||||
nsOutlinerRows::Find(nsConflictSet& aConflictSet, nsIRDFResource* aMember)
|
||||
{
|
||||
// XXX Mmm, scan through the rows one-by-one...
|
||||
iterator last = Last();
|
||||
iterator iter;
|
||||
|
||||
for (iter = First(); iter != last; ++iter) {
|
||||
nsTemplateMatch* match = iter->mMatch;
|
||||
|
||||
Value val;
|
||||
match->GetAssignmentFor(aConflictSet, match->mRule->GetMemberVariable(), &val);
|
||||
|
||||
if (VALUE_TO_IRDFRESOURCE(val) == aMember)
|
||||
break;
|
||||
}
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
void
|
||||
nsOutlinerRows::Clear()
|
||||
{
|
||||
mRoot.Clear();
|
||||
InvalidateCachedRow();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
// nsOutlinerRows::Subtree
|
||||
//
|
||||
|
||||
nsOutlinerRows::Subtree::~Subtree()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void
|
||||
nsOutlinerRows::Subtree::Clear()
|
||||
{
|
||||
for (PRInt32 i = mCount - 1; i >= 0; --i)
|
||||
delete mRows[i].mSubtree;
|
||||
|
||||
delete[] mRows;
|
||||
|
||||
mRows = nsnull;
|
||||
mCount = mCapacity = 0;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsOutlinerRows::Subtree::InsertRowAt(nsTemplateMatch* aMatch, PRInt32 aIndex)
|
||||
{
|
||||
if (mCount >= mCapacity || aIndex >= mCapacity) {
|
||||
PRInt32 newCapacity = NS_MAX(mCapacity * 2, aIndex + 1);
|
||||
Row* newRows = new Row[newCapacity];
|
||||
if (! newRows)
|
||||
return PR_FALSE;
|
||||
|
||||
for (PRInt32 i = mCount - 1; i >= 0; --i)
|
||||
newRows[i] = mRows[i];
|
||||
|
||||
delete[] mRows;
|
||||
|
||||
mRows = newRows;
|
||||
mCapacity = newCapacity;
|
||||
}
|
||||
|
||||
for (PRInt32 i = mCount - 1; i >= aIndex; --i)
|
||||
mRows[i + 1] = mRows[i];
|
||||
|
||||
mRows[aIndex].mMatch = aMatch;
|
||||
mRows[aIndex].mSubtree = nsnull;
|
||||
++mCount;
|
||||
|
||||
for (Subtree* subtree = this; subtree != nsnull; subtree = subtree->mParent)
|
||||
++subtree->mSubtreeSize;
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
nsOutlinerRows::Subtree::RemoveRowAt(PRInt32 aIndex)
|
||||
{
|
||||
NS_PRECONDITION(aIndex >= 0 && aIndex < Count(), "bad index");
|
||||
if (aIndex < 0 || aIndex >= Count())
|
||||
return;
|
||||
|
||||
PRInt32 subtreeSize = mRows[aIndex].mSubtree
|
||||
? mRows[aIndex].mSubtree->GetSubtreeSize()
|
||||
: 0;
|
||||
|
||||
++subtreeSize;
|
||||
|
||||
delete mRows[aIndex].mSubtree;
|
||||
|
||||
for (PRInt32 i = aIndex + 1; i < mCount; ++i)
|
||||
mRows[i - 1] = mRows[i];
|
||||
|
||||
--mCount;
|
||||
|
||||
for (Subtree* subtree = this; subtree != nsnull; subtree = subtree->mParent)
|
||||
subtree->mSubtreeSize -= subtreeSize;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
// nsOutlinerRows::iterator
|
||||
//
|
||||
|
||||
nsOutlinerRows::iterator::iterator(const iterator& aIterator)
|
||||
: mTop(aIterator.mTop),
|
||||
mRowIndex(aIterator.mRowIndex)
|
||||
{
|
||||
for (PRInt32 i = mTop; i >= 0; --i)
|
||||
mLink[i] = aIterator.mLink[i];
|
||||
}
|
||||
|
||||
nsOutlinerRows::iterator&
|
||||
nsOutlinerRows::iterator::operator=(const iterator& aIterator)
|
||||
{
|
||||
mTop = aIterator.mTop;
|
||||
mRowIndex = aIterator.mRowIndex;
|
||||
for (PRInt32 i = mTop; i >= 0; --i)
|
||||
mLink[i] = aIterator.mLink[i];
|
||||
return *this;
|
||||
}
|
||||
|
||||
void
|
||||
nsOutlinerRows::iterator::Push(Subtree* aParent, PRInt32 aChildIndex)
|
||||
{
|
||||
if (mTop < kMaxDepth - 1) {
|
||||
++mTop;
|
||||
mLink[mTop].mParent = aParent;
|
||||
mLink[mTop].mChildIndex = aChildIndex;
|
||||
}
|
||||
else
|
||||
NS_ERROR("overflow");
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsOutlinerRows::iterator::operator==(const iterator& aIterator) const
|
||||
{
|
||||
if (mTop != aIterator.mTop)
|
||||
return PR_FALSE;
|
||||
|
||||
if (mTop == -1)
|
||||
return PR_TRUE;
|
||||
|
||||
return PRBool(mLink[mTop] == aIterator.mLink[mTop]);
|
||||
}
|
||||
|
||||
void
|
||||
nsOutlinerRows::iterator::Next()
|
||||
{
|
||||
NS_PRECONDITION(mTop >= 0, "cannot increment an uninitialized iterator");
|
||||
|
||||
// Increment the absolute row index
|
||||
++mRowIndex;
|
||||
|
||||
Link& top = mLink[mTop];
|
||||
|
||||
// Is there a child subtree? If so, descend into the child
|
||||
// subtree.
|
||||
Subtree* subtree = top.GetRow().mSubtree;
|
||||
|
||||
if (subtree && subtree->Count()) {
|
||||
Push(subtree, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Have we exhausted the current subtree?
|
||||
if (top.mChildIndex >= top.mParent->Count() - 1) {
|
||||
// Yep. See if we've just iterated path the last element in
|
||||
// the tree, period. Walk back up the stack, looking for any
|
||||
// unfinished subtrees.
|
||||
PRInt32 unfinished;
|
||||
for (unfinished = mTop - 1; unfinished >= 0; --unfinished) {
|
||||
const Link& link = mLink[unfinished];
|
||||
if (link.mChildIndex < link.mParent->Count() - 1)
|
||||
break;
|
||||
}
|
||||
|
||||
// If there are no unfinished subtrees in the stack, then this
|
||||
// iterator is exhausted. Leave it in the same state that
|
||||
// Last() does.
|
||||
if (unfinished < 0)
|
||||
return;
|
||||
|
||||
// Otherwise, we ran off the end of one of the inner
|
||||
// subtrees. Pop up to the next unfinished level in the stack.
|
||||
mTop = unfinished;
|
||||
}
|
||||
|
||||
// Advance to the next child in this subtree
|
||||
++(mLink[mTop].mChildIndex);
|
||||
}
|
||||
|
||||
void
|
||||
nsOutlinerRows::iterator::Prev()
|
||||
{
|
||||
NS_PRECONDITION(mTop >= 0, "cannot increment an uninitialized iterator");
|
||||
|
||||
// Decrement the absolute row index
|
||||
--mRowIndex;
|
||||
|
||||
// Move to the previous child in this subtree
|
||||
--(mLink[mTop].mChildIndex);
|
||||
|
||||
// Have we exhausted the current subtree?
|
||||
if (mLink[mTop].mChildIndex < 0) {
|
||||
// Yep. See if we've just iterated back to the first element
|
||||
// in the tree, period. Walk back up the stack, looking for
|
||||
// any unfinished subtrees.
|
||||
PRInt32 unfinished;
|
||||
for (unfinished = mTop - 1; unfinished >= 0; --unfinished) {
|
||||
const Link& link = mLink[unfinished];
|
||||
if (link.mChildIndex >= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
// If there are no unfinished subtrees in the stack, then this
|
||||
// iterator is exhausted. Leave it in the same state that
|
||||
// First() does.
|
||||
if (unfinished < 0)
|
||||
return;
|
||||
|
||||
// Otherwise, we ran off the end of one of the inner
|
||||
// subtrees. Pop up to the next unfinished level in the stack.
|
||||
mTop = unfinished;
|
||||
return;
|
||||
}
|
||||
|
||||
// Is there a child subtree immediately prior to our current
|
||||
// position? If so, descend into it, grovelling down to the
|
||||
// deepest, rightmost left edge.
|
||||
Subtree* parent = mLink[mTop].GetParent();
|
||||
PRInt32 index = mLink[mTop].GetChildIndex();
|
||||
|
||||
Subtree* subtree = (*parent)[index].mSubtree;
|
||||
|
||||
if (subtree && subtree->Count()) {
|
||||
do {
|
||||
index = subtree->Count() - 1;
|
||||
Push(subtree, index);
|
||||
|
||||
parent = subtree;
|
||||
subtree = (*parent)[index].mSubtree;
|
||||
} while (subtree && subtree->Count());
|
||||
}
|
||||
}
|
415
content/xul/templates/src/nsOutlinerRows.h
Normal file
415
content/xul/templates/src/nsOutlinerRows.h
Normal file
@ -0,0 +1,415 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#ifndef nsOutlinerRows_h__
|
||||
#define nsOutlinerRows_h__
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIRDFResource.h"
|
||||
#include "pldhash.h"
|
||||
class nsConflictSet;
|
||||
class nsTemplateMatch;
|
||||
|
||||
/**
|
||||
* This class maintains the state of the XUL outliner builder's
|
||||
* rows. It maps a row number to the nsTemplateMatch object that
|
||||
* populates the row.
|
||||
*/
|
||||
class nsOutlinerRows
|
||||
{
|
||||
public:
|
||||
enum Direction { eDirection_Forwards = +1, eDirection_Backwards = -1 };
|
||||
|
||||
class Subtree;
|
||||
|
||||
/**
|
||||
* A row in the outliner. Contains the match that the row
|
||||
* corresponds to, and a pointer to the row's subtree, if there
|
||||
* are any.
|
||||
*/
|
||||
struct Row {
|
||||
nsTemplateMatch* mMatch;
|
||||
Subtree* mSubtree; // XXX eventually move to hashtable
|
||||
};
|
||||
|
||||
/**
|
||||
* A subtree in the outliner. A subtree contains rows, which may
|
||||
* contain other subtrees.
|
||||
*/
|
||||
class Subtree {
|
||||
protected:
|
||||
friend class nsOutlinerRows; // so that it can access members, for now
|
||||
|
||||
/**
|
||||
* The parent subtree; null if we're the root
|
||||
*/
|
||||
Subtree* mParent;
|
||||
|
||||
/**
|
||||
* The number of immediate children in this subtree
|
||||
*/
|
||||
PRInt32 mCount;
|
||||
|
||||
/**
|
||||
* The capacity of the subtree
|
||||
*/
|
||||
PRInt32 mCapacity;
|
||||
|
||||
/**
|
||||
* The total number of rows in this subtree, recursively
|
||||
* including child subtrees.
|
||||
*/
|
||||
PRInt32 mSubtreeSize;
|
||||
|
||||
/**
|
||||
* The array of rows in the subtree
|
||||
*/
|
||||
Row* mRows;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates a subtree with the specified parent.
|
||||
*/
|
||||
Subtree(Subtree* aParent)
|
||||
: mParent(aParent),
|
||||
mCount(0),
|
||||
mCapacity(0),
|
||||
mSubtreeSize(0),
|
||||
mRows(nsnull) {}
|
||||
|
||||
~Subtree();
|
||||
|
||||
/**
|
||||
* Return the number of immediate child rows in the subtree
|
||||
*/
|
||||
PRInt32 Count() const { return mCount; }
|
||||
|
||||
/**
|
||||
* Return the number of rows in this subtree, as well as all
|
||||
* the subtrees it contains.
|
||||
*/
|
||||
PRInt32 GetSubtreeSize() const { return mSubtreeSize; }
|
||||
|
||||
/**
|
||||
* Retrieve the immediate child row at the specified index.
|
||||
*/
|
||||
const Row& operator[](PRInt32 aIndex) const {
|
||||
NS_PRECONDITION(aIndex >= 0 && aIndex < mCount, "bad index");
|
||||
return mRows[aIndex]; }
|
||||
|
||||
/**
|
||||
* Retrieve the immediate row at the specified index.
|
||||
*/
|
||||
Row& operator[](PRInt32 aIndex) {
|
||||
NS_PRECONDITION(aIndex >= 0 && aIndex < mCount, "bad index");
|
||||
return mRows[aIndex]; }
|
||||
|
||||
/**
|
||||
* Remove all rows from the subtree.
|
||||
*/
|
||||
void Clear();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Insert an immediate child row at the specified index.
|
||||
*/
|
||||
PRBool InsertRowAt(nsTemplateMatch* aMatch, PRInt32 aIndex);
|
||||
|
||||
/**
|
||||
* Remove an immediate child row from the specified index.
|
||||
*/
|
||||
void RemoveRowAt(PRInt32 aChildIndex);
|
||||
};
|
||||
|
||||
friend class Subtree;
|
||||
|
||||
enum { kMaxDepth = 32 };
|
||||
|
||||
protected:
|
||||
/**
|
||||
* A link in the path through the view's tree.
|
||||
*/
|
||||
struct Link {
|
||||
Subtree* mParent;
|
||||
PRInt32 mChildIndex;
|
||||
|
||||
Link&
|
||||
operator=(const Link& aLink) {
|
||||
mParent = aLink.mParent;
|
||||
mChildIndex = aLink.mChildIndex;
|
||||
return *this; }
|
||||
|
||||
PRBool
|
||||
operator==(const Link& aLink) const {
|
||||
return (mParent == aLink.mParent)
|
||||
&& (mChildIndex == aLink.mChildIndex); }
|
||||
|
||||
Subtree* GetParent() { return mParent; }
|
||||
const Subtree* GetParent() const { return mParent; }
|
||||
|
||||
PRInt32 GetChildIndex() const { return mChildIndex; }
|
||||
|
||||
Row& GetRow() { return (*mParent)[mChildIndex]; }
|
||||
const Row& GetRow() const { return (*mParent)[mChildIndex]; }
|
||||
};
|
||||
|
||||
public:
|
||||
class iterator;
|
||||
friend class iterator;
|
||||
|
||||
/**
|
||||
* An iterator that can be used to traverse the outliner view.
|
||||
*/
|
||||
class iterator {
|
||||
protected:
|
||||
PRInt32 mTop;
|
||||
PRInt32 mRowIndex;
|
||||
Link mLink[kMaxDepth];
|
||||
|
||||
void Next();
|
||||
void Prev();
|
||||
|
||||
friend class nsOutlinerRows; // so nsOutlinerRows can initialize us
|
||||
|
||||
/**
|
||||
* Used by PathTo() to initialize an iterator.
|
||||
*/
|
||||
void Push(Subtree* aParent, PRInt32 aChildIndex);
|
||||
|
||||
/**
|
||||
* Used by PathTo() to initialize an iterator.
|
||||
*/
|
||||
void SetRowIndex(PRInt32 aRowIndex) { mRowIndex = aRowIndex; }
|
||||
|
||||
public:
|
||||
iterator() : mTop(-1), mRowIndex(-1) {}
|
||||
|
||||
iterator(const iterator& aIterator);
|
||||
iterator& operator=(const iterator& aIterator);
|
||||
|
||||
PRBool operator==(const iterator& aIterator) const;
|
||||
|
||||
PRBool operator!=(const iterator& aIterator) const {
|
||||
return !aIterator.operator==(*this); }
|
||||
|
||||
const Row& operator*() const { return mLink[mTop].GetRow(); }
|
||||
Row& operator*() { return mLink[mTop].GetRow(); }
|
||||
|
||||
const Row* operator->() const { return &(mLink[mTop].GetRow()); }
|
||||
Row* operator->() { return &(mLink[mTop].GetRow()); }
|
||||
|
||||
iterator& operator++() { Next(); return *this; }
|
||||
iterator operator++(int) { iterator temp(*this); Next(); return temp; }
|
||||
iterator& operator--() { Prev(); return *this; }
|
||||
iterator operator--(int) { iterator temp(*this); Prev(); return temp; }
|
||||
|
||||
/**
|
||||
* Return the current parent link
|
||||
*/
|
||||
Subtree* GetParent() {
|
||||
return mLink[mTop].GetParent(); }
|
||||
|
||||
const Subtree* GetParent() const {
|
||||
return mLink[mTop].GetParent(); }
|
||||
|
||||
/**
|
||||
* Return the current child index
|
||||
*/
|
||||
PRInt32 GetChildIndex() const {
|
||||
return mLink[mTop].GetChildIndex(); }
|
||||
|
||||
/**
|
||||
* Return the depth of the path the iterator is maintaining
|
||||
* into the tree.
|
||||
*/
|
||||
PRInt32 GetDepth() const { return mTop + 1; }
|
||||
|
||||
/**
|
||||
* Return the current row index of the iterator
|
||||
*/
|
||||
PRInt32 GetRowIndex() const { return mRowIndex; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve the first element in the view
|
||||
*/
|
||||
iterator First();
|
||||
|
||||
/**
|
||||
* Retrieve (one past) the last element in the view
|
||||
*/
|
||||
iterator Last();
|
||||
|
||||
/**
|
||||
* Find the row that contains the match with the specified member
|
||||
* resource.
|
||||
*/
|
||||
iterator Find(nsConflictSet& aConflictSet, nsIRDFResource* aMember);
|
||||
|
||||
/**
|
||||
* Retrieve the ith element in the view
|
||||
*/
|
||||
iterator operator[](PRInt32 aIndex);
|
||||
|
||||
nsOutlinerRows() : mRoot(nsnull), mRootResource(nsnull) {}
|
||||
~nsOutlinerRows() {}
|
||||
|
||||
/**
|
||||
* Ensure that a child subtree exists within the specified parent
|
||||
* at the specified child index within the parent. (In other
|
||||
* words, create a subtree if one doesn't already exist.)
|
||||
*/
|
||||
Subtree*
|
||||
EnsureSubtreeFor(Subtree* aParent, PRInt32 aChildIndex);
|
||||
|
||||
/**
|
||||
* Ensure that a child subtree exists at the iterator's position.
|
||||
*/
|
||||
Subtree*
|
||||
EnsureSubtreeFor(iterator& aIterator) {
|
||||
return EnsureSubtreeFor(aIterator.GetParent(),
|
||||
aIterator.GetChildIndex()); }
|
||||
|
||||
/**
|
||||
* Get the child subtree for the specified parent at the specified
|
||||
* child index. Optionally return the child subtree's size. Will
|
||||
* return `null' if no subtree exists.
|
||||
*/
|
||||
Subtree*
|
||||
GetSubtreeFor(const Subtree* aParent,
|
||||
PRInt32 aChildIndex,
|
||||
PRInt32* aSubtreeSize = nsnull);
|
||||
|
||||
/**
|
||||
* Retrieve the size of the subtree within the specified parent.
|
||||
*/
|
||||
PRInt32
|
||||
GetSubtreeSizeFor(const Subtree* aParent,
|
||||
PRInt32 aChildIndex) {
|
||||
PRInt32 size;
|
||||
GetSubtreeFor(aParent, aChildIndex, &size);
|
||||
return size; }
|
||||
|
||||
/**
|
||||
* Retrieve the size of the subtree within the specified parent.
|
||||
*/
|
||||
PRInt32
|
||||
GetSubtreeSizeFor(const iterator& aIterator) {
|
||||
PRInt32 size;
|
||||
GetSubtreeFor(aIterator.GetParent(), aIterator.GetChildIndex(), &size);
|
||||
return size; }
|
||||
|
||||
/**
|
||||
* Remove the specified subtree for a row, leaving the row itself
|
||||
* intact.
|
||||
*/
|
||||
void
|
||||
RemoveSubtreeFor(Subtree* aParent, PRInt32 aChildIndex);
|
||||
|
||||
/**
|
||||
* Remove the specified subtree for a row, leaving the row itself
|
||||
* intact.
|
||||
*/
|
||||
void
|
||||
RemoveSubtreeFor(iterator& aIterator) {
|
||||
RemoveSubtreeFor(aIterator.GetParent(), aIterator.GetChildIndex()); }
|
||||
|
||||
/**
|
||||
* Remove the specified row from the view
|
||||
*/
|
||||
void
|
||||
RemoveRowAt(iterator& aIterator) {
|
||||
iterator temp = aIterator++;
|
||||
Subtree* parent = temp.GetParent();
|
||||
parent->RemoveRowAt(temp.GetChildIndex());
|
||||
InvalidateCachedRow(); }
|
||||
|
||||
/**
|
||||
* Insert a new match into the view
|
||||
*/
|
||||
void
|
||||
InsertRowAt(nsTemplateMatch* aMatch, Subtree* aSubtree, PRInt32 aChildIndex) {
|
||||
aSubtree->InsertRowAt(aMatch, aChildIndex);
|
||||
InvalidateCachedRow(); }
|
||||
|
||||
/**
|
||||
* Raw access to the rows; e.g., for sorting.
|
||||
*/
|
||||
Row*
|
||||
GetRowsFor(Subtree* aSubtree) { return aSubtree->mRows; }
|
||||
|
||||
/**
|
||||
* Remove all of the rows
|
||||
*/
|
||||
void Clear();
|
||||
|
||||
/**
|
||||
* Return the total number of rows in the outliner view.
|
||||
*/
|
||||
PRInt32 Count() const { return mRoot.GetSubtreeSize(); }
|
||||
|
||||
/**
|
||||
* Retrieve the root subtree
|
||||
*/
|
||||
Subtree* GetRoot() { return &mRoot; }
|
||||
|
||||
/**
|
||||
* Set the root resource for the view
|
||||
*/
|
||||
void SetRootResource(nsIRDFResource* aResource) {
|
||||
mRootResource = aResource; }
|
||||
|
||||
/**
|
||||
* Retrieve hte root resource for the view
|
||||
*/
|
||||
nsIRDFResource* GetRootResource() {
|
||||
return mRootResource.get(); }
|
||||
|
||||
/**
|
||||
* Invalidate the cached row; e.g., because the view has changed
|
||||
* in a way that would corrupt the iterator.
|
||||
*/
|
||||
void
|
||||
InvalidateCachedRow() { mLastRow = iterator(); }
|
||||
|
||||
protected:
|
||||
/**
|
||||
* The root subtree.
|
||||
*/
|
||||
Subtree mRoot;
|
||||
|
||||
/**
|
||||
* The root resource for the view
|
||||
*/
|
||||
nsCOMPtr<nsIRDFResource> mRootResource;
|
||||
|
||||
/**
|
||||
* The last row that was asked for by operator[]. By remembering
|
||||
* this, we can usually avoid the O(n) search through the row
|
||||
* array to find the row at the specified index.
|
||||
*/
|
||||
iterator mLastRow;
|
||||
};
|
||||
|
||||
|
||||
#endif // nsOutlinerRows_h__
|
327
content/xul/templates/src/nsRDFConInstanceTestNode.cpp
Normal file
327
content/xul/templates/src/nsRDFConInstanceTestNode.cpp
Normal file
@ -0,0 +1,327 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#include "nsConflictSet.h"
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIRDFContainer.h"
|
||||
#include "nsIRDFContainerUtils.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsRDFCID.h"
|
||||
#include "nsRDFConInstanceTestNode.h"
|
||||
#include "nsResourceSet.h"
|
||||
|
||||
#include "prlog.h"
|
||||
#ifdef PR_LOGGING
|
||||
#include "nsXULContentUtils.h"
|
||||
extern PRLogModuleInfo* gXULTemplateLog;
|
||||
|
||||
static const char*
|
||||
TestToString(nsRDFConInstanceTestNode::Test aTest) {
|
||||
switch (aTest) {
|
||||
case nsRDFConInstanceTestNode::eFalse: return "false";
|
||||
case nsRDFConInstanceTestNode::eTrue: return "true";
|
||||
case nsRDFConInstanceTestNode::eDontCare: return "dontcare";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
#endif
|
||||
|
||||
nsRDFConInstanceTestNode::nsRDFConInstanceTestNode(InnerNode* aParent,
|
||||
nsConflictSet& aConflictSet,
|
||||
nsIRDFDataSource* aDataSource,
|
||||
const nsResourceSet& aMembershipProperties,
|
||||
PRInt32 aContainerVariable,
|
||||
Test aContainer,
|
||||
Test aEmpty)
|
||||
: nsRDFTestNode(aParent),
|
||||
mConflictSet(aConflictSet),
|
||||
mDataSource(aDataSource),
|
||||
mMembershipProperties(aMembershipProperties),
|
||||
mContainerVariable(aContainerVariable),
|
||||
mContainer(aContainer),
|
||||
mEmpty(aEmpty)
|
||||
{
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
nsCAutoString props;
|
||||
|
||||
nsResourceSet::ConstIterator last = aMembershipProperties.Last();
|
||||
nsResourceSet::ConstIterator first = aMembershipProperties.First();
|
||||
nsResourceSet::ConstIterator iter;
|
||||
|
||||
for (iter = first; iter != last; ++iter) {
|
||||
if (iter != first)
|
||||
props += " ";
|
||||
|
||||
const char* str;
|
||||
iter->GetValueConst(&str);
|
||||
|
||||
props += str;
|
||||
}
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("nsRDFConInstanceTestNode[%p]: parent=%p member-props=(%s) container-var=%d container=%s empty=%s",
|
||||
this,
|
||||
aParent,
|
||||
props.get(),
|
||||
mContainerVariable,
|
||||
TestToString(aContainer),
|
||||
TestToString(aEmpty)));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsRDFConInstanceTestNode::FilterInstantiations(InstantiationSet& aInstantiations, void* aClosure) const
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIRDFContainerUtils> rdfc
|
||||
= do_GetService("@mozilla.org/rdf/container-utils;1");
|
||||
|
||||
if (! rdfc)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
InstantiationSet::Iterator last = aInstantiations.Last();
|
||||
for (InstantiationSet::Iterator inst = aInstantiations.First(); inst != last; ++inst) {
|
||||
Value value;
|
||||
if (! inst->mAssignments.GetAssignmentFor(mContainerVariable, &value)) {
|
||||
NS_ERROR("can't do unbounded container testing");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
const char* container;
|
||||
VALUE_TO_IRDFRESOURCE(value)->GetValueConst(&container);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("nsRDFConInstanceTestNode[%p]::FilterInstantiations() container=[%s]",
|
||||
this, container));
|
||||
}
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIRDFContainer> rdfcontainer;
|
||||
|
||||
PRBool isRDFContainer;
|
||||
rv = rdfc->IsContainer(mDataSource, VALUE_TO_IRDFRESOURCE(value), &isRDFContainer);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// If they've asked us to test for emptiness, do that first
|
||||
// because it doesn't require us to create any enumerators.
|
||||
if (mEmpty != eDontCare) {
|
||||
Test empty;
|
||||
|
||||
if (isRDFContainer) {
|
||||
// It's an RDF container. Use the container utilities
|
||||
// to deduce what's in it.
|
||||
//
|
||||
// XXX should cache the factory
|
||||
rdfcontainer = do_CreateInstance("@mozilla.org/rdf/container;1", &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = rdfcontainer->Init(mDataSource, VALUE_TO_IRDFRESOURCE(value));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRInt32 count;
|
||||
rv = rdfcontainer->GetCount(&count);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
empty = (count == 0) ? eTrue : eFalse;
|
||||
}
|
||||
else {
|
||||
empty = eTrue;
|
||||
|
||||
for (nsResourceSet::ConstIterator property = mMembershipProperties.First();
|
||||
property != mMembershipProperties.Last();
|
||||
++property) {
|
||||
nsCOMPtr<nsIRDFNode> target;
|
||||
rv = mDataSource->GetTarget(VALUE_TO_IRDFRESOURCE(value), *property, PR_TRUE, getter_AddRefs(target));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (target != nsnull) {
|
||||
// bingo. we found one.
|
||||
empty = eFalse;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
(" empty => %s",
|
||||
(empty == mEmpty) ? "consistent" : "inconsistent"));
|
||||
|
||||
if (empty == mEmpty) {
|
||||
Element* element = new (mConflictSet.GetPool())
|
||||
Element(VALUE_TO_IRDFRESOURCE(value),
|
||||
mContainer, mEmpty);
|
||||
|
||||
if (! element)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
inst->AddSupportingElement(element);
|
||||
}
|
||||
else {
|
||||
aInstantiations.Erase(inst--);
|
||||
}
|
||||
}
|
||||
else if (mContainer != eDontCare) {
|
||||
// We didn't care about emptiness, only containerhood.
|
||||
Test container;
|
||||
|
||||
if (isRDFContainer) {
|
||||
// Wow, this is easy.
|
||||
container = eTrue;
|
||||
}
|
||||
else {
|
||||
// Okay, suckage. We need to look at all of the arcs
|
||||
// leading out of the thing, and see if any of them
|
||||
// are properties that are deemed as denoting
|
||||
// containerhood.
|
||||
container = eFalse;
|
||||
|
||||
nsCOMPtr<nsISimpleEnumerator> arcsout;
|
||||
rv = mDataSource->ArcLabelsOut(VALUE_TO_IRDFRESOURCE(value), getter_AddRefs(arcsout));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
while (1) {
|
||||
PRBool hasmore;
|
||||
rv = arcsout->HasMoreElements(&hasmore);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (! hasmore)
|
||||
break;
|
||||
|
||||
nsCOMPtr<nsISupports> isupports;
|
||||
rv = arcsout->GetNext(getter_AddRefs(isupports));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIRDFResource> property = do_QueryInterface(isupports);
|
||||
NS_ASSERTION(property != nsnull, "not a property");
|
||||
if (! property)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
if (mMembershipProperties.Contains(property)) {
|
||||
container = eTrue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
(" container => %s",
|
||||
(container == mContainer) ? "consistent" : "inconsistent"));
|
||||
|
||||
if (container == mContainer) {
|
||||
Element* element = new (mConflictSet.GetPool())
|
||||
Element(VALUE_TO_IRDFRESOURCE(value), mContainer, mEmpty);
|
||||
|
||||
|
||||
if (! element)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
inst->AddSupportingElement(element);
|
||||
}
|
||||
else {
|
||||
aInstantiations.Erase(inst--);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsRDFConInstanceTestNode::GetAncestorVariables(VariableSet& aVariables) const
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = aVariables.Add(mContainerVariable);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return TestNode::GetAncestorVariables(aVariables);
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsRDFConInstanceTestNode::CanPropogate(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget,
|
||||
Instantiation& aInitialBindings) const
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
PRBool canpropogate = PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIRDFContainerUtils> rdfc
|
||||
= do_GetService("@mozilla.org/rdf/container-utils;1");
|
||||
|
||||
if (! rdfc)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// We can certainly propogate ordinal properties
|
||||
rv = rdfc->IsOrdinalProperty(aProperty, &canpropogate);
|
||||
if (NS_FAILED(rv)) return PR_FALSE;
|
||||
|
||||
if (! canpropogate) {
|
||||
canpropogate = mMembershipProperties.Contains(aProperty);
|
||||
}
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
const char* source;
|
||||
aSource->GetValueConst(&source);
|
||||
|
||||
const char* property;
|
||||
aProperty->GetValueConst(&property);
|
||||
|
||||
nsAutoString target;
|
||||
nsXULContentUtils::GetTextForNode(aTarget, target);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("nsRDFConInstanceTestNode[%p]: CanPropogate([%s]==[%s]=>[%s]) => %s",
|
||||
this, source, property, NS_ConvertUCS2toUTF8(target).get(),
|
||||
canpropogate ? "true" : "false"));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (canpropogate) {
|
||||
aInitialBindings.AddAssignment(mContainerVariable, Value(aSource));
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
nsRDFConInstanceTestNode::Retract(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget,
|
||||
nsTemplateMatchSet& aFirings,
|
||||
nsTemplateMatchSet& aRetractions) const
|
||||
{
|
||||
// XXXwaterson oof. complicated. figure this out.
|
||||
if (0) {
|
||||
mConflictSet.Remove(Element(aSource, mContainer, mEmpty), aFirings, aRetractions);
|
||||
}
|
||||
}
|
||||
|
124
content/xul/templates/src/nsRDFConInstanceTestNode.h
Normal file
124
content/xul/templates/src/nsRDFConInstanceTestNode.h
Normal file
@ -0,0 +1,124 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#ifndef nsRDFConInstanceTestNode_h__
|
||||
#define nsRDFConInstanceTestNode_h__
|
||||
|
||||
#include "nsRDFTestNode.h"
|
||||
#include "nsFixedSizeAllocator.h"
|
||||
#include "nsIRDFResource.h"
|
||||
#include "nsIRDFDataSource.h"
|
||||
class nsConflictSet;
|
||||
class nsResourceSet;
|
||||
|
||||
/**
|
||||
* Rule network node that tests if a resource is an RDF container, or
|
||||
* uses multi-attributes to ``contain'' other elements.
|
||||
*/
|
||||
class nsRDFConInstanceTestNode : public nsRDFTestNode
|
||||
{
|
||||
public:
|
||||
enum Test { eFalse, eTrue, eDontCare };
|
||||
|
||||
nsRDFConInstanceTestNode(InnerNode* aParent,
|
||||
nsConflictSet& aConflictSet,
|
||||
nsIRDFDataSource* aDataSource,
|
||||
const nsResourceSet& aMembershipProperties,
|
||||
PRInt32 aContainerVariable,
|
||||
Test aContainer,
|
||||
Test aEmpty);
|
||||
|
||||
virtual nsresult FilterInstantiations(InstantiationSet& aInstantiations, void* aClosure) const;
|
||||
|
||||
virtual nsresult GetAncestorVariables(VariableSet& aVariables) const;
|
||||
|
||||
virtual PRBool
|
||||
CanPropogate(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget,
|
||||
Instantiation& aInitialBindings) const;
|
||||
|
||||
virtual void
|
||||
Retract(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget,
|
||||
nsTemplateMatchSet& aFirings,
|
||||
nsTemplateMatchSet& aRetractions) const;
|
||||
|
||||
|
||||
class Element : public MemoryElement {
|
||||
public:
|
||||
static void* operator new(size_t aSize, nsFixedSizeAllocator& aAllocator) {
|
||||
return aAllocator.Alloc(aSize); }
|
||||
|
||||
static void operator delete(void* aPtr, size_t aSize) {
|
||||
nsFixedSizeAllocator::Free(aPtr, aSize); }
|
||||
|
||||
Element(nsIRDFResource* aContainer,
|
||||
Test aContainerTest,
|
||||
Test aEmptyTest)
|
||||
: mContainer(aContainer),
|
||||
mContainerTest(aContainerTest),
|
||||
mEmptyTest(aEmptyTest) {
|
||||
MOZ_COUNT_CTOR(nsRDFConInstanceTestNode::Element); }
|
||||
|
||||
virtual ~Element() { MOZ_COUNT_DTOR(nsRDFConInstanceTestNode::Element); }
|
||||
|
||||
virtual const char* Type() const {
|
||||
return "nsRDFConInstanceTestNode::Element"; }
|
||||
|
||||
virtual PLHashNumber Hash() const {
|
||||
return (PLHashNumber(mContainer.get()) >> 4) ^
|
||||
PLHashNumber(mContainerTest) ^
|
||||
(PLHashNumber(mEmptyTest) << 4); }
|
||||
|
||||
virtual PRBool Equals(const MemoryElement& aElement) const {
|
||||
if (aElement.Type() == Type()) {
|
||||
const Element& element = NS_STATIC_CAST(const Element&, aElement);
|
||||
return mContainer == element.mContainer
|
||||
&& mContainerTest == element.mContainerTest
|
||||
&& mEmptyTest == element.mEmptyTest;
|
||||
}
|
||||
return PR_FALSE; }
|
||||
|
||||
virtual MemoryElement* Clone(void* aPool) const {
|
||||
return new (*NS_STATIC_CAST(nsFixedSizeAllocator*, aPool))
|
||||
Element(mContainer, mContainerTest, mEmptyTest); }
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIRDFResource> mContainer;
|
||||
Test mContainerTest;
|
||||
Test mEmptyTest;
|
||||
};
|
||||
|
||||
protected:
|
||||
nsConflictSet& mConflictSet;
|
||||
nsCOMPtr<nsIRDFDataSource> mDataSource;
|
||||
const nsResourceSet& mMembershipProperties;
|
||||
PRInt32 mContainerVariable;
|
||||
Test mContainer;
|
||||
Test mEmpty;
|
||||
};
|
||||
|
||||
#endif // nsRDFConInstanceTestNode_h__
|
||||
|
553
content/xul/templates/src/nsRDFConMemberTestNode.cpp
Normal file
553
content/xul/templates/src/nsRDFConMemberTestNode.cpp
Normal file
@ -0,0 +1,553 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#include "nsRDFConMemberTestNode.h"
|
||||
#include "nsIRDFContainer.h"
|
||||
#include "nsIRDFContainerUtils.h"
|
||||
#include "nsRDFCID.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsResourceSet.h"
|
||||
#include "nsConflictSet.h"
|
||||
|
||||
#include "prlog.h"
|
||||
#ifdef PR_LOGGING
|
||||
#include "nsXULContentUtils.h"
|
||||
extern PRLogModuleInfo* gXULTemplateLog;
|
||||
#endif
|
||||
|
||||
nsRDFConMemberTestNode::nsRDFConMemberTestNode(InnerNode* aParent,
|
||||
nsConflictSet& aConflictSet,
|
||||
nsIRDFDataSource* aDataSource,
|
||||
const nsResourceSet& aMembershipProperties,
|
||||
PRInt32 aContainerVariable,
|
||||
PRInt32 aMemberVariable)
|
||||
: nsRDFTestNode(aParent),
|
||||
mConflictSet(aConflictSet),
|
||||
mDataSource(aDataSource),
|
||||
mMembershipProperties(aMembershipProperties),
|
||||
mContainerVariable(aContainerVariable),
|
||||
mMemberVariable(aMemberVariable)
|
||||
{
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
nsCAutoString props;
|
||||
|
||||
nsResourceSet::ConstIterator last = aMembershipProperties.Last();
|
||||
nsResourceSet::ConstIterator first = aMembershipProperties.First();
|
||||
nsResourceSet::ConstIterator iter;
|
||||
|
||||
for (iter = first; iter != last; ++iter) {
|
||||
if (iter != first)
|
||||
props += " ";
|
||||
|
||||
const char* str;
|
||||
iter->GetValueConst(&str);
|
||||
|
||||
props += str;
|
||||
}
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("nsRDFConMemberTestNode[%p]: parent=%p member-props=(%s) container-var=%d member-var=%d",
|
||||
this,
|
||||
aParent,
|
||||
props.get(),
|
||||
mContainerVariable,
|
||||
mMemberVariable));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsRDFConMemberTestNode::FilterInstantiations(InstantiationSet& aInstantiations, void* aClosure) const
|
||||
{
|
||||
// XXX Uh, factor me, please!
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIRDFContainerUtils> rdfc =
|
||||
do_GetService("@mozilla.org/rdf/container-utils;1");
|
||||
|
||||
if (! rdfc)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
InstantiationSet::Iterator last = aInstantiations.Last();
|
||||
for (InstantiationSet::Iterator inst = aInstantiations.First(); inst != last; ++inst) {
|
||||
PRBool hasContainerBinding;
|
||||
Value containerValue;
|
||||
hasContainerBinding = inst->mAssignments.GetAssignmentFor(mContainerVariable, &containerValue);
|
||||
|
||||
nsCOMPtr<nsIRDFContainer> rdfcontainer;
|
||||
|
||||
if (hasContainerBinding) {
|
||||
// If we have a container assignment, then see if the
|
||||
// container is an RDF container (bag, seq, alt), and if
|
||||
// so, wrap it.
|
||||
PRBool isRDFContainer;
|
||||
rv = rdfc->IsContainer(mDataSource,
|
||||
VALUE_TO_IRDFRESOURCE(containerValue),
|
||||
&isRDFContainer);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (isRDFContainer) {
|
||||
rdfcontainer = do_CreateInstance("@mozilla.org/rdf/container;1", &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = rdfcontainer->Init(mDataSource, VALUE_TO_IRDFRESOURCE(containerValue));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
}
|
||||
|
||||
PRBool hasMemberBinding;
|
||||
Value memberValue;
|
||||
hasMemberBinding = inst->mAssignments.GetAssignmentFor(mMemberVariable, &memberValue);
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
const char* container = "(unbound)";
|
||||
if (hasContainerBinding)
|
||||
VALUE_TO_IRDFRESOURCE(containerValue)->GetValueConst(&container);
|
||||
|
||||
nsAutoString member = NS_LITERAL_STRING("(unbound)");
|
||||
if (hasMemberBinding)
|
||||
nsXULContentUtils::GetTextForNode(VALUE_TO_IRDFRESOURCE(memberValue), member);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("nsRDFConMemberTestNode[%p]: FilterInstantiations() container=[%s] member=[%s]",
|
||||
this, container, NS_ConvertUCS2toUTF8(member).get()));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (hasContainerBinding && hasMemberBinding) {
|
||||
// it's a consistency check. see if we have a assignment that is consistent
|
||||
PRBool isconsistent = PR_FALSE;
|
||||
|
||||
if (rdfcontainer) {
|
||||
// RDF containers are easy. Just use the container API.
|
||||
PRInt32 index;
|
||||
rv = rdfcontainer->IndexOf(VALUE_TO_IRDFRESOURCE(memberValue), &index);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (index >= 0)
|
||||
isconsistent = PR_TRUE;
|
||||
}
|
||||
|
||||
// XXXwaterson oof. if we *are* an RDF container, why do
|
||||
// we still need to grovel through all the containment
|
||||
// properties if the thing we're looking for wasn't there?
|
||||
|
||||
if (! isconsistent) {
|
||||
// Othewise, we'll need to grovel through the
|
||||
// membership properties to see if we have an
|
||||
// assertion that indicates membership.
|
||||
for (nsResourceSet::ConstIterator property = mMembershipProperties.First();
|
||||
property != mMembershipProperties.Last();
|
||||
++property) {
|
||||
PRBool hasAssertion;
|
||||
rv = mDataSource->HasAssertion(VALUE_TO_IRDFRESOURCE(containerValue),
|
||||
*property,
|
||||
VALUE_TO_IRDFNODE(memberValue),
|
||||
PR_TRUE,
|
||||
&hasAssertion);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (hasAssertion) {
|
||||
// it's consistent. leave it in the set and we'll
|
||||
// run it up to our parent.
|
||||
isconsistent = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
(" consistency check => %s", isconsistent ? "passed" : "failed"));
|
||||
|
||||
if (isconsistent) {
|
||||
// Add a memory element to our set-of-support.
|
||||
Element* element = new (mConflictSet.GetPool())
|
||||
Element(VALUE_TO_IRDFRESOURCE(containerValue),
|
||||
VALUE_TO_IRDFNODE(memberValue));
|
||||
|
||||
if (! element)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
inst->AddSupportingElement(element);
|
||||
}
|
||||
else {
|
||||
// it's inconsistent. remove it.
|
||||
aInstantiations.Erase(inst--);
|
||||
}
|
||||
|
||||
// We're done, go on to the next instantiation
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hasContainerBinding && rdfcontainer) {
|
||||
// We've got a container assignment, and the container is
|
||||
// bound to an RDF container. Add each member as a new
|
||||
// instantiation.
|
||||
nsCOMPtr<nsISimpleEnumerator> elements;
|
||||
rv = rdfcontainer->GetElements(getter_AddRefs(elements));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
while (1) {
|
||||
PRBool hasmore;
|
||||
rv = elements->HasMoreElements(&hasmore);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (! hasmore)
|
||||
break;
|
||||
|
||||
nsCOMPtr<nsISupports> isupports;
|
||||
rv = elements->GetNext(getter_AddRefs(isupports));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIRDFNode> node = do_QueryInterface(isupports);
|
||||
if (! node)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
nsAutoString member;
|
||||
nsXULContentUtils::GetTextForNode(node, member);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
(" member => %s", NS_ConvertUCS2toUTF8(member).get()));
|
||||
}
|
||||
#endif
|
||||
|
||||
Instantiation newinst = *inst;
|
||||
newinst.AddAssignment(mMemberVariable, Value(node.get()));
|
||||
|
||||
Element* element = new (mConflictSet.GetPool())
|
||||
Element(VALUE_TO_IRDFRESOURCE(containerValue), node);
|
||||
|
||||
if (! element)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
newinst.AddSupportingElement(element);
|
||||
|
||||
aInstantiations.Insert(inst, newinst);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasMemberBinding) {
|
||||
// Oh, this is so nasty. If we have a member assignment, then
|
||||
// grovel through each one of our inbound arcs to see if
|
||||
// any of them are ordinal properties (like an RDF
|
||||
// container might have). If so, walk it backwards to get
|
||||
// the container we're in.
|
||||
nsCOMPtr<nsISimpleEnumerator> arcsin;
|
||||
rv = mDataSource->ArcLabelsIn(VALUE_TO_IRDFNODE(memberValue), getter_AddRefs(arcsin));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
while (1) {
|
||||
nsCOMPtr<nsIRDFResource> property;
|
||||
|
||||
{
|
||||
PRBool hasmore;
|
||||
rv = arcsin->HasMoreElements(&hasmore);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (! hasmore)
|
||||
break;
|
||||
|
||||
nsCOMPtr<nsISupports> isupports;
|
||||
rv = arcsin->GetNext(getter_AddRefs(isupports));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
property = do_QueryInterface(isupports);
|
||||
if (! property)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Ordinal properties automagically indicate container
|
||||
// membership as far as we're concerned. Note that
|
||||
// we're *only* concerned with ordinal properties
|
||||
// here: the next block will worry about the other
|
||||
// membership properties.
|
||||
PRBool isordinal;
|
||||
rv = rdfc->IsOrdinalProperty(property, &isordinal);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (isordinal) {
|
||||
// If we get here, we've found a property that
|
||||
// indicates container membership leading *into* a
|
||||
// member node. Find all the people that point to
|
||||
// it, and call them containers.
|
||||
nsCOMPtr<nsISimpleEnumerator> sources;
|
||||
rv = mDataSource->GetSources(property, VALUE_TO_IRDFNODE(memberValue), PR_TRUE,
|
||||
getter_AddRefs(sources));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
while (1) {
|
||||
PRBool hasmore;
|
||||
rv = sources->HasMoreElements(&hasmore);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (! hasmore)
|
||||
break;
|
||||
|
||||
nsCOMPtr<nsISupports> isupports;
|
||||
rv = sources->GetNext(getter_AddRefs(isupports));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIRDFResource> source = do_QueryInterface(isupports);
|
||||
if (! source)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
const char* container;
|
||||
source->GetValueConst(&container);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
(" container => %s", container));
|
||||
}
|
||||
#endif
|
||||
|
||||
// Add a new instantiation
|
||||
Instantiation newinst = *inst;
|
||||
newinst.AddAssignment(mContainerVariable, Value(source.get()));
|
||||
|
||||
Element* element = new (mConflictSet.GetPool())
|
||||
Element(source, VALUE_TO_IRDFNODE(memberValue));
|
||||
|
||||
if (! element)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
newinst.AddSupportingElement(element);
|
||||
|
||||
aInstantiations.Insert(inst, newinst);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((hasContainerBinding && ! hasMemberBinding) ||
|
||||
(! hasContainerBinding && hasMemberBinding)) {
|
||||
// it's an open ended query on the container or member. go
|
||||
// through our containment properties to see if anything
|
||||
// applies.
|
||||
for (nsResourceSet::ConstIterator property = mMembershipProperties.First();
|
||||
property != mMembershipProperties.Last();
|
||||
++property) {
|
||||
nsCOMPtr<nsISimpleEnumerator> results;
|
||||
if (hasContainerBinding) {
|
||||
rv = mDataSource->GetTargets(VALUE_TO_IRDFRESOURCE(containerValue), *property, PR_TRUE,
|
||||
getter_AddRefs(results));
|
||||
}
|
||||
else {
|
||||
rv = mDataSource->GetSources(*property, VALUE_TO_IRDFNODE(memberValue), PR_TRUE,
|
||||
getter_AddRefs(results));
|
||||
}
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
while (1) {
|
||||
PRBool hasmore;
|
||||
rv = results->HasMoreElements(&hasmore);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (! hasmore)
|
||||
break;
|
||||
|
||||
nsCOMPtr<nsISupports> isupports;
|
||||
rv = results->GetNext(getter_AddRefs(isupports));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRInt32 variable;
|
||||
Value value;
|
||||
|
||||
if (hasContainerBinding) {
|
||||
variable = mMemberVariable;
|
||||
|
||||
nsCOMPtr<nsIRDFNode> member = do_QueryInterface(isupports);
|
||||
NS_ASSERTION(member != nsnull, "member is not an nsIRDFNode");
|
||||
if (! member) continue;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
nsAutoString s;
|
||||
nsXULContentUtils::GetTextForNode(member, s);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
(" member => %s", NS_ConvertUCS2toUTF8(s).get()));
|
||||
}
|
||||
#endif
|
||||
|
||||
value = member.get();
|
||||
}
|
||||
else {
|
||||
variable = mContainerVariable;
|
||||
|
||||
nsCOMPtr<nsIRDFResource> container = do_QueryInterface(isupports);
|
||||
NS_ASSERTION(container != nsnull, "container is not an nsIRDFResource");
|
||||
if (! container) continue;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
const char* s;
|
||||
container->GetValueConst(&s);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
(" container => %s", s));
|
||||
}
|
||||
#endif
|
||||
|
||||
value = container.get();
|
||||
}
|
||||
|
||||
// Copy the original instantiation, and add it to the
|
||||
// instantiation set with the new assignment that we've
|
||||
// introduced. Ownership will be transferred to the
|
||||
Instantiation newinst = *inst;
|
||||
newinst.AddAssignment(variable, value);
|
||||
|
||||
Element* element;
|
||||
if (hasContainerBinding) {
|
||||
element = new (mConflictSet.GetPool())
|
||||
Element(VALUE_TO_IRDFRESOURCE(containerValue),
|
||||
VALUE_TO_IRDFNODE(value));
|
||||
}
|
||||
else {
|
||||
element = new (mConflictSet.GetPool())
|
||||
Element(VALUE_TO_IRDFRESOURCE(value),
|
||||
VALUE_TO_IRDFNODE(memberValue));
|
||||
}
|
||||
|
||||
if (! element)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
newinst.AddSupportingElement(element);
|
||||
|
||||
aInstantiations.Insert(inst, newinst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! hasContainerBinding && ! hasMemberBinding) {
|
||||
// Neither container nor member assignment!
|
||||
NS_ERROR("can't do open ended queries like that!");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
// finally, remove the "under specified" instantiation.
|
||||
aInstantiations.Erase(inst--);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsRDFConMemberTestNode::GetAncestorVariables(VariableSet& aVariables) const
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = aVariables.Add(mContainerVariable);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = aVariables.Add(mMemberVariable);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return TestNode::GetAncestorVariables(aVariables);
|
||||
}
|
||||
|
||||
|
||||
PRBool
|
||||
nsRDFConMemberTestNode::CanPropogate(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget,
|
||||
Instantiation& aInitialBindings) const
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
PRBool canpropogate = PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIRDFContainerUtils> rdfc =
|
||||
do_GetService("@mozilla.org/rdf/container-utils;1");
|
||||
|
||||
if (! rdfc)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// We can certainly propogate ordinal properties
|
||||
rv = rdfc->IsOrdinalProperty(aProperty, &canpropogate);
|
||||
if (NS_FAILED(rv)) return PR_FALSE;
|
||||
|
||||
if (! canpropogate) {
|
||||
canpropogate = mMembershipProperties.Contains(aProperty);
|
||||
}
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
const char* source;
|
||||
aSource->GetValueConst(&source);
|
||||
|
||||
const char* property;
|
||||
aProperty->GetValueConst(&property);
|
||||
|
||||
nsAutoString target;
|
||||
nsXULContentUtils::GetTextForNode(aTarget, target);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("nsRDFConMemberTestNode[%p]: CanPropogate([%s]==[%s]=>[%s]) => %s",
|
||||
this, source, property, NS_ConvertUCS2toUTF8(target).get(),
|
||||
canpropogate ? "true" : "false"));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (canpropogate) {
|
||||
aInitialBindings.AddAssignment(mContainerVariable, Value(aSource));
|
||||
aInitialBindings.AddAssignment(mMemberVariable, Value(aTarget));
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
nsRDFConMemberTestNode::Retract(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget,
|
||||
nsTemplateMatchSet& aFirings,
|
||||
nsTemplateMatchSet& aRetractions) const
|
||||
{
|
||||
PRBool canretract = PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIRDFContainerUtils> rdfc =
|
||||
do_GetService("@mozilla.org/rdf/container-utils;1");
|
||||
|
||||
if (! rdfc)
|
||||
return;
|
||||
|
||||
// We can certainly retract ordinal properties
|
||||
nsresult rv;
|
||||
rv = rdfc->IsOrdinalProperty(aProperty, &canretract);
|
||||
if (NS_FAILED(rv)) return;
|
||||
|
||||
if (! canretract) {
|
||||
canretract = mMembershipProperties.Contains(aProperty);
|
||||
}
|
||||
|
||||
if (canretract) {
|
||||
mConflictSet.Remove(Element(aSource, aTarget), aFirings, aRetractions);
|
||||
}
|
||||
}
|
112
content/xul/templates/src/nsRDFConMemberTestNode.h
Normal file
112
content/xul/templates/src/nsRDFConMemberTestNode.h
Normal file
@ -0,0 +1,112 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#ifndef nsRDFConMemberTestNode_h__
|
||||
#define nsRDFConMemberTestNode_h__
|
||||
|
||||
#include "nsRDFTestNode.h"
|
||||
#include "nsIRDFDataSource.h"
|
||||
#include "nsFixedSizeAllocator.h"
|
||||
class nsConflictSet;
|
||||
class nsResourceSet;
|
||||
|
||||
/**
|
||||
* Rule network node that test if a resource is a member of an RDF
|
||||
* container, or is ``contained'' by another resource that refers to
|
||||
* it using a ``containment'' attribute.
|
||||
*/
|
||||
class nsRDFConMemberTestNode : public nsRDFTestNode
|
||||
{
|
||||
public:
|
||||
nsRDFConMemberTestNode(InnerNode* aParent,
|
||||
nsConflictSet& aConflictSet,
|
||||
nsIRDFDataSource* aDataSource,
|
||||
const nsResourceSet& aMembershipProperties,
|
||||
PRInt32 aContainerVariable,
|
||||
PRInt32 aMemberVariable);
|
||||
|
||||
virtual nsresult FilterInstantiations(InstantiationSet& aInstantiations, void* aClosure) const;
|
||||
|
||||
virtual nsresult GetAncestorVariables(VariableSet& aVariables) const;
|
||||
|
||||
virtual PRBool
|
||||
CanPropogate(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget,
|
||||
Instantiation& aInitialBindings) const;
|
||||
|
||||
virtual void
|
||||
Retract(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget,
|
||||
nsTemplateMatchSet& aFirings,
|
||||
nsTemplateMatchSet& aRetractions) const;
|
||||
|
||||
class Element : public MemoryElement {
|
||||
public:
|
||||
static void* operator new(size_t aSize, nsFixedSizeAllocator& aAllocator) {
|
||||
return aAllocator.Alloc(aSize); }
|
||||
|
||||
static void operator delete(void* aPtr, size_t aSize) {
|
||||
nsFixedSizeAllocator::Free(aPtr, aSize); }
|
||||
|
||||
Element(nsIRDFResource* aContainer,
|
||||
nsIRDFNode* aMember)
|
||||
: mContainer(aContainer),
|
||||
mMember(aMember) {
|
||||
MOZ_COUNT_CTOR(nsRDFConMemberTestNode::Element); }
|
||||
|
||||
virtual ~Element() { MOZ_COUNT_DTOR(nsRDFConMemberTestNode::Element); }
|
||||
|
||||
virtual const char* Type() const {
|
||||
return "nsRDFConMemberTestNode::Element"; }
|
||||
|
||||
virtual PLHashNumber Hash() const {
|
||||
return PLHashNumber(mContainer.get()) ^
|
||||
(PLHashNumber(mMember.get()) >> 12); }
|
||||
|
||||
virtual PRBool Equals(const MemoryElement& aElement) const {
|
||||
if (aElement.Type() == Type()) {
|
||||
const Element& element = NS_STATIC_CAST(const Element&, aElement);
|
||||
return mContainer == element.mContainer && mMember == element.mMember;
|
||||
}
|
||||
return PR_FALSE; }
|
||||
|
||||
virtual MemoryElement* Clone(void* aPool) const {
|
||||
return new (*NS_STATIC_CAST(nsFixedSizeAllocator*, aPool))
|
||||
Element(mContainer, mMember); }
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIRDFResource> mContainer;
|
||||
nsCOMPtr<nsIRDFNode> mMember;
|
||||
};
|
||||
|
||||
protected:
|
||||
nsConflictSet& mConflictSet;
|
||||
nsCOMPtr<nsIRDFDataSource> mDataSource;
|
||||
const nsResourceSet& mMembershipProperties;
|
||||
PRInt32 mContainerVariable;
|
||||
PRInt32 mMemberVariable;
|
||||
};
|
||||
|
||||
#endif // nsRDFConMemberTestNode_h__
|
406
content/xul/templates/src/nsRDFPropertyTestNode.cpp
Normal file
406
content/xul/templates/src/nsRDFPropertyTestNode.cpp
Normal file
@ -0,0 +1,406 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#include "nsRDFPropertyTestNode.h"
|
||||
#include "nsConflictSet.h"
|
||||
|
||||
#include "prlog.h"
|
||||
#ifdef PR_LOGGING
|
||||
extern PRLogModuleInfo* gXULTemplateLog;
|
||||
#include "nsIRDFLiteral.h"
|
||||
#include "nsXULContentUtils.h"
|
||||
#endif
|
||||
|
||||
nsRDFPropertyTestNode::nsRDFPropertyTestNode(InnerNode* aParent,
|
||||
nsConflictSet& aConflictSet,
|
||||
nsIRDFDataSource* aDataSource,
|
||||
PRInt32 aSourceVariable,
|
||||
nsIRDFResource* aProperty,
|
||||
PRInt32 aTargetVariable)
|
||||
: nsRDFTestNode(aParent),
|
||||
mConflictSet(aConflictSet),
|
||||
mDataSource(aDataSource),
|
||||
mSourceVariable(aSourceVariable),
|
||||
mSource(nsnull),
|
||||
mProperty(aProperty),
|
||||
mTargetVariable(aTargetVariable),
|
||||
mTarget(nsnull)
|
||||
{
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
const char* prop = "(null)";
|
||||
if (aProperty)
|
||||
aProperty->GetValueConst(&prop);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("nsRDFPropertyTestNode[%p]: parent=%p source=%d property=%s target=%d",
|
||||
this, aParent, aSourceVariable, prop, aTargetVariable));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
nsRDFPropertyTestNode::nsRDFPropertyTestNode(InnerNode* aParent,
|
||||
nsConflictSet& aConflictSet,
|
||||
nsIRDFDataSource* aDataSource,
|
||||
nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
PRInt32 aTargetVariable)
|
||||
: nsRDFTestNode(aParent),
|
||||
mConflictSet(aConflictSet),
|
||||
mDataSource(aDataSource),
|
||||
mSourceVariable(0),
|
||||
mSource(aSource),
|
||||
mProperty(aProperty),
|
||||
mTargetVariable(aTargetVariable),
|
||||
mTarget(nsnull)
|
||||
{
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
const char* source = "(null)";
|
||||
if (aSource)
|
||||
aSource->GetValueConst(&source);
|
||||
|
||||
const char* prop = "(null)";
|
||||
if (aProperty)
|
||||
aProperty->GetValueConst(&prop);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("nsRDFPropertyTestNode[%p]: parent=%p source=%s property=%s target=%d",
|
||||
this, source, prop, aTargetVariable));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
nsRDFPropertyTestNode::nsRDFPropertyTestNode(InnerNode* aParent,
|
||||
nsConflictSet& aConflictSet,
|
||||
nsIRDFDataSource* aDataSource,
|
||||
PRInt32 aSourceVariable,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget)
|
||||
: nsRDFTestNode(aParent),
|
||||
mConflictSet(aConflictSet),
|
||||
mDataSource(aDataSource),
|
||||
mSourceVariable(aSourceVariable),
|
||||
mSource(nsnull),
|
||||
mProperty(aProperty),
|
||||
mTargetVariable(0),
|
||||
mTarget(aTarget)
|
||||
{
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
const char* prop = "(null)";
|
||||
if (aProperty)
|
||||
aProperty->GetValueConst(&prop);
|
||||
|
||||
nsAutoString target;
|
||||
nsXULContentUtils::GetTextForNode(aTarget, target);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("nsRDFPropertyTestNode[%p]: parent=%p source=%s property=%s target=%d",
|
||||
this, aSourceVariable, prop, NS_ConvertUCS2toUTF8(target).get()));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRDFPropertyTestNode::FilterInstantiations(InstantiationSet& aInstantiations, void* aClosure) const
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
InstantiationSet::Iterator last = aInstantiations.Last();
|
||||
for (InstantiationSet::Iterator inst = aInstantiations.First(); inst != last; ++inst) {
|
||||
PRBool hasSourceBinding;
|
||||
Value sourceValue;
|
||||
|
||||
if (mSource) {
|
||||
hasSourceBinding = PR_TRUE;
|
||||
sourceValue = mSource;
|
||||
}
|
||||
else {
|
||||
hasSourceBinding = inst->mAssignments.GetAssignmentFor(mSourceVariable, &sourceValue);
|
||||
}
|
||||
|
||||
PRBool hasTargetBinding;
|
||||
Value targetValue;
|
||||
|
||||
if (mTarget) {
|
||||
hasTargetBinding = PR_TRUE;
|
||||
targetValue = mTarget;
|
||||
}
|
||||
else {
|
||||
hasTargetBinding = inst->mAssignments.GetAssignmentFor(mTargetVariable, &targetValue);
|
||||
}
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
const char* source = "(unbound)";
|
||||
if (hasSourceBinding)
|
||||
VALUE_TO_IRDFRESOURCE(sourceValue)->GetValueConst(&source);
|
||||
|
||||
nsAutoString target = NS_LITERAL_STRING("(unbound)");
|
||||
if (hasTargetBinding)
|
||||
nsXULContentUtils::GetTextForNode(VALUE_TO_IRDFNODE(targetValue), target);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("nsRDFPropertyTestNode[%p]: FilterInstantiations() source=[%s] target=[%s]",
|
||||
this, source, NS_ConvertUCS2toUTF8(target).get()));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (hasSourceBinding && hasTargetBinding) {
|
||||
// it's a consistency check. see if we have a assignment that is consistent
|
||||
PRBool hasAssertion;
|
||||
rv = mDataSource->HasAssertion(VALUE_TO_IRDFRESOURCE(sourceValue),
|
||||
mProperty,
|
||||
VALUE_TO_IRDFNODE(targetValue),
|
||||
PR_TRUE,
|
||||
&hasAssertion);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
(" consistency check => %s", hasAssertion ? "passed" : "failed"));
|
||||
#endif
|
||||
|
||||
if (hasAssertion) {
|
||||
// it's consistent.
|
||||
Element* element = new (mConflictSet.GetPool())
|
||||
Element(VALUE_TO_IRDFRESOURCE(sourceValue),
|
||||
mProperty,
|
||||
VALUE_TO_IRDFNODE(targetValue));
|
||||
|
||||
if (! element)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
inst->AddSupportingElement(element);
|
||||
}
|
||||
else {
|
||||
// it's inconsistent. remove it.
|
||||
aInstantiations.Erase(inst--);
|
||||
}
|
||||
}
|
||||
else if ((hasSourceBinding && ! hasTargetBinding) ||
|
||||
(! hasSourceBinding && hasTargetBinding)) {
|
||||
// it's an open ended query on the source or
|
||||
// target. figure out what matches and add as a
|
||||
// cross-product.
|
||||
nsCOMPtr<nsISimpleEnumerator> results;
|
||||
if (hasSourceBinding) {
|
||||
rv = mDataSource->GetTargets(VALUE_TO_IRDFRESOURCE(sourceValue),
|
||||
mProperty,
|
||||
PR_TRUE,
|
||||
getter_AddRefs(results));
|
||||
}
|
||||
else {
|
||||
rv = mDataSource->GetSources(mProperty,
|
||||
VALUE_TO_IRDFNODE(targetValue),
|
||||
PR_TRUE,
|
||||
getter_AddRefs(results));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
PRBool hasMore;
|
||||
rv = results->HasMoreElements(&hasMore);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (! hasMore)
|
||||
break;
|
||||
|
||||
nsCOMPtr<nsISupports> isupports;
|
||||
rv = results->GetNext(getter_AddRefs(isupports));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRInt32 variable;
|
||||
Value value;
|
||||
|
||||
if (hasSourceBinding) {
|
||||
variable = mTargetVariable;
|
||||
|
||||
nsCOMPtr<nsIRDFNode> target = do_QueryInterface(isupports);
|
||||
NS_ASSERTION(target != nsnull, "target is not an nsIRDFNode");
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
nsAutoString s = NS_LITERAL_STRING("(none found)");
|
||||
if (target)
|
||||
nsXULContentUtils::GetTextForNode(target, s);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
(" target => %s", NS_ConvertUCS2toUTF8(s).get()));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (! target) continue;
|
||||
|
||||
targetValue = value = target.get();
|
||||
}
|
||||
else {
|
||||
variable = mSourceVariable;
|
||||
|
||||
nsCOMPtr<nsIRDFResource> source = do_QueryInterface(isupports);
|
||||
NS_ASSERTION(source != nsnull, "source is not an nsIRDFResource");
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
const char* s = "(none found)";
|
||||
if (source)
|
||||
source->GetValueConst(&s);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
(" source => %s", s));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (! source) continue;
|
||||
|
||||
sourceValue = value = source.get();
|
||||
}
|
||||
|
||||
// Copy the original instantiation, and add it to the
|
||||
// instantiation set with the new assignment that we've
|
||||
// introduced. Ownership will be transferred to the
|
||||
Instantiation newinst = *inst;
|
||||
newinst.AddAssignment(variable, value);
|
||||
|
||||
Element* element = new (mConflictSet.GetPool())
|
||||
Element(VALUE_TO_IRDFRESOURCE(sourceValue),
|
||||
mProperty,
|
||||
VALUE_TO_IRDFNODE(targetValue));
|
||||
|
||||
if (! element)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
newinst.AddSupportingElement(element);
|
||||
|
||||
aInstantiations.Insert(inst, newinst);
|
||||
}
|
||||
|
||||
// finally, remove the "under specified" instantiation.
|
||||
aInstantiations.Erase(inst--);
|
||||
}
|
||||
else {
|
||||
// Neither source nor target assignment!
|
||||
NS_ERROR("can't do open ended queries like that!");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRDFPropertyTestNode::GetAncestorVariables(VariableSet& aVariables) const
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (mSourceVariable) {
|
||||
rv = aVariables.Add(mSourceVariable);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
if (mTargetVariable) {
|
||||
rv = aVariables.Add(mTargetVariable);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
return TestNode::GetAncestorVariables(aVariables);
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsRDFPropertyTestNode::CanPropogate(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget,
|
||||
Instantiation& aInitialBindings) const
|
||||
{
|
||||
PRBool result;
|
||||
|
||||
if ((mProperty.get() != aProperty) ||
|
||||
(mSource && mSource.get() != aSource) ||
|
||||
(mTarget && mTarget.get() != aTarget)) {
|
||||
result = PR_FALSE;
|
||||
}
|
||||
else {
|
||||
if (mSourceVariable)
|
||||
aInitialBindings.AddAssignment(mSourceVariable, Value(aSource));
|
||||
|
||||
if (mTargetVariable)
|
||||
aInitialBindings.AddAssignment(mTargetVariable, Value(aTarget));
|
||||
|
||||
result = PR_TRUE;
|
||||
}
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
const char* source;
|
||||
aSource->GetValueConst(&source);
|
||||
|
||||
const char* property;
|
||||
aProperty->GetValueConst(&property);
|
||||
|
||||
nsAutoString target;
|
||||
nsXULContentUtils::GetTextForNode(aTarget, target);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("nsRDFPropertyTestNode[%p]: CanPropogate([%s]==[%s]=>[%s]) => %s",
|
||||
this, source, property, NS_ConvertUCS2toUTF8(target).get(),
|
||||
result ? "true" : "false"));
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
nsRDFPropertyTestNode::Retract(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget,
|
||||
nsTemplateMatchSet& aFirings,
|
||||
nsTemplateMatchSet& aRetractions) const
|
||||
{
|
||||
if (aProperty == mProperty.get()) {
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
const char* source;
|
||||
aSource->GetValueConst(&source);
|
||||
|
||||
const char* property;
|
||||
aProperty->GetValueConst(&property);
|
||||
|
||||
nsAutoString target;
|
||||
nsXULContentUtils::GetTextForNode(aTarget, target);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("nsRDFPropertyTestNode[%p]: Retract([%s]==[%s]=>[%s])",
|
||||
this, source, property, NS_ConvertUCS2toUTF8(target).get()));
|
||||
}
|
||||
#endif
|
||||
|
||||
mConflictSet.Remove(Element(aSource, aProperty, aTarget), aFirings, aRetractions);
|
||||
}
|
||||
}
|
||||
|
139
content/xul/templates/src/nsRDFPropertyTestNode.h
Normal file
139
content/xul/templates/src/nsRDFPropertyTestNode.h
Normal file
@ -0,0 +1,139 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#ifndef nsRDFPropertyTestNode_h__
|
||||
#define nsRDFPropertyTestNode_h__
|
||||
|
||||
#include "nsFixedSizeAllocator.h"
|
||||
#include "nsRDFTestNode.h"
|
||||
#include "nsIRDFDataSource.h"
|
||||
#include "nsIRDFResource.h"
|
||||
class nsConflictSet;
|
||||
|
||||
class nsRDFPropertyTestNode : public nsRDFTestNode
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Both source and target unbound (?source ^property ?target)
|
||||
*/
|
||||
nsRDFPropertyTestNode(InnerNode* aParent,
|
||||
nsConflictSet& aConflictSet,
|
||||
nsIRDFDataSource* aDataSource,
|
||||
PRInt32 aSourceVariable,
|
||||
nsIRDFResource* aProperty,
|
||||
PRInt32 aTargetVariable);
|
||||
|
||||
/**
|
||||
* Source bound, target unbound (source ^property ?target)
|
||||
*/
|
||||
nsRDFPropertyTestNode(InnerNode* aParent,
|
||||
nsConflictSet& aConflictSet,
|
||||
nsIRDFDataSource* aDataSource,
|
||||
nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
PRInt32 aTargetVariable);
|
||||
|
||||
/**
|
||||
* Source unbound, target bound (?source ^property target)
|
||||
*/
|
||||
nsRDFPropertyTestNode(InnerNode* aParent,
|
||||
nsConflictSet& aConflictSet,
|
||||
nsIRDFDataSource* aDataSource,
|
||||
PRInt32 aSourceVariable,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget);
|
||||
|
||||
virtual nsresult FilterInstantiations(InstantiationSet& aInstantiations, void* aClosure) const;
|
||||
|
||||
virtual nsresult GetAncestorVariables(VariableSet& aVariables) const;
|
||||
|
||||
virtual PRBool
|
||||
CanPropogate(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget,
|
||||
Instantiation& aInitialBindings) const;
|
||||
|
||||
virtual void
|
||||
Retract(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget,
|
||||
nsTemplateMatchSet& aFirings,
|
||||
nsTemplateMatchSet& aRetractions) const;
|
||||
|
||||
|
||||
class Element : public MemoryElement {
|
||||
public:
|
||||
static void* operator new(size_t aSize, nsFixedSizeAllocator& aAllocator) {
|
||||
return aAllocator.Alloc(aSize); }
|
||||
|
||||
static void operator delete(void* aPtr, size_t aSize) {
|
||||
nsFixedSizeAllocator::Free(aPtr, aSize); }
|
||||
|
||||
Element(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget)
|
||||
: mSource(aSource),
|
||||
mProperty(aProperty),
|
||||
mTarget(aTarget) {
|
||||
MOZ_COUNT_CTOR(nsRDFPropertyTestNode::Element); }
|
||||
|
||||
virtual ~Element() { MOZ_COUNT_DTOR(nsRDFPropertyTestNode::Element); }
|
||||
|
||||
virtual const char* Type() const {
|
||||
return "nsRDFPropertyTestNode::Element"; }
|
||||
|
||||
virtual PLHashNumber Hash() const {
|
||||
return PLHashNumber(mSource.get()) ^
|
||||
(PLHashNumber(mProperty.get()) >> 4) ^
|
||||
(PLHashNumber(mTarget.get()) >> 12); }
|
||||
|
||||
virtual PRBool Equals(const MemoryElement& aElement) const {
|
||||
if (aElement.Type() == Type()) {
|
||||
const Element& element = NS_STATIC_CAST(const Element&, aElement);
|
||||
return mSource == element.mSource
|
||||
&& mProperty == element.mProperty
|
||||
&& mTarget == element.mTarget;
|
||||
}
|
||||
return PR_FALSE; }
|
||||
|
||||
virtual MemoryElement* Clone(void* aPool) const {
|
||||
return new (*NS_STATIC_CAST(nsFixedSizeAllocator*, aPool))
|
||||
Element(mSource, mProperty, mTarget); }
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIRDFResource> mSource;
|
||||
nsCOMPtr<nsIRDFResource> mProperty;
|
||||
nsCOMPtr<nsIRDFNode> mTarget;
|
||||
};
|
||||
|
||||
protected:
|
||||
nsConflictSet& mConflictSet;
|
||||
nsCOMPtr<nsIRDFDataSource> mDataSource;
|
||||
PRInt32 mSourceVariable;
|
||||
nsCOMPtr<nsIRDFResource> mSource;
|
||||
nsCOMPtr<nsIRDFResource> mProperty;
|
||||
PRInt32 mTargetVariable;
|
||||
nsCOMPtr<nsIRDFNode> mTarget;
|
||||
};
|
||||
|
||||
#endif // nsRDFPropertyTestNode_h__
|
69
content/xul/templates/src/nsRDFTestNode.h
Normal file
69
content/xul/templates/src/nsRDFTestNode.h
Normal file
@ -0,0 +1,69 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#ifndef nsRDFTestNode_h__
|
||||
#define nsRDFTestNode_h__
|
||||
|
||||
#include "nsRuleNetwork.h"
|
||||
class nsIRDFResource;
|
||||
class nsIRDFNode;
|
||||
class nsTemplateMatchSet;
|
||||
|
||||
/**
|
||||
* An abstract base class for all of the RDF-related tests. This interface
|
||||
* allows us to iterate over all of the RDF tests to find the one in the
|
||||
* network that is apropos for a newly-added assertion.
|
||||
*/
|
||||
class nsRDFTestNode : public TestNode
|
||||
{
|
||||
public:
|
||||
nsRDFTestNode(InnerNode* aParent)
|
||||
: TestNode(aParent) {}
|
||||
|
||||
/**
|
||||
* Determine wether the node can propogate an assertion
|
||||
* with the specified source, property, and target. If the
|
||||
* assertion can be propogated, aInitialBindings will be
|
||||
* initialized with appropriate variable-to-value assignments
|
||||
* to allow the rule network to start a constrain and propogate
|
||||
* search from this node in the network.
|
||||
*
|
||||
* @return PR_TRUE if the node can propogate the specified
|
||||
* assertion.
|
||||
*/
|
||||
virtual PRBool CanPropogate(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget,
|
||||
Instantiation& aInitialBindings) const = 0;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
virtual void Retract(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget,
|
||||
nsTemplateMatchSet& aFirings,
|
||||
nsTemplateMatchSet& aRetractions) const = 0;
|
||||
};
|
||||
|
||||
#endif // nsRDFTestNode_h__
|
104
content/xul/templates/src/nsResourceSet.cpp
Normal file
104
content/xul/templates/src/nsResourceSet.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#include "nsResourceSet.h"
|
||||
|
||||
nsResourceSet::nsResourceSet(const nsResourceSet& aResourceSet)
|
||||
: mResources(nsnull),
|
||||
mCount(0),
|
||||
mCapacity(0)
|
||||
{
|
||||
ConstIterator last = aResourceSet.Last();
|
||||
for (ConstIterator resource = aResourceSet.First(); resource != last; ++resource)
|
||||
Add(*resource);
|
||||
}
|
||||
|
||||
|
||||
nsResourceSet&
|
||||
nsResourceSet::operator=(const nsResourceSet& aResourceSet)
|
||||
{
|
||||
Clear();
|
||||
ConstIterator last = aResourceSet.Last();
|
||||
for (ConstIterator resource = aResourceSet.First(); resource != last; ++resource)
|
||||
Add(*resource);
|
||||
return *this;
|
||||
}
|
||||
|
||||
nsResourceSet::~nsResourceSet()
|
||||
{
|
||||
MOZ_COUNT_DTOR(nsResourceSet);
|
||||
Clear();
|
||||
delete[] mResources;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsResourceSet::Clear()
|
||||
{
|
||||
while (--mCount >= 0) {
|
||||
NS_RELEASE(mResources[mCount]);
|
||||
}
|
||||
mCount = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsResourceSet::Add(nsIRDFResource* aResource)
|
||||
{
|
||||
NS_PRECONDITION(aResource != nsnull, "null ptr");
|
||||
if (! aResource)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if (Contains(aResource))
|
||||
return NS_OK;
|
||||
|
||||
if (mCount >= mCapacity) {
|
||||
PRInt32 capacity = mCapacity + 4;
|
||||
nsIRDFResource** resources = new nsIRDFResource*[capacity];
|
||||
if (! resources)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
for (PRInt32 i = mCount - 1; i >= 0; --i)
|
||||
resources[i] = mResources[i];
|
||||
|
||||
delete[] mResources;
|
||||
|
||||
mResources = resources;
|
||||
mCapacity = capacity;
|
||||
}
|
||||
|
||||
mResources[mCount++] = aResource;
|
||||
NS_ADDREF(aResource);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsResourceSet::Contains(nsIRDFResource* aResource) const
|
||||
{
|
||||
for (PRInt32 i = mCount - 1; i >= 0; --i) {
|
||||
if (mResources[i] == aResource)
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
99
content/xul/templates/src/nsResourceSet.h
Normal file
99
content/xul/templates/src/nsResourceSet.h
Normal file
@ -0,0 +1,99 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
#ifndef nsResourceSet_h__
|
||||
#define nsResourceSet_h__
|
||||
|
||||
#include "nsIRDFResource.h"
|
||||
|
||||
class nsResourceSet
|
||||
{
|
||||
public:
|
||||
nsResourceSet()
|
||||
: mResources(nsnull),
|
||||
mCount(0),
|
||||
mCapacity(0) {
|
||||
MOZ_COUNT_CTOR(nsResourceSet); }
|
||||
|
||||
nsResourceSet(const nsResourceSet& aResourceSet);
|
||||
|
||||
nsResourceSet& operator=(const nsResourceSet& aResourceSet);
|
||||
|
||||
~nsResourceSet();
|
||||
|
||||
nsresult Clear();
|
||||
nsresult Add(nsIRDFResource* aProperty);
|
||||
|
||||
PRBool Contains(nsIRDFResource* aProperty) const;
|
||||
|
||||
protected:
|
||||
nsIRDFResource** mResources;
|
||||
PRInt32 mCount;
|
||||
PRInt32 mCapacity;
|
||||
|
||||
public:
|
||||
class ConstIterator {
|
||||
protected:
|
||||
nsIRDFResource** mCurrent;
|
||||
|
||||
public:
|
||||
ConstIterator() : mCurrent(nsnull) {}
|
||||
|
||||
ConstIterator(const ConstIterator& aConstIterator)
|
||||
: mCurrent(aConstIterator.mCurrent) {}
|
||||
|
||||
ConstIterator& operator=(const ConstIterator& aConstIterator) {
|
||||
mCurrent = aConstIterator.mCurrent;
|
||||
return *this; }
|
||||
|
||||
ConstIterator& operator++() {
|
||||
++mCurrent;
|
||||
return *this; }
|
||||
|
||||
ConstIterator operator++(int) {
|
||||
ConstIterator result(*this);
|
||||
++mCurrent;
|
||||
return result; }
|
||||
|
||||
/*const*/ nsIRDFResource* operator*() const {
|
||||
return *mCurrent; }
|
||||
|
||||
/*const*/ nsIRDFResource* operator->() const {
|
||||
return *mCurrent; }
|
||||
|
||||
PRBool operator==(const ConstIterator& aConstIterator) const {
|
||||
return mCurrent == aConstIterator.mCurrent; }
|
||||
|
||||
PRBool operator!=(const ConstIterator& aConstIterator) const {
|
||||
return mCurrent != aConstIterator.mCurrent; }
|
||||
|
||||
protected:
|
||||
ConstIterator(nsIRDFResource** aProperty) : mCurrent(aProperty) {}
|
||||
friend class nsResourceSet;
|
||||
};
|
||||
|
||||
ConstIterator First() const { return ConstIterator(mResources); }
|
||||
ConstIterator Last() const { return ConstIterator(mResources + mCount); }
|
||||
};
|
||||
|
||||
#endif // nsResourceSet_h__
|
||||
|
107
content/xul/templates/src/nsTemplateMap.h
Normal file
107
content/xul/templates/src/nsTemplateMap.h
Normal file
@ -0,0 +1,107 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#ifndef nsTemplateMap_h__
|
||||
#define nsTemplateMap_h__
|
||||
|
||||
#include "pldhash.h"
|
||||
|
||||
class nsTemplateMap {
|
||||
protected:
|
||||
struct Entry {
|
||||
PLDHashEntryHdr mHdr;
|
||||
nsIContent* mContent;
|
||||
nsIContent* mTemplate;
|
||||
};
|
||||
|
||||
PLDHashTable mTable;
|
||||
|
||||
void
|
||||
Init() { PL_DHashTableInit(&mTable, PL_DHashGetStubOps(), nsnull, sizeof(Entry), PL_DHASH_MIN_SIZE); }
|
||||
|
||||
void
|
||||
Finish() { PL_DHashTableFinish(&mTable); }
|
||||
|
||||
public:
|
||||
nsTemplateMap() { Init(); }
|
||||
|
||||
~nsTemplateMap() { Finish(); }
|
||||
|
||||
void
|
||||
Put(nsIContent* aContent, nsIContent* aTemplate) {
|
||||
NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mTable, aContent, PL_DHASH_LOOKUP)),
|
||||
"aContent already in map");
|
||||
|
||||
Entry* entry =
|
||||
NS_REINTERPRET_CAST(Entry*, PL_DHashTableOperate(&mTable, aContent, PL_DHASH_ADD));
|
||||
|
||||
if (entry) {
|
||||
entry->mContent = aContent;
|
||||
entry->mTemplate = aTemplate;
|
||||
} }
|
||||
|
||||
void
|
||||
Remove(nsIContent* aContent) {
|
||||
NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableOperate(&mTable, aContent, PL_DHASH_LOOKUP)),
|
||||
"aContent not in map");
|
||||
|
||||
PL_DHashTableOperate(&mTable, aContent, PL_DHASH_REMOVE);
|
||||
|
||||
PRInt32 count;
|
||||
|
||||
// If possible, use the special nsIXULContent interface to
|
||||
// "peek" at the child count without accidentally creating
|
||||
// children as a side effect, since we're about to rip 'em
|
||||
// outta the map anyway.
|
||||
nsCOMPtr<nsIXULContent> xulcontent = do_QueryInterface(aContent);
|
||||
if (xulcontent) {
|
||||
xulcontent->PeekChildCount(count);
|
||||
}
|
||||
else {
|
||||
aContent->ChildCount(count);
|
||||
}
|
||||
|
||||
for (PRInt32 i = 0; i < count; ++i) {
|
||||
nsCOMPtr<nsIContent> child;
|
||||
aContent->ChildAt(i, *getter_AddRefs(child));
|
||||
|
||||
Remove(child);
|
||||
} }
|
||||
|
||||
|
||||
void
|
||||
GetTemplateFor(nsIContent* aContent, nsIContent** aResult) {
|
||||
Entry* entry =
|
||||
NS_REINTERPRET_CAST(Entry*, PL_DHashTableOperate(&mTable, aContent, PL_DHASH_LOOKUP));
|
||||
|
||||
if (PL_DHASH_ENTRY_IS_BUSY(&entry->mHdr))
|
||||
NS_IF_ADDREF(*aResult = entry->mTemplate);
|
||||
else
|
||||
*aResult = nsnull; }
|
||||
|
||||
void
|
||||
Clear() { Finish(); Init(); }
|
||||
};
|
||||
|
||||
#endif // nsTemplateMap_h__
|
||||
|
42
content/xul/templates/src/nsTemplateMatch.cpp
Normal file
42
content/xul/templates/src/nsTemplateMatch.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#include "nsTemplateMatch.h"
|
||||
#include "nsTemplateRule.h"
|
||||
|
||||
#ifdef NEED_CPP_UNUSED_IMPLEMENTATIONS
|
||||
nsTemplateMatch::nsTemplateMatch(const nsTemplateMatch& aMatch) {}
|
||||
void nsTemplateMatch::operator=(const nsTemplateMatch& aMatch) {}
|
||||
#endif
|
||||
|
||||
PRBool
|
||||
nsTemplateMatch::GetAssignmentFor(nsConflictSet& aConflictSet, PRInt32 aVariable, Value* aValue)
|
||||
{
|
||||
if (mAssignments.GetAssignmentFor(aVariable, aValue)) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
else {
|
||||
return mRule->ComputeAssignmentFor(aConflictSet, this, aVariable, aValue);
|
||||
}
|
||||
}
|
||||
|
124
content/xul/templates/src/nsTemplateMatch.h
Normal file
124
content/xul/templates/src/nsTemplateMatch.h
Normal file
@ -0,0 +1,124 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#ifndef nsTemplateMatch_h__
|
||||
#define nsTemplateMatch_h__
|
||||
|
||||
#include "nsFixedSizeAllocator.h"
|
||||
#include "nsResourceSet.h"
|
||||
#include "nsRuleNetwork.h"
|
||||
|
||||
/**
|
||||
* A "match" is a fully instantiated rule; that is, a complete and
|
||||
* consistent set of variable-to-value assignments for all the rule's
|
||||
* condition elements.
|
||||
*
|
||||
* Each match also contains information about the "optional"
|
||||
* variable-to-value assignments that can be specified using the
|
||||
* <bindings> element in a rule.
|
||||
*/
|
||||
|
||||
class nsConflictSet;
|
||||
class nsTemplateRule;
|
||||
|
||||
class nsTemplateMatch {
|
||||
protected:
|
||||
PRInt32 mRefCnt;
|
||||
|
||||
public:
|
||||
static void* operator new(size_t aSize, nsFixedSizeAllocator& aAllocator) {
|
||||
return aAllocator.Alloc(aSize); }
|
||||
|
||||
static void operator delete(void* aPtr, size_t aSize) {
|
||||
nsFixedSizeAllocator::Free(aPtr, aSize); }
|
||||
|
||||
nsTemplateMatch(const nsTemplateRule* aRule,
|
||||
const Instantiation& aInstantiation,
|
||||
const nsAssignmentSet& aAssignments)
|
||||
: mRefCnt(1),
|
||||
mRule(aRule),
|
||||
mInstantiation(aInstantiation),
|
||||
mAssignments(aAssignments)
|
||||
{ MOZ_COUNT_CTOR(nsTemplateMatch); }
|
||||
|
||||
PRBool operator==(const nsTemplateMatch& aMatch) const {
|
||||
return mRule == aMatch.mRule && mInstantiation == aMatch.mInstantiation; }
|
||||
|
||||
PRBool operator!=(const nsTemplateMatch& aMatch) const {
|
||||
return !(*this == aMatch); }
|
||||
|
||||
/**
|
||||
* Get the assignment for the specified variable, computing the
|
||||
* value using the rule's bindings, if necessary.
|
||||
* @param aConflictSet
|
||||
* @param aVariable the variable for which to determine the assignment
|
||||
* @param aValue an out parameter that receives the value assigned to
|
||||
* aVariable.
|
||||
* @return PR_TRUE if aVariable has an assignment, PR_FALSE otherwise.
|
||||
*/
|
||||
PRBool GetAssignmentFor(nsConflictSet& aConflictSet, PRInt32 aVariable, Value* aValue);
|
||||
|
||||
/**
|
||||
* The rule that this match applies for.
|
||||
*/
|
||||
const nsTemplateRule* mRule;
|
||||
|
||||
/**
|
||||
* The fully bound instantiation (variable-to-value assignments, with
|
||||
* memory element support) that match the rule's conditions.
|
||||
*/
|
||||
Instantiation mInstantiation;
|
||||
|
||||
/**
|
||||
* Any additional assignments that apply because of the rule's
|
||||
* bindings. These are computed lazily.
|
||||
*/
|
||||
nsAssignmentSet mAssignments;
|
||||
|
||||
/**
|
||||
* The set of resources that the nsTemplateMatch's bindings depend on. Should the
|
||||
* assertions relating to these resources change, then the rule will
|
||||
* still match (i.e., this match object is still "good"); however, we
|
||||
* may need to recompute the assignments that have been made using the
|
||||
* rule's bindings.
|
||||
*/
|
||||
nsResourceSet mBindingDependencies;
|
||||
|
||||
PRInt32 AddRef() { return ++mRefCnt; }
|
||||
|
||||
PRInt32 Release() {
|
||||
NS_PRECONDITION(mRefCnt > 0, "bad refcnt");
|
||||
PRInt32 refcnt = --mRefCnt;
|
||||
if (refcnt == 0) delete this;
|
||||
return refcnt; }
|
||||
|
||||
protected:
|
||||
~nsTemplateMatch() { MOZ_COUNT_DTOR(nsTemplateMatch); }
|
||||
|
||||
private:
|
||||
nsTemplateMatch(const nsTemplateMatch& aMatch); // not to be implemented
|
||||
void operator=(const nsTemplateMatch& aMatch); // not to be implemented
|
||||
};
|
||||
|
||||
#endif // nsConflictSet_h__
|
||||
|
197
content/xul/templates/src/nsTemplateMatchSet.cpp
Normal file
197
content/xul/templates/src/nsTemplateMatchSet.cpp
Normal file
@ -0,0 +1,197 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#include "nsTemplateMatchSet.h"
|
||||
#include "nsTemplateRule.h"
|
||||
|
||||
PLHashAllocOps nsTemplateMatchSet::gAllocOps = {
|
||||
AllocTable, FreeTable, AllocEntry, FreeEntry };
|
||||
|
||||
|
||||
nsTemplateMatchSet::nsTemplateMatchSet()
|
||||
: mMatches(nsnull), mCount(0), mLastMatch(nsnull)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsTemplateMatchSet);
|
||||
mHead.mNext = mHead.mPrev = &mHead;
|
||||
}
|
||||
|
||||
#ifdef NEED_CPP_UNUSED_IMPLEMENTATIONS
|
||||
nsTemplateMatchSet::nsTemplateMatchSet(const nsTemplateMatchSet& aMatchSet) {}
|
||||
void nsTemplateMatchSet::operator=(const nsTemplateMatchSet& aMatchSet) {}
|
||||
#endif
|
||||
|
||||
nsTemplateMatchSet::~nsTemplateMatchSet()
|
||||
{
|
||||
if (mMatches) {
|
||||
PL_HashTableDestroy(mMatches);
|
||||
mMatches = nsnull;
|
||||
}
|
||||
|
||||
Clear();
|
||||
MOZ_COUNT_DTOR(nsTemplateMatchSet);
|
||||
}
|
||||
|
||||
|
||||
nsTemplateMatchSet::Iterator
|
||||
nsTemplateMatchSet::Insert(nsFixedSizeAllocator& aPool, Iterator aIterator, nsTemplateMatch* aMatch)
|
||||
{
|
||||
if (++mCount > kHashTableThreshold && !mMatches) {
|
||||
// If we've exceeded a high-water mark, then hash everything.
|
||||
mMatches = PL_NewHashTable(2 * kHashTableThreshold,
|
||||
HashMatch,
|
||||
CompareMatches,
|
||||
PL_CompareValues,
|
||||
&gAllocOps,
|
||||
&aPool);
|
||||
|
||||
Iterator last = Last();
|
||||
for (Iterator match = First(); match != last; ++match) {
|
||||
// The sole purpose of the hashtable is to make
|
||||
// determining nsTemplateMatchSet membership an O(1)
|
||||
// operation. Since the linked list is maintaining
|
||||
// storage, we can use a pointer to the nsTemplateMatch object
|
||||
// (obtained from the iterator) as the key. We'll just
|
||||
// stuff something non-zero into the table as a value.
|
||||
PL_HashTableAdd(mMatches, match.operator->(), match.mCurrent);
|
||||
}
|
||||
}
|
||||
|
||||
List* newelement = new (aPool) List();
|
||||
if (newelement) {
|
||||
newelement->mMatch = aMatch;
|
||||
aMatch->AddRef();
|
||||
|
||||
aIterator.mCurrent->mPrev->mNext = newelement;
|
||||
|
||||
newelement->mNext = aIterator.mCurrent;
|
||||
newelement->mPrev = aIterator.mCurrent->mPrev;
|
||||
|
||||
aIterator.mCurrent->mPrev = newelement;
|
||||
|
||||
if (mMatches)
|
||||
PL_HashTableAdd(mMatches, newelement->mMatch, newelement);
|
||||
}
|
||||
return aIterator;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsTemplateMatchSet::CopyInto(nsTemplateMatchSet& aMatchSet, nsFixedSizeAllocator& aPool) const
|
||||
{
|
||||
aMatchSet.Clear();
|
||||
for (nsTemplateMatchSet::ConstIterator match = First(); match != Last(); ++match)
|
||||
aMatchSet.Add(aPool, NS_CONST_CAST(nsTemplateMatch*, match.operator->()));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsTemplateMatchSet::Clear()
|
||||
{
|
||||
Iterator match = First();
|
||||
while (match != Last())
|
||||
Erase(match++);
|
||||
}
|
||||
|
||||
nsTemplateMatchSet::ConstIterator
|
||||
nsTemplateMatchSet::Find(const nsTemplateMatch& aMatch) const
|
||||
{
|
||||
if (mMatches) {
|
||||
List* list = NS_STATIC_CAST(List*, PL_HashTableLookup(mMatches, &aMatch));
|
||||
if (list)
|
||||
return ConstIterator(list);
|
||||
}
|
||||
else {
|
||||
ConstIterator last = Last();
|
||||
for (ConstIterator i = First(); i != last; ++i) {
|
||||
if (*i == aMatch)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return Last();
|
||||
}
|
||||
|
||||
nsTemplateMatchSet::Iterator
|
||||
nsTemplateMatchSet::Find(const nsTemplateMatch& aMatch)
|
||||
{
|
||||
if (mMatches) {
|
||||
List* list = NS_STATIC_CAST(List*, PL_HashTableLookup(mMatches, &aMatch));
|
||||
if (list)
|
||||
return Iterator(list);
|
||||
}
|
||||
else {
|
||||
Iterator last = Last();
|
||||
for (Iterator i = First(); i != last; ++i) {
|
||||
if (*i == aMatch)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return Last();
|
||||
}
|
||||
|
||||
nsTemplateMatch*
|
||||
nsTemplateMatchSet::FindMatchWithHighestPriority() const
|
||||
{
|
||||
// Find the rule with the "highest priority"; i.e., the rule with
|
||||
// the lowest value for GetPriority().
|
||||
nsTemplateMatch* result = nsnull;
|
||||
PRInt32 max = ~(1 << 31); // XXXwaterson portable?
|
||||
for (ConstIterator match = First(); match != Last(); ++match) {
|
||||
PRInt32 priority = match->mRule->GetPriority();
|
||||
if (priority < max) {
|
||||
result = NS_CONST_CAST(nsTemplateMatch*, match.operator->());
|
||||
max = priority;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
nsTemplateMatchSet::Iterator
|
||||
nsTemplateMatchSet::Erase(Iterator aIterator)
|
||||
{
|
||||
Iterator result = aIterator;
|
||||
|
||||
--mCount;
|
||||
|
||||
if (mMatches)
|
||||
PL_HashTableRemove(mMatches, aIterator.operator->());
|
||||
|
||||
++result;
|
||||
aIterator.mCurrent->mNext->mPrev = aIterator.mCurrent->mPrev;
|
||||
aIterator.mCurrent->mPrev->mNext = aIterator.mCurrent->mNext;
|
||||
|
||||
aIterator->Release();
|
||||
delete aIterator.mCurrent;
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
nsTemplateMatchSet::Remove(nsTemplateMatch* aMatch)
|
||||
{
|
||||
Iterator doomed = Find(*aMatch);
|
||||
if (doomed != Last())
|
||||
Erase(doomed);
|
||||
}
|
||||
|
230
content/xul/templates/src/nsTemplateMatchSet.h
Normal file
230
content/xul/templates/src/nsTemplateMatchSet.h
Normal file
@ -0,0 +1,230 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#ifndef nsTemplateMatchSet_h__
|
||||
#define nsTemplateMatchSet_h__
|
||||
|
||||
#include "nsRuleNetwork.h"
|
||||
#include "nsFixedSizeAllocator.h"
|
||||
#include "nsTemplateMatch.h"
|
||||
#include "plhash.h"
|
||||
|
||||
/**
|
||||
* A collection of unique nsTemplateMatch objects.
|
||||
*/
|
||||
class nsTemplateMatchSet
|
||||
{
|
||||
public:
|
||||
class ConstIterator;
|
||||
friend class ConstIterator;
|
||||
|
||||
class Iterator;
|
||||
friend class Iterator;
|
||||
|
||||
nsTemplateMatchSet();
|
||||
~nsTemplateMatchSet();
|
||||
|
||||
private:
|
||||
nsTemplateMatchSet(const nsTemplateMatchSet& aMatchSet); // XXX not to be implemented
|
||||
void operator=(const nsTemplateMatchSet& aMatchSet); // XXX not to be implemented
|
||||
|
||||
protected:
|
||||
struct List {
|
||||
static void* operator new(size_t aSize, nsFixedSizeAllocator& aPool) {
|
||||
return aPool.Alloc(aSize); }
|
||||
|
||||
static void operator delete(void* aPtr, size_t aSize) {
|
||||
nsFixedSizeAllocator::Free(aPtr, aSize); }
|
||||
|
||||
nsTemplateMatch* mMatch;
|
||||
List* mNext;
|
||||
List* mPrev;
|
||||
};
|
||||
|
||||
List mHead;
|
||||
|
||||
// Lazily created when we pass a size threshold.
|
||||
PLHashTable* mMatches;
|
||||
PRInt32 mCount;
|
||||
|
||||
const nsTemplateMatch* mLastMatch;
|
||||
|
||||
static PLHashNumber PR_CALLBACK HashMatch(const void* aMatch) {
|
||||
const nsTemplateMatch* match = NS_STATIC_CAST(const nsTemplateMatch*, aMatch);
|
||||
return Instantiation::Hash(&match->mInstantiation) ^ (PLHashNumber(match->mRule) >> 2); }
|
||||
|
||||
static PRIntn PR_CALLBACK CompareMatches(const void* aLeft, const void* aRight) {
|
||||
const nsTemplateMatch* left = NS_STATIC_CAST(const nsTemplateMatch*, aLeft);
|
||||
const nsTemplateMatch* right = NS_STATIC_CAST(const nsTemplateMatch*, aRight);
|
||||
return *left == *right; }
|
||||
|
||||
enum { kHashTableThreshold = 8 };
|
||||
|
||||
static PLHashAllocOps gAllocOps;
|
||||
|
||||
static void* PR_CALLBACK AllocTable(void* aPool, PRSize aSize) {
|
||||
return new char[aSize]; }
|
||||
|
||||
static void PR_CALLBACK FreeTable(void* aPool, void* aItem) {
|
||||
delete[] NS_STATIC_CAST(char*, aItem); }
|
||||
|
||||
static PLHashEntry* PR_CALLBACK AllocEntry(void* aPool, const void* aKey) {
|
||||
nsFixedSizeAllocator* pool = NS_STATIC_CAST(nsFixedSizeAllocator*, aPool);
|
||||
PLHashEntry* entry = NS_STATIC_CAST(PLHashEntry*, pool->Alloc(sizeof(PLHashEntry)));
|
||||
return entry; }
|
||||
|
||||
static void PR_CALLBACK FreeEntry(void* aPool, PLHashEntry* aEntry, PRUintn aFlag) {
|
||||
if (aFlag == HT_FREE_ENTRY)
|
||||
nsFixedSizeAllocator::Free(aEntry, sizeof(PLHashEntry)); }
|
||||
|
||||
public:
|
||||
// Used to initialize the nsFixedSizeAllocator that's used to pool
|
||||
// entries.
|
||||
enum {
|
||||
kEntrySize = sizeof(List),
|
||||
kIndexSize = sizeof(PLHashEntry)
|
||||
};
|
||||
|
||||
class ConstIterator {
|
||||
protected:
|
||||
friend class Iterator; // XXXwaterson so broken.
|
||||
List* mCurrent;
|
||||
|
||||
public:
|
||||
ConstIterator() : mCurrent(nsnull) {}
|
||||
|
||||
ConstIterator(List* aCurrent) : mCurrent(aCurrent) {}
|
||||
|
||||
ConstIterator(const ConstIterator& aConstIterator)
|
||||
: mCurrent(aConstIterator.mCurrent) {}
|
||||
|
||||
ConstIterator& operator=(const ConstIterator& aConstIterator) {
|
||||
mCurrent = aConstIterator.mCurrent;
|
||||
return *this; }
|
||||
|
||||
ConstIterator& operator++() {
|
||||
mCurrent = mCurrent->mNext;
|
||||
return *this; }
|
||||
|
||||
ConstIterator operator++(int) {
|
||||
ConstIterator result(*this);
|
||||
mCurrent = mCurrent->mNext;
|
||||
return result; }
|
||||
|
||||
ConstIterator& operator--() {
|
||||
mCurrent = mCurrent->mPrev;
|
||||
return *this; }
|
||||
|
||||
ConstIterator operator--(int) {
|
||||
ConstIterator result(*this);
|
||||
mCurrent = mCurrent->mPrev;
|
||||
return result; }
|
||||
|
||||
const nsTemplateMatch& operator*() const {
|
||||
return *mCurrent->mMatch; }
|
||||
|
||||
const nsTemplateMatch* operator->() const {
|
||||
return mCurrent->mMatch; }
|
||||
|
||||
PRBool operator==(const ConstIterator& aConstIterator) const {
|
||||
return mCurrent == aConstIterator.mCurrent; }
|
||||
|
||||
PRBool operator!=(const ConstIterator& aConstIterator) const {
|
||||
return mCurrent != aConstIterator.mCurrent; }
|
||||
};
|
||||
|
||||
ConstIterator First() const { return ConstIterator(mHead.mNext); }
|
||||
ConstIterator Last() const { return ConstIterator(NS_CONST_CAST(List*, &mHead)); }
|
||||
|
||||
class Iterator : public ConstIterator {
|
||||
public:
|
||||
Iterator() {}
|
||||
|
||||
Iterator(List* aCurrent) : ConstIterator(aCurrent) {}
|
||||
|
||||
Iterator& operator++() {
|
||||
mCurrent = mCurrent->mNext;
|
||||
return *this; }
|
||||
|
||||
Iterator operator++(int) {
|
||||
Iterator result(*this);
|
||||
mCurrent = mCurrent->mNext;
|
||||
return result; }
|
||||
|
||||
Iterator& operator--() {
|
||||
mCurrent = mCurrent->mPrev;
|
||||
return *this; }
|
||||
|
||||
Iterator operator--(int) {
|
||||
Iterator result(*this);
|
||||
mCurrent = mCurrent->mPrev;
|
||||
return result; }
|
||||
|
||||
nsTemplateMatch& operator*() const {
|
||||
return *mCurrent->mMatch; }
|
||||
|
||||
nsTemplateMatch* operator->() const {
|
||||
return mCurrent->mMatch; }
|
||||
|
||||
PRBool operator==(const ConstIterator& aConstIterator) const {
|
||||
return mCurrent == aConstIterator.mCurrent; }
|
||||
|
||||
PRBool operator!=(const ConstIterator& aConstIterator) const {
|
||||
return mCurrent != aConstIterator.mCurrent; }
|
||||
|
||||
friend class nsTemplateMatchSet;
|
||||
};
|
||||
|
||||
Iterator First() { return Iterator(mHead.mNext); }
|
||||
Iterator Last() { return Iterator(&mHead); }
|
||||
|
||||
PRBool Empty() const { return First() == Last(); }
|
||||
|
||||
PRInt32 Count() const { return mCount; }
|
||||
|
||||
ConstIterator Find(const nsTemplateMatch& aMatch) const;
|
||||
Iterator Find(const nsTemplateMatch& aMatch);
|
||||
|
||||
PRBool Contains(const nsTemplateMatch& aMatch) const {
|
||||
return Find(aMatch) != Last(); }
|
||||
|
||||
nsTemplateMatch* FindMatchWithHighestPriority() const;
|
||||
|
||||
const nsTemplateMatch* GetLastMatch() const { return mLastMatch; }
|
||||
void SetLastMatch(const nsTemplateMatch* aMatch) { mLastMatch = aMatch; }
|
||||
|
||||
Iterator Insert(nsFixedSizeAllocator& aPool, Iterator aIterator, nsTemplateMatch* aMatch);
|
||||
|
||||
Iterator Add(nsFixedSizeAllocator& aPool, nsTemplateMatch* aMatch) {
|
||||
return Insert(aPool, Last(), aMatch); }
|
||||
|
||||
nsresult CopyInto(nsTemplateMatchSet& aMatchSet, nsFixedSizeAllocator& aPool) const;
|
||||
|
||||
void Clear();
|
||||
|
||||
Iterator Erase(Iterator aIterator);
|
||||
|
||||
void Remove(nsTemplateMatch* aMatch);
|
||||
};
|
||||
|
||||
#endif // nsTemplateMatchSet_h__
|
330
content/xul/templates/src/nsTemplateRule.cpp
Normal file
330
content/xul/templates/src/nsTemplateRule.cpp
Normal file
@ -0,0 +1,330 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#include "nsTemplateRule.h"
|
||||
#include "nsTemplateMatch.h"
|
||||
#include "nsRuleNetwork.h"
|
||||
#include "nsConflictSet.h"
|
||||
#include "nsVoidArray.h"
|
||||
|
||||
nsTemplateRule::~nsTemplateRule()
|
||||
{
|
||||
MOZ_COUNT_DTOR(nsTemplateRule);
|
||||
|
||||
while (mBindings) {
|
||||
Binding* doomed = mBindings;
|
||||
mBindings = mBindings->mNext;
|
||||
delete doomed;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsTemplateRule::GetContent(nsIContent** aResult) const
|
||||
{
|
||||
*aResult = mContent.get();
|
||||
NS_IF_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsTemplateRule::HasBinding(PRInt32 aSourceVariable,
|
||||
nsIRDFResource* aProperty,
|
||||
PRInt32 aTargetVariable) const
|
||||
{
|
||||
for (Binding* binding = mBindings; binding != nsnull; binding = binding->mNext) {
|
||||
if ((binding->mSourceVariable == aSourceVariable) &&
|
||||
(binding->mProperty == aProperty) &&
|
||||
(binding->mTargetVariable == aTargetVariable))
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTemplateRule::AddBinding(PRInt32 aSourceVariable,
|
||||
nsIRDFResource* aProperty,
|
||||
PRInt32 aTargetVariable)
|
||||
{
|
||||
NS_PRECONDITION(aSourceVariable != 0, "no source variable!");
|
||||
if (! aSourceVariable)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
NS_PRECONDITION(aProperty != nsnull, "null ptr");
|
||||
if (! aProperty)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
NS_PRECONDITION(aTargetVariable != 0, "no target variable!");
|
||||
if (! aTargetVariable)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
NS_ASSERTION(! HasBinding(aSourceVariable, aProperty, aTargetVariable),
|
||||
"binding added twice");
|
||||
|
||||
Binding* newbinding = new Binding;
|
||||
if (! newbinding)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
newbinding->mSourceVariable = aSourceVariable;
|
||||
newbinding->mProperty = aProperty;
|
||||
newbinding->mTargetVariable = aTargetVariable;
|
||||
newbinding->mParent = nsnull;
|
||||
|
||||
Binding* binding = mBindings;
|
||||
Binding** link = &mBindings;
|
||||
|
||||
// Insert it at the end, unless we detect that an existing
|
||||
// binding's source is dependent on the newbinding's target.
|
||||
//
|
||||
// XXXwaterson this isn't enough to make sure that we get all of
|
||||
// the dependencies worked out right, but it'll do for now. For
|
||||
// example, if you have (ab, bc, cd), and insert them in the order
|
||||
// (cd, ab, bc), you'll get (bc, cd, ab). The good news is, if the
|
||||
// person uses a natural ordering when writing the XUL, it'll all
|
||||
// work out ok.
|
||||
while (binding) {
|
||||
if (binding->mSourceVariable == newbinding->mTargetVariable) {
|
||||
binding->mParent = newbinding;
|
||||
break;
|
||||
}
|
||||
else if (binding->mTargetVariable == newbinding->mSourceVariable) {
|
||||
newbinding->mParent = binding;
|
||||
}
|
||||
|
||||
link = &binding->mNext;
|
||||
binding = binding->mNext;
|
||||
}
|
||||
|
||||
// Insert the newbinding
|
||||
*link = newbinding;
|
||||
newbinding->mNext = binding;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsTemplateRule::DependsOn(PRInt32 aChildVariable, PRInt32 aParentVariable) const
|
||||
{
|
||||
// Determine whether the value for aChildVariable will depend on
|
||||
// the value for aParentVariable by examining the rule's bindings.
|
||||
Binding* child = mBindings;
|
||||
while ((child != nsnull) && (child->mSourceVariable != aChildVariable))
|
||||
child = child->mNext;
|
||||
|
||||
if (! child)
|
||||
return PR_FALSE;
|
||||
|
||||
Binding* parent = child->mParent;
|
||||
while (parent != nsnull) {
|
||||
if (parent->mSourceVariable == aParentVariable)
|
||||
return PR_TRUE;
|
||||
|
||||
parent = parent->mParent;
|
||||
}
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
// nsTemplateRule
|
||||
//
|
||||
|
||||
nsresult
|
||||
nsTemplateRule::InitBindings(nsConflictSet& aConflictSet, nsTemplateMatch* aMatch) const
|
||||
{
|
||||
// Initialize a match's binding dependencies, so we can handle
|
||||
// updates and queries later.
|
||||
|
||||
for (Binding* binding = mBindings; binding != nsnull; binding = binding->mNext) {
|
||||
// Add a dependency for bindings whose source variable comes
|
||||
// from one of the <conditions>.
|
||||
Value sourceValue;
|
||||
PRBool hasBinding =
|
||||
aMatch->mInstantiation.mAssignments.GetAssignmentFor(binding->mSourceVariable, &sourceValue);
|
||||
|
||||
if (hasBinding)
|
||||
aConflictSet.AddBindingDependency(aMatch, VALUE_TO_IRDFRESOURCE(sourceValue));
|
||||
|
||||
// If this binding is dependant on another binding, then we
|
||||
// need to eagerly compute its source variable's assignment.
|
||||
if (binding->mParent) {
|
||||
Value value;
|
||||
ComputeAssignmentFor(aConflictSet, aMatch, binding->mSourceVariable, &value);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTemplateRule::RecomputeBindings(nsConflictSet& aConflictSet,
|
||||
nsTemplateMatch* aMatch,
|
||||
nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aOldTarget,
|
||||
nsIRDFNode* aNewTarget,
|
||||
VariableSet& aModifiedVars) const
|
||||
{
|
||||
// Given a match with a source, property, old target, and new
|
||||
// target, compute the minimal changes to the match's bindings.
|
||||
|
||||
// A temporary, mutable collection for holding all of the
|
||||
// assignments that comprise the current match.
|
||||
nsAutoVoidArray assignments;
|
||||
|
||||
{
|
||||
// Collect -all- of the assignments in match into a temporary,
|
||||
// mutable collection
|
||||
nsAssignmentSet::ConstIterator last = aMatch->mAssignments.Last();
|
||||
for (nsAssignmentSet::ConstIterator binding = aMatch->mAssignments.First(); binding != last; ++binding)
|
||||
assignments.AppendElement(new nsAssignment(*binding));
|
||||
|
||||
// Truncate the match's assignments to only include
|
||||
// assignments made via condition tests. We'll add back
|
||||
// assignments as they are recomputed.
|
||||
aMatch->mAssignments = aMatch->mInstantiation.mAssignments;
|
||||
}
|
||||
|
||||
PRInt32 i;
|
||||
|
||||
// Iterate through each assignment, looking for the assignment
|
||||
// whose value corresponds to the source of the assertion that's
|
||||
// changing.
|
||||
for (i = 0; i < assignments.Count(); ++i) {
|
||||
nsAssignment* assignment = NS_STATIC_CAST(nsAssignment*, assignments[i]);
|
||||
if ((assignment->mValue.GetType() == Value::eISupports) &&
|
||||
(NS_STATIC_CAST(nsISupports*, assignment->mValue) == aSource)) {
|
||||
|
||||
// ...When we find it, look for binding's whose source
|
||||
// variable depends on the assignment's variable
|
||||
for (Binding* binding = mBindings; binding != nsnull; binding = binding->mNext) {
|
||||
if ((binding->mSourceVariable != assignment->mVariable) ||
|
||||
(binding->mProperty.get() != aProperty))
|
||||
continue;
|
||||
|
||||
// Found one. Now we iterate through the assignments,
|
||||
// doing fixup.
|
||||
for (PRInt32 j = 0; j < assignments.Count(); ++j) {
|
||||
nsAssignment* dependent = NS_STATIC_CAST(nsAssignment*, assignments[j]);
|
||||
if (dependent->mVariable == binding->mTargetVariable) {
|
||||
// The assignment's variable is the target
|
||||
// varible for the binding: we can update it
|
||||
// in-place.
|
||||
dependent->mValue = Value(aNewTarget);
|
||||
aModifiedVars.Add(dependent->mVariable);
|
||||
}
|
||||
else if (DependsOn(dependent->mVariable, binding->mTargetVariable)) {
|
||||
// The assignment's variable depends on the
|
||||
// binding's target variable, which is
|
||||
// changing. Rip it out.
|
||||
aConflictSet.RemoveBindingDependency(aMatch, VALUE_TO_IRDFRESOURCE(dependent->mValue));
|
||||
|
||||
delete dependent;
|
||||
assignments.RemoveElementAt(j--);
|
||||
|
||||
aModifiedVars.Add(dependent->mVariable);
|
||||
}
|
||||
else {
|
||||
// The dependent variable is irrelevant. Leave
|
||||
// it alone.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now our set of assignments will contain the original
|
||||
// assignments from the conditions, any unchanged assignments, and
|
||||
// the single assignment that was updated by iterating through the
|
||||
// bindings.
|
||||
//
|
||||
// Add these assignments *back* to the match (modulo the ones
|
||||
// already in the conditions).
|
||||
//
|
||||
// The values for any dependent assignments that we've ripped out
|
||||
// will be computed the next time that somebody asks us for them.
|
||||
for (i = assignments.Count() - 1; i >= 0; --i) {
|
||||
nsAssignment* assignment = NS_STATIC_CAST(nsAssignment*, assignments[i]);
|
||||
|
||||
// Only add it if it's not already in the match's conditions
|
||||
if (! aMatch->mInstantiation.mAssignments.HasAssignment(*assignment)) {
|
||||
aMatch->mAssignments.Add(*assignment);
|
||||
}
|
||||
|
||||
delete assignment;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsTemplateRule::ComputeAssignmentFor(nsConflictSet& aConflictSet,
|
||||
nsTemplateMatch* aMatch,
|
||||
PRInt32 aVariable,
|
||||
Value* aValue) const
|
||||
{
|
||||
// Compute the value assignment for an arbitrary variable in a
|
||||
// match. Potentially fill in dependencies if they haven't been
|
||||
// resolved yet.
|
||||
for (Binding* binding = mBindings; binding != nsnull; binding = binding->mNext) {
|
||||
if (binding->mTargetVariable != aVariable)
|
||||
continue;
|
||||
|
||||
// Potentially recur to find the value of the source.
|
||||
//
|
||||
// XXXwaterson this is sloppy, and could be dealt with more
|
||||
// directly by following binding->mParent.
|
||||
Value sourceValue;
|
||||
PRBool hasSourceAssignment =
|
||||
aMatch->GetAssignmentFor(aConflictSet, binding->mSourceVariable, &sourceValue);
|
||||
|
||||
if (! hasSourceAssignment)
|
||||
return PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIRDFNode> target;
|
||||
|
||||
nsIRDFResource* source = VALUE_TO_IRDFRESOURCE(sourceValue);
|
||||
|
||||
if (source) {
|
||||
mDataSource->GetTarget(source,
|
||||
binding->mProperty,
|
||||
PR_TRUE,
|
||||
getter_AddRefs(target));
|
||||
|
||||
// Store the assignment in the match so we won't need to
|
||||
// retrieve it again.
|
||||
nsAssignment assignment(binding->mTargetVariable, Value(target.get()));
|
||||
aMatch->mAssignments.Add(assignment);
|
||||
|
||||
// Add a dependency on the source, so we'll recompute the
|
||||
// assignment if somebody tweaks it.
|
||||
aConflictSet.AddBindingDependency(aMatch, source);
|
||||
}
|
||||
|
||||
*aValue = target.get();
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
236
content/xul/templates/src/nsTemplateRule.h
Normal file
236
content/xul/templates/src/nsTemplateRule.h
Normal file
@ -0,0 +1,236 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#ifndef nsTemplateRule_h__
|
||||
#define nsTemplateRule_h__
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIRDFDataSource.h"
|
||||
#include "nsIRDFResource.h"
|
||||
#include "nsIContent.h"
|
||||
|
||||
class nsConflictSet;
|
||||
class nsTemplateMatch;
|
||||
class Value;
|
||||
class VariableSet;
|
||||
|
||||
/**
|
||||
* A rule consists of:
|
||||
*
|
||||
* - Conditions, a set of unbound variables with consistency
|
||||
* constraints that specify the values that each variable can
|
||||
* assume. The conditions must be completely and consistently
|
||||
* "bound" for the rule to be considered "matched".
|
||||
*
|
||||
* - Bindings, a set of unbound variables with consistency constraints
|
||||
* that specify the values that each variable can assume. Unlike the
|
||||
* conditions, the bindings need not be bound for the rule to be
|
||||
* considered matched.
|
||||
*
|
||||
* - Content that should be constructed when the rule is "activated".
|
||||
*
|
||||
* - Priority, which helps to determine which rule should be
|
||||
* considered "active" if several rules "match".
|
||||
*
|
||||
*/
|
||||
class nsTemplateRule
|
||||
{
|
||||
public:
|
||||
nsTemplateRule(nsIRDFDataSource* aDataSource,
|
||||
nsIContent* aContent,
|
||||
PRInt32 aPriority)
|
||||
: mDataSource(aDataSource),
|
||||
mContent(aContent),
|
||||
mContainerVariable(0),
|
||||
mMemberVariable(0),
|
||||
mPriority(aPriority),
|
||||
mCount(0),
|
||||
mCapacity(0),
|
||||
mBindings(nsnull)
|
||||
{ MOZ_COUNT_CTOR(nsTemplateRule); }
|
||||
|
||||
~nsTemplateRule();
|
||||
|
||||
/**
|
||||
* Return the content node that this rule was constructed from.
|
||||
* @param aResult an out parameter, which will contain the content node
|
||||
* that this rule was constructed from
|
||||
* @return NS_OK if no errors occur.
|
||||
*/
|
||||
nsresult GetContent(nsIContent** aResult) const;
|
||||
|
||||
/**
|
||||
* Set the variable which should be used as the "container
|
||||
* variable" in this rule. The container variable will be bound to
|
||||
* an RDF resource that is the parent of the member resources.
|
||||
* @param aContainerVariable the variable that should be used as the
|
||||
* "container variable" in this rule
|
||||
*/
|
||||
void SetContainerVariable(PRInt32 aContainerVariable) {
|
||||
mContainerVariable = aContainerVariable; }
|
||||
|
||||
/**
|
||||
* Retrieve the variable that this rule uses as its "container variable".
|
||||
* @return the variable that this rule uses as its "container variable".
|
||||
*/
|
||||
PRInt32 GetContainerVariable() const {
|
||||
return mContainerVariable; }
|
||||
|
||||
/**
|
||||
* Set the variable which should be used as the "member variable"
|
||||
* in this rule. The member variable will be bound to an RDF
|
||||
* resource that is the child of the container resource.
|
||||
* @param aMemberVariable the variable that should be used as the
|
||||
* "member variable" in this rule.
|
||||
*/
|
||||
void SetMemberVariable(PRInt32 aMemberVariable) {
|
||||
mMemberVariable = aMemberVariable; }
|
||||
|
||||
/**
|
||||
* Retrieve the variable that this rule uses as its "member variable".
|
||||
* @return the variable that this rule uses as its "member variable"
|
||||
*/
|
||||
PRInt32 GetMemberVariable() const {
|
||||
return mMemberVariable; }
|
||||
|
||||
/**
|
||||
* Retrieve the "priority" of the rule with respect to the
|
||||
* other rules in the template
|
||||
* @return the rule's priority, lower values mean "use this first".
|
||||
*/
|
||||
PRInt32 GetPriority() const {
|
||||
return mPriority; }
|
||||
|
||||
/**
|
||||
* Determine if the rule has the specified binding
|
||||
*/
|
||||
PRBool
|
||||
HasBinding(PRInt32 aSourceVariable,
|
||||
nsIRDFResource* aProperty,
|
||||
PRInt32 aTargetVariable) const;
|
||||
|
||||
/**
|
||||
* Add a binding to the rule. A binding consists of an already-bound
|
||||
* source variable, and the RDF property that should be tested to
|
||||
* generate a target value. The target value is bound to a target
|
||||
* variable.
|
||||
*
|
||||
* @param aSourceVariable the source variable that will be used in
|
||||
* the RDF query.
|
||||
* @param aProperty the RDF property that will be used in the RDF
|
||||
* query.
|
||||
* @param aTargetVariable the variable whose value will be bound
|
||||
* to the RDF node that is returned when querying the binding
|
||||
* @return NS_OK if no errors occur.
|
||||
*/
|
||||
nsresult AddBinding(PRInt32 aSourceVariable,
|
||||
nsIRDFResource* aProperty,
|
||||
PRInt32 aTargetVariable);
|
||||
|
||||
/**
|
||||
* Initialize a match by adding necessary binding dependencies to
|
||||
* the conflict set. This will allow us to properly update the
|
||||
* match later if a value should change that the match's bindings
|
||||
* depend on.
|
||||
* @param aConflictSet the conflict set
|
||||
* @param aMatch the match we to initialize
|
||||
* @return NS_OK if no errors occur.
|
||||
*/
|
||||
nsresult InitBindings(nsConflictSet& aConflictSet, nsTemplateMatch* aMatch) const;
|
||||
|
||||
/**
|
||||
* Compute the minimal set of changes to a match's bindings that
|
||||
* must occur which the specified change is made to the RDF graph.
|
||||
* @param aConflictSet the conflict set, which we may need to manipulate
|
||||
* to update the binding dependencies.
|
||||
* @param aMatch the match for which we must recompute the bindings
|
||||
* @param aSource the "source" resource in the RDF graph
|
||||
* @param aProperty the "property" resource in the RDF graph
|
||||
* @param aOldTarget the old "target" node in the RDF graph
|
||||
* @param aNewTarget the new "target" node in the RDF graph.
|
||||
* @param aModifiedVars a VariableSet, into which this routine
|
||||
* will assign each variable whose value has changed.
|
||||
* @return NS_OK if no errors occurred.
|
||||
*/
|
||||
nsresult RecomputeBindings(nsConflictSet& aConflictSet,
|
||||
nsTemplateMatch* aMatch,
|
||||
nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aOldTarget,
|
||||
nsIRDFNode* aNewTarget,
|
||||
VariableSet& aModifiedVars) const;
|
||||
|
||||
/**
|
||||
* Compute the value to assign to an arbitrary variable in a
|
||||
* match. This may require us to work out several dependancies,
|
||||
* if there are bindings set up for this rule.
|
||||
* @param aConflictSet the conflict set; if necessary, we may add
|
||||
* a "binding dependency" to the conflict set, which will allow us
|
||||
* to correctly recompute the bindings later if they should change.
|
||||
* @param aMatch the match that provides the "seed" variable assignments,
|
||||
* which we may need to extend using the rule's bindings.
|
||||
* @param aVariable the variable for which we are to compute the
|
||||
* assignment.
|
||||
* @param aValue an out parameter that will receive the value that
|
||||
* was assigned to aVariable, if we could find one.
|
||||
* @return PR_TRUE if an assignment was found for aVariable, PR_FALSE
|
||||
* otherwise.
|
||||
*/
|
||||
PRBool ComputeAssignmentFor(nsConflictSet& aConflictSet,
|
||||
nsTemplateMatch* aMatch,
|
||||
PRInt32 aVariable,
|
||||
Value* aValue) const;
|
||||
|
||||
/**
|
||||
* Determine if one variable depends on another in the rule's
|
||||
* bindings.
|
||||
* @param aChild the dependent variable, whose value may
|
||||
* depend on the assignment of aParent.
|
||||
* @param aParent the variable whose value aChild is depending on.
|
||||
* @return PR_TRUE if aChild's assignment depends on the assignment
|
||||
* for aParent, PR_FALSE otherwise.
|
||||
*/
|
||||
PRBool DependsOn(PRInt32 aChild, PRInt32 aParent) const;
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIRDFDataSource> mDataSource;
|
||||
nsCOMPtr<nsIContent> mContent;
|
||||
PRInt32 mContainerVariable;
|
||||
PRInt32 mMemberVariable;
|
||||
PRInt32 mPriority;
|
||||
|
||||
PRInt32 mCount;
|
||||
PRInt32 mCapacity;
|
||||
|
||||
struct Binding {
|
||||
PRInt32 mSourceVariable;
|
||||
nsCOMPtr<nsIRDFResource> mProperty;
|
||||
PRInt32 mTargetVariable;
|
||||
Binding* mNext;
|
||||
Binding* mParent;
|
||||
};
|
||||
|
||||
Binding* mBindings;
|
||||
};
|
||||
|
||||
#endif // nsTemplateRule_h__
|
102
content/xul/templates/src/nsTreeRowTestNode.cpp
Normal file
102
content/xul/templates/src/nsTreeRowTestNode.cpp
Normal file
@ -0,0 +1,102 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#include "nsOutlinerRowTestNode.h"
|
||||
#include "nsOutlinerRows.h"
|
||||
#include "nsIRDFResource.h"
|
||||
#include "nsXULContentUtils.h"
|
||||
#include "nsConflictSet.h"
|
||||
|
||||
#include "prlog.h"
|
||||
#ifdef PR_LOGGING
|
||||
extern PRLogModuleInfo* gXULTemplateLog;
|
||||
#endif
|
||||
|
||||
nsOutlinerRowTestNode::nsOutlinerRowTestNode(InnerNode* aParent,
|
||||
nsConflictSet& aConflictSet,
|
||||
nsOutlinerRows& aRows,
|
||||
PRInt32 aIdVariable)
|
||||
: TestNode(aParent),
|
||||
mConflictSet(aConflictSet),
|
||||
mRows(aRows),
|
||||
mIdVariable(aIdVariable)
|
||||
{
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("nsOutlinerRowTestNode[%p]: parent=%p id-var=%d",
|
||||
this, aParent, aIdVariable));
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsOutlinerRowTestNode::FilterInstantiations(InstantiationSet& aInstantiations, void* aClosure) const
|
||||
{
|
||||
InstantiationSet::Iterator last = aInstantiations.Last();
|
||||
for (InstantiationSet::Iterator inst = aInstantiations.First(); inst != last; ++inst) {
|
||||
Value idValue;
|
||||
PRBool hasIdBinding =
|
||||
inst->mAssignments.GetAssignmentFor(mIdVariable, &idValue);
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
if (PR_LOG_TEST(gXULTemplateLog, PR_LOG_DEBUG)) {
|
||||
const char* id = "(unbound)";
|
||||
if (hasIdBinding)
|
||||
VALUE_TO_IRDFRESOURCE(idValue)->GetValueConst(&id);
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
|
||||
("nsOutlinerRowTestNode[%p]: FilterInstantiations() id=[%s]",
|
||||
this, id));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (hasIdBinding) {
|
||||
nsIRDFResource* container = VALUE_TO_IRDFRESOURCE(idValue);
|
||||
|
||||
// Is the row in the outliner?
|
||||
if ((container == mRows.GetRootResource()) ||
|
||||
(mRows.Find(mConflictSet, container) != mRows.Last())) {
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG, (" => passed"));
|
||||
Element* element = new (mConflictSet.GetPool())
|
||||
Element(container);
|
||||
|
||||
if (! element)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
inst->AddSupportingElement(element);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
PR_LOG(gXULTemplateLog, PR_LOG_DEBUG, (" => failed"));
|
||||
aInstantiations.Erase(inst--);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsOutlinerRowTestNode::GetAncestorVariables(VariableSet& aVariables) const
|
||||
{
|
||||
aVariables.Add(mIdVariable);
|
||||
return TestNode::GetAncestorVariables(aVariables);
|
||||
}
|
90
content/xul/templates/src/nsTreeRowTestNode.h
Normal file
90
content/xul/templates/src/nsTreeRowTestNode.h
Normal file
@ -0,0 +1,90 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#ifndef nsOutlinerRowTestNode_h__
|
||||
#define nsOutlinerRowTestNode_h__
|
||||
|
||||
#include "nsFixedSizeAllocator.h"
|
||||
#include "nsRuleNetwork.h"
|
||||
#include "nsIRDFResource.h"
|
||||
class nsConflictSet;
|
||||
class nsOutlinerRows;
|
||||
|
||||
class nsOutlinerRowTestNode : public TestNode
|
||||
{
|
||||
public:
|
||||
enum { kRoot = -1 };
|
||||
|
||||
nsOutlinerRowTestNode(InnerNode* aParent,
|
||||
nsConflictSet& aConflictSet,
|
||||
nsOutlinerRows& aRows,
|
||||
PRInt32 aIdVariable);
|
||||
|
||||
virtual nsresult
|
||||
FilterInstantiations(InstantiationSet& aInstantiations, void* aClosure) const;
|
||||
|
||||
virtual nsresult
|
||||
GetAncestorVariables(VariableSet& aVariables) const;
|
||||
|
||||
class Element : public MemoryElement {
|
||||
public:
|
||||
static void* operator new(size_t aSize, nsFixedSizeAllocator& aAllocator) {
|
||||
return aAllocator.Alloc(aSize); }
|
||||
|
||||
static void operator delete(void* aPtr, size_t aSize) {
|
||||
nsFixedSizeAllocator::Free(aPtr, aSize); }
|
||||
|
||||
Element(nsIRDFResource* aResource)
|
||||
: mResource(aResource) {
|
||||
MOZ_COUNT_CTOR(nsOutlinerRowTestNode::Element); }
|
||||
|
||||
virtual ~Element() { MOZ_COUNT_DTOR(nsOutlinerRowTestNode::Element); }
|
||||
|
||||
virtual const char* Type() const {
|
||||
return "nsOutlinerRowTestNode::Element"; }
|
||||
|
||||
virtual PLHashNumber Hash() const {
|
||||
return PLHashNumber(mResource.get()) >> 2; }
|
||||
|
||||
virtual PRBool Equals(const MemoryElement& aElement) const {
|
||||
if (aElement.Type() == Type()) {
|
||||
const Element& element = NS_STATIC_CAST(const Element&, aElement);
|
||||
return mResource == element.mResource;
|
||||
}
|
||||
return PR_FALSE; }
|
||||
|
||||
virtual MemoryElement* Clone(void* aPool) const {
|
||||
return new (*NS_STATIC_CAST(nsFixedSizeAllocator*, aPool))
|
||||
Element(mResource); }
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIRDFResource> mResource;
|
||||
};
|
||||
|
||||
protected:
|
||||
nsConflictSet& mConflictSet;
|
||||
nsOutlinerRows& mRows;
|
||||
PRInt32 mIdVariable;
|
||||
};
|
||||
|
||||
#endif // nsOutlinerRowTestNode_h__
|
412
content/xul/templates/src/nsTreeRows.cpp
Normal file
412
content/xul/templates/src/nsTreeRows.cpp
Normal file
@ -0,0 +1,412 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#include "nsOutlinerRows.h"
|
||||
#include "nsTemplateMatch.h"
|
||||
#include "nsTemplateRule.h"
|
||||
|
||||
nsOutlinerRows::Subtree*
|
||||
nsOutlinerRows::EnsureSubtreeFor(Subtree* aParent,
|
||||
PRInt32 aChildIndex)
|
||||
{
|
||||
Subtree* subtree = GetSubtreeFor(aParent, aChildIndex);
|
||||
|
||||
if (! subtree) {
|
||||
subtree = aParent->mRows[aChildIndex].mSubtree = new Subtree(aParent);
|
||||
InvalidateCachedRow();
|
||||
}
|
||||
|
||||
return subtree;
|
||||
}
|
||||
|
||||
nsOutlinerRows::Subtree*
|
||||
nsOutlinerRows::GetSubtreeFor(const Subtree* aParent,
|
||||
PRInt32 aChildIndex,
|
||||
PRInt32* aSubtreeSize)
|
||||
{
|
||||
NS_PRECONDITION(aParent, "no parent");
|
||||
NS_PRECONDITION(aChildIndex >= 0, "bad child index");
|
||||
|
||||
Subtree* result = nsnull;
|
||||
|
||||
if (aChildIndex < aParent->mCount)
|
||||
result = aParent->mRows[aChildIndex].mSubtree;
|
||||
|
||||
if (aSubtreeSize)
|
||||
*aSubtreeSize = result ? result->mSubtreeSize : 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
nsOutlinerRows::RemoveSubtreeFor(Subtree* aParent, PRInt32 aChildIndex)
|
||||
{
|
||||
NS_PRECONDITION(aParent, "no parent");
|
||||
NS_PRECONDITION(aChildIndex >= 0 && aChildIndex < aParent->mCount, "bad child index");
|
||||
|
||||
Row& row = aParent->mRows[aChildIndex];
|
||||
|
||||
if (row.mSubtree) {
|
||||
PRInt32 subtreeSize = row.mSubtree->GetSubtreeSize();
|
||||
|
||||
delete row.mSubtree;
|
||||
row.mSubtree = nsnull;
|
||||
|
||||
for (Subtree* subtree = aParent; subtree != nsnull; subtree = subtree->mParent)
|
||||
subtree->mSubtreeSize -= subtreeSize;
|
||||
}
|
||||
|
||||
InvalidateCachedRow();
|
||||
}
|
||||
|
||||
nsOutlinerRows::iterator
|
||||
nsOutlinerRows::First()
|
||||
{
|
||||
iterator result;
|
||||
Subtree* current = &mRoot;
|
||||
while (current && current->Count()) {
|
||||
result.Push(current, 0);
|
||||
current = GetSubtreeFor(current, 0);
|
||||
}
|
||||
result.SetRowIndex(0);
|
||||
return result;
|
||||
}
|
||||
|
||||
nsOutlinerRows::iterator
|
||||
nsOutlinerRows::Last()
|
||||
{
|
||||
iterator result;
|
||||
|
||||
// Build up a path along the rightmost edge of the tree
|
||||
Subtree* current = &mRoot;
|
||||
while (current && current->Count()) {
|
||||
result.Push(current, current->Count() - 1);
|
||||
current = GetSubtreeFor(current, current->Count() - 1);
|
||||
}
|
||||
|
||||
// Now, at the bottom rightmost leaf, advance us one off the end.
|
||||
result.mLink[result.mTop].mChildIndex++;
|
||||
|
||||
// Our row index will be the size of the root subree, plus one.
|
||||
result.SetRowIndex(mRoot.GetSubtreeSize() + 1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
nsOutlinerRows::iterator
|
||||
nsOutlinerRows::operator[](PRInt32 aRow)
|
||||
{
|
||||
// See if we're just lucky, and end up with something
|
||||
// nearby. (This tends to happen a lot due to the way that we get
|
||||
// asked for rows n' stuff.)
|
||||
PRInt32 last = mLastRow.GetRowIndex();
|
||||
if (last != -1) {
|
||||
if (aRow == last)
|
||||
return mLastRow;
|
||||
else if (last + 1 == aRow)
|
||||
return ++mLastRow;
|
||||
else if (last - 1 == aRow)
|
||||
return --mLastRow;
|
||||
}
|
||||
|
||||
// Nope. Construct a path to the specified index. This is a little
|
||||
// bit better than O(n), because we can skip over subtrees. (So it
|
||||
// ends up being approximately linear in the subtree size, instead
|
||||
// of the entire view size. But, most of the time, big views are
|
||||
// flat. Oh well.)
|
||||
iterator result;
|
||||
Subtree* current = &mRoot;
|
||||
|
||||
PRInt32 index = 0;
|
||||
result.SetRowIndex(aRow);
|
||||
|
||||
do {
|
||||
PRInt32 subtreeSize;
|
||||
Subtree* subtree = GetSubtreeFor(current, index, &subtreeSize);
|
||||
|
||||
if (subtreeSize >= aRow) {
|
||||
result.Push(current, index);
|
||||
current = subtree;
|
||||
index = 0;
|
||||
--aRow;
|
||||
}
|
||||
else {
|
||||
++index;
|
||||
aRow -= subtreeSize + 1;
|
||||
}
|
||||
} while (aRow >= 0);
|
||||
|
||||
mLastRow = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
nsOutlinerRows::iterator
|
||||
nsOutlinerRows::Find(nsConflictSet& aConflictSet, nsIRDFResource* aMember)
|
||||
{
|
||||
// XXX Mmm, scan through the rows one-by-one...
|
||||
iterator last = Last();
|
||||
iterator iter;
|
||||
|
||||
for (iter = First(); iter != last; ++iter) {
|
||||
nsTemplateMatch* match = iter->mMatch;
|
||||
|
||||
Value val;
|
||||
match->GetAssignmentFor(aConflictSet, match->mRule->GetMemberVariable(), &val);
|
||||
|
||||
if (VALUE_TO_IRDFRESOURCE(val) == aMember)
|
||||
break;
|
||||
}
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
void
|
||||
nsOutlinerRows::Clear()
|
||||
{
|
||||
mRoot.Clear();
|
||||
InvalidateCachedRow();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
// nsOutlinerRows::Subtree
|
||||
//
|
||||
|
||||
nsOutlinerRows::Subtree::~Subtree()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void
|
||||
nsOutlinerRows::Subtree::Clear()
|
||||
{
|
||||
for (PRInt32 i = mCount - 1; i >= 0; --i)
|
||||
delete mRows[i].mSubtree;
|
||||
|
||||
delete[] mRows;
|
||||
|
||||
mRows = nsnull;
|
||||
mCount = mCapacity = 0;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsOutlinerRows::Subtree::InsertRowAt(nsTemplateMatch* aMatch, PRInt32 aIndex)
|
||||
{
|
||||
if (mCount >= mCapacity || aIndex >= mCapacity) {
|
||||
PRInt32 newCapacity = NS_MAX(mCapacity * 2, aIndex + 1);
|
||||
Row* newRows = new Row[newCapacity];
|
||||
if (! newRows)
|
||||
return PR_FALSE;
|
||||
|
||||
for (PRInt32 i = mCount - 1; i >= 0; --i)
|
||||
newRows[i] = mRows[i];
|
||||
|
||||
delete[] mRows;
|
||||
|
||||
mRows = newRows;
|
||||
mCapacity = newCapacity;
|
||||
}
|
||||
|
||||
for (PRInt32 i = mCount - 1; i >= aIndex; --i)
|
||||
mRows[i + 1] = mRows[i];
|
||||
|
||||
mRows[aIndex].mMatch = aMatch;
|
||||
mRows[aIndex].mSubtree = nsnull;
|
||||
++mCount;
|
||||
|
||||
for (Subtree* subtree = this; subtree != nsnull; subtree = subtree->mParent)
|
||||
++subtree->mSubtreeSize;
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
nsOutlinerRows::Subtree::RemoveRowAt(PRInt32 aIndex)
|
||||
{
|
||||
NS_PRECONDITION(aIndex >= 0 && aIndex < Count(), "bad index");
|
||||
if (aIndex < 0 || aIndex >= Count())
|
||||
return;
|
||||
|
||||
PRInt32 subtreeSize = mRows[aIndex].mSubtree
|
||||
? mRows[aIndex].mSubtree->GetSubtreeSize()
|
||||
: 0;
|
||||
|
||||
++subtreeSize;
|
||||
|
||||
delete mRows[aIndex].mSubtree;
|
||||
|
||||
for (PRInt32 i = aIndex + 1; i < mCount; ++i)
|
||||
mRows[i - 1] = mRows[i];
|
||||
|
||||
--mCount;
|
||||
|
||||
for (Subtree* subtree = this; subtree != nsnull; subtree = subtree->mParent)
|
||||
subtree->mSubtreeSize -= subtreeSize;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
// nsOutlinerRows::iterator
|
||||
//
|
||||
|
||||
nsOutlinerRows::iterator::iterator(const iterator& aIterator)
|
||||
: mTop(aIterator.mTop),
|
||||
mRowIndex(aIterator.mRowIndex)
|
||||
{
|
||||
for (PRInt32 i = mTop; i >= 0; --i)
|
||||
mLink[i] = aIterator.mLink[i];
|
||||
}
|
||||
|
||||
nsOutlinerRows::iterator&
|
||||
nsOutlinerRows::iterator::operator=(const iterator& aIterator)
|
||||
{
|
||||
mTop = aIterator.mTop;
|
||||
mRowIndex = aIterator.mRowIndex;
|
||||
for (PRInt32 i = mTop; i >= 0; --i)
|
||||
mLink[i] = aIterator.mLink[i];
|
||||
return *this;
|
||||
}
|
||||
|
||||
void
|
||||
nsOutlinerRows::iterator::Push(Subtree* aParent, PRInt32 aChildIndex)
|
||||
{
|
||||
if (mTop < kMaxDepth - 1) {
|
||||
++mTop;
|
||||
mLink[mTop].mParent = aParent;
|
||||
mLink[mTop].mChildIndex = aChildIndex;
|
||||
}
|
||||
else
|
||||
NS_ERROR("overflow");
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsOutlinerRows::iterator::operator==(const iterator& aIterator) const
|
||||
{
|
||||
if (mTop != aIterator.mTop)
|
||||
return PR_FALSE;
|
||||
|
||||
if (mTop == -1)
|
||||
return PR_TRUE;
|
||||
|
||||
return PRBool(mLink[mTop] == aIterator.mLink[mTop]);
|
||||
}
|
||||
|
||||
void
|
||||
nsOutlinerRows::iterator::Next()
|
||||
{
|
||||
NS_PRECONDITION(mTop >= 0, "cannot increment an uninitialized iterator");
|
||||
|
||||
// Increment the absolute row index
|
||||
++mRowIndex;
|
||||
|
||||
Link& top = mLink[mTop];
|
||||
|
||||
// Is there a child subtree? If so, descend into the child
|
||||
// subtree.
|
||||
Subtree* subtree = top.GetRow().mSubtree;
|
||||
|
||||
if (subtree && subtree->Count()) {
|
||||
Push(subtree, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Have we exhausted the current subtree?
|
||||
if (top.mChildIndex >= top.mParent->Count() - 1) {
|
||||
// Yep. See if we've just iterated path the last element in
|
||||
// the tree, period. Walk back up the stack, looking for any
|
||||
// unfinished subtrees.
|
||||
PRInt32 unfinished;
|
||||
for (unfinished = mTop - 1; unfinished >= 0; --unfinished) {
|
||||
const Link& link = mLink[unfinished];
|
||||
if (link.mChildIndex < link.mParent->Count() - 1)
|
||||
break;
|
||||
}
|
||||
|
||||
// If there are no unfinished subtrees in the stack, then this
|
||||
// iterator is exhausted. Leave it in the same state that
|
||||
// Last() does.
|
||||
if (unfinished < 0)
|
||||
return;
|
||||
|
||||
// Otherwise, we ran off the end of one of the inner
|
||||
// subtrees. Pop up to the next unfinished level in the stack.
|
||||
mTop = unfinished;
|
||||
}
|
||||
|
||||
// Advance to the next child in this subtree
|
||||
++(mLink[mTop].mChildIndex);
|
||||
}
|
||||
|
||||
void
|
||||
nsOutlinerRows::iterator::Prev()
|
||||
{
|
||||
NS_PRECONDITION(mTop >= 0, "cannot increment an uninitialized iterator");
|
||||
|
||||
// Decrement the absolute row index
|
||||
--mRowIndex;
|
||||
|
||||
// Move to the previous child in this subtree
|
||||
--(mLink[mTop].mChildIndex);
|
||||
|
||||
// Have we exhausted the current subtree?
|
||||
if (mLink[mTop].mChildIndex < 0) {
|
||||
// Yep. See if we've just iterated back to the first element
|
||||
// in the tree, period. Walk back up the stack, looking for
|
||||
// any unfinished subtrees.
|
||||
PRInt32 unfinished;
|
||||
for (unfinished = mTop - 1; unfinished >= 0; --unfinished) {
|
||||
const Link& link = mLink[unfinished];
|
||||
if (link.mChildIndex >= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
// If there are no unfinished subtrees in the stack, then this
|
||||
// iterator is exhausted. Leave it in the same state that
|
||||
// First() does.
|
||||
if (unfinished < 0)
|
||||
return;
|
||||
|
||||
// Otherwise, we ran off the end of one of the inner
|
||||
// subtrees. Pop up to the next unfinished level in the stack.
|
||||
mTop = unfinished;
|
||||
return;
|
||||
}
|
||||
|
||||
// Is there a child subtree immediately prior to our current
|
||||
// position? If so, descend into it, grovelling down to the
|
||||
// deepest, rightmost left edge.
|
||||
Subtree* parent = mLink[mTop].GetParent();
|
||||
PRInt32 index = mLink[mTop].GetChildIndex();
|
||||
|
||||
Subtree* subtree = (*parent)[index].mSubtree;
|
||||
|
||||
if (subtree && subtree->Count()) {
|
||||
do {
|
||||
index = subtree->Count() - 1;
|
||||
Push(subtree, index);
|
||||
|
||||
parent = subtree;
|
||||
subtree = (*parent)[index].mSubtree;
|
||||
} while (subtree && subtree->Count());
|
||||
}
|
||||
}
|
415
content/xul/templates/src/nsTreeRows.h
Normal file
415
content/xul/templates/src/nsTreeRows.h
Normal file
@ -0,0 +1,415 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
#ifndef nsOutlinerRows_h__
|
||||
#define nsOutlinerRows_h__
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIRDFResource.h"
|
||||
#include "pldhash.h"
|
||||
class nsConflictSet;
|
||||
class nsTemplateMatch;
|
||||
|
||||
/**
|
||||
* This class maintains the state of the XUL outliner builder's
|
||||
* rows. It maps a row number to the nsTemplateMatch object that
|
||||
* populates the row.
|
||||
*/
|
||||
class nsOutlinerRows
|
||||
{
|
||||
public:
|
||||
enum Direction { eDirection_Forwards = +1, eDirection_Backwards = -1 };
|
||||
|
||||
class Subtree;
|
||||
|
||||
/**
|
||||
* A row in the outliner. Contains the match that the row
|
||||
* corresponds to, and a pointer to the row's subtree, if there
|
||||
* are any.
|
||||
*/
|
||||
struct Row {
|
||||
nsTemplateMatch* mMatch;
|
||||
Subtree* mSubtree; // XXX eventually move to hashtable
|
||||
};
|
||||
|
||||
/**
|
||||
* A subtree in the outliner. A subtree contains rows, which may
|
||||
* contain other subtrees.
|
||||
*/
|
||||
class Subtree {
|
||||
protected:
|
||||
friend class nsOutlinerRows; // so that it can access members, for now
|
||||
|
||||
/**
|
||||
* The parent subtree; null if we're the root
|
||||
*/
|
||||
Subtree* mParent;
|
||||
|
||||
/**
|
||||
* The number of immediate children in this subtree
|
||||
*/
|
||||
PRInt32 mCount;
|
||||
|
||||
/**
|
||||
* The capacity of the subtree
|
||||
*/
|
||||
PRInt32 mCapacity;
|
||||
|
||||
/**
|
||||
* The total number of rows in this subtree, recursively
|
||||
* including child subtrees.
|
||||
*/
|
||||
PRInt32 mSubtreeSize;
|
||||
|
||||
/**
|
||||
* The array of rows in the subtree
|
||||
*/
|
||||
Row* mRows;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates a subtree with the specified parent.
|
||||
*/
|
||||
Subtree(Subtree* aParent)
|
||||
: mParent(aParent),
|
||||
mCount(0),
|
||||
mCapacity(0),
|
||||
mSubtreeSize(0),
|
||||
mRows(nsnull) {}
|
||||
|
||||
~Subtree();
|
||||
|
||||
/**
|
||||
* Return the number of immediate child rows in the subtree
|
||||
*/
|
||||
PRInt32 Count() const { return mCount; }
|
||||
|
||||
/**
|
||||
* Return the number of rows in this subtree, as well as all
|
||||
* the subtrees it contains.
|
||||
*/
|
||||
PRInt32 GetSubtreeSize() const { return mSubtreeSize; }
|
||||
|
||||
/**
|
||||
* Retrieve the immediate child row at the specified index.
|
||||
*/
|
||||
const Row& operator[](PRInt32 aIndex) const {
|
||||
NS_PRECONDITION(aIndex >= 0 && aIndex < mCount, "bad index");
|
||||
return mRows[aIndex]; }
|
||||
|
||||
/**
|
||||
* Retrieve the immediate row at the specified index.
|
||||
*/
|
||||
Row& operator[](PRInt32 aIndex) {
|
||||
NS_PRECONDITION(aIndex >= 0 && aIndex < mCount, "bad index");
|
||||
return mRows[aIndex]; }
|
||||
|
||||
/**
|
||||
* Remove all rows from the subtree.
|
||||
*/
|
||||
void Clear();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Insert an immediate child row at the specified index.
|
||||
*/
|
||||
PRBool InsertRowAt(nsTemplateMatch* aMatch, PRInt32 aIndex);
|
||||
|
||||
/**
|
||||
* Remove an immediate child row from the specified index.
|
||||
*/
|
||||
void RemoveRowAt(PRInt32 aChildIndex);
|
||||
};
|
||||
|
||||
friend class Subtree;
|
||||
|
||||
enum { kMaxDepth = 32 };
|
||||
|
||||
protected:
|
||||
/**
|
||||
* A link in the path through the view's tree.
|
||||
*/
|
||||
struct Link {
|
||||
Subtree* mParent;
|
||||
PRInt32 mChildIndex;
|
||||
|
||||
Link&
|
||||
operator=(const Link& aLink) {
|
||||
mParent = aLink.mParent;
|
||||
mChildIndex = aLink.mChildIndex;
|
||||
return *this; }
|
||||
|
||||
PRBool
|
||||
operator==(const Link& aLink) const {
|
||||
return (mParent == aLink.mParent)
|
||||
&& (mChildIndex == aLink.mChildIndex); }
|
||||
|
||||
Subtree* GetParent() { return mParent; }
|
||||
const Subtree* GetParent() const { return mParent; }
|
||||
|
||||
PRInt32 GetChildIndex() const { return mChildIndex; }
|
||||
|
||||
Row& GetRow() { return (*mParent)[mChildIndex]; }
|
||||
const Row& GetRow() const { return (*mParent)[mChildIndex]; }
|
||||
};
|
||||
|
||||
public:
|
||||
class iterator;
|
||||
friend class iterator;
|
||||
|
||||
/**
|
||||
* An iterator that can be used to traverse the outliner view.
|
||||
*/
|
||||
class iterator {
|
||||
protected:
|
||||
PRInt32 mTop;
|
||||
PRInt32 mRowIndex;
|
||||
Link mLink[kMaxDepth];
|
||||
|
||||
void Next();
|
||||
void Prev();
|
||||
|
||||
friend class nsOutlinerRows; // so nsOutlinerRows can initialize us
|
||||
|
||||
/**
|
||||
* Used by PathTo() to initialize an iterator.
|
||||
*/
|
||||
void Push(Subtree* aParent, PRInt32 aChildIndex);
|
||||
|
||||
/**
|
||||
* Used by PathTo() to initialize an iterator.
|
||||
*/
|
||||
void SetRowIndex(PRInt32 aRowIndex) { mRowIndex = aRowIndex; }
|
||||
|
||||
public:
|
||||
iterator() : mTop(-1), mRowIndex(-1) {}
|
||||
|
||||
iterator(const iterator& aIterator);
|
||||
iterator& operator=(const iterator& aIterator);
|
||||
|
||||
PRBool operator==(const iterator& aIterator) const;
|
||||
|
||||
PRBool operator!=(const iterator& aIterator) const {
|
||||
return !aIterator.operator==(*this); }
|
||||
|
||||
const Row& operator*() const { return mLink[mTop].GetRow(); }
|
||||
Row& operator*() { return mLink[mTop].GetRow(); }
|
||||
|
||||
const Row* operator->() const { return &(mLink[mTop].GetRow()); }
|
||||
Row* operator->() { return &(mLink[mTop].GetRow()); }
|
||||
|
||||
iterator& operator++() { Next(); return *this; }
|
||||
iterator operator++(int) { iterator temp(*this); Next(); return temp; }
|
||||
iterator& operator--() { Prev(); return *this; }
|
||||
iterator operator--(int) { iterator temp(*this); Prev(); return temp; }
|
||||
|
||||
/**
|
||||
* Return the current parent link
|
||||
*/
|
||||
Subtree* GetParent() {
|
||||
return mLink[mTop].GetParent(); }
|
||||
|
||||
const Subtree* GetParent() const {
|
||||
return mLink[mTop].GetParent(); }
|
||||
|
||||
/**
|
||||
* Return the current child index
|
||||
*/
|
||||
PRInt32 GetChildIndex() const {
|
||||
return mLink[mTop].GetChildIndex(); }
|
||||
|
||||
/**
|
||||
* Return the depth of the path the iterator is maintaining
|
||||
* into the tree.
|
||||
*/
|
||||
PRInt32 GetDepth() const { return mTop + 1; }
|
||||
|
||||
/**
|
||||
* Return the current row index of the iterator
|
||||
*/
|
||||
PRInt32 GetRowIndex() const { return mRowIndex; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve the first element in the view
|
||||
*/
|
||||
iterator First();
|
||||
|
||||
/**
|
||||
* Retrieve (one past) the last element in the view
|
||||
*/
|
||||
iterator Last();
|
||||
|
||||
/**
|
||||
* Find the row that contains the match with the specified member
|
||||
* resource.
|
||||
*/
|
||||
iterator Find(nsConflictSet& aConflictSet, nsIRDFResource* aMember);
|
||||
|
||||
/**
|
||||
* Retrieve the ith element in the view
|
||||
*/
|
||||
iterator operator[](PRInt32 aIndex);
|
||||
|
||||
nsOutlinerRows() : mRoot(nsnull), mRootResource(nsnull) {}
|
||||
~nsOutlinerRows() {}
|
||||
|
||||
/**
|
||||
* Ensure that a child subtree exists within the specified parent
|
||||
* at the specified child index within the parent. (In other
|
||||
* words, create a subtree if one doesn't already exist.)
|
||||
*/
|
||||
Subtree*
|
||||
EnsureSubtreeFor(Subtree* aParent, PRInt32 aChildIndex);
|
||||
|
||||
/**
|
||||
* Ensure that a child subtree exists at the iterator's position.
|
||||
*/
|
||||
Subtree*
|
||||
EnsureSubtreeFor(iterator& aIterator) {
|
||||
return EnsureSubtreeFor(aIterator.GetParent(),
|
||||
aIterator.GetChildIndex()); }
|
||||
|
||||
/**
|
||||
* Get the child subtree for the specified parent at the specified
|
||||
* child index. Optionally return the child subtree's size. Will
|
||||
* return `null' if no subtree exists.
|
||||
*/
|
||||
Subtree*
|
||||
GetSubtreeFor(const Subtree* aParent,
|
||||
PRInt32 aChildIndex,
|
||||
PRInt32* aSubtreeSize = nsnull);
|
||||
|
||||
/**
|
||||
* Retrieve the size of the subtree within the specified parent.
|
||||
*/
|
||||
PRInt32
|
||||
GetSubtreeSizeFor(const Subtree* aParent,
|
||||
PRInt32 aChildIndex) {
|
||||
PRInt32 size;
|
||||
GetSubtreeFor(aParent, aChildIndex, &size);
|
||||
return size; }
|
||||
|
||||
/**
|
||||
* Retrieve the size of the subtree within the specified parent.
|
||||
*/
|
||||
PRInt32
|
||||
GetSubtreeSizeFor(const iterator& aIterator) {
|
||||
PRInt32 size;
|
||||
GetSubtreeFor(aIterator.GetParent(), aIterator.GetChildIndex(), &size);
|
||||
return size; }
|
||||
|
||||
/**
|
||||
* Remove the specified subtree for a row, leaving the row itself
|
||||
* intact.
|
||||
*/
|
||||
void
|
||||
RemoveSubtreeFor(Subtree* aParent, PRInt32 aChildIndex);
|
||||
|
||||
/**
|
||||
* Remove the specified subtree for a row, leaving the row itself
|
||||
* intact.
|
||||
*/
|
||||
void
|
||||
RemoveSubtreeFor(iterator& aIterator) {
|
||||
RemoveSubtreeFor(aIterator.GetParent(), aIterator.GetChildIndex()); }
|
||||
|
||||
/**
|
||||
* Remove the specified row from the view
|
||||
*/
|
||||
void
|
||||
RemoveRowAt(iterator& aIterator) {
|
||||
iterator temp = aIterator++;
|
||||
Subtree* parent = temp.GetParent();
|
||||
parent->RemoveRowAt(temp.GetChildIndex());
|
||||
InvalidateCachedRow(); }
|
||||
|
||||
/**
|
||||
* Insert a new match into the view
|
||||
*/
|
||||
void
|
||||
InsertRowAt(nsTemplateMatch* aMatch, Subtree* aSubtree, PRInt32 aChildIndex) {
|
||||
aSubtree->InsertRowAt(aMatch, aChildIndex);
|
||||
InvalidateCachedRow(); }
|
||||
|
||||
/**
|
||||
* Raw access to the rows; e.g., for sorting.
|
||||
*/
|
||||
Row*
|
||||
GetRowsFor(Subtree* aSubtree) { return aSubtree->mRows; }
|
||||
|
||||
/**
|
||||
* Remove all of the rows
|
||||
*/
|
||||
void Clear();
|
||||
|
||||
/**
|
||||
* Return the total number of rows in the outliner view.
|
||||
*/
|
||||
PRInt32 Count() const { return mRoot.GetSubtreeSize(); }
|
||||
|
||||
/**
|
||||
* Retrieve the root subtree
|
||||
*/
|
||||
Subtree* GetRoot() { return &mRoot; }
|
||||
|
||||
/**
|
||||
* Set the root resource for the view
|
||||
*/
|
||||
void SetRootResource(nsIRDFResource* aResource) {
|
||||
mRootResource = aResource; }
|
||||
|
||||
/**
|
||||
* Retrieve hte root resource for the view
|
||||
*/
|
||||
nsIRDFResource* GetRootResource() {
|
||||
return mRootResource.get(); }
|
||||
|
||||
/**
|
||||
* Invalidate the cached row; e.g., because the view has changed
|
||||
* in a way that would corrupt the iterator.
|
||||
*/
|
||||
void
|
||||
InvalidateCachedRow() { mLastRow = iterator(); }
|
||||
|
||||
protected:
|
||||
/**
|
||||
* The root subtree.
|
||||
*/
|
||||
Subtree mRoot;
|
||||
|
||||
/**
|
||||
* The root resource for the view
|
||||
*/
|
||||
nsCOMPtr<nsIRDFResource> mRootResource;
|
||||
|
||||
/**
|
||||
* The last row that was asked for by operator[]. By remembering
|
||||
* this, we can usually avoid the O(n) search through the row
|
||||
* array to find the row at the specified index.
|
||||
*/
|
||||
iterator mLastRow;
|
||||
};
|
||||
|
||||
|
||||
#endif // nsOutlinerRows_h__
|
2280
content/xul/templates/src/nsXULContentBuilder.cpp
Normal file
2280
content/xul/templates/src/nsXULContentBuilder.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1448
content/xul/templates/src/nsXULOutlinerBuilder.cpp
Normal file
1448
content/xul/templates/src/nsXULOutlinerBuilder.cpp
Normal file
File diff suppressed because it is too large
Load Diff
31
content/xul/templates/src/nsXULResourceList.h
Normal file
31
content/xul/templates/src/nsXULResourceList.h
Normal file
@ -0,0 +1,31 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
*/
|
||||
|
||||
// N.B., no include guard! We'll include this multiple times in some
|
||||
// files.
|
||||
|
||||
XUL_RESOURCE(NC_child, NC_NAMESPACE_URI "child");
|
||||
XUL_RESOURCE(NC_Folder, NC_NAMESPACE_URI "Folder");
|
||||
XUL_RESOURCE(NC_open, NC_NAMESPACE_URI "open");
|
||||
|
||||
XUL_LITERAL(true_, "true");
|
427
content/xul/templates/src/nsXULTemplateBuilder.h
Normal file
427
content/xul/templates/src/nsXULTemplateBuilder.h
Normal file
@ -0,0 +1,427 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* 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/
|
||||
*
|
||||
* 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 Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Robert Churchill <rjc@netscape.com>
|
||||
* David Hyatt <hyatt@netscape.com>
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||
*/
|
||||
|
||||
#ifndef nsXULTemplateBuilder_h__
|
||||
#define nsXULTemplateBuilder_h__
|
||||
|
||||
#include "nsIDocumentObserver.h"
|
||||
#include "nsINameSpaceManager.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsISecurityCheckedComponent.h"
|
||||
#include "nsIRDFCompositeDataSource.h"
|
||||
#include "nsIRDFContainer.h"
|
||||
#include "nsIRDFDataSource.h"
|
||||
#include "nsIRDFObserver.h"
|
||||
#include "nsIRDFService.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsIXULTemplateBuilder.h"
|
||||
|
||||
#include "nsConflictSet.h"
|
||||
#include "nsFixedSizeAllocator.h"
|
||||
#include "nsResourceSet.h"
|
||||
#include "nsRuleNetwork.h"
|
||||
|
||||
#include "prlog.h"
|
||||
#ifdef PR_LOGGING
|
||||
extern PRLogModuleInfo* gXULTemplateLog;
|
||||
#endif
|
||||
|
||||
class nsClusterKeySet;
|
||||
class nsTemplateMatch;
|
||||
class nsTemplateRule;
|
||||
class nsIXULDocument;
|
||||
class nsIRDFCompositeDataSource;
|
||||
|
||||
/**
|
||||
* An object that translates an RDF graph into a presentation using a
|
||||
* set of rules.
|
||||
*/
|
||||
class nsXULTemplateBuilder : public nsIXULTemplateBuilder,
|
||||
public nsISecurityCheckedComponent,
|
||||
public nsIDocumentObserver,
|
||||
public nsIRDFObserver
|
||||
{
|
||||
public:
|
||||
nsXULTemplateBuilder();
|
||||
virtual ~nsXULTemplateBuilder();
|
||||
|
||||
nsresult Init();
|
||||
|
||||
// nsISupports interface
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIXULTemplateBuilder interface
|
||||
NS_IMETHOD GetRoot(nsIDOMElement** aResult);
|
||||
NS_IMETHOD GetDatabase(nsIRDFCompositeDataSource** aResult);
|
||||
NS_IMETHOD Rebuild() = 0; // must be implemented by subclasses
|
||||
|
||||
// nsISecurityCheckedComponent
|
||||
NS_DECL_NSISECURITYCHECKEDCOMPONENT
|
||||
|
||||
// nsIDocumentObserver
|
||||
NS_IMETHOD BeginUpdate(nsIDocument *aDocument);
|
||||
NS_IMETHOD EndUpdate(nsIDocument *aDocument);
|
||||
NS_IMETHOD BeginLoad(nsIDocument *aDocument);
|
||||
NS_IMETHOD EndLoad(nsIDocument *aDocument);
|
||||
NS_IMETHOD BeginReflow(nsIDocument *aDocument, nsIPresShell* aShell);
|
||||
NS_IMETHOD EndReflow(nsIDocument *aDocument, nsIPresShell* aShell);
|
||||
|
||||
NS_IMETHOD ContentChanged(nsIDocument *aDocument,
|
||||
nsIContent* aContent,
|
||||
nsISupports* aSubContent);
|
||||
|
||||
NS_IMETHOD ContentStatesChanged(nsIDocument* aDocument,
|
||||
nsIContent* aContent1,
|
||||
nsIContent* aContent2);
|
||||
|
||||
NS_IMETHOD AttributeChanged(nsIDocument *aDocument,
|
||||
nsIContent* aContent,
|
||||
PRInt32 aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
PRInt32 aHint);
|
||||
|
||||
NS_IMETHOD ContentAppended(nsIDocument *aDocument,
|
||||
nsIContent* aContainer,
|
||||
PRInt32 aNewIndexInContainer);
|
||||
|
||||
NS_IMETHOD ContentInserted(nsIDocument *aDocument,
|
||||
nsIContent* aContainer,
|
||||
nsIContent* aChild,
|
||||
PRInt32 aIndexInContainer);
|
||||
|
||||
NS_IMETHOD ContentReplaced(nsIDocument *aDocument,
|
||||
nsIContent* aContainer,
|
||||
nsIContent* aOldChild,
|
||||
nsIContent* aNewChild,
|
||||
PRInt32 aIndexInContainer);
|
||||
|
||||
NS_IMETHOD ContentRemoved(nsIDocument *aDocument,
|
||||
nsIContent* aContainer,
|
||||
nsIContent* aChild,
|
||||
PRInt32 aIndexInContainer);
|
||||
|
||||
NS_IMETHOD StyleSheetAdded(nsIDocument *aDocument,
|
||||
nsIStyleSheet* aStyleSheet);
|
||||
|
||||
NS_IMETHOD StyleSheetRemoved(nsIDocument *aDocument,
|
||||
nsIStyleSheet* aStyleSheet);
|
||||
|
||||
NS_IMETHOD StyleSheetDisabledStateChanged(nsIDocument *aDocument,
|
||||
nsIStyleSheet* aStyleSheet,
|
||||
PRBool aDisabled);
|
||||
|
||||
NS_IMETHOD StyleRuleChanged(nsIDocument *aDocument,
|
||||
nsIStyleSheet* aStyleSheet,
|
||||
nsIStyleRule* aStyleRule,
|
||||
PRInt32 aHint);
|
||||
|
||||
NS_IMETHOD StyleRuleAdded(nsIDocument *aDocument,
|
||||
nsIStyleSheet* aStyleSheet,
|
||||
nsIStyleRule* aStyleRule);
|
||||
|
||||
NS_IMETHOD StyleRuleRemoved(nsIDocument *aDocument,
|
||||
nsIStyleSheet* aStyleSheet,
|
||||
nsIStyleRule* aStyleRule);
|
||||
|
||||
NS_IMETHOD DocumentWillBeDestroyed(nsIDocument *aDocument);
|
||||
|
||||
// nsIRDFObserver interface
|
||||
NS_DECL_NSIRDFOBSERVER
|
||||
|
||||
nsresult
|
||||
ComputeContainmentProperties();
|
||||
|
||||
static PRBool
|
||||
IsTemplateElement(nsIContent* aContent);
|
||||
|
||||
/**
|
||||
* Initialize the rule network.
|
||||
*/
|
||||
virtual nsresult
|
||||
InitializeRuleNetwork();
|
||||
|
||||
/**
|
||||
* Initialize the rule network for handling rules that use the
|
||||
* ``simple'' syntax.
|
||||
*/
|
||||
virtual nsresult
|
||||
InitializeRuleNetworkForSimpleRules(InnerNode** aChildNode) = 0;
|
||||
|
||||
/**
|
||||
* Find the <template> tag that applies for this builder
|
||||
*/
|
||||
nsresult
|
||||
GetTemplateRoot(nsIContent** aResult);
|
||||
|
||||
/**
|
||||
* Compile the template's rules
|
||||
*/
|
||||
nsresult
|
||||
CompileRules();
|
||||
|
||||
/**
|
||||
* Compile a rule that's specified using the extended template
|
||||
* syntax.
|
||||
*/
|
||||
nsresult
|
||||
CompileExtendedRule(nsIContent* aRuleElement,
|
||||
PRInt32 aPriority,
|
||||
InnerNode* aParentNode);
|
||||
|
||||
/**
|
||||
* Compile the <conditions> of a rule that uses the extended
|
||||
* template syntax.
|
||||
*/
|
||||
nsresult
|
||||
CompileConditions(nsTemplateRule* aRule,
|
||||
nsIContent* aConditions,
|
||||
InnerNode* aParentNode,
|
||||
InnerNode** aLastNode);
|
||||
|
||||
/**
|
||||
* Compile a single condition from an extended template syntax
|
||||
* rule. Subclasses may override to provide additional,
|
||||
* subclass-specific condition processing.
|
||||
*/
|
||||
virtual nsresult
|
||||
CompileCondition(nsIAtom* aTag,
|
||||
nsTemplateRule* aRule,
|
||||
nsIContent* aConditions,
|
||||
InnerNode* aParentNode,
|
||||
TestNode** aResult);
|
||||
|
||||
/**
|
||||
* Compile a <triple> condition
|
||||
*/
|
||||
nsresult
|
||||
CompileTripleCondition(nsTemplateRule* aRule,
|
||||
nsIContent* aCondition,
|
||||
InnerNode* aParentNode,
|
||||
TestNode** aResult);
|
||||
|
||||
/**
|
||||
* Compile a <member> condition
|
||||
*/
|
||||
nsresult
|
||||
CompileMemberCondition(nsTemplateRule* aRule,
|
||||
nsIContent* aCondition,
|
||||
InnerNode* aParentNode,
|
||||
TestNode** aResult);
|
||||
|
||||
|
||||
/**
|
||||
* Compile the <bindings> for an extended template syntax rule.
|
||||
*/
|
||||
nsresult
|
||||
CompileBindings(nsTemplateRule* aRule, nsIContent* aBindings);
|
||||
|
||||
/**
|
||||
* Compile a single binding for an extended template syntax rule.
|
||||
*/
|
||||
nsresult
|
||||
CompileBinding(nsTemplateRule* aRule, nsIContent* aBinding);
|
||||
|
||||
/**
|
||||
* Compile a rule that's specified using the simple template
|
||||
* syntax.
|
||||
*/
|
||||
nsresult
|
||||
CompileSimpleRule(nsIContent* aRuleElement, PRInt32 aPriorty, InnerNode* naParentNode);
|
||||
|
||||
/**
|
||||
* Can be overridden by subclasses to handle special attribute conditions
|
||||
* for the simple syntax.
|
||||
* @return PR_TRUE if the condition was handled
|
||||
*/
|
||||
virtual PRBool
|
||||
CompileSimpleAttributeCondition(PRInt32 aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAReadableString& aValue,
|
||||
InnerNode* aParentNode,
|
||||
TestNode** aResult);
|
||||
/**
|
||||
* Add automatic bindings for simple rules
|
||||
*/
|
||||
nsresult
|
||||
AddSimpleRuleBindings(nsTemplateRule* aRule, nsIContent* aElement);
|
||||
|
||||
static void
|
||||
AddBindingsFor(nsXULTemplateBuilder* aSelf,
|
||||
const nsAReadableString& aVariable,
|
||||
void* aClosure);
|
||||
|
||||
// XXX sigh, the string template foo doesn't mix with
|
||||
// operator->*() on egcs-1.1.2, so we'll need to explicitly pass
|
||||
// "this" and use good ol' fashioned static callbacks.
|
||||
void
|
||||
ParseAttribute(const nsAReadableString& aAttributeValue,
|
||||
void (*aVariableCallback)(nsXULTemplateBuilder* aThis, const nsAReadableString&, void*),
|
||||
void (*aTextCallback)(nsXULTemplateBuilder* aThis, const nsAReadableString&, void*),
|
||||
void* aClosure);
|
||||
|
||||
nsresult
|
||||
LoadDataSources();
|
||||
|
||||
nsresult
|
||||
InitHTMLTemplateRoot();
|
||||
|
||||
nsresult
|
||||
SubstituteText(nsTemplateMatch& aMatch,
|
||||
const nsAReadableString& aAttributeValue,
|
||||
nsString& aResult);
|
||||
|
||||
static void
|
||||
SubstituteTextAppendText(nsXULTemplateBuilder* aThis, const nsAReadableString& aText, void* aClosure);
|
||||
|
||||
static void
|
||||
SubstituteTextReplaceVariable(nsXULTemplateBuilder* aThis, const nsAReadableString& aVariable, void* aClosure);
|
||||
|
||||
PRBool
|
||||
IsAttrImpactedByVars(nsTemplateMatch& aMatch,
|
||||
const nsAReadableString& aAttributeValue,
|
||||
const VariableSet& aModifiedVars);
|
||||
|
||||
static void
|
||||
IsVarInSet(nsXULTemplateBuilder* aThis, const nsAReadableString& aVariable, void* aClosure);
|
||||
|
||||
nsresult
|
||||
SynchronizeAll(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aOldTarget,
|
||||
nsIRDFNode* aNewTarget);
|
||||
|
||||
nsresult
|
||||
Propogate(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget,
|
||||
nsClusterKeySet& aNewKeys);
|
||||
|
||||
nsresult
|
||||
FireNewlyMatchedRules(const nsClusterKeySet& aNewKeys);
|
||||
|
||||
nsresult
|
||||
Retract(nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget);
|
||||
|
||||
nsresult
|
||||
CheckContainer(nsIRDFResource* aTargetResource, PRBool* aIsContainer, PRBool* aIsEmpty);
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
nsresult
|
||||
Log(const char* aOperation,
|
||||
nsIRDFResource* aSource,
|
||||
nsIRDFResource* aProperty,
|
||||
nsIRDFNode* aTarget);
|
||||
|
||||
#define LOG(_op, _src, _prop, _targ) \
|
||||
Log(_op, _src, _prop, _targ)
|
||||
|
||||
#else
|
||||
#define LOG(_op, _src, _prop, _targ)
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// We are an observer of the composite datasource. The cycle is
|
||||
// broken when the document is destroyed.
|
||||
nsCOMPtr<nsIRDFCompositeDataSource> mDB;
|
||||
|
||||
// Circular reference, broken when the document is destroyed.
|
||||
nsCOMPtr<nsIContent> mRoot;
|
||||
|
||||
nsCOMPtr<nsIRDFDataSource> mCache;
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
|
||||
PRInt32 mUpdateBatchNest;
|
||||
|
||||
// For the rule network
|
||||
nsResourceSet mContainmentProperties;
|
||||
PRBool mRulesCompiled;
|
||||
|
||||
public:
|
||||
nsRuleNetwork mRules;
|
||||
PRInt32 mContainerVar;
|
||||
nsString mContainerSymbol;
|
||||
PRInt32 mMemberVar;
|
||||
nsString mMemberSymbol;
|
||||
nsConflictSet mConflictSet;
|
||||
NodeSet mRDFTests;
|
||||
|
||||
protected:
|
||||
// pseudo-constants
|
||||
static nsrefcnt gRefCnt;
|
||||
static nsIRDFService* gRDFService;
|
||||
static nsINameSpaceManager* gNameSpaceManager;
|
||||
static nsIScriptSecurityManager* gScriptSecurityManager;
|
||||
static nsIPrincipal* gSystemPrincipal;
|
||||
|
||||
static PRInt32 kNameSpaceID_RDF;
|
||||
static PRInt32 kNameSpaceID_XUL;
|
||||
|
||||
PRBool mIsBuilding;
|
||||
|
||||
enum {
|
||||
eDontTestEmpty = (1 << 0)
|
||||
};
|
||||
|
||||
PRInt32 mFlags;
|
||||
|
||||
/**
|
||||
* Stack-based helper class to maintain a latch variable without
|
||||
* worrying about control flow headaches.
|
||||
*/
|
||||
class AutoLatch {
|
||||
protected:
|
||||
PRBool* mVariable;
|
||||
|
||||
public:
|
||||
AutoLatch(PRBool* aVariable) : mVariable(aVariable) {
|
||||
NS_ASSERTION(! *mVariable, "latch already set");
|
||||
*mVariable = PR_TRUE; }
|
||||
|
||||
~AutoLatch() { *mVariable = PR_FALSE; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Must be implemented by subclasses. Handle replacing aOldMatch
|
||||
* with aNewMatch. Either aOldMatch or aNewMatch may be null.
|
||||
*/
|
||||
virtual nsresult
|
||||
ReplaceMatch(nsIRDFResource* aMember, const nsTemplateMatch* aOldMatch, nsTemplateMatch* aNewMatch) = 0;
|
||||
|
||||
/**
|
||||
* Must be implemented by subclasses. Handle change in bound
|
||||
* variable values for aMatch. aModifiedVars contains the set
|
||||
* of variables that have changed.
|
||||
* @param aMatch the match for which variable bindings has changed.
|
||||
* @param aModifiedVars the set of variables for which the bindings
|
||||
* have changed.
|
||||
*/
|
||||
virtual nsresult
|
||||
SynchronizeMatch(nsTemplateMatch* aMatch, const VariableSet& aModifiedVars) = 0;
|
||||
};
|
||||
|
||||
#endif // nsXULTemplateBuilder_h__
|
1448
content/xul/templates/src/nsXULTreeBuilder.cpp
Normal file
1448
content/xul/templates/src/nsXULTreeBuilder.cpp
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user