#!/usr/bin/env python2.3
################################################################################
#
# This file is part of Gato (Graph Animation Toolbox)
#
# file: GatoFile.py
# author: Achim Gaedke (achim.gaedke@zpr.uni-koeln.de)
#
# Copyright (C) 1998-2005, Alexander Schliep, Winfried Hochstaettler and
# Copyright 1998-2001 ZAIK/ZPR, Universitaet zu Koeln
#
# Contact: schliep@molgen.mpg.de, wh@zpr.uni-koeln.de
# Information: http://gato.sf.net
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Library General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public
# License along with this library; if not, write to the Free
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# This file is version $Revision: 1.1 $
# from $Date: 2007/10/04 14:36:39 $
# last change by $Author: edream $.
#
################################################################################
import sys
import os
import types
import codecs
import StringIO
import urllib2
import xml.dom.minidom
import Gato
import Graph
import GraphUtil
import Tkinter
import TreeWidget
import TextTreeWidget
import ScrolledText
# code handling:
# the data object model module is unicode
# xml*Element functions return iso-8859-1 strings
# tkinter does not like python unicode, it gets iso-8859-1 strings
# file data are encoded to iso-8859-1
# xmlDecode(unicode) returns iso char string
(_isoEncoder,_isoDecoder,_isoStreamReader,_isoStreamWriter)=codecs.lookup("iso-8859-1")
xmlDecode=lambda x:_isoEncoder(x)[0]
# xmlEnocde(iso_char_string) returns unicode
xmlEncode=lambda x:_isoDecoder(x)[0]
# object that encodes stream data from unicode to iso-8859-1
xmlEncodedStream=_isoStreamWriter
class FileException(Exception):
"""
is the subclass for all file and xml related things that can go wrong in this module
"""
def __init__(self, reason):
"""
takes the reason or explanation as argument
"""
self.reason=reason
class GatoStorageCache:
"""
singleton list for all accessed/used/cached storage locations
"""
pass
class GatoStorageLocation:
"""
bundle of common functions for file load/save/selection
These functions act on the level of graphs and algorithms.
they propagate the open and save calls to the different file implementations
"""
def __init__(self,fileName=None):
"""
opens the file and prepares the access
"""
self.fileName=fileName
def chooseLocation(self,accessMode="rw"):
"""
opens a suitable dialog to choose a possible location for reading/writing gato data
"""
def __repr__(self):
"""
a short representation of the instance
"""
return "<%s: %s>"%(self.__class__.__name__,self.fileName)
def __str__(self):
"""
should display the name in human understandable manner
"""
return self.fileName
def readGraph(self,whichGraph=None):
"""
returns a Graph object
"""
pass
def readAlgortihm(self, whichAlgorithm=None):
"""
returns an Algorithm object
"""
pass
def writeGraph(self, Graph, whichGraph=None):
"""
puts a graph to the collection of graphs
"""
pass
def writeAlgorithm(self, Algorithm, whichAlgorithm=None):
"""
puts a graph to the collection of algorithms
"""
pass
class GatoStorageLocationTest:
"""
some tests for GatoStorageLocation
"""
def __init__(self):
l=GatoStorageLocation("bla")
print "human readable: %s, python representation %s"%(l,repr(l))
class GatoDirBranch(TreeWidget.DirBranch):
"""
"""
def updateChildList(self):
"""
create/update child list suitable for gato
"""
oldChildren=self.children
self.children=[]
entries=[]
try:
entries=os.listdir(self.path)
except OSError:
pass
entries.sort()
oldEntries=map(lambda c:c.name,oldChildren)
for entry in entries:
if entry in oldEntries:
self.children.append(oldChildren[oldEntries.index(entry)])
else:
entrypath=os.path.join(self.path,entry)
if os.path.isdir(entrypath):
self.children.append(GatoDirBranch(parent=self,name=entry))
elif os.path.isfile(entrypath):
# select suitable leaf
if entry[-5:]==".gato":
self.children.append(GatoFileBranch(parent=self,name=entry))
elif entry[-4:]==".xml":
self.children.append(xmlGatoFileBranch(parent=self,name=entry))
elif entry[-4:]==".alg" and os.path.isfile(entrypath[:-4]+".pro"):
self.children.append(algLeaf(parent=self,name=entry))
elif entry[-4:]==".cat":
self.children.append(catLeaf(parent=self,name=entry))
class GatoFileBranch(TreeWidget.xmlFileBranch):
"""
ToDo: supports xml files with gato root section
"""
pass
class xmlGatoFileBranch(TreeWidget.xmlFileBranch):
"""
ToDo supports xml files with gato sections inside
"""
pass
class algLeaf(TreeWidget.Leaf):
"""
old algortithm file
"""
def __init__(self,parent=None,name=None):
TreeWidget.Leaf.__init__(self,parent=parent, name=name)
self.selectable=1
class catLeaf(TreeWidget.Leaf):
"""
old graph file
"""
def __init__(self,parent=None,name=None):
TreeWidget.Leaf.__init__(self,parent=parent, name=name)
self.selectable=1
class GatoTree(TreeWidget.scrolledTree):
"""
"""
def __init__(self,master):
TreeWidget.scrolledTree.__init__(self,master)
self.root=GatoDirBranch(parent=self,name="/",anchor=(1,1))
self.root.display()
# show current work directory
current=os.getcwd()
currentList=[]
while current!=self.root.name:
(current,piece)=os.path.split(current)
currentList.insert(0,piece)
# expand all branches on the way
thisNode=self.root
thisNode.expand()
for piece in currentList:
thisNode=filter(lambda x:x.name==piece,thisNode.children)[0]
thisNode.expand()
(Nx0,Ny0,Nx1,Ny1)=thisNode.getBoundingBox()
(Cx0,Cy0,Cx1,Cy1)=self.bbox(Tkinter.ALL)
self.yview(Tkinter.MOVETO,float(Ny0)/float(Cy1-Cy0))
class WorkInProgress(Tkinter.Tk):
"""
my development and test class
"""
def __init__(self):
Tkinter.Tk.__init__(self)
self.tree=GatoTree(self)
self.tree.pack(expand=1,fill=Tkinter.BOTH)
def run(self):
self.mainloop()
class xmlAlgorithmElement:
algorithmElementName="algorithm"
sourceElementName="text"
prologElementName="prolog"
aboutElementName="about"
def __init__(self,dom):
# test for right tag
if dom.tagName!=self.algorithmElementName:
raise FileException("Wrong element name: %s, %s expected"
%(dom.tagName,self.algorithmElementName))
self.domElement=dom
def setAlgorithmFromALGFile(self,fileName):
"""
writes algorithm data to xml sections
"""
algorithm=Gato.Algorithm()
algorithm.Open(fileName)
self.setAlgorithm(algorithm.source)
self.setAbout(algorithm.About())
PrologFileName=fileName[:-4]+'.pro'
if os.access(PrologFileName,os.R_OK):
self.setProlog(file(PrologFileName).read())
else:
print "Warning: could not read prolog file %s"%PrologFileName
def setProlog(self,text):
"""
creates/repaces the prolog section
"""
#create new one
newProlog=None
if self.domElement.ownerDocument:
newProlog=self.domElement.ownerDocument.createElement(self.prologElementName)
newProlog.appendChild(self.domElement.ownerDocument.createCDATASection(
xmlEncode(text)
))
else:
newProlog=xml.dom.Element(self.prologElementName)
newProlog.appendChild(xml.dom.CDATASection(xmlEncode(text)))
existingProlog=self.domElement.getElementsByTagName(self.prologElementName)
if len(existingProlog)>0:
# replace existing prolog
self.domElement.repaceChild(newProlog,existingProlog[0])
else:
self.domElement.appendChild(newProlog)
def setAlgorithm(self,text):
"""
creates/repaces the algorithm section
"""
#create new one
newAlgorithm=None
if self.domElement.ownerDocument:
newAlgorithm=self.domElement.ownerDocument.createElement(self.sourceElementName)
newAlgorithm.appendChild(self.domElement.ownerDocument.createCDATASection(
xmlEncode(text)
))
else:
newAlgorithm=xml.dom.Element(self.sourceElementName)
newAlgorithm.appendChild(xml.dom.CDATASection(xmlEncode(text)))
existingAlgorithm=self.domElement.getElementsByTagName(self.sourceElementName)
if len(existingAlgorithm)>0:
# replace existing algorithm
self.domElement.repaceChild(newAlgorithm,existingAlgorithm[0])
else:
self.domElement.appendChild(newAlgorithm)
def setAbout(self,text):
"""
ToDo
"""
pass
def getTextFromElement(self,tagName):
"returns the text of specified tag"
requestedElements=self.domElement.getElementsByTagName(tagName)
if len(requestedElements)!=1:
return None
requestedElement=requestedElements[0]
text=""
for e in requestedElement.childNodes:
if (e.nodeType==xml.dom.minidom.Node.TEXT_NODE or
e.nodeType==xml.dom.minidom.Node.CDATA_SECTION_NODE):
text+=e.data
return xmlDecode(text)
def getText(self):
t=self.getTextFromElement(self.sourceElementName)
if t:
return t
else:
return ""
def getAboutAsString(self):
requestedElements=filter(lambda e:e.nodeType==xml.dom.Node.ELEMENT_NODE and \
e.tagName==self.aboutElementName,
self.domElement.childNodes)
if len(requestedElements)<1:
return None
else:
return requestedElements[0].toxml()
def getTextAsFile(self):
"""
creates a StringIO Object from file
"""
return StringIO.StringIO(self.getText())
def getProlog(self):
"returns the prolog"
p=self.getTextFromElement(self.prologElementName)
if p:
return p
else:
return ""
def getPrologAsFile(self):
return StringIO.StringIO(self.getProlog())
def getName(self):
return xmlDecode(self.domElement.getAttribute("name"))
def setName(self,name):
self.domElement.setAttribute("name",xmlEncode(name))
class xmlGraphElement:
graphElementName="graph"
def __init__(self,graph,name=None):
"""
called with a dom element: grants access to Graph
called with a graph and a name string: creates the dom structure from graph
"""
# test for right tag
if issubclass(graph.__class__,xml.dom.minidom.Element):
# we were called with a dom element as argument
if graph.tagName!=self.graphElementName:
raise FileException("Wrong element name: %s, %s expected"
%(graph.tagName,self.graphElementName))
self.domElement=graph
elif issubclass(graph.__class__,Graph.Graph) and type(name) in types.StringTypes:
# initialise dom element
self.domElement=xml.dom.minidom.Element(xmlGraphElement.graphElementName)
self.setName(name)
self.setGraph(graph)
else:
raise FileException("wrong arguments provided")
def getAboutAsString(self):
requestedElements=filter(lambda e:e.nodeType==xml.dom.Node.ELEMENT_NODE and e.tagName=="about",
self.domElement.childNodes)
if len(requestedElements)<1:
return None
else:
return requestedElements[0].toxml()
def getGraph(self):
"""
returns the Graph object constructed from this dom element
"""
return GraphUtil.OpenCATBoxGraph(self.getGraphAsStringIO())
def getGraphAsStringIO(self):
text=StringIO.StringIO()
for e in self.domElement.childNodes:
if (e.nodeType==xml.dom.minidom.Node.TEXT_NODE or
e.nodeType==xml.dom.minidom.Node.CDATA_SECTION_NODE):
text.write(xmlDecode(e.data))
text.seek(0)
return text
def setGraph(self,graph):
# we were called with a Graph and a name as arguments
data=StringIO.StringIO()
GraphUtil.SaveCATBoxGraph(graph,data)
#remove all other text nodes
textNodes=filter(lambda e:e.nodeType==xml.dom.minidom.Node.TEXT_NODE or
e.nodeType==xml.dom.minidom.Node.CDATA_SECTION_NODE,
self.domElement.childNodes)
map(self.domElement.removeChild,textNodes)
# create necessary dom elements
# maybe xml.dom.minidom.Text is ok, too
newCDATASection=None
if self.domElement.ownerDocument:
newCDATASection=self.domElement.ownerDocument.createCDATASection(
xmlEncode(data.getvalue())
)
else:
newCDATASection=xml.dom.minidom.CDATASection(xmlEncode(data.getvalue()))
self.domElement.appendChild(newCDATASection)
def setGraphFromCATFile(self,GraphFile):
"""
creates a graph object from .cat file and sets it
this detour assures an actual graph format
"""
self.setGraph(GraphUtil.OpenCATBoxGraph(GraphFile))
def getName(self):
return xmlDecode(self.domElement.getAttribute("name"))
def setName(self,name):
self.domElement.setAttribute("name",xmlEncode(name))
class xmlGatoElement:
"""
is an access and modification interface to the gato dom structure
"""
gatoElementName="gato"
def __init__(self,_domElement):
"""
creates the access and modification interface
"""
# test for right tag
if _domElement.tagName!=self.gatoElementName:
raise FileException("Wrong element name: %s, %s expected"
%(_domElement.tagName,self.gatoElementName))
self.domElement=_domElement
def createGraphElement(self,name=None):
"""
creates a new graph Element
"""
newDOMElement=None
if self.domElement.ownerDocument:
newDOMElement=self.domElement.ownerDocument.createElement(
xmlGraphElement.graphElementName)
else:
newDOMElement=xml.dom.Element(xmlGraphElement.graphElementName)
newElement=xmlGraphElement(newDOMElement)
if name is not None:
newElement.setName(name)
return newElement
def createAlgorithmElement(self,name=None):
"""
creates a new algorithm element
"""
newDOMElement=None
if self.domElement.ownerDocument:
newDOMElement=self.domElement.ownerDocument.createElement(
xmlAlgorithmElement.algorithmElementName)
else:
newDOMElement=xml.dom.Element(xmlAlgorithmElement.algorithmElementName)
newElement=xmlAlgorithmElement(newDOMElement)
if name is not None:
newElement.setName(name)
return newElement
def setName(self,name):
"""
sets the name attribute for this element
"""
self.domElement.setAttribute("name",xmlEncode(name))
def getName(self,name):
"""
gets the name of this element, if unset an empty string
"""
return xmlDecode(self.domElement.getAttribute("name"))
def getAboutAsString(self):
requestedElements=filter(lambda e:e.nodeType==xml.dom.Node.ELEMENT_NODE and e.tagName=="about",
self.domElement.childNodes)
if len(requestedElements)<1:
return None
else:
return requestedElements[0].toxml()
def getGraphElements(self):
"""
returns all direct child elements with graph's tagName
"""
return filter(lambda x:(x.nodeType==xml.dom.minidom.Node.ELEMENT_NODE and
x.tagName==xmlGraphElement.graphElementName),
self.domElement.childNodes)
def getAlgorithmElements(self):
"""
returns all direct child elements with algorithm's tagName
"""
return filter(lambda x:(x.nodeType==xml.dom.minidom.Node.ELEMENT_NODE and
x.tagName==xmlAlgorithmElement.algorithmElementName),
self.domElement.childNodes)
def getGraphNames(self):
"""
extracts all graph names
"""
# return a list of name attribute values from graph elements
return map(lambda x:xmlDecode(x.getAttribute("name")),
self.getGraphElements())
def getAlgorithmNames(self):
"""
extracts all algorithm names
"""
# return a list of name attribute values from graph elements
return map(lambda x:xmlDecode(x.getAttribute("name")),
self.getAlgorithmElements())
def getGraphByName(self,name):
"""
gets a xmlGraphElement by its name
"""
graphs=filter(lambda x:x.getAttribute("name")==name,
self.getGraphElements())
return xmlGraphElement(graphs[0])
def getAlgorithmByName(self,name):
"""
gets a xmlAlgorithmElement by its name
"""
graphs=filter(lambda x:x.getAttribute("name")==name,
self.getAlgorithmElements())
return xmlAlgorithmElement(graphs[0])
def getDefaultSelection(self):
"""
searches for the default selection, e.g.
only one graph and one algorithm
"""
defaultSelection={}
graphs=self.getGraphNames()
algorithms=self.getAlgorithmNames()
if len(graphs)<2 and len(algorithms)<2:
if len(graphs)==1:
defaultSelection["graph"]=self.getGraphByName(graphs[0])
if len(algorithms)==1:
defaultSelection["algorithm"]=self.getAlgorithmByName(algorithms[0])
return defaultSelection
if self.domElement.hasAttribute("defaultGraph"):
defaultSelection["graph"]=self.getGraphByName(
self.domElement.getAttribute("defaultGraph"))
if self.domElement.hasAttribute("defaultAlgorithm"):
defaultSelection["algorithm"]=self.getAlgorithmByName(
self.domElement.getAttribute("defaultAlgorithm"))
return defaultSelection
def updateGraphByName(self,graph,name=None):
"""
appends or replaces a graph, if name not given, the graphs name is taken
"""
newGraph=None
newName=None
if issubclass(graph.__class__,Graph.Graph):
newGraph=xmlGraphElement(graph,name)
elif issubclass(graph.__class__,xmlGraphElement):
newGraph=graph
if name:
graph.setName(name)
else:
name=graph.getName()
else:
raise FileException("argument mismatch!")
graphs=filter(lambda x:x.getAttribute("name")==name,
self.getGraphElements())
if len(graphs):
# replace graph, more exactly the first one
self.domElement.replaceChild(newGraph.domElement,graphs[0])
else:
# append graph
self.domElement.appendChild(newGraph.domElement)
def updateAlgorithmByName(self,algorithm,name=None):
"""
appends or replaces an algorithm
"""
newAlgorithm=None
newName=None
if issubclass(algorithm.__class__,Gato.Algorithm):
newAlgorithm=xmlAlgorithmElement(algorithm,name)
elif issubclass(algorithm.__class__,xmlAlgorithmElement):
newAlgorithm=algorithm
if name:
algorithm.setName(name)
else:
name=algorithm.getName()
else:
raise FileException("argument mismatch!")
algorithms=filter(lambda x:x.getAttribute("name")==name,
self.getAlgorithmElements())
if len(algorithms):
# replace graph, more exactly the first one
self.domElement.replaceChild(newAlgorithm.domElement,graphs[0])
else:
# append graph
self.domElement.appendChild(newAlgorithm.domElement)
def removeGraphByName(self,name):
"""
removes the named graph
"""
graphs=filter(lambda x:x.getAttribute("name")==name,
self.getGraphElements())
map(self.domElement.removeChild,graphs)
def removeAlgorithmByName(self,name):
"""
removes the named algorithm
"""
algorithms=filter(lambda x:x.getAttribute("name")==name,
self.getAlgorithmElements())
map(self.domElement.removeChild,algorithms)
class ElementDisplay(Tkinter.Frame):
"""
displays the selected element
"""
def __init__(self,master,**config):
"""
"""
config.update({"width":500, "height":500})
Tkinter.Frame.__init__(self,master,bg="white",cnf=config)
self.pack_propagate(0) # keep everything in a rigid frame
self.displayedWidget=None
self.displayedNode=None
def clearDisplay(self):
"""
cleanup and display nothing
"""
# cleanup radically
for child in self.children.values():
child.pack_forget()
child.destroy()
self.displayedNode=None
def setDisplay(self,node):
"""
display node...
"""
if node is None:
self.clearDisplay()
return
else:
if self.displayedNode is not None and self.displayedNode==node:
return #nothing to do
self.clearDisplay()
displayedWidget=None
if node.tagName==xmlGraphElement.graphElementName:
html_data=xmlGraphElement(node).getAboutAsString()
displayedWidget=AboutWidget(self,html_data)
self.displayedNode=node
elif node.tagName==xmlAlgorithmElement.algorithmElementName:
displayedWidget=AlgorithmInfoWidget(self,xmlAlgorithmElement(node))
self.displayedNode=node
elif node.tagName==xmlGatoElement.gatoElementName:
html_data=xmlGatoElement(node).getAboutAsString()
displayedWidget=AboutWidget(self,html_data)
self.displayedNode=node
else:
print "toDo: ",node
if displayedWidget:
displayedWidget.pack(expand=1,fill=Tkinter.BOTH)
class AlgorithmInfoWidget(Tkinter.Frame):
"""
creates an algorithm widget
"""
def __init__(self,master,algorithmElement):
"""
create it
"""
Tkinter.Frame.__init__(self,master,highlightthickness=0)
html_data=algorithmElement.getAboutAsString()
self.About=AboutWidget(self,html_data)
self.About.pack(side=Tkinter.TOP,expand=1,fill=Tkinter.BOTH)
text_data=algorithmElement.getText()
self.Text=ScrolledText.ScrolledText(self,
background='white',
wrap='word',
font="Times 10")
self.Text.insert(Tkinter.END, text_data)
self.Text.pack(side=Tkinter.TOP,expand=1,fill=Tkinter.BOTH)
self.Text['state'] = Tkinter.DISABLED
class AboutWidget(ScrolledText.ScrolledText):
"""
displays html text
copied and modified from GatoDialogs.py
Basic class which provides a scrollable area for viewing HTML text
"""
def __init__(self, master, htmlcode):
ScrolledText.ScrolledText.__init__(self, master,
background='white',
wrap='word',
font="Times 10",
)
self.inserthtml(htmlcode)
def Update(self,htmlcode):
self.inserthtml(htmlcode)
def inserthtml(self, htmlcode):
if htmlcode is None:
htmlcode="""<html><body>
No information avaliable !
</body></html>
"""
import formatter
import GatoDialogs
self['state'] = Tkinter.NORMAL
self.delete('0.0', Tkinter.END)
writer = GatoDialogs.HTMLWriter(self, self)
format = formatter.AbstractFormatter(writer)
parser = GatoDialogs.MyHTMLParser(format, self)
parser.feed(htmlcode)
parser.close()
self['state'] = Tkinter.DISABLED
class GatoFileButtonBar(Tkinter.Frame):
"""
holds the buttons for the node selection dialog
"""
def __init__(self, master, reporter, cnf={}, **config):
cnf.update(config)
Tkinter.Frame.__init__(self,master,cnf=cnf)
self.reporter=reporter
self.okButton=Tkinter.Button(self,text="Ok",command=lambda e=None :self.reporter("quit"))
self.okButton.grid(row=0,column=0,sticky=Tkinter.E+Tkinter.W)
self.cancelButton=Tkinter.Button(self,text="Cancel",command=lambda e=None:self.reporter("cancel"))
self.cancelButton.grid(row=0,column=1,sticky=Tkinter.E+Tkinter.W)
self.columnconfigure(0,weight=1)
self.columnconfigure(1,weight=1)
class GatoFileStructureWidget(TextTreeWidget.dom_structure_widget):
"""
customized for .gato files
"""
def __init__(self,master,dom,report_function,**conf):
"""
report function coordinates the element display
"""
TextTreeWidget.dom_structure_widget.__init__(self,master,dom,self.report_func,width=30,cnf=conf)
self.chosenNodes={}
self.report_to=report_function
def report_func(self,event,*opts):
"""
reports nodes that are marked aka chosen
"""
if event=="chosenNode":
# double click on node, or hit <Return>
if len(opts)<1 or opts[0] is None:
return
node=opts[0]
# is this a gato element?
if node.tagName==xmlGatoElement.gatoElementName:
if self.report_to and not self.report_to(event,node):
return
self.chosenNode(node,xmlGatoElement.gatoElementName)
# is it a valid graph or algorithm object?
if self.isGatoMemberElement(node)!=1:
# nothing to do...
return
if node.tagName==xmlAlgorithmElement.algorithmElementName:
if self.report_to and not self.report_to(event,node):
return
self.chosenNode(node,xmlAlgorithmElement.algorithmElementName)
elif node.tagName==xmlGraphElement.graphElementName:
if self.report_to and not self.report_to(event,node):
return
self.chosenNode(node,xmlGraphElement.graphElementName)
elif event=="selectedNode":
# selected Node
if len(opts)<1 or opts[0] is None:
return
node=opts[0]
if self.report_to:
self.report_to(event, node)
else:
print event, opts
def chosenNode(self,node,register):
"""
mark and save chosen node
"""
last=self.chosenNodes.get(register)
if last:
self.setNodeColor(last,"black")
if last==node:
# erase selection
self.chosenNodes[register]=None
else:
# new selection
self.chosenNodes[register]=node
self.setNodeColor(node,"red")
def nameNode(self,node):
"""
chose proper names for node
"""
if node.nodeType==xml.dom.Node.ELEMENT_NODE:
myName=xmlDecode(node.tagName)
if myName==xmlGatoElement.gatoElementName:
if node.hasAttribute("name"):
return "gato: %s"%xmlDecode(node.getAttribute("name"))
else:
return "gato"
elif myName==xmlGraphElement.graphElementName:
return "graph: %s"%xmlDecode(node.getAttribute("name"))
elif myName==xmlAlgorithmElement.algorithmElementName:
return "algorithm: %s"%xmlDecode(node.getAttribute("name"))
else:
return TextTreeWidget.dom_structure_widget.nameNode(self,node)
else:
return TextTreeWidget.dom_structure_widget.nameNode(self,node)
def isGatoMemberElement(self,node):
"""
if this is a subtag of gato, return actual depth
returns 0, if not in a gato element, or is a gato element itself
"""
parent=node.parentNode
if parent:
if parent.nodeType==xml.dom.Node.DOCUMENT_NODE:
return 0
elif parent.nodeType==xml.dom.Node.ELEMENT_NODE and parent.tagName=="gato":
return 1
else:
depth=self.isGatoMemberElement(parent)
if depth:
return depth+1
else:
return 0
else:
raise FileException("could not determine, if node is member of gato section")
def isVisible(self,node):
"""
filter out subsections of graph and algorithm in gato sections
"""
isMember=self.isGatoMemberElement(node)
if isMember==0:
return TextTreeWidget.dom_structure_widget.isVisible(self,node)
elif isMember>1:
# hide everything deeper than 1
return 0
else:
# hide everything except graph and algorithm
if (node.nodeType==xml.dom.Node.ELEMENT_NODE and
node.tagName in [xmlGraphElement.graphElementName,
xmlAlgorithmElement.algorithmElementName]):
return 1
else:
return 0
class GatoDOMDialog(Tkinter.Toplevel):
"""
contains the xml structure and the display of selected element and some buttons
opt_choose contains the elements, that may be chosen
mand_choose contains the elements, that must be choosen
"""
def __init__(self, master, dom, opt_choose=("algorithm","graph"), mand_choose=(), **config):
"""
create it
"""
self.dom=dom
self.opt_choose=opt_choose
self.mand_choose=mand_choose
self.result={} # None in case of canceled dialog, (graphNode, algoNode) in case of selection
Tkinter.Toplevel.__init__(self,master, cnf=config)
# the structure widget...
self.struct_widget=GatoFileStructureWidget(self, self.dom, self.reportFromStructure, font="Times 12")
self.struct_widget.grid(row=0, column=0, sticky=Tkinter.NSEW)
# and the element display....
self.display_widget=ElementDisplay(self,width=400)
self.display_widget.grid(row=0, column=1, sticky=Tkinter.NSEW)
# the button bar...
self.buttons=GatoFileButtonBar(self,self.reportFromButtons)
self.buttons.grid(row=1, column=0, columnspan=2, sticky=Tkinter.EW)
self.protocol("WM_DELETE_WINDOW", lambda e=None: self.reportFromButtons("cancel"))
def reportFromStructure(self,event,node):
"""
coordinates element display
"""
if event=="selectedNode":
self.display_widget.setDisplay(node)
elif event=="chosenNode":
# should be selected?
if node and node.nodeType==xml.dom.Node.ELEMENT_NODE and \
(node.tagName in self.opt_choose or node.tagName in self.mand_choose):
return 1
def reportFromButtons(self,event):
"""
gets interesting events from button bar
"""
if event=="quit":
# graph
graph=self.struct_widget.chosenNodes.get(xmlGraphElement.graphElementName)
if graph:
self.result[xmlGraphElement.graphElementName]=xmlGraphElement(graph)
else:
if xmlGraphElement.graphElementName in self.mand_choose:
return
# algorithm
algorithm=self.struct_widget.chosenNodes.get(xmlAlgorithmElement.algorithmElementName)
if algorithm:
self.result[xmlAlgorithmElement.algorithmElementName]=xmlAlgorithmElement(algorithm)
else:
if xmlAlgorithmElement.algorithmElementName in self.mand_choose:
return
# gato section
gato=self.struct_widget.chosenNodes.get(xmlGatoElement.gatoElementName)
if gato:
self.result[xmlGatoElement.gatoElementName]=xmlGatoElement(gato)
else:
if xmlGatoElement.gatoElementName in self.mand_choose:
return
self.destroy()
self.quit()
elif event=="cancel":
self.result=None
self.destroy()
self.quit()
else:
raise Exception("unknown event %s"%event)
def run(self):
"""
runs this dialog
"""
self.mainloop()
return self.result
class GatoFile:
"""
encapsulates the dom creation from file
"""
validModes=['r', # expect valid gato file and read this file
'w', # create new file or overwrite existing file
]
def __init__(self,myFile=None, mode='r'):
"""
open a file and read the dom from it, or provide an empty gato document
"""
if myFile:
if mode not in self.validModes:
raise FileException("mode %c not supported"%mode)
self.mode=mode
import types
# test if name or file is given
if self.mode=='r':
self.file=None
self.name=None
if type(myFile) in types.StringTypes:
if os.access(myFile,os.R_OK):
self.file=file(myFile,"r")
self.name=myFile
else:
urlRequest=urllib2.Request(myFile)
self.file=urllib2.urlopen(urlRequest,"r")
elif type(myFile)==types.FileType:
self.file=myFile
try:
# pull dom out of file
self.dom = xml.dom.minidom.parse(self.file)
except xml.dom.DOMException, e:
print e
raise FileException(str(e))
elif self.mode=='w':
if type(myFile) in types.StringTypes:
if os.access(myFile,os.W_OK):
self.file=file(myFile,"w")
self.name=myFile
else:
urlRequest=urllib2.Request(myFile)
self.file=urllib2.urlopen(urlRequest,"w")
else:
self.file=myFile
# create empty document
self.dom = xml.dom.minidom.Document()
else: #myFile=None
# without file, but create empty doc, too
self.dom = xml.dom.minidom.Document()
# self.dom.appendChild(self.dom.createElement(xmlGatoElement.gatoElementName))
def write(self,_file=None):
"""
writes the (modified) dom to the file
"""
# ???? write to right place????
_thisFile=None
if _file is not None:
if type(_file) in types.StringTypes:
_thisFile=encodedStream(file(_file,"w"))
elif type(_file)==types.FileType:
_thisFile=_file
else:
_thisFile=self.file
encoding="iso-8859-1"
_thisFile.write("<?xml version=\"1.0\" encoding=\"%s\" ?>\n"%encoding)
if self.dom.hasChildNodes():
for n in self.dom.childNodes:
n.writexml(xmlEncodedStream(_thisFile))
def getDefaultSelection(self):
"""
returns the default selected elements
"""
if (not self.dom.documentElement) or \
self.dom.documentElement.tagName!=xmlGatoElement.gatoElementName:
return None
else:
return xmlGatoElement(self.dom.documentElement).getDefaultSelection()
def getGatoElements(self):
"""
returns an xmlGatoElement instance
"""
return self.dom.getElementsByTagName(xmlGatoElement.gatoElementName)
def appendGatoElement(self,newElement):
"""
append the element without checking unique name
"""
if self.dom.hasChildNodes():
# replace doc root gato node with a more general section
if self.dom.documentElement.tagName==xmlGatoElement.gatoElementName:
tmpGatoElement=self.dom.documentElement
self.dom.replaceChild(self.dom.createElement("xml"),tmpGatoElement)
self.dom.documentElement.appendChild(tmpGatoElement)
# append to document element
self.dom.documentElement.appendChild(newElement.domElement)
else:
# start with a gato node as root element
self.dom.appendChild(newElement.domElement)
def createGatoElement(self,name=None):
"""
creates a new (opt. unnamed) Gato element
"""
newElement=xmlGatoElement(self.dom.createElement(xmlGatoElement.gatoElementName))
if name is not None:
newElement.setName(name)
return newElement
def displaySelectionDialog(self,master):
"""
runs the dom structure
"""
w=GatoDOMDialog(master,self.dom)
return w.run()
def displayGraphSelectionDialog(self,master):
w=GatoDOMDialog(master,self.dom,to_choose=(('graph',)))
s=w.run()
if s:
return s["graph"]
else:
return None
def displayAlgorithmSelectionDialog(self,master):
w=GatoDOMDialog(master, self.dom,to_choose=(('algorithm',)))
s=w.run()
if s:
return s["algorithm"]
else:
return None
if __name__=='__main__':
# some test progs
WorkInProgress().run()
# old ones
# f=GatoFile('DFS.gato') # parse an XML file by name
# f.displayGraphSelectionDialog(Tkinter.Tk())
|