diff options
| author | pinky <> | 2007-01-07 23:34:45 +0000 |
|---|---|---|
| committer | pinky <> | 2007-01-07 23:34:45 +0000 |
| commit | ac5f8444449ad5cae6a7ca5f4c7e313c9caa9fdb (patch) | |
| tree | 05b3ad3a3a03ae428da5e07a4b605e2fa2daee1f /bin/reportlab/lib/sequencer.py | |
| parent | 3af6ec6aa7cbb9c5ae2a99e8e21f02a771924916 (diff) | |
RL2
bzr revid: pinky-2e44d4c158101b4eb29c9fb7cee91c9aaabfed06
Diffstat (limited to 'bin/reportlab/lib/sequencer.py')
| -rw-r--r-- | bin/reportlab/lib/sequencer.py | 284 |
1 files changed, 284 insertions, 0 deletions
diff --git a/bin/reportlab/lib/sequencer.py b/bin/reportlab/lib/sequencer.py new file mode 100644 index 00000000000..c9d9274d2d7 --- /dev/null +++ b/bin/reportlab/lib/sequencer.py @@ -0,0 +1,284 @@ +#Copyright ReportLab Europe Ltd. 2000-2004 +#see license.txt for license details +#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/lib/sequencer.py +__version__=''' $Id: sequencer.py 2423 2004-08-24 11:36:22Z rgbecker $ ''' +"""This module defines a single public class, Sequencer, which aids in +numbering and formatting lists.""" +# +# roman numbers conversion thanks to +# +# fredrik lundh, november 1996 (based on a C hack from 1984) +# +# fredrik@pythonware.com +# http://www.pythonware.com + +_RN_TEMPLATES = [ 0, 01, 011, 0111, 012, 02, 021, 0211, 02111, 013 ] +_RN_LETTERS = "IVXLCDM" + +from string import lower + + +def _format_I(value): + if value < 0 or value > 3999: + raise ValueError, "illegal value" + str = "" + base = -1 + while value: + value, index = divmod(value, 10) + tmp = _RN_TEMPLATES[index] + while tmp: + tmp, index = divmod(tmp, 8) + str = _RN_LETTERS[index+base] + str + base = base + 2 + return str + +def _format_i(num): + return lower(_format_I(num)) + +def _format_123(num): + """The simplest formatter""" + return str(num) + +def _format_ABC(num): + """Uppercase. Wraps around at 26.""" + n = (num -1) % 26 + return chr(n+65) + +def _format_abc(num): + """Lowercase. Wraps around at 26.""" + n = (num -1) % 26 + return chr(n+97) + + +class _Counter: + """Private class used by Sequencer. Each counter + knows its format, and the IDs of anything it + resets, as well as its value. Starts at zero + and increments just before you get the new value, + so that it is still 'Chapter 5' and not 'Chapter 6' + when you print 'Figure 5.1'""" + + def __init__(self): + self._base = 0 + self._value = self._base + self._formatter = _format_123 + self._resets = [] + + def setFormatter(self, formatFunc): + self._formatter = formatFunc + + def reset(self, value=None): + if value: + self._value = value + else: + self._value = self._base + + def next(self): + self._value = self._value + 1 + v = self._value + for counter in self._resets: + counter.reset() + return v + + def _this(self): + return self._value + + def nextf(self): + """Returns next value formatted""" + return self._formatter(self.next()) + + def thisf(self): + return self._formatter(self._this()) + + def chain(self, otherCounter): + if not otherCounter in self._resets: + self._resets.append(otherCounter) + + +class Sequencer: + """Something to make it easy to number paragraphs, sections, + images and anything else. The features include registering + new string formats for sequences, and 'chains' whereby + some counters are reset when their parents. + It keeps track of a number of + 'counters', which are created on request: + Usage: + >>> seq = layout.Sequencer() + >>> seq.next('Bullets') + 1 + >>> seq.next('Bullets') + 2 + >>> seq.next('Bullets') + 3 + >>> seq.reset('Bullets') + >>> seq.next('Bullets') + 1 + >>> seq.next('Figures') + 1 + >>> + """ + + def __init__(self): + self._counters = {} #map key to current number + self._defaultCounter = None + + self._formatters = { + # the formats it knows initially + '1':_format_123, + 'A':_format_ABC, + 'a':_format_abc, + 'I':_format_I, + 'i':_format_i, + } + + def _getCounter(self, counter=None): + """Creates one if not present""" + try: + return self._counters[counter] + except KeyError: + cnt = _Counter() + self._counters[counter] = cnt + return cnt + + def _this(self, counter=None): + """Retrieves counter value but does not increment. For + new counters, sets base value to 1.""" + if not counter: + counter = self._defaultCounter + return self._getCounter(counter)._this() + + def next(self, counter=None): + """Retrieves the numeric value for the given counter, then + increments it by one. New counters start at one.""" + if not counter: + counter = self._defaultCounter + return self._getCounter(counter).next() + + def thisf(self, counter=None): + if not counter: + counter = self._defaultCounter + return self._getCounter(counter).thisf() + + def nextf(self, counter=None): + """Retrieves the numeric value for the given counter, then + increments it by one. New counters start at one.""" + if not counter: + counter = self._defaultCounter + return self._getCounter(counter).nextf() + + def setDefaultCounter(self, default=None): + """Changes the key used for the default""" + self._defaultCounter = default + + def registerFormat(self, format, func): + """Registers a new formatting function. The funtion + must take a number as argument and return a string; + fmt is a short menmonic string used to access it.""" + self._formatters[format] = func + + def setFormat(self, counter, format): + """Specifies that the given counter should use + the given format henceforth.""" + func = self._formatters[format] + self._getCounter(counter).setFormatter(func) + + def reset(self, counter=None, base=0): + if not counter: + counter = self._defaultCounter + self._getCounter(counter)._value = base + + def chain(self, parent, child): + p = self._getCounter(parent) + c = self._getCounter(child) + p.chain(c) + + def __getitem__(self, key): + """Allows compact notation to support the format function. + s['key'] gets current value, s['key+'] increments.""" + if key[-1:] == '+': + counter = key[:-1] + return self.nextf(counter) + else: + return self.thisf(key) + + def format(self, template): + """The crowning jewels - formats multi-level lists.""" + return template % self + + def dump(self): + """Write current state to stdout for diagnostics""" + counters = self._counters.items() + counters.sort() + print 'Sequencer dump:' + for (key, counter) in counters: + print ' %s: value = %d, base = %d, format example = %s' % ( + key, counter._this(), counter._base, counter.thisf()) + + +"""Your story builder needs to set this to""" +_sequencer = None + +def getSequencer(): + global _sequencer + if _sequencer is None: + _sequencer = Sequencer() + return _sequencer + +def setSequencer(seq): + global _sequencer + s = _sequencer + _sequencer = seq + return s + +def test(): + s = Sequencer() + print 'Counting using default sequence: %d %d %d' % (s.next(),s.next(), s.next()) + print 'Counting Figures: Figure %d, Figure %d, Figure %d' % ( + s.next('figure'), s.next('figure'), s.next('figure')) + print 'Back to default again: %d' % s.next() + s.setDefaultCounter('list1') + print 'Set default to list1: %d %d %d' % (s.next(),s.next(), s.next()) + s.setDefaultCounter() + print 'Set default to None again: %d %d %d' % (s.next(),s.next(), s.next()) + print + print 'Creating Appendix counter with format A, B, C...' + s.setFormat('Appendix', 'A') + print ' Appendix %s, Appendix %s, Appendix %s' % ( + s.nextf('Appendix'), s.nextf('Appendix'),s.nextf('Appendix')) + + def format_french(num): + return ('un','deux','trois','quatre','cinq')[(num-1)%5] + print + print 'Defining a custom format with french words:' + s.registerFormat('french', format_french) + s.setFormat('FrenchList', 'french') + print ' ', + for i in range(1,6): + print s.nextf('FrenchList'), + print + print 'Chaining H1 and H2 - H2 goes back to one when H1 increases' + s.chain('H1','H2') + print ' H1 = %d' % s.next('H1') + print ' H2 = %d' % s.next('H2') + print ' H2 = %d' % s.next('H2') + print ' H2 = %d' % s.next('H2') + print ' H1 = %d' % s.next('H1') + print ' H2 = %d' % s.next('H2') + print ' H2 = %d' % s.next('H2') + print ' H2 = %d' % s.next('H2') + print + print 'GetItem notation - append a plus to increment' + print ' seq["Appendix"] = %s' % s["Appendix"] + print ' seq["Appendix+"] = %s' % s["Appendix+"] + print ' seq["Appendix+"] = %s' % s["Appendix+"] + print ' seq["Appendix"] = %s' % s["Appendix"] + print + print 'Finally, string format notation for nested lists. Cool!' + print 'The expression ("Figure %(Chapter)s.%(Figure+)s" % seq) gives:' + print ' Figure %(Chapter)s.%(Figure+)s' % s + print ' Figure %(Chapter)s.%(Figure+)s' % s + print ' Figure %(Chapter)s.%(Figure+)s' % s + + +if __name__=='__main__': + test() |
