Blob Blame Raw
From a53f0408ea3fb6d8a19ba75f93f6315375fbf978 Mon Sep 17 00:00:00 2001
From: Patrick Monnerat <patrick@monnerat.net>
Date: Thu, 23 May 2019 20:42:23 +0200
Subject: [PATCH] externaltools plugin: change code for Python 2 & 3
 compatibility.

---
 plugins/externaltools/tools/__init__.py    |  13 +-
 plugins/externaltools/tools/capture.py     |  21 +-
 plugins/externaltools/tools/functions.py   |   6 +-
 plugins/externaltools/tools/library.py     |  78 ++-
 plugins/externaltools/tools/manager.py     | 209 ++----
 plugins/externaltools/tools/outputpanel.py |   9 +-
 plugins/externaltools/tools/outputpanel.ui |  22 +-
 plugins/externaltools/tools/tools.ui       | 706 ++++++++++-----------
 8 files changed, 469 insertions(+), 595 deletions(-)

diff --git a/plugins/externaltools/tools/__init__.py b/plugins/externaltools/tools/__init__.py
index 153d6c6..b0b67dc 100755
--- a/plugins/externaltools/tools/__init__.py
+++ b/plugins/externaltools/tools/__init__.py
@@ -16,14 +16,13 @@
 #    along with this program; if not, write to the Free Software
 #    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
-__all__ = ('ExternalToolsPlugin', 'Manager', 'OutputPanel', 'Capture', 'UniqueById')
+__all__ = ('ExternalToolsPlugin', )
 
 from gi.repository import GObject, Gtk, Peas, Pluma
-from manager import Manager
-from library import ToolLibrary
-from outputpanel import OutputPanel
-from capture import Capture
-from functions import *
+from .manager import Manager
+from .library import ToolLibrary
+from .outputpanel import OutputPanel
+from .functions import *
 
 class ToolMenu(object):
     def __init__(self, library, window, panel, plugin, menupath):
@@ -214,7 +213,7 @@ class ExternalToolsPlugin(GObject.Object, Peas.Activatable):
         bottom = window.get_bottom_panel()
         bottom.add_item_with_icon(self._output_buffer.panel,
                                   _("Shell Output"),
-                                  Gtk.STOCK_EXECUTE)
+                                  "system-run")
 
     def do_deactivate(self):
         window = self.object
diff --git a/plugins/externaltools/tools/capture.py b/plugins/externaltools/tools/capture.py
index 73ce270..67d12bf 100755
--- a/plugins/externaltools/tools/capture.py
+++ b/plugins/externaltools/tools/capture.py
@@ -18,7 +18,9 @@
 
 __all__ = ('Capture', )
 
-import os, sys, signal
+import os
+import sys
+import signal
 import locale
 import subprocess
 import fcntl
@@ -39,7 +41,7 @@ class Capture(GObject.Object):
         'end-execute'  : (GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, (GObject.TYPE_INT,))
     }
 
-    def __init__(self, command, cwd = None, env = {}):
+    def __init__(self, command, cwd=None, env={}):
         GObject.GObject.__init__(self)
         self.pipe = None
         self.env = env
@@ -58,6 +60,8 @@ class Capture(GObject.Object):
         self.flags = flags
 
     def set_input(self, text):
+        if text and not isinstance(text, bytes):
+            text = text.encode("utf-8")
         self.input_text = text
 
     def set_cwd(self, cwd):
@@ -87,7 +91,7 @@ class Capture(GObject.Object):
 
         try:
             self.pipe = subprocess.Popen(self.command, **popen_args)
-        except OSError, e:
+        except OSError as e:
             self.pipe = None
             self.emit('stderr-line', _('Could not execute command: %s') % (e, ))
             return
@@ -116,7 +120,7 @@ class Capture(GObject.Object):
         # IO
         if self.input_text is not None:
             # Write async, in chunks of something
-            self.write_buffer = str(self.input_text)
+            self.write_buffer = self.input_text
 
             if self.idle_write_chunk():
                 self.idle_write_id = GLib.idle_add(self.idle_write_chunk)
@@ -136,7 +140,7 @@ class Capture(GObject.Object):
             self.pipe.stdin.write(self.write_buffer[:m])
 
             if m == l:
-                self.write_buffer = ''
+                self.write_buffer = b''
                 self.pipe.stdin.close()
 
                 self.idle_write_id = 0
@@ -157,11 +161,10 @@ class Capture(GObject.Object):
 
             if len(line) > 0:
                 try:
-                    line = unicode(line, 'utf-8')
+                    line = line.decode('utf-8')
                 except:
-                    line = unicode(line,
-                                   locale.getdefaultlocale()[1],
-                                   'replace')
+                    line = line.decode(locale.getdefaultlocale()[1],
+                                       'replace')
 
                 self.read_buffer += line
                 lines = self.read_buffer.splitlines(True)
diff --git a/plugins/externaltools/tools/functions.py b/plugins/externaltools/tools/functions.py
index dd4f82b..e76689b 100755
--- a/plugins/externaltools/tools/functions.py
+++ b/plugins/externaltools/tools/functions.py
@@ -18,8 +18,8 @@
 
 import os
 from gi.repository import Gio, Gdk, Gtk, GtkSource, Pluma
-from outputpanel import OutputPanel
-from capture import *
+from .outputpanel import OutputPanel
+from .capture import *
 
 def default(val, d):
     if val is not None:
@@ -131,8 +131,6 @@ def run_external_tool(window, panel, node):
         elif input_type == 'selection' or input_type == 'selection-document':
             try:
                 start, end = document.get_selection_bounds()
-
-                print start, end
             except ValueError:
                 if input_type == 'selection-document':
                     start, end = document.get_bounds()
diff --git a/plugins/externaltools/tools/library.py b/plugins/externaltools/tools/library.py
index 186c33f..ff3fa9b 100755
--- a/plugins/externaltools/tools/library.py
+++ b/plugins/externaltools/tools/library.py
@@ -19,19 +19,21 @@
 import os
 import re
 import locale
+import codecs
 from gi.repository import GLib
 
+
 class Singleton(object):
     _instance = None
 
     def __new__(cls, *args, **kwargs):
         if not cls._instance:
-            cls._instance = super(Singleton, cls).__new__(
-                             cls, *args, **kwargs)
+            cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
             cls._instance.__init_once__()
 
         return cls._instance
 
+
 class ToolLibrary(Singleton):
     def __init_once__(self):
         self.locations = []
@@ -46,7 +48,7 @@ class ToolLibrary(Singleton):
 
         # self.locations[0] is where we save the custom scripts
         toolsdir = os.path.join(GLib.get_user_config_dir(), 'pluma/tools')
-        self.locations.insert(0, toolsdir);
+        self.locations.insert(0, toolsdir)
 
         if not os.path.isdir(self.locations[0]):
             os.makedirs(self.locations[0])
@@ -74,7 +76,7 @@ class ToolLibrary(Singleton):
         if not os.path.isfile(filename):
             return
 
