]>
Commit | Line | Data |
---|---|---|
2e0ae50e RD |
1 | #---------------------------------------------------------------------- |
2 | # Name: wx.tools.pywxrc | |
3 | # Purpose: XML resource compiler | |
4 | # | |
5 | # Author: Robin Dunn | |
6 | # Based on wxrc.cpp by Vaclav Slavik, Eduardo Marques | |
7 | # Ported to Python in order to not require yet another | |
8 | # binary in wxPython distributions | |
9 | # | |
10 | # RCS-ID: $Id$ | |
11 | # Copyright: (c) 2004 by Total Control Software, 2000 Vaclav Slavik | |
12 | # Licence: wxWindows license | |
13 | #---------------------------------------------------------------------- | |
14 | ||
15 | """ | |
16 | pywxrc -- XML resource compiler | |
17 | ||
18 | Usage: wxrc [-h] [-v] [-e] [-c] [-p] [-g] [-n <str>] [-o <str>] input file(s)... | |
19 | -h, --help show help message | |
20 | -v, --verbose be verbose | |
21 | -e, --extra-cpp-code output C++ header file with XRC derived classes | |
22 | -c, --cpp-code output C++ source rather than .xrs file | |
23 | -p, --python-code output wxPython source rather than .rsc file | |
24 | -g, --gettext output list of translatable strings (to stdout or file if -o used) | |
25 | -n, --function str C++/Python function name (with -c or -p) [InitXmlResource] | |
26 | -o, --output str output file [resource.xrs/cpp/py] | |
27 | """ | |
28 | ||
29 | import sys, os, getopt, glob | |
30 | import wx | |
31 | import wx.xrc | |
32 | ||
33 | ||
34 | #---------------------------------------------------------------------- | |
35 | ||
36 | class XRCWidgetData: | |
37 | def __init__(self, vname, vclass): | |
38 | self.name = vname | |
39 | self.klass = vclass | |
40 | def GetName(self): | |
41 | return self.name | |
42 | def GetClass(self): | |
43 | return self.klass | |
44 | ||
45 | ||
46 | #---------------------------------------------------------------------- | |
47 | ||
48 | class XRCWndClassData: | |
49 | def __init__(self, className, parentClassName, node): | |
50 | self.className = className | |
51 | self.parentClassName = parentClassName | |
52 | self.BrowseXmlNode(node.GetChildren()) | |
53 | self.wdata = [] | |
54 | ||
55 | ||
56 | def BrowseXmlNode(self, node): | |
57 | while node: | |
58 | if node.GetName() == "object" and node.HasProp("class") and node.HasProp("name"): | |
59 | classVal = node.GetPropVal("class", "") | |
60 | nameVal = node.GetPropVal("name", "") | |
61 | self.wdata.append(XRCWidgetData(nameVal, classVal)) | |
62 | children = node.GetChildren() | |
63 | if children: | |
64 | self.BrowseXmlNode(children) | |
65 | node = node.GetNext() | |
66 | ||
67 | ||
68 | def GetWidgetData(self): | |
69 | return self.wdata | |
70 | ||
71 | ||
72 | def IsRealClass(self, name): | |
73 | if name in ['tool', 'unknown', 'notebookpage', 'separator', | |
74 | 'sizeritem', 'wxMenuItem']: | |
75 | return False | |
76 | else: | |
77 | return True | |
78 | ||
79 | ||
80 | def GenerateHeaderCode(self, file): | |
81 | file.write("class %s : public %s {\nprotected:\n" % (self.className, self.parentClassName)) | |
82 | ||
83 | for w in self.wdata: | |
84 | if not self.IsRealClass(w.GetClass()): | |
85 | continue | |
86 | if not w.GetName(): | |
87 | continue | |
88 | file.write(" " + w.GetClass() + "* " + w.GetName() + ";\n") | |
89 | ||
90 | file.write("\nprivate:\n void InitWidgetsFromXRC(){\n", | |
91 | + " wxXmlResource::Get()->LoadObject(this,NULL,\"" | |
92 | + self.className | |
93 | + "\",\"" | |
94 | + self.parentClassName | |
95 | + "\");\n"); | |
96 | ||
97 | for w in self.wdata: | |
98 | if not self.IsRealClass(w.GetClass()): | |
99 | continue | |
100 | if not w.GetName(): | |
101 | continue | |
102 | file.write( " " | |
103 | + w.GetName() | |
104 | + " = XRCCTRL(*this,\"" | |
105 | + w.GetName() | |
106 | + "\"," | |
107 | + w.GetClass() | |
108 | + ");\n") | |
109 | ||
110 | file.write(" }\n") | |
111 | file.write("public:\n" | |
112 | + self.className | |
113 | + "::" | |
114 | + self.className | |
115 | + "(){\n" | |
116 | + " InitWidgetsFromXRC();\n" | |
117 | + " }\n" | |
118 | + "};\n") | |
119 | ||
120 | ||
121 | ||
122 | #---------------------------------------------------------------------- | |
123 | ||
124 | ||
125 | class XmlResApp: | |
126 | def __init__(self): | |
127 | self.flagVerbose = False | |
128 | self.flagCPP = False | |
129 | self.flagH = False | |
130 | self.flagPython = False | |
131 | self.flagGettext = False | |
132 | self.parOutput = "" | |
133 | self.parFuncname = "InitXmlResource" | |
134 | self.parFiles = [] | |
135 | self.aXRCWndClassData = [] | |
136 | ||
137 | ||
138 | #-------------------------------------------------- | |
139 | def main(self, args): | |
140 | try: | |
141 | opts, args = getopt.getopt(args, "hvecpgn:o:", | |
142 | "help verbose extra-cpp-code cpp-code python-code gettext function= output=".split()) | |
143 | except getopt.GetoptError: | |
144 | print __doc__ | |
145 | sys.exit(1) | |
146 | ||
147 | for opt, val in opts: | |
148 | if opt in ["-h", "--help"]: | |
149 | print __doc__ | |
150 | sys.exit(1) | |
151 | ||
152 | if opt in ["-v", "--verbose"]: | |
153 | self.flagVerbose = True | |
154 | ||
155 | if opt in ["-e", "--extra-cpp-code"]: | |
156 | self.flagH = True | |
157 | ||
158 | if opt in ["-c", "--cpp-code"]: | |
159 | self.flagCPP = True | |
160 | ||
161 | if opt in ["-p", "--python-code"]: | |
162 | self.flagPython = True | |
163 | ||
164 | if opt in ["-g", "--gettext"]: | |
165 | self.flagGettext = True | |
166 | ||
167 | if opt in ["-n", "--function"]: | |
168 | self.parFuncname = val | |
169 | ||
170 | if opt in ["-o", "--output"]: | |
171 | self.parOutput = val | |
172 | ||
173 | if self.flagCPP + self.flagPython + self.flagGettext == 0: | |
174 | print __doc__ | |
175 | print "\nYou must specify one of -c, -p or -g!\n" | |
176 | sys.exit(1) | |
177 | ||
178 | if self.flagCPP + self.flagPython + self.flagGettext > 1: | |
179 | print __doc__ | |
180 | print "\n-c, -p and -g are mutually exclusive, specify only 1!\n" | |
181 | sys.exit(1) | |
182 | ||
183 | ||
184 | if self.parOutput: | |
185 | self.parOutput = os.path.normpath(self.parOutput) | |
186 | self.parOutputPath = os.path.split(self.parOutput)[0] | |
187 | else: | |
188 | self.parOutputPath = "." | |
189 | if self.flagCPP: | |
190 | self.parOutput = "resource.cpp" | |
191 | elif self.flagPython: | |
192 | self.parOutput = "resource.py" | |
193 | elif self.flagGettext: | |
194 | self.parOutput = "" | |
195 | else: | |
196 | self.parOutput = "resource.xrs" | |
197 | ||
198 | if not args: | |
199 | print __doc__ | |
200 | sys.exit(1) | |
201 | for arg in args: | |
202 | self.parFiles += glob.glob(arg) | |
203 | ||
204 | self.retCode = 0 | |
205 | if self.flagGettext: | |
206 | self.OutputGettext() | |
207 | else: | |
208 | self.CompileRes() | |
209 | ||
210 | ||
211 | ||
212 | #-------------------------------------------------- | |
213 | def CompileRes(self): | |
214 | files = self.PrepareTempFiles() | |
215 | try: | |
216 | os.unlink(self.parOutput) | |
217 | except OSError: | |
218 | pass | |
219 | ||
220 | if not self.retCode: | |
221 | if self.flagCPP: | |
222 | self.MakePackageCPP(files) | |
223 | if self.flagH: | |
224 | self.GenCPPHeader() | |
225 | ||
226 | elif self.flagPython: | |
227 | self.MakePackagePython(files) | |
228 | ||
229 | else: | |
230 | self.MakePackageZIP(files) | |
231 | ||
232 | self.DeleteTempFiles(files) | |
233 | ||
234 | ||
235 | #-------------------------------------------------- | |
236 | def OutputGettext(self): | |
237 | pass | |
238 | ||
239 | ||
240 | #-------------------------------------------------- | |
241 | def GetInternalFileName(self, name, flist): | |
242 | name2 = name; | |
243 | name2 = name2.replace(":", "_") | |
244 | name2 = name2.replace("/", "_") | |
245 | name2 = name2.replace("\\", "_") | |
246 | name2 = name2.replace("*", "_") | |
247 | name2 = name2.replace("?", "_") | |
248 | ||
249 | s = os.path.split(self.parOutput)[1] + "$" + name2 | |
250 | ||
251 | if os.path.exists(s) and s not in flist: | |
252 | i = 0 | |
253 | while True: | |
254 | s = os.path.split(self.parOutput)[1] + ("$%s%03d" % (name2, i)) | |
255 | if not os.path.exists(s) or s in flist: | |
256 | break | |
257 | return s; | |
258 | ||
259 | ||
260 | #-------------------------------------------------- | |
261 | def PrepareTempFiles(self): | |
262 | flist = [] | |
263 | for f in self.parFiles: | |
264 | if self.flagVerbose: | |
265 | print "processing %s..." % f | |
266 | ||
267 | doc = wx.xrc.EmptyXmlDocument() | |
268 | ||
269 | if not doc.Load(f): | |
270 | print "Error parsing file", f | |
271 | self.retCode = 1 | |
272 | continue | |
273 | ||
274 | path, name = os.path.split(f) | |
275 | name, ext = os.path.splitext(name) | |
276 | ||
277 | self.FindFilesInXML(doc.GetRoot(), flist, path) | |
278 | if self.flagH: | |
279 | node = doc.GetRoot().GetChildren() | |
280 | while node: | |
281 | if node.GetName() == "object" and node.HasProp("class") and node.HasProp("name"): | |
282 | classVal = node.GetPropVal("class", "") | |
283 | nameVal = node.GetPropVal("name", "") | |
284 | self.aXRCWndClassData.append(XRCWidgetData(nameVal, classVal)) | |
285 | node = node.GetNext() | |
286 | internalName = self.GetInternalFileName(f, flist) | |
287 | ||
288 | doc.Save(os.path.join(self.parOutputPath, internalName)) | |
289 | flist.append(internalName) | |
290 | ||
291 | return flist | |
292 | ||
293 | ||
294 | #-------------------------------------------------- | |
295 | # Does 'node' contain filename information at all? | |
296 | def NodeContainsFilename(self, node): | |
297 | # Any bitmaps: | |
298 | if node.GetName() == "bitmap": | |
299 | return True | |
300 | ||
7aada1e0 RD |
301 | if node.GetName() == "icon": |
302 | return True | |
303 | ||
2e0ae50e RD |
304 | # URLs in wxHtmlWindow: |
305 | if node.GetName() == "url": | |
306 | return True | |
307 | ||
308 | # wxBitmapButton: | |
309 | parent = node.GetParent() | |
310 | if parent != None and \ | |
311 | parent.GetPropVal("class", "") == "wxBitmapButton" and \ | |
312 | (node.GetName() == "focus" or node.etName() == "disabled" or | |
313 | node.GetName() == "selected"): | |
314 | return True | |
315 | ||
316 | # wxBitmap or wxIcon toplevel resources: | |
317 | if node.GetName() == "object": | |
318 | klass = node.GetPropVal("class", "") | |
319 | if klass == "wxBitmap" or klass == "wxIcon": | |
320 | return True | |
321 | ||
322 | return False | |
323 | ||
324 | #-------------------------------------------------- | |
325 | # find all files mentioned in structure, e.g. <bitmap>filename</bitmap> | |
326 | def FindFilesInXML(self, node, flist, inputPath): | |
327 | # Is 'node' XML node element? | |
328 | if node is None: return | |
329 | if node.GetType() != wx.xrc.XML_ELEMENT_NODE: return | |
330 | ||
331 | containsFilename = self.NodeContainsFilename(node); | |
332 | ||
333 | n = node.GetChildren() | |
334 | while n: | |
335 | if (containsFilename and | |
336 | (n.GetType() == wx.xrc.XML_TEXT_NODE or | |
337 | n.GetType() == wx.xrc.XML_CDATA_SECTION_NODE)): | |
338 | ||
339 | if os.path.isabs(n.GetContent()) or inputPath == "": | |
340 | fullname = n.GetContent() | |
341 | else: | |
342 | fullname = os.path.join(inputPath, n.GetContent()) | |
343 | ||
344 | if self.flagVerbose: | |
345 | print "adding %s..." % fullname | |
346 | ||
347 | filename = self.GetInternalFileName(n.GetContent(), flist) | |
348 | n.SetContent(filename) | |
349 | ||
350 | if filename not in flist: | |
351 | flist.append(filename) | |
352 | ||
353 | inp = open(fullname) | |
354 | out = open(os.path.join(self.parOutputPath, filename), "w") | |
355 | out.write(inp.read()) | |
356 | ||
357 | # subnodes: | |
358 | if n.GetType() == wx.xrc.XML_ELEMENT_NODE: | |
359 | self.FindFilesInXML(n, flist, inputPath); | |
360 | ||
361 | n = n.GetNext() | |
362 | ||
363 | ||
364 | ||
365 | #-------------------------------------------------- | |
366 | def DeleteTempFiles(self, flist): | |
367 | for f in flist: | |
368 | os.unlink(os.path.join(self.parOutputPath, f)) | |
369 | ||
370 | ||
371 | #-------------------------------------------------- | |
372 | def MakePackageZIP(self, flist): | |
373 | files = " ".join(flist) | |
374 | ||
375 | if self.flagVerbose: | |
376 | print "compressing %s..." % self.parOutput | |
377 | ||
378 | cwd = os.getcwd() | |
379 | os.chdir(self.parOutputPath) | |
380 | cmd = "zip -9 -j " | |
381 | if not self.flagVerbose: | |
382 | cmd += "-q " | |
383 | cmd += self.parOutput + " " + files | |
384 | ||
385 | from distutils.spawn import spawn | |
386 | try: | |
387 | spawn(cmd.split()) | |
388 | success = True | |
389 | except: | |
390 | success = False | |
391 | ||
392 | os.chdir(cwd) | |
393 | ||
394 | if not success: | |
395 | print "Unable to execute zip program. Make sure it is in the path." | |
396 | print "You can download it at http://www.cdrom.com/pub/infozip/" | |
397 | self.retCode = 1 | |
398 | ||
399 | ||
400 | #-------------------------------------------------- | |
401 | def FileToCppArray(self, filename, num): | |
402 | output = [] | |
403 | buffer = open(filename, "rb").read() | |
404 | lng = len(buffer) | |
405 | ||
406 | output.append("static size_t xml_res_size_%d = %d;\n" % (num, lng)) | |
407 | output.append("static unsigned char xml_res_file_%d[] = {\n" % num) | |
408 | # we cannot use string literals because MSVC is dumb wannabe compiler | |
409 | # with arbitrary limitation to 2048 strings :( | |
410 | ||
411 | linelng = 0 | |
412 | for i in xrange(lng): | |
413 | tmp = "%i" % ord(buffer[i]) | |
414 | if i != 0: output.append(',') | |
415 | if linelng > 70: | |
416 | linelng = 0 | |
417 | output.append("\n") | |
418 | ||
419 | output.append(tmp) | |
420 | linelng += len(tmp)+1 | |
421 | ||
422 | output.append("};\n\n") | |
423 | ||
424 | return "".join(output) | |
425 | ||
426 | ||
427 | ||
428 | #-------------------------------------------------- | |
429 | def MakePackageCPP(self, flist): | |
430 | file = open(self.parOutput, "wt") | |
431 | ||
432 | if self.flagVerbose: | |
433 | print "creating C++ source file %s..." % self.parOutput | |
434 | ||
435 | file.write("""\ | |
436 | // | |
437 | // This file was automatically generated by wxrc, do not edit by hand. | |
438 | // | |
439 | ||
440 | #include <wx/wxprec.h> | |
441 | ||
442 | #ifdef __BORLANDC__ | |
443 | #pragma hdrstop | |
444 | #endif | |
445 | ||
446 | #ifndef WX_PRECOMP | |
447 | #include <wx/wx.h> | |
448 | #endif | |
449 | ||
450 | #include <wx/filesys.h> | |
451 | #include <wx/fs_mem.h> | |
452 | #include <wx/xrc/xmlres.h> | |
453 | #include <wx/xrc/xh_all.h> | |
454 | ||
455 | """) | |
456 | ||
457 | num = 0 | |
458 | for f in flist: | |
459 | file.write(self.FileToCppArray(os.path.join(self.parOutputPath, f), num)) | |
460 | num += 1 | |
461 | ||
462 | ||
463 | file.write("void " + self.parFuncname + "()\n") | |
464 | file.write("""\ | |
465 | { | |
466 | ||
467 | // Check for memory FS. If not present, load the handler: | |
468 | { | |
469 | wxMemoryFSHandler::AddFile(wxT(\"XRC_resource/dummy_file\"), wxT(\"dummy one\")); | |
470 | wxFileSystem fsys; | |
471 | wxFSFile *f = fsys.OpenFile(wxT(\"memory:XRC_resource/dummy_file\")); | |
472 | wxMemoryFSHandler::RemoveFile(wxT(\"XRC_resource/dummy_file\")); | |
473 | if (f) delete f; | |
474 | else wxFileSystem::AddHandler(new wxMemoryFSHandler); | |
475 | } | |
476 | """); | |
477 | ||
478 | for i in range(len(flist)): | |
479 | file.write(" wxMemoryFSHandler::AddFile(wxT(\"XRC_resource/" + flist[i]) | |
480 | file.write("\"), xml_res_file_%i, xml_res_size_%i);\n" %(i, i)) | |
481 | ||
482 | ||
483 | for i in range(len(self.parFiles)): | |
484 | file.write(" wxXmlResource::Get()->Load(wxT(\"memory:XRC_resource/" + | |
485 | self.GetInternalFileName(self.parFiles[i], flist) + | |
486 | "\"));\n") | |
487 | ||
488 | file.write("}\n") | |
489 | ||
490 | ||
491 | #-------------------------------------------------- | |
492 | def GenCPPHeader(self): | |
493 | path, name = os.path.split(self.parOutput) | |
494 | name, ext = os.path.splitext(name) | |
495 | heaFileName = name+'.h' | |
496 | ||
497 | file = open(heaFileName, "wt") | |
498 | file.write("""\ | |
499 | // | |
500 | // This file was automatically generated by wxrc, do not edit by hand. | |
501 | // | |
502 | """); | |
503 | file.write("#ifndef __" + name + "_h__\n") | |
504 | file.write("#define __" + name + "_h__\n") | |
505 | ||
506 | for data in self.aXRCWndClassData: | |
507 | data.GenerateHeaderCode(file) | |
508 | ||
509 | file.write("\nvoid \n" + self.parFuncname + "();\n#endif\n") | |
510 | ||
511 | ||
512 | #-------------------------------------------------- | |
513 | def FileToPythonArray(self, filename, num): | |
514 | output = [] | |
515 | buffer = open(filename, "rb").read() | |
516 | lng = len(buffer) | |
517 | ||
518 | output.append(" xml_res_file_%d = '''\\\n" % num) | |
519 | ||
520 | linelng = 0 | |
521 | for i in xrange(lng): | |
522 | s = buffer[i] | |
523 | c = ord(s) | |
524 | if s == '\n': | |
525 | tmp = s | |
526 | linelng = 0 | |
527 | elif c < 32 or c > 127 or s == "'": | |
528 | tmp = "\\x%02x" % c | |
529 | elif s == "\\": | |
530 | tmp = "\\\\" | |
531 | else: | |
532 | tmp = s | |
533 | ||
534 | if linelng > 70: | |
535 | linelng = 0 | |
536 | output.append("\\\n") | |
537 | ||
538 | output.append(tmp) | |
539 | linelng += len(tmp) | |
540 | ||
541 | output.append("'''\n\n") | |
542 | ||
543 | return "".join(output) | |
544 | ||
545 | #-------------------------------------------------- | |
546 | def MakePackagePython(self, flist): | |
547 | file = open(self.parOutput, "wt") | |
548 | ||
549 | if self.flagVerbose: | |
550 | print "creating Python source file %s..." % self.parOutput | |
551 | ||
552 | file.write("""\ | |
553 | # | |
554 | # This file was automatically generated by wxrc, do not edit by hand. | |
555 | # | |
556 | ||
557 | import wx | |
558 | import wx.xrc | |
559 | ||
560 | """) | |
561 | file.write("def " + self.parFuncname + "():\n") | |
562 | ||
563 | num = 0 | |
564 | for f in flist: | |
565 | file.write(self.FileToPythonArray(os.path.join(self.parOutputPath, f), num)) | |
566 | num += 1 | |
567 | ||
568 | file.write(""" | |
569 | ||
570 | # check if the memory filesystem handler has been loaded yet, and load it if not | |
571 | wx.MemoryFSHandler.AddFile('XRC_resource/dummy_file', 'dummy value') | |
572 | fsys = wx.FileSystem() | |
573 | f = fsys.OpenFile('memory:XRC_resource/dummy_file') | |
574 | wx.MemoryFSHandler.RemoveFile('XRC_resource/dummy_file') | |
575 | if f is not None: | |
576 | f.Destroy() | |
577 | else: | |
578 | wx.FileSystem.AddHandler(wx.MemoryFSHandler()) | |
579 | ||
580 | # load all the strings as memory files and load into XmlRes | |
581 | """) | |
582 | ||
583 | for i in range(len(flist)): | |
584 | file.write(" wx.MemoryFSHandler.AddFile('XRC_resource/" + flist[i] + | |
585 | "', xml_res_file_%i)\n" % i) | |
586 | ||
587 | for pf in self.parFiles: | |
588 | file.write(" wx.xrc.XmlResource.Get().Load('memory:XRC_resource/" + | |
589 | self.GetInternalFileName(pf, flist) + "')\n") | |
590 | ||
591 | ||
592 | #-------------------------------------------------- | |
593 | def OutputGettext(self): | |
594 | strings = self.FindStrings() | |
595 | ||
596 | if not self.parOutput: | |
597 | out = sys.stdout | |
598 | else: | |
599 | out = open(self.parOutput, "wt") | |
600 | ||
601 | for st in strings: | |
602 | out.write("_(\"%s\")\n" % st) | |
603 | ||
604 | ||
605 | ||
606 | #-------------------------------------------------- | |
607 | def FindStrings(self): | |
608 | strings = [] | |
609 | for pf in self.parFiles: | |
610 | if self.flagVerbose: | |
611 | print "processing %s..." % pf | |
612 | ||
613 | doc = wx.xrc.EmptyXmlDocument() | |
614 | if not doc.Load(pf): | |
615 | print "Error parsing file", pf | |
616 | self.retCode = 1 | |
617 | continue | |
618 | ||
619 | strings += self.FindStringsInNode(doc.GetRoot()) | |
620 | ||
621 | return strings | |
622 | ||
623 | ||
624 | #-------------------------------------------------- | |
625 | def ConvertText(self, st): | |
626 | st2 = "" | |
627 | dt = list(st) | |
628 | ||
629 | skipNext = False | |
630 | for i in range(len(dt)): | |
631 | if skipNext: | |
632 | skipNext = False | |
633 | continue | |
634 | ||
635 | if dt[i] == '_': | |
636 | if dt[i+1] == '_': | |
637 | st2 += '_' | |
638 | skipNext = True | |
639 | else: | |
640 | st2 += '&' | |
641 | elif dt[i] == '\n': | |
642 | st2 += '\\n' | |
643 | elif dt[i] == '\t': | |
644 | st2 += '\\t' | |
645 | elif dt[i] == '\r': | |
646 | st2 += '\\r' | |
647 | elif dt[i] == '\\': | |
648 | if dt[i+1] not in ['n', 't', 'r']: | |
649 | st2 += '\\\\' | |
650 | else: | |
651 | st2 += '\\' | |
652 | elif dt[i] == '"': | |
653 | st2 += '\\"' | |
654 | else: | |
655 | st2 += dt[i] | |
656 | ||
657 | return st2 | |
658 | ||
659 | ||
660 | ||
661 | #-------------------------------------------------- | |
662 | def FindStringsInNode(self, parent): | |
663 | def is_number(st): | |
664 | try: | |
665 | i = int(st) | |
666 | return True | |
667 | except ValueError: | |
668 | return False | |
669 | ||
670 | strings = [] | |
671 | if parent is None: | |
672 | return strings; | |
673 | child = parent.GetChildren() | |
674 | ||
675 | while child: | |
676 | if ((parent.GetType() == wx.xrc.XML_ELEMENT_NODE) and | |
677 | # parent is an element, i.e. has subnodes... | |
678 | (child.GetType() == wx.xrc.XML_TEXT_NODE or | |
679 | child.GetType() == wx.xrc.XML_CDATA_SECTION_NODE) and | |
680 | # ...it is textnode... | |
681 | ( | |
682 | parent.GetName() == "label" or | |
683 | (parent.GetName() == "value" and | |
684 | not is_number(child.GetContent())) or | |
685 | parent.GetName() == "help" or | |
686 | parent.GetName() == "longhelp" or | |
687 | parent.GetName() == "tooltip" or | |
688 | parent.GetName() == "htmlcode" or | |
689 | parent.GetName() == "title" or | |
690 | parent.GetName() == "item" | |
691 | )): | |
692 | # ...and known to contain translatable string | |
693 | if (not self.flagGettext or | |
694 | parent.GetPropVal("translate", "1") != "0"): | |
695 | ||
696 | strings.append(self.ConvertText(child.GetContent())) | |
697 | ||
698 | # subnodes: | |
699 | if child.GetType() == wx.xrc.XML_ELEMENT_NODE: | |
700 | strings += self.FindStringsInNode(child) | |
701 | ||
702 | child = child.GetNext() | |
703 | ||
704 | return strings | |
705 | ||
706 | #--------------------------------------------------------------------------- | |
707 | ||
708 | def main(): | |
709 | XmlResApp().main(sys.argv[1:]) | |
710 | ||
711 | ||
712 | if __name__ == "__main__": | |
713 | main() | |
714 |