From 496e4e5e55beff8bc5a01ef5a22585a0444cec76 Mon Sep 17 00:00:00 2001
From: Benoit Favre <benoit.favre@lif.univ-mrs.fr>
Date: Sun, 22 Feb 2015 17:36:33 +0100
Subject: [PATCH] update ui

---
 README             |   7 +-
 actions.py         |   8 +-
 animate.py         |   2 +
 asr.py             |  31 +++++--
 confirm.py         |   1 +
 data/style.css     |   4 +-
 main.py            |  34 ++------
 timer.py           |  19 +++++
 xmlview.py         | 205 ++++++++++++++++++++++++++++++++-------------
 xmlview_widgets.py | 176 --------------------------------------
 10 files changed, 207 insertions(+), 280 deletions(-)
 create mode 100644 timer.py
 delete mode 100644 xmlview_widgets.py

diff --git a/README b/README
index a0a66bf..e0d4651 100644
--- a/README
+++ b/README
@@ -31,11 +31,12 @@ DONE global action send which deals with
 DONE - show a warning (optional)
 DONE - send action through osc
 DONE - show an action performed message (message log with timing?)
+DONE click section = select that section
+DONE click action = perform action 
 
 events = click action or words to resynchronize ?
-    click line = synchronize to that line
-    click section = select that section
-    click action = perform action and synchronize to the next line
+click line = synchronize to that line
+click action = synchronize to the next line
 
 add global timer which shows elapsed time
 change xml view to reflect already performed actions, already recognized text
diff --git a/actions.py b/actions.py
index 89e47bc..43a6849 100644
--- a/actions.py
+++ b/actions.py
@@ -3,11 +3,11 @@ import osc, log
 class Action:
     def __init__(self, text, **kwargs):
         self.text = text
-        for key, value in kwargs:
+        for key, value in kwargs.items():
             setattr(self, key, value)
 
 class ActionManager:
-    def __init__(self, host, port, confirmer, highlighter, logger=log.ConsoleLogger()):
+    def __init__(self, confirmer, highlighter, logger=log.ConsoleLogger()):
         #self.client = osc.Client(host, port)
         self.confirmer = confirmer
         self.highlighter = highlighter
@@ -20,13 +20,13 @@ class ActionManager:
 
     def perform(self, action, confirm=True, timeout=3):
         if confirm:
-            self.confirmer.confirm('Perform action "%s"?' % action.text, time, lambda: self.confirmed_perform(action))
+            self.confirmer.confirm('Perform action "%s"?' % action.text, timeout, lambda: self.confirmed_perform(action))
         else:
             self.confirmed_perform(action)
 
 manager = None
 
-def setup(confirmer, highlighter, logger):
+def setup(confirmer, highlighter, logger=log.ConsoleLogger()):
     global manager
     manager = ActionManager(confirmer, highlighter, logger)
 
diff --git a/animate.py b/animate.py
index bb71dab..4d4eea1 100644
--- a/animate.py
+++ b/animate.py
@@ -5,12 +5,14 @@ def cancel():
     global timer
     if timer:
         GObject.source_remove(timer)
+        timer = None
 
 LINEAR=1
 DECELERATE=2
 
 def animate_value(callback, current, target, policy=DECELERATE, speed=32):
     global timer
+    timer = None
     if current != target:
         if policy == DECELERATE:
             delta = abs(target - current) / 2
diff --git a/asr.py b/asr.py
index 1299008..dc6a8c7 100644
--- a/asr.py
+++ b/asr.py
@@ -26,9 +26,20 @@ class ASR(Gtk.HBox):
         self.scrolled.set_size_request(-1, 100)
         self.pack_start(self.scrolled, True, True, 5)
 
-        self.button = Gtk.Button("Speak")
+        vbox = Gtk.VBox()
+        self.pack_start(vbox, False, False, 5)
+
+        self.button = Gtk.Button("Record")
+        self.button.set_size_request(100, -1)
         self.button.set_sensitive(False)
