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

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.