]>
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 # URLs in wxHtmlWindow:
302 if node
.GetName() == "url":
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"):
313 # wxBitmap or wxIcon toplevel resources:
314 if node
.GetName() == "object":
315 klass
= node
.GetPropVal("class", "")
316 if klass
== "wxBitmap" or klass
== "wxIcon":
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
328 containsFilename
= self
.NodeContainsFilename(node
);
330 n
= node
.GetChildren()
332 if (containsFilename
and
333 (n
.GetType() == wx
.xrc
.XML_TEXT_NODE
or
334 n
.GetType() == wx
.xrc
.XML_CDATA_SECTION_NODE
)):
336 if os
.path
.isabs(n
.GetContent()) or inputPath
== "":
337 fullname
= n
.GetContent()
339 fullname
= os
.path
.join(inputPath
, n
.GetContent())
342 print "adding %s..." % fullname
344 filename
= self
.GetInternalFileName(n
.GetContent(), flist
)
345 n
.SetContent(filename
)
347 if filename
not in flist
:
348 flist
.append(filename
)
351 out
= open(os
.path
.join(self
.parOutputPath
, filename
), "w")
352 out
.write(inp
.read())
355 if n
.GetType() == wx
.xrc
.XML_ELEMENT_NODE
:
356 self
.FindFilesInXML(n
, flist
, inputPath
);
362 #--------------------------------------------------
363 def DeleteTempFiles(self
, flist
):
365 os
.unlink(os
.path
.join(self
.parOutputPath
, f
))
368 #--------------------------------------------------
369 def MakePackageZIP(self
, flist
):
370 files
= " ".join(flist
)
373 print "compressing %s..." % self
.parOutput
376 os
.chdir(self
.parOutputPath
)
378 if not self
.flagVerbose
:
380 cmd
+= self
.parOutput
+ " " + files
382 from distutils
.spawn
import spawn
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/"
397 #--------------------------------------------------
398 def FileToCppArray(self
, filename
, num
):
400 buffer = open(filename
, "rb").read()
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 :(
409 for i
in xrange(lng
):
410 tmp
= "%i" % ord(buffer[i
])
411 if i
!= 0: output
.append(',')
417 linelng
+= len(tmp
)+1
419 output
.append("};\n\n")
421 return "".join(output
)
425 #--------------------------------------------------
426 def MakePackageCPP(self
, flist
):
427 file = open(self
.parOutput
, "wt")
430 print "creating C++ source file %s..." % self
.parOutput
434 // This file was automatically generated by wxrc, do not edit by hand.
437 #include <wx/wxprec.h>
447 #include <wx/filesys.h>
448 #include <wx/fs_mem.h>
449 #include <wx/xrc/xmlres.h>
450 #include <wx/xrc/xh_all.h>
456 file.write(self
.FileToCppArray(os
.path
.join(self
.parOutputPath
, f
), num
))
460 file.write("void " + self
.parFuncname
+ "()\n")
464 // Check for memory FS. If not present, load the handler:
466 wxMemoryFSHandler::AddFile(wxT(\"XRC_resource/dummy_file\"), wxT(\"dummy one\"));
468 wxFSFile *f = fsys.OpenFile(wxT(\"memory:XRC_resource/dummy_file\"));
469 wxMemoryFSHandler::RemoveFile(wxT(\"XRC_resource/dummy_file\"));
471 else wxFileSystem::AddHandler(new wxMemoryFSHandler);
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
))
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
) +
488 #--------------------------------------------------
489 def GenCPPHeader(self
):
490 path
, name
= os
.path
.split(self
.parOutput
)
491 name
, ext
= os
.path
.splitext(name
)
492 heaFileName
= name
+'.h'
494 file = open(heaFileName
, "wt")
497 // This file was automatically generated by wxrc, do not edit by hand.
500 file.write("#ifndef __" + name
+ "_h__\n")
501 file.write("#define __" + name
+ "_h__\n")
503 for data
in self
.aXRCWndClassData
:
504 data
.GenerateHeaderCode(file)
506 file.write("\nvoid \n" + self
.parFuncname
+ "();\n#endif\n")
509 #--------------------------------------------------
510 def FileToPythonArray(self
, filename
, num
):
512 buffer = open(filename
, "rb").read()
515 output
.append(" xml_res_file_%d = '''\\\n" % num
)
518 for i
in xrange(lng
):
524 elif c
< 32 or c
> 127 or s
== "'":
533 output
.append("\\\n")
538 output
.append("'''\n\n")
540 return "".join(output
)
542 #--------------------------------------------------
543 def MakePackagePython(self
, flist
):
544 file = open(self
.parOutput
, "wt")
547 print "creating Python source file %s..." % self
.parOutput
551 # This file was automatically generated by wxrc, do not edit by hand.
558 file.write("def " + self
.parFuncname
+ "():\n")
562 file.write(self
.FileToPythonArray(os
.path
.join(self
.parOutputPath
, f
), num
))
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')
575 wx.FileSystem.AddHandler(wx.MemoryFSHandler())
577 # load all the strings as memory files and load into XmlRes
580 for i
in range(len(flist
)):
581 file.write(" wx.MemoryFSHandler.AddFile('XRC_resource/" + flist
[i
] +
582 "', xml_res_file_%i)\n" % i
)
584 for pf
in self
.parFiles
:
585 file.write(" wx.xrc.XmlResource.Get().Load('memory:XRC_resource/" +
586 self
.GetInternalFileName(pf
, flist
) + "')\n")
589 #--------------------------------------------------
590 def OutputGettext(self
):
591 strings
= self
.FindStrings()
593 if not self
.parOutput
:
596 out
= open(self
.parOutput
, "wt")
599 out
.write("_(\"%s\")\n" % st
)
603 #--------------------------------------------------
604 def FindStrings(self
):
606 for pf
in self
.parFiles
:
608 print "processing %s..." % pf
610 doc
= wx
.xrc
.EmptyXmlDocument()
612 print "Error parsing file", pf
616 strings
+= self
.FindStringsInNode(doc
.GetRoot())
621 #--------------------------------------------------
622 def ConvertText(self
, st
):
627 for i
in range(len(dt
)):
645 if dt
[i
+1] not in ['n', 't', 'r']:
658 #--------------------------------------------------
659 def FindStringsInNode(self
, parent
):
670 child
= parent
.GetChildren()
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...
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"
689 # ...and known to contain translatable string
690 if (not self
.flagGettext
or
691 parent
.GetPropVal("translate", "1") != "0"):
693 strings
.append(self
.ConvertText(child
.GetContent()))
696 if child
.GetType() == wx
.xrc
.XML_ELEMENT_NODE
:
697 strings
+= self
.FindStringsInNode(child
)
699 child
= child
.GetNext()
703 #---------------------------------------------------------------------------
706 XmlResApp().main(sys
.argv
[1:])
709 if __name__
== "__main__":