Attachment 'CreatePdfDocument2_1_3.py'

Download

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