rtf 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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.