[Xfce4-commits] [apps/catfish] 01/01: Various usability improvements - New preferences dialog with window layout, display options, custom exclude directories, and the close-after-select option - Improved app menu with better space usage, clearer labels, and the sidebar keyboard accelerator displayed - Better use of alt-key accelerators - Standardized icon sizes in the results list

noreply at xfce.org noreply at xfce.org
Sun Aug 25 17:02:24 CEST 2019


This is an automated email from the git hooks/post-receive script.

b   l   u   e   s   a   b   r   e       p   u   s   h   e   d       a       c   o   m   m   i   t       t   o       b   r   a   n   c   h       m   a   s   t   e   r   
   in repository apps/catfish.

commit b0476823471bac6aef18acd4f05e3c86c4f6d48c
Author: Sean Davis <smd.seandavis at gmail.com>
Date:   Sun Aug 25 11:00:00 2019 -0400

    Various usability improvements
    - New preferences dialog with window layout, display options, custom exclude directories, and the close-after-select option
    - Improved app menu with better space usage, clearer labels, and the sidebar keyboard accelerator displayed
    - Better use of alt-key accelerators
    - Standardized icon sizes in the results list
---
 ChangeLog                        |  12 +
 catfish/CatfishPrefsDialog.py    | 135 ++++++++++
 catfish/CatfishSearchEngine.py   |  29 +--
 catfish/CatfishWindow.py         |  72 ++++--
 catfish_lib/Builder.py           |   5 +-
 catfish_lib/CatfishSettings.py   |  13 +-
 catfish_lib/PrefsDialog.py       |  52 ++++
 catfish_lib/Window.py            |   2 +-
 data/ui/CatfishPreferences.ui    | 547 +++++++++++++++++++++++++++++++++++++++
 data/ui/CatfishWindow.ui         | 169 +++++++++---
 data/ui/about_catfish_dialog.xml |   4 +-
 data/ui/catfish-wl-headerbar.png | Bin 0 -> 6629 bytes
 data/ui/catfish-wl-titlebar.png  | Bin 0 -> 8145 bytes
 data/ui/catfish_preferences.xml  |   8 +
 data/ui/catfish_window.xml       |   4 +-
 po/POTFILES.in                   |  15 +-
 po/catfish.pot                   | 172 ++++++++----
 17 files changed, 1108 insertions(+), 131 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 50fbf83..06ffcdc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,16 @@
 v1.4.10 (UNRELEASED):
