content/xul/templates/src/nsXULContentUtils.cpp

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

mercurial