Attachment 'text_word.py'
Download 1 # -*- coding: iso-8859-1 -*-
2 """
3 MoinMoin - "text/word" Formatter
4
5 Experimental by RS, derived from text_html.py
6
7 Create MS Word Document as 'side effect'
8
9 ORS modifications
10 =================
11 - 13.01.04 RS upgrade to 1.1.
12 - 20.01.04 RS fatal errors handling
13 - 22.01.04 RS print replaced by self.request.write
14 - 28.01.05 RS fixed img handling (path problem)
15 - 27.09.05 RS upgrade to 1.3.5, old 1.1 code removed
16
17 @todo: Handle distorted tables (with spanning cells)
18 """
19
20 # Imports
21 import cgi, string, sys, time, os, re, copy,traceback,urllib
22 from MoinMoin.formatter.base import FormatterBase
23 from MoinMoin import wikiutil, config, user,webapi, i18n
24
25 from MoinMoin.Page import Page
26 #RS Word
27 import win32com.client, win32com.client.dynamic
28 vbTrue=-1
29 vbFalse=0
30 #RS end
31
32 DOC_SUFFIX = ".doc" # perhaps put this in config.py as html_suffix?
33
34 #############################################################################
35 ### HTML Formatter
36 #############################################################################
37
38 _debug=1
39
40 class Formatter(FormatterBase):
41 """
42 Send HTML data.
43 """
44
45 # hardspace = ' '
46 hardspace = ' '
47
48 def __init__(self, request, **kw):
49 if _debug:
50 traceback.print_stack(limit=1,file=sys.stdout)
51 apply(FormatterBase.__init__, (self, request), kw)
52 #RS additional property "mimetype"
53 self.mimetype="text/word"
54 sys.stderr.write("\nThis is the Word Formatter....")
55 #RS end
56 self.dead=0
57 self.store_text=0 # store text in self._text instead of emitting it
58 self.recordedtext=""
59 self.recordedcursor=0
60 # inline tags stack. When an inline tag is called, it goes into
61 # the stack. When a block element starts, all inline tags in
62 # the stack are closed.
63 self._inlineStack = []
64
65 self._in_li = 0
66 self._first_li = 0
67 self._first_tr = 0
68 self._first_td = 0
69 self._table_start=0
70 self._ignore_next_paragraph=0
71 self.list_levels={'ul':0,'ol':0,'dl':0,'table':0,'all':0}
72 self.last_indent_type=''
73 self._in_code = 0
74 self._base_depth = 0
75 self._in_code_area = 0
76 self._in_code_line = 0
77 self._code_area_num = 0
78 self._code_area_js = 0
79 self._code_area_state = ['', 0, -1, -1, 0]
80 self._show_section_numbers = None
81 self._content_ids = []
82 self.pagelink_preclosed = False
83 self._is_included = kw.get('is_included',False)
84 self.request = request
85 self.cfg = request.cfg
86 # self.targetdir=kw.get('targetdir',config.data_dir)
87 self.targetdir=kw.get('targetdir',request.cfg.data_dir)
88
89 if not hasattr(request, '_fmt_hd_counters'):
90 request._fmt_hd_counters = []
91 self.document=None
92 self.doctemplate="D_ORS_Entwicklungsauftrag_v02.dot"
93 self.doctemplate="Normal.dot"
94 self.word_host = None
95 self.doccount=0
96 self.tt_start=0
97
98 def _reset_indents(self):
99 if _debug:
100 traceback.print_stack(limit=1,file=sys.stdout)
101 self._in_li = 0
102 self._first_li = 0
103 self._first_tr = 0
104 self._first_td = 0
105 self._table_start=0
106 self._ignore_next_paragraph=0
107 self.list_levels={'ul':0,'ol':0,'dl':0,'table':0,'all':0}
108 self.last_indent_type=''
109
110
111 def FatalEnd(self):
112 """
113 make sure we do not leave any ActiveX corpses behind if errors occur
114 """
115 if _debug:
116 traceback.print_stack(limit=1,file=sys.stdout)
117 try:
118 if self.document is not None:
119 self.document.Close(-1)
120 if self.word_host is not None:
121 self.word_host.Quit()
122 self.document=None
123 self.word_host=None
124 except:
125 pass
126 # raise
127 self.dead=1
128
129 def _save(self):
130 if _debug:
131 traceback.print_stack(limit=1,file=sys.stdout)
132 #RS fatal error handling
133 if self.dead==1:
134 return
135 #RS end
136 if self.document!=None:
137 self.document.Save()
138
139 # Primitive formatter functions #####################################
140
141 # all other methods should use these to format tags. This keeps the
142 # code clean and handle pathological cases like unclosed p and
143 # inline tags.
144
145 def langAttr(self, lang=None):
146 """ Return lang and dir attribute
147
148 Must be used on all block elements - div, p, table, etc.
149 @param lang: if defined, will return attributes for lang. if not
150 defined, will return attributes only if the current lang is
151 different from the content lang.
152 @rtype: dict
153 @return: language attributes
154 """
155 if not lang:
156 lang = self.request.current_lang
157 # Actions that generate content in user language should change
158 # the content lang from the default defined in cfg.
159 if lang == self.request.content_lang:
160 # lang is inherited from content div
161 return {}
162
163 attr = {'lang': lang, 'dir': i18n.getDirection(lang),}
164 return attr
165
166 def formatAttributes(self, attr=None):
167 """ Return formatted attributes string
168
169 @param attr: dict containing keys and values
170 @rtype: string ?
171 @return: formated attributes or empty string
172 """
173 if attr:
174 attr = [' %s="%s"' % (k, v) for k, v in attr.items()]
175 return ''.join(attr)
176 return ''
177
178 # TODO: use set when we require Python 2.3
179 # TODO: The list is not complete, add missing from dtd
180 #RS Word: use _blocks for all tags that can only be interpreted on close, i.e. text between open and close must be recorded
181 ## _blocks = 'p div pre table tr td ol ul dl li dt dd h1 h2 h3 h4 h5 h6 hr form'
182 _blocks = 'div pre dt dd h1 h2 h3 h4 h5 h6 form url pagelink'
183 #RS end
184 _blocks = dict(zip(_blocks.split(), [1] * len(_blocks)))
185
186 def open(self, tag, newline=False, attr=None):
187 """ Open a tag with optional attributes
188
189 @param tag: html tag, string
190 @param newline: render tag on a separate line
191 @param attr: dict with tag attributes
192 @rtype: string ?
193 @return: open tag with attributes
194 """
195 # if _debug:
196 # traceback.print_stack(limit=1,file=sys.stdout)
197 if tag in self._blocks:
198 # Block elements
199 #RS word
200 if _debug:
201 print "OPEN %s (recording)" % tag
202 # if self.document!=None:
203 # self.word_host.Selection.TypeText("OPEN %s (recording)" % tag)
204 self.store_text=1
205 self.recordedtext=""
206 if self.word_host:
207 self.recordedcursor=int(self.word_host.Selection.Range.End)
208 #RS end
209 result = []
210
211 # Add language attributes, but let caller overide the default
212 attributes = self.langAttr()
213 if attr:
214 attributes.update(attr)
215
216 # Format
217 attributes = self.formatAttributes(attributes)
218 result.append('<%s%s>' % (tag, attributes))
219 if newline:
220 if _debug:
221 print "OPEN with NEWLINE"
222 if self.document:
223 self.word_host.Selection.TypeParagraph()
224
225 result.append('\n')
226 return ''.join(result)
227 else:
228 # Inline elements
229 # Add to inlineStack
230 if _debug:
231 print "OPEN %s (inline)" % tag
232 # if self.document!=None:
233 # self.word_host.Selection.TypeText("OPEN %s (inline)" % tag)
234 self._inlineStack.append(tag)
235 # Format
236 return '<%s%s>' % (tag, self.formatAttributes(attr))
237
238 def close(self, tag, newline=False):
239 """ Close tag
240
241 @param tag: html tag, string
242 @rtype: string ?
243 @return: closing tag
244 """
245 # if _debug:
246 # traceback.print_stack(limit=1,file=sys.stdout)
247 if tag in self._blocks:
248 # Block elements
249 # Close all tags in inline stack
250 # Work on a copy, because close(inline) manipulate the stack
251 #RS word
252 if _debug:
253 try:
254 print 'CLOSE %s (recorded="%s", at %s)' % (tag,self.recordedtext,self.recordedcursor)
255 except:
256 print 'CLOSE %s (recorded=???, at %s)' % (tag,self.recordedcursor)
257
258 # if self.document!=None:
259 # self.word_host.Selection.TypeText("CLOSE %s (recorded)" % tag)
260 self.store_text=0
261 self.recordedtext=""
262 self.recordedcursor=0
263 #RS end
264 result = []
265 stack = self._inlineStack[:]
266 stack.reverse()
267 for inline in stack:
268 result.append(self.close(inline))
269 # Format with newline
270 if newline:
271 if _debug:
272 print "CLOSE with NEWLINE"
273 result.append('\n')
274 result.append('</%s>\n' % (tag))
275 return ''.join(result)
276 else:
277 # Inline elements
278 # Pull from stack, ignore order, that is not our problem.
279 # The code that calls us should keep correct calling order.
280 if _debug:
281 print "CLOSE %s (inline)" % tag
282 # if self.document!=None:
283 # self.word_host.Selection.TypeText("CLOSE %s (inline)" % tag)
284 if tag in self._inlineStack:
285 if _debug:
286 print "CLOSE %s (inline stack remove)" % tag
287 self._inlineStack.remove(tag)
288 return '</%s>' % tag
289
290 def startDocument(self, pagename):
291 if _debug:
292 traceback.print_stack(limit=1,file=sys.stdout)
293 sys.stderr.write("\nThis is the Word Formatter::startDocument....")
294 self.doccount+=1
295 if self.word_host==None:
296 try:
297 self.word_host = win32com.client.Dispatch("Word.Application") # open MS Word
298
299 except:
300 self.request.write( "#STARTDOC %s %s failed at Host Initialisation" % (self.doccount,pagename))
301 self.word_host=None
302 raise
303
304 try:
305 self.word_host.Visible=1
306 #Visible is essential, otherwise strange things may happen (Kill Bill!!!)
307 except:
308 self.request.write("#STARTDOC %s %s failed at Host Visible" % (self.doccount,pagename))
309 try:
310 self.request.write("#STARTDOC uses template dir %s" % str(self.word_host.Options.DefaultFilePath(win32com.client.constants.wdUserTemplatesPath)))
311 except:
312 raise
313 else:
314 self.request.write("\nMSWORD HOST already active!\n")
315 if self.document!=None:
316 self.request.write("ignore#STARTDOC %s %s" % (self.doccount,pagename))
317 return u"ignore#STARTDOC %s %s" % (self.doccount,pagename)
318 try:
319
320 ## self.document=self.word_host.Documents.Add(Template=self.doctemplate,Visible=vbFalse)
321 self.document=self.word_host.Documents.Add(Template=self.doctemplate,Visible=vbTrue)
322 #we only want the styles from the template, not the content
323 except:
324 self.FatalEnd()
325 self.request.write("#STARTDOC %s %s failed at Documents.Add(%s..." % (self.doccount,pagename,self.doctemplate))
326 raise
327
328 try:
329 self.document.Content.Delete()
330 self.wdCharacter=win32com.client.constants.wdCharacter
331 self.wdExtend=win32com.client.constants.wdExtend
332 self.ul_type=win32com.client.constants.wdListBullet
333 self.ol_type=win32com.client.constants.wdListOutlineNumbering
334 self.tt_style=win32com.client.constants.wdStyleHtmlTt
335 self.pre_style=win32com.client.constants.wdStyleHtmlPre
336 self.defchar_style=win32com.client.constants.wdStyleDefaultParagraphFont
337 self.defpara_style=win32com.client.constants.wdStyleNormal
338 self.wdWord9ListBehavior=win32com.client.constants.wdWord9ListBehavior
339 self.wdNumberGallery=win32com.client.constants.wdNumberGallery
340 self.wdListApplyToThisPointForward=win32com.client.constants.wdListApplyToThisPointForward
341
342 self.word_host.Selection.Style=self.defpara_style
343 self.normalstyle=self.word_host.Selection.Style
344 self.request.write("NORMSTYLE: %s" % self.normalstyle)
345 self._reset_indents()
346
347 file = wikiutil.quoteWikinameFS(pagename) + DOC_SUFFIX
348 filepath = os.path.abspath(os.path.join(self.targetdir, file))
349 self.document.SaveAs(filepath,0)
350 # self.request.write("#STARTDOC %s %s" % (self.doccount,pagename)
351 return u"#STARTDOC %s %s" % (self.doccount,pagename)
352 except:
353 self.FatalEnd()
354 self.request.write("#STARTDOC %s %s failed" % (self.doccount,pagename))
355 raise
356
357 def endDocument(self):
358 #RS fatal error handling
359 if _debug:
360 traceback.print_stack(limit=1,file=sys.stdout)
361 if self.dead==1:
362 return u""
363 #RS end
364 self.doccount-=1
365 if self.doccount==0:
366 try:
367 self.word_host.ActiveDocument.Fields.Update()
368 self.document.Close(-1)
369 self.word_host.Quit()
370 self.document=None
371 self.word_host=None
372 return u"#ENDDOC"
373 except:
374 return u"#ENDDOC failed"
375
376 return u"#ENDDOC %s" % self.doccount
377
378 def startContent(self, content_id='content', **kwargs):
379 """ Start page content div """
380 return ''
381 if _debug:
382 traceback.print_stack(limit=1,file=sys.stdout)
383 # Setup id
384 if content_id!='content':
385 aid = 'top_%s' % (content_id,)
386 else:
387 aid = 'top'
388 self._content_ids.append(content_id)
389 result = []
390 # Use the content language
391 attr = self.langAttr(self.request.content_lang)
392 attr['id'] = content_id
393 result.append(self.open('div', newline=1, attr=attr))
394 result.append(self.anchordef(aid))
395 return ''.join(result)
396
397 def endContent(self):
398 """ Close page content div """
399 return ''
400 if _debug:
401 traceback.print_stack(limit=1,file=sys.stdout)
402
403 # Setup id
404 try:
405 cid = self._content_ids.pop()
406 except:
407 cid = 'content'
408 if cid!='content':
409 aid = 'bottom_%s' % (cid,)
410 else:
411 aid = 'bottom'
412
413 result = []
414 result.append(self.anchordef(aid))
415 result.append(self.close('div', newline=1))
416 return ''.join(result)
417
418 def lang(self, on, lang_name):
419 """ Insert text with specific lang and direction.
420
421 Enclose within span tag if lang_name is different from
422 the current lang
423 """
424 tag = 'span'
425 if lang_name != self.request.current_lang:
426 # Enclose text in span using lang attributes
427 if on:
428 attr = self.langAttr(lang=lang_name)
429 ret=self.open(tag, attr=attr)
430 return ret
431 else:
432 if self.document!=None:
433 pass
434 #TODO RS word: text with language info?
435 ### self.document.XXXX
436 ret=self.close(tag)
437 return ret
438
439 # Direction did not change, no need for span
440 return ''
441
442
443 def sysmsg(self, on, **kw):
444 if _debug:
445 traceback.print_stack(limit=1,file=sys.stdout)
446 #RS fatal error handling
447 if self.dead==1:
448 return u""
449 #RS end
450 tag = 'div'
451 if on:
452 ret=self.open(tag, attr={'class': 'message'})
453 return ret
454 else:
455 text=self.recordedtext
456 if self.document!=None and text!=None:
457 self.document.Content.TypeText('#SYSMSG#'+text+'#')
458 ret=self.close(tag)
459 return ret
460
461
462 def pagelink(self, on, pagename='', page=None, **kw):
463 """ Link to a page.
464
465 formatter.text_python will use an optimized call with a page!=None
466 parameter. DO NOT USE THIS YOURSELF OR IT WILL BREAK.
467
468 See wikiutil.link_tag() for possible keyword parameters.
469 """
470 if _debug:
471 traceback.print_stack(limit=1,file=sys.stdout)
472 #RS fatal error handling
473 if self.dead==1:
474 return u""
475 #RS end
476 apply(FormatterBase.pagelink, (self, on, pagename, page), kw)
477 if page is None:
478 page = Page(self.request, pagename, formatter=self);
479 tag = 'pagelink'
480 url = wikiutil.quoteWikinameFS(pagename) + DOC_SUFFIX
481 if on:
482 ret=self.open(tag, attr={'class': 'pagelink'})
483 return ret
484 else:
485 text=self.recordedtext
486 if text==None:
487 text=pagename
488 if self.document!=None:
489 # if text!=None:
490 # self.word_host.Selection.TypeText('#PLINK#'+str(text)+'#')
491 # else:
492 # self.word_host.Selection.TypeText('#PLINK#'+str(pagename)+'#')
493 self.word_host.ActiveDocument.Hyperlinks.Add(\
494 Anchor=self.word_host.Selection.Range, Address=url,\
495 SubAddress="", ScreenTip="", TextToDisplay=text)
496 ret=self.close(tag)
497 return ret
498
499
500
501
502 def interwikilink(self, on, interwiki='', pagename='', **kw):
503 if not on: return '</a>'
504
505 wikitag, wikiurl, wikitail, wikitag_bad = wikiutil.resolve_wiki(self.request, '%s:%s' % (interwiki, pagename))
506 wikiurl = wikiutil.mapURL(self.request, wikiurl)
507
508 if wikitag == 'Self': # for own wiki, do simple links
509 import urllib
510 if wikitail.find('#')>-1:
511 wikitail, kw['anchor'] = wikitail.split('#', 1)
512 wikitail = urllib.unquote(wikitail)
513 return apply(self.pagelink, (on, wikiutil.AbsPageName(self.request, self.page.page_name, wikitail)), kw)
514 else: # return InterWiki hyperlink
515 href = wikiutil.join_wiki(wikiurl, wikitail)
516 if wikitag_bad:
517 html_class = 'badinterwiki'
518 else:
519 html_class = 'interwiki'
520
521 icon = ''
522 if self.request.user.show_fancy_links:
523 icon = self.request.theme.make_icon('interwiki', {'wikitag': wikitag})
524 return (self.url(1, href, title=wikitag, unescaped=0,
525 pretty_url=kw.get('pretty_url', 0), css = html_class) +
526 icon)
527 # unescaped=1 was changed to 0 to make interwiki links with pages with umlauts (or other non-ascii) work
528
529
530 #SYNC URL
531
532 def url(self, on, url=None, css=None, **kw):
533 """ render URL
534
535 @keyword type: "www" or "mailto" to use that icon
536 @keyword title: <a> title attribute
537 @keyword attrs: just include those <a> attrs "as is"
538 """
539 if _debug:
540 traceback.print_stack(limit=1,file=sys.stdout)
541 #RS fatal error handling
542 if self.dead==1:
543 return u""
544 #RS end
545 if url is not None:
546 url = wikiutil.mapURL(self.request, url)
547 title = kw.get('title', None)
548 attrs = kw.get('attrs', None)
549 #RS 1.1
550 target = kw.get('target', None)
551 #RS stop
552 str = ''
553 if css:
554 str = '%s class="%s"' % (str, css)
555 if title:
556 str = '%s title="%s"' % (str, title)
557 else:
558 title=""
559 if attrs:
560 str = '%s %s' % (str, attrs)
561
562 # create link
563 #TODO? insert link icons and other pretty stuff?
564 tag = 'url'
565 if on:
566 #store this for the close action
567 self.url_url=url
568 self.url_title=title
569
570 ret=self.open(tag, attr=attrs)
571 return ret
572 else:
573 text=self.recordedtext
574 url=self.url_url
575 title=self.url_title
576 if text is None:
577 text = url
578 if self.document!=None:
579 self.word_host.ActiveDocument.Hyperlinks.Add(\
580 Anchor=self.word_host.Selection.Range, Address=wikiutil.escape(url, 1),\
581 SubAddress="", ScreenTip=title, TextToDisplay=text)
582 ret=self.close(tag)
583 return ret
584
585
586 def _wordbookmark(self,name):
587 """
588 transform name into a valid Word bookmark name
589 """
590 return name.replace("-","_")
591
592 def anchordef(self, id):
593 if _debug:
594 traceback.print_stack(limit=1,file=sys.stdout)
595 #RS fatal error handling
596 if self.dead==1:
597 return u""
598 #RS end
599 if self.document!=None:
600 self.document.Bookmarks.Add(Range=self.word_host.Selection.Range,Name=self._wordbookmark(id))
601 return '<a id="%s"></a>\n' % (id, )
602
603 def anchorlink(self, on, name='', id = None):
604 if _debug:
605 traceback.print_stack(limit=1,file=sys.stdout)
606 ## if self.document!=None:
607 ## self.word_host.Selection.TypeText('_'+text+'_')
608 #RS fatal error handling
609 if self.dead==1:
610 return u""
611 #RS end
612 extra = ''
613 if id:
614 extra = ' id="%s"' % id
615 else:
616 id=''
617 tag = 'a'
618 if on:
619 ret=self.open(tag, attr={'id':'%s' % id})
620 #store this for the close action
621 self.anchorlink_name=name
622 self.anchorlink_id=id
623
624 return ret
625 else:
626 text=self.recordedtext
627 name=self.anchorlink_name
628 id=self.anchorlink_id
629 if text==None:
630 text=name
631 if self.document!=None:
632 if _debug:
633 out="""
634 self.word_host.ActiveDocument.Hyperlinks.Add(\
635 Anchor=%s, Address="",\
636 SubAddress='%s', ScreenTip="", TextToDisplay='%s')
637 """ % (str(self.word_host.Selection.Range.Start),name,text)
638 sys.stdout.write(out)
639 sys.stdout.flush()
640 # self.word_host.Selection.TypeText('##')
641 # self.word_host.Selection.MoveLeft(Unit=self.wdCharacter,Count=2,Extend=self.wdExtend)
642 self.word_host.ActiveDocument.Hyperlinks.Add(\
643 Anchor=self.word_host.Selection.Range, Address="",\
644 SubAddress=self._wordbookmark(name), ScreenTip="", TextToDisplay=text)
645 ret=self.close(tag)
646 return ret
647 #RS
648
649 ## def escape(self,s, quote=None):
650 ## """
651 ## """
652 ## if _debug:
653 ## traceback.print_stack(limit=1,file=sys.stdout)
654 ### s = s.replace("&", "&") # Must be done first!
655 ### s = s.replace("<", "<")
656 ### s = s.replace(">", ">")#
657 ## if quote:
658 ## s = s.replace('"', '""')
659 ## return s
660
661
662 def pure(self, text):
663 """
664 this handles the "not in any markup" case
665 used in formatters with "side effects"
666 """
667 if _debug:
668 traceback.print_stack(limit=1,file=sys.stdout)
669 #RS fatal error handling
670 if self.dead==1:
671 return u""
672 #RS end
673 if (self._table_start == 1):
674 return u''
675 # if self.document!=None:
676 # self.word_host.Selection.InsertAfter(text)
677 # self.word_host.Selection.TypeText(text)
678 # self.document.Content.InsertAfter(text)
679 # self.document.Content.InsertAfter('#'+text+'#')
680 return self._text(text)
681
682 def _text(self, text):
683 # return '{'+text+'}'
684 #RS fatal error handling
685 if _debug:
686 traceback.print_stack(limit=2,file=sys.stdout)
687 if self.dead==1:
688 return u""
689 #RS end
690 tx=self.escapedText(text)
691 if self._in_code:
692 tx=string.replace(self.escapedText(text), u' ', self.hardspace)
693 if self.store_text:
694 self.recordedtext+=tx
695 return tx
696 else:
697 if self.document!=None:
698 self.word_host.Selection.TypeText(tx)
699
700 return tx
701
702 # Inline ###########################################################
703 def strong(self, on):
704 #RS fatal error handling
705 if self.dead==1:
706 return u""
707 #RS end
708 tag = 'strong'
709 if on:
710 ret=self.open(tag)
711 if self.document!=None:
712 self.word_host.Selection.Font.Bold=\
713 win32com.client.constants.wdToggle
714 self.word_host.Selection.TypeText('')
715 return ret
716 else:
717 if self.document!=None:
718 pass
719 self.word_host.Selection.Font.Bold=\
720 win32com.client.constants.wdToggle
721 self.word_host.Selection.TypeText('')
722 ret=self.close(tag)
723 return ret
724
725
726 def emphasis(self, on):
727 #RS fatal error handling
728 if self.dead==1:
729 return u""
730 #RS end
731 tag = 'em'
732 if on:
733 ret=self.open(tag)
734 if self.document!=None:
735 self.word_host.Selection.Font.Italic=\
736 win32com.client.constants.wdToggle
737 self.word_host.Selection.TypeText('')
738 return ret
739 else:
740 if self.document!=None:
741 self.word_host.Selection.Font.Italic=\
742 win32com.client.constants.wdToggle
743 self.word_host.Selection.TypeText('')
744 ret=self.close(tag)
745 return ret
746
747 def underline(self, on):
748 if _debug:
749 traceback.print_stack(limit=1,file=sys.stdout)
750 #RS fatal error handling
751 if self.dead==1:
752 return u""
753 #RS end
754 tag = 'span'
755 if on:
756 ret=self.open(tag,attr={'class': 'u'})
757 if self.document!=None:
758 self.word_host.Selection.Font.Underline=\
759 win32com.client.constants.wdUnderlineSingle
760 self.word_host.Selection.TypeText('')
761 return ret
762 else:
763 if self.document!=None:
764 self.word_host.Selection.Font.Underline=\
765 win32com.client.constants.wdUnderlineNone
766 self.word_host.Selection.TypeText('')
767 ret=self.close(tag)
768 return ret
769
770 def highlight(self, on):
771 #RS fatal error handling
772 if self.dead==1:
773 return u""
774 #RS end
775 tag = 'strong'
776 if on:
777 ret=self.open(tag, attr={'class': 'highlight'})
778 if self.document!=None:
779 self.word_host.Selection.Font.Bold=\
780 win32com.client.constants.wdToggle
781 self.word_host.Selection.TypeText('')
782 return ret
783 else:
784 if self.document!=None:
785 self.word_host.Selection.Font.Bold=\
786 win32com.client.constants.wdToggle
787 self.word_host.Selection.TypeText('')
788 ret=self.close(tag)
789 return ret
790
791 def sup(self, on):
792 #RS fatal error handling
793 if self.dead==1:
794 return u""
795 #RS end
796 tag = 'sup'
797 if on:
798 ret=self.open(tag)
799 if self.document!=None:
800 self.word_host.Selection.Font.Superscript=\
801 win32com.client.constants.wdToggle
802 self.word_host.Selection.TypeText('')
803 return ret
804 else:
805 if self.document!=None:
806 self.word_host.Selection.Font.Superscript=\
807 win32com.client.constants.wdToggle
808 self.word_host.Selection.TypeText('')
809 ret=self.close(tag)
810 return ret
811
812 def sub(self, on):
813 #RS fatal error handling
814 if self.dead==1:
815 return u""
816 #RS end
817 tag = 'sub'
818 if on:
819 ret=self.open(tag)
820 if self.document!=None:
821 self.word_host.Selection.Font.Subscript=\
822 win32com.client.constants.wdToggle
823 self.word_host.Selection.TypeText('')
824 return ret
825 else:
826 if self.document!=None:
827 self.word_host.Selection.Font.Subscript=\
828 win32com.client.constants.wdToggle
829 self.word_host.Selection.TypeText('')
830 ret=self.close(tag)
831 return ret
832 #RS end
833
834
835 def code(self, on):
836 if _debug:
837 traceback.print_stack(limit=1,file=sys.stdout)
838 #RS fatal error handling
839 if self.dead==1:
840 return u""
841 #RS end
842 tag = 'tt'
843 self._in_code = on
844 if on:
845 ret=self.open(tag)
846 if self.document!=None:
847 self.word_host.Selection.Style=self.tt_style
848 self.word_host.Selection.TypeText('')
849 return ret
850 else:
851 if self.document!=None:
852 self.word_host.Selection.Style=self.defchar_style
853 self.word_host.Selection.TypeText('')
854 ## lastend=self.recordedcursor
855 ## currend=int(self.word_host.Selection.Range.End)
856 ## if lastend<currend and lastend>0:
857 ## ttrange=self.document.Range(lastend,currend)
858 ## ttrange.Style=self.tt_style
859 ## else:
860 ## self.request.write("TT formatter error, ignored")
861 ## self.word_host.Selection.TypeText('')
862 ret=self.close(tag)
863 return ret
864
865
866 def small(self, on):
867 tag = 'small'
868 if on:
869 ret=self.open(tag)
870 if self.document!=None:
871 pass
872 #TODO
873 # self.word_host.Selection.Font.Subscript=\
874 # win32com.client.constants.wdToggle
875 self.word_host.Selection.TypeText('')
876 return ret
877 else:
878 if self.document!=None:
879 pass
880 #TODO
881 # self.word_host.Selection.Font.Subscript=\
882 # win32com.client.constants.wdToggle
883 self.word_host.Selection.TypeText('')
884 ret=self.close(tag)
885 return ret
886
887 def big(self, on):
888 tag = 'big'
889 if on:
890 ret=self.open(tag)
891 if self.document!=None:
892 pass
893 #TODO
894 # self.word_host.Selection.Font.Subscript=\
895 # win32com.client.constants.wdToggle
896 # self.word_host.Selection.TypeText('')
897 return ret
898 else:
899 if self.document!=None:
900 pass
901 #TODO
902 # self.word_host.Selection.Font.Subscript=\
903 # win32com.client.constants.wdToggle
904 # self.word_host.Selection.TypeText('')
905 ret=self.close(tag)
906 return ret
907
908 # Block elements ####################################################
909
910 #framing pre:
911 #Selection.ParagraphFormat.Borders(wdBorderLeft).LineStyle = wdLineStyleSingle
912 ## Selection.MoveUp Unit:=wdLine, Count:=3, Extend:=wdExtend
913 ## With Selection.ParagraphFormat
914 ## With .Borders(wdBorderLeft)
915 ## .LineStyle = wdLineStyleSingle
916 ## .LineWidth = wdLineWidth050pt
917 ## .Color = wdColorAutomatic
918 ## End With
919 ## With .Borders(wdBorderRight)
920 ## .LineStyle = wdLineStyleSingle
921 ## .LineWidth = wdLineWidth050pt
922 ## .Color = wdColorAutomatic
923 ## End With
924 ## With .Borders(wdBorderTop)
925 ## .LineStyle = wdLineStyleSingle
926 ## .LineWidth = wdLineWidth050pt
927 ## .Color = wdColorAutomatic
928 ## End With
929 ## With .Borders(wdBorderBottom)
930 ## .LineStyle = wdLineStyleSingle
931 ## .LineWidth = wdLineWidth050pt
932 ## .Color = wdColorAutomatic
933 ## End With
934 ## .Borders(wdBorderHorizontal).LineStyle = wdLineStyleNone
935 ## With .Borders
936 ## .DistanceFromTop = 1
937 ## .DistanceFromLeft = 4
938 ## .DistanceFromBottom = 1
939 ## .DistanceFromRight = 4
940 ## .Shadow = False
941 ## End With
942 ## End With
943 ## With Options
944 ## .DefaultBorderLineStyle = wdLineStyleSingle
945 ## .DefaultBorderLineWidth = wdLineWidth050pt
946 ## .DefaultBorderColor = wdColorAutomatic
947 ## End With
948
949
950 def preformatted(self, on):
951 if _debug:
952 traceback.print_stack(limit=1,file=sys.stdout)
953 #RS fatal error handling
954 if self.dead==1:
955 return u""
956 #RS end
957 self.in_pre = on != 0
958 tag = 'preformatted'
959 if on:
960 ret=self.open(tag,newline=1)
961 if self.document!=None:
962 ### lastend=self.recordedcursor
963 ### currend=int(self.word_host.Selection.Range.End)
964 ### if lastend<currend and lastend>0:
965 ### ttrange=self.document.Range(lastend,currend)
966 ## ttrange.Style=self.pre_style
967 ## else:
968 ## self.request.write("PRE formatter error, ignored")
969 self.word_host.Selection.TypeParagraph()
970 self.word_host.Selection.Style=self.pre_style
971 self.word_host.Selection.ParagraphFormat.Borders(win32com.client.constants.wdBorderTop).LineStyle = win32com.client.constants.wdLineStyleSingle
972 self.word_host.Selection.ParagraphFormat.Borders(win32com.client.constants.wdBorderBottom).LineStyle = win32com.client.constants.wdLineStyleSingle
973 self.word_host.Selection.ParagraphFormat.Borders(win32com.client.constants.wdBorderLeft).LineStyle = win32com.client.constants.wdLineStyleSingle
974 self.word_host.Selection.ParagraphFormat.Borders(win32com.client.constants.wdBorderRight).LineStyle = win32com.client.constants.wdLineStyleSingle
975
976 self.word_host.Selection.TypeParagraph()
977 return ret
978 else:
979 if self.document!=None:
980 self.word_host.Selection.TypeParagraph()
981 self.word_host.Selection.Style=self.defpara_style
982 self.word_host.Selection.TypeParagraph()
983 self.word_host.Selection.ParagraphFormat.Borders(win32com.client.constants.wdBorderTop).LineStyle = win32com.client.constants.wdLineStyleNone
984 self.word_host.Selection.ParagraphFormat.Borders(win32com.client.constants.wdBorderBottom).LineStyle = win32com.client.constants.wdLineStyleNone
985 self.word_host.Selection.ParagraphFormat.Borders(win32com.client.constants.wdBorderLeft).LineStyle = win32com.client.constants.wdLineStyleNone
986 self.word_host.Selection.ParagraphFormat.Borders(win32com.client.constants.wdBorderRight).LineStyle = win32com.client.constants.wdLineStyleNone
987 ## lastend=self.recordedcursor
988 ## currend=int(self.word_host.Selection.Range.End)
989 ## if lastend<currend and lastend>0:
990 ## ttrange=self.document.Range(lastend,currend)
991 ## ttrange.Style=self.pre_style
992 ## else:
993 ## self.request.write("PRE formatter error, ignored")
994 ## self.word_host.Selection.TypeParagraph()
995 ## self.word_host.Selection.Style=self.defpara_style
996 ret=self.close(tag)
997 return ret
998
999 # special markup for syntax highlighting #############################
1000
1001 def code_area(self, on, code_id, code_type='code', show=0, start=-1, step=-1):
1002 #RS word: for now, just use preformatted?
1003 if on:
1004 # Open a code area
1005 self._in_code_area = 1
1006 self._in_code_line = 0
1007 else:
1008 # Close code area
1009 self._in_code_area = 0
1010 self._code_area_num += 1
1011 return self.preformatted(on)
1012 #RS end
1013 res = []
1014 ci = self.request.makeUniqueID('CA-%s_%03d' % (code_id, self._code_area_num))
1015 if on:
1016 # Open a code area
1017 self._in_code_area = 1
1018 self._in_code_line = 0
1019 self._code_area_state = [ci, show, start, step, start]
1020
1021 # Open the code div - using left to right always!
1022 attr = {'class': 'codearea', 'lang': 'en', 'dir': 'ltr'}
1023 res.append(self.open('div', attr=attr))
1024
1025 # Add the script only in the first code area on the page
1026 if self._code_area_js == 0 and self._code_area_state[1] >= 0:
1027 res.append(self._toggleLineNumbersScript)
1028 self._code_area_js = 1
1029
1030 # Add line number link, but only for JavaScript enabled browsers.
1031 if self._code_area_state[1] >= 0:
1032 toggleLineNumbersLink = r'''
1033 <script type="text/javascript">
1034 document.write('<a href="#" onClick="return togglenumber(\'%s\', %d, %d);" \
1035 class="codenumbers">Toggle line numbers<\/a>');
1036 </script>
1037 ''' % (self._code_area_state[0], self._code_area_state[2], self._code_area_state[3])
1038 res.append(toggleLineNumbersLink)
1039
1040 # Open pre - using left to right always!
1041 attr = {'id': self._code_area_state[0], 'lang': 'en', 'dir': 'ltr'}
1042 res.append(self.open('pre', newline=True, attr=attr))
1043 else:
1044 # Close code area
1045 res = []
1046 if self._in_code_line:
1047 res.append(self.code_line(0))
1048 res.append(self.close('pre'))
1049 res.append(self.close('div'))
1050
1051 # Update state
1052 self._in_code_area = 0
1053 self._code_area_num += 1
1054
1055 return ''.join(res)
1056
1057 def code_line(self, on):
1058 #RS word: for now, just linebreaks on on?
1059 self._in_code_line = on != 0
1060 if on:
1061 ret=self.linebreak(on)
1062 else:
1063 ret=''
1064 return ret
1065
1066 return self.preformatted(on)
1067 #RS end
1068 #RS end
1069 res = ''
1070 if not on or (on and self._in_code_line):
1071 res += '</span>\n'
1072 if on:
1073 res += '<span class="line">'
1074 if self._code_area_state[1] > 0:
1075 res += '<span class="LineNumber">%4d </span>' % (self._code_area_state[4], )
1076 self._code_area_state[4] += self._code_area_state[3]
1077 self._in_code_line = on != 0
1078 return res
1079
1080 def code_token(self, on, tok_type):
1081 #RS word: for now, just use code?
1082 return self.code(on)
1083 #RS end
1084 return ['<span class="%s">' % tok_type, '</span>'][not on]
1085
1086 # Paragraphs, Lines, Rules ###########################################
1087
1088 def linebreak(self, preformatted=1):
1089 if _debug:
1090 traceback.print_stack(limit=1,file=sys.stdout)
1091 #RS fatal error handling
1092 if self.dead==1:
1093 return u""
1094 #RS end
1095 if self._in_code_area:
1096 preformatted = 1
1097 if preformatted==1:
1098
1099 self.word_host.Selection.TypeParagraph()
1100 return '#\n'
1101 else:
1102 self.word_host.Selection.TypeText("#\x0B #")
1103 return '<br>\n'
1104 # self.document.Content.InsertAfter("\x0B ")
1105
1106
1107 def paragraph(self, on):
1108 if _debug:
1109 traceback.print_stack(limit=1,file=sys.stdout)
1110 #RS fatal error handling
1111 if self.dead==1:
1112 return u""
1113 #RS end
1114 if self._terse:
1115 return ''
1116 FormatterBase.paragraph(self, on)
1117 if self._in_li:
1118 self._in_li = self._in_li + 1
1119 tag = 'p'
1120 if on:
1121 ret=self.open(tag)
1122 if self.document!=None:
1123 if self._ignore_next_paragraph: #we already inserted a paragraph
1124 self._ignore_next_paragraph=0
1125 return u''
1126 else:
1127 self.word_host.Selection.TypeParagraph()
1128 return u'<pli>'
1129 return ret
1130 else:
1131 text=self.recordedtext
1132 if self.document!=None:
1133 if self._ignore_next_paragraph: #we already inserted a paragraph
1134 self._ignore_next_paragraph=0
1135 return u''
1136 else:
1137 self.word_host.Selection.TypeParagraph()
1138 return u'</pli>'
1139 ret=self.close(tag)
1140 return ret
1141
1142
1143 def rule(self, size=None):
1144 if _debug:
1145 traceback.print_stack(limit=1,file=sys.stdout)
1146 #RS fatal error handling
1147 if self.dead==1:
1148 return u""
1149 #RS end
1150 #TODO RS draw a line?
1151 if size:
1152 # Add hr class: hr1 - hr6
1153 return self.open('hr', newline=1, attr={'class': 'hr%d' % size})
1154 return self.open('hr', newline=1)
1155
1156 def icon(self, type):
1157 #TODO RS or just ignore (probably just wiki control icons)?
1158 return self.request.theme.make_icon(type)
1159
1160 def img_url(self, img):
1161 """ Generate an image href
1162
1163 @param img: the image filename
1164 @rtype: string
1165 @return: the image href
1166 """
1167 return "%s%s\\img\\%s" % (self.cfg.url_prefix_dir, self.request.theme.name, img)
1168
1169
1170 def smiley(self, text):
1171 w, h, b, img = config.smileys[text.strip()]
1172 href = img
1173 if not href.startswith('/'):
1174 href = self.img_url(img)
1175 return self.image(src=href, alt=text, width=str(w), height=str(h))
1176
1177 # Lists ##############################################################
1178
1179
1180 def number_list(self, on, type=None, start=None):
1181 if _debug:
1182 traceback.print_stack(limit=1,file=sys.stdout)
1183 #RS fatal error handling
1184 if self.dead==1:
1185 return u""
1186 #RS end
1187 tag = 'ol'
1188 self.request.write("<number_list>:on=%s,type=%s,start=%s" % (str(on),str(type),str(start)))
1189 if on:
1190 attr = {}
1191 if type is not None:
1192 attr['type'] = type
1193 if start is not None:
1194 attr['start'] = start
1195 ret=self.open(tag, newline=1, attr=attr)
1196
1197 self.list_levels['ol']=self.list_levels['ol']+1
1198 self.list_levels['all']=self.list_levels['all']+1
1199 if self.document!=None:
1200 # self.word_host.Selection.TypeParagraph()
1201 self.request.write("<OL> List type was: %s" % str(self.word_host.Selection.Range.ListFormat.ListType))
1202 if self.list_levels['ol']==1: #only first
1203 if self.word_host.Selection.Range.ListFormat.ListType != self.ol_type:
1204 # self.word_host.Selection.TypeText("{bulleton}")
1205 ## self.word_host.Selection.Range.ListFormat.ApplyNumberDefault(self.wdWord9ListBehavior)
1206 if self.last_indent_type=='ul':
1207 #need more indent
1208 self.request.write("UL->OL 1")
1209 self.word_host.Selection.Range.ListFormat.ListIndent()
1210 listtemplate=self.word_host.ListGalleries(self.wdNumberGallery).ListTemplates(self.list_levels['ol'])
1211 self.word_host.Selection.Range.ListFormat.ApplyListTemplate(ListTemplate=listtemplate,
1212 ContinuePreviousList=vbFalse, ApplyTo=self.wdListApplyToThisPointForward, DefaultListBehavior=self.wdWord9ListBehavior)
1213
1214 else:
1215 if self.word_host.Selection.Range.ListFormat.ListType != self.ol_type:
1216 # self.word_host.Selection.TypeText("{bulleton}")
1217 ## self.word_host.Selection.Range.ListFormat.ApplyNumberDefault(self.wdWord9ListBehavior)
1218 listtemplate=self.word_host.ListGalleries(self.wdNumberGallery).ListTemplates(self.list_levels['ol'])
1219 self.word_host.Selection.Range.ListFormat.ApplyListTemplate(ListTemplate=listtemplate,
1220 ContinuePreviousList=vbFalse, ApplyTo=self.wdListApplyToThisPointForward, DefaultListBehavior=self.wdWord9ListBehavior)
1221 if self.last_indent_type=='ul':
1222 #need more indent
1223 self.request.write("UL->OL 2")
1224 self.word_host.Selection.Range.ListFormat.ListIndent()
1225 # else:
1226 self.word_host.Selection.Range.ListFormat.ListIndent()
1227
1228 self._ignore_next_paragraph=1
1229 self._first_li = 1
1230 self.last_indent_type='ol'
1231 else:
1232 self.list_levels['ol']=self.list_levels['ol']-1
1233 self.list_levels['all']=self.list_levels['all']-1
1234
1235 if self.document!=None:
1236 # self.word_host.Selection.TypeParagraph()
1237 self.request.write("</OL> List type was: %s" % str(self.word_host.Selection.Range.ListFormat.ListType))
1238 if self.list_levels['ul']==0:
1239 if self.word_host.Selection.Range.ListFormat.ListType == self.ol_type:
1240 # self.word_host.Selection.TypeText("{bulletoff}")
1241 self.word_host.Selection.Range.ListFormat.ApplyNumberDefault(self.wdWord9ListBehavior)
1242 if self.last_indent_type=='ul':
1243 #need more outdent
1244 self.request.write("UL->OL ??1??")
1245 self.word_host.Selection.Range.ListFormat.ListOutdent()
1246
1247 else:
1248 if self.word_host.Selection.Range.ListFormat.ListType == self.ol_type:
1249 self.word_host.Selection.Range.ListFormat.ApplyNumberDefault(self.wdWord9ListBehavior)
1250 # else:
1251 self.word_host.Selection.Range.ListFormat.ListOutdent()
1252 self._ignore_next_paragraph=1
1253 self.last_indent_type=''
1254
1255 ret=self.close(tag)
1256 return ret
1257
1258
1259 def bullet_list(self, on):
1260 if _debug:
1261 traceback.print_stack(limit=1,file=sys.stdout)
1262 #RS fatal error handling
1263 if self.dead==1:
1264 return u""
1265 #RS end
1266 tag = 'ul'
1267 self.request.write("<bullet_list>:on=%s" % (str(on)))
1268 if on:
1269 ret=self.open(tag, newline=1)
1270 self.list_levels['ul']=self.list_levels['ul']+1
1271 self.list_levels['all']=self.list_levels['all']+1
1272 if self.document!=None:
1273 # self.word_host.Selection.TypeParagraph()
1274 self.request.write("<UL> List type was: %s" % str(self.word_host.Selection.Range.ListFormat.ListType))
1275 # self.word_host.Selection.TypeText("[%s]" % self.list_levels['all'])
1276 if self.list_levels['ul']==1: #only first
1277 if self.word_host.Selection.Range.ListFormat.ListType != self.ul_type:
1278 # self.word_host.Selection.TypeText("{bulleton}")
1279 self.word_host.Selection.Range.ListFormat.ApplyBulletDefault(self.wdWord9ListBehavior)
1280 else:
1281 if self.word_host.Selection.Range.ListFormat.ListType != self.ul_type:
1282 # self.word_host.Selection.TypeText("{bulleton}")
1283 self.word_host.Selection.Range.ListFormat.ApplyBulletDefault(self.wdWord9ListBehavior)
1284 # else:
1285 self.word_host.Selection.Range.ListFormat.ListIndent()
1286 # self.word_host.Selection.TypeText("{indent}")
1287 self._ignore_next_paragraph=1
1288 self.last_indent_type='ul'
1289
1290 return ret
1291 else:
1292 self.list_levels['ul']=self.list_levels['ul']-1
1293 self.list_levels['all']=self.list_levels['all']-1
1294 if self.document!=None:
1295 # self.word_host.Selection.TypeParagraph()
1296 self.request.write("</UL> List type was: %s" % str(self.word_host.Selection.Range.ListFormat.ListType))
1297 if self.list_levels['ul']==0:
1298 if self.word_host.Selection.Range.ListFormat.ListType == self.ul_type:
1299 # self.word_host.Selection.TypeText("{bulletoff}")
1300 self.word_host.Selection.Range.ListFormat.ApplyBulletDefault(self.wdWord9ListBehavior)
1301 else:
1302 if self.word_host.Selection.Range.ListFormat.ListType == self.ul_type:
1303 self.word_host.Selection.Range.ListFormat.ApplyBulletDefault(self.wdWord9ListBehavior)
1304 # else:
1305 self.word_host.Selection.Range.ListFormat.ListOutdent()
1306 # self.word_host.Selection.TypeText("{outdent}")
1307 # self.word_host.Selection.TypeText("[/%s]" % (self.list_levels['all']+1))
1308 self._ignore_next_paragraph=1
1309 self.last_indent_type=''
1310
1311 ret=self.close(tag)
1312 return ret
1313
1314 def listitem(self, on, **kw):
1315 if _debug:
1316 traceback.print_stack(limit=1,file=sys.stdout)
1317 #RS fatal error handling
1318 if self.dead==1:
1319 return u""
1320 #RS end
1321 ## self._in_li = on != 0
1322 tag = 'li'
1323 self._in_li = on != 0
1324 if on:
1325 attr = {}
1326 css_class = kw.get('css_class', None)
1327 if css_class:
1328 attr['class'] = css_class
1329 style = kw.get('style', None)
1330 if style:
1331 attr['style'] = style
1332 if style=="list-style-type:none":
1333 pass
1334 #this is indent, not bullet
1335 ret=self.open(tag, attr=attr)
1336 self._ignore_next_paragraph=1
1337 return ret
1338 else:
1339 ret=self.close(tag)
1340 return ret
1341 #RS end
1342
1343 def definition_list(self, on):
1344 if _debug:
1345 traceback.print_stack(limit=1,file=sys.stdout)
1346 #RS fatal error handling
1347 if self.dead==1:
1348 return u""
1349 #RS end
1350 tag = 'dl'
1351 if on:
1352 ret=self.open(tag, newline=1)
1353 self.list_levels['dl']=self.list_levels['dl']+1
1354 self.list_levels['all']=self.list_levels['all']+1
1355 return ret
1356 else:
1357 self.list_levels['dl']=self.list_levels['dl']-1
1358 self.list_levels['all']=self.list_levels['all']-1
1359 ret=self.close(tag)
1360 return ret
1361
1362 def definition_term(self, on):
1363 if _debug:
1364 traceback.print_stack(limit=1,file=sys.stdout)
1365 #RS fatal error handling
1366 if self.dead==1:
1367 return u""
1368 #RS end
1369 tag = 'dt'
1370 if on:
1371 ret=self.open(tag)
1372 return ret
1373 else:
1374 ret=self.close(tag)
1375 return ret
1376
1377
1378 def definition_desc(self, on):
1379 if _debug:
1380 traceback.print_stack(limit=1,file=sys.stdout)
1381 #RS fatal error handling
1382 if self.dead==1:
1383 return u""
1384 #RS end
1385 tag = 'dd'
1386 if on:
1387 ret=self.open(tag)
1388 return ret
1389 else:
1390 ret=self.close(tag)
1391 return ret
1392
1393
1394 def heading(self, on, depth, id = None, **kw):
1395 # remember depth of first heading, and adapt current depth accordingly
1396 if _debug:
1397 traceback.print_stack(limit=1,file=sys.stdout)
1398 #RS fatal error handling
1399 if self.dead==1:
1400 return u""
1401 #RS end
1402
1403 self._reset_indents()
1404 if not self._base_depth:
1405 self._base_depth = depth
1406 #RS adapt base depth if included
1407 self._base_depth=long(self.request.getPragma('_base_depth',str(self._base_depth)))
1408 oridepth=depth
1409
1410 #RS isn't this nonsense???
1411 # depth = max(depth - (self._base_depth - 1), 1)
1412 count_depth = max(depth - (self._base_depth - 1), 1)
1413
1414 #? depth = max(depth + (self._base_depth - 1), self._base_depth)
1415 #RS 1.1
1416 # check numbering, possibly changing the default
1417 if self._show_section_numbers is None:
1418 self._show_section_numbers = self.cfg.show_section_numbers
1419 numbering = self.request.getPragma('section-numbers', '').lower()
1420 if numbering in ['0', 'off']:
1421 self._show_section_numbers = 0
1422 elif numbering in ['1', 'on']:
1423 self._show_section_numbers = 1
1424 elif numbering in ['2', '3', '4', '5', '6']:
1425 # explicit base level for section number display
1426 self._show_section_numbers = int(numbering)
1427 #RS stop
1428
1429 heading_depth = depth + 1
1430 if on:
1431 # create section number
1432 number = ''
1433 if self._show_section_numbers:
1434 # count headings on all levels
1435 self.request._fmt_hd_counters = self.request._fmt_hd_counters[:count_depth]
1436 while len(self.request._fmt_hd_counters) < count_depth:
1437 self.request._fmt_hd_counters.append(0)
1438 self.request._fmt_hd_counters[-1] = self.request._fmt_hd_counters[-1] + 1
1439 number = '.'.join(map(str, self.request._fmt_hd_counters[self._show_section_numbers-1:]))
1440 if number: number += ". "
1441 attr = {}
1442 if id:
1443 attr['id'] = id
1444 # Add space before heading, easier to check source code
1445 ret='\n' +self.open('h%d' % heading_depth, attr=attr)
1446 return "%s%s" % (ret,number)
1447
1448 else:
1449 # closing tag, with empty line after, to make source more readable
1450 title=self.recordedtext
1451 if self.document!=None:
1452 self.word_host.Selection.TypeParagraph()
1453 style=win32com.client.constants.wdStyleHeading1 - depth +1
1454 self.word_host.Selection.Paragraphs.Last.Style=style
1455 self.word_host.Selection.TypeText('%s' % (title))
1456 self.word_host.Selection.TypeParagraph()
1457 self.word_host.Selection.Paragraphs.Last.Style=win32com.client.constants.wdStyleNormal
1458 ret=self.close('h%d' % heading_depth) + '\n'
1459 return ret
1460
1461
1462
1463 # Tables #############################################################
1464
1465 _allowed_table_attrs = {
1466 'table': ['class', 'id', 'style'],
1467 'row': ['class', 'id', 'style'],
1468 '': ['colspan', 'rowspan', 'class', 'id', 'style'],
1469 }
1470
1471 def _checkTableAttr(self, attrs, prefix):
1472 if _debug:
1473 traceback.print_stack(limit=1,file=sys.stdout)
1474 if not attrs: return u''
1475
1476 result = ''
1477 for key, val in attrs.items():
1478 if prefix and key[:len(prefix)] != prefix: continue
1479 key = key[len(prefix):]
1480 if key not in self._allowed_table_attrs[prefix]: continue
1481 result = '%s %s=%s' % (result, key, val)
1482
1483 return result
1484
1485 def table(self, on, attrs=None):
1486 """ Create table
1487
1488 @param on: start table
1489 @param attrs: table attributes
1490 @rtype: string
1491 @return start or end tag of a table
1492 """
1493 if _debug:
1494 traceback.print_stack(limit=1,file=sys.stdout)
1495 #RS fatal error handling
1496 if self.dead==1:
1497 return u""
1498 #RS end
1499 result = []
1500 if on:
1501 # Open div to get correct alignment with table width smaller
1502 # than 100%
1503 # ret=self.open('div', newline=1)
1504 # result.append(ret)
1505
1506 # Open table
1507 if not attrs:
1508 attrs = {}
1509 else:
1510 attrs = self._checkTableAttr(attrs, 'table')
1511 ret= self.open('table', newline=1, attr=attrs)
1512
1513 self.list_levels['table']=self.list_levels['table']+1
1514 self.list_levels['all']=self.list_levels['all']+1
1515 if self.document!=None:
1516 ##self.word_host.Selection.TypeParagraph()
1517 if self.word_host.Selection.Range.ListFormat.ListType == win32com.client.constants.wdListBullet:
1518 self.word_host.Selection.Range.ListFormat.ApplyBulletDefault(win32com.client.constants.wdWord9ListBehavior)
1519 self.word_host.Selection.TypeParagraph()
1520 self.document.Tables.Add(Range=self.word_host.Selection.Range,
1521 NumRows=1, NumColumns= 1, DefaultTableBehavior=win32com.client.constants.wdWord9TableBehavior,
1522 AutoFitBehavior= win32com.client.constants.wdAutoFitContent)
1523 self._first_tr = 1
1524 self._first_td = 1
1525 self._table_start=1
1526 return ret
1527 else:
1528 self.list_levels['table']=self.list_levels['table']-1
1529 self.list_levels['all']=self.list_levels['all']-1
1530 if self.document!=None:
1531 self.word_host.Selection.MoveDown(Unit=win32com.client.constants.wdLine, Count=1)
1532 self.word_host.Selection.TypeParagraph()
1533
1534 ret=self.close('table')
1535 # ret=self.close('div')
1536
1537 return ret
1538
1539 def table_row(self, on, attrs=None):
1540 if _debug:
1541 traceback.print_stack(limit=1,file=sys.stdout)
1542 #RS fatal error handling
1543 if self.dead==1:
1544 return u""
1545 #RS end
1546 tag = 'tr'
1547 if on:
1548 if not attrs:
1549 attrs = {}
1550 else:
1551 attrs = self._checkTableAttr(attrs, 'row')
1552 ret=self.open(tag, newline=1, attr=attrs)
1553 if self._first_tr == 0:
1554 #first row always existing
1555 if self.document!=None:
1556 self.word_host.Selection.InsertRowsBelow(1)
1557 self._first_td = 1
1558 elif self._first_td == 1:
1559 # if self.document!=None:
1560 # self.word_host.Selection.TypeText('#')
1561 self._table_start = 0
1562 return ret
1563 else:
1564 self._first_tr = 0
1565 ret=self.close(tag)
1566 return ret
1567
1568
1569 def table_cell(self, on, attrs=None):
1570 if _debug:
1571 traceback.print_stack(limit=1,file=sys.stdout)
1572 #RS fatal error handling
1573 if self.dead==1:
1574 return u""
1575 #RS end
1576 tag = 'tr'
1577 if on:
1578 if not attrs:
1579 attrs = {}
1580 else:
1581 attrs = self._checkTableAttr(attrs, 'row')
1582 ret=self.open(tag, newline=1, attr=attrs)
1583 if self.document!=None:
1584 self.word_host.Selection.Style=self.defchar_style
1585 if self._first_tr == 1:
1586 if self._first_td == 0:
1587 #first cell always existing
1588 if self.document!=None:
1589 self.word_host.Selection.InsertColumnsRight()
1590 self.word_host.Selection.Style=self.defchar_style
1591
1592 else:
1593 #jump into cell
1594 if self.document!=None:
1595 self.word_host.Selection.MoveRight(Unit=win32com.client.constants.wdCell)
1596 self.word_host.Selection.Style=self.defchar_style
1597 self._first_td = 0
1598 return ret
1599 else:
1600 self._first_td = 0
1601 ret=self.close(tag)
1602 return ret
1603
1604 def macro(self, macro_obj, name, args):
1605 # call the macro
1606 if name in ['TableOfContents',]:
1607 #skip call, emulate behavior
1608 ## With ActiveDocument
1609 ## .TablesOfContents.Add Range:=Selection.Range, RightAlignPageNumbers:= _
1610 ## True, UseHeadingStyles:=True, UpperHeadingLevel:=1, _
1611 ## LowerHeadingLevel:=3, IncludePageNumbers:=True, AddedStyles:="", _
1612 ## UseHyperlinks:=True, HidePageNumbersInWeb:=True
1613 ## .TablesOfContents(1).TabLeader = wdTabLeaderSpaces
1614 ## .TablesOfContents.Format = wdIndexIndent
1615 try:
1616 self.mindepth = max(int(self.request.getPragma('section-numbers', 1)),1)
1617 except (ValueError, TypeError):
1618 self.mindepth = 1
1619
1620 try:
1621 self.maxdepth = max(int(args), 1)
1622 except (ValueError, TypeError):
1623 self.maxdepth = 9
1624 sys.stdout.write("TOCrange:%s-%s" % (self.mindepth,self.maxdepth))
1625 if self.document!=None:
1626 self.word_host.ActiveDocument.TablesOfContents.Add(\
1627 Range=self.word_host.Selection.Range, UpperHeadingLevel=self.mindepth,\
1628 LowerHeadingLevel=self.maxdepth,UseHyperlinks=vbTrue)
1629 return "<TOC/>"
1630
1631 return macro_obj.execute(name, args)
1632
1633 def processor(self, processor_name, lines, is_parser = 0):
1634 """ processor_name MUST be valid!
1635 writes out the result instead of returning it!
1636 """
1637 if not is_parser:
1638 processor = wikiutil.importPlugin(self.request.cfg, "processor",
1639 processor_name, "process")
1640 processor(self.request, self, lines)
1641 else:
1642 if processor_name in ['tpython',]:
1643 processor_name='wiki'
1644 parser = wikiutil.importPlugin(self.request.cfg, "parser",
1645 processor_name, "Parser")
1646 args = self._get_bang_args(lines[0])
1647 if args is not None:
1648 lines=lines[1:]
1649 p = parser('\n'.join(lines), self.request, format_args = args)
1650 p.format(self)
1651 del p
1652 return ''
1653
1654
1655
1656 def escapedText(self, text):
1657 return text
1658 return wikiutil.escape(text)
1659
1660
1661 def _img(self,imgurl,**kw):
1662
1663 if _debug:
1664 traceback.print_stack(limit=1,file=sys.stdout)
1665 #RS fatal error handling
1666 if self.dead==1:
1667 return u""
1668 #RS end
1669 trusted=1
1670 scheme = string.split(imgurl, ":", 1)[0]
1671 if scheme in tuple(string.split('http|https|ftp|nntp','|')):
1672 trusted=0
1673 #retrieve remote file to temp
1674 try:
1675 (filename, headers)=urllib.urlretrieve( imgurl)
1676 print "remote url %s retrieved to %s" % (imgurl,filename)
1677 filepath=filename
1678 except:
1679 filepath=imgurl
1680 self.request.write("adding http picture, filepath=%s" % (filepath))
1681 elif scheme in tuple(string.split('file|self|wiki','|')):
1682 trusted=0
1683 filepath=imgurl
1684 self.request.write("adding file|self|wiki picture, filepath=%s" % (filepath))
1685 else:
1686 trusted=1
1687 if imgurl.startswith("./"):
1688 imgfile=imgurl[2:]
1689 else:
1690 imgfile=imgurl
1691
1692
1693 filepath = os.path.abspath(os.path.join(self.cfg.url_prefix_dir, imgfile))
1694 self.request.write("\n adding .. picture, imgfile=%s, targetdir=%s, filepath=%s" % (imgfile,self.targetdir,filepath))
1695 if self.document!=None:
1696 if self.word_host.Selection.Range.ListFormat.ListType == win32com.client.constants.wdListBullet:
1697 self.word_host.Selection.Range.ListFormat.ApplyBulletDefault(win32com.client.constants.wdWord9ListBehavior)
1698 try:
1699 self.word_host.Selection.InlineShapes.AddPicture(FileName=filepath,\
1700 LinkToFile=False, SaveWithDocument=True)
1701 except:
1702 if trusted:
1703 self.request.write("error in img, imgfile=%s, docpath=%s" % (filepath,str(self.document.Path)))
1704 self.request.write("Active %s" % str(self.word_host.Selection.Active))
1705 # raise
1706 errtext='[internal image not found:%s]' % filepath
1707 # self.document.Undo()
1708 try:
1709 self.word_host.Selection.TypeText(errtext)
1710 except:
1711 self.request.write("error reset did not work, may need Office 2000 SP3?")
1712 raise "error reset did not work, may need Office 2000 SP3?"
1713 else:
1714 raise
1715 self.request.write("warning in img, imgfile=%s, docpath=%s" % (filepath,str(self.document.Path)))
1716 self.word_host.Selection.TypeText('[external image not found:%s]' % filepath)
1717
1718 self.word_host.Selection.TypeText(' ')
1719 # self._save()
1720
1721
1722 def image(self, **kw):
1723 """ Take HTML <IMG> tag attributes in `attr`.
1724 Attribute names have to be lowercase!
1725 """
1726 if _debug:
1727 traceback.print_stack(limit=1,file=sys.stdout)
1728 #RS fatal error handling
1729 if self.dead==1:
1730 return u""
1731 #RS end
1732 attrstr = u''
1733 for attr, value in kw.items():
1734 if attr=='html_class':
1735 attr='class'
1736 attrstr = attrstr + u' %s="%s"' % (attr, wikiutil.escape(value))
1737 imgurl=kw.get('src','')
1738 self.request.write("\n try image, imgurl=%s" % (imgurl))
1739 if imgurl!='':
1740 self._img(imgurl,**kw)
1741 result= u'<img%s/>' % attrstr
1742 return result
1743
1744
1745
1746
1747 def rawHTML(self, markup):
1748 """ This allows emitting pre-formatted HTML markup, and should be
1749 used wisely (i.e. very seldom).
1750
1751 Using this event while generating content results in unwanted
1752 effects, like loss of markup or insertion of CDATA sections
1753 when output goes to XML formats.
1754 """
1755 return '<<'+markup+'>>'
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.You are not allowed to attach a file to this page.