Attachment 'CreatePdfDocument2_2_0.py'
Download 1 # -*- coding: iso-8859-1 -*-
2 __doc__ = """
3 MoinMoin - Generate PDF document using HTMLDOC
4
5 This action script generate PDF documents from a Wiki site using
6 the HTMLDOC (http://www.htmldoc.org) software packages which has
7 to be preinstalled first.
8
9 To use this feature install this script in your's MoinMoin action
10 script plugin directory.
11
12 Thanks goes to Pascal Bauermeister who initiated the implementaion.
13 Lot of things changes since then but the idear using HTMLDOC is the
14 main concept of this implementation.
15
16 @copyright: (C) 2006 Pascal Bauermeister
17 @copyright: (C) 2006-2007 Raphael Bossek
18 @license: GNU GPL, see COPYING for details
19 """
20
21 __version__ = u'2.2.0'
22
23 release_information = """
24 2007-09-25 RaphaelBossek
25 * Release v2.2.0
26 * Fixed debug information for Windows.
27 * Added support for Windows where HTMLDOC_NOCGI environment variable was missing.
28 * Added preview mode added. It's now possible to see what HTMLDOC will process.
29
30 2007-09-23 RaphaelBossek
31 * Release v2.1.5
32 * Added support for line numbers in code blocks.
33 * Remove page information so it's not printed for webpage style.
34 * Added table cell padding to 5 pixels.
35
36 2007-09-21 RaphaelBossek
37 * Release v2.1.4
38 * HTMLDOC supports only HTML 4.1 (http://www.htmldoc.org/documentation.php/Elements.html)
39 * Fix for table borders and cell background.
40 * Added support for code blocks (break on page boundries).
41
42 2007-09-18 RaphaelBossek
43 * Release v2.1.3
44 * Added support for scaling images (--browserwidth).
45
46 2007-08-21 RaphaelBossek
47 * Release v2.1.2
48 * Fixed support for python 2.3.
49
50 2007-08-21 RaphaelBossek
51 * Release v2.1.1
52 * Applied speed improvemtn patch from BrianDickman.
53 * Fixed font size values where x.9 was missing.
54 * Some cosmetic changes in the form.
55
56 2007-08-20 RaphaelBossek
57 * Release v2.1.0
58 * Configuration is seperated by tabbs.
59 * Added support for font style and colors.
60 * Fixed save/load of configuration variables within page (may be empty).
61
62 2007-08-17 RaphaelBossek
63 * Release v2.0.11
64 * Added support for alternative title page and title page logo.
65 * Added support for additional fields for the title page author, docnumber
66 and copyright.
67
68 2006-12-18 RaphaelBossek
69 * Release v2.0.10
70 * Improved support for webpage/book styles if the HTML documents does not.
71
72 2006-12-17 RaphaelBossek
73 * Release v2.0.9
74 * Added AUTH_TYPE for RedirectOutputRequest()
75
76 2006-11-16 RaphaelBossek
77 * Release v2.0.8
78 * Fixed another missing configuration for RedirectOutputRequest()
79
80 2006-11-15 RaphaelBossek
81 * Release v2.0.7
82 * Fixed support for MoinMoin 1.5.3
83 * Fixed SSL support.
84
85 2006-11-14 RaphaelBossek
86 * Release v2.0.6
87 * MoinMoin 1.6 support added.
88 * Fixed Windows(TM) platform support.
89 * Added support for alternative title text.
90
91 2006-09-13 RaphaelBossek
92 * Release v2.0.5
93 * Fixed RedirectOutputRequest class where definition of script_name
94 was missing.
95
96 2006-09-12 RaphaelBossek
97 * Release v2.0.4
98 * Fixed RedirectOutputRequest class where function was redifined
99 to boolean value.
100
101 2006-09-06 RaphaelBossek
102 * Release v2.0.3
103 * Fixed FastCGI support by removing stdout redirect output code. The
104 same functionality will be done by the RedirectOutputRequest class.
105 * Renamed to CreatePdfDocument (for better translation possibilities).
106 * Fixed encoding of title page.
107 * Added charset set option.
108 * Fixed waiting for HTMLDOC.
109
110 2006-09-02 RaphaelBossek
111 * Release v2.0.2
112 * Added createpdfdocument_validoptions and createpdfdocument_defaultvalues
113 configuration parameter support. You are not able to preset available
114 options and which defaults are used in your configuration file.
115
116 2006-08-30 RaphaelBossek
117 * Release v2.0.1
118 * Fixed issue with page revision number forwarding (traceback).
119
120 2006-08-30 RaphaelBossek
121 * Release v2.0.0
122 * Feature enchanced and bug fixed version.
123
124 2006-05-26 PascalBauermeister
125 * Release v1.0.2
126 * Relative image URLs turned absolute was bogus. It is less bogus now.
127
128 2006-05-26 PascalBauermeister
129 * Release v1.0.1
130 * Set env var HTMLDOC_NOCGI to solve CGI issue
131
132 2006-05-24 PascalBauermeister
133 * Initial release v1.0.0
134 """
135
136 import os
137 import sys
138 import stat
139 import re
140 import copy
141 import shutil
142 import StringIO
143 import array
144 from MoinMoin import config
145 from MoinMoin import util
146 from MoinMoin import wikiutil
147 from MoinMoin import packages
148 from MoinMoin import error
149 from MoinMoin.Page import Page
150 from MoinMoin.request import RequestBase
151 from MoinMoin.widget.dialog import Dialog
152 from MoinMoin.version import release as moinmoin_release
153
154 # http://www.barelyfitz.com/projects/tabber/
155 tabber_minimized = '''
156 // Version 1.9 stripped by Creativyst SS & JavaScript Compressor v2.2c (http://www.creativyst.com/Prod/3/)
157 function tabberObj(argsObj)
158 { var arg; this.div = null; this.classMain = "tabber"; this.classMainLive = "tabberlive"; this.classTab = "tabbertab"; this.classTabDefault = "tabbertabdefault"; this.classNav = "tabbernav"; this.classTabHide = "tabbertabhide"; this.classNavActive = "tabberactive"; this.titleElements = ['h2','h3','h4','h5','h6']; this.titleElementsStripHTML = true; this.removeTitle = true; this.addLinkId = false; this.linkIdFormat = '<tabberid>nav<tabnumberone>'; for (arg in argsObj) { this[arg] = argsObj[arg];}
159 this.REclassMain = new RegExp('\\\\b' + this.classMain + '\\\\b', 'gi'); this.REclassMainLive = new RegExp('\\\\b' + this.classMainLive + '\\\\b', 'gi'); this.REclassTab = new RegExp('\\\\b' + this.classTab + '\\\\b', 'gi'); this.REclassTabDefault = new RegExp('\\\\b' + this.classTabDefault + '\\\\b', 'gi'); this.REclassTabHide = new RegExp('\\\\b' + this.classTabHide + '\\\\b', 'gi'); this.tabs = new Array(); if (this.div) { this.init(this.div); this.div = null;}
160 }
161 tabberObj.prototype.init = function(e)
162 { var
163 childNodes, i, i2, t, defaultTab=0, DOM_ul, DOM_li, DOM_a, aId, headingElement; if (!document.getElementsByTagName) { return false;}
164 if (e.id) { this.id = e.id;}
165 this.tabs.length = 0; childNodes = e.childNodes; for(i=0; i < childNodes.length; i++) { if(childNodes[i].className &&
166 childNodes[i].className.match(this.REclassTab)) { t = new Object(); t.div = childNodes[i]; this.tabs[this.tabs.length] = t; if (childNodes[i].className.match(this.REclassTabDefault)) { defaultTab = this.tabs.length-1;}
167 }
168 }
169 DOM_ul = document.createElement("ul"); DOM_ul.className = this.classNav; for (i=0; i < this.tabs.length; i++) { t = this.tabs[i]; t.headingText = t.div.title; if (this.removeTitle) { t.div.title = '';}
170 if (!t.headingText) { for (i2=0; i2<this.titleElements.length; i2++) { headingElement = t.div.getElementsByTagName(this.titleElements[i2])[0]; if (headingElement) { t.headingText = headingElement.innerHTML; if (this.titleElementsStripHTML) { t.headingText.replace(/<br>/gi," "); t.headingText = t.headingText.replace(/<[^>]+>/g,"");}
171 break;}
172 }
173 }
174 if (!t.headingText) { t.headingText = i + 1;}
175 DOM_li = document.createElement("li"); t.li = DOM_li; DOM_a = document.createElement("a"); DOM_a.appendChild(document.createTextNode(t.headingText)); DOM_a.href = "javascript:void(null);"; DOM_a.title = t.headingText; DOM_a.onclick = this.navClick; DOM_a.tabber = this; DOM_a.tabberIndex = i; if (this.addLinkId && this.linkIdFormat) { aId = this.linkIdFormat; aId = aId.replace(/<tabberid>/gi, this.id); aId = aId.replace(/<tabnumberzero>/gi, i); aId = aId.replace(/<tabnumberone>/gi, i+1); aId = aId.replace(/<tabtitle>/gi, t.headingText.replace(/[^a-zA-Z0-9\-]/gi, '')); DOM_a.id = aId;}
176 DOM_li.appendChild(DOM_a); DOM_ul.appendChild(DOM_li);}
177 e.insertBefore(DOM_ul, e.firstChild); e.className = e.className.replace(this.REclassMain, this.classMainLive); this.tabShow(defaultTab); if (typeof this.onLoad == 'function') { this.onLoad({tabber:this});}
178 return this;}; tabberObj.prototype.navClick = function(event)
179 { var
180 rVal, a, self, tabberIndex, onClickArgs; a = this; if (!a.tabber) { return false;}
181 self = a.tabber; tabberIndex = a.tabberIndex; a.blur(); if (typeof self.onClick == 'function') { onClickArgs = {'tabber':self, 'index':tabberIndex, 'event':event}; if (!event) { onClickArgs.event = window.event;}
182 rVal = self.onClick(onClickArgs); if (rVal === false) { return false;}
183 }
184 self.tabShow(tabberIndex); return false;}; tabberObj.prototype.tabHideAll = function()
185 { var i; for (i = 0; i < this.tabs.length; i++) { this.tabHide(i);}
186 }; tabberObj.prototype.tabHide = function(tabberIndex)
187 { var div; if (!this.tabs[tabberIndex]) { return false;}
188 div = this.tabs[tabberIndex].div; if (!div.className.match(this.REclassTabHide)) { div.className += ' ' + this.classTabHide;}
189 this.navClearActive(tabberIndex); return this;}; tabberObj.prototype.tabShow = function(tabberIndex)
190 { var div; if (!this.tabs[tabberIndex]) { return false;}
191 this.tabHideAll(); div = this.tabs[tabberIndex].div; div.className = div.className.replace(this.REclassTabHide, ''); this.navSetActive(tabberIndex); if (typeof this.onTabDisplay == 'function') { this.onTabDisplay({'tabber':this, 'index':tabberIndex});}
192 return this;}; tabberObj.prototype.navSetActive = function(tabberIndex)
193 { this.tabs[tabberIndex].li.className = this.classNavActive; return this;}; tabberObj.prototype.navClearActive = function(tabberIndex)
194 { this.tabs[tabberIndex].li.className = ''; return this;}; function tabberAutomatic(tabberArgs)
195 { var
196 tempObj, divs, i; if (!tabberArgs) { tabberArgs = {};}
197 tempObj = new tabberObj(tabberArgs); divs = document.getElementsByTagName("div"); for (i=0; i < divs.length; i++) { if (divs[i].className &&
198 divs[i].className.match(tempObj.REclassMain)) { tabberArgs.div = divs[i]; divs[i].tabber = new tabberObj(tabberArgs);}
199 }
200 return this;}
201 function tabberAutomaticOnLoad(tabberArgs)
202 { var oldOnLoad; if (!tabberArgs) { tabberArgs = {};}
203 oldOnLoad = window.onload; if (typeof window.onload != 'function') { window.onload = function() { tabberAutomatic(tabberArgs);};} else { window.onload = function() { oldOnLoad(); tabberAutomatic(tabberArgs);};}
204 }
205 if (typeof tabberOptions == 'undefined') { tabberAutomaticOnLoad();} else { if (!tabberOptions['manualStartup']) { tabberAutomaticOnLoad(tabberOptions);}
206 }
207 '''
208
209 tabber_minimized_css = '''
210 <style type="text/css">
211 /*--------------------------------------------------
212 REQUIRED to hide the non-active tab content.
213 But do not hide them in the print stylesheet!
214 --------------------------------------------------*/
215 .tabberlive .tabbertabhide {
216 display:none;
217 }
218
219 /*--------------------------------------------------
220 .tabber = before the tabber interface is set up
221 .tabberlive = after the tabber interface is set up
222 --------------------------------------------------*/
223 .tabber {
224 }
225 .tabberlive {
226 margin-top:1em;
227 }
228
229 /*--------------------------------------------------
230 ul.tabbernav = the tab navigation list
231 li.tabberactive = the active tab
232 --------------------------------------------------*/
233 ul.tabbernav
234 {
235 margin:0;
236 padding: 3px 0;
237 border-bottom: 1px solid #778;
238 font: bold 12px Verdana, sans-serif;
239 }
240
241 ul.tabbernav li
242 {
243 list-style: none;
244 margin: 0;
245 display: inline;
246 }
247
248 ul.tabbernav li a
249 {
250 padding: 3px 0.5em;
251 margin-left: 3px;
252 border: 1px solid #778;
253 border-bottom: none;
254 background: #DDE;
255 text-decoration: none;
256 }
257
258 ul.tabbernav li a:link { color: #448; }
259 ul.tabbernav li a:visited { color: #667; }
260
261 ul.tabbernav li a:hover
262 {
263 color: #000;
264 background: #AAE;
265 border-color: #227;
266 }
267
268 ul.tabbernav li.tabberactive a
269 {
270 background-color: #fff;
271 border-bottom: 1px solid #fff;
272 }
273
274 ul.tabbernav li.tabberactive a:hover
275 {
276 color: #000;
277 background: white;
278 border-bottom: 1px solid white;
279 }
280
281 /*--------------------------------------------------
282 .tabbertab = the tab content
283 Add style only after the tabber interface is set up (.tabberlive)
284 --------------------------------------------------*/
285 .tabberlive .tabbertab {
286 padding:5px;
287 border:1px solid #aaa;
288 border-top:0;
289
290 /* If you don't want the tab size changing whenever a tab is changed
291 you can set a fixed height */
292
293 /* height:200px; */
294
295 /* If you set a fix height set overflow to auto and you will get a
296 scrollbar when necessary */
297
298 /* overflow:auto; */
299 }
300
301 /* If desired, hide the heading since a heading is provided by the tab */
302 .tabberlive .tabbertab h2 {
303 display:none;
304 }
305 .tabberlive .tabbertab h3 {
306 display:none;
307 }
308
309 /* Example of using an ID to set different styles for the tabs on the page */
310 .tabberlive#tab1 {
311 }
312 .tabberlive#tab2 {
313 }
314 .tabberlive#tab2 .tabbertab {
315 height:200px;
316 overflow:auto;
317 }
318 </style>
319 '''
320
321 class RedirectOutputRequest(RequestBase):
322 """Redirect output to string without HTTP headers."""
323 def __init__ (self, req, action='print'):
324 """Prepare a compatible request."""
325 # 1.5,1.6:req.path_info = u'/RaphaelBossek/\xd6nologe' | u'/FrontPage'
326 # after enconde() self.path_info = '/RaphaelBossek/\xd6nologe'
327 self.path_info = req.path_info.encode(config.charset)
328 # 1.5,1.6:query_string = req.query_string = u'action=CreatePdfDocument'
329 self.query_string = 'action=' + action
330 if isinstance(self.query_string, unicode):
331 raise UnicodeError('self.query_string can not be of type UNICODE for python 2.3 compatibility reasons.')
332 # 1.5,1.6:request_uri = req.request_uri = u'/FrontPage?action=CreatePdfDocument'
333 self.request_uri = req.path_info.replace(req.query_string, self.query_string)
334 # 1.5,1.6:url = req.url = u'localhost:8080/FrontPage?action=CreatePdfDocument'
335 self.url = req.url.replace(req.query_string, self.query_string)
336 # 1.5,1.6: Not all kinds of request support SSL.
337 if 'is_ssl' in req.__dict__:
338 self.is_ssl = req.is_ssl
339 else:
340 self.is_ssl = 0
341 # 1.5,1.6: Not all kinds of request set env.
342 self.env = {}
343 if 'env' in req.__dict__:
344 # 1.5,1.6: Do not copy env otherwise UNICODE encoding does not work right.
345 #self._setup_vars_from_std_env(req.env)
346 self.env['AUTH_TYPE'] = req.env.get('AUTH_TYPE', '')
347 self.http_host = req.http_host
348 self.http_user_agent = req.http_user_agent
349 self.request_method = None
350 self.saved_cookie = req.saved_cookie
351 self.remote_addr = req.remote_addr
352 self.script_name = getattr (req, u'script_name', u'')
353
354 self.req = req
355 RequestBase.__init__(self)
356
357 def run(self, rev = None):
358 """Start processing the document."""
359 # 1.6:MoinMoin/request/__init__.py: Initialise action from environment variables not from form.
360 self.action = 'print'
361 if rev:
362 self.form[u'rev'] = [rev]
363 self.output_string = u''
364 self.error_string = u''
365 self.sent_headers = False
366 self.failed = 0
367 RequestBase.run(self)
368 return (self.output_string, self.error_string)
369
370 def http_headers (self, *args, **kw):
371 """Used by MoinMoin 1.5.x instead of emit_http_headers()."""
372 self.sent_headers = True
373
374 def emit_http_headers(self, *args, **kw):
375 """Used by MoinMoin 1.6.x instaed of http_headers()."""
376 self.sent_headers = 1
377
378 def fail (self, err):
379 """Catch if a error occurs and save the message in our string."""
380 RequestBase.fail (self, err)
381 if not self.error_string:
382 self.error_string = str(err)
383
384 def write (self, *data):
385 """Catch the document in our output_string."""
386 if self.sent_headers:
387 if self.failed:
388 self.error_string += data[0]
389 else:
390 self.output_string += data[0]
391
392 def flush(self):
393 pass
394
395
396 def attachment_fsname(attachment, page, request):
397 """Return location of attament on the file system. current_page is the relative location
398 where attachment is used.
399 """
400 from MoinMoin.action import AttachFile
401 pagename, filename = AttachFile.absoluteName(attachment, page.page_name)
402 #self.request.log("attachment_link: url %s pagename %s filename %s" % (url, pagename, filename))
403 fname = wikiutil.taintfilename(filename)
404 return AttachFile.getFilename(request, pagename, fname)
405
406
407 def shell_quote(parameter):
408 o = parameter
409 for c in [u' ', u'(', u')']:
410 o = o.replace(c, u'\\' + c)
411 return o
412
413
414 def getEditorName(request):
415 """Return name of the last editor."""
416 editorname = u''
417 log = request.page._last_edited(request)
418 if log:
419 if request.cfg.show_hosts:
420 title = " @ %s[%s]" % (log.hostname, log.addr)
421 else:
422 title = ""
423 kind, info = log.getInterwikiEditorData(request)
424 if kind in ['interwiki', 'email']:
425 if log._usercache[log.userid].__dict__.get('aliasname', u''):
426 editorname = log._usercache[log.userid].aliasname
427 else:
428 editorname = log._usercache[log.userid].name
429 elif kind == 'ip':
430 try:
431 idx = info.index('.')
432 except ValueError:
433 idx = len(info)
434 editorname = wikiutil.escape(info[:idx])
435 return editorname
436
437
438 def pipeCommand(cmdstr, input=None):
439 child_stdin, child_stdout, child_stderr = os.popen3(cmdstr, u'b')
440 try:
441 if input:
442 child_stdin.write(input)
443 child_stdin.close()
444 except:
445 pass
446
447 child_output = child_stdout.read()
448 child_stdout.close()
449
450 child_error = child_stderr.read()
451 child_stderr.close()
452
453 if os.name in ['posix', 'mac']:
454 try:
455 # REMARK: Otherwise we get <defunct> processes.
456 os.wait()
457 except OSError, e:
458 # 10: No child processes.
459 if e.errno != 10:
460 raise
461 return (child_output, child_error)
462
463
464 class CreatePdfDocument:
465 """Implementation of the PDF document generator."""
466
467 def __init__(self):
468 self.action_name = self.__class__.__name__
469 self.pagename = None
470 self.request = None
471 self._ = None
472 self.debug = False
473 self.msg = None
474 self.errormsgsent = False
475 self.default_values = {
476 'style': u'webpage',
477 'format': u'pdf13',
478 'titlefileimage': u'',
479 'linkstyle': u'underline',
480 'headerleft': u't',
481 'headermiddle': u'.',
482 'headerright': u'D',
483 'footerleft': u'.',
484 'footermiddle': u'/',
485 'footerright': u'.',
486 'tocheaderleft': u'.',
487 'tocheadermiddle': u't',
488 'tocheaderright': u'.',
489 'tocfooterleft': u'.',
490 'tocfootermiddle': u'.',
491 'tocfooterright': u'i',
492 'bodycolor': u'FFFFFF',
493 'bodyimage': u'',
494 'textcolor': u'000000',
495 'linkcolor': u'0000E0',
496 'size': u'legal',
497 'user-password': u'',
498 'owner-password': u'',
499 'toclevels': u'3',
500 'grayscale': u'unchecked',
501 'title': u'checked',
502 'duplex': u'unchecked',
503 'landscape': u'unchecked',
504 'usersize': u'',
505 'margintop': u'0.50in',
506 'marginbottom': u'0.50in',
507 'marginleft': u'1.00in',
508 'marginright': u'0.50in',
509 'no-toc': u'checked',
510 'no-links': u'checked',
511 'firstpage': u'p1',
512 'jpeg': u'0',
513 'compression': u'0',
514 'pagemode': u'outline',
515 'pagelayout': u'single',
516 'firstpage': u'c1',
517 'numbered': u'checked',
518 'encryption': u'unchecked',
519 'permissioncopy': u'checked',
520 'permissionprint': u'checked',
521 'permissionannotate': u'checked',
522 'permissionmodify': u'checked',
523 'charset': u'iso-8859-1',
524 'debug': u'',
525 'rev': 0,
526 'extra-titledocnumber': u'',
527 'extra-titleauthor': u'',
528 'extra-titlecopyright': u'',
529 'pageinfo': u'unchecked',
530 'bodyfont': u'times',
531 'headingfont': u'helvetica',
532 'headfootfont': u'helvetica',
533 'fontsize': u'11.0',
534 'headfootsize': u'11.0',
535 'fontspacing': u'1.2',
536 'embedfonts': u'checked',
537 'browserwidth': u'680',
538 'extra-dynamiccodeblock': u'checked',
539 'extra-codeblocklinenumbers': u'checked',
540 'htmldoc_cmd': u'htmldoc',
541 }
542 # We have to know which values are checkboxes within the form. If a key does
543 # not exists wihtin the form the corresponding checkbox is not checked.
544 self.form_checkbox = []
545 for key, value in self.default_values.items():
546 if value in [u'checked', u'unchecked']:
547 self.form_checkbox += [key]
548 self.contenttype = u'application/pdf'
549
550 def error_msg(self, msg):
551 """Display error message."""
552 if not self.errormsgsent:
553 # Backward compatiblity with MoinMoin 1.5.
554 if Page.send_page.func_code.co_varnames[1] == 'request':
555 Page(self.request, self.pagename).send_page(self.request, msg=msg)
556 else:
557 Page(self.request, self.pagename).send_page(msg=msg)
558 self.errormsgsent = True
559
560 def fixhtmlstr(self, str):
561 """Convert utf-8 encoded multi-byte sequences into &#XXXX; format."""
562 htmlstr = array.array('c')
563 for c in str:
564 if ord(c) >= 128:
565 htmlstr.fromstring('&#%d;' % ord(c))
566 else:
567 htmlstr.fromstring(c)
568 return htmlstr.tostring()
569
570 def set_page_values(self):
571 """Scan raw page for additional information relating PDF generation."""
572 #pdflines = False
573 for line in self.request.page.get_raw_body().split(u'\n'):
574 if line[:6] == u'##pdf ' and len(line[6:]):
575 line = line[6:]
576 key = line.split()[0]
577 value = line[len(key) + 1:]
578 # Only accept known values/settings.
579 if key in self.default_values:
580 # Check if there are any restrictions for key.
581 if key in self.valid_options:
582 # Set only the value if the restrictions are confirmed.
583 valid_values = self.valid_options[key].keys()
584 if value in valid_values:
585 self.values[key] = value
586 else:
587 # There are no restrictions for value.
588 self.values[key] = value
589 elif not line:
590 break
591
592 def set_page_default_values(self):
593 # We are not able to recognise if this string is part of a verbatim area.
594 matchtoclvl = re.compile(r'^\[\[TableOfContents\(\s*(\d+)\s*\)\]\]')
595 matchtoc = re.compile(r'^\[\[TableOfContents\(*\)*\]\]')
596 toc = False
597 for line in self.request.page.get_raw_body().split(u'\n'):
598 if line[:10] == u'#language ' and not u'language' in self.values:
599 lang = self.make_isolang(line[10:])
600 if lang:
601 self.default_values[u'language'] = lang
602 elif not u'toclevels' in self.values and not toc:
603 result = matchtoclvl.match(line)
604 if result:
605 toclevels = int(result.group(1).strip())
606 if toclevels > 4:
607 toclevels = 4
608 self.default_values[u'toclevels'] = str(toclevels)
609 toc = True
610 elif matchtoc.match(line):
611 toc = True
612 # We assume if table-of-contents is used we intent to generate a book.
613 if toc:
614 # Do not change style if set manually or by configuration.
615 self.default_values[u'style'] = self.default_values.get(u'style', u'book')
616 # Do not generate a table of contents page.
617 if self.default_values[u'style'] != u'book':
618 # Do not change style if set manually or by configuration.
619 self.default_values[u'no-toc'] = self.default_values.get(u'no-toc', u'unchecked')
620
621 def _select (self, name, description=None):
622 """Helper function to create a selection control."""
623 str = u'<select name="%s" size="1">' % (name,)
624 if not description:
625 description = self.valid_options[name]
626 keys = description.keys()
627 keys.sort()
628 for value in keys:
629 if value == self.values[name]:
630 selected = u'selected'
631 else:
632 selected = u''
633 str += u'<option value="%s" %s>%s</option>' % (value, selected, description[value],)
634 str += u'</select>'
635 return str
636
637 def _chooseformat (self, name):
638 """Helper function to create left/middle/right selection controls."""
639 str = u""" <tr>
640 <td class="label"><label>%s</label></td>
641 <td><table>
642 <tr>
643 <td>%s</td>
644 <td>%s</td>
645 </tr>
646 <tr>
647 <td>%s</td>
648 <td>%s</td>
649 </tr>
650 <tr>
651 <td>%s</td>
652 <td>%s</td>
653 </tr>
654 </table>
655 </td>
656 <td>%s</td>
657 </tr>""" % (self.fields[u'label_' + name],
658 self.fields[u'label_left'], self._select(name + u'left', self.valid_options[u'tocformats']),
659 self.fields[u'label_middle'], self._select(name + u'middle', self.valid_options[u'tocformats']),
660 self.fields[u'label_right'], self._select(name + u'right', self.valid_options[u'tocformats']),
661 self.fields[u'help_' + name],)
662 return str
663
664 def makeform (self, errormsg=u''):
665 self.fields = {
666 'error': errormsg,
667 'pagename': wikiutil.escape(self.pagename),
668 'action': self.action_name,
669 'version': __version__,
670 'moinmoin_release': moinmoin_release,
671
672 'label_input': self._(u'Input'),
673 'label_output': self._(u'Output'),
674 'label_page': self._(u'Page'),
675 'label_tableofcontents': self._(u'Contents'),
676 'label_pdf': self._(u'PDF'),
677 'label_security': self._(u'Security'),
678
679 'label_choose_style': self._(u'Choose style'),
680 'help_choose_style': self._(u'book: Create a structured PDF document with headings, chapters, etc.') + u'<br/>' + \
681 self._(u'webpage: Specifies that the HTML sources are unstructured (plain web pages.) A page break is inserted between each file or URL in the output.') + u'<br/>' + \
682 self._(u'continuous: Specifies that the HTML sources are unstructured (plain web pages.) No page breaks are inserted between each file or URL in the output.'),
683
684 'help_titletext': self._(u'Title of the document for the front page.'),
685
686 'label_titlefileimage': self._(u'Title file/image'),
687 'help_titlefileimage': self._(u'The title image or HTML page. These file has to be an attachments!'),
688
689 'label_extra-titledocnumber': self._(u'Version'),
690 'help_extra-titledocnumber': self._(u'Specify document version to be displayed on the title page.'),
691
692 'label_extra-titleauthor': self._(u'Author'),
693 'help_extra-titleauthor': self._(u'Intellectual property owner of this document.'),
694
695 'label_extra-titlecopyright': self._(u'Copyright'),
696 'help_extra-titlecopyright': self._(u'Copyright notice for this document.'),
697
698 'label_pageinfo': self._(u'Apply page information'),
699 'help_pageinfo': self._(u'Information about who and when modified the document are applied at the end.'),
700
701 'label_format': self._(u'Output format'),
702 'help_format': self._(u'Specifies the output format.'),
703
704 'label_outputoptions': self._(u'Output options'),
705 'label_grayscale': self._(u'Grayscale document'),
706 'label_titlepage': self._(u'Title page'),
707 'label_titletext': self._(u'Title'),
708 'label_jpeg': self._(u'JPEG big images'),
709 'label_compression': self._(u'Compression'),
710
711 'label_no-toc': self._(u'Generate a table of contents'),
712 'help_no-toc': self._(u''),
713
714 'label_toclevels': self._(u'Limit the number of levels in the table-of-contents'),
715 'help_toclevels': self._(u'Sets the number of levels in the table-of-contents.') + u' ' + self._(u'Empty for unlimited levels.'),
716
717 'label_numbered': self._(u'Numbered headings'),
718 'help_numbered': self._(u'Check to number all of the headings in the document.'),
719
720 'label_toctitle': self._(u'Table-of-contents title'),
721 'help_toctitle': self._(u'Sets the title for the table-of-contents.') + u' ' + self._(u'Empty for default title.'),
722
723 'label_left': self._(u'Left'),
724 'label_middle': self._(u'Middle'),
725 'label_right': self._(u'Right'),
726
727 'label_tocheader': self._(u'Header of table-of-contantes page'),
728 'help_tocheader': self._(u'Sets the page header to use on table-of-contents pages.'),
729
730 'label_tocfooter': self._(u'Footer of table-of-contantes page'),
731 'help_tocfooter': self._(u'Sets the page footer to use on table-of-contents pages.'),
732
733 'label_header': self._(u'Page header'),
734 'help_header': self._(u'Sets the page header to use on body pages.'),
735
736 'label_footer': self._(u'Page footer'),
737 'help_footer': self._(u'Sets the page footer to use on body pages.'),
738
739 'label_colors': self._(u'Colors'),
740 'label_no-links': self._(u'Create HTTP links'),
741 'help_no-links': self._(u'Enables generation of links in PDF files.'),
742
743 'label_linkstyle': self._(u'Style of HTTP links'),
744 'help_linkstyle': self._(u''),
745
746 'label_linkcolor': self._(u'HTTP links color'),
747 'help_linkcolor': self._(u'Sets the color of links.'),
748
749 'label_bodycolor': self._(u'Body color'),
750 'help_bodycolor': self._(u'Enter the HTML color for the body (background).'),
751
752 'label_bodyimage': self._(u'Body image'),
753 'help_bodyimage': self._(u'Enter the image file for the body (background). These file has to be an attachments!'),
754
755 'label_textcolor': self._(u'Text color'),
756 'help_textcolor': self._(u'Enter the HTML color for the text.'),
757
758 'label_duplex': self._(u'2-Sided'),
759 'help_duplex': self._(u'Specifies that the output should be formatted for double-sided printing.'),
760
761 'label_landscape': self._(u'Landscape'),
762
763 'label_choose_size': self._(u'Choose page size'),
764 'help_choose_size': self._(u'Choose one of the predefined standard sizes or select user defined.'),
765
766 'label_usersize': self._(u'User defined page size'),
767 'help_usersize': self._(u'Specifies the page size using a standard name or in points (no suffix or ##x##pt), inches (##x##in), centimeters (##x##cm), or millimeters (##x##mm).'),
768
769 'label_browserwidth': self._(u'Browser width'),
770 'help_browserwidth': self._(u'Set the target browser width in pixels (400-1200). This determines the page scaling of images.'),
771
772 'label_margin': self._(u'User defined margin'),
773 'label_margintop': self._(u'Top'),
774 'label_marginbottom': self._(u'Bottom'),
775 'label_marginleft': self._(u'Left'),
776 'label_marginright': self._(u'Right'),
777 'help_margin': self._(u'Specifies the margin size using points (no suffix or ##x##pt), inches (##x##in), centimeters (##x##cm), or millimeters (##x##mm).') + u' ' + self._(u'Keep empty for default value.'),
778
779 'label_pagemode': self._(u'Page mode'),
780 'help_pagemode': self._(u'Controls the initial viewing mode for the document.') + u'<br/>' + self._(u'Document: Displays only the docuemnt pages.') + u'<br/>' + self._(u'Outline: Display the table-of-contents outline as well as the document pages.') + u'<br/>' + self._(u'Full-screen: Displays pages on the whole screen; this mode is used primarily for presentations.'),
781
782 'label_pagelayout': self._(u'Page layout'),
783 'help_pagelayout': self._(u'Controls the initial layout of document pages on the screen.') + u'<br/>' + self._(u'Single: Displays a single page at a time.') + u'<br/>' + self._(u'One column: Displays a single column of pages at a time.') + u'<br/>' + self._(u'Two column left/right: Display two columns of pages at a time; the first page is displayed in the left or right column as selected.'),
784
785 'label_firstpage': self._(u'First page'),
786 'help_firstpage': self._(u'Choose the initial page that will be shown.'),
787
788 'label_encryption': self._(u'Encryption'),
789 'help_encryptin': self._(u'Enables encryption and security features for PDF output.'),
790 'label_permissions': self._(u'Permissions'),
791 'help_permissions': self._(u'Specifies the document permissions.'),
792
793 'label_permissionannotate': self._(u'Annotate'),
794 'label_permissionprint': self._(u'Print'),
795 'label_permissionmodify': self._(u'Modify'),
796 'label_permissioncopy': self._(u'Copy'),
797
798 'label_owner-password': self._(u'Owner password'),
799 'help_owner-password': self._(u'Specifies the owner password to control who can change document permissions etc.') + u' ' + self._(u'If this field is left blank, a random 32-character password is generated so that no one can change the document.'),
800
801 'label_user-password': self._(u'User password'),
802 'help_user-password': self._(u'Specifies the user password to restrict viewing permissions on this PDF document.') + u' ' + self._(u'Empty for no encryption.'),
803
804 'label_expert': self._(u'Expert'),
805 'label_language': self._(u'Language translation'),
806 'help_language': self._(u'Specify language to use for date and time format.'),
807
808 'label_extra-dynamiccodeblock': self._(u'Dynamic code block'),
809 'help_extra-dynamiccodeblock': self._(u'Shrink code blocks on page.'),
810
811 'label_extra-codeblocklinenumbers': self._(u'Lines in code block'),
812 'help_extra-codeblocklinenumbers': self._(u'Show line numbers for code blocks.'),
813
814 'label_fonts': self._(u'Fonts'),
815 'label_fontsize': self._(u'Base font size'),
816 'help_fontsize': self._(u'Set the default size of text.'),
817 'label_fontspacing': self._(u'Line spacing'),
818 'help_fontspacing': self._(u'Set the spacing between lines of text.'),
819 'label_bodyfont': self._(u'Body typeface'),
820 'help_bodyfont': self._(u'Choose the default typeface (font) of text.'),
821 'label_headingfont': self._(u'Heading typeface'),
822 'help_headingfont': self._(u'Choose the default typeface (font) of headings.'),
823 'label_headfootsize': self._(u'Header/Footer size'),
824 'help_headfootsize': self._(u'Set the size of header and footer text.'),
825 'label_headfootfont': self._(u'Header/Footer font'),
826 'help_headfootfont': self._(u'Choose the font for header and footer text.'),
827 'label_charset': self._(u'Charset set'),
828 'help_charset': self._(u'Change the encoding of the text in document.'),
829 'label_embedfonts': self._(u'Embed fonts'),
830 'help_embedfonts': self._(u'Check to embed font in the output file.'),
831
832 'label_about': self._(u'About'),
833 'copyright': u'',
834 'version': self._(u'Version') + u' ' + __version__,
835
836 'button_generate': self._(u'Generate PDF'),
837 'button_preview': self._(u'Preview'),
838 'button_remember': self._(u'Remember form'),
839 'button_cancel': self._(u'Cancel'),
840 'button_reset': self._(u'Reset'),
841 }
842
843 self.fields['copyright'] = u"<br/>\n".join(wikiutil.escape(__doc__).split(u"\n"))
844 self.fields.update(self.values)
845
846 # Status of debug.
847 if self.debug:
848 self.fields[u'debug'] = u'1'
849 else:
850 self.fields[u'debug'] = u'0'
851
852 # Go through all format strings.
853 for name in [u'tocheader', u'tocfooter', u'header', u'footer']:
854 self.fields[u'choose_' + name] = self._chooseformat(name)
855
856 self.fields[u'select_style'] = self._select(u'style')
857 self.fields[u'select_format'] = self._select(u'format')
858 self.fields[u'select_linkstyle'] = self._select(u'linkstyle')
859 self.fields[u'select_size'] = self._select(u'size')
860 self.fields[u'select_jpeg'] = self._select(u'jpeg')
861 self.fields[u'select_compression'] = self._select(u'compression')
862 self.fields[u'select_toclevels'] = self._select(u'toclevels')
863 self.fields[u'select_pagemode'] = self._select(u'pagemode')
864 self.fields[u'select_pagelayout'] = self._select(u'pagelayout')
865 self.fields[u'select_firstpage'] = self._select(u'firstpage')
866 self.fields[u'select_charset'] = self._select(u'charset')
867 self.fields[u'select_fontsize'] = self._select(u'fontsize')
868 self.fields[u'select_bodyfont'] = self._select(u'bodyfont')
869 self.fields[u'select_headingfont'] = self._select(u'headingfont')
870 self.fields[u'select_headfootsize'] = self._select(u'headfootsize')
871 self.fields[u'select_headfootfont'] = self._select(u'headfootfont')
872 self.fields[u'select_fontspacing'] = self._select(u'fontspacing')
873
874 # Add tabber implementation.
875 self.request.cfg.html_head += """
876 <script type="text/javascript">
877 <!-- //
878 %s
879 //-->
880 </script>
881
882 %s
883 """ % (tabber_minimized, tabber_minimized_css,)
884
885 form = u''
886 if self.debug:
887 form += u'<p class="warning">Debug mode activated.</p>'
888 if not moinmoin_release[:3] in [u'1.6', u'1.5']:
889 form += u'<p class="warning">This plugin is not designed for MoinMoin %(moinmoin_release)s.</p>'
890 form += """
891 <p class="error">%(error)s</p>
892 <form method="post" action="">
893 <input type="hidden" name="action" value="%(action)s"/>
894 <div class="tabber">
895 <div class="tabbertab">
896 <h3>%(label_input)s</h3>
897 <table>
898 <tr>
899 <td class="label"><label>%(label_choose_style)s</label></td>
900 <td class="content">%(select_style)s</td>
901 <td>%(help_choose_style)s</td>
902 </tr>
903 <tr>
904 <td class="label"><label>%(label_titletext)s</label></td>
905 <td class="content"><input type="text" size="30" name="titletext" value="%(titletext)s" /></td>
906 <td>%(help_titletext)s</td>
907 </tr>
908 <tr>
909 <td class="label"><label>%(label_titlefileimage)s</label></td>
910 <td class="content"><input type="text" size="30" name="titlefileimage" value="%(titlefileimage)s" /></td>
911 <td>%(help_titlefileimage)s</td>
912 </tr>
913 <tr>
914 <td class="label"><label>%(label_extra-titledocnumber)s</label></td>
915 <td class="content"><input type="text" size="30" name="extra-titledocnumber" value="%(extra-titledocnumber)s" /></td>
916 <td>%(help_extra-titledocnumber)s</td>
917 </tr>
918 <tr>
919 <td class="label"><label>%(label_extra-titleauthor)s</label></td>
920 <td class="content"><input type="text" size="30" name="extra-titleauthor" value="%(extra-titleauthor)s" /></td>
921 <td>%(help_extra-titleauthor)s</td>
922 </tr>
923 <tr>
924 <td class="label"><label>%(label_extra-titlecopyright)s</label></td>
925 <td class="content"><input type="text" size="30" name="extra-titlecopyright" value="%(extra-titlecopyright)s" /></td>
926 <td>%(help_extra-titlecopyright)s</td>
927 </tr>
928 <tr>
929 <td class="label"><label>%(label_pageinfo)s</label></td>
930 <td class="checkbox"><input type="checkbox" name="pageinfo" value="checked" %(pageinfo)s /></td>
931 <td>%(help_pageinfo)s</td>
932 </tr>
933 </table>
934 </div>
935 <div class="tabbertab">
936 <h3>%(label_output)s</h3>
937 <table>
938 <tr>
939 <td class="label"><label>%(label_format)s</label></td>
940 <td class="content">%(select_format)s</td>
941 <td>%(help_format)s</td>
942 </tr>
943 <tr>
944 <td class="label"><label>%(label_outputoptions)s</label></td>
945 <td colspan="2"><input type="checkbox" name="grayscale" value="checked" %(grayscale)s />%(label_grayscale)s
946 <input type="checkbox" name="title" value="checked" %(title)s />%(label_titlepage)s<br />
947 %(label_compression)s : %(select_compression)s
948 %(label_jpeg)s %(select_jpeg)s</td>
949 </tr>
950 </table>
951 </div>
952 <div class="tabbertab">
953 <h3>%(label_page)s</h3>
954 <table>
955 <tr>
956 <td class="label"><label>%(label_choose_size)s</label></td>
957 <td>%(select_size)s <br /><nobr>%(label_usersize)s <input type="text" size="15" name="usersize" value="%(usersize)s" /></nobr></td>
958 <td>%(help_choose_size)s<br />%(help_usersize)s</td>
959 </tr>
960 <tr>
961 <td class="label"><label>%(label_browserwidth)s</label></td>
962 <td class="content"><input type="text" size="30" name="browserwidth" value="%(browserwidth)s" /></td>
963 <td>%(help_browserwidth)s</td>
964 </tr>
965 <tr>
966 <td> </td>
967 <td colspan="2"><input type="checkbox" name="duplex" value="checked" %(duplex)s /> %(label_duplex)s
968 <input type="checkbox" name="landscape" value="checked" %(landscape)s /> %(label_landscape)s</td>
969 </tr>
970 <tr>
971 <td class="label"><label>%(label_margin)s</label></td>
972 <td><table><tr><td> </td><td><nobr><label>%(label_margintop)s</label> <input type="text" name="margintop" value="%(margintop)s" size="7" /></nobr></td><td> </td></tr>
973 <tr><td><nobr><label>%(label_marginleft)s</label> <input type="text" name="marginleft" value="%(marginleft)s" size="7" /></nobr></td><td> </td><td><nobr><label>%(label_marginright)s</label> <input type="text" name="marginright" value="%(marginright)s" size="7" /></nobr></td></tr>
974 <tr><td> </td><td><nobr><label>%(label_marginbottom)s</label> <input type="text" name="marginbottom" value="%(marginbottom)s" size="7" /></nobr></td><td> </td></tr></table>
975 <td>%(help_margin)s</td>
976 </tr>
977 %(choose_header)s
978 %(choose_footer)s
979 </table>
980 </div>
981 <div class="tabbertab">
982 <h3>%(label_tableofcontents)s</h3>
983 <table>
984 <tr>
985 <td class="label"><label>%(label_no-toc)s</label></td>
986 <td class="checkbox"><input type="checkbox" name="no-toc" value="checked" %(no-toc)s /></td>
987 <td>%(help_no-toc)s</td>
988 </tr>
989 <tr>
990 <td class="label"><label>%(label_toclevels)s</label></td>
991 <td class="content">%(select_toclevels)s</td>
992 <td>%(help_toclevels)s</td>
993 </tr>
994 <tr>
995 <td> </td>
996 <td><input type="checkbox" name="numbered" value="checked" %(numbered)s /> %(label_numbered)s</td>
997 <td>%(help_numbered)s</td>
998 </tr>
999 <tr>
1000 <td class="label"><label>%(label_toctitle)s</label></td>
1001 <td class="content"><input type="text" size="30" name="toctitle" value="%(toctitle)s" /></td>
1002 <td>%(help_toctitle)s</td>
1003 </tr>
1004 %(choose_tocheader)s
1005 %(choose_tocfooter)s
1006 </table>
1007 </div>
1008 <div class="tabbertab">
1009 <h3>%(label_colors)s</h3>
1010 <table>
1011 <tr>
1012 <td class="label"><label>%(label_bodycolor)s</label></td>
1013 <td class="content"><input type="text" size="6" name="bodycolor" value="%(bodycolor)s" /></td>
1014 <td>%(help_bodycolor)s</td>
1015 </tr>
1016 <tr>
1017 <td class="label"><label>%(label_bodyimage)s</label></td>
1018 <td class="content"><input type="text" size="30" name="bodyimage" value="%(bodyimage)s" /></td>
1019 <td>%(help_bodyimage)s</td>
1020 </tr>
1021 <tr>
1022 <td class="label"><label>%(label_textcolor)s</label></td>
1023 <td class="content"><input type="text" size="6" name="textcolor" value="%(textcolor)s" /></td>
1024 <td>%(help_textcolor)s</td>
1025 </tr>
1026 <tr>
1027 <td class="label"><label>%(label_linkcolor)s</label></td>
1028 <td class="content"><input type="text" size="6" name="linkcolor" value="%(linkcolor)s" /></td>
1029 <td>%(help_linkcolor)s</td>
1030 </tr>
1031 <tr>
1032 <td class="label"><label>%(label_linkstyle)s</label></td>
1033 <td class="content">%(select_linkstyle)s</td>
1034 <td>%(help_linkstyle)s</td>
1035 </tr>
1036 <tr>
1037 <td class="label"><label>%(label_no-links)s</label></td>
1038 <td><input type="checkbox" name="no-links" value="checked" %(no-links)s /></td>
1039 <td>%(help_no-links)s</td>
1040 </tr>
1041 </table>
1042 </div>
1043 <div class="tabbertab">
1044 <h3>%(label_fonts)s</h3>
1045 <table>
1046 <tr>
1047 <td class="label"><label>%(label_fontsize)s</label></td>
1048 <td class="content">%(select_fontsize)s</td>
1049 <td>%(help_fontsize)s</td>
1050 </tr>
1051 <tr>
1052 <td class="label"><label>%(label_fontspacing)s</label></td>
1053 <td class="content">%(select_fontspacing)s</td>
1054 <td>%(help_fontspacing)s</td>
1055 </tr>
1056 <tr>
1057 <td class="label"><label>%(label_bodyfont)s</label></td>
1058 <td class="content">%(select_bodyfont)s</td>
1059 <td>%(help_bodyfont)s</td>
1060 </tr>
1061 <tr>
1062 <td class="label"><label>%(label_headingfont)s</label></td>
1063 <td class="content">%(select_headingfont)s</td>
1064 <td>%(help_headingfont)s</td>
1065 </tr>
1066 <tr>
1067 <td class="label"><label>%(label_headfootsize)s</label></td>
1068 <td class="content">%(select_headfootsize)s</td>
1069 <td>%(help_headfootsize)s</td>
1070 </tr>
1071 <tr>
1072 <td class="label"><label>%(label_headfootfont)s</label></td>
1073 <td class="content">%(select_headfootfont)s</td>
1074 <td>%(help_headfootfont)s</td>
1075 </tr>
1076 <tr>
1077 <td class="label"><label>%(label_charset)s</label></td>
1078 <td class="content">%(select_charset)s</td>
1079 <td>%(help_charset)s</td>
1080 </tr>
1081 <tr>
1082 <td class="label"><label>%(label_embedfonts)s</label></td>
1083 <td class="checkbox"><input type="checkbox" name="embedfonts" value="checked" %(embedfonts)s /></td>
1084 <td>%(help_embedfonts)s</td>
1085 </tr>
1086 </table>
1087 </div>
1088 <div class="tabbertab">
1089 <h3>%(label_pdf)s</h3>
1090 <table>
1091 <tr>
1092 <td class="label"><label>%(label_pagemode)s</label></td>
1093 <td class="content">%(select_pagemode)s</td>
1094 <td>%(help_pagemode)s</td>
1095 </tr>
1096 <tr>
1097 <td class="label"><label>%(label_pagelayout)s</label></td>
1098 <td class="content">%(select_pagelayout)s</td>
1099 <td>%(help_pagelayout)s</td>
1100 </tr>
1101 <tr>
1102 <td class="label"><label>%(label_firstpage)s</label></td>
1103 <td class="content">%(select_firstpage)s</td>
1104 <td>%(help_firstpage)s</td>
1105 </tr>
1106 </table>
1107 </div>
1108 <div class="tabbertab">
1109 <h3>%(label_security)s</h3>
1110 <table>
1111 <tr>
1112 <td class="label"><label>%(label_encryption)s</label></td>
1113 <td><input type="checkbox" name="encryption" value="checked" %(encryption)s /></td>
1114 <td>%(help_numbered)s</td>
1115 </tr>
1116 <tr>
1117 <td class="label"><label>%(label_permissions)s</label></td>
1118 <td><nobr><input type="checkbox" name="permissionprint" value="checked" %(permissionprint)s /> %(label_permissionprint)s</nobr>
1119 <nobr><input type="checkbox" name="permissionmodify" value="checked" %(permissionmodify)s /> %(label_permissionmodify)s</nobr><br />
1120 <nobr><input type="checkbox" name="permissioncopy" value="checked" %(permissioncopy)s /> %(label_permissioncopy)s</nobr>
1121 <nobr><input type="checkbox" name="permissionannotate" value="checked" %(permissionannotate)s /> %(label_permissionannotate)s</nobr></td>
1122 <td>%(help_permissions)s</td>
1123 </tr>
1124 <tr>
1125 <td class="label"><label>%(label_user-password)s</label></td>
1126 <td class="content"><input type="password" size="30" name="user-password" value="%(user-password)s" /></td>
1127 <td>%(help_user-password)s</td>
1128 </tr>
1129 <tr>
1130 <td class="label"><label>%(label_owner-password)s</label></td>
1131 <td class="content"><input type="password" size="30" name="owner-password" value="%(owner-password)s" /></td>
1132 <td>%(help_owner-password)s</td>
1133 </tr>
1134 </table>
1135 </div>
1136 <div class="tabbertab">
1137 <h3>%(label_expert)s</h3>
1138 <table>
1139 <tr>
1140 <td class="label"><label>%(label_language)s</label></td>
1141 <td class="content"><input type="text" size="6" name="language" value="%(language)s" /></td>
1142 <td>%(help_language)s</td>
1143 </tr>
1144 <tr>
1145 <td class="label"><label>%(label_extra-dynamiccodeblock)s</label></td>
1146 <td class="checkbox"><input type="checkbox" name="extra-dynamiccodeblock" value="checked" %(extra-dynamiccodeblock)s /></td>
1147 <td>%(help_extra-dynamiccodeblock)s</td>
1148 </tr>
1149 <tr>
1150 <td class="label"><label>%(label_extra-codeblocklinenumbers)s</label></td>
1151 <td class="checkbox"><input type="checkbox" name="extra-codeblocklinenumbers" value="checked" %(extra-codeblocklinenumbers)s /></td>
1152 <td>%(help_extra-codeblocklinenumbers)s</td>
1153 </tr>
1154 </table>
1155 </div>
1156 <div class="tabbertab">
1157 <h3>%(label_about)s</h3>
1158 <p>%(version)s (MoinMoin %(moinmoin_release)s)</p>
1159 <p>%(copyright)s</p>
1160 </div>
1161 </div>
1162 <p>
1163 <input type="hidden" name="debug" value="%(debug)s" /><input type="hidden" name="rev" value="%(rev)s" />
1164 <input type="submit" name="generate_from_form" value="%(button_generate)s" />
1165 <input type="submit" name="preview" value="%(button_preview)s" />
1166 <input type="submit" name="remember" value="%(button_remember)s" />
1167 <input type="submit" name="cancel" value="%(button_cancel)s" />
1168 </p>
1169 </form>
1170 """ % self.fields
1171 return Dialog(self.request, content=form)
1172
1173 def run(self, pagename, request):
1174 """ Main dispatcher for the action."""
1175 self.pagename = pagename
1176 self.request = request
1177 self._ = self.request.getText
1178 self.form = self.request.form
1179 self.cfg = self.request.cfg
1180
1181 # Canceled by user.
1182 if self.form.has_key(u'cancel'):
1183 # Backward compatiblity with MoinMoin 1.5.
1184 if Page.send_page.func_code.co_varnames[1] == "request":
1185 return self.request.page.send_page(self.request)
1186 else:
1187 return self.request.page.send_page()
1188
1189 # Determine calling parameters.
1190 if self.form.get(u'debug', [u'0']) == [u'1']:
1191 self.debug = True
1192
1193 # This dict contains all possible values.
1194 self.valid_options = {}
1195
1196 self.valid_options[u'tocformats'] = {
1197 u'/': self._(u'1/N,2/N Arabic page numbers'),
1198 u':': self._(u'1/C,2/C Arabic chapter page numbers'),
1199 u'1': self._(u'1,2,3,...'),
1200 u'a': self._(u'a,b,c,...'),
1201 u'A': self._(u'A,B,C,...'),
1202 u'c': self._(u'Chapter title'),
1203 u'C': self._(u'Chapter page number'),
1204 u'd': self._(u'Date'),
1205 u'D': self._(u'Date + Time'),
1206 u'h': self._(u'Heading'),
1207 u'i': self._(u'i,ii,iii,iv,...'),
1208 u'I': self._(u'I,II,III,IV,...'),
1209 u't': self._(u'Title'),
1210 u'T': self._(u'Time'),
1211 u'.': self._(u'Blank'),
1212 # TODO: Not supported yet; u'l': self._(u'Logo image'),
1213 }
1214 self.valid_options[u'style'] = {
1215 u'webpage': self._(u'webpage'),
1216 u'book': self._(u'book'),
1217 u'continuous': self._(u'continuous'),
1218 }
1219 self.valid_options[u'size'] = {
1220 u'legal': self._(u'Legal (8.5x14in)'),
1221 u'a4': self._(u'A4 (210x297mm)'),
1222 u'letter': self._(u'Letter (8.5x11in)'),
1223 u'universal': self._(u'Universal (8.27x11in)'),
1224 u'': self._(u'User defined'),
1225 }
1226 self.valid_options[u'format'] = {
1227 u'pdf11': self._(u'PDF 1.1 (Acrobat 2.0)'),
1228 u'pdf12': self._(u'PDF 1.2 (Acrobat 3.0)'),
1229 u'pdf13': self._(u'PDF 1.3 (Acrobat 4.0)'),
1230 u'pdf14': self._(u'PDF 1.4 (Acrobat 5.0)'),
1231 # TODO: Not supported yet:
1232 #u'ps1': self._(u'PostScript Level 1'),
1233 #u'ps2': self._(u'PostScript Level 2'),
1234 #u'ps3': self._(u'PostScript Level 3'),
1235 }
1236 self.valid_options[u'linkstyle'] = {
1237 u'underline': self._(u'Underline'),
1238 u'plain': self._(u'Plain'),
1239 }
1240 self.valid_options[u'firstpage'] = {
1241 u'c1': self._(u'1st chapter'),
1242 u'p1': self._(u'1st page'),
1243 u'toc': self._(u'Contents'),
1244 }
1245 self.valid_options[u'jpeg'] = {
1246 u'0': self._(u'None'),
1247 u'50': self._(u' 50% (Good)'),
1248 u'55': u'55%', u' 60': u' 60%', u' 65': ' 65%', u' 70': ' 70%', u' 75': ' 75%',
1249 u'80': ' 80%', u' 85': ' 85%', u' 90': ' 90%', u' 95': ' 95%',
1250 u'100': self._(u'100% (Best)'),
1251 }
1252 self.valid_options[u'compression'] = {
1253 u'0': self._(u'None'),
1254 u'1': self._(u'1 (Fast)'),
1255 u'2': u'2', u'3': u'3', u'4': u'4', u'5': u'5', u'6': u'6', u'7': u'7', u'8': u'8',
1256 u'9': self._(u'9 (Best)'),
1257 }
1258 self.valid_options[u'toclevels'] = {
1259 u'0': self._(u'None'),
1260 u'1': u'1', u'2': '2', u'3': '3', u'4': '4'
1261 }
1262 self.valid_options[u'pagemode'] = {
1263 u'outline': self._(u'Outline'),
1264 u'document': self._(u'Document'),
1265 u'fullscreen': self._(u'Full-screen'),
1266 }
1267 self.valid_options[u'pagelayout'] = {
1268 u'single': self._(u'Single'),
1269 u'one': self._(u'One column'),
1270 u'twoleft': self._(u'Two column left'),
1271 u'tworight': self._(u'Two column right'),
1272 }
1273 self.valid_options[u'charset'] = {
1274 u'iso-8859-1': self._(u'ISO 8859-1'),
1275 u'iso-8859-2': self._(u'ISO 8859-2'),
1276 u'iso-8859-3': self._(u'ISO 8859-3'),
1277 u'iso-8859-4': self._(u'ISO 8859-4'),
1278 u'iso-8859-5': self._(u'ISO 8859-5'),
1279 u'iso-8859-6': self._(u'ISO 8859-6'),
1280 u'iso-8859-7': self._(u'ISO 8859-7'),
1281 u'iso-8859-8': self._(u'ISO 8859-8'),
1282 u'iso-8859-9': self._(u'ISO 8859-9'),
1283 u'iso-8859-14': self._(u'ISO 8859-14'),
1284 u'iso-8859-15': self._(u'ISO 8859-15'),
1285 u'cp-874': self._(u'cp-847'),
1286 u'cp-1250': self._(u'cp-1250'),
1287 u'cp-1251': self._(u'cp-1251'),
1288 u'cp-1252': self._(u'cp-1252'),
1289 u'cp-1253': self._(u'cp-1253'),
1290 u'cp-1254': self._(u'cp-1254'),
1291 u'cp-1255': self._(u'cp-1255'),
1292 u'cp-1256': self._(u'cp-1256'),
1293 u'cp-1257': self._(u'cp-1257'),
1294 u'cp-1258': self._(u'cp-1258'),
1295 u'koi-8r': self._(u'koi-8r'),
1296 }
1297 self.valid_options[u'bodyfont'] = {
1298 u'courier': self._(u'Courier'),
1299 u'helvetica': self._(u'Helvetica'),
1300 u'monospace': self._(u'Monospace'),
1301 u'sans': self._(u'Sans'),
1302 u'serif': self._(u'Serif'),
1303 u'times': self._(u'Times'),
1304 }
1305 self.valid_options[u'headingfont'] = self.valid_options[u'bodyfont']
1306 self.valid_options[u'headfootfont'] = self.valid_options[u'bodyfont']
1307 # Go through all font types and create fontname{-bold,-oblique,-boldoblique} entries.
1308 for fontname in self.valid_options[u'bodyfont'].keys():
1309 for fontstyle in [u'bold', u'oblique', u'boldoblique']:
1310 self.valid_options[u'headfootfont'][fontname + u'-' + fontstyle] = u'%s (%s)' % (self.valid_options[u'headfootfont'][fontname], self._(fontstyle),)
1311 # Set possible font sizes.
1312 self._set_fontsize(u'headfootsize', 6, 24, 5)
1313 self._set_fontsize(u'fontsize', 4, 24, 5)
1314 self._set_fontsize(u'fontspacing', 1, 3, 1)
1315
1316 # Set translated name of table of contents as default.
1317 self.default_values[u'toctitle'] = self._(u'Contents')
1318
1319 self.default_values[u'titletext'] = self.pagename
1320 self.default_values[u'extra-titledocnumber'] = u'%d' % self.request.page.get_rev()[1]
1321 page_editor = self.request.page.lastEditInfo().get(u'editor', u'')
1322 self.default_values[u'extra-titleauthor'] = wikiutil.escape(getEditorName(self.request))
1323
1324 # Make sure we create date and time strings in right format.
1325 if self.request.current_lang:
1326 self.default_values[u'language'] = self.request.current_lang
1327 elif self.request.page.language:
1328 self.default_values[u'language'] = self.request.page.language
1329 else:
1330 #self.cfg.language_default or "en"
1331 self.default_values[u'language'] = self.make_isolang(self.cfg.__dict__.get(u'default_language', u'en'))
1332
1333 self.values = {}
1334
1335 # If the configuration variable 'createpdfdocument_validoptions' exists we update our
1336 # self.valid_options dict with these values.
1337 if getattr (self.request.cfg, u'createpdfdocument_validoptions', None):
1338 self.valid_options.update (self.request.cfg.createpdfdocument_validoptions)
1339
1340 # If the configuration variable 'createpdfdocument_defaultvalues' exists we update our
1341 # self.default_values dict with these values.
1342 if getattr (self.request.cfg, u'createpdfdocument_defaultvalues', None):
1343 for key, value in self.request.cfg.createpdfdocument_defaultvalues.items():
1344 self.default_values[key] = value
1345
1346 # Scan page to extract default values.
1347 self.set_page_default_values()
1348
1349 # Create a PDF document direct without any user iteraction from default and page settings.
1350 if self.form.has_key(u'generate'):
1351 self.set_page_values()
1352 self.update_values(useform=False)
1353 return self.do_generate()
1354
1355 # Create a PDF document from form settings.
1356 if self.form.has_key(u'generate_from_form') or self.form.has_key(u'preview'):
1357 self.update_values()
1358 return self.do_generate()
1359
1360 if self.form.has_key(u'remember'):
1361 self.update_values()
1362 return self.do_remember()
1363
1364 self.set_page_values()
1365 self.update_values(useform=False)
1366 # Backward compatiblity with MoinMoin 1.5.
1367 if Page.send_page.func_code.co_varnames[1] == 'request':
1368 return self.request.page.send_page(self.request, msg=self.makeform())
1369 else:
1370 return self.request.page.send_page(msg=self.makeform())
1371
1372 def update_values (self, useform=True):
1373 """Preset values with they form values or defaults."""
1374 for key, default in self.default_values.items():
1375 # Modify value only if not already set.
1376 if not key in self.values:
1377 # If the form does not contain the value (e.g. for checkboxes) set the
1378 # default value (e.g. for checkboxes unset by default).
1379 if not key in self.form:
1380 # Special processing for checkboxes in forms. If the key does not exists
1381 # within the form it is not checked.
1382 if key in self.form_checkbox and useform:
1383 self.values[key] = u'unchecked'
1384 elif useform:
1385 # Edit fields are missing if they are empty.
1386 self.values[key] = u''
1387 else:
1388 self.values[key] = default
1389 else:
1390 self.values[key] = self.form[key][0]
1391 # Check if revision is an integer value.
1392 try:
1393 self.values[u'rev'] = int(self.values.get(u'rev', self.request.page.rev))
1394 except:
1395 self.values[u'rev'] = self.request.page.rev
1396 # Check if page revision exists.
1397 (pagefname, realrev, exists) = self.request.page.get_rev(rev=self.values[u'rev'])
1398 if exists:
1399 self.values[u'rev'] = realrev
1400 else:
1401 # Determine latest revision number.
1402 (pagefname, self.values[u'rev'], exists) = self.request.page.get_rev()
1403 # Check valid value range.
1404 try:
1405 self.values[u'browserwidth'] = int(self.values[u'browserwidth'])
1406 if self.values[u'browserwidth'] < 400 or self.values[u'browserwidth'] > 1200:
1407 self.values[u'browserwidth'] = self.default_values[u'browserwidth']
1408 except:
1409 self.values[u'browserwidth'] = self.default_values[u'browserwidth']
1410 # We need a string.
1411 self.values[u'browserwidth'] = u'%s' % self.values[u'browserwidth']
1412
1413 def do_generate(self):
1414 """Create PDF document."""
1415 # Generate the HTML page using MoinMoin wiki engine.
1416 html = self.get_html()
1417 if html:
1418 if self.form.has_key('preview'):
1419 self.request.http_headers()
1420 self.request.write(html)
1421 else:
1422 pdfdata = self.html2pdf(html)
1423 if pdfdata:
1424 # Send as application/pdf the generated file by HTMLDOC
1425 self.send_pdf(pdfdata)
1426
1427 # MoinMoin1.6: send_closing_html() has to be called explicit.
1428 # MoinMoin1.5: raise MoinMoinNoFooter exception to forbit creation of HTML footer.
1429 if moinmoin_release[:3] == u'1.5':
1430 from MoinMoin.util import MoinMoinNoFooter
1431 raise MoinMoinNoFooter
1432
1433 def do_remember(self):
1434 """Create a message containing information about how to save the form values for future reuse."""
1435 save = u''
1436 for key, value in self.values.items():
1437 if key in [u'user-password', u'owner-password', u'rev', u'debug']:
1438 continue
1439 if key in self.default_values and value == self.default_values[key]:
1440 continue
1441 save += u'##pdf %s %s' % (key, value,)
1442 if self.debug:
1443 if key in self.default_values:
1444 save += u' <-- default value is "%s" (without quotes)' % self.default_values[key]
1445 else:
1446 save += u' <-- keyword missing in defaults'
1447 save += u'\n'
1448 if save:
1449 msg = self._(u'Add follwing lines at the beginning of your page:') + u'<br/><pre>' + save + u'</pre>'
1450 else:
1451 msg = self._(u'All values correspond to they default. Nothing have to be saved.')
1452 # Backward compatiblity with MoinMoin 1.5.
1453 if Page.send_page.func_code.co_varnames[1] == "request":
1454 return self.request.page.send_page(self.request, msg)
1455 else:
1456 return self.request.page.send_page(msg)
1457
1458 def send_pdf (self, data):
1459 """Send PDF file to HTTP server."""
1460 filename = self.pagename.replace (u'/', u'-') + u'-v' + str(self.values[u'rev']) + u'.pdf'
1461
1462 # Send HTTP header.
1463 self.request.http_headers([
1464 'Content-Type: %s' % self.contenttype,
1465 'Content-Length: %d' % len(data),
1466 # TODO: fix the encoding here, plain 8 bit is not allowed
1467 # according to the RFCs There is no solution that is
1468 # compatible to IE except stripping non-ascii chars
1469 'Content-Disposition: inline; filename="%s"' % filename.encode(config.charset),
1470 ])
1471
1472 # Send binary data.
1473 sio = StringIO.StringIO(data)
1474 shutil.copyfileobj(sio, self.request, 8192)
1475
1476 def get_html (self):
1477 """Generate the HTML body of this page."""
1478 # Save page as HTML.
1479 newreq = RedirectOutputRequest(self.request)
1480 # Do not add edit information.
1481 # Add extra meta tags.
1482 orig_html_head = self.request.cfg.html_head
1483 self.request.cfg.html_head = self.request.cfg.html_head + u"""
1484 <meta name="docnumber" content="%s">
1485 <meta name="author" content="%s">
1486 <meta name="copyright" content="%s">
1487 """ % (wikiutil.escape(self.values['extra-titledocnumber']), wikiutil.escape(self.values['extra-titleauthor']), wikiutil.escape(self.values['extra-titlecopyright']),)
1488 (html, errmsg) = newreq.run(rev = self.values.get(u'rev', None))
1489 # Restore original HTML head configuration.
1490 self.request.cfg.html_head = orig_html_head
1491 if html:
1492 html = self.fixhtmlstr(html)
1493 # Make URLs absolute.
1494 # FIXME: Until MoinMoin is not XHTML compilant we can not use a XML parser
1495 # (e.g. expat) to transform the HTML document. In the meantime we try to
1496 # achive the same with regular expressions subtitution.
1497 base = self.request.getQualifiedURL()
1498 for htmlref in [u'src', u'href']:
1499 reurlref = r'(%s=[\'"])(/[^\'"]*)[\'"]' % (htmlref,)
1500 urlref = re.compile (reurlref, re.I)
1501 for match in urlref.finditer(html):
1502 foundref = match.groups()
1503 html = html.replace (foundref[0] + foundref[1], foundref[0] + base + foundref[1])
1504
1505 # Rename title of the document.
1506 titletext_html = self.fixhtmlstr(wikiutil.escape(self.values['titletext']))
1507 html = re.compile(r'<title>[^<]+</title>').sub(u'<title>%s</title>' % titletext_html, html)
1508
1509 if self.values['pageinfo'] == u'unchecked':
1510 # Remove pageinfo by regex. There is no standard way to do that yet.
1511 # Read the comment in ThemeBase.shouldShowPageinfo().
1512 html = re.compile(r'<p[^>]+id="pageinfo".*</p>').sub(u'', html)
1513
1514 # HTMLDOC workarround: Add borders to tables. HTMLDOC assume border="0" if not defined.
1515 html = re.compile(r'<table>').sub(u'<table border="1" cellpadding="5">', html)
1516
1517 # Display line numbers for code blocks without ·.
1518 if self.values[u'extra-dynamiccodeblock'] == u'checked':
1519 if self.values[u'extra-codeblocklinenumbers'] == u'checked':
1520 codeblocknr = re.compile(r'<span +class="LineNumber">([^<]+)</span>', re.IGNORECASE)
1521 for match in codeblocknr.finditer(html):
1522 newlinenr = u'<font color="%s">%s</font>' % (self.values[u'linkcolor'], match.group(1).replace(u' ', u' '),)
1523 html = html.replace(match.group(0), newlinenr, 1)
1524 else:
1525 html = re.compile(r'<span +class="LineNumber">[^<]+</span>', re.IGNORECASE).sub(u'', html)
1526
1527 # HTMLDOC: Does not support <span> so we remove them.
1528 for spanmatch in [r'<span[^>]*>', r'</span>']:
1529 html = re.compile(spanmatch).sub(u'', html)
1530
1531 # HTMLDOC: Does not support JavaScript
1532 html = re.compile(r'<script type="text/javascript".*?</script>', re.IGNORECASE | re.DOTALL).sub(u'', html)
1533
1534 # HTMLDOC does not support stylesheets.
1535 html = re.compile(r'<link rel="stylesheet".*?>', re.IGNORECASE | re.DOTALL).sub(u'', html)
1536
1537 # Remove page location added by &action=print.
1538 html = re.compile(r'<ul id="pagelocation">.*?</ul>', re.IGNORECASE | re.DOTALL).sub(u'', html)
1539
1540 # HTMLDOC workarround: There is no CSS support in HTMLDOC.
1541 tablecolor = re.compile(r'<td.*?background-color: (#......).*?>')
1542 for match in tablecolor.finditer(html):
1543 html = html.replace(match.group(0), u'<td bgcolor="%s">' % match.group(1), 1)
1544
1545 # HTMLDOC workarround: Handle <pre> sections over page boundries.
1546 if self.values[u'extra-dynamiccodeblock'] == u'checked':
1547 multiplespaces = re.compile(r'( {2,})')
1548 for regexstr in [r'(<pre>)(.*?)(</pre>)', r'(<div class="codearea".*?>.*<pre.*?>)(.*?)(</pre>.*?</div>)']:
1549 codesections = re.compile(regexstr, re.IGNORECASE | re.DOTALL)
1550 for match in codesections.finditer(html):
1551 foundref = match.groups()
1552 presection = foundref[1]
1553 # Search for multiple spaces and replace them by · except the last space.
1554 for spaces in multiplespaces.finditer(presection):
1555 newspaces = u'·' * (len(spaces.group(1)) - 1) + u' '
1556 presection = presection.replace (spaces.group(1), newspaces, 1)
1557 # Go through lines and add a ¶ sign at the end of eatch line.
1558 newprelines = []
1559 prelines = presection.split(u"\n")
1560 if len(prelines) > 1:
1561 # For multiple lines we remove the last one.
1562 for preline in prelines[:-1]:
1563 preline = preline + u'¶<br />'
1564 newprelines.append(preline)
1565 else:
1566 newprelines = prelines
1567 # Create a table arround an multi-line block.
1568 if newprelines:
1569 tablestart = u'<table border="1" bgcolor="#F3F5F7" cellpadding="5"><tr><td>'
1570 tableend = u'</td></tr></table><br />'
1571 else:
1572 newprelines.append(preline)
1573 tablestart = u''
1574 tableend = u''
1575 # Replace the <pre> block with new dynamic text.
1576 html = html.replace(u''.join(foundref), u'%s<font face="Courier,Monospace">%s</font>%s' % (tablestart, u"\n".join(newprelines), tableend,), 1)
1577 else:
1578 self.error_msg(self._(u'Could not redirect HTML output for further processing:') + errmsg)
1579 return html
1580
1581 def make_isolang (self, language):
1582 return language + u'_' + language.upper()
1583
1584 def html2pdf(self, html):
1585 """Create a PDF document based on the current parameters."""
1586 # Set environment variables for HTMLDOC
1587 os.environ['LANG'] = self.values[u'language']
1588 os.environ['HTMLDOC_NOCGI'] = '1'
1589 # Determine UID to access ACL protected sites too (mandatory to download attached images).
1590 htmldocopts = [self.default_values['htmldoc_cmd'], "--cookies", "MOIN_ID=" + self.request.user.id, u'--no-duplex']
1591
1592 for key in [u'header', u'footer', u'tocheader', u'tocfooter']:
1593 self.values[key] = self.values.get(key + u'left', u'.') + self.values.get(key + u'middle', u'.') + self.values.get(key + u'right', u'.')
1594
1595 permissions = []
1596 for opt, value in self.values.items():
1597 # Skip alle non-HTMLDOC configuration parameters.
1598 if opt in [u'language', u'debug', u'rev', u'titletext', 'pageinfo', 'htmldoc_cmd'] or opt[:6] == u'extra-':
1599 continue
1600
1601 # Skip options without values.
1602 value = value.strip()
1603 if not value:
1604 continue
1605
1606 # Skip options for header/footer configuration which differenciate between position (e.g. footerright or tocheadermiddle)
1607 if opt[:6] in [u'header', u'footer'] and opt[6:] or opt[:9] in [u'tocheader', u'tocfooter'] and opt[9:]:
1608 continue
1609
1610 if opt == u'titlefileimage':
1611 # Check if we have a --titlefile or --titleimage option.
1612 lower_value = value.lower()
1613 dotpos = lower_value.rfind(u'.')
1614 if lower_value[dotpos:] in [u'.bmp', u'.gif', u'.jpg', u'.jpeg', u'.png']:
1615 opt = u'titleimage'
1616 else:
1617 opt = u'titlefile'
1618 value = attachment_fsname(value, self.request.page, self.request)
1619 elif opt == u'bodyimage':
1620 value = attachment_fsname(value, self.request.page, self.request)
1621
1622 if opt in [u'style']:
1623 htmldocopts += [u'--' + value]
1624 elif opt in self.form_checkbox:
1625 if value == u'checked':
1626 if opt[:10] == u'permission':
1627 permissions += [opt[10:]]
1628 # Reverse meaning of 'no-' options.
1629 elif opt[:3] != u'no-':
1630 htmldocopts += [u'--' + opt]
1631 elif opt[:3] == u'no-':
1632 htmldocopts += [u'--' + opt]
1633 elif opt[:6] == u'margin':
1634 htmldocopts += [u'--' + opt[6:], value]
1635 else:
1636 htmldocopts += [u'--' + opt, value]
1637 if permissions:
1638 htmldocopts += [u'--permission', u','.join (permissions)]
1639 htmldocopts += [u'-']
1640 # Do not forget to escape all spaces!
1641 eschtmldocopts = [shell_quote(arg) for arg in htmldocopts]
1642 cmdstr = u' '.join(eschtmldocopts)
1643 errmsg = None
1644
1645 pdf = None
1646 os.environ['HTMLDOC_NOCGI'] = '1'
1647 if self.debug:
1648 self.request.http_headers()
1649 errmsg = self._(u'HTMLDOC command:') + u'<pre>' + wikiutil.escape(cmdstr) + u'</pre>'
1650 cmdstr = self.default_values['htmldoc_cmd'] + u' --help'
1651 (htmldoc_help, htmldoc_err) = pipeCommand(cmdstr)
1652 errmsg += u'<p>Execute <tt>%s</tt><br /><pre>%s</pre></p>' % (wikiutil.escape(cmdstr), wikiutil.escape(htmldoc_help),)
1653 if 'env' in self.request.__dict__:
1654 reqenv = u'%s' % wikiutil.escape(self.request.env)
1655 else:
1656 reqenv = u'None'
1657 errmsg += u'<p>Python release %s<br />MoinMoin release <tt>%s</tt><br />CreatePdfDocument release <tt>%s</tt><br />self.request = <tt>%s</tt><br />self.request.env = <tt>%s</tt><br />os.environ = <tt>%s</tt></p>' % (wikiutil.escape(sys.version), wikiutil.escape(moinmoin_release), wikiutil.escape(__version__), wikiutil.escape(type(self.request)), wikiutil.escape(reqenv), wikiutil.escape(u"%s" % os.environ),)
1658 errmsg += u'<hr/><hr/><hr/>'
1659 else:
1660 (pdf, htmldocmsg) = pipeCommand(cmdstr, html)
1661
1662 # Check for error message on STDOUT.
1663 if pdf[:8] == u'HTMLDOC ':
1664 htmldocmsg += pdf
1665 pdf = None
1666
1667 if htmldocmsg:
1668 errmsg = self._(u'Command:') + u'<pre>' + wikiutil.escape(cmdstr) + u'</pre>' + self._('returned:') + u'<pre>' + \
1669 wikiutil.escape(htmldocmsg).replace(u'\n', u'<br/>') + u'</pre>'
1670
1671 # As it is difficult to get the htmldoc return code, we check for
1672 # error by checking the produced pdf length
1673 if not pdf and errmsg:
1674 if self.debug:
1675 self.request.write(u'<html><body>%s</body></hftml>' % errmsg)
1676 self.request.write(html)
1677 else:
1678 self.error_msg(errmsg)
1679 elif pdf[:4] != '%PDF':
1680 self.error_msg(self._(u'Invalid PDF document generated') + wikiutil.escape(pdf[:80]))
1681 pdf = None
1682
1683 return pdf
1684
1685 def _set_fontsize(self, key, min, max, smallstep):
1686 self.valid_options[key] = {}
1687 for fontsize_big in range(min, max):
1688 for fontsize_step in range(0, 10, smallstep):
1689 fontsize = u'%d.%d' % (fontsize_big, fontsize_step,)
1690 self.valid_options[key][fontsize] = self._(fontsize)
1691 self.valid_options[key][u'%d.0' % max] = self._(u'%d.0' % max)
1692
1693
1694 def execute (pagename, request):
1695 try:
1696 CreatePdfDocument().run (pagename = pagename, request = request)
1697 except:
1698 raise
Attached Files
To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.You are not allowed to attach a file to this page.