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