-        print "External tools: importing old tools into the new store..."
+        print("External tools: importing old tools into the new store...")
 
         xtree = et.parse(filename)
         xroot = xtree.getroot()
@@ -97,7 +99,7 @@ class ToolLibrary(Singleton):
 
             tool.save_with_script(xtool.text)
 
-    def get_full_path(self, path, mode='r', system = True, local = True):
+    def get_full_path(self, path, mode='r', system=True, local=True):
         assert (system or local)
         if path is None:
             return None
@@ -123,6 +125,7 @@ class ToolLibrary(Singleton):
                 os.mkdir(dirname)
             return path
 
+
 class ToolDirectory(object):
     def __init__(self, parent, dirname):
         super(ToolDirectory, self).__init__()
@@ -145,8 +148,7 @@ class ToolDirectory(object):
                 continue
             for i in os.listdir(d):
                 elements[i] = None
-        keys = elements.keys()
-        keys.sort()
+        keys = sorted(elements.keys())
         return keys
 
     def _load(self):
@@ -196,7 +198,7 @@ class ToolDirectory(object):
 class Tool(object):
     RE_KEY = re.compile('^([a-zA-Z_][a-zA-Z0-9_.\-]*)(\[([a-zA-Z_@]+)\])?$')
 
-    def __init__(self, parent, filename = None):
+    def __init__(self, parent, filename=None):
         super(Tool, self).__init__()
         self.parent = parent
         self.library = parent.library
@@ -212,7 +214,7 @@ class Tool(object):
         if value.strip() == '':
             return []
         else:
-            return map(lambda x: x.strip(), value.split(','))
+            return [x.strip() for x in value.split(',')]
 
     def _from_list(self, value):
         return ','.join(value)
@@ -231,7 +233,7 @@ class Tool(object):
         if filename is None:
             return
 
-        fp = file(filename, 'r', 1)
+        fp = codecs.open(filename, 'r', encoding='utf-8')
         in_block = False
         lang = locale.getlocale(locale.LC_MESSAGES)[0]
 
@@ -239,8 +241,10 @@ class Tool(object):
             if not in_block:
                 in_block = line.startswith('# [Pluma Tool]')
                 continue
-            if line.startswith('##') or line.startswith('# #'): continue
-            if not line.startswith('# '): break
+            if line.startswith('##') or line.startswith('# #'):
+                continue
+            if not line.startswith('# '):
+                break
 
             try:
                 (key, value) = [i.strip() for i in line[2:].split('=', 1)]
@@ -266,9 +270,6 @@ class Tool(object):
     def is_local(self):
         return self.library.get_full_path(self.get_path(), system=False) is not None
 
-    def is_global(self):
-        return self.library.get_full_path(self.get_path(), local=False) is not None
-
     def get_path(self):
         if self.filename is not None:
             return os.path.join(self.parent.get_path(), self.filename)
@@ -284,7 +285,8 @@ class Tool(object):
 
     def get_applicability(self):
         applicability = self._properties.get('Applicability')
-        if applicability: return applicability
+        if applicability:
+            return applicability
         return 'all'
 
     def set_applicability(self, value):
@@ -294,7 +296,8 @@ class Tool(object):
 
     def get_name(self):
         name = self._properties.get('Name')
-        if name: return name
+        if name:
+            return name
         return os.path.basename(self.filename)
 
     def set_name(self, value):
@@ -304,7 +307,8 @@ class Tool(object):
 
     def get_shortcut(self):
         shortcut = self._properties.get('Shortcut')
-        if shortcut: return shortcut
+        if shortcut:
+            return shortcut
         return None
 
     def set_shortcut(self, value):
@@ -314,7 +318,8 @@ class Tool(object):
 
     def get_comment(self):
         comment = self._properties.get('Comment')
-        if comment: return comment
+        if comment:
+            return comment
         return self.filename
 
     def set_comment(self, value):
@@ -324,7 +329,8 @@ class Tool(object):
 
     def get_input(self):
         input = self._properties.get('Input')
-        if input: return input
+        if input:
+            return input
         return 'nothing'
 
     def set_input(self, value):
@@ -334,7 +340,8 @@ class Tool(object):
 
     def get_output(self):
         output = self._properties.get('Output')
-        if output: return output
+        if output:
+            return output
         return 'output-panel'
 
     def set_output(self, value):
@@ -344,7 +351,8 @@ class Tool(object):
 
     def get_save_files(self):
         save_files = self._properties.get('Save-files')
-        if save_files: return save_files
+        if save_files:
+            return save_files
         return 'nothing'
 
     def set_save_files(self, value):
@@ -354,7 +362,8 @@ class Tool(object):
 
     def get_languages(self):
         languages = self._properties.get('Languages')
-        if languages: return languages
+        if languages:
+            return languages
         return []
 
     def set_languages(self, value):
@@ -370,7 +379,7 @@ class Tool(object):
         if filename is None:
             return True
 
-        fp = open(filename, 'r', 1)
+        fp = codecs.open(filename, 'r', encoding='utf-8')
         for line in fp:
             if line.strip() == '':
                 continue
@@ -386,7 +395,7 @@ class Tool(object):
         if filename is None:
             return ["#!/bin/sh\n"]
 
-        fp = open(filename, 'r', 1)
+        fp = codecs.open(filename, 'r', encoding='utf-8')
         lines = list()
 
         # before entering the data block
@@ -396,7 +405,8 @@ class Tool(object):
             lines.append(line)
         # in the block:
         for line in fp:
-            if line.startswith('##'): continue
+            if line.startswith('##'):
+                continue
             if not (line.startswith('# ') and '=' in line):
                 # after the block: strip one emtpy line (if present)
                 if line.strip() != '':
@@ -410,7 +420,7 @@ class Tool(object):
 
     def _dump_properties(self):
         lines = ['# [Pluma Tool]']
-        for item in self._properties.iteritems():
+        for item in self._properties.items():
             if item[0] in self._transform:
                 lines.append('# %s=%s' % (item[0], self._transform[item[0]][1](item[1])))
             elif item[1] is not None:
@@ -419,7 +429,7 @@ class Tool(object):
 
     def save_with_script(self, script):
         filename = self.library.get_full_path(self.filename, 'w')
-        fp = open(filename, 'w', 1)
+        fp = codecs.open(filename, 'w', encoding='utf-8')
 
         # Make sure to first print header (shebang, modeline), then
         # properties, and then actual content
@@ -430,7 +440,6 @@ class Tool(object):
         # Parse
         for line in script:
             line = line.rstrip("\n")
-
             if not inheader:
                 content.append(line)
             elif line.startswith('#!'):
@@ -453,7 +462,7 @@ class Tool(object):
             fp.write(line + "\n")
 
         fp.close()
-        os.chmod(filename, 0750)
+        os.chmod(filename, 0o750)
         self.changed = False
 
     def save(self):
@@ -478,16 +487,17 @@ class Tool(object):
 
 if __name__ == '__main__':
     library = ToolLibrary()
