rtf 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/rtf/node.rb ADDED
@@ -0,0 +1,1398 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'stringio'
4
+
5
+ module RTF
6
+ # This class represents an element within an RTF document. The class provides
7
+ # a base class for more specific node types.
8
+ class Node
9
+ # Attribute accessor.
10
+ attr_reader :parent
11
+
12
+ # Attribute mutator.
13
+ attr_writer :parent
14
+
15
+
16
+ # This is the constructor for the Node class.
17
+ #
18
+ # ==== Parameters
19
+ # parent:: A reference to the Node that owns the new Node. May be nil
20
+ # to indicate a base or root node.
21
+ def initialize(parent)
22
+ @parent = parent
23
+ end
24
+
25
+ # This method retrieves a Node objects previous peer node, returning nil
26
+ # if the Node has no previous peer.
27
+ def previous_node
28
+ peer = nil
29
+ if parent != nil and parent.respond_to?(:children)
30
+ index = parent.children.index(self)
31
+ peer = index > 0 ? parent.children[index - 1] : nil
32
+ end
33
+ peer
34
+ end
35
+
36
+ # This method retrieves a Node objects next peer node, returning nil
37
+ # if the Node has no previous peer.
38
+ def next_node
39
+ peer = nil
40
+ if parent != nil and parent.respond_to?(:children)
41
+ index = parent.children.index(self)
42
+ peer = parent.children[index + 1]
43
+ end
44
+ peer
45
+ end
46
+
47
+ # This method is used to determine whether a Node object represents a
48
+ # root or base element. The method returns true if the Nodes parent is
49
+ # nil, false otherwise.
50
+ def is_root?
51
+ @parent == nil
52
+ end
53
+
54
+ # This method traverses a Node tree to locate the root element.
55
+ def root
56
+ node = self
57
+ node = node.parent while node.parent != nil
58
+ node
59
+ end
60
+ end # End of the Node class.
61
+
62
+
63
+ # This class represents a specialisation of the Node class to refer to a Node
64
+ # that simply contains text.
65
+ class TextNode < Node
66
+ # Attribute accessor.
67
+ attr_reader :text
68
+
69
+ # Attribute mutator.
70
+ attr_writer :text
71
+
72
+ # This is the constructor for the TextNode class.
73
+ #
74
+ # ==== Parameters
75
+ # parent:: A reference to the Node that owns the TextNode. Must not be
76
+ # nil.
77
+ # text:: A String containing the node text. Defaults to nil.
78
+ #
79
+ # ==== Exceptions
80
+ # RTFError:: Generated whenever an nil parent object is specified to
81
+ # the method.
82
+ def initialize(parent, text=nil)
83
+ super(parent)
84
+ if parent == nil
85
+ RTFError.fire("Nil parent specified for text node.")
86
+ end
87
+ @parent = parent
88
+ @text = text
89
+ end
90
+
91
+ # This method concatenates a String on to the end of the existing text
92
+ # within a TextNode object.
93
+ #
94
+ # ==== Parameters
95
+ # text:: The String to be added to the end of the text node.
96
+ def append(text)
97
+ if @text != nil
98
+ @text = @text + text.to_s
99
+ else
100
+ @text = text.to_s
101
+ end
102
+ end
103
+
104
+ # This method inserts a String into the existing text within a TextNode
105
+ # object. If the TextNode contains no text then it is simply set to the
106
+ # text passed in. If the offset specified is past the end of the nodes
107
+ # text then it is simply appended to the end.
108
+ #
109
+ # ==== Parameters
110
+ # text:: A String containing the text to be added.
111
+ # offset:: The numbers of characters from the first character to insert
112
+ # the new text at.
113
+ def insert(text, offset)
114
+ if @text != nil
115
+ @text = @text[0, offset] + text.to_s + @text[offset, @text.length]
116
+ else
117
+ @text = text.to_s
118
+ end
119
+ end
120
+
121
+ # This method generates the RTF equivalent for a TextNode object. This
122
+ # method escapes any special sequences that appear in the text.
123
+ def to_rtf
124
+ @text == nil ? '' : @text.gsub("{", "\\{").gsub("}", "\\}").gsub("\\", "\\\\")
125
+ end
126
+ end # End of the TextNode class.
127
+
128
+
129
+ # This class represents a Node that can contain other Node objects. Its a
130
+ # base class for more specific Node types.
131
+ class ContainerNode < Node
132
+ include Enumerable
133
+
134
+ # Attribute accessor.
135
+ attr_reader :children
136
+
137
+ # Attribute mutator.
138
+ attr_writer :children
139
+
140
+ # This is the constructor for the ContainerNode class.
141
+ #
142
+ # ==== Parameters
143
+ # parent:: A reference to the parent node that owners the new
144
+ # ContainerNode object.
145
+ def initialize(parent)
146
+ super(parent)
147
+ @children = []
148
+ @children.concat(yield) if block_given?
149
+ end
150
+
151
+ # This method adds a new node element to the end of the list of nodes
152
+ # maintained by a ContainerNode object. Nil objects are ignored.
153
+ #
154
+ # ==== Parameters
155
+ # node:: A reference to the Node object to be added.
156
+ def store(node)
157
+ if node != nil
158
+ @children.push(node) if @children.include?(Node) == false
159
+ node.parent = self if node.parent != self
160
+ end
161
+ node
162
+ end
163
+
164
+ # This method fetches the first node child for a ContainerNode object. If
165
+ # a container contains no children this method returns nil.
166
+ def first
167
+ @children[0]
168
+ end
169
+
170
+ # This method fetches the last node child for a ContainerNode object. If
171
+ # a container contains no children this method returns nil.
172
+ def last
173
+ @children.last
174
+ end
175
+
176
+ # This method provides for iteration over the contents of a ContainerNode
177
+ # object.
178
+ def each
179
+ @children.each {|child| yield child}
180
+ end
181
+
182
+ # This method returns a count of the number of children a ContainerNode
183
+ # object contains.
184
+ def size
185
+ @children.size
186
+ end
187
+
188
+ # This method overloads the array dereference operator to allow for
189
+ # access to the child elements of a ContainerNode object.
190
+ #
191
+ # ==== Parameters
192
+ # index:: The offset from the first child of the child object to be
193
+ # returned. Negative index values work from the back of the
194
+ # list of children. An invalid index will cause a nil value
195
+ # to be returned.
196
+ def [](index)
197
+ @children[index]
198
+ end
199
+
200
+ # This method generates the RTF text for a ContainerNode object.
201
+ def to_rtf
202
+ RTFError.fire("#{self.class.name}.to_rtf method not yet implemented.")
203
+ end
204
+ end # End of the ContainerNode class.
205
+
206
+
207
+ # This class represents a RTF command element within a document. This class
208
+ # is concrete enough to be used on its own but will also be used as the
209
+ # base class for some specific command node types.
210
+ class CommandNode < ContainerNode
211
+ # Attribute accessor.
212
+ attr_reader :prefix, :suffix, :split
213
+
214
+ # Attribute mutator.
215
+ attr_writer :prefix, :suffix, :split
216
+
217
+ # This is the constructor for the CommandNode class.
218
+ #
219
+ # ==== Parameters
220
+ # parent:: A reference to the node that owns the new node.
221
+ # prefix:: A String containing the prefix text for the command.
222
+ # suffix:: A String containing the suffix text for the command. Defaults
223
+ # to nil.
224
+ # split:: A boolean to indicate whether the prefix and suffix should
225
+ # be written to separate lines whether the node is converted
226
+ # to RTF. Defaults to true.
227
+ def initialize(parent, prefix, suffix=nil, split=true)
228
+ super(parent)
229
+ @prefix = prefix
230
+ @suffix = suffix
231
+ @split = split
232
+ end
233
+
234
+ # This method adds text to a command node. If the last child node of the
235
+ # target node is a TextNode then the text is appended to that. Otherwise
236
+ # a new TextNode is created and append to the node.
237
+ #
238
+ # ==== Parameters
239
+ # text:: The String of text to be written to the node.
240
+ def <<(text)
241
+ if last != nil and last.respond_to?(:text=)
242
+ last.append(text)
243
+ else
244
+ self.store(TextNode.new(self, text))
245
+ end
246
+ end
247
+
248
+ # This method generates the RTF text for a CommandNode object.
249
+ def to_rtf
250
+ text = StringIO.new
251
+ separator = split? ? "\n" : " "
252
+ line = (separator == " ")
253
+
254
+ text << "{#{@prefix}"
255
+ text << separator if self.size > 0
256
+ self.each do |entry|
257
+ text << "\n" if line
258
+ line = true
259
+ text << "#{entry.to_rtf}"
260
+ end
261
+ text << "\n" if split?
262
+ text << "#{@suffix}}"
263
+ text.string
264
+ end
265
+
266
+ # This method provides a short cut means of creating a paragraph command
267
+ # node. The method accepts a block that will be passed a single parameter
268
+ # which will be a reference to the paragraph node created. After the
269
+ # block is complete the paragraph node is appended to the end of the child
270
+ # nodes on the object that the method is called against.
271
+ #
272
+ # ==== Parameters
273
+ # style:: A reference to a ParagraphStyle object that defines the style
274
+ # for the new paragraph. Defaults to nil to indicate that the
275
+ # currently applied paragraph styling should be used.
276
+ def paragraph(style=nil)
277
+ # Create the node prefix.
278
+ text = StringIO.new
279
+ text << '\pard'
280
+ text << style.prefix(nil, nil) if style != nil
281
+
282
+ node = CommandNode.new(self, text.string, '\par')
283
+ yield node if block_given?
284
+ self.store(node)
285
+ end
286
+
287
+ # This method provides a short cut means of creating a line break command
288
+ # node. This command node does not take a block and may possess no other
289
+ # content.
290
+ def line_break
291
+ self.store(CommandNode.new(self, '\line', nil, false))
292
+ nil
293
+ end
294
+
295
+ # This method inserts a footnote at the current position in a node.
296
+ #
297
+ # ==== Parameters
298
+ # text:: A string containing the text for the footnote.
299
+ def footnote(text)
300
+ if text != nil && text != ''
301
+ mark = CommandNode.new(self, '\fs16\up6\chftn', nil, false)
302
+ note = CommandNode.new(self, '\footnote {\fs16\up6\chftn}', nil, false)
303
+ note.paragraph << text
304
+ self.store(mark)
305
+ self.store(note)
306
+ end
307
+ end
308
+
309
+ # This method provides a short cut means for applying multiple styles via
310
+ # single command node. The method accepts a block that will be passed a
311
+ # reference to the node created. Once the block is complete the new node
312
+ # will be append as the last child of the CommandNode the method is called
313
+ # on.
314
+ #
315
+ # ==== Parameters
316
+ # style:: A reference to a CharacterStyle object that contains the style
317
+ # settings to be applied.
318
+ #
319
+ # ==== Exceptions
320
+ # RTFError:: Generated whenever a non-character style is specified to
321
+ # the method.
322
+ def apply(style)
323
+ # Check the input style.
324
+ if style.is_character_style? == false
325
+ RTFError.fire("Non-character style specified to the "\
326
+ "CommandNode#apply() method.")
327
+ end
328
+
329
+ # Store fonts and colours.
330
+ root.colours << style.foreground if style.foreground != nil
331
+ root.colours << style.background if style.background != nil
332
+ root.fonts << style.font if style.font != nil
333
+
334
+ # Generate the command node.
335
+ node = CommandNode.new(self, style.prefix(root.fonts, root.colours))
336
+ yield node if block_given?
337
+ self.store(node)
338
+ end
339
+
340
+ # This method provides a short cut means of creating a bold command node.
341
+ # The method accepts a block that will be passed a single parameter which
342
+ # will be a reference to the bold node created. After the block is
343
+ # complete the bold node is appended to the end of the child nodes on
344
+ # the object that the method is call against.
345
+ def bold
346
+ style = CharacterStyle.new
347
+ style.bold = true
348
+ if block_given?
349
+ apply(style) {|node| yield node}
350
+ else
351
+ apply(style)
352
+ end
353
+ end
354
+
355
+ # This method provides a short cut means of creating an italic command
356
+ # node. The method accepts a block that will be passed a single parameter
357
+ # which will be a reference to the italic node created. After the block is
358
+ # complete the italic node is appended to the end of the child nodes on
359
+ # the object that the method is call against.
360
+ def italic
361
+ style = CharacterStyle.new
362
+ style.italic = true
363
+ if block_given?
364
+ apply(style) {|node| yield node}
365
+ else
366
+ apply(style)
367
+ end
368
+ end
369
+
370
+ # This method provides a short cut means of creating an underline command
371
+ # node. The method accepts a block that will be passed a single parameter
372
+ # which will be a reference to the underline node created. After the block
373
+ # is complete the underline node is appended to the end of the child nodes
374
+ # on the object that the method is call against.
375
+ def underline
376
+ style = CharacterStyle.new
377
+ style.underline = true
378
+ if block_given?
379
+ apply(style) {|node| yield node}
380
+ else
381
+ apply(style)
382
+ end
383
+ end
384
+
385
+ # This method provides a short cut means of creating a superscript command
386
+ # node. The method accepts a block that will be passed a single parameter
387
+ # which will be a reference to the superscript node created. After the
388
+ # block is complete the superscript node is appended to the end of the
389
+ # child nodes on the object that the method is call against.
390
+ def superscript
391
+ style = CharacterStyle.new
392
+ style.superscript = true
393
+ if block_given?
394
+ apply(style) {|node| yield node}
395
+ else
396
+ apply(style)
397
+ end
398
+ end
399
+
400
+ # This method provides a short cut means of creating a font command node.
401
+ # The method accepts a block that will be passed a single parameter which
402
+ # will be a reference to the font node created. After the block is
403
+ # complete the font node is appended to the end of the child nodes on the
404
+ # object that the method is called against.
405
+ #
406
+ # ==== Parameters
407
+ # font:: A reference to font object that represents the font to be used
408
+ # within the node.
409
+ # size:: An integer size setting for the font. Defaults to nil to
410
+ # indicate that the current font size should be used.
411
+ def font(font, size=nil)
412
+ style = CharacterStyle.new
413
+ style.font = font
414
+ style.font_size = size
415
+ root.fonts << font
416
+ if block_given?
417
+ apply(style) {|node| yield node}
418
+ else
419
+ apply(style)
420
+ end
421
+ end
422
+
423
+ # This method provides a short cut means of creating a foreground colour
424
+ # command node. The method accepts a block that will be passed a single
425
+ # parameter which will be a reference to the foreground colour node
426
+ # created. After the block is complete the foreground colour node is
427
+ # appended to the end of the child nodes on the object that the method
428
+ # is called against.
429
+ #
430
+ # ==== Parameters
431
+ # colour:: The foreground colour to be applied by the command.
432
+ def foreground(colour)
433
+ style = CharacterStyle.new
434
+ style.foreground = colour
435
+ root.colours << colour
436
+ if block_given?
437
+ apply(style) {|node| yield node}
438
+ else
439
+ apply(style)
440
+ end
441
+ end
442
+
443
+ # This method provides a short cut means of creating a background colour
444
+ # command node. The method accepts a block that will be passed a single
445
+ # parameter which will be a reference to the background colour node
446
+ # created. After the block is complete the background colour node is
447
+ # appended to the end of the child nodes on the object that the method
448
+ # is called against.
449
+ #
450
+ # ==== Parameters
451
+ # colour:: The background colour to be applied by the command.
452
+ def background(colour)
453
+ style = CharacterStyle.new
454
+ style.background = colour
455
+ root.colours << colour
456
+ if block_given?
457
+ apply(style) {|node| yield node}
458
+ else
459
+ apply(style)
460
+ end
461
+ end
462
+
463
+ # This method provides a short cut menas of creating a colour node that
464
+ # deals with foreground and background colours. The method accepts a
465
+ # block that will be passed a single parameter which will be a reference
466
+ # to the colour node created. After the block is complete the colour node
467
+ # is append to the end of the child nodes on the object that the method
468
+ # is called against.
469
+ #
470
+ # ==== Parameters
471
+ # fore:: The foreground colour to be applied by the command.
472
+ # back:: The background colour to be applied by the command.
473
+ def colour(fore, back)
474
+ style = CharacterStyle.new
475
+ style.foreground = fore
476
+ style.background = back
477
+ root.colours << fore
478
+ root.colours << back
479
+ if block_given?
480
+ apply(style) {|node| yield node}
481
+ else
482
+ apply(style)
483
+ end
484
+ end
485
+
486
+ # This method creates a new table node and returns it. The method accepts
487
+ # a block that will be passed the table as a parameter. The node is added
488
+ # to the node the method is called upon after the block is complete.
489
+ #
490
+ # ==== Parameters
491
+ # rows:: The number of rows that the table contains.
492
+ # columns:: The number of columns that the table contains.
493
+ # *widths:: One or more integers representing the widths for the table
494
+ # columns.
495
+ def table(rows, columns, *widths)
496
+ node = TableNode.new(self, rows, columns, *widths)
497
+ yield node if block_given?
498
+ store(node)
499
+ node
500
+ end
501
+
502
+ alias :write :<<
503
+ alias :color :colour
504
+ alias :split? :split
505
+ end # End of the CommandNode class.
506
+
507
+
508
+ # This class represents a table node within an RTF document. Table nodes are
509
+ # specialised container nodes that contain only TableRowNodes and have their
510
+ # size specified when they are created an cannot be resized after that.
511
+ class TableNode < ContainerNode
512
+ # Attribute accessor.
513
+ attr_reader :cell_margin
514
+
515
+ # Attribute mutator.
516
+ attr_writer :cell_margin
517
+
518
+ # This is a constructor for the TableNode class.
519
+ #
520
+ # ==== Parameters
521
+ # parent:: A reference to the node that owns the table.
522
+ # rows:: The number of rows in the tabkle.
523
+ # columns:: The number of columns in the table.
524
+ # *widths:: One or more integers specifying the widths of the table
525
+ # columns.
526
+ def initialize(parent, rows, columns, *widths)
527
+ super(parent) do
528
+ entries = []
529
+ rows.times {entries.push(TableRowNode.new(self, columns, *widths))}
530
+ entries
531
+ end
532
+ @cell_margin = 100
533
+ end
534
+
535
+ # Attribute accessor.
536
+ def rows
537
+ entries.size
538
+ end
539
+
540
+ # Attribute accessor.
541
+ def columns
542
+ entries[0].length
543
+ end
544
+
545
+ # This method assigns a border width setting to all of the sides on all
546
+ # of the cells within a table.
547
+ #
548
+ # ==== Parameters
549
+ # width:: The border width setting to apply. Negative values are ignored
550
+ # and zero switches the border off.
551
+ def border_width=(width)
552
+ self.each {|row| row.border_width = width}
553
+ end
554
+
555
+ # This method assigns a shading colour to a specified row within a
556
+ # TableNode object.
557
+ #
558
+ # ==== Parameters
559
+ # index:: The offset from the first row of the row to have shading
560
+ # applied to it.
561
+ # colour:: A reference to a Colour object representing the shading colour
562
+ # to be used. Set to nil to clear shading.
563
+ def row_shading_colour(index, colour)
564
+ row = self[index]
565
+ row.shading_colour = colour if row != nil
566
+ end
567
+
568
+ # This method assigns a shading colour to a specified column within a
569
+ # TableNode object.
570
+ #
571
+ # ==== Parameters
572
+ # index:: The offset from the first column of the column to have shading
573
+ # applied to it.
574
+ # colour:: A reference to a Colour object representing the shading colour
575
+ # to be used. Set to nil to clear shading.
576
+ def column_shading_colour(index, colour)
577
+ self.each do |row|
578
+ cell = row[index]
579
+ cell.shading_colour = colour if cell != nil
580
+ end
581
+ end
582
+
583
+ # This method provides a means of assigning a shading colour to a
584
+ # selection of cells within a table. The method accepts a block that
585
+ # takes three parameters - a TableCellNode representing a cell within the
586
+ # table, an integer representing the x offset of the cell and an integer
587
+ # representing the y offset of the cell. If the block returns true then
588
+ # shading will be applied to the cell.
589
+ #
590
+ # ==== Parameters
591
+ # colour:: A reference to a Colour object representing the shading colour
592
+ # to be applied. Set to nil to remove shading.
593
+ def shading_colour(colour)
594
+ if block_given?
595
+ 0.upto(self.size - 1) do |x|
596
+ row = self[x]
597
+ 0.upto(row.size - 1) do |y|
598
+ apply = yield row[y], x, y
599
+ row[y].shading_colour = colour if apply
600
+ end
601
+ end
602
+ end
603
+ end
604
+
605
+ # This method overloads the store method inherited from the ContainerNode
606
+ # class to forbid addition of further nodes.
607
+ #
608
+ # ==== Parameters
609
+ # node:: A reference to the node to be added.
610
+ def store(node)
611
+ RTFError.fire("Table nodes cannot have nodes added to.")
612
+ end
613
+
614
+ # This method generates the RTF document text for a TableCellNode object.
615
+ def to_rtf
616
+ text = StringIO.new
617
+ size = 0
618
+
619
+ self.each do |row|
620
+ if size > 0
621
+ text << "\n"
622
+ else
623
+ size = 1
624
+ end
625
+ text << row.to_rtf
626
+ end
627
+
628
+ text.string
629
+ end
630
+
631
+ alias :column_shading_color :column_shading_colour
632
+ alias :row_shading_color :row_shading_colour
633
+ alias :shading_color :shading_colour
634
+ end # End of the TableNode class.
635
+
636
+
637
+ # This class represents a row within an RTF table. The TableRowNode is a
638
+ # specialised container node that can hold only TableCellNodes and, once
639
+ # created, cannot be resized. Its also not possible to change the parent
640
+ # of a TableRowNode object.
641
+ class TableRowNode < ContainerNode
642
+ # This is the constructor for the TableRowNode class.
643
+ #
644
+ # ===== Parameters
645
+ # table:: A reference to table that owns the row.
646
+ # cells:: The number of cells that the row will contain.
647
+ # widths:: One or more integers specifying the widths for the table
648
+ # columns
649
+ def initialize(table, cells, *widths)
650
+ super(table) do
651
+ entries = []
652
+ cells.times do |index|
653
+ entries.push(TableCellNode.new(self, widths[index]))
654
+ end
655
+ entries
656
+ end
657
+ end
658
+
659
+ # Attrobute accessors
660
+ def length
661
+ entries.size
662
+ end
663
+
664
+ # This method assigns a border width setting to all of the sides on all
665
+ # of the cells within a table row.
666
+ #
667
+ # ==== Parameters
668
+ # width:: The border width setting to apply. Negative values are ignored
669
+ # and zero switches the border off.
670
+ def border_width=(width)
671
+ self.each {|cell| cell.border_width = width}
672
+ end
673
+
674
+ # This method overloads the parent= method inherited from the Node class
675
+ # to forbid the alteration of the cells parent.
676
+ #
677
+ # ==== Parameters
678
+ # parent:: A reference to the new node parent.
679
+ def parent=(parent)
680
+ RTFError.fire("Table row nodes cannot have their parent changed.")
681
+ end
682
+
683
+ # This method sets the shading colour for a row.
684
+ #
685
+ # ==== Parameters
686
+ # colour:: A reference to the Colour object that represents the new
687
+ # shading colour. Set to nil to switch shading off.
688
+ def shading_colour=(colour)
689
+ self.each {|cell| cell.shading_colour = colour}
690
+ end
691
+
692
+ # This method overloads the store method inherited from the ContainerNode
693
+ # class to forbid addition of further nodes.
694
+ #
695
+ # ==== Parameters
696
+ # node:: A reference to the node to be added.
697
+ #def store(node)
698
+ # RTFError.fire("Table row nodes cannot have nodes added to.")
699
+ #end
700
+
701
+ # This method generates the RTF document text for a TableCellNode object.
702
+ def to_rtf
703
+ text = StringIO.new
704
+ temp = StringIO.new
705
+ offset = 0
706
+
707
+ text << "\\trowd\\tgraph#{parent.cell_margin}"
708
+ self.each do |entry|
709
+ widths = entry.border_widths
710
+ colour = entry.shading_colour
711
+
712
+ text << "\n"
713
+ text << "\\clbrdrt\\brdrw#{widths[0]}\\brdrs" if widths[0] != 0
714
+ text << "\\clbrdrl\\brdrw#{widths[3]}\\brdrs" if widths[3] != 0
715
+ text << "\\clbrdrb\\brdrw#{widths[2]}\\brdrs" if widths[2] != 0
716
+ text << "\\clbrdrr\\brdrw#{widths[1]}\\brdrs" if widths[1] != 0
717
+ text << "\\clcbpat#{root.colours.index(colour)}" if colour != nil
718
+ text << "\\cellx#{entry.width + offset}"
719
+ temp << "\n#{entry.to_rtf}"
720
+ offset += entry.width
721
+ end
722
+ text << "#{temp.string}\n\\row"
723
+
724
+ text.string
725
+ end
726
+ end # End of the TableRowNode class.
727
+
728
+
729
+ # This class represents a cell within an RTF table. The TableCellNode is a
730
+ # specialised command node that is forbidden from creating tables or having
731
+ # its parent changed.
732
+ class TableCellNode < CommandNode
733
+ # A definition for the default width for the cell.
734
+ DEFAULT_WIDTH = 300
735
+
736
+ # Attribute accessor.
737
+ attr_reader :width, :shading_colour, :style
738
+
739
+ # Attribute mutator.
740
+ attr_writer :width, :style
741
+
742
+ # This is the constructor for the TableCellNode class.
743
+ #
744
+ # ==== Parameters
745
+ # row:: The row that the cell belongs to.
746
+ # width:: The width to be assigned to the cell. This defaults to
747
+ # TableCellNode::DEFAULT_WIDTH.
748
+ # style:: The style that is applied to the cell. This must be a
749
+ # ParagraphStyle class. Defaults to nil.
750
+ # top:: The border width for the cells top border. Defaults to nil.
751
+ # right:: The border width for the cells right hand border. Defaults to
752
+ # nil.
753
+ # bottom:: The border width for the cells bottom border. Defaults to nil.
754
+ # left:: The border width for the cells left hand border. Defaults to
755
+ # nil.
756
+ #
757
+ # ==== Exceptions
758
+ # RTFError:: Generated whenever an invalid style setting is specified.
759
+ def initialize(row, width=DEFAULT_WIDTH, style=nil, top=nil, right=nil,
760
+ bottom=nil, left=nil)
761
+ super(row, nil)
762
+ if style != nil && style.is_paragraph_style? == false
763
+ RTFError.fire("Non-paragraph style specified for TableCellNode "\
764
+ "constructor.")
765
+ end
766
+
767
+ @width = (width != nil && width > 0) ? width : DEFAULT_WIDTH
768
+ @borders = [(top != nil && top > 0) ? top : nil,
769
+ (right != nil && right > 0) ? right : nil,
770
+ (bottom != nil && bottom > 0) ? bottom : nil,
771
+ (left != nil && left > 0) ? left : nil]
772
+ @shading_colour = nil
773
+ @style = style
774
+ end
775
+
776
+ # Attribute mutator.
777
+ #
778
+ # ==== Parameters
779
+ # style:: A reference to the style object to be applied to the cell.
780
+ # Must be an instance of the ParagraphStyle class. Set to nil
781
+ # to clear style settings.
782
+ #
783
+ # ==== Exceptions
784
+ # RTFError:: Generated whenever an invalid style setting is specified.
785
+ def style=(style)
786
+ if style != nil && style.is_paragraph_style? == false
787
+ RTFError.fire("Non-paragraph style specified for TableCellNode "\
788
+ "constructor.")
789
+ end
790
+ @style = style
791
+ end
792
+
793
+ # This method assigns a width, in twips, for the borders on all sides of
794
+ # the cell. Negative widths will be ignored and a width of zero will
795
+ # switch the border off.
796
+ #
797
+ # ==== Parameters
798
+ # width:: The setting for the width of the border.
799
+ def border_width=(width)
800
+ size = width == nil ? 0 : width
801
+ if size > 0
802
+ @borders[0] = @borders[1] = @borders[2] = @borders[3] = size.to_i
803
+ else
804
+ @borders = [nil, nil, nil, nil]
805
+ end
806
+ end
807
+
808
+ # This method assigns a border width to the top side of a table cell.
809
+ # Negative values are ignored and a value of 0 switches the border off.
810
+ #
811
+ # ==== Parameters
812
+ # width:: The new border width setting.
813
+ def top_border_width=(width)
814
+ size = width == nil ? 0 : width
815
+ if size > 0
816
+ @borders[0] = size.to_i
817
+ else
818
+ @borders[0] = nil
819
+ end
820
+ end
821
+
822
+ # This method assigns a border width to the right side of a table cell.
823
+ # Negative values are ignored and a value of 0 switches the border off.
824
+ #
825
+ # ==== Parameters
826
+ # width:: The new border width setting.
827
+ def right_border_width=(width)
828
+ size = width == nil ? 0 : width
829
+ if size > 0
830
+ @borders[1] = size.to_i
831
+ else
832
+ @borders[1] = nil
833
+ end
834
+ end
835
+
836
+ # This method assigns a border width to the bottom side of a table cell.
837
+ # Negative values are ignored and a value of 0 switches the border off.
838
+ #
839
+ # ==== Parameters
840
+ # width:: The new border width setting.
841
+ def bottom_border_width=(width)
842
+ size = width == nil ? 0 : width
843
+ if size > 0
844
+ @borders[2] = size.to_i
845
+ else
846
+ @borders[2] = nil
847
+ end
848
+ end
849
+
850
+ # This method assigns a border width to the left side of a table cell.
851
+ # Negative values are ignored and a value of 0 switches the border off.
852
+ #
853
+ # ==== Parameters
854
+ # width:: The new border width setting.
855
+ def left_border_width=(width)
856
+ size = width == nil ? 0 : width
857
+ if size > 0
858
+ @borders[3] = size.to_i
859
+ else
860
+ @borders[3] = nil
861
+ end
862
+ end
863
+
864
+ # This method alters the shading colour associated with a TableCellNode
865
+ # object.
866
+ #
867
+ # ==== Parameters
868
+ # colour:: A reference to the Colour object to use in shading the cell.
869
+ # Assign nil to clear cell shading.
870
+ def shading_colour=(colour)
871
+ root.colours << colour
872
+ @shading_colour = colour
873
+ end
874
+
875
+ # This method retrieves an array with the cell border width settings.
876
+ # The values are inserted in top, right, bottom, left order.
877
+ def border_widths
878
+ widths = []
879
+ @borders.each {|entry| widths.push(entry == nil ? 0 : entry)}
880
+ widths
881
+ end
882
+
883
+ # This method fetches the width for top border of a cell.
884
+ def top_border_width
885
+ @borders[0] == nil ? 0 : @borders[0]
886
+ end
887
+
888
+ # This method fetches the width for right border of a cell.
889
+ def right_border_width
890
+ @borders[1] == nil ? 0 : @borders[1]
891
+ end
892
+
893
+ # This method fetches the width for bottom border of a cell.
894
+ def bottom_border_width
895
+ @borders[2] == nil ? 0 : @borders[2]
896
+ end
897
+
898
+ # This method fetches the width for left border of a cell.
899
+ def left_border_width
900
+ @borders[3] == nil ? 0 : @borders[3]
901
+ end
902
+
903
+ # This method overloads the paragraph method inherited from the
904
+ # ComamndNode class to forbid the creation of paragraphs.
905
+ #
906
+ # ==== Parameters
907
+ # justification:: The justification to be applied to the paragraph.
908
+ # before:: The amount of space, in twips, to be inserted before
909
+ # the paragraph. Defaults to nil.
910
+ # after:: The amount of space, in twips, to be inserted after
911
+ # the paragraph. Defaults to nil.
912
+ # left:: The amount of indentation to place on the left of the
913
+ # paragraph. Defaults to nil.
914
+ # right:: The amount of indentation to place on the right of the
915
+ # paragraph. Defaults to nil.
916
+ # first:: The amount of indentation to place on the left of the
917
+ # first line in the paragraph. Defaults to nil.
918
+ def paragraph(justification=CommandNode::LEFT_JUSTIFY, before=nil,
919
+ after=nil, left=nil, right=nil, first=nil)
920
+ RTFError.fire("TableCellNode#paragraph() called. Table cells cannot "\
921
+ "contain paragraphs.")
922
+ end
923
+
924
+ # This method overloads the parent= method inherited from the Node class
925
+ # to forbid the alteration of the cells parent.
926
+ #
927
+ # ==== Parameters
928
+ # parent:: A reference to the new node parent.
929
+ def parent=(parent)
930
+ RTFError.fire("Table cell nodes cannot have their parent changed.")
931
+ end
932
+
933
+ # This method overrides the table method inherited from CommandNode to
934
+ # forbid its use in table cells.
935
+ #
936
+ # ==== Parameters
937
+ # rows:: The number of rows for the table.
938
+ # columns:: The number of columns for the table.
939
+ # *widths:: One or more integers representing the widths for the table
940
+ # columns.
941
+ def table(rows, columns, *widths)
942
+ RTFError.fire("TableCellNode#table() called. Nested tables not allowed.")
943
+ end
944
+
945
+ # This method generates the RTF document text for a TableCellNode object.
946
+ def to_rtf
947
+ text = StringIO.new
948
+ separator = split? ? "\n" : " "
949
+ line = (separator == " ")
950
+
951
+ text << "\\pard\\intbl"
952
+ text << @style.prefix(nil, nil) if @style != nil
953
+ text << separator
954
+ self.each do |entry|
955
+ text << "\n" if line
956
+ line = true
957
+ text << entry.to_rtf
958
+ end
959
+ text << (split? ? "\n" : " ")
960
+ text << "\\cell"
961
+
962
+ text.string
963
+ end
964
+ end # End of the TableCellNode class.
965
+
966
+
967
+ # This class represents a document header.
968
+ class HeaderNode < CommandNode
969
+ # A definition for a header type.
970
+ UNIVERSAL = :header
971
+
972
+ # A definition for a header type.
973
+ LEFT_PAGE = :headerl
974
+
975
+ # A definition for a header type.
976
+ RIGHT_PAGE = :headerr
977
+
978
+ # A definition for a header type.
979
+ FIRST_PAGE = :headerf
980
+
981
+ # Attribute accessor.
982
+ attr_reader :type
983
+
984
+ # Attribute mutator.
985
+ attr_writer :type
986
+
987
+
988
+ # This is the constructor for the HeaderNode class.
989
+ #
990
+ # ==== Parameters
991
+ # document:: A reference to the Document object that will own the new
992
+ # header.
993
+ # type:: The style type for the new header. Defaults to a value of
994
+ # HeaderNode::UNIVERSAL.
995
+ def initialize(document, type=UNIVERSAL)
996
+ super(document, "\\#{type.id2name}", nil, false)
997
+ @type = type
998
+ end
999
+
1000
+ # This method overloads the footnote method inherited from the CommandNode
1001
+ # class to prevent footnotes being added to headers.
1002
+ #
1003
+ # ==== Parameters
1004
+ # text:: Not used.
1005
+ #
1006
+ # ==== Exceptions
1007
+ # RTFError:: Always generated whenever this method is called.
1008
+ def footnote(text)
1009
+ RTFError.fire("Footnotes are not permitted in page headers.")
1010
+ end
1011
+ end # End of the HeaderNode class.
1012
+
1013
+
1014
+ # This class represents a document footer.
1015
+ class FooterNode < CommandNode
1016
+ # A definition for a header type.
1017
+ UNIVERSAL = :footer
1018
+
1019
+ # A definition for a header type.
1020
+ LEFT_PAGE = :footerl
1021
+
1022
+ # A definition for a header type.
1023
+ RIGHT_PAGE = :footerr
1024
+
1025
+ # A definition for a header type.
1026
+ FIRST_PAGE = :footerf
1027
+
1028
+ # Attribute accessor.
1029
+ attr_reader :type
1030
+
1031
+ # Attribute mutator.
1032
+ attr_writer :type
1033
+
1034
+
1035
+ # This is the constructor for the FooterNode class.
1036
+ #
1037
+ # ==== Parameters
1038
+ # document:: A reference to the Document object that will own the new
1039
+ # footer.
1040
+ # type:: The style type for the new footer. Defaults to a value of
1041
+ # FooterNode::UNIVERSAL.
1042
+ def initialize(document, type=UNIVERSAL)
1043
+ super(document, "\\#{type.id2name}", nil, false)
1044
+ @type = type
1045
+ end
1046
+
1047
+ # This method overloads the footnote method inherited from the CommandNode
1048
+ # class to prevent footnotes being added to footers.
1049
+ #
1050
+ # ==== Parameters
1051
+ # text:: Not used.
1052
+ #
1053
+ # ==== Exceptions
1054
+ # RTFError:: Always generated whenever this method is called.
1055
+ def footnote(text)
1056
+ RTFError.fire("Footnotes are not permitted in page footers.")
1057
+ end
1058
+ end # End of the FooterNode class.
1059
+
1060
+
1061
+ # This class represents an RTF document. In actuality it is just a
1062
+ # specialised Node type that cannot be assigned a parent and that holds
1063
+ # document font, colour and information tables.
1064
+ class Document < CommandNode
1065
+ # A definition for a document character set setting.
1066
+ CS_ANSI = :ansi
1067
+
1068
+ # A definition for a document character set setting.
1069
+ CS_MAC = :mac
1070
+
1071
+ # A definition for a document character set setting.
1072
+ CS_PC = :pc
1073
+
1074
+ # A definition for a document character set setting.
1075
+ CS_PCA = :pca
1076
+
1077
+ # A definition for a document language setting.
1078
+ LC_AFRIKAANS = 1078
1079
+
1080
+ # A definition for a document language setting.
1081
+ LC_ARABIC = 1025
1082
+
1083
+ # A definition for a document language setting.
1084
+ LC_CATALAN = 1027
1085
+
1086
+ # A definition for a document language setting.
1087
+ LC_CHINESE_TRADITIONAL = 1028
1088
+
1089
+ # A definition for a document language setting.
1090
+ LC_CHINESE_SIMPLIFIED = 2052
1091
+
1092
+ # A definition for a document language setting.
1093
+ LC_CZECH = 1029
1094
+
1095
+ # A definition for a document language setting.
1096
+ LC_DANISH = 1030
1097
+
1098
+ # A definition for a document language setting.
1099
+ LC_DUTCH = 1043
1100
+
1101
+ # A definition for a document language setting.
1102
+ LC_DUTCH_BELGIAN = 2067
1103
+
1104
+ # A definition for a document language setting.
1105
+ LC_ENGLISH_UK = 2057
1106
+
1107
+ # A definition for a document language setting.
1108
+ LC_ENGLISH_US = 1033
1109
+
1110
+ # A definition for a document language setting.
1111
+ LC_FINNISH = 1035
1112
+
1113
+ # A definition for a document language setting.
1114
+ LC_FRENCH = 1036
1115
+
1116
+ # A definition for a document language setting.
1117
+ LC_FRENCH_BELGIAN = 2060
1118
+
1119
+ # A definition for a document language setting.
1120
+ LC_FRENCH_CANADIAN = 3084
1121
+
1122
+ # A definition for a document language setting.
1123
+ LC_FRENCH_SWISS = 4108
1124
+
1125
+ # A definition for a document language setting.
1126
+ LC_GERMAN = 1031
1127
+
1128
+ # A definition for a document language setting.
1129
+ LC_GERMAN_SWISS = 2055
1130
+
1131
+ # A definition for a document language setting.
1132
+ LC_GREEK = 1032
1133
+
1134
+ # A definition for a document language setting.
1135
+ LC_HEBREW = 1037
1136
+
1137
+ # A definition for a document language setting.
1138
+ LC_HUNGARIAN = 1038
1139
+
1140
+ # A definition for a document language setting.
1141
+ LC_ICELANDIC = 1039
1142
+
1143
+ # A definition for a document language setting.
1144
+ LC_INDONESIAN = 1057
1145
+
1146
+ # A definition for a document language setting.
1147
+ LC_ITALIAN = 1040
1148
+
1149
+ # A definition for a document language setting.
1150
+ LC_JAPANESE = 1041
1151
+
1152
+ # A definition for a document language setting.
1153
+ LC_KOREAN = 1042
1154
+
1155
+ # A definition for a document language setting.
1156
+ LC_NORWEGIAN_BOKMAL = 1044
1157
+
1158
+ # A definition for a document language setting.
1159
+ LC_NORWEGIAN_NYNORSK = 2068
1160
+
1161
+ # A definition for a document language setting.
1162
+ LC_POLISH = 1045
1163
+
1164
+ # A definition for a document language setting.
1165
+ LC_PORTUGUESE = 2070
1166
+
1167
+ # A definition for a document language setting.
1168
+ LC_POTUGUESE_BRAZILIAN = 1046
1169
+
1170
+ # A definition for a document language setting.
1171
+ LC_ROMANIAN = 1048
1172
+
1173
+ # A definition for a document language setting.
1174
+ LC_RUSSIAN = 1049
1175
+
1176
+ # A definition for a document language setting.
1177
+ LC_SERBO_CROATIAN_CYRILLIC = 2074
1178
+
1179
+ # A definition for a document language setting.
1180
+ LC_SERBO_CROATIAN_LATIN = 1050
1181
+
1182
+ # A definition for a document language setting.
1183
+ LC_SLOVAK = 1051
1184
+
1185
+ # A definition for a document language setting.
1186
+ LC_SPANISH_CASTILLIAN = 1034
1187
+
1188
+ # A definition for a document language setting.
1189
+ LC_SPANISH_MEXICAN = 2058
1190
+
1191
+ # A definition for a document language setting.
1192
+ LC_SWAHILI = 1089
1193
+
1194
+ # A definition for a document language setting.
1195
+ LC_SWEDISH = 1053
1196
+
1197
+ # A definition for a document language setting.
1198
+ LC_THAI = 1054
1199
+
1200
+ # A definition for a document language setting.
1201
+ LC_TURKISH = 1055
1202
+
1203
+ # A definition for a document language setting.
1204
+ LC_UNKNOWN = 1024
1205
+
1206
+ # A definition for a document language setting.
1207
+ LC_VIETNAMESE = 1066
1208
+
1209
+ # Attribute accessor.
1210
+ attr_reader :fonts, :colours, :information, :character_set, :language,
1211
+ :style
1212
+
1213
+ # Attribute mutator.
1214
+ attr_writer :character_set, :language
1215
+
1216
+
1217
+ # This is a constructor for the Document class.
1218
+ #
1219
+ # ==== Parameters
1220
+ # font:: The default font to be used by the document.
1221
+ # style:: The style settings to be applied to the document. This
1222
+ # defaults to nil.
1223
+ # character:: The character set to be applied to the document. This
1224
+ # defaults to Document::CS_ANSI.
1225
+ # language:: The language setting to be applied to document. This
1226
+ # defaults to Document::LC_ENGLISH_UK.
1227
+ def initialize(font, style=nil, character=CS_ANSI, language=LC_ENGLISH_UK)
1228
+ super(nil, '\rtf1')
1229
+ @fonts = FontTable.new(font)
1230
+ @default_font = 0
1231
+ @colours = ColourTable.new
1232
+ @information = Information.new
1233
+ @character_set = character
1234
+ @language = language
1235
+ @style = style == nil ? DocumentStyle.new : style
1236
+ @headers = [nil, nil, nil, nil]
1237
+ @footers = [nil, nil, nil, nil]
1238
+ end
1239
+
1240
+ # Attribute accessor.
1241
+ def default_font
1242
+ @fonts[@default_font]
1243
+ end
1244
+
1245
+ # This method assigns a new header to a document. A Document object can
1246
+ # have up to four header - a default header, a header for left pages, a
1247
+ # header for right pages and a header for the first page. The method
1248
+ # checks the header type and stores it appropriately.
1249
+ #
1250
+ # ==== Parameters
1251
+ # header:: A reference to the header object to be stored. Existing header
1252
+ # objects are overwritten.
1253
+ def header=(header)
1254
+ if header.type == HeaderNode::UNIVERSAL
1255
+ @headers[0] = header
1256
+ elsif header.type == HeaderNode::LEFT_PAGE
1257
+ @headers[1] = header
1258
+ elsif header.type == HeaderNode::RIGHT_PAGE
1259
+ @headers[2] = header
1260
+ elsif header.type == HeaderNode::FIRST_PAGE
1261
+ @headers[3] = header
1262
+ end
1263
+ end
1264
+
1265
+ # This method assigns a new footer to a document. A Document object can
1266
+ # have up to four footers - a default footer, a footer for left pages, a
1267
+ # footer for right pages and a footer for the first page. The method
1268
+ # checks the footer type and stores it appropriately.
1269
+ #
1270
+ # ==== Parameters
1271
+ # footer:: A reference to the footer object to be stored. Existing footer
1272
+ # objects are overwritten.
1273
+ def footer=(footer)
1274
+ if footer.type == FooterNode::UNIVERSAL
1275
+ @footers[0] = footer
1276
+ elsif footer.type == FooterNode::LEFT_PAGE
1277
+ @footers[1] = footer
1278
+ elsif footer.type == FooterNode::RIGHT_PAGE
1279
+ @footers[2] = footer
1280
+ elsif footer.type == FooterNode::FIRST_PAGE
1281
+ @footers[3] = footer
1282
+ end
1283
+ end
1284
+
1285
+ # This method fetches a header from a Document object.
1286
+ #
1287
+ # ==== Parameters
1288
+ # type:: One of the header types defined in the header class. Defaults to
1289
+ # HeaderNode::UNIVERSAL.
1290
+ def header(type=HeaderNode::UNIVERSAL)
1291
+ index = 0
1292
+ if type == HeaderNode::LEFT_PAGE
1293
+ index = 1
1294
+ elsif type == HeaderNode::RIGHT_PAGE
1295
+ index = 2
1296
+ elsif type == HeaderNode::FIRST_PAGE
1297
+ index = 3
1298
+ end
1299
+ @headers[index]
1300
+ end
1301
+
1302
+ # This method fetches a footer from a Document object.
1303
+ #
1304
+ # ==== Parameters
1305
+ # type:: One of the footer types defined in the footer class. Defaults to
1306
+ # FooterNode::UNIVERSAL.
1307
+ def footer(type=FooterNode::UNIVERSAL)
1308
+ index = 0
1309
+ if type == FooterNode::LEFT_PAGE
1310
+ index = 1
1311
+ elsif type == FooterNode::RIGHT_PAGE
1312
+ index = 2
1313
+ elsif type == FooterNode::FIRST_PAGE
1314
+ index = 3
1315
+ end
1316
+ @footers[index]
1317
+ end
1318
+
1319
+ # Attribute mutator.
1320
+ #
1321
+ # ==== Parameters
1322
+ # font:: The new default font for the Document object.
1323
+ def default_font=(font)
1324
+ @fonts << font
1325
+ @default_font = @fonts.index(font)
1326
+ end
1327
+
1328
+ # This method provides a short cut for obtaining the Paper object
1329
+ # associated with a Document object.
1330
+ def paper
1331
+ @style.paper
1332
+ end
1333
+
1334
+ # This method overrides the parent=() method inherited from the
1335
+ # CommandNode class to disallow setting a parent on a Document object.
1336
+ #
1337
+ # ==== Parameters
1338
+ # parent:: A reference to the new parent node for the Document object.
1339
+ #
1340
+ # ==== Exceptions
1341
+ # RTFError:: Generated whenever this method is called.
1342
+ def parent=(parent)
1343
+ RTFError.fire("Document objects may not have a parent.")
1344
+ end
1345
+
1346
+ # This method inserts a page break into a document.
1347
+ def page_break
1348
+ self.store(CommandNode.new(self, '\page', nil, false))
1349
+ nil
1350
+ end
1351
+
1352
+ # This method fetches the width of the available work area space for a
1353
+ # typical Document object page.
1354
+ def body_width
1355
+ @style.body_width
1356
+ end
1357
+
1358
+ # This method fetches the height of the available work area space for a
1359
+ # a typical Document object page.
1360
+ def body_height
1361
+ @style.body_height
1362
+ end
1363
+
1364
+ # This method generates the RTF text for a Document object.
1365
+ def to_rtf
1366
+ text = StringIO.new
1367
+
1368
+ text << "{#{prefix}\\#{@character_set.id2name}"
1369
+ text << "\\deff#{@default_font}"
1370
+ text << "\\deflang#{@language}" if @language != nil
1371
+ text << "\\plain\\fs24\\fet1"
1372
+ text << "\n#{@fonts.to_rtf}"
1373
+ text << "\n#{@colours.to_rtf}" if @colours.size > 0
1374
+ text << "\n#{@information.to_rtf}"
1375
+ if @headers.compact != []
1376
+ text << "\n#{@headers[3].to_rtf}" if @headers[3] != nil
1377
+ text << "\n#{@headers[2].to_rtf}" if @headers[2] != nil
1378
+ text << "\n#{@headers[1].to_rtf}" if @headers[1] != nil
1379
+ if @headers[1] == nil or @headers[2] == nil
1380
+ text << "\n#{@headers[0].to_rtf}"
1381
+ end
1382
+ end
1383
+ if @footers.compact != []
1384
+ text << "\n#{@footers[3].to_rtf}" if @footers[3] != nil
1385
+ text << "\n#{@footers[2].to_rtf}" if @footers[2] != nil
1386
+ text << "\n#{@footers[1].to_rtf}" if @footers[1] != nil
1387
+ if @footers[1] == nil or @footers[2] == nil
1388
+ text << "\n#{@footers[0].to_rtf}"
1389
+ end
1390
+ end
1391
+ text << "\n#{@style.prefix(self)}" if @style != nil
1392
+ self.each {|entry| text << "\n#{entry.to_rtf}"}
1393
+ text << "\n}"
1394
+
1395
+ text.string
1396
+ end
1397
+ end # End of the Document class.
1398
+ end # End of the RTF module.