]>
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 | ||
301 | # URLs in wxHtmlWindow: | |
302 | if node.GetName() == "url": | |
303 | return True | |
304 | ||
305 | # wxBitmapButton: | |
306 | parent = node.GetParent() | |
307 | if parent != None and \ | |
308 | parent.GetPropVal("class", "") == "wxBitmapButton" and \ | |
309 | (node.GetName() == "focus" or node.etName() == "disabled" or | |
310 | node.GetName() == "selected"): | |
311 | return True | |
312 | ||
313 | # wxBitmap or wxIcon toplevel resources: | |
314 | if node.GetName() == "object": | |
315 | klass = node.GetPropVal("class", "") | |
316 | if klass == "wxBitmap" or klass == "wxIcon": | |
317 | return True | |
318 | ||
319 | return False | |
320 | ||
321 | #-------------------------------------------------- | |
322 | # find all files mentioned in structure, e.g. <bitmap>filename</bitmap> | |
323 | def FindFilesInXML(self, node, flist, inputPath): | |
324 | # Is 'node' XML node element? | |
325 | if node is None: return | |
326 | if node.GetType() != wx.xrc.XML_ELEMENT_NODE: return | |
327 | ||
328 | containsFilename = self.NodeContainsFilename(node); | |
329 | ||
330 | n = node.GetChildren() | |
331 | while n: | |
332 | if (containsFilename and | |
333 | (n.GetType() == wx.xrc.XML_TEXT_NODE or | |
334 | n.GetType() == wx.xrc.XML_CDATA_SECTION_NODE)): | |
335 | ||
336 | if os.path.isabs(n.GetContent()) or inputPath == "": | |
337 | fullname = n.GetContent() | |
338 | else: | |
339 | fullname = os.path.join(inputPath, n.GetContent()) | |
340 | ||
341 | if self.flagVerbose: | |
342 | print "adding %s..." % fullname | |
343 | ||
344 | filename = self.GetInternalFileName(n.GetContent(), flist) | |
345 | n.SetContent(filename) | |
346 | ||
347 | if filename not in flist: | |
348 | flist.append(filename) | |
349 | ||
350 | inp = open(fullname) | |
351 | out = open(os.path.join(self.parOutputPath, filename), "w") | |
352 | out.write(inp.read()) | |
353 | ||
354 | # subnodes: | |
355 | if n.GetType() == wx.xrc.XML_ELEMENT_NODE: | |
356 | self.FindFilesInXML(n, flist, inputPath); | |
357 | ||
358 | n = n.GetNext() | |
359 | ||
360 | ||
361 | ||
362 | #-------------------------------------------------- | |
363 | def DeleteTempFiles(self, flist): | |
364 | for f in flist: | |
365 | os.unlink(os.path.join(self.parOutputPath, f)) | |
366 | ||
367 | ||
368 | #-------------------------------------------------- | |
369 | def MakePackageZIP(self, flist): | |
370 | files = " ".join(flist) | |
371 | ||
372 | if self.flagVerbose: | |
373 | print "compressing %s..." % self.parOutput | |
374 | ||
375 | cwd = os.getcwd() | |
376 | os.chdir(self.parOutputPath) | |
377 | cmd = "zip -9 -j " | |
378 | if not self.flagVerbose: | |
379 | cmd += "-q " | |
380 | cmd += self.parOutput + " " + files | |
381 | ||
382 | from distutils.spawn import spawn | |
383 | try: | |
384 | spawn(cmd.split()) | |
385 | success = True | |
386 | except: | |
387 | success = False | |
388 | ||
389 | os.chdir(cwd) | |
390 | ||
391 | if not success: | |
392 | print "Unable to execute zip program. Make sure it is in the path." | |
393 | print "You can download it at http://www.cdrom.com/pub/infozip/" | |
394 | self.retCode = 1 | |
395 | ||
396 | ||
397 | #-------------------------------------------------- | |
398 | def FileToCppArray(self, filename, num): | |
399 | output = [] | |
400 | buffer = open(filename, "rb").read() | |
401 | lng = len(buffer) | |
402 | ||
403 | output.append("static size_t xml_res_size_%d = %d;\n" % (num, lng)) | |
404 | output.append("static unsigned char xml_res_file_%d[] = {\n" % num) | |
405 | # we cannot use string literals because MSVC is dumb wannabe compiler | |
406 | # with arbitrary limitation to 2048 strings :( | |
407 | ||
408 | linelng = 0 | |
409 | for i in xrange(lng): | |
410 | tmp = "%i" % ord(buffer[i]) | |
411 | if i != 0: output.append(',') | |
412 | if linelng > 70: | |
413 | linelng = 0 | |
414 | output.append("\n") | |
415 | ||
416 | output.append(tmp) | |
417 | linelng += len(tmp)+1 | |
418 | ||
419 | output.append("};\n\n") | |
420 | ||
421 | return "".join(output) | |
422 | ||
423 | ||
424 | ||
425 | #-------------------------------------------------- | |
426 | def MakePackageCPP(self, flist): | |
427 | file = open(self.parOutput, "wt") | |
428 | ||
429 | if self.flagVerbose: | |
430 | print "creating C++ source file %s..." % self.parOutput | |
431 | ||
432 | file.write("""\ | |
433 | // | |
434 | // This file was automatically generated by wxrc, do not edit by hand. | |
435 | // | |
436 | ||
437 | #include <wx/wxprec.h> | |
438 | ||
439 | #ifdef __BORLANDC__ | |
440 | #pragma hdrstop | |
441 | #endif | |
442 | ||
443 | #ifndef WX_PRECOMP | |
444 | #include <wx/wx.h> | |
445 | #endif | |
446 | ||
447 | #include <wx/filesys.h> | |
448 | #include <wx/fs_mem.h> | |
449 | #include <wx/xrc/xmlres.h> | |
450 | #include <wx/xrc/xh_all.h> | |
451 | ||
452 | """) | |
453 | ||
454 | num = 0 | |
455 | for f in flist: | |
456 | file.write(self.FileToCppArray(os.path.join(self.parOutputPath, f), num)) | |
457 | num += 1 | |
458 | ||
459 | ||
460 | file.write("void " + self.parFuncname + "()\n") | |
461 | file.write("""\ | |
462 | { | |
463 | ||
464 | // Check for memory FS. If not present, load the handler: | |
465 | { | |
466 | wxMemoryFSHandler::AddFile(wxT(\"XRC_resource/dummy_file\"), wxT(\"dummy one\")); | |
467 | wxFileSystem fsys; | |
468 | wxFSFile *f = fsys.OpenFile(wxT(\"memory:XRC_resource/dummy_file\")); | |
469 | wxMemoryFSHandler::RemoveFile(wxT(\"XRC_resource/dummy_file\")); | |
470 | if (f) delete f; | |
471 | else wxFileSystem::AddHandler(new wxMemoryFSHandler); | |
472 | } | |
473 | """); | |
474 | ||
475 | for i in range(len(flist)): | |
476 | file.write(" wxMemoryFSHandler::AddFile(wxT(\"XRC_resource/" + flist[i]) | |
477 | file.write("\"), xml_res_file_%i, xml_res_size_%i);\n" %(i, i)) | |
478 | ||
479 | ||
480 | for i in range(len(self.parFiles)): | |
481 | file.write(" wxXmlResource::Get()->Load(wxT(\"memory:XRC_resource/" + | |
482 | self.GetInternalFileName(self.parFiles[i], flist) + | |
483 | "\"));\n") | |
484 | ||
485 | file.write("}\n") | |
486 | ||
487 | ||
488 | #-------------------------------------------------- | |
489 | def GenCPPHeader(self): | |
490 | path, name = os.path.split(self.parOutput) | |
491 | name, ext = os.path.splitext(name) | |
492 | heaFileName = name+'.h' | |
493 | ||
494 | file = open(heaFileName, "wt") | |
495 | file.write("""\ | |
496 | // | |
497 | // This file was automatically generated by wxrc, do not edit by hand. | |
498 | // | |
499 | """); | |
500 | file.write("#ifndef __" + name + "_h__\n") | |
501 | file.write("#define __" + name + "_h__\n") | |
502 | ||
503 | for data in self.aXRCWndClassData: | |
504 | data.GenerateHeaderCode(file) | |
505 | ||
506 | file.write("\nvoid \n" + self.parFuncname + "();\n#endif\n") | |
507 | ||
508 | ||
509 | #-------------------------------------------------- | |
510 | def FileToPythonArray(self, filename, num): | |
511 | output = [] | |
512 | buffer = open(filename, "rb").read() | |
513 | lng = len(buffer) | |
514 | ||
515 | output.append(" xml_res_file_%d = '''\\\n" % num) | |
516 | ||
517 | linelng = 0 | |
518 | for i in xrange(lng): | |
519 | s = buffer[i] | |
520 | c = ord(s) | |
521 | if s == '\n': | |
522 | tmp = s | |
523 | linelng = 0 | |
524 | elif c < 32 or c > 127 or s == "'": | |
525 | tmp = "\\x%02x" % c | |
526 | elif s == "\\": | |
527 | tmp = "\\\\" | |
528 | else: | |
529 | tmp = s | |
530 | ||
531 | if linelng > 70: | |
532 | linelng = 0 | |
533 | output.append("\\\n") | |
534 | ||
535 | output.append(tmp) | |
536 | linelng += len(tmp) | |
537 | ||
538 | output.append("'''\n\n") | |
539 | ||
540 | return "".join(output) | |
541 | ||
542 | #-------------------------------------------------- | |
543 | def MakePackagePython(self, flist): | |
544 | file = open(self.parOutput, "wt") | |
545 | ||
546 | if self.flagVerbose: | |
547 | print "creating Python source file %s..." % self.parOutput | |
548 | ||
549 | file.write("""\ | |
550 | # | |
551 | # This file was automatically generated by wxrc, do not edit by hand. | |
552 | # | |
553 | ||
554 | import wx | |
555 | import wx.xrc | |
556 | ||
557 | """) | |
558 | file.write("def " + self.parFuncname + "():\n") | |
559 | ||
560 | num = 0 | |
561 | for f in flist: | |
562 | file.write(self.FileToPythonArray(os.path.join(self.parOutputPath, f), num)) | |
563 | num += 1 | |
564 | ||
565 | file.write(""" | |
566 | ||
567 | # check if the memory filesystem handler has been loaded yet, and load it if not | |
568 | wx.MemoryFSHandler.AddFile('XRC_resource/dummy_file', 'dummy value') | |
569 | fsys = wx.FileSystem() | |
570 | f = fsys.OpenFile('memory:XRC_resource/dummy_file') | |
571 | wx.MemoryFSHandler.RemoveFile('XRC_resource/dummy_file') | |
572 | if f is not None: | |
573 | f.Destroy() | |
574 | else: | |
575 | wx.FileSystem.AddHandler(wx.MemoryFSHandler()) | |
576 | ||
577 | # load all the strings as memory files and load into XmlRes | |
578 | """) | |
579 | ||
580 | for i in range(len(flist)): | |
581 | file.write(" wx.MemoryFSHandler.AddFile('XRC_resource/" + flist[i] + | |
582 | "', xml_res_file_%i)\n" % i) | |
583 | ||
584 | for pf in self.parFiles: | |
585 | file.write(" wx.xrc.XmlResource.Get().Load('memory:XRC_resource/" + | |
586 | self.GetInternalFileName(pf, flist) + "')\n") | |
587 | ||
588 | ||
589 | #-------------------------------------------------- | |
590 | def OutputGettext(self): | |
591 | strings = self.FindStrings() | |
592 | ||
593 | if not self.parOutput: | |
594 | out = sys.stdout | |
595 | else: | |
596 | out = open(self.parOutput, "wt") | |
597 | ||
598 | for st in strings: | |
599 | out.write("_(\"%s\")\n" % st) | |
600 | ||
601 | ||
602 | ||
603 | #-------------------------------------------------- | |
604 | def FindStrings(self): | |
605 | strings = [] | |
606 | for pf in self.parFiles: | |
607 | if self.flagVerbose: | |
608 | print "processing %s..." % pf | |
609 | ||
610 | doc = wx.xrc.EmptyXmlDocument() | |
611 | if not doc.Load(pf): | |
612 | print "Error parsing file", pf | |
613 | self.retCode = 1 | |
614 | continue | |
615 | ||
616 | strings += self.FindStringsInNode(doc.GetRoot()) | |
617 | ||
618 | return strings | |
619 | ||
620 | ||
621 | #-------------------------------------------------- | |
622 | def ConvertText(self, st): | |
623 | st2 = "" | |
624 | dt = list(st) | |
625 | ||
626 | skipNext = False | |
627 | for i in range(len(dt)): | |
628 | if skipNext: | |
629 | skipNext = False | |
630 | continue | |
631 | ||
632 | if dt[i] == '_': | |
633 | if dt[i+1] == '_': | |
634 | st2 += '_' | |
635 | skipNext = True | |
636 | else: | |
637 | st2 += '&' | |
638 | elif dt[i] == '\n': | |
639 | st2 += '\\n' | |
640 | elif dt[i] == '\t': | |
641 | st2 += '\\t' | |
642 | elif dt[i] == '\r': | |
643 | st2 += '\\r' | |
644 | elif dt[i] == '\\': | |
645 | if dt[i+1] not in ['n', 't', 'r']: | |
646 | st2 += '\\\\' | |
647 | else: | |
648 | st2 += '\\' | |
649 | elif dt[i] == '"': | |
650 | st2 += '\\"' | |
651 | else: | |
652 | st2 += dt[i] | |
653 | ||
654 | return st2 | |
655 | ||
656 | ||
657 | ||
658 | #-------------------------------------------------- | |
659 | def FindStringsInNode(self, parent): | |
660 | def is_number(st): | |
661 | try: | |
662 | i = int(st) | |
663 | return True | |
664 | except ValueError: | |
665 | return False | |
666 | ||
667 | strings = [] | |
668 | if parent is None: | |
669 | return strings; | |
670 | child = parent.GetChildren() | |
671 | ||
672 | while child: | |
673 | if ((parent.GetType() == wx.xrc.XML_ELEMENT_NODE) and | |
674 | # parent is an element, i.e. has subnodes... | |
675 | (child.GetType() == wx.xrc.XML_TEXT_NODE or | |
676 | child.GetType() == wx.xrc.XML_CDATA_SECTION_NODE) and | |
677 | # ...it is textnode... | |
678 | ( | |
679 | parent.GetName() == "label" or | |
680 | (parent.GetName() == "value" and | |
681 | not is_number(child.GetContent())) or | |
682 | parent.GetName() == "help" or | |
683 | parent.GetName() == "longhelp" or | |
684 | parent.GetName() == "tooltip" or | |
685 | parent.GetName() == "htmlcode" or | |
686 | parent.GetName() == "title" or | |
687 | parent.GetName() == "item" | |
688 | )): | |
689 | # ...and known to contain translatable string | |
690 | if (not self.flagGettext or | |
691 | parent.GetPropVal("translate", "1") != "0"): | |
692 | ||
693 | strings.append(self.ConvertText(child.GetContent())) | |
694 | ||
695 | # subnodes: | |
696 | if child.GetType() == wx.xrc.XML_ELEMENT_NODE: | |
697 | strings += self.FindStringsInNode(child) | |
698 | ||
699 | child = child.GetNext() | |
700 | ||
701 | return strings | |
702 | ||
703 | #--------------------------------------------------------------------------- | |
704 | ||
705 | def main(): | |
706 | XmlResApp().main(sys.argv[1:]) | |
707 | ||
708 | ||
709 | if __name__ == "__main__": | |
710 | main() | |
711 |