ajack 2004/04/20 10:44:32 Modified: python .cvsignore python/gump/document/forrest xdoc.py documenter.py python/gump/test drawing.py python/gump/model depend.py python/gump/svg depdiag.py svg.py drawing.py Log: Tinkering with SVGs... Revision Changes Path 1.10 +2 -1 gump/python/.cvsignore Index: .cvsignore =================================================================== RCS file: /home/cvs/gump/python/.cvsignore,v retrieving revision 1.9 retrieving revision 1.10 diff -u -r1.9 -r1.10 --- .cvsignore 14 Apr 2004 22:32:45 -0000 1.9 +++ .cvsignore 20 Apr 2004 17:44:32 -0000 1.10 @@ -14,4 +14,5 @@ *.log bogus gumpy_log.txt -gumpy.lock \ No newline at end of file +gumpy.lock +*.svg \ No newline at end of file 1.4 +3 -0 gump/python/gump/document/forrest/xdoc.py Index: xdoc.py =================================================================== RCS file: /home/cvs/gump/python/gump/document/forrest/xdoc.py,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- xdoc.py 14 Apr 2004 23:06:56 -0000 1.3 +++ xdoc.py 20 Apr 2004 17:44:32 -0000 1.4 @@ -308,6 +308,9 @@ def createFork(self,href,text=None): return self.storePiece(XDocFork(self.createSubContext(),href,text)) + + def createIcon(self,href,alt=None): + return self.storePiece(XDocIcon(self.createSubContext(),href,alt)) class XDocComment(XDocPiece): def __init__(self,context,text): 1.7 +49 -26 gump/python/gump/document/forrest/documenter.py Index: documenter.py =================================================================== RCS file: /home/cvs/gump/python/gump/document/forrest/documenter.py,v retrieving revision 1.6 retrieving revision 1.7 diff -u -r1.6 -r1.7 --- documenter.py 19 Apr 2004 15:47:05 -0000 1.6 +++ documenter.py 20 Apr 2004 17:44:32 -0000 1.7 @@ -219,13 +219,17 @@ # Sync over public pages... # syncDirectories(stagingDirectory,logDirectory) - # - # Clean up - wipeDirectoryTree(stagingDirectory) - - # Clean only if successful. - if (forrestResult.state==CMD_STATE_SUCCESS): - wipeDirectoryTree(forrestWorkDir) + + cleanUp=0 + + if cleanUp: + # + # Clean up + wipeDirectoryTree(stagingDirectory) + + # Clean only if successful. + if (forrestResult.state==CMD_STATE_SUCCESS): + wipeDirectoryTree(forrestWorkDir) except: log.error('--- Failed to staging->log sync and/or clean-up', exc_info=1) success=0 @@ -1518,7 +1522,7 @@ statsTable=statsSection.createTable() # Generate an SVG for FOG: - (pngFile,pngTitle) = self.documentFOG(project) + (pngFile,pngTitle) = self.diagramFOG(project) if pngFile: statsTable.createEntry('FOG Factor').createData().createIcon(pngFile,pngTitle) @@ -1541,16 +1545,16 @@ self.documentFileList(run,document,project,'Project-level Files') self.documentWorkList(run,document,project,'Project-level Work') - #addnSection=document.createSection('Additional Details') - #addnPara=addnSection.createParagraph() - #addnPara.createLink(gumpSafeName(project.getName()) + '_details.html', \ - # 'More project details ...') - #document.serialize() - # - #document=XDocDocument('Project Details : ' + project.getName(), \ - # self.resolver.getFile(project, \ - # project.getName() + '_details', \ - # '.xml')) + addnSection=document.createSection('Additional Details') + addnPara=addnSection.createParagraph() + addnPara.createLink(gumpSafeName(project.getName()) + '_details.html', \ + 'For additional project details (including dependencies) ...') + document.serialize() + + document=XDocDocument('Project Details : ' + project.getName(), \ + self.resolver.getFile(project, \ + project.getName() + '_details', \ + '.xml')) # x.write('<p><strong>Project Config :</strong> <link href=\'%s\'>XML</link></p>' \ # % (getModuleProjectRelativeUrl(modulename,project.name)) ) @@ -1636,7 +1640,15 @@ dependencySection.createNote('No projects depend upon this project.') if not depens: dependencySection.createNote('This project depends upon no others.') - + + try: + # Generate an SVG for FOG: + (pngFile,pngTitle) = self.diagramDependencies(project) + if pngFile: + para=dependencySection.createSection('Dependency Diagram').createParagraph() + para.createFork(pngFile).createIcon(pngFile,pngTitle) + except: + log.error('Failed to diagram dependencies for [' + project.getName() + ']', exc_info=1) document.serialize() @@ -2194,7 +2206,7 @@ fdocument.serialize() fdocument=None - def documentFOG(self,object,base=None): + def diagramFOG(self,object,base=None): stats = object.getStats() name=object.getName() @@ -2214,6 +2226,20 @@ return (None, None) + def diagramDependencies(self,project,base=None): + + name=project.getName() + if not base: base=project + + svgFile=self.resolver.getFile(base,name+'_depend','.svg') + pngFile=os.path.basename(svgFile).replace('.svg','.png') + from gump.svg.depdiag import DependencyDiagram + diagram=DependencyDiagram(project) + diagram.compute() + diagram.generateDiagram().serializeToFile(svgFile) + + return (pngFile, 'Dependency Diagram') + ##################################################################### # # Helper Methods @@ -2639,16 +2665,13 @@ fogRow.createData(pstats.failures) fogRow.createData(pstats.prereqs) fogRow.createData('%02.2f' % pstats.getFOGFactor()) - - + # Generate an SVG for FOG: - (pngFile,pngTitle) = self.documentFOG(project,stats) + (pngFile,pngTitle) = self.diagramFOG(project,stats) if pngFile: fogRow.createData().createIcon(pngFile,pngTitle) else: - fogRow.createData('Not Available') - - + fogRow.createData('Not Available') document.serialize() 1.3 +4 -4 gump/python/gump/test/drawing.py Index: drawing.py =================================================================== RCS file: /home/cvs/gump/python/gump/test/drawing.py,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- drawing.py 14 Apr 2004 22:12:57 -0000 1.2 +++ drawing.py 20 Apr 2004 17:44:32 -0000 1.3 @@ -50,7 +50,7 @@ self.assertEqual('Shifted & Scaled', 125, y) def testGridDrawingContext(self): - baseContext=StandardDrawingContext(rect=Rect(0,0,100,100)) + baseContext=StandardDrawingContext(rect=Rect(0,0,100,200)) context=GridDrawingContext('TestGrid',baseContext,10,10) for row in [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]: for col in [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]: @@ -59,10 +59,10 @@ # Calculate expected expectedX=(row*10)+5 - expectedY=(col*10)+5 + expectedY=(col*20)+10 - print `(row,col)` - print `(x,y)` + #print `(row,col)` + #print `(x,y)` # Check... self.assertEqual('Grid', expectedX, x) 1.26 +2 -2 gump/python/gump/model/depend.py Index: depend.py =================================================================== RCS file: /home/cvs/gump/python/gump/model/depend.py,v retrieving revision 1.25 retrieving revision 1.26 diff -u -r1.25 -r1.26 --- depend.py 31 Mar 2004 17:41:41 -0000 1.25 +++ depend.py 20 Apr 2004 17:44:32 -0000 1.26 @@ -314,10 +314,10 @@ # def getDependencyDepth(self): if self.depth: return self.depth - maxDepth=1 + maxDepth=0 for depend in self.directDependencies.getDepends(): dependencyDepth=depend.getProject().getDependencyDepth() + 1 - if maxDepth < dependencyDepth: + if maxDepth < dependencyDepth: maxDepth=dependencyDepth self.depth=maxDepth return self.depth 1.7 +37 -31 gump/python/gump/svg/depdiag.py Index: depdiag.py =================================================================== RCS file: /home/cvs/gump/python/gump/svg/depdiag.py,v retrieving revision 1.6 retrieving revision 1.7 diff -u -r1.6 -r1.7 --- depdiag.py 16 Apr 2004 17:28:42 -0000 1.6 +++ depdiag.py 20 Apr 2004 17:44:32 -0000 1.7 @@ -71,6 +71,7 @@ # Create a sparse matrix self.depths={} + self.maxDepth=0 self.maxNumAtDepth=0 # Create a lookup @@ -98,7 +99,7 @@ for rowNo in self.depths.keys(): colNo=0 for node in self.depths[rowNo]: - node.setRowCol(rowNo-1,colNo) + node.setRowCol(rowNo,colNo) colNo+=1 # Insert into lists @@ -114,17 +115,21 @@ depthList=self.depths[depth] depthList.append(node) - # Keep track of + # Keep track of ... numAtDepth=len(depthList) if (numAtDepth > self.maxNumAtDepth): - self.maxNumAtDepth=numAtDepth + self.maxNumAtDepth=numAtDepth + + # Keep track of ... + if (depth > self.maxDepth): + self.maxDepth=depth # Lookups self.nodes[project]=node def getExtent(self): # Max by max - return (len(self.depths.keys()),self.maxNumAtDepth) + return (self.maxDepth+1,self.maxNumAtDepth) def getRowWidth(self,row): return len(self.depths[row]) @@ -168,21 +173,28 @@ # Get the maximum rows/cols (rows, cols) = self.matrix.getExtent() - mainContext=StandardDrawingContext('Dependencies', None, \ - Rect(0,0,100*rows,100*cols)) - - # Let the context define the rect. - rect=mainContext.realRect() - - print 'RECT: ' + str(rect) - print '(ROWS,COLS) : ' + `(rows, cols)` + # The drawing plane + absoluteRect=Rect(0,0,100*cols,100*rows) - context=GridDrawingContext('Grid', mainContext, rows, cols ) + # The standard context for that plane + mainContext=StandardDrawingContext('Dependencies', None, + absoluteRect) + + #print 'RECT: ' + str(absoluteRect) + #print '(ROWS,COLS) : ' + `(rows, cols)` + + context=SwitchAxisDrawingContext('Switch', + YInvertDrawingContext('Invert', + GridDrawingContext('Grid', mainContext, cols, rows ), + rows - 1 ) ) # Build an SVG to fit the real world size, and the # context rectangle. - svg=SimpleSvg(rect.getWidth(),rect.getHeight()) + svg=SimpleSvg(absoluteRect.getWidth(), absoluteRect.getHeight()) + # + # Add a border + # svg.addBorder() # @@ -198,16 +210,10 @@ #print cols,rowWidth,row,col,' -> ',centeredCol - print '(ROW,COL) : ' + `(row, col)` - (x,y) = context.realPoint(col,(rows-row)+2) - print '(X,Y) : ' + `(x, y)` - node.setPoint(Point(x,y)) - - for x in range(0,rows): - for y in range(0,cols): - print 'DOTTY : ' + `(x,y)` - (x1,y1)=context.realPoint(x,y) - svg.addSpot(x1,y1) + #print 'NODE (ROW,COL) : ' + `(row, col)` + (x,y) = context.realPoint(row,col) + #print '(X,Y) : ' + `(x, y)` + node.setPoint(Point(x,y)) # # Draw dependency lines @@ -240,7 +246,7 @@ elif project.getFOGFactor() < 0.1: color='red' - print 'LINE %s,%s -> %s,%s' % (x,y,x1,y1) + #print 'LINE %s,%s -> %s,%s' % (x,y,x1,y1) svg.addLine(x,y,x1,y1, \ { 'stroke':color, \ 'stroke-width':width, \ @@ -253,10 +259,10 @@ project = node.getProject() (row, col) = node.getRowCol() - (x,y) = context.realPoint(col-0.25,(rows-row)+2-0.25) - (x1,y1) = context.realPoint(col+0.25,(rows-row)+2+0.25) + (x,y) = context.realPoint(row+0.25,col-0.25) + (x1,y1) = context.realPoint(row-0.25,col+0.25) - print 'RECTANGLE %s,%s -> %s,%s' % (x,y,x1,y1) + #print 'RECTANGLE %s,%s -> %s,%s' % (x,y,x1,y1) # Shape color color='green' @@ -271,8 +277,8 @@ { 'fill':color, \ 'comment':project.getName() } ) - (x,y) = context.realPoint(col-0.25,(rows-row)+2-0.27) - print 'TEXT %s,%s' % (x,y) + (x,y) = context.realPoint(row+0.27,col-0.27) + #print 'TEXT %s,%s' % (x,y) svg.addText(x,y,project.getName() + ' (' + `project.getFOGFactor()` + ')', \ { 'fill':'red', \ @@ -287,7 +293,7 @@ from gump.core.gumprun import GumpRun, GumpRunOptions, GumpSet from gump.core.commandLine import handleArgv - from gump.core.model.loader import WorkspaceLoader + from gump.model.loader import WorkspaceLoader from gump.output.statsdb import * # Process command line 1.6 +19 -8 gump/python/gump/svg/svg.py Index: svg.py =================================================================== RCS file: /home/cvs/gump/python/gump/svg/svg.py,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- svg.py 16 Apr 2004 17:28:42 -0000 1.5 +++ svg.py 20 Apr 2004 17:44:32 -0000 1.6 @@ -102,9 +102,10 @@ # Assume the pixels are at least an order of # magnitude larger than we'd like this in - # centimeters - svgW=int(w/10) - svgH=int(h/10) + # centimeters. :TODO: Unhack these values, + # which basically work for DepDiag only... + svgW=int(w/30) + svgH=int(h/30) if svgW > 20: ratio = float(svgW)/20 @@ -173,13 +174,23 @@ self.actions.append(self.formatElement(type,attrs,content)) def addBorder(self): - x=self.viewWidth*0.05 - y=self.viewHeight*0.05 - w=min(self.viewWidth*0.02,self.viewHeight*0.02) - self.addRect(x,y,self.viewWidth-(2*x),self.viewHeight-(2*y), \ + + # Make stroke width proportional, but not greater than 1 + w=min(self.viewWidth*0.01,self.viewHeight*0.01) + if w > 1: w = 1 + self.addRect(w,w,self.viewWidth-w,self.viewHeight-w, \ {'stroke':'black','stroke-width':w,'fill':'none', \ 'comment':'Border Rectangle'}) - + + + #print '(ROWS,COLS) : ' + `(rows, cols)` + #for r in range(0,rows): + # for c in range(0,cols): + # print 'DOTTY (ROW,COL): ' + `(r,c)` + # (x,y)=context.realPoint(r,c) + # svg.addSpot(x,y) + # svg.addText(x,y, `(r,c)`, {'stroke':'black'}) + def addSpot(self,x,y): self.addRect(x-2,y-2,4,4, \ {'stroke':'black','stroke-width':1,'fill':'black', \ 1.5 +65 -5 gump/python/gump/svg/drawing.py Index: drawing.py =================================================================== RCS file: /home/cvs/gump/python/gump/svg/drawing.py,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- drawing.py 15 Apr 2004 17:26:07 -0000 1.4 +++ drawing.py 20 Apr 2004 17:44:32 -0000 1.5 @@ -89,7 +89,7 @@ class DrawingContext: """ The interface to a chainable context """ - def __init__(self,name=None,next=None) : + def __init__(self,name,next=None) : self.name=name self.next=next @@ -110,6 +110,7 @@ # Calculate (or pass though) if hasattr(self,'getRealPoint')and callable(self.getRealPoint): (x1,y1)=self.getRealPoint(x,y) + #log.debug(`self.name` + ' : ' + `(x,y)` + ' -> ' + `(x1,y1)`) else: (x1,y1)=(x,y) @@ -145,7 +146,7 @@ class StandardDrawingContext(DrawingContext): """ A drawing context, is an area width*height """ - def __init__(self,name=None,context=None,rect=None): + def __init__(self,name,context=None,rect=None): DrawingContext.__init__(self,name,context) if rect: self.rect=rect @@ -169,7 +170,7 @@ output.write(getIndent(indent)+'Height : ' + `self.getHeight()` + '\n') class ScaledDrawingContext(StandardDrawingContext): - def __init__(self,name=None,context=None,rect=None,scaledWidth=1,scaledHeight=1): + def __init__(self,name,context=None,rect=None,scaledWidth=1,scaledHeight=1): StandardDrawingContext.__init__(self,name,context,rect) if not scaledWidth: raise RuntimeError, 'Can\'t scale with 0 width.' @@ -197,7 +198,7 @@ output.write(getIndent(indent)+'hRatio : ' + `self.hRatio` + '\n') class ShiftedDrawingContext(StandardDrawingContext): - def __init__(self,name=None,context=None,shiftedX=0,shiftedY=0): + def __init__(self,name,context=None,shiftedX=0,shiftedY=0): StandardDrawingContext.__init__(self,name,context) if not (shiftedX or shiftedY): @@ -224,11 +225,14 @@ middle of their blocks. E.g. 0,0 -> 5,5 (with units of 10 points) """ - def __init__(self,name=None,context=None,rows=10,cols=10): + def __init__(self,name,context=None,rows=10,cols=10): # Initiaze w/o sub-context DrawingContext.__init__(self,name) + self.rows=rows + self.cols=cols + # Create the scale self.scale=ScaledDrawingContext('GridScale:'+name,context,None,rows,cols) @@ -238,6 +242,24 @@ # Install this context... self.setNextContext(self.shift) + def getRealPoint(self,x,y): + #if not x == int(x): + # raise RuntimeError, 'X isn\'t an integer [' + `x` + ']' + # + #if not y == int(y): + # raise RuntimeError, 'Y isn\'t an integer [' + `y` + ']' + + return (x,y) + + xrange=range(0,self.rows) + if not x in xrange: + raise RuntimeError, 'X isn\'t in range [' + `x` + '] [' + `xrange` + ']' + + yrange=range(0,self.cols) + if not y in yrange: + raise RuntimeError, 'Y isn\'t in range [' + `y` + '] [' + `yrange` + ']' + + return (x,y) # def generateRowContexts(self,context): # rowContexts={} @@ -264,6 +286,44 @@ # row+=1 # # return rowContexts + +class XInvertDrawingContext(DrawingContext): + """ + Invert X + """ + def __init__(self,name,context,maxX): + + # Initiaze w/o sub-context + DrawingContext.__init__(self,name) + self.maxX=maxX + + def getRealPoint(self,x,y): + return (self.maxX - x,y) + +class YInvertDrawingContext(DrawingContext): + """ + Invert Y + """ + def __init__(self,name,context,maxY): + + # Initiaze w/o sub-context + DrawingContext.__init__(self,name,context) + self.maxY=maxY + + def getRealPoint(self,x,y): + return (x,self.maxY-y) + +class SwitchAxisDrawingContext(DrawingContext): + """ + Invert Y + """ + def __init__(self,name,context): + + # Initiaze w/o sub-context + DrawingContext.__init__(self,name,context) + + def getRealPoint(self,x,y): + return (y,x) class VirtualPoint: def __init__(self,x,y,context):
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]