Back to index

lightning-sunbird  0.9+nobinonly
nsXULContentUtils.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is Mozilla Communicator client code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK *****
00038  *
00039  *
00040  * This Original Code has been modified by IBM Corporation.
00041  * Modifications made by IBM described herein are
00042  * Copyright (c) International Business Machines
00043  * Corporation, 2000
00044  *
00045  * Modifications to Mozilla code or documentation
00046  * identified per MPL Section 3.3
00047  *
00048  * Date         Modified by     Description of modification
00049  * 03/27/2000   IBM Corp.       Added PR_CALLBACK for Optlink
00050  *                               use in OS2
00051  */
00052 
00053 
00054 /*
00055 
00056   A package of routines shared by the XUL content code.
00057 
00058  */
00059 
00060 
00061 #include "nsCOMPtr.h"
00062 #include "nsIContent.h"
00063 #include "nsINodeInfo.h"
00064 #include "nsIDocument.h"
00065 #include "nsIDOMElement.h"
00066 #include "nsIDOMXULCommandDispatcher.h"
00067 #include "nsIDOMXULDocument.h"
00068 #include "nsIRDFNode.h"
00069 #include "nsINameSpaceManager.h"
00070 #include "nsIRDFService.h"
00071 #include "nsIServiceManager.h"
00072 #include "nsITextContent.h"
00073 #include "nsIURL.h"
00074 #include "nsXULContentUtils.h"
00075 #include "nsIXULPrototypeCache.h"
00076 #include "nsLayoutCID.h"
00077 #include "nsNetUtil.h"
00078 #include "nsRDFCID.h"
00079 #include "nsString.h"
00080 #include "nsXPIDLString.h"
00081 #include "nsXULAtoms.h"
00082 #include "prlog.h"
00083 #include "prtime.h"
00084 #include "rdf.h"
00085 #include "nsContentUtils.h"
00086 #include "nsIDateTimeFormat.h"
00087 #include "nsDateTimeFormatCID.h"
00088 #include "nsIScriptableDateFormat.h"
00089 #include "nsIDOMXULElement.h"
00090 
00091 static NS_DEFINE_CID(kDateTimeFormatCID,    NS_DATETIMEFORMAT_CID);
00092 static NS_DEFINE_CID(kRDFServiceCID,        NS_RDFSERVICE_CID);
00093 
00094 //------------------------------------------------------------------------
00095 
00096 nsrefcnt nsXULContentUtils::gRefCnt;
00097 nsIRDFService* nsXULContentUtils::gRDF;
00098 nsIDateTimeFormat* nsXULContentUtils::gFormat;
00099 
00100 #define XUL_RESOURCE(ident, uri) nsIRDFResource* nsXULContentUtils::ident
00101 #define XUL_LITERAL(ident, val) nsIRDFLiteral* nsXULContentUtils::ident
00102 #include "nsXULResourceList.h"
00103 #undef XUL_RESOURCE
00104 #undef XUL_LITERAL
00105 
00106 //------------------------------------------------------------------------
00107 // Constructors n' stuff
00108 //
00109 
00110 nsresult
00111 nsXULContentUtils::Init()
00112 {
00113     if (gRefCnt++ == 0) {
00114         nsresult rv = CallGetService(kRDFServiceCID, &gRDF);
00115         if (NS_FAILED(rv)) {
00116             return rv;
00117         }
00118 
00119 #define XUL_RESOURCE(ident, uri)                              \
00120   PR_BEGIN_MACRO                                              \
00121    rv = gRDF->GetResource(NS_LITERAL_CSTRING(uri), &(ident)); \
00122    if (NS_FAILED(rv)) return rv;                              \
00123   PR_END_MACRO
00124 
00125 #define XUL_LITERAL(ident, val)                                   \
00126   PR_BEGIN_MACRO                                                  \
00127    rv = gRDF->GetLiteral(NS_LITERAL_STRING(val).get(), &(ident)); \
00128    if (NS_FAILED(rv)) return rv;                                  \
00129   PR_END_MACRO
00130 
00131 #include "nsXULResourceList.h"
00132 #undef XUL_RESOURCE
00133 #undef XUL_LITERAL
00134 
00135         rv = CallCreateInstance(kDateTimeFormatCID, &gFormat);
00136         if (NS_FAILED(rv)) {
00137             return rv;
00138         }
00139     }
00140 
00141     return NS_OK;
00142 }
00143 
00144 
00145 nsresult
00146 nsXULContentUtils::Finish()
00147 {
00148     if (--gRefCnt == 0) {
00149         NS_IF_RELEASE(gRDF);
00150 
00151 #define XUL_RESOURCE(ident, uri) NS_IF_RELEASE(ident)
00152 #define XUL_LITERAL(ident, val) NS_IF_RELEASE(ident)
00153 #include "nsXULResourceList.h"
00154 #undef XUL_RESOURCE
00155 #undef XUL_LITERAL
00156 
00157         NS_IF_RELEASE(gFormat);
00158     }
00159 
00160     return NS_OK;
00161 }
00162 
00163 
00164 //------------------------------------------------------------------------
00165 // nsIXULContentUtils methods
00166 
00167 nsresult
00168 nsXULContentUtils::FindChildByTag(nsIContent* aElement,
00169                                   PRInt32 aNameSpaceID,
00170                                   nsIAtom* aTag,
00171                                   nsIContent** aResult)
00172 {
00173     PRUint32 count = aElement->GetChildCount();
00174 
00175     for (PRUint32 i = 0; i < count; ++i) {
00176         nsIContent *kid = aElement->GetChildAt(i);
00177 
00178         if (kid->GetNameSpaceID() != aNameSpaceID)
00179             continue; // wrong namespace
00180 
00181         nsINodeInfo *ni = kid->GetNodeInfo();
00182 
00183         if (!ni || !ni->Equals(aTag))
00184             continue;
00185 
00186         *aResult = kid;
00187         NS_ADDREF(*aResult);
00188         return NS_OK;
00189     }
00190 
00191     *aResult = nsnull;
00192     return NS_RDF_NO_VALUE; // not found
00193 }
00194 
00195 
00196 nsresult
00197 nsXULContentUtils::GetElementResource(nsIContent* aElement, nsIRDFResource** aResult)
00198 {
00199     // Perform a reverse mapping from an element in the content model
00200     // to an RDF resource.
00201     nsresult rv;
00202 
00203     PRUnichar buf[128];
00204     nsFixedString id(buf, NS_ARRAY_LENGTH(buf), 0);
00205 
00206     rv = aElement->GetAttr(kNameSpaceID_None, nsXULAtoms::id, id);
00207     NS_ASSERTION(NS_SUCCEEDED(rv), "severe error retrieving attribute");
00208     if (NS_FAILED(rv)) return rv;
00209 
00210     if (rv != NS_CONTENT_ATTR_HAS_VALUE)
00211         return NS_ERROR_FAILURE;
00212 
00213     // Since the element will store its ID attribute as a document-relative value,
00214     // we may need to qualify it first...
00215     nsCOMPtr<nsIDocument> doc = aElement->GetDocument();
00216     NS_ASSERTION(doc, "element is not in any document");
00217     if (! doc)
00218         return NS_ERROR_FAILURE;
00219 
00220     rv = nsXULContentUtils::MakeElementResource(doc, id, aResult);
00221     if (NS_FAILED(rv)) return rv;
00222 
00223     return NS_OK;
00224 }
00225 
00226 
00227 nsresult
00228 nsXULContentUtils::GetElementRefResource(nsIContent* aElement, nsIRDFResource** aResult)
00229 {
00230     *aResult = nsnull;
00231     // Perform a reverse mapping from an element in the content model
00232     // to an RDF resource. Check for a "ref" attribute first, then
00233     // fallback on an "id" attribute.
00234     nsresult rv;
00235     PRUnichar buf[128];
00236     nsFixedString uri(buf, NS_ARRAY_LENGTH(buf), 0);
00237 
00238     rv = aElement->GetAttr(kNameSpaceID_None, nsXULAtoms::ref, uri);
00239     NS_ASSERTION(NS_SUCCEEDED(rv), "severe error retrieving attribute");
00240     if (NS_FAILED(rv)) return rv;
00241 
00242     if (rv != NS_CONTENT_ATTR_HAS_VALUE) {
00243         rv = aElement->GetAttr(kNameSpaceID_None, nsXULAtoms::id, uri);
00244     }
00245 
00246     if (rv == NS_CONTENT_ATTR_HAS_VALUE) {
00247         // We'll use rdf_MakeAbsolute() to translate this to a URL.
00248         nsCOMPtr<nsIDocument> doc = aElement->GetOwnerDoc();
00249 
00250         nsIURI *url = doc->GetDocumentURI();
00251         NS_ASSERTION(url != nsnull, "document has no uri");
00252         if (! url)
00253             return NS_ERROR_UNEXPECTED;
00254 
00255         // N.B. that if this fails (e.g., because necko doesn't grok
00256         // the protocol), uriStr will be untouched.
00257         NS_MakeAbsoluteURI(uri, uri, url);
00258 
00259         rv = gRDF->GetUnicodeResource(uri, aResult);
00260     }
00261     else {
00262         nsCOMPtr<nsIDOMXULElement> xulElem(do_QueryInterface(aElement, &rv));
00263         if (xulElem) {
00264             rv = xulElem->GetResource(aResult);
00265         }
00266     }
00267 
00268     return rv;
00269 }
00270 
00271 
00272 
00273 /*
00274        Note: this routine is similar, yet distinctly different from, nsBookmarksService::GetTextForNode
00275 */
00276 
00277 nsresult
00278 nsXULContentUtils::GetTextForNode(nsIRDFNode* aNode, nsAString& aResult)
00279 {
00280     if (! aNode) {
00281         aResult.Truncate();
00282         return NS_OK;
00283     }
00284 
00285     nsresult rv;
00286 
00287     // Literals are the most common, so try these first.
00288     nsCOMPtr<nsIRDFLiteral> literal = do_QueryInterface(aNode);
00289     if (literal) {
00290         const PRUnichar* p;
00291         rv = literal->GetValueConst(&p);
00292         if (NS_FAILED(rv)) return rv;
00293 
00294         aResult = p;
00295         return NS_OK;
00296     }
00297 
00298     nsCOMPtr<nsIRDFDate> dateLiteral = do_QueryInterface(aNode);
00299     if (dateLiteral) {
00300         PRInt64      value;
00301         rv = dateLiteral->GetValue(&value);
00302         if (NS_FAILED(rv)) return rv;
00303 
00304         nsAutoString str;
00305         rv = gFormat->FormatPRTime(nsnull /* nsILocale* locale */,
00306                                   kDateFormatShort,
00307                                   kTimeFormatSeconds,
00308                                   PRTime(value),
00309                                   str);
00310         aResult.Assign(str);
00311 
00312         if (NS_FAILED(rv)) return rv;
00313 
00314         return NS_OK;
00315     }
00316 
00317     nsCOMPtr<nsIRDFInt> intLiteral = do_QueryInterface(aNode);
00318     if (intLiteral) {
00319         PRInt32      value;
00320         rv = intLiteral->GetValue(&value);
00321         if (NS_FAILED(rv)) return rv;
00322 
00323         aResult.Truncate();
00324         nsAutoString intStr;
00325         intStr.AppendInt(value, 10);
00326         aResult.Append(intStr);
00327         return NS_OK;
00328     }
00329 
00330 
00331     nsCOMPtr<nsIRDFResource> resource = do_QueryInterface(aNode);
00332     if (resource) {
00333         const char* p;
00334         rv = resource->GetValueConst(&p);
00335         if (NS_FAILED(rv)) return rv;
00336         CopyUTF8toUTF16(p, aResult);
00337         return NS_OK;
00338     }
00339 
00340     NS_ERROR("not a resource or a literal");
00341     return NS_ERROR_UNEXPECTED;
00342 }
00343 
00344 nsresult
00345 nsXULContentUtils::MakeElementURI(nsIDocument* aDocument,
00346                                   const nsAString& aElementID,
00347                                   nsCString& aURI)
00348 {
00349     // Convert an element's ID to a URI that can be used to refer to
00350     // the element in the XUL graph.
00351 
00352     nsIURI *docURL = aDocument->GetDocumentURI();
00353     NS_ENSURE_TRUE(docURL, NS_ERROR_UNEXPECTED);
00354 
00355     nsCOMPtr<nsIURI> docURIClone;
00356     nsresult rv = docURL->Clone(getter_AddRefs(docURIClone));
00357     NS_ENSURE_SUCCESS(rv, rv);
00358 
00359     nsCOMPtr<nsIURL> mutableURL(do_QueryInterface(docURIClone));
00360     NS_ENSURE_TRUE(mutableURL, NS_ERROR_NOT_AVAILABLE);
00361 
00362     rv = mutableURL->SetRef(NS_ConvertUTF16toUTF8(aElementID));
00363     NS_ENSURE_SUCCESS(rv, rv);
00364 
00365     return mutableURL->GetSpec(aURI);
00366 }
00367 
00368 
00369 nsresult
00370 nsXULContentUtils::MakeElementResource(nsIDocument* aDocument, const nsAString& aID, nsIRDFResource** aResult)
00371 {
00372     nsresult rv;
00373 
00374     char buf[256];
00375     nsFixedCString uri(buf, sizeof(buf), 0);
00376     rv = MakeElementURI(aDocument, aID, uri);
00377     if (NS_FAILED(rv)) return rv;
00378 
00379     rv = gRDF->GetResource(uri, aResult);
00380     NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create resource");
00381     if (NS_FAILED(rv)) return rv;
00382 
00383     return NS_OK;
00384 }
00385 
00386 
00387 
00388 nsresult
00389 nsXULContentUtils::MakeElementID(nsIDocument* aDocument,
00390                                  const nsACString& aURI,
00391                                  nsAString& aElementID)
00392 {
00393     // Convert a URI into an element ID that can be accessed from the
00394     // DOM APIs.
00395     nsCOMPtr<nsIURI> uri;
00396     nsresult rv = NS_NewURI(getter_AddRefs(uri), aURI,
00397                             aDocument->GetDocumentCharacterSet().get());
00398     NS_ENSURE_SUCCESS(rv, rv);
00399 
00400     nsCOMPtr<nsIURL> url = do_QueryInterface(uri);
00401     if (url) {
00402         nsCAutoString ref;
00403         url->GetRef(ref);
00404         CopyUTF8toUTF16(ref, aElementID);
00405     } else {
00406         aElementID.Truncate();
00407     }
00408 
00409     return NS_OK;
00410 }
00411 
00412 nsresult
00413 nsXULContentUtils::GetResource(PRInt32 aNameSpaceID, nsIAtom* aAttribute, nsIRDFResource** aResult)
00414 {
00415     // construct a fully-qualified URI from the namespace/tag pair.
00416     NS_PRECONDITION(aAttribute != nsnull, "null ptr");
00417     if (! aAttribute)
00418         return NS_ERROR_NULL_POINTER;
00419 
00420     nsresult rv;
00421 
00422     nsAutoString attr;
00423     rv = aAttribute->ToString(attr);
00424     if (NS_FAILED(rv)) return rv;
00425 
00426     return GetResource(aNameSpaceID, attr, aResult);
00427 }
00428 
00429 
00430 nsresult
00431 nsXULContentUtils::GetResource(PRInt32 aNameSpaceID, const nsAString& aAttribute, nsIRDFResource** aResult)
00432 {
00433     // construct a fully-qualified URI from the namespace/tag pair.
00434 
00435     // XXX should we allow nodes with no namespace???
00436     //NS_PRECONDITION(aNameSpaceID != kNameSpaceID_Unknown, "no namespace");
00437     //if (aNameSpaceID == kNameSpaceID_Unknown)
00438     //    return NS_ERROR_UNEXPECTED;
00439 
00440     nsresult rv;
00441 
00442     PRUnichar buf[256];
00443     nsFixedString uri(buf, NS_ARRAY_LENGTH(buf), 0);
00444     if (aNameSpaceID != kNameSpaceID_Unknown && aNameSpaceID != kNameSpaceID_None) {
00445         rv = nsContentUtils::GetNSManagerWeakRef()->GetNameSpaceURI(aNameSpaceID, uri);
00446         // XXX ignore failure; treat as "no namespace"
00447     }
00448 
00449     // XXX check to see if we need to insert a '/' or a '#'. Oy.
00450     if (!uri.IsEmpty()  && uri.Last() != '#' && uri.Last() != '/' && aAttribute.First() != '#')
00451         uri.Append(PRUnichar('#'));
00452 
00453     uri.Append(aAttribute);
00454 
00455     rv = gRDF->GetUnicodeResource(uri, aResult);
00456     NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get resource");
00457     if (NS_FAILED(rv)) return rv;
00458 
00459     return NS_OK;
00460 }
00461 
00462 
00463 nsresult
00464 nsXULContentUtils::SetCommandUpdater(nsIDocument* aDocument, nsIContent* aElement)
00465 {
00466     // Deal with setting up a 'commandupdater'. Pulls the 'events' and
00467     // 'targets' attributes off of aElement, and adds it to the
00468     // document's command dispatcher.
00469     NS_PRECONDITION(aDocument != nsnull, "null ptr");
00470     if (! aDocument)
00471         return NS_ERROR_NULL_POINTER;
00472 
00473     NS_PRECONDITION(aElement != nsnull, "null ptr");
00474     if (! aElement)
00475         return NS_ERROR_NULL_POINTER;
00476 
00477     nsresult rv;
00478 
00479     nsCOMPtr<nsIDOMXULDocument> xuldoc = do_QueryInterface(aDocument);
00480     NS_ASSERTION(xuldoc != nsnull, "not a xul document");
00481     if (! xuldoc)
00482         return NS_ERROR_UNEXPECTED;
00483 
00484     nsCOMPtr<nsIDOMXULCommandDispatcher> dispatcher;
00485     rv = xuldoc->GetCommandDispatcher(getter_AddRefs(dispatcher));
00486     NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get dispatcher");
00487     if (NS_FAILED(rv)) return rv;
00488 
00489     NS_ASSERTION(dispatcher != nsnull, "no dispatcher");
00490     if (! dispatcher)
00491         return NS_ERROR_UNEXPECTED;
00492 
00493     nsAutoString events;
00494     rv = aElement->GetAttr(kNameSpaceID_None, nsXULAtoms::events, events);
00495 
00496     if (rv != NS_CONTENT_ATTR_HAS_VALUE)
00497         events.AssignLiteral("*");
00498 
00499     nsAutoString targets;
00500     rv = aElement->GetAttr(kNameSpaceID_None, nsXULAtoms::targets, targets);
00501 
00502     if (rv != NS_CONTENT_ATTR_HAS_VALUE)
00503         targets.AssignLiteral("*");
00504 
00505     nsCOMPtr<nsIDOMElement> domelement = do_QueryInterface(aElement);
00506     NS_ASSERTION(domelement != nsnull, "not a DOM element");
00507     if (! domelement)
00508         return NS_ERROR_UNEXPECTED;
00509 
00510     rv = dispatcher->AddCommandUpdater(domelement, events, targets);
00511     if (NS_FAILED(rv)) return rv;
00512 
00513     return NS_OK;
00514 }
00515 
00516