Bug 12811. Fix frame system notifications s.t. as _few_ as possible get forwarded through to layout. Temporarily remove timer hacks from tree widget.

This commit is contained in:
waterson%netscape.com 1999-08-31 06:40:41 +00:00
Родитель 5a7eac87ed
Коммит c1ca0ebd36
9 изменённых файлов: 2046 добавлений и 993 удалений

Просмотреть файл

@ -802,7 +802,7 @@ public:
nsresult OpenWidgetItem(nsIContent* aElement);
nsresult CloseWidgetItem(nsIContent* aElement);
nsresult RemoveAndRebuildGeneratedChildren(nsIContent* aElement);
nsresult RebuildWidgetItem(nsIContent* aElement);
nsresult
AddElementToMap(nsIContent* aElement, PRBool aDeep);
@ -2101,14 +2101,14 @@ XULDocumentImpl::ContentStatesChanged(nsIContent* aContent1, nsIContent* aConten
}
NS_IMETHODIMP
XULDocumentImpl::AttributeChanged(nsIContent* aChild,
XULDocumentImpl::AttributeChanged(nsIContent* aElement,
nsIAtom* aAttribute,
PRInt32 aHint)
{
nsresult rv;
PRInt32 nameSpaceID;
rv = aChild->GetNameSpaceID(nameSpaceID);
rv = aElement->GetNameSpaceID(nameSpaceID);
if (NS_FAILED(rv)) return rv;
// First see if we need to update our element map.
@ -2120,27 +2120,7 @@ XULDocumentImpl::AttributeChanged(nsIContent* aChild,
// That'll have removed _both_ the 'ref' and 'id' entries from
// the map. So add 'em back now.
rv = AddElementToMap(aChild, PR_FALSE);
if (NS_FAILED(rv)) return rv;
}
}
// Handle "special" cases.
if (nameSpaceID == kNameSpaceID_XUL) {
if (aAttribute == kOpenAtom) {
nsAutoString open;
rv = aChild->GetAttribute(kNameSpaceID_None, kOpenAtom, open);
if (NS_FAILED(rv)) return rv;
if ((rv == NS_CONTENT_ATTR_HAS_VALUE) && (open.Equals("true"))) {
OpenWidgetItem(aChild);
}
else {
CloseWidgetItem(aChild);
}
}
else if (aAttribute == kRefAtom) {
rv = RemoveAndRebuildGeneratedChildren(aChild);
rv = AddElementToMap(aElement, PR_FALSE);
if (NS_FAILED(rv)) return rv;
}
}
@ -2148,11 +2128,34 @@ XULDocumentImpl::AttributeChanged(nsIContent* aChild,
// Now notify external observers
for (PRInt32 i = 0; i < mObservers.Count(); i++) {
nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i];
observer->AttributeChanged(this, aChild, aAttribute, aHint);
observer->AttributeChanged(this, aElement, aAttribute, aHint);
if (observer != (nsIDocumentObserver*)mObservers.ElementAt(i)) {
i--;
}
}
// Handle "special" cases. We do this handling _after_ we've
// notified the observer to ensure that any frames that are
// caching information (e.g., the tree widget and the 'open'
// attribute) will notice things properly.
if (nameSpaceID == kNameSpaceID_XUL) {
if (aAttribute == kOpenAtom) {
nsAutoString open;
rv = aElement->GetAttribute(kNameSpaceID_None, kOpenAtom, open);
if (NS_FAILED(rv)) return rv;
if ((rv == NS_CONTENT_ATTR_HAS_VALUE) && (open.Equals("true"))) {
OpenWidgetItem(aElement);
}
else {
CloseWidgetItem(aElement);
}
}
else if (aAttribute == kRefAtom) {
RebuildWidgetItem(aElement);
}
}
return NS_OK;
}
@ -4483,10 +4486,17 @@ XULDocumentImpl::ReleaseEvent(const nsString& aType)
nsresult
XULDocumentImpl::OpenWidgetItem(nsIContent* aElement)
{
NS_PRECONDITION(aElement != nsnull, "null ptr");
if (! aElement)
return NS_ERROR_NULL_POINTER;
if (! mBuilders)
return NS_ERROR_NOT_INITIALIZED;
nsresult rv;
#ifdef PR_LOGGING
if (PR_LOG_TEST(gXULLog, PR_LOG_DEBUG)) {
nsresult rv;
nsCOMPtr<nsIAtom> tag;
rv = aElement->GetTag(*getter_AddRefs(tag));
if (NS_FAILED(rv)) return rv;
@ -4499,12 +4509,39 @@ XULDocumentImpl::OpenWidgetItem(nsIContent* aElement)
(const char*) nsCAutoString(tagStr)));
}
#endif
return CreateContents(aElement);
PRUint32 cnt = 0;
rv = mBuilders->Count(&cnt);
NS_ASSERTION(NS_SUCCEEDED(rv), "Count failed");
for (PRUint32 i = 0; i < cnt; ++i) {
// XXX we should QueryInterface() here
nsIRDFContentModelBuilder* builder
= (nsIRDFContentModelBuilder*) mBuilders->ElementAt(i);
NS_ASSERTION(builder != nsnull, "null ptr");
if (! builder)
continue;
rv = builder->OpenContainer(aElement);
NS_ASSERTION(NS_SUCCEEDED(rv), "error opening container");
// XXX ignore error code?
NS_RELEASE(builder);
}
return NS_OK;
}
nsresult
XULDocumentImpl::CloseWidgetItem(nsIContent* aElement)
{
NS_PRECONDITION(aElement != nsnull, "null ptr");
if (! aElement)
return NS_ERROR_NULL_POINTER;
if (! mBuilders)
return NS_ERROR_NOT_INITIALIZED;
nsresult rv;
#ifdef PR_LOGGING
@ -4522,163 +4559,78 @@ XULDocumentImpl::CloseWidgetItem(nsIContent* aElement)
}
#endif
// Find the tag that contains the children so that we can remove
// all of the children.
//
// XXX We make a bit of a leap here and assume that the same
// template that was used to generate _us_ was used to generate
// our _kids_. I'm sure this'll break when we do toolbars or
// something.
nsAutoString tmplID;
rv = aElement->GetAttribute(kNameSpaceID_None, kTemplateAtom, tmplID);
if (NS_FAILED(rv)) return rv;
PRUint32 cnt = 0;
rv = mBuilders->Count(&cnt);
NS_ASSERTION(NS_SUCCEEDED(rv), "Count failed");
for (PRUint32 i = 0; i < cnt; ++i) {
// XXX we should QueryInterface() here
nsIRDFContentModelBuilder* builder
= (nsIRDFContentModelBuilder*) mBuilders->ElementAt(i);
if (rv != NS_CONTENT_ATTR_HAS_VALUE)
return NS_OK;
NS_ASSERTION(builder != nsnull, "null ptr");
if (! builder)
continue;
nsCOMPtr<nsIDOMElement> tmplDOMEle;
rv = GetElementById(tmplID, getter_AddRefs(tmplDOMEle));
if (NS_FAILED(rv)) return rv;
rv = builder->CloseContainer(aElement);
NS_ASSERTION(NS_SUCCEEDED(rv), "error closing container");
// XXX ignore error code?
nsCOMPtr<nsIContent> tmpl = do_QueryInterface(tmplDOMEle);
if (! tmpl)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIContent> tmplParent;
rv = tmpl->GetParent(*getter_AddRefs(tmplParent));
if (NS_FAILED(rv)) return rv;
NS_ASSERTION(tmplParent != nsnull, "template node has no parent");
if (! tmplParent)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIAtom> tmplParentTag;
rv = tmplParent->GetTag(*getter_AddRefs(tmplParentTag));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIContent> childcontainer;
if ((tmplParentTag.get() == kRuleAtom) || (tmplParentTag.get() == kTemplateAtom)) {
childcontainer = dont_QueryInterface(aElement);
NS_RELEASE(builder);
}
else {
rv = nsRDFContentUtils::FindChildByTag(aElement,
kNameSpaceID_XUL,
tmplParentTag,
getter_AddRefs(childcontainer));
if (NS_FAILED(rv)) return rv;
if (rv == NS_RDF_NO_VALUE) {
// No tag; must've already been closed
return NS_OK;
}
}
PRInt32 count;
rv = childcontainer->ChildCount(count);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get count of the parent's children");
if (NS_FAILED(rv)) return rv;
while (--count >= 0) {
nsCOMPtr<nsIContent> child;
rv = childcontainer->ChildAt(count, *getter_AddRefs(child));
if (NS_FAILED(rv)) return rv;
rv = childcontainer->RemoveChildAt(count, PR_TRUE);
NS_ASSERTION(NS_SUCCEEDED(rv), "error removing child");
do {
// If it's _not_ a XUL element, then we want to blow it and
// all of its kids out of the XUL document's
// resource-to-element map.
nsCOMPtr<nsIRDFResource> resource;
rv = nsRDFContentUtils::GetElementResource(child, getter_AddRefs(resource));
if (NS_FAILED(rv)) break;
PRBool isXULElement;
rv = mDocumentDataSource->HasAssertion(resource, kRDF_instanceOf, kXUL_element, PR_TRUE, &isXULElement);
if (NS_FAILED(rv)) break;
if (! isXULElement)
break;
rv = child->SetDocument(nsnull, PR_TRUE);
if (NS_FAILED(rv)) return rv;
} while (0);
}
// Clear the container-contents-generated attribute so that the next time we
// come back, we'll regenerate the kids we just killed.
rv = aElement->UnsetAttribute(kNameSpaceID_None,
kContainerContentsGeneratedAtom,
PR_FALSE);
if (NS_FAILED(rv)) return rv;
// This is a _total_ hack to make sure that any XUL we blow away
// gets rebuilt.
rv = childcontainer->UnsetAttribute(kNameSpaceID_None,
kXULContentsGeneratedAtom,
PR_FALSE);
if (NS_FAILED(rv)) return rv;
rv = childcontainer->SetAttribute(kNameSpaceID_None,
kLazyContentAtom,
"true",
PR_FALSE);
if (NS_FAILED(rv)) return rv;
return NS_OK;
}
nsresult
XULDocumentImpl::RemoveAndRebuildGeneratedChildren(nsIContent* aElement)
XULDocumentImpl::RebuildWidgetItem(nsIContent* aElement)
{
NS_PRECONDITION(aElement != nsnull, "null ptr");
if (! aElement)
return NS_ERROR_NULL_POINTER;
if (! mBuilders)
return NS_ERROR_NOT_INITIALIZED;
nsresult rv;
PRInt32 count;
rv = aElement->ChildCount(count);
if (NS_FAILED(rv)) return rv;
while (--count >= 0) {
nsCOMPtr<nsIContent> child;
rv = aElement->ChildAt(count, *getter_AddRefs(child));
#ifdef PR_LOGGING
if (PR_LOG_TEST(gXULLog, PR_LOG_DEBUG)) {
nsCOMPtr<nsIAtom> tag;
rv = aElement->GetTag(*getter_AddRefs(tag));
if (NS_FAILED(rv)) return rv;
nsAutoString tmplID;
rv = child->GetAttribute(kNameSpaceID_None, kTemplateAtom, tmplID);
if (NS_FAILED(rv)) return rv;
nsAutoString tagStr;
tag->ToString(tagStr);
if (rv != NS_CONTENT_ATTR_HAS_VALUE)
PR_LOG(gXULLog, PR_LOG_DEBUG,
("xuldoc close-widget-item %s",
(const char*) nsCAutoString(tagStr)));
}
#endif
PRUint32 cnt = 0;
rv = mBuilders->Count(&cnt);
NS_ASSERTION(NS_SUCCEEDED(rv), "Count failed");
for (PRUint32 i = 0; i < cnt; ++i) {
// XXX we should QueryInterface() here
nsIRDFContentModelBuilder* builder
= (nsIRDFContentModelBuilder*) mBuilders->ElementAt(i);
NS_ASSERTION(builder != nsnull, "null ptr");
if (! builder)
continue;
// It's a generated element. Remove it, and set its document
// to null so that it'll get knocked out of the XUL doc's
// resource-to-element map.
rv = aElement->RemoveChildAt(count, PR_TRUE);
NS_ASSERTION(NS_SUCCEEDED(rv), "error removing child");
rv = builder->RebuildContainer(aElement);
NS_ASSERTION(NS_SUCCEEDED(rv), "error rebuilding container");
// XXX ignore error code?
rv = child->SetDocument(nsnull, PR_TRUE);
if (NS_FAILED(rv)) return rv;
NS_RELEASE(builder);
}
// Clear the contents-generated attribute so that the next time we
// come back, we'll regenerate the kids we just killed.
rv = aElement->UnsetAttribute(kNameSpaceID_None,
kTemplateContentsGeneratedAtom,
PR_FALSE);
if (NS_FAILED(rv)) return rv;
rv = aElement->UnsetAttribute(kNameSpaceID_None,
kContainerContentsGeneratedAtom,
PR_FALSE);
if (NS_FAILED(rv)) return rv;
rv = CreateContents(aElement);
if (NS_FAILED(rv)) return rv;
return NS_OK;
}

Просмотреть файл

@ -41,38 +41,36 @@
#include "nsIDOMElement.h"
#include "nsIDOMNode.h"
#include "nsIDOMXULDocument.h"
#include "nsIDOMXULElement.h"
#include "nsIDocument.h"
#include "nsIHTMLContent.h"
#include "nsIHTMLElementFactory.h"
#include "nsINameSpaceManager.h"
#include "nsIRDFContentModelBuilder.h"
#include "nsIRDFCompositeDataSource.h"
#include "nsIRDFContainerUtils.h"
#include "nsIRDFContentModelBuilder.h"
#include "nsIRDFDocument.h"
#include "nsIRDFNode.h"
#include "nsIRDFObserver.h"
#include "nsIRDFRemoteDataSource.h"
#include "nsIRDFService.h"
#include "nsIServiceManager.h"
#include "nsINameSpaceManager.h"
#include "nsIServiceManager.h"
#include "nsISupportsArray.h"
#include "nsITextContent.h"
#include "nsITimer.h"
#include "nsIURL.h"
#include "nsIXULSortService.h"
#include "nsLayoutCID.h"
#include "nsRDFCID.h"
#include "nsRDFContentUtils.h"
#include "nsString.h"
#include "nsVoidArray.h"
#include "nsXPIDLString.h"
#include "prlog.h"
#include "rdf.h"
#include "rdfutil.h"
#include "nsITimer.h"
#include "nsIDOMXULElement.h"
#include "nsVoidArray.h"
#include "nsIXULSortService.h"
#include "nsIHTMLElementFactory.h"
#include "nsIHTMLContent.h"
#include "nsRDFGenericBuilder.h"
#include "prlog.h"
#include "nsIRDFRemoteDataSource.h"
// Return values for EnsureElementHasGenericChild()
#define NS_RDF_ELEMENT_WAS_CREATED NS_RDF_NO_VALUE
#define NS_RDF_ELEMENT_WAS_THERE NS_OK
@ -107,8 +105,252 @@ static NS_DEFINE_CID(kIHTMLElementFactoryIID, NS_IHTML_ELEMENT_FACTORY_IID);
////////////////////////////////////////////////////////////////////////
class RDFGenericBuilderImpl : public nsIRDFContentModelBuilder,
public nsIRDFObserver
{
public:
RDFGenericBuilderImpl();
virtual ~RDFGenericBuilderImpl();
nsresult Init();
// nsISupports interface
NS_DECL_ISUPPORTS
// nsIRDFContentModelBuilder interface
NS_IMETHOD SetDocument(nsIRDFDocument* aDocument);
NS_IMETHOD SetDataBase(nsIRDFCompositeDataSource* aDataBase);
NS_IMETHOD GetDataBase(nsIRDFCompositeDataSource** aDataBase);
NS_IMETHOD CreateRootContent(nsIRDFResource* aResource);
NS_IMETHOD SetRootContent(nsIContent* aElement);
NS_IMETHOD CreateContents(nsIContent* aElement);
NS_IMETHOD OpenContainer(nsIContent* aContainer);
NS_IMETHOD CloseContainer(nsIContent* aContainer);
NS_IMETHOD RebuildContainer(nsIContent* aContainer);
NS_IMETHOD CreateElement(PRInt32 aNameSpaceID,
nsIAtom* aTag,
nsIRDFResource* aResource,
nsIContent** aResult);
// nsIRDFObserver interface
NS_IMETHOD OnAssert(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget);
NS_IMETHOD OnUnassert(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget);
NS_IMETHOD OnChange(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aOldTarget,
nsIRDFNode* aNewTarget);
NS_IMETHOD OnMove(nsIRDFResource* aOldSource,
nsIRDFResource* aNewSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget);
// Implementation methods
nsresult
FindTemplate(nsIContent* aElement,
nsIRDFResource* aProperty,
nsIRDFResource* aChild,
nsIContent **theTemplate);
nsresult
IsTemplateRuleMatch(nsIContent* aElement,
nsIRDFResource* aProperty,
nsIRDFResource* aChild,
nsIContent *aRule,
PRBool *isMatch);
PRBool
IsIgnoreableAttribute(PRInt32 aNameSpaceID, nsIAtom* aAtom);
nsresult
GetSubstitutionText(nsIRDFResource* aResource,
const nsString& aSubstitution,
nsString& aResult);
nsresult
BuildContentFromTemplate(nsIContent *aTemplateNode,
nsIContent *aRealNode,
PRBool aIsUnique,
nsIRDFResource* aChild,
PRInt32 aNaturalOrderPos,
PRBool aNotify);
nsresult
CreateWidgetItem(nsIContent* aElement,
nsIRDFResource* aProperty,
nsIRDFResource* aChild,
PRInt32 aNaturalOrderPos,
PRBool aNotify);
enum eUpdateAction { eSet, eClear };
#if 0
PRBool
IsAttributePersisent(nsIContent *element, PRInt32 aNameSpaceID, nsIAtom* aAtom);
void
GetPersistentAttributes(nsIContent *realKid);
void
PersistAttribute(nsIContent *element,
PRInt32 aNameSpaceID,
nsIAtom* aAtom,
nsString aValue,
eUpdateAction action);
void
PersistProperty(nsIContent *element,
nsIRDFResource *aProperty,
nsIRDFNode *aTarget,
eUpdateAction action);
#endif
nsresult
SynchronizeUsingTemplate(nsIContent *aTemplateNode,
nsIContent* aRealNode,
eUpdateAction aAction,
nsIRDFResource* aProperty,
nsIRDFNode* aValue);
nsresult
RemoveWidgetItem(nsIContent* aElement,
nsIRDFResource* aProperty,
nsIRDFResource* aValue,
PRBool aNotify);
nsresult
CreateContainerContents(nsIContent* aElement, nsIRDFResource* aResource, PRBool aNotify);
nsresult
CreateTemplateContents(nsIContent* aElement, const nsString& aTemplateID);
nsresult
EnsureElementHasGenericChild(nsIContent* aParent,
PRInt32 aNameSpaceID,
nsIAtom* aTag,
PRBool aNotify,
nsIContent** aResult);
PRBool
IsContainmentProperty(nsIContent* aElement, nsIRDFResource* aProperty);
PRBool
IsIgnoredProperty(nsIContent* aElement, nsIRDFResource* aProperty);
PRBool
IsContainer(nsIContent* aParentElement, nsIRDFResource* aTargetResource);
PRBool
IsEmpty(nsIContent* aParentElement, nsIRDFResource* aContainer);
PRBool
IsOpen(nsIContent* aElement);
PRBool
IsElementInWidget(nsIContent* aElement);
PRBool
IsResourceElement(nsIContent* aElement);
nsresult
GetDOMNodeResource(nsIDOMNode* aNode, nsIRDFResource** aResource);
nsresult
GetResource(PRInt32 aNameSpaceID,
nsIAtom* aNameAtom,
nsIRDFResource** aResource);
nsresult FindInsertionPoint(nsIContent* aElement, nsIContent** aResult);
nsresult RemoveGeneratedContent(nsIContent* aElement);
nsresult FindFirstGeneratedChild(nsIContent* aElement, PRInt32* aIndex);
// XXX. Urg. Hack until layout can batch reflows. See bug 10818.
PRBool
IsTreeWidgetItem(nsIContent* aElement);
PRBool
IsReflowScheduled();
nsresult
ScheduleReflow();
static void
ForceTreeReflow(nsITimer* aTimer, void* aClosure);
protected:
nsIRDFDocument* mDocument; // [WEAK]
// We are an observer of the composite datasource. The cycle is
// broken by out-of-band SetDataBase(nsnull) call when document is
// destroyed.
nsCOMPtr<nsIRDFCompositeDataSource> mDB;
nsCOMPtr<nsIContent> mRoot;
nsCOMPtr<nsITimer> mTimer;
static nsIRDFDataSource *mLocalstore;
static PRBool persistLock;
// pseudo-constants
static nsrefcnt gRefCnt;
static nsIRDFService* gRDFService;
static nsIRDFContainerUtils* gRDFContainerUtils;
static nsINameSpaceManager* gNameSpaceManager;
static nsIHTMLElementFactory* gHTMLElementFactory;
static nsIAtom* kContainerAtom;
static nsIAtom* kLazyContentAtom;
static nsIAtom* kIsContainerAtom;
static nsIAtom* kIsEmptyAtom;
static nsIAtom* kXULContentsGeneratedAtom;
static nsIAtom* kTemplateContentsGeneratedAtom;
static nsIAtom* kContainerContentsGeneratedAtom;
static nsIAtom* kNaturalOrderPosAtom;
static nsIAtom* kIdAtom;
static nsIAtom* kPersistAtom;
static nsIAtom* kOpenAtom;
static nsIAtom* kEmptyAtom;
static nsIAtom* kResourceAtom;
static nsIAtom* kURIAtom;
static nsIAtom* kContainmentAtom;
static nsIAtom* kIgnoreAtom;
static nsIAtom* kRefAtom;
static nsIAtom* kValueAtom;
static nsIAtom* kTemplateAtom;
static nsIAtom* kRuleAtom;
static nsIAtom* kTextAtom;
static nsIAtom* kPropertyAtom;
static nsIAtom* kInstanceOfAtom;
static nsIAtom* kTreeAtom;
static nsIAtom* kTreeChildrenAtom;
static nsIAtom* kTreeItemAtom;
static PRInt32 kNameSpaceID_RDF;
static PRInt32 kNameSpaceID_XUL;
static nsIRDFResource* kNC_Title;
static nsIRDFResource* kNC_child;
static nsIRDFResource* kNC_Column;
static nsIRDFResource* kNC_Folder;
static nsIRDFResource* kRDF_child;
static nsIRDFResource* kRDF_instanceOf;
static nsIRDFResource* kXUL_element;
static nsIXULSortService* gXULSortService;
};
////////////////////////////////////////////////////////////////////////
nsrefcnt RDFGenericBuilderImpl::gRefCnt = 0;
nsIXULSortService* RDFGenericBuilderImpl::XULSortService = nsnull;
nsIXULSortService* RDFGenericBuilderImpl::gXULSortService = nsnull;
nsIAtom* RDFGenericBuilderImpl::kContainerAtom;
nsIAtom* RDFGenericBuilderImpl::kLazyContentAtom;
@ -252,7 +494,7 @@ RDFGenericBuilderImpl::~RDFGenericBuilderImpl(void)
nsServiceManager::ReleaseService(kRDFServiceCID, gRDFService);
nsServiceManager::ReleaseService(kRDFContainerUtilsCID, gRDFContainerUtils);
nsServiceManager::ReleaseService(kXULSortServiceCID, XULSortService);
nsServiceManager::ReleaseService(kXULSortServiceCID, gXULSortService);
NS_RELEASE(gNameSpaceManager);
NS_IF_RELEASE(gHTMLElementFactory);
}
@ -351,7 +593,7 @@ RDFGenericBuilderImpl::Init()
rv = nsServiceManager::GetService(kXULSortServiceCID,
kIXULSortServiceIID,
(nsISupports**) &XULSortService);
(nsISupports**) &gXULSortService);
if (NS_FAILED(rv)) return rv;
rv = nsComponentManager::CreateInstance(kHTMLElementFactoryCID,
@ -475,19 +717,23 @@ RDFGenericBuilderImpl::SetRootContent(nsIContent* aElement)
NS_IMETHODIMP
RDFGenericBuilderImpl::CreateContents(nsIContent* aElement)
{
nsresult rv;
NS_PRECONDITION(aElement != nsnull, "null ptr");
if (! aElement)
return NS_ERROR_NULL_POINTER;
// First, make sure that the element is in the right widget -- ours.
if (!IsElementInWidget(aElement))
return NS_OK;
nsresult rv;
nsCOMPtr<nsIRDFResource> resource;
rv = nsRDFContentUtils::GetElementRefResource(aElement, getter_AddRefs(resource));
if (NS_SUCCEEDED(rv)) {
// The element has a resource; that means that it corresponds
// to something in the graph, so we need to go to the graph to
// create its contents.
rv = CreateContainerContents(aElement, resource);
rv = CreateContainerContents(aElement, resource, PR_FALSE);
if (NS_FAILED(rv)) return rv;
}
@ -505,6 +751,192 @@ RDFGenericBuilderImpl::CreateContents(nsIContent* aElement)
}
NS_IMETHODIMP
RDFGenericBuilderImpl::OpenContainer(nsIContent* aElement)
{
nsresult rv;
// First, make sure that the element is in the right widget -- ours.
if (!IsElementInWidget(aElement))
return NS_OK;
nsCOMPtr<nsIRDFResource> resource;
rv = nsRDFContentUtils::GetElementRefResource(aElement, getter_AddRefs(resource));
// If it has no resource, there's nothing that we need to be
// concerned about here.
if (NS_FAILED(rv))
return NS_OK;
// The element has a resource; that means that it corresponds
// to something in the graph, so we need to go to the graph to
// create its contents.
rv = CreateContainerContents(aElement, resource, PR_TRUE);
if (NS_FAILED(rv)) return rv;
if (rv == NS_RDF_ELEMENT_WAS_CREATED) {
nsCOMPtr<nsIAtom> tag;
rv = aElement->GetTag(*getter_AddRefs(tag));
if (NS_FAILED(rv)) return rv;
if (tag.get() == kTreeItemAtom) {
nsCOMPtr<nsIContent> insertionpoint;
rv = FindInsertionPoint(aElement, getter_AddRefs(insertionpoint));
if (NS_FAILED(rv)) return rv;
if (! insertionpoint) {
// No content got built. Bail!
return NS_OK;
}
// Find the first element beneath the insertion point that
// is generated from a template.
PRInt32 indx;
rv = FindFirstGeneratedChild(insertionpoint, &indx);
if (NS_FAILED(rv)) return rv;
if (indx != -1) {
nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
if (! doc)
return NS_ERROR_UNEXPECTED;
rv = doc->ContentAppended(insertionpoint, indx);
if (NS_FAILED(rv)) return rv;
}
}
}
return NS_OK;
}
NS_IMETHODIMP
RDFGenericBuilderImpl::CloseContainer(nsIContent* aElement)
{
NS_PRECONDITION(aElement != nsnull, "null ptr");
if (! aElement)
return NS_ERROR_NULL_POINTER;
// First, make sure that the element is in the right widget -- ours.
if (!IsElementInWidget(aElement))
return NS_OK;
nsresult rv;
nsCOMPtr<nsIAtom> tag;
rv = aElement->GetTag(*getter_AddRefs(tag));
if (NS_FAILED(rv)) return rv;
// If it's not a tree, just bail. Keep the content around until
// the cows come home.
if (tag.get() != kTreeItemAtom)
return NS_OK;
// Find the tag that contains the children so that we can remove
// all of the children.
//
// XXX We do this as a (premature?) optimization so that nodes
// which are not being displayed don't hang around taking up
// space. Unfortunately, the tree widget currently _relies_ on
// this behavior and will break if we don't do it :-(.
nsCOMPtr<nsIContent> insertionpoint;
rv = FindInsertionPoint(aElement, getter_AddRefs(insertionpoint));
if (NS_FAILED(rv)) return rv;
if (insertionpoint) {
PRInt32 count;
rv = insertionpoint->ChildCount(count);
if (NS_FAILED(rv)) return rv;
rv = RemoveGeneratedContent(insertionpoint);
if (NS_FAILED(rv)) return rv;
}
// Clear the contents-generated attribute so that the next time we
// come back, we'll regenerate the kids we just killed.
rv = aElement->UnsetAttribute(kNameSpaceID_None,
kContainerContentsGeneratedAtom,
PR_FALSE);
if (NS_FAILED(rv)) return rv;
// XXX Hack. Setting this attribute forces the RDF element to
// remember that it needs to be re-generated next time around.
rv = aElement->SetAttribute(kNameSpaceID_None,
kLazyContentAtom,
"true",
PR_FALSE);
if (NS_FAILED(rv)) return rv;
return NS_OK;
}
NS_IMETHODIMP
RDFGenericBuilderImpl::RebuildContainer(nsIContent* aElement)
{
nsresult rv;
// Remove any generated children from this node
rv = RemoveGeneratedContent(aElement);
if (NS_FAILED(rv)) return rv;
// Clear the contents-generated attribute so that the next time we
// come back, we'll regenerate the kids we just killed.
rv = aElement->UnsetAttribute(kNameSpaceID_None,
kContainerContentsGeneratedAtom,
PR_FALSE);
if (NS_FAILED(rv)) return rv;
// XXX Hack. Setting this attribute forces the RDF element to
// remember that it needs to be re-generated next time around.
rv = aElement->SetAttribute(kNameSpaceID_None,
kLazyContentAtom,
"true",
PR_FALSE);
if (NS_FAILED(rv)) return rv;
// Since we're changing the 'ref' attribute, we'll need to
// rebuild content for _this_ resource template, too.
rv = aElement->UnsetAttribute(kNameSpaceID_None,
kTemplateContentsGeneratedAtom,
PR_FALSE);
if (NS_FAILED(rv)) return rv;
// Do it!!!
rv = CreateContents(aElement);
if (NS_FAILED(rv)) return rv;
// Now see where on earth the content was _really_ appended so we
// can tell the frames to go reflow themselves. Start with _this_
// element.
nsCOMPtr<nsIContent> insertionpoint = dont_QueryInterface(aElement);
PRInt32 indx;
rv = FindFirstGeneratedChild(insertionpoint, &indx);
if (NS_FAILED(rv)) return rv;
if (indx == -1) {
// Okay, nothing got inserted directly beneath this node; see
// if the it was inserted somewhere _below_ us...
rv = FindInsertionPoint(aElement, getter_AddRefs(insertionpoint));
if (NS_FAILED(rv)) return rv;
if ((insertionpoint != nsnull) && (insertionpoint.get() != aElement)) {
rv = FindFirstGeneratedChild(insertionpoint, &indx);
if (NS_FAILED(rv)) return rv;
}
}
if (indx != -1) {
nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
rv = doc->ContentAppended(insertionpoint, indx);
if (NS_FAILED(rv)) return rv;
}
return NS_OK;
}
NS_IMETHODIMP
RDFGenericBuilderImpl::CreateElement(PRInt32 aNameSpaceID,
nsIAtom* aTag,
@ -634,27 +1066,19 @@ RDFGenericBuilderImpl::OnAssert(nsIRDFResource* aSource,
// Okay, it's a "live" element, so go ahead and append the new
// child to this node.
// XXX Bug 10818.
PRBool notify = PR_TRUE;
if (IsTreeWidgetItem(element)) {
if (!IsReflowScheduled()) {
rv = ScheduleReflow();
if (NS_FAILED(rv)) return rv;
}
else {
// a reflow has been scheduled. we'll add the
// element but won't notify right now.
notify = PR_FALSE;
}
}
rv = CreateWidgetItem(element, aProperty, resource, 0, notify);
rv = CreateWidgetItem(element, aProperty, resource, 0, PR_TRUE);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create widget item");
if (NS_FAILED(rv)) return rv;
rv = element->SetAttribute(kNameSpaceID_None, kEmptyAtom, "false", PR_TRUE);
// Update the "empty" attribute
nsAutoString empty;
rv = element->GetAttribute(kNameSpaceID_None, kEmptyAtom, empty);
if (NS_FAILED(rv)) return rv;
if ((rv != NS_CONTENT_ATTR_HAS_VALUE) || (! empty.Equals("false"))) {
rv = element->SetAttribute(kNameSpaceID_None, kEmptyAtom, "false", PR_TRUE);
if (NS_FAILED(rv)) return rv;
}
}
else {
// Either the target of the assertion is not a resource,
@ -762,8 +1186,14 @@ RDFGenericBuilderImpl::OnUnassert(nsIRDFResource* aSource,
if (NS_FAILED(rv)) return rv;
if (numKids == 0) {
rv = element->SetAttribute(kNameSpaceID_None, kEmptyAtom, "true", PR_TRUE);
nsAutoString empty;
rv = element->GetAttribute(kNameSpaceID_None, kEmptyAtom, empty);
if (NS_FAILED(rv)) return rv;
if ((rv != NS_CONTENT_ATTR_HAS_VALUE) && (! empty.Equals("true"))) {
rv = element->SetAttribute(kNameSpaceID_None, kEmptyAtom, "true", PR_TRUE);
if (NS_FAILED(rv)) return rv;
}
}
}
@ -1020,7 +1450,7 @@ RDFGenericBuilderImpl::GetPersistentAttributes(nsIContent *element)
literal->GetValueConst(&uniLiteral);
if (uniLiteral)
{
rv = element->SetAttribute(nameSpaceID, tag, uniLiteral, PR_TRUE);
rv = element->SetAttribute(nameSpaceID, tag, uniLiteral, PR_FALSE);
}
}
}
@ -1430,7 +1860,7 @@ RDFGenericBuilderImpl::BuildContentFromTemplate(nsIContent *aTemplateNode,
nsCOMPtr<nsIContent> realKid;
if (aIsUnique) {
rv = EnsureElementHasGenericChild(aRealNode, nameSpaceID, tag, getter_AddRefs(realKid));
rv = EnsureElementHasGenericChild(aRealNode, nameSpaceID, tag, aNotify, getter_AddRefs(realKid));
if (NS_FAILED(rv)) return rv;
if (rv == NS_RDF_ELEMENT_WAS_THERE) {
@ -1489,7 +1919,7 @@ RDFGenericBuilderImpl::BuildContentFromTemplate(nsIContent *aTemplateNode,
rv = content->SetText(text.GetUnicode(), text.Length(), PR_FALSE);
if (NS_FAILED(rv)) return rv;
rv = aRealNode->AppendChildTo(nsCOMPtr<nsIContent>( do_QueryInterface(content) ), PR_FALSE);
rv = aRealNode->AppendChildTo(nsCOMPtr<nsIContent>( do_QueryInterface(content) ), aNotify);
if (NS_FAILED(rv)) return rv;
}
}
@ -1564,15 +1994,14 @@ RDFGenericBuilderImpl::BuildContentFromTemplate(nsIContent *aTemplateNode,
// We'll _already_ have added the unique elements.
if (! aIsUnique) {
// Note: add into tree, but only sort if its a resource element!
if ((nsnull != XULSortService) && (isResourceElement)) {
rv = XULSortService->InsertContainerNode(aRealNode, realKid, aNotify);
if (NS_FAILED(rv)) {
aRealNode->AppendChildTo(realKid, aNotify);
}
// Add into content model, special casing treeitems.
if ((nsnull != gXULSortService) && (isResourceElement) && (tag.get() == kTreeItemAtom)) {
rv = gXULSortService->InsertContainerNode(aRealNode, realKid, aNotify);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to insert element via sort service");
}
else {
aRealNode->AppendChildTo(realKid, aNotify);
rv = aRealNode->AppendChildTo(realKid, aNotify);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to insert element");
}
}
@ -1605,12 +2034,8 @@ RDFGenericBuilderImpl::CreateWidgetItem(nsIContent *aElement,
return NS_OK;
}
rv = BuildContentFromTemplate(tmpl,
aElement,
PR_TRUE,
aChild,
aNaturalOrderPos,
aNotify);
rv = BuildContentFromTemplate(tmpl, aElement, PR_TRUE, aChild, aNaturalOrderPos, aNotify);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to build content from template");
return rv;
}
@ -1777,7 +2202,7 @@ RDFGenericBuilderImpl::RemoveWidgetItem(nsIContent* aElement,
nsresult
RDFGenericBuilderImpl::CreateContainerContents(nsIContent* aElement, nsIRDFResource* aResource)
RDFGenericBuilderImpl::CreateContainerContents(nsIContent* aElement, nsIRDFResource* aResource, PRBool aNotify)
{
// Create the contents of a container by iterating over all of the
// "containment" arcs out of the element's resource.
@ -1801,7 +2226,7 @@ RDFGenericBuilderImpl::CreateContainerContents(nsIContent* aElement, nsIRDFResou
if (NS_FAILED(rv)) return rv;
if ((rv == NS_CONTENT_ATTR_HAS_VALUE) && (attrValue.EqualsIgnoreCase("true")))
return NS_OK;
return NS_RDF_ELEMENT_WAS_CREATED;
// Now mark the element's contents as being generated so that
// any re-entrant calls don't trigger an infinite recursion.
@ -1821,11 +2246,6 @@ RDFGenericBuilderImpl::CreateContainerContents(nsIContent* aElement, nsIRDFResou
rv = mDB->ArcLabelsOut(aResource, getter_AddRefs(properties));
if (NS_FAILED(rv)) return rv;
// rjc - sort
nsCOMPtr<nsISupportsArray> tempArray;
rv = NS_NewISupportsArray(getter_AddRefs(tempArray));
if NS_FAILED(rv) return rv;
while (1) {
PRBool hasMore;
rv = properties->HasMoreElements(&hasMore);
@ -1865,74 +2285,13 @@ RDFGenericBuilderImpl::CreateContainerContents(nsIContent* aElement, nsIRDFResou
rv = targets->GetNext(getter_AddRefs(isupportsNext));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIRDFResource> valueResource = do_QueryInterface(isupportsNext);
NS_ASSERTION(valueResource != nsnull, "not a resource");
if (! valueResource)
nsCOMPtr<nsIRDFResource> target = do_QueryInterface(isupportsNext);
NS_ASSERTION(target != nsnull, "not a resource");
if (! target)
continue;
// XXX hack: always append value resource 1st due to sort
// callback implementation
tempArray->AppendElement(valueResource);
tempArray->AppendElement(property);
}
}
PRUint32 numElements;
rv = tempArray->Count(&numElements);
if (NS_FAILED(rv)) return rv;
if (numElements == 0)
return NS_OK;
// Tree widget hackery. To be removed if and when the
// reflow lock is exposed. See bug 10818.
PRBool istree = IsTreeWidgetItem(aElement);
{
// XXX change to use nsVoidArray?
nsIRDFResource** flatArray = new nsIRDFResource*[numElements];
if (! flatArray) return NS_ERROR_OUT_OF_MEMORY;
// flatten array of resources, sort them, then add as item elements
PRUint32 loop;
for (loop=0; loop<numElements; loop++)
flatArray[loop] = (nsIRDFResource *)tempArray->ElementAt(loop);
if (XULSortService) {
XULSortService->OpenContainer(mDB, aElement, flatArray, numElements/2, 2*sizeof(nsIRDFResource *));
}
// This will insert all of the elements into the
// container, but _won't_ bother layout about it.
for (loop=0; loop<numElements; loop+=2) {
rv = CreateWidgetItem(aElement, flatArray[loop+1], flatArray[loop], loop+1, PR_FALSE);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create widget item");
if (NS_FAILED(rv)) break;
}
for (PRInt32 i = PRInt32(numElements) - 1; i >=0; i--) {
NS_IF_RELEASE(flatArray[i]);
}
delete [] flatArray;
if (NS_FAILED(rv)) return rv;
}
if (istree) {
nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
if (! doc)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIContent> treechildren;
rv = nsRDFContentUtils::FindChildByTag(aElement,
kNameSpaceID_XUL,
kTreeChildrenAtom,
getter_AddRefs(treechildren));
if (NS_SUCCEEDED(rv)) {
// _Now_ tell layout that we've mucked with the container. This'll
// force a reflow and get the content displayed.
rv = doc->ContentAppended(treechildren, 0);
rv = CreateWidgetItem(aElement, property, target, -1, aNotify);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create item");
if (NS_FAILED(rv)) return rv;
}
}
@ -2000,7 +2359,7 @@ RDFGenericBuilderImpl::CreateTemplateContents(nsIContent* aElement, const nsStri
element = parent;
}
rv = BuildContentFromTemplate(tmpl, aElement, PR_FALSE, resource, -1, PR_TRUE);
rv = BuildContentFromTemplate(tmpl, aElement, PR_FALSE, resource, -1, PR_FALSE);
if (NS_FAILED(rv)) return rv;
return NS_OK;
@ -2010,6 +2369,7 @@ nsresult
RDFGenericBuilderImpl::EnsureElementHasGenericChild(nsIContent* parent,
PRInt32 nameSpaceID,
nsIAtom* tag,
PRBool aNotify,
nsIContent** result)
{
nsresult rv;
@ -2026,7 +2386,7 @@ RDFGenericBuilderImpl::EnsureElementHasGenericChild(nsIContent* parent,
if (NS_FAILED(rv)) return rv;
// XXX Note that the notification ensures we won't batch insertions! This could be bad! - Dave
rv = parent->AppendChildTo(element, PR_TRUE);
rv = parent->AppendChildTo(element, aNotify);
if (NS_FAILED(rv)) return rv;
*result = element;
@ -2381,6 +2741,109 @@ RDFGenericBuilderImpl::GetResource(PRInt32 aNameSpaceID,
}
nsresult
RDFGenericBuilderImpl::FindInsertionPoint(nsIContent* aElement, nsIContent** aResult)
{
nsresult rv;
// XXX Hack-o-rama. This needs to be fixed to actually grovel over
// the template n' stuff.
nsCOMPtr<nsIAtom> tag;
rv = aElement->GetTag(*getter_AddRefs(tag));
if (NS_FAILED(rv)) return rv;
nsAutoString tagName;
rv = tag->ToString(tagName);
if (NS_FAILED(rv)) return rv;
if (tagName.Equals("tree") || tagName.Equals("treeitem")) {
rv = nsRDFContentUtils::FindChildByTag(aElement, kNameSpaceID_XUL, NS_NewAtom("treechildren"), aResult);
if (NS_FAILED(rv)) return rv;
}
else if (tagName.Equals("menu")) {
rv = nsRDFContentUtils::FindChildByTag(aElement, kNameSpaceID_XUL, NS_NewAtom("menupopup"), aResult);
if (NS_FAILED(rv)) return rv;
}
else {
*aResult = aElement;
NS_ADDREF(*aResult);
}
return NS_OK;
}
nsresult
RDFGenericBuilderImpl::RemoveGeneratedContent(nsIContent* aElement)
{
// Remove all the content beneath aElement that has been generated
// from a template.
nsresult rv;
PRInt32 count;
rv = aElement->ChildCount(count);
if (NS_FAILED(rv)) return rv;
while (--count >= 0) {
nsCOMPtr<nsIContent> child;
rv = aElement->ChildAt(count, *getter_AddRefs(child));
if (NS_FAILED(rv)) return rv;
nsAutoString tmplID;
rv = child->GetAttribute(kNameSpaceID_None, kTemplateAtom, tmplID);
if (NS_FAILED(rv)) return rv;
if (rv != NS_CONTENT_ATTR_HAS_VALUE)
continue;
// It's a generated element. Remove it, and set its document
// to null so that it'll get knocked out of the XUL doc's
// resource-to-element map.
rv = aElement->RemoveChildAt(count, PR_TRUE);
NS_ASSERTION(NS_SUCCEEDED(rv), "error removing child");
rv = child->SetDocument(nsnull, PR_TRUE);
if (NS_FAILED(rv)) return rv;
}
return NS_OK;
}
nsresult
RDFGenericBuilderImpl::FindFirstGeneratedChild(nsIContent* aElement, PRInt32* aIndex)
{
// Find the first kid of aElement that has been generated from a
// template.
nsresult rv;
PRInt32 count;
rv = aElement->ChildCount(count);
if (NS_FAILED(rv)) return rv;
PRInt32 i = 0;
while (i < count) {
nsCOMPtr<nsIContent> child;
rv = aElement->ChildAt(i, *getter_AddRefs(child));
if (NS_FAILED(rv)) return rv;
nsAutoString tmplID;
rv = child->GetAttribute(kNameSpaceID_None, kTemplateAtom, tmplID);
if (NS_FAILED(rv)) return rv;
if (rv == NS_CONTENT_ATTR_HAS_VALUE)
break;
++i;
}
*aIndex = (i < count) ? i : -1;
return NS_OK;
}
PRBool
RDFGenericBuilderImpl::IsTreeWidgetItem(nsIContent* aElement)
{

Просмотреть файл

@ -67,6 +67,23 @@ public:
*/
NS_IMETHOD CreateContents(nsIContent* aElement) = 0;
/**
* 'Open' a container element that was closed before. This gives
* the container a chance to populate its contents.
*/
NS_IMETHOD OpenContainer(nsIContent* aContainer) = 0;
/**
* 'Close' an open container. This gives the container a chance to
* release unused content nodes.
*/
NS_IMETHOD CloseContainer(nsIContent* aContainer) = 0;
/**
* Rebuild the contents of a container.
*/
NS_IMETHOD RebuildContainer(nsIContent* aContainer) = 0;
/**
* Construct an element. This is exposed as a public method,
* because the document implementation may need to call it to
@ -76,6 +93,7 @@ public:
nsIAtom* aTag,
nsIRDFResource* aResource,
nsIContent** aResult) = 0;
};
extern nsresult NS_NewXULTemplateBuilder(nsIRDFContentModelBuilder** aResult);

Просмотреть файл

@ -93,7 +93,7 @@ nsRDFContentUtils::AttachTextNode(nsIContent* parent, nsIRDFNode* value)
if (NS_FAILED(rv)) return rv;
// hook it up to the child
rv = parent->AppendChildTo(nsCOMPtr<nsIContent>( do_QueryInterface(text) ), PR_TRUE);
rv = parent->AppendChildTo(nsCOMPtr<nsIContent>( do_QueryInterface(text) ), PR_FALSE);
if (NS_FAILED(rv)) return rv;
return NS_OK;

Просмотреть файл

@ -41,38 +41,36 @@
#include "nsIDOMElement.h"
#include "nsIDOMNode.h"
#include "nsIDOMXULDocument.h"
#include "nsIDOMXULElement.h"
#include "nsIDocument.h"
#include "nsIHTMLContent.h"
#include "nsIHTMLElementFactory.h"
#include "nsINameSpaceManager.h"
#include "nsIRDFContentModelBuilder.h"
#include "nsIRDFCompositeDataSource.h"
#include "nsIRDFContainerUtils.h"
#include "nsIRDFContentModelBuilder.h"
#include "nsIRDFDocument.h"
#include "nsIRDFNode.h"
#include "nsIRDFObserver.h"
#include "nsIRDFRemoteDataSource.h"
#include "nsIRDFService.h"
#include "nsIServiceManager.h"
#include "nsINameSpaceManager.h"
#include "nsIServiceManager.h"
#include "nsISupportsArray.h"
#include "nsITextContent.h"
#include "nsITimer.h"
#include "nsIURL.h"
#include "nsIXULSortService.h"
#include "nsLayoutCID.h"
#include "nsRDFCID.h"
#include "nsRDFContentUtils.h"
#include "nsString.h"
#include "nsVoidArray.h"
#include "nsXPIDLString.h"
#include "prlog.h"
#include "rdf.h"
#include "rdfutil.h"
#include "nsITimer.h"
#include "nsIDOMXULElement.h"
#include "nsVoidArray.h"
#include "nsIXULSortService.h"
#include "nsIHTMLElementFactory.h"
#include "nsIHTMLContent.h"
#include "nsRDFGenericBuilder.h"
#include "prlog.h"
#include "nsIRDFRemoteDataSource.h"
// Return values for EnsureElementHasGenericChild()
#define NS_RDF_ELEMENT_WAS_CREATED NS_RDF_NO_VALUE
#define NS_RDF_ELEMENT_WAS_THERE NS_OK
@ -107,8 +105,252 @@ static NS_DEFINE_CID(kIHTMLElementFactoryIID, NS_IHTML_ELEMENT_FACTORY_IID);
////////////////////////////////////////////////////////////////////////
class RDFGenericBuilderImpl : public nsIRDFContentModelBuilder,
public nsIRDFObserver
{
public:
RDFGenericBuilderImpl();
virtual ~RDFGenericBuilderImpl();
nsresult Init();
// nsISupports interface
NS_DECL_ISUPPORTS
// nsIRDFContentModelBuilder interface
NS_IMETHOD SetDocument(nsIRDFDocument* aDocument);
NS_IMETHOD SetDataBase(nsIRDFCompositeDataSource* aDataBase);
NS_IMETHOD GetDataBase(nsIRDFCompositeDataSource** aDataBase);
NS_IMETHOD CreateRootContent(nsIRDFResource* aResource);
NS_IMETHOD SetRootContent(nsIContent* aElement);
NS_IMETHOD CreateContents(nsIContent* aElement);
NS_IMETHOD OpenContainer(nsIContent* aContainer);
NS_IMETHOD CloseContainer(nsIContent* aContainer);
NS_IMETHOD RebuildContainer(nsIContent* aContainer);
NS_IMETHOD CreateElement(PRInt32 aNameSpaceID,
nsIAtom* aTag,
nsIRDFResource* aResource,
nsIContent** aResult);
// nsIRDFObserver interface
NS_IMETHOD OnAssert(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget);
NS_IMETHOD OnUnassert(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget);
NS_IMETHOD OnChange(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aOldTarget,
nsIRDFNode* aNewTarget);
NS_IMETHOD OnMove(nsIRDFResource* aOldSource,
nsIRDFResource* aNewSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget);
// Implementation methods
nsresult
FindTemplate(nsIContent* aElement,
nsIRDFResource* aProperty,
nsIRDFResource* aChild,
nsIContent **theTemplate);
nsresult
IsTemplateRuleMatch(nsIContent* aElement,
nsIRDFResource* aProperty,
nsIRDFResource* aChild,
nsIContent *aRule,
PRBool *isMatch);
PRBool
IsIgnoreableAttribute(PRInt32 aNameSpaceID, nsIAtom* aAtom);
nsresult
GetSubstitutionText(nsIRDFResource* aResource,
const nsString& aSubstitution,
nsString& aResult);
nsresult
BuildContentFromTemplate(nsIContent *aTemplateNode,
nsIContent *aRealNode,
PRBool aIsUnique,
nsIRDFResource* aChild,
PRInt32 aNaturalOrderPos,
PRBool aNotify);
nsresult
CreateWidgetItem(nsIContent* aElement,
nsIRDFResource* aProperty,
nsIRDFResource* aChild,
PRInt32 aNaturalOrderPos,
PRBool aNotify);
enum eUpdateAction { eSet, eClear };
#if 0
PRBool
IsAttributePersisent(nsIContent *element, PRInt32 aNameSpaceID, nsIAtom* aAtom);
void
GetPersistentAttributes(nsIContent *realKid);
void
PersistAttribute(nsIContent *element,
PRInt32 aNameSpaceID,
nsIAtom* aAtom,
nsString aValue,
eUpdateAction action);
void
PersistProperty(nsIContent *element,
nsIRDFResource *aProperty,
nsIRDFNode *aTarget,
eUpdateAction action);
#endif
nsresult
SynchronizeUsingTemplate(nsIContent *aTemplateNode,
nsIContent* aRealNode,
eUpdateAction aAction,
nsIRDFResource* aProperty,
nsIRDFNode* aValue);
nsresult
RemoveWidgetItem(nsIContent* aElement,
nsIRDFResource* aProperty,
nsIRDFResource* aValue,
PRBool aNotify);
nsresult
CreateContainerContents(nsIContent* aElement, nsIRDFResource* aResource, PRBool aNotify);
nsresult
CreateTemplateContents(nsIContent* aElement, const nsString& aTemplateID);
nsresult
EnsureElementHasGenericChild(nsIContent* aParent,
PRInt32 aNameSpaceID,
nsIAtom* aTag,
PRBool aNotify,
nsIContent** aResult);
PRBool
IsContainmentProperty(nsIContent* aElement, nsIRDFResource* aProperty);
PRBool
IsIgnoredProperty(nsIContent* aElement, nsIRDFResource* aProperty);
PRBool
IsContainer(nsIContent* aParentElement, nsIRDFResource* aTargetResource);
PRBool
IsEmpty(nsIContent* aParentElement, nsIRDFResource* aContainer);
PRBool
IsOpen(nsIContent* aElement);
PRBool
IsElementInWidget(nsIContent* aElement);
PRBool
IsResourceElement(nsIContent* aElement);
nsresult
GetDOMNodeResource(nsIDOMNode* aNode, nsIRDFResource** aResource);
nsresult
GetResource(PRInt32 aNameSpaceID,
nsIAtom* aNameAtom,
nsIRDFResource** aResource);
nsresult FindInsertionPoint(nsIContent* aElement, nsIContent** aResult);
nsresult RemoveGeneratedContent(nsIContent* aElement);
nsresult FindFirstGeneratedChild(nsIContent* aElement, PRInt32* aIndex);
// XXX. Urg. Hack until layout can batch reflows. See bug 10818.
PRBool
IsTreeWidgetItem(nsIContent* aElement);
PRBool
IsReflowScheduled();
nsresult
ScheduleReflow();
static void
ForceTreeReflow(nsITimer* aTimer, void* aClosure);
protected:
nsIRDFDocument* mDocument; // [WEAK]
// We are an observer of the composite datasource. The cycle is
// broken by out-of-band SetDataBase(nsnull) call when document is
// destroyed.
nsCOMPtr<nsIRDFCompositeDataSource> mDB;
nsCOMPtr<nsIContent> mRoot;
nsCOMPtr<nsITimer> mTimer;
static nsIRDFDataSource *mLocalstore;
static PRBool persistLock;
// pseudo-constants
static nsrefcnt gRefCnt;
static nsIRDFService* gRDFService;
static nsIRDFContainerUtils* gRDFContainerUtils;
static nsINameSpaceManager* gNameSpaceManager;
static nsIHTMLElementFactory* gHTMLElementFactory;
static nsIAtom* kContainerAtom;
static nsIAtom* kLazyContentAtom;
static nsIAtom* kIsContainerAtom;
static nsIAtom* kIsEmptyAtom;
static nsIAtom* kXULContentsGeneratedAtom;
static nsIAtom* kTemplateContentsGeneratedAtom;
static nsIAtom* kContainerContentsGeneratedAtom;
static nsIAtom* kNaturalOrderPosAtom;
static nsIAtom* kIdAtom;
static nsIAtom* kPersistAtom;
static nsIAtom* kOpenAtom;
static nsIAtom* kEmptyAtom;
static nsIAtom* kResourceAtom;
static nsIAtom* kURIAtom;
static nsIAtom* kContainmentAtom;
static nsIAtom* kIgnoreAtom;
static nsIAtom* kRefAtom;
static nsIAtom* kValueAtom;
static nsIAtom* kTemplateAtom;
static nsIAtom* kRuleAtom;
static nsIAtom* kTextAtom;
static nsIAtom* kPropertyAtom;
static nsIAtom* kInstanceOfAtom;
static nsIAtom* kTreeAtom;
static nsIAtom* kTreeChildrenAtom;
static nsIAtom* kTreeItemAtom;
static PRInt32 kNameSpaceID_RDF;
static PRInt32 kNameSpaceID_XUL;
static nsIRDFResource* kNC_Title;
static nsIRDFResource* kNC_child;
static nsIRDFResource* kNC_Column;
static nsIRDFResource* kNC_Folder;
static nsIRDFResource* kRDF_child;
static nsIRDFResource* kRDF_instanceOf;
static nsIRDFResource* kXUL_element;
static nsIXULSortService* gXULSortService;
};
////////////////////////////////////////////////////////////////////////
nsrefcnt RDFGenericBuilderImpl::gRefCnt = 0;
nsIXULSortService* RDFGenericBuilderImpl::XULSortService = nsnull;
nsIXULSortService* RDFGenericBuilderImpl::gXULSortService = nsnull;
nsIAtom* RDFGenericBuilderImpl::kContainerAtom;
nsIAtom* RDFGenericBuilderImpl::kLazyContentAtom;
@ -252,7 +494,7 @@ RDFGenericBuilderImpl::~RDFGenericBuilderImpl(void)
nsServiceManager::ReleaseService(kRDFServiceCID, gRDFService);
nsServiceManager::ReleaseService(kRDFContainerUtilsCID, gRDFContainerUtils);
nsServiceManager::ReleaseService(kXULSortServiceCID, XULSortService);
nsServiceManager::ReleaseService(kXULSortServiceCID, gXULSortService);
NS_RELEASE(gNameSpaceManager);
NS_IF_RELEASE(gHTMLElementFactory);
}
@ -351,7 +593,7 @@ RDFGenericBuilderImpl::Init()
rv = nsServiceManager::GetService(kXULSortServiceCID,
kIXULSortServiceIID,
(nsISupports**) &XULSortService);
(nsISupports**) &gXULSortService);
if (NS_FAILED(rv)) return rv;
rv = nsComponentManager::CreateInstance(kHTMLElementFactoryCID,
@ -475,19 +717,23 @@ RDFGenericBuilderImpl::SetRootContent(nsIContent* aElement)
NS_IMETHODIMP
RDFGenericBuilderImpl::CreateContents(nsIContent* aElement)
{
nsresult rv;
NS_PRECONDITION(aElement != nsnull, "null ptr");
if (! aElement)
return NS_ERROR_NULL_POINTER;
// First, make sure that the element is in the right widget -- ours.
if (!IsElementInWidget(aElement))
return NS_OK;
nsresult rv;
nsCOMPtr<nsIRDFResource> resource;
rv = nsRDFContentUtils::GetElementRefResource(aElement, getter_AddRefs(resource));
if (NS_SUCCEEDED(rv)) {
// The element has a resource; that means that it corresponds
// to something in the graph, so we need to go to the graph to
// create its contents.
rv = CreateContainerContents(aElement, resource);
rv = CreateContainerContents(aElement, resource, PR_FALSE);
if (NS_FAILED(rv)) return rv;
}
@ -505,6 +751,192 @@ RDFGenericBuilderImpl::CreateContents(nsIContent* aElement)
}
NS_IMETHODIMP
RDFGenericBuilderImpl::OpenContainer(nsIContent* aElement)
{
nsresult rv;
// First, make sure that the element is in the right widget -- ours.
if (!IsElementInWidget(aElement))
return NS_OK;
nsCOMPtr<nsIRDFResource> resource;
rv = nsRDFContentUtils::GetElementRefResource(aElement, getter_AddRefs(resource));
// If it has no resource, there's nothing that we need to be
// concerned about here.
if (NS_FAILED(rv))
return NS_OK;
// The element has a resource; that means that it corresponds
// to something in the graph, so we need to go to the graph to
// create its contents.
rv = CreateContainerContents(aElement, resource, PR_TRUE);
if (NS_FAILED(rv)) return rv;
if (rv == NS_RDF_ELEMENT_WAS_CREATED) {
nsCOMPtr<nsIAtom> tag;
rv = aElement->GetTag(*getter_AddRefs(tag));
if (NS_FAILED(rv)) return rv;
if (tag.get() == kTreeItemAtom) {
nsCOMPtr<nsIContent> insertionpoint;
rv = FindInsertionPoint(aElement, getter_AddRefs(insertionpoint));
if (NS_FAILED(rv)) return rv;
if (! insertionpoint) {
// No content got built. Bail!
return NS_OK;
}
// Find the first element beneath the insertion point that
// is generated from a template.
PRInt32 indx;
rv = FindFirstGeneratedChild(insertionpoint, &indx);
if (NS_FAILED(rv)) return rv;
if (indx != -1) {
nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
if (! doc)
return NS_ERROR_UNEXPECTED;
rv = doc->ContentAppended(insertionpoint, indx);
if (NS_FAILED(rv)) return rv;
}
}
}
return NS_OK;
}
NS_IMETHODIMP
RDFGenericBuilderImpl::CloseContainer(nsIContent* aElement)
{
NS_PRECONDITION(aElement != nsnull, "null ptr");
if (! aElement)
return NS_ERROR_NULL_POINTER;
// First, make sure that the element is in the right widget -- ours.
if (!IsElementInWidget(aElement))
return NS_OK;
nsresult rv;
nsCOMPtr<nsIAtom> tag;
rv = aElement->GetTag(*getter_AddRefs(tag));
if (NS_FAILED(rv)) return rv;
// If it's not a tree, just bail. Keep the content around until
// the cows come home.
if (tag.get() != kTreeItemAtom)
return NS_OK;
// Find the tag that contains the children so that we can remove
// all of the children.
//
// XXX We do this as a (premature?) optimization so that nodes
// which are not being displayed don't hang around taking up
// space. Unfortunately, the tree widget currently _relies_ on
// this behavior and will break if we don't do it :-(.
nsCOMPtr<nsIContent> insertionpoint;
rv = FindInsertionPoint(aElement, getter_AddRefs(insertionpoint));
if (NS_FAILED(rv)) return rv;
if (insertionpoint) {
PRInt32 count;
rv = insertionpoint->ChildCount(count);
if (NS_FAILED(rv)) return rv;
rv = RemoveGeneratedContent(insertionpoint);
if (NS_FAILED(rv)) return rv;
}
// Clear the contents-generated attribute so that the next time we
// come back, we'll regenerate the kids we just killed.
rv = aElement->UnsetAttribute(kNameSpaceID_None,
kContainerContentsGeneratedAtom,
PR_FALSE);
if (NS_FAILED(rv)) return rv;
// XXX Hack. Setting this attribute forces the RDF element to
// remember that it needs to be re-generated next time around.
rv = aElement->SetAttribute(kNameSpaceID_None,
kLazyContentAtom,
"true",
PR_FALSE);
if (NS_FAILED(rv)) return rv;
return NS_OK;
}
NS_IMETHODIMP
RDFGenericBuilderImpl::RebuildContainer(nsIContent* aElement)
{
nsresult rv;
// Remove any generated children from this node
rv = RemoveGeneratedContent(aElement);
if (NS_FAILED(rv)) return rv;
// Clear the contents-generated attribute so that the next time we
// come back, we'll regenerate the kids we just killed.
rv = aElement->UnsetAttribute(kNameSpaceID_None,
kContainerContentsGeneratedAtom,
PR_FALSE);
if (NS_FAILED(rv)) return rv;
// XXX Hack. Setting this attribute forces the RDF element to
// remember that it needs to be re-generated next time around.
rv = aElement->SetAttribute(kNameSpaceID_None,
kLazyContentAtom,
"true",
PR_FALSE);
if (NS_FAILED(rv)) return rv;
// Since we're changing the 'ref' attribute, we'll need to
// rebuild content for _this_ resource template, too.
rv = aElement->UnsetAttribute(kNameSpaceID_None,
kTemplateContentsGeneratedAtom,
PR_FALSE);
if (NS_FAILED(rv)) return rv;
// Do it!!!
rv = CreateContents(aElement);
if (NS_FAILED(rv)) return rv;
// Now see where on earth the content was _really_ appended so we
// can tell the frames to go reflow themselves. Start with _this_
// element.
nsCOMPtr<nsIContent> insertionpoint = dont_QueryInterface(aElement);
PRInt32 indx;
rv = FindFirstGeneratedChild(insertionpoint, &indx);
if (NS_FAILED(rv)) return rv;
if (indx == -1) {
// Okay, nothing got inserted directly beneath this node; see
// if the it was inserted somewhere _below_ us...
rv = FindInsertionPoint(aElement, getter_AddRefs(insertionpoint));
if (NS_FAILED(rv)) return rv;
if ((insertionpoint != nsnull) && (insertionpoint.get() != aElement)) {
rv = FindFirstGeneratedChild(insertionpoint, &indx);
if (NS_FAILED(rv)) return rv;
}
}
if (indx != -1) {
nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
rv = doc->ContentAppended(insertionpoint, indx);
if (NS_FAILED(rv)) return rv;
}
return NS_OK;
}
NS_IMETHODIMP
RDFGenericBuilderImpl::CreateElement(PRInt32 aNameSpaceID,
nsIAtom* aTag,
@ -634,27 +1066,19 @@ RDFGenericBuilderImpl::OnAssert(nsIRDFResource* aSource,
// Okay, it's a "live" element, so go ahead and append the new
// child to this node.
// XXX Bug 10818.
PRBool notify = PR_TRUE;
if (IsTreeWidgetItem(element)) {
if (!IsReflowScheduled()) {
rv = ScheduleReflow();
if (NS_FAILED(rv)) return rv;
}
else {
// a reflow has been scheduled. we'll add the
// element but won't notify right now.
notify = PR_FALSE;
}
}
rv = CreateWidgetItem(element, aProperty, resource, 0, notify);
rv = CreateWidgetItem(element, aProperty, resource, 0, PR_TRUE);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create widget item");
if (NS_FAILED(rv)) return rv;
rv = element->SetAttribute(kNameSpaceID_None, kEmptyAtom, "false", PR_TRUE);
// Update the "empty" attribute
nsAutoString empty;
rv = element->GetAttribute(kNameSpaceID_None, kEmptyAtom, empty);
if (NS_FAILED(rv)) return rv;
if ((rv != NS_CONTENT_ATTR_HAS_VALUE) || (! empty.Equals("false"))) {
rv = element->SetAttribute(kNameSpaceID_None, kEmptyAtom, "false", PR_TRUE);
if (NS_FAILED(rv)) return rv;
}
}
else {
// Either the target of the assertion is not a resource,
@ -762,8 +1186,14 @@ RDFGenericBuilderImpl::OnUnassert(nsIRDFResource* aSource,
if (NS_FAILED(rv)) return rv;
if (numKids == 0) {
rv = element->SetAttribute(kNameSpaceID_None, kEmptyAtom, "true", PR_TRUE);
nsAutoString empty;
rv = element->GetAttribute(kNameSpaceID_None, kEmptyAtom, empty);
if (NS_FAILED(rv)) return rv;
if ((rv != NS_CONTENT_ATTR_HAS_VALUE) && (! empty.Equals("true"))) {
rv = element->SetAttribute(kNameSpaceID_None, kEmptyAtom, "true", PR_TRUE);
if (NS_FAILED(rv)) return rv;
}
}
}
@ -1020,7 +1450,7 @@ RDFGenericBuilderImpl::GetPersistentAttributes(nsIContent *element)
literal->GetValueConst(&uniLiteral);
if (uniLiteral)
{
rv = element->SetAttribute(nameSpaceID, tag, uniLiteral, PR_TRUE);
rv = element->SetAttribute(nameSpaceID, tag, uniLiteral, PR_FALSE);
}
}
}
@ -1430,7 +1860,7 @@ RDFGenericBuilderImpl::BuildContentFromTemplate(nsIContent *aTemplateNode,
nsCOMPtr<nsIContent> realKid;
if (aIsUnique) {
rv = EnsureElementHasGenericChild(aRealNode, nameSpaceID, tag, getter_AddRefs(realKid));
rv = EnsureElementHasGenericChild(aRealNode, nameSpaceID, tag, aNotify, getter_AddRefs(realKid));
if (NS_FAILED(rv)) return rv;
if (rv == NS_RDF_ELEMENT_WAS_THERE) {
@ -1489,7 +1919,7 @@ RDFGenericBuilderImpl::BuildContentFromTemplate(nsIContent *aTemplateNode,
rv = content->SetText(text.GetUnicode(), text.Length(), PR_FALSE);
if (NS_FAILED(rv)) return rv;
rv = aRealNode->AppendChildTo(nsCOMPtr<nsIContent>( do_QueryInterface(content) ), PR_FALSE);
rv = aRealNode->AppendChildTo(nsCOMPtr<nsIContent>( do_QueryInterface(content) ), aNotify);
if (NS_FAILED(rv)) return rv;
}
}
@ -1564,15 +1994,14 @@ RDFGenericBuilderImpl::BuildContentFromTemplate(nsIContent *aTemplateNode,
// We'll _already_ have added the unique elements.
if (! aIsUnique) {
// Note: add into tree, but only sort if its a resource element!
if ((nsnull != XULSortService) && (isResourceElement)) {
rv = XULSortService->InsertContainerNode(aRealNode, realKid, aNotify);
if (NS_FAILED(rv)) {
aRealNode->AppendChildTo(realKid, aNotify);
}
// Add into content model, special casing treeitems.
if ((nsnull != gXULSortService) && (isResourceElement) && (tag.get() == kTreeItemAtom)) {
rv = gXULSortService->InsertContainerNode(aRealNode, realKid, aNotify);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to insert element via sort service");
}
else {
aRealNode->AppendChildTo(realKid, aNotify);
rv = aRealNode->AppendChildTo(realKid, aNotify);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to insert element");
}
}
@ -1605,12 +2034,8 @@ RDFGenericBuilderImpl::CreateWidgetItem(nsIContent *aElement,
return NS_OK;
}
rv = BuildContentFromTemplate(tmpl,
aElement,
PR_TRUE,
aChild,
aNaturalOrderPos,
aNotify);
rv = BuildContentFromTemplate(tmpl, aElement, PR_TRUE, aChild, aNaturalOrderPos, aNotify);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to build content from template");
return rv;
}
@ -1777,7 +2202,7 @@ RDFGenericBuilderImpl::RemoveWidgetItem(nsIContent* aElement,
nsresult
RDFGenericBuilderImpl::CreateContainerContents(nsIContent* aElement, nsIRDFResource* aResource)
RDFGenericBuilderImpl::CreateContainerContents(nsIContent* aElement, nsIRDFResource* aResource, PRBool aNotify)
{
// Create the contents of a container by iterating over all of the
// "containment" arcs out of the element's resource.
@ -1801,7 +2226,7 @@ RDFGenericBuilderImpl::CreateContainerContents(nsIContent* aElement, nsIRDFResou
if (NS_FAILED(rv)) return rv;
if ((rv == NS_CONTENT_ATTR_HAS_VALUE) && (attrValue.EqualsIgnoreCase("true")))
return NS_OK;
return NS_RDF_ELEMENT_WAS_CREATED;
// Now mark the element's contents as being generated so that
// any re-entrant calls don't trigger an infinite recursion.
@ -1821,11 +2246,6 @@ RDFGenericBuilderImpl::CreateContainerContents(nsIContent* aElement, nsIRDFResou
rv = mDB->ArcLabelsOut(aResource, getter_AddRefs(properties));
if (NS_FAILED(rv)) return rv;
// rjc - sort
nsCOMPtr<nsISupportsArray> tempArray;
rv = NS_NewISupportsArray(getter_AddRefs(tempArray));
if NS_FAILED(rv) return rv;
while (1) {
PRBool hasMore;
rv = properties->HasMoreElements(&hasMore);
@ -1865,74 +2285,13 @@ RDFGenericBuilderImpl::CreateContainerContents(nsIContent* aElement, nsIRDFResou
rv = targets->GetNext(getter_AddRefs(isupportsNext));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIRDFResource> valueResource = do_QueryInterface(isupportsNext);
NS_ASSERTION(valueResource != nsnull, "not a resource");
if (! valueResource)
nsCOMPtr<nsIRDFResource> target = do_QueryInterface(isupportsNext);
NS_ASSERTION(target != nsnull, "not a resource");
if (! target)
continue;
// XXX hack: always append value resource 1st due to sort
// callback implementation
tempArray->AppendElement(valueResource);
tempArray->AppendElement(property);
}
}
PRUint32 numElements;
rv = tempArray->Count(&numElements);
if (NS_FAILED(rv)) return rv;
if (numElements == 0)
return NS_OK;
// Tree widget hackery. To be removed if and when the
// reflow lock is exposed. See bug 10818.
PRBool istree = IsTreeWidgetItem(aElement);
{
// XXX change to use nsVoidArray?
nsIRDFResource** flatArray = new nsIRDFResource*[numElements];
if (! flatArray) return NS_ERROR_OUT_OF_MEMORY;
// flatten array of resources, sort them, then add as item elements
PRUint32 loop;
for (loop=0; loop<numElements; loop++)
flatArray[loop] = (nsIRDFResource *)tempArray->ElementAt(loop);
if (XULSortService) {
XULSortService->OpenContainer(mDB, aElement, flatArray, numElements/2, 2*sizeof(nsIRDFResource *));
}
// This will insert all of the elements into the
// container, but _won't_ bother layout about it.
for (loop=0; loop<numElements; loop+=2) {
rv = CreateWidgetItem(aElement, flatArray[loop+1], flatArray[loop], loop+1, PR_FALSE);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create widget item");
if (NS_FAILED(rv)) break;
}
for (PRInt32 i = PRInt32(numElements) - 1; i >=0; i--) {
NS_IF_RELEASE(flatArray[i]);
}
delete [] flatArray;
if (NS_FAILED(rv)) return rv;
}
if (istree) {
nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
if (! doc)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIContent> treechildren;
rv = nsRDFContentUtils::FindChildByTag(aElement,
kNameSpaceID_XUL,
kTreeChildrenAtom,
getter_AddRefs(treechildren));
if (NS_SUCCEEDED(rv)) {
// _Now_ tell layout that we've mucked with the container. This'll
// force a reflow and get the content displayed.
rv = doc->ContentAppended(treechildren, 0);
rv = CreateWidgetItem(aElement, property, target, -1, aNotify);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create item");
if (NS_FAILED(rv)) return rv;
}
}
@ -2000,7 +2359,7 @@ RDFGenericBuilderImpl::CreateTemplateContents(nsIContent* aElement, const nsStri
element = parent;
}
rv = BuildContentFromTemplate(tmpl, aElement, PR_FALSE, resource, -1, PR_TRUE);
rv = BuildContentFromTemplate(tmpl, aElement, PR_FALSE, resource, -1, PR_FALSE);
if (NS_FAILED(rv)) return rv;
return NS_OK;
@ -2010,6 +2369,7 @@ nsresult
RDFGenericBuilderImpl::EnsureElementHasGenericChild(nsIContent* parent,
PRInt32 nameSpaceID,
nsIAtom* tag,
PRBool aNotify,
nsIContent** result)
{
nsresult rv;
@ -2026,7 +2386,7 @@ RDFGenericBuilderImpl::EnsureElementHasGenericChild(nsIContent* parent,
if (NS_FAILED(rv)) return rv;
// XXX Note that the notification ensures we won't batch insertions! This could be bad! - Dave
rv = parent->AppendChildTo(element, PR_TRUE);
rv = parent->AppendChildTo(element, aNotify);
if (NS_FAILED(rv)) return rv;
*result = element;
@ -2381,6 +2741,109 @@ RDFGenericBuilderImpl::GetResource(PRInt32 aNameSpaceID,
}
nsresult
RDFGenericBuilderImpl::FindInsertionPoint(nsIContent* aElement, nsIContent** aResult)
{
nsresult rv;
// XXX Hack-o-rama. This needs to be fixed to actually grovel over
// the template n' stuff.
nsCOMPtr<nsIAtom> tag;
rv = aElement->GetTag(*getter_AddRefs(tag));
if (NS_FAILED(rv)) return rv;
nsAutoString tagName;
rv = tag->ToString(tagName);
if (NS_FAILED(rv)) return rv;
if (tagName.Equals("tree") || tagName.Equals("treeitem")) {
rv = nsRDFContentUtils::FindChildByTag(aElement, kNameSpaceID_XUL, NS_NewAtom("treechildren"), aResult);
if (NS_FAILED(rv)) return rv;
}
else if (tagName.Equals("menu")) {
rv = nsRDFContentUtils::FindChildByTag(aElement, kNameSpaceID_XUL, NS_NewAtom("menupopup"), aResult);
if (NS_FAILED(rv)) return rv;
}
else {
*aResult = aElement;
NS_ADDREF(*aResult);
}
return NS_OK;
}
nsresult
RDFGenericBuilderImpl::RemoveGeneratedContent(nsIContent* aElement)
{
// Remove all the content beneath aElement that has been generated
// from a template.
nsresult rv;
PRInt32 count;
rv = aElement->ChildCount(count);
if (NS_FAILED(rv)) return rv;
while (--count >= 0) {
nsCOMPtr<nsIContent> child;
rv = aElement->ChildAt(count, *getter_AddRefs(child));
if (NS_FAILED(rv)) return rv;
nsAutoString tmplID;
rv = child->GetAttribute(kNameSpaceID_None, kTemplateAtom, tmplID);
if (NS_FAILED(rv)) return rv;
if (rv != NS_CONTENT_ATTR_HAS_VALUE)
continue;
// It's a generated element. Remove it, and set its document
// to null so that it'll get knocked out of the XUL doc's
// resource-to-element map.
rv = aElement->RemoveChildAt(count, PR_TRUE);
NS_ASSERTION(NS_SUCCEEDED(rv), "error removing child");
rv = child->SetDocument(nsnull, PR_TRUE);
if (NS_FAILED(rv)) return rv;
}
return NS_OK;
}
nsresult
RDFGenericBuilderImpl::FindFirstGeneratedChild(nsIContent* aElement, PRInt32* aIndex)
{
// Find the first kid of aElement that has been generated from a
// template.
nsresult rv;
PRInt32 count;
rv = aElement->ChildCount(count);
if (NS_FAILED(rv)) return rv;
PRInt32 i = 0;
while (i < count) {
nsCOMPtr<nsIContent> child;
rv = aElement->ChildAt(i, *getter_AddRefs(child));
if (NS_FAILED(rv)) return rv;
nsAutoString tmplID;
rv = child->GetAttribute(kNameSpaceID_None, kTemplateAtom, tmplID);
if (NS_FAILED(rv)) return rv;
if (rv == NS_CONTENT_ATTR_HAS_VALUE)
break;
++i;
}
*aIndex = (i < count) ? i : -1;
return NS_OK;
}
PRBool
RDFGenericBuilderImpl::IsTreeWidgetItem(nsIContent* aElement)
{

Просмотреть файл

@ -1,274 +0,0 @@
/* -*- 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.0 (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.
*/
/*
An implementation that builds a XUL
content model that is to be used with a certain widget. This class
is abstract.
*/
#include "nsIRDFContainerUtils.h"
#include "nsIRDFContentModelBuilder.h"
#include "nsIRDFObserver.h"
#include "nsITimer.h"
#include "nsIXULSortService.h"
class nsIRDFDocument;
class nsIRDFCompositeDataSource;
class nsIRDFResource;
class nsIContent;
class nsIRDFNode;
class nsIAtom;
class nsIRDFService;
class nsIHTMLElementFactory;
class RDFGenericBuilderImpl : public nsIRDFContentModelBuilder,
public nsIRDFObserver
{
public:
RDFGenericBuilderImpl();
virtual ~RDFGenericBuilderImpl();
nsresult Init();
// nsISupports interface
NS_DECL_ISUPPORTS
// nsIRDFContentModelBuilder interface
NS_IMETHOD SetDocument(nsIRDFDocument* aDocument);
NS_IMETHOD SetDataBase(nsIRDFCompositeDataSource* aDataBase);
NS_IMETHOD GetDataBase(nsIRDFCompositeDataSource** aDataBase);
NS_IMETHOD CreateRootContent(nsIRDFResource* aResource);
NS_IMETHOD SetRootContent(nsIContent* aElement);
NS_IMETHOD CreateContents(nsIContent* aElement);
NS_IMETHOD CreateElement(PRInt32 aNameSpaceID,
nsIAtom* aTag,
nsIRDFResource* aResource,
nsIContent** aResult);
// nsIRDFObserver interface
NS_IMETHOD OnAssert(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget);
NS_IMETHOD OnUnassert(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget);
NS_IMETHOD OnChange(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aOldTarget,
nsIRDFNode* aNewTarget);
NS_IMETHOD OnMove(nsIRDFResource* aOldSource,
nsIRDFResource* aNewSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget);
// Implementation methods
nsresult
FindTemplate(nsIContent* aElement,
nsIRDFResource* aProperty,
nsIRDFResource* aChild,
nsIContent **theTemplate);
nsresult
IsTemplateRuleMatch(nsIContent* aElement,
nsIRDFResource* aProperty,
nsIRDFResource* aChild,
nsIContent *aRule,
PRBool *isMatch);
PRBool
IsIgnoreableAttribute(PRInt32 aNameSpaceID, nsIAtom* aAtom);
nsresult
GetSubstitutionText(nsIRDFResource* aResource,
const nsString& aSubstitution,
nsString& aResult);
nsresult
BuildContentFromTemplate(nsIContent *aTemplateNode,
nsIContent *aRealNode,
PRBool aIsUnique,
nsIRDFResource* aChild,
PRInt32 aNaturalOrderPos,
PRBool aNotify);
nsresult
CreateWidgetItem(nsIContent* aElement,
nsIRDFResource* aProperty,
nsIRDFResource* aChild,
PRInt32 aNaturalOrderPos,
PRBool aNotify);
enum eUpdateAction { eSet, eClear };
#if 0
PRBool
IsAttributePersisent(nsIContent *element, PRInt32 aNameSpaceID, nsIAtom* aAtom);
void
GetPersistentAttributes(nsIContent *realKid);
void
PersistAttribute(nsIContent *element,
PRInt32 aNameSpaceID,
nsIAtom* aAtom,
nsString aValue,
eUpdateAction action);
void
PersistProperty(nsIContent *element,
nsIRDFResource *aProperty,
nsIRDFNode *aTarget,
eUpdateAction action);
#endif
nsresult
SynchronizeUsingTemplate(nsIContent *aTemplateNode,
nsIContent* aRealNode,
eUpdateAction aAction,
nsIRDFResource* aProperty,
nsIRDFNode* aValue);
nsresult
RemoveWidgetItem(nsIContent* aElement,
nsIRDFResource* aProperty,
nsIRDFResource* aValue,
PRBool aNotify);
nsresult
CreateContainerContents(nsIContent* aElement, nsIRDFResource* aResource);
nsresult
CreateTemplateContents(nsIContent* aElement, const nsString& aTemplateID);
nsresult
EnsureElementHasGenericChild(nsIContent* aParent,
PRInt32 aNameSpaceID,
nsIAtom* aTag,
nsIContent** aResult);
PRBool
IsContainmentProperty(nsIContent* aElement, nsIRDFResource* aProperty);
PRBool
IsIgnoredProperty(nsIContent* aElement, nsIRDFResource* aProperty);
PRBool
IsContainer(nsIContent* aParentElement, nsIRDFResource* aTargetResource);
PRBool
IsEmpty(nsIContent* aParentElement, nsIRDFResource* aContainer);
PRBool
IsOpen(nsIContent* aElement);
PRBool
IsElementInWidget(nsIContent* aElement);
PRBool
IsResourceElement(nsIContent* aElement);
nsresult
GetDOMNodeResource(nsIDOMNode* aNode, nsIRDFResource** aResource);
nsresult
GetResource(PRInt32 aNameSpaceID,
nsIAtom* aNameAtom,
nsIRDFResource** aResource);
// XXX. Urg. Hack until layout can batch reflows. See bug 10818.
PRBool
IsTreeWidgetItem(nsIContent* aElement);
PRBool
IsReflowScheduled();
nsresult
ScheduleReflow();
static void
ForceTreeReflow(nsITimer* aTimer, void* aClosure);
protected:
nsIRDFDocument* mDocument; // [WEAK]
// We are an observer of the composite datasource. The cycle is
// broken by out-of-band SetDataBase(nsnull) call when document is
// destroyed.
nsCOMPtr<nsIRDFCompositeDataSource> mDB;
nsCOMPtr<nsIContent> mRoot;
nsCOMPtr<nsITimer> mTimer;
static nsIRDFDataSource *mLocalstore;
static PRBool persistLock;
// pseudo-constants
static nsrefcnt gRefCnt;
static nsIRDFService* gRDFService;
static nsIRDFContainerUtils* gRDFContainerUtils;
static nsINameSpaceManager* gNameSpaceManager;
static nsIHTMLElementFactory* gHTMLElementFactory;
static nsIAtom* kContainerAtom;
static nsIAtom* kLazyContentAtom;
static nsIAtom* kIsContainerAtom;
static nsIAtom* kIsEmptyAtom;
static nsIAtom* kXULContentsGeneratedAtom;
static nsIAtom* kTemplateContentsGeneratedAtom;
static nsIAtom* kContainerContentsGeneratedAtom;
static nsIAtom* kNaturalOrderPosAtom;
static nsIAtom* kIdAtom;
static nsIAtom* kPersistAtom;
static nsIAtom* kOpenAtom;
static nsIAtom* kEmptyAtom;
static nsIAtom* kResourceAtom;
static nsIAtom* kURIAtom;
static nsIAtom* kContainmentAtom;
static nsIAtom* kIgnoreAtom;
static nsIAtom* kRefAtom;
static nsIAtom* kValueAtom;
static nsIAtom* kTemplateAtom;
static nsIAtom* kRuleAtom;
static nsIAtom* kTextAtom;
static nsIAtom* kPropertyAtom;
static nsIAtom* kInstanceOfAtom;
static nsIAtom* kTreeAtom;
static nsIAtom* kTreeChildrenAtom;
static nsIAtom* kTreeItemAtom;
static PRInt32 kNameSpaceID_RDF;
static PRInt32 kNameSpaceID_XUL;
static nsIRDFResource* kNC_Title;
static nsIRDFResource* kNC_child;
static nsIRDFResource* kNC_Column;
static nsIRDFResource* kNC_Folder;
static nsIRDFResource* kRDF_child;
static nsIRDFResource* kRDF_instanceOf;
static nsIRDFResource* kXUL_element;
static nsIXULSortService *XULSortService;
};

Просмотреть файл

@ -188,8 +188,6 @@ private:
static nsIAtom* kDataSourcesAtom;
static nsIAtom* kIdAtom;
static nsIAtom* kInstanceOfAtom;
static nsIAtom* kTemplateContentsGeneratedAtom;
static nsIAtom* kContainerContentsGeneratedAtom;
static nsIAtom* kMenuAtom;
static nsIAtom* kMenuBarAtom;
static nsIAtom* kKeysetAtom;
@ -225,6 +223,9 @@ public:
NS_IMETHOD CreateRootContent(nsIRDFResource* aResource);
NS_IMETHOD SetRootContent(nsIContent* aResource);
NS_IMETHOD CreateContents(nsIContent* aElement);
NS_IMETHOD OpenContainer(nsIContent* aElement);
NS_IMETHOD CloseContainer(nsIContent* aElement);
NS_IMETHOD RebuildContainer(nsIContent* aElement);
NS_IMETHOD CreateElement(PRInt32 aNameSpaceID,
nsIAtom* aTagName,
nsIRDFResource* aResource,
@ -342,8 +343,6 @@ nsIAtom* RDFXULBuilderImpl::kLazyContentAtom;
nsIAtom* RDFXULBuilderImpl::kDataSourcesAtom;
nsIAtom* RDFXULBuilderImpl::kIdAtom;
nsIAtom* RDFXULBuilderImpl::kInstanceOfAtom;
nsIAtom* RDFXULBuilderImpl::kTemplateContentsGeneratedAtom;
nsIAtom* RDFXULBuilderImpl::kContainerContentsGeneratedAtom;
nsIAtom* RDFXULBuilderImpl::kMenuAtom;
nsIAtom* RDFXULBuilderImpl::kMenuBarAtom;
nsIAtom* RDFXULBuilderImpl::kKeysetAtom;
@ -418,8 +417,6 @@ RDFXULBuilderImpl::Init()
kDataSourcesAtom = NS_NewAtom("datasources");
kIdAtom = NS_NewAtom("id");
kInstanceOfAtom = NS_NewAtom("instanceof");
kTemplateContentsGeneratedAtom = NS_NewAtom("itemcontentsgenerated");
kContainerContentsGeneratedAtom = NS_NewAtom("containercontentsgenerated");
kMenuAtom = NS_NewAtom("menu");
kMenuBarAtom = NS_NewAtom("menubar");
kKeysetAtom = NS_NewAtom("keyset");
@ -491,8 +488,6 @@ RDFXULBuilderImpl::~RDFXULBuilderImpl(void)
NS_IF_RELEASE(kLazyContentAtom);
NS_IF_RELEASE(kXULContentsGeneratedAtom);
NS_IF_RELEASE(kIdAtom);
NS_IF_RELEASE(kTemplateContentsGeneratedAtom);
NS_IF_RELEASE(kContainerContentsGeneratedAtom);
NS_IF_RELEASE(kDataSourcesAtom);
NS_IF_RELEASE(kTreeAtom);
NS_IF_RELEASE(kMenuAtom);
@ -749,6 +744,27 @@ RDFXULBuilderImpl::CreateContents(nsIContent* aElement)
}
NS_IMETHODIMP
RDFXULBuilderImpl::OpenContainer(nsIContent* aContainer)
{
return NS_OK;
}
NS_IMETHODIMP
RDFXULBuilderImpl::CloseContainer(nsIContent* aContainer)
{
return NS_OK;
}
NS_IMETHODIMP
RDFXULBuilderImpl::RebuildContainer(nsIContent* aContainer)
{
return NS_OK;
}
NS_IMETHODIMP
RDFXULBuilderImpl::CreateElement(PRInt32 aNameSpaceID,
nsIAtom* aTagName,
@ -1318,7 +1334,7 @@ RDFXULBuilderImpl::InsertChildAt(nsINameSpace* aNameSpace,
}
#endif
rv = aElement->InsertChildAt(child, aIndex, PR_TRUE);
rv = aElement->InsertChildAt(child, aIndex, PR_FALSE);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to add element to content model");
if (NS_FAILED(rv)) return rv;
}
@ -1398,7 +1414,7 @@ RDFXULBuilderImpl::ReplaceChildAt(nsINameSpace* aNameSpace,
}
#endif
rv = aElement->ReplaceChildAt(child, aIndex, PR_TRUE);
rv = aElement->ReplaceChildAt(child, aIndex, PR_FALSE);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to add element to content model");
if (NS_FAILED(rv)) return rv;
}

Просмотреть файл

@ -802,7 +802,7 @@ public:
nsresult OpenWidgetItem(nsIContent* aElement);
nsresult CloseWidgetItem(nsIContent* aElement);
nsresult RemoveAndRebuildGeneratedChildren(nsIContent* aElement);
nsresult RebuildWidgetItem(nsIContent* aElement);
nsresult
AddElementToMap(nsIContent* aElement, PRBool aDeep);
@ -2101,14 +2101,14 @@ XULDocumentImpl::ContentStatesChanged(nsIContent* aContent1, nsIContent* aConten
}
NS_IMETHODIMP
XULDocumentImpl::AttributeChanged(nsIContent* aChild,
XULDocumentImpl::AttributeChanged(nsIContent* aElement,
nsIAtom* aAttribute,
PRInt32 aHint)
{
nsresult rv;
PRInt32 nameSpaceID;
rv = aChild->GetNameSpaceID(nameSpaceID);
rv = aElement->GetNameSpaceID(nameSpaceID);
if (NS_FAILED(rv)) return rv;
// First see if we need to update our element map.
@ -2120,27 +2120,7 @@ XULDocumentImpl::AttributeChanged(nsIContent* aChild,
// That'll have removed _both_ the 'ref' and 'id' entries from
// the map. So add 'em back now.
rv = AddElementToMap(aChild, PR_FALSE);
if (NS_FAILED(rv)) return rv;
}
}
// Handle "special" cases.
if (nameSpaceID == kNameSpaceID_XUL) {
if (aAttribute == kOpenAtom) {
nsAutoString open;
rv = aChild->GetAttribute(kNameSpaceID_None, kOpenAtom, open);
if (NS_FAILED(rv)) return rv;
if ((rv == NS_CONTENT_ATTR_HAS_VALUE) && (open.Equals("true"))) {
OpenWidgetItem(aChild);
}
else {
CloseWidgetItem(aChild);
}
}
else if (aAttribute == kRefAtom) {
rv = RemoveAndRebuildGeneratedChildren(aChild);
rv = AddElementToMap(aElement, PR_FALSE);
if (NS_FAILED(rv)) return rv;
}
}
@ -2148,11 +2128,34 @@ XULDocumentImpl::AttributeChanged(nsIContent* aChild,
// Now notify external observers
for (PRInt32 i = 0; i < mObservers.Count(); i++) {
nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i];
observer->AttributeChanged(this, aChild, aAttribute, aHint);
observer->AttributeChanged(this, aElement, aAttribute, aHint);
if (observer != (nsIDocumentObserver*)mObservers.ElementAt(i)) {
i--;
}
}
// Handle "special" cases. We do this handling _after_ we've
// notified the observer to ensure that any frames that are
// caching information (e.g., the tree widget and the 'open'
// attribute) will notice things properly.
if (nameSpaceID == kNameSpaceID_XUL) {
if (aAttribute == kOpenAtom) {
nsAutoString open;
rv = aElement->GetAttribute(kNameSpaceID_None, kOpenAtom, open);
if (NS_FAILED(rv)) return rv;
if ((rv == NS_CONTENT_ATTR_HAS_VALUE) && (open.Equals("true"))) {
OpenWidgetItem(aElement);
}
else {
CloseWidgetItem(aElement);
}
}
else if (aAttribute == kRefAtom) {
RebuildWidgetItem(aElement);
}
}
return NS_OK;
}
@ -4483,10 +4486,17 @@ XULDocumentImpl::ReleaseEvent(const nsString& aType)
nsresult
XULDocumentImpl::OpenWidgetItem(nsIContent* aElement)
{
NS_PRECONDITION(aElement != nsnull, "null ptr");
if (! aElement)
return NS_ERROR_NULL_POINTER;
if (! mBuilders)
return NS_ERROR_NOT_INITIALIZED;
nsresult rv;
#ifdef PR_LOGGING
if (PR_LOG_TEST(gXULLog, PR_LOG_DEBUG)) {
nsresult rv;
nsCOMPtr<nsIAtom> tag;
rv = aElement->GetTag(*getter_AddRefs(tag));
if (NS_FAILED(rv)) return rv;
@ -4499,12 +4509,39 @@ XULDocumentImpl::OpenWidgetItem(nsIContent* aElement)
(const char*) nsCAutoString(tagStr)));
}
#endif
return CreateContents(aElement);
PRUint32 cnt = 0;
rv = mBuilders->Count(&cnt);
NS_ASSERTION(NS_SUCCEEDED(rv), "Count failed");
for (PRUint32 i = 0; i < cnt; ++i) {
// XXX we should QueryInterface() here
nsIRDFContentModelBuilder* builder
= (nsIRDFContentModelBuilder*) mBuilders->ElementAt(i);
NS_ASSERTION(builder != nsnull, "null ptr");
if (! builder)
continue;
rv = builder->OpenContainer(aElement);
NS_ASSERTION(NS_SUCCEEDED(rv), "error opening container");
// XXX ignore error code?
NS_RELEASE(builder);
}
return NS_OK;
}
nsresult
XULDocumentImpl::CloseWidgetItem(nsIContent* aElement)
{
NS_PRECONDITION(aElement != nsnull, "null ptr");
if (! aElement)
return NS_ERROR_NULL_POINTER;
if (! mBuilders)
return NS_ERROR_NOT_INITIALIZED;
nsresult rv;
#ifdef PR_LOGGING
@ -4522,163 +4559,78 @@ XULDocumentImpl::CloseWidgetItem(nsIContent* aElement)
}
#endif
// Find the tag that contains the children so that we can remove
// all of the children.
//
// XXX We make a bit of a leap here and assume that the same
// template that was used to generate _us_ was used to generate
// our _kids_. I'm sure this'll break when we do toolbars or
// something.
nsAutoString tmplID;
rv = aElement->GetAttribute(kNameSpaceID_None, kTemplateAtom, tmplID);
if (NS_FAILED(rv)) return rv;
PRUint32 cnt = 0;
rv = mBuilders->Count(&cnt);
NS_ASSERTION(NS_SUCCEEDED(rv), "Count failed");
for (PRUint32 i = 0; i < cnt; ++i) {
// XXX we should QueryInterface() here
nsIRDFContentModelBuilder* builder
= (nsIRDFContentModelBuilder*) mBuilders->ElementAt(i);
if (rv != NS_CONTENT_ATTR_HAS_VALUE)
return NS_OK;
NS_ASSERTION(builder != nsnull, "null ptr");
if (! builder)
continue;
nsCOMPtr<nsIDOMElement> tmplDOMEle;
rv = GetElementById(tmplID, getter_AddRefs(tmplDOMEle));
if (NS_FAILED(rv)) return rv;
rv = builder->CloseContainer(aElement);
NS_ASSERTION(NS_SUCCEEDED(rv), "error closing container");
// XXX ignore error code?
nsCOMPtr<nsIContent> tmpl = do_QueryInterface(tmplDOMEle);
if (! tmpl)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIContent> tmplParent;
rv = tmpl->GetParent(*getter_AddRefs(tmplParent));
if (NS_FAILED(rv)) return rv;
NS_ASSERTION(tmplParent != nsnull, "template node has no parent");
if (! tmplParent)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIAtom> tmplParentTag;
rv = tmplParent->GetTag(*getter_AddRefs(tmplParentTag));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIContent> childcontainer;
if ((tmplParentTag.get() == kRuleAtom) || (tmplParentTag.get() == kTemplateAtom)) {
childcontainer = dont_QueryInterface(aElement);
NS_RELEASE(builder);
}
else {
rv = nsRDFContentUtils::FindChildByTag(aElement,
kNameSpaceID_XUL,
tmplParentTag,
getter_AddRefs(childcontainer));
if (NS_FAILED(rv)) return rv;
if (rv == NS_RDF_NO_VALUE) {
// No tag; must've already been closed
return NS_OK;
}
}
PRInt32 count;
rv = childcontainer->ChildCount(count);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get count of the parent's children");
if (NS_FAILED(rv)) return rv;
while (--count >= 0) {
nsCOMPtr<nsIContent> child;
rv = childcontainer->ChildAt(count, *getter_AddRefs(child));
if (NS_FAILED(rv)) return rv;
rv = childcontainer->RemoveChildAt(count, PR_TRUE);
NS_ASSERTION(NS_SUCCEEDED(rv), "error removing child");
do {
// If it's _not_ a XUL element, then we want to blow it and
// all of its kids out of the XUL document's
// resource-to-element map.
nsCOMPtr<nsIRDFResource> resource;
rv = nsRDFContentUtils::GetElementResource(child, getter_AddRefs(resource));
if (NS_FAILED(rv)) break;
PRBool isXULElement;
rv = mDocumentDataSource->HasAssertion(resource, kRDF_instanceOf, kXUL_element, PR_TRUE, &isXULElement);
if (NS_FAILED(rv)) break;
if (! isXULElement)
break;
rv = child->SetDocument(nsnull, PR_TRUE);
if (NS_FAILED(rv)) return rv;
} while (0);
}
// Clear the container-contents-generated attribute so that the next time we
// come back, we'll regenerate the kids we just killed.
rv = aElement->UnsetAttribute(kNameSpaceID_None,
kContainerContentsGeneratedAtom,
PR_FALSE);
if (NS_FAILED(rv)) return rv;
// This is a _total_ hack to make sure that any XUL we blow away
// gets rebuilt.
rv = childcontainer->UnsetAttribute(kNameSpaceID_None,
kXULContentsGeneratedAtom,
PR_FALSE);
if (NS_FAILED(rv)) return rv;
rv = childcontainer->SetAttribute(kNameSpaceID_None,
kLazyContentAtom,
"true",
PR_FALSE);
if (NS_FAILED(rv)) return rv;
return NS_OK;
}
nsresult
XULDocumentImpl::RemoveAndRebuildGeneratedChildren(nsIContent* aElement)
XULDocumentImpl::RebuildWidgetItem(nsIContent* aElement)
{
NS_PRECONDITION(aElement != nsnull, "null ptr");
if (! aElement)
return NS_ERROR_NULL_POINTER;
if (! mBuilders)
return NS_ERROR_NOT_INITIALIZED;
nsresult rv;
PRInt32 count;
rv = aElement->ChildCount(count);
if (NS_FAILED(rv)) return rv;
while (--count >= 0) {
nsCOMPtr<nsIContent> child;
rv = aElement->ChildAt(count, *getter_AddRefs(child));
#ifdef PR_LOGGING
if (PR_LOG_TEST(gXULLog, PR_LOG_DEBUG)) {
nsCOMPtr<nsIAtom> tag;
rv = aElement->GetTag(*getter_AddRefs(tag));
if (NS_FAILED(rv)) return rv;
nsAutoString tmplID;
rv = child->GetAttribute(kNameSpaceID_None, kTemplateAtom, tmplID);
if (NS_FAILED(rv)) return rv;
nsAutoString tagStr;
tag->ToString(tagStr);
if (rv != NS_CONTENT_ATTR_HAS_VALUE)
PR_LOG(gXULLog, PR_LOG_DEBUG,
("xuldoc close-widget-item %s",
(const char*) nsCAutoString(tagStr)));
}
#endif
PRUint32 cnt = 0;
rv = mBuilders->Count(&cnt);
NS_ASSERTION(NS_SUCCEEDED(rv), "Count failed");
for (PRUint32 i = 0; i < cnt; ++i) {
// XXX we should QueryInterface() here
nsIRDFContentModelBuilder* builder
= (nsIRDFContentModelBuilder*) mBuilders->ElementAt(i);
NS_ASSERTION(builder != nsnull, "null ptr");
if (! builder)
continue;
// It's a generated element. Remove it, and set its document
// to null so that it'll get knocked out of the XUL doc's
// resource-to-element map.
rv = aElement->RemoveChildAt(count, PR_TRUE);
NS_ASSERTION(NS_SUCCEEDED(rv), "error removing child");
rv = builder->RebuildContainer(aElement);
NS_ASSERTION(NS_SUCCEEDED(rv), "error rebuilding container");
// XXX ignore error code?
rv = child->SetDocument(nsnull, PR_TRUE);
if (NS_FAILED(rv)) return rv;
NS_RELEASE(builder);
}
// Clear the contents-generated attribute so that the next time we
// come back, we'll regenerate the kids we just killed.
rv = aElement->UnsetAttribute(kNameSpaceID_None,
kTemplateContentsGeneratedAtom,
PR_FALSE);
if (NS_FAILED(rv)) return rv;
rv = aElement->UnsetAttribute(kNameSpaceID_None,
kContainerContentsGeneratedAtom,
PR_FALSE);
if (NS_FAILED(rv)) return rv;
rv = CreateContents(aElement);
if (NS_FAILED(rv)) return rv;
return NS_OK;
}

Просмотреть файл

@ -41,38 +41,36 @@
#include "nsIDOMElement.h"
#include "nsIDOMNode.h"
#include "nsIDOMXULDocument.h"
#include "nsIDOMXULElement.h"
#include "nsIDocument.h"
#include "nsIHTMLContent.h"
#include "nsIHTMLElementFactory.h"
#include "nsINameSpaceManager.h"
#include "nsIRDFContentModelBuilder.h"
#include "nsIRDFCompositeDataSource.h"
#include "nsIRDFContainerUtils.h"
#include "nsIRDFContentModelBuilder.h"
#include "nsIRDFDocument.h"
#include "nsIRDFNode.h"
#include "nsIRDFObserver.h"
#include "nsIRDFRemoteDataSource.h"
#include "nsIRDFService.h"
#include "nsIServiceManager.h"
#include "nsINameSpaceManager.h"
#include "nsIServiceManager.h"
#include "nsISupportsArray.h"
#include "nsITextContent.h"
#include "nsITimer.h"
#include "nsIURL.h"
#include "nsIXULSortService.h"
#include "nsLayoutCID.h"
#include "nsRDFCID.h"
#include "nsRDFContentUtils.h"
#include "nsString.h"
#include "nsVoidArray.h"
#include "nsXPIDLString.h"
#include "prlog.h"
#include "rdf.h"
#include "rdfutil.h"
#include "nsITimer.h"
#include "nsIDOMXULElement.h"
#include "nsVoidArray.h"
#include "nsIXULSortService.h"
#include "nsIHTMLElementFactory.h"
#include "nsIHTMLContent.h"
#include "nsRDFGenericBuilder.h"
#include "prlog.h"
#include "nsIRDFRemoteDataSource.h"
// Return values for EnsureElementHasGenericChild()
#define NS_RDF_ELEMENT_WAS_CREATED NS_RDF_NO_VALUE
#define NS_RDF_ELEMENT_WAS_THERE NS_OK
@ -107,8 +105,252 @@ static NS_DEFINE_CID(kIHTMLElementFactoryIID, NS_IHTML_ELEMENT_FACTORY_IID);
////////////////////////////////////////////////////////////////////////
class RDFGenericBuilderImpl : public nsIRDFContentModelBuilder,
public nsIRDFObserver
{
public:
RDFGenericBuilderImpl();
virtual ~RDFGenericBuilderImpl();
nsresult Init();
// nsISupports interface
NS_DECL_ISUPPORTS
// nsIRDFContentModelBuilder interface
NS_IMETHOD SetDocument(nsIRDFDocument* aDocument);
NS_IMETHOD SetDataBase(nsIRDFCompositeDataSource* aDataBase);
NS_IMETHOD GetDataBase(nsIRDFCompositeDataSource** aDataBase);
NS_IMETHOD CreateRootContent(nsIRDFResource* aResource);
NS_IMETHOD SetRootContent(nsIContent* aElement);
NS_IMETHOD CreateContents(nsIContent* aElement);
NS_IMETHOD OpenContainer(nsIContent* aContainer);
NS_IMETHOD CloseContainer(nsIContent* aContainer);
NS_IMETHOD RebuildContainer(nsIContent* aContainer);
NS_IMETHOD CreateElement(PRInt32 aNameSpaceID,
nsIAtom* aTag,
nsIRDFResource* aResource,
nsIContent** aResult);
// nsIRDFObserver interface
NS_IMETHOD OnAssert(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget);
NS_IMETHOD OnUnassert(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget);
NS_IMETHOD OnChange(nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aOldTarget,
nsIRDFNode* aNewTarget);
NS_IMETHOD OnMove(nsIRDFResource* aOldSource,
nsIRDFResource* aNewSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget);
// Implementation methods
nsresult
FindTemplate(nsIContent* aElement,
nsIRDFResource* aProperty,
nsIRDFResource* aChild,
nsIContent **theTemplate);
nsresult
IsTemplateRuleMatch(nsIContent* aElement,
nsIRDFResource* aProperty,
nsIRDFResource* aChild,
nsIContent *aRule,
PRBool *isMatch);
PRBool
IsIgnoreableAttribute(PRInt32 aNameSpaceID, nsIAtom* aAtom);
nsresult
GetSubstitutionText(nsIRDFResource* aResource,
const nsString& aSubstitution,
nsString& aResult);
nsresult
BuildContentFromTemplate(nsIContent *aTemplateNode,
nsIContent *aRealNode,
PRBool aIsUnique,
nsIRDFResource* aChild,
PRInt32 aNaturalOrderPos,
PRBool aNotify);
nsresult
CreateWidgetItem(nsIContent* aElement,
nsIRDFResource* aProperty,
nsIRDFResource* aChild,
PRInt32 aNaturalOrderPos,
PRBool aNotify);
enum eUpdateAction { eSet, eClear };
#if 0
PRBool
IsAttributePersisent(nsIContent *element, PRInt32 aNameSpaceID, nsIAtom* aAtom);
void
GetPersistentAttributes(nsIContent *realKid);
void
PersistAttribute(nsIContent *element,
PRInt32 aNameSpaceID,
nsIAtom* aAtom,
nsString aValue,
eUpdateAction action);
void
PersistProperty(nsIContent *element,
nsIRDFResource *aProperty,
nsIRDFNode *aTarget,
eUpdateAction action);
#endif
nsresult
SynchronizeUsingTemplate(nsIContent *aTemplateNode,
nsIContent* aRealNode,
eUpdateAction aAction,
nsIRDFResource* aProperty,
nsIRDFNode* aValue);
nsresult
RemoveWidgetItem(nsIContent* aElement,
nsIRDFResource* aProperty,
nsIRDFResource* aValue,
PRBool aNotify);
nsresult
CreateContainerContents(nsIContent* aElement, nsIRDFResource* aResource, PRBool aNotify);
nsresult
CreateTemplateContents(nsIContent* aElement, const nsString& aTemplateID);
nsresult
EnsureElementHasGenericChild(nsIContent* aParent,
PRInt32 aNameSpaceID,
nsIAtom* aTag,
PRBool aNotify,
nsIContent** aResult);
PRBool
IsContainmentProperty(nsIContent* aElement, nsIRDFResource* aProperty);
PRBool
IsIgnoredProperty(nsIContent* aElement, nsIRDFResource* aProperty);
PRBool
IsContainer(nsIContent* aParentElement, nsIRDFResource* aTargetResource);
PRBool
IsEmpty(nsIContent* aParentElement, nsIRDFResource* aContainer);
PRBool
IsOpen(nsIContent* aElement);
PRBool
IsElementInWidget(nsIContent* aElement);
PRBool
IsResourceElement(nsIContent* aElement);
nsresult
GetDOMNodeResource(nsIDOMNode* aNode, nsIRDFResource** aResource);
nsresult
GetResource(PRInt32 aNameSpaceID,
nsIAtom* aNameAtom,
nsIRDFResource** aResource);
nsresult FindInsertionPoint(nsIContent* aElement, nsIContent** aResult);
nsresult RemoveGeneratedContent(nsIContent* aElement);
nsresult FindFirstGeneratedChild(nsIContent* aElement, PRInt32* aIndex);
// XXX. Urg. Hack until layout can batch reflows. See bug 10818.
PRBool
IsTreeWidgetItem(nsIContent* aElement);
PRBool
IsReflowScheduled();
nsresult
ScheduleReflow();
static void
ForceTreeReflow(nsITimer* aTimer, void* aClosure);
protected:
nsIRDFDocument* mDocument; // [WEAK]
// We are an observer of the composite datasource. The cycle is
// broken by out-of-band SetDataBase(nsnull) call when document is
// destroyed.
nsCOMPtr<nsIRDFCompositeDataSource> mDB;
nsCOMPtr<nsIContent> mRoot;
nsCOMPtr<nsITimer> mTimer;
static nsIRDFDataSource *mLocalstore;
static PRBool persistLock;
// pseudo-constants
static nsrefcnt gRefCnt;
static nsIRDFService* gRDFService;
static nsIRDFContainerUtils* gRDFContainerUtils;
static nsINameSpaceManager* gNameSpaceManager;
static nsIHTMLElementFactory* gHTMLElementFactory;
static nsIAtom* kContainerAtom;
static nsIAtom* kLazyContentAtom;
static nsIAtom* kIsContainerAtom;
static nsIAtom* kIsEmptyAtom;
static nsIAtom* kXULContentsGeneratedAtom;
static nsIAtom* kTemplateContentsGeneratedAtom;
static nsIAtom* kContainerContentsGeneratedAtom;
static nsIAtom* kNaturalOrderPosAtom;
static nsIAtom* kIdAtom;
static nsIAtom* kPersistAtom;
static nsIAtom* kOpenAtom;
static nsIAtom* kEmptyAtom;
static nsIAtom* kResourceAtom;
static nsIAtom* kURIAtom;
static nsIAtom* kContainmentAtom;
static nsIAtom* kIgnoreAtom;
static nsIAtom* kRefAtom;
static nsIAtom* kValueAtom;
static nsIAtom* kTemplateAtom;
static nsIAtom* kRuleAtom;
static nsIAtom* kTextAtom;
static nsIAtom* kPropertyAtom;
static nsIAtom* kInstanceOfAtom;
static nsIAtom* kTreeAtom;
static nsIAtom* kTreeChildrenAtom;
static nsIAtom* kTreeItemAtom;
static PRInt32 kNameSpaceID_RDF;
static PRInt32 kNameSpaceID_XUL;
static nsIRDFResource* kNC_Title;
static nsIRDFResource* kNC_child;
static nsIRDFResource* kNC_Column;
static nsIRDFResource* kNC_Folder;
static nsIRDFResource* kRDF_child;
static nsIRDFResource* kRDF_instanceOf;
static nsIRDFResource* kXUL_element;
static nsIXULSortService* gXULSortService;
};
////////////////////////////////////////////////////////////////////////
nsrefcnt RDFGenericBuilderImpl::gRefCnt = 0;
nsIXULSortService* RDFGenericBuilderImpl::XULSortService = nsnull;
nsIXULSortService* RDFGenericBuilderImpl::gXULSortService = nsnull;
nsIAtom* RDFGenericBuilderImpl::kContainerAtom;
nsIAtom* RDFGenericBuilderImpl::kLazyContentAtom;
@ -252,7 +494,7 @@ RDFGenericBuilderImpl::~RDFGenericBuilderImpl(void)
nsServiceManager::ReleaseService(kRDFServiceCID, gRDFService);
nsServiceManager::ReleaseService(kRDFContainerUtilsCID, gRDFContainerUtils);
nsServiceManager::ReleaseService(kXULSortServiceCID, XULSortService);
nsServiceManager::ReleaseService(kXULSortServiceCID, gXULSortService);
NS_RELEASE(gNameSpaceManager);
NS_IF_RELEASE(gHTMLElementFactory);
}
@ -351,7 +593,7 @@ RDFGenericBuilderImpl::Init()
rv = nsServiceManager::GetService(kXULSortServiceCID,
kIXULSortServiceIID,
(nsISupports**) &XULSortService);
(nsISupports**) &gXULSortService);
if (NS_FAILED(rv)) return rv;
rv = nsComponentManager::CreateInstance(kHTMLElementFactoryCID,
@ -475,19 +717,23 @@ RDFGenericBuilderImpl::SetRootContent(nsIContent* aElement)
NS_IMETHODIMP
RDFGenericBuilderImpl::CreateContents(nsIContent* aElement)
{
nsresult rv;
NS_PRECONDITION(aElement != nsnull, "null ptr");
if (! aElement)
return NS_ERROR_NULL_POINTER;
// First, make sure that the element is in the right widget -- ours.
if (!IsElementInWidget(aElement))
return NS_OK;
nsresult rv;
nsCOMPtr<nsIRDFResource> resource;
rv = nsRDFContentUtils::GetElementRefResource(aElement, getter_AddRefs(resource));
if (NS_SUCCEEDED(rv)) {
// The element has a resource; that means that it corresponds
// to something in the graph, so we need to go to the graph to
// create its contents.
rv = CreateContainerContents(aElement, resource);
rv = CreateContainerContents(aElement, resource, PR_FALSE);
if (NS_FAILED(rv)) return rv;
}
@ -505,6 +751,192 @@ RDFGenericBuilderImpl::CreateContents(nsIContent* aElement)
}
NS_IMETHODIMP
RDFGenericBuilderImpl::OpenContainer(nsIContent* aElement)
{
nsresult rv;
// First, make sure that the element is in the right widget -- ours.
if (!IsElementInWidget(aElement))
return NS_OK;
nsCOMPtr<nsIRDFResource> resource;
rv = nsRDFContentUtils::GetElementRefResource(aElement, getter_AddRefs(resource));
// If it has no resource, there's nothing that we need to be
// concerned about here.
if (NS_FAILED(rv))
return NS_OK;
// The element has a resource; that means that it corresponds
// to something in the graph, so we need to go to the graph to
// create its contents.
rv = CreateContainerContents(aElement, resource, PR_TRUE);
if (NS_FAILED(rv)) return rv;
if (rv == NS_RDF_ELEMENT_WAS_CREATED) {
nsCOMPtr<nsIAtom> tag;
rv = aElement->GetTag(*getter_AddRefs(tag));
if (NS_FAILED(rv)) return rv;
if (tag.get() == kTreeItemAtom) {
nsCOMPtr<nsIContent> insertionpoint;
rv = FindInsertionPoint(aElement, getter_AddRefs(insertionpoint));
if (NS_FAILED(rv)) return rv;
if (! insertionpoint) {
// No content got built. Bail!
return NS_OK;
}
// Find the first element beneath the insertion point that
// is generated from a template.
PRInt32 indx;
rv = FindFirstGeneratedChild(insertionpoint, &indx);
if (NS_FAILED(rv)) return rv;
if (indx != -1) {
nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
if (! doc)
return NS_ERROR_UNEXPECTED;
rv = doc->ContentAppended(insertionpoint, indx);
if (NS_FAILED(rv)) return rv;
}
}
}
return NS_OK;
}
NS_IMETHODIMP
RDFGenericBuilderImpl::CloseContainer(nsIContent* aElement)
{
NS_PRECONDITION(aElement != nsnull, "null ptr");
if (! aElement)
return NS_ERROR_NULL_POINTER;
// First, make sure that the element is in the right widget -- ours.
if (!IsElementInWidget(aElement))
return NS_OK;
nsresult rv;
nsCOMPtr<nsIAtom> tag;
rv = aElement->GetTag(*getter_AddRefs(tag));
if (NS_FAILED(rv)) return rv;
// If it's not a tree, just bail. Keep the content around until
// the cows come home.
if (tag.get() != kTreeItemAtom)
return NS_OK;
// Find the tag that contains the children so that we can remove
// all of the children.
//
// XXX We do this as a (premature?) optimization so that nodes
// which are not being displayed don't hang around taking up
// space. Unfortunately, the tree widget currently _relies_ on
// this behavior and will break if we don't do it :-(.
nsCOMPtr<nsIContent> insertionpoint;
rv = FindInsertionPoint(aElement, getter_AddRefs(insertionpoint));
if (NS_FAILED(rv)) return rv;
if (insertionpoint) {
PRInt32 count;
rv = insertionpoint->ChildCount(count);
if (NS_FAILED(rv)) return rv;
rv = RemoveGeneratedContent(insertionpoint);
if (NS_FAILED(rv)) return rv;
}
// Clear the contents-generated attribute so that the next time we
// come back, we'll regenerate the kids we just killed.
rv = aElement->UnsetAttribute(kNameSpaceID_None,
kContainerContentsGeneratedAtom,
PR_FALSE);
if (NS_FAILED(rv)) return rv;
// XXX Hack. Setting this attribute forces the RDF element to
// remember that it needs to be re-generated next time around.
rv = aElement->SetAttribute(kNameSpaceID_None,
kLazyContentAtom,
"true",
PR_FALSE);
if (NS_FAILED(rv)) return rv;
return NS_OK;
}
NS_IMETHODIMP
RDFGenericBuilderImpl::RebuildContainer(nsIContent* aElement)
{
nsresult rv;
// Remove any generated children from this node
rv = RemoveGeneratedContent(aElement);
if (NS_FAILED(rv)) return rv;
// Clear the contents-generated attribute so that the next time we
// come back, we'll regenerate the kids we just killed.
rv = aElement->UnsetAttribute(kNameSpaceID_None,
kContainerContentsGeneratedAtom,
PR_FALSE);
if (NS_FAILED(rv)) return rv;
// XXX Hack. Setting this attribute forces the RDF element to
// remember that it needs to be re-generated next time around.
rv = aElement->SetAttribute(kNameSpaceID_None,
kLazyContentAtom,
"true",
PR_FALSE);
if (NS_FAILED(rv)) return rv;
// Since we're changing the 'ref' attribute, we'll need to
// rebuild content for _this_ resource template, too.
rv = aElement->UnsetAttribute(kNameSpaceID_None,
kTemplateContentsGeneratedAtom,
PR_FALSE);
if (NS_FAILED(rv)) return rv;
// Do it!!!
rv = CreateContents(aElement);
if (NS_FAILED(rv)) return rv;
// Now see where on earth the content was _really_ appended so we
// can tell the frames to go reflow themselves. Start with _this_
// element.
nsCOMPtr<nsIContent> insertionpoint = dont_QueryInterface(aElement);
PRInt32 indx;
rv = FindFirstGeneratedChild(insertionpoint, &indx);
if (NS_FAILED(rv)) return rv;
if (indx == -1) {
// Okay, nothing got inserted directly beneath this node; see
// if the it was inserted somewhere _below_ us...
rv = FindInsertionPoint(aElement, getter_AddRefs(insertionpoint));
if (NS_FAILED(rv)) return rv;
if ((insertionpoint != nsnull) && (insertionpoint.get() != aElement)) {
rv = FindFirstGeneratedChild(insertionpoint, &indx);
if (NS_FAILED(rv)) return rv;
}
}
if (indx != -1) {
nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
rv = doc->ContentAppended(insertionpoint, indx);
if (NS_FAILED(rv)) return rv;
}
return NS_OK;
}
NS_IMETHODIMP
RDFGenericBuilderImpl::CreateElement(PRInt32 aNameSpaceID,
nsIAtom* aTag,
@ -634,27 +1066,19 @@ RDFGenericBuilderImpl::OnAssert(nsIRDFResource* aSource,
// Okay, it's a "live" element, so go ahead and append the new
// child to this node.
// XXX Bug 10818.
PRBool notify = PR_TRUE;
if (IsTreeWidgetItem(element)) {
if (!IsReflowScheduled()) {
rv = ScheduleReflow();
if (NS_FAILED(rv)) return rv;
}
else {
// a reflow has been scheduled. we'll add the
// element but won't notify right now.
notify = PR_FALSE;
}
}
rv = CreateWidgetItem(element, aProperty, resource, 0, notify);
rv = CreateWidgetItem(element, aProperty, resource, 0, PR_TRUE);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create widget item");
if (NS_FAILED(rv)) return rv;
rv = element->SetAttribute(kNameSpaceID_None, kEmptyAtom, "false", PR_TRUE);
// Update the "empty" attribute
nsAutoString empty;
rv = element->GetAttribute(kNameSpaceID_None, kEmptyAtom, empty);
if (NS_FAILED(rv)) return rv;
if ((rv != NS_CONTENT_ATTR_HAS_VALUE) || (! empty.Equals("false"))) {
rv = element->SetAttribute(kNameSpaceID_None, kEmptyAtom, "false", PR_TRUE);
if (NS_FAILED(rv)) return rv;
}
}
else {
// Either the target of the assertion is not a resource,
@ -762,8 +1186,14 @@ RDFGenericBuilderImpl::OnUnassert(nsIRDFResource* aSource,
if (NS_FAILED(rv)) return rv;
if (numKids == 0) {
rv = element->SetAttribute(kNameSpaceID_None, kEmptyAtom, "true", PR_TRUE);
nsAutoString empty;
rv = element->GetAttribute(kNameSpaceID_None, kEmptyAtom, empty);
if (NS_FAILED(rv)) return rv;
if ((rv != NS_CONTENT_ATTR_HAS_VALUE) && (! empty.Equals("true"))) {
rv = element->SetAttribute(kNameSpaceID_None, kEmptyAtom, "true", PR_TRUE);
if (NS_FAILED(rv)) return rv;
}
}
}
@ -1020,7 +1450,7 @@ RDFGenericBuilderImpl::GetPersistentAttributes(nsIContent *element)
literal->GetValueConst(&uniLiteral);
if (uniLiteral)
{
rv = element->SetAttribute(nameSpaceID, tag, uniLiteral, PR_TRUE);
rv = element->SetAttribute(nameSpaceID, tag, uniLiteral, PR_FALSE);
}
}
}
@ -1430,7 +1860,7 @@ RDFGenericBuilderImpl::BuildContentFromTemplate(nsIContent *aTemplateNode,
nsCOMPtr<nsIContent> realKid;
if (aIsUnique) {
rv = EnsureElementHasGenericChild(aRealNode, nameSpaceID, tag, getter_AddRefs(realKid));
rv = EnsureElementHasGenericChild(aRealNode, nameSpaceID, tag, aNotify, getter_AddRefs(realKid));
if (NS_FAILED(rv)) return rv;
if (rv == NS_RDF_ELEMENT_WAS_THERE) {
@ -1489,7 +1919,7 @@ RDFGenericBuilderImpl::BuildContentFromTemplate(nsIContent *aTemplateNode,
rv = content->SetText(text.GetUnicode(), text.Length(), PR_FALSE);
if (NS_FAILED(rv)) return rv;
rv = aRealNode->AppendChildTo(nsCOMPtr<nsIContent>( do_QueryInterface(content) ), PR_FALSE);
rv = aRealNode->AppendChildTo(nsCOMPtr<nsIContent>( do_QueryInterface(content) ), aNotify);
if (NS_FAILED(rv)) return rv;
}
}
@ -1564,15 +1994,14 @@ RDFGenericBuilderImpl::BuildContentFromTemplate(nsIContent *aTemplateNode,
// We'll _already_ have added the unique elements.
if (! aIsUnique) {
// Note: add into tree, but only sort if its a resource element!
if ((nsnull != XULSortService) && (isResourceElement)) {
rv = XULSortService->InsertContainerNode(aRealNode, realKid, aNotify);
if (NS_FAILED(rv)) {
aRealNode->AppendChildTo(realKid, aNotify);
}
// Add into content model, special casing treeitems.
if ((nsnull != gXULSortService) && (isResourceElement) && (tag.get() == kTreeItemAtom)) {
rv = gXULSortService->InsertContainerNode(aRealNode, realKid, aNotify);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to insert element via sort service");
}
else {
aRealNode->AppendChildTo(realKid, aNotify);
rv = aRealNode->AppendChildTo(realKid, aNotify);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to insert element");
}
}
@ -1605,12 +2034,8 @@ RDFGenericBuilderImpl::CreateWidgetItem(nsIContent *aElement,
return NS_OK;
}
rv = BuildContentFromTemplate(tmpl,
aElement,
PR_TRUE,
aChild,
aNaturalOrderPos,
aNotify);
rv = BuildContentFromTemplate(tmpl, aElement, PR_TRUE, aChild, aNaturalOrderPos, aNotify);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to build content from template");
return rv;
}
@ -1777,7 +2202,7 @@ RDFGenericBuilderImpl::RemoveWidgetItem(nsIContent* aElement,
nsresult
RDFGenericBuilderImpl::CreateContainerContents(nsIContent* aElement, nsIRDFResource* aResource)
RDFGenericBuilderImpl::CreateContainerContents(nsIContent* aElement, nsIRDFResource* aResource, PRBool aNotify)
{
// Create the contents of a container by iterating over all of the
// "containment" arcs out of the element's resource.
@ -1801,7 +2226,7 @@ RDFGenericBuilderImpl::CreateContainerContents(nsIContent* aElement, nsIRDFResou
if (NS_FAILED(rv)) return rv;
if ((rv == NS_CONTENT_ATTR_HAS_VALUE) && (attrValue.EqualsIgnoreCase("true")))
return NS_OK;
return NS_RDF_ELEMENT_WAS_CREATED;
// Now mark the element's contents as being generated so that
// any re-entrant calls don't trigger an infinite recursion.
@ -1821,11 +2246,6 @@ RDFGenericBuilderImpl::CreateContainerContents(nsIContent* aElement, nsIRDFResou
rv = mDB->ArcLabelsOut(aResource, getter_AddRefs(properties));
if (NS_FAILED(rv)) return rv;
// rjc - sort
nsCOMPtr<nsISupportsArray> tempArray;
rv = NS_NewISupportsArray(getter_AddRefs(tempArray));
if NS_FAILED(rv) return rv;
while (1) {
PRBool hasMore;
rv = properties->HasMoreElements(&hasMore);
@ -1865,74 +2285,13 @@ RDFGenericBuilderImpl::CreateContainerContents(nsIContent* aElement, nsIRDFResou
rv = targets->GetNext(getter_AddRefs(isupportsNext));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIRDFResource> valueResource = do_QueryInterface(isupportsNext);
NS_ASSERTION(valueResource != nsnull, "not a resource");
if (! valueResource)
nsCOMPtr<nsIRDFResource> target = do_QueryInterface(isupportsNext);
NS_ASSERTION(target != nsnull, "not a resource");
if (! target)
continue;
// XXX hack: always append value resource 1st due to sort
// callback implementation
tempArray->AppendElement(valueResource);
tempArray->AppendElement(property);
}
}
PRUint32 numElements;
rv = tempArray->Count(&numElements);
if (NS_FAILED(rv)) return rv;
if (numElements == 0)
return NS_OK;
// Tree widget hackery. To be removed if and when the
// reflow lock is exposed. See bug 10818.
PRBool istree = IsTreeWidgetItem(aElement);
{
// XXX change to use nsVoidArray?
nsIRDFResource** flatArray = new nsIRDFResource*[numElements];
if (! flatArray) return NS_ERROR_OUT_OF_MEMORY;
// flatten array of resources, sort them, then add as item elements
PRUint32 loop;
for (loop=0; loop<numElements; loop++)
flatArray[loop] = (nsIRDFResource *)tempArray->ElementAt(loop);
if (XULSortService) {
XULSortService->OpenContainer(mDB, aElement, flatArray, numElements/2, 2*sizeof(nsIRDFResource *));
}
// This will insert all of the elements into the
// container, but _won't_ bother layout about it.
for (loop=0; loop<numElements; loop+=2) {
rv = CreateWidgetItem(aElement, flatArray[loop+1], flatArray[loop], loop+1, PR_FALSE);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create widget item");
if (NS_FAILED(rv)) break;
}
for (PRInt32 i = PRInt32(numElements) - 1; i >=0; i--) {
NS_IF_RELEASE(flatArray[i]);
}
delete [] flatArray;
if (NS_FAILED(rv)) return rv;
}
if (istree) {
nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
if (! doc)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIContent> treechildren;
rv = nsRDFContentUtils::FindChildByTag(aElement,
kNameSpaceID_XUL,
kTreeChildrenAtom,
getter_AddRefs(treechildren));
if (NS_SUCCEEDED(rv)) {
// _Now_ tell layout that we've mucked with the container. This'll
// force a reflow and get the content displayed.
rv = doc->ContentAppended(treechildren, 0);
rv = CreateWidgetItem(aElement, property, target, -1, aNotify);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create item");
if (NS_FAILED(rv)) return rv;
}
}
@ -2000,7 +2359,7 @@ RDFGenericBuilderImpl::CreateTemplateContents(nsIContent* aElement, const nsStri
element = parent;
}
rv = BuildContentFromTemplate(tmpl, aElement, PR_FALSE, resource, -1, PR_TRUE);
rv = BuildContentFromTemplate(tmpl, aElement, PR_FALSE, resource, -1, PR_FALSE);
if (NS_FAILED(rv)) return rv;
return NS_OK;
@ -2010,6 +2369,7 @@ nsresult
RDFGenericBuilderImpl::EnsureElementHasGenericChild(nsIContent* parent,
PRInt32 nameSpaceID,
nsIAtom* tag,
PRBool aNotify,
nsIContent** result)
{
nsresult rv;
@ -2026,7 +2386,7 @@ RDFGenericBuilderImpl::EnsureElementHasGenericChild(nsIContent* parent,
if (NS_FAILED(rv)) return rv;
// XXX Note that the notification ensures we won't batch insertions! This could be bad! - Dave
rv = parent->AppendChildTo(element, PR_TRUE);
rv = parent->AppendChildTo(element, aNotify);
if (NS_FAILED(rv)) return rv;
*result = element;
@ -2381,6 +2741,109 @@ RDFGenericBuilderImpl::GetResource(PRInt32 aNameSpaceID,
}
nsresult
RDFGenericBuilderImpl::FindInsertionPoint(nsIContent* aElement, nsIContent** aResult)
{
nsresult rv;
// XXX Hack-o-rama. This needs to be fixed to actually grovel over
// the template n' stuff.
nsCOMPtr<nsIAtom> tag;
rv = aElement->GetTag(*getter_AddRefs(tag));
if (NS_FAILED(rv)) return rv;
nsAutoString tagName;
rv = tag->ToString(tagName);
if (NS_FAILED(rv)) return rv;
if (tagName.Equals("tree") || tagName.Equals("treeitem")) {
rv = nsRDFContentUtils::FindChildByTag(aElement, kNameSpaceID_XUL, NS_NewAtom("treechildren"), aResult);
if (NS_FAILED(rv)) return rv;
}
else if (tagName.Equals("menu")) {
rv = nsRDFContentUtils::FindChildByTag(aElement, kNameSpaceID_XUL, NS_NewAtom("menupopup"), aResult);
if (NS_FAILED(rv)) return rv;
}
else {
*aResult = aElement;
NS_ADDREF(*aResult);
}
return NS_OK;
}
nsresult
RDFGenericBuilderImpl::RemoveGeneratedContent(nsIContent* aElement)
{
// Remove all the content beneath aElement that has been generated
// from a template.
nsresult rv;
PRInt32 count;
rv = aElement->ChildCount(count);
if (NS_FAILED(rv)) return rv;
while (--count >= 0) {
nsCOMPtr<nsIContent> child;
rv = aElement->ChildAt(count, *getter_AddRefs(child));
if (NS_FAILED(rv)) return rv;
nsAutoString tmplID;
rv = child->GetAttribute(kNameSpaceID_None, kTemplateAtom, tmplID);
if (NS_FAILED(rv)) return rv;
if (rv != NS_CONTENT_ATTR_HAS_VALUE)
continue;
// It's a generated element. Remove it, and set its document
// to null so that it'll get knocked out of the XUL doc's
// resource-to-element map.
rv = aElement->RemoveChildAt(count, PR_TRUE);
NS_ASSERTION(NS_SUCCEEDED(rv), "error removing child");
rv = child->SetDocument(nsnull, PR_TRUE);
if (NS_FAILED(rv)) return rv;
}
return NS_OK;
}
nsresult
RDFGenericBuilderImpl::FindFirstGeneratedChild(nsIContent* aElement, PRInt32* aIndex)
{
// Find the first kid of aElement that has been generated from a
// template.
nsresult rv;
PRInt32 count;
rv = aElement->ChildCount(count);
if (NS_FAILED(rv)) return rv;
PRInt32 i = 0;
while (i < count) {
nsCOMPtr<nsIContent> child;
rv = aElement->ChildAt(i, *getter_AddRefs(child));
if (NS_FAILED(rv)) return rv;
nsAutoString tmplID;
rv = child->GetAttribute(kNameSpaceID_None, kTemplateAtom, tmplID);
if (NS_FAILED(rv)) return rv;
if (rv == NS_CONTENT_ATTR_HAS_VALUE)
break;
++i;
}
*aIndex = (i < count) ? i : -1;
return NS_OK;
}
PRBool
RDFGenericBuilderImpl::IsTreeWidgetItem(nsIContent* aElement)
{