73b2a9a749
from Eli Golovinsky, with lots of additional mods by me. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@38618 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
359 lines
11 KiB
Python
359 lines
11 KiB
Python
#----------------------------------------------------------------------
|
|
# Name: wx.tools.pywxrc
|
|
# Purpose: XML resource compiler
|
|
#
|
|
# Author: Robin Dunn
|
|
# Based on wxrc.cpp by Vaclav Slavik, Eduardo Marques
|
|
# 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 -- Python XML resource compiler
|
|
|
|
Usage: python pywxrc.py -h
|
|
python pywxrc.py <resource.xrc> [-e] [-o filename]
|
|
|
|
-h, --help show help message
|
|
-e, --embed embed resources in output file
|
|
-o, --output output filename, or - for stdout
|
|
"""
|
|
|
|
import sys, os, getopt, glob, re
|
|
import xml.dom.minidom as minidom
|
|
import wx
|
|
import wx.xrc
|
|
|
|
#----------------------------------------------------------------------
|
|
|
|
class PythonTemplates:
|
|
FILE_HEADER = """\
|
|
# This file was automatically generated by pywxrc, do not edit by hand.
|
|
|
|
import wx
|
|
import wx.xrc as xrc
|
|
|
|
__res = None
|
|
|
|
def get_resources():
|
|
\"\"\" This function provides access to the XML resources in this module.\"\"\"
|
|
global __res
|
|
if __res == None:
|
|
__init_resources()
|
|
return __res
|
|
|
|
"""
|
|
|
|
CLASS_HEADER = """\
|
|
class %(windowName)sBase(wx.%(windowClass)s):
|
|
def PreCreate(self):
|
|
\"\"\" This function is called during the class's initialization.
|
|
|
|
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\")
|
|
"""
|
|
|
|
INIT_RESOURE_HEADER = """\
|
|
# -------------------------------------------------------------
|
|
# ------------------------ Resource data ----------------------
|
|
# -------------------------------------------------------------
|
|
|
|
def __init_resources():
|
|
"""
|
|
|
|
LOAD_RES_FILE = """\
|
|
global __res
|
|
__res = xrc.XmlResource('%(resourceFilename)s')
|
|
"""
|
|
|
|
FILE_AS_STRING = """\
|
|
%(filename)s = '''\\
|
|
%(fileData)s'''
|
|
|
|
|
|
"""
|
|
|
|
PREPARE_MEMFS = """\
|
|
# Load all the strings as memory files
|
|
|
|
wx.FileSystem.AddHandler(wx.MemoryFSHandler())
|
|
"""
|
|
|
|
ADD_FILE_TO_MEMFS = """\
|
|
wx.MemoryFSHandler.AddFile('XRC/%(memoryPath)s/%(filename)s', %(filename)s)
|
|
"""
|
|
|
|
LOAD_RES_MEMFS = """\
|
|
global __res
|
|
__res = xrc.EmptyXmlResource()
|
|
__res.Load('memory:XRC/%(memoryPath)s/%(resourceFilename)s')
|
|
"""
|
|
|
|
#----------------------------------------------------------------------
|
|
|
|
class XmlResourceCompiler:
|
|
|
|
templates = PythonTemplates()
|
|
|
|
"""This class generates Python code from XML resource files (XRC)."""
|
|
|
|
def MakePythonModule(self, resourceFilename, outputFilename, embedResources=False):
|
|
if outputFilename == "-":
|
|
outputFile = sys.stdout
|
|
else:
|
|
try:
|
|
outputFile = open(outputFilename, "wt")
|
|
except IOError:
|
|
raise IOError("Can't write output to '%s'" % outputFilename)
|
|
|
|
resourceDocument = minidom.parse(resourceFilename)
|
|
print >>outputFile, self.templates.FILE_HEADER
|
|
print >>outputFile, self.GenerateClasses(resourceDocument)
|
|
|
|
if embedResources:
|
|
print >>outputFile, self.GenerateInitResourcesEmbedded(resourceFilename, resourceDocument)
|
|
else:
|
|
print >>outputFile, self.GenerateInitResourcesFile(resourceFilename, resourceDocument)
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
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")
|
|
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 != "" and
|
|
widgetClass not in
|
|
['tool', 'unknown', 'notebookpage',
|
|
'separator', 'sizeritem', 'MenuItem']):
|
|
outputList.append(self.templates.CREATE_WIDGET_VAR % locals())
|
|
outputList.append('\n\n')
|
|
|
|
return "".join(outputList)
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
def GenerateInitResourcesEmbedded(self, resourceFilename, resourceDocument):
|
|
outputList = []
|
|
|
|
outputList.append(self.templates.INIT_RESOURE_HEADER)
|
|
|
|
files = []
|
|
|
|
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()
|
|
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())
|
|
|
|
outputList.append(self.templates.PREPARE_MEMFS % 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)
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
def GenerateInitResourcesFile(self, resourceFilename, resourceDocument):
|
|
outputList = []
|
|
outputList.append(self.templates.INIT_RESOURE_HEADER)
|
|
outputList.append(self.templates.LOAD_RES_FILE % locals())
|
|
return "".join(outputList)
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
def GetMemoryFilename(self, filename):
|
|
# Remove special chars from the filename
|
|
return re.sub(r"[^A-Za-z0-9_]", "_", filename)
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
def FileToString(self, filename):
|
|
outputList = []
|
|
|
|
buffer = open(filename, "rb").read()
|
|
fileLen = len(buffer)
|
|
|
|
linelng = 0
|
|
for i in xrange(fileLen):
|
|
s = buffer[i]
|
|
c = ord(s)
|
|
if s == '\n':
|
|
tmp = s
|
|
linelng = 0
|
|
elif c < 32 or c > 127 or s == "'":
|
|
tmp = "\\x%02x" % c
|
|
elif s == "\\":
|
|
tmp = "\\\\"
|
|
else:
|
|
tmp = s
|
|
|
|
if linelng > 70:
|
|
linelng = 0
|
|
outputList.append("\\\n")
|
|
|
|
outputList.append(tmp)
|
|
linelng += len(tmp)
|
|
|
|
return "".join(outputList)
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
def NodeContainsFilename(self, node):
|
|
""" Does 'node' contain filename information at all? """
|
|
|
|
# Any bitmaps:
|
|
if node.nodeName == "bitmap":
|
|
return True
|
|
|
|
if node.nodeName == "icon":
|
|
return True
|
|
|
|
# URLs in wxHtmlWindow:
|
|
if node.nodeName == "url":
|
|
return True
|
|
|
|
# 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
|
|
|
|
# wxBitmap or wxIcon toplevel resources:
|
|
if node.nodeName == "object":
|
|
klass = node.getAttribute("class")
|
|
if klass == "wxBitmap" or klass == "wxIcon":
|
|
return True
|
|
|
|
return False
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
def ReplaceFilenamesInXRC(self, node, files, resourcePath):
|
|
""" Finds all files mentioned in resource file, e.g. <bitmap>filename</bitmap>
|
|
and replaces them with the memory filenames.
|
|
|
|
Fills a list of the filenames found."""
|
|
|
|
# Is 'node' XML node element?
|
|
if node is None: return
|
|
if node.nodeType != minidom.Document.ELEMENT_NODE: return
|
|
|
|
containsFilename = self.NodeContainsFilename(node);
|
|
|
|
for n in node.childNodes:
|
|
|
|
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 main(args):
|
|
resourceFilename = ""
|
|
outputFilename = ""
|
|
embedResources = False
|
|
|
|
try:
|
|
opts, args = getopt.gnu_getopt(args, "heo:", "help embed output=".split())
|
|
except getopt.GetoptError:
|
|
print __doc__
|
|
sys.exit(1)
|
|
|
|
# If there is no input file argument, show help and exit
|
|
if args:
|
|
resourceFilename = args[0]
|
|
else:
|
|
print __doc__
|
|
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 ["-o", "--output"]:
|
|
outputFilename = val
|
|
|
|
if opt in ["-e", "--embed"]:
|
|
embedResources = True
|
|
|
|
if outputFilename is None or outputFilename == "":
|
|
outputFilename = os.path.splitext(resourceFilename)[0] + "_xrc.py"
|
|
|
|
comp = XmlResourceCompiler()
|
|
|
|
try:
|
|
comp.MakePythonModule(resourceFilename, outputFilename, embedResources)
|
|
except IOError, e:
|
|
print >>sys.stderr, "%s." % str(e)
|
|
else:
|
|
if outputFilename != "-":
|
|
print >>sys.stderr, "Resources written to %s." % outputFilename
|
|
|
|
if __name__ == "__main__":
|
|
main(sys.argv[1:])
|
|
|