~fluidity-core/fluidity/embedded_models

« back to all changes in this revision

Viewing changes to libspud/diamond/diamond/TextBufferMarkup.py

  • Committer: Timothy Bond
  • Date: 2011-04-14 15:40:24 UTC
  • Revision ID: timothy.bond@imperial.ac.uk-20110414154024-116ci9gq6mwigmaw
Following the move from svn to bzr we change the nature of inclusion of these
four software libraries. Previously, they were included as svn externals and
pulled at latest version for trunk, pinned to specific versions for release
and stable trunk. Since bzr is less elegant at dealing with externals we have
made the decision to include the packages directly into the trunk instead.

At this import the versions are:

libadaptivity: r163
libvtkfortran: r67
libspud: r545
libmba2d: r28

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
### Copyright (C) 2005 Thomas M. Hinkle
 
2
### Copyright (C) 2007 Imperial College London and others.
 
3
### Please see the AUTHORS file for a full list of contributors.
 
4
###
 
5
### This library is free software; you can redistribute it and/or
 
6
### modify it under the terms of the GNU General Public License as
 
7
### published by the Free Software Foundation; either version 2 of the
 
8
### License, or (at your option) any later version.
 
9
###
 
10
### This library is distributed in the hope that it will be useful,
 
11
### but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
13
### General Public License for more details.
 
14
###
 
15
### You should have received a copy of the GNU General Public License
 
16
### along with this library; if not, write to the Free Software
 
17
### Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 
18
### 02111-1307, USA.
 
19
 
 
20
import pango,gtk, xml.sax.saxutils
 
21
 
 
22
import debug
 
23
 
 
24
class PangoBuffer (gtk.TextBuffer):
 
25
    desc_to_attr_table = {
 
26
        'family':[pango.AttrFamily,""],
 
27
        'style':[pango.AttrStyle,pango.STYLE_NORMAL],
 
28
        'variant':[pango.AttrVariant,pango.VARIANT_NORMAL],
 
29
        'weight':[pango.AttrWeight,pango.WEIGHT_NORMAL],
 
30
        'stretch':[pango.AttrStretch,pango.STRETCH_NORMAL],
 
31
        }
 
32
    pango_translation_properties={
 
33
            # pango ATTR TYPE : (pango attr property / tag property)
 
34
            pango.ATTR_SIZE : 'size',
 
35
            pango.ATTR_WEIGHT: 'weight',
 
36
            pango.ATTR_UNDERLINE: 'underline',
 
37
            pango.ATTR_STRETCH: 'stretch',
 
38
            pango.ATTR_VARIANT: 'variant',
 
39
            pango.ATTR_STYLE: 'style',
 
40
            pango.ATTR_SCALE: 'scale',
 
41
            pango.ATTR_STRIKETHROUGH: 'strikethrough',
 
42
            pango.ATTR_RISE: 'rise',
 
43
            }
 
44
    attval_to_markup={
 
45
            'underline':{pango.UNDERLINE_SINGLE:'single',
 
46
                         pango.UNDERLINE_DOUBLE:'double',
 
47
                         pango.UNDERLINE_LOW:'low',
 
48
                         pango.UNDERLINE_NONE:'none'},
 
49
            'stretch':{pango.STRETCH_ULTRA_EXPANDED:'ultraexpanded',
 
50
                       pango.STRETCH_EXPANDED:'expanded',
 
51
                       pango.STRETCH_EXTRA_EXPANDED:'extraexpanded',
 
52
                       pango.STRETCH_EXTRA_CONDENSED:'extracondensed',
 
53
                       pango.STRETCH_ULTRA_CONDENSED:'ultracondensed',
 
54
                       pango.STRETCH_CONDENSED:'condensed',
 
55
                       pango.STRETCH_NORMAL:'normal',
 
56
                       },
 
57
            'variant':{pango.VARIANT_NORMAL:'normal',
 
58
                       pango.VARIANT_SMALL_CAPS:'smallcaps',
 
59
                       },
 
60
            'style':{pango.STYLE_NORMAL:'normal',
 
61
                     pango.STYLE_OBLIQUE:'oblique',
 
62
                     pango.STYLE_ITALIC:'italic',
 
63
                     },
 
64
            'stikethrough':{1:'true',
 
65
                            True:'true',
 
66
                            0:'false',
 
67
                            False:'false'},
 
68
            }
 
69
    def __init__ (self):
 
