# Name: model.py
# Purpose: Model class and related
# Author: Roman Rolinsky <rolinsky@femagsoft.com>
# Created: 07.06.2007
# RCS-ID: $Id: model.py 64107 2010-04-22 14:05:36Z ROL $
import os,sys
from xml.dom import minidom
from globals import *
# Redefine writing to include encoding
class MyDocument(minidom.Document):
def __init__(self):
minidom.Document.__init__(self)
self.encoding = ''
def writexml(self, writer, indent="", addindent="", newl="", encoding=""):
if encoding: encdstr = 'encoding="%s"' % encoding
else: encdstr = ''
writer.write('<?xml version="1.0" %s?>\n' % encdstr)
for node in self.childNodes:
node.writexml(writer, indent, addindent, newl)
# Model object is used for data manipulation
class _Model:
def __init__(self):
self.dom = None
def init(self, dom=None):
self.external = []
self.allowExec = None
if self.dom: self.dom.unlink()
if not dom:
self.dom = MyDocument()
self.mainNode = self.dom.createElement('resource')
self.dom.appendChild(self.mainNode)
# Dummy node to be replaced by the node being tested
self.testElem = self.dom.createElement('dummy')
else:
dom.normalize()
self.dom = dom
self.testElem = self.dom.createElement('dummy')
self.mainNode = dom.documentElement
# Test element node is always first
self.mainNode.insertBefore(self.testElem, self.mainNode.firstChild)
def loadXML(self, path):
f = open(path)
dom = minidom.parse(f)
f.close()
self.init(dom)
# Set encoding global variable and default encoding
if dom.encoding:
wx.SetDefaultPyEncoding(dom.encoding.encode())
else:
dom.encoding = ''
def saveXML(self, path):
if self.dom.encoding:
import codecs
f = codecs.open(path, 'wt', self.dom.encoding)
else:
f = open(path, 'wt')
# Make temporary copy for formatting it
domCopy = MyDocument()
mainNode = domCopy.appendChild(self.mainNode.cloneNode(True))
# Remove first child (testElem)
mainNode.removeChild(mainNode.firstChild).unlink()
self.indent(domCopy, mainNode)
domCopy.writexml(f, encoding = self.dom.encoding)
f.close()
domCopy.unlink()
def saveTestMemoryFile(self):
# Save in memory FS
memFile = MemoryFile(TEST_FILE)
encd = self.dom.encoding
if not encd: encd = None
try:
self.dom.writexml(memFile, encoding=encd)
except:
logger.exception('error writing temporary XML file')
wx.LogError('Error writing temporary XML file')
memFile.close() # write to wxMemoryFS
def indent(self, domCopy, node, indent = 0):
'''Indent node which must be a comment or an element node and children.'''
if indent != 0:
prevNode = node.previousSibling
if prevNode and prevNode.nodeType == prevNode.TEXT_NODE:
prevNode.data = '\n' + ' ' * indent
else:
text = domCopy.createTextNode('\n' + ' ' * indent)
node.parentNode.insertBefore(text, node)
# Indent element/comment children recurcively
if node.hasChildNodes():
lastIndented = None
for n in node.childNodes[:]:
if n.nodeType in [n.ELEMENT_NODE, n.COMMENT_NODE]:
self.indent(domCopy, n, indent + 2)
lastIndented = n
# Insert newline after last element/comment child
if lastIndented:
n = lastIndented.nextSibling
if n and n.nodeType == n.TEXT_NODE:
n.data = '\n' + ' ' * indent
else:
text = domCopy.createTextNode('\n' + ' ' * indent)
node.appendChild(text)
def createObjectNode(self, className):
node = self.dom.createElement('object')
node.setAttribute('class', className)
return node
def createRefNode(self, ref):
node = self.dom.createElement('object_ref')
node.setAttribute('ref', ref)
return node
def createCommentNode(self):
node = self.dom.createComment('')
return node
def createComponentNode(self, className):
node = self.dom.createElement('component')
node.setAttribute('class', className)
return node
def parseString(self, data):
return minidom.parseString(data).childNodes[0]
def setTestElem(self, elem):
oldTestElem = Model.testElem
self.mainNode.replaceChild(elem, oldTestElem)
self.testElem = elem
oldTestElem.unlink()
def addExternal(self, path):
f = open(path)
self.external.append(minidom.parse(f))
f.close()
def findResource(self, name, classname='', recursive=True):
found = DoFindResource(self.mainNode, name, classname, recursive)
if found: return found
# Try to look in external files
for dom in self.external:
found = DoFindResource(dom.documentElement, name, '', True)
if found: return found
wx.LogError('XRC resource "%s" not found!' % name)
Model = _Model()
class MemoryFile:
'''Memory file proxy for python-like file object.'''
def __init__(self, name):
self.name = name
self.buffer = ''
def write(self, data):
if Model.dom.encoding:
encoding = Model.dom.encoding
else:
encoding = wx.GetDefaultPyEncoding()
try:
self.buffer += data.encode(encoding)
except UnicodeEncodeError:
self.buffer += data.encode(encoding, 'xmlcharrefreplace')
def close(self):
wx.MemoryFSHandler.AddFile(self.name, self.buffer)
# Imitation of FindResource/DoFindResource from xmlres.cpp
def DoFindResource(parent, name, classname, recursive):
for n in parent.childNodes:
if n.nodeType == minidom.Node.ELEMENT_NODE and \
n.tagName in ['object', 'object_ref'] and \
n.getAttribute('name') == name:
cls = n.getAttribute('class')
if not classname or cls == classname: return n
if not cls and n.tagName == 'object_ref':
refName = n.getAttribute('ref')
if not refName: continue
refNode = FindResource(refName)
if refName and refNode.getAttribute('class') == classname:
return n
if recursive:
for n in parent.childNodes:
if n.nodeType == minidom.Node.ELEMENT_NODE and \
n.tagName in ['object', 'object_ref']:
found = DoFindResource(n, name, classname, True)
if found: return found
|