Details to problems (thanks branden)
[docutils.git] / sandbox / rtf-writer / RTFWriter.py
blob15cd8d64726a08c905b199886226c188d1797dec
1 # -*- coding: utf-8 -*-
2 """ This is a docutils RTF Writer
4 We just need a few features so it shouldn't be too difficult
6 This was made possible by:
8 http://search.cpan.org/~sburke/RTF-Writer/lib/RTF/Cookbook.pod
10 from:
12 Sean M. Burke, sburke@cpan.org
14 Author: BenoƮt Allard
15 Contact: benoit@aeteurope.nl
16 Copyright: This module has been placed in the public domain.
17 """
19 from docutils import writers, nodes
21 class Writer(writers.Writer):
23 supported = ('rtf',)
24 output = None
26 def __init__(self):
27 writers.Writer.__init__(self)
28 self._translator_class = RTFTranslator
30 def translate(self):
31 visitor = self._translator_class(self.document)
32 self.document.walkabout(visitor)
33 self.output = visitor.astext()
35 def toansi(text):
36 """ Encode special characters """
37 trans = {'{': r'\{',
38 '}': r'\}',
39 '\\': r'\\',
41 out = ''
42 for char in text:
43 if char in trans:
44 out += trans[char]
45 elif ord(char) < 127:
46 out += char
47 else:
48 out += r"\'%x" % ord(char)
49 return out
51 FONT_NAME = 'Tahoma'
53 # Unit is half point
54 FONT_SIZE = {
55 -1: 18, # text
56 0: 24, # title
57 1: 28, # first heading
58 2: 24, # second heading
61 PAR_INDENT = 480
63 def indent(fn):
64 def wrapper(self, *args, **kwargs):
65 self.par_level += 1
66 return fn(self, *args, **kwargs)
67 return wrapper
70 def dedent(fn):
71 def wrapper(self, *args, **kwargs):
72 self.par_level -= 1
73 return fn(self, *args, **kwargs)
74 return wrapper
76 class RTFTranslator(nodes.NodeVisitor):
78 def __init__(self, document):
79 nodes.NodeVisitor.__init__(self, document)
80 self.body = []
81 self.section_level = 0
82 self.par_level = -1
83 self.bullets = [] # stack of the currents bullets
84 self.bullet = None # next one to add to the next paragraph
86 def astext(self):
87 return '\n'.join(self.body)
89 def visit_document(self, node):
90 self.body.append(r'{\rtf1\ansi\deff0{\fonttbl{\f0 %s;}}' % FONT_NAME)
91 self.body.append(r'\deflang1033\widowctrl\fs%d' % FONT_SIZE[-1])
93 def depart_document(self, node):
94 self.body.append('}')
96 def visit_title(self, node):
97 if isinstance(node.parent, nodes.document):
98 """ doc title """
99 self.body.append(r'{\pard\par\qc\f0\fs%d\b' % FONT_SIZE[0])
100 elif isinstance(node.parent, nodes.section):
101 level = self.section_level
102 self.body.append(r'{\pard\par\f0\fs%d\b' % FONT_SIZE[level])
104 def depart_title(self, node):
105 self.body.append(r'\par}')
107 def visit_Text(self, node):
108 if self.bullet is not None:
109 self.body.append(self.bullet+'\~')
110 self.bullet = None
111 self.body.append(toansi(node.astext()))
113 def depart_Text(self, node):
114 pass
116 def visit_strong(self, node):
117 self.body.append(r'{\b')
119 def depart_strong(self, node):
120 self.body.append('}')
122 def visit_section(self, node):
123 self.section_level += 1
125 def depart_section(self, node):
126 self.section_level -= 1
128 @indent
129 def visit_paragraph(self, node):
130 self.body.append(r'{\pard\par\f0\qj\li%d' % (PAR_INDENT * self.par_level))
131 if self.bullet is not None:
132 self.body.append(r'\fi-%d' % (PAR_INDENT / 2))
134 @dedent
135 def depart_paragraph(self, node):
136 self.body.append('\par}')
138 @indent
139 def visit_bullet_list(self, node):
140 self.bullets.append(node['bullet'])
142 @dedent
143 def depart_bullet_list(self, node):
144 self.bullets.pop()
146 def visit_list_item(self, node):
147 self.bullet = self.bullets[-1]
149 def depart_list_item(self, node):
150 pass
152 @indent
153 def visit_block_quote(self, node):
154 pass
156 @dedent
157 def depart_block_quote(self, node):
158 pass
160 def visit_reference(self, node):
161 if 'refuri' in node:
162 self.body.append(r'{\field{\*\fldinst{HYPERLINK "%s"}}{\fldrslt{\ul' % node['refuri'])
163 else:
164 # to balance parenthesis
165 self.body.append(r'{{{')
167 def depart_reference(self, node):
168 self.body.append('}}}')
170 def visit_docinfo(self, node):
171 self.body.append(r'{\info')
173 def depart_docinfo(self, node):
174 self.body.append('}')
176 def visit_author(self, node):
177 self.body.append(r'{\author')
179 def depart_author(self, node):
180 self.body.append(r'}')
182 if __name__ == "__main__":
183 """ To test the writer """
184 from docutils.core import publish_string
185 f_in = open('test.rtf', 'rb')
186 rtf = publish_string(f_in.read(), writer=Writer())
187 f_in.close()
189 print rtf
191 f_out = open('a.out', 'wb')
192 f_out.write(rtf)
193 f_out.close()