+    library.set_locations(os.path.expanduser("~/.config/pluma/tools"))
 
     def print_tool(t, indent):
-        print indent * "  " + "%s: %s" % (t.filename, t.name)
+        print(indent * "  " + "%s: %s" % (t.filename, t.name))
 
     def print_dir(d, indent):
-        print indent * "  " + d.dirname + '/'
+        print(indent * "  " + d.dirname + '/')
         for i in d.subdirs:
-            print_dir(i, indent+1)
+            print_dir(i, indent + 1)
         for i in d.tools:
-            print_tool(i, indent+1)
+            print_tool(i, indent + 1)
 
     print_dir(library.tree, 0)
 
diff --git a/plugins/externaltools/tools/manager.py b/plugins/externaltools/tools/manager.py
index 4da0deb..b8e143b 100755
--- a/plugins/externaltools/tools/manager.py
+++ b/plugins/externaltools/tools/manager.py
@@ -19,71 +19,41 @@
 __all__ = ('Manager', )
 
 import os.path
-from library import *
-from functions import *
+import re
+from .library import *
+from .functions import *
 import hashlib
 from xml.sax import saxutils
 from gi.repository import GObject, Gio, Gdk, Gtk, GtkSource, Pluma
 
-class LanguagesPopup(Gtk.Window):
-    __gtype_name__ = "LanguagePopup"
+class LanguagesPopup(Gtk.Popover):
+    __gtype_name__ = "LanguagesPopup"
 
     COLUMN_NAME = 0
     COLUMN_ID = 1
     COLUMN_ENABLED = 2
 
-    def __init__(self, languages):
-        Gtk.Window.__init__(self, type=Gtk.WindowType.POPUP)
+    def __init__(self, widget, languages):
+        Gtk.Popover.__init__(self, relative_to=widget)
 
-        self.set_default_size(200, 200)
         self.props.can_focus = True
 
         self.build()
         self.init_languages(languages)
 
-        self.show()
-
-        self.grab_add()
-
-        self.keyboard = None
-        device_manager = Gdk.Display.get_device_manager(self.get_window().get_display())
-        for device in device_manager.list_devices(Gdk.DeviceType.MASTER):
-            if device.get_source() == Gdk.InputSource.KEYBOARD:
-                self.keyboard = device
-                break
-
-        self.pointer = device_manager.get_client_pointer()
-
-        if self.keyboard is not None:
-            self.keyboard.grab(self.get_window(),
-                               Gdk.GrabOwnership.WINDOW, False,
-                               Gdk.EventMask.KEY_PRESS_MASK |
-                               Gdk.EventMask.KEY_RELEASE_MASK,
-                               None, Gdk.CURRENT_TIME)
-        self.pointer.grab(self.get_window(),
-                          Gdk.GrabOwnership.WINDOW, False,
-                          Gdk.EventMask.BUTTON_PRESS_MASK |
-                          Gdk.EventMask.BUTTON_RELEASE_MASK |
-                          Gdk.EventMask.POINTER_MOTION_MASK |
-                          Gdk.EventMask.ENTER_NOTIFY_MASK |
-                          Gdk.EventMask.LEAVE_NOTIFY_MASK |
-                          Gdk.EventMask.PROXIMITY_IN_MASK |
-                          Gdk.EventMask.PROXIMITY_OUT_MASK |
-                          Gdk.EventMask.SCROLL_MASK,
-                          None, Gdk.CURRENT_TIME)
-
         self.view.get_selection().select_path((0,))
 
     def build(self):
         self.model = Gtk.ListStore(str, str, bool)
 
         self.sw = Gtk.ScrolledWindow()
+        self.sw.set_size_request(-1, 200)
         self.sw.show()
 
-        self.sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
+        self.sw.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
         self.sw.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
 
-        self.view = Gtk.TreeView(self.model)
+        self.view = Gtk.TreeView(model=self.model)
         self.view.show()
 
         self.view.set_headers_visible(False)
@@ -92,16 +62,16 @@ class LanguagesPopup(Gtk.Window):
 
         renderer = Gtk.CellRendererToggle()
         column.pack_start(renderer, False)
-        column.set_attributes(renderer, active=self.COLUMN_ENABLED)
+        column.add_attribute(renderer, 'active', self.COLUMN_ENABLED)
 
         renderer.connect('toggled', self.on_language_toggled)
 
         renderer = Gtk.CellRendererText()
         column.pack_start(renderer, True)
-        column.set_attributes(renderer, text=self.COLUMN_NAME)
+        column.add_attribute(renderer, 'text', self.COLUMN_NAME)
 
         self.view.append_column(column)
-        self.view.set_row_separator_func(self.on_separator)
+        self.view.set_row_separator_func(self.on_separator, None)
 
         self.sw.add(self.view)
 
@@ -124,7 +94,7 @@ class LanguagesPopup(Gtk.Window):
         self.model.foreach(self.enabled_languages, ret)
         return ret
 
-    def on_separator(self, model, piter):
+    def on_separator(self, model, piter, user_data=None):
         val = model.get_value(piter, self.COLUMN_NAME)
         return val == '-'
 
@@ -142,7 +112,7 @@ class LanguagesPopup(Gtk.Window):
             self.model.append([lang.get_name(), lang.get_id(), lang.get_id() in languages])
 
     def correct_all(self, model, path, piter, enabled):
-        if path == (0,):
+        if path.get_indices()[0] == 0:
             return False
 
         model.set_value(piter, self.COLUMN_ENABLED, enabled)
@@ -158,113 +128,6 @@ class LanguagesPopup(Gtk.Window):
         else:
             self.model.set_value(self.model.get_iter_first(), self.COLUMN_ENABLED, False)
 
