diff --git a/chat/richtext.py b/chat/richtext.py index 5f0e6e59..59c58f46 100644 --- a/chat/richtext.py +++ b/chat/richtext.py @@ -4,6 +4,7 @@ import pygtk pygtk.require('2.0') import gtk import pango +import xml.sax class RichTextBuffer(gtk.TextBuffer): def __init__(self): @@ -32,12 +33,6 @@ class RichTextBuffer(gtk.TextBuffer): pos_end = pos.copy() pos_end.backward_chars(length) self.apply_tag_by_name(tag, pos, pos_end) - - def to_xml(): - next_iter = buffer.get_start_iter() - while not next_iter.is_end(): - - class RichTextToolbar(gtk.Toolbar): def __init__(self, buf): @@ -60,9 +55,100 @@ class RichTextToolbar(gtk.Toolbar): self.buf.apply_tag(tag_name) else: self.buf.unapply_tag(tag_name) + +class RichTextHandler(xml.sax.handler.ContentHandler): + def __init__(self, buf): + self.buf = buf + self.tags = [] + + def _deserialize_element(self, el_name): + if el_name == "bold": + return "bold" + elif el_name == "italic": + return "italic" + else: + return None + + def startElement(self, name, attributes): + tag = self._deserialize_element(name) + if tag: + self.tags.append(tag) + + def characters(self, data): + start_it = it = self.buf.get_end_iter() + mark = self.buf.create_mark(None, start_it, True) + self.buf.insert(it, data) + start_it = self.buf.get_iter_at_mark(mark) + + for tag in self.tags: + self.buf.apply_tag_by_name(tag, start_it, it) + + def endElement(self, name): + tag = self._deserialize_element(name) + if tag: + self.tags.remove(tag) + +class RichTextSerializer: + def __init__(self): + self._open_xml_tags = [] + + def _get_xml_tag(self, tag): + if tag.get_property("name") == "bold": + return "bold" + elif tag.get_property("name") == "italic": + return "italic" + else: + return "unknown_tag" + + def serialize(self, buf): + xml = "" + + next_it = buf.get_start_iter() + while not next_it.is_end(): + it = next_it.copy() + if not next_it.forward_to_tag_toggle(None): + next_it = buf.get_end_iter() + + reopen_xml_tags = [] + for tag in it.get_toggled_tags(False): + xml_tag = self._get_xml_tag(tag) + while 1: + open_xml_tag = self._open_xml_tags.pop() + if open_xml_tag != xml_tag: + xml += "" + reopen_xml_tags.append(open_xml_tag) + else: + xml += "" + break + + for xml_tag in reopen_xml_tags: + self._open_xml_tags.append(xml_tag) + xml += "<" + xml_tag + ">" + + for tag in it.get_toggled_tags(True): + xml_tag = self._get_xml_tag(tag) + self._open_xml_tags.append(xml_tag) + xml += "<" + xml_tag + ">" + + xml += buf.get_text(it, next_it) + + if next_it.is_end(): + for xml_tag in self._open_xml_tags: + xml += "" + + xml += "" + + return xml + + def deserialize(self, xml_string, buf): + parser = xml.sax.make_parser() + handler = RichTextHandler(buf) + parser.setContentHandler(handler) + parser.feed(xml_string) + parser.close() def test_quit(window, rich_buf): - print rich_buf.to_xml() + print RichTextSerializer().serialize(rich_buf) gtk.main_quit() if __name__ == "__main__": @@ -73,6 +159,9 @@ if __name__ == "__main__": rich_buf = RichTextBuffer() + xml_string = "HelloWorld" + RichTextSerializer().deserialize(xml_string, rich_buf) + view = gtk.TextView(rich_buf) vbox.pack_start(view) view.show()