"Fossies" - the Fresh Open Source Software Archive

Member "reportlab-3.5.23/src/reportlab/lib/styles.py" (31 May 2019, 16778 Bytes) of package /linux/privat/reportlab-3.5.23.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "styles.py" see the Fossies "Dox" file reference documentation.

    1 #Copyright ReportLab Europe Ltd. 2000-2017
    2 #see license.txt for license details
    3 #history https://bitbucket.org/rptlab/reportlab/history-node/tip/src/reportlab/lib/styles.py
    4 __version__='3.3.0'
    5 __doc__='''Classes for ParagraphStyle and similar things.
    6 
    7 A style is a collection of attributes, but with some extra features
    8 to allow 'inheritance' from a parent, and to ensure nobody makes
    9 changes after construction.
   10 
   11 ParagraphStyle shows all the attributes available for formatting
   12 paragraphs.
   13 
   14 getSampleStyleSheet()  returns a stylesheet you can use for initial
   15 development, with a few basic heading and text styles.
   16 '''
   17 __all__=(
   18         'PropertySet',
   19         'ParagraphStyle',
   20         'LineStyle',
   21         'ListStyle',
   22         'StyleSheet1',
   23         'getSampleStyleSheet',
   24         )
   25 from reportlab.lib.colors import white, black
   26 from reportlab.lib.enums import TA_LEFT, TA_CENTER
   27 from reportlab.lib.fonts import tt2ps
   28 from reportlab.rl_config import canvas_basefontname as _baseFontName, \
   29                                 underlineWidth as _baseUnderlineWidth, \
   30                                 underlineOffset as _baseUnderlineOffset, \
   31                                 underlineGap as _baseUnderlineGap, \
   32                                 strikeWidth as _baseStrikeWidth, \
   33                                 strikeOffset as _baseStrikeOffset, \
   34                                 strikeGap as _baseStrikeGap, \
   35                                 spaceShrinkage as _spaceShrinkage, \
   36                                 platypus_link_underline as _platypus_link_underline, \
   37                                 hyphenationLang as _hyphenationLang, \
   38                                 hyphenationMinWordLength as _hyphenationMinWordLength, \
   39                                 uriWasteReduce as _uriWasteReduce, \
   40                                 embeddedHyphenation as _embeddedHyphenation
   41 _baseFontNameB = tt2ps(_baseFontName,1,0)
   42 _baseFontNameI = tt2ps(_baseFontName,0,1)
   43 _baseFontNameBI = tt2ps(_baseFontName,1,1)
   44 
   45 ###########################################################
   46 # This class provides an 'instance inheritance'
   47 # mechanism for its descendants, simpler than acquisition
   48 # but not as far-reaching
   49 ###########################################################
   50 class PropertySet:
   51     defaults = {}
   52 
   53     def __init__(self, name, parent=None, **kw):
   54         """When initialized, it copies the class defaults;
   55         then takes a copy of the attributes of the parent
   56         if any.  All the work is done in init - styles
   57         should cost little to use at runtime."""
   58         # step one - validate the hell out of it
   59         assert 'name' not in self.defaults, "Class Defaults may not contain a 'name' attribute"
   60         assert 'parent' not in self.defaults, "Class Defaults may not contain a 'parent' attribute"
   61         if parent:
   62             assert parent.__class__ == self.__class__, "Parent style %s must have same class as new style %s" % (parent.__class__.__name__,self.__class__.__name__)
   63 
   64         #step two
   65         self.name = name
   66         self.parent = parent
   67         self.__dict__.update(self.defaults)
   68 
   69         #step two - copy from parent if any.  Try to be
   70         # very strict that only keys in class defaults are
   71         # allowed, so they cannot inherit
   72         self.refresh()
   73         self._setKwds(**kw)
   74 
   75     def _setKwds(self,**kw):
   76         #step three - copy keywords if any
   77         for key, value in kw.items():
   78              self.__dict__[key] = value
   79 
   80     def __repr__(self):
   81         return "<%s '%s'>" % (self.__class__.__name__, self.name)
   82 
   83     def refresh(self):
   84         """re-fetches attributes from the parent on demand;
   85         use if you have been hacking the styles.  This is
   86         used by __init__"""
   87         if self.parent:
   88             for key, value in self.parent.__dict__.items():
   89                 if (key not in ['name','parent']):
   90                     self.__dict__[key] = value
   91 
   92     def listAttrs(self, indent=''):
   93         print(indent + 'name =', self.name)
   94         print(indent + 'parent =', self.parent)
   95         keylist = list(self.__dict__.keys())
   96         keylist.sort()
   97         keylist.remove('name')
   98         keylist.remove('parent')
   99         for key in keylist:
  100             value = self.__dict__.get(key, None)
  101             print(indent + '%s = %s' % (key, value))
  102 
  103     def clone(self, name, parent=None, **kwds):
  104         r = self.__class__(name,parent)
  105         r.__dict__ = self.__dict__.copy()
  106         r.name = name
  107         r.parent = parent is None and self or parent
  108         r._setKwds(**kwds)
  109         return r
  110 
  111 class ParagraphStyle(PropertySet):
  112     defaults = {
  113         'fontName':_baseFontName,
  114         'fontSize':10,
  115         'leading':12,
  116         'leftIndent':0,
  117         'rightIndent':0,
  118         'firstLineIndent':0,
  119         'alignment':TA_LEFT,
  120         'spaceBefore':0,
  121         'spaceAfter':0,
  122         'bulletFontName':_baseFontName,
  123         'bulletFontSize':10,
  124         'bulletIndent':0,
  125         #'bulletColor':black,
  126         'textColor': black,
  127         'backColor':None,
  128         'wordWrap':None,        #None means do nothing special
  129                                 #CJK use Chinese Line breaking
  130                                 #LTR RTL use left to right / right to left
  131                                 #with support from pyfribi2 if available
  132         'borderWidth': 0,
  133         'borderPadding': 0,
  134         'borderColor': None,
  135         'borderRadius': None,
  136         'allowWidows': 1,
  137         'allowOrphans': 0,
  138         'textTransform':None,   #uppercase lowercase (captitalize not yet) or None or absent
  139         'endDots':None,         #dots on the last line of left/right justified paras
  140                                 #string or object with text and optional fontName, fontSize, textColor & backColor
  141                                 #dy
  142         'splitLongWords':1,     #make best efforts to split long words
  143         'underlineWidth': _baseUnderlineWidth,  #underline width
  144         'bulletAnchor': 'start',    #where the bullet is anchored ie start, middle, end or numeric
  145         'justifyLastLine': 0,   #n allow justification on the last line for more than n words 0 means don't bother
  146         'justifyBreaks': 0,     #justify lines broken with <br/>
  147         'spaceShrinkage': _spaceShrinkage,  #allow shrinkage of percentage of space to fit on line
  148         'strikeWidth': _baseStrikeWidth,    #stroke width
  149         'underlineOffset': _baseUnderlineOffset,    #fraction of fontsize to offset underlines
  150         'underlineGap': _baseUnderlineGap,      #gap for double/triple underline
  151         'strikeOffset': _baseStrikeOffset,  #fraction of fontsize to offset strikethrough
  152         'strikeGap': _baseStrikeGap,        #gap for double/triple strike
  153         'linkUnderline': _platypus_link_underline,
  154         #'underlineColor':  None,
  155         #'strikeColor': None,
  156         'hyphenationLang': _hyphenationLang,
  157         #'hyphenationMinWordLength': _hyphenationMinWordLength,
  158         'embeddedHyphenation': _embeddedHyphenation,
  159         'uriWasteReduce': _uriWasteReduce,
  160         }
  161 
  162 class LineStyle(PropertySet):
  163     defaults = {
  164         'width':1,
  165         'color': black
  166         }
  167     def prepareCanvas(self, canvas):
  168         """You can ask a LineStyle to set up the canvas for drawing
  169         the lines."""
  170         canvas.setLineWidth(1)
  171         #etc. etc.
  172 
  173 class ListStyle(PropertySet):
  174     defaults = dict(
  175                 leftIndent=18,
  176                 rightIndent=0,
  177                 bulletAlign='left',
  178                 bulletType='1',
  179                 bulletColor=black,
  180                 bulletFontName='Helvetica',
  181                 bulletFontSize=12,
  182                 bulletOffsetY=0,
  183                 bulletDedent='auto',
  184                 bulletDir='ltr',
  185                 bulletFormat=None,
  186                 start=None,         #starting value for a list; if a list then the start sequence
  187                 )
  188 
  189 _stylesheet1_undefined = object()
  190 
  191 class StyleSheet1:
  192     """
  193     This may or may not be used.  The idea is to:
  194     
  195     1. slightly simplify construction of stylesheets;
  196     
  197     2. enforce rules to validate styles when added
  198        (e.g. we may choose to disallow having both
  199        'heading1' and 'Heading1' - actual rules are
  200        open to discussion);
  201        
  202     3. allow aliases and alternate style lookup
  203        mechanisms
  204        
  205     4. Have a place to hang style-manipulation
  206        methods (save, load, maybe support a GUI
  207        editor)
  208    
  209     Access is via getitem, so they can be
  210     compatible with plain old dictionaries.
  211     """
  212 
  213     def __init__(self):
  214         self.byName = {}
  215         self.byAlias = {}
  216 
  217     def __getitem__(self, key):
  218         try:
  219             return self.byAlias[key]
  220         except KeyError:
  221             try:
  222                 return self.byName[key]
  223             except KeyError:
  224                 raise KeyError("Style '%s' not found in stylesheet" % key)
  225 
  226     def get(self,key,default=_stylesheet1_undefined):
  227         try:
  228             return self[key]
  229         except KeyError:
  230             if default!=_stylesheet1_undefined: return default
  231             raise
  232 
  233     def __contains__(self, key):
  234         return key in self.byAlias or key in self.byName
  235 
  236     def has_key(self,key):
  237         return key in self
  238 
  239     def add(self, style, alias=None):
  240         key = style.name
  241         if key in self.byName:
  242             raise KeyError("Style '%s' already defined in stylesheet" % key)
  243         if key in self.byAlias:
  244             raise KeyError("Style name '%s' is already an alias in stylesheet" % key)
  245 
  246         if alias:
  247             if alias in self.byName:
  248                 raise KeyError("Style '%s' already defined in stylesheet" % alias)
  249             if alias in self.byAlias:
  250                 raise KeyError("Alias name '%s' is already an alias in stylesheet" % alias)
  251         #passed all tests?  OK, add it
  252         self.byName[key] = style
  253         if alias:
  254             self.byAlias[alias] = style
  255 
  256     def list(self):
  257         styles = list(self.byName.items())
  258         styles.sort()
  259         alii = {}
  260         for (alias, style) in list(self.byAlias.items()):
  261             alii[style] = alias
  262         for (name, style) in styles:
  263             alias = alii.get(style, None)
  264             print(name, alias)
  265             style.listAttrs('    ')
  266             print()
  267 
  268 def testStyles():
  269     pNormal = ParagraphStyle('Normal',None)
  270     pNormal.fontName = _baseFontName
  271     pNormal.fontSize = 12
  272     pNormal.leading = 14.4
  273 
  274     pNormal.listAttrs()
  275     print()
  276     pPre = ParagraphStyle('Literal', pNormal)
  277     pPre.fontName = 'Courier'
  278     pPre.listAttrs()
  279     return pNormal, pPre
  280 
  281 def getSampleStyleSheet():
  282     """Returns a stylesheet object"""
  283     stylesheet = StyleSheet1()
  284 
  285     stylesheet.add(ParagraphStyle(name='Normal',
  286                                   fontName=_baseFontName,
  287                                   fontSize=10,
  288                                   leading=12)
  289                    )
  290 
  291     stylesheet.add(ParagraphStyle(name='BodyText',
  292                                   parent=stylesheet['Normal'],
  293                                   spaceBefore=6)
  294                    )
  295     stylesheet.add(ParagraphStyle(name='Italic',
  296                                   parent=stylesheet['BodyText'],
  297                                   fontName = _baseFontNameI)
  298                    )
  299 
  300     stylesheet.add(ParagraphStyle(name='Heading1',
  301                                   parent=stylesheet['Normal'],
  302                                   fontName = _baseFontNameB,
  303                                   fontSize=18,
  304                                   leading=22,
  305                                   spaceAfter=6),
  306                    alias='h1')
  307 
  308     stylesheet.add(ParagraphStyle(name='Title',
  309                                   parent=stylesheet['Normal'],
  310                                   fontName = _baseFontNameB,
  311                                   fontSize=18,
  312                                   leading=22,
  313                                   alignment=TA_CENTER,
  314                                   spaceAfter=6),
  315                    alias='title')
  316 
  317     stylesheet.add(ParagraphStyle(name='Heading2',
  318                                   parent=stylesheet['Normal'],
  319                                   fontName = _baseFontNameB,
  320                                   fontSize=14,
  321                                   leading=18,
  322                                   spaceBefore=12,
  323                                   spaceAfter=6),
  324                    alias='h2')
  325 
  326     stylesheet.add(ParagraphStyle(name='Heading3',
  327                                   parent=stylesheet['Normal'],
  328                                   fontName = _baseFontNameBI,
  329                                   fontSize=12,
  330                                   leading=14,
  331                                   spaceBefore=12,
  332                                   spaceAfter=6),
  333                    alias='h3')
  334 
  335     stylesheet.add(ParagraphStyle(name='Heading4',
  336                                   parent=stylesheet['Normal'],
  337                                   fontName = _baseFontNameBI,
  338                                   fontSize=10,
  339                                   leading=12,
  340                                   spaceBefore=10,
  341                                   spaceAfter=4),
  342                    alias='h4')
  343 
  344     stylesheet.add(ParagraphStyle(name='Heading5',
  345                                   parent=stylesheet['Normal'],
  346                                   fontName = _baseFontNameB,
  347                                   fontSize=9,
  348                                   leading=10.8,
  349                                   spaceBefore=8,
  350                                   spaceAfter=4),
  351                    alias='h5')
  352 
  353     stylesheet.add(ParagraphStyle(name='Heading6',
  354                                   parent=stylesheet['Normal'],
  355                                   fontName = _baseFontNameB,
  356                                   fontSize=7,
  357                                   leading=8.4,
  358                                   spaceBefore=6,
  359                                   spaceAfter=2),
  360                    alias='h6')
  361 
  362     stylesheet.add(ParagraphStyle(name='Bullet',
  363                                   parent=stylesheet['Normal'],
  364                                   firstLineIndent=0,
  365                                   spaceBefore=3),
  366                    alias='bu')
  367 
  368     stylesheet.add(ParagraphStyle(name='Definition',
  369                                   parent=stylesheet['Normal'],
  370                                   firstLineIndent=0,
  371                                   leftIndent=36,
  372                                   bulletIndent=0,
  373                                   spaceBefore=6,
  374                                   bulletFontName=_baseFontNameBI),
  375                    alias='df')
  376 
  377     stylesheet.add(ParagraphStyle(name='Code',
  378                                   parent=stylesheet['Normal'],
  379                                   fontName='Courier',
  380                                   fontSize=8,
  381                                   leading=8.8,
  382                                   firstLineIndent=0,
  383                                   leftIndent=36,
  384                                   hyphenationLang=''))
  385 
  386     stylesheet.add(ListStyle(name='UnorderedList',
  387                                 parent=None,
  388                                 leftIndent=18,
  389                                 rightIndent=0,
  390                                 bulletAlign='left',
  391                                 bulletType='1',
  392                                 bulletColor=black,
  393                                 bulletFontName='Helvetica',
  394                                 bulletFontSize=12,
  395                                 bulletOffsetY=0,
  396                                 bulletDedent='auto',
  397                                 bulletDir='ltr',
  398                                 bulletFormat=None,
  399                                 #start='circle square blackstar sparkle disc diamond'.split(),
  400                                 start=None,
  401                             ),
  402                    alias='ul')
  403 
  404     stylesheet.add(ListStyle(name='OrderedList',
  405                                 parent=None,
  406                                 leftIndent=18,
  407                                 rightIndent=0,
  408                                 bulletAlign='left',
  409                                 bulletType='1',
  410                                 bulletColor=black,
  411                                 bulletFontName='Helvetica',
  412                                 bulletFontSize=12,
  413                                 bulletOffsetY=0,
  414                                 bulletDedent='auto',
  415                                 bulletDir='ltr',
  416                                 bulletFormat=None,
  417                                 #start='1 a A i I'.split(),
  418                                 start=None,
  419                             ),
  420                    alias='ol')
  421     return stylesheet