# This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Library General Public # License as published by the Free Software Foundation; either # version 2 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Library General Public License for more details. # # You should have received a copy of the GNU Library General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA class StyletextError(Exception): pass class Style: is_Style = 1 def __init__(self, **kw): if len(kw) != 1: raise StyletextError( "Style should be called with exactly one parameter " "eg. Style(size=3): %s" % kw) self.sort = kw.keys()[0] self.options = kw.values()[0] self._signature_ = str(kw) def __cmp__ (self, other): if not hasattr(other, 'is_Style'): raise StyletextError( "can't compare styles to non-style objects: %s" % other) s1 = self._signature_ s2 = other._signature_ return cmp(s1,s2) class Id: def __init__(self): self.next_id = -1 def new_id(self): self.next_id = self.next_id+1 return '_'+str(self.next_id) class Pool(Id): def __init__(self, text_inst=None): self.keys = [] self.signatures = [] self.dict = {} self.Text = text_inst Id.__init__(self) def __len__(self): return len(self.keys) def __getitem__(self, key): i = self.keys.index(key) sig = self.signatures[i] return self.dict[sig] def __setitem__(self, key, value): # XXX inconistency: keys should be created solely by pool try: i = self.keys.index(key) sig = value._signature_ except: self.keys.append(key) sig = value._signature_ self.signatures.append(sig) self.dict[sig] = value def __delitem__(self, key): i = self.keys.index(key) del self.keys[i] sig = self.signatures[i] del self.signatures[i] try: i = self.signatures.index(sig) except: del self.dict[sig] def dump(self): out = [] print "______________ POOL DUMP __________" for i in range(len(self.keys)): sig = self.signatures[i] id = self.keys[i] if self.Text is not None: index = self.Text.index(id) else: index = "" out.append((index, id, self.dict[sig])) for index, id, style in out: print index,"\t", id,"\t", style print "# of keys = ", len(self.keys) print "# of signatures = ", len(self.signatures) class Iterator: def __init__(self, pool): self.pool = pool self.i = -1 self._update() def __repr__(self): return "Iterator of %s" % repr(self.pool) def __str__(self): if self.i<0: index = "1.0" elif self.i>=len(self.pool): index = "end" else: index = self.id return str(index) def _update(self): if self.i >= len(self.pool) or self.i <0: self.outofboundary = 1 self.current = None self.id = None else: self.outofboundary = 0 self.id = self.pool.keys[self.i] sig = self.pool.signatures[self.i] self.current = self.pool.dict[sig] def next(self): if self.i=0: self.i = self.i-1 self._update() return self.current def insert_left(self, style, index=None): '''inserts stlye before index or if it is not given, after current id''' texti = self._textinst() if index is None: index = self.current if index is None: raise StyletextError( "Can't insert at index: %s" % index) it = self.pool.iterator() it.before(index) it.next() it.align_left() # case 1: there is no mark before index if it.outofboundary: i = it.i # case 2: there is already a mark at index elif texti.compare(it, '==', index): it.align_left() i = it.i # case 3: there is no mark at index, but after index else: i = it.i sig = style._signature_ id = self.pool.new_id() texti.mark_set(id, index) texti.mark_gravity(id, 'right') self.pool.keys.insert(i, id) self.pool.signatures.insert(i, sig) self.pool.dict[sig] = style self.i = i return self._update() def insert_right(self, style, index=None): '''inserts stlye after index or if it is not given, after current id''' texti = self._textinst() if index is None: index = self.current if index is None: raise StyletextError( "Can't insert at index '%s'" % index) it = self.pool.iterator() it.after(index) it.align_right() # case 1: there is no mark at or after index if it.outofboundary: i = it.i # case 2: there is already a mark at index elif texti.compare(it, '==', index): it.align_right() i = it.i+1 # case 3: there is no mark at index, but after index else: i = it.i sig = style._signature_ id = self.pool.new_id() texti.mark_set(id, index) texti.mark_gravity(id, 'right') self.pool.keys.insert(i, id) self.pool.signatures.insert(i, sig) self.pool.dict[sig] = style self.i = i return self._update() def delete(self): texti = self._textinst() del self.pool.keys[self.i] del self.pool.signatures[self.i] texti.mark_unset(self.id) if self.i>len(self.pool): self.i = self.i-1 self._update() def _textinst(self): '''Returns pools assigned text instance, error if no Text is assigned''' if self.pool.Text is None: raise StyletextError("pool has no 'text' instance") return self.pool.Text def guess(self, indexOrId): '''finds a style mark which is before indexOrId. Not Necessarily the nearest one. ''' if len(self.pool) == 0: return self._update() texti = self._textinst() # start with a good guess index = indexOrId while 1: mark = texti.mark_previous(index) #print "mark = ",mark if mark is None or type(mark)=='None': # there is no mark before indexorid then self.i = -1 return self._update() if mark[0] == '_': id = mark break index = mark i = self.pool.keys.index(id) self.i = i return self._update() def after(self, indexOrId): '''finds last stylemark which is at index or, if there is none, the next one''' if len(self.pool) == 0: return self._update() texti = self._textinst() it = self.pool.iterator() # start with a good guess it.guess(indexOrId) if it.i<0: it.next() i = it.i # fine tuning while texti.compare(self.pool.keys[i],'<', indexOrId): i = i+1 if i>=len(self.pool): break self.i = i def before(self, indexOrId): '''finds last style mark which is before indexOrId # XXX inconsistent to Tk: previous = next mark bevor or at index ''' if len(self.pool) == 0: return self._update() texti = self._textinst() it = self.pool.iterator() # start with a good guess it.guess(indexOrId) while (not it.outofboundary) and (texti.compare(it,'>=', \ indexOrId)): it.prev() if it.outofboundary: self.i = it.i return self._update() i = it.i # now fine tuning oi = i while texti.compare(self.pool.keys[i], '<',indexOrId): #~ print i, "<", texti.index(indexOrId) oi = i i = i+1 if i>=len(self.pool): break # now oi is at the last stylemark which is before indexOrId self.i = oi return self._update() def set(self, id): self.i = self.pool.keys.index(id) self._update() return current def align_left(self): if self.outofboundary: return self.current ids = self.pool.keys compare = self._textinst().compare i = self.i while i>0 and i