import animate from gi.repository import GObject, Gtk, Pango, Gdk from xml.etree import ElementTree as ET class Section(Gtk.VBox): def __init__(self, section): super(Section, self).__init__() self.name = section.get('id') self.get_style_context().add_class('section-body') self.title = Gtk.EventBox() self.label = Gtk.Label('Section %s' % self.name) self.label.get_style_context().add_class('section-title') self.title.add(self.label) self.title.connect('button-press-event', self.clicked) self.handler = None #cursor = Gdk.Cursor(Gdk.CursorType.HAND1) #self.label.get_window().set_cursor(cursor) self.pack_start(self.title, True, True, 5) self.sequences = [] num = 1 for sequence in section.findall('./sequence'): self.sequences.append(Sequence(sequence, section.get('id') + '.' + str(num))) self.pack_start(self.sequences[-1], True, True, 5) num += 1 def highlight(self, active=True): if active: self.label.get_style_context().remove_class('section-title') self.label.get_style_context().add_class('selected-section-title') self.get_style_context().add_class('selected-section-body') self.get_style_context().remove_class('section-body') else: self.label.get_style_context().remove_class('selected-section-title') self.label.get_style_context().add_class('section-title') self.get_style_context().remove_class('selected-section-body') self.get_style_context().add_class('section-body') def clicked(self, widget, event): if self.handler: self.handler(int(self.name) - 1) def set_handler(self, handler): self.handler = handler class Sequence(Gtk.VBox): def __init__(self, sequence, name): super(Sequence, self).__init__() self.name = name self.get_style_context().add_class('sequence-body') self.label = Gtk.Label('Sequence %s' % name) self.label.get_style_context().add_class('sequence-title') self.pack_start(self.label, True, True, 5) self.lines = [] elements = [] for line in sequence.text.split('\n'): line = line.strip() if line != '': elements.append(Text(line)) if len(elements) > 0: self.lines.append(Line(elements)) self.pack_start(self.lines[-1], True, True, 5) elements = [] for node in sequence: if node.tag == 'keyword': text = str(node.text).strip() if node.get('action').strip() != '': elements.append(Keyword(text, node.get('action'), node.get('lang'))) else: elements.append(Text(text)) for line in node.tail.split('\n'): line = line.strip() if line != '': elements.append(Text(line)) if len(elements) > 0: self.lines.append(Line(elements)) self.pack_start(self.lines[-1], True, True, 5) elements = [] if len(elements) > 0: self.lines.append(Line(elements)) self.pack_start(self.lines[-1], True, True, 5) class Line(Gtk.HBox): def __init__(self, elements): super(Line, self).__init__() self.pack_start(Gtk.Label(' '), False, False, 0) for element in elements: self.pack_start(element, False, False, 0) self.elements = elements self.get_style_context().add_class('text-line') def set_handler(self, handler): for element in self.elements: if hasattr(element, 'set_handler'): element.set_handler(handler) def highlight(self, active=True): if active: self.label.get_style_context().add_class('highlighted') else: self.label.get_style_context().remove_class('highlighted') class Keyword(Gtk.Label): def __init__(self, text, action, lang): super(Keyword, self).__init__() self.action = action self.lang = lang text = '\n'.join([x.strip() for x in text.split('\n')]) self.set_markup(text + ' [<a href="%s">%s</a>] ' % (action, action)) self.get_style_context().add_class('keyword') self.connect('activate-link', self.link_clicked) self.handler = None def set_handler(self, handler): self.handler = handler def link_clicked(self, widget, uri): if self.handler: self.handler(uri) return True class Text(Gtk.Label): def __init__(self, text): super(Text, self).__init__() text = '\n'.join([x.strip() for x in text.split('\n')]) self.set_text(text + ' ') self.get_style_context().add_class('text') class XmlView(Gtk.ScrolledWindow): def __init__(self, filename): super(XmlView, self).__init__() self.sections = [] self.words = [] self.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.ALWAYS) self.vbox = self.parse_xml(filename) self.add_with_viewport(self.vbox) self.last_section = None self.connect('scroll-event', lambda widget, event: animate.cancel()) def get_view(self): return self def parse_xml(self, filename): self.sections = [] root = ET.parse(filename) vbox = Gtk.VBox() vbox.get_style_context().add_class('xmlview') for section in root.findall(".//section"): self.sections.append(Section(section)) vbox.pack_start(self.sections[-1], True, True, 5) return vbox def set_action_clicked_handler(self, handler): for line in self.get_line_iterator(): line.set_handler(handler) def get_line_iterator(self): for section in self.sections: for sequence in section.sequences: for line in sequence.lines: yield line def highlight_section(self, section): if section < 1 or section > len(self.sections): print "invalid section", section else: for current in range(len(self.sections)): self.sections[current].highlight(current == section - 1) animate.scroll_to(self, self.sections[section - 1])