|
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 } |