]> git.evergreen-ils.org Git - working/Evergreen.git/blob - stylesheets/evergreen_docbook_files/docbook-xsl-1.75.2/extensions/docbook.py
Add stylesheets for our evergreen docbook site.
[working/Evergreen.git] / stylesheets / evergreen_docbook_files / docbook-xsl-1.75.2 / extensions / docbook.py
1 # docbook.py: extension module\r
2 # $Id: docbook.py 8353 2009-03-17 16:57:50Z mzjn $\r
3 \r
4 import sys\r
5 import string\r
6 import libxml2\r
7 import libxslt\r
8 import re\r
9 import math\r
10 \r
11 # Some globals\r
12 pixelsPerInch = 96.0\r
13 unitHash = { 'in': pixelsPerInch,\r
14              'cm': pixelsPerInch / 2.54,\r
15              'mm': pixelsPerInch / 25.4,\r
16              'pc': (pixelsPerInch / 72.0) * 12,\r
17              'pt': pixelsPerInch / 72.0,\r
18              'px': 1 }\r
19 \r
20 # ======================================================================\r
21 \r
22 def adjustColumnWidths(ctx, nodeset):\r
23     #\r
24     # Small check to verify the context is correcly accessed\r
25     #\r
26     try:\r
27         pctxt = libxslt.xpathParserContext(_obj=ctx)\r
28         ctxt = pctxt.context()\r
29         tctxt = ctxt.transformContext()\r
30     except:\r
31         pass\r
32 \r
33     # Get the nominal table width\r
34     varString = lookupVariable(tctxt, "nominal.table.width", None)\r
35     if varString == None:\r
36         nominalWidth = 6 * pixelsPerInch;\r
37     else:\r
38         nominalWidth = convertLength(varString);\r
39 \r
40     # Get the requested table width\r
41     tableWidth = lookupVariable(tctxt, "table.width", "100%")\r
42 \r
43     foStylesheet = (tctxt.variableLookup("stylesheet.result.type", None) == "fo")\r
44 \r
45     relTotal = 0\r
46     relParts = []\r
47 \r
48     absTotal = 0\r
49     absParts = []\r
50 \r
51     colgroup = libxml2.xmlNode(_obj = nodeset[0])\r
52     # If this is an foStylesheet, we've been passed a list of fo:table-columns.\r
53     # Otherwise we've been passed a colgroup that contains a list of cols.\r
54     if foStylesheet:\r
55         colChildren = colgroup\r
56     else:\r
57         colChildren = colgroup.children\r
58 \r
59     col = colChildren\r
60     while col != None:\r
61         if foStylesheet:\r
62             width = col.prop("column-width")\r
63         else:\r
64             width = col.prop("width")\r
65 \r
66         if width == None:\r
67             width = "1*"\r
68 \r
69         relPart = 0.0\r
70         absPart = 0.0\r
71         starPos = string.find(width, "*")\r
72         if starPos >= 0:\r
73             relPart, absPart = string.split(width, "*", 2)\r
74             relPart = float(relPart)\r
75             relTotal = relTotal + float(relPart)\r
76         else:\r
77             absPart = width\r
78 \r
79         pixels = convertLength(absPart)\r
80         absTotal = absTotal + pixels\r
81 \r
82         relParts.append(relPart)\r
83         absParts.append(pixels)\r
84 \r
85         col = col.next\r
86 \r
87     # Ok, now we have the relative widths and absolute widths in\r
88     # two parallel arrays.\r
89     #\r
90     # - If there are no relative widths, output the absolute widths\r
91     # - If there are no absolute widths, output the relative widths\r
92     # - If there are a mixture of relative and absolute widths,\r
93     #   - If the table width is absolute, turn these all into absolute\r
94     #     widths.\r
95     #   - If the table width is relative, turn these all into absolute\r
96     #     widths in the nominalWidth and then turn them back into\r
97     #     percentages.\r
98 \r
99     widths = []\r
100 \r
101     if relTotal == 0:\r
102         for absPart in absParts:\r
103             if foStylesheet:\r
104                 inches = absPart / pixelsPerInch\r
105                 widths.append("%4.2fin" % inches)\r
106             else:\r
107                 widths.append("%d" % absPart)\r
108     elif absTotal == 0:\r
109         for relPart in relParts:\r
110             rel = relPart / relTotal * 100\r
111             widths.append(rel)\r
112         widths = correctRoundingError(widths)\r
113     else:\r
114         pixelWidth = nominalWidth\r
115         if string.find(tableWidth, "%") < 0:\r
116             pixelWidth = convertLength(tableWidth)\r
117 \r
118         if pixelWidth <= absTotal:\r
119             print "Table is wider than table width"\r
120         else:\r
121             pixelWidth = pixelWidth - absTotal\r
122 \r
123         absTotal = 0\r
124         for count in range(len(relParts)):\r
125             rel = relParts[count] / relTotal * pixelWidth\r
126             relParts[count] = rel + absParts[count]\r
127             absTotal = absTotal + rel + absParts[count]\r
128 \r
129         if string.find(tableWidth, "%") < 0:\r
130             for count in range(len(relParts)):\r
131                 if foStylesheet:\r
132                     pixels = relParts[count]\r
133                     inches = pixels / pixelsPerInch\r
134                     widths.append("%4.2fin" % inches)\r
135                 else:\r
136                     widths.append(relParts[count])\r
137         else:\r
138             for count in range(len(relParts)):\r
139                 rel = relParts[count] / absTotal * 100\r
140                 widths.append(rel)\r
141             widths = correctRoundingError(widths)\r
142 \r
143     # Danger, Will Robinson! In-place modification of the result tree!\r
144     # Side-effect free? We don' need no steenkin' side-effect free!\r
145     count = 0\r
146     col = colChildren\r
147     while col != None:\r
148         if foStylesheet:\r
149             col.setProp("column-width", widths[count])\r
150         else:\r
151             col.setProp("width", widths[count])\r
152 \r
153         count = count+1\r
154         col = col.next\r
155 \r
156     return nodeset\r
157 \r
158 def convertLength(length):\r
159     # Given "3.4in" return the width in pixels\r
160     global pixelsPerInch\r
161     global unitHash\r
162 \r
163     m = re.search('([+-]?[\d\.]+)(\S+)', length)\r
164     if m != None and m.lastindex > 1:\r
165         unit = pixelsPerInch\r
166         if unitHash.has_key(m.group(2)):\r
167             unit = unitHash[m.group(2)]\r
168         else:\r
169             print "Unrecognized length: " + m.group(2)\r
170 \r
171         pixels = unit * float(m.group(1))\r
172     else:\r
173         pixels = 0\r
174 \r
175     return pixels\r
176 \r
177 def correctRoundingError(floatWidths):\r
178     # The widths are currently floating point numbers, we have to truncate\r
179     # them back to integers and then distribute the error so that they sum\r
180     # to exactly 100%.\r
181 \r
182     totalWidth = 0\r
183     widths = []\r
184     for width in floatWidths:\r
185         width = math.floor(width)\r
186         widths.append(width)\r
187         totalWidth = totalWidth + math.floor(width)\r
188 \r
189     totalError = 100 - totalWidth\r
190     columnError = totalError / len(widths)\r
191     error = 0\r
192     for count in range(len(widths)):\r
193         width = widths[count]\r
194         error = error + columnError\r
195         if error >= 1.0:\r
196             adj = math.floor(error)\r
197             error = error - adj\r
198             widths[count] = "%d%%" % (width + adj)\r
199         else:\r
200             widths[count] = "%d%%" % width\r
201 \r
202     return widths\r
203 \r
204 def lookupVariable(tctxt, varName, default):\r
205     varString = tctxt.variableLookup(varName, None)\r
206     if varString == None:\r
207         return default\r
208 \r
209     # If it's a list, get the first element\r
210     if type(varString) == type([]):\r
211         varString = varString[0]\r
212 \r
213     # If it's not a string, it must be a node, get its content\r
214     if type(varString) != type(""):\r
215         varString = varString.content\r
216 \r
217     return varString\r
218 \r
219 # ======================================================================\r
220 # Random notes...\r
221 \r
222 #once you have a node which is a libxml2 python xmlNode wrapper all common\r
223 #operations are possible:\r
224 #   .children .last .parent .next .prev .doc for navigation\r
225 #   .content .type for introspection\r
226 #   .prop("attribute_name") to lookup attribute values\r
227 \r
228 #    # Now make a nodeset to return\r
229 #    # Danger, Will Robinson! This creates a memory leak!\r
230 #    newDoc = libxml2.newDoc("1.0")\r
231 #    newColGroup = newDoc.newDocNode(None, "colgroup", None)\r
232 #    newDoc.addChild(newColGroup)\r
233 #    col = colgroup.children\r
234 #    while col != None:\r
235 #        newCol = newDoc.newDocNode(None, "col", None)\r
236 #        newCol.copyPropList(col);\r
237 #        newCol.setProp("width", "4")\r
238 #        newColGroup.addChild(newCol)\r
239 #        col = col.next\r