]>
git.saurik.com Git - wxWidgets.git/blob - wxPython/wx/tools/pywxrc.py
1 #----------------------------------------------------------------------
2 # Name: wx.tools.pywxrc
3 # Purpose: XML resource compiler
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
11 # Copyright: (c) 2004 by Total Control Software, 2000 Vaclav Slavik
12 # Licence: wxWindows license
13 #----------------------------------------------------------------------
16 pywxrc -- XML resource compiler
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]
29 import sys
, os
, getopt
, glob
34 #----------------------------------------------------------------------
37 def __init__(self
, vname
, vclass
):
46 #----------------------------------------------------------------------
48 class XRCWndClassData
:
49 def __init__(self
, className
, parentClassName
, node
):
50 self
.className
= className
51 self
.parentClassName
= parentClassName
52 self
.BrowseXmlNode(node
.GetChildren())
56 def BrowseXmlNode(self
, 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()
64 self
.BrowseXmlNode(children
)
68 def GetWidgetData(self
):
72 def IsRealClass(self
, name
):
73 if name
in ['tool', 'unknown', 'notebookpage', 'separator',
74 'sizeritem', 'wxMenuItem']:
80 def GenerateHeaderCode(self
, file):
81 file.write("class %s : public %s {\nprotected:\n" % (self
.className
, self
.parentClassName
))
84 if not self
.IsRealClass(w
.GetClass()):
88 file.write(" " + w
.GetClass() + "* " + w
.GetName() + ";\n")
90 file.write("\nprivate:\n void InitWidgetsFromXRC(){\n",
91 + " wxXmlResource::Get()->LoadObject(this,NULL,\""
94 + self
.parentClassName
98 if not self
.IsRealClass(w
.GetClass()):
104 + " = XRCCTRL(*this,\""
111 file.write("public:\n"
116 + " InitWidgetsFromXRC();\n"
122 #----------------------------------------------------------------------
127 self
.flagVerbose
= False
130 self
.flagPython
= False
131 self
.flagGettext
= False
133 self
.parFuncname
= "InitXmlResource"
135 self
.aXRCWndClassData
= []
138 #--------------------------------------------------
139 def main(self
, args
):
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
:
147 for opt
, val
in opts
:
148 if opt
in ["-h", "--help"]:
152 if opt
in ["-v", "--verbose"]:
153 self
.flagVerbose
= True
155 if opt
in ["-e", "--extra-cpp-code"]:
158 if opt
in ["-c", "--cpp-code"]:
161 if opt
in ["-p", "--python-code"]:
162 self
.flagPython
= True
164 if opt
in ["-g", "--gettext"]:
165 self
.flagGettext
= True
167 if opt
in ["-n", "--function"]:
168 self
.parFuncname
= val
170 if opt
in ["-o", "--output"]:
173 if self
.flagCPP
+ self
.flagPython
+ self
.flagGettext
== 0:
175 print "\nYou must specify one of -c, -p or -g!\n"
178 if self
.flagCPP
+ self
.flagPython
+ self
.flagGettext
> 1:
180 print "\n-c, -p and -g are mutually exclusive, specify only 1!\n"
185 self
.parOutput
= os
.path
.normpath(self
.parOutput
)
186 self
.parOutputPath
= os
.path
.split(self
.parOutput
)[0]
188 self
.parOutputPath
= "."
190 self
.parOutput
= "resource.cpp"
191 elif self
.flagPython
:
192 self
.parOutput
= "resource.py"
193 elif self
.flagGettext
:
196 self
.parOutput
= "resource.xrs"
202 self
.parFiles
+= glob
.glob(arg
)
212 #--------------------------------------------------
213 def CompileRes(self
):
214 files
= self
.PrepareTempFiles()
216 os
.unlink(self
.parOutput
)
222 self
.MakePackageCPP(files
)
226 elif self
.flagPython
:
227 self
.MakePackagePython(files
)
230 self
.MakePackageZIP(files
)
232 self
.DeleteTempFiles(files
)
235 #--------------------------------------------------
236 def OutputGettext(self
):
240 #--------------------------------------------------
241 def GetInternalFileName(self
, name
, flist
):
243 name2
= name2
.replace(":", "_")
244 name2
= name2
.replace("/", "_")
245 name2
= name2
.replace("\\", "_")
246 name2
= name2
.replace("*", "_")
247 name2
= name2
.replace("?", "_")
249 s
= os
.path
.split(self
.parOutput
)[1] + "$" + name2
251 if os
.path
.exists(s
) and s
not in flist
:
254 s
= os
.path
.split(self
.parOutput
)[1] + ("$%s%03d" % (name2
, i
))
255 if not os
.path
.exists(s
) or s
in flist
:
260 #--------------------------------------------------
261 def PrepareTempFiles(self
):
263 for f
in self
.parFiles
:
265 print "processing %s..." % f
267 doc
= wx
.xrc
.EmptyXmlDocument()
270 print "Error parsing file", f
274 path
, name
= os
.path
.split(f
)
275 name
, ext
= os
.path
.splitext(name
)
277 self
.FindFilesInXML(doc
.GetRoot(), flist
, path
)
279 node
= doc
.GetRoot().GetChildren()
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
)
288 doc
.Save(os
.path
.join(self
.parOutputPath
, internalName
))
289 flist
.append(internalName
)
294 #--------------------------------------------------
295 # Does 'node' contain filename information at all?
296 def NodeContainsFilename(self
, node
):
298 if node
.GetName() == "bitmap":
301 if node
.GetName() == "icon":
304 # URLs in wxHtmlWindow:
305 if node
.GetName() == "url":
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"):
316 # wxBitmap or wxIcon toplevel resources:
317 if node
.GetName() == "object":
318 klass
= node
.GetPropVal("class", "")
319 if klass
== "wxBitmap" or klass
== "wxIcon":
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
331 containsFilename
= self
.NodeContainsFilename(node
);
333 n
= node
.GetChildren()
335 if (containsFilename
and
336 (n
.GetType() == wx
.xrc
.XML_TEXT_NODE
or
337 n
.GetType() == wx
.xrc
.XML_CDATA_SECTION_NODE
)):
339 if os
.path
.isabs(n
.GetContent()) or inputPath
== "":
340 fullname
= n
.GetContent()
342 fullname
= os
.path
.join(inputPath
, n
.GetContent())
345 print "adding %s..." % fullname
347 filename
= self
.GetInternalFileName(n
.GetContent(), flist
)
348 n
.SetContent(filename
)
350 if filename
not in flist
:
351 flist
.append(filename
)
354 out
= open(os
.path
.join(self
.parOutputPath
, filename
), "w")
355 out
.write(inp
.read())
358 if n
.GetType() == wx
.xrc
.XML_ELEMENT_NODE
:
359 self
.FindFilesInXML(n
, flist
, inputPath
);
365 #--------------------------------------------------
366 def DeleteTempFiles(self
, flist
):
368 os
.unlink(os
.path
.join(self
.parOutputPath
, f
))
371 #--------------------------------------------------
372 def MakePackageZIP(self
, flist
):
373 files
= " ".join(flist
)
376 print "compressing %s..." % self
.parOutput
379 os
.chdir(self
.parOutputPath
)
381 if not self
.flagVerbose
:
383 cmd
+= self
.parOutput
+ " " + files
385 from distutils
.spawn
import spawn
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/"
400 #--------------------------------------------------
401 def FileToCppArray(self
, filename
, num
):
403 buffer = open(filename
, "rb").read()
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 :(
412 for i
in xrange(lng
):
413 tmp
= "%i" % ord(buffer[i
])
414 if i
!= 0: output
.append(',')
420 linelng
+= len(tmp
)+1
422 output
.append("};\n\n")
424 return "".join(output
)
428 #--------------------------------------------------
429 def MakePackageCPP(self
, flist
):
430 file = open(self
.parOutput
, "wt")
433 print "creating C++ source file %s..." % self
.parOutput
437 // This file was automatically generated by wxrc, do not edit by hand.
440 #include <wx/wxprec.h>
450 #include <wx/filesys.h>
451 #include <wx/fs_mem.h>
452 #include <wx/xrc/xmlres.h>
453 #include <wx/xrc/xh_all.h>
459 file.write(self
.FileToCppArray(os
.path
.join(self
.parOutputPath
, f
), num
))
463 file.write("void " + self
.parFuncname
+ "()\n")
467 // Check for memory FS. If not present, load the handler:
469 wxMemoryFSHandler::AddFile(wxT(\"XRC_resource/dummy_file\"), wxT(\"dummy one\"));
471 wxFSFile *f = fsys.OpenFile(wxT(\"memory:XRC_resource/dummy_file\"));
472 wxMemoryFSHandler::RemoveFile(wxT(\"XRC_resource/dummy_file\"));
474 else wxFileSystem::AddHandler(new wxMemoryFSHandler);
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
))
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
) +
491 #--------------------------------------------------
492 def GenCPPHeader(self
):
493 path
, name
= os
.path
.split(self
.parOutput
)
494 name
, ext
= os
.path
.splitext(name
)
495 heaFileName
= name
+'.h'
497 file = open(heaFileName
, "wt")
500 // This file was automatically generated by wxrc, do not edit by hand.
503 file.write("#ifndef __" + name
+ "_h__\n")
504 file.write("#define __" + name
+ "_h__\n")
506 for data
in self
.aXRCWndClassData
:
507 data
.GenerateHeaderCode(file)
509 file.write("\nvoid \n" + self
.parFuncname
+ "();\n#endif\n")
512 #--------------------------------------------------
513 def FileToPythonArray(self
, filename
, num
):
515 buffer = open(filename
, "rb").read()
518 output
.append(" xml_res_file_%d = '''\\\n" % num
)
521 for i
in xrange(lng
):
527 elif c
< 32 or c
> 127 or s
== "'":
536 output
.append("\\\n")
541 output
.append("'''\n\n")
543 return "".join(output
)
545 #--------------------------------------------------
546 def MakePackagePython(self
, flist
):
547 file = open(self
.parOutput
, "wt")
550 print "creating Python source file %s..." % self
.parOutput
554 # This file was automatically generated by wxrc, do not edit by hand.
561 file.write("def " + self
.parFuncname
+ "():\n")
565 file.write(self
.FileToPythonArray(os
.path
.join(self
.parOutputPath
, f
), num
))
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')
578 wx.FileSystem.AddHandler(wx.MemoryFSHandler())
580 # load all the strings as memory files and load into XmlRes
583 for i
in range(len(flist
)):
584 file.write(" wx.MemoryFSHandler.AddFile('XRC_resource/" + flist
[i
] +
585 "', xml_res_file_%i)\n" % i
)
587 for pf
in self
.parFiles
:
588 file.write(" wx.xrc.XmlResource.Get().Load('memory:XRC_resource/" +
589 self
.GetInternalFileName(pf
, flist
) + "')\n")
592 #--------------------------------------------------
593 def OutputGettext(self
):
594 strings
= self
.FindStrings()
596 if not self
.parOutput
:
599 out
= open(self
.parOutput
, "wt")
602 out
.write("_(\"%s\")\n" % st
)
606 #--------------------------------------------------
607 def FindStrings(self
):
609 for pf
in self
.parFiles
:
611 print "processing %s..." % pf
613 doc
= wx
.xrc
.EmptyXmlDocument()
615 print "Error parsing file", pf
619 strings
+= self
.FindStringsInNode(doc
.GetRoot())
624 #--------------------------------------------------
625 def ConvertText(self
, st
):
630 for i
in range(len(dt
)):
648 if dt
[i
+1] not in ['n', 't', 'r']:
661 #--------------------------------------------------
662 def FindStringsInNode(self
, parent
):
673 child
= parent
.GetChildren()
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...
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"
692 # ...and known to contain translatable string
693 if (not self
.flagGettext
or
694 parent
.GetPropVal("translate", "1") != "0"):
696 strings
.append(self
.ConvertText(child
.GetContent()))
699 if child
.GetType() == wx
.xrc
.XML_ELEMENT_NODE
:
700 strings
+= self
.FindStringsInNode(child
)
702 child
= child
.GetNext()
706 #---------------------------------------------------------------------------
709 XmlResApp().main(sys
.argv
[1:])
712 if __name__
== "__main__":