]>
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__":