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

You are not allowed to attach a file to this page.