1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : *
3 : * ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Mozilla Communicator client code.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Netscape Communications Corporation.
20 : * Portions created by the Initial Developer are Copyright (C) 1998
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK *****
38 : *
39 : *
40 : * This Original Code has been modified by IBM Corporation.
41 : * Modifications made by IBM described herein are
42 : * Copyright (c) International Business Machines
43 : * Corporation, 2000
44 : *
45 : * Modifications to Mozilla code or documentation
46 : * identified per MPL Section 3.3
47 : *
48 : * Date Modified by Description of modification
49 : * 03/27/2000 IBM Corp. Added PR_CALLBACK for Optlink
50 : * use in OS2
51 : */
52 :
53 :
54 : /*
55 :
56 : A package of routines shared by the XUL content code.
57 :
58 : */
59 :
60 : #include "mozilla/Util.h"
61 :
62 : #include "nsCOMPtr.h"
63 : #include "nsIContent.h"
64 : #include "nsINodeInfo.h"
65 : #include "nsIDocument.h"
66 : #include "nsIDOMElement.h"
67 : #include "nsIDOMXULCommandDispatcher.h"
68 : #include "nsIDOMXULDocument.h"
69 : #include "nsIRDFNode.h"
70 : #include "nsINameSpaceManager.h"
71 : #include "nsIRDFService.h"
72 : #include "nsIServiceManager.h"
73 : #include "nsIURL.h"
74 : #include "nsXULContentUtils.h"
75 : #include "nsLayoutCID.h"
76 : #include "nsNetUtil.h"
77 : #include "nsRDFCID.h"
78 : #include "nsString.h"
79 : #include "nsXPIDLString.h"
80 : #include "nsGkAtoms.h"
81 : #include "prlog.h"
82 : #include "prtime.h"
83 : #include "rdf.h"
84 : #include "nsContentUtils.h"
85 : #include "nsIDateTimeFormat.h"
86 : #include "nsDateTimeFormatCID.h"
87 : #include "nsIScriptableDateFormat.h"
88 : #include "nsICollation.h"
89 : #include "nsCollationCID.h"
90 : #include "nsILocale.h"
91 : #include "nsILocaleService.h"
92 : #include "nsIConsoleService.h"
93 : #include "nsEscape.h"
94 :
95 : using namespace mozilla;
96 :
97 : static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
98 :
99 : //------------------------------------------------------------------------
100 :
101 : nsIRDFService* nsXULContentUtils::gRDF;
102 : nsIDateTimeFormat* nsXULContentUtils::gFormat;
103 : nsICollation *nsXULContentUtils::gCollation;
104 :
105 : #ifdef PR_LOGGING
106 : extern PRLogModuleInfo* gXULTemplateLog;
107 : #endif
108 :
109 : #define XUL_RESOURCE(ident, uri) nsIRDFResource* nsXULContentUtils::ident
110 : #define XUL_LITERAL(ident, val) nsIRDFLiteral* nsXULContentUtils::ident
111 : #include "nsXULResourceList.h"
112 : #undef XUL_RESOURCE
113 : #undef XUL_LITERAL
114 :
115 : //------------------------------------------------------------------------
116 : // Constructors n' stuff
117 : //
118 :
119 : nsresult
120 1404 : nsXULContentUtils::Init()
121 : {
122 1404 : nsresult rv = CallGetService(kRDFServiceCID, &gRDF);
123 1404 : if (NS_FAILED(rv)) {
124 0 : return rv;
125 : }
126 :
127 : #define XUL_RESOURCE(ident, uri) \
128 : PR_BEGIN_MACRO \
129 : rv = gRDF->GetResource(NS_LITERAL_CSTRING(uri), &(ident)); \
130 : if (NS_FAILED(rv)) return rv; \
131 : PR_END_MACRO
132 :
133 : #define XUL_LITERAL(ident, val) \
134 : PR_BEGIN_MACRO \
135 : rv = gRDF->GetLiteral(NS_LITERAL_STRING(val).get(), &(ident)); \
136 : if (NS_FAILED(rv)) return rv; \
137 : PR_END_MACRO
138 :
139 : #include "nsXULResourceList.h"
140 : #undef XUL_RESOURCE
141 : #undef XUL_LITERAL
142 :
143 1404 : rv = CallCreateInstance(NS_DATETIMEFORMAT_CONTRACTID, &gFormat);
144 1404 : if (NS_FAILED(rv)) {
145 0 : return rv;
146 : }
147 :
148 1404 : return NS_OK;
149 : }
150 :
151 :
152 : nsresult
153 1403 : nsXULContentUtils::Finish()
154 : {
155 1403 : NS_IF_RELEASE(gRDF);
156 :
157 : #define XUL_RESOURCE(ident, uri) NS_IF_RELEASE(ident)
158 : #define XUL_LITERAL(ident, val) NS_IF_RELEASE(ident)
159 : #include "nsXULResourceList.h"
160 : #undef XUL_RESOURCE
161 : #undef XUL_LITERAL
162 :
163 1403 : NS_IF_RELEASE(gFormat);
164 1403 : NS_IF_RELEASE(gCollation);
165 :
166 1403 : return NS_OK;
167 : }
168 :
169 : nsICollation*
170 0 : nsXULContentUtils::GetCollation()
171 : {
172 0 : if (!gCollation) {
173 : nsresult rv;
174 :
175 : // get a locale service
176 : nsCOMPtr<nsILocaleService> localeService =
177 0 : do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
178 0 : if (NS_SUCCEEDED(rv)) {
179 0 : nsCOMPtr<nsILocale> locale;
180 0 : rv = localeService->GetApplicationLocale(getter_AddRefs(locale));
181 0 : if (NS_SUCCEEDED(rv) && locale) {
182 : nsCOMPtr<nsICollationFactory> colFactory =
183 0 : do_CreateInstance(NS_COLLATIONFACTORY_CONTRACTID);
184 0 : if (colFactory) {
185 0 : rv = colFactory->CreateCollation(locale, &gCollation);
186 0 : NS_ASSERTION(NS_SUCCEEDED(rv),
187 : "couldn't create collation instance");
188 : } else
189 0 : NS_ERROR("couldn't create instance of collation factory");
190 : } else
191 0 : NS_ERROR("unable to get application locale");
192 : } else
193 0 : NS_ERROR("couldn't get locale factory");
194 : }
195 :
196 0 : return gCollation;
197 : }
198 :
199 : //------------------------------------------------------------------------
200 :
201 : nsresult
202 0 : nsXULContentUtils::FindChildByTag(nsIContent* aElement,
203 : PRInt32 aNameSpaceID,
204 : nsIAtom* aTag,
205 : nsIContent** aResult)
206 : {
207 0 : for (nsIContent* child = aElement->GetFirstChild();
208 : child;
209 0 : child = child->GetNextSibling()) {
210 :
211 0 : if (child->NodeInfo()->Equals(aTag, aNameSpaceID)) {
212 0 : NS_ADDREF(*aResult = child);
213 :
214 0 : return NS_OK;
215 : }
216 : }
217 :
218 0 : *aResult = nsnull;
219 0 : return NS_RDF_NO_VALUE; // not found
220 : }
221 :
222 :
223 : nsresult
224 0 : nsXULContentUtils::GetElementResource(nsIContent* aElement, nsIRDFResource** aResult)
225 : {
226 : // Perform a reverse mapping from an element in the content model
227 : // to an RDF resource.
228 : nsresult rv;
229 :
230 : PRUnichar buf[128];
231 0 : nsFixedString id(buf, ArrayLength(buf), 0);
232 :
233 : // Whoa. Why the "id" attribute? What if it's not even a XUL
234 : // element? This is totally bogus!
235 0 : aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::id, id);
236 0 : if (id.IsEmpty())
237 0 : return NS_ERROR_FAILURE;
238 :
239 : // Since the element will store its ID attribute as a document-relative value,
240 : // we may need to qualify it first...
241 0 : nsCOMPtr<nsIDocument> doc = aElement->GetDocument();
242 0 : NS_ASSERTION(doc, "element is not in any document");
243 0 : if (! doc)
244 0 : return NS_ERROR_FAILURE;
245 :
246 0 : rv = nsXULContentUtils::MakeElementResource(doc, id, aResult);
247 0 : if (NS_FAILED(rv)) return rv;
248 :
249 0 : return NS_OK;
250 : }
251 :
252 :
253 : /*
254 : Note: this routine is similar, yet distinctly different from, nsBookmarksService::GetTextForNode
255 : */
256 :
257 : nsresult
258 0 : nsXULContentUtils::GetTextForNode(nsIRDFNode* aNode, nsAString& aResult)
259 : {
260 0 : if (! aNode) {
261 0 : aResult.Truncate();
262 0 : return NS_OK;
263 : }
264 :
265 : nsresult rv;
266 :
267 : // Literals are the most common, so try these first.
268 0 : nsCOMPtr<nsIRDFLiteral> literal = do_QueryInterface(aNode);
269 0 : if (literal) {
270 : const PRUnichar* p;
271 0 : rv = literal->GetValueConst(&p);
272 0 : if (NS_FAILED(rv)) return rv;
273 :
274 0 : aResult = p;
275 0 : return NS_OK;
276 : }
277 :
278 0 : nsCOMPtr<nsIRDFDate> dateLiteral = do_QueryInterface(aNode);
279 0 : if (dateLiteral) {
280 : PRInt64 value;
281 0 : rv = dateLiteral->GetValue(&value);
282 0 : if (NS_FAILED(rv)) return rv;
283 :
284 0 : nsAutoString str;
285 : rv = gFormat->FormatPRTime(nsnull /* nsILocale* locale */,
286 : kDateFormatShort,
287 : kTimeFormatSeconds,
288 : PRTime(value),
289 0 : str);
290 0 : aResult.Assign(str);
291 :
292 0 : if (NS_FAILED(rv)) return rv;
293 :
294 0 : return NS_OK;
295 : }
296 :
297 0 : nsCOMPtr<nsIRDFInt> intLiteral = do_QueryInterface(aNode);
298 0 : if (intLiteral) {
299 : PRInt32 value;
300 0 : rv = intLiteral->GetValue(&value);
301 0 : if (NS_FAILED(rv)) return rv;
302 :
303 0 : aResult.Truncate();
304 0 : nsAutoString intStr;
305 0 : intStr.AppendInt(value, 10);
306 0 : aResult.Append(intStr);
307 0 : return NS_OK;
308 : }
309 :
310 :
311 0 : nsCOMPtr<nsIRDFResource> resource = do_QueryInterface(aNode);
312 0 : if (resource) {
313 : const char* p;
314 0 : rv = resource->GetValueConst(&p);
315 0 : if (NS_FAILED(rv)) return rv;
316 0 : CopyUTF8toUTF16(p, aResult);
317 0 : return NS_OK;
318 : }
319 :
320 0 : NS_ERROR("not a resource or a literal");
321 0 : return NS_ERROR_UNEXPECTED;
322 : }
323 :
324 : nsresult
325 0 : nsXULContentUtils::MakeElementURI(nsIDocument* aDocument,
326 : const nsAString& aElementID,
327 : nsCString& aURI)
328 : {
329 : // Convert an element's ID to a URI that can be used to refer to
330 : // the element in the XUL graph.
331 :
332 0 : nsIURI *docURI = aDocument->GetDocumentURI();
333 0 : NS_ENSURE_TRUE(docURI, NS_ERROR_UNEXPECTED);
334 :
335 0 : nsRefPtr<nsIURI> docURIClone;
336 0 : nsresult rv = docURI->Clone(getter_AddRefs(docURIClone));
337 0 : NS_ENSURE_SUCCESS(rv, rv);
338 :
339 0 : rv = docURIClone->SetRef(NS_ConvertUTF16toUTF8(aElementID));
340 0 : if (NS_SUCCEEDED(rv)) {
341 0 : return docURIClone->GetSpec(aURI);
342 : }
343 :
344 : // docURIClone is apparently immutable. Fine - we can append ref manually.
345 0 : rv = docURI->GetSpec(aURI);
346 0 : NS_ENSURE_SUCCESS(rv, rv);
347 :
348 0 : nsCAutoString ref;
349 0 : NS_EscapeURL(NS_ConvertUTF16toUTF8(aElementID), esc_FilePath | esc_AlwaysCopy, ref);
350 :
351 0 : aURI.Append('#');
352 0 : aURI.Append(ref);
353 :
354 0 : return NS_OK;
355 : }
356 :
357 :
358 : nsresult
359 0 : nsXULContentUtils::MakeElementResource(nsIDocument* aDocument, const nsAString& aID, nsIRDFResource** aResult)
360 : {
361 : nsresult rv;
362 :
363 : char buf[256];
364 0 : nsFixedCString uri(buf, sizeof(buf), 0);
365 0 : rv = MakeElementURI(aDocument, aID, uri);
366 0 : if (NS_FAILED(rv)) return rv;
367 :
368 0 : rv = gRDF->GetResource(uri, aResult);
369 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create resource");
370 0 : if (NS_FAILED(rv)) return rv;
371 :
372 0 : return NS_OK;
373 : }
374 :
375 :
376 :
377 : nsresult
378 0 : nsXULContentUtils::MakeElementID(nsIDocument* aDocument,
379 : const nsACString& aURI,
380 : nsAString& aElementID)
381 : {
382 : // Convert a URI into an element ID that can be accessed from the
383 : // DOM APIs.
384 0 : nsCOMPtr<nsIURI> uri;
385 0 : nsresult rv = NS_NewURI(getter_AddRefs(uri), aURI,
386 0 : aDocument->GetDocumentCharacterSet().get());
387 0 : NS_ENSURE_SUCCESS(rv, rv);
388 :
389 0 : nsCAutoString ref;
390 0 : uri->GetRef(ref);
391 0 : CopyUTF8toUTF16(ref, aElementID);
392 :
393 0 : return NS_OK;
394 : }
395 :
396 : nsresult
397 0 : nsXULContentUtils::GetResource(PRInt32 aNameSpaceID, nsIAtom* aAttribute, nsIRDFResource** aResult)
398 : {
399 : // construct a fully-qualified URI from the namespace/tag pair.
400 0 : NS_PRECONDITION(aAttribute != nsnull, "null ptr");
401 0 : if (! aAttribute)
402 0 : return NS_ERROR_NULL_POINTER;
403 :
404 0 : return GetResource(aNameSpaceID, nsDependentAtomString(aAttribute),
405 0 : aResult);
406 : }
407 :
408 :
409 : nsresult
410 0 : nsXULContentUtils::GetResource(PRInt32 aNameSpaceID, const nsAString& aAttribute, nsIRDFResource** aResult)
411 : {
412 : // construct a fully-qualified URI from the namespace/tag pair.
413 :
414 : // XXX should we allow nodes with no namespace???
415 : //NS_PRECONDITION(aNameSpaceID != kNameSpaceID_Unknown, "no namespace");
416 : //if (aNameSpaceID == kNameSpaceID_Unknown)
417 : // return NS_ERROR_UNEXPECTED;
418 :
419 : nsresult rv;
420 :
421 : PRUnichar buf[256];
422 0 : nsFixedString uri(buf, ArrayLength(buf), 0);
423 0 : if (aNameSpaceID != kNameSpaceID_Unknown && aNameSpaceID != kNameSpaceID_None) {
424 0 : rv = nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID, uri);
425 : // XXX ignore failure; treat as "no namespace"
426 : }
427 :
428 : // XXX check to see if we need to insert a '/' or a '#'. Oy.
429 0 : if (!uri.IsEmpty() && uri.Last() != '#' && uri.Last() != '/' && aAttribute.First() != '#')
430 0 : uri.Append(PRUnichar('#'));
431 :
432 0 : uri.Append(aAttribute);
433 :
434 0 : rv = gRDF->GetUnicodeResource(uri, aResult);
435 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get resource");
436 0 : if (NS_FAILED(rv)) return rv;
437 :
438 0 : return NS_OK;
439 : }
440 :
441 :
442 : nsresult
443 0 : nsXULContentUtils::SetCommandUpdater(nsIDocument* aDocument, nsIContent* aElement)
444 : {
445 : // Deal with setting up a 'commandupdater'. Pulls the 'events' and
446 : // 'targets' attributes off of aElement, and adds it to the
447 : // document's command dispatcher.
448 0 : NS_PRECONDITION(aDocument != nsnull, "null ptr");
449 0 : if (! aDocument)
450 0 : return NS_ERROR_NULL_POINTER;
451 :
452 0 : NS_PRECONDITION(aElement != nsnull, "null ptr");
453 0 : if (! aElement)
454 0 : return NS_ERROR_NULL_POINTER;
455 :
456 : nsresult rv;
457 :
458 0 : nsCOMPtr<nsIDOMXULDocument> xuldoc = do_QueryInterface(aDocument);
459 0 : NS_ASSERTION(xuldoc != nsnull, "not a xul document");
460 0 : if (! xuldoc)
461 0 : return NS_ERROR_UNEXPECTED;
462 :
463 0 : nsCOMPtr<nsIDOMXULCommandDispatcher> dispatcher;
464 0 : rv = xuldoc->GetCommandDispatcher(getter_AddRefs(dispatcher));
465 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get dispatcher");
466 0 : if (NS_FAILED(rv)) return rv;
467 :
468 0 : NS_ASSERTION(dispatcher != nsnull, "no dispatcher");
469 0 : if (! dispatcher)
470 0 : return NS_ERROR_UNEXPECTED;
471 :
472 0 : nsAutoString events;
473 0 : aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::events, events);
474 0 : if (events.IsEmpty())
475 0 : events.AssignLiteral("*");
476 :
477 0 : nsAutoString targets;
478 0 : aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::targets, targets);
479 :
480 0 : if (targets.IsEmpty())
481 0 : targets.AssignLiteral("*");
482 :
483 0 : nsCOMPtr<nsIDOMElement> domelement = do_QueryInterface(aElement);
484 0 : NS_ASSERTION(domelement != nsnull, "not a DOM element");
485 0 : if (! domelement)
486 0 : return NS_ERROR_UNEXPECTED;
487 :
488 0 : rv = dispatcher->AddCommandUpdater(domelement, events, targets);
489 0 : if (NS_FAILED(rv)) return rv;
490 :
491 0 : return NS_OK;
492 : }
493 :
494 : void
495 0 : nsXULContentUtils::LogTemplateError(const char* aStr)
496 : {
497 0 : nsAutoString message;
498 0 : message.AssignLiteral("Error parsing template: ");
499 0 : message.Append(NS_ConvertUTF8toUTF16(aStr).get());
500 :
501 0 : nsCOMPtr<nsIConsoleService> cs = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
502 0 : if (cs) {
503 0 : cs->LogStringMessage(message.get());
504 0 : PR_LOG(gXULTemplateLog, PR_LOG_ALWAYS, ("Error parsing template: %s", aStr));
505 : }
506 0 : }
|