[meld] preferences: Migrate filter settings to GSettings



commit ee6bddc964e1f65ca87b77919d15c017da9a9dc9
Author: Kai Willadsen <kai willadsen gmail com>
Date:   Sun Nov 24 07:02:58 2013 +1000

    preferences: Migrate filter settings to GSettings

 data/org.gnome.meld.gschema.xml |   29 ++++++++++++++++++++++
 meld/dirdiff.py                 |   29 +++++++++++++---------
 meld/filediff.py                |   17 +++++++-----
 meld/filters.py                 |    8 ++++++
 meld/meldapp.py                 |   27 ---------------------
 meld/preferences.py             |   50 ++++++--------------------------------
 meld/settings.py                |   40 ++++++++++++++++++++++++++++++-
 7 files changed, 111 insertions(+), 89 deletions(-)
---
diff --git a/data/org.gnome.meld.gschema.xml b/data/org.gnome.meld.gschema.xml
index 8401f2a..09e8e2e 100644
--- a/data/org.gnome.meld.gschema.xml
+++ b/data/org.gnome.meld.gschema.xml
@@ -106,5 +106,34 @@
           <summary>Version control status filters</summary>
           <description>List of statuses used to filter visible files in version control 
comparison.</description>
       </key>
+
+      <!-- Filters -->
+      <key name="filename-filters" type="a(sbs)">
+          <default>
+            [
+              ("Backups", true, "#*# .#* ~* *~ *.{orig,bak,swp}"),
+              ("OS-specific metadata", true, ".DS_Store ._* .Spotlight-V100 .Trashes Thumbs.db Desktop.ini"),
+              ("Version Control", true, "_MTN .bzr .svn .svn .hg .fslckout _FOSSIL_ .fos CVS _darcs .git 
.svn"),
+              ("Binaries", true, "*.{pyc,a,obj,o,so,la,lib,dll,exe}"),
+              ("Media", false, "*.{jpg,gif,png,bmp,wav,mp3,ogg,flac,avi,mpg,xcf,xpm}")
+            ]
+          </default>
+          <summary>Filename-based filters</summary>
+          <description>List of predefined filename-based filters that, if active, will remove matching files 
from a folder comparison.</description>
+      </key>
+      <key name="text-filters" type="a(sbs)">
+          <default>
+            [
+              ("CVS keywords", false, "\$\\w+(:[^\\n$]+)?\$"),
+              ("C++ comment", false, "//.*"),
+              ("C comment", false, "/\\*.*?\\*/"),
+              ("All whitespace", false, "[ \\t\\r\\f\\v]*"),
+              ("Leading whitespace", false, "^[ \\t\\r\\f\\v]*"),
+              ("Script comment", false, "#.*")
+            ]
+          </default>
+          <summary>Text-based filters</summary>
+          <description>List of predefined text-based regex filters that, if active, will remove text from 
being used in a file comparison. The text will still be displayed, but won't contribute to the comparison 
itself.</description>
+      </key>
   </schema>
 </schemalist>
diff --git a/meld/dirdiff.py b/meld/dirdiff.py
index 79a2406..13b4efc 100644
--- a/meld/dirdiff.py
+++ b/meld/dirdiff.py
@@ -47,7 +47,7 @@ from gettext import gettext as _
 from gettext import ngettext
 from .meldapp import app
 
-from meld.settings import settings
+from meld.settings import meldsettings, settings
 
 
 ################################################################################
@@ -316,10 +316,12 @@ class DirDiff(melddoc.MeldDoc, gnomeglade.Component):
         self.text_filters = []
         self.create_name_filters()
         self.create_text_filters()
-        self.app_handlers = [app.connect("file-filters-changed",
-                                         self.on_file_filters_changed),
-                             app.connect("text-filters-changed",
-                                         self.on_text_filters_changed)]
+        self.settings_handlers = [
+            meldsettings.connect("file-filters-changed",
+                                 self.on_file_filters_changed),
+            meldsettings.connect("text-filters-changed",
+                                 self.on_text_filters_changed)
+        ]
 
         self.map_widgets_into_lists(["treeview", "fileentry", "scrolledwindow",
                                      "diffmap", "linkmap", "msgarea_mgr",
@@ -543,11 +545,13 @@ class DirDiff(melddoc.MeldDoc, gnomeglade.Component):
 
     def create_name_filters(self):
         # Ordering of name filters is irrelevant
-        old_active = set([f.filter_string for f in self.name_filters if f.active])
-        new_active = set([f.filter_string for f in app.file_filters if f.active])
+        old_active = set([f.filter_string for f in self.name_filters
+                          if f.active])
+        new_active = set([f.filter_string for f in meldsettings.file_filters
+                          if f.active])
         active_filters_changed = old_active != new_active
 
-        self.name_filters = [copy.copy(f) for f in app.file_filters]
+        self.name_filters = [copy.copy(f) for f in meldsettings.file_filters]
         actions = []
         disabled_actions = []
         self.filter_ui = []
@@ -575,10 +579,11 @@ class DirDiff(melddoc.MeldDoc, gnomeglade.Component):
     def create_text_filters(self):
         # In contrast to file filters, ordering of text filters can matter
         old_active = [f.filter_string for f in self.text_filters if f.active]
-        new_active = [f.filter_string for f in app.text_filters if f.active]
+        new_active = [f.filter_string for f in meldsettings.text_filters
+                      if f.active]
         active_filters_changed = old_active != new_active
 
-        self.text_filters = [copy.copy(f) for f in app.text_filters]
+        self.text_filters = [copy.copy(f) for f in meldsettings.text_filters]
 
         return active_filters_changed
 
@@ -1508,8 +1513,8 @@ class DirDiff(melddoc.MeldDoc, gnomeglade.Component):
         self.on_fileentry_file_set(None)
 
     def on_delete_event(self, appquit=0):
-        for h in self.app_handlers:
-            app.disconnect(h)
+        for h in self.settings_handlers:
+            meldsettings.disconnect(h)
 
         return Gtk.ResponseType.OK
 
diff --git a/meld/filediff.py b/meld/filediff.py
index 174b7b1..b514ef8 100644
--- a/meld/filediff.py
+++ b/meld/filediff.py
@@ -46,7 +46,7 @@ from . import undo
 from .ui import findbar
 from .ui import gnomeglade
 
-from meld.settings import settings
+from meld.settings import meldsettings, settings
 from .meldapp import app
 from .util.compat import text_type
 from .util.sourceviewer import LanguageManager
@@ -197,8 +197,10 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
         self.undosequence = undo.UndoSequence()
         self.text_filters = []
         self.create_text_filters()
-        self.app_handlers = [app.connect("text-filters-changed",
-                             self.on_text_filters_changed)]
+        self.settings_handlers = [
+            meldsettings.connect("text-filters-changed",
+                                 self.on_text_filters_changed)
+        ]
         self.buffer_filtered = [meldbuffer.BufferLines(b, self._filter_text)
                                 for b in self.textbuffer]
         for (i, w) in enumerate(self.scrolledwindow):
@@ -425,10 +427,11 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
     def create_text_filters(self):
         # In contrast to file filters, ordering of text filters can matter
         old_active = [f.filter_string for f in self.text_filters if f.active]
-        new_active = [f.filter_string for f in app.text_filters if f.active]
+        new_active = [f.filter_string for f in meldsettings.text_filters
+                      if f.active]
         active_filters_changed = old_active != new_active
 
-        self.text_filters = [copy.copy(f) for f in app.text_filters]
+        self.text_filters = [copy.copy(f) for f in meldsettings.text_filters]
 
         return active_filters_changed
 
@@ -892,8 +895,8 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
     def on_delete_event(self, appquit=0):
         response = self.check_save_modified()
         if response == Gtk.ResponseType.OK:
-            for h in self.app_handlers:
-                app.disconnect(h)
+            for h in self.settings_handlers:
+                meldsettings.disconnect(h)
         return response
 
         #
diff --git a/meld/filters.py b/meld/filters.py
index 9a95e5c..4dd9da1 100644
--- a/meld/filters.py
+++ b/meld/filters.py
@@ -71,6 +71,14 @@ class FilterEntry(object):
         return FilterEntry(name, active, compiled, filter_string)
 
     @classmethod
+    def new_from_gsetting(cls, elements, filter_type):
+        name, active, filter_string = elements
+        compiled = FilterEntry.compile_filter(filter_string, filter_type)
+        if compiled is None:
+            active = False
+        return FilterEntry(name, active, compiled, filter_string)
+
+    @classmethod
     def compile_filter(cls, filter_string, filter_type):
         if filter_type == FilterEntry.REGEX:
             compiled = FilterEntry._compile_regex(filter_string)
diff --git a/meld/meldapp.py b/meld/meldapp.py
index a0e2447..920f68f 100644
--- a/meld/meldapp.py
+++ b/meld/meldapp.py
@@ -37,13 +37,6 @@ import meld.recent
 
 class MeldApp(Gtk.Application):
 
-    __gsignals__ = {
-        'file-filters-changed': (GObject.SignalFlags.RUN_FIRST,
-                                 None, ()),
-        'text-filters-changed': (GObject.SignalFlags.RUN_FIRST,
-                                 None, ()),
-    }
-
     def __init__(self):
         Gtk.Application.__init__(self)
         self.set_flags(Gio.ApplicationFlags.HANDLES_COMMAND_LINE)
@@ -51,11 +44,6 @@ class MeldApp(Gtk.Application):
         GObject.set_application_name("Meld")
         Gtk.Window.set_default_icon_name("meld")
         self.prefs = meld.preferences.MeldPreferences()
-        self.prefs.notify_add(self.on_preference_changed)
-        self.file_filters = self._parse_filters(self.prefs.filters,
-                                                meld.filters.FilterEntry.SHELL)
-        self.text_filters = self._parse_filters(self.prefs.regexes,
-                                                meld.filters.FilterEntry.REGEX)
         self.recent_comparisons = meld.recent.RecentFiles(sys.argv[0])
         self.window = None
 
@@ -133,21 +121,6 @@ class MeldApp(Gtk.Application):
 
         return self.window.open_paths(paths, **kwargs)
 
-    def on_preference_changed(self, key, val):
-        if key == "filters":
-            self.file_filters = self._parse_filters(
-                val, meld.filters.FilterEntry.SHELL)
-            self.emit('file-filters-changed')
-        elif key == "regexes":
-            self.text_filters = self._parse_filters(
-                val, meld.filters.FilterEntry.REGEX)
-            self.emit('text-filters-changed')
-
-    def _parse_filters(self, string, filt_type):
-        filt = [meld.filters.FilterEntry.parse(l, filt_type) for l
-                in string.split("\n")]
-        return [f for f in filt if f is not None]
-
     def diff_files_callback(self, option, opt_str, value, parser):
         """Gather --diff arguments and append to a list"""
         assert value is None
diff --git a/meld/preferences.py b/meld/preferences.py
index 5d9ac89..2463bcd 100644
--- a/meld/preferences.py
+++ b/meld/preferences.py
@@ -19,12 +19,11 @@
 from gettext import gettext as _
 
 from gi.repository import Gio
+from gi.repository import GLib
 from gi.repository import GObject
 from gi.repository import Gtk
 
 from . import filters
-from . import misc
-from . import vc
 from .ui import gnomeglade
 from .ui import listwidget
 from .util import prefs
@@ -40,20 +39,19 @@ TIMESTAMP_RESOLUTION_PRESETS = [('1ns (ext4)', 1),
 
 class FilterList(listwidget.ListWidget):
 
-    def __init__(self, prefs, key, filter_type):
+    def __init__(self, key, filter_type):
         default_entry = [_("label"), False, _("pattern"), True]
         listwidget.ListWidget.__init__(self, "EditableList.ui",
                                        "list_alignment", ["EditableListStore"],
                                        "EditableList", default_entry)
-        self.prefs = prefs
         self.key = key
         self.filter_type = filter_type
 
         self.pattern_column.set_cell_data_func(self.validity_renderer,
                                                self.valid_icon_celldata)
 
-        for filtstring in getattr(self.prefs, self.key).split("\n"):
-            filt = filters.FilterEntry.parse(filtstring, filter_type)
+        for filter_params in settings.get_value(self.key):
+            filt = filters.FilterEntry.new_from_gsetting(filter_params, filter_type)
             if filt is None:
                 continue
             valid = filt.filter is not None
@@ -84,14 +82,8 @@ class FilterList(listwidget.ListWidget):
         self.model[path][3] = valid
 
     def _update_filter_string(self, *args):
-        pref = []
-        for row in self.model:
-            pattern = row[2]
-            if pattern:
-                pattern = pattern.replace('\r', '')
-                pattern = pattern.replace('\n', '')
-            pref.append("%s\t%s\t%s" % (row[0], 1 if row[1] else 0, pattern))
-        setattr(self.prefs, self.key, "\n".join(pref))
+        value = [(row[0], row[1], row[2]) for row in self.model]
+        settings.set_value(self.key, GLib.Variant('a(sbs)', value))
 
 
 class ColumnList(listwidget.ListWidget):
@@ -226,13 +218,11 @@ class PreferencesDialog(gnomeglade.Component):
             self.checkbutton_wrap_text.set_active(True)
 
         # file filters
-        self.filefilter = FilterList(self.prefs, "filters",
-                                     filters.FilterEntry.SHELL)
+        self.filefilter = FilterList("filename-filters", filters.FilterEntry.SHELL)
         self.file_filters_tab.pack_start(self.filefilter.widget, True, True, 0)
 
         # text filters
-        self.textfilter = FilterList(self.prefs, "regexes",
-                                     filters.FilterEntry.REGEX)
+        self.textfilter = FilterList("text-filters", filters.FilterEntry.REGEX)
         self.text_filters_tab.pack_start(self.textfilter.widget, True, True, 0)
         self.checkbutton_ignore_blank_lines.set_active( self.prefs.ignore_blank_lines )
         # encoding
@@ -304,29 +294,6 @@ class MeldPreferences(prefs.Preferences):
         "edit_wrap_lines" : prefs.Value(prefs.INT, 0),
         "text_codecs": prefs.Value(prefs.STRING, "utf8 latin1"),
         "vc_console_visible": prefs.Value(prefs.BOOL, 0),
-        "filters" : prefs.Value(prefs.STRING,
-            #TRANSLATORS: translate this string ONLY to the first "\t", leave it and the following parts 
intact
-            _("Backups\t1\t#*# .#* ~* *~ *.{orig,bak,swp}\n") + \
-            #TRANSLATORS: translate this string ONLY to the first "\t", leave it and the following parts 
intact
-            _("OS-specific metadata\t0\t.DS_Store ._* .Spotlight-V100 .Trashes Thumbs.db Desktop.ini\n") + \
-            #TRANSLATORS: translate this string ONLY to the first "\t", leave it and the following parts 
intact
-            _("Version Control\t1\t%s\n") % misc.shell_escape(' '.join(vc.get_plugins_metadata())) + \
-            #TRANSLATORS: translate this string ONLY to the first "\t", leave it and the following parts 
intact
-            _("Binaries\t1\t*.{pyc,a,obj,o,so,la,lib,dll,exe}\n") + \
-            #TRANSLATORS: translate this string ONLY to the first "\t", leave it and the following parts 
intact
-            _("Media\t0\t*.{jpg,gif,png,bmp,wav,mp3,ogg,flac,avi,mpg,xcf,xpm}")),
-            #TRANSLATORS: translate this string ONLY to the first "\t", leave it and the following parts 
intact
-        "regexes" : prefs.Value(prefs.STRING, _("CVS keywords\t0\t\$\\w+(:[^\\n$]+)?\$\n") + \
-            #TRANSLATORS: translate this string ONLY to the first "\t", leave it and the following parts 
intact
-            _("C++ comment\t0\t//.*\n") + \
-            #TRANSLATORS: translate this string ONLY to the first "\t", leave it and the following parts 
intact
-            _("C comment\t0\t/\*.*?\*/\n") + \
-            #TRANSLATORS: translate this string ONLY to the first "\t", leave it and the following parts 
intact
-            _("All whitespace\t0\t[ \\t\\r\\f\\v]*\n") + \
-            #TRANSLATORS: translate this string ONLY to the first "\t", leave it and the following parts 
intact
-            _("Leading whitespace\t0\t^[ \\t\\r\\f\\v]*\n") + \
-            #TRANSLATORS: translate this string ONLY to the first "\t", leave it and the following parts 
intact
-            _("Script comment\t0\t#.*")),
         "ignore_blank_lines" : prefs.Value(prefs.BOOL, False),
         "toolbar_visible" : prefs.Value(prefs.BOOL, True),
         "statusbar_visible" : prefs.Value(prefs.BOOL, True),
@@ -336,7 +303,6 @@ class MeldPreferences(prefs.Preferences):
         "dirdiff_columns": prefs.Value(prefs.LIST,
                                          ["size 1", "modification time 1",
                                           "permissions 0"]),
-
         "vc_left_is_local": prefs.Value(prefs.BOOL, False),
     }
 
diff --git a/meld/settings.py b/meld/settings.py
index 3295b88..0f4d001 100644
--- a/meld/settings.py
+++ b/meld/settings.py
@@ -15,9 +15,10 @@
 # Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 from gi.repository import Gio
+from gi.repository import GObject
 
 import meld.conf
-
+import meld.filters
 
 schema_source = Gio.SettingsSchemaSource.new_from_directory(
     meld.conf.DATADIR,
@@ -28,3 +29,40 @@ schema = schema_source.lookup('org.gnome.meld', False)
 settings = Gio.Settings.new_full(schema, None, None)
 
 interface_settings = Gio.Settings.new('org.gnome.desktop.interface')
+
+
+class MeldSettings(GObject.GObject):
+    """Handler for settings that can't easily be bound to object properties"""
+
+    __gsignals__ = {
+        'file-filters-changed': (GObject.SignalFlags.RUN_FIRST,
+                                 None, ()),
+        'text-filters-changed': (GObject.SignalFlags.RUN_FIRST,
+                                 None, ()),
+    }
+
+    def __init__(self):
+        GObject.GObject.__init__(self)
+        self.on_setting_changed(settings, 'filename-filters')
+        self.on_setting_changed(settings, 'text-filters')
+        settings.connect('changed', self.on_setting_changed)
+
+    def on_setting_changed(self, settings, key):
+        if key == 'filename-filters':
+            self.file_filters = self._filters_from_gsetting(
+                'filename-filters', meld.filters.FilterEntry.SHELL)
+            self.emit('file-filters-changed')
+        elif key == 'text-filters':
+            self.text_filters = self._filters_from_gsetting(
+                'text-filters', meld.filters.FilterEntry.REGEX)
+            self.emit('text-filters-changed')
+
+    def _filters_from_gsetting(self, key, filt_type):
+        filter_params = settings.get_value(key)
+        filters = [
+            meld.filters.FilterEntry.new_from_gsetting(params, filt_type)
+            for params in filter_params
+        ]
+        return filters
+
+meldsettings = MeldSettings()


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]