70
        self.tagdict = {}
 
71
        self.tags = {}
 
72
        #self.buf = buf
 
73
        #self.set_text(txt)
 
74
        gtk.TextBuffer.__init__(self)
 
75
 
 
76
    def set_text (self, txt):
 
77
        gtk.TextBuffer.set_text(self,"")
 
78
        try:
 
79
            self.parsed,self.txt,self.separator = pango.parse_markup(txt,u'\x00')
 
80
        except:
 
81
            debug.deprint('Escaping text, we seem to have a problem here!', 2)
 
82
            txt=xml.sax.saxutils.escape(txt)
 
83
            self.parsed,self.txt,self.separator = pango.parse_markup(txt,u'\x00')
 
84
        self.attrIter = self.parsed.get_iterator()
 
85
        self.add_iter_to_buffer()
 
86
        while self.attrIter.next():
 
87
            self.add_iter_to_buffer()
 
88
 
 
89
    def add_iter_to_buffer (self):
 
90
        range=self.attrIter.range()
 
91
        font,lang,attrs = self.attrIter.get_font()
 
92
        tags = self.get_tags_from_attrs(font,lang,attrs)
 
93
        text = self.txt[range[0]:range[1]]
 
94
        if tags: self.insert_with_tags(self.get_end_iter(),text,*tags)
 
95
        else: self.insert_with_tags(self.get_end_iter(),text)
 
96
 
 
97
    def get_tags_from_attrs (self, font,lang,attrs):
 
98
        tags = []
 
99
        if font:
 
100
            font,fontattrs = self.fontdesc_to_attrs(font)
 
101
            fontdesc = font.to_string()
 
102
            if fontattrs:
 
103
                attrs.extend(fontattrs)
 
104
            if fontdesc and fontdesc!='Normal':
 
105
                if not self.tags.has_key(font.to_string()):
 
106
                    tag=self.create_tag()
 
107
                    tag.set_property('font-desc',font)
 
108
                    if not self.tagdict.has_key(tag): self.tagdict[tag]={}
 
109
                    self.tagdict[tag]['font_desc']=font.to_string()
 
110
                    self.tags[font.to_string()]=tag
 
111
                tags.append(self.tags[font.to_string()])
 
112
        if lang:
 
113
            if not self.tags.has_key(lang):
 
114
                tag = self.create_tag()
 
115
                tag.set_property('language',lang)
 
116
                self.tags[lang]=tag
 
117
            tags.append(self.tags[lang])
 
118
        if attrs:
 
119
            for a in attrs:
 
120
                if a.type == pango.ATTR_FOREGROUND:
 
121
                    gdkcolor = self.pango_color_to_gdk(a.color)
 
122
                    key = 'foreground%s'%self.color_to_hex(gdkcolor)
 
123
                    if not self.tags.has_key(key):
 
124
                        self.tags[key]=self.create_tag()
 
125
                        self.tags[key].set_property('foreground-gdk',gdkcolor)
 
126
                        self.tagdict[self.tags[key]]={}
 
127
                        self.tagdict[self.tags[key]]['foreground']="#%s"%self.color_to_hex(gdkcolor)
 
128
                    tags.append(self.tags[key])
 
129
                if a.type == pango.ATTR_BACKGROUND:
 
130
                    gdkcolor = self.pango_color_to_gdk(a.color)
 
131
                    key = 'background%s'%self.color_to_hex(gdkcolor)
 
132
                    if not self.tags.has_key(key):
 
133
                        self.tags[key]=self.create_tag()
 
134
                        self.tags[key].set_property('background-gdk',gdkcolor)
 
135
                        self.tagdict[self.tags[key]]={}
 
136
                        self.tagdict[self.tags[key]]['background']="#%s"%self.color_to_hex(gdkcolor)
 
137
                    tags.append(self.tags[key])
 
138
                if self.pango_translation_properties.has_key(a.type):
 
139
                    prop=self.pango_translation_properties[a.type]
 
140
                    #print 'setting property %s of %s (type: %s)'%(prop,a,a.type)
 
141
                    val=getattr(a,'value')
 
142
                    #tag.set_property(prop,val)
 
143
                    mval = val
 
144
                    if self.attval_to_markup.has_key(prop):
 
145
                        #print 'converting ',prop,' in ',val
 
146
                        if self.attval_to_markup[prop].has_key(val):
 
147
                            mval = self.attval_to_markup[prop][val]
 