-    def do_key_press_event(self, event):
-        if event.keyval == Gdk.KEY_Escape:
-            self.destroy()
-            return True
-        else:
-            event.window = self.view.get_bin_window()
-            return self.view.event(event)
-
-    def do_key_release_event(self, event):
-        event.window = self.view.get_bin_window()
-        return self.view.event(event)
-
-    def in_window(self, event, window=None):
-        if not window:
-            window = self.get_window()
-
-        geometry = window.get_geometry()
-        origin = window.get_origin()
-
-        return event.x_root >= origin[1] and \
-               event.x_root <= origin[1] + geometry[2] and \
-               event.y_root >= origin[2] and \
-               event.y_root <= origin[2] + geometry[3]
-
-    def do_destroy(self):
-        if self.keyboard:
-            self.keyboard.ungrab(Gdk.CURRENT_TIME)
-        self.pointer.ungrab(Gdk.CURRENT_TIME)
-
-        return Gtk.Window.do_destroy(self)
-
-    def setup_event(self, event, window):
-        fr = event.window.get_origin()
-        to = window.get_origin()
-
-        event.window = window
-        event.x += fr[1] - to[1]
-        event.y += fr[2] - to[2]
-
-    def resolve_widgets(self, root):
-        res = [root]
-
-        if isinstance(root, Gtk.Container):
-            root.forall(lambda x, y: res.extend(self.resolve_widgets(x)), None)
-
-        return res
-
-    def resolve_windows(self, window):
-        if not window:
-            return []
-
-        res = [window]
-        res.extend(window.get_children())
-
-        return res
-
-    def propagate_mouse_event(self, event, reverse=True):
-        allwidgets = self.resolve_widgets(self.get_child())
-
-        if reverse:
-            allwidgets.reverse()
-
-        for widget in allwidgets:
-            windows = self.resolve_windows(widget.get_window())
-            windows.reverse()
-
-            for window in windows:
-                if not (window.get_events() & event.type):
-                    continue
-
-                if self.in_window(event, window):
-                    self.setup_event(event, window)
-
-                    if widget.event(event):
-                        return True
-
-        return False
-
-    def do_button_press_event(self, event):
-        if not self.in_window(event):
-            self.destroy()
-        else:
-            return self.propagate_mouse_event(event)
-
-    def do_button_release_event(self, event):
-        if not self.in_window(event):
-            self.destroy()
-        else:
-            return self.propagate_mouse_event(event)
-
-    def do_scroll_event(self, event):
-        return self.propagate_mouse_event(event, False)
-
-    def do_motion_notify_event(self, event):
-        return self.propagate_mouse_event(event)
-
-    def do_enter_notify_event(self, event):
-        return self.propagate_mouse_event(event)
-
-    def do_leave_notify_event(self, event):
-        return self.propagate_mouse_event(event)
-
-    def do_proximity_in_event(self, event):
-        return self.propagate_mouse_event(event)
-
-    def do_proximity_out_event(self, event):
-        return self.propagate_mouse_event(event)
 
 class Manager(GObject.Object):
     TOOL_COLUMN = 0 # For Tree
@@ -450,7 +313,9 @@ class Manager(GObject.Object):
             n1 = t1.name
             n2 = t2.name
 
-        return cmp(n1.lower(), n2.lower())
+        n1 = n1.lower()
+        n2 = n2.lower()
+        return (n1 > n2) - (n1 < n2)
 
     def __init_tools_view(self):
         # Tools column
@@ -499,8 +364,8 @@ class Manager(GObject.Object):
         else:
             return None, None
 
-    def compute_hash(self, string):
-        return hashlib.md5(string).hexdigest()
+    def compute_hash(self, stringofbytes):
+        return hashlib.md5(stringofbytes).hexdigest()
 
     def save_current_tool(self):
         if self.current_node is None:
@@ -521,7 +386,10 @@ class Manager(GObject.Object):
         buf = self['commands'].get_buffer()
         (start, end) = buf.get_bounds()
         script  = buf.get_text(start, end, False)
-        h = self.compute_hash(script)
+        scriptbytes = script
+        if not isinstance(scriptbytes, bytes):
+            scriptbytes = scriptbytes.encode('utf-8')
+        h = self.compute_hash(scriptbytes)
         if h != self.script_hash:
             # script has changed -> save it
             self.current_node.save_with_script([line + "\n" for line in script.splitlines()])
@@ -573,6 +441,9 @@ class Manager(GObject.Object):
         buf.set_text(script)
         buf.end_not_undoable_action()
 
+        if not isinstance(script, bytes):
+            script = script.encode('utf-8')
+
         self.script_hash = self.compute_hash(script)
         contenttype, uncertain = Gio.content_type_guess(None, script)
         lmanager = GtkSource.LanguageManager.get_default()
@@ -703,7 +574,7 @@ class Manager(GObject.Object):
             if language in node.languages:
                 node.languages.remove(language)
 
-            self._tool_rows[node] = filter(lambda x: x.valid(), self._tool_rows[node])
+            self._tool_rows[node] = [x for x in self._tool_rows[node] if x.valid()]
 
             if not self._tool_rows[node]:
                 del self._tool_rows[node]
@@ -714,7 +585,9 @@ class Manager(GObject.Object):
                     self.script_hash = None
 
                     if self.model.iter_is_valid(piter):
-                        self.view.set_cursor(self.model.get_path(piter), self.view.get_column(self.TOOL_COLUMN), False)
+                        self.view.set_cursor(self.model.get_path(piter),
+                                             self.view.get_column(self.TOOL_COLUMN),
+                                             False)
 
                 self.view.grab_focus()
 
@@ -799,19 +672,19 @@ class Manager(GObject.Object):
 
     def on_accelerator_key_press(self, entry, event):
         mask = event.state & Gtk.accelerator_get_default_mod_mask()
+        keyname = Gdk.keyval_name(event.keyval)
 
-        if event.keyval == Gdk.KEY_Escape:
+        if keyname == 'Escape':
             entry.set_text(default(self.current_node.shortcut, ''))
             self['commands'].grab_focus()
             return True
-        elif event.keyval == Gdk.KEY_Delete \
-          or event.keyval == Gdk.KEY_BackSpace:
+        elif keyname == 'Delete' or keyname == 'BackSpace':
             entry.set_text('')
             self.remove_accelerator(self.current_node)
             self.current_node.shortcut = None
             self['commands'].grab_focus()
             return True
-        elif event.keyval in range(Gdk.KEY_F1, Gdk.KEY_F12 + 1):
+        elif re.match('^F(:1[012]?|[2-9])$', keyname):
             # New accelerator
             if self.set_accelerator(event.keyval, mask):
                 entry.set_text(default(self.current_node.shortcut, ''))
@@ -911,7 +784,7 @@ class Manager(GObject.Object):
         ret = None
 
         if node:
-            ref = Gtk.TreeRowReference(self.model, self.model.get_path(piter))
+            ref = Gtk.TreeRowReference.new(self.model, self.model.get_path(piter))
 
         # Update languages, make sure to inhibit selection change stuff
         self.view.get_selection().handler_block(self.selection_changed_id)
@@ -966,12 +839,8 @@ class Manager(GObject.Object):
         self.view.get_selection().handler_unblock(self.selection_changed_id)
 
     def on_languages_button_clicked(self, button):
-        popup = LanguagesPopup(self.current_node.languages)
-        popup.set_transient_for(self.dialog)
-
-        origin = button.get_window().get_origin()
-        popup.move(origin[1], origin[2] - popup.get_allocation().height)
-
-        popup.connect('destroy', self.update_languages)
+        popup = LanguagesPopup(button, self.current_node.languages)
+        popup.show()
+        popup.connect('closed', self.update_languages)
 
 # ex:et:ts=4:
diff --git a/plugins/externaltools/tools/outputpanel.py b/plugins/externaltools/tools/outputpanel.py
index e063eb2..39fd99a 100755
--- a/plugins/externaltools/tools/outputpanel.py
+++ b/plugins/externaltools/tools/outputpanel.py
@@ -20,11 +20,12 @@
 __all__ = ('OutputPanel', 'UniqueById')
 
 import os
-from weakref import WeakKeyDictionary
-from capture import *
 import re
