source: OpenRLabs-Git/deploy/rlabs-docker/web2py-rlabs/gluon/contrib/pyrtf/Renderer.py

main
Last change on this file was 42bd667, checked in by David Fuertes <dfuertes@…>, 4 years ago

Historial Limpio

  • Property mode set to 100755
File size: 25.5 KB
Line 
1from copy import deepcopy
2
3from .Elements import *
4from .Constants import PY2
5if PY2:
6    StringType = basestring
7else:
8    StringType = str
9
10DEFAULT_TAB_WIDTH = 720
11
12ParagraphAlignmentMap = { ParagraphPropertySet.LEFT       : 'ql',
13                          ParagraphPropertySet.RIGHT      : 'qr',
14                          ParagraphPropertySet.CENTER     : 'qc',
15                          ParagraphPropertySet.JUSTIFY    : 'qj',
16                          ParagraphPropertySet.DISTRIBUTE : 'qd' }
17
18TabAlignmentMap = { TabPropertySet.LEFT    : '',
19                    TabPropertySet.RIGHT   : 'tqr',
20                    TabPropertySet.CENTER  : 'tqc',
21                    TabPropertySet.DECIMAL : 'tqdec' }
22
23TableAlignmentMap = { Table.LEFT   : 'trql',
24                      Table.RIGHT  : 'trqr',
25                      Table.CENTER : 'trqc' }
26
27CellAlignmentMap = { Cell.ALIGN_TOP            : '', # clvertalt
28                     Cell.ALIGN_CENTER         : 'clvertalc',
29                     Cell.ALIGN_BOTTOM         : 'clvertalb' }
30
31CellFlowMap = { Cell.FLOW_LR_TB          : '',           # cltxlrtb, Text in a cell flows from left to right and top to bottom (default)
32                Cell.FLOW_RL_TB          : 'cltxtbrl',   # Text in a cell flows right to left and top to bottom
33                Cell.FLOW_LR_BT          : 'cltxbtlr',   # Text in a cell flows left to right and bottom to top
34                Cell.FLOW_VERTICAL_LR_TB : 'cltxlrtbv',  # Text in a cell flows left to right and top to bottom, vertical
35                Cell.FLOW_VERTICAL_TB_RL : 'cltxtbrlv' } # Text in a cell flows top to bottom and right to left, vertical
36
37ShadingPatternMap = { ShadingPropertySet.HORIZONTAL             : 'bghoriz',
38                      ShadingPropertySet.VERTICAL               : 'bgvert',
39                      ShadingPropertySet.FORWARD_DIAGONAL       : 'bgfdiag',
40                      ShadingPropertySet.BACKWARD_DIAGONAL      : 'bgbdiag',
41                      ShadingPropertySet.VERTICAL_CROSS         : 'bgcross',
42                      ShadingPropertySet.DIAGONAL_CROSS         : 'bgdcross',
43                      ShadingPropertySet.DARK_HORIZONTAL        : 'bgdkhoriz',
44                      ShadingPropertySet.DARK_VERTICAL          : 'bgdkvert',
45                      ShadingPropertySet.DARK_FORWARD_DIAGONAL  : 'bgdkfdiag',
46                      ShadingPropertySet.DARK_BACKWARD_DIAGONAL : 'bgdkbdiag',
47                      ShadingPropertySet.DARK_VERTICAL_CROSS    : 'bgdkcross',
48                      ShadingPropertySet.DARK_DIAGONAL_CROSS    : 'bgdkdcross' }
49
50TabLeaderMap = { TabPropertySet.DOTS        : 'tldot',
51                 TabPropertySet.HYPHENS     : 'tlhyph',
52                 TabPropertySet.UNDERLINE   : 'tlul',
53                 TabPropertySet.THICK_LINE  : 'tlth',
54                 TabPropertySet.EQUAL_SIGN  : 'tleq' }
55
56BorderStyleMap = { BorderPropertySet.SINGLE   : 'brdrs',
57                   BorderPropertySet.DOUBLE   : 'brdrth',
58                   BorderPropertySet.SHADOWED : 'brdrsh',
59                   BorderPropertySet.DOUBLED  : 'brdrdb',
60                   BorderPropertySet.DOTTED   : 'brdrdot',
61                   BorderPropertySet.DASHED   : 'brdrdash',
62                   BorderPropertySet.HAIRLINE : 'brdrhair' }
63
64SectionBreakTypeMap = { Section.NONE   : 'sbknone',
65                        Section.COLUMN : 'sbkcol',
66                        Section.PAGE   : 'sbkpage',
67                        Section.EVEN   : 'sbkeven',
68                        Section.ODD    : 'sbkodd' }
69
70class Settings( list ) :
71    def __init__( self ) :
72        super( Settings, self ).__init__()
73        self._append = super( Settings, self ).append
74
75    def append( self, value, mask=None, fallback=None ) :
76        if (value is not 0) and value in [ False, None, '' ] :
77            if fallback : self._append( self, fallback )
78
79        else :
80            if mask :
81                if value is True :
82                    value = mask
83                else :
84                    value = mask % value
85            self._append( value )
86
87    def Join( self ) :
88        if self : return r'\%s' % '\\'.join( self )
89        return ''
90
91    def __repr__( self ) :
92        return self.Join()
93
94class Renderer :
95    def __init__( self, write_custom_element_callback=None ) :
96        self.character_style_map = {}
97        self.paragraph_style_map = {}
98        self.WriteCustomElement  = write_custom_element_callback
99
100    #
101    #   All of the Rend* Functions populate a Settings object with values
102    #
103    def _RendPageProperties( self, section, settings, in_section ) :
104        #  this one is different from the others as it takes the settings from a
105        if in_section :
106            #paper_size_code   = 'psz%s'
107            paper_width_code  = 'pgwsxn%s'
108            paper_height_code = 'pghsxn%s'
109            landscape         = 'lndscpsxn'
110            margin_suffix     = 'sxn'
111
112        else :
113            #paper_size_code   = 'psz%s'
114            paper_width_code  = 'paperw%s'
115            paper_height_code = 'paperh%s'
116            landscape         = 'landscape'
117            margin_suffix     = ''
118
119        #settings.append( section.Paper.Code,   paper_size_code  )
120        settings.append( section.Paper.Width,  paper_width_code  )
121        settings.append( section.Paper.Height, paper_height_code )
122
123        if section.Landscape :
124            settings.append( landscape )
125
126        if section.FirstPageNumber :
127            settings.append( section.FirstPageNumber, 'pgnstarts%s' )
128            settings.append( 'pgnrestart' )
129
130        self._RendMarginsPropertySet( section.Margins, settings, margin_suffix )
131
132    def _RendShadingPropertySet( self, shading_props, settings, prefix='' ) :
133        if not shading_props : return
134
135        settings.append( shading_props.Shading, prefix + 'shading%s' )
136        settings.append( ShadingPatternMap.get( shading_props.Pattern, False ) )
137
138        settings.append( self._colour_map.get( shading_props.Foreground, False ), prefix + 'cfpat%s' )
139        settings.append( self._colour_map.get( shading_props.Background, False ), prefix + 'cbpat%s' )
140
141    def _RendBorderPropertySet( self, edge_props, settings ) :
142        settings.append( BorderStyleMap[ edge_props.Style ] )
143        settings.append( edge_props.Width                                , 'brdrw%s'  )
144        settings.append( self._colour_map.get( edge_props.Colour, False ), 'brdrcf%s' )
145        settings.append( edge_props.Spacing or False                     , 'brsp%s'   )
146
147    def _RendFramePropertySet( self, frame_props, settings, tag_prefix='' ) :
148        if not frame_props : return
149
150        if frame_props.Top :
151            settings.append( tag_prefix + 'brdrt' )
152            self._RendBorderPropertySet( frame_props.Top, settings )
153
154        if frame_props.Left :
155            settings.append( tag_prefix + 'brdrl' )
156            self._RendBorderPropertySet( frame_props.Left, settings )
157
158        if frame_props.Bottom :
159            settings.append( tag_prefix + 'brdrb' )
160            self._RendBorderPropertySet( frame_props.Bottom, settings )
161
162        if frame_props.Right :
163            settings.append( tag_prefix + 'brdrr' )
164            self._RendBorderPropertySet( frame_props.Right, settings )
165
166    def _RendMarginsPropertySet( self, margin_props, settings, suffix='' ) :
167        if not margin_props : return
168
169        settings.append( margin_props.Top,    'margt' + suffix + '%s' )
170        settings.append( margin_props.Left,   'margl' + suffix + '%s' )
171        settings.append( margin_props.Bottom, 'margb' + suffix + '%s' )
172        settings.append( margin_props.Right,  'margr' + suffix + '%s' )
173
174    def _RendParagraphPropertySet( self, paragraph_props, settings ) :
175        if not paragraph_props : return
176        settings.append( ParagraphAlignmentMap[ paragraph_props.Alignment ] )
177
178        settings.append( paragraph_props.SpaceBefore, 'sb%s' )
179        settings.append( paragraph_props.SpaceAfter,  'sa%s' )
180
181        #   then we have to find out all of the tabs
182        width = 0
183        for tab in paragraph_props.Tabs :
184            settings.append( TabAlignmentMap[ tab.Alignment ]   )
185            settings.append( TabLeaderMap.get( tab.Leader, '' ) )
186
187            width += tab.Width or DEFAULT_TAB_WIDTH
188            settings.append( 'tx%s' % width             )
189
190        settings.append( paragraph_props.PageBreakBefore, 'pagebb' )
191
192        settings.append( paragraph_props.FirstLineIndent, 'fi%s'   )
193        settings.append( paragraph_props.LeftIndent,      'li%s'   )
194        settings.append( paragraph_props.RightIndent,     'ri%s'   )
195
196        if paragraph_props.SpaceBetweenLines :
197            if paragraph_props.SpaceBetweenLines < 0 :
198                settings.append( paragraph_props.SpaceBetweenLines, r'sl%s\slmult0' )
199            else :
200                settings.append( paragraph_props.SpaceBetweenLines, r'sl%s\slmult1' )
201
202    def _RendTextPropertySet( self, text_props, settings ) :
203        if not text_props : return
204
205        if text_props.Expansion :
206            settings.append( text_props.Expansion, 'expndtw%s' )
207
208        settings.append( text_props.Bold,            'b'    )
209        settings.append( text_props.Italic,          'i'    )
210        settings.append( text_props.Underline,       'ul'   )
211        settings.append( text_props.DottedUnderline, 'uld'  )
212        settings.append( text_props.DoubleUnderline, 'uldb' )
213        settings.append( text_props.WordUnderline,   'ulw'  )
214
215        settings.append( self._font_map.get( text_props.Font, False ), 'f%s' )
216        settings.append( text_props.Size, 'fs%s' )
217        settings.append( self._colour_map.get( text_props.Colour, False ), 'cf%s' )
218
219        if text_props.Frame :
220            frame = text_props.Frame
221            settings.append( 'chbrdr' )
222            settings.append( BorderStyleMap[ frame.Style ] )
223            settings.append( frame.Width                                , 'brdrw%s' )
224            settings.append( self._colour_map.get( frame.Colour, False ), 'brdrcf%s' )
225
226    #
227    #   All of the Write* functions will write to the internal file object
228    #
229    #   the _ ones probably don't need to be used by anybody outside
230    #   but the other ones like WriteTextElement could be used in the Custom
231    #   callback.
232    def Write( self, document, fout ) :
233        #  write all of the standard stuff based upon the first document
234        self._doc  = document
235        self._fout = fout
236        self._WriteDocument  ()
237        self._WriteColours   ()
238        self._WriteFonts     ()
239        self._WriteStyleSheet()
240
241        settings = Settings()
242        self._RendPageProperties( self._doc.Sections[ 0 ], settings, in_section=False )
243        self._write( repr( settings ) )
244
245        #  handle the simplest case first, we don't need to do anymore mucking around
246        #  with section headers, etc we can just rip the document out
247        if len( document.Sections ) == 1 :
248            self._WriteSection( document.Sections[ 0 ],
249                                is_first   = True,
250                                add_header = False )
251
252        else :
253            for section_idx, section in enumerate( document.Sections ) :
254                is_first       = section_idx == 0
255                add_header     = True
256                self._WriteSection( section, is_first, add_header )
257
258        self._write( '}' )
259
260        del self._fout, self._doc, self._CurrentStyle
261
262    def _write( self, data, *params ) :
263        #----------------------------------
264        # begin modification
265        # by Herbert Weinhandl
266        # to convert accented characters
267        # to their rtf-compatible form
268        #for c in range( 128, 256 ) :
269        #   data = data.replace( chr(c), "\'%x" % c)
270        # end modification
271        #
272        #  This isn't the right place for this as it is going to do
273        #  this loop for all sorts of writes, including settings, control codes, etc.
274        #
275        #  I will create a def _WriteText (or something) method that is used when the
276        #  actual string that is to be viewed in the document is written, this can then
277        #  do the final accented character check.
278        #
279        #  I left it here so that I remember to do the right thing when I have time
280        #----------------------------------
281
282        if params : data = data % params
283        self._fout.write( data )
284
285    def _WriteDocument( self ) :
286        settings = Settings()
287
288        assert Languages.IsValid   ( self._doc.DefaultLanguage )
289        assert ViewKind.IsValid    ( self._doc.ViewKind        )
290        assert ViewZoomKind.IsValid( self._doc.ViewZoomKind    )
291        assert ViewScale.IsValid   ( self._doc.ViewScale       )
292
293        settings.append( self._doc.DefaultLanguage, 'deflang%s'   )
294        settings.append( self._doc.ViewKind       , 'viewkind%s'  )
295        settings.append( self._doc.ViewZoomKind   , 'viewzk%s'    )
296        settings.append( self._doc.ViewScale      , 'viewscale%s' )
297
298        self._write( "{\\rtf1\\ansi\\ansicpg1252\\deff0%s\n" % settings )
299
300    def _WriteColours( self ) :
301        self._write( r"{\colortbl ;" )
302
303        self._colour_map = {}
304        offset = 0
305        for colour in self._doc.StyleSheet.Colours :
306            self._write( r'\red%s\green%s\blue%s;', colour.Red, colour.Green, colour.Blue )
307            self._colour_map[ colour ] = offset + 1
308            offset += 1
309        self._write( "}\n" )
310
311    def _WriteFonts( self ) :
312        self._write( r'{\fonttbl' )
313
314        self._font_map = {}
315        offset = 0
316        for font in self._doc.StyleSheet.Fonts :
317            pitch     = ''
318            panose    = ''
319            alternate = ''
320            if font.Pitch     : pitch     = r'\fprq%s'    % font.Pitch
321            if font.Panose    : panose    = r'{\*\panose %s}' % font.Panose
322            if font.Alternate : alternate = r'{\*\falt %s}'   % font.Alternate.Name
323
324            self._write( r'{\f%s\f%s%s\fcharset%s%s %s%s;}',
325                         offset,
326                         font.Family,
327                         pitch,
328                         font.CharacterSet,
329                         panose,
330                         font.Name,
331                         alternate )
332
333            self._font_map[ font ] = offset
334            offset += 1
335
336        self._write( "}\n" )
337
338    def _WriteStyleSheet( self ) :
339        self._write( r"{\stylesheet" )
340
341        #   TO DO: character styles, does anybody actually use them?
342
343        offset_map = {}
344        for idx, style in enumerate( self._doc.StyleSheet.ParagraphStyles ) :
345            offset_map[ style ] = idx
346
347        #   paragraph styles
348        self.paragraph_style_map = {}
349        for idx, style in enumerate( self._doc.StyleSheet.ParagraphStyles ) :
350
351            if idx == 0 :
352                default = style
353            else :
354                self._write( '\n' )
355
356            settings = Settings()
357
358            #   paragraph properties
359            self._RendParagraphPropertySet( style.ParagraphPropertySet, settings )
360            self._RendFramePropertySet    ( style.FramePropertySet,     settings )
361            self._RendShadingPropertySet  ( style.ShadingPropertySet,   settings )
362
363            #   text properties
364            self._RendTextPropertySet   ( style.TextStyle.TextPropertySet,     settings )
365            self._RendShadingPropertySet( style.TextStyle.ShadingPropertySet,  settings )
366
367            #   have to take
368            based_on = '\\sbasedon%s' % offset_map.get( style.BasedOn, 0 )
369            next     = '\\snext%s'    % offset_map.get( style.Next,    0 )
370
371            inln = '\\s%s%s' % ( idx, settings )
372            self._write( "{%s%s%s %s;}", inln, based_on, next, style.Name )
373
374            self.paragraph_style_map[ style ] = inln
375
376        #   if now style is specified for the first paragraph to be written, this one
377        #   will be used
378        self._CurrentStyle = self.paragraph_style_map[ default ]
379
380        self._write( "}\n" )
381
382    def _WriteSection( self, section, is_first, add_header ) :
383
384        def WriteHF( hf, rtfword ) :
385            #if not hf : return
386
387            #  if we don't have anything in the header/footer then include
388            #  a blank paragraph, this stops it from picking up the header/footer
389            #  from the previous section
390            # if not hf :   hf = [ Paragraph( '' ) ]
391            if not hf : hf = []
392
393            self._write( '{\\%s' % rtfword )
394            self._WriteElements( hf )
395            self._write( '}\n' )
396
397        settings = Settings()
398
399        if not is_first :
400            #  we need to finish off the preceding section
401            #  and reset all of our defaults back to standard
402            settings.append( 'sect'  )
403
404        #  reset to our defaults
405        settings.append( 'sectd' )
406
407        if add_header :
408            settings.append( SectionBreakTypeMap[ section.BreakType ] )
409            self._RendPageProperties( section, settings, in_section=True )
410
411        settings.append( section.HeaderY, 'headery%s' )
412        settings.append( section.FooterY, 'footery%s' )
413
414        #  write all of these out now as we need to do a write elements in the
415        #  next section
416        self._write( repr( settings ) )
417
418        #   finally after all that has settled down we can do the
419        #   headers and footers
420        if section.FirstHeader or section.FirstFooter :
421            #  include the titlepg flag if the first page has a special format
422            self._write( r'\titlepg' )
423            WriteHF( section.FirstHeader, 'headerf' )
424            WriteHF( section.FirstFooter, 'footerf' )
425
426        WriteHF( section.Header, 'header' )
427        WriteHF( section.Footer, 'footer' )
428
429        #   and at last the contents of the section that actually appear on the page
430        self._WriteElements( section )
431
432    def _WriteElements( self, elements ) :
433        new_line = ''
434        for element in elements :
435            self._write( new_line )
436            new_line = '\n'
437
438            clss = element.__class__
439
440            if clss == Paragraph :
441                self.WriteParagraphElement( element )
442
443            elif clss == Table :
444                self.WriteTableElement( element )
445
446            elif ininstance(element, StringType) :
447                self.WriteParagraphElement( Paragraph( element ) )
448
449            elif clss in [ RawCode, Image ] :
450                self.WriteRawCode( element )
451
452            #elif clss == List  :
453            #   self._HandleListElement( element )
454
455            elif self.WriteCustomElement :
456                self.WriteCustomElement( self, element )
457
458            else :
459                raise Exception( "Don't know how to handle elements of type %s" % clss )
460
461    def WriteParagraphElement( self, paragraph_elem, tag_prefix='', tag_suffix=r'\par', opening='{', closing='}' ) :
462
463        #   the tag_prefix and the tag_suffix take care of paragraphs in tables.  A
464        #   paragraph in a table requires and extra tag at the front (intbl) and we
465        #   don't want the ending tag everytime.  We want it for all paragraphs but
466        #   the last.
467
468        overrides = Settings()
469        self._RendParagraphPropertySet( paragraph_elem.Properties, overrides )
470        self._RendFramePropertySet    ( paragraph_elem.Frame,      overrides )
471        self._RendShadingPropertySet  ( paragraph_elem.Shading,    overrides )
472
473        #   when writing the RTF the style is carried from the previous paragraph to the next,
474        #   so if the currently written paragraph has a style then make it the current one,
475        #   otherwise leave it as it was
476        self._CurrentStyle = self.paragraph_style_map.get( paragraph_elem.Style, self._CurrentStyle )
477
478        self._write( r'%s\pard\plain%s %s%s ' % ( opening, tag_prefix, self._CurrentStyle, overrides ) )
479
480        for element in paragraph_elem :
481
482            if isinstance( element, StringType ) :
483                self._write( element )
484
485            elif isinstance( element, RawCode ) :
486                self._write( element.Data )
487
488            elif isinstance( element, Text ) :
489                self.WriteTextElement( element )
490
491            elif isinstance( element, Inline ) :
492                self.WriteInlineElement( element )
493
494            elif element == TAB :
495                self._write( r'\tab ' )
496
497            elif element == LINE :
498                self._write( r'\line ' )
499
500            elif self.WriteCustomElement :
501                self.WriteCustomElement( self, element )
502
503            else :
504                raise Exception( 'Don\'t know how to handle %s' % element )
505
506        self._write( tag_suffix + closing )
507
508    def WriteRawCode( self, raw_elem ) :
509        self._write( raw_elem.Data )
510
511    def WriteTextElement( self, text_elem ) :
512        overrides = Settings()
513
514        self._RendTextPropertySet   ( text_elem.Properties, overrides )
515        self._RendShadingPropertySet( text_elem.Shading,    overrides, 'ch' )
516
517        #   write the wrapper and then let the custom handler have a go
518        if overrides : self._write( '{%s ' % repr( overrides ) )
519
520        #   if the data is just a string then we can now write it
521        if isinstance( text_elem.Data, StringType ) :
522            self._write( text_elem.Data or '' )
523
524        elif text_elem.Data == TAB :
525            self._write( r'\tab ' )
526
527        else :
528            self.WriteCustomElement( self, text_elem.Data )
529
530        if overrides : self._write( '}' )
531
532    def WriteInlineElement( self, inline_elem ) :
533        overrides = Settings()
534
535        self._RendTextPropertySet   ( inline_elem.Properties, overrides )
536        self._RendShadingPropertySet( inline_elem.Shading,    overrides, 'ch' )
537
538        #   write the wrapper and then let the custom handler have a go
539        if overrides : self._write( '{%s ' % repr( overrides ) )
540
541        for element in inline_elem :
542            #   if the data is just a string then we can now write it
543            if isinstance( element, StringType ) :
544                self._write( element )
545
546            elif isinstance( element, RawCode ) :
547                self._write( element.Data )
548
549            elif element == TAB :
550                self._write( r'\tab ' )
551
552            elif element == LINE :
553                self._write( r'\line ' )
554
555            else :
556                self.WriteCustomElement( self, element )
557
558        if overrides : self._write( '}' )
559
560    def WriteText( self, text ) :
561        self._write( text or '' )
562
563    def WriteTableElement( self, table_elem ) :
564
565        vmerge = [ False ] * table_elem.ColumnCount
566        for height, cells in table_elem.Rows :
567
568            #   calculate the right hand edge of the cells taking into account the spans
569            offset   = table_elem.LeftOffset or 0
570            cellx    = []
571            cell_idx = 0
572            for cell in cells :
573                cellx.append( offset + sum( table_elem.ColumnWidths[ : cell_idx + cell.Span ] ) )
574                cell_idx += cell.Span
575
576            self._write( r'{\trowd' )
577
578            settings = Settings()
579
580            #   the spec says that this value is mandatory and I think that 108 is the default value
581            #   so I'll take care of it here
582            settings.append( table_elem.GapBetweenCells or 108, 'trgaph%s' )
583            settings.append( TableAlignmentMap[ table_elem.Alignment ] )
584            settings.append( height, 'trrh%s' )
585            settings.append( table_elem.LeftOffset, 'trleft%s' )
586
587            width = table_elem.LeftOffset or 0
588            for idx, cell in enumerate( cells ) :
589                self._RendFramePropertySet  ( cell.Frame,   settings, 'cl' )
590
591                #  cells don't have margins so I don't know why I was doing this
592                #  I think it might have an affect in some versions of some WPs.
593                #self._RendMarginsPropertySet( cell.Margins, settings, 'cl' )
594
595                #  if we are starting to merge or if this one is the first in what is
596                #  probably a series of merges then start the vertical merging
597                if cell.StartVerticalMerge or (cell.VerticalMerge and not vmerge[ idx ]) :
598                    settings.append( 'clvmgf' )
599                    vmerge[ idx ] = True
600
601                elif cell.VerticalMerge :
602                    #..continuing a merge
603                    settings.append( 'clvmrg' )
604
605                else :
606                    #..no merging going on so make sure that it is off
607                    vmerge[ idx ] = False
608
609                #  for any cell in the next row that is covered by this span we
610                #  need to run off the vertical merging as we don't want them
611                #  merging up into this spanned cell
612                for vmerge_idx in range( idx + 1, idx + cell.Span - 1 ) :
613                    vmerge[ vmerge_idx ] = False
614
615                settings.append( CellAlignmentMap[ cell.Alignment ] )
616                settings.append( CellFlowMap[ cell.Flow ] )
617
618                #  this terminates the definition of a cell and represents the right most edge of the cell from the left margin
619                settings.append( cellx[ idx ], 'cellx%s' )
620
621            self._write( repr( settings ) )
622
623            for cell in cells :
624                if len( cell ) :
625                    last_idx = len( cell ) - 1
626                    for element_idx, element in enumerate( cell ) :
627                        #   wrap plain strings in paragraph tags
628                        if isinstance( element, StringType ) :
629                            element = Paragraph( element )
630
631                        #   don't forget the prefix or else word crashes and does all sorts of strange things
632                        if element_idx == last_idx :
633                            self.WriteParagraphElement( element, tag_prefix=r'\intbl', tag_suffix='', opening='', closing='' )
634
635                        else :
636                            self.WriteParagraphElement( element, tag_prefix=r'\intbl', opening='', closing='' )
637
638                    self._write( r'\cell' )
639
640                else :
641                    self._write( r'\pard\intbl\cell' )
642
643            self._write( '\\row}\n' )
644
Note: See TracBrowser for help on using the repository browser.