148
                        else:
 
149
                            debug.deprint("hmmm, didn't know what to do with value %s"%val, 2)
 
150
                    key="%s%s"%(prop,val)
 
151
                    if not self.tags.has_key(key):
 
152
                        self.tags[key]=self.create_tag()
 
153
                        self.tags[key].set_property(prop,val)
 
154
                        self.tagdict[self.tags[key]]={}
 
155
                        self.tagdict[self.tags[key]][prop]=mval
 
156
                    tags.append(self.tags[key])
 
157
        return tags
 
158
 
 
159
    def get_tags (self):
 
160
        tagdict = {}
 
161
        for pos in range(self.get_char_count()):
 
162
            iter=self.get_iter_at_offset(pos)
 
163
            for tag in iter.get_tags():
 
164
                if tagdict.has_key(tag):
 
165
                    if tagdict[tag][-1][1] == pos - 1:
 
166
                        tagdict[tag][-1] = (tagdict[tag][-1][0],pos)
 
167
                    else:
 
168
                        tagdict[tag].append((pos,pos))
 
169
                else:
 
170
                    tagdict[tag]=[(pos,pos)]
 
171
        return tagdict
 
172
 
 
173
    def get_text (self, start=None, end=None, include_hidden_chars=True):
 
174
        tagdict=self.get_tags()
 
175
        if not start: start=self.get_start_iter()
 
176
        if not end: end=self.get_end_iter()
 
177
        txt = unicode(gtk.TextBuffer.get_text(self,start,end))
 
178
        cuts = {}
 
179
        for k,v in tagdict.items():
 
180
            stag,etag = self.tag_to_markup(k)
 
181
            for st,e in v:
 
182
                if cuts.has_key(st): cuts[st].append(stag) #add start tags second
 
183
                else: cuts[st]=[stag]
 
184
                if cuts.has_key(e+1): cuts[e+1]=[etag]+cuts[e+1] #add end tags first
 
185
                else: cuts[e+1]=[etag]
 
186
        last_pos = 0
 
187
        outbuff = ""
 
188
        cut_indices = cuts.keys()
 
189
        cut_indices.sort()
 
190
        soffset = start.get_offset()
 
191
        eoffset = end.get_offset()
 
192
        cut_indices = filter(lambda i: eoffset >= i >= soffset, cut_indices)
 
193
        for c in cut_indices:
 
194
            if not last_pos==c:
 
195
                outbuff += xml.sax.saxutils.escape(txt[last_pos:c])
 
196
                last_pos = c
 
197
            for tag in cuts[c]:
 
198
                outbuff += tag
 
199
        outbuff += xml.sax.saxutils.escape(txt[last_pos:])
 
200
        return outbuff
 
201
 
 
202
    def tag_to_markup (self, tag):
 
203
        stag = "<span"
 
204
        for k,v in self.tagdict[tag].items():
 
205
            stag += ' %s="%s"'%(k,v)
 
206
        stag += ">"
 
207
        return stag,"</span>"
 
208
 
 
209
    def fontdesc_to_attrs (self,font):
 
210
        nicks = font.get_set_fields().value_nicks
 
211
        attrs = []
 
212
        for n in nicks:
 
213
            if self.desc_to_attr_table.has_key(n):
 
214
                Attr,norm = self.desc_to_attr_table[n]
 
215
                # create an attribute with our current value
 
216
                attrs.append(Attr(getattr(font,'get_%s'%n)()))
 
217
                # unset our font's value
 
218
                getattr(font,'set_%s'%n)(norm)
 
219
        return font,attrs
 
220
 
 
221
    def pango_color_to_gdk (self, pc):
 
222
        return gtk.gdk.Color(pc.red,pc.green,pc.blue)
 
223
 
 
224
    def color_to_hex (self, color):
 
225
        hexstring = ""
 
226
        for col in 'red','green','blue':
 
227
            hexfrag = hex(getattr(color,col)/(16*16)).split("x")[1]
 
228
            if len(hexfrag)<2: hexfrag = "0" + hexfrag
 
229
            hexstring += hexfrag
 
230
        return hexstring
 
231
 
 
232
    def apply_font_and_attrs (self, font, attrs):
 
233
        tags = self.get_tags_from_attrs(font,None,attrs)
 
234
        for t in tags: self.apply_tag_to_selection(t)
 
