]>
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 [-p] [-g] [-e] [-o filename] xrc input files...  
  24   -h, --help     show help message 
  25   -p, --python   generate python module 
  26   -g, --gettext  output list of translatable strings (may be combined with -p) 
  27   -e, --embed    embed XRC resources in the output file 
  28   -o, --output   output filename, or - for stdout 
  31 import sys
, os
, getopt
, glob
, re
 
  32 import xml
.dom
.minidom 
as minidom
 
  36 #---------------------------------------------------------------------- 
  38 class PythonTemplates
: 
  40 # This file was automatically generated by pywxrc, do not edit by hand. 
  41 # -*- coding: UTF-8 -*- 
  49     \"\"\" This function provides access to the XML resources in this module.\"\"\" 
  58 class xrc%(windowName)s(wx.%(windowClass)s): 
  59     def PreCreate(self, pre): 
  60         \"\"\" This function is called during the class's initialization. 
  62         Override it for custom setup before the window is created usually to 
  63         set additional window styles using SetWindowStyle() and SetExtraStyle().\"\"\" 
  66     def __init__(self, parent): 
  67         # Two stage creation (see http://wiki.wxpython.org/index.cgi/TwoStageCreation) 
  68         pre = wx.Pre%(windowClass)s() 
  70         get_resources().LoadOn%(windowClass)s(pre, parent, "%(windowName)s") 
  73         # Define variables for the controls 
  76     CREATE_WIDGET_VAR 
= """\ 
  77         self.%(widgetName)s = xrc.XRCCTRL(self, \"%(widgetName)s\") 
  80     MENU_CLASS_HEADER 
= """\ 
  81 class xrc%(windowName)s(wx.%(windowClass)s): 
  83         pre = get_resources().LoadMenu("%(windowName)s") 
  85         # This is a copy of Robin's PostCreate voodoo magic in wx.Window that 
  86         # relinks the self object with the menu object. 
  88         self.thisown = pre.thisown 
  90         if hasattr(self, '_setOORInfo'): 
  91             self._setOORInfo(self) 
  92         if hasattr(self, '_setCallbackInfo'): 
  93             self._setCallbackInfo(self, self.__class__) 
  95         # Define variables for the menu items 
  98     CREATE_MENUITEM_VAR 
= """\ 
  99         self.%(widgetName)s = self.FindItemById(xrc.XRCID(\"%(widgetName)s\")) 
 102     INIT_RESOURE_HEADER 
= """\ 
 103 # ------------------------ Resource data ---------------------- 
 105 def __init_resources(): 
 107     __res = xrc.EmptyXmlResource() 
 111     __res.Load('%(resourceFilename)s')""" 
 113     FILE_AS_STRING 
= """\ 
 120     wx.FileSystem.AddHandler(wx.MemoryFSHandler()) 
 123     ADD_FILE_TO_MEMFS 
= """\ 
 124     wx.MemoryFSHandler.AddFile('XRC/%(memoryPath)s/%(filename)s', %(filename)s) 
 127     LOAD_RES_MEMFS 
= """\ 
 128     __res.Load('memory:XRC/%(memoryPath)s/%(resourceFilename)s') 
 131     GETTEXT_DUMMY_FUNC 