-import linkparsing
-import filelookup
+
+from weakref import WeakKeyDictionary
+from .capture import *
+from . import linkparsing
+from . import filelookup
 from gi.repository import GLib, Gdk, Gtk, Pango, Pluma
 
 class UniqueById:
diff --git a/plugins/externaltools/tools/outputpanel.ui b/plugins/externaltools/tools/outputpanel.ui
index 01904a6..30f2e33 100644
--- a/plugins/externaltools/tools/outputpanel.ui
+++ b/plugins/externaltools/tools/outputpanel.ui
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.20.2 
+<!-- Generated with glade 3.22.1 
 
 Version: 2.91.3
 	Date: Sat Nov 18 13:58:59 2006
@@ -9,14 +9,17 @@ Version: 2.91.3
 -->
 <interface>
   <requires lib="gtk+" version="3.22"/>
-  <object class="GtkBox" id="output-panel">
+  <object class="GtkGrid" id="output-panel">
     <property name="visible">True</property>
     <property name="can_focus">False</property>
+    <property name="hexpand">True</property>
+    <property name="vexpand">True</property>
     <child>
       <object class="GtkScrolledWindow" id="scrolledwindow1">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
         <property name="hexpand">True</property>
+        <property name="vexpand">True</property>
         <property name="shadow_type">in</property>
         <child>
           <object class="GtkTextView" id="view">
@@ -33,9 +36,8 @@ Version: 2.91.3
         </child>
       </object>
       <packing>
-        <property name="expand">False</property>
-        <property name="fill">True</property>
-        <property name="position">0</property>
+        <property name="left_attach">0</property>
+        <property name="top_attach">0</property>
       </packing>
     </child>
     <child>
@@ -43,7 +45,6 @@ Version: 2.91.3
         <property name="visible">True</property>
         <property name="can_focus">False</property>
         <property name="border_width">6</property>
-        <property name="orientation">vertical</property>
         <property name="spacing">6</property>
         <property name="layout_style">end</property>
         <child>
@@ -57,16 +58,15 @@ Version: 2.91.3
             <signal name="clicked" handler="on_stop_clicked" swapped="no"/>
           </object>
           <packing>
-            <property name="expand">True</property>
-            <property name="fill">True</property>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
             <property name="position">0</property>
           </packing>
         </child>
       </object>
       <packing>
-        <property name="expand">False</property>
-        <property name="fill">True</property>
-        <property name="position">1</property>
+        <property name="left_attach">1</property>
+        <property name="top_attach">0</property>
       </packing>
     </child>
   </object>
diff --git a/plugins/externaltools/tools/tools.ui b/plugins/externaltools/tools/tools.ui
index afdd3f9..21de842 100644
--- a/plugins/externaltools/tools/tools.ui
+++ b/plugins/externaltools/tools/tools.ui
@@ -1,30 +1,45 @@
-<?xml version="1.0"?>
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
 <interface>
-  <object class="GtkListStore" id="model_save_files">
+  <requires lib="gtk+" version="3.0"/>
+  <object class="PlumaDocument" id="commands_buffer">
+  	<property name="highlight-matching-brackets">True</property>
+  </object>
+  <object class="GtkListStore" id="model_applicability">
     <columns>
       <!-- column-name gchararray -->
       <column type="gchararray"/>
-      <!-- column-name gchararray -->
+      <!-- column-name gchararray1 -->
       <column type="gchararray"/>
     </columns>
     <data>
       <row>
-        <col id="0" translatable="yes">Nothing</col>
-        <col id="1">nothing</col>
+        <col id="0" translatable="yes">All documents</col>
+        <col id="1">all</col>
       </row>
       <row>
-        <col id="0" translatable="yes">Current document</col>
-        <col id="1">document</col>
+        <col id="0" translatable="yes">All documents except untitled ones</col>
+        <col id="1">titled</col>
       </row>
       <row>
-        <col id="0" translatable="yes">All documents</col>
-        <col id="1">all</col>
+        <col id="0" translatable="yes">Local files only</col>
+        <col id="1">local</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Remote files only</col>
+        <col id="1">remote</col>
+      </row>
+      <row>
+        <col id="0" translatable="yes">Untitled documents only</col>
+        <col id="1">untitled</col>
       </row>
     </data>
   </object>
   <object class="GtkListStore" id="model_input">
     <columns>
+      <!-- column-name gchararray -->
       <column type="gchararray"/>
+      <!-- column-name gchararray1 -->
       <column type="gchararray"/>
     </columns>
     <data>
@@ -62,7 +77,7 @@
       <column type="gchararray"/>
     </columns>
     <data>
-	  <row>
+      <row>
         <col id="0" translatable="yes">Nothing</col>
         <col id="1">nothing</col>
       </row>
@@ -92,7 +107,7 @@
       </row>
     </data>
   </object>
-  <object class="GtkListStore" id="model_applicability">
+  <object class="GtkListStore" id="model_save_files">
     <columns>
       <!-- column-name gchararray -->
       <column type="gchararray"/>
@@ -101,72 +116,105 @@
     </columns>
     <data>
       <row>
-        <col id="0" translatable="yes">All documents</col>
-        <col id="1">all</col>
-      </row>
-      <row>
-        <col id="0" translatable="yes">All documents except untitled ones</col>
-        <col id="1">titled</col>
-      </row>
-      <row>
-        <col id="0" translatable="yes">Local files only</col>
-        <col id="1">local</col>
+        <col id="0" translatable="yes">Nothing</col>
+        <col id="1">nothing</col>
       </row>
       <row>
-        <col id="0" translatable="yes">Remote files only</col>
-        <col id="1">remote</col>
+        <col id="0" translatable="yes">Current document</col>
+        <col id="1">document</col>
       </row>
       <row>
-        <col id="0" translatable="yes">Untitled documents only</col>
-        <col id="1">untitled</col>
+        <col id="0" translatable="yes">All documents</col>
+        <col id="1">all</col>
       </row>
     </data>
   </object>
-  <object class="PlumaDocument" id="commands_buffer">
-  	<property name="highlight-matching-brackets">True</property>
-  </object>
   <object class="GtkDialog" id="tool-manager-dialog">
+    <property name="can_focus">False</property>
     <property name="title" translatable="yes">External Tools Manager</property>
     <property name="default_width">750</property>
     <property name="default_height">500</property>
     <property name="type_hint">dialog</property>
     <property name="skip_taskbar_hint">True</property>
-    <signal name="configure_event" handler="on_tool_manager_dialog_configure_event"/>
-    <signal name="focus_out_event" handler="on_tool_manager_dialog_focus_out"/>
-    <signal name="response" handler="on_tool_manager_dialog_response"/>
+    <signal name="configure-event" handler="on_tool_manager_dialog_configure_event" swapped="no"/>
+    <signal name="focus-out-event" handler="on_tool_manager_dialog_focus_out" swapped="no"/>
+    <signal name="response" handler="on_tool_manager_dialog_response" swapped="no"/>
+    <child>
+      <placeholder/>
+    </child>
     <child internal-child="vbox">
