]>
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
10 # Massive rework by Eli Golovinsky
13 # Copyright: (c) 2004 by Total Control Software, 2000 Vaclav Slavik
14 # Licence: wxWindows license
15 #----------------------------------------------------------------------
18 pywxrc -- Python XML resource compiler
19 (see http://wiki.wxpython.org/index.cgi/pywxrc for more info)
21 Usage: python pywxrc.py -h
22 python pywxrc.py <resource.xrc> [-e] [-g] [-o filename]
24 -h, --help show help message
25 -e, --embed embed resources in the output file
26 -g, --gettext embed list of translatable strings in the output file
27 -o, --output output filename, or - for stdout
30 import sys
, os
, getopt
, glob
, re
31 import xml
.dom
.minidom
as minidom
35 #----------------------------------------------------------------------
37 class PythonTemplates
:
39 # This file was automatically generated by pywxrc, do not edit by hand.
47 \"\"\" This function provides access to the XML resources in this module.\"\"\"
56 class xrc%(windowName)s(wx.%(windowClass)s):
58 \"\"\" This function is called during the class's initialization.
60 Override it for custom setup before the window is created usually to
61 set additional window styles using SetWindowStyle() and SetExtraStyle().\"\"\"
64 def __init__(self, parent):
65 # Two stage creation (see http://wiki.wxpython.org/index.cgi/TwoStageCreation)
66 pre = wx.Pre%(windowClass)s()
67 get_resources().LoadOn%(windowClass)s(pre, parent, "%(windowName)s")
71 # Define variables for the controls
74 CREATE_WIDGET_VAR
= """\
75 self.%(widgetName)s = xrc.XRCCTRL(self, \"%(widgetName)s\")
78 INIT_RESOURE_HEADER
= """\
79 # ------------------------ Resource data ----------------------
81 def __init_resources():
86 __res = xrc.XmlResource('%(resourceFilename)s')
97 # Load all the strings as memory files
99 wx.FileSystem.AddHandler(wx.MemoryFSHandler())
102 ADD_FILE_TO_MEMFS
= """\
103 wx.MemoryFSHandler.AddFile('XRC/%(memoryPath)s/%(filename)s', %(filename)s)
106 LOAD_RES_MEMFS
= """\
108 __res = xrc.EmptyXmlResource()
109 __res.Load('memory:XRC/%(memoryPath)s/%(resourceFilename)s')
112 GETTEXT_DUMMY_FUNC
= """\
113 # ----------------------- Gettext strings ---------------------
115 def __gettext_strings():
116 # This is a dummy function that lists all the strings that are used in
117 # the XRC file in the _("a string") format to be recognized by GNU
118 # gettext utilities (specificaly the xgettext utility) and the
119 # mki18n.py script. For more information see:
120 # http://wiki.wxpython.org/index.cgi/Internationalization
127 #----------------------------------------------------------------------
129 class XmlResourceCompiler
:
131 templates
= PythonTemplates()
133 """This class generates Python code from XML resource files (XRC)."""
135 def MakePythonModule(self
, resourceFilename
, outputFilename
,
136 embedResources
=False, generateGetText
=False):
137 if outputFilename
== "-":
138 outputFile
= sys
.stdout
141 outputFile
= open(outputFilename
, "wt")
143 raise IOError("Can't write output to '%s'" % outputFilename
)
145 resourceDocument
= minidom
.parse(resourceFilename
)
146 print >>outputFile
, self
.templates
.FILE_HEADER
147 print >>outputFile
, self
.GenerateClasses(resourceDocument
)
150 print >>outputFile
, self
.GenerateInitResourcesEmbedded(resourceFilename
, resourceDocument
)
152 print >>outputFile
, self
.GenerateInitResourcesFile(resourceFilename
, resourceDocument
)
155 print >>outputFile
, self
.GenerateGetText(resourceDocument
)
157 #-------------------------------------------------------------------
159 def GenerateClasses(self
, resourceDocument
):
162 resource
= resourceDocument
.firstChild
163 topWindows
= [e
for e
in resource
.childNodes
164 if e
.nodeType
== e
.ELEMENT_NODE
and e
.tagName
== "object"]
166 # Generate a class for each top-window object (Frame, Panel, Dialog, etc.)
167 for topWindow
in topWindows
:
168 windowClass
= topWindow
.getAttribute("class")
169 windowClass
= re
.sub("^wx", "", windowClass
)
170 windowName
= topWindow
.getAttribute("name")
171 outputList
.append(self
.templates
.CLASS_HEADER
% locals())
173 # Generate a variable for each control, and standard event handlers
174 # for standard controls.
175 for widget
in topWindow
.getElementsByTagName("object"):
176 widgetClass
= widget
.getAttribute("class")
177 widgetClass
= re
.sub("^wx", "", widgetClass
)
178 widgetName
= widget
.getAttribute("name")
179 if (widgetName
!= "" and widgetClass
!= "" and
181 ['tool', 'unknown', 'notebookpage',
182 'separator', 'sizeritem', 'MenuItem']):
183 outputList
.append(self
.templates
.CREATE_WIDGET_VAR
% locals())
184 outputList
.append('\n\n')
186 return "".join(outputList
)
188 #-------------------------------------------------------------------
190 def GenerateGetText(self
, resourceDocument
):
191 resource
= resourceDocument
.firstChild
192 strings
= self
.FindStringsInNode(resource
)
193 strings
= [' _("%s")\n' % s
for s
in strings
]
194 gettextStrings
= "".join(strings
)
195 return self
.templates
.GETTEXT_DUMMY_FUNC
% locals()
197 #-------------------------------------------------------------------
199 def GenerateInitResourcesEmbedded(self
, resourceFilename
, resourceDocument
):
202 outputList
.append(self
.templates
.INIT_RESOURE_HEADER
)
206 resourcePath
= os
.path
.split(resourceFilename
)[0]
207 memoryPath
= self
.GetMemoryFilename(os
.path
.splitext(os
.path
.split(resourceFilename
)[1])[0])
208 resourceFilename
= self
.GetMemoryFilename(os
.path
.split(resourceFilename
)[1])
210 self
.ReplaceFilenamesInXRC(resourceDocument
.firstChild
, files
, resourcePath
)
212 filename
= resourceFilename
213 fileData
= resourceDocument
.toxml()
214 outputList
.append(self
.templates
.FILE_AS_STRING
% locals())
217 filename
= self
.GetMemoryFilename(f
)
218 fileData
= self
.FileToString(os
.path
.join(resourcePath
, f
))
219 outputList
.append(self
.templates
.FILE_AS_STRING
% locals())
221 outputList
.append(self
.templates
.PREPARE_MEMFS
% locals())
223 for f
in [resourceFilename
] + files
:
224 filename
= self
.GetMemoryFilename(f
)
225 outputList
.append(self
.templates
.ADD_FILE_TO_MEMFS
% locals())
227 outputList
.append(self
.templates
.LOAD_RES_MEMFS
% locals())
229 return "".join(outputList
)
231 #-------------------------------------------------------------------
233 def GenerateInitResourcesFile(self
, resourceFilename
, resourceDocument
):
234 # take only the filename portion out of resourceFilename
235 resourceFilename
= os
.path
.split(resourceFilename
)[1]
237 outputList
.append(self
.templates
.INIT_RESOURE_HEADER
)
238 outputList
.append(self
.templates
.LOAD_RES_FILE
% locals())
239 return "".join(outputList
)
241 #-------------------------------------------------------------------
243 def GetMemoryFilename(self
, filename
):
244 # Remove special chars from the filename
245 return re
.sub(r
"[^A-Za-z0-9_]", "_", filename
)
247 #-------------------------------------------------------------------
249 def FileToString(self
, filename
):
252 buffer = open(filename
, "rb").read()
253 fileLen
= len(buffer)
256 for i
in xrange(fileLen
):
262 elif c
< 32 or c
> 127 or s
== "'":
271 outputList
.append("\\\n")
273 outputList
.append(tmp
)
276 return "".join(outputList
)
278 #-------------------------------------------------------------------
280 def NodeContainsFilename(self
, node
):
281 """ Does 'node' contain filename information at all? """
284 if node
.nodeName
== "bitmap":
287 if node
.nodeName
== "icon":
290 # URLs in wxHtmlWindow:
291 if node
.nodeName
== "url":
295 parent
= node
.parentNode
296 if parent
.__class
__ != minidom
.Document
and \
297 parent
.getAttribute("class") == "wxBitmapButton" and \
298 (node
.nodeName
== "focus" or node
.nodeName
== "disabled" or
299 node
.nodeName
== "selected"):
302 # wxBitmap or wxIcon toplevel resources:
303 if node
.nodeName
== "object":
304 klass
= node
.getAttribute("class")
305 if klass
== "wxBitmap" or klass
== "wxIcon":
310 #-------------------------------------------------------------------
312 def ReplaceFilenamesInXRC(self
, node
, files
, resourcePath
):
313 """ Finds all files mentioned in resource file, e.g. <bitmap>filename</bitmap>
314 and replaces them with the memory filenames.
316 Fills a list of the filenames found."""
318 # Is 'node' XML node element?
319 if node
is None: return
320 if node
.nodeType
!= minidom
.Document
.ELEMENT_NODE
: return
322 containsFilename
= self
.NodeContainsFilename(node
);
324 for n
in node
.childNodes
:
326 if (containsFilename
and
327 (n
.nodeType
== minidom
.Document
.TEXT_NODE
or
328 n
.nodeType
== minidom
.Document
.CDATA_SECTION_NODE
)):
330 filename
= n
.nodeValue
331 memoryFilename
= self
.GetMemoryFilename(filename
)
332 n
.nodeValue
= memoryFilename
334 if filename
not in files
:
335 files
.append(filename
)
337 # Recurse into children
338 if n
.nodeType
== minidom
.Document
.ELEMENT_NODE
:
339 self
.ReplaceFilenamesInXRC(n
, files
, resourcePath
);
341 #-------------------------------------------------------------------
343 def FindStringsInNode(self
, parent
):
355 for child
in parent
.childNodes
:
356 if ((parent
.nodeType
== parent
.ELEMENT_NODE
) and
357 # parent is an element, i.e. has subnodes...
358 (child
.nodeType
== child
.TEXT_NODE
or
359 child
.nodeType
== child
.CDATA_SECTION_NODE
) and
360 # ...it is textnode...
362 parent
.tagName
== "label" or
363 (parent
.tagName
== "value" and
364 not is_number(child
.nodeValue
)) or
365 parent
.tagName
== "help" or
366 parent
.tagName
== "longhelp" or
367 parent
.tagName
== "tooltip" or
368 parent
.tagName
== "htmlcode" or
369 parent
.tagName
== "title" or
370 parent
.tagName
== "item"
372 # ...and known to contain translatable string
373 if (parent
.getAttribute("translate") != "0"):
374 strings
.append(self
.ConvertText(child
.nodeValue
))
377 if child
.nodeType
== child
.ELEMENT_NODE
:
378 strings
+= self
.FindStringsInNode(child
)
382 #-------------------------------------------------------------------
384 def ConvertText(self
, st
):
389 for i
in range(len(dt
)):
407 if dt
[i
+1] not in ['n', 't', 'r']:
420 #---------------------------------------------------------------------------
423 resourceFilename
= ""
425 embedResources
= False
426 generateGetText
= False
429 opts
, args
= getopt
.gnu_getopt(args
, "hego:", "help embed gettext output=".split())
430 except getopt
.GetoptError
, e
:
431 print "\nError : %s\n" % str(e
)
435 # If there is no input file argument, show help and exit
437 resourceFilename
= args
[0]
442 # Parse options and arguments
443 for opt
, val
in opts
:
444 if opt
in ["-h", "--help"]:
448 if opt
in ["-o", "--output"]:
451 if opt
in ["-e", "--embed"]:
452 embedResources
= True
454 if opt
in ["-g", "--gettext"]:
455 generateGetText
= True
457 if outputFilename
is None or outputFilename
== "":
458 outputFilename
= os
.path
.splitext(resourceFilename
)[0] + "_xrc.py"
460 comp
= XmlResourceCompiler()
463 comp
.MakePythonModule(resourceFilename
, outputFilename
, embedResources
, generateGetText
)
465 print >>sys
.stderr
, "%s." % str(e
)
467 if outputFilename
!= "-":
468 print >>sys
.stderr
, "Resources written to %s." % outputFilename
470 if __name__
== "__main__":