# Python Script for Adaptive Path
# Convert Mental Model Excel WorkSheet or Word Doc to Visio Chart
#
# 4-6-2006 Gary Wang firepotter@gmail.com
# 07-Apr-09 Alexey Pavlenko alex.gripav@gmail.com - added variables the user
# can change for box height, etc. Did not test if it works for
# Word doc conversion, still.
#----------------------------------------------------------------------------------------
from win32com.client import Dispatch
import string, os, sys, re
filePath = '' # leave these blank if you want to use the default
excelFilename = ''
"""
These are the printable characters:
0123456789abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ
!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
"""
boxInTopDownOrder = 1
generateDebugFiles = 1 #set to 1 to generate a debug output file
#
# Color Generator Function
def makeColor( red=1, green=1, blue=1 ):
rc = int( red*255 ) % 256
gc = int( green*255 ) % 256
bc = int( blue*255 ) % 256
return ( bc*0x010000 + gc*0x000100 + rc*0x000001 )
colorBlack = makeColor(red=0,green=0,blue=0)
colorRed = makeColor(red=1,green=0,blue=0)
colorGreen = makeColor(red=0,green=1,blue=0)
colorYellow = makeColor(red=1,green=1,blue=0)
colorBlue = makeColor(red=0,green=0,blue=1)
colorMagenta = makeColor(red=1,green=0,blue=1)
colorCyan = makeColor(red=0,green=1,blue=1)
colorWhite = makeColor(red=1,green=1,blue=1)
colorLightCyan = makeColor(red=0.5,green=1,blue=1)
# Chart Property Constants
filePath = '' # leave these blank if you want to use the default
wordFilename = ''
#unit = inch
# Height of a page (8.5 - landscape, 11 - portrait)
PageLength = 11
#PageWidth=88
# The gap of this size is placed between the content (boxes, lines) and the end
# of the page.
PageMargin = 0.25
ChartStartX=1+5.0/8
HorizontalLinePosition = PageLength/2.0-0.125
# An empty space between two boxes in a row (either vertical or horizontal)
Box2BoxSpacing = 0.0625
# A gap between a tower border and a box side
Box2TowerSpacing = 0.125
# A gap between two towers in a row
Tower2TowerSpacing = 0.125
# An empty space between a section border and the first or the last tower
Tower2SectionSpacing = 0.125
# Height of the tower header. This value is used in case VariableTowerHeader = False
TowerHeaderExtra = 0.250+0.125
# Height of a section, currently is calculated from the PageLength value and margins.
# Please use PageLength instead in order to modify the height of a page.
SectionHeight = PageLength/2-PageMargin - 0.25
# Sets the maximum number of boxes in a column of a tower.
MaxBoxNumberPerColumn = 7
# Regular box height, used when VariableHeight = False
BOXHEIGHT=0.375
# Maximum box height, limits the height of the box when VariableHeight = True
MAXBOXHEIGHT= BOXHEIGHT * 4
# Minimum box height, sets the minumum height of the box when VariableHeight = True
MINBOXHEIGHT=0.375 #BOXHEIGHT / 2
# Adjust task box height to fit the content, True or False
VariableHeight = True
# Absolute tower maximum height, used in case VariableHeight = True
MaxTowerHeight = MAXBOXHEIGHT * 2.7
# Adjust tower header to fit the content. Used only in case VariableHeight = True
VariableTowerHeader = True
# A width of a single box
BOXWIDTH=0.625
# A width of a medium size tower of one column.
# Please do not change this value.
TOWERWIDTH = BOXWIDTH + 2 * Box2TowerSpacing #0.875
DefaultLineWeight = 0.06
SectionFontPoint = 12
SectionLineWeight = 0.01
SectionFill = 0
SectionFillColor = colorWhite
SectionLine = 0
SectionLineColor = colorWhite
TowerFontPoint = 6
TowerLineWeight = 0.01
TowerFill = 1
TowerFillColor = colorLightCyan
TowerLine = 0
TowerLineColor = colorLightCyan
BoxFontPoint = 6
BoxLineWeight = 0.01
BoxFill = 1
BoxFillColor = colorWhite
BoxLine = 1
BoxLineColor = colorBlack
#
# Global Variables
sectionIndex = 0
towerIndex = 0
boxIndex = 0
sectionX=2
sectionY=0
sectionNextX = ChartStartX
towerX=0
towerY=0
runningBoxX=0
runningBoxY=0
columnsInTower=1
styleList = {}
# Current tower header text
currentTowerHeader = 0
#----------------------------------------------------------------------------------------
import string, os, sys, time
allowedFileTypeList = ['.xml']
operatingSystem = os.environ['OS']
print 'OS=',operatingSystem
if operatingSystem in ['Windows_NT']:
allowedFileTypeList.append('.xls')
allowedFileTypeList.append('.doc')
def prepareText(text):
''' Adapt the text to the measurement process '''
text = text.split('::::')[0]
# Prepare the replacement
text = text.replace('&', '&')
text = text.replace('<', '<')
text = text.replace('>', '>')
text = text.replace('"', '"')
text = re.sub(r'[\-/]', ' ', text)
return text
def getTextHeight(text, width = BOXWIDTH):
''' Return the height of the task box '''
global VariableHeight
if VariableHeight:
text = prepareText(text)
return getTextHeight_win(text, width)
return BOXHEIGHT
def getTextHeight_win(text, width):
''' Based on a BOXWIDTH value determine the height of the
Box that is going to be displayed by Visio. The return value is in inches.
Visio default font for task boxes is 'Arial 6pt normal', thus we should
use in the computation.
Windows implementation of the routine.
'''
import win32api, win32gui, win32print, win32con
# Base font settings, override if necessary
fontFace = 'Arial'
fontHeight = 6
# First, create a DCs we're going to work with
hWinDC = win32gui.GetDC(0)
hDC = win32gui.CreateCompatibleDC(hWinDC)
# Set antialiasing
#oldSmoothing = win32gui.SystemParametersInfo(win32con.SPI_GETFONTSMOOTHING)
#oldSmoothType = win32gui.SystemParametersInfo(win32con.SPI_GETFONTSMOOTHINGTYPE)
#win32gui.SystemParametersInfo(win32con.SPI_SETFONTSMOOTHING, True, 0)
#win32gui.SystemParametersInfo(win32con.SPI_SETFONTSMOOTHINGTYPE, win32con.FE_FONTSMOOTHINGCLEARTYPE)
# Get font height in logical units
height = -int((fontHeight * win32print.GetDeviceCaps(hDC, win32con.LOGPIXELSY)) / 72.0 + 0.5)
# Now create the font that is going to be used
lf = win32gui.LOGFONT()
lf.lfWeight = win32con.FW_NORMAL
lf.lfHeight = height
lf.lfFaceName = 'Arial'
lf.lfQuality = win32con.CLEARTYPE_NATURAL_QUALITY
hFont = win32gui.CreateFontIndirect(lf)
if not hFont:
raise StandardError('Unable to create font')
# Set our font to get measurement
hFont = win32gui.SelectObject(hDC, hFont)
# Visio rect is using margins, so take it into account
rectWidth = int(width * win32print.GetDeviceCaps(hDC, win32con.LOGPIXELSX))
rectWidth = rectWidth - 10 # Margins from both sides
# Now finally measure text height
rect = (0, 300, rectWidth, 10000)
(height, rect) = win32gui.DrawText(hDC, text, len(text), rect,
win32con.DT_CENTER | win32con.DT_WORDBREAK )
#win32gui.SystemParametersInfo(win32con.SPI_SETFONTSMOOTHING, oldSmoothing, 0)
#win32gui.SystemParametersInfo(win32con.SPI_SETFONTSMOOTHINGTYPE, oldSmoothType)
height = float(height) / win32print.GetDeviceCaps(hDC, win32con.LOGPIXELSY)
# Return the original font to the device context
win32gui.SelectObject(hDC, hFont)
# Delete font
win32gui.DeleteObject(hFont)
# Delete the DCs
win32gui.DeleteDC(hDC)
win32gui.ReleaseDC(0, hWinDC)
return height
def adjustedTextHeight(text):
global MINBOXHEIGHT, MAXBOXHEIGHT
height = getTextHeight(text)
height = min(height, MAXBOXHEIGHT)
height = max(height, MINBOXHEIGHT)
return height
#
from xml.sax import saxutils
from xml.sax import ContentHandler
from xml.sax import make_parser
from xml.sax.handler import feature_namespaces
def hex2Integer( s='' ):
s = string.lower(s)
sum = 0
for c in s:
i = string.find( string.hexdigits, c )
if i>=0:
sum = sum*16 + i
return sum
def normalize_whitespace(text):
"Remove redundant whitespace from a string"
return ' '.join(text.split())
class ProcessData(ContentHandler):
def __init__(self):
self.inDataContent = 0
self.inTargetSheet = 0
self.sID = "Default"
self.styleList = {}
self.dataList = {}
def startElement(self, name, attrs):
try:
if name=='Style':
self.sID = attrs.get('ss:ID', None)
self.styleList[self.sID]={}
if name=='Font':
self.styleList[self.sID]['Family']=attrs.get('x:Family', None)
self.styleList[self.sID]['Size'] = attrs.get('ss:Size', None)
self.styleList[self.sID]['Color'] = attrs.get('ss:Color', '#FFFFFF')
self.styleList[self.sID]['Italic'] = attrs.get('ss:Italic', None)
self.styleList[self.sID]['Bold'] = attrs.get('ss:Bold', None)
self.styleList[self.sID]['Underline'] = attrs.get('ss:Underline', None)
if name=='Interior':
self.styleList[self.sID]['iColor'] = attrs.get('ss:Color', '#FFFFFF')
self.styleList[self.sID]['iPattern'] = attrs.get('ss:Pattern', None)
#
if name=='Worksheet':
self.currentSheet = attrs.get('ss:Name', None)
self.currentRow = 0
if name=='Row':
self.currentRow = self.currentRow + 1
self.currentCell = 0
if name=='Cell':
self.sID = attrs.get('ss:StyleID', None)
sIx = attrs.get('ss:Index', None)
if sIx==None:
self.currentCell = self.currentCell + 1
else:
#print sIx
self.currentCell = string.atoi(sIx)
if name=='Data':
self.inDataContent = 1
self.dataContent = ""
except:
pass
def characters(self, ch):
if self.inDataContent:
#XML special characters (< > & ") must be encoded (< > & ")
#to be used in python code. This, unfortunately, is unavoidable.
if ch=='&': ch = '&'
if ch=='<': ch = '<'
if ch=='>': ch = '>'
if ch=='"': ch = '"'
self.dataContent = self.dataContent + ch
def endElement(self, name):
if name=='Data':
self.inDataContent = 0
self.dataContent = normalize_whitespace(self.dataContent)
data = (self.currentRow, self.currentCell, self.sID, self.dataContent)
if not self.dataList.has_key(self.currentSheet):
self.dataList[self.currentSheet] = []
self.dataList[self.currentSheet].append( data )
def readXMLDoc( filename, debug=1 ):
# Create a parser
parser = make_parser()
# Tell the parser we are not interested in XML namespaces
parser.setFeature(feature_namespaces, 0)
# Create the handler
dh = ProcessData()
# Tell the parser to use our handler
parser.setContentHandler(dh)
# Parse the input
parser.parse(filename)
tmpFilename = filename[:-4]+'tmp2139'
fd = open( tmpFilename+".txt", "w" )
operatingSystem = os.environ['OS']
fd.write('\nOS=%s\n' % (operatingSystem) )
fd.write('Script=%s\n' % (sys.argv[0]) )
fd.write('Date=%s\n' % (time.asctime() ) )
fd.flush()
for key in dh.styleList.keys():
ss = '%s' % (key)
for skey in dh.styleList[key].keys():
ss = ss + ', %s:%s ' % (skey, dh.styleList[key][skey])
if debug:
print ss
fd.write(ss+'\n')
fd.write('\n\n')
workSheetKeys = dh.dataList.keys()
#print workSheetKeys
stack = {}
for worksheet in workSheetKeys:
(chart, section, tower) = ([],[],[])
(sectionIndex, towerIndex, boxIndex) = (0,0,0)
#print worksheet
for (row, col, sID, text) in dh.dataList[worksheet]:
if row==1 and text=='Mental Space':
sectionIndex = col
if row==1 and text=='Task Tower':
towerIndex = col
if row==1 and text=='Task':
boxIndex = col
if row>1 and (sectionIndex, towerIndex, boxIndex) == (0,0,0):
break
text = '%s::::%s' % (text , sID)
if row>1 and col==sectionIndex:
if len(section)>0:
if len(tower)>0:
section.append(tower)
chart.append(section)
section=[text]
tower = []
if row>1 and col==towerIndex:
if len(tower)>0:
section.append(tower)
tower=[text]
if row>1 and col==boxIndex:
tower.append( text )
if len(section)>0:
if len(tower)>0:
section.append(tower)
chart.append(section)
if len(chart)>0:
stack[worksheet]=chart
fd.close()
if not debug:
os.remove( tmpFilename+".txt" )
return (dh.styleList, stack)
def process( s ):
s1 = s[10:]
s2 = ''
flag = 0
for i in range(0,len(s1)):
bStart = (s1[i]=='<')
bEnd = (s1[i]=='>')
if bStart:
flag = 1
if not flag:
if s1[i] in string.printable:
s2 = s2 + s1[i]
if bEnd:
flag = 0
s3 = string.split(s2,'>')
s4 = string.split(s3[0],' ')
return (s4[0],s3[-1])
def readWordDocFast( fname='', debug=0 ):
#Faster Method.
#Save to a *.htm file and parse it.
print fname
chart=[]
if fname=='':
return chart
filename = fname[:-4]
style = {}
style['APHeading2'] = 'section'
style['APHeading3'] = 'tower'
style['APHeading4'] = 'box'
tmpFilename = filename+'tmp2138'
filteredHTMLFormat = 8
app = Dispatch("Word.Application")
"""
#using word's File Open GUI ?????
#app.Visible = 1
#app.Dialogs(80).Show()
app.Dialogs(80).Display()
print 'Name is', app.Dialogs(80).Name
"""
app.Visible = 0
doc = app.Documents.Open( filename + ".doc" )
doc.SaveAs(tmpFilename+".htm",filteredHTMLFormat)
doc.Close(0)
del app
fd = open( tmpFilename+".htm", 'r')
lines=fd.readlines()
fd.close()
os.remove( tmpFilename+"_files\\filelist.xml" )
os.remove( tmpFilename+"_files\\header.htm" )
os.rmdir( tmpFilename+"_files")
if not debug:
os.remove( tmpFilename+".htm" )
fd = open( tmpFilename+".txt", "w" )
output = []
flag = 0
tFlag = 0
s = ''
for line in lines:
pStart = string.find(line,'
')>=0
tStart = string.find(line,'
=0
tEnd = string.find(line,'
')>=0
if tStart:
tFlag = 1
if tEnd:
tFlag = 0
pStart = 0
s = ''
flag = 0
if pStart:
flag = 1
if (pStart or pEnd or flag) and (not tFlag):
s = s + ' ' + string.strip(line)
if pEnd:
flag = 0
if len(s)>0:
(key,t) = process(s)
if key in style.keys():
t = string.strip(t)
#t = string.replace(t,'&','&')
#t = string.replace(t,'x',"'")
if style[key]=='section':
section = t
chart.append([section])
sectionIndex = len(chart)-1
if style[key]=='tower':
tower = t
chart[sectionIndex].append([tower])
towerIndex = len(chart[sectionIndex])-1
if style[key]=='box':
chart[sectionIndex][towerIndex].append(t)
ss = "%s %7s %s" % (key, style[key], t)
print ss
fd.write( ss+'\n' )
fd.write( s+'\n' )
s = ''
fd.close()
if not debug:
os.remove( tmpFilename+".txt" )
return chart
def readWordDocSlow( filename='' ):
from win32com.client import Dispatch
#Get the info from Word Objects
#This is slower than readWordDoc2
chart=[]
if filename=='':
return chart
style = {}
style['AP Heading 2'] = 'section'
style['AP Heading 3'] = 'tower'
style['AP Heading 4'] = 'box'
app = Dispatch("Word.Application")
app.Visible = 0
doc = app.Documents.Open(filename)
for para in doc.paragraphs:
s = para.format.style.nameLocal
if s in style.keys():
t = string.strip(para.Range.Text)
t = string.replace(t,'&','&')
if style[key]=='section':
section = t
chart.append([section])
sectionIndex = len(chart)-1
if style[key]=='tower':
tower = t
chart[sectionIndex].append([tower])
towerIndex = len(chart[sectionIndex])-1
if style[key]=='box':
chart[sectionIndex][towerIndex].append(t)
print "%s %7s %s" % (key, style[key], t)
doc.Close(0)
del app
return chart
def drawVisio( filename, shapes, width=88, length=PageLength ):
fd = open( filename, 'w' )
fd.write("\n")
fd.write("\n")
fd.write("\n")
fd.write("\n")
fd.write("\n")
fd.write("\n")
fd.write("%.2f\n" % (width) )
fd.write("%.2f\n" % (length) )
fd.write("1\n")
fd.write("3\n")
fd.write("0\n")
fd.write("\n")
fd.write("\n")
fd.write("8\n")
fd.write("8\n")
fd.write("4\n")
fd.write("4\n")
fd.write("\n")
fd.write("\n")
fd.write("\n")
shapeID = 1
for (X, Y, Width, Height, Text, vAlign, TextColor, TextFont, TextPoint, TextStyle, Line, \
LineColor, LineWeight, Fill, FillColor) in shapes:
shapeWidth = Width
shapeHeight = Height
shapeX = X
shapeY = Y
fillColor = FillColor
lineWeight = LineWeight
lineColor = LineColor
textMarginHorizontal = 0.02
textMarginVertical = 0.02
verticalAlignment = vAlign
fill = Fill
line = Line
text = Text
pSize = TextPoint*(0.11111111111/8)
if string.find(text,'::::')>=0:
tlist = string.split(text,'::::')
text = tlist[0]
try:
fillColor = string.atoi(styleList[tlist[-1]]['iColor'][1:],16)
except:
pass
x1 = 0
x2 = shapeWidth
y1 = 0
y2 = shapeHeight
shapeCenterX = shapeX + shapeWidth/2.0
shapeCenterY = shapeY + shapeHeight/2.0
#LineStyle='6' FillStyle='6' TextStyle='6'
fd.write("\n" % (shapeID, shapeID) )
fd.write("\n")
fd.write("%.4f\n" % (shapeCenterX) )
fd.write("%.4f\n" % (shapeCenterY) )
fd.write("%.4f\n" % (shapeWidth) )
fd.write("%.4f\n" % (shapeHeight) )
fd.write("%.4f\n" % (shapeWidth/2.0) )
fd.write("%.4f\n" % (shapeHeight/2.0) )
fd.write("\n")
fd.write("%.3f\n" % (lineWeight) )
if lineColor!=0:
fd.write("#%x\n" % (lineColor) )
fd.write("\n")
fd.write("#%x\n" % (fillColor) )
fd.write("\n")
fd.write("0\n")
fd.write("0\n")
fd.write("\n" % (TextStyle) )
fd.write("0\n")
fd.write("0\n")
fd.write("%.10f\n" % (pSize) )
fd.write("\n")
fd.write("\n")
fd.write("%.3f\n" % (textMarginHorizontal) )
fd.write("%.3f\n" % (textMarginHorizontal) )
fd.write("%.3f\n" % (textMarginVertical) )
fd.write("%.3f\n" % (textMarginVertical) )
fd.write("%d\n" % (verticalAlignment) )
fd.write("\n")
fd.write("\n")
fd.write("%d\n" % (1-fill) )
fd.write("%d\n" % (1-line) )
fd.write("0\n")
fd.write("0\n")
fd.write("\n%.4f\n%.4f\n\n" % (x1,y1) )
fd.write("\n%.4f\n%.4f\n\n" % (x2,y1) )
fd.write("\n%.4f\n%.4f\n\n" % (x2,y2) )
fd.write("\n%.4f\n%.4f\n\n" % (x1,y2) )
fd.write("\n%.4f\n%.4f\n\n" % (x1,y1) )
fd.write("\n")
try:
fd.write("%s\n" % (text) )
except:
fd.write("%s\n" % ('ERROR???') )
fd.write("\n")
shapeID = shapeID + 1
fd.write("\n\n\n\n")
fd.close()
return 1
def shape( X, Y, Width=1, Height=1, Text='', vAlign=1, TextColor=0xffff80, TextFont='arial', \
TextPoint=6, TextStyle=0, Line=1, LineColor=0x000000, LineWeight=0.02, \
Fill=0, FillColor=0xffffff):
return((X, Y, Width, Height, Text, vAlign, TextColor, TextFont, TextPoint, TextStyle,\
Line, LineColor, LineWeight, Fill, FillColor))
def line( x1, y1, x2, y2, Text='' ):
Width=x2-x1
Height=y2-y1
return shape( x1, y1, Width, Height, Text, LineWeight=DefaultLineWeight )
def getTowerTextHeight(text, columns):
''' Return the height of the tower boxs' caption '''
global VariableTowerHeader, VariableHeight, TowerHeaderExtra
if VariableHeight and VariableTowerHeader:
width = 2 * Box2TowerSpacing - Box2BoxSpacing + \
(BOXWIDTH+Box2BoxSpacing) * columns
return getTextHeight(text, width) + Box2BoxSpacing
return TowerHeaderExtra
def getTowerSplit(tower):
''' Split boxes to different towers depending on the settings.
Returns a list of 'boxes per tower'
'''
global TowerHeaderExtra, MaxTowerHeight, Box2BoxSpacing, MAXBOXHEIGHT
global VariableHeight, MaxBoxNumberPerColumn, currentTowerHeader
global Box2TowerSpacing, BOXWIDTH, MINBOXHEIGHT
split = []
boxCnt = 0
towerHeight = 0
maxHeight = 0 # TODO: support this
for box in tower[1:]:
boxCnt += 1
if VariableHeight:
boxHeight = adjustedTextHeight(box)
if towerHeight + boxHeight + Box2BoxSpacing > \
MaxTowerHeight - getTowerTextHeight(tower[0], len(split) + 1):
split.append(boxCnt - 1)
towerHeight = boxHeight + Box2BoxSpacing
boxCnt = 1
else:
towerHeight += boxHeight + Box2BoxSpacing
maxHeight = max(maxHeight, towerHeight)
if boxCnt == MaxBoxNumberPerColumn:
split.append(boxCnt)
boxCnt = 0
towerHeight = 0
# Add tail tower
if boxCnt:
split.append(boxCnt)
# Erase empty columns
split = filter(None, split)
return (maxHeight, split)
def getTowerCount(tower):
''' Based on the task box height compute
the actual number of the towers
'''
return len(getTowerSplit(tower)[1])
def getTowerMaxHeight(tower):
''' Return the maximum height for tower '''
return getTowerSplit(tower)[0]
def sectionBox( section ):
global sectionIndex, towerIndex
global sectionX, sectionY, sectionNextX
global towerX, towerY
global VariableHeight, sectionHeight
Text = section['name']
numberOfTowers = len(section['towers'])
sectionIndex = sectionIndex + 1
Width = Tower2SectionSpacing
for tower in section['towers']:
m = len(tower['boxes'])
#Width = Width + (0.1+(TOWERWIDTH-0.1)*m) + Tower2TowerSpacing
Width = Width + Box2TowerSpacing * 2 + BOXWIDTH * m + Box2BoxSpacing * (m-1) + Tower2TowerSpacing
if numberOfTowers==0:
Width = Width+TOWERWIDTH+Tower2SectionSpacing
else:
# Remove the last Tower2TowerSpacing and add final Tower2SectionSpacing
Width -= Tower2TowerSpacing
Width += Tower2SectionSpacing
Height= SectionHeight
sectionX = sectionNextX
sectionNextX = sectionNextX + Width
sectionY = PageLength/2.0
towerIndex = 0
return shape( sectionX, sectionY, Width, Height, Text, vAlign=0, TextStyle=1, \
LineWeight=SectionLineWeight, Fill=SectionFill, Line=SectionLine,\
FillColor=SectionFillColor, LineColor=SectionLineColor, TextPoint=SectionFontPoint )
def getBoxCount(boxes):
count = 0
for x in boxes:
count += len(x)
return count
def towerBox( tower ):
global MaxBoxNumberPerColumn
global towerIndex, boxIndex
global sectionX, sectionY
global towerX, towerY, VariableTowerHeader
global VariableHeight, runningBoxY, runningBoxX, currentTowerHeader
global Tower2SectionSpacing, TowerHeaderExtra
global BOXWIDTH, Box2BoxSpacing, Tower2TowerSpacing
global columnsInTower
Text=tower['name']
currentTowerHeader = Text
boxNumber = getBoxCount(tower['boxes'])
widthMultiplier = len(tower['boxes'])
towerIndex = towerIndex + 1
boxIndex = 0
towerX=sectionX+Tower2SectionSpacing+(towerIndex-1)*(TOWERWIDTH+Tower2TowerSpacing)
towerY=sectionY
runningBoxX = towerX
runningBoxY = towerY
columnsInTower = 1
bn = boxNumber
if bn > MaxBoxNumberPerColumn:
bn = MaxBoxNumberPerColumn
Width = 2*Box2TowerSpacing-Box2BoxSpacing+(BOXWIDTH+Box2BoxSpacing)*widthMultiplier
if VariableHeight:
towerHeaderHeight = getTowerTextHeight(Text, widthMultiplier)
Height = tower['maxHeight'] + towerHeaderHeight
else:
Height = bn*(BOXHEIGHT+Box2BoxSpacing)+TowerHeaderExtra
return shape( towerX, towerY, Width, Height, Text, vAlign=0, \
LineWeight=TowerLineWeight, Fill=TowerFill, Line=TowerLine,\
FillColor=TowerFillColor, LineColor=TowerLineColor, TextPoint=TowerFontPoint )
def boxBox( Text='Box', extendTower=False ):
global boxIndex, Box2BoxSpacing, currentTowerHeader
global sectionX, sectionY
global towerX, towerY, MaxBoxNumberPerColumn
global VariableHeight, MAXBOXHEIGHT, MaxTowerHeight, MINBOXHEIGHT
global runningBoxX, runningBoxY
global BOXWIDTH, BOXHEIGHT, columnsInTower
boxIndex = boxIndex + 1
# Get the height of the box
if not VariableHeight:
Height=BOXHEIGHT
else:
Height=adjustedTextHeight(Text)
# If box index is greater then the maximum number or
# Box height is greater then the tower height start a new tower
if extendTower:
columnsInTower += 1
towerX = towerX + BOXWIDTH + Box2BoxSpacing
towerY = sectionY
runningBoxX = towerX
runningBoxY = towerY
sectionX = sectionX + BOXWIDTH + Box2BoxSpacing
boxIndex = 1
boxX = runningBoxX + Box2TowerSpacing
boxY = runningBoxY + Box2BoxSpacing
runningBoxY = boxY + Height
Width=BOXWIDTH
return shape( boxX, boxY, Width, Height, Text, vAlign=1, \
LineWeight=BoxLineWeight, Fill=BoxFill, Line=BoxLine,\
FillColor=BoxFillColor, LineColor=BoxLineColor, TextPoint=BoxFontPoint )
def drawSection( section ):
s = []
s.append( sectionBox( section ) )
for tower in section['towers']:
s = s + drawTower( tower, topDown=boxInTopDownOrder )
return s
def drawTower( tower, topDown=0 ):
s = []
s.append( towerBox( tower ) )
split = tower['boxes']
startNewPart = False
for towerPart in tower['boxes']:
for box in towerPart:
s.append( boxBox(box, startNewPart))
startNewPart = False
# Extend the tower
startNewPart = True
return s
def rearrangeTaskBoxes(boxes):
''' For each box in the tower find the height of the box and move it
to the top of the list
'''
return sorted(boxes, key=adjustedTextHeight)
def calculateTower(tower):
# Set the name to the beginning of the list
my = {}
my['name'] = tower[0]
my['boxes'] = []
# Get the way how towers are going to be splitted
maxHeight, split = getTowerSplit(tower)
my['maxHeight'] = maxHeight
# Now make the split
tower = tower[1:]
for t in split:
arranged = rearrangeTaskBoxes(tower[:t])
my['boxes'].append( arranged )
tower = tower[t:]
return my
def calculateSheet(section):
my = {}
my['name'] = section[0]
my['towers'] = []
for tower in section[1:]:
my['towers'].append( calculateTower(tower) )
return my
if __name__ == '__main__':
#get filename from user
if len(filePath)==0:
filePath = string.replace( os.path.abspath('') ,'\\','\\\\') +'\\\\'
if len(excelFilename)==0:
files = []
for file in os.listdir( filePath ):
if file[-4:] in allowedFileTypeList and file[0]!='~':
files.append(file)
files.append('QUIT')
i = 0
for file in files:
print "%2d: %s" % (i, file)
i = i + 1
while 1:
try:
j = string.atoi(raw_input('Select File: '))
excelFilename = files[j]
break
except:
pass
if excelFilename=='QUIT':
sys.exit(0)
print 'Processing', excelFilename, '...'
filename = os.path.abspath('')+'\\'+excelFilename[:-4]+'.xml'
fileType = excelFilename[-4:]
if fileType=='.xls':
# convert file to xml format, window system only, will not work on mac or linux
from win32com.client import Dispatch
app = Dispatch("Excel.Application")
app.Visible = 0
doc = app.Workbooks.Open( filePath+excelFilename )
print 'Saving File As', filename
type = 46
doc.SaveAs(filename, type)
doc.Close(0)
del app
if fileType in ['.xml','.xls']:
(styleList, stack) = readXMLDoc( filename, debug=generateDebugFiles )
#print styleList.keys()
if fileType=='.doc':
filename = os.path.abspath('')+'\\'+excelFilename
chart = readWordDocFast( filename, debug=generateDebugFiles )
stack = { '%FORWORDDOC%': chart }
print stack.keys()
vFileList = []
for key in stack.keys():
ChartStartX=1+5.0/8
sectionIndex = 0
towerIndex = 0
boxIndex = 0
sectionX=2
sectionY=0
sectionNextX = ChartStartX
towerX=0
towerY=0
chart = stack[key]
#print key
#print chart
s = []
for section in chart:
calculated = calculateSheet(section)
s = s + drawSection(calculated) # drawSection( section )
s.append( line(sectionNextX, PageMargin, sectionNextX, PageLength-PageMargin) )
PageWidth= sectionNextX + PageMargin
s.append( line(ChartStartX, HorizontalLinePosition, PageWidth-PageMargin, HorizontalLinePosition) )
tag = '-'+key
if key=='%FORWORDDOC%':
tag = ''
visioFilename = filename[:-4]+tag+ '.vdx'
print visioFilename
vFileList.append(visioFilename)
drawVisio( visioFilename, s, width=PageWidth, length=PageLength )
# Launch Visio and Open the file
visioFilename = vFileList[0]
print '\nLaunching Visio and Opening ' + visioFilename
appVisio = Dispatch("Visio.Application")
appVisio.Visible = 1
doc = appVisio.Documents.Open( visioFilename)