def __getEntityList(self, selection): """ If selection is empty, get all nodes on the canvas Else filter out links Returns semantic objects, subclasses of ASGNode rather than VisualObj """ entityNodeList = [] # Selection may contain a mixed bag of nodes and links if(selection): for node in selection: if(not isConnectionLink(node)): semObj = node.semanticObject semObj._treeVisit = False semObj._treeChildren = [] entityNodeList.append(semObj) # No selection? Grab all nodes in diagram else: if(not self.atom3i.ASGroot): return [] for nodetype in self.atom3i.ASGroot.nodeTypes: for node in self.atom3i.ASGroot.listNodes[nodetype]: if(not isConnectionLink(node.graphObject_)): node._treeVisit = False node._treeChildren = [] entityNodeList.append(node) return entityNodeList
def __buildAbstractGraphSelectOnly(self, selectionList): """ Generate abstraction of graph found in selection list NOTE: AToM3 dependent method """ # Go through all the nodes #nodeList = filter(lambda x: not isConnectionLink(x), selectionList) nodeList = [ node for node in selectionList if not isConnectionLink(node) ] for node in nodeList: self.__NodeList.append(Node(node.semanticObject)) # Go through all the edges #edgeList = filter(isConnectionLink, selectionList) edgeList = [node for node in selectionList if isConnectionLink(node)] for edge in edgeList: semObj = edge.semanticObject # Directed edge (could be self-loop) if (len(semObj.in_connections_) == len(semObj.out_connections_) == 1): self.__buildDirectedEdge(semObj) # Hyper-edge, multiple sources/targets else: self.__buildHyperEdge(semObj)
def __getEntityList(self, selection): """ If selection is empty, get all nodes on the canvas Else filter out links Returns semantic objects, subclasses of ASGNode rather than VisualObj """ entityNodeList = [] # Selection may contain a mixed bag of nodes and links if (selection): for node in selection: if (not isConnectionLink(node)): semObj = node.semanticObject semObj._treeVisit = False semObj._treeChildren = [] entityNodeList.append(semObj) # No selection? Grab all nodes in diagram else: if (not self.atom3i.ASGroot): return [] for nodetype in self.atom3i.ASGroot.nodeTypes: for node in self.atom3i.ASGroot.listNodes[nodetype]: if (not isConnectionLink(node.graphObject_)): node._treeVisit = False node._treeChildren = [] entityNodeList.append(node) return entityNodeList
def genLayoutConstraintsCode( self,file, myName, indent): """ Generates code related to graphical layout constraints """ file.write(indent+myName+'.layConstraints = dict() # Graphical Layout Constraints \n') lcDict = self.graphObject_.layConstraints # Links will have their layout constraints tucked away in the center object... if( isConnectionLink( self.graphObject_ ) ): if( self.graphObject_.centerObject ): centerConstraints = self.graphObject_.centerObject.layConstraints # Add in the center object constraints for key in centerConstraints: if( not lcDict.has_key( key ) ): lcDict[ key ] = centerConstraints[ key ] # Scaling of the arrow width doesn't exist, so we must want the center object scale elif( key == 'scale' ): lcDict[ key ] = centerConstraints[ key ] # Uh oh, conflict... just use one of them... else: ## print "WARNING: Constraint conflict, see ASGNode.py in genLayoutConstraintsCode() if this is a problem." ## print lcDict, "<-- Object constraints" ## print centerConstraints, "<-- Center object constraints" ## print centerConstraints[ key ], "<-- Saved constraint (other one dropped)" lcDict[ key ] = centerConstraints[ key ] # Write down all the constraints... for key in lcDict.keys(): file.write(indent+myName+'.layConstraints[\''+str(key)+'\'] = '+str(lcDict[key])+'\n' )
def __buildAbstractGraphEntireCanvas(self, atom3i): """ Generate abstraction of graph found on the whole atom3i canvas NOTE: AToM3 dependent method """ if (not atom3i.ASGroot): return edgeList = [] for nodetype in atom3i.ASGroot.nodeTypes: for node in atom3i.ASGroot.listNodes[nodetype]: # Regular node if (not isConnectionLink(node.graphObject_)): self.__NodeList.append(Node(node)) # Edge else: edgeList.append(node) # Do edges in a 2nd phase, otherwise might try to lookup a Node object # that does not exist yet. for edge in edgeList: # Regular edge (could be self-loop) if (len(edge.in_connections_) == len(edge.out_connections_) == 1): self.__buildDirectedEdge(edge) # Hyper-edge else: self.__buildHyperEdge(edge)
def smoothSelected(self): """ Toggle smooths all links in the selection, toggles via majority vote """ howManySmoothOnes = 0 itemHandlers = [] smoothFlag = True # Gather Statistics on what's smooth and what's not :D for tag in self.selectionDict: obj = self.selectionDict[tag][1] if(isConnectionLink(obj)): for connObjTuple in obj.in_connections_ + obj.out_connections_: itemHandler = connObjTuple[0] itemHandlers.append(itemHandler) if(self.dc.itemcget(itemHandler, "smooth") != "0"): howManySmoothOnes += 1 # Most of them are already smooth, so un-smooth them if(howManySmoothOnes != 0 and float(len(itemHandlers)) / float(howManySmoothOnes) > 0.5): smoothFlag = False # Apply the smoothness to the items... for itemHandler in itemHandlers: self.dc.itemconfigure(itemHandler, smooth = smoothFlag)
def makeAllConnectionsVisible(self): """ """ color = 'orange' print '\nVisual modification activated' print 'All invisible links have been re-colored to the color', color print 'NOTE:' print ' Effect is purely visual.' print ' Re-load model to restore invisibility of affected links.' print ' The', color, 'color is hard-coded in', __file__, print 'method makeAllConnectionsVisible\n' from ModelSpecificCode import isConnectionLink dc = self.cb.getCanvas() for nodeList in self.ASGroot.listNodes.values(): for node in nodeList: obj = node.graphObject_ if isConnectionLink(obj): for connectionList in [obj.in_connections_ + obj.out_connections_]: for conInfoTuple in connectionList: itemHandler = conInfoTuple[0] #print 'itemHandler', itemHandler if(not self.cb.isItemVisible(itemHandler)): #print 'invisible' itemtype = dc.type(itemHandler) #print 'itemtype', itemtype if itemtype in ['line', 'text']: dc.itemconfigure(itemHandler, fill=color) else: dc.itemconfigure(itemHandler, outline=color)
def __getEntityList(self, selection): """ If selection is empty, get all nodes on the canvas Else filter out links """ entityNodeList = [] # Selection may contain a mixed bag of nodes and links if (selection): for node in selection: if (not isConnectionLink(node)): entityNodeList.append(node) # No selection? Grab all nodes in diagram else: if (not self.atom3i.ASGroot): return [] for nodetype in self.atom3i.ASGroot.nodeTypes: for node in self.atom3i.ASGroot.listNodes[nodetype]: if (not isConnectionLink(node.graphObject_)): entityNodeList.append(node.graphObject_) return entityNodeList
def __getEntityList(self, selection): """ If selection is empty, get all nodes on the canvas Else filter out links """ entityNodeList = [] # Selection may contain a mixed bag of nodes and links if(selection): for node in selection: if(not isConnectionLink(node)): entityNodeList.append(node) # No selection? Grab all nodes in diagram else: if(not self.atom3i.ASGroot): return [] for nodetype in self.atom3i.ASGroot.nodeTypes: for node in self.atom3i.ASGroot.listNodes[nodetype]: if(not isConnectionLink(node.graphObject_)): entityNodeList.append(node.graphObject_) return entityNodeList
def __getEntityLinkTuple(self, selection): """ If selection is empty, get all nodes & links on the canvas Else returns the entities and links in the selection Returns a tuple containing: entityList = List of entity ASG nodes linkNodeDict = Mapping of link ASG nodes to VisualObj graph objects """ entityNodeList = [] # Non-edge entities linkNodeDict = dict() # Regular and self-looping edges # Selection may contain a mixed bag of nodes and links if(selection): for node in selection: semObj = node.semanticObject if(isConnectionLink(node)): #linkNodeList.append(semObj) linkNodeDict[semObj] = node else: entityNodeList.append(semObj) # No selection? Grab all nodes in diagram else: if(not self.atom3i.ASGroot): return ([], []) for nodetype in self.atom3i.ASGroot.nodeTypes: for node in self.atom3i.ASGroot.listNodes[nodetype]: if(isConnectionLink(node.graphObject_)): #linkNodeList.append(node) linkNodeDict[node] = node.graphObject_ else: entityNodeList.append(node) if(selection): return (entityNodeList, linkNodeDict) return (entityNodeList, linkNodeDict)
def __getEntityLinkTuple(self, selection): """ If selection is empty, get all nodes & links on the canvas Else returns the entities and links in the selection Returns a tuple containing: entityList = List of entity ASG nodes linkNodeDict = Mapping of link ASG nodes to VisualObj graph objects """ entityNodeList = [] # Non-edge entities linkNodeDict = dict() # Regular and self-looping edges # Selection may contain a mixed bag of nodes and links if (selection): for node in selection: semObj = node.semanticObject if (isConnectionLink(node)): #linkNodeList.append(semObj) linkNodeDict[semObj] = node else: entityNodeList.append(semObj) # No selection? Grab all nodes in diagram else: if (not self.atom3i.ASGroot): return ([], []) for nodetype in self.atom3i.ASGroot.nodeTypes: for node in self.atom3i.ASGroot.listNodes[nodetype]: if (isConnectionLink(node.graphObject_)): #linkNodeList.append(node) linkNodeDict[node] = node.graphObject_ else: entityNodeList.append(node) if (selection): return (entityNodeList, linkNodeDict) return (entityNodeList, linkNodeDict)
def __grabInfoFromGraphicalObject(self, obj): """ Takes a graphical object and stores relevent info in a data structure """ # This be a node/entity object if (not isConnectionLink(obj)): try: x0, y0, x1, y1 = obj.getbbox() width = abs((x0 - x1)) height = abs((y0 - y1)) center = [x0 + width / 2, y0 + height / 2] except: print "ERROR caught and handled in ForceTransfer.py in __grabInfoFromGraphicalObject" width = 4 height = 4 center = [obj.x, obj.y] x0 = obj.x - 2 y0 = obj.y - 2 NodeObject(obj, center, [width, height], self.__minNodeDist, topLeftPos=[x0, y0]) # This be a link/edge object elif (self.__minLinkDist > 0): # Treat the link center as a repulsive object EdgeObject(obj, obj.getCenterCoord(), self.__minLinkDist) # Treat each control point as a repulsive object if (self.__minControlDist > 0): if (not self.dc): return for connTuple in obj.connections: itemHandler = connTuple[0] c = self.dc.coords(itemHandler) for i in range(2, len(c) - 2, 2): ControlPoint(c[i:i + 2], self.__minControlDist, itemHandler, i, self.dc)
def createDynamicMenu(self, event): """ Create a dynamic context sensitive popup menu system """ cb = self.cb selectionIsEmpty = cb.isLastSelectionEmpty() # Item under cursor? itemTuple = cb.getItemUnderCursor(self, event) if(itemTuple and cb.isItemVisible(itemTuple[0])): obj = itemTuple[2] # Graph Entity Object Selected if(isEntityNode(obj)): if(selectionIsEmpty): self.popupMenuCreator.EntityAtCursorNoSelectPopup(event) else: self.popupMenuCreator.EntityAtCursorMultiSelectPopup(event) # Graph Link Object Selected elif(isConnectionLink(obj)): if(selectionIsEmpty): self.popupMenuCreator.LinkAtCursorNoSelectPopup(event) else: self.popupMenuCreator.LinkAtCursorMultiSelectPopup(event) # Uknown Object Selected else: raise Exception, \ "Not an entity, not a link, what is it? Superman? " + str(obj) # No item under cursor, no items selected elif(selectionIsEmpty): self.popupMenuCreator.NoCursorNoSelectPopup(event) # No item under cursor, but multiple items selected else: self.popupMenuCreator.NoCursorMultiSelectPopup(event)
def createDynamicMenu(self, event): """ Create a dynamic context sensitive popup menu system """ cb = self.cb selectionIsEmpty = cb.isLastSelectionEmpty() # Item under cursor? itemTuple = cb.getItemUnderCursor(self, event) if (itemTuple and cb.isItemVisible(itemTuple[0])): obj = itemTuple[2] # Graph Entity Object Selected if (isEntityNode(obj)): if (selectionIsEmpty): self.popupMenuCreator.EntityAtCursorNoSelectPopup(event) else: self.popupMenuCreator.EntityAtCursorMultiSelectPopup(event) # Graph Link Object Selected elif (isConnectionLink(obj)): if (selectionIsEmpty): self.popupMenuCreator.LinkAtCursorNoSelectPopup(event) else: self.popupMenuCreator.LinkAtCursorMultiSelectPopup(event) # Uknown Object Selected else: raise Exception, \ "Not an entity, not a link, what is it? Superman? " + str(obj) # No item under cursor, no items selected elif (selectionIsEmpty): self.popupMenuCreator.NoCursorNoSelectPopup(event) # No item under cursor, but multiple items selected else: self.popupMenuCreator.NoCursorMultiSelectPopup(event)
def __grabInfoFromGraphicalObject( self, obj ): """ Takes a graphical object and stores relevent info in a data structure """ # This be a node/entity object if( not isConnectionLink( obj ) ): try: x0,y0,x1,y1 = obj.getbbox() width = abs( (x0 - x1) ) height = abs( (y0 - y1) ) center = [ x0 + width/2, y0 + height/2 ] except: print "ERROR caught and handled in ForceTransfer.py in __grabInfoFromGraphicalObject" width = 4 height = 4 center = [obj.x, obj.y] x0 = obj.x - 2 y0 = obj.y - 2 NodeObject( obj, center, [width,height], self.__minNodeDist, topLeftPos = [x0,y0] ) # This be a link/edge object elif( self.__minLinkDist > 0 ) : # Treat the link center as a repulsive object EdgeObject( obj, obj.getCenterCoord(), self.__minLinkDist ) # Treat each control point as a repulsive object if( self.__minControlDist > 0 ): if( not self.dc ): return for connTuple in obj.connections: itemHandler = connTuple[0] c = self.dc.coords( itemHandler ) for i in range(2,len(c)-2,2): ControlPoint( c[i:i+2], self.__minControlDist, itemHandler, i, self.dc )
def writeExportCode(self, fileName, exportFormat, graphicDict, labelingMode=False): """ Generates GML code for creating this graph. self = ASGroot """ file = open(fileName, "w+t") dir, fil = os.path.split(fileName) funcName = string.split(fil, ".") # Compose class name # Header code if (exportFormat == Exporter.GML_LABELED or exportFormat == Exporter.GML_CLASSIC): # GML file.write('Creator \"Atom3 GML Exporter\"\n') file.write('Version \"0.2.2\"\n') file.write('graph\n') file.write('[\n') file.write(' hierarchic 1\n') file.write(' label \"' + funcName[0] + '\"\n') file.write(' directed 1\n') elif (exportFormat == Exporter.GXL_LABELED or exportFormat == Exporter.GXL_CLASSIC): # GXL file.write('<gxl><graph>\n') elif (exportFormat == Exporter.DOT_LABELED): # DOT file.write('digraph g {\n') else: raise Exception # Body Code, Version 1: generates a graph with nodes in between nodes (as labels) if (labelingMode): for nodetype in self.nodeTypes: # Iterate on all the node types... for node in self.listNodes[ nodetype]: # Iterate on all the nodes of each type if (isConnectionLink(node.graphObject_)): whiteLabel = True else: whiteLabel = False shape, color, label = getShapeColorLabel( node, nodetype, graphicDict) position = [node.graphObject_.x, node.graphObject_.y] # Label with no border if (whiteLabel and exportFormat == Exporter.GML_CLASSIC): file.write( genGMLNodeCode(node.objectNumber,label,position, \ fill="#FFFFFF", outline= "#FFFFFF" ) ) else: if (exportFormat == Exporter.GML_CLASSIC): file.write( genGMLNodeCode(node.objectNumber, label, position, fill=color, type=shape)) elif (exportFormat == Exporter.GXL_CLASSIC): file.write(genGXLNodeCode(node.objectNumber, label)) # Generate code for the connections... edgeID = 0 for nodetype in self.nodeTypes: for node in self.listNodes[nodetype]: # Looping over the output connections is sufficient for obj in node.out_connections_: if (exportFormat == Exporter.GML_CLASSIC): file.write( genGMLConnectionCode(node.objectNumber, obj.objectNumber)) elif (exportFormat == Exporter.GXL_CLASSIC): file.write( genGXLConnectionCode(node.objectNumber, obj.objectNumber, edgeID)) edgeID += 1 # Body Code, Version 2: no intermediate nodes, labels directly on the edges else: for nodetype in self.nodeTypes: # Iterate on all the node types... for node in self.listNodes[ nodetype]: # Iterate on all the nodes of each type if (isConnectionLink(node.graphObject_)): continue shape, color, label = getShapeColorLabel( node, nodetype, graphicDict) position = [node.graphObject_.x, node.graphObject_.y] # Generate code for the nodes... if (exportFormat == Exporter.GML_LABELED): file.write( genGMLNodeCode(node.objectNumber, label, position, fill=color, type=shape)) elif (exportFormat == Exporter.GXL_LABELED): file.write(genGXLNodeCode(node.objectNumber, label)) elif (exportFormat == Exporter.DOT_LABELED): file.write(genDOTNodeCode(node.objectNumber, label)) # Generate code for the connections... edgeID = 0 for nodetype in self.nodeTypes: for node in self.listNodes[nodetype]: if (not isConnectionLink(node.graphObject_)): continue label = getShapeColorLabel(node, nodetype, graphicDict)[2] target = node.out_connections_[0].objectNumber source = node.in_connections_[0].objectNumber if (exportFormat == Exporter.GML_LABELED): file.write(genGMLConnectionCode(source, target, label)) elif (exportFormat == Exporter.GXL_LABELED): file.write( genGXLConnectionCode(source, target, edgeID, label)) edgeID += 1 elif (exportFormat == Exporter.DOT_LABELED): file.write(genDOTConnectionCode(source, target, label)) # Footer code if (exportFormat == Exporter.GML_LABELED or exportFormat == Exporter.GML_CLASSIC): # GML file.write(']\n') elif (exportFormat == Exporter.GXL_LABELED or exportFormat == Exporter.GXL_CLASSIC): # GXL file.write('</graph></gxl>\n') elif (exportFormat == Exporter.DOT_LABELED): #DOT file.write('}\n') else: raise Exception file.close() return funcName[0] # This indicates that we've done something
def edit(self, event=None): """ Edit window for setting up the graphical appearence of a given node type """ nodeType = self.listbox.get(self.listbox.curselection()[0]) shape, color, attrList = self.EXPORT_GRAPHIC_DICT[nodeType] node = self.atom3i.ASGroot.listNodes[nodeType][0] allAttrList = node.generatedAttributes.keys() useShape, useColor, useLabels = self.getExportTypeTuple( getExportableAttributes=True) # New toplevel window self.editWindow = Tkinter.Toplevel(self.Tkroot) self.editWindow.geometry("+%d+%d" % (150, 150)) self.editWindow.title("Export Appearence: " + nodeType) self.editWindow.transient(self.Tkroot) try: self.editWindow.grab_set() except: pass self.editWindow.focus_set() self.editWindow.tk_focusFollowsMouse() # Frame Creation Area self.superEditFrame = Tkinter.Frame(self.editWindow) self.editFrame = Tkinter.Frame(self.superEditFrame) self.shapeColorFrame = Tkinter.Frame(self.editFrame) self.labelFrame = Tkinter.Frame(self.shapeColorFrame) self.shapeFrame = Tkinter.Frame(self.shapeColorFrame) self.colorFrame = Tkinter.Frame(self.shapeColorFrame) self.activeFrame = Tkinter.Frame(self.editFrame) self.av_labelFrame = Tkinter.Frame(self.activeFrame) self.av_listFrame = Tkinter.Frame(self.activeFrame) self.av_remFrame = Tkinter.Frame(self.activeFrame) self.allAttributesFrame = Tkinter.Frame(self.editFrame) self.all_labelFrame = Tkinter.Frame(self.allAttributesFrame) self.all_listFrame = Tkinter.Frame(self.allAttributesFrame) self.all_addFrame = Tkinter.Frame(self.allAttributesFrame) # Shape & Color Panel self.shapeColorl = Tkinter.Label(self.labelFrame, height=2, text='Shape & Color', relief=Tkinter.GROOVE, bg='white') self.shapeListBox = self.createListBox(self.shapeFrame, self.GML_SHAPE_LIST) # Set the active shape for i in range(0, len(self.GML_SHAPE_LIST)): if (shape == self.GML_SHAPE_LIST[i]): self.shapeListBox[0].selection_set(i) self.colorb = Tkinter.Button(self.colorFrame, text="Choose Color", command=self.chooseColor) self.colorl = Tkinter.Label(self.colorFrame, height=2, relief=Tkinter.RIDGE, bg=color) self.shapeColorl.pack(side=Tkinter.LEFT, fill=Tkinter.BOTH, expand=1) self.shapeListBox[0].pack(side=Tkinter.LEFT, fill=Tkinter.BOTH, expand=1) self.shapeListBox[1].pack(side=Tkinter.LEFT, fill=Tkinter.Y) self.colorb.pack(side=Tkinter.LEFT, fill=Tkinter.BOTH) self.colorl.pack(side=Tkinter.LEFT, fill=Tkinter.BOTH, expand=1) # Active Attributes Panel self.av_activel = Tkinter.Label(self.av_labelFrame, height=2, text='Export Attributes', relief=Tkinter.GROOVE, bg='white') self.av_activeListbox = self.createListBox( self.av_listFrame, attrList, doubleclickCallback=self.removeActiveAttribute) self.av_orderb = Tkinter.Button(self.av_remFrame, text="Remove Attribute", command=self.removeActiveAttribute) self.av_activel.pack(side=Tkinter.LEFT, fill=Tkinter.BOTH, expand=1) self.av_activeListbox[0].pack(side=Tkinter.LEFT, fill=Tkinter.BOTH, expand=1) self.av_activeListbox[1].pack(side=Tkinter.LEFT, fill=Tkinter.Y) self.av_orderb.pack(side=Tkinter.LEFT, fill=Tkinter.BOTH, expand=1) # All Attributes Panel self.all_activel = Tkinter.Label(self.all_labelFrame, height=2, text='All Attributes', relief=Tkinter.GROOVE, bg='white') self.all_attributesListbox = self.createListBox( self.all_listFrame, allAttrList, doubleclickCallback=self.addAttribute) self.all_orderb = Tkinter.Button(self.all_addFrame, text="Add Attribute", command=self.addAttribute) self.all_activel.pack(side=Tkinter.LEFT, fill=Tkinter.BOTH, expand=1) self.all_attributesListbox[0].pack(side=Tkinter.LEFT, fill=Tkinter.BOTH, expand=1) self.all_attributesListbox[1].pack(side=Tkinter.LEFT, fill=Tkinter.Y) self.all_orderb.pack(side=Tkinter.LEFT, fill=Tkinter.BOTH, expand=1) # Done & Ready Panel self.editDoneb = Tkinter.Button(self.superEditFrame, text="Done", command=self.editDone) self.editDoneb.pack(side=Tkinter.BOTTOM, fill=Tkinter.BOTH, expand=1) # Frame Packaging Area if (not isConnectionLink(node.graphObject_) and (useShape or useColor)): self.labelFrame.pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=1) if (useShape): self.shapeFrame.pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=1) if (useColor): self.colorFrame.pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=1) self.shapeColorFrame.pack(side=Tkinter.LEFT, fill=Tkinter.BOTH, expand=1) if (useLabels): self.av_labelFrame.pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=1) self.av_listFrame.pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=1) self.av_remFrame.pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=1) self.activeFrame.pack(side=Tkinter.LEFT, fill=Tkinter.BOTH, expand=1) self.all_labelFrame.pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=1) self.all_listFrame.pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=1) self.all_addFrame.pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=1) self.allAttributesFrame.pack(side=Tkinter.LEFT, fill=Tkinter.BOTH, expand=1) self.superEditFrame.pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=1) self.editFrame.pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=1)
def writeExportCode(self, fileName,exportFormat, graphicDict, labelingMode = False ): """ Generates GML code for creating this graph. self = ASGroot """ file = open(fileName, "w+t" ) dir, fil = os.path.split(fileName) funcName = string.split (fil, ".") # Compose class name # Header code if( exportFormat == Exporter.GML_LABELED or exportFormat == Exporter.GML_CLASSIC ): # GML file.write('Creator \"Atom3 GML Exporter\"\n') file.write('Version \"0.2.2\"\n') file.write('graph\n') file.write('[\n') file.write(' hierarchic 1\n') file.write(' label \"' + funcName[0] + '\"\n') file.write(' directed 1\n') elif( exportFormat == Exporter.GXL_LABELED or exportFormat == Exporter.GXL_CLASSIC ): # GXL file.write('<gxl><graph>\n') elif(exportFormat == Exporter.DOT_LABELED ): # DOT file.write('digraph g {\n') else: raise Exception # Body Code, Version 1: generates a graph with nodes in between nodes (as labels) if( labelingMode ): for nodetype in self.nodeTypes: # Iterate on all the node types... for node in self.listNodes[nodetype]: # Iterate on all the nodes of each type if( isConnectionLink( node.graphObject_ ) ): whiteLabel = True else: whiteLabel = False shape, color, label = getShapeColorLabel( node, nodetype, graphicDict ) position = [node.graphObject_.x, node.graphObject_.y] # Label with no border if( whiteLabel and exportFormat == Exporter.GML_CLASSIC ): file.write( genGMLNodeCode(node.objectNumber,label,position, \ fill="#FFFFFF", outline= "#FFFFFF" ) ) else: if( exportFormat == Exporter.GML_CLASSIC ): file.write( genGMLNodeCode(node.objectNumber,label,position, fill = color, type = shape ) ) elif( exportFormat == Exporter.GXL_CLASSIC ): file.write( genGXLNodeCode(node.objectNumber,label ) ) # Generate code for the connections... edgeID = 0 for nodetype in self.nodeTypes: for node in self.listNodes[nodetype]: # Looping over the output connections is sufficient for obj in node.out_connections_: if( exportFormat == Exporter.GML_CLASSIC ): file.write( genGMLConnectionCode(node.objectNumber,obj.objectNumber)) elif( exportFormat == Exporter.GXL_CLASSIC ): file.write( genGXLConnectionCode(node.objectNumber,obj.objectNumber,edgeID)) edgeID += 1 # Body Code, Version 2: no intermediate nodes, labels directly on the edges else: for nodetype in self.nodeTypes: # Iterate on all the node types... for node in self.listNodes[nodetype]: # Iterate on all the nodes of each type if( isConnectionLink( node.graphObject_ ) ): continue shape, color, label = getShapeColorLabel( node, nodetype, graphicDict ) position = [ node.graphObject_.x, node.graphObject_.y] # Generate code for the nodes... if( exportFormat == Exporter.GML_LABELED ): file.write( genGMLNodeCode(node.objectNumber,label,position, fill=color, type=shape) ) elif( exportFormat == Exporter.GXL_LABELED ): file.write( genGXLNodeCode(node.objectNumber,label) ) elif(exportFormat == Exporter.DOT_LABELED ): file.write( genDOTNodeCode(node.objectNumber,label) ) # Generate code for the connections... edgeID = 0 for nodetype in self.nodeTypes: for node in self.listNodes[nodetype]: if( not isConnectionLink( node.graphObject_ ) ): continue label = getShapeColorLabel( node, nodetype, graphicDict )[ 2 ] target = node.out_connections_[0].objectNumber source = node.in_connections_[0].objectNumber if( exportFormat == Exporter.GML_LABELED ): file.write( genGMLConnectionCode(source,target,label) ) elif( exportFormat == Exporter.GXL_LABELED ): file.write( genGXLConnectionCode(source,target,edgeID,label) ) edgeID += 1 elif(exportFormat == Exporter.DOT_LABELED ): file.write( genDOTConnectionCode(source,target,label) ) # Footer code if( exportFormat == Exporter.GML_LABELED or exportFormat == Exporter.GML_CLASSIC ): # GML file.write(']\n') elif( exportFormat == Exporter.GXL_LABELED or exportFormat == Exporter.GXL_CLASSIC ): # GXL file.write('</graph></gxl>\n') elif(exportFormat == Exporter.DOT_LABELED ): #DOT file.write('}\n') else: raise Exception file.close() return funcName[0] # This indicates that we've done something
def edit( self, event=None ): """ Edit window for setting up the graphical appearence of a given node type """ nodeType = self.listbox.get(self.listbox.curselection()[0]) shape, color, attrList = self.EXPORT_GRAPHIC_DICT[ nodeType ] node = self.atom3i.ASGroot.listNodes[ nodeType ][ 0 ] allAttrList = node.generatedAttributes.keys() useShape, useColor, useLabels = self.getExportTypeTuple( getExportableAttributes = True ) # New toplevel window self.editWindow = Tkinter.Toplevel(self.Tkroot) self.editWindow.geometry("+%d+%d" % (150,150)) self.editWindow.title("Export Appearence: " + nodeType ) self.editWindow.transient(self.Tkroot) try: self.editWindow.grab_set() except: pass self.editWindow.focus_set() self.editWindow.tk_focusFollowsMouse() # Frame Creation Area self.superEditFrame = Tkinter.Frame(self.editWindow) self.editFrame = Tkinter.Frame(self.superEditFrame) self.shapeColorFrame = Tkinter.Frame(self.editFrame) self.labelFrame = Tkinter.Frame(self.shapeColorFrame) self.shapeFrame = Tkinter.Frame(self.shapeColorFrame) self.colorFrame = Tkinter.Frame(self.shapeColorFrame) self.activeFrame = Tkinter.Frame(self.editFrame) self.av_labelFrame = Tkinter.Frame(self.activeFrame) self.av_listFrame = Tkinter.Frame(self.activeFrame) self.av_remFrame = Tkinter.Frame(self.activeFrame) self.allAttributesFrame = Tkinter.Frame(self.editFrame) self.all_labelFrame = Tkinter.Frame(self.allAttributesFrame) self.all_listFrame = Tkinter.Frame(self.allAttributesFrame) self.all_addFrame = Tkinter.Frame(self.allAttributesFrame) # Shape & Color Panel self.shapeColorl = Tkinter.Label(self.labelFrame, height=2, text='Shape & Color', relief=Tkinter.GROOVE, bg='white' ) self.shapeListBox = self.createListBox( self.shapeFrame, self.GML_SHAPE_LIST ) # Set the active shape for i in range( 0, len( self.GML_SHAPE_LIST ) ): if( shape == self.GML_SHAPE_LIST[ i ] ): self.shapeListBox[0].selection_set( i ) self.colorb = Tkinter.Button(self.colorFrame, text="Choose Color", command=self.chooseColor ) self.colorl = Tkinter.Label(self.colorFrame, height=2, relief=Tkinter.RIDGE, bg=color ) self.shapeColorl.pack(side=Tkinter.LEFT, fill=Tkinter.BOTH, expand=1 ) self.shapeListBox[0].pack(side=Tkinter.LEFT, fill=Tkinter.BOTH, expand=1) self.shapeListBox[1].pack(side=Tkinter.LEFT, fill=Tkinter.Y) self.colorb.pack(side=Tkinter.LEFT, fill=Tkinter.BOTH ) self.colorl.pack(side=Tkinter.LEFT, fill=Tkinter.BOTH, expand=1 ) # Active Attributes Panel self.av_activel = Tkinter.Label(self.av_labelFrame, height=2, text='Export Attributes', relief=Tkinter.GROOVE, bg='white' ) self.av_activeListbox = self.createListBox( self.av_listFrame, attrList, doubleclickCallback = self.removeActiveAttribute ) self.av_orderb = Tkinter.Button(self.av_remFrame, text="Remove Attribute", command=self.removeActiveAttribute ) self.av_activel.pack(side=Tkinter.LEFT, fill=Tkinter.BOTH, expand=1 ) self.av_activeListbox[0].pack(side=Tkinter.LEFT, fill=Tkinter.BOTH, expand=1) self.av_activeListbox[1].pack(side=Tkinter.LEFT, fill=Tkinter.Y) self.av_orderb.pack(side=Tkinter.LEFT, fill=Tkinter.BOTH, expand=1 ) # All Attributes Panel self.all_activel = Tkinter.Label(self.all_labelFrame, height=2, text='All Attributes', relief=Tkinter.GROOVE, bg='white' ) self.all_attributesListbox = self.createListBox( self.all_listFrame, allAttrList, doubleclickCallback = self.addAttribute) self.all_orderb = Tkinter.Button(self.all_addFrame, text="Add Attribute", command=self.addAttribute ) self.all_activel.pack(side=Tkinter.LEFT, fill=Tkinter.BOTH, expand=1 ) self.all_attributesListbox[0].pack(side=Tkinter.LEFT, fill=Tkinter.BOTH, expand=1) self.all_attributesListbox[1].pack(side=Tkinter.LEFT, fill=Tkinter.Y) self.all_orderb.pack(side=Tkinter.LEFT, fill=Tkinter.BOTH, expand=1 ) # Done & Ready Panel self.editDoneb = Tkinter.Button(self.superEditFrame, text="Done", command=self.editDone ) self.editDoneb.pack(side=Tkinter.BOTTOM, fill=Tkinter.BOTH, expand=1 ) # Frame Packaging Area if( not isConnectionLink( node.graphObject_ ) and (useShape or useColor) ): self.labelFrame.pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=1) if( useShape ): self.shapeFrame.pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=1) if( useColor ): self.colorFrame.pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=1) self.shapeColorFrame.pack(side=Tkinter.LEFT, fill=Tkinter.BOTH, expand=1) if( useLabels ): self.av_labelFrame.pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=1) self.av_listFrame.pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=1) self.av_remFrame.pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=1) self.activeFrame.pack(side=Tkinter.LEFT, fill=Tkinter.BOTH, expand=1) self.all_labelFrame.pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=1) self.all_listFrame.pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=1) self.all_addFrame.pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=1) self.allAttributesFrame.pack(side=Tkinter.LEFT, fill=Tkinter.BOTH, expand=1) self.superEditFrame.pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=1) self.editFrame.pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=1)
def main(self, selection): if( not selection ): return atom3i = self.atom3i nodeObject.nodeList = [] edgeObject.edgeList = [] edgeObject.dc = self.dc #------------------------- INFORMATION GATHERING ------------------------- # Generate a datastructure for the Nodes and Edges in the diagram, containing # only the information needed by this algorithm. edgeList = [] nodeDict = dict() self.sourceTargetDict = dict() for obj in selection: if( isConnectionLink( obj ) ): # Edge! edgeList.append( obj.getSemanticObject() ) else: # Node pos = obj.getCenterCoord() boundBox = obj.getbbox() if( self.__stickyBoundary ): boundary = self.atom3i.CANVAS_SIZE_TUPLE else: boundary = None n = nodeObject( obj, pos, boundBox, self.__chargeStrength, boundary ) nodeDict.update( { obj : n } ) # Now lets go through the "node" edges... for node in edgeList: # Source object key = node.in_connections_[0].graphObject_ if( not nodeDict.has_key( key ) ): continue source = nodeDict[ key ] # Target object key = node.out_connections_[0].graphObject_ if( not nodeDict.has_key( key ) ): continue target = nodeDict[ key ] # Make the edge object with the info... edgeObject(node, source, target) self.sourceTargetDict[ source ] = target # These nodes have edges... source.setHasEdgeTrue() target.setHasEdgeTrue() # Count the beans... self.__totalNodes = len( nodeObject.nodeList ) if( self.__totalNodes <= 1 ): return #-------------------------- MAIN SIMULATION LOOP ------------------------- # Initial card shuffling :D if( self.__randomness ): self.__shakeThingsUp( self.__randomness ) i = 0 while( i < self.__maxIterations ): # Calculate the powers that be self.__calculateRepulsiveForces() self.__calculateAttractiveForces() # Move move move! for node in nodeObject.nodeList: node.commitMove() # Force a screen update every x calculation if( i % self.__animationUpdates == 0 ): self.dc.update_idletasks() i+=1 #--------------------------- FINAL OPTIMIZATIONS ------------------------- # Optimize the arrows to use the nearest connectors optimizeLinks( self.atom3i.cb, self.__splineArrows, self.__arrowCurvature ) # Make sure the canvas is updated self.dc.update_idletasks()
def getSelectedItemsForDelete(self, entityOnlyFlag=False): """ Use: Finds all the selected nodes and links, then creates a custom event, DeleteEvent, which it sends to the UI_scope that then sends the event to whichever scoped statechart will handle it. The DeleteEvent uses the x, y coordinates of the node/link to be deleted, so potentially, each node/link's deletion could be handled by a different scoped statechart. Parameters: self, ATOM3 instance entityOnlyFlag, if this boolean flag is True, then deleting an entity will NOT automatically delete arrows that connect to that entity """ class DeleteEvent: """ A special event that mimics the x, y coordinates of a Tkinter binding generated event, but lacks many of the normal attributes, and includes tag and itemHandler attributes not normally found there... """ def __init__(self, obj, tag=None, itemHandlerTagList=None, entityOnlyFlag=False): self.x = obj.x self.y = obj.y self.tag = tag self.semanticObject = obj.semanticObject self.atom3i = obj.semanticObject.parent self.itemHandlerTagList = itemHandlerTagList self.entityOnlyFlag = entityOnlyFlag def destroy(self): """ Deletes the associated ATOM3 node or link """ if (self.itemHandlerTagList): tag2objMap = self.atom3i.cb.getTag2ObjMap() for itemHandler, tag in self.itemHandlerTagList: # Deleting one segment of an arrow, can delete the other, so careful! if (tag2objMap.has_key(tag)): self.atom3i.deleteConnection(itemHandler, tag) else: self.atom3i.deleteRealEntity(self.tag, entityOnly=self.entityOnlyFlag) def getSemanticObject(self): """ Returns the ASGNode instance being deleted """ return self.semanticObject selectionDict = self.cb.getSelectionDict() # Dict of selected items objTagDict = dict() self.fromClass = None self.toClass = None # This little dictionary gymnastic is being used to prevent duplicate objects for tag in selectionDict: obj = selectionDict[tag][1] objTagDict.update({obj: tag}) # Now do the connections first, since if entities disappear, # connections might too. And we DO NOT want that to happen... crash crash :p for obj in objTagDict: tag = objTagDict[obj] # Connection if (isConnectionLink(obj)): #print "Now deleting connection: ", tag, obj, selectionDict[tag][0] # This may seem like overkill, but it's necessary for hyper-edges connList = [] for connTuple in obj.in_connections_: connList.append(connTuple) for connTuple in obj.out_connections_: connList.append(connTuple) itemHandlerTagList = [] for connTuple in connList: itemHandlerTagList.append(connTuple[:2]) event = DeleteEvent(obj, itemHandlerTagList=itemHandlerTagList) self.UI_scope('<serviceLinkDeleteRequest>', event) # Entity else: event = DeleteEvent(obj, tag=tag, entityOnlyFlag=entityOnlyFlag) self.UI_scope('<serviceNodeDeleteRequest>', event) # Model changed! modelChange(self) # No more selected objects :-( self.cb.clearSelectionDict()
def optimizeConnectionPorts(self, entityList=None, linkObjectList=None, doAllLinks=False, cb=None): """ Ensures that the endpoints of the arrows use the optimal connectors Applied only to selected arrows and to the arrows attached to selected nodes Does not move arrows attached to named ports :D 4 Modes of operation: i) Given entityList, a list of nodes, the links between them will be optimized ii) Given linkObjectList, a list of edge graph objects, the links are optimized iii) Given doAllLinks, a boolean and self=atom3i, optimizes all links on the canvas iv) Given self=atom3i or cb=cb, will optimize everything currently selected on the canvas NOTES: a) self argument should be atom3 instance, required if doAllLinks=True, otherwise, cb=cb is acceptable b) cb is an instance of CallbackState """ if (not cb): cb = self.cb dc = cb.getCanvas() # Step 1A: Given entities, not a selection dict, so get all affected links if (entityList): augmentedSelection = dict() # List of node/entity objects for obj in entityList: # Any one of its links may need optimization augmentTheSelection(dc, obj, augmentedSelection) # Step 1B: Given list of link objects elif (linkObjectList): augmentedSelection = dict() for linkObject in linkObjectList: linkTag = linkObject.tag + "1stSeg0" itemHandler = dc.find_withtag(linkTag) if (not itemHandler): print "WARNING: Utilities.optimizeConnectionPorts() cannot find item with tag", linkTag continue # raise Exception, "optimizeConnectionPorts() having trouble playing " \ # + "tag, Step 1B (Try save & load)" # Add to the selection, {tag : [itemHandler, Object] } augmentedSelection[linkTag] = [itemHandler[0], linkObject] # Step 1C: Find all the links! elif (doAllLinks): augmentedSelection = dict() nodeTypes = self.ASGroot.nodeTypes listNodes = self.ASGroot.listNodes for nodetype in nodeTypes: if (listNodes[nodetype]): if (isConnectionLink(listNodes[nodetype][0].graphObject_)): # Iterate over all the links only for node in listNodes[nodetype]: linkTag = node.graphObject_.tag + "1stSeg0" itemHandler = dc.find_withtag(linkTag) if (not itemHandler): print "WARNING: itemhandler not found! Utilities.py --> " \ + "optimizeConnectionPorts() fails (Try save & load)" continue # Add to the selection, {tag : [itemHandler, Object] } augmentedSelection[linkTag] = [ itemHandler[0], node.graphObject_ ] # Step 1D: Augment the selection with links affected by the node movement # & remove nodes else: selection = cb.getSelectionDict() augmentedSelection = selection.copy( ) # <--- This copy() is soooo important for tag in selection: itemHandler, obj = selection[tag] # This is a NODE if (isEntityNode(obj)): # Any one of its links may need optimization augmentTheSelection(dc, obj, augmentedSelection) # We don't need to optimize nodes, just links... so... bye bye node del augmentedSelection[tag] # Step 2: Optimize all the selected links for tag in augmentedSelection: obj = augmentedSelection[tag][1] baseTag = obj.tag # Ex: Obj3 , the tag of the intermediate link object # Some links have center objects (labels/drawings) that look way better # if they are above the arrow centerObj = obj.getCenterObject() if (centerObj): dc.tag_raise(centerObj.tag) # Find all the entities that the edge is linking to # (general enough to handle hyperedges) objectsFrom = [] objectsTo = [] semObject = obj.getSemanticObject() arrowArrowCase = False for semObj in semObject.in_connections_: if (isConnectionLink(semObj.graphObject_)): arrowArrowCase = True objectsFrom.append(semObj.graphObject_) for semObj in semObject.out_connections_: if (isConnectionLink(semObj.graphObject_)): arrowArrowCase = True objectsTo.append(semObj.graphObject_) # Arrow connected to another arrow, this isn't handled!!! if (arrowArrowCase): continue # Initial point/s in the connection ---> Object/s From for i in range(0, len(objectsFrom)): # Get the tag & itemhandler for each from segement segTag = baseTag + "1stSeg" + str(i) itemHandler = dc.find_withtag(segTag) if (not itemHandler): print "WARNING: Having problems looking up canvas tags!", segTag continue #raise Exception, "Having problems looking up canvas tags!" coords = dc.coords(itemHandler) objFrom = objectsFrom[i] # If the object has connectors and they are not NAMED connectors if (objFrom.hasConnectors() and not objFrom.isConnectedByNamedPort(obj.semanticObject)): # Snap to the nearest connection port if not already there # NOTE: the [obj.x,obj.y] part makes sure we connect directly # to the intermediate object x, y = objFrom.getClosestConnector2Point( objFrom, coords[2], coords[3]) if (x != coords[0] or y != coords[1]): dc.coords(*[itemHandler] + [x, y] + coords[2:-2] + [obj.x, obj.y]) # Check if a link drawing needs moving... obj.updateDrawingsTo(x, y, itemHandler[0]) # Final point/s in the connection ---> Object/s To for i in range(0, len(objectsTo)): # Get the tag & itemhandler for each to segement segTag = baseTag + "2ndSeg" + str(i) itemHandler = dc.find_withtag(segTag) if (not itemHandler): print "WARNING: Having problems looking up canvas tags!", segTag continue #raise Exception, "Having problems looking up canvas tags!" itemHandler = itemHandler[0] coords = dc.coords(itemHandler) objTo = objectsTo[i] if (objTo.hasConnectors() and not objTo.isConnectedByNamedPort(obj.semanticObject)): # Snap to the nearest connection port if not already there # NOTE: the [obj.x,obj.y] part makes sure we connect directly to the # intermediate object x, y = objTo.getClosestConnector2Point(objTo, coords[2], coords[3]) if (x != coords[0] or y != coords[1]): dc.coords(*[itemHandler] + [x, y] + coords[2:-2] + [obj.x, obj.y]) # Check if a link drawing needs moving... obj.updateDrawingsTo(x, y, itemHandler, segmentNumber=2)
def optimizeLinks( cb, setSmooth = True, setCurved = 10, selectedLinks=list(), curveDirection=-1 ): """ Optimizes the links associated with the nodes in entityList or all the nodes in the graph if entityList is not provided. The links are set straight, with the endpoints at the nearest connectors of the nodes they connect. Optionally, additional control points can be added to make a smooth arrow, and give it some curvature (setCurved is a pixel distance perpendicular to what would have been a straight arrow ). It is possible to pass a list of link objects directly, and optimize those. It is also possible to specify the direction of the curve, Random=-1, Right=0, Left=1 Created July 25, 2004 by Denis Dube """ dc = cb.getCanvas() # Step 1: Find the selected links if( not selectedLinks ): selection = cb.getSelectionDict() selectedLinks = [] for tag in selection: itemHandler, obj = selection[tag] # This is a Link if( isConnectionLink( obj ) ): if( obj not in selectedLinks ): selectedLinks.append( obj ) # Step 2: Optimize all the selected links for obj in selectedLinks: # Optimize the end point connection ports optimizeConnectionPorts( None, linkObjectList=selectedLinks, cb=cb ) # Find all the entities that the edge is linking to # (general enough to handle hyperedges) objectsFrom = [] objectsTo = [] semObject = obj.semanticObject #obj.getSemanticObject() if(not semObject): continue arrowArrowCase = False for semObj in semObject.in_connections_: if(isConnectionLink(semObj.graphObject_)): arrowArrowCase = True objectsFrom.append( semObj.graphObject_ ) for semObj in semObject.out_connections_: if(isConnectionLink(semObj.graphObject_)): arrowArrowCase = True objectsTo.append( semObj.graphObject_ ) # Arrow connected to another arrow, this isn't handled!!! if(arrowArrowCase): continue # Edge with 2 endpoints if( len( objectsFrom ) == 1 and len( objectsTo ) == 1 ): # Edge with both endpoints on one object if( objectsFrom[0] == objectsTo[0] ): optimizeSelfLink(dc, obj, objectsFrom[0], setSmooth, setCurved) # Regular edge else: optimizeRegularLink( dc, obj, objectsFrom[0], objectsTo[0], setSmooth, setCurved, curveDirection ) # Hyper-edge with multiple endpoints else: optimizerHyperLink( dc, obj, objectsFrom, objectsTo, setSmooth, setCurved, curveDirection )
def optimizeLinks(cb, setSmooth=True, setCurved=10, selectedLinks=list(), curveDirection=-1): """ Optimizes the links associated with the nodes in entityList or all the nodes in the graph if entityList is not provided. The links are set straight, with the endpoints at the nearest connectors of the nodes they connect. Optionally, additional control points can be added to make a smooth arrow, and give it some curvature (setCurved is a pixel distance perpendicular to what would have been a straight arrow ). It is possible to pass a list of link objects directly, and optimize those. It is also possible to specify the direction of the curve, Random=-1, Right=0, Left=1 Created July 25, 2004 by Denis Dube """ dc = cb.getCanvas() # Step 1: Find the selected links if (not selectedLinks): selection = cb.getSelectionDict() selectedLinks = [] for tag in selection: itemHandler, obj = selection[tag] # This is a Link if (isConnectionLink(obj)): if (obj not in selectedLinks): selectedLinks.append(obj) # Step 2: Optimize all the selected links for obj in selectedLinks: # Optimize the end point connection ports optimizeConnectionPorts(None, linkObjectList=selectedLinks, cb=cb) # Find all the entities that the edge is linking to # (general enough to handle hyperedges) objectsFrom = [] objectsTo = [] semObject = obj.semanticObject #obj.getSemanticObject() if (not semObject): continue arrowArrowCase = False for semObj in semObject.in_connections_: if (isConnectionLink(semObj.graphObject_)): arrowArrowCase = True objectsFrom.append(semObj.graphObject_) for semObj in semObject.out_connections_: if (isConnectionLink(semObj.graphObject_)): arrowArrowCase = True objectsTo.append(semObj.graphObject_) # Arrow connected to another arrow, this isn't handled!!! if (arrowArrowCase): continue # Edge with 2 endpoints if (len(objectsFrom) == 1 and len(objectsTo) == 1): # Edge with both endpoints on one object if (objectsFrom[0] == objectsTo[0]): optimizeSelfLink(dc, obj, objectsFrom[0], setSmooth, setCurved) # Regular edge else: optimizeRegularLink(dc, obj, objectsFrom[0], objectsTo[0], setSmooth, setCurved, curveDirection) # Hyper-edge with multiple endpoints else: optimizerHyperLink(dc, obj, objectsFrom, objectsTo, setSmooth, setCurved, curveDirection)
def main(self, selection): if (not selection): return atom3i = self.atom3i nodeObject.nodeList = [] edgeObject.edgeList = [] edgeObject.dc = self.dc #------------------------- INFORMATION GATHERING ------------------------- # Generate a datastructure for the Nodes and Edges in the diagram, containing # only the information needed by this algorithm. edgeList = [] nodeDict = dict() self.sourceTargetDict = dict() for obj in selection: if (isConnectionLink(obj)): # Edge! edgeList.append(obj.getSemanticObject()) else: # Node pos = obj.getCenterCoord() boundBox = obj.getbbox() if (self.__stickyBoundary): boundary = self.atom3i.CANVAS_SIZE_TUPLE else: boundary = None n = nodeObject(obj, pos, boundBox, self.__chargeStrength, boundary) nodeDict.update({obj: n}) # Now lets go through the "node" edges... for node in edgeList: # Source object key = node.in_connections_[0].graphObject_ if (not nodeDict.has_key(key)): continue source = nodeDict[key] # Target object key = node.out_connections_[0].graphObject_ if (not nodeDict.has_key(key)): continue target = nodeDict[key] # Make the edge object with the info... edgeObject(node, source, target) self.sourceTargetDict[source] = target # These nodes have edges... source.setHasEdgeTrue() target.setHasEdgeTrue() # Count the beans... self.__totalNodes = len(nodeObject.nodeList) if (self.__totalNodes <= 1): return #-------------------------- MAIN SIMULATION LOOP ------------------------- # Initial card shuffling :D if (self.__randomness): self.__shakeThingsUp(self.__randomness) i = 0 while (i < self.__maxIterations): # Calculate the powers that be self.__calculateRepulsiveForces() self.__calculateAttractiveForces() # Move move move! for node in nodeObject.nodeList: node.commitMove() # Force a screen update every x calculation if (i % self.__animationUpdates == 0): self.dc.update_idletasks() i += 1 #--------------------------- FINAL OPTIMIZATIONS ------------------------- # Optimize the arrows to use the nearest connectors optimizeLinks(self.atom3i.cb, self.__splineArrows, self.__arrowCurvature) # Make sure the canvas is updated self.dc.update_idletasks()
def startArrowEditorMode(self, event): """ Checks that the selected object is a link, then starts the editor Return True if editor is started """ cb = self.cb dc = cb.getCanvas() itemTuple = cb.getItemUnderCursor(self, event) if(itemTuple): itemHandler, tag, obj = itemTuple # This is a link --> Proceed if(isConnectionLink(obj)): # Get information from the tag, segment type and segmenet number segTuple = cb.getSegmentTagInfoTuple(tag) if(not segTuple): return self.arrowEditor.setArrowEditorAbort() objNum, segType, segNum = segTuple # This is the 1st segment, so get the 2nd part if(segType == 1): nextSegmentTag = "Obj" + str(objNum) + "2ndSeg0" nextItemHandler = cb.findItemHandlerWithTag(nextSegmentTag) # This is the 2nd segment, so get the 1st part elif(segType == 2): nextSegmentTag = tag nextItemHandler = itemHandler tag = "Obj" + str(objNum) + "1stSeg0" itemHandler = cb.findItemHandlerWithTag(tag) # Never! else: raise Exception, \ "This will never happen... setType must be 1 or 2!" + str(segType) seg1coords = dc.coords(itemHandler) # Reverse the 2nd segments coords # (so that they are in same direction as the 1st ) seg2coords = obj.reverseList2by2(dc.coords(nextItemHandler)) # Get the connected objects: objFrom and objTo semObject = obj.getSemanticObject() if(not semObject.in_connections_ or not semObject.out_connections_): return self.arrowEditor.setArrowEditorAbort() if(segType == 1): connectedObjects = (semObject.in_connections_[segNum].graphObject_, semObject.out_connections_[0].graphObject_) else: connectedObjects = (semObject.in_connections_[0].graphObject_, semObject.out_connections_[segNum].graphObject_) # Now construct the interactive editor arrow self.arrowEditor.constructEditorArrow(seg1coords, seg2coords, (itemHandler, nextItemHandler), connectedObjects, obj, self.snapGridInfoTuple) return # Things didn't work out... abort! self.arrowEditor.setArrowEditorAbort()
def startArrowEditorMode(self, event): """ Checks that the selected object is a link, then starts the editor Return True if editor is started """ cb = self.cb dc = cb.getCanvas() itemTuple = cb.getItemUnderCursor(self, event) if (itemTuple): itemHandler, tag, obj = itemTuple # This is a link --> Proceed if (isConnectionLink(obj)): # Get information from the tag, segment type and segmenet number segTuple = cb.getSegmentTagInfoTuple(tag) if (not segTuple): return self.arrowEditor.setArrowEditorAbort() objNum, segType, segNum = segTuple # This is the 1st segment, so get the 2nd part if (segType == 1): nextSegmentTag = "Obj" + str(objNum) + "2ndSeg0" nextItemHandler = cb.findItemHandlerWithTag(nextSegmentTag) # This is the 2nd segment, so get the 1st part elif (segType == 2): nextSegmentTag = tag nextItemHandler = itemHandler tag = "Obj" + str(objNum) + "1stSeg0" itemHandler = cb.findItemHandlerWithTag(tag) # Never! else: raise Exception, \ "This will never happen... setType must be 1 or 2!" + str(segType) seg1coords = dc.coords(itemHandler) # Reverse the 2nd segments coords # (so that they are in same direction as the 1st ) seg2coords = obj.reverseList2by2(dc.coords(nextItemHandler)) # Get the connected objects: objFrom and objTo semObject = obj.getSemanticObject() if (not semObject.in_connections_ or not semObject.out_connections_): return self.arrowEditor.setArrowEditorAbort() if (segType == 1): connectedObjects = ( semObject.in_connections_[segNum].graphObject_, semObject.out_connections_[0].graphObject_) else: connectedObjects = ( semObject.in_connections_[0].graphObject_, semObject.out_connections_[segNum].graphObject_) # Now construct the interactive editor arrow self.arrowEditor.constructEditorArrow( seg1coords, seg2coords, (itemHandler, nextItemHandler), connectedObjects, obj, self.snapGridInfoTuple) return # Things didn't work out... abort! self.arrowEditor.setArrowEditorAbort()
def getSelectedItemsForDelete(self, entityOnlyFlag=False): """ Use: Finds all the selected nodes and links, then creates a custom event, DeleteEvent, which it sends to the UI_scope that then sends the event to whichever scoped statechart will handle it. The DeleteEvent uses the x, y coordinates of the node/link to be deleted, so potentially, each node/link's deletion could be handled by a different scoped statechart. Parameters: self, ATOM3 instance entityOnlyFlag, if this boolean flag is True, then deleting an entity will NOT automatically delete arrows that connect to that entity """ class DeleteEvent: """ A special event that mimics the x, y coordinates of a Tkinter binding generated event, but lacks many of the normal attributes, and includes tag and itemHandler attributes not normally found there... """ def __init__(self, obj, tag=None, itemHandlerTagList=None, entityOnlyFlag=False): self.x = obj.x self.y = obj.y self.tag = tag self.semanticObject = obj.semanticObject self.atom3i = obj.semanticObject.parent self.itemHandlerTagList = itemHandlerTagList self.entityOnlyFlag = entityOnlyFlag def destroy(self): """ Deletes the associated ATOM3 node or link """ if(self.itemHandlerTagList): tag2objMap = self.atom3i.cb.getTag2ObjMap() for itemHandler, tag in self.itemHandlerTagList: # Deleting one segment of an arrow, can delete the other, so careful! if(tag2objMap.has_key(tag)): self.atom3i.deleteConnection(itemHandler, tag) else: self.atom3i.deleteRealEntity(self.tag, entityOnly=self.entityOnlyFlag) def getSemanticObject(self): """ Returns the ASGNode instance being deleted """ return self.semanticObject selectionDict = self.cb.getSelectionDict() # Dict of selected items objTagDict = dict() self.fromClass = None self.toClass = None # This little dictionary gymnastic is being used to prevent duplicate objects for tag in selectionDict: obj = selectionDict[tag][1] objTagDict.update({obj:tag}) # Now do the connections first, since if entities disappear, # connections might too. And we DO NOT want that to happen... crash crash :p for obj in objTagDict: tag = objTagDict[obj] # Connection if(isConnectionLink(obj)): #print "Now deleting connection: ", tag, obj, selectionDict[tag][0] # This may seem like overkill, but it's necessary for hyper-edges connList = [] for connTuple in obj.in_connections_: connList.append(connTuple) for connTuple in obj.out_connections_: connList.append(connTuple) itemHandlerTagList = [] for connTuple in connList: itemHandlerTagList.append(connTuple[:2]) event = DeleteEvent(obj, itemHandlerTagList=itemHandlerTagList) self.UI_scope('<serviceLinkDeleteRequest>', event) # Entity else: event = DeleteEvent(obj, tag=tag, entityOnlyFlag=entityOnlyFlag) self.UI_scope('<serviceNodeDeleteRequest>', event) # Model changed! modelChange(self) # No more selected objects :-( self.cb.clearSelectionDict()
def optimizeConnectionPorts(self, entityList = None, linkObjectList=None, doAllLinks = False, cb=None ): """ Ensures that the endpoints of the arrows use the optimal connectors Applied only to selected arrows and to the arrows attached to selected nodes Does not move arrows attached to named ports :D 4 Modes of operation: i) Given entityList, a list of nodes, the links between them will be optimized ii) Given linkObjectList, a list of edge graph objects, the links are optimized iii) Given doAllLinks, a boolean and self=atom3i, optimizes all links on the canvas iv) Given self=atom3i or cb=cb, will optimize everything currently selected on the canvas NOTES: a) self argument should be atom3 instance, required if doAllLinks=True, otherwise, cb=cb is acceptable b) cb is an instance of CallbackState """ if( not cb ): cb = self.cb dc = cb.getCanvas() # Step 1A: Given entities, not a selection dict, so get all affected links if( entityList ): augmentedSelection = dict() # List of node/entity objects for obj in entityList: # Any one of its links may need optimization augmentTheSelection( dc, obj, augmentedSelection ) # Step 1B: Given list of link objects elif( linkObjectList ): augmentedSelection = dict() for linkObject in linkObjectList: linkTag = linkObject.tag + "1stSeg0" itemHandler = dc.find_withtag( linkTag ) if( not itemHandler ): print "WARNING: Utilities.optimizeConnectionPorts() cannot find item with tag", linkTag continue # raise Exception, "optimizeConnectionPorts() having trouble playing " \ # + "tag, Step 1B (Try save & load)" # Add to the selection, {tag : [itemHandler, Object] } augmentedSelection[ linkTag ] = [ itemHandler[0], linkObject ] # Step 1C: Find all the links! elif( doAllLinks ): augmentedSelection = dict() nodeTypes = self.ASGroot.nodeTypes listNodes = self.ASGroot.listNodes for nodetype in nodeTypes: if( listNodes[nodetype] ): if( isConnectionLink( listNodes[nodetype][0].graphObject_ ) ): # Iterate over all the links only for node in listNodes[nodetype]: linkTag = node.graphObject_.tag + "1stSeg0" itemHandler = dc.find_withtag( linkTag ) if( not itemHandler ): print "WARNING: itemhandler not found! Utilities.py --> " \ + "optimizeConnectionPorts() fails (Try save & load)" continue # Add to the selection, {tag : [itemHandler, Object] } augmentedSelection[ linkTag ] = [ itemHandler[0], node.graphObject_ ] # Step 1D: Augment the selection with links affected by the node movement # & remove nodes else: selection = cb.getSelectionDict() augmentedSelection = selection.copy() # <--- This copy() is soooo important for tag in selection: itemHandler, obj = selection[tag] # This is a NODE if( isEntityNode( obj ) ): # Any one of its links may need optimization augmentTheSelection( dc, obj, augmentedSelection ) # We don't need to optimize nodes, just links... so... bye bye node del augmentedSelection[tag] # Step 2: Optimize all the selected links for tag in augmentedSelection: obj = augmentedSelection[tag][1] baseTag = obj.tag # Ex: Obj3 , the tag of the intermediate link object # Some links have center objects (labels/drawings) that look way better # if they are above the arrow centerObj = obj.getCenterObject() if( centerObj ): dc.tag_raise(centerObj.tag ) # Find all the entities that the edge is linking to # (general enough to handle hyperedges) objectsFrom = [] objectsTo = [] semObject = obj.getSemanticObject() arrowArrowCase = False for semObj in semObject.in_connections_: if(isConnectionLink(semObj.graphObject_)): arrowArrowCase = True objectsFrom.append( semObj.graphObject_ ) for semObj in semObject.out_connections_: if(isConnectionLink(semObj.graphObject_)): arrowArrowCase = True objectsTo.append( semObj.graphObject_ ) # Arrow connected to another arrow, this isn't handled!!! if(arrowArrowCase): continue # Initial point/s in the connection ---> Object/s From for i in range(0, len(objectsFrom) ): # Get the tag & itemhandler for each from segement segTag = baseTag + "1stSeg" + str(i) itemHandler = dc.find_withtag( segTag ) if( not itemHandler ): print "WARNING: Having problems looking up canvas tags!", segTag continue #raise Exception, "Having problems looking up canvas tags!" coords = dc.coords( itemHandler ) objFrom = objectsFrom[i] # If the object has connectors and they are not NAMED connectors if( objFrom.hasConnectors() and not objFrom.isConnectedByNamedPort( obj.semanticObject ) ): # Snap to the nearest connection port if not already there # NOTE: the [obj.x,obj.y] part makes sure we connect directly # to the intermediate object x, y = objFrom.getClosestConnector2Point(objFrom, coords[2], coords[3]) if( x != coords[0] or y != coords[1] ): dc.coords(* [itemHandler] + [x, y] + coords[2:-2] + [obj.x, obj.y]) # Check if a link drawing needs moving... obj.updateDrawingsTo( x, y, itemHandler[0] ) # Final point/s in the connection ---> Object/s To for i in range(0, len(objectsTo) ): # Get the tag & itemhandler for each to segement segTag = baseTag + "2ndSeg" + str(i) itemHandler = dc.find_withtag( segTag ) if( not itemHandler ): print "WARNING: Having problems looking up canvas tags!", segTag continue #raise Exception, "Having problems looking up canvas tags!" itemHandler = itemHandler[0] coords = dc.coords( itemHandler ) objTo = objectsTo[i] if( objTo.hasConnectors() and not objTo.isConnectedByNamedPort( obj.semanticObject ) ): # Snap to the nearest connection port if not already there # NOTE: the [obj.x,obj.y] part makes sure we connect directly to the # intermediate object x, y = objTo.getClosestConnector2Point(objTo, coords[2], coords[3]) if( x != coords[0] or y != coords[1] ): dc.coords(* [itemHandler] + [x, y] + coords[2:-2] + [obj.x, obj.y]) # Check if a link drawing needs moving... obj.updateDrawingsTo( x, y, itemHandler, segmentNumber=2 )