-        self.pack_start(self.button, False, False, 5)
+        vbox.pack_start(self.button, True, True, 5)
+
+        #save_state = Gtk.Button("Save state")
+        #save_state.connect('clicked', self.save_state)
+        #vbox.pack_start(save_state, False, False, 5)
+        #load_state = Gtk.Button("Load state")
+        #load_state.connect('clicked', self.load_state)
+        #vbox.pack_start(load_state, False, False, 5)
 
         self.button.connect('clicked', self.button_clicked)
         self.text.connect("size-allocate", self.autoscroll)
@@ -82,28 +93,30 @@ class ASR(Gtk.HBox):
 
         GObject.idle_add(self._finished_loading_asr)
 
-    def load_state(self):
+    def load_state(self, *args):
         try:
             with open('state.txt') as fp:
                 self.asr.set_property('adaptation-state', fp.read())
+                print "ASR: State loaded"
         except:
-          print >> sys.stderr, 'failed to load asr state'
+            print >> sys.stderr, 'failed to load asr state'
 
-    def save_state(self):
+    def save_state(self, *args):
         if hasattr(self, 'asr'):
             state = self.asr.get_property('adaptation-state')
             try:
                 with open('state.txt', 'w') as fp:
                     fp.write(state)
+                print "ASR: State saved"
             except:
                 print >> sys.stderr, 'failed to save asr state'
 
     def _started_loading_asr(self):
         self.button.set_sensitive(False)
-        self.button.set_label("Loading...")
+        self.button.set_label("Loading")
 
     def _finished_loading_asr(self):
-        self.button.set_label("Speak")
+        self.button.set_label("Record")
         self.button.set_sensitive(True)
 
     def _on_partial_result(self, asr, hyp):
@@ -149,12 +162,12 @@ class ASR(Gtk.HBox):
 
     def button_clicked(self, button):
         """Handle button presses."""
-        if button.get_label() == "Speak":
+        if button.get_label() == "Record":
             button.set_label("Stop")
             self.asr.set_property("silent", False)
             self.hyp = []
             self.buffer.set_text('...')
         else:
-            button.set_label("Speak")
+            button.set_label("Record")
             self.asr.set_property("silent", True)
             
diff --git a/confirm.py b/confirm.py
index 3a02299..0bb476f 100644
--- a/confirm.py
+++ b/confirm.py
@@ -56,6 +56,7 @@ class ConfirmationBox(Gtk.HBox):
             self.yes_button.get_child().set_text("YES (%d)" % self.counter)
             self.timer = GObject.timeout_add_seconds(1, self.countdown)
         else:
+            self.timer = None
             self.click_yes()
 
     def cancel_timer(self):
diff --git a/data/style.css b/data/style.css
index d8bd271..dca8aa2 100644
--- a/data/style.css
+++ b/data/style.css
@@ -15,7 +15,7 @@
     font: bold;
 }
 