235
 
 
236
    def remove_font_and_attrs (self, font, attrs):
 
237
        tags = self.get_tags_from_attrs(font,None,attrs)
 
238
        for t in tags: self.remove_tag_from_selection(t)
 
239
 
 
240
    def setup_default_tags (self):
 
241
        self.italics = self.get_tags_from_attrs(None,None,[pango.AttrStyle('italic')])[0]
 
242
        self.bold = self.get_tags_from_attrs(None,None,[pango.AttrWeight('bold')])[0]
 
243
        self.underline = self.get_tags_from_attrs(None,None,[pango.AttrUnderline('single')])[0]
 
244
 
 
245
    def get_selection (self):
 
246
        bounds = self.get_selection_bounds()
 
247
        if not bounds:
 
248
            iter=self.get_iter_at_mark(self.get_insert())
 
249
            if iter.inside_word():
 
250
                start_pos = iter.get_offset()
 
251
                iter.forward_word_end()
 
252
                word_end = iter.get_offset()
 
253
                iter.backward_word_start()
 
254
                word_start = iter.get_offset()
 
255
                iter.set_offset(start_pos)
 
256
                bounds = (self.get_iter_at_offset(word_start),
 
257
                          self.get_iter_at_offset(word_end+1))
 
258
            else:
 
259
                bounds = (iter,self.get_iter_at_offset(iter.get_offset()+1))
 
260
        return bounds
 
261
 
 
262
    def apply_tag_to_selection (self, tag):
 
263
        selection = self.get_selection()
 
264
        if selection:
 
265
            self.apply_tag(tag,*selection)
 
266
 
 
267
    def remove_tag_from_selection (self, tag):
 
268
        selection = self.get_selection()
 
269
        if selection:
 
270
            self.remove_tag(tag,*selection)
 
271
 
 
272
    def remove_all_tags (self):
 
273
        selection = self.get_selection()
 
274
        if selection:
 
275
            for t in self.tags.values():
 
276
                self.remove_tag(t,*selection)
 
277
 
 
278
class InteractivePangoBuffer (PangoBuffer):
 
279
    def __init__ (self,
 
280
                  normal_button=None,
 
281
                  toggle_widget_alist=[]):
 
282
        """An interactive interface to allow marking up a gtk.TextBuffer.
 
283
        txt is initial text, with markup.
 
284
        buf is the gtk.TextBuffer
 
285
        normal_button is a widget whose clicked signal will make us normal
 
286
        toggle_widget_alist is a list that looks like this:
 
287
        [(widget, (font,attr)),
 
288
         (widget2, (font,attr))]
 
289
         """
 
290
        PangoBuffer.__init__(self)
 
291
        if normal_button: normal_button.connect('clicked',lambda *args: self.remove_all_tags())
 
292
        self.tag_widgets = {}
 
293
        self.internal_toggle = False
 
294
        self.insert = self.get_insert()
 
295
        self.connect('mark-set',self._mark_set_cb)
 
296
        self.connect('changed',self._changed_cb)
 
297
        for w,tup in toggle_widget_alist:
 
298
            self.setup_widget(w,*tup)
 
299
 
 
300
    def setup_widget_from_pango (self, widg, markupstring):
 
301
        """setup widget from a pango markup string"""
 
302
        #font = pango.FontDescription(fontstring)
 
303
        a,t,s = pango.parse_markup(markupstring,u'\x00')
 
304
        ai=a.get_iterator()
 
305
        font,lang,attrs=ai.get_font()
 
306
        return self.setup_widget(widg,font,attrs)
 
307
 
 
308
    def setup_widget (self, widg, font, attr):
 
309
        tags=self.get_tags_from_attrs(font,None,attr)
 
310
        self.tag_widgets[tuple(tags)]=widg
 
311
        return widg.connect('toggled',self._toggle,tags)
 
312
 
 
313
    def _toggle (self, widget, tags):
 
314
        if self.internal_toggle: return
 
315
        if widget.get_active():
 
316
            for t in tags: self.apply_tag_to_selection(t)
 
317
        else:
 
318
            for t in tags: self.remove_tag_from_selection(t)
 
319
 
 
320
    def _mark_set_cb (self, buffer, iter, mark, *params):
 
321
        # Every time the cursor moves, update our widgets that reflect
 
322
        # the state of the text.
 
323
        if hasattr(self,'_in_mark_set') and self._in_mark_set: return
 
324
        self._in_mark_set = True
 
