reportlab: fixed <greek> added <unichar [name=..|code=../> to paragraph
authorrgbecker
Fri, 28 Apr 2006 14:08:58 +0000
changeset 2584 0fed2bd8ef90
parent 2583 9ee2e44c662d
child 2585 ee08fea4505b
reportlab: fixed <greek> added <unichar [name=..|code=../> to paragraph
reportlab/platypus/paragraph.py
reportlab/platypus/paraparser.py
reportlab/test/test_platypus_paragraphs.py
--- a/reportlab/platypus/paragraph.py	Thu Apr 27 17:42:12 2006 +0000
+++ b/reportlab/platypus/paragraph.py	Fri Apr 28 14:08:58 2006 +0000
@@ -1013,11 +1013,11 @@
 <onDraw name=myIndex label="Eingabeaufforderung :: (&gt;&gt;&gt;)">
 <b><font color=red>&gt;&gt;&gt; (Eingabeaufforderung)</font></b>
 <onDraw name=myIndex label="&gt;&gt;&gt; (Eingabeaufforderung)">
-Einf\374hrung in Python <b><font color=red>Python :: Einf\374hrung</font></b>
-<onDraw name=myIndex label="Python :: Einf\374hrung">.
+Einf&#xfc;hrung in Python <b><font color=red>Python :: Einf&#xfc;hrung</font></b>
+<onDraw name=myIndex label="Python :: Einf&#xfc;hrung">.
 Das Ziel ist, die grundlegenden Eigenschaften von Python darzustellen, ohne
 sich zu sehr in speziellen Regeln oder Details zu verstricken. Dazu behandelt
-dieses Kapitel kurz die wesentlichen Konzepte wie Variablen, Ausdr\374cke,
+dieses Kapitel kurz die wesentlichen Konzepte wie Variablen, Ausdr&#xfc;cke,
 Kontrollfluss, Funktionen sowie Ein- und Ausgabe. Es erhebt nicht den Anspruch,
 umfassend zu sein."""
         P=Paragraph(text, styleSheet['Code'])
@@ -1026,7 +1026,7 @@
         dumpParagraphLines(P)
 
     if flagged(4):
-        text='''Die eingebaute Funktion <font name=Courier>range(i, j [, stride])</font><onDraw name=myIndex label="eingebaute Funktionen::range()"><onDraw name=myIndex label="range() (Funktion)"><onDraw name=myIndex label="Funktionen::range()"> erzeugt eine Liste von Ganzzahlen und f\374llt sie mit Werten <font name=Courier>k</font>, f\374r die gilt: <font name=Courier>i &lt;= k &lt; j</font>. Man kann auch eine optionale Schrittweite angeben. Die eingebaute Funktion <font name=Courier>xrange()</font><onDraw name=myIndex label="eingebaute Funktionen::xrange()"><onDraw name=myIndex label="xrange() (Funktion)"><onDraw name=myIndex label="Funktionen::xrange()"> erf\374llt einen \344hnlichen Zweck, gibt aber eine unver\344nderliche Sequenz vom Typ <font name=Courier>XRangeType</font><onDraw name=myIndex label="XRangeType"> zur\374ck. Anstatt alle Werte in der Liste abzuspeichern, berechnet diese Liste ihre Werte, wann immer sie angefordert werden. Das ist sehr viel speicherschonender, wenn mit sehr langen Listen von Ganzzahlen gearbeitet wird. <font name=Courier>XRangeType</font> kennt eine einzige Methode, <font name=Courier>s.tolist()</font><onDraw name=myIndex label="XRangeType::tolist() (Methode)"><onDraw name=myIndex label="s.tolist() (Methode)"><onDraw name=myIndex label="Methoden::s.tolist()">, die seine Werte in eine Liste umwandelt.'''
+        text='''Die eingebaute Funktion <font name=Courier>range(i, j [, stride])</font><onDraw name=myIndex label="eingebaute Funktionen::range()"><onDraw name=myIndex label="range() (Funktion)"><onDraw name=myIndex label="Funktionen::range()"> erzeugt eine Liste von Ganzzahlen und f&#xfc;llt sie mit Werten <font name=Courier>k</font>, f&#xfc;r die gilt: <font name=Courier>i &lt;= k &lt; j</font>. Man kann auch eine optionale Schrittweite angeben. Die eingebaute Funktion <font name=Courier>xrange()</font><onDraw name=myIndex label="eingebaute Funktionen::xrange()"><onDraw name=myIndex label="xrange() (Funktion)"><onDraw name=myIndex label="Funktionen::xrange()"> erf&#xfc;llt einen &#xe4;hnlichen Zweck, gibt aber eine unver&#xe4;nderliche Sequenz vom Typ <font name=Courier>XRangeType</font><onDraw name=myIndex label="XRangeType"> zur&#xfc;ck. Anstatt alle Werte in der Liste abzuspeichern, berechnet diese Liste ihre Werte, wann immer sie angefordert werden. Das ist sehr viel speicherschonender, wenn mit sehr langen Listen von Ganzzahlen gearbeitet wird. <font name=Courier>XRangeType</font> kennt eine einzige Methode, <font name=Courier>s.tolist()</font><onDraw name=myIndex label="XRangeType::tolist() (Methode)"><onDraw name=myIndex label="s.tolist() (Methode)"><onDraw name=myIndex label="Methoden::s.tolist()">, die seine Werte in eine Liste umwandelt.'''
         aW = 420
         aH = 64.4
         P=Paragraph(text, B)
@@ -1058,7 +1058,7 @@
             dumpParagraphLines(P)
 
     if flagged(7):
-        text = """<para align="CENTER" fontSize="24" leading="30"><b>Generated by:</b>\tDilbert</para>"""
+        text = """<para align="CENTER" fontSize="24" leading="30"><b>Generated by:</b>Dilbert</para>"""
         P=Paragraph(text, styleSheet['Code'])
         dumpParagraphFrags(P)
         w,h = P.wrap(6*72, 9.7*72)
--- a/reportlab/platypus/paraparser.py	Thu Apr 27 17:42:12 2006 +0000
+++ b/reportlab/platypus/paraparser.py	Fri Apr 28 14:08:58 2006 +0000
@@ -282,9 +282,29 @@
     fontname, fontSize, rise, textColor, cbDefn
     """
 
+
+_greek2Utf8=None
+def _greekConvert(data):
+    global _greek2Utf8
+    if not _greek2Utf8:
+        from reportlab.pdfbase.rl_codecs import RL_Codecs
+        import codecs
+        dm = decoding_map = codecs.make_identity_dict(xrange(32,256))
+        for k in xrange(0,32):
+            dm[k] = None
+        dm.update(RL_Codecs._RL_Codecs__rl_codecs_data['symbol'][0])
+        _greek2Utf8 = {}
+        for k,v in dm.iteritems():
+            if not v:
+                u = '\0'
+            else:
+                u = unichr(v).encode('utf8')
+            _greek2Utf8[chr(k)] = u
+    return ''.join(map(_greek2Utf8.__getitem__,data))
+
 #------------------------------------------------------------------
 # !!! NOTE !!! THIS TEXT IS NOW REPLICATED IN PARAGRAPH.PY !!!
-# The ParaFormatter will be able to format the following xml
+# The ParaFormatter will be able to format the following
 # tags:
 #       < /b > - bold
 #       < /i > - italics
@@ -295,6 +315,9 @@
 #       <font name=fontfamily/fontname color=colorname size=float>
 #       < bullet > </bullet> - bullet text (at head of para only)
 #       <onDraw name=callable label="a label">
+#       <unichar name="unicode character name"/>
+#       <unichar value="unicode code point"/>
+#       <greek> - </greek>
 #
 #       The whole may be surrounded by <para> </para> tags
 #
@@ -410,12 +433,40 @@
         if message[:10]=="attribute " and message[-17:]==" value not quoted": return
         self.errors.append(message)
 
-    def start_greek(self, attributes):
+    def start_greek(self, attr):
         self._push(greek=1)
 
     def end_greek(self):
         self._pop(greek=1)
 
+    def start_unichar(self, attr):
+        if attr.has_key('name'):
+            if attr.has_key('code'):
+                self._syntax_error('<unichar/> invalid with both name and code attributes')
+            try:
+                v = unicodedata.lookup(attr['name']).encode('utf8')
+            except KeyError:
+                self._syntax_error('<unichar/> invalid name attribute\n"%s"' % name)
+                v = '\0'
+        elif attr.has_key('code'):
+            try:
+                v = unichr(int(eval(attr['code']))).encode('utf8')
+            except:
+                self._syntax_error('<unichar/> invalid code attribute %s' % attr['code'])
+                v = '\0'
+        else:
+            v = None
+            if attr: 
+                self._syntax_error('<unichar/> invalid attribute %s' % attr.keys()[0])
+
+
+        if v is not None:
+            self.handle_data(v)
+        self._push()
+
+    def end_unichar(self):
+        self._pop()
+
     def start_font(self,attr):
         self._push(**self.getAttributes(attr,_fontAttrMap))
 
@@ -606,6 +657,9 @@
         frag = copy.copy(self._stack[-1])
         if hasattr(frag,'cbDefn'):
             if data!='': syntax_error('Only <onDraw> tag allowed')
+        elif hasattr(frag,'_selfClosingTag'):
+            if data!='': syntax_error('No content allowed in %s tag' % frag._selfClosingTag)
+            return
         else:
             # if sub and super are both on they will cancel each other out
             if frag.sub == 1 and frag.super == 1:
@@ -619,7 +673,9 @@
                 frag.rise = frag.fontSize*superFraction
                 frag.fontSize = max(frag.fontSize-sizeDelta,3)
 
-            if frag.greek: frag.fontName = 'symbol'
+            if frag.greek:
+                frag.fontName = 'symbol'
+                data = _greekConvert(data)
 
         # bold, italic, and underline
         x = frag.fontName = tt2ps(frag.fontName,frag.bold,frag.italic)
@@ -737,7 +793,7 @@
     style.bulletFontSize=12
 
     text='''
-    <b><i><greek>a</greek>D</i></b>&beta;
+    <b><i><greek>a</greek>D</i></b>&beta;<unichr value="0x394"/>
     <font name="helvetica" size="15" color=green>
     Tell me, O muse, of that ingenious hero who travelled far and wide
     after</font> he had sacked the famous town of Troy. Many cities did he visit,
--- a/reportlab/test/test_platypus_paragraphs.py	Thu Apr 27 17:42:12 2006 +0000
+++ b/reportlab/test/test_platypus_paragraphs.py	Fri Apr 28 14:08:58 2006 +0000
@@ -130,7 +130,8 @@
 timetable section (page 8), there are adverts for "AdSu" and "O'Reilly". I can
 see how the AdSu one might be done generically, but the O'Reilly, unsure...
 I guess I'm hoping that I've missed something, and that
-it's actually easy to do using platypus.
+it's actually easy to do using platypus.We can do greek letters <greek>mDngG</greek>. This should be a
+u with a dieresis on top "<unichar code=0xfc/>" and this "&#xfc;".
 '''
         from reportlab.platypus.flowables import ImageAndFlowables, Image
         from reportlab.lib.utils import _RL_DIR