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