Skip to content
Snippets Groups Projects
xmlview.py 9.63 KiB
import animate, actions

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.start_text = section.get('start')
        self.action_start = section.get('action_start')
        self.end_text = section.get('end')
        self.action_end = section.get('action_end')
        self.get_style_context().add_class('section-body')
        self.title = Gtk.Label()
        self.title.set_markup('Section [<a href="%s">%s</a>]' % (self.name, self.name))
        self.title.get_style_context().add_class('section-title')
        self.listeners = []
        self.title.connect('activate-link', self.link_clicked)
        self.pack_start(self.title, False, False, 5)
        if self.start_text != None and self.end_text != None:
            info = Gtk.Label('start="' + self.start_text + '" [' + self.action_start + '], end="' + self.end_text + '" [' + self.action_end + ']')
            info.get_style_context().add_class('section-info')
            self.pack_start(info, False, False, 5)
        self.sequences = []

        num = 1
        for sequence in section.findall('./sequence'):
            self.sequences.append(Sequence(sequence, section.get('id') + '.' + str(num), int(self.name) - 1))
            self.pack_start(self.sequences[-1], False, False, 5)
            num += 1

    def highlight(self, active=True):
        if active:
            self.get_style_context().add_class('selected-section')
            self.get_style_context().remove_class('section-body')
        else:
            self.get_style_context().remove_class('selected-section')
            self.get_style_context().add_class('section-body')

    def link_clicked(self, widget, uri):
        for listener in self.listeners:
            listener(self)
        return True

    def add_listener(self, listener):
        self.listeners.append(listener)


class Sequence(Gtk.VBox):
    def __init__(self, sequence, name, section):
        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, False, False, 5)

        self.lines = []

        line = ''
        for c in sequence.text:
            if c == '\n':
                line = line.strip()
                if line != '':
                    self.lines.append(Line([Text(line)]))
                    self.pack_start(self.lines[-1], False, False, 5)
                line = ''
            else:
                line += c
        elements = []
        for node in sequence:
            line = line.strip()
            if line != '':
                elements.append(Text(line))
            if node.tag == 'keyword':
                text = str(node.text).strip()
                if node.get('action').strip() != '':
                    elements.append(Keyword(text, node.get('action'), node.get('lang'), section))
                else:
                    elements.append(Text(text))
            line = ''
            for c in node.tail:
                if c == '\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], False, False, 5)
                        elements = []
                    line = ''
                else:
                    line += c
        line = line.strip()
        if line != '':
            elements.append(Text(line))
        if len(elements) > 0:
            self.lines.append(Line(elements))
            self.pack_start(self.lines[-1], False, False, 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 highlight(self, active=True, scrollable=None):
    #    if active:
    #        self.label.get_style_context().add_class('highlighted')
    #    else:
    #        self.label.get_style_context().remove_class('highlighted')
    #    if scrollable != None:
    #        animate.scroll_to(scrollable, self)

class Keyword(Gtk.Label):
    def __init__(self, text, action, lang, section):
        super(Keyword, self).__init__()
        self.section = section
        self.action = action
        self.lang = lang
        self.text = '\n'.join([x.strip() for x in text.split('\n')])
        self.set_markup(self.text + ' [<a href="%s">%s</a>] ' % (action, action))
        self.get_style_context().add_class('keyword')
        self.connect('activate-link', self.link_clicked)
        self.listeners = []
        self.num = 0

    def highlight(self, active=True, scrollable=None):
        if active:
            self.get_style_context().remove_class('keyword')
            self.get_style_context().add_class('keyword-highlighted')
            if scrollable != None:
                animate.scroll_to(scrollable, self)
        else:
            self.get_style_context().add_class('keyword')
            self.get_style_context().remove_class('keyword-highlighted')

    def add_listener(self, listener):
        self.listeners.append(listener)

    def set_num(self, num):
        self.num = num

    def link_clicked(self, widget, uri):
        actions.perform_action(actions.Action(uri, keyword=widget), False)
        for listener in self.listeners:
            listener(self, uri, self.num)
        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.connect('scroll-event', lambda widget, event: animate.cancel())

        for section in self.sections:
            section.add_listener(self.section_clicked)

        self.keywords = []
        for section in self.sections:
            for sequence in section.sequences:
                for line in sequence.lines:
                    for element in line.elements:
                        if hasattr(element, 'action'):
                            element.set_num(len(self.keywords))
                            self.keywords.append(element)
        self.last_highlighted = -1
        self.follow = True
        self.set_section(0)

    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')
        
        section0 = ET.fromstring('<section id="0">[empty]</section>')
        section0_widget = Section(section0)
        self.sections.append(section0_widget)
        vbox.pack_start(self.sections[-1], True, True, 5)

        for section in root.findall(".//section"):
            section_widget = Section(section)
            self.sections.append(section_widget)
            vbox.pack_start(section_widget, True, True, 5)
            info = Gtk.Label("open section " + section_widget.name + ': "' + section_widget.start_text + '"')
            info.get_style_context().add_class('section-info')
            section0_widget.pack_start(info, True, False, 5)

        return vbox

    def num_sections(self):
        return len(self.sections)

    def get_section(self):
        return int(self.current_section.name)

    def set_section(self, section_id, scroll=True):
        self.current_section = self.sections[section_id]
        for section in self.sections:
            section.highlight(self.current_section is section)
            for keyword in self.keywords:
                keyword.highlight(False)
        if scroll:
            animate.scroll_to(self, self.current_section)

    def section_clicked(self, current):
        self.set_section(int(current.name))
        for keyword in self.keywords:
            keyword.highlight(False)

    def highlight(self, action):
        print 'HIGHLIGHT', action
        if hasattr(action, 'keyword'):
            if self.follow:
                action.keyword.highlight(True, self)
            else:
                action.keyword.highlight(True)
        elif hasattr(action, 'action_id'):
            #start = min([x.num for x in self.keywords if x.section == self.get_section()])
            start = 0
            print action.action_id
            action_id = action.action_id + start
            if self.follow:
                self.keywords[action_id].highlight(True, self)
            else:
                self.keywords[action_id].highlight(True)
        #else:
        #    i = self.last_highlighted + 1
        #    while i < len(self.keywords):
        #        if self.keywords[i].action == action.text:
        #            if self.follow:
        #                self.keywords[i].highlight(True, self)
        #            else:
        #                self.keywords[i].highlight(True)
        #            self.last_highlighted = i
        #            #print 'HIGHLIGHT:', action.text, self.last_highlighted
        #            break
        #        i += 1