mirror of
https://github.com/Sneed-Group/Poodletooth-iLand
synced 2024-12-27 05:32:41 -06:00
933 lines
33 KiB
Python
933 lines
33 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
|
|
#
|
|
# Editable blocks by Roman Rolinsky
|
|
#
|
|
# Copyright: (c) 2004 by Total Control Software, 2000 Vaclav Slavik
|
|
# Licence: wxWindows license
|
|
# Tags: phoenix-port
|
|
#----------------------------------------------------------------------
|
|
|
|
"""
|
|
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] [-v] [-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
|
|
-v, --novar suppress default assignment of variables
|
|
-o, --output output filename, or - for stdout
|
|
"""
|
|
|
|
import sys, os, getopt, glob, re, cPickle
|
|
import xml.dom.minidom as minidom
|
|
import wx
|
|
import wx.xrc
|
|
from wx.lib.six import print_
|
|
|
|
#----------------------------------------------------------------------
|
|
|
|
reBeginBlock = re.compile(r'^#!XRCED:begin-block:(\S+)')
|
|
reEndBlock = re.compile(r'^#!XRCED:end-block:(\S+)')
|
|
|
|
class PythonTemplates:
|
|
FILE_HEADER = """\
|
|
# This file was automatically generated by pywxrc.
|
|
# -*- coding: UTF-8 -*-
|
|
|
|
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 xrc%(windowName)s(wx.%(windowClass)s):
|
|
#!XRCED:begin-block:xrc%(windowName)s.PreCreate
|
|
def PreCreate(self, pre):
|
|
\"\"\" 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
|
|
|
|
#!XRCED:end-block:xrc%(windowName)s.PreCreate
|
|
|
|
def __init__(self, parent):
|
|
# Two stage creation (see http://wiki.wxpython.org/index.cgi/TwoStageCreation)
|
|
pre = wx.Pre%(windowClass)s()
|
|
self.PreCreate(pre)
|
|
get_resources().LoadOn%(windowClass)s(pre, parent, "%(windowName)s")
|
|
self.PostCreate(pre)
|
|
|
|
# Define variables for the controls, bind event handlers
|
|
"""
|
|
|
|
SUBCLASS_HEADER = """\
|
|
class %(subclass)s(wx.%(windowClass)s):
|
|
def __init__(self):
|
|
# Two stage creation (see http://wiki.wxpython.org/index.cgi/TwoStageCreation)
|
|
pre = wx.Pre%(windowClass)s()
|
|
self.PostCreate(pre)
|
|
self.Bind(wx.EVT_WINDOW_CREATE, self.OnCreate)
|
|
|
|
#!XRCED:begin-block:%(subclass)s._PostInit
|
|
def _PostInit(self):
|
|
\"\"\" This function is called after the subclassed object is created.
|
|
|
|
Override it for custom setup before the window is created usually to
|
|
set additional window styles using SetWindowStyle() and SetExtraStyle().
|
|
\"\"\"
|
|
pass
|
|
#!XRCED:end-block:%(subclass)s._PostInit
|
|
|
|
def OnCreate(self, evt):
|
|
self.Unbind(wx.EVT_WINDOW_CREATE)
|
|
self._PostInit()
|
|
"""
|
|
|
|
CREATE_WIDGET_VAR = """\
|
|
self.%(widgetName)s = xrc.XRCCTRL(self, \"%(widgetName)s\")
|
|
"""
|
|
|
|
FRAME_MENUBAR_VAR = """\
|
|
self.%(widgetName)s = self.GetMenuBar()
|
|
"""
|
|
|
|
FRAME_MENUBAR_MENUITEM_VAR = """\
|
|
self.%(widgetName)s = self.GetMenuBar().FindItemById(xrc.XRCID(\"%(widgetName)s\"))
|
|
"""
|
|
|
|
FRAME_MENUBAR_MENU_VAR = """\
|
|
idx = self.GetMenuBar().FindMenu(\"%(label)s\")
|
|
if idx != wx.NOT_FOUND:
|
|
self.%(widgetName)s = self.GetMenuBar().GetMenu(idx)
|
|
else:
|
|
self.%(widgetName)s = self.GetMenuBar().FindItemById(xrc.XRCID(\"%(widgetName)s\")).GetSubMenu()
|
|
"""
|
|
|
|
|
|
MENUBAR_MENUITEM_VAR = """\
|
|
self.%(widgetName)s = self.FindItemById(xrc.XRCID(\"%(widgetName)s\"))
|
|
"""
|
|
|
|
MENUBAR_MENU_VAR = """\
|
|
idx = self.FindMenu(\"%(label)s\")
|
|
if idx != wx.NOT_FOUND:
|
|
self.%(widgetName)s = self.GetMenu(idx)
|
|
else:
|
|
self.%(widgetName)s = self.FindItemById(xrc.XRCID(\"%(widgetName)s\")).GetSubMenu()
|
|
"""
|
|
|
|
MENU_MENUITEM_VAR = """\
|
|
self.%(widgetName)s = self.FindItemById(xrc.XRCID(\"%(widgetName)s\"))
|
|
"""
|
|
|
|
MENU_MENU_VAR = """\
|
|
self.%(widgetName)s = self.FindItemById(xrc.XRCID(\"%(widgetName)s\")).GetSubMenu()
|
|
"""
|
|
|
|
FRAME_TOOLBAR_VAR = """\
|
|
self.%(widgetName)s = self.GetToolBar()
|
|
"""
|
|
|
|
FRAME_TOOLBAR_TOOL_VAR = """\
|
|
self.%(widgetName)s = self.GetToolBar().FindById(xrc.XRCID(\"%(widgetName)s\"))
|
|
"""
|
|
|
|
TOOLBAR_TOOL_VAR = """\
|
|
self.%(widgetName)s = self.FindById(xrc.XRCID(\"%(widgetName)s\"))
|
|
"""
|
|
|
|
BIND_WIDGET_EVENT = """\
|
|
self.Bind(wx.%(event)s, self.%(eventHandler)s, %(eventObject)s)
|
|
"""
|
|
|
|
BIND_EVENT = """\
|
|
self.Bind(wx.%(event)s, self.%(eventHandler)s)
|
|
"""
|
|
|
|
CREATE_EVENT_HANDLER = """\
|
|
#!XRCED:begin-block:xrc%(windowName)s.%(eventHandler)s
|
|
def %(eventHandler)s(self, evt):
|
|
# Replace with event handler code
|
|
print(\"%(eventHandler)s()\")
|
|
#!XRCED:end-block:xrc%(windowName)s.%(eventHandler)s
|
|
"""
|
|
|
|
MENU_CLASS_HEADER = """\
|
|
class xrc%(windowName)s(wx.%(windowClass)s):
|
|
def __init__(self):
|
|
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)
|
|
|
|
# Define variables for the menu items
|
|
"""
|
|
|
|
MENUBAR_CLASS_HEADER = """\
|
|
class xrc%(windowName)s(wx.%(windowClass)s):
|
|
def __init__(self):
|
|
pre = get_resources().LoadMenuBar("%(windowName)s")
|
|
self.PostCreate(pre)
|
|
|
|
# Define variables for the menu items
|
|
"""
|
|
|
|
TOOLBAR_CLASS_HEADER = """\
|
|
class xrc%(windowName)s(wx.%(windowClass)s):
|
|
def __init__(self, parent):
|
|
pre = get_resources().LoadToolBar(parent, "%(windowName)s")
|
|
self.PostCreate(pre)
|
|
|
|
# Define variables for the toolbar items
|
|
"""
|
|
|
|
INIT_RESOURE_HEADER = """\
|
|
# ------------------------ Resource data ----------------------
|
|
|
|
def __init_resources():
|
|
global __res
|
|
__res = xrc.EmptyXmlResource()
|
|
"""
|
|
|
|
LOAD_RES_FILE = """\
|
|
__res.Load('%(resourceFilename)s')"""
|
|
|
|
FILE_AS_STRING = """\
|
|
%(filename)s = '''\\
|
|
%(fileData)s'''
|
|
|
|
"""
|
|
|
|
PREPARE_MEMFS = """\
|
|
wx.FileSystem.AddHandler(wx.MemoryFSHandler())
|
|
"""
|
|
|
|
ADD_FILE_TO_MEMFS = """\
|
|
wx.MemoryFSHandler.AddFile('XRC/%(memoryPath)s/%(filename)s', %(filename)s)
|
|
"""
|
|
|
|
LOAD_RES_MEMFS = """\
|
|
__res.Load('memory:XRC/%(memoryPath)s/%(resourceFilename)s')
|
|
"""
|
|
|
|
GETTEXT_DUMMY_FUNC = """
|
|
# ----------------------- Gettext strings ---------------------
|
|
|
|
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
|
|
|
|
%s
|
|
"""
|
|
|
|
#----------------------------------------------------------------------
|
|
|
|
class XmlResourceCompiler:
|
|
|
|
templates = PythonTemplates()
|
|
|
|
"""This class generates Python code from XML resource files (XRC)."""
|
|
|
|
def MakePythonModule(self, inputFiles, outputFilename,
|
|
embedResources=False, generateGetText=False,
|
|
assignVariables=True):
|
|
|
|
self.blocks = {}
|
|
self.outputFilename = outputFilename
|
|
outputFile = self._OpenOutputFile(outputFilename)
|
|
self.assignVariables = assignVariables
|
|
|
|
classes = []
|
|
subclasses = []
|
|
resources = []
|
|
gettextStrings = []
|
|
|
|
# process all the inputFiles, collecting the output data
|
|
for inFile in inputFiles:
|
|
resourceDocument = minidom.parse(inFile)
|
|
subclasses.append(self.GenerateSubclasses(resourceDocument))
|
|
classes.append(self.GenerateClasses(resourceDocument))
|
|
|
|
if embedResources:
|
|
res = self.GenerateInitResourcesEmbedded(inFile, resourceDocument)
|
|
else:
|
|
res = self.GenerateInitResourcesFile(inFile, resourceDocument)
|
|
resources.append(res)
|
|
|
|
if generateGetText:
|
|
gettextStrings += self.FindStringsInNode(resourceDocument.firstChild)
|
|
|
|
# now write it all out
|
|
print_(self.templates.FILE_HEADER, file=outputFile)
|
|
|
|
# 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.
|
|
if subclasses:
|
|
subclasses = self.ReplaceBlocks(u"\n".join(subclasses))
|
|
print_(subclasses.encode("UTF-8"), file=outputFile)
|
|
if classes:
|
|
classes = self.ReplaceBlocks(u"\n".join(classes))
|
|
print_(classes.encode("UTF-8"), file=outputFile)
|
|
|
|
print_(self.templates.INIT_RESOURE_HEADER, file=outputFile)
|
|
if embedResources:
|
|
print_(self.templates.PREPARE_MEMFS, file=outputFile)
|
|
resources = u"\n".join(resources)
|
|
print_(resources.encode("UTF-8"), file=outputFile)
|
|
|
|
if generateGetText:
|
|
# These have already been converted to utf-8...
|
|
gettextStrings = [' _("%s")' % s for s in gettextStrings]
|
|
gettextStrings = "\n".join(gettextStrings)
|
|
print_(self.templates.GETTEXT_DUMMY_FUNC % gettextStrings, file=outputFile)
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
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_("\n".join(strings), file=outputFile)
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
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" \
|
|
and not e.getAttribute('subclass')]
|
|
|
|
# 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")
|
|
if not windowName: continue
|
|
|
|
if windowClass in ["MenuBar"]:
|
|
genfunc = self.GenerateMenuBarClass
|
|
elif windowClass in ["Menu"]:
|
|
genfunc = self.GenerateMenuClass
|
|
elif windowClass in ["ToolBar"]:
|
|
genfunc = self.GenerateToolBarClass
|
|
else:
|
|
genfunc = self.GenerateWidgetClass
|
|
|
|
vars = []
|
|
outputList += genfunc(windowClass, windowName, topWindow, vars)
|
|
outputList.append('\n')
|
|
|
|
outputList += self.GenerateEventHandlers(windowClass, windowName, topWindow, vars)
|
|
|
|
return "".join(outputList)
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
def CheckAssignVar(self, widget):
|
|
if self.assignVariables: return True # assign_var override mode
|
|
assign_var = False
|
|
for node in widget.getElementsByTagName("XRCED"):
|
|
if node.parentNode is widget:
|
|
try:
|
|
elem = node.getElementsByTagName("assign_var")[0]
|
|
except IndexError:
|
|
continue
|
|
if elem.childNodes:
|
|
ch = elem.childNodes[0]
|
|
if ch.nodeType == ch.TEXT_NODE and bool(ch.nodeValue):
|
|
assign_var = True
|
|
return assign_var
|
|
|
|
|
|
def GenerateMenuBarClass(self, windowClass, windowName, topWindow, vars):
|
|
outputList = []
|
|
|
|
# output the header
|
|
outputList.append(self.templates.MENUBAR_CLASS_HEADER % locals())
|
|
|
|
# create an attribute for menus and menu items that have names
|
|
for widget in topWindow.getElementsByTagName("object"):
|
|
if not self.CheckAssignVar(widget): continue
|
|
widgetClass = widget.getAttribute("class")
|
|
widgetClass = re.sub("^wx", "", widgetClass)
|
|
widgetName = widget.getAttribute("name")
|
|
if widgetName != "" and widgetClass != "":
|
|
vars.append(widgetName)
|
|
if widgetClass == "MenuItem":
|
|
outputList.append(self.templates.MENUBAR_MENUITEM_VAR % locals())
|
|
elif widgetClass == "Menu":
|
|
label = widget.getElementsByTagName("label")[0]
|
|
label = label.childNodes[0].data
|
|
outputList.append(self.templates.MENUBAR_MENU_VAR % locals())
|
|
else:
|
|
raise RuntimeError("Unexpected widgetClass for MenuBar: %s" % widgetClass)
|
|
|
|
return outputList
|
|
|
|
|
|
def GenerateMenuClass(self, windowClass, windowName, topWindow, vars):
|
|
outputList = []
|
|
|
|
# output the header
|
|
outputList.append(self.templates.MENU_CLASS_HEADER % locals())
|
|
for widget in topWindow.getElementsByTagName("object"):
|
|
if not self.CheckAssignVar(widget): continue
|
|
widgetClass = widget.getAttribute("class")
|
|
widgetClass = re.sub("^wx", "", widgetClass)
|
|
widgetName = widget.getAttribute("name")
|
|
if widgetName != "" and widgetClass != "":
|
|
vars.append(widgetName)
|
|
if widgetClass == "MenuItem":
|
|
outputList.append(self.templates.MENU_MENUITEM_VAR % locals())
|
|
elif widgetClass == "Menu":
|
|
label = widget.getElementsByTagName("label")[0]
|
|
label = label.childNodes[0].data
|
|
outputList.append(self.templates.MENU_MENU_VAR % locals())
|
|
else:
|
|
raise RuntimeError("Unexpected widgetClass for Menu: %s" % widgetClass)
|
|
|
|
return outputList
|
|
|
|
|
|
def GenerateToolBarClass(self, windowClass, windowName, topWindow, vars):
|
|
outputList = []
|
|
|
|
# output the header
|
|
outputList.append(self.templates.TOOLBAR_CLASS_HEADER % locals())
|
|
|
|
# create an attribute for menus and menu items that have names
|
|
for widget in topWindow.getElementsByTagName("object"):
|
|
if not self.CheckAssignVar(widget): continue
|
|
widgetClass = widget.getAttribute("class")
|
|
widgetClass = re.sub("^wx", "", widgetClass)
|
|
widgetName = widget.getAttribute("name")
|
|
if widgetName != "" and widgetClass != "":
|
|
vars.append(widgetName)
|
|
if widgetClass == "tool":
|
|
outputList.append(self.templates.TOOLBAR_TOOL_VAR % locals())
|
|
else:
|
|
raise RuntimeError("Unexpected widgetClass for ToolBar: %s" % widgetClass)
|
|
|
|
return outputList
|
|
|
|
|
|
def GenerateWidgetClass(self, windowClass, windowName, topWindow, vars):
|
|
outputList = []
|
|
|
|
# output the header
|
|
outputList.append(self.templates.CLASS_HEADER % locals())
|
|
|
|
# Generate an attribute for each named item in the container
|
|
for widget in topWindow.getElementsByTagName("object"):
|
|
if not self.CheckAssignVar(widget): continue
|
|
widgetClass = widget.getAttribute("class")
|
|
widgetClass = re.sub("^wx", "", widgetClass)
|
|
widgetName = widget.getAttribute("name")
|
|
if widgetName != "" and widgetClass != "":
|
|
vars.append(widgetName)
|
|
if widgetClass not in \
|
|
['tool', 'unknown', 'notebookpage', 'separator',
|
|
'sizeritem', 'Menu', 'MenuBar', 'MenuItem']:
|
|
outputList.append(self.templates.CREATE_WIDGET_VAR % locals())
|
|
elif widgetClass == "MenuBar":
|
|
outputList.append(self.templates.FRAME_MENUBAR_VAR % locals())
|
|
elif widgetClass == "MenuItem":
|
|
outputList.append(self.templates.FRAME_MENUBAR_MENUITEM_VAR % locals())
|
|
elif widgetClass == "Menu":
|
|
label = widget.getElementsByTagName("label")[0]
|
|
label = label.childNodes[0].data
|
|
outputList.append(self.templates.FRAME_MENUBAR_MENU_VAR % locals())
|
|
elif widgetClass == "ToolBar":
|
|
outputList.append(self.templates.FRAME_TOOLBAR_VAR % locals())
|
|
elif widgetClass == "tool":
|
|
outputList.append(self.templates.FRAME_TOOLBAR_TOOL_VAR % locals())
|
|
|
|
return outputList
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
def GenerateSubclasses(self, resourceDocument):
|
|
outputList = []
|
|
|
|
objectNodes = resourceDocument.getElementsByTagName("object")
|
|
subclasses = set()
|
|
bases = {}
|
|
baseName = os.path.splitext(self.outputFilename)[0]
|
|
for node in objectNodes:
|
|
subclass = node.getAttribute('subclass')
|
|
if subclass:
|
|
module = subclass[:subclass.find('.')]
|
|
if module != baseName: continue
|
|
klass = node.getAttribute("class")
|
|
if subclass not in subclasses:
|
|
subclasses.add(subclass)
|
|
bases[subclass] = klass
|
|
else:
|
|
if klass != bases[subclass]:
|
|
print('pywxrc: error: conflicting base classes for subclass %(subclass)s' % subclass)
|
|
|
|
# Generate subclasses
|
|
for subclass in subclasses:
|
|
windowClass = bases[subclass]
|
|
subclass = re.sub("^\S+\.", "", subclass)
|
|
windowClass = re.sub("^wx", "", windowClass)
|
|
outputList.append(self.templates.SUBCLASS_HEADER % locals())
|
|
outputList.append('\n')
|
|
|
|
return "".join(outputList)
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
def GenerateEventHandlers(self, windowClass, windowName, topWindow, vars):
|
|
outputList = []
|
|
|
|
# Generate child event handlers
|
|
eventHandlers = []
|
|
for elem in topWindow.getElementsByTagName("XRCED"):
|
|
try:
|
|
eventNode = elem.getElementsByTagName("events")[0]
|
|
except IndexError:
|
|
continue
|
|
events = eventNode.childNodes[0].data.split('|')
|
|
for event in events:
|
|
if elem.parentNode is topWindow:
|
|
eventHandler = "On%s" % event[4:].capitalize()
|
|
outputList.append(self.templates.BIND_EVENT % locals())
|
|
eventHandlers.append(eventHandler)
|
|
else:
|
|
widget = elem.parentNode
|
|
widgetClass = widget.getAttribute("class")
|
|
widgetClass = re.sub("^wx", "", widgetClass)
|
|
widgetName = widget.getAttribute("name")
|
|
if not widgetName or not widgetClass: continue
|
|
eventObject = None
|
|
if widgetClass == "MenuItem" and windowClass != "MenuBar":
|
|
if widgetName[:2] == "wx":
|
|
eventObject = 'id=wx.%s' % re.sub("^wx", "", widgetName)
|
|
eventHandler = "On%s_%s" % (event[4:].capitalize(), widgetName)
|
|
if widgetName in vars: eventObject = "self.%s" % widgetName
|
|
else:
|
|
eventHandler = "On%s_%s" % (event[4:].capitalize(), widgetName)
|
|
if widgetName in vars: eventObject = "self.%s" % widgetName
|
|
if not eventObject:
|
|
eventObject = "id=xrc.XRCID('%s')" % widgetName
|
|
outputList.append(self.templates.BIND_WIDGET_EVENT % locals())
|
|
eventHandlers.append(eventHandler)
|
|
outputList.append("\n")
|
|
|
|
for eventHandler in eventHandlers:
|
|
block = "xrc%(windowName)s.%(eventHandler)s" % locals()
|
|
try:
|
|
outputList.append(self.blocks[block])
|
|
except KeyError:
|
|
outputList.append(self.templates.CREATE_EVENT_HANDLER % locals())
|
|
outputList.append("\n")
|
|
|
|
outputList.append("\n")
|
|
return "".join(outputList)
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
def GenerateInitResourcesEmbedded(self, resourceFilename, resourceDocument):
|
|
outputList = []
|
|
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() # 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)
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
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)
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
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 FindStringsInNode(self, parent):
|
|
def is_number(st):
|
|
try:
|
|
i = int(st)
|
|
return True
|
|
except ValueError:
|
|
return False
|
|
|
|
strings = []
|
|
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))
|
|
|
|
# subnodes:
|
|
if child.nodeType == child.ELEMENT_NODE:
|
|
strings += self.FindStringsInNode(child)
|
|
|
|
return strings
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
def ConvertText(self, st):
|
|
st2 = ""
|
|
dt = list(st)
|
|
|
|
skipNext = False
|
|
for i in range(len(dt)):
|
|
if skipNext:
|
|
skipNext = False
|
|
continue
|
|
|
|
if dt[i] == '_':
|
|
if dt[i+1] == '_':
|
|
st2 += '_'
|
|
skipNext = True
|
|
else:
|
|
st2 += '&'
|
|
elif dt[i] == '\n':
|
|
st2 += '\\n'
|
|
elif dt[i] == '\t':
|
|
st2 += '\\t'
|
|
elif dt[i] == '\r':
|
|
st2 += '\\r'
|
|
elif dt[i] == '\\':
|
|
if dt[i+1] not in ['n', 't', 'r']:
|
|
st2 += '\\\\'
|
|
else:
|
|
st2 += '\\'
|
|
elif dt[i] == '"':
|
|
st2 += '\\"'
|
|
else:
|
|
st2 += dt[i]
|
|
|
|
return st2.encode("UTF-8")
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
# Replace editable block contents with previous
|
|
def ReplaceBlocks(self, input):
|
|
output = []
|
|
block = None
|
|
blockLines = []
|
|
for l in input.split('\n'):
|
|
if not block:
|
|
mo = reBeginBlock.match(l)
|
|
if mo and mo.groups()[0] in self.blocks:
|
|
block = mo.groups()[0]
|
|
output.append(self.blocks[block])
|
|
else:
|
|
output.append(l + '\n')
|
|
else:
|
|
mo = reEndBlock.match(l)
|
|
if mo:
|
|
if mo.groups()[0] != block:
|
|
print("pywxrc: error: block mismatch: %s != %s" % (block, mo.groups()[0]))
|
|
block = None
|
|
return ''.join(output)
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
def _OpenOutputFile(self, outputFilename):
|
|
if outputFilename == "-":
|
|
outputFile = sys.stdout
|
|
else:
|
|
# Parse existing file to collect editable blocks
|
|
if os.path.isfile(outputFilename):
|
|
outputFile = open(outputFilename)
|
|
block = None
|
|
blockLines = []
|
|
for l in outputFile.readlines():
|
|
if not block:
|
|
mo = reBeginBlock.match(l)
|
|
if mo:
|
|
block = mo.groups()[0]
|
|
blockLines = [l]
|
|
else:
|
|
blockLines.append(l)
|
|
mo = reEndBlock.match(l)
|
|
if mo:
|
|
if mo.groups()[0] != block:
|
|
print("pywxrc: error: block mismatch: %s != %s" % (block, mo.groups()[0]))
|
|
self.blocks[block] = "".join(blockLines)
|
|
block = None
|
|
|
|
try:
|
|
outputFile = open(outputFilename, "wt")
|
|
except IOError:
|
|
raise IOError("Can't write output to '%s'" % outputFilename)
|
|
return outputFile
|
|
|
|
|
|
|
|
|
|
|
|
#---------------------------------------------------------------------------
|
|
|
|
def main(args=None):
|
|
if not args:
|
|
args = sys.argv[1:]
|
|
|
|
resourceFilename = ""
|
|
outputFilename = None
|
|
embedResources = False
|
|
generateGetText = False
|
|
assignVariables = True
|
|
generatePython = False
|
|
|
|
try:
|
|
opts, args = getopt.gnu_getopt(args,
|
|
"hpgevo:",
|
|
"help python gettext embed novar output=".split())
|
|
except getopt.GetoptError as exc:
|
|
print("\nError : %s\n" % str(exc))
|
|
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 ["-v", "--novar"]:
|
|
assignVariables = False
|
|
|
|
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,
|
|
assignVariables)
|
|
|
|
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 as exc:
|
|
print_("%s." % str(exc), file=sys.stderr)
|
|
else:
|
|
if outputFilename != "-":
|
|
print_("Resources written to %s." % outputFilename, file=outputFilename)
|
|
|
|
if __name__ == "__main__":
|
|
main(sys.argv[1:])
|