[meld] Added shallow directory comparison mode



commit 3bd021b412b185f281704ac7e234b5966ad1c5a9
Author: Cristian Dinu <goc9000 gmail com>
Date:   Tue Feb 5 16:03:50 2013 +0100

    Added shallow directory comparison mode

 data/ui/preferences.ui |  125 +++++++++++++++++++++++++++++++++++++++++++++++-
 meld/dirdiff.py        |   30 ++++++++++--
 meld/preferences.py    |   31 ++++++++++++
 3 files changed, 180 insertions(+), 6 deletions(-)
---
diff --git a/data/ui/preferences.ui b/data/ui/preferences.ui
index e2ee426..a06e2b7 100644
--- a/data/ui/preferences.ui
+++ b/data/ui/preferences.ui
@@ -558,6 +558,127 @@
                 <property name="border_width">12</property>
                 <property name="spacing">12</property>
                 <child>
+                  <object class="GtkVBox" id="vbox3">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="spacing">6</property>
+                    <child>
+                      <object class="GtkLabel" id="label5">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">Shallow comparison</property>
+                        <property name="use_markup">True</property>
+                        <attributes>
+                          <attribute name="weight" value="bold"/>
+                        </attributes>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkHBox" id="hbox2">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <child>
+                          <object class="GtkLabel" id="label6">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="xpad">12</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkVBox" id="vbox4">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="spacing">6</property>
+                            <child>
+                              <object class="GtkCheckButton" id="checkbutton_shallow_compare">
+                                <property name="label" translatable="yes">Enable _shallow comparison (trust size+date)</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="use_action_appearance">False</property>
+                                <property name="use_underline">True</property>
+                                <property name="xalign">0.51999998092651367</property>
+                                <property name="draw_indicator">True</property>
+                                <signal name="toggled" handler="on_checkbutton_shallow_compare_toggled" swapped="no"/>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkHBox" id="timestamp_hbox">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="spacing">6</property>
+                                <child>
+                                  <object class="GtkLabel" id="label7">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="xalign">0</property>
+                                    <property name="label" translatable="yes">_Timestamp resolution:</property>
+                                    <property name="use_underline">True</property>
+                                    <property name="mnemonic_widget">spinbutton_tabsize</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkComboBox" id="combo_timestamp">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <signal name="changed" handler="on_combo_timestamp_changed" swapped="no"/>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">True</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">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>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
                   <object class="GtkVBox" id="vbox1">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
@@ -623,7 +744,7 @@
                   <packing>
                     <property name="expand">False</property>
                     <property name="fill">True</property>
-                    <property name="position">0</property>
+                    <property name="position">1</property>
                   </packing>
                 </child>
                 <child>
@@ -689,7 +810,7 @@
                   <packing>
                     <property name="expand">True</property>
                     <property name="fill">True</property>
-                    <property name="position">1</property>
+                    <property name="position">2</property>
                   </packing>
                 </child>
               </object>
diff --git a/meld/dirdiff.py b/meld/dirdiff.py
index 159fd42..412be6c 100644
--- a/meld/dirdiff.py
+++ b/meld/dirdiff.py
@@ -29,6 +29,8 @@ import time
 import gtk
 import gtk.keysyms
 
+from decimal import Decimal
+
 from . import melddoc
 from . import tree
 from . import misc
@@ -58,6 +60,15 @@ class StatItem(namedtuple('StatItem', 'mode size time')):
         return StatItem(stat.S_IFMT(stat_result.st_mode),
                         stat_result.st_size, stat_result.st_mtime)
 
+    def shallow_equal(self, other, prefs):
+        if self.size != other.size:
+            return False
+
+        mtime1 = Decimal(self.time).scaleb(9).quantize(1) // prefs.dirdiff_time_resolution_ns
+        mtime2 = Decimal(other.time).scaleb(9).quantize(1) // prefs.dirdiff_time_resolution_ns
+
+        return mtime1 == mtime2
+
 
 CacheResult = namedtuple('CacheResult', 'stats result')
 
@@ -73,7 +84,7 @@ def all_same(lst):
     return not lst or lst.count(lst[0]) == len(lst)
 
 