325
        if mark.get_name()=='insert':
 
326
            for tags,widg in self.tag_widgets.items():
 
327
                active = True
 
328
                for t in tags:
 
329
                    if not iter.has_tag(t):
 
330
                        active=False
 
331
                self.internal_toggle=True
 
332
                widg.set_active(active)
 
333
                self.internal_toggle=False
 
334
        if hasattr(self,'last_mark'):
 
335
            self.move_mark(self.last_mark,iter)
 
336
        else:
 
337
            self.last_mark = self.create_mark('last',iter,left_gravity=True)
 
338
        self._in_mark_set = False
 
339
 
 
340
    def _changed_cb (self, tb):
 
341
        if not hasattr(self,'last_mark'): return
 
342
        # If our insertion point has a mark, we want to apply the tag
 
343
        # each time the user types...
 
344
        old_itr = self.get_iter_at_mark(self.last_mark)
 
345
        insert_itr = self.get_iter_at_mark(self.insert)
 
346
        if old_itr!=insert_itr:
 
347
            # Use the state of our widgets to determine what
 
348
            # properties to apply...
 
349
            for tags,w in self.tag_widgets.items():
 
350
                if w.get_active():
 
351
                    #print 'apply tags...',tags
 
352
                    for t in tags: self.apply_tag(t,old_itr,insert_itr)
 
353
 
 
354
 
 
355
 
 
356
 
 
357
 
 
358
class SimpleEditor:
 
359
    def __init__ (self):
 
360
        self.w = gtk.Window()
 
361
        self.vb = gtk.VBox()
 
362
        self.editBox = gtk.HButtonBox()
 
363
        self.nb = gtk.Button('Normal')
 
364
        self.editBox.add(self.nb)
 
365
        self.sw = gtk.ScrolledWindow()
 
366
        self.tv = gtk.TextView()
 
367
        self.sw.add(self.tv)
 
368
        self.ipb = InteractivePangoBuffer(
 
369
            normal_button=self.nb)
 
370
        self.ipb.set_text("""<b>This is bold</b>. <i>This is italic</i>
 
371
            <b><i>This is bold, italic, and <u>underlined!</u></i></b>
 
372
            <span background="blue">This is a test of bg color</span>
 
373
            <span foreground="blue">This is a test of fg color</span>
 
374
            <span foreground="white" background="blue">This is a test of fg and bg color</span>
 
375
            """)
 
376
        #    Here are some more: 1-2, 2-3, 3-4, 10-20, 30-40, 50-60
 
377
        #    This is <span color="blue">blue</span>, <span color="red">red</span> and <span color="green">green</span>""")
 
378
        #self.ipb.set_text("""This is a numerical range (three hundred and fifty to four hundred) 350-400 which may get messed up.
 
379
        #Here are some more: 1-2, 2-3, 3-4, 10-20, 30-40, 50-60""")
 
380
 
 
381
        self.tv.set_buffer(self.ipb)
 
382
        for lab,stock,font in [('gtk-italic',True,'<i>italic</i>'),
 
383
                               ('gtk-bold',True,'<b>bold</b>'),
 
384
                               ('gtk-underline',True,'<u>underline</u>'),
 
385
                               ('Blue',True,'<span foreground="blue">blue</span>'),
 
386
                               ('Red',False,'<span foreground="red">smallcaps</span>'),
 
387
                               ]:
 
388
            button = gtk.ToggleButton(lab)
 
389
            self.editBox.add(button)
 
390
            if stock: button.set_use_stock(True)
 
391
            self.ipb.setup_widget_from_pango(button,font)
 
392
        self.vb.add(self.editBox)
 
393
        self.vb.add(self.sw)
 
394
        self.actionBox = gtk.HButtonBox()
 
395
        self.qb = gtk.Button(stock='quit')
 
396
        self.pmbut = gtk.Button('Print markup')
 
397
        self.pmbut.connect('clicked',self.print_markup)
 
398
        self.qb.connect('clicked',lambda *args: self.w.destroy() or gtk.main_quit())
 
399
        self.actionBox.add(self.pmbut)
 
400
        self.actionBox.add(self.qb)
 
401
        self.vb.add(self.actionBox)
 
402
        self.w.add(self.vb)
 
403
        self.w.show_all()
 
404
 
 
405
    def print_markup (self,*args):
 
406
        debug.dprint(self.ipb.get_text(), 0)