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&nbsp;
 946             <input type="checkbox" name="title" value="checked" %(title)s />%(label_titlepage)s<br />
 947             %(label_compression)s&nbsp:&nbsp;%(select_compression)s&nbsp;
 948             %(label_jpeg)s&nbsp;%(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&nbsp;<br /><nobr>%(label_usersize)s&nbsp;<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>&nbsp;</td>
 967         <td colspan="2"><input type="checkbox" name="duplex" value="checked" %(duplex)s />&nbsp;%(label_duplex)s&nbsp;
 968             <input type="checkbox" name="landscape" value="checked" %(landscape)s />&nbsp;%(label_landscape)s</td>
 969     </tr>
 970     <tr>
 971         <td class="label"><label>%(label_margin)s</label></td>
 972         <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>
 973             <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>
 974             <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>
 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>&nbsp;</td>
 996         <td><input type="checkbox" name="numbered" value="checked" %(numbered)s />&nbsp;%(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 />&nbsp;%(label_permissionprint)s</nobr>&nbsp;
1119             <nobr><input type="checkbox" name="permissionmodify" value="checked" %(permissionmodify)s />&nbsp;%(label_permissionmodify)s</nobr><br />
1120             <nobr><input type="checkbox" name="permissioncopy" value="checked" %(permissioncopy)s />&nbsp;%(label_permissioncopy)s</nobr>&nbsp;
1121             <nobr><input type="checkbox" name="permissionannotate" value="checked" %(permissionannotate)s />&nbsp;%(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" />&nbsp;
1165 <input type="submit" name="preview" value="%(button_preview)s" />&nbsp;
1166 <input type="submit" name="remember" value="%(button_remember)s" />&nbsp;
1167 <input type="submit" name="cancel" value="%(button_cancel)s" />&nbsp;
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 &middot;.
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'&nbsp;'),)
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 &middot; except the last space.
1554                         for spaces in multiplespaces.finditer(presection):
1555                             newspaces = u'&middot;' * (len(spaces.group(1)) - 1) + u' '
1556                             presection = presection.replace (spaces.group(1), newspaces, 1)
1557                         # Go through lines and add a &para; 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'&para;<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.
  • [get | view] (2011-04-14 07:28:03, 4.7 KB) [[attachment:CreateNewPage.py]]
  • [get | view] (2011-04-14 07:26:24, 4.2 KB) [[attachment:CreateNewPage1.6.py]]
  • [get | view] (2006-09-10 21:29:29, 40.4 KB) [[attachment:CreatePdfDocument2_0_3.py]]
  • [get | view] (2006-09-12 06:05:06, 40.5 KB) [[attachment:CreatePdfDocument2_0_4.py]]
  • [get | view] (2006-09-12 12:00:09, 40.6 KB) [[attachment:CreatePdfDocument2_0_5.py]]
  • [get | view] (2006-11-14 21:56:11, 43.5 KB) [[attachment:CreatePdfDocument2_0_6.py]]
  • [get | view] (2006-11-15 17:00:47, 43.8 KB) [[attachment:CreatePdfDocument2_0_7.py]]
  • [get | view] (2006-11-16 22:06:18, 43.8 KB) [[attachment:CreatePdfDocument2_0_8.py]]
  • [get | view] (2006-12-17 15:54:21, 43.6 KB) [[attachment:CreatePdfDocument2_0_9.py]]
  • [get | view] (2007-08-20 09:10:23, 67.2 KB) [[attachment:CreatePdfDocument2_1_0.py]]
  • [get | view] (2007-08-21 07:39:49, 67.1 KB) [[attachment:CreatePdfDocument2_1_1.py]]
  • [get | view] (2007-09-11 19:16:37, 67.3 KB) [[attachment:CreatePdfDocument2_1_2.py]]
  • [get | view] (2007-09-18 20:17:58, 68.1 KB) [[attachment:CreatePdfDocument2_1_3.py]]
  • [get | view] (2007-09-21 13:32:54, 71.1 KB) [[attachment:CreatePdfDocument2_1_4.py]]
  • [get | view] (2007-09-23 20:56:30, 73.4 KB) [[attachment:CreatePdfDocument2_1_5.py]]
  • [get | view] (2007-09-25 20:54:48, 74.5 KB) [[attachment:CreatePdfDocument2_2_0.py]]
  • [get | view] (2008-06-23 21:08:49, 77.0 KB) [[attachment:CreatePdfDocument2_3_0.py]]
  • [get | view] (2008-06-26 19:25:07, 81.0 KB) [[attachment:CreatePdfDocument2_3_1.py]]
  • [get | view] (2008-07-06 05:50:38, 83.1 KB) [[attachment:CreatePdfDocument2_3_2.py]]
  • [get | view] (2008-07-09 17:42:02, 83.3 KB) [[attachment:CreatePdfDocument2_3_3.py]]
  • [get | view] (2008-09-07 11:11:01, 83.5 KB) [[attachment:CreatePdfDocument2_3_4.py]]
  • [get | view] (2009-01-11 15:53:09, 84.3 KB) [[attachment:CreatePdfDocument2_3_5.py]]
  • [get | view] (2009-02-16 06:52:06, 84.2 KB) [[attachment:CreatePdfDocument2_3_6.py]]
  • [get | view] (2010-01-29 11:53:21, 82.8 KB) [[attachment:CreatePdfDocument2_4_0.py]]
  • [get | view] (2010-01-31 14:10:03, 84.6 KB) [[attachment:CreatePdfDocument2_4_1.py]]
  • [get | view] (2010-09-18 16:23:23, 85.6 KB) [[attachment:CreatePdfDocument2_4_2.py]]
  • [get | view] (2006-06-16 20:56:53, 4.9 KB) [[attachment:FlashManager.py-1.5.3-1]]
  • [get | view] (2003-12-07 18:15:53, 3.9 KB) [[attachment:HTML2MoinMoin.py]]
  • [get | view] (2005-10-16 08:24:35, 4.9 KB) [[attachment:HelpOn-1.3.5-4.py]]
  • [get | view] (2006-02-03 19:21:04, 4.9 KB) [[attachment:HelpOn-1.5.1-5.py]]
  • [get | view] (2006-07-04 10:45:22, 4.8 KB) [[attachment:HelpOn-1.5.4-6.py]]
  • [get | view] (2006-07-04 22:39:14, 4.8 KB) [[attachment:HelpOn-1.6.0-7.py]]
  • [get | view] (2006-07-06 13:50:17, 4.0 KB) [[attachment:HelpOn-1.6.0-8.py]]
  • [get | view] (2008-01-10 17:43:24, 4.8 KB) [[attachment:HelpOn-1.6.0-9.py]]
  • [get | view] (2008-08-19 14:44:54, 5.0 KB) [[attachment:HelpOn-1.7.1-10.py]]
  • [get | view] (2005-02-20 18:28:34, 10.8 KB) [[attachment:IRSS.py]]
  • [get | view] (2005-03-09 22:46:23, 2.9 KB) [[attachment:ImportHtml-1.2.py]]
  • [get | view] (2003-12-07 18:15:53, 2.8 KB) [[attachment:ImportHtml.py]]
  • [get | view] (2003-12-07 18:15:53, 1.8 KB) [[attachment:IrcChat.py]]
  • [get | view] (2008-06-09 11:27:20, 4.4 KB) [[attachment:MoinCrypt.py]]
  • [get | view] (2010-11-29 12:08:27, 7.5 KB) [[attachment:PageActions.py]]
  • [get | view] (2006-08-07 15:12:19, 0.5 KB) [[attachment:PermanentLink.py]]
  • [get | view] (2003-12-07 18:15:53, 6.3 KB) [[attachment:PhoneDial.py]]
  • [get | view] (2005-04-17 14:21:47, 3.6 KB) [[attachment:RecommendPage-1.3.4-1.py]]
  • [get | view] (2005-04-19 18:21:52, 5.5 KB) [[attachment:RecommendPage-1.3.4-2.py]]
  • [get | view] (2005-05-02 19:53:09, 5.6 KB) [[attachment:RecommendPage-1.3.4-3.py]]
  • [get | view] (2005-09-03 07:33:35, 6.3 KB) [[attachment:RecommendPage-1.3.4-4.py]]
  • [get | view] (2005-09-05 17:44:03, 6.9 KB) [[attachment:RecommendPage-1.3.5-5.py]]
  • [get | view] (2005-09-07 16:42:26, 7.5 KB) [[attachment:RecommendPage-1.3.5-6.py]]
  • [get | view] (2005-09-08 16:06:28, 7.7 KB) [[attachment:RecommendPage-1.3.5-7.py]]
  • [get | view] (2005-11-01 11:31:51, 9.0 KB) [[attachment:RecommendPage-1.3.5-8.py]]
  • [get | view] (2006-02-03 19:40:51, 8.3 KB) [[attachment:RecommendPage-1.5.1-9.py]]
  • [get | view] (2008-01-11 09:14:35, 6.8 KB) [[attachment:RecommendPage-1.6.0-10.py]]
  • [get | view] (2008-08-19 14:44:59, 6.9 KB) [[attachment:RecommendPage-1.7.1-11.py]]
  • [get | view] (2008-06-09 11:27:40, 1.7 KB) [[attachment:ShowActions.py]]
  • [get | view] (2008-06-09 10:34:02, 5.3 KB) [[attachment:ShowDecrypted.py]]
  • [get | view] (2005-03-30 21:17:28, 7.7 KB) [[attachment:Slideshow.py]]
  • [get | view] (2004-02-02 20:48:31, 2.0 KB) [[attachment:SubscribeUser.py]]
  • [get | view] (2007-01-26 17:08:30, 2.2 KB) [[attachment:Subscribers-1.6.0.py]]
  • [get | view] (2003-12-07 18:15:53, 1.8 KB) [[attachment:Subscribers.py]]
  • [get | view] (2006-03-18 23:16:51, 0.8 KB) [[attachment:UserPreferences.py]]
  • [get | view] (2004-01-05 09:56:25, 8.1 KB) [[attachment:VisualSiteMap.py]]
  • [get | view] (2015-08-30 21:04:23, 11.1 KB) [[attachment:VisualSiteMap_1.10.py]]
  • [get | view] (2004-10-08 10:59:16, 9.3 KB) [[attachment:VisualSiteMap_1.2.py]]
  • [get | view] (2005-03-16 01:30:09, 9.8 KB) [[attachment:VisualSiteMap_1.3.py]]
  • [get | view] (2014-08-19 01:34:10, 10.8 KB) [[attachment:VisualSiteMap_1.9.py]]
  • [get | view] (2007-08-18 18:52:55, 1.0 KB) [[attachment:backlink.py]]
  • [get | view] (2007-03-15 05:53:49, 23.5 KB) [[attachment:findandreplace0.1Beta.py]]
  • [get | view] (2005-03-27 20:32:10, 3.6 KB) [[attachment:gallery2image-1.3.3-1.py]]
  • [get | view] (2005-08-03 20:14:56, 4.0 KB) [[attachment:gallery2image-1.3.3-2.py]]
  • [get | view] (2005-11-13 18:10:26, 20.7 KB) [[attachment:gallery2image-1.3.5-10.py]]
  • [get | view] (2005-11-25 22:03:50, 20.8 KB) [[attachment:gallery2image-1.3.5-11.py]]
  • [get | view] (2005-08-08 17:23:43, 8.4 KB) [[attachment:gallery2image-1.3.5-4.py]]
  • [get | view] (2005-08-13 15:15:45, 13.7 KB) [[attachment:gallery2image-1.3.5-5.py]]
  • [get | view] (2005-08-31 22:05:22, 15.5 KB) [[attachment:gallery2image-1.3.5-6.py]]
  • [get | view] (2005-10-29 20:23:50, 15.9 KB) [[attachment:gallery2image-1.3.5-8.py]]
  • [get | view] (2005-11-01 11:31:24, 17.6 KB) [[attachment:gallery2image-1.3.5-9.py]]
  • [get | view] (2006-01-27 20:52:32, 20.9 KB) [[attachment:gallery2image-1.5.1-12.py]]
  • [get | view] (2006-08-06 09:01:01, 22.1 KB) [[attachment:gallery2image-1.5.4-13.py]]
  • [get | view] (2006-08-11 18:21:40, 22.2 KB) [[attachment:gallery2image-1.5.4-14.py]]
  • [get | view] (2006-11-16 20:23:27, 22.6 KB) [[attachment:gallery2image-1.5.6-16.py]]
  • [get | view] (2006-08-11 18:30:22, 22.2 KB) [[attachment:gallery2image-1.6.0-15.py]]
  • [get | view] (2008-02-06 10:13:45, 22.3 KB) [[attachment:gallery2image-1.6.0-16.py]]
  • [get | view] (2008-05-20 15:51:09, 22.4 KB) [[attachment:gallery2image-1.6.3-17.py]]
  • [get | view] (2006-09-06 06:19:48, 1.3 KB) [[attachment:getmmap.py]]
  • [get | view] (2004-07-18 09:48:00, 1.5 KB) [[attachment:localnames.py]]
  • [get | view] (2005-03-25 15:02:31, 2.6 KB) [[attachment:newpageonly.py]]
  • [get | view] (2005-03-30 09:02:00, 3.5 KB) [[attachment:newpageonly_20050330.py]]
  • [get | view] (2006-06-06 19:12:27, 9.7 KB) [[attachment:pdf.py]]
  • [get | view] (2006-08-30 10:51:51, 36.0 KB) [[attachment:pdf2_0_0.py]]
  • [get | view] (2006-08-30 13:57:36, 36.5 KB) [[attachment:pdf2_0_1.py]]
  • [get | view] (2006-02-04 04:25:29, 1.0 KB) [[attachment:sisterindex.py]]
  • [get | view] (2004-10-28 07:33:10, 0.7 KB) [[attachment:xml.py]]
 All files | Selected Files: delete move to page copy to page

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