-      <object class="GtkVBox" id="tool-manager-dialog-vbox">
+      <object class="GtkBox" id="tool-manager-dialog-vbox">
         <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox" id="hbuttonbox1">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="button1">
+                <property name="label">gtk-help</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="button2">
+                <property name="label">gtk-close</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
         <child>
-          <object class="GtkHPaned" id="paned">
+          <object class="GtkPaned" id="paned">
             <property name="visible">True</property>
             <property name="can_focus">True</property>
-            <property name="border_width">6</property>
+            <property name="hexpand">True</property>
+            <property name="vexpand">True</property>
             <property name="position">275</property>
             <child>
-              <object class="GtkVBox" id="vbox2">
+              <object class="GtkGrid">
                 <property name="visible">True</property>
-                <property name="spacing">6</property>
-                <child>
-                  <object class="GtkLabel" id="label20">
-                    <property name="visible">True</property>
-                    <property name="xalign">0</property>
-                    <property name="label" translatable="yes">_Tools:</property>
-                    <property name="use_underline">True</property>
-                    <property name="mnemonic_widget">view</property>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">False</property>
-                    <property name="position">0</property>
-                  </packing>
-                </child>
+                <property name="can_focus">False</property>
+                <property name="margin_left">6</property>
+                <property name="margin_right">6</property>
+                <property name="margin_top">6</property>
+                <property name="margin_bottom">6</property>
+                <property name="hexpand">True</property>
+                <property name="vexpand">True</property>
+                <property name="orientation">vertical</property>
+                <property name="row_spacing">6</property>
                 <child>
                   <object class="GtkScrolledWindow" id="scrolled_window1">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
-                    <property name="hscrollbar_policy">automatic</property>
-                    <property name="vscrollbar_policy">automatic</property>
+                    <property name="hexpand">True</property>
+                    <property name="vexpand">True</property>
                     <property name="shadow_type">in</property>
                     <child>
                       <object class="GtkTreeView" id="view">
@@ -174,29 +222,49 @@
                         <property name="can_focus">True</property>
                         <property name="headers_visible">False</property>
                         <property name="reorderable">True</property>
+                        <child internal-child="selection">
+                          <object class="GtkTreeSelection"/>
+                        </child>
                       </object>
                     </child>
                   </object>
                   <packing>
-                    <property name="position">1</property>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label20">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label" translatable="yes">_Tools:</property>
+                    <property name="use_underline">True</property>
+                    <property name="mnemonic_widget">view</property>
+                    <property name="xalign">0</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">0</property>
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkHBox" id="hbox2">
+                  <object class="GtkButtonBox">
                     <property name="visible">True</property>
-                    <property name="spacing">6</property>
+                    <property name="can_focus">False</property>
+                    <property name="layout_style">start</property>
                     <child>
                       <object class="GtkButton" id="new-tool-button">
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
                         <property name="can_default">True</property>
                         <property name="receives_default">False</property>
-                        <signal name="clicked" handler="on_new_tool_button_clicked"/>
+                        <property name="halign">start</property>
+                        <signal name="clicked" handler="on_new_tool_button_clicked" swapped="no"/>
                         <child>
                           <object class="GtkImage" id="new-tool-image">
                             <property name="visible">True</property>
+                            <property name="can_focus">False</property>
                             <property name="stock">gtk-new</property>
-                            <property name="icon-size">4</property>
                           </object>
                         </child>
                       </object>
@@ -204,344 +272,311 @@
                         <property name="expand">False</property>
                         <property name="fill">False</property>
                         <property name="position">0</property>
+                        <property name="non_homogeneous">True</property>
                       </packing>
                     </child>
                     <child>
-                      <object class="GtkButton" id="revert-tool-button">
+                      <object class="GtkButton" id="remove-tool-button">
+                        <property name="visible">True</property>
                         <property name="can_focus">False</property>
+                        <property name="can_default">True</property>
                         <property name="receives_default">False</property>
-                        <signal name="clicked" handler="on_remove_tool_button_clicked"/>
+                        <property name="halign">start</property>
+                        <signal name="clicked" handler="on_remove_tool_button_clicked" swapped="no"/>
                         <child>
-                          <object class="GtkImage" id="revert-tool-image">
+                          <object class="GtkImage" id="remove-tool-image">
                             <property name="visible">True</property>
-                            <property name="stock">gtk-revert-to-saved</property>
-                            <property name="icon-size">4</property>
+                            <property name="can_focus">False</property>
+                            <property name="stock">gtk-delete</property>
                           </object>
                         </child>
                       </object>
                       <packing>
                         <property name="expand">False</property>
                         <property name="fill">False</property>
-                        <property name="pack_type">end</property>
-                        <property name="position">2</property>
+                        <property name="position">1</property>
+                        <property name="non_homogeneous">True</property>
                       </packing>
                     </child>
                     <child>
-                      <object class="GtkButton" id="remove-tool-button">
-                        <property name="visible">True</property>
+                      <object class="GtkButton" id="revert-tool-button">
                         <property name="can_focus">False</property>
-                        <property name="can_default">True</property>
                         <property name="receives_default">False</property>
-                        <signal name="clicked" handler="on_remove_tool_button_clicked"/>
+                        <property name="halign">start</property>
+                        <signal name="clicked" handler="on_remove_tool_button_clicked" swapped="no"/>
                         <child>
-                          <object class="GtkImage" id="remove-tool-image">
+                          <object class="GtkImage" id="revert-tool-image">
                             <property name="visible">True</property>
-                            <property name="stock">gtk-delete</property>
-                            <property name="icon-size">4</property>
+                            <property name="can_focus">False</property>
+                            <property name="stock">gtk-revert-to-saved</property>
                           </object>
                         </child>
                       </object>
                       <packing>
                         <property name="expand">False</property>
                         <property name="fill">False</property>
-                        <property name="pack_type">end</property>
-                        <property name="position">1</property>
+                        <property name="position">2</property>
+                        <property name="non_homogeneous">True</property>
                       </packing>
                     </child>
                   </object>
                   <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">False</property>
-                    <property name="position">2</property>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">2</property>
                   </packing>
                 </child>
               </object>
               <packing>
-                <property name="resize">False</property>
-                <property name="shrink">False</property>
+                <property name="resize">True</property>
+                <property name="shrink">True</property>
               </packing>
             </child>
             <child>
-              <object class="GtkVBox" id="vbox5">
+              <object class="GtkGrid">
                 <property name="visible">True</property>
-                <property name="spacing">6</property>
+                <property name="can_focus">False</property>
+                <property name="hexpand">True</property>
+                <property name="vexpand">True</property>
+                <property name="orientation">vertical</property>
+                <property name="row_spacing">6</property>
                 <child>
-                  <object class="GtkLabel" id="title">
-                    <property name="visible">True</property>
-                    <property name="xalign">0</property>
-                    <property name="yalign">0.5</property>
-                    <property name="label" translatable="yes">_Edit:</property>
-                    <property name="mnemonic_widget">commands</property>
-                    <property name="use_underline">True</property>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">False</property>
-                    <property name="position">0</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkHBox" id="hbox7">
+                  <object class="GtkGrid" id="tool-table">
                     <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="hexpand">True</property>
