2315 lines
74 KiB
C++
2315 lines
74 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; 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 nsIRDFDocument implementation that builds a tree widget XUL
|
|
content model that is to be used with a tree control.
|
|
|
|
TO DO
|
|
|
|
1) Get a real namespace for XUL. This should go in a
|
|
header file somewhere.
|
|
|
|
2) Can we do sorting as an insertion sort? This is especially
|
|
important in the case where content streams in; e.g., gets added
|
|
in the OnAssert() method as opposed to the CreateContents()
|
|
method.
|
|
|
|
*/
|
|
|
|
#include "nsCOMPtr.h"
|
|
#include "nsCRT.h"
|
|
#include "nsIAtom.h"
|
|
#include "nsIContent.h"
|
|
#include "nsIDOMElement.h"
|
|
#include "nsIDOMElementObserver.h"
|
|
#include "nsIDOMNode.h"
|
|
#include "nsIDOMNodeObserver.h"
|
|
#include "nsIDocument.h"
|
|
#include "nsINameSpaceManager.h"
|
|
#include "nsIRDFContentModelBuilder.h"
|
|
#include "nsIRDFCompositeDataSource.h"
|
|
#include "nsIRDFDocument.h"
|
|
#include "nsIRDFNode.h"
|
|
#include "nsIRDFObserver.h"
|
|
#include "nsIRDFService.h"
|
|
#include "nsIServiceManager.h"
|
|
#include "nsINameSpaceManager.h"
|
|
#include "nsIServiceManager.h"
|
|
#include "nsISupportsArray.h"
|
|
#include "nsIURL.h"
|
|
#include "nsLayoutCID.h"
|
|
#include "nsRDFCID.h"
|
|
#include "nsRDFContentUtils.h"
|
|
#include "nsString.h"
|
|
#include "nsXPIDLString.h"
|
|
#include "rdf.h"
|
|
#include "rdfutil.h"
|
|
#include "nsITimer.h"
|
|
#include "nsITimerCallback.h"
|
|
#include "nsIDOMXULElement.h"
|
|
#include "nsVoidArray.h"
|
|
#include "nsIXULSortService.h"
|
|
#include "nsIHTMLElementFactory.h"
|
|
#include "nsIHTMLContent.h"
|
|
#include "nsRDFGenericBuilder.h"
|
|
|
|
#define XUL_TEMPLATES 1
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
static NS_DEFINE_IID(kIContentIID, NS_ICONTENT_IID);
|
|
static NS_DEFINE_IID(kIDocumentIID, NS_IDOCUMENT_IID);
|
|
static NS_DEFINE_IID(kINameSpaceManagerIID, NS_INAMESPACEMANAGER_IID);
|
|
static NS_DEFINE_IID(kIRDFResourceIID, NS_IRDFRESOURCE_IID);
|
|
static NS_DEFINE_IID(kIRDFLiteralIID, NS_IRDFLITERAL_IID);
|
|
static NS_DEFINE_IID(kIRDFContentModelBuilderIID, NS_IRDFCONTENTMODELBUILDER_IID);
|
|
static NS_DEFINE_IID(kIRDFObserverIID, NS_IRDFOBSERVER_IID);
|
|
static NS_DEFINE_IID(kIRDFServiceIID, NS_IRDFSERVICE_IID);
|
|
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
|
|
|
|
static NS_DEFINE_CID(kNameSpaceManagerCID, NS_NAMESPACEMANAGER_CID);
|
|
static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
|
|
static NS_DEFINE_CID(kRDFContainerUtilsCID, NS_RDFCONTAINERUTILS_CID);
|
|
|
|
static NS_DEFINE_IID(kXULSortServiceCID, NS_XULSORTSERVICE_CID);
|
|
static NS_DEFINE_IID(kIXULSortServiceIID, NS_IXULSORTSERVICE_IID);
|
|
|
|
static NS_DEFINE_CID(kHTMLElementFactoryCID, NS_HTML_ELEMENT_FACTORY_CID);
|
|
static NS_DEFINE_CID(kIHTMLElementFactoryIID, NS_IHTML_ELEMENT_FACTORY_IID);
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
nsrefcnt RDFGenericBuilderImpl::gRefCnt = 0;
|
|
nsIXULSortService* RDFGenericBuilderImpl::XULSortService = nsnull;
|
|
|
|
nsIAtom* RDFGenericBuilderImpl::kContainerAtom;
|
|
nsIAtom* RDFGenericBuilderImpl::kIsContainerAtom;
|
|
nsIAtom* RDFGenericBuilderImpl::kXULContentsGeneratedAtom;
|
|
nsIAtom* RDFGenericBuilderImpl::kItemContentsGeneratedAtom;
|
|
nsIAtom* RDFGenericBuilderImpl::kIdAtom;
|
|
nsIAtom* RDFGenericBuilderImpl::kOpenAtom;
|
|
nsIAtom* RDFGenericBuilderImpl::kResourceAtom;
|
|
nsIAtom* RDFGenericBuilderImpl::kURIAtom;
|
|
nsIAtom* RDFGenericBuilderImpl::kContainmentAtom;
|
|
nsIAtom* RDFGenericBuilderImpl::kNaturalOrderPosAtom;
|
|
nsIAtom* RDFGenericBuilderImpl::kIgnoreAtom;
|
|
|
|
nsIAtom* RDFGenericBuilderImpl::kSubcontainmentAtom;
|
|
nsIAtom* RDFGenericBuilderImpl::kRootcontainmentAtom;
|
|
nsIAtom* RDFGenericBuilderImpl::kTreeTemplateAtom;
|
|
nsIAtom* RDFGenericBuilderImpl::kRuleAtom;
|
|
nsIAtom* RDFGenericBuilderImpl::kTreeContentsGeneratedAtom;
|
|
nsIAtom* RDFGenericBuilderImpl::kTextAtom;
|
|
nsIAtom* RDFGenericBuilderImpl::kPropertyAtom;
|
|
nsIAtom* RDFGenericBuilderImpl::kInstanceOfAtom;
|
|
|
|
PRInt32 RDFGenericBuilderImpl::kNameSpaceID_RDF;
|
|
PRInt32 RDFGenericBuilderImpl::kNameSpaceID_XUL;
|
|
|
|
nsIRDFService* RDFGenericBuilderImpl::gRDFService;
|
|
nsIRDFContainerUtils* RDFGenericBuilderImpl::gRDFContainerUtils;
|
|
nsINameSpaceManager* RDFGenericBuilderImpl::gNameSpaceManager;
|
|
|
|
nsIRDFResource* RDFGenericBuilderImpl::kNC_Title;
|
|
nsIRDFResource* RDFGenericBuilderImpl::kNC_child;
|
|
nsIRDFResource* RDFGenericBuilderImpl::kNC_Column;
|
|
nsIRDFResource* RDFGenericBuilderImpl::kNC_Folder;
|
|
nsIRDFResource* RDFGenericBuilderImpl::kRDF_child;
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
RDFGenericBuilderImpl::RDFGenericBuilderImpl(void)
|
|
: mDocument(nsnull),
|
|
mDB(nsnull),
|
|
mRoot(nsnull),
|
|
mTimer(nsnull)
|
|
{
|
|
NS_INIT_REFCNT();
|
|
|
|
if (gRefCnt == 0) {
|
|
kContainerAtom = NS_NewAtom("container");
|
|
kIsContainerAtom = NS_NewAtom("iscontainer");
|
|
kXULContentsGeneratedAtom = NS_NewAtom("xulcontentsgenerated");
|
|
kItemContentsGeneratedAtom = NS_NewAtom("itemcontentsgenerated");
|
|
kTreeContentsGeneratedAtom = NS_NewAtom("treecontentsgenerated");
|
|
|
|
kIdAtom = NS_NewAtom("id");
|
|
kOpenAtom = NS_NewAtom("open");
|
|
kResourceAtom = NS_NewAtom("resource");
|
|
kURIAtom = NS_NewAtom("uri");
|
|
kContainmentAtom = NS_NewAtom("containment");
|
|
kIgnoreAtom = NS_NewAtom("ignore");
|
|
kNaturalOrderPosAtom = NS_NewAtom("pos");
|
|
|
|
kSubcontainmentAtom = NS_NewAtom("subcontainment");
|
|
kRootcontainmentAtom = NS_NewAtom("rootcontainment");
|
|
kTreeTemplateAtom = NS_NewAtom("template");
|
|
kRuleAtom = NS_NewAtom("rule");
|
|
|
|
kTextAtom = NS_NewAtom("text");
|
|
kPropertyAtom = NS_NewAtom("property");
|
|
kInstanceOfAtom = NS_NewAtom("instanceOf");
|
|
|
|
nsresult rv;
|
|
|
|
// Register the XUL and RDF namespaces: these'll just retrieve
|
|
// the IDs if they've already been registered by someone else.
|
|
if (NS_SUCCEEDED(rv = nsComponentManager::CreateInstance(kNameSpaceManagerCID,
|
|
nsnull,
|
|
kINameSpaceManagerIID,
|
|
(void**) &gNameSpaceManager))) {
|
|
|
|
// XXX This is sure to change. Copied from mozilla/layout/xul/content/src/nsXULAtoms.cpp
|
|
static const char kXULNameSpaceURI[]
|
|
= "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
|
|
|
static const char kRDFNameSpaceURI[]
|
|
= RDF_NAMESPACE_URI;
|
|
|
|
rv = gNameSpaceManager->RegisterNameSpace(kXULNameSpaceURI, kNameSpaceID_XUL);
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to register XUL namespace");
|
|
|
|
rv = gNameSpaceManager->RegisterNameSpace(kRDFNameSpaceURI, kNameSpaceID_RDF);
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to register RDF namespace");
|
|
}
|
|
else {
|
|
NS_ERROR("couldn't create namepsace manager");
|
|
}
|
|
|
|
|
|
// Initialize the global shared reference to the service
|
|
// manager and get some shared resource objects.
|
|
rv = nsServiceManager::GetService(kRDFServiceCID,
|
|
kIRDFServiceIID,
|
|
(nsISupports**) &gRDFService);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
gRDFService->GetResource(NC_NAMESPACE_URI "Title", &kNC_Title);
|
|
gRDFService->GetResource(NC_NAMESPACE_URI "child", &kNC_child);
|
|
gRDFService->GetResource(NC_NAMESPACE_URI "Column", &kNC_Column);
|
|
gRDFService->GetResource(NC_NAMESPACE_URI "Folder", &kNC_Folder);
|
|
gRDFService->GetResource(RDF_NAMESPACE_URI "child", &kRDF_child);
|
|
}
|
|
|
|
rv = nsServiceManager::GetService(kRDFContainerUtilsCID,
|
|
nsIRDFContainerUtils::GetIID(),
|
|
(nsISupports**) &gRDFContainerUtils);
|
|
|
|
rv = nsServiceManager::GetService(kXULSortServiceCID,
|
|
kIXULSortServiceIID,
|
|
(nsISupports**) &XULSortService);
|
|
|
|
}
|
|
++gRefCnt;
|
|
}
|
|
|
|
RDFGenericBuilderImpl::~RDFGenericBuilderImpl(void)
|
|
{
|
|
NS_IF_RELEASE(mRoot);
|
|
if (mDB) {
|
|
mDB->RemoveObserver(this);
|
|
NS_RELEASE(mDB);
|
|
}
|
|
// NS_IF_RELEASE(mDocument) not refcounted
|
|
|
|
--gRefCnt;
|
|
if (gRefCnt == 0) {
|
|
NS_RELEASE(kContainerAtom);
|
|
NS_RELEASE(kIsContainerAtom);
|
|
NS_RELEASE(kXULContentsGeneratedAtom);
|
|
NS_RELEASE(kItemContentsGeneratedAtom);
|
|
|
|
NS_RELEASE(kIdAtom);
|
|
NS_RELEASE(kOpenAtom);
|
|
NS_RELEASE(kResourceAtom);
|
|
NS_RELEASE(kURIAtom);
|
|
NS_RELEASE(kContainmentAtom);
|
|
NS_RELEASE(kIgnoreAtom);
|
|
NS_RELEASE(kNaturalOrderPosAtom);
|
|
|
|
NS_RELEASE(kSubcontainmentAtom);
|
|
NS_RELEASE(kRootcontainmentAtom);
|
|
NS_RELEASE(kTreeTemplateAtom);
|
|
NS_RELEASE(kRuleAtom);
|
|
NS_RELEASE(kTreeContentsGeneratedAtom);
|
|
NS_RELEASE(kTextAtom);
|
|
NS_RELEASE(kPropertyAtom);
|
|
NS_RELEASE(kInstanceOfAtom);
|
|
|
|
NS_RELEASE(kNC_Title);
|
|
NS_RELEASE(kNC_Column);
|
|
|
|
nsServiceManager::ReleaseService(kRDFServiceCID, gRDFService);
|
|
nsServiceManager::ReleaseService(kRDFContainerUtilsCID, gRDFContainerUtils);
|
|
nsServiceManager::ReleaseService(kXULSortServiceCID, XULSortService);
|
|
NS_RELEASE(gNameSpaceManager);
|
|
}
|
|
|
|
if (mTimer)
|
|
{
|
|
mTimer->Cancel();
|
|
NS_RELEASE(mTimer);
|
|
mTimer = nsnull;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
NS_IMPL_ADDREF(RDFGenericBuilderImpl);
|
|
NS_IMPL_RELEASE(RDFGenericBuilderImpl);
|
|
|
|
NS_IMETHODIMP
|
|
RDFGenericBuilderImpl::QueryInterface(REFNSIID iid, void** aResult)
|
|
{
|
|
NS_PRECONDITION(aResult != nsnull, "null ptr");
|
|
if (! aResult)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
if (iid.Equals(kIRDFContentModelBuilderIID) ||
|
|
iid.Equals(kISupportsIID)) {
|
|
*aResult = NS_STATIC_CAST(nsIRDFContentModelBuilder*, this);
|
|
}
|
|
else if (iid.Equals(kIRDFObserverIID)) {
|
|
*aResult = NS_STATIC_CAST(nsIRDFObserver*, this);
|
|
}
|
|
else if (iid.Equals(nsIDOMNodeObserver::GetIID())) {
|
|
*aResult = NS_STATIC_CAST(nsIDOMNodeObserver*, this);
|
|
}
|
|
else if (iid.Equals(nsIDOMElementObserver::GetIID())) {
|
|
*aResult = NS_STATIC_CAST(nsIDOMElementObserver*, this);
|
|
}
|
|
else {
|
|
*aResult = nsnull;
|
|
return NS_NOINTERFACE;
|
|
}
|
|
NS_ADDREF(this);
|
|
return NS_OK;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// nsIRDFContentModelBuilder methods
|
|
|
|
NS_IMETHODIMP
|
|
RDFGenericBuilderImpl::SetDocument(nsIRDFDocument* aDocument)
|
|
{
|
|
// note: null now allowed, it indicates document going away
|
|
|
|
mDocument = aDocument; // not refcounted
|
|
if (aDocument)
|
|
{
|
|
if (nsnull == mTimer)
|
|
{
|
|
NS_VERIFY(NS_SUCCEEDED(NS_NewTimer(&mTimer)), "couldn't get timer");
|
|
if (mTimer)
|
|
{
|
|
mTimer->Init(this, /* PR_TRUE, */ 1L);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (mTimer)
|
|
{
|
|
mTimer->Cancel();
|
|
NS_RELEASE(mTimer);
|
|
mTimer = nsnull;
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
RDFGenericBuilderImpl::SetDataBase(nsIRDFCompositeDataSource* aDataBase)
|
|
{
|
|
NS_PRECONDITION(aDataBase != nsnull, "null ptr");
|
|
if (! aDataBase)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
NS_PRECONDITION(mDB == nsnull, "already initialized");
|
|
if (mDB)
|
|
return NS_ERROR_ALREADY_INITIALIZED;
|
|
|
|
mDB = aDataBase;
|
|
NS_ADDREF(mDB);
|
|
|
|
mDB->AddObserver(this);
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
RDFGenericBuilderImpl::GetDataBase(nsIRDFCompositeDataSource** aDataBase)
|
|
{
|
|
NS_PRECONDITION(aDataBase != nsnull, "null ptr");
|
|
if (! aDataBase)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
*aDataBase = mDB;
|
|
NS_ADDREF(mDB);
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
RDFGenericBuilderImpl::CreateRootContent(nsIRDFResource* aResource)
|
|
{
|
|
// Create a structure that looks like this:
|
|
//
|
|
// <html:document>
|
|
// <html:body>
|
|
// <xul:rootwidget>
|
|
// </xul:rootwidget>
|
|
// </html:body>
|
|
// </html:document>
|
|
//
|
|
// Eventually, we should be able to do away with the HTML tags and
|
|
// just have it create XUL in some other context.
|
|
|
|
nsresult rv;
|
|
nsCOMPtr<nsIAtom> tag;
|
|
nsCOMPtr<nsIDocument> doc;
|
|
nsCOMPtr<nsIAtom> rootAtom;
|
|
if (NS_FAILED(rv = GetRootWidgetAtom(getter_AddRefs(rootAtom)))) {
|
|
return rv;
|
|
}
|
|
|
|
if (NS_FAILED(rv = mDocument->QueryInterface(kIDocumentIID,
|
|
(void**) getter_AddRefs(doc))))
|
|
return rv;
|
|
|
|
// Create the DOCUMENT element
|
|
if ((tag = dont_AddRef(NS_NewAtom("document"))) == nsnull)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
nsCOMPtr<nsIContent> root;
|
|
if (NS_FAILED(rv = NS_NewRDFElement(kNameSpaceID_HTML, /* XXX */
|
|
tag,
|
|
getter_AddRefs(root))))
|
|
return rv;
|
|
|
|
doc->SetRootContent(NS_STATIC_CAST(nsIContent*, root));
|
|
|
|
// Create the BODY element
|
|
nsCOMPtr<nsIContent> body;
|
|
if ((tag = dont_AddRef(NS_NewAtom("body"))) == nsnull)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
if (NS_FAILED(rv = NS_NewRDFElement(kNameSpaceID_HTML, /* XXX */
|
|
tag,
|
|
getter_AddRefs(body))))
|
|
return rv;
|
|
|
|
|
|
// Attach the BODY to the DOCUMENT
|
|
if (NS_FAILED(rv = root->AppendChildTo(body, PR_FALSE)))
|
|
return rv;
|
|
|
|
// Create the xul:rootwidget element, and indicate that children should
|
|
// be recursively generated on demand
|
|
nsCOMPtr<nsIContent> widget;
|
|
if (NS_FAILED(rv = CreateElement(kNameSpaceID_XUL,
|
|
rootAtom,
|
|
aResource,
|
|
getter_AddRefs(widget))))
|
|
return rv;
|
|
|
|
if (NS_FAILED(rv = widget->SetAttribute(kNameSpaceID_RDF, kContainerAtom, "true", PR_FALSE)))
|
|
return rv;
|
|
|
|
// Attach the ROOTWIDGET to the BODY
|
|
if (NS_FAILED(rv = body->AppendChildTo(widget, PR_FALSE)))
|
|
return rv;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
RDFGenericBuilderImpl::SetRootContent(nsIContent* aElement)
|
|
{
|
|
NS_IF_RELEASE(mRoot);
|
|
mRoot = aElement;
|
|
NS_IF_ADDREF(mRoot);
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
RDFGenericBuilderImpl::CreateContents(nsIContent* aElement)
|
|
{
|
|
nsresult rv;
|
|
|
|
// First, make sure that the element is in the right widget -- ours.
|
|
if (!IsElementInWidget(aElement))
|
|
return NS_OK;
|
|
|
|
// Next, see if the item is even "open". If not, then just
|
|
// pretend it doesn't have _any_ contents. We check this _before_
|
|
// checking the contents-generated attribute so that we don't
|
|
// eagerly set contents-generated on a closed node.
|
|
if (!IsOpen(aElement))
|
|
return NS_OK;
|
|
|
|
// Now see if someone has marked the element's contents as being
|
|
// generated: this prevents a re-entrant call from triggering
|
|
// another generation.
|
|
nsAutoString attrValue;
|
|
if (NS_FAILED(rv = aElement->GetAttribute(kNameSpaceID_None,
|
|
kItemContentsGeneratedAtom,
|
|
attrValue))) {
|
|
NS_ERROR("unable to test contents-generated attribute");
|
|
return rv;
|
|
}
|
|
|
|
if ((rv == NS_CONTENT_ATTR_HAS_VALUE) && (attrValue.EqualsIgnoreCase("true")))
|
|
return NS_OK;
|
|
|
|
// Now mark the element's contents as being generated so that
|
|
// any re-entrant calls don't trigger an infinite recursion.
|
|
if (NS_FAILED(rv = aElement->SetAttribute(kNameSpaceID_None,
|
|
kItemContentsGeneratedAtom,
|
|
"true",
|
|
PR_FALSE))) {
|
|
NS_ERROR("unable to set contents-generated attribute");
|
|
return rv;
|
|
}
|
|
|
|
// Get the element's resource so that we can generate cell
|
|
// values. We could QI for the nsIRDFResource here, but doing this
|
|
// via the nsIContent interface allows us to support generic nodes
|
|
// that might get added in by DOM calls.
|
|
nsCOMPtr<nsIRDFResource> resource;
|
|
if (NS_FAILED(rv = nsRDFContentUtils::GetElementRefResource(aElement, getter_AddRefs(resource)))) {
|
|
NS_ERROR("unable to get element resource");
|
|
return rv;
|
|
}
|
|
|
|
// XXX Eventually, we may want to factor this into one method that
|
|
// handles RDF containers (RDF:Bag, et al.) and another that
|
|
// handles multi-attributes. For performance...
|
|
|
|
// Create a cursor that'll enumerate all of the outbound arcs
|
|
nsCOMPtr<nsISimpleEnumerator> properties;
|
|
rv = mDB->ArcLabelsOut(resource, getter_AddRefs(properties));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
// rjc - sort
|
|
nsISupportsArray *tempArray;
|
|
if (NS_FAILED(rv = NS_NewISupportsArray(&tempArray)))
|
|
return(rv);
|
|
|
|
while (1) {
|
|
PRBool hasMore;
|
|
rv = properties->HasMoreElements(&hasMore);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
if (! hasMore)
|
|
break;
|
|
|
|
nsCOMPtr<nsISupports> isupports;
|
|
rv = properties->GetNext(getter_AddRefs(isupports));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsCOMPtr<nsIRDFResource> property = do_QueryInterface(isupports);
|
|
|
|
// If it's not a widget item property, then it doesn't specify an
|
|
// object that is member of the current container element;
|
|
// rather, it specifies a "simple" property of the container
|
|
// element. Skip it.
|
|
if (!IsContainmentProperty(aElement, property))
|
|
continue;
|
|
|
|
// Create a second cursor that'll enumerate all of the values
|
|
// for all of the arcs.
|
|
nsCOMPtr<nsISimpleEnumerator> targets;
|
|
rv = mDB->GetTargets(resource, property, PR_TRUE, getter_AddRefs(targets));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
while (1) {
|
|
PRBool hasMoreElements;
|
|
rv = targets->HasMoreElements(&hasMoreElements);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
if (! hasMoreElements)
|
|
break;
|
|
|
|
nsCOMPtr<nsISupports> isupportsNext;
|
|
rv = targets->GetNext(getter_AddRefs(isupportsNext));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsCOMPtr<nsIRDFResource> valueResource = do_QueryInterface(isupportsNext);
|
|
if (valueResource && IsContainmentProperty(aElement, property)) {
|
|
/* XXX hack: always append value resource 1st!
|
|
due to sort callback implementation */
|
|
tempArray->AppendElement(valueResource);
|
|
tempArray->AppendElement(property);
|
|
}
|
|
else {
|
|
nsCOMPtr<nsIRDFNode> value = do_QueryInterface(isupportsNext);
|
|
rv = SetWidgetAttribute(aElement, property, value);
|
|
if (NS_FAILED(rv)) return rv;
|
|
}
|
|
}
|
|
}
|
|
|
|
PRUint32 cnt = 0;
|
|
rv = tempArray->Count(&cnt);
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "Count failed");
|
|
unsigned long numElements = cnt;
|
|
if (numElements > 0)
|
|
{
|
|
nsIRDFResource ** flatArray = new nsIRDFResource *[numElements];
|
|
if (flatArray)
|
|
{
|
|
// flatten array of resources, sort them, then add as item elements
|
|
unsigned long loop;
|
|
|
|
for (loop=0; loop<numElements; loop++)
|
|
flatArray[loop] = (nsIRDFResource *)tempArray->ElementAt(loop);
|
|
|
|
if (nsnull != XULSortService)
|
|
{
|
|
XULSortService->OpenContainer(mDB, aElement, flatArray, numElements/2, 2*sizeof(nsIRDFResource *));
|
|
}
|
|
|
|
for (loop=0; loop<numElements; loop+=2)
|
|
{
|
|
#ifdef XUL_TEMPLATES
|
|
rv = CreateWidgetItem(aElement, flatArray[loop+1], flatArray[loop], loop+1);
|
|
#else
|
|
rv = AddWidgetItem(aElement, flatArray[loop+1], flatArray[loop], loop+1);
|
|
#endif
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create widget item");
|
|
}
|
|
|
|
for (int i = numElements - 1; i >=0; i--)
|
|
{
|
|
NS_IF_RELEASE(flatArray[i]);
|
|
}
|
|
delete [] flatArray;
|
|
}
|
|
}
|
|
for (int i = numElements - 1; i >= 0; i--)
|
|
{
|
|
tempArray->RemoveElementAt(i);
|
|
}
|
|
NS_IF_RELEASE(tempArray);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
RDFGenericBuilderImpl::CreateElement(PRInt32 aNameSpaceID,
|
|
nsIAtom* aTag,
|
|
nsIRDFResource* aResource,
|
|
nsIContent** aResult)
|
|
{
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIContent> result;
|
|
rv = NS_NewRDFElement(aNameSpaceID, aTag, getter_AddRefs(result));
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create new RDFElement");
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsXPIDLCString uri;
|
|
rv = aResource->GetValue( getter_Copies(uri) );
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get resource URI");
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
rv = result->SetAttribute(kNameSpaceID_None, kIdAtom, (const char*) uri, PR_FALSE);
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to set id attribute");
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsCOMPtr<nsIDocument> doc( do_QueryInterface(mDocument) );
|
|
rv = result->SetDocument(doc, PR_FALSE);
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to set element's document");
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
*aResult = result;
|
|
NS_ADDREF(*aResult);
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
RDFGenericBuilderImpl::SetAllAttributesOnElement(nsIContent *aNode, nsIRDFResource *res)
|
|
{
|
|
// get all arcs out, and if not a containment property, set attribute
|
|
nsresult rv = NS_OK;
|
|
PRBool markAsContainer = PR_FALSE;
|
|
nsCOMPtr<nsISimpleEnumerator> arcs;
|
|
if (NS_SUCCEEDED(rv = mDB->ArcLabelsOut(res, getter_AddRefs(arcs))))
|
|
{
|
|
PRBool hasMore = PR_TRUE;
|
|
while(hasMore)
|
|
{
|
|
rv = arcs->HasMoreElements(&hasMore);
|
|
if (NS_FAILED(rv)) break;
|
|
if (hasMore == PR_FALSE) break;
|
|
|
|
nsCOMPtr<nsISupports> isupports;
|
|
if (NS_FAILED(rv = arcs->GetNext(getter_AddRefs(isupports)))) break;
|
|
|
|
nsCOMPtr<nsIRDFResource> property = do_QueryInterface(isupports);
|
|
// Ignore properties that are used to indicate "tree-ness"
|
|
if (IsContainmentProperty(aNode, property))
|
|
{
|
|
markAsContainer = PR_TRUE;
|
|
continue;
|
|
}
|
|
|
|
// Ignore any properties set in ignore attribute
|
|
if (IsIgnoredProperty(aNode, property))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
PRInt32 nameSpaceID;
|
|
nsCOMPtr<nsIAtom> tag;
|
|
if (NS_FAILED(rv = mDocument->SplitProperty(property, &nameSpaceID, getter_AddRefs(tag))))
|
|
break;
|
|
nsCOMPtr<nsIRDFNode> value;
|
|
if (NS_FAILED(rv = mDB->GetTarget(res, property, PR_TRUE, getter_AddRefs(value))))
|
|
break;
|
|
if (rv == NS_RDF_NO_VALUE)
|
|
continue;
|
|
nsAutoString s;
|
|
if (NS_SUCCEEDED(rv = nsRDFContentUtils::GetTextForNode(value, s)))
|
|
{
|
|
aNode->SetAttribute(nameSpaceID, tag, s, PR_FALSE);
|
|
}
|
|
}
|
|
}
|
|
if (markAsContainer == PR_TRUE)
|
|
{
|
|
// mark this as a "container" so that we know to
|
|
// recursively generate kids if they're asked for.
|
|
rv = aNode->SetAttribute(kNameSpaceID_RDF, kContainerAtom, "true", PR_FALSE);
|
|
}
|
|
return(rv);
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
RDFGenericBuilderImpl::IsTemplateRuleMatch(nsIRDFResource *aNode, nsIContent *aRule, PRBool *matchingRuleFound)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
PRInt32 count;
|
|
|
|
*matchingRuleFound = PR_FALSE;
|
|
|
|
if (NS_FAILED(rv = aRule->GetAttributeCount(count)))
|
|
{
|
|
return(rv);
|
|
}
|
|
|
|
*matchingRuleFound = PR_TRUE;
|
|
for (PRInt32 loop=0; loop<count; loop++)
|
|
{
|
|
PRInt32 attribNameSpaceID;
|
|
nsCOMPtr<nsIAtom> attribAtom;
|
|
if (NS_FAILED(rv = aRule->GetAttributeNameAt(loop, attribNameSpaceID, *getter_AddRefs(attribAtom))))
|
|
{
|
|
*matchingRuleFound = PR_FALSE;
|
|
break;
|
|
}
|
|
nsAutoString attribValue;
|
|
if (NS_FAILED(rv = aRule->GetAttribute(attribNameSpaceID, attribAtom, attribValue)))
|
|
{
|
|
*matchingRuleFound = PR_FALSE;
|
|
break;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
nsAutoString nsName;
|
|
attribAtom->ToString(nsName);
|
|
char *debugName = nsName.ToNewCString();
|
|
if (debugName)
|
|
{
|
|
delete [] debugName;
|
|
debugName = nsnull;
|
|
}
|
|
#endif
|
|
|
|
// Note: some attributes must be skipped on XUL template rule subtree
|
|
|
|
// never compare against rdf:container attribute
|
|
if ((attribAtom.get() == kContainerAtom) && (attribNameSpaceID == kNameSpaceID_RDF))
|
|
continue;
|
|
// never compare against rdf:property attribute
|
|
else if ((attribAtom.get() == kPropertyAtom) && (attribNameSpaceID == kNameSpaceID_RDF))
|
|
continue;
|
|
// never compare against rdf:instanceOf attribute
|
|
else if ((attribAtom.get() == kInstanceOfAtom) && (attribNameSpaceID == kNameSpaceID_RDF))
|
|
continue;
|
|
// never compare against {}:id attribute
|
|
else if ((attribAtom.get() == kIdAtom) && (attribNameSpaceID == kNameSpaceID_None))
|
|
continue;
|
|
// never compare against {}:rootcontainment attribute
|
|
else if ((attribAtom.get() == kRootcontainmentAtom) && (attribNameSpaceID == kNameSpaceID_None))
|
|
continue;
|
|
// never compare against {}:subcontainment attribute
|
|
else if ((attribAtom.get() == kSubcontainmentAtom) && (attribNameSpaceID == kNameSpaceID_None))
|
|
continue;
|
|
// never compare against {}:xulcontentsgenerated attribute
|
|
else if ((attribAtom.get() == kXULContentsGeneratedAtom) && (attribNameSpaceID == kNameSpaceID_None))
|
|
continue;
|
|
// never compare against {}:itemcontentsgenerated attribute (bogus)
|
|
else if ((attribAtom.get() == kItemContentsGeneratedAtom) && (attribNameSpaceID == kNameSpaceID_None))
|
|
continue;
|
|
// never compare against {}:treecontentsgenerated attribute (bogus)
|
|
else if ((attribAtom.get() == kTreeContentsGeneratedAtom) && (attribNameSpaceID == kNameSpaceID_None))
|
|
continue;
|
|
|
|
else if ((attribNameSpaceID == kNameSpaceID_None) && (attribAtom.get() == kIsContainerAtom))
|
|
{
|
|
// check and see if aNode is a container
|
|
PRBool containerFlag = IsContainer(aRule, aNode);
|
|
if (containerFlag && (!attribValue.EqualsIgnoreCase("true")))
|
|
{
|
|
*matchingRuleFound = PR_FALSE;
|
|
break;
|
|
}
|
|
else if (!containerFlag && (!attribValue.EqualsIgnoreCase("false")))
|
|
{
|
|
*matchingRuleFound = PR_FALSE;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nsCOMPtr<nsIRDFResource> attribAtomResource;
|
|
if (NS_FAILED(rv = GetResource(attribNameSpaceID, attribAtom, getter_AddRefs(attribAtomResource))))
|
|
{
|
|
*matchingRuleFound = PR_FALSE;
|
|
break;
|
|
}
|
|
nsCOMPtr<nsIRDFNode> aResult;
|
|
if (NS_FAILED(rv = mDB->GetTarget(aNode, attribAtomResource, PR_TRUE, getter_AddRefs(aResult))))
|
|
{
|
|
*matchingRuleFound = PR_FALSE;
|
|
break;
|
|
}
|
|
nsAutoString resultStr;
|
|
if (NS_FAILED(rv = nsRDFContentUtils::GetTextForNode(aResult, resultStr)))
|
|
{
|
|
*matchingRuleFound = PR_FALSE;
|
|
break;
|
|
}
|
|
if (!attribValue.Equals(resultStr))
|
|
{
|
|
*matchingRuleFound = PR_FALSE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return(rv);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
RDFGenericBuilderImpl::FindTemplateForResource(nsIRDFResource *aNode, nsIContent **theTemplate)
|
|
{
|
|
nsresult rv;
|
|
PRInt32 count;
|
|
nsCOMPtr<nsIContent> aTemplate;
|
|
|
|
*theTemplate = nsnull;
|
|
if (NS_FAILED(rv = mRoot->ChildCount(count))) return(rv);
|
|
|
|
for (PRInt32 loop=0; loop<count; loop++)
|
|
{
|
|
if (NS_FAILED(rv = mRoot->ChildAt(loop, *getter_AddRefs(aTemplate))))
|
|
continue;
|
|
PRInt32 nameSpaceID;
|
|
if (NS_FAILED(rv = aTemplate->GetNameSpaceID(nameSpaceID)))
|
|
continue;
|
|
if (nameSpaceID != kNameSpaceID_XUL)
|
|
continue;
|
|
|
|
nsCOMPtr<nsIAtom> tag;
|
|
if (NS_FAILED(rv = aTemplate->GetTag(*getter_AddRefs(tag))))
|
|
continue;
|
|
if (tag.get() != kTreeTemplateAtom)
|
|
continue;
|
|
|
|
/*
|
|
// check for debugging
|
|
nsAutoString debugValue;
|
|
if (NS_SUCCEEDED(rv = aTemplate->GetAttribute(kNameSpaceID_None, kDebugAtom, debugValue)))
|
|
{
|
|
debugValue = "true";
|
|
}
|
|
*/
|
|
|
|
// found a template; check against any (optional) rules
|
|
PRInt32 numRuleChildren, numRulesFound = 0;
|
|
if (NS_FAILED(rv = aTemplate->ChildCount(numRuleChildren)))
|
|
continue;
|
|
for (PRInt32 ruleLoop=0; ruleLoop<numRuleChildren; ruleLoop++)
|
|
{
|
|
nsCOMPtr<nsIContent> aRule;
|
|
if (NS_FAILED(rv = aTemplate->ChildAt(ruleLoop, *getter_AddRefs(aRule))))
|
|
continue;
|
|
PRInt32 ruleNameSpaceID;
|
|
if (NS_FAILED(rv = aRule->GetNameSpaceID(ruleNameSpaceID)))
|
|
continue;
|
|
if (ruleNameSpaceID != kNameSpaceID_XUL)
|
|
continue;
|
|
nsCOMPtr<nsIAtom> ruleTag;
|
|
if (NS_SUCCEEDED(rv = aRule->GetTag(*getter_AddRefs(ruleTag))))
|
|
{
|
|
if (ruleTag.get() == kRuleAtom)
|
|
{
|
|
++numRulesFound;
|
|
PRBool matchingRuleFound = PR_FALSE;
|
|
if (NS_SUCCEEDED(rv = IsTemplateRuleMatch(aNode, aRule,
|
|
&matchingRuleFound)))
|
|
{
|
|
if (matchingRuleFound == PR_TRUE)
|
|
{
|
|
// found a matching rule, use it as the template
|
|
*theTemplate = aRule;
|
|
NS_ADDREF(*theTemplate);
|
|
return(NS_OK);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (numRulesFound == 0)
|
|
{
|
|
// if no rules are specified in the template, just use it
|
|
*theTemplate = aTemplate;
|
|
NS_ADDREF(*theTemplate);
|
|
break;
|
|
}
|
|
}
|
|
return(rv);
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
RDFGenericBuilderImpl::PopulateWidgetItemSubtree(nsIContent *aTemplateRoot, nsIContent *aTemplate,
|
|
nsIContent *treeChildren, nsIContent* aElement, nsIRDFResource* aProperty,
|
|
nsIRDFResource* aValue, PRInt32 aNaturalOrderPos)
|
|
{
|
|
PRInt32 count;
|
|
nsresult rv;
|
|
|
|
if (NS_FAILED(rv = aTemplate->ChildCount(count))) return(rv);
|
|
for (PRInt32 loop=0; loop<count; loop++)
|
|
{
|
|
nsCOMPtr<nsIContent> aTemplateKid;
|
|
if (NS_FAILED(rv = aTemplate->ChildAt(loop, *getter_AddRefs(aTemplateKid))))
|
|
continue;
|
|
PRInt32 nameSpaceID;
|
|
if (NS_FAILED(rv = aTemplateKid->GetNameSpaceID(nameSpaceID)))
|
|
continue;
|
|
|
|
// check whether this item is a containment item for aValue
|
|
PRBool isContainmentElement = PR_FALSE;
|
|
if (nameSpaceID == kNameSpaceID_XUL)
|
|
{
|
|
nsAutoString idValue;
|
|
if (NS_SUCCEEDED(rv = aTemplateKid->GetAttribute(kNameSpaceID_None,
|
|
kURIAtom, idValue)) && (rv == NS_CONTENT_ATTR_HAS_VALUE))
|
|
{
|
|
if (idValue.EqualsIgnoreCase("..."))
|
|
{
|
|
isContainmentElement = PR_TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
nsCOMPtr<nsIAtom> tag;
|
|
if (NS_SUCCEEDED(rv = aTemplateKid->GetTag(*getter_AddRefs(tag))))
|
|
{
|
|
nsCOMPtr<nsIContent> treeGrandchild;
|
|
if (isContainmentElement == PR_TRUE)
|
|
{
|
|
if (NS_FAILED(rv = CreateElement(nameSpaceID,
|
|
tag, aValue, getter_AddRefs(treeGrandchild))))
|
|
continue;
|
|
if (NS_FAILED(rv = SetAllAttributesOnElement(treeGrandchild, aValue)))
|
|
continue;
|
|
}
|
|
else if ((tag.get() == kTextAtom) && (nameSpaceID == kNameSpaceID_XUL))
|
|
{
|
|
// <xul:text rdf:resource="..."> is replaced by text of the
|
|
// actual value of the rdf:resource attribute for the given node
|
|
nsAutoString attrValue;
|
|
if (NS_FAILED(rv = aTemplateKid->GetAttribute(kNameSpaceID_RDF,
|
|
kResourceAtom, attrValue)))
|
|
continue;
|
|
if (rv != NS_CONTENT_ATTR_HAS_VALUE)
|
|
continue;
|
|
if (attrValue.Length() < 1)
|
|
continue;
|
|
char *prop = attrValue.ToNewCString();
|
|
if (nsnull == prop)
|
|
continue;
|
|
|
|
nsCOMPtr<nsIRDFResource> propRes;
|
|
if (NS_FAILED(rv = gRDFService->GetResource(prop, getter_AddRefs(propRes))))
|
|
continue;
|
|
|
|
nsCOMPtr<nsIRDFNode> aResult;
|
|
if (NS_FAILED(rv = mDB->GetTarget(aValue,
|
|
propRes, PR_TRUE, getter_AddRefs(aResult))))
|
|
continue;
|
|
rv = nsRDFContentUtils::AttachTextNode(treeChildren, aResult);
|
|
delete [] prop;
|
|
prop = nsnull;
|
|
}
|
|
else
|
|
{
|
|
if (nameSpaceID == kNameSpaceID_HTML)
|
|
{
|
|
nsIHTMLElementFactory *mHTMLElementFactory;
|
|
|
|
rv = nsComponentManager::CreateInstance(kHTMLElementFactoryCID,
|
|
nsnull, kIHTMLElementFactoryIID, (void**) &mHTMLElementFactory);
|
|
if (NS_FAILED(rv))
|
|
continue;
|
|
|
|
nsCOMPtr<nsIHTMLContent> element;
|
|
nsAutoString tagName(tag->GetUnicode());
|
|
rv = mHTMLElementFactory->CreateInstanceByTag(tagName, getter_AddRefs(element));
|
|
if (NS_FAILED(rv))
|
|
continue;
|
|
|
|
nsCOMPtr<nsIDocument> doc;
|
|
if (NS_FAILED(rv = mDocument->QueryInterface(kIDocumentIID, getter_AddRefs(doc))))
|
|
continue;
|
|
|
|
// XXX To do
|
|
// Make sure our ID is set. Unlike XUL elements, we want to make sure
|
|
// that our ID is relative if possible.
|
|
|
|
if (NS_FAILED(rv = element->SetDocument(doc, PR_FALSE)))
|
|
continue;
|
|
|
|
treeGrandchild = do_QueryInterface(element);
|
|
|
|
NS_RELEASE(mHTMLElementFactory);
|
|
}
|
|
else
|
|
{
|
|
if (NS_FAILED(rv = NS_NewRDFElement(nameSpaceID, tag,
|
|
getter_AddRefs(treeGrandchild))))
|
|
continue;
|
|
|
|
nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
|
|
if (! doc)
|
|
continue;
|
|
|
|
treeGrandchild->SetDocument(doc, PR_FALSE);
|
|
}
|
|
}
|
|
|
|
if (treeGrandchild && treeGrandchild.get())
|
|
{
|
|
// copy all attributes from template to new node
|
|
PRInt32 numAttribs;
|
|
if (NS_SUCCEEDED(rv = aTemplateKid->GetAttributeCount(numAttribs)) &&
|
|
(rv == NS_CONTENT_ATTR_HAS_VALUE))
|
|
{
|
|
for (PRInt32 aLoop=0; aLoop<numAttribs; aLoop++)
|
|
{
|
|
PRInt32 attribNameSpaceID;
|
|
nsCOMPtr<nsIAtom> attribName;
|
|
if (NS_SUCCEEDED(rv = aTemplateKid->GetAttributeNameAt(aLoop,
|
|
attribNameSpaceID, *getter_AddRefs(attribName))))
|
|
{
|
|
// only copy attributes that aren't already set on the node
|
|
nsAutoString val;
|
|
if (NS_SUCCEEDED(rv = treeGrandchild->GetAttribute(attribNameSpaceID,
|
|
attribName, val)))
|
|
{
|
|
if (rv == NS_CONTENT_ATTR_HAS_VALUE) continue;
|
|
}
|
|
// never copy rdf:container attribute
|
|
if ((attribName.get() == kContainerAtom) &&
|
|
(attribNameSpaceID == kNameSpaceID_RDF))
|
|
continue;
|
|
// never copy rdf:property attribute
|
|
else if ((attribName.get() == kPropertyAtom) &&
|
|
(attribNameSpaceID == kNameSpaceID_RDF))
|
|
continue;
|
|
// never copy rdf:instanceOf attribute
|
|
else if ((attribName.get() == kInstanceOfAtom) &&
|
|
(attribNameSpaceID == kNameSpaceID_RDF))
|
|
continue;
|
|
// never copy {}:rootcontainment attribute
|
|
else if ((attribName.get() == kRootcontainmentAtom) &&
|
|
(attribNameSpaceID == kNameSpaceID_None))
|
|
continue;
|
|
// never copy {}:subcontainment attribute
|
|
else if ((attribName.get() == kSubcontainmentAtom) &&
|
|
(attribNameSpaceID == kNameSpaceID_None))
|
|
continue;
|
|
// never copy {}:ID attribute
|
|
else if ((attribName.get() == kIdAtom) &&
|
|
(attribNameSpaceID == kNameSpaceID_None))
|
|
continue;
|
|
// never copy {}:uri attribute
|
|
else if ((attribName.get() == kURIAtom) &&
|
|
(attribNameSpaceID == kNameSpaceID_None))
|
|
continue;
|
|
// never copy {}:itemcontentsgenerated attribute (bogus)
|
|
else if ((attribName.get() == kItemContentsGeneratedAtom) &&
|
|
(attribNameSpaceID == kNameSpaceID_None))
|
|
continue;
|
|
// never copy {}:treecontentsgenerated attribute (bogus)
|
|
else if ((attribName.get() == kTreeContentsGeneratedAtom) &&
|
|
(attribNameSpaceID == kNameSpaceID_None))
|
|
continue;
|
|
|
|
nsAutoString attribValue;
|
|
if (NS_SUCCEEDED(rv = aTemplateKid->GetAttribute(attribNameSpaceID,
|
|
attribName,attribValue)) && (rv == NS_CONTENT_ATTR_HAS_VALUE))
|
|
{
|
|
if (attribValue.Find("rdf:") == 0)
|
|
{
|
|
// found an attribute which wants to bind its value
|
|
// to RDF so look it up in the graph
|
|
attribValue.Cut(0,4);
|
|
char *prop = attribValue.ToNewCString();
|
|
if (nsnull == prop) continue;
|
|
attribValue = "";
|
|
|
|
nsCOMPtr<nsIRDFResource> propRes;
|
|
rv = gRDFService->GetResource(prop, getter_AddRefs(propRes));
|
|
delete [] prop;
|
|
if (NS_FAILED(rv)) continue;
|
|
|
|
nsCOMPtr<nsIRDFNode> valueNode;
|
|
if (NS_FAILED(rv = mDB->GetTarget(aValue, propRes, PR_TRUE,
|
|
getter_AddRefs(valueNode))) || (rv == NS_RDF_NO_VALUE))
|
|
continue;
|
|
nsCOMPtr<nsIRDFLiteral> literalValue = do_QueryInterface(valueNode);
|
|
if (!literalValue)
|
|
continue;
|
|
PRUnichar *uniVal;
|
|
if (NS_FAILED(rv = literalValue->GetValue(&uniVal)))
|
|
continue;
|
|
attribValue = uniVal;
|
|
}
|
|
else if (attribValue.EqualsIgnoreCase("..."))
|
|
{
|
|
char *uri = nsnull;
|
|
aValue->GetValue(&uri);
|
|
attribValue=uri;
|
|
}
|
|
treeGrandchild->SetAttribute(attribNameSpaceID,
|
|
attribName, attribValue, PR_FALSE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// set natural order hint
|
|
if (aNaturalOrderPos > 0)
|
|
{
|
|
nsAutoString pos, zero("0000");
|
|
pos.Append(aNaturalOrderPos, 10);
|
|
if (pos.Length() < 4)
|
|
{
|
|
pos.Insert(zero, 0, 4-pos.Length());
|
|
}
|
|
treeGrandchild->SetAttribute(kNameSpaceID_None, kNaturalOrderPosAtom, pos, PR_FALSE);
|
|
}
|
|
|
|
// recurse into template subtree
|
|
PRInt32 numTemplateKids;
|
|
if (NS_SUCCEEDED(rv = aTemplateKid->ChildCount(numTemplateKids)))
|
|
{
|
|
if (numTemplateKids > 0)
|
|
{
|
|
rv = PopulateWidgetItemSubtree(aTemplateRoot, aTemplateKid, treeGrandchild,
|
|
aElement, aProperty, aValue, aNaturalOrderPos);
|
|
}
|
|
}
|
|
|
|
// Note: add into tree, but only sort if its a containment element!
|
|
if ((nsnull != XULSortService) && (isContainmentElement == PR_TRUE))
|
|
{
|
|
if (NS_FAILED(rv = XULSortService->InsertContainerNode(treeChildren, treeGrandchild)))
|
|
{
|
|
treeChildren->AppendChildTo(treeGrandchild, PR_TRUE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
treeChildren->AppendChildTo(treeGrandchild, PR_TRUE);
|
|
}
|
|
|
|
// If item says its "open", then recurve now and build up its children
|
|
nsAutoString openState;
|
|
if (NS_SUCCEEDED(rv = treeGrandchild->GetAttribute(kNameSpaceID_None, kOpenAtom, openState))
|
|
&& (rv == NS_CONTENT_ATTR_HAS_VALUE) && (openState.EqualsIgnoreCase("true")))
|
|
{
|
|
OpenWidgetItem(treeGrandchild);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return(rv);
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
RDFGenericBuilderImpl::CreateWidgetItem(nsIContent *aElement, nsIRDFResource *aProperty,
|
|
nsIRDFResource *aValue, PRInt32 aNaturalOrderPos)
|
|
{
|
|
nsCOMPtr<nsIContent> aTemplate;
|
|
nsresult rv;
|
|
|
|
if (NS_SUCCEEDED(rv = FindTemplateForResource(aValue, getter_AddRefs(aTemplate))) &&
|
|
(aTemplate))
|
|
{
|
|
nsCOMPtr<nsIContent> children = do_QueryInterface(aElement);
|
|
PRBool isRoot = PR_FALSE;
|
|
|
|
// if template specifies a rootcontainment attribute, get it
|
|
// and determine if we are building children off of the root
|
|
nsAutoString rootAttrValue;
|
|
if (NS_SUCCEEDED(rv = aTemplate->GetAttribute(kNameSpaceID_None,
|
|
kRootcontainmentAtom, rootAttrValue)) && (rv == NS_CONTENT_ATTR_HAS_VALUE))
|
|
{
|
|
nsCOMPtr<nsIAtom> rootAtom = NS_NewAtom(rootAttrValue);
|
|
if (rootAtom)
|
|
{
|
|
PRInt32 nameSpaceID;
|
|
if (NS_SUCCEEDED(rv = aElement->GetNameSpaceID(nameSpaceID)))
|
|
{
|
|
if (nameSpaceID == kNameSpaceID_XUL)
|
|
{
|
|
nsCOMPtr<nsIAtom> tag;
|
|
if (NS_SUCCEEDED(rv = aElement->GetTag(*getter_AddRefs(tag))))
|
|
{
|
|
if (tag == rootAtom)
|
|
{
|
|
isRoot = PR_TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// if template specifies a subcontainment attribute, get it
|
|
// and make sure aElement contains it (if not the root),
|
|
// otherwise use aElement
|
|
if (isRoot == PR_FALSE)
|
|
{
|
|
nsAutoString attrValue;
|
|
if (NS_SUCCEEDED(rv = aTemplate->GetAttribute(kNameSpaceID_None,
|
|
kSubcontainmentAtom, attrValue)) && (rv == NS_CONTENT_ATTR_HAS_VALUE))
|
|
{
|
|
nsCOMPtr<nsIAtom> childrenAtom = NS_NewAtom(attrValue);
|
|
if (childrenAtom)
|
|
{
|
|
if (NS_SUCCEEDED(rv = EnsureElementHasGenericChild(aElement,
|
|
kNameSpaceID_XUL, childrenAtom, getter_AddRefs(children))))
|
|
{
|
|
}
|
|
}
|
|
}
|
|
}
|
|
rv = PopulateWidgetItemSubtree(aTemplate, aTemplate, children,
|
|
aElement, aProperty, aValue, aNaturalOrderPos);
|
|
}
|
|
else
|
|
{
|
|
rv = AddWidgetItem(aElement, aProperty, aValue, aNaturalOrderPos);
|
|
}
|
|
|
|
return(rv);
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
RDFGenericBuilderImpl::OnAssert(nsIRDFResource* aSubject,
|
|
nsIRDFResource* aPredicate,
|
|
nsIRDFNode* aObject)
|
|
{
|
|
NS_PRECONDITION(mDocument != nsnull, "not initialized");
|
|
if (! mDocument)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsISupportsArray> elements;
|
|
if (NS_FAILED(rv = NS_NewISupportsArray(getter_AddRefs(elements)))) {
|
|
NS_ERROR("unable to create new ISupportsArray");
|
|
return rv;
|
|
}
|
|
|
|
// Find all the elements in the content model that correspond to
|
|
// aSubject: for each, we'll try to build XUL children if
|
|
// appropriate.
|
|
if (NS_FAILED(rv = mDocument->GetElementsForResource(aSubject, elements))) {
|
|
NS_ERROR("unable to retrieve elements from resource");
|
|
return rv;
|
|
}
|
|
|
|
PRUint32 cnt = 0;
|
|
rv = elements->Count(&cnt);
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "Count failed");
|
|
for (PRInt32 i = cnt - 1; i >= 0; --i) {
|
|
nsCOMPtr<nsIContent> element( do_QueryInterface(elements->ElementAt(i)) );
|
|
|
|
// XXX somehow figure out if building XUL kids on this
|
|
// particular element makes any sense whatsoever.
|
|
|
|
// We'll start by making sure that the element at least has
|
|
// the same parent has the content model builder's root
|
|
if (!IsElementInWidget(element))
|
|
continue;
|
|
|
|
nsCOMPtr<nsIRDFResource> resource;
|
|
if (NS_SUCCEEDED(aObject->QueryInterface(kIRDFResourceIID,
|
|
(void**) getter_AddRefs(resource)))
|
|
&& IsContainmentProperty(element, aPredicate)) {
|
|
// Okay, the object _is_ a resource, and the predicate is
|
|
// a containment property. So this'll be a new item in the widget
|
|
// control.
|
|
|
|
// But if the contents of aElement _haven't_ yet been
|
|
// generated, then just ignore the assertion. We do this
|
|
// because we know that _eventually_ the contents will be
|
|
// generated (via CreateContents()) when somebody asks for
|
|
// them later.
|
|
nsAutoString contentsGenerated;
|
|
if (NS_FAILED(rv = element->GetAttribute(kNameSpaceID_None,
|
|
kItemContentsGeneratedAtom,
|
|
contentsGenerated))) {
|
|
NS_ERROR("severe problem trying to get attribute");
|
|
return rv;
|
|
}
|
|
|
|
if ((rv == NS_CONTENT_ATTR_HAS_VALUE) &&
|
|
contentsGenerated.EqualsIgnoreCase("true")) {
|
|
// Okay, it's a "live" element, so go ahead and append the new
|
|
// child to this node.
|
|
#ifdef XUL_TEMPLATES
|
|
rv = CreateWidgetItem(element, aPredicate, resource, 0);
|
|
#else
|
|
rv = AddWidgetItem(element, aPredicate, resource, 0);
|
|
#endif
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create widget item");
|
|
if (NS_FAILED(rv)) return rv;
|
|
}
|
|
}
|
|
else {
|
|
// Either the object of the assertion is not a resource,
|
|
// or the object is a resource and the predicate is not a
|
|
// tree property. So this won't be a new row in the
|
|
// table. See if we can use it to set a cell value on the
|
|
// current element.
|
|
nsCOMPtr<nsIRDFNode> target;
|
|
rv = mDB->GetTarget(aSubject, aPredicate, PR_TRUE, getter_AddRefs(target));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
return SetWidgetAttribute(element, aPredicate, target);
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
RDFGenericBuilderImpl::OnUnassert(nsIRDFResource* aSubject,
|
|
nsIRDFResource* aPredicate,
|
|
nsIRDFNode* aObject)
|
|
{
|
|
NS_PRECONDITION(mDocument != nsnull, "not initialized");
|
|
if (! mDocument)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsISupportsArray> elements;
|
|
if (NS_FAILED(rv = NS_NewISupportsArray(getter_AddRefs(elements)))) {
|
|
NS_ERROR("unable to create new ISupportsArray");
|
|
return rv;
|
|
}
|
|
|
|
// Find all the elements in the content model that correspond to
|
|
// aSubject: for each, we'll try to build XUL children if
|
|
// appropriate.
|
|
if (NS_FAILED(rv = mDocument->GetElementsForResource(aSubject, elements))) {
|
|
NS_ERROR("unable to retrieve elements from resource");
|
|
return rv;
|
|
}
|
|
|
|
PRUint32 cnt = 0;
|
|
rv = elements->Count(&cnt);
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "Count failed");
|
|
for (PRInt32 i = cnt - 1; i >= 0; --i) {
|
|
nsCOMPtr<nsIContent> element( do_QueryInterface(elements->ElementAt(i)) );
|
|
|
|
// XXX somehow figure out if building XUL kids on this
|
|
// particular element makes any sense whatsoever.
|
|
|
|
// We'll start by making sure that the element at least has
|
|
// the same parent has the content model builder's root
|
|
if (!IsElementInWidget(element))
|
|
continue;
|
|
|
|
nsCOMPtr<nsIRDFResource> resource;
|
|
if (NS_SUCCEEDED(aObject->QueryInterface(kIRDFResourceIID,
|
|
(void**) getter_AddRefs(resource)))
|
|
&& IsContainmentProperty(element, aPredicate)) {
|
|
// Okay, the object _is_ a resource, and the predicate is
|
|
// a containment property. So this'll be a new item in the widget
|
|
// control.
|
|
|
|
// But if the contents of aElement _haven't_ yet been
|
|
// generated, then just ignore the unassertion: nothing is
|
|
// in the content model to remove.
|
|
nsAutoString contentsGenerated;
|
|
if (NS_FAILED(rv = element->GetAttribute(kNameSpaceID_None,
|
|
kItemContentsGeneratedAtom,
|
|
contentsGenerated))) {
|
|
NS_ERROR("severe problem trying to get attribute");
|
|
return rv;
|
|
}
|
|
|
|
if ((rv == NS_CONTENT_ATTR_HAS_VALUE) &&
|
|
contentsGenerated.EqualsIgnoreCase("true")) {
|
|
// Okay, it's a "live" element, so go ahead and append the new
|
|
// child to this node.
|
|
if (NS_FAILED(rv = RemoveWidgetItem(element, aPredicate, resource))) {
|
|
NS_ERROR("unable to create new widget item");
|
|
return rv;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// Either the object of the assertion is not a resource,
|
|
// or the object is a resource and the predicate is not a
|
|
// tree property. So this won't be a new row in the
|
|
// table. See if we can use it to set a cell value on the
|
|
// current element.
|
|
nsCOMPtr<nsIRDFNode> target;
|
|
rv = mDB->GetTarget(aSubject, aPredicate, PR_TRUE, getter_AddRefs(target));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
if (rv == NS_RDF_NO_VALUE) {
|
|
return UnsetWidgetAttribute(element, aPredicate, aObject);
|
|
}
|
|
else {
|
|
return SetWidgetAttribute(element, aPredicate, target);
|
|
}
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// nsIDOMNodeObserver interface
|
|
//
|
|
// XXX Any of these methods that can't be implemented in a generic
|
|
// way should become pure virtual on this class.
|
|
//
|
|
|
|
NS_IMETHODIMP
|
|
RDFGenericBuilderImpl::OnSetNodeValue(nsIDOMNode* aNode, const nsString& aValue)
|
|
{
|
|
NS_NOTYETIMPLEMENTED("write me!");
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
RDFGenericBuilderImpl::OnInsertBefore(nsIDOMNode* aParent, nsIDOMNode* aNewChild, nsIDOMNode* aRefChild)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
RDFGenericBuilderImpl::OnReplaceChild(nsIDOMNode* aParent, nsIDOMNode* aNewChild, nsIDOMNode* aOldChild)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
RDFGenericBuilderImpl::OnRemoveChild(nsIDOMNode* aParent, nsIDOMNode* aOldChild)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
RDFGenericBuilderImpl::OnAppendChild(nsIDOMNode* aParent, nsIDOMNode* aNewChild)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// nsIDOMElementObserver interface
|
|
|
|
|
|
NS_IMETHODIMP
|
|
RDFGenericBuilderImpl::OnSetAttribute(nsIDOMElement* aElement, const nsString& aName, const nsString& aValue)
|
|
{
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIRDFResource> resource;
|
|
if (NS_FAILED(rv = GetDOMNodeResource(aElement, getter_AddRefs(resource)))) {
|
|
// XXX it's not a resource element, so there's no assertions
|
|
// we need to make on the back-end. Should we just do the
|
|
// update?
|
|
return NS_OK;
|
|
}
|
|
|
|
// Get the nsIContent interface, it's a bit more utilitarian
|
|
nsCOMPtr<nsIContent> element( do_QueryInterface(aElement) );
|
|
if (! element) {
|
|
NS_ERROR("element doesn't support nsIContent");
|
|
return NS_ERROR_UNEXPECTED;
|
|
}
|
|
|
|
// Make sure that the element is in the widget. XXX Even this may be
|
|
// a bit too promiscuous: an element may also be a XUL element...
|
|
if (!IsElementInWidget(element))
|
|
return NS_OK;
|
|
|
|
// Split the element into its namespace and tag components
|
|
PRInt32 elementNameSpaceID;
|
|
if (NS_FAILED(rv = element->GetNameSpaceID(elementNameSpaceID))) {
|
|
NS_ERROR("unable to get element namespace ID");
|
|
return rv;
|
|
}
|
|
|
|
nsCOMPtr<nsIAtom> elementNameAtom;
|
|
if (NS_FAILED(rv = element->GetTag( *getter_AddRefs(elementNameAtom) ))) {
|
|
NS_ERROR("unable to get element tag");
|
|
return rv;
|
|
}
|
|
|
|
// Split the property name into its namespace and tag components
|
|
PRInt32 attrNameSpaceID;
|
|
nsCOMPtr<nsIAtom> attrNameAtom;
|
|
if (NS_FAILED(rv = element->ParseAttributeString(aName, *getter_AddRefs(attrNameAtom), attrNameSpaceID))) {
|
|
NS_ERROR("unable to parse attribute string");
|
|
return rv;
|
|
}
|
|
|
|
// Now do the work to change the attribute. There are a couple of
|
|
// special cases that we need to check for here...
|
|
if ((elementNameSpaceID == kNameSpaceID_XUL) &&
|
|
IsItemOrFolder(element) && // XXX IsItemOrFolder(): is this what we really mean?
|
|
(attrNameSpaceID == kNameSpaceID_None) &&
|
|
(attrNameAtom.get() == kOpenAtom)) {
|
|
|
|
// We are (possibly) changing the value of the "open"
|
|
// attribute. This may require us to generate or destroy
|
|
// content in the widget. See what the old value was...
|
|
nsAutoString attrValue;
|
|
if (NS_FAILED(rv = element->GetAttribute(kNameSpaceID_None, kOpenAtom, attrValue))) {
|
|
NS_ERROR("unable to get current open state");
|
|
return rv;
|
|
}
|
|
|
|
if ((rv == NS_CONTENT_ATTR_NO_VALUE) || (rv == NS_CONTENT_ATTR_NOT_THERE) ||
|
|
((rv == NS_CONTENT_ATTR_HAS_VALUE) && (! attrValue.EqualsIgnoreCase(aValue))) ||
|
|
PR_TRUE // XXX just always allow this to fire.
|
|
) {
|
|
// Okay, it's really changing.
|
|
|
|
// This is a "transient" property, so we _don't_ go to the
|
|
// RDF graph to set it.
|
|
if (NS_FAILED(rv = element->SetAttribute(kNameSpaceID_None, kOpenAtom, aValue, PR_TRUE))) {
|
|
NS_ERROR("unable to update attribute on content node");
|
|
return rv;
|
|
}
|
|
|
|
if (aValue.EqualsIgnoreCase("true")) {
|
|
rv = OpenWidgetItem(element);
|
|
}
|
|
else {
|
|
rv = CloseWidgetItem(element);
|
|
}
|
|
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to open/close tree item");
|
|
return rv;
|
|
}
|
|
}
|
|
else if ((elementNameSpaceID == kNameSpaceID_XUL) &&
|
|
(IsItemOrFolder(element) || // XXX IsItemOrFolder(): is this what we really mean?
|
|
IsWidgetInsertionRootElement(element)) &&
|
|
(attrNameSpaceID == kNameSpaceID_None) &&
|
|
(attrNameAtom.get() == kIdAtom)) {
|
|
|
|
// We are (possibly) changing the actual identity of the
|
|
// element; e.g., re-rooting an item in the tree.
|
|
|
|
nsCOMPtr<nsIRDFResource> newResource;
|
|
if (NS_FAILED(rv = gRDFService->GetUnicodeResource(aValue.GetUnicode(), getter_AddRefs(newResource)))) {
|
|
NS_ERROR("unable to get new resource");
|
|
return rv;
|
|
}
|
|
|
|
#if 0 // XXX we're fighting with the XUL builder, so just _always_ let this through.
|
|
// Didn't change. So bail!
|
|
if (resource == newResource)
|
|
return NS_OK;
|
|
#endif
|
|
|
|
// Allright, it really is changing. So blow away the old
|
|
// content node and insert a new one with the new ID in
|
|
// its place.
|
|
nsCOMPtr<nsIContent> parent;
|
|
if (NS_FAILED(rv = element->GetParent(*getter_AddRefs(parent)))) {
|
|
NS_ERROR("unable to get element's parent");
|
|
return rv;
|
|
}
|
|
|
|
PRInt32 elementIndex;
|
|
if (NS_FAILED(rv = parent->IndexOf(element, elementIndex))) {
|
|
NS_ERROR("unable to get element's index within parent");
|
|
return rv;
|
|
}
|
|
|
|
if (NS_FAILED(rv = parent->RemoveChildAt(elementIndex, PR_TRUE))) {
|
|
NS_ERROR("unable to remove element");
|
|
return rv;
|
|
}
|
|
|
|
nsCOMPtr<nsIContent> newElement;
|
|
if (NS_FAILED(rv = CreateElement(elementNameSpaceID,
|
|
elementNameAtom,
|
|
newResource,
|
|
getter_AddRefs(newElement)))) {
|
|
NS_ERROR("unable to create new element");
|
|
return rv;
|
|
}
|
|
|
|
// Attach transient properties to the new element.
|
|
//
|
|
// XXX all I really care about right this minute is the
|
|
// "open" state. We could put this stuff in a table and
|
|
// drive it that way.
|
|
nsAutoString attrValue;
|
|
if (NS_FAILED(rv = element->GetAttribute(kNameSpaceID_None, kOpenAtom, attrValue))) {
|
|
NS_ERROR("unable to get open state of old element");
|
|
return rv;
|
|
}
|
|
|
|
if (rv == NS_CONTENT_ATTR_HAS_VALUE) {
|
|
if (NS_FAILED(rv = newElement->SetAttribute(kNameSpaceID_None, kOpenAtom, attrValue, PR_FALSE))) {
|
|
NS_ERROR("unable to set open state of new element");
|
|
return rv;
|
|
}
|
|
}
|
|
|
|
// Mark as a container so the contents get regenerated
|
|
if (NS_FAILED(rv = newElement->SetAttribute(kNameSpaceID_RDF,
|
|
kContainerAtom,
|
|
"true",
|
|
PR_FALSE))) {
|
|
NS_ERROR("unable to mark as a container");
|
|
return rv;
|
|
}
|
|
|
|
// Now insert the new element into the parent. This should
|
|
// trigger a reflow and cause the contents to be regenerated.
|
|
if (NS_FAILED(rv = parent->InsertChildAt(newElement, elementIndex, PR_TRUE))) {
|
|
NS_ERROR("unable to add new element to the parent");
|
|
return rv;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
// If we get here, it's a "vanilla" property: push its value into the graph.
|
|
if (kNameSpaceID_Unknown == attrNameSpaceID) {
|
|
attrNameSpaceID = kNameSpaceID_None; // ignore unknown prefix XXX is this correct?
|
|
}
|
|
nsCOMPtr<nsIRDFResource> property;
|
|
if (NS_FAILED(rv = GetResource(attrNameSpaceID, attrNameAtom, getter_AddRefs(property)))) {
|
|
NS_ERROR("unable to construct resource");
|
|
return rv;
|
|
}
|
|
|
|
// Unassert the old value, if there was one.
|
|
nsAutoString oldValue;
|
|
if (NS_CONTENT_ATTR_HAS_VALUE == element->GetAttribute(attrNameSpaceID, attrNameAtom, oldValue)) {
|
|
nsCOMPtr<nsIRDFLiteral> value;
|
|
if (NS_FAILED(rv = gRDFService->GetLiteral(oldValue.GetUnicode(), getter_AddRefs(value)))) {
|
|
NS_ERROR("unable to construct literal");
|
|
return rv;
|
|
}
|
|
|
|
rv = mDB->Unassert(resource, property, value);
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to unassert old property value");
|
|
}
|
|
|
|
// Assert the new value
|
|
{
|
|
nsCOMPtr<nsIRDFLiteral> value;
|
|
if (NS_FAILED(rv = gRDFService->GetLiteral(aValue.GetUnicode(), getter_AddRefs(value)))) {
|
|
NS_ERROR("unable to construct literal");
|
|
return rv;
|
|
}
|
|
|
|
rv = mDB->Assert(resource, property, value, PR_TRUE);
|
|
NS_ASSERTION(rv == NS_RDF_ASSERTION_ACCEPTED, "unable to assert new property value");
|
|
if (NS_FAILED(rv)) return rv;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
RDFGenericBuilderImpl::OnRemoveAttribute(nsIDOMElement* aElement, const nsString& aName)
|
|
{
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIRDFResource> resource;
|
|
if (NS_FAILED(rv = GetDOMNodeResource(aElement, getter_AddRefs(resource)))) {
|
|
// XXX it's not a resource element, so there's no assertions
|
|
// we need to make on the back-end. Should we just do the
|
|
// update?
|
|
return NS_OK;
|
|
}
|
|
|
|
// Get the nsIContent interface, it's a bit more utilitarian
|
|
nsCOMPtr<nsIContent> element( do_QueryInterface(aElement) );
|
|
if (! element) {
|
|
NS_ERROR("element doesn't support nsIContent");
|
|
return NS_ERROR_UNEXPECTED;
|
|
}
|
|
|
|
// Make sure that the element is in the widget. XXX Even this may be
|
|
// a bit too promiscuous: an element may also be a XUL element...
|
|
if (!IsElementInWidget(element))
|
|
return NS_OK;
|
|
|
|
// Split the element into its namespace and tag components
|
|
PRInt32 elementNameSpaceID;
|
|
if (NS_FAILED(rv = element->GetNameSpaceID(elementNameSpaceID))) {
|
|
NS_ERROR("unable to get element namespace ID");
|
|
return rv;
|
|
}
|
|
|
|
nsCOMPtr<nsIAtom> elementNameAtom;
|
|
if (NS_FAILED(rv = element->GetTag( *getter_AddRefs(elementNameAtom) ))) {
|
|
NS_ERROR("unable to get element tag");
|
|
return rv;
|
|
}
|
|
|
|
// Split the property name into its namespace and tag components
|
|
PRInt32 attrNameSpaceID;
|
|
nsCOMPtr<nsIAtom> attrNameAtom;
|
|
if (NS_FAILED(rv = element->ParseAttributeString(aName, *getter_AddRefs(attrNameAtom), attrNameSpaceID))) {
|
|
NS_ERROR("unable to parse attribute string");
|
|
return rv;
|
|
}
|
|
|
|
if ((elementNameSpaceID == kNameSpaceID_XUL) &&
|
|
IsItemOrFolder(element) && // XXX Is this what we really mean?
|
|
(attrNameSpaceID == kNameSpaceID_None) &&
|
|
(attrNameAtom.get() == kOpenAtom)) {
|
|
// We are removing the value of the "open" attribute. This may
|
|
// require us to destroy content from the tree.
|
|
|
|
// XXX should we check for existence of the attribute first?
|
|
if (NS_FAILED(rv = element->UnsetAttribute(kNameSpaceID_None, kOpenAtom, PR_TRUE))) {
|
|
NS_ERROR("unable to attribute on update content node");
|
|
return rv;
|
|
}
|
|
|
|
if (NS_FAILED(rv = CloseWidgetItem(element))) {
|
|
NS_ERROR("unable to close widget item");
|
|
return rv;
|
|
}
|
|
}
|
|
else {
|
|
// It's a "vanilla" property: push its value into the graph.
|
|
|
|
nsCOMPtr<nsIRDFResource> property;
|
|
if (kNameSpaceID_Unknown == attrNameSpaceID) {
|
|
attrNameSpaceID = kNameSpaceID_None; // ignore unknown prefix XXX is this correct?
|
|
}
|
|
if (NS_FAILED(rv = GetResource(attrNameSpaceID, attrNameAtom, getter_AddRefs(property)))) {
|
|
NS_ERROR("unable to construct resource");
|
|
return rv;
|
|
}
|
|
|
|
// Unassert the old value, if there was one.
|
|
nsAutoString oldValue;
|
|
if (NS_CONTENT_ATTR_HAS_VALUE == element->GetAttribute(attrNameSpaceID, attrNameAtom, oldValue)) {
|
|
nsCOMPtr<nsIRDFLiteral> value;
|
|
if (NS_FAILED(rv = gRDFService->GetLiteral(oldValue.GetUnicode(), getter_AddRefs(value)))) {
|
|
NS_ERROR("unable to construct literal");
|
|
return rv;
|
|
}
|
|
|
|
rv = mDB->Unassert(resource, property, value);
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to unassert old property value");
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
RDFGenericBuilderImpl::OnSetAttributeNode(nsIDOMElement* aElement, nsIDOMAttr* aNewAttr)
|
|
{
|
|
NS_NOTYETIMPLEMENTED("write me!");
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
RDFGenericBuilderImpl::OnRemoveAttributeNode(nsIDOMElement* aElement, nsIDOMAttr* aOldAttr)
|
|
{
|
|
NS_NOTYETIMPLEMENTED("write me!");
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Implementation methods
|
|
|
|
nsresult
|
|
RDFGenericBuilderImpl::EnsureElementHasGenericChild(nsIContent* parent,
|
|
PRInt32 nameSpaceID,
|
|
nsIAtom* tag,
|
|
nsIContent** result)
|
|
{
|
|
nsresult rv;
|
|
|
|
rv = nsRDFContentUtils::FindChildByTag(parent, nameSpaceID, tag, result);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
if (rv == NS_RDF_NO_VALUE) {
|
|
// we need to construct a new child element.
|
|
nsCOMPtr<nsIContent> element;
|
|
|
|
if (NS_FAILED(rv = NS_NewRDFElement(nameSpaceID, tag, getter_AddRefs(element))))
|
|
return rv;
|
|
|
|
if (NS_FAILED(rv = parent->AppendChildTo(element, PR_FALSE)))
|
|
return rv;
|
|
|
|
*result = element;
|
|
NS_ADDREF(*result);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
RDFGenericBuilderImpl::FindWidgetRootElement(nsIContent* aElement,
|
|
nsIContent** aWidgetElement)
|
|
{
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIAtom> rootAtom;
|
|
if (NS_FAILED(rv = GetRootWidgetAtom(getter_AddRefs(rootAtom)))) {
|
|
return rv;
|
|
}
|
|
|
|
// walk up the tree until you find rootAtom
|
|
nsCOMPtr<nsIContent> element(do_QueryInterface(aElement));
|
|
|
|
while (element) {
|
|
PRInt32 nameSpaceID;
|
|
if (NS_FAILED(rv = element->GetNameSpaceID(nameSpaceID)))
|
|
return rv; // XXX fatal
|
|
|
|
if (nameSpaceID == kNameSpaceID_XUL) {
|
|
nsCOMPtr<nsIAtom> tag;
|
|
if (NS_FAILED(rv = element->GetTag(*getter_AddRefs(tag))))
|
|
return rv;
|
|
|
|
if (tag == rootAtom) {
|
|
*aWidgetElement = element;
|
|
NS_ADDREF(*aWidgetElement);
|
|
return NS_OK;
|
|
}
|
|
}
|
|
|
|
// up to the parent...
|
|
nsCOMPtr<nsIContent> parent;
|
|
element->GetParent(*getter_AddRefs(parent));
|
|
element = parent;
|
|
}
|
|
|
|
//NS_ERROR("must not've started from within the XUL widget");
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
|
|
PRBool
|
|
RDFGenericBuilderImpl::IsItemOrFolder(nsIContent* aElement)
|
|
{
|
|
// XXX It seems like this should be a pure virtual method that
|
|
// subclasses implement?
|
|
|
|
// XXX All of the callers of this method actually only seem to
|
|
// care if the element is a "folder".
|
|
|
|
// Returns PR_TRUE if the element is an "item" or a "folder" in
|
|
// the widget.
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIAtom> itemAtom;
|
|
nsCOMPtr<nsIAtom> folderAtom;
|
|
if (NS_FAILED(rv = GetWidgetItemAtom(getter_AddRefs(itemAtom))) ||
|
|
NS_FAILED(rv = GetWidgetFolderAtom(getter_AddRefs(folderAtom)))) {
|
|
return rv;
|
|
}
|
|
|
|
// "element" must be itemAtom
|
|
nsCOMPtr<nsIAtom> tag;
|
|
if (NS_FAILED(rv = aElement->GetTag(*getter_AddRefs(tag))))
|
|
return PR_FALSE;
|
|
|
|
if (tag != itemAtom && tag != folderAtom)
|
|
return PR_FALSE;
|
|
|
|
return PR_TRUE;
|
|
}
|
|
|
|
PRBool
|
|
RDFGenericBuilderImpl::IsWidgetInsertionRootElement(nsIContent* element)
|
|
{
|
|
// Returns PR_TRUE if the element is the root point to insert new items.
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIAtom> rootAtom;
|
|
if (NS_FAILED(rv = GetInsertionRootAtom(getter_AddRefs(rootAtom)))) {
|
|
return rv;
|
|
}
|
|
|
|
PRInt32 nameSpaceID;
|
|
if (NS_FAILED(rv = element->GetNameSpaceID(nameSpaceID))) {
|
|
NS_ERROR("unable to get namespace ID");
|
|
return PR_FALSE;
|
|
}
|
|
|
|
if (nameSpaceID != kNameSpaceID_XUL)
|
|
return PR_FALSE; // not a XUL element
|
|
|
|
nsCOMPtr<nsIAtom> elementTag;
|
|
if (NS_FAILED(rv = element->GetTag(*getter_AddRefs(elementTag)))) {
|
|
NS_ERROR("unable to get tag");
|
|
return PR_FALSE;
|
|
}
|
|
|
|
if (elementTag != rootAtom)
|
|
return PR_FALSE; // not the place to insert a child
|
|
|
|
return PR_TRUE;
|
|
}
|
|
|
|
PRBool
|
|
RDFGenericBuilderImpl::IsContainmentProperty(nsIContent* aElement, nsIRDFResource* aProperty)
|
|
{
|
|
// XXX is this okay to _always_ treat ordinal properties as tree
|
|
// properties? Probably not...
|
|
nsresult rv;
|
|
|
|
PRBool isOrdinal;
|
|
rv = gRDFContainerUtils->IsOrdinalProperty(aProperty, &isOrdinal);
|
|
if (NS_FAILED(rv))
|
|
return PR_FALSE;
|
|
|
|
if (isOrdinal)
|
|
return PR_TRUE;
|
|
|
|
nsXPIDLCString propertyURI;
|
|
if (NS_FAILED(rv = aProperty->GetValue( getter_Copies(propertyURI) ))) {
|
|
NS_ERROR("unable to get property URI");
|
|
return PR_FALSE;
|
|
}
|
|
|
|
nsAutoString uri;
|
|
|
|
// Walk up the content tree looking for the "rdf:containment"
|
|
// attribute, so we can determine if the specified property
|
|
// actually defines containment.
|
|
nsCOMPtr<nsIContent> element( dont_QueryInterface(aElement) );
|
|
while (element) {
|
|
// Never ever ask an HTML element about non-HTML attributes.
|
|
PRInt32 nameSpaceID;
|
|
if (NS_FAILED(rv = element->GetNameSpaceID(nameSpaceID))) {
|
|
NS_ERROR("unable to get element namespace");
|
|
return PR_FALSE;
|
|
}
|
|
|
|
if (nameSpaceID != kNameSpaceID_HTML) {
|
|
// Is this the "containment" property?
|
|
if (NS_FAILED(rv = element->GetAttribute(kNameSpaceID_None, kContainmentAtom, uri))) {
|
|
NS_ERROR("unable to get attribute value");
|
|
return PR_FALSE;
|
|
}
|
|
|
|
if (rv == NS_CONTENT_ATTR_HAS_VALUE) {
|
|
// Okay we've found the locally-scoped tree properties,
|
|
// a whitespace-separated list of property URIs. So we
|
|
// definitively know whether this is a tree property or
|
|
// not.
|
|
if (uri.Find(propertyURI) >= 0)
|
|
return PR_TRUE;
|
|
else
|
|
return PR_FALSE;
|
|
}
|
|
}
|
|
|
|
nsCOMPtr<nsIContent> parent;
|
|
element->GetParent(*getter_AddRefs(parent));
|
|
element = parent;
|
|
}
|
|
|
|
// If we get here, we didn't find any tree property: so now
|
|
// defaults start to kick in.
|
|
|
|
#define TREE_PROPERTY_HACK
|
|
#if defined(TREE_PROPERTY_HACK)
|
|
if ((aProperty == kNC_child) ||
|
|
(aProperty == kNC_Folder) ||
|
|
(aProperty == kRDF_child)) {
|
|
return PR_TRUE;
|
|
}
|
|
else
|
|
#endif // defined(TREE_PROPERTY_HACK)
|
|
|
|
return PR_FALSE;
|
|
}
|
|
|
|
|
|
PRBool
|
|
RDFGenericBuilderImpl::IsIgnoredProperty(nsIContent* aElement, nsIRDFResource* aProperty)
|
|
{
|
|
nsresult rv;
|
|
|
|
nsXPIDLCString propertyURI;
|
|
rv = aProperty->GetValue( getter_Copies(propertyURI) );
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsAutoString uri;
|
|
|
|
// Walk up the content tree looking for the "rdf:ignore"
|
|
// attribute, so we can determine if the specified property should
|
|
// be ignored.
|
|
nsCOMPtr<nsIContent> element( dont_QueryInterface(aElement) );
|
|
while (element) {
|
|
PRInt32 nameSpaceID;
|
|
rv = element->GetNameSpaceID(nameSpaceID);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
// Never ever ask an HTML element about non-HTML attributes
|
|
if (nameSpaceID != kNameSpaceID_HTML) {
|
|
rv = element->GetAttribute(kNameSpaceID_None, kIgnoreAtom, uri);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
if (rv == NS_CONTENT_ATTR_HAS_VALUE) {
|
|
// Okay, we've found the locally-scoped ignore
|
|
// properties, which is a whitespace-separated list of
|
|
// property URIs. So we definitively know whether this
|
|
// property should be ignored or not.
|
|
if (uri.Find(propertyURI) >= 0)
|
|
return PR_TRUE;
|
|
else
|
|
return PR_FALSE;
|
|
}
|
|
}
|
|
|
|
nsCOMPtr<nsIContent> parent;
|
|
element->GetParent(*getter_AddRefs(parent));
|
|
element = parent;
|
|
}
|
|
|
|
// Walked _all_ the way to the top and couldn't find anything to
|
|
// ignore.
|
|
return PR_FALSE;
|
|
}
|
|
|
|
PRBool
|
|
RDFGenericBuilderImpl::IsContainer(nsIContent* aElement, nsIRDFResource* aResource)
|
|
{
|
|
// Look at all of the arcs extending _out_ of the resource: if any
|
|
// of them are that "containment" property, then we know we'll
|
|
// have children.
|
|
|
|
nsCOMPtr<nsISimpleEnumerator> arcs;
|
|
nsresult rv;
|
|
|
|
rv = mDB->ArcLabelsOut(aResource, getter_AddRefs(arcs));
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get arcs out");
|
|
if (NS_FAILED(rv))
|
|
return PR_FALSE;
|
|
|
|
while (1) {
|
|
PRBool hasMore;
|
|
rv = arcs->HasMoreElements(&hasMore);
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "severe error advancing cursor");
|
|
if (NS_FAILED(rv))
|
|
return PR_FALSE;
|
|
|
|
if (! hasMore)
|
|
break;
|
|
|
|
nsCOMPtr<nsISupports> isupports;
|
|
rv = arcs->GetNext(getter_AddRefs(isupports));
|
|
if (NS_FAILED(rv))
|
|
return PR_FALSE;
|
|
|
|
nsCOMPtr<nsIRDFResource> property = do_QueryInterface(isupports);
|
|
|
|
if (! IsContainmentProperty(aElement, property))
|
|
continue;
|
|
|
|
// see if it has a value
|
|
nsCOMPtr<nsIRDFNode> value;
|
|
rv = mDB->GetTarget(aResource, property, PR_TRUE, getter_AddRefs(value));
|
|
if (NS_FAILED(rv))
|
|
return PR_FALSE;
|
|
|
|
if (value)
|
|
return PR_TRUE;
|
|
}
|
|
|
|
return PR_FALSE;
|
|
}
|
|
|
|
PRBool
|
|
RDFGenericBuilderImpl::IsOpen(nsIContent* aElement)
|
|
{
|
|
nsresult rv;
|
|
|
|
// needs to be a the valid insertion root or an item to begin with.
|
|
PRInt32 nameSpaceID;
|
|
if (NS_FAILED(rv = aElement->GetNameSpaceID(nameSpaceID))) {
|
|
NS_ERROR("unable to get namespace ID");
|
|
return PR_FALSE;
|
|
}
|
|
|
|
if (nameSpaceID != kNameSpaceID_XUL)
|
|
return PR_FALSE;
|
|
|
|
nsCOMPtr<nsIAtom> tag;
|
|
if (NS_FAILED(rv = aElement->GetTag( *getter_AddRefs(tag) ))) {
|
|
NS_ERROR("unable to get element's tag");
|
|
return PR_FALSE;
|
|
}
|
|
|
|
nsCOMPtr<nsIAtom> insertionAtom;
|
|
if (NS_FAILED(rv = GetInsertionRootAtom(getter_AddRefs(insertionAtom)))) {
|
|
return rv;
|
|
}
|
|
|
|
nsCOMPtr<nsIAtom> folderAtom;
|
|
if (NS_FAILED(rv = GetWidgetFolderAtom(getter_AddRefs(folderAtom)))) {
|
|
return rv;
|
|
}
|
|
|
|
// The insertion root is _always_ open.
|
|
if (tag == insertionAtom)
|
|
return PR_TRUE;
|
|
|
|
// If it's not a widget folder item, then it's not open.
|
|
if (tag != folderAtom)
|
|
return PR_FALSE;
|
|
|
|
nsAutoString value;
|
|
if (NS_FAILED(rv = aElement->GetAttribute(kNameSpaceID_None, kOpenAtom, value))) {
|
|
NS_ERROR("unable to get open attribute");
|
|
return rv;
|
|
}
|
|
|
|
if (rv == NS_CONTENT_ATTR_HAS_VALUE) {
|
|
if (value.EqualsIgnoreCase("true"))
|
|
return PR_TRUE;
|
|
}
|
|
|
|
return PR_FALSE;
|
|
}
|
|
|
|
|
|
PRBool
|
|
RDFGenericBuilderImpl::IsElementInWidget(nsIContent* aElement)
|
|
{
|
|
// Make sure that we're actually creating content for the tree
|
|
// content model that we've been assigned to deal with.
|
|
|
|
// Walk up the parent chain from us to the root and
|
|
// see what we find.
|
|
if (aElement == mRoot)
|
|
return PR_TRUE;
|
|
|
|
// walk up the tree until you find rootAtom
|
|
nsCOMPtr<nsIContent> element(do_QueryInterface(aElement));
|
|
nsCOMPtr<nsIContent> parent;
|
|
element->GetParent(*getter_AddRefs(parent));
|
|
element = parent;
|
|
|
|
while (element) {
|
|
|
|
if (element.get() == mRoot)
|
|
return PR_TRUE;
|
|
|
|
// up to the parent...
|
|
nsCOMPtr<nsIContent> parent;
|
|
element->GetParent(*getter_AddRefs(parent));
|
|
element = parent;
|
|
}
|
|
|
|
return PR_FALSE;
|
|
}
|
|
|
|
nsresult
|
|
RDFGenericBuilderImpl::GetDOMNodeResource(nsIDOMNode* aNode, nsIRDFResource** aResource)
|
|
{
|
|
nsresult rv;
|
|
|
|
// Given an nsIDOMNode that presumably has been created as a proxy
|
|
// for an RDF resource, pull the RDF resource information out of
|
|
// it.
|
|
|
|
nsCOMPtr<nsIContent> element;
|
|
if (NS_FAILED(rv = aNode->QueryInterface(kIContentIID, getter_AddRefs(element) ))) {
|
|
NS_ERROR("DOM element doesn't support nsIContent");
|
|
return rv;
|
|
}
|
|
|
|
return nsRDFContentUtils::GetElementRefResource(element, aResource);
|
|
}
|
|
|
|
|
|
nsresult
|
|
RDFGenericBuilderImpl::GetResource(PRInt32 aNameSpaceID,
|
|
nsIAtom* aNameAtom,
|
|
nsIRDFResource** aResource)
|
|
{
|
|
NS_PRECONDITION(aNameAtom != nsnull, "null ptr");
|
|
if (! aNameAtom)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
// XXX should we allow nodes with no namespace???
|
|
NS_PRECONDITION(aNameSpaceID != kNameSpaceID_Unknown, "no namespace");
|
|
if (aNameSpaceID == kNameSpaceID_Unknown)
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
// construct a fully-qualified URI from the namespace/tag pair.
|
|
nsAutoString uri;
|
|
gNameSpaceManager->GetNameSpaceURI(aNameSpaceID, uri);
|
|
|
|
// XXX check to see if we need to insert a '/' or a '#'
|
|
nsAutoString tag(aNameAtom->GetUnicode());
|
|
if (0 < uri.Length() && uri.Last() != '#' && uri.Last() != '/' && tag.First() != '#')
|
|
uri.Append('#');
|
|
|
|
uri.Append(tag);
|
|
|
|
nsresult rv = gRDFService->GetUnicodeResource(uri.GetUnicode(), aResource);
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get resource");
|
|
return rv;
|
|
}
|
|
|
|
|
|
nsresult
|
|
RDFGenericBuilderImpl::OpenWidgetItem(nsIContent* aElement)
|
|
{
|
|
return CreateContents(aElement);
|
|
}
|
|
|
|
|
|
nsresult
|
|
RDFGenericBuilderImpl::CloseWidgetItem(nsIContent* aElement)
|
|
{
|
|
nsresult rv;
|
|
|
|
// Find the tag that contains the children so that we can remove all of
|
|
// the children.
|
|
nsCOMPtr<nsIAtom> parentAtom;
|
|
if (NS_FAILED(rv = GetItemAtomThatContainsTheChildren(getter_AddRefs(parentAtom)))) {
|
|
return rv;
|
|
}
|
|
|
|
nsCOMPtr<nsIContent> parentNode;
|
|
nsCOMPtr<nsIAtom> tag;
|
|
if (NS_FAILED(rv = aElement->GetTag(*getter_AddRefs(tag))))
|
|
return rv; // XXX fatal
|
|
|
|
if (tag == parentAtom) {
|
|
parentNode = dont_QueryInterface(aElement);
|
|
rv = NS_OK;
|
|
}
|
|
else {
|
|
rv = nsRDFContentUtils::FindChildByTag(aElement, kNameSpaceID_XUL, parentAtom, getter_AddRefs(parentNode));
|
|
}
|
|
|
|
if (rv == NS_RDF_NO_VALUE) {
|
|
// No tag; must've already been closed
|
|
return NS_OK;
|
|
}
|
|
|
|
if (NS_FAILED(rv)) {
|
|
NS_ERROR("severe error retrieving parent node for removal");
|
|
return rv;
|
|
}
|
|
|
|
PRInt32 count;
|
|
if (NS_FAILED(rv = parentNode->ChildCount(count))) {
|
|
NS_ERROR("unable to get count of the parent's children");
|
|
return rv;
|
|
}
|
|
|
|
while (--count >= 0) {
|
|
// XXX This is a bit gross. We need to recursively remove any
|
|
// subtrees before we remove the current subtree.
|
|
nsIContent* child;
|
|
if (NS_SUCCEEDED(rv = parentNode->ChildAt(count, child))) {
|
|
rv = CloseWidgetItem(child);
|
|
NS_RELEASE(child);
|
|
}
|
|
|
|
rv = parentNode->RemoveChildAt(count, PR_TRUE);
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "error removing child");
|
|
}
|
|
|
|
// Clear the contents-generated attribute so that the next time we
|
|
// come back, we'll regenerate the kids we just killed.
|
|
if (NS_FAILED(rv = aElement->UnsetAttribute(kNameSpaceID_None,
|
|
kItemContentsGeneratedAtom,
|
|
PR_FALSE))) {
|
|
NS_ERROR("unable to clear contents-generated attribute");
|
|
return rv;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|