-.selected-section-title {
+.selected-section > .section-title {
     font: bold 18;
     color: white;
     background: #009900;
@@ -31,7 +31,7 @@
     margin: 20px;
 }
 
-.selected-section-body {
+.selected-section {
     background: #eeffee;
     margin: 20px;
 }
diff --git a/main.py b/main.py
index 8417cfc..699bcd6 100644
--- a/main.py
+++ b/main.py
@@ -24,43 +24,27 @@ import signal
 signal.signal(signal.SIGINT, signal.SIG_DFL)
 
 # import local stuff
-import confirm, asr, actions, xmlview_widgets
-import sections
+import confirm, asr, actions, xmlview
 import levenstein, SLU, osc
 
 class ScriptedASR(Gtk.Window):
     def __init__(self, xml_filename, asr_config_file, osc_host, osc_port):
         super(ScriptedASR, self).__init__()
 
-        osc.setup(osc_host, osc_port)
-
         self.connect("destroy", self.quit)
         self.set_default_size(1024, 768)
         self.set_border_width(10)
         self.set_title('ASR Transcript [xml=%s asr=%s osc=%s:%s]' % (xml_filename, asr_config_file, osc_host, osc_port))
         vbox = Gtk.VBox()
 
-        self.sections = sections.SectionManager()
-        vbox.pack_start(self.sections, False, True, 5)
-
-        self.xmlview = xmlview_widgets.XmlView(xml_filename)
+        self.xmlview = xmlview.XmlView(xml_filename)
         vbox.pack_start(self.xmlview, True, True, 5)
         self.lines = [x for x in self.xmlview.get_line_iterator()]
         self.current_line = -1
-        self.xmlview.set_action_clicked_handler(self.keyword_clicked)
 
         self.confirmer = confirm.ConfirmationBox()
         vbox.pack_start(self.confirmer, False, True, 5)
 
-        #self.actions = action.ActionView()
-        #vbox.pack_start(self.actions, False, True, 5)
-
-        self.sections.set_confirmer(self.confirmer)
-        #self.actions.set_confirmer(self.confirmer)
-
-        self.sections.set_highlight(self.xmlview)
-        self.sections.set_section(1)
-
         # transcript view
         self.asr = asr.ASR(asr_config_file, self.hyp_changed, self.hyp_changed)
         vbox.pack_start(self.asr, False, True, 5)
@@ -71,7 +55,6 @@ class ScriptedASR(Gtk.Window):
         for section_fst in glob.glob(prefix % 'section*.fst'):
             found = re.search('section(\d+)\.fst$', section_fst)
             if found:
-                print section_fst
                 section_id = int(found.group(1))
                 self.slu[section_id] = SLU.SLU(prefix % 'dico_word.txt', prefix % 'dico_action.txt', section_fst, prefix % 'clean_tail.fst')
 
@@ -85,6 +68,10 @@ class ScriptedASR(Gtk.Window):
         style_provider.load_from_data(open('data/style.css', 'rb').read())
         Gtk.StyleContext.add_provider_for_screen( Gdk.Screen.get_default(), style_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
 
+        # setup singletons 
+        osc.setup(osc_host, osc_port)
+        actions.setup(self.confirmer, self.xmlview)
+
     def line_clicked(self, widget, event):
         if self.current_line >= 0:
             self.lines[self.current_line].highlight(False)
@@ -93,22 +80,17 @@ class ScriptedASR(Gtk.Window):
                 self.current_line = i
                 self.lines[self.current_line].highlight(True)
 
-    def keyword_clicked(self, action):
-        self.confirmer.confirm('Force action \"%s\"?' % action, 3, None)
-
     def hyp_changed(self, hyp):
         #hyp = ' '.join(hyp).replace('[noise]', ' ').split()
         words = hyp[-1].strip().replace('_', ' ').split()
-        section_id = self.sections.get_section()
-        print section_id, self.slu.keys()
+        section_id = int(self.xmlview.current_section.name) - 1
         if section_id in self.slu:
-            print 'SLU: ', section_id
             slu = self.slu[section_id]
             previous_actions = slu.num_actions()
             slu.process(words)
             for action_id in range(previous_actions, slu.num_actions()):
                 action = slu.get_action(action_id)
-                self.confirmer.confirm('Perform action \"%s\"?' % action, 3, None)
+                actions.perform_action(actions.Action(action))
 
         #if self.current_line >= len(self.lines) - 1:
         #    print "FINISHED"
diff --git a/timer.py b/timer.py
new file mode 100644
index 0000000..97d9eef
--- /dev/null
+++ b/timer.py
@@ -0,0 +1,19 @@
+from gi.repository import Gtk, GObject
+import datetime
+
+class Timer(Gtk.Label):
+    def __init__(self):
+        super(Timer, self).__init__()
+        self.start_time = datetime.datetime.now()
+        self.timer = GObject.timeout_add(100, self.update)
+        self.get_style_context().add_class('timer')
+
+    def update(self):
+        self.current_time = datetime.datetime.now() - self.start_time
+        self.set_text(self.to_string())
+        self.timer = GObject.timeout_add(100, self.update)
+
+    def to_string(self):
+        time = self.current_time
+        return '%02d:%02d:%02d.%01d' % (time.seconds / 3600, (time.seconds / 60) % 60, time.seconds % 60, time.microseconds / 100000)
+
diff --git a/xmlview.py b/xmlview.py
index aba9b3c..d6ceee0 100644
--- a/xmlview.py
+++ b/xmlview.py
@@ -1,17 +1,117 @@
-from gi.repository import GObject, Gtk, Pango
+import animate, actions
+
+from gi.repository import GObject, Gtk, Pango, Gdk
 from xml.etree import ElementTree as ET
 
-class Section:
-    def __init__(self, name, start, end):
-        self.name = name
-        self.start = start
-        self.end = end
+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')
 
-class Word:
-    def __init__(self, text, start, end):
-        self.text = text
-        self.start = start
-        self.end = end
+    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 link_clicked(self, widget, uri):
+        actions.perform_action(actions.Action(uri, keyword=widget))
+        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):
@@ -19,64 +119,49 @@ class XmlView(Gtk.ScrolledWindow):
         self.sections = []
         self.words = []
 
-        self.view = Gtk.TextView()
-        self.view.set_editable(False)
-        self.view.set_cursor_visible(False)
-        self.buffer = self.view.get_buffer()
-
         self.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.ALWAYS)
-        self.add_with_viewport(self.view)
 
-        #self.inactive_section = self.buffer.create_tag("inactive_section", background="#ffffff")
-        self.active_section = self.buffer.create_tag("active_section", background="red")
-        self.section_title = self.buffer.create_tag("section_title", scale=2, weight=Pango.Weight.BOLD, justification=Gtk.Justification.CENTER)
-        self.subsection_title = self.buffer.create_tag("subsection_title", scale=1.5, weight=Pango.Weight.BOLD, justification=Gtk.Justification.CENTER)
+        self.vbox = self.parse_xml(filename)
+        self.add_with_viewport(self.vbox)
 
-        self.parse_xml(filename)
+        self.connect('scroll-event', lambda widget, event: animate.cancel())
 
-        self.last_section = None
-        self.show_section(0)
+        for section in self.sections:
+            section.add_listener(self.section_clicked)
+        self.set_section(0)
 
     def get_view(self):
         return self
 
-    def parse_sequence(self, sequence, name):
-        self.buffer.insert_with_tags(self.buffer.get_end_iter(), 'Sequence %s\n' % name, self.subsection_title)
-
-        text = str(sequence.text)
-        for node in sequence:
-            text += node.text
-            text += node.tail
-        for line in text.split('\n'):
-            line = line.strip()
-            if line != '':
-                self.buffer.insert_with_tags(self.buffer.get_end_iter(), '   %s\n' % line)
-
-    def parse_section(self, section):
-        name = section.get('id')
-        section_start = self.buffer.create_mark('section-start %s' % name, self.buffer.get_end_iter(), True)
-        self.buffer.insert_with_tags(self.buffer.get_end_iter(), 'Section %s\n' % section.get('id'), self.section_title)
-
-        num = 1
-        for sequence in section.findall('./sequence'):
-            self.parse_sequence(sequence, section.get('id') + '.' + str(num))
-            num += 1
-        self.sections.append(Section(name, section_start, self.buffer.create_mark('section-end %s' % name, self.buffer.get_end_iter(), True)))
-
     def parse_xml(self, filename):
+        self.sections = []
         root = ET.parse(filename)
-        treestore = Gtk.TreeStore(str)
+        vbox = Gtk.VBox()
+        vbox.get_style_context().add_class('xmlview')
         for section in root.findall(".//section"):
-            self.parse_section(section)
-        return treestore
-
-    def show_section(self, section):
-        if self.last_section != None:
-            self.buffer.remove_tag(self.active_section, 
-                    self.buffer.get_iter_at_mark(self.sections[self.last_section].start), 
-                    self.buffer.get_iter_at_mark(self.sections[self.last_section].end))
-        self.last_section = section
-        self.buffer.apply_tag(self.active_section, 
-                self.buffer.get_iter_at_mark(self.sections[section].start), 
-                self.buffer.get_iter_at_mark(self.sections[section].end))
+            self.sections.append(Section(section))
+            vbox.pack_start(self.sections[-1], True, True, 5)
+        return vbox
+
+    def get_line_iterator(self):
+        for section in self.sections:
+            for sequence in section.sequences:
+                for line in sequence.lines:
+                    yield line
+
+    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):
+        pass
 
diff --git a/xmlview_widgets.py b/xmlview_widgets.py
deleted file mode 100644
index ab30d77..0000000
--- a/xmlview_widgets.py
+++ /dev/null
@@ -1,176 +0,0 @@
-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])
-
-- 
GitLab