+ + New Preferences Dialog:
+   - Window layout (titlebar vs. headerbar)
+   - Display options
+   - Custom exclude directories
+   - "Close after select" option
+ + Improved Application Menu:
+   - Better use of space, padding, and margins
+   - Clearer purpose labels
+   - Keyboard accelerator for the sidebar (F9) is now displayed
+ + General:
+   - Better use of alt-accelerators
+   - Standardized icon sizes, no more wrongly-sized icons in the results
  + Translations:
    - Combine 3 strings into 1 to help translators (Xfce #15596)
 
diff --git a/catfish/CatfishPrefsDialog.py b/catfish/CatfishPrefsDialog.py
new file mode 100644
index 0000000..c7850a8
--- /dev/null
+++ b/catfish/CatfishPrefsDialog.py
@@ -0,0 +1,135 @@
+#!/usr/bin/env python
+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
+#   Catfish - a versatile file searching tool
+#   Copyright (C) 2007-2012 Christian Dywan <christian at twotoasts.de>
+#   Copyright (C) 2012-2019 Sean Davis <bluesabre at xfce.org>
+#
+#   This program is free software: you can redistribute it and/or modify it
+#   under the terms of the GNU General Public License version 2, as published
+#   by the Free Software Foundation.
+#
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY; without even the implied warranties of
+#   MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+#   PURPOSE.  See the GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License along
+#   with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+import logging
+
+import gi
+gi.require_version('Gtk', '3.0')  # noqa
+from gi.repository import Gtk
+
+from catfish_lib.PrefsDialog import PrefsDialog
+
+logger = logging.getLogger('catfish')
+
+
+# See catfish_lib.AboutDialog.py for more details about how this class works.
+class CatfishPrefsDialog(PrefsDialog):
+
+    """Creates the about dialog for catfish"""
+    __gtype_name__ = "CatfishPrefsDialog"
+
+    def finish_initializing(self, builder):
+        """Set up the about dialog"""
+        super(CatfishPrefsDialog, self).finish_initializing(builder)
+        self.changed_properties = []
+        self.process_events = False
+
+    def connect_settings(self, settings):
+        self.settings = settings
+        if self.settings.get_setting("use-headerbar"):
+            self.builder.get_object("wl_headerbar").set_active(True)
+        if self.settings.get_setting("show-hidden-files"):
+            self.builder.get_object("do_show_hidden").set_active(True)
+        if self.settings.get_setting("show-sidebar"):
+            self.builder.get_object("do_show_sidebar").set_active(True)
+        if self.settings.get_setting("close-after-select"):
+            self.builder.get_object("close_after_select").set_active(True)
+        self.set_exclude_directories(
+            self.settings.get_setting("exclude-paths"))
+        self.process_events = True
+
+    def on_wl_titlebar_toggled(self, widget):
+        if not self.process_events:
+            return
+        if widget.get_active():
+            self.settings.set_setting("use-headerbar", False)
+        else:
+            self.settings.set_setting("use-headerbar", True)
+        self.builder.get_object("wl_info").show()
+        self.changed_properties.append("use-headerbar")
+
+    def on_do_show_hidden_toggled(self, widget):
+        if not self.process_events:
+            return
+        if widget.get_active():
+            self.settings.set_setting("show-hidden-files", True)
+        else:
+            self.settings.set_setting("show-hidden-files", False)
+        self.changed_properties.append("show-hidden-files")
+
+    def on_do_show_sidebar_toggled(self, widget):
+        if not self.process_events:
+            return
+        if widget.get_active():
+            self.settings.set_setting("show-sidebar", True)
+        else:
+            self.settings.set_setting("show-sidebar", False)
+        self.changed_properties.append("show-sidebar")
+
+    def on_close_after_select_toggled(self, widget):
+        if not self.process_events:
+            return
+        if widget.get_active():
+            self.settings.set_setting("close-after-select", True)
+        else:
+            self.settings.set_setting("close-after-select", False)
+        self.changed_properties.append("close-after-select")
+
+    def on_add_directory_clicked(self, widget):
+        dlg = Gtk.FileChooserDialog("Add Excluded Directory",
+                                    self,
+                                    Gtk.FileChooserAction.SELECT_FOLDER,
+                                    (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
+                                     Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
+        response = dlg.run()
+        if (response == Gtk.ResponseType.OK):
+            path = dlg.get_filename()
+            treeview = self.builder.get_object("exclude_treeview")
+            model = treeview.get_model()
+            model.append([path])
+            self.treemodel_to_settings(model)
+        dlg.destroy()
+
+    def on_remove_directory_clicked(self, widget):
+        treeview = self.builder.get_object("exclude_treeview")
+        model = treeview.get_model()
+        sel = treeview.get_selection().get_selected()
+        if sel is not None:
+            model.remove(sel[1])
+        self.treemodel_to_settings(model)
+
+    def treemodel_to_settings(self, model):
+        child = model.iter_children()
+
+        rows = []
+        while child is not None:
+            path = model[child][0]
+            if path not in rows and len(path) > 0:
+                rows.append(path)
+            child = model.iter_next(child)
+
+        rows.sort()
+
+        self.settings.set_setting("exclude-paths", rows)
+
+    def set_exclude_directories(self, exclude_directories):
+        treeview = self.builder.get_object("exclude_treeview")
+        model = treeview.get_model()
+
+        for path in exclude_directories:
+            model.append([path])
diff --git a/catfish/CatfishSearchEngine.py b/catfish/CatfishSearchEngine.py
index 8309b16..e06e6c0 100644
--- a/catfish/CatfishSearchEngine.py
+++ b/catfish/CatfishSearchEngine.py
@@ -98,7 +98,8 @@ class CatfishSearchEngine:
     """CatfishSearchEngine is the collection of search backends that are used
     to perform a query.  Each backend is a CatfishSearchMethod"""
 
-    def __init__(self, methods=['zeitgeist', 'locate', 'walk']):
+    def __init__(self, methods=['zeitgeist', 'locate', 'walk'],
+                 exclude_paths=[]):
         """Initialize the CatfishSearchEngine.  Provide a list of methods to
         be included in the search backends.  Available backends include:
 
@@ -124,6 +125,7 @@ class CatfishSearchEngine:
             self.add_method(CatfishSearchMethod_Fulltext)
         if 'walk' in methods:
             self.add_method(CatfishSearchMethod_Walk)
+        self.exclude_paths = exclude_paths
         initialized = []
         for method in self.methods:
             initialized.append(method.method_name)
@@ -171,11 +173,7 @@ class CatfishSearchEngine:
 
         # Path exclusions for efficiency
         exclude = []
-        maybe_exclude = [
-            os.path.expanduser("~/.cache"),
-            os.path.expanduser("~/.gvfs"),
-            "/dev"
-        ]
+        maybe_exclude = self.exclude_paths
         for maybe_path in maybe_exclude:
             if not path.startswith(maybe_path):
                 exclude.append(maybe_path)
@@ -188,7 +186,8 @@ class CatfishSearchEngine:
             logger.debug(
                 "[%i] Starting search method: %s",
                 self.engine_id, method.method_name)
-            for filename in method.run(keywords, path, regex):
+            for filename in method.run(keywords, path, regex,
+                                       self.exclude_paths):
                 if isinstance(filename, str) and path in filename:
                     found_bad = False
                     for filepath in exclude:
@@ -274,7 +273,7 @@ class CatfishSearchMethod:
         """Base CatfishSearchMethod Initializer."""
         self.method_name = method_name
 
-    def run(self, keywords, path, regex=False):
+    def run(self, keywords, path, regex=False, exclude_paths=[]):
         """Base CatfishSearchMethod run method."""
         return NotImplemented
 
@@ -339,18 +338,14 @@ class CatfishSearchMethod_Walk(CatfishSearchMethod):
             results.append(os.path.join(path, dirpath))
         return results
 
-    def run(self, keywords, path, regex=False):
+    def run(self, keywords, path, regex=False, exclude_paths=[]):
         """Run the search method using keywords and path.  regex is not used
         by this search method.
 
         This function is a generator and will yield files as they are found or
         True if still running."""
         exclude = []
-        maybe_exclude = [
-            os.path.expanduser("~/.cache"),
-            os.path.expanduser("~/.gvfs"),
-            "/dev"
-        ]
+        maybe_exclude = exclude_paths
         for maybe_path in maybe_exclude:
             if not path.startswith(maybe_path):
                 exclude.append(maybe_path)
@@ -425,7 +420,7 @@ class CatfishSearchMethod_Fulltext(CatfishSearchMethod):
         self.running = False
         self.exact = False
 
-    def run(self, keywords, path, regex=False): # noqa
+    def run(self, keywords, path, regex=False, exclude_paths=[]):  # noqa
         """Run the search method using keywords and path.  regex is not used
         by this search method.
 
@@ -513,7 +508,7 @@ class CatfishSearchMethod_Zeitgeist(CatfishSearchMethod):
         """Initialize the Zeitgeist SearchMethod."""
         CatfishSearchMethod.__init__(self, "zeitgeist")
 
-    def run(self, keywords, path, regex=False):
+    def run(self, keywords, path, regex=False, exclude_paths=[]):
         """Run the Zeitgeist SearchMethod."""
         self.stop_search = False
         event_template = Event()
@@ -571,7 +566,7 @@ class CatfishSearchMethodExternal(CatfishSearchMethod):
         """Base assemble_query method."""
         return False
 
-    def run(self, keywords, path, regex=False):
+    def run(self, keywords, path, regex=False, exclude_paths=[]):
         """Run the search method using keywords and path.
 
         This function returns the process.stdout generator and will yield files
diff --git a/catfish/CatfishWindow.py b/catfish/CatfishWindow.py
index 6118353..dd13949 100644
--- a/catfish/CatfishWindow.py
+++ b/catfish/CatfishWindow.py
@@ -41,6 +41,7 @@ gi.require_version('Gtk', '3.0')  # noqa
 from gi.repository import GLib, GObject, Pango, Gdk, GdkPixbuf, Gtk
 
 from catfish.AboutCatfishDialog import AboutCatfishDialog
+from catfish.CatfishPrefsDialog import CatfishPrefsDialog
 from catfish.CatfishSearchEngine import CatfishSearchEngine
 from catfish_lib import catfishconfig, helpers
 from catfish_lib import CatfishSettings, SudoDialog, Window
@@ -130,6 +131,8 @@ class CatfishWindow(Window):
 
         self.AboutDialog = AboutCatfishDialog
 
+        self.settings = CatfishSettings.CatfishSettings()
+
         # -- Folder Chooser Combobox -- #
         self.folderchooser = builder.get_named_object("toolbar.folderchooser")
 
@@ -149,8 +152,6 @@ class CatfishWindow(Window):
         self.fulltext = builder.get_named_object("menus.application.fulltext")
         self.sidebar_toggle_menu = builder.get_named_object(
             "menus.application.advanced")
-        self.close_after_select = builder.get_named_object(
-            "menus.application.closeafterselect")
 
         # -- Sidebar -- #
         self.button_time_custom = builder.get_named_object(
@@ -270,7 +271,9 @@ class CatfishWindow(Window):
         self.extensions_entry = \
             builder.get_named_object("dialogs.filetype.extensions.entry")
 
-        self.search_engine = CatfishSearchEngine()
+        self.search_engine = CatfishSearchEngine(
+            ['zeitgeist', 'locate', 'walk'],
+            self.settings.get_setting("exclude-paths"))
 
         self.icon_cache = {}
         self.icon_theme = Gtk.IconTheme.get_default()
@@ -278,7 +281,6 @@ class CatfishWindow(Window):
         self.selected_filenames = []
         self.rows = []
 
-        self.settings = CatfishSettings.CatfishSettings()
         paned = builder.get_named_object("window.paned")
         paned.set_property('height_request',
                            self.settings.get_setting('window-height'))
@@ -392,10 +394,13 @@ class CatfishWindow(Window):
         self.app_menu_event = not self.app_menu_event
         if not self.app_menu_event:
             return
-        if listbox.get_row_at_index(6) == row:
+        if listbox.get_row_at_index(8) == row:
             listbox.get_parent().hide()
             self.on_menu_update_index_activate(row)
-        if listbox.get_row_at_index(7) == row:
+        if listbox.get_row_at_index(10) == row:
+            listbox.get_parent().hide()
+            self.on_menu_preferences_activate(row)
+        if listbox.get_row_at_index(11) == row:
             listbox.get_parent().hide()
             self.on_mnu_about_activate(row)
 
@@ -544,8 +549,6 @@ class CatfishWindow(Window):
         self.fulltext.set_active(self.options.fulltext)
         self.sidebar_toggle_menu.set_active(
             self.settings.get_setting('show-sidebar'))
-        self.close_after_select.set_active(
-            self.settings.get_setting('close-after-select'))
 
         self.show_thumbnail = self.options.thumbnails
 
@@ -590,7 +593,7 @@ class CatfishWindow(Window):
 
     def thumbnail_cell_data_func(self, col, renderer, model, treeiter, data):
         """Cell Renderer Function to Thumbnails View."""
-        name, size, path, modified = model[treeiter][1:4]
+        name, size, path, modified = model[treeiter][1:5]
         name = escape(name)
         size = self.format_size(size)
         path = escape(path)
@@ -605,7 +608,8 @@ class CatfishWindow(Window):
         fallback if unavailable."""
         context = self.sidebar.get_style_context()
         try:
-            icon_lookup_flags = Gtk.IconLookupFlags.FORCE_SVG
+            icon_lookup_flags = Gtk.IconLookupFlags.FORCE_SVG | \
+                Gtk.IconLookupFlags.FORCE_SIZE
             icon_info = self.icon_theme.choose_icon([icon_name + '-symbolic'],
                                                     size,
                                                     icon_lookup_flags)
@@ -614,7 +618,8 @@ class CatfishWindow(Window):
         except (AttributeError, GLib.GError):
             icon_lookup_flags = Gtk.IconLookupFlags.FORCE_SVG | \
                 Gtk.IconLookupFlags.USE_BUILTIN | \
-                Gtk.IconLookupFlags.GENERIC_FALLBACK
+                Gtk.IconLookupFlags.GENERIC_FALLBACK | \
+                Gtk.IconLookupFlags.FORCE_SIZE
             icon = self.icon_theme.load_icon(
                 icon_name, size, icon_lookup_flags)
         return icon
@@ -922,11 +927,30 @@ class CatfishWindow(Window):
         """Show the Update Search Index dialog."""
         self.update_index_dialog.show()
 
-    def on_menu_closeafterselect_toggled(self, widget):
-        active = widget.get_active()
-        self.settings.set_setting('close-after-select', active)
+    def on_menu_preferences_activate(self, widget):
+        dialog = CatfishPrefsDialog()
+        dialog.set_transient_for(self)
+        dialog.connect_settings(self.settings)
+        dialog.run()
+        changed_properties = dialog.changed_properties
+        dialog.destroy()
+        self.refresh_from_settings(changed_properties)
+
+    def refresh_from_settings(self, changed_properties):
+        for prop in changed_properties:
+            setting = self.settings.get_setting(prop)
+            if (prop == "show-hidden-files"):
+                self.hidden_files.set_active(setting)
+            if (prop == "show-sidebar"):
+                self.set_sidebar_active(setting)
 
     # -- Sidebar -- #
+    def set_sidebar_active(self, active):
+        if self.sidebar_toggle_menu.get_active() != active:
+            self.sidebar_toggle_menu.set_active(active)
+        if self.sidebar.get_visible() != active:
+            self.sidebar.set_visible(active)
+
     def on_sidebar_toggle_toggled(self, widget):
         """Toggle visibility of the sidebar."""
         if isinstance(widget, Gtk.CheckButton):
@@ -934,10 +958,7 @@ class CatfishWindow(Window):
         else:
             active = not self.settings.get_setting('show-sidebar')
         self.settings.set_setting('show-sidebar', active)
-        if self.sidebar_toggle_menu.get_active() != active:
-            self.sidebar_toggle_menu.set_active(active)
-        if active != self.sidebar.get_visible():
-            self.sidebar.set_visible(active)
+        self.set_sidebar_active(active)
 
     def set_modified_range(self, value):
         if value == 'any':
@@ -1642,10 +1663,12 @@ class CatfishWindow(Window):
             return self.icon_cache[name]
         except KeyError:
             icon_size = Gtk.icon_size_lookup(self.icon_size)[1]
+            flags = Gtk.IconLookupFlags.FORCE_SIZE
             if self.icon_theme.has_icon(name):
-                icon = self.icon_theme.load_icon(name, icon_size, 0)
+                icon = self.icon_theme.load_icon(name, icon_size, flags)
             else:
-                icon = self.icon_theme.load_icon('image-missing', icon_size, 0)
+                icon = self.icon_theme.load_icon('image-missing', icon_size,
+                                                 flags)
             self.icon_cache[name] = icon
             return icon
 
@@ -1742,10 +1765,15 @@ class CatfishWindow(Window):
 
         # Check if this is a fulltext query or standard query.
         if self.filter_formats['fulltext']:
-            self.search_engine = CatfishSearchEngine(['fulltext'])
+            self.search_engine = \
+                CatfishSearchEngine(['fulltext'],
+                                    self.settings.get_setting("exclude-paths"))
             self.search_engine.set_exact(self.filter_formats['exact'])
         else:
-            self.search_engine = CatfishSearchEngine()
+            self.search_engine = CatfishSearchEngine(
+                ['zeitgeist', 'locate', 'walk'],
+                self.settings.get_setting("exclude-paths")
+            )
 
         for filename in self.search_engine.run(keywords, folder, regex=True):
             if not self.stop_search and isinstance(filename, str) and \
diff --git a/catfish_lib/Builder.py b/catfish_lib/Builder.py
index 9ed1077..5b4c067 100644
--- a/catfish_lib/Builder.py
+++ b/catfish_lib/Builder.py
@@ -86,7 +86,10 @@ class Builder(Gtk.Builder):
 
         ele_widgets = tree.getiterator("object")
         for ele_widget in ele_widgets:
-            name = ele_widget.attrib['id']
+            try:
+                name = ele_widget.attrib['id']
+            except AttributeError:
+                continue
             widget = self.get_object(name)
 
             # populate indexes - a dictionary of widgets
diff --git a/catfish_lib/CatfishSettings.py b/catfish_lib/CatfishSettings.py
index 275b0b3..234b713 100644
--- a/catfish_lib/CatfishSettings.py
+++ b/catfish_lib/CatfishSettings.py
@@ -28,7 +28,8 @@ default_settings = {
     'window-width': 650,
     'window-height': 470,
     'window-x': -1,
-    'window-y': -1
+    'window-y': -1,
+    'exclude-paths': '/dev;~/.cache;~/.gvfs;'
 }
 
 
@@ -66,6 +67,14 @@ class CatfishSettings:
         if key in self.settings:
             if (key.startswith('window')):
                 return int(self.settings[key])
+            if (key == "exclude-paths"):
+                exclude_directories = []
+                for path in (self.settings[key].strip()).split(";"):
+                    if len(path) > 0:
+                        path = os.path.expanduser(path)
+                        exclude_directories.append(path)
+                exclude_directories.sort()
+                return exclude_directories
             return self.settings[key]
         else:
             return None
@@ -73,6 +82,8 @@ class CatfishSettings:
     def set_setting(self, key, value):
         """Set the value for the specified key."""
         if key in self.settings:
+            if key == "exclude-paths":
+                value = ";".join(value)
             self.settings[key] = value
         else:
             pass
diff --git a/catfish_lib/PrefsDialog.py b/catfish_lib/PrefsDialog.py
new file mode 100644
index 0000000..3433f67
--- /dev/null
+++ b/catfish_lib/PrefsDialog.py
@@ -0,0 +1,52 @@
+#!/usr/bin/env python
+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
+#   Catfish - a versatile file searching tool
+#   Copyright (C) 2007-2012 Christian Dywan <christian at twotoasts.de>
+#   Copyright (C) 2012-2019 Sean Davis <bluesabre at xfce.org>
+#
+#   This program is free software: you can redistribute it and/or modify it
+#   under the terms of the GNU General Public License version 2, as published
+#   by the Free Software Foundation.
+#
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY; without even the implied warranties of
+#   MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+#   PURPOSE.  See the GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License along
+#   with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+from gi.repository import Gtk  # pylint: disable=E0611
+
+from . helpers import get_builder
+
+
+class PrefsDialog(Gtk.Dialog):
+
+    """Catfish PrefsDialog"""
+    __gtype_name__ = "PrefsDialog"
+
+    def __new__(cls):
+        """Special static method that's automatically called by Python when
+        constructing a new instance of this class.
+
+        Returns a fully instantiated PrefsDialog object.
+        """
+        builder = get_builder('CatfishPreferences')
+        new_object = builder.get_object("catfish_preferences")
+        new_object.finish_initializing(builder)
+        return new_object
+
+    def finish_initializing(self, builder):
+        """Called while initializing this instance in __new__
+
+        finish_initalizing should be called after parsing the ui definition
+        and creating a PrefsDialog object with it in order
+        to finish initializing the start of the new CatfishPrefsDialog
+        instance.
+
+        Put your initialization code in here and leave __init__ undefined.
+        """
+        # Get a reference to the builder and set up the signals.
+        self.builder = builder
+        self.ui = builder.get_ui(self)
diff --git a/catfish_lib/Window.py b/catfish_lib/Window.py
index 2d57a51..8ce6947 100644
--- a/catfish_lib/Window.py
+++ b/catfish_lib/Window.py
@@ -57,7 +57,7 @@ __builder__ = {
             "fulltext": "application_menu_fulltext",
             "advanced": "application_menu_advanced",
             "update": "application_menu_update",
-            "closeafterselect": "application_menu_closeafterselect"
+            "preferences": "application_menu_prefs",
         },
         # File Context Menu
         "file": {
diff --git a/data/ui/CatfishPreferences.ui b/data/ui/CatfishPreferences.ui
new file mode 100644
index 0000000..40d8ea9
--- /dev/null
+++ b/data/ui/CatfishPreferences.ui
@@ -0,0 +1,547 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface>
+  <requires lib="gtk+" version="3.20"/>
+  <requires lib="catfish_preferences" version="1.0"/>
+  <object class="GtkListStore" id="liststore1">
+    <columns>
+      <!-- column-name path -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+  <object class="CatfishPrefsDialog" id="catfish_preferences">
+    <property name="can_focus">False</property>
+    <property name="title" translatable="yes">Catfish Preferences</property>
+    <property name="default_width">500</property>
+    <property name="default_height">400</property>
+    <property name="icon_name">catfish</property>
+    <property name="type_hint">dialog</property>
+    <child type="titlebar">
+      <placeholder/>
+    </child>
+    <child internal-child="vbox">
+      <object class="GtkBox" id="catfish_prefs_layout">
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox" id="catfish_prefs_buttons">
+            <property name="can_focus">False</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="button1">
+                <property name="label" translatable="yes">_Close</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_underline">True</property>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkNotebook" id="catfish_prefs_notebook">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="border_width">6</property>
+            <child>
+              <object class="GtkBox" id="catfish_prefs_notebook_layout">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="border_width">12</property>
+                <property name="orientation">vertical</property>
+                <property name="spacing">18</property>
+                <child>
+                  <object class="GtkFrame" id="wl_frame">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">none</property>
+                    <child>
+                      <object class="GtkAlignment" id="wl_alignment">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="top_padding">6</property>
+                        <child>
+                          <object class="GtkBox" id="wl_layout">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="orientation">vertical</property>
+                            <property name="spacing">12</property>
+                            <child>
+                              <object class="GtkBox" id="wl_box">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="spacing">12</property>
+                                <child>
+                                  <object class="GtkRadioButton" id="wl_titlebar">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="active">True</property>
+                                    <property name="draw_indicator">False</property>
+                                    <signal name="toggled" handler="on_wl_titlebar_toggled" swapped="no"/>
+                                    <child>
+                                      <object class="GtkBox" id="wl_titlebar_box">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="orientation">vertical</property>
+                                        <property name="spacing">6</property>
+                                        <child>
+                                          <object class="GtkImage" id="wl_titlebar_image">
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">False</property>
+                                            <property name="pixbuf">catfish-wl-titlebar.png</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">True</property>
+                                            <property name="position">0</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkLabel" id="wl_titlebar_label">
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">False</property>
+                                            <property name="label" translatable="yes">Classic (_Titlebar)</property>
+                                            <property name="use_underline">True</property>
+                                            <attributes>
+                                              <attribute name="weight" value="bold"/>
+                                            </attributes>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">True</property>
+                                            <property name="position">1</property>
+                                          </packing>
+                                        </child>
+                                      </object>
+                                    </child>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkRadioButton" id="wl_headerbar">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="active">True</property>
+                                    <property name="draw_indicator">False</property>
+                                    <property name="group">wl_titlebar</property>
+                                    <child>
+                                      <object class="GtkBox" id="wl_headerbar_box">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="orientation">vertical</property>
+                                        <property name="spacing">6</property>
+                                        <child>
+                                          <object class="GtkImage" id="wl_headerbar_image">
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">False</property>
+                                            <property name="pixbuf">catfish-wl-headerbar.png</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">True</property>
+                                            <property name="position">0</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkLabel" id="wl_headerbar_label">
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">False</property>
+                                            <property name="label" translatable="yes">_Modern (CSD)</property>
+                                            <property name="use_underline">True</property>
+                                            <attributes>
+                                              <attribute name="weight" value="bold"/>
+                                            </attributes>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">True</property>
+                                            <property name="position">1</property>
+                                          </packing>
+                                        </child>
+                                      </object>
+                                    </child>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">2</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkBox" id="wl_info">
+                                <property name="can_focus">False</property>
+                                <property name="spacing">6</property>
+                                <child>
+                                  <object class="GtkImage" id="wl_info_image">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="icon_name">dialog-information</property>
+                                    <property name="icon_size">2</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkLabel" id="wl_info_label">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="label" translatable="yes">Your new window layout will be applied after restarting Catifish.</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                    <child type="label">
+                      <object class="GtkLabel" id="wl_frame_label">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">Window Layout</property>
+                        <attributes>
+                          <attribute name="weight" value="bold"/>
+                        </attributes>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkFrame" id="do_frame">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">none</property>
+                    <child>
+                      <object class="GtkAlignment" id="do_alignment">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="top_padding">6</property>
+                        <child>
+                          <object class="GtkBox" id="do_box">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="orientation">vertical</property>
+                            <property name="spacing">3</property>
+                            <child>
+                              <object class="GtkCheckButton" id="do_show_hidden">
+                                <property name="label" translatable="yes">Show _hidden files in the results</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="use_underline">True</property>
+                                <property name="draw_indicator">True</property>
+                                <signal name="toggled" handler="on_do_show_hidden_toggled" swapped="no"/>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkCheckButton" id="do_show_sidebar">
+                                <property name="label" translatable="yes">Show filter _sidebar</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="use_underline">True</property>
+                                <property name="draw_indicator">True</property>
+                                <signal name="toggled" handler="on_do_show_sidebar_toggled" swapped="no"/>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                    <child type="label">
+                      <object class="GtkLabel" id="do_frame_label">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">Display Options</property>
+                        <attributes>
+                          <attribute name="weight" value="bold"/>
+                        </attributes>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+            </child>
+            <child type="tab">
+              <object class="GtkLabel" id="catfish_prefs_notebook_tab1">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">_Appearance</property>
+                <property name="use_underline">True</property>
+              </object>
+              <packing>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkBox" id="catfish_prefs_advanced_layout">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="border_width">12</property>
+                <property name="orientation">vertical</property>
+                <property name="spacing">18</property>
+                <child>
+                  <object class="GtkFrame" id="exclude_frame">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">none</property>
+                    <child>
+                      <object class="GtkAlignment" id="exclude_alignment">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="top_padding">6</property>
+                        <child>
+                          <object class="GtkBox" id="exclude_layout">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="orientation">vertical</property>
+                            <child>
+                              <object class="GtkScrolledWindow" id="exclude_scrolled">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="shadow_type">in</property>
+                                <child>
+                                  <object class="GtkTreeView" id="exclude_treeview">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="model">liststore1</property>
+                                    <child internal-child="selection">
+                                      <object class="GtkTreeSelection" id="exclude_treeview_sel"/>
+                                    </child>
+                                    <child>
+                                      <object class="GtkTreeViewColumn" id="exclude_path">
+                                        <property name="title" translatable="yes">Path</property>
+                                        <child>
+                                          <object class="GtkCellRendererText" id="exclude_path_text"/>
+                                          <attributes>
+                                            <attribute name="text">0</attribute>
+                                          </attributes>
+                                        </child>
+                                      </object>
+                                    </child>
+                                  </object>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">True</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkToolbar" id="exclude_toolbar">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="icon_size">2</property>
+                                <child>
+                                  <object class="GtkToolButton" id="add_directory">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="tooltip_text" translatable="yes">Add Directory...</property>
+                                    <property name="label" translatable="yes">_Add</property>
+                                    <property name="use_underline">True</property>
+                                    <property name="icon_name">list-add-symbolic</property>
+                                    <signal name="clicked" handler="on_add_directory_clicked" swapped="no"/>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="homogeneous">True</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkToolButton" id="remove_directory">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="tooltip_text" translatable="yes">Remove Directory</property>
+                                    <property name="label" translatable="yes">_Remove</property>
+                                    <property name="use_underline">True</property>
+                                    <property name="icon_name">list-remove-symbolic</property>
+                                    <signal name="clicked" handler="on_remove_directory_clicked" swapped="no"/>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="homogeneous">True</property>
+                                  </packing>
+                                </child>
+                                <style>
+                                  <class name="inline-toolbar"/>
+                                </style>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                    <child type="label">
+                      <object class="GtkLabel" id="exclude_frame_label">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">Exclude Directories</property>
+                        <attributes>
+                          <attribute name="weight" value="bold"/>
+                        </attributes>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkFrame" id="misc_frame">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">none</property>
+                    <child>
+                      <object class="GtkAlignment" id="misc_alignment">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="top_padding">6</property>
+                        <child>
+                          <object class="GtkBox" id="misc_layout">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="orientation">vertical</property>
+                            <property name="spacing">3</property>
+                            <child>
+                              <object class="GtkCheckButton" id="close_after_select">
+                                <property name="label" translatable="yes">Close the search _window after opening a file</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="use_underline">True</property>
+                                <property name="draw_indicator">True</property>
+                                <signal name="toggled" handler="on_close_after_select_toggled" swapped="no"/>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                    <child type="label">
+                      <object class="GtkLabel" id="misc_frame_label">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">Miscellaneous</property>
+                        <attributes>
+                          <attribute name="weight" value="bold"/>
+                        </attributes>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child type="tab">
+              <object class="GtkLabel" id="catfish_prefs_notebook_tab2">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">A_dvanced</property>
+                <property name="use_underline">True</property>
+              </object>
+              <packing>
+                <property name="position">1</property>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <placeholder/>
+            </child>
+            <child type="tab">
+              <placeholder/>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="-7">button1</action-widget>
+    </action-widgets>
+  </object>
+</interface>
diff --git a/data/ui/CatfishWindow.ui b/data/ui/CatfishWindow.ui
index f139895..93d0faa 100644
--- a/data/ui/CatfishWindow.ui
+++ b/data/ui/CatfishWindow.ui
@@ -1063,8 +1063,8 @@
           <object class="GtkBox" id="toolbar_view">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
-            <property name="halign">center</property>
             <property name="valign">center</property>
+            <property name="homogeneous">True</property>
             <child>
               <object class="GtkRadioButton" id="toolbar_view_list">
                 <property name="width_request">32</property>
@@ -1074,7 +1074,6 @@
                 <property name="receives_default">False</property>
                 <property name="tooltip_text" translatable="yes">Compact List</property>
                 <property name="image">toolbar_view_list_icon</property>
-                <property name="xalign">0.5</property>
                 <property name="active">True</property>
                 <property name="draw_indicator">False</property>
                 <signal name="toggled" handler="on_treeview_list_toggled" swapped="no"/>
@@ -1094,7 +1093,6 @@
                 <property name="receives_default">False</property>
                 <property name="tooltip_text" translatable="yes">Thumbnails</property>
                 <property name="image">toolbar_view_thumbnails_icon</property>
-                <property name="xalign">0.5</property>
                 <property name="draw_indicator">False</property>
                 <property name="group">toolbar_view_list</property>
                 <signal name="toggled" handler="on_treeview_thumbnails_toggled" swapped="no"/>
@@ -1113,19 +1111,57 @@
       </object>
     </child>
     <child>
+      <object class="GtkListBoxRow" id="listseprow1">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="valign">start</property>
+        <property name="activatable">False</property>
+        <property name="selectable">False</property>
+        <child>
+          <object class="GtkSeparator" id="listsep1">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="valign">start</property>
+          </object>
+        </child>
+      </object>
+    </child>
+    <child>
       <object class="GtkListBoxRow" id="listboxrow2">
         <property name="visible">True</property>
         <property name="can_focus">True</property>
         <child>
-          <object class="GtkCheckButton" id="application_menu_hidden">
-            <property name="label" translatable="yes">Show _Hidden Files</property>
+          <object class="GtkCheckButton" id="application_menu_advanced">
             <property name="visible">True</property>
             <property name="can_focus">True</property>
             <property name="receives_default">False</property>
             <property name="use_underline">True</property>
-            <property name="xalign">0</property>
             <property name="draw_indicator">True</property>
-            <signal name="toggled" handler="on_menu_hidden_files_toggled" swapped="no"/>
+            <signal name="toggled" handler="on_sidebar_toggle_toggled" swapped="no"/>
+            <child>
+              <object class="GtkAccelLabel" id="accel_label_1">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">Show _sidebar</property>
+                <property name="use_underline">True</property>
+                <property name="accel_widget">application_menu_advanced</property>
+              </object>
+            </child>
+            <accelerator key="F9" signal="activate"/>
+          </object>
+        </child>
+      </object>
+    </child>
+    <child>
+      <object class="GtkListBoxRow" id="listseprow2">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="valign">start</property>
+        <child>
+          <object class="GtkSeparator" id="listsep2">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="valign">start</property>
           </object>
         </child>
       </object>
@@ -1135,15 +1171,14 @@
         <property name="visible">True</property>
         <property name="can_focus">True</property>
         <child>
-          <object class="GtkCheckButton" id="application_menu_fulltext">
-            <property name="label" translatable="yes">Search File _Contents</property>
+          <object class="GtkCheckButton" id="application_menu_hidden">
+            <property name="label" translatable="yes">Show _hidden files</property>
             <property name="visible">True</property>
             <property name="can_focus">True</property>
             <property name="receives_default">False</property>
             <property name="use_underline">True</property>
-            <property name="xalign">0</property>
             <property name="draw_indicator">True</property>
-            <signal name="toggled" handler="on_menu_fulltext_toggled" swapped="no"/>
+            <signal name="toggled" handler="on_menu_hidden_files_toggled" swapped="no"/>
           </object>
         </child>
       </object>
@@ -1153,15 +1188,14 @@
         <property name="visible">True</property>
         <property name="can_focus">True</property>
         <child>
-          <object class="GtkCheckButton" id="application_menu_exact">
-            <property name="label" translatable="yes">_Exact Match</property>
+          <object class="GtkCheckButton" id="application_menu_fulltext">
+            <property name="label" translatable="yes">Search file _contents</property>
             <property name="visible">True</property>
             <property name="can_focus">True</property>
             <property name="receives_default">False</property>
             <property name="use_underline">True</property>
-            <property name="xalign">0</property>
             <property name="draw_indicator">True</property>
-            <signal name="toggled" handler="on_menu_exact_match_toggled" swapped="no"/>
+            <signal name="toggled" handler="on_menu_fulltext_toggled" swapped="no"/>
           </object>
         </child>
       </object>
@@ -1171,34 +1205,29 @@
         <property name="visible">True</property>
         <property name="can_focus">True</property>
         <child>
-          <object class="GtkCheckButton" id="application_menu_advanced">
-            <property name="label" translatable="yes">Show _Sidebar</property>
+          <object class="GtkCheckButton" id="application_menu_exact">
+            <property name="label" translatable="yes">_Match results exactly</property>
             <property name="visible">True</property>
             <property name="can_focus">True</property>
             <property name="receives_default">False</property>
             <property name="use_underline">True</property>
-            <property name="xalign">0</property>
             <property name="draw_indicator">True</property>
-            <signal name="toggled" handler="on_sidebar_toggle_toggled" swapped="no"/>
+            <signal name="toggled" handler="on_menu_exact_match_toggled" swapped="no"/>
           </object>
         </child>
       </object>
     </child>
     <child>
-      <object class="GtkListBoxRow" id="listboxrow8">
+      <object class="GtkListBoxRow" id="listseprow3">
         <property name="width_request">100</property>
         <property name="visible">True</property>
         <property name="can_focus">True</property>
+        <property name="valign">start</property>
         <child>
-          <object class="GtkCheckButton" id="application_menu_closeafterselect">
-            <property name="label" translatable="yes">Close _on Selection</property>
+          <object class="GtkSeparator" id="listsep3">
             <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="receives_default">False</property>
-            <property name="use_underline">True</property>
-            <property name="xalign">0</property>
-            <property name="draw_indicator">True</property>
-            <signal name="toggled" handler="on_menu_closeafterselect_toggled" swapped="no"/>
+            <property name="can_focus">False</property>
+            <property name="valign">start</property>
           </object>
         </child>
       </object>
@@ -1212,11 +1241,16 @@
           <object class="GtkBox" id="box1">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
+            <property name="margin_left">9</property>
+            <property name="margin_right">9</property>
+            <property name="spacing">8</property>
             <child>
               <object class="GtkImage" id="image1">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
+                <property name="pixel_size">16</property>
                 <property name="icon_name">view-refresh-symbolic</property>
+                <property name="icon_size">1</property>
               </object>
               <packing>
                 <property name="expand">False</property>
@@ -1228,8 +1262,63 @@
               <object class="GtkLabel" id="label1">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
-                <property name="margin_left">5</property>
-                <property name="label" translatable="yes">_Update Search Index...</property>
+                <property name="label" translatable="yes">_Refresh search index...</property>
+                <property name="use_underline">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+        </child>
+      </object>
+    </child>
+    <child>
+      <object class="GtkListBoxRow" id="listseprow4">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <child>
+          <object class="GtkSeparator" id="listsep4">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="valign">start</property>
+          </object>
+        </child>
+      </object>
+    </child>
+    <child>
+      <object class="GtkListBoxRow" id="application_menu_prefs">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <child>
+          <object class="GtkBox" id="box4">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="margin_left">9</property>
+            <property name="margin_right">9</property>
+            <property name="spacing">8</property>
+            <child>
+              <object class="GtkImage" id="image3">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="pixel_size">16</property>
+                <property name="icon_name">document-properties-symbolic</property>
+                <property name="use_fallback">True</property>
+                <property name="icon_size">1</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label6">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">_Preferences</property>
                 <property name="use_underline">True</property>
               </object>
               <packing>
@@ -1243,7 +1332,7 @@
       </object>
     </child>
     <child>
-      <object class="GtkListBoxRow" id="listboxrow7">
+      <object class="GtkListBoxRow" id="listboxrow8">
         <property name="visible">True</property>
         <property name="can_focus">True</property>
         <property name="selectable">False</property>
@@ -1251,11 +1340,16 @@
           <object class="GtkBox" id="box2">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
+            <property name="margin_left">9</property>
+            <property name="margin_right">9</property>
+            <property name="spacing">8</property>
             <child>
               <object class="GtkImage" id="image2">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
+                <property name="pixel_size">16</property>
                 <property name="icon_name">help-about-symbolic</property>
+                <property name="icon_size">1</property>
               </object>
               <packing>
                 <property name="expand">False</property>
@@ -1267,7 +1361,6 @@
               <object class="GtkLabel" id="label2">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
-                <property name="margin_left">5</property>
                 <property name="label" translatable="yes">_About</property>
                 <property name="use_underline">True</property>
               </object>
@@ -1282,6 +1375,18 @@
       </object>
     </child>
   </object>
+  <object class="GtkSizeGroup" id="application_menu_sg">
+    <property name="mode">vertical</property>
+    <widgets>
+      <widget name="listboxrow2"/>
+      <widget name="listboxrow3"/>
+      <widget name="listboxrow4"/>
+      <widget name="listboxrow5"/>
+      <widget name="application_menu_update"/>
+      <widget name="application_menu_prefs"/>
+      <widget name="listboxrow8"/>
+    </widgets>
+  </object>
   <object class="GtkImage" id="update_unlock_icon">
     <property name="visible">True</property>
     <property name="can_focus">False</property>
diff --git a/data/ui/about_catfish_dialog.xml b/data/ui/about_catfish_dialog.xml
index 4b226f5..3654a65 100644
--- a/data/ui/about_catfish_dialog.xml
+++ b/data/ui/about_catfish_dialog.xml
@@ -1,7 +1,7 @@
-<glade-catalog name="about_catfish_dialog" domain="glade-3" 
+<glade-catalog name="about_catfish_dialog" domain="glade-3"
                depends="gtk+" version="1.0">
   <glade-widget-classes>
-    <glade-widget-class title="About Catfish Dialog" name="AboutCatfishDialog" 
+    <glade-widget-class title="About Catfish Dialog" name="AboutCatfishDialog"
                         generic-name="AboutCatfishDialog" parent="GtkAboutDialog"
                         icon-name="widget-gtk-about-dialog"/>
   </glade-widget-classes>
diff --git a/data/ui/catfish-wl-headerbar.png b/data/ui/catfish-wl-headerbar.png
new file mode 100644
index 0000000..8271d24
Binary files /dev/null and b/data/ui/catfish-wl-headerbar.png differ
diff --git a/data/ui/catfish-wl-titlebar.png b/data/ui/catfish-wl-titlebar.png
new file mode 100644
index 0000000..e4e91ee
Binary files /dev/null and b/data/ui/catfish-wl-titlebar.png differ
diff --git a/data/ui/catfish_preferences.xml b/data/ui/catfish_preferences.xml
new file mode 100644
index 0000000..441bc62
--- /dev/null
+++ b/data/ui/catfish_preferences.xml
@@ -0,0 +1,8 @@
+<glade-catalog name="catfish_preferences" domain="glade-3"
+               depends="gtk+" version="1.0">
+  <glade-widget-classes>
+    <glade-widget-class title="Catfish Preferences" name="CatfishPrefsDialog"
+                        generic-name="CatfishPrefsDialog" parent="GtkDialog"
+                        icon-name="widget-gtk-window"/>
+  </glade-widget-classes>
+</glade-catalog>
diff --git a/data/ui/catfish_window.xml b/data/ui/catfish_window.xml
index b2f45db..e039107 100644
--- a/data/ui/catfish_window.xml
+++ b/data/ui/catfish_window.xml
@@ -1,7 +1,7 @@
-<glade-catalog name="catfish_window" domain="glade-3" 
+<glade-catalog name="catfish_window" domain="glade-3"
                depends="gtk+" version="1.0">
   <glade-widget-classes>
-    <glade-widget-class title="Catfish Window" name="CatfishWindow" 
+    <glade-widget-class title="Catfish Window" name="CatfishWindow"
                         generic-name="CatfishWindow" parent="GtkWindow"
                         icon-name="widget-gtk-window"/>
   </glade-widget-classes>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 1f127f4..efea239 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -19,20 +19,25 @@ org.xfce.Catfish.desktop.in
 
 # Glade Files
 [type: gettext/glade]data/ui/AboutCatfishDialog.ui
+[type: gettext/glade]data/ui/CatfishPreferences.ui
 [type: gettext/glade]data/ui/CatfishWindow.ui
 
 # Python Files
 catfish/__init__.py
-catfish/CatfishWindow.py
-catfish/CatfishSearchEngine.py
 catfish/AboutCatfishDialog.py
+catfish/CatfishPrefsDialog.py
+catfish/CatfishSearchEngine.py
+catfish/CatfishWindow.py
+catfish_lib/__init__.py
+catfish_lib/AboutDialog.py
 catfish_lib/Builder.py
 catfish_lib/catfishconfig.py
-catfish_lib/AboutDialog.py
-catfish_lib/__init__.py
+catfish_lib/CatfishSettings.py
 catfish_lib/helpers.py
-catfish_lib/Window.py
+catfish_lib/PrefsDialog.py
 catfish_lib/SudoDialog.py
+catfish_lib/Thumbnailer.py
+catfish_lib/Window.py
 
 # XML Files
 [type: gettext/xml]data/metainfo/catfish.appdata.xml.in
diff --git a/po/catfish.pot b/po/catfish.pot
index 8ee499a..d30e4dc 100644
--- a/po/catfish.pot
+++ b/po/catfish.pot
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2019-08-24 16:35-0400\n"
+"POT-Creation-Date: 2019-08-25 10:52-0400\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL at ADDRESS>\n"
 "Language-Team: LANGUAGE <LL at li.org>\n"
@@ -18,7 +18,7 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 
 #: ../org.xfce.Catfish.desktop.in.h:1 ../data/ui/CatfishWindow.ui.h:28
-#: ../catfish/CatfishWindow.py:713
+#: ../catfish/CatfishWindow.py:718
 msgid "Catfish File Search"
 msgstr ""
 
@@ -39,6 +39,82 @@ msgstr ""
 msgid "Catfish is a versatile file searching tool."
 msgstr ""
 
+#: ../data/ui/CatfishPreferences.ui.h:1
+msgid "Catfish Preferences"
+msgstr ""
+
+#: ../data/ui/CatfishPreferences.ui.h:2
+msgid "_Close"
+msgstr ""
+
+#: ../data/ui/CatfishPreferences.ui.h:3
+msgid "Classic (_Titlebar)"
+msgstr ""
+
+#: ../data/ui/CatfishPreferences.ui.h:4
+msgid "_Modern (CSD)"
+msgstr ""
+
+#: ../data/ui/CatfishPreferences.ui.h:5
+msgid "Your new window layout will be applied after restarting Catifish."
+msgstr ""
+
+#: ../data/ui/CatfishPreferences.ui.h:6
+msgid "Window Layout"
+msgstr ""
+
+#: ../data/ui/CatfishPreferences.ui.h:7
+msgid "Show _hidden files in the results"
+msgstr ""
+
+#: ../data/ui/CatfishPreferences.ui.h:8
+msgid "Show filter _sidebar"
+msgstr ""
+
+#: ../data/ui/CatfishPreferences.ui.h:9
+msgid "Display Options"
+msgstr ""
+
+#: ../data/ui/CatfishPreferences.ui.h:10
+msgid "_Appearance"
+msgstr ""
+
+#: ../data/ui/CatfishPreferences.ui.h:11
+msgid "Path"
+msgstr ""
+
+#: ../data/ui/CatfishPreferences.ui.h:12
+msgid "Add Directory..."
+msgstr ""
+
+#: ../data/ui/CatfishPreferences.ui.h:13
+msgid "_Add"
+msgstr ""
+
+#: ../data/ui/CatfishPreferences.ui.h:14
+msgid "Remove Directory"
+msgstr ""
+
+#: ../data/ui/CatfishPreferences.ui.h:15
+msgid "_Remove"
+msgstr ""
+
+#: ../data/ui/CatfishPreferences.ui.h:16
+msgid "Exclude Directories"
+msgstr ""
+
+#: ../data/ui/CatfishPreferences.ui.h:17
+msgid "Close the search _window after opening a file"
+msgstr ""
+
+#: ../data/ui/CatfishPreferences.ui.h:18
+msgid "Miscellaneous"
+msgstr ""
+
+#: ../data/ui/CatfishPreferences.ui.h:19
+msgid "A_dvanced"
+msgstr ""
+
 #: ../data/ui/CatfishWindow.ui.h:1
 msgid "_Open"
 msgstr ""
@@ -137,11 +213,11 @@ msgstr ""
 msgid "File Type"
 msgstr ""
 
-#: ../data/ui/CatfishWindow.ui.h:27 ../catfish/CatfishWindow.py:1256
+#: ../data/ui/CatfishWindow.ui.h:27 ../catfish/CatfishWindow.py:1277
 msgid "Modified"
 msgstr ""
 
-#: ../data/ui/CatfishWindow.ui.h:29 ../catfish/CatfishWindow.py:1704
+#: ../data/ui/CatfishWindow.ui.h:29 ../catfish/CatfishWindow.py:1727
 msgid "Results will be displayed as soon as they are found."
 msgstr ""
 
@@ -162,27 +238,27 @@ msgid "Thumbnails"
 msgstr ""
 
 #: ../data/ui/CatfishWindow.ui.h:34
-msgid "Show _Hidden Files"
+msgid "Show _sidebar"
 msgstr ""
 
 #: ../data/ui/CatfishWindow.ui.h:35
-msgid "Search File _Contents"
+msgid "Show _hidden files"
 msgstr ""
 
 #: ../data/ui/CatfishWindow.ui.h:36
-msgid "_Exact Match"
+msgid "Search file _contents"
 msgstr ""
 
 #: ../data/ui/CatfishWindow.ui.h:37
-msgid "Show _Sidebar"
+msgid "_Match results exactly"
 msgstr ""
 
 #: ../data/ui/CatfishWindow.ui.h:38
-msgid "Close _on Selection"
+msgid "_Refresh search index..."
 msgstr ""
 
 #: ../data/ui/CatfishWindow.ui.h:39
-msgid "_Update Search Index..."
+msgid "_Preferences"
 msgstr ""
 
 #: ../data/ui/CatfishWindow.ui.h:40
@@ -263,170 +339,170 @@ msgstr ""
 msgid "Try GDK_BACKEND=x11 {0}\n"
 msgstr ""
 
+#: ../catfish/AboutCatfishDialog.py:37
+msgid "translator-credits"
+msgstr ""
+
 #. Translators: this text is displayed next to
 #. a filename that is not utf-8 encoded.
-#: ../catfish/CatfishWindow.py:99
+#: ../catfish/CatfishWindow.py:100
 #, python-format
 msgid "%s (invalid encoding)"
 msgstr ""
 
-#: ../catfish/CatfishWindow.py:255
+#: ../catfish/CatfishWindow.py:256
 msgid "Unknown"
 msgstr ""
 
-#: ../catfish/CatfishWindow.py:259
+#: ../catfish/CatfishWindow.py:260
 msgid "Never"
 msgstr ""
 
-#: ../catfish/CatfishWindow.py:337
+#: ../catfish/CatfishWindow.py:339
 #, python-format
 msgid ""
 "Enter your query above to find your files\n"
 "or click the %s icon for more options."
 msgstr ""
 
-#: ../catfish/CatfishWindow.py:681
+#: ../catfish/CatfishWindow.py:686
 msgid "An error occurred while updating the database."
 msgstr ""
 
-#: ../catfish/CatfishWindow.py:683
+#: ../catfish/CatfishWindow.py:688
 msgid "Authentication failed."
 msgstr ""
 
-#: ../catfish/CatfishWindow.py:689
+#: ../catfish/CatfishWindow.py:694
 msgid "Authentication cancelled."
 msgstr ""
 
-#: ../catfish/CatfishWindow.py:695
+#: ../catfish/CatfishWindow.py:700
 msgid "Search database updated successfully."
 msgstr ""
 
 #. Set the dialog status to running.
-#: ../catfish/CatfishWindow.py:770
+#: ../catfish/CatfishWindow.py:775
 msgid "Updating..."
 msgstr ""
 
-#: ../catfish/CatfishWindow.py:804
+#: ../catfish/CatfishWindow.py:809
 msgid "Stop Search"
 msgstr ""
 
-#: ../catfish/CatfishWindow.py:805
+#: ../catfish/CatfishWindow.py:810
 msgid ""
 "Search is in progress...\n"
 "Press the cancel button or the Escape key to stop."
 msgstr ""
 
-#: ../catfish/CatfishWindow.py:814
+#: ../catfish/CatfishWindow.py:819
 msgid "Begin Search"
 msgstr ""
 
-#: ../catfish/CatfishWindow.py:1076
+#: ../catfish/CatfishWindow.py:1097
 #, python-format
 msgid "\"%s\" could not be opened."
 msgstr ""
 
-#: ../catfish/CatfishWindow.py:1128
+#: ../catfish/CatfishWindow.py:1149
 #, python-format
 msgid "\"%s\" could not be saved."
 msgstr ""
 
-#: ../catfish/CatfishWindow.py:1145
+#: ../catfish/CatfishWindow.py:1166
 #, python-format
 msgid "\"%s\" could not be deleted."
 msgstr ""
 
-#: ../catfish/CatfishWindow.py:1185
+#: ../catfish/CatfishWindow.py:1206
 #, python-format
 msgid "Save \"%s\" as..."
 msgstr ""
 
-#: ../catfish/CatfishWindow.py:1220
+#: ../catfish/CatfishWindow.py:1241
 #, python-format
 msgid ""
 "Are you sure that you want to \n"
 "permanently delete \"%s\"?"
 msgstr ""
 
-#: ../catfish/CatfishWindow.py:1224
+#: ../catfish/CatfishWindow.py:1245
 #, python-format
 msgid ""
 "Are you sure that you want to \n"
 "permanently delete the %i selected files?"
 msgstr ""
 
-#: ../catfish/CatfishWindow.py:1227
+#: ../catfish/CatfishWindow.py:1248
 msgid "If you delete a file, it is permanently lost."
 msgstr ""
 
-#: ../catfish/CatfishWindow.py:1250
+#: ../catfish/CatfishWindow.py:1271
 msgid "Filename"
 msgstr ""
 
-#: ../catfish/CatfishWindow.py:1252
+#: ../catfish/CatfishWindow.py:1273
 msgid "Size"
 msgstr ""
 
-#: ../catfish/CatfishWindow.py:1254
+#: ../catfish/CatfishWindow.py:1275
 msgid "Location"
 msgstr ""
 
-#: ../catfish/CatfishWindow.py:1266
+#: ../catfish/CatfishWindow.py:1287
 msgid "Preview"
 msgstr ""
 
-#: ../catfish/CatfishWindow.py:1274
+#: ../catfish/CatfishWindow.py:1295
 msgid "Details"
 msgstr ""
 
-#: ../catfish/CatfishWindow.py:1493
+#: ../catfish/CatfishWindow.py:1514
 msgid "Today"
 msgstr ""
 
-#: ../catfish/CatfishWindow.py:1495
+#: ../catfish/CatfishWindow.py:1516
 msgid "Yesterday"
 msgstr ""
 
-#: ../catfish/CatfishWindow.py:1576
+#: ../catfish/CatfishWindow.py:1597
 msgid "No files found."
 msgstr ""
 
-#: ../catfish/CatfishWindow.py:1578
+#: ../catfish/CatfishWindow.py:1599
 msgid ""
 "Try making your search less specific\n"
 "or try another directory."
 msgstr ""
 
-#: ../catfish/CatfishWindow.py:1585
+#: ../catfish/CatfishWindow.py:1606
 msgid "1 file found."
 msgstr ""
 
-#: ../catfish/CatfishWindow.py:1587
+#: ../catfish/CatfishWindow.py:1608
 #, python-format
 msgid "%i files found."
 msgstr ""
 
-#: ../catfish/CatfishWindow.py:1593
+#: ../catfish/CatfishWindow.py:1614
 msgid "bytes"
 msgstr ""
 
-#: ../catfish/CatfishWindow.py:1702 ../catfish/CatfishWindow.py:1712
+#: ../catfish/CatfishWindow.py:1725 ../catfish/CatfishWindow.py:1735
 msgid "Searching..."
 msgstr ""
 
-#: ../catfish/CatfishWindow.py:1710
+#: ../catfish/CatfishWindow.py:1733
 #, python-format
 msgid "Searching for \"%s\""
 msgstr ""
 
-#: ../catfish/CatfishWindow.py:1794
+#: ../catfish/CatfishWindow.py:1822
 #, python-format
 msgid "Search results for \"%s\""
 msgstr ""
 
-#: ../catfish/AboutCatfishDialog.py:37
-msgid "translator-credits"
-msgstr ""
-
 #: ../catfish_lib/SudoDialog.py:138
 msgid "Password Required"
 msgstr ""

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the Xfce4-commits mailing list