| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239 | # docbook.py: extension module# $Id: docbook.py 8353 2009-03-17 16:57:50Z mzjn $import sysimport stringimport libxml2import libxsltimport reimport math# Some globalspixelsPerInch = 96.0unitHash = { 'in': pixelsPerInch,             'cm': pixelsPerInch / 2.54,             'mm': pixelsPerInch / 25.4,             'pc': (pixelsPerInch / 72.0) * 12,             'pt': pixelsPerInch / 72.0,             'px': 1 }# ======================================================================def adjustColumnWidths(ctx, nodeset):    #    # Small check to verify the context is correcly accessed    #    try:        pctxt = libxslt.xpathParserContext(_obj=ctx)        ctxt = pctxt.context()        tctxt = ctxt.transformContext()    except:        pass    # Get the nominal table width    varString = lookupVariable(tctxt, "nominal.table.width", None)    if varString == None:        nominalWidth = 6 * pixelsPerInch;    else:        nominalWidth = convertLength(varString);    # Get the requested table width    tableWidth = lookupVariable(tctxt, "table.width", "100%")    foStylesheet = (tctxt.variableLookup("stylesheet.result.type", None) == "fo")    relTotal = 0    relParts = []    absTotal = 0    absParts = []    colgroup = libxml2.xmlNode(_obj = nodeset[0])    # If this is an foStylesheet, we've been passed a list of fo:table-columns.    # Otherwise we've been passed a colgroup that contains a list of cols.    if foStylesheet:        colChildren = colgroup    else:        colChildren = colgroup.children    col = colChildren    while col != None:        if foStylesheet:            width = col.prop("column-width")        else:            width = col.prop("width")        if width == None:            width = "1*"        relPart = 0.0        absPart = 0.0        starPos = string.find(width, "*")        if starPos >= 0:            relPart, absPart = string.split(width, "*", 2)            relPart = float(relPart)            relTotal = relTotal + float(relPart)        else:            absPart = width        pixels = convertLength(absPart)        absTotal = absTotal + pixels        relParts.append(relPart)        absParts.append(pixels)        col = col.next    # Ok, now we have the relative widths and absolute widths in    # two parallel arrays.    #    # - If there are no relative widths, output the absolute widths    # - If there are no absolute widths, output the relative widths    # - If there are a mixture of relative and absolute widths,    #   - If the table width is absolute, turn these all into absolute    #     widths.    #   - If the table width is relative, turn these all into absolute    #     widths in the nominalWidth and then turn them back into    #     percentages.    widths = []    if relTotal == 0:        for absPart in absParts:            if foStylesheet:                inches = absPart / pixelsPerInch                widths.append("%4.2fin" % inches)            else:                widths.append("%d" % absPart)    elif absTotal == 0:        for relPart in relParts:            rel = relPart / relTotal * 100            widths.append(rel)        widths = correctRoundingError(widths)    else:        pixelWidth = nominalWidth        if string.find(tableWidth, "%") < 0:            pixelWidth = convertLength(tableWidth)        if pixelWidth <= absTotal:            print "Table is wider than table width"        else:            pixelWidth = pixelWidth - absTotal        absTotal = 0        for count in range(len(relParts)):            rel = relParts[count] / relTotal * pixelWidth            relParts[count] = rel + absParts[count]            absTotal = absTotal + rel + absParts[count]        if string.find(tableWidth, "%") < 0:            for count in range(len(relParts)):                if foStylesheet:                    pixels = relParts[count]                    inches = pixels / pixelsPerInch                    widths.append("%4.2fin" % inches)                else:                    widths.append(relParts[count])        else:            for count in range(len(relParts)):                rel = relParts[count] / absTotal * 100                widths.append(rel)            widths = correctRoundingError(widths)    # Danger, Will Robinson! In-place modification of the result tree!    # Side-effect free? We don' need no steenkin' side-effect free!    count = 0    col = colChildren    while col != None:        if foStylesheet:            col.setProp("column-width", widths[count])        else:            col.setProp("width", widths[count])        count = count+1        col = col.next    return nodesetdef convertLength(length):    # Given "3.4in" return the width in pixels    global pixelsPerInch    global unitHash    m = re.search('([+-]?[\d\.]+)(\S+)', length)    if m != None and m.lastindex > 1:        unit = pixelsPerInch        if unitHash.has_key(m.group(2)):            unit = unitHash[m.group(2)]        else:            print "Unrecognized length: " + m.group(2)        pixels = unit * float(m.group(1))    else:        pixels = 0    return pixelsdef correctRoundingError(floatWidths):    # The widths are currently floating point numbers, we have to truncate    # them back to integers and then distribute the error so that they sum    # to exactly 100%.    totalWidth = 0    widths = []    for width in floatWidths:        width = math.floor(width)        widths.append(width)        totalWidth = totalWidth + math.floor(width)    totalError = 100 - totalWidth    columnError = totalError / len(widths)    error = 0    for count in range(len(widths)):        width = widths[count]        error = error + columnError        if error >= 1.0:            adj = math.floor(error)            error = error - adj            widths[count] = "%d%%" % (width + adj)        else:            widths[count] = "%d%%" % width    return widthsdef lookupVariable(tctxt, varName, default):    varString = tctxt.variableLookup(varName, None)    if varString == None:        return default    # If it's a list, get the first element    if type(varString) == type([]):        varString = varString[0]    # If it's not a string, it must be a node, get its content    if type(varString) != type(""):        varString = varString.content    return varString# ======================================================================# Random notes...#once you have a node which is a libxml2 python xmlNode wrapper all common#operations are possible:#   .children .last .parent .next .prev .doc for navigation#   .content .type for introspection#   .prop("attribute_name") to lookup attribute values#    # Now make a nodeset to return#    # Danger, Will Robinson! This creates a memory leak!#    newDoc = libxml2.newDoc("1.0")#    newColGroup = newDoc.newDocNode(None, "colgroup", None)#    newDoc.addChild(newColGroup)#    col = colgroup.children#    while col != None:#        newCol = newDoc.newDocNode(None, "col", None)#        newCol.copyPropList(col);#        newCol.setProp("width", "4")#        newColGroup.addChild(newCol)#        col = col.next
 |