X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/2e0ae50eca2072965af2714b918e79afcc1195c6..3ad84671d3668996da1e351e83c7d859fc094603:/wxPython/wx/tools/pywxrc.py diff --git a/wxPython/wx/tools/pywxrc.py b/wxPython/wx/tools/pywxrc.py index 178d45a6eb..f26fb00f4f 100644 --- a/wxPython/wx/tools/pywxrc.py +++ b/wxPython/wx/tools/pywxrc.py @@ -7,515 +7,301 @@ # Ported to Python in order to not require yet another # binary in wxPython distributions # +# Massive rework by Eli Golovinsky +# # RCS-ID: $Id$ # Copyright: (c) 2004 by Total Control Software, 2000 Vaclav Slavik # Licence: wxWindows license #---------------------------------------------------------------------- """ -pywxrc -- XML resource compiler - -Usage: wxrc [-h] [-v] [-e] [-c] [-p] [-g] [-n ] [-o ] input file(s)... - -h, --help show help message - -v, --verbose be verbose - -e, --extra-cpp-code output C++ header file with XRC derived classes - -c, --cpp-code output C++ source rather than .xrs file - -p, --python-code output wxPython source rather than .rsc file - -g, --gettext output list of translatable strings (to stdout or file if -o used) - -n, --function str C++/Python function name (with -c or -p) [InitXmlResource] - -o, --output str output file [resource.xrs/cpp/py] +pywxrc -- Python XML resource compiler + (see http://wiki.wxpython.org/index.cgi/pywxrc for more info) + +Usage: python pywxrc.py -h + python pywxrc.py [-p] [-g] [-e] [-o filename] xrc input files... + + -h, --help show help message + -p, --python generate python module + -g, --gettext output list of translatable strings (may be combined with -p) + -e, --embed embed XRC resources in the output file + -o, --output output filename, or - for stdout """ -import sys, os, getopt, glob +import sys, os, getopt, glob, re +import xml.dom.minidom as minidom import wx import wx.xrc - #---------------------------------------------------------------------- -class XRCWidgetData: - def __init__(self, vname, vclass): - self.name = vname - self.klass = vclass - def GetName(self): - return self.name - def GetClass(self): - return self.klass +class PythonTemplates: + FILE_HEADER = """\ +# This file was automatically generated by pywxrc, do not edit by hand. +# -*- coding: UTF-8 -*- +import wx +import wx.xrc as xrc -#---------------------------------------------------------------------- - -class XRCWndClassData: - def __init__(self, className, parentClassName, node): - self.className = className - self.parentClassName = parentClassName - self.BrowseXmlNode(node.GetChildren()) - self.wdata = [] - - - def BrowseXmlNode(self, node): - while node: - if node.GetName() == "object" and node.HasProp("class") and node.HasProp("name"): - classVal = node.GetPropVal("class", "") - nameVal = node.GetPropVal("name", "") - self.wdata.append(XRCWidgetData(nameVal, classVal)) - children = node.GetChildren() - if children: - self.BrowseXmlNode(children) - node = node.GetNext() +__res = None - - def GetWidgetData(self): - return self.wdata +def get_resources(): + \"\"\" This function provides access to the XML resources in this module.\"\"\" + global __res + if __res == None: + __init_resources() + return __res - - def IsRealClass(self, name): - if name in ['tool', 'unknown', 'notebookpage', 'separator', - 'sizeritem', 'wxMenuItem']: - return False - else: - return True - - - def GenerateHeaderCode(self, file): - file.write("class %s : public %s {\nprotected:\n" % (self.className, self.parentClassName)) +""" - for w in self.wdata: - if not self.IsRealClass(w.GetClass()): - continue - if not w.GetName(): - continue - file.write(" " + w.GetClass() + "* " + w.GetName() + ";\n") + CLASS_HEADER = """\ +class xrc%(windowName)s(wx.%(windowClass)s): + def PreCreate(self): + \"\"\" This function is called during the class's initialization. - file.write("\nprivate:\n void InitWidgetsFromXRC(){\n", - + " wxXmlResource::Get()->LoadObject(this,NULL,\"" - + self.className - + "\",\"" - + self.parentClassName - + "\");\n"); - - for w in self.wdata: - if not self.IsRealClass(w.GetClass()): - continue - if not w.GetName(): - continue - file.write( " " - + w.GetName() - + " = XRCCTRL(*this,\"" - + w.GetName() - + "\"," - + w.GetClass() - + ");\n") - - file.write(" }\n") - file.write("public:\n" - + self.className - + "::" - + self.className - + "(){\n" - + " InitWidgetsFromXRC();\n" - + " }\n" - + "};\n") - + Override it for custom setup before the window is created usually to + set additional window styles using SetWindowStyle() and SetExtraStyle().\"\"\" + pass + def __init__(self, parent): + # Two stage creation (see http://wiki.wxpython.org/index.cgi/TwoStageCreation) + pre = wx.Pre%(windowClass)s() + get_resources().LoadOn%(windowClass)s(pre, parent, "%(windowName)s") + self.PreCreate() + self.PostCreate(pre) -#---------------------------------------------------------------------- + # Define variables for the controls +""" + CREATE_WIDGET_VAR = """\ + self.%(widgetName)s = xrc.XRCCTRL(self, \"%(widgetName)s\") +""" -class XmlResApp: + MENU_CLASS_HEADER = """\ +class xrc%(windowName)s(wx.%(windowClass)s): def __init__(self): - self.flagVerbose = False - self.flagCPP = False - self.flagH = False - self.flagPython = False - self.flagGettext = False - self.parOutput = "" - self.parFuncname = "InitXmlResource" - self.parFiles = [] - self.aXRCWndClassData = [] - - - #-------------------------------------------------- - def main(self, args): - try: - opts, args = getopt.getopt(args, "hvecpgn:o:", - "help verbose extra-cpp-code cpp-code python-code gettext function= output=".split()) - except getopt.GetoptError: - print __doc__ - sys.exit(1) - - for opt, val in opts: - if opt in ["-h", "--help"]: - print __doc__ - sys.exit(1) - - if opt in ["-v", "--verbose"]: - self.flagVerbose = True - - if opt in ["-e", "--extra-cpp-code"]: - self.flagH = True - - if opt in ["-c", "--cpp-code"]: - self.flagCPP = True - - if opt in ["-p", "--python-code"]: - self.flagPython = True - - if opt in ["-g", "--gettext"]: - self.flagGettext = True - - if opt in ["-n", "--function"]: - self.parFuncname = val - - if opt in ["-o", "--output"]: - self.parOutput = val - - if self.flagCPP + self.flagPython + self.flagGettext == 0: - print __doc__ - print "\nYou must specify one of -c, -p or -g!\n" - sys.exit(1) - - if self.flagCPP + self.flagPython + self.flagGettext > 1: - print __doc__ - print "\n-c, -p and -g are mutually exclusive, specify only 1!\n" - sys.exit(1) - - - if self.parOutput: - self.parOutput = os.path.normpath(self.parOutput) - self.parOutputPath = os.path.split(self.parOutput)[0] - else: - self.parOutputPath = "." - if self.flagCPP: - self.parOutput = "resource.cpp" - elif self.flagPython: - self.parOutput = "resource.py" - elif self.flagGettext: - self.parOutput = "" - else: - self.parOutput = "resource.xrs" - - if not args: - print __doc__ - sys.exit(1) - for arg in args: - self.parFiles += glob.glob(arg) - - self.retCode = 0 - if self.flagGettext: - self.OutputGettext() - else: - self.CompileRes() - - - - #-------------------------------------------------- - def CompileRes(self): - files = self.PrepareTempFiles() - try: - os.unlink(self.parOutput) - except OSError: - pass - - if not self.retCode: - if self.flagCPP: - self.MakePackageCPP(files) - if self.flagH: - self.GenCPPHeader() - - elif self.flagPython: - self.MakePackagePython(files) + pre = get_resources().LoadMenu("%(windowName)s") + + # This is a copy of Robin's PostCreate voodoo magic in wx.Window that + # relinks the self object with the menu object. + self.this = pre.this + self.thisown = pre.thisown + pre.thisown = 0 + if hasattr(self, '_setOORInfo'): + self._setOORInfo(self) + if hasattr(self, '_setCallbackInfo'): + self._setCallbackInfo(self, self.__class__) + + # Define variables for the menu items +""" - else: - self.MakePackageZIP(files) + CREATE_MENUITEM_VAR = """\ + self.%(widgetName)s = self.FindItemById(xrc.XRCID(\"%(widgetName)s\")) +""" - self.DeleteTempFiles(files) + INIT_RESOURE_HEADER = """\ +# ------------------------ Resource data ---------------------- +def __init_resources(): + global __res + __res = xrc.EmptyXmlResource() +""" - #-------------------------------------------------- - def OutputGettext(self): - pass - + LOAD_RES_FILE = """\ + __res.Load('%(resourceFilename)s')""" - #-------------------------------------------------- - def GetInternalFileName(self, name, flist): - name2 = name; - name2 = name2.replace(":", "_") - name2 = name2.replace("/", "_") - name2 = name2.replace("\\", "_") - name2 = name2.replace("*", "_") - name2 = name2.replace("?", "_") - - s = os.path.split(self.parOutput)[1] + "$" + name2 - - if os.path.exists(s) and s not in flist: - i = 0 - while True: - s = os.path.split(self.parOutput)[1] + ("$%s%03d" % (name2, i)) - if not os.path.exists(s) or s in flist: - break - return s; - + FILE_AS_STRING = """\ + %(filename)s = '''\\ +%(fileData)s''' - #-------------------------------------------------- - def PrepareTempFiles(self): - flist = [] - for f in self.parFiles: - if self.flagVerbose: - print "processing %s..." % f +""" - doc = wx.xrc.EmptyXmlDocument() - - if not doc.Load(f): - print "Error parsing file", f - self.retCode = 1 - continue + PREPARE_MEMFS = """\ + wx.FileSystem.AddHandler(wx.MemoryFSHandler()) +""" - path, name = os.path.split(f) - name, ext = os.path.splitext(name) + ADD_FILE_TO_MEMFS = """\ + wx.MemoryFSHandler.AddFile('XRC/%(memoryPath)s/%(filename)s', %(filename)s) +""" - self.FindFilesInXML(doc.GetRoot(), flist, path) - if self.flagH: - node = doc.GetRoot().GetChildren() - while node: - if node.GetName() == "object" and node.HasProp("class") and node.HasProp("name"): - classVal = node.GetPropVal("class", "") - nameVal = node.GetPropVal("name", "") - self.aXRCWndClassData.append(XRCWidgetData(nameVal, classVal)) - node = node.GetNext() - internalName = self.GetInternalFileName(f, flist) + LOAD_RES_MEMFS = """\ + __res.Load('memory:XRC/%(memoryPath)s/%(resourceFilename)s') +""" - doc.Save(os.path.join(self.parOutputPath, internalName)) - flist.append(internalName) + GETTEXT_DUMMY_FUNC = """ +# ----------------------- Gettext strings --------------------- - return flist +def __gettext_strings(): + # This is a dummy function that lists all the strings that are used in + # the XRC file in the _("a string") format to be recognized by GNU + # gettext utilities (specificaly the xgettext utility) and the + # mki18n.py script. For more information see: + # http://wiki.wxpython.org/index.cgi/Internationalization + def _(str): pass - #-------------------------------------------------- - # Does 'node' contain filename information at all? - def NodeContainsFilename(self, node): - # Any bitmaps: - if node.GetName() == "bitmap": - return True - - # URLs in wxHtmlWindow: - if node.GetName() == "url": - return True - - # wxBitmapButton: - parent = node.GetParent() - if parent != None and \ - parent.GetPropVal("class", "") == "wxBitmapButton" and \ - (node.GetName() == "focus" or node.etName() == "disabled" or - node.GetName() == "selected"): - return True - - # wxBitmap or wxIcon toplevel resources: - if node.GetName() == "object": - klass = node.GetPropVal("class", "") - if klass == "wxBitmap" or klass == "wxIcon": - return True - - return False - - #-------------------------------------------------- - # find all files mentioned in structure, e.g. filename - def FindFilesInXML(self, node, flist, inputPath): - # Is 'node' XML node element? - if node is None: return - if node.GetType() != wx.xrc.XML_ELEMENT_NODE: return - - containsFilename = self.NodeContainsFilename(node); - - n = node.GetChildren() - while n: - if (containsFilename and - (n.GetType() == wx.xrc.XML_TEXT_NODE or - n.GetType() == wx.xrc.XML_CDATA_SECTION_NODE)): - - if os.path.isabs(n.GetContent()) or inputPath == "": - fullname = n.GetContent() - else: - fullname = os.path.join(inputPath, n.GetContent()) - - if self.flagVerbose: - print "adding %s..." % fullname - - filename = self.GetInternalFileName(n.GetContent(), flist) - n.SetContent(filename) - - if filename not in flist: - flist.append(filename) - - inp = open(fullname) - out = open(os.path.join(self.parOutputPath, filename), "w") - out.write(inp.read()) +%s +""" - # subnodes: - if n.GetType() == wx.xrc.XML_ELEMENT_NODE: - self.FindFilesInXML(n, flist, inputPath); +#---------------------------------------------------------------------- - n = n.GetNext() +class XmlResourceCompiler: + templates = PythonTemplates() + """This class generates Python code from XML resource files (XRC).""" - #-------------------------------------------------- - def DeleteTempFiles(self, flist): - for f in flist: - os.unlink(os.path.join(self.parOutputPath, f)) + def MakePythonModule(self, inputFiles, outputFilename, + embedResources=False, generateGetText=False): + outputFile = self._OpenOutputFile(outputFilename) - #-------------------------------------------------- - def MakePackageZIP(self, flist): - files = " ".join(flist) + classes = [] + resources = [] + gettextStrings = [] - if self.flagVerbose: - print "compressing %s..." % self.parOutput + # process all the inputFiles, collecting the output data + for inFile in inputFiles: + resourceDocument = minidom.parse(inFile) + classes.append(self.GenerateClasses(resourceDocument)) - cwd = os.getcwd() - os.chdir(self.parOutputPath) - cmd = "zip -9 -j " - if not self.flagVerbose: - cmd += "-q " - cmd += self.parOutput + " " + files + if embedResources: + res = self.GenerateInitResourcesEmbedded(inFile, resourceDocument) + else: + res = self.GenerateInitResourcesFile(inFile, resourceDocument) + resources.append(res) - from distutils.spawn import spawn - try: - spawn(cmd.split()) - success = True - except: - success = False + if generateGetText: + gettextStrings += self.FindStringsInNode(resourceDocument.firstChild) + + # now write it all out + print >>outputFile, self.templates.FILE_HEADER + + # Note: Technically it is not legal to have anything other + # than ascii for class and variable names, but since the user + # can create the XML with non-ascii names we'll go ahead and + # allow for it here, and then let Python complain about it + # later when they try to run the program. + classes = u"\n".join(classes) + print >>outputFile, classes.encode("UTF-8") + + print >>outputFile, self.templates.INIT_RESOURE_HEADER + if embedResources: + print >>outputFile, self.templates.PREPARE_MEMFS + resources = u"\n".join(resources) + print >>outputFile, resources.encode("UTF-8") + + if generateGetText: + # These have already been converted to utf-8... + gettextStrings = [' _("%s")' % s for s in gettextStrings] + gettextStrings = "\n".join(gettextStrings) + print >>outputFile, self.templates.GETTEXT_DUMMY_FUNC % gettextStrings + + #------------------------------------------------------------------- + + def MakeGetTextOutput(self, inputFiles, outputFilename): + """ + Just output the gettext strings by themselves, with no other + code generation. + """ + outputFile = self._OpenOutputFile(outputFilename) + for inFile in inputFiles: + resourceDocument = minidom.parse(inFile) + resource = resourceDocument.firstChild + strings = self.FindStringsInNode(resource) + strings = ['_("%s");' % s for s in strings] + print >>outputFile, "\n".join(strings) + + #------------------------------------------------------------------- + + def GenerateClasses(self, resourceDocument): + outputList = [] + + resource = resourceDocument.firstChild + topWindows = [e for e in resource.childNodes + if e.nodeType == e.ELEMENT_NODE and e.tagName == "object"] + + # Generate a class for each top-window object (Frame, Panel, Dialog, etc.) + for topWindow in topWindows: + windowClass = topWindow.getAttribute("class") + windowClass = re.sub("^wx", "", windowClass) + windowName = topWindow.getAttribute("name") - os.chdir(cwd) - - if not success: - print "Unable to execute zip program. Make sure it is in the path." - print "You can download it at http://www.cdrom.com/pub/infozip/" - self.retCode = 1 - + if windowClass == "Menu": + outputList.append(self.templates.MENU_CLASS_HEADER % locals()) + else: + outputList.append(self.templates.CLASS_HEADER % locals()) + + # Generate a variable for each control, and standard event handlers + # for standard controls. + for widget in topWindow.getElementsByTagName("object"): + widgetClass = widget.getAttribute("class") + widgetClass = re.sub("^wx", "", widgetClass) + widgetName = widget.getAttribute("name") + if (widgetName != "" and widgetClass != ""): + if widgetClass == "MenuItem": + outputList.append(self.templates.CREATE_MENUITEM_VAR % locals()) + elif widgetClass not in \ + ['tool', 'unknown', 'notebookpage', 'separator', 'sizeritem']: + outputList.append(self.templates.CREATE_WIDGET_VAR % locals()) + outputList.append('\n\n') + + return "".join(outputList) - #-------------------------------------------------- - def FileToCppArray(self, filename, num): - output = [] - buffer = open(filename, "rb").read() - lng = len(buffer) + #------------------------------------------------------------------- - output.append("static size_t xml_res_size_%d = %d;\n" % (num, lng)) - output.append("static unsigned char xml_res_file_%d[] = {\n" % num) - # we cannot use string literals because MSVC is dumb wannabe compiler - # with arbitrary limitation to 2048 strings :( + def GenerateInitResourcesEmbedded(self, resourceFilename, resourceDocument): + outputList = [] + files = [] - linelng = 0 - for i in xrange(lng): - tmp = "%i" % ord(buffer[i]) - if i != 0: output.append(',') - if linelng > 70: - linelng = 0 - output.append("\n") + resourcePath = os.path.split(resourceFilename)[0] + memoryPath = self.GetMemoryFilename(os.path.splitext(os.path.split(resourceFilename)[1])[0]) + resourceFilename = self.GetMemoryFilename(os.path.split(resourceFilename)[1]) + + self.ReplaceFilenamesInXRC(resourceDocument.firstChild, files, resourcePath) + + filename = resourceFilename + fileData = resourceDocument.toxml() # what about this? encoding=resourceDocument.encoding) + outputList.append(self.templates.FILE_AS_STRING % locals()) + + for f in files: + filename = self.GetMemoryFilename(f) + fileData = self.FileToString(os.path.join(resourcePath, f)) + outputList.append(self.templates.FILE_AS_STRING % locals()) + + for f in [resourceFilename] + files: + filename = self.GetMemoryFilename(f) + outputList.append(self.templates.ADD_FILE_TO_MEMFS % locals()) + + outputList.append(self.templates.LOAD_RES_MEMFS % locals()) + + return "".join(outputList) - output.append(tmp) - linelng += len(tmp)+1 + #------------------------------------------------------------------- - output.append("};\n\n") + def GenerateInitResourcesFile(self, resourceFilename, resourceDocument): + # take only the filename portion out of resourceFilename + resourceFilename = os.path.split(resourceFilename)[1] + outputList = [] + outputList.append(self.templates.LOAD_RES_FILE % locals()) + return "".join(outputList) - return "".join(output) + #------------------------------------------------------------------- + def GetMemoryFilename(self, filename): + # Remove special chars from the filename + return re.sub(r"[^A-Za-z0-9_]", "_", filename) - - #-------------------------------------------------- - def MakePackageCPP(self, flist): - file = open(self.parOutput, "wt") - - if self.flagVerbose: - print "creating C++ source file %s..." % self.parOutput - - file.write("""\ -// -// This file was automatically generated by wxrc, do not edit by hand. -// - -#include - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include -#endif - -#include -#include -#include -#include - -""") - - num = 0 - for f in flist: - file.write(self.FileToCppArray(os.path.join(self.parOutputPath, f), num)) - num += 1 - - - file.write("void " + self.parFuncname + "()\n") - file.write("""\ -{ - - // Check for memory FS. If not present, load the handler: - { - wxMemoryFSHandler::AddFile(wxT(\"XRC_resource/dummy_file\"), wxT(\"dummy one\")); - wxFileSystem fsys; - wxFSFile *f = fsys.OpenFile(wxT(\"memory:XRC_resource/dummy_file\")); - wxMemoryFSHandler::RemoveFile(wxT(\"XRC_resource/dummy_file\")); - if (f) delete f; - else wxFileSystem::AddHandler(new wxMemoryFSHandler); - } -"""); - - for i in range(len(flist)): - file.write(" wxMemoryFSHandler::AddFile(wxT(\"XRC_resource/" + flist[i]) - file.write("\"), xml_res_file_%i, xml_res_size_%i);\n" %(i, i)) - - - for i in range(len(self.parFiles)): - file.write(" wxXmlResource::Get()->Load(wxT(\"memory:XRC_resource/" + - self.GetInternalFileName(self.parFiles[i], flist) + - "\"));\n") - - file.write("}\n") - - - #-------------------------------------------------- - def GenCPPHeader(self): - path, name = os.path.split(self.parOutput) - name, ext = os.path.splitext(name) - heaFileName = name+'.h' - - file = open(heaFileName, "wt") - file.write("""\ -// -// This file was automatically generated by wxrc, do not edit by hand. -// -"""); - file.write("#ifndef __" + name + "_h__\n") - file.write("#define __" + name + "_h__\n") - - for data in self.aXRCWndClassData: - data.GenerateHeaderCode(file) - - file.write("\nvoid \n" + self.parFuncname + "();\n#endif\n") - + #------------------------------------------------------------------- - #-------------------------------------------------- - def FileToPythonArray(self, filename, num): - output = [] + def FileToString(self, filename): + outputList = [] + buffer = open(filename, "rb").read() - lng = len(buffer) - - output.append(" xml_res_file_%d = '''\\\n" % num) + fileLen = len(buffer) linelng = 0 - for i in xrange(lng): + for i in xrange(fileLen): s = buffer[i] c = ord(s) if s == '\n': @@ -530,95 +316,119 @@ class XmlResApp: if linelng > 70: linelng = 0 - output.append("\\\n") - - output.append(tmp) + outputList.append("\\\n") + + outputList.append(tmp) linelng += len(tmp) + + return "".join(outputList) + + #------------------------------------------------------------------- - output.append("'''\n\n") + def NodeContainsFilename(self, node): + """ Does 'node' contain filename information at all? """ - return "".join(output) + # Any bitmaps: + if node.nodeName == "bitmap": + return True - #-------------------------------------------------- - def MakePackagePython(self, flist): - file = open(self.parOutput, "wt") + if node.nodeName == "icon": + return True - if self.flagVerbose: - print "creating Python source file %s..." % self.parOutput - - file.write("""\ -# -# This file was automatically generated by wxrc, do not edit by hand. -# + # URLs in wxHtmlWindow: + if node.nodeName == "url": + return True -import wx -import wx.xrc + # wxBitmapButton: + parent = node.parentNode + if parent.__class__ != minidom.Document and \ + parent.getAttribute("class") == "wxBitmapButton" and \ + (node.nodeName == "focus" or node.nodeName == "disabled" or + node.nodeName == "selected"): + return True -""") - file.write("def " + self.parFuncname + "():\n") - - num = 0 - for f in flist: - file.write(self.FileToPythonArray(os.path.join(self.parOutputPath, f), num)) - num += 1 + # wxBitmap or wxIcon toplevel resources: + if node.nodeName == "object": + klass = node.getAttribute("class") + if klass == "wxBitmap" or klass == "wxIcon": + return True - file.write(""" - - # check if the memory filesystem handler has been loaded yet, and load it if not - wx.MemoryFSHandler.AddFile('XRC_resource/dummy_file', 'dummy value') - fsys = wx.FileSystem() - f = fsys.OpenFile('memory:XRC_resource/dummy_file') - wx.MemoryFSHandler.RemoveFile('XRC_resource/dummy_file') - if f is not None: - f.Destroy() - else: - wx.FileSystem.AddHandler(wx.MemoryFSHandler()) + return False - # load all the strings as memory files and load into XmlRes -""") - - for i in range(len(flist)): - file.write(" wx.MemoryFSHandler.AddFile('XRC_resource/" + flist[i] + - "', xml_res_file_%i)\n" % i) + #------------------------------------------------------------------- - for pf in self.parFiles: - file.write(" wx.xrc.XmlResource.Get().Load('memory:XRC_resource/" + - self.GetInternalFileName(pf, flist) + "')\n") - + def ReplaceFilenamesInXRC(self, node, files, resourcePath): + """ Finds all files mentioned in resource file, e.g. filename + and replaces them with the memory filenames. + + Fills a list of the filenames found.""" - #-------------------------------------------------- - def OutputGettext(self): - strings = self.FindStrings() + # Is 'node' XML node element? + if node is None: return + if node.nodeType != minidom.Document.ELEMENT_NODE: return - if not self.parOutput: - out = sys.stdout - else: - out = open(self.parOutput, "wt") + containsFilename = self.NodeContainsFilename(node); - for st in strings: - out.write("_(\"%s\")\n" % st) - + for n in node.childNodes: - - #-------------------------------------------------- - def FindStrings(self): + if (containsFilename and + (n.nodeType == minidom.Document.TEXT_NODE or + n.nodeType == minidom.Document.CDATA_SECTION_NODE)): + + filename = n.nodeValue + memoryFilename = self.GetMemoryFilename(filename) + n.nodeValue = memoryFilename + + if filename not in files: + files.append(filename) + + # Recurse into children + if n.nodeType == minidom.Document.ELEMENT_NODE: + self.ReplaceFilenamesInXRC(n, files, resourcePath); + + #------------------------------------------------------------------- + + def FindStringsInNode(self, parent): + def is_number(st): + try: + i = int(st) + return True + except ValueError: + return False + strings = [] - for pf in self.parFiles: - if self.flagVerbose: - print "processing %s..." % pf - - doc = wx.xrc.EmptyXmlDocument() - if not doc.Load(pf): - print "Error parsing file", pf - self.retCode = 1 - continue + if parent is None: + return strings; + + for child in parent.childNodes: + if ((parent.nodeType == parent.ELEMENT_NODE) and + # parent is an element, i.e. has subnodes... + (child.nodeType == child.TEXT_NODE or + child.nodeType == child.CDATA_SECTION_NODE) and + # ...it is textnode... + ( + parent.tagName == "label" or + (parent.tagName == "value" and + not is_number(child.nodeValue)) or + parent.tagName == "help" or + parent.tagName == "longhelp" or + parent.tagName == "tooltip" or + parent.tagName == "htmlcode" or + parent.tagName == "title" or + parent.tagName == "item" + )): + # ...and known to contain translatable string + if (parent.getAttribute("translate") != "0"): + strings.append(self.ConvertText(child.nodeValue)) - strings += self.FindStringsInNode(doc.GetRoot()) + # subnodes: + if child.nodeType == child.ELEMENT_NODE: + strings += self.FindStringsInNode(child) return strings - - - #-------------------------------------------------- + + #------------------------------------------------------------------- + def ConvertText(self, st): st2 = "" dt = list(st) @@ -651,61 +461,100 @@ import wx.xrc else: st2 += dt[i] - return st2 - - - - #-------------------------------------------------- - def FindStringsInNode(self, parent): - def is_number(st): - try: - i = int(st) - return True - except ValueError: - return False - - strings = [] - if parent is None: - return strings; - child = parent.GetChildren() + return st2.encode("UTF-8") - while child: - if ((parent.GetType() == wx.xrc.XML_ELEMENT_NODE) and - # parent is an element, i.e. has subnodes... - (child.GetType() == wx.xrc.XML_TEXT_NODE or - child.GetType() == wx.xrc.XML_CDATA_SECTION_NODE) and - # ...it is textnode... - ( - parent.GetName() == "label" or - (parent.GetName() == "value" and - not is_number(child.GetContent())) or - parent.GetName() == "help" or - parent.GetName() == "longhelp" or - parent.GetName() == "tooltip" or - parent.GetName() == "htmlcode" or - parent.GetName() == "title" or - parent.GetName() == "item" - )): - # ...and known to contain translatable string - if (not self.flagGettext or - parent.GetPropVal("translate", "1") != "0"): - strings.append(self.ConvertText(child.GetContent())) + #------------------------------------------------------------------- - # subnodes: - if child.GetType() == wx.xrc.XML_ELEMENT_NODE: - strings += self.FindStringsInNode(child) + def _OpenOutputFile(self, outputFilename): + if outputFilename == "-": + outputFile = sys.stdout + else: + try: + outputFile = open(outputFilename, "wt") + except IOError: + raise IOError("Can't write output to '%s'" % outputFilename) + return outputFile + + - child = child.GetNext() - return strings #--------------------------------------------------------------------------- -def main(): - XmlResApp().main(sys.argv[1:]) +def main(args): + resourceFilename = "" + outputFilename = None + embedResources = False + generateGetText = False + generatePython = False + + try: + opts, args = getopt.gnu_getopt(args, + "hpgeo:", + "help python gettext embed output=".split()) + except getopt.GetoptError, e: + print "\nError : %s\n" % str(e) + print __doc__ + sys.exit(1) + + # If there is no input file argument, show help and exit + if not args: + print __doc__ + print "No xrc input file was specified." + sys.exit(1) + + # Parse options and arguments + for opt, val in opts: + if opt in ["-h", "--help"]: + print __doc__ + sys.exit(1) + + if opt in ["-p", "--python"]: + generatePython = True + if opt in ["-o", "--output"]: + outputFilename = val + + if opt in ["-e", "--embed"]: + embedResources = True + + if opt in ["-g", "--gettext"]: + generateGetText = True + + + # check for and expand any wildcards in the list of input files + inputFiles = [] + for arg in args: + inputFiles += glob.glob(arg) + + + comp = XmlResourceCompiler() + + try: + if generatePython: + if not outputFilename: + outputFilename = os.path.splitext(args[0])[0] + "_xrc.py" + comp.MakePythonModule(inputFiles, outputFilename, + embedResources, generateGetText) + + elif generateGetText: + if not outputFilename: + outputFilename = '-' + comp.MakeGetTextOutput(inputFiles, outputFilename) + + else: + print __doc__ + print "One or both of -p, -g must be specified." + sys.exit(1) + + + except IOError, e: + print >>sys.stderr, "%s." % str(e) + else: + if outputFilename != "-": + print >>sys.stderr, "Resources written to %s." % outputFilename if __name__ == "__main__": - main() + main(sys.argv[1:])