#!/usr/bin/env python ################################################################################ # # 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.7 $ # from $Date: 2005/02/22 11:12:49 $ # last change by $Author: schliep $. # ################################################################################ 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=""" No information avaliable ! """ 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 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("\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())