from types import IntType, FloatType, LongType, StringTypes from copy import deepcopy from binascii import hexlify from Constants import * from Styles import * class UnhandledParamError( Exception ) : def __init__( self, param ) : Exception.__init__( self, "Don't know what to do with param %s" % param ) # red green blue StandardColours = Colours() StandardColours.append( Colour( 'Black', 0, 0, 0 ) ) StandardColours.append( Colour( 'Blue', 0, 0, 255 ) ) StandardColours.append( Colour( 'Turquoise', 0, 255, 255 ) ) StandardColours.append( Colour( 'Green', 0, 255, 0 ) ) StandardColours.append( Colour( 'Pink', 255, 0, 255 ) ) StandardColours.append( Colour( 'Red', 255, 0, 0 ) ) StandardColours.append( Colour( 'Yellow', 255, 255, 0 ) ) StandardColours.append( Colour( 'White', 255, 255, 255 ) ) StandardColours.append( Colour( 'Blue Dark', 0, 0, 128 ) ) StandardColours.append( Colour( 'Teal', 0, 128, 128 ) ) StandardColours.append( Colour( 'Green Dark', 0, 128, 0 ) ) StandardColours.append( Colour( 'Violet', 128, 0, 128 ) ) StandardColours.append( Colour( 'Red Dark', 128, 0, 0 ) ) StandardColours.append( Colour( 'Yellow Dark', 128, 128, 0 ) ) StandardColours.append( Colour( 'Grey Dark', 128, 128, 128 ) ) StandardColours.append( Colour( 'Grey', 192, 192, 192 ) ) StandardFonts = Fonts() StandardFonts.append( Font( 'Arial' , 'swiss' , 0, 2, '020b0604020202020204' ) ) StandardFonts.append( Font( 'Arial Black' , 'swiss' , 0, 2, '020b0a04020102020204' ) ) StandardFonts.append( Font( 'Arial Narrow' , 'swiss' , 0, 2, '020b0506020202030204' ) ) StandardFonts.append( Font( 'Bitstream Vera Sans Mono', 'modern', 0, 1, '020b0609030804020204' ) ) StandardFonts.append( Font( 'Bitstream Vera Sans' , 'swiss' , 0, 2, '020b0603030804020204' ) ) StandardFonts.append( Font( 'Bitstream Vera Serif' , 'roman' , 0, 2, '02060603050605020204' ) ) StandardFonts.append( Font( 'Book Antiqua' , 'roman' , 0, 2, '02040602050305030304' ) ) StandardFonts.append( Font( 'Bookman Old Style' , 'roman' , 0, 2, '02050604050505020204' ) ) StandardFonts.append( Font( 'Castellar' , 'roman' , 0, 2, '020a0402060406010301' ) ) StandardFonts.append( Font( 'Century Gothic' , 'swiss' , 0, 2, '020b0502020202020204' ) ) StandardFonts.append( Font( 'Comic Sans MS' , 'script', 0, 2, '030f0702030302020204' ) ) StandardFonts.append( Font( 'Courier New' , 'modern', 0, 1, '02070309020205020404' ) ) StandardFonts.append( Font( 'Franklin Gothic Medium' , 'swiss' , 0, 2, '020b0603020102020204' ) ) StandardFonts.append( Font( 'Garamond' , 'roman' , 0, 2, '02020404030301010803' ) ) StandardFonts.append( Font( 'Georgia' , 'roman' , 0, 2, '02040502050405020303' ) ) StandardFonts.append( Font( 'Haettenschweiler' , 'swiss' , 0, 2, '020b0706040902060204' ) ) StandardFonts.append( Font( 'Impact' , 'swiss' , 0, 2, '020b0806030902050204' ) ) StandardFonts.append( Font( 'Lucida Console' , 'modern', 0, 1, '020b0609040504020204' ) ) StandardFonts.append( Font( 'Lucida Sans Unicode' , 'swiss' , 0, 2, '020b0602030504020204' ) ) StandardFonts.append( Font( 'Microsoft Sans Serif' , 'swiss' , 0, 2, '020b0604020202020204' ) ) StandardFonts.append( Font( 'Monotype Corsiva' , 'script', 0, 2, '03010101010201010101' ) ) StandardFonts.append( Font( 'Palatino Linotype' , 'roman' , 0, 2, '02040502050505030304' ) ) StandardFonts.append( Font( 'Papyrus' , 'script', 0, 2, '03070502060502030205' ) ) StandardFonts.append( Font( 'Sylfaen' , 'roman' , 0, 2, '010a0502050306030303' ) ) StandardFonts.append( Font( 'Symbol' , 'roman' , 2, 2, '05050102010706020507' ) ) StandardFonts.append( Font( 'Tahoma' , 'swiss' , 0, 2, '020b0604030504040204' ) ) StandardFonts.append( Font( 'Times New Roman' , 'roman' , 0, 2, '02020603050405020304' ) ) StandardFonts.append( Font( 'Trebuchet MS' , 'swiss' , 0, 2, '020b0603020202020204' ) ) StandardFonts.append( Font( 'Verdana' , 'swiss' , 0, 2, '020b0604030504040204' ) ) StandardFonts.Castellar.SetAlternate( StandardFonts.Georgia ) """ Found the following definition at http://www.pbdr.com/vbtips/gen/convtwip.htm Twips are screen-independent units used to ensure that the placement and proportion of screen elements in your screen application are the same on all display systems. A twip is a unit of screen measurement equal to 1/20 of a printer's point. The conversion between twips and inches/centimeters/millimeters is as follows: There are approximately 1440 twips to a inch (the length of a screen item measuring one inch when printed). As there are 2.54 centimeters to 1 inch, then there are approximately 567 twips to a centimeter (the length of a screen item measuring one centimeter when printed). Or in millimeters, as there are 25.4 millimeters to 1 inch, therefore there are approximately 56.7 twips to a millimeter (the length of a screen item measuring one millimeter when printed).""" # Width default is 12240, Height default is 15840 StandardPaper = Papers() StandardPaper.append( Paper( 'LETTER' , 1, 'Letter 8 1/2 x 11 in' , 12240, 15840 ) ) StandardPaper.append( Paper( 'LETTERSMALL' , 2, 'Letter Small 8 1/2 x 11 in' , 12240, 15840 ) ) StandardPaper.append( Paper( 'TABLOID' , 3, 'Tabloid 11 x 17 in' , 15840, 24480 ) ) StandardPaper.append( Paper( 'LEDGER' , 4, 'Ledger 17 x 11 in' , 24480, 15840 ) ) StandardPaper.append( Paper( 'LEGAL' , 5, 'Legal 8 1/2 x 14 in' , 12240, 20160 ) ) StandardPaper.append( Paper( 'STATEMENT' , 6, 'Statement 5 1/2 x 8 1/2 in' , 7920, 12240 ) ) StandardPaper.append( Paper( 'EXECUTIVE' , 7, 'Executive 7 1/4 x 10 1/2 in' , 10440, 15120 ) ) StandardPaper.append( Paper( 'A3' , 8, 'A3 297 x 420 mm' , 16838, 23811 ) ) StandardPaper.append( Paper( 'A4' , 9, 'A4 210 x 297 mm' , 11907, 16838 ) ) StandardPaper.append( Paper( 'A4SMALL' , 10, 'A4 Small 210 x 297 mm' , 11907, 16838 ) ) StandardPaper.append( Paper( 'A5' , 11, 'A5 148 x 210 mm' , 8391, 11907 ) ) StandardPaper.append( Paper( 'B4' , 12, 'B4 (JIS) 250 x 354' , 14175, 20072 ) ) StandardPaper.append( Paper( 'B5' , 13, 'B5 (JIS) 182 x 257 mm' , 10319, 14572 ) ) StandardPaper.append( Paper( 'FOLIO' , 14, 'Folio 8 1/2 x 13 in' , 12240, 18720 ) ) StandardPaper.append( Paper( 'QUARTO' , 15, 'Quarto 215 x 275 mm' , 12191, 15593 ) ) StandardPaper.append( Paper( '10X14' , 16, '10x14 in' , 14400, 20160 ) ) StandardPaper.append( Paper( '11X17' , 17, '11x17 in' , 15840, 24480 ) ) StandardPaper.append( Paper( 'NOTE' , 18, 'Note 8 1/2 x 11 in' , 12240, 15840 ) ) StandardPaper.append( Paper( 'ENV_9' , 19, 'Envelope #9 3 7/8 x 8 7/8' , 5580, 12780 ) ) StandardPaper.append( Paper( 'ENV_10' , 20, 'Envelope #10 4 1/8 x 9 1/2' , 5940, 13680 ) ) StandardPaper.append( Paper( 'ENV_11' , 21, 'Envelope #11 4 1/2 x 10 3/8' , 6480, 14940 ) ) StandardPaper.append( Paper( 'ENV_12' , 22, 'Envelope #12 4 3/4 x 11' , 6840, 15840 ) ) StandardPaper.append( Paper( 'ENV_14' , 23, 'Envelope #14 5 x 11 1/2' , 7200, 16560 ) ) StandardPaper.append( Paper( 'CSHEET' , 24, 'C size sheet 18 x 24 in' , 29520, 34560 ) ) StandardPaper.append( Paper( 'DSHEET' , 25, 'D size sheet 22 x 34 in' , 31680, 48960 ) ) StandardPaper.append( Paper( 'ESHEET' , 26, 'E size sheet 34 x 44 in' , 48960, 63360 ) ) StandardPaper.append( Paper( 'ENV_DL' , 27, 'Envelope DL 110 x 220mm' , 6237, 12474 ) ) StandardPaper.append( Paper( 'ENV_C5' , 28, 'Envelope C5 162 x 229 mm' , 9185, 12984 ) ) StandardPaper.append( Paper( 'ENV_C3' , 29, 'Envelope C3 324 x 458 mm' , 18371, 25969 ) ) StandardPaper.append( Paper( 'ENV_C4' , 30, 'Envelope C4 229 x 324 mm' , 12984, 18371 ) ) StandardPaper.append( Paper( 'ENV_C6' , 31, 'Envelope C6 114 x 162 mm' , 6464, 9185 ) ) StandardPaper.append( Paper( 'ENV_C65' , 32, 'Envelope C65 114 x 229 mm' , 6464, 12984 ) ) StandardPaper.append( Paper( 'ENV_B4' , 33, 'Envelope B4 250 x 353 mm' , 14175, 20015 ) ) StandardPaper.append( Paper( 'ENV_B5' , 34, 'Envelope B5 176 x 250 mm' , 9979, 14175 ) ) StandardPaper.append( Paper( 'ENV_B6' , 35, 'Envelope B6 176 x 125 mm' , 9979, 7088 ) ) StandardPaper.append( Paper( 'ENV_ITALY' , 36, 'Envelope 110 x 230 mm' , 6237, 13041 ) ) StandardPaper.append( Paper( 'ENV_MONARCH' , 37, 'Envelope Monarch 3.875 x 7.5 in' , 5580, 10800 ) ) StandardPaper.append( Paper( 'ENV_PERSONAL' , 38, '6 3/4 Envelope 3 5/8 x 6 1/2 in' , 5220, 9360 ) ) StandardPaper.append( Paper( 'FANFOLD_US' , 39, 'US Std Fanfold 14 7/8 x 11 in' , 21420, 15840 ) ) StandardPaper.append( Paper( 'FANFOLD_STD_GERMAN' , 40, 'German Std Fanfold 8 1/2 x 12 in' , 12240, 17280 ) ) StandardPaper.append( Paper( 'FANFOLD_LGL_GERMAN' , 41, 'German Legal Fanfold 8 1/2 x 13 in' , 12240, 18720 ) ) # # Finally a StyleSheet in which all of this stuff is put together # class StyleSheet : def __init__( self, colours=None, fonts=None ) : self.Colours = colours or deepcopy( StandardColours ) self.Fonts = fonts or deepcopy( StandardFonts ) self.TextStyles = AttributedList() self.ParagraphStyles = AttributedList() class Section( list ) : NONE = 1 COLUMN = 2 PAGE = 3 EVEN = 4 ODD = 5 BREAK_TYPES = [ NONE, COLUMN, PAGE, EVEN, ODD ] def __init__( self, paper=None, margins=None, break_type=None, headery=None, footery=None, landscape=None, first_page_number=None ) : super( Section, self ).__init__() self.Paper = paper or StandardPaper.A4 self.SetMargins( margins ) self.Header = [] self.Footer = [] self.FirstHeader = [] self.FirstFooter = [] self.SetBreakType( break_type or self.NONE ) self.SetHeaderY( headery ) self.SetFooterY( footery ) self.SetLandscape( landscape ) self.SetFirstPageNumber( first_page_number ) def TwipsToRightMargin( self ) : return self.Paper.Width - ( self.Margins.Left + self.Margins.Right ) def SetMargins( self, value ) : self.Margins = value or MarginsPropertySet( top=1000, left=1200, bottom=1000, right=1200 ) self.Width = self.Paper.Width - ( self.Margins.Left + self.Margins.Right ) def SetBreakType( self, value ) : assert value in self.BREAK_TYPES self.BreakType = value return self def SetHeaderY( self, value ) : self.HeaderY = value return self def SetFooterY( self, value ) : self.FooterY = value return self def SetLandscape( self, value ) : self.Landscape = False if value : self.Landscape = True return self def SetFirstPageNumber( self, value ) : self.FirstPageNumber = value return self def MakeDefaultStyleSheet( ) : result = StyleSheet() NormalText = TextStyle( TextPropertySet( result.Fonts.Arial, 22 ) ) ps = ParagraphStyle( 'Normal', NormalText.Copy(), ParagraphPropertySet( space_before = 60, space_after = 60 ) ) result.ParagraphStyles.append( ps ) ps = ParagraphStyle( 'Normal Short', NormalText.Copy() ) result.ParagraphStyles.append( ps ) NormalText.TextPropertySet.SetSize( 32 ) ps = ParagraphStyle( 'Heading 1', NormalText.Copy(), ParagraphPropertySet( space_before = 240, space_after = 60 ) ) result.ParagraphStyles.append( ps ) NormalText.TextPropertySet.SetSize( 24 ).SetBold( True ) ps = ParagraphStyle( 'Heading 2', NormalText.Copy(), ParagraphPropertySet( space_before = 240, space_after = 60 ) ) result.ParagraphStyles.append( ps ) # Add some more in that are based on the normal template but that # have some indenting set that makes them suitable for doing numbered normal_numbered = result.ParagraphStyles.Normal.Copy() normal_numbered.SetName( 'Normal Numbered' ) normal_numbered.ParagraphPropertySet.SetFirstLineIndent( TabPropertySet.DEFAULT_WIDTH * -1 ) normal_numbered.ParagraphPropertySet.SetLeftIndent ( TabPropertySet.DEFAULT_WIDTH ) result.ParagraphStyles.append( normal_numbered ) normal_numbered2 = result.ParagraphStyles.Normal.Copy() normal_numbered2.SetName( 'Normal Numbered 2' ) normal_numbered2.ParagraphPropertySet.SetFirstLineIndent( TabPropertySet.DEFAULT_WIDTH * -1 ) normal_numbered2.ParagraphPropertySet.SetLeftIndent ( TabPropertySet.DEFAULT_WIDTH * 2 ) result.ParagraphStyles.append( normal_numbered2 ) ## LIST STYLES for idx, indent in [ (1, TabPS.DEFAULT_WIDTH ), (2, TabPS.DEFAULT_WIDTH * 2), (3, TabPS.DEFAULT_WIDTH * 3) ] : indent = TabPropertySet.DEFAULT_WIDTH ps = ParagraphStyle( 'List %s' % idx, TextStyle( TextPropertySet( result.Fonts.Arial, 22 ) ), ParagraphPropertySet( space_before = 60, space_after = 60, first_line_indent = -indent, left_indent = indent) ) result.ParagraphStyles.append( ps ) return result class TAB : pass class LINE : pass class RawCode : def __init__( self, data ) : self.Data = data PAGE_NUMBER = RawCode( r'{\field{\fldinst page}}' ) TOTAL_PAGES = RawCode( r'{\field{\fldinst numpages}}' ) SECTION_PAGES = RawCode( r'{\field{\fldinst sectionpages}}' ) ARIAL_BULLET = RawCode( r'{\f2\'95}' ) def _get_jpg_dimensions( fin ): """ converted from: http://dev.w3.org/cvsweb/Amaya/libjpeg/rdjpgcom.c?rev=1.2 """ M_SOF0 = chr( 0xC0 ) # /* Start Of Frame N */ M_SOF1 = chr( 0xC1 ) # /* N indicates which compression process */ M_SOF2 = chr( 0xC2 ) # /* Only SOF0-SOF2 are now in common use */ M_SOF3 = chr( 0xC3 ) # M_SOF5 = chr( 0xC5 ) # /* NB: codes C4 and CC are NOT SOF markers */ M_SOF6 = chr( 0xC6 ) # M_SOF7 = chr( 0xC7 ) # M_SOF9 = chr( 0xC9 ) # M_SOF10 = chr( 0xCA ) # M_SOF11 = chr( 0xCB ) # M_SOF13 = chr( 0xCD ) # M_SOF14 = chr( 0xCE ) # M_SOF15 = chr( 0xCF ) # M_SOI = chr( 0xD8 ) # /* Start Of Image (beginning of datastream) */ M_EOI = chr( 0xD9 ) # /* End Of Image (end of datastream) */ M_FF = chr( 0xFF ) MARKERS = [ M_SOF0, M_SOF1, M_SOF2, M_SOF3, M_SOF5, M_SOF6, M_SOF7, M_SOF9, M_SOF10,M_SOF11, M_SOF13, M_SOF14, M_SOF15 ] def get_length() : b1 = fin.read( 1 ) b2 = fin.read( 1 ) return (ord(b1) << 8) + ord(b2) def next_marker() : # markers come straight after an 0xFF so skip everything # up to the first 0xFF that we find while fin.read(1) != M_FF : pass # there can be more than one 0xFF as they can be used # for padding so we are now looking for the first byte # that isn't an 0xFF, this will be the marker while True : result = fin.read(1) if result != M_FF : return result raise Exception( 'Invalid JPEG' ) # BODY OF THE FUNCTION if not ((fin.read(1) == M_FF) and (fin.read(1) == M_SOI)) : raise Exception( 'Invalid Jpeg' ) while True : marker = next_marker() # the marker is always followed by two bytes representing the length of the data field length = get_length () if length < 2 : raise Exception( "Erroneous JPEG marker length" ) # if it is a compression process marker then it will contain the dimension of the image if marker in MARKERS : # the next byte is the data precision, just skip it fin.read(1) # bingo image_height = get_length() image_width = get_length() return image_width, image_height # just skip whatever data it contains fin.read( length - 2 ) raise Exception( 'Invalid JPEG, end of stream reached' ) _PNG_HEADER = '\x89\x50\x4e' def _get_png_dimensions( data ) : if data[0:3] != _PNG_HEADER : raise Exception( 'Invalid PNG image' ) width = (ord(data[18]) * 256) + (ord(data[19])) height = (ord(data[22]) * 256) + (ord(data[23])) return width, height class Image( RawCode ) : # Need to add in the width and height in twips as it crashes # word xp with these values. Still working out the most # efficient way of getting these values. # \picscalex100\picscaley100\piccropl0\piccropr0\piccropt0\piccropb0 # picwgoal900\pichgoal281 PNG_LIB = 'pngblip' JPG_LIB = 'jpegblip' PICT_TYPES = { 'png' : PNG_LIB, 'jpg' : JPG_LIB } def __init__( self, file_name, **kwargs ) : fin = file( file_name, 'rb' ) pict_type = self.PICT_TYPES[ file_name[ -3 : ].lower() ] if pict_type == self.PNG_LIB : width, height = _get_png_dimensions( fin.read( 100 ) ) else : width, height = _get_jpg_dimensions( fin ) codes = [ pict_type, 'picwgoal%s' % (width * 20), 'pichgoal%s' % (height * 20) ] for kwarg, code, default in [ ( 'scale_x', 'scalex', '100' ), ( 'scale_y', 'scaley', '100' ), ( 'crop_left', 'cropl', '0' ), ( 'crop_right', 'cropr', '0' ), ( 'crop_top', 'cropt', '0' ), ( 'crop_bottom', 'cropb', '0' ) ] : codes.append( 'pic%s%s' % ( code, kwargs.pop( kwarg, default ) ) ) # reset back to the start of the file to get all of it and now # turn it into hex. fin.seek( 0, 0 ) data = [] image = hexlify( fin.read() ) for i in range( 0, len( image ), 128 ) : data.append( image[ i : i + 128 ] ) data = r'{\pict{\%s}%s}' % ( '\\'.join( codes ), '\n'.join( data ) ) RawCode.__init__( self, data ) def ToRawCode( self, var_name ) : return '%s = RawCode( """%s""" )' % ( var_name, self.Data ) class Text : def __init__( self, *params ) : self.Data = None self.Style = None self.Properties = None self.Shading = None for param in params : if isinstance( param, TextStyle ) : self.Style = param elif isinstance( param, TextPS ) : self.Properties = param elif isinstance( param, ShadingPS ) : self.Shading = param else : # otherwise let the rendering custom handler sort it out itself self.Data = param def SetData( self, value ) : self.Data = value class Inline( list ) : def __init__( self, *params ) : super( Inline, self ).__init__() self.Style = None self.Properties = None self.Shading = None self._append = super( Inline, self ).append for param in params : if isinstance( param, TextStyle ) : self.Style = param elif isinstance( param, TextPS ) : self.Properties = param elif isinstance( param, ShadingPS ) : self.Shading = param else : # otherwise we add to it to our list of elements and let # the rendering custom handler sort it out itself. self.append( param ) def append( self, *params ) : # filter out any that are explicitly None [ self._append( param ) for param in params if param is not None ] class Paragraph( list ) : def __init__( self, *params ) : super( Paragraph, self ).__init__() self.Style = None self.Properties = None self.Frame = None self.Shading = None self._append = super( Paragraph, self ).append for param in params : if isinstance( param, ParagraphStyle ) : self.Style = param elif isinstance( param, ParagraphPS ) : self.Properties = param elif isinstance( param, FramePS ) : self.Frame = param elif isinstance( param, ShadingPS ) : self.Shading = param else : # otherwise we add to it to our list of elements and let # the rendering custom handler sort it out itself. self.append( param ) def append( self, *params ) : # filter out any that are explicitly None [ self._append( param ) for param in params if param is not None ] def insert( self, index, value ) : if value is not None : super( Paragraph, self ).insert( index, value ) class Table : LEFT = 1 RIGHT = 2 CENTER = 3 ALIGNMENT = [ LEFT, RIGHT, CENTER ] NO_WRAPPING = 1 WRAP_AROUND = 2 WRAPPING = [ NO_WRAPPING, WRAP_AROUND ] # trrh height of row, 0 means automatically adjust, use negative for an absolute # trgaph is half of the space between a table cell in width, reduce this one # to get a really tiny column def __init__( self, *column_widths, **kwargs ) : self.Rows = [] self.SetAlignment ( kwargs.pop( 'alignment', self.LEFT ) ) self.SetLeftOffset ( kwargs.pop( 'left_offset', None ) ) self.SetGapBetweenCells( kwargs.pop( 'gap_between_cells', None ) ) self.SetColumnWidths ( *column_widths ) assert not kwargs, 'invalid keyword args %s' % kwargs def SetAlignment( self, value ) : assert value is None or value in self.ALIGNMENT self.Alignment = value or self.LEFT return self def SetLeftOffset( self, value ) : self.LeftOffset = value return self def SetGapBetweenCells( self, value ) : self.GapBetweenCells = value return self def SetColumnWidths( self, *column_widths ) : self.ColumnWidths = column_widths self.ColumnCount = len( column_widths ) return self def AddRow( self, *cells ) : height = None if isinstance( cells[ 0 ], (IntType, FloatType, LongType) ): height = int( cells[ 0 ] ) cells = cells[ 1 : ] # make sure all of the spans add up to the number of columns # otherwise the table will get corrupted if self.ColumnCount != sum( [ cell.Span for cell in cells ] ) : raise Exception( 'ColumnCount != the total of this row\'s cell.Spans.' ) self.Rows.append( ( height, cells ) ) append = AddRow class Cell( list ) : """ \clvertalt Text is top-aligned in cell (the default). \clvertalc Text is centered vertically in cell. \clvertalb Text is bottom-aligned in cell. \cltxlrtb Vertical text aligned left (direction bottom up). \cltxtbrl Vertical text aligned right (direction top down). """ ALIGN_TOP = 1 ALIGN_CENTER = 2 ALIGN_BOTTOM = 3 FLOW_LR_TB = 1 FLOW_RL_TB = 2 FLOW_LR_BT = 3 FLOW_VERTICAL_LR_TB = 4 FLOW_VERTICAL_TB_RL = 5 def __init__( self, *params, **kwargs ) : super( Cell, self ).__init__() self.SetFrame ( None ) self.SetMargins( None ) self.SetAlignment( kwargs.get( 'alignment', self.ALIGN_TOP ) ) self.SetFlow ( kwargs.get( 'flow' , self.FLOW_LR_TB ) ) self.SetSpan ( kwargs.get( 'span', 1 ) ) self.SetStartVerticalMerge( kwargs.get( 'start_vertical_merge', False ) ) self.SetVerticalMerge ( kwargs.get( 'vertical_merge', False ) ) self._append = super( Cell, self ).append for param in params : if isinstance( param, StringType ) : self.append ( param ) elif isinstance( param, Paragraph ) : self.append ( param ) elif isinstance( param, FramePS ) : self.SetFrame ( param ) elif isinstance( param, MarginsPS ) : self.SetMargins( param ) def SetFrame( self, value ) : self.Frame = value return self def SetMargins( self, value ) : self.Margins = value return self def SetAlignment( self, value ) : assert value in [ self.ALIGN_TOP, self.ALIGN_CENTER, self.ALIGN_BOTTOM ] #, self.ALIGN_TEXT_TOP_DOWN, self.ALIGN_TEXT_BOTTOM_UP ] self.Alignment = value def SetFlow( self, value ) : assert value in [ self.FLOW_LR_TB, self.FLOW_RL_TB, self.FLOW_LR_BT, self.FLOW_VERTICAL_LR_TB, self.FLOW_VERTICAL_TB_RL ] self.Flow = value def SetSpan( self, value ) : # must be a positive integer self.Span = int( max( value, 1 ) ) return self def SetStartVerticalMerge( self, value ) : self.StartVerticalMerge = False if value : self.StartVerticalMerge = True return self def SetVerticalMerge( self, value ) : self.VerticalMerge = False if value : self.VerticalMerge = True return self def append( self, *params ) : [ self._append( param ) for param in params ] class Document : def __init__( self, style_sheet=None, default_language=None, view_kind=None, view_zoom_kind=None, view_scale=None ) : self.StyleSheet = style_sheet or MakeDefaultStyleSheet() self.Sections = AttributedList( Section ) self.SetTitle( None ) self.DefaultLanguage = default_language or Languages.DEFAULT self.ViewKind = view_kind or ViewKind.DEFAULT self.ViewZoomKind = view_zoom_kind self.ViewScale = view_scale def NewSection( self, *params, **kwargs ) : result = Section( *params, **kwargs ) self.Sections.append( result ) return result def SetTitle( self, value ) : self.Title = value return self def Copy( self ) : result = Document( style_sheet = self.StyleSheet.Copy(), default_language = self.DefaultLanguage, view_kind = self.ViewKind, view_zoom_kind = self.ViewZoomKind, view_scale = self.ViewScale ) result.SetTitle( self.Title ) result.Sections = self.Sections.Copy() return result def TEXT( *params, **kwargs ) : text_props = TextPropertySet() text_props.SetFont ( kwargs.get( 'font', None ) ) text_props.SetSize ( kwargs.get( 'size', None ) ) text_props.SetBold ( kwargs.get( 'bold', False ) ) text_props.SetItalic ( kwargs.get( 'italic', False ) ) text_props.SetUnderline( kwargs.get( 'underline', False ) ) text_props.SetColour ( kwargs.get( 'colour', None ) ) if len( params ) == 1 : return Text( params[ 0 ], text_props ) result = Inline( text_props ) apply( result.append, params ) return result def B( *params ) : text_props = TextPropertySet( bold=True ) if len( params ) == 1 : return Text( params[ 0 ], text_props ) result = Inline( text_props ) apply( result.append, params ) return result def I( *params ) : text_props = TextPropertySet( italic=True ) if len( params ) == 1 : return Text( params[ 0 ], text_props ) result = Inline( text_props ) apply( result.append, params ) return result def U( *params ) : text_props = TextPropertySet( underline=True ) if len( params ) == 1 : return Text( params[ 0 ], text_props ) result = Inline( text_props ) apply( result.append, params ) return result