+                    <property name="vexpand">True</property>
+                    <property name="orientation">vertical</property>
+                    <property name="row_spacing">6</property>
+                    <property name="column_spacing">6</property>
                     <child>
-                      <object class="GtkLabel" id="label22">
+                      <object class="GtkLabel" id="label23">
                         <property name="visible">True</property>
-                        <property name="label" translatable="yes">    </property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">_Applicability:</property>
+                        <property name="use_underline">True</property>
+                        <property name="xalign">0</property>
                       </object>
                       <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">False</property>
-                        <property name="position">0</property>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">5</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="label8">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">_Output:</property>
+                        <property name="use_underline">True</property>
+                        <property name="xalign">0</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">4</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="label7">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">_Input:</property>
+                        <property name="use_underline">True</property>
+                        <property name="xalign">0</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">3</property>
                       </packing>
                     </child>
                     <child>
-                      <object class="GtkTable" id="tool-table">
+                      <object class="GtkLabel" id="label6">
                         <property name="visible">True</property>
-                        <property name="n_rows">6</property>
-                        <property name="n_columns">2</property>
-                        <property name="column_spacing">6</property>
-                        <property name="row_spacing">6</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">_Save:</property>
+                        <property name="use_underline">True</property>
+                        <property name="xalign">0</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="label3">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">_Shortcut Key:</property>
+                        <property name="use_underline">True</property>
+                        <property name="xalign">0</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkComboBox" id="output">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="model">model_output</property>
                         <child>
-                          <object class="GtkEntry" id="accelerator">
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <signal name="key_press_event" handler="on_accelerator_key_press"/>
-                            <signal name="focus_out_event" handler="on_accelerator_focus_out"/>
-                            <signal name="focus_in_event" handler="on_accelerator_focus_in"/>
-                          </object>
-                          <packing>
-                            <property name="left_attach">1</property>
-                            <property name="right_attach">2</property>
-                            <property name="top_attach">1</property>
-                            <property name="bottom_attach">2</property>
-                            <property name="x_options">GTK_EXPAND | GTK_SHRINK | GTK_FILL</property>
-                            <property name="y_options">GTK_FILL</property>
-                          </packing>
+                          <object class="GtkCellRendererText" id="output_renderer"/>
+                          <attributes>
+                            <attribute name="text">0</attribute>
+                          </attributes>
                         </child>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="top_attach">4</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkComboBox" id="input">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="model">model_input</property>
                         <child>
-                          <object class="GtkHBox" id="hbox1">
-                            <property name="visible">True</property>
-                            <child>
-		                      <object class="GtkComboBox" id="applicability">
-		                        <property name="visible">True</property>
-		                        <property name="model">model_applicability</property>
-		                        <child>
-		                          <object class="GtkCellRendererText" id="applicability_renderer"/>
-		                          <attributes>
-		                            <attribute name="text">0</attribute>
-		                          </attributes>
-		                        </child>
-		                      </object>
-                              <packing>
-                                <property name="position">0</property>
-                                <property name="expand">False</property>
-                                <property name="fill">True</property>
-                              </packing>
-                            </child>
-                            <child>
-                              <object class="GtkEventBox" id="languages_event_box">
-                              	<property name="visible">True</property>
-                              	<property name="visible-window">True</property>
-                              	<child>
-		                          <object class="GtkButton" id="languages_button">
-		                            <property name="visible">True</property>
-		                            <signal name="clicked" handler="on_languages_button_clicked"/>
-		                            <child>
-		                              <object class="GtkLabel" id="languages_label">
-		                                <property name="visible">True</property>
-		                                <property name="label" translatable="yes">All Languages</property>
-		                                <property name="xalign">0</property>
-		                                <property name="yalign">0.5</property>
-		                                <property name="ellipsize">PANGO_ELLIPSIZE_MIDDLE</property>
-		                              </object>
-		                            </child>
-		                          </object>
-		                        </child>
-		                      </object>
-                              <packing>
-                                <property name="position">1</property>
-                                <property name="expand">True</property>
-                                <property name="fill">True</property>
-                              </packing>
-                            </child>
-                          </object>
-                          <packing>
-                            <property name="left_attach">1</property>
-                            <property name="right_attach">2</property>
-                            <property name="top_attach">5</property>
-                            <property name="bottom_attach">6</property>
-                            <property name="x_options">GTK_EXPAND | GTK_SHRINK | GTK_FILL</property>
-                            <property name="y_options">GTK_FILL</property>
-                          </packing>
+                          <object class="GtkCellRendererText" id="input_renderer"/>
+                          <attributes>
+                            <attribute name="text">0</attribute>
+                          </attributes>
                         </child>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="top_attach">3</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkComboBox" id="save-files">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="model">model_save_files</property>
                         <child>
-                          <object class="GtkComboBox" id="output">
-                            <property name="visible">True</property>
-                            <property name="model">model_output</property>
-                            <child>
-                              <object class="GtkCellRendererText" id="output_renderer"/>
-                              <attributes>
-                                <attribute name="text">0</attribute>
-                              </attributes>
-                            </child>
-                          </object>
-                          <packing>
-                            <property name="left_attach">1</property>
-                            <property name="right_attach">2</property>
-                            <property name="top_attach">4</property>
-                            <property name="bottom_attach">5</property>
-                            <property name="x_options">GTK_EXPAND | GTK_SHRINK | GTK_FILL</property>
-                            <property name="y_options">GTK_FILL</property>
-                          </packing>
+                          <object class="GtkCellRendererText" id="renderer1"/>
+                          <attributes>
+                            <attribute name="text">0</attribute>
+                          </attributes>
                         </child>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="top_attach">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkEntry" id="accelerator">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <signal name="focus-in-event" handler="on_accelerator_focus_in" swapped="no"/>
+                        <signal name="focus-out-event" handler="on_accelerator_focus_out" swapped="no"/>
+                        <signal name="key-press-event" handler="on_accelerator_key_press" swapped="no"/>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="top_attach">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkScrolledWindow" id="scrolledwindow1">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="hexpand">True</property>
+                        <property name="vexpand">True</property>
+                        <property name="shadow_type">in</property>
+                            <child>
+		                      <object class="PlumaView" id="commands">
+		                        <property name="buffer">commands_buffer</property>
+		                        <property name="visible">True</property>
+		                        <property name="auto-indent">True</property>
+		                        <property name="insert-spaces-instead-of-tabs">False</property>
+		                        <property name="smart-home-end">GTK_SOURCE_SMART_HOME_END_AFTER</property>
+		                        <property name="tab-width">2</property>
+		                        <property name="highlight-current-line">True</property>
+		                        <property name="show-right-margin">False</property>
+		                        <property name="show-line-numbers">True</property>
+		                      </object>
+		                    </child>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">0</property>
+                        <property name="width">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkGrid">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                         <child>
-                          <object class="GtkComboBox" id="input">
+                          <object class="GtkEventBox" id="languages_event_box">
                             <property name="visible">True</property>