-def _files_same(files, regexes):
+def _files_same(files, regexes, prefs):
     """Determine whether a list of files are the same.
 
     Possible results are:
@@ -104,6 +115,13 @@ def _files_same(files, regexes):
     if not regexes and not all_same([s.size for s in stats]):
         return Different
 
+    # Compare files superficially if the options tells us to
+    if prefs.dirdiff_shallow_comparison:
+        if all(s.shallow_equal(stats[0], prefs) for s in stats):
+            return DodgySame
+        else:
+            return Different
+
     # Check the cache before doing the expensive comparison
     cache = _cache.get((files, regexes))
     if cache and cache.stats == stats:
@@ -378,6 +396,10 @@ class DirDiff(melddoc.MeldDoc, gnomeglade.Component):
     def on_preference_changed(self, key, value):
         if key == "dirdiff_columns":
             self.update_treeview_columns(value)
+        elif key == "dirdiff_shallow_comparison":
+            self.refresh()
+        elif key == "dirdiff_time_resolution_ns":
+            self.refresh()
 
     def update_treeview_columns(self, columns):
         """Update the visibility and order of columns"""
@@ -1067,7 +1089,7 @@ class DirDiff(melddoc.MeldDoc, gnomeglade.Component):
             is_present = [ os.path.exists( f ) for f in curfiles ]
             all_present = 0 not in is_present
             if all_present:
-                if _files_same(curfiles, regexes) in (Same, SameFiltered):
+                if _files_same(curfiles, regexes, self.prefs) in (Same, SameFiltered):
                     state = tree.STATE_NORMAL
                 else:
                     state = tree.STATE_MODIFIED
@@ -1099,7 +1121,7 @@ class DirDiff(melddoc.MeldDoc, gnomeglade.Component):
             newest_index = -1 # all same
         all_present = 0 not in mod_times
         if all_present:
-            all_same = _files_same(files, regexes)
+            all_same = _files_same(files, regexes, self.prefs)
             all_present_same = all_same
         else:
             lof = []
@@ -1107,7 +1129,7 @@ class DirDiff(melddoc.MeldDoc, gnomeglade.Component):
                 if mod_times[j]:
                     lof.append( files[j] )
             all_same = Different
-            all_present_same = _files_same(lof, regexes)
+            all_present_same = _files_same(lof, regexes, self.prefs)
         different = 1
         one_isdir = [None for i in range(self.model.ntree)]
         for j in range(self.model.ntree):
diff --git a/meld/preferences.py b/meld/preferences.py
index e764552..28110cf 100644
--- a/meld/preferences.py
+++ b/meld/preferences.py
@@ -32,6 +32,12 @@ from .util import prefs
 from .util.sourceviewer import srcviewer
 
 
+TIMESTAMP_RESOLUTION_PRESETS = [('1ns (ext4)', 1),
+                                ('100ns (NTFS)', 100),
+                                ('1s (ext2/ext3)', 1000000000),
+                                ('2s (VFAT)', 2000000000)]
+
+
 class FilterList(listwidget.ListWidget):
 
     def __init__(self, prefs, key, filter_type):
@@ -192,6 +198,22 @@ class PreferencesDialog(gnomeglade.Component):
         columnlist = ColumnList(self.prefs, "dirdiff_columns")
         self.column_list_vbox.pack_start(columnlist.widget)
 
+        self.checkbutton_shallow_compare.set_active(self.prefs.dirdiff_shallow_comparison)
+
+        self.combo_timestamp.lock = True
+        model = gtk.ListStore(str, int)
+        active_idx = 0
+        for i, entry in enumerate(TIMESTAMP_RESOLUTION_PRESETS):
+            model.append(entry)
+            if entry[1] == self.prefs.dirdiff_time_resolution_ns:
+                active_idx = i
+        self.combo_timestamp.set_model(model)
+        cell = gtk.CellRendererText()
+        self.combo_timestamp.pack_start(cell, False)
+        self.combo_timestamp.add_attribute(cell, 'text', 0)
+        self.combo_timestamp.set_active(active_idx)
+        self.combo_timestamp.lock = False
+
         self.widget.show()
 
     def on_fontpicker_font_set(self, picker):
@@ -249,6 +271,13 @@ class PreferencesDialog(gnomeglade.Component):
         # Called on "activate" and "focus-out-event"
         self.prefs.text_codecs = entry.props.text
 
+    def on_checkbutton_shallow_compare_toggled(self, check):
+        self.prefs.dirdiff_shallow_comparison = check.get_active()
+    
+    def on_combo_timestamp_changed(self, combo):
+        if not combo.lock:
+            self.prefs.dirdiff_time_resolution_ns = combo.get_model()[combo.get_active_iter()][1]
+    
     def on_response(self, dialog, response_id):
         self.widget.destroy()
 
@@ -306,6 +335,8 @@ class MeldPreferences(prefs.Preferences):
         "dirdiff_columns": prefs.Value(prefs.LIST,
                                          ["size 1", "modification time 1",
                                           "permissions 0"]),
+        "dirdiff_shallow_comparison" : prefs.Value(prefs.BOOL, False),
+        "dirdiff_time_resolution_ns" : prefs.Value(prefs.INT, 100),
     }
 
     def __init__(self):


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