Skip to content
Snippets Groups Projects
xmlview.py 6.49 KiB
Newer Older
Benoit Favre's avatar
Benoit Favre committed
import animate, actions

from gi.repository import GObject, Gtk, Pango, Gdk
Benoit Favre's avatar
Benoit Favre committed
from xml.etree import ElementTree as ET

Benoit Favre's avatar
Benoit Favre committed
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.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, 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.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')
Benoit Favre's avatar
Benoit Favre committed
    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):
        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 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)

    def highlight(self):
        self.get_style_context().remove_class('keyword')
        self.get_style_context().add_class('keyword-highlighted')

Benoit Favre's avatar
Benoit Favre committed
    def link_clicked(self, widget, uri):
        actions.perform_action(actions.Action(uri, keyword=widget), False)
Benoit Favre's avatar
Benoit Favre committed
        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')
Benoit Favre's avatar
Benoit Favre committed

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)

Benoit Favre's avatar
Benoit Favre committed
        self.vbox = self.parse_xml(filename)
        self.add_with_viewport(self.vbox)
Benoit Favre's avatar
Benoit Favre committed
        self.connect('scroll-event', lambda widget, event: animate.cancel())
Benoit Favre's avatar
Benoit Favre committed
        for section in self.sections:
            section.add_listener(self.section_clicked)
        self.set_section(0)
        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'):
                            self.keywords.append(element)
        self.last_highlighted = -1

Benoit Favre's avatar
Benoit Favre committed
    def get_view(self):
        return self

    def parse_xml(self, filename):
Benoit Favre's avatar
Benoit Favre committed
        self.sections = []
Benoit Favre's avatar
Benoit Favre committed
        root = ET.parse(filename)
Benoit Favre's avatar
Benoit Favre committed
        vbox = Gtk.VBox()
        vbox.get_style_context().add_class('xmlview')
Benoit Favre's avatar
Benoit Favre committed
        for section in root.findall(".//section"):
Benoit Favre's avatar
Benoit Favre committed
            self.sections.append(Section(section))
            vbox.pack_start(self.sections[-1], True, True, 5)
        return vbox

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

    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)
        if scroll:
            animate.scroll_to(self, self.current_section)

    def section_clicked(self, current):
        self.set_section(int(current.name) - 1)

    def highlight(self, action):
        if hasattr(action, 'keyword'):
            action.keyword.highlight()
        else:
            i = self.last_highlighted + 1
            while i < len(self.keywords):
                if self.keywords[i].action == action.text:
                    self.keywords[i].highlight()
                    self.last_highlighted = i
                    break
                i += 1