= """ 
 132 # ----------------------- Gettext strings --------------------- 
 134 def __gettext_strings(): 
 135     # This is a dummy function that lists all the strings that are used in 
 136     # the XRC file in the _("a string") format to be recognized by GNU 
 137     # gettext utilities (specificaly the xgettext utility) and the 
 138     # mki18n.py script.  For more information see: 
 139     # http://wiki.wxpython.org/index.cgi/Internationalization  
 146 #---------------------------------------------------------------------- 
 148 class XmlResourceCompiler
: 
 150     templates 
= PythonTemplates() 
 152     """This class generates Python code from XML resource files (XRC).""" 
 154     def MakePythonModule(self
, inputFiles
, outputFilename
, 
 155                          embedResources
=False, generateGetText
=False): 
 157         outputFile 
= self
._OpenOutputFile
(outputFilename
) 
 163         # process all the inputFiles, collecting the output data 
 164         for inFile 
in inputFiles
: 
 165             resourceDocument 
= minidom
.parse(inFile
) 
 166             classes
.append(self
.GenerateClasses(resourceDocument
)) 
 169                 res 
= self
.GenerateInitResourcesEmbedded(inFile
, resourceDocument
) 
 171                 res 
= self
.GenerateInitResourcesFile(inFile
, resourceDocument
) 
 172             resources
.append(res
) 
 175                 gettextStrings 
+= self
.FindStringsInNode(resourceDocument
.firstChild
) 
 177         # now write it all out 
 178         print >>outputFile
, self
.templates
.FILE_HEADER
 
 180         # Note: Technically it is not legal to have anything other 
 181         # than ascii for class and variable names, but since the user 
 182         # can create the XML with non-ascii names we'll go ahead and 
 183         # allow for it here, and then let Python complain about it 
 184         # later when they try to run the program. 
 185         classes 
= u
"\n".join(classes
) 
 186         print >>outputFile
, classes
.encode("UTF-8") 
 188         print >>outputFile
, self
.templates
.INIT_RESOURE_HEADER
 
 190             print >>outputFile
, self
.templates
.PREPARE_MEMFS
 
 191         resources 
= u
"\n".join(resources
) 
 192         print >>outputFile
, resources
.encode("UTF-8") 
 195             # These have already been converted to utf-8... 
 196             gettextStrings 
= ['    _("%s")' % s 
for s 
in gettextStrings
] 
 197             gettextStrings 
= "\n".join(gettextStrings
) 
 198             print >>outputFile
, self
.templates
.GETTEXT_DUMMY_FUNC 
% gettextStrings
 
 200     #------------------------------------------------------------------- 
 202     def MakeGetTextOutput(self
, inputFiles
, outputFilename
): 
 204         Just output the gettext strings by themselves, with no other 
 207         outputFile 
= self
._OpenOutputFile
(outputFilename
) 
 208         for inFile 
in inputFiles
: 
 209             resourceDocument 
= minidom
.parse(inFile
) 
 210             resource 
= resourceDocument
.firstChild
 
 211             strings 
= self
.FindStringsInNode(resource
) 
 212             strings 
= ['_("%s");' % s 
for s 
in strings
] 
 213             print >>outputFile
, "\n".join(strings
) 
 215     #------------------------------------------------------------------- 
 217     def GenerateClasses(self
, resourceDocument
): 
 220         resource 
= resourceDocument
.firstChild
 
 221         topWindows 
= [e 
for e 
in resource
.childNodes
 
 222                       if e
.nodeType 
== e
.ELEMENT_NODE 
and e
.tagName 
== "object"] 
 224         # Generate a class for each top-window object (Frame, Panel, Dialog, etc.) 
 225         for topWindow 
in topWindows
: 
 226             windowClass 
= topWindow
.getAttribute("class") 
 227             windowClass 
= re
.sub("^wx", "", windowClass
) 
 228             windowName 
= topWindow
.getAttribute("name") 
 230             if windowClass 
in ["Menu", "MenuItem"]: 
 231                 outputList
.append(self
.templates
.MENU_CLASS_HEADER 
% locals()) 
 233                 outputList
.append(self
.templates
.CLASS_HEADER 
% locals()) 
 235             # Generate a variable for each control, and standard event handlers 
 236             # for standard controls. 
 237             for widget 
in topWindow
.getElementsByTagName("object"): 
 238                 widgetClass 
= widget
.getAttribute("class") 
 239                 widgetClass 
= re
.sub("^wx", "", widgetClass
) 
 240                 widgetName 
= widget
.getAttribute("name") 
 241                 if (widgetName 
!= "" and widgetClass 
!= ""): 
 242                     if widgetClass 
== "MenuItem": 
 243                         outputList
.append(self
.templates
.CREATE_MENUITEM_VAR 
% locals()) 
 244                     elif widgetClass 
not in \
 
 245                         ['tool', 'unknown', 'notebookpage', 'separator', 'sizeritem']: 
 246                         outputList
.append(self
.templates
.CREATE_WIDGET_VAR 
% locals()) 
 247             outputList
.append('\n\n') 
 249         return "".join(outputList
) 
 251     #------------------------------------------------------------------- 
 253     def GenerateInitResourcesEmbedded(self
, resourceFilename
, resourceDocument
): 
 257         resourcePath 
= os
.path
.split(resourceFilename
)[0] 
 258         memoryPath 
= self
.GetMemoryFilename(os
.path
.splitext(os
.path
.split(resourceFilename
)[1])[0]) 
 259         resourceFilename 
= self
.GetMemoryFilename(os
.path
.split(resourceFilename
)[1]) 
 261         self
.ReplaceFilenamesInXRC(resourceDocument
.firstChild
, files
, resourcePath
) 
 263         filename 
= resourceFilename
 
 264         fileData 
= resourceDocument
.toxml() # what about this? encoding=resourceDocument.encoding) 
 265         outputList
.append(self
.templates
.FILE_AS_STRING 
% locals()) 
 268             filename 
= self
.GetMemoryFilename(f
) 
 269             fileData 
= self
.FileToString(os
.path
.join(resourcePath
, f
)) 
 270             outputList
.append(self
.templates
.FILE_AS_STRING 
% locals()) 
 272         for f 
in [resourceFilename
] + files
: 
 273             filename 
= self
.GetMemoryFilename(f
) 
 274             outputList
.append(self
.templates
.ADD_FILE_TO_MEMFS 
% locals()) 
 276         outputList
.append(self
.templates
.LOAD_RES_MEMFS 
% locals()) 
 278         return "".join(outputList
) 
 280     #------------------------------------------------------------------- 
 282     def GenerateInitResourcesFile(self
, resourceFilename
, resourceDocument
): 
 283         # take only the filename portion out of resourceFilename 
 284         resourceFilename 
= os
.path
.split(resourceFilename
)[1] 
 286         outputList
.append(self
.templates
.LOAD_RES_FILE 
% locals()) 
 287         return "".join(outputList
) 
 289     #------------------------------------------------------------------- 
 291     def GetMemoryFilename(self
, filename
): 
 292         # Remove special chars from the filename 
 293         return re
.sub(r
"[^A-Za-z0-9_]", "_", filename
) 
 295     #------------------------------------------------------------------- 
 297     def FileToString(self
, filename
): 
 300         buffer = open(filename
, "rb").read() 
 301         fileLen 
= len(buffer) 
 304         for i 
in xrange(fileLen
): 
 310             elif c 
< 32 or c 
> 127 or s 
== "'": 
 319                 outputList
.append("\\\n") 
 321             outputList
.append(tmp
) 
 324         return "".join(outputList
) 
 326     #------------------------------------------------------------------- 
 328     def NodeContainsFilename(self
, node
): 
 329         """ Does 'node' contain filename information at all? """ 
 332         if node
.nodeName 
== "bitmap": 
 335         if node
.nodeName 
== "icon": 
 338         # URLs in wxHtmlWindow: 
 339         if node
.nodeName 
== "url": 
 343         parent 
= node
.parentNode
 
 344         if parent
.__class
__ != minidom
.Document 
and \
 
 345            parent
.getAttribute("class") == "wxBitmapButton" and \
 
 346            (node
.nodeName 
== "focus" or node
.nodeName 
== "disabled" or 
 347             node
.nodeName 
== "selected"): 
 350         # wxBitmap or wxIcon toplevel resources: 
 351         if node
.nodeName 
== "object": 
 352             klass 
= node
.getAttribute("class") 
 353             if klass 
== "wxBitmap" or klass 
== "wxIcon": 
 358     #------------------------------------------------------------------- 
 360     def ReplaceFilenamesInXRC(self
, node
, files
, resourcePath
): 
 361         """ Finds all files mentioned in resource file, e.g. <bitmap>filename</bitmap>  
 362         and replaces them with the memory filenames. 
 364         Fills a list of the filenames found.""" 
 366         # Is 'node' XML node element? 
 367         if node 
is None: return 
 368         if node
.nodeType 
!= minidom
.Document
.ELEMENT_NODE
: return 
 370         containsFilename 
= self
.NodeContainsFilename(node
); 
 372         for n 
in node
.childNodes
: 
 374             if (containsFilename 
and 
 375                 (n
.nodeType 
== minidom
.Document
.TEXT_NODE 
or 
 376                  n
.nodeType 
== minidom
.Document
.CDATA_SECTION_NODE
)): 
 378                 filename 
= n
.nodeValue
 
 379                 memoryFilename 
= self
.GetMemoryFilename(filename
) 
 380                 n
.nodeValue 
= memoryFilename
 
 382                 if filename 
not in files
: 
 383                     files
.append(filename
) 
 385             # Recurse into children 
 386             if n
.nodeType 
== minidom
.Document
.ELEMENT_NODE
: 
 387                 self
.ReplaceFilenamesInXRC(n
, files
, resourcePath
); 
 389     #------------------------------------------------------------------- 
 391     def FindStringsInNode(self
, parent
): 
 403         for child 
in parent
.childNodes
: 
 404             if ((parent
.nodeType 
== parent
.ELEMENT_NODE
) and 
 405                 # parent is an element, i.e. has subnodes... 
 406                 (child
.nodeType 
== child
.TEXT_NODE 
or 
 407                 child
.nodeType 
== child
.CDATA_SECTION_NODE
) and 
 408                 # ...it is textnode... 
 410                     parent
.tagName 
== "label" or 
 411                     (parent
.tagName 
== "value" and 
 412                                    not is_number(child
.nodeValue
)) or 
 413                     parent
.tagName 
== "help" or 
 414                     parent
.tagName 
== "longhelp" or 
 415                     parent
.tagName 
== "tooltip" or 
 416                     parent
.tagName 
== "htmlcode" or 
 417                     parent
.tagName 
== "title" or 
 418                     parent
.tagName 
== "item" 
 420                 # ...and known to contain translatable string 
 421                 if (parent
.getAttribute("translate") != "0"): 
 422                     strings
.append(self
.ConvertText(child
.nodeValue
)) 
 425             if child
.nodeType 
== child
.ELEMENT_NODE
: 
 426                 strings 
+= self
.FindStringsInNode(child
) 
 430     #------------------------------------------------------------------- 
 432     def ConvertText(self
, st
): 
 437         for i 
in range(len(dt
)): 
 455                 if dt
[i
+1] not in ['n', 't', 'r']: 
 464         return st2
.encode("UTF-8")                 
 467     #------------------------------------------------------------------- 
 469     def _OpenOutputFile(self
, outputFilename
): 
 470         if outputFilename 
== "-": 
 471             outputFile 
= sys
.stdout
 
 474                 outputFile 
= open(outputFilename
, "wt") 
 476                 raise IOError("Can't write output to '%s'" % outputFilename
) 
 483 #--------------------------------------------------------------------------- 
 486     resourceFilename 
= "" 
 487     outputFilename 
= None 
 488     embedResources 
= False 
 489     generateGetText 
= False 
 490     generatePython 
= False 
 493         opts
, args 
= getopt
.gnu_getopt(args
, 
 495                                        "help python gettext embed output=".split()) 
 496     except getopt
.GetoptError
, e
: 
 497         print "\nError : %s\n" % str(e
) 
 501     # If there is no input file argument, show help and exit 
 504         print "No xrc input file was specified." 
 507     # Parse options and arguments 
 508     for opt
, val 
in opts
: 
 509         if opt 
in ["-h", "--help"]: 
 513         if opt 
in ["-p", "--python"]: 
 514             generatePython 
= True 
 516         if opt 
in ["-o", "--output"]: 
 519         if opt 
in ["-e", "--embed"]: 
 520             embedResources 
= True 
 522         if opt 
in ["-g", "--gettext"]: 
 523             generateGetText 
= True 
 526     # check for and expand any wildcards in the list of input files 
 529         inputFiles 
+= glob
.glob(arg
) 
 532     comp 
= XmlResourceCompiler() 
 536             if not outputFilename
: 
 537                 outputFilename 
= os
.path
.splitext(args
[0])[0] + "_xrc.py" 
 538             comp
.MakePythonModule(inputFiles
, outputFilename
, 
 539                                   embedResources
, generateGetText
) 
 541         elif generateGetText
: 
 542             if not outputFilename
: 
 544             comp
.MakeGetTextOutput(inputFiles
, outputFilename
) 
 548             print "One or both of -p, -g must be specified." 
 553         print >>sys
.stderr
, "%s." % str(e
) 
 555         if outputFilename 
!= "-": 
 556             print >>sys
.stderr
, "Resources written to %s." % outputFilename
 
 558 if __name__ 
== "__main__":