-                            <property name="model">model_input</property>
+                            <property name="can_focus">False</property>
                             <child>
-                              <object class="GtkCellRendererText" id="input_renderer"/>
-                              <attributes>
-                                <attribute name="text">0</attribute>
-                              </attributes>
+                              <object class="GtkButton" id="languages_button">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="receives_default">False</property>
+                                <signal name="clicked" handler="on_languages_button_clicked" swapped="no"/>
+                                <child>
+                                  <object class="GtkLabel" id="languages_label">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="label" translatable="yes">All Languages</property>
+                                    <property name="ellipsize">middle</property>
+                                    <property name="xalign">0</property>
+                                    <property name="yalign">0.5</property>
+                                  </object>
+                                </child>
+                              </object>
                             </child>
                           </object>
                           <packing>
                             <property name="left_attach">1</property>
-                            <property name="right_attach">2</property>
-                            <property name="top_attach">3</property>
-                            <property name="bottom_attach">4</property>
-                            <property name="x_options">GTK_EXPAND | GTK_SHRINK | GTK_FILL</property>
-                            <property name="y_options">GTK_FILL</property>
+                            <property name="top_attach">0</property>
                           </packing>
                         </child>
                         <child>
-                          <object class="GtkComboBox" id="save-files">
-                            <property name="model">model_save_files</property>
+                          <object class="GtkComboBox" id="applicability">
                             <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="model">model_applicability</property>
                             <child>
-                              <object class="GtkCellRendererText" id="renderer1"/>
+                              <object class="GtkCellRendererText" id="applicability_renderer"/>
                               <attributes>
                                 <attribute name="text">0</attribute>
                               </attributes>
                             </child>
                           </object>
                           <packing>
-                            <property name="left_attach">1</property>
-                            <property name="right_attach">2</property>
-                            <property name="top_attach">2</property>
-                            <property name="bottom_attach">3</property>
-                            <property name="x_options">GTK_EXPAND | GTK_SHRINK | GTK_FILL</property>
-                            <property name="y_options">GTK_FILL</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkLabel" id="label23">
-                            <property name="visible">True</property>
-                            <property name="xalign">0</property>
-                            <property name="label" translatable="yes">_Applicability:</property>
-                            <property name="use_underline">True</property>
-                            <property name="mnemonic_widget">applicability</property>
-                          </object>
-                          <packing>
-                            <property name="top_attach">5</property>
-                            <property name="bottom_attach">6</property>
-                            <property name="x_options">GTK_FILL</property>
-                            <property name="y_options"></property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkLabel" id="label8">
-                            <property name="visible">True</property>
-                            <property name="xalign">0</property>
-                            <property name="label" translatable="yes">_Output:</property>
-                            <property name="use_underline">True</property>
-                            <property name="mnemonic_widget">output</property>
-                          </object>
-                          <packing>
-                            <property name="top_attach">4</property>
-                            <property name="bottom_attach">5</property>
-                            <property name="x_options">GTK_FILL</property>
-                            <property name="y_options"></property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkLabel" id="label7">
-                            <property name="visible">True</property>
-                            <property name="xalign">0</property>
-                            <property name="label" translatable="yes">_Input:</property>
-                            <property name="use_underline">True</property>
-                            <property name="mnemonic_widget">input</property>
-                          </object>
-                          <packing>
-                            <property name="top_attach">3</property>
-                            <property name="bottom_attach">4</property>
-                            <property name="x_options">GTK_FILL</property>
-                            <property name="y_options"></property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkLabel" id="label6">
-                            <property name="xalign">0</property>
-                            <property name="label" translatable="yes">_Save:</property>
-                            <property name="use_underline">True</property>
-                            <property name="mnemonic_widget">save-files</property>
-                            <property name="visible">True</property>
-                          </object>
-                          <packing>
-                            <property name="top_attach">2</property>
-                            <property name="bottom_attach">3</property>
-                            <property name="x_options">GTK_FILL</property>
-                            <property name="y_options"></property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkLabel" id="label3">
-                            <property name="visible">True</property>
-                            <property name="xalign">0</property>
-                            <property name="label" translatable="yes">_Shortcut Key:</property>
-                            <property name="use_underline">True</property>
-                            <property name="mnemonic_widget">accelerator</property>
-                          </object>
-                          <packing>
-                            <property name="top_attach">1</property>
-                            <property name="bottom_attach">2</property>
-                            <property name="x_options">GTK_FILL</property>
-                            <property name="y_options"></property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkScrolledWindow" id="scrolledwindow1">
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="hscrollbar_policy">automatic</property>
-                            <property name="vscrollbar_policy">automatic</property>
-                            <property name="shadow_type">in</property>
-                            <child>
-		                      <object class="PlumaView" id="commands">
-		                        <property name="buffer">commands_buffer</property>
-		                        <property name="visible">True</property>
-		                        <property name="auto-indent">True</property>
-		                        <property name="insert-spaces-instead-of-tabs">False</property>
-		                        <property name="smart-home-end">GTK_SOURCE_SMART_HOME_END_AFTER</property>
-		                        <property name="tab-width">2</property>
-		                        <property name="highlight-current-line">True</property>
-		                        <property name="show-right-margin">False</property>
-		                        <property name="show-line-numbers">True</property>
-		                      </object>
-		                    </child>
-                          </object>
-                          <packing>
-                            <property name="right_attach">2</property>
+                            <property name="left_attach">0</property>
+                            <property name="top_attach">0</property>
                           </packing>
                         </child>
                       </object>
                       <packing>
-                        <property name="position">1</property>
+                        <property name="left_attach">1</property>
+                        <property name="top_attach">5</property>
                       </packing>
                     </child>
                   </object>
                   <packing>
-                    <property name="position">1</property>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="title">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label" translatable="yes">_Edit:</property>
+                    <property name="use_underline">True</property>
+                    <property name="xalign">0</property>
+                    <property name="yalign">0.5</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">0</property>
                   </packing>
                 </child>
               </object>
@@ -557,47 +592,6 @@
             <property name="position">1</property>
           </packing>
         </child>
-        <child internal-child="action_area">
-          <object class="GtkHButtonBox" id="hbuttonbox1">
-            <property name="visible">True</property>
-            <property name="layout_style">end</property>
-            <child>
-              <object class="GtkButton" id="button1">
-                <property name="label">gtk-help</property>
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="can_default">True</property>
-                <property name="receives_default">False</property>
-                <property name="use_stock">True</property>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">False</property>
-                <property name="position">0</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkButton" id="button2">
-                <property name="label">gtk-close</property>
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="can_default">True</property>
-                <property name="receives_default">False</property>
-                <property name="use_stock">True</property>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">False</property>
-                <property name="position">1</property>
-              </packing>
-            </child>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="pack_type">end</property>
-            <property name="position">0</property>
-          </packing>
-        </child>
       </object>
     </child>
     <action-widgets>
-- 
2.21.0