Updated hscommon to its tip.

Because the latest changes in hscommon include the introduction of a base GUIObject which significantly changes view setting mechanisms, significant adjustments had to be made in dupeGuru.
This commit is contained in:
Virgil Dupras 2012-03-13 14:27:08 -04:00
parent 878c744c21
commit 49a7043b4d
11 changed files with 56 additions and 60 deletions

View File

@ -37,7 +37,7 @@ http://www.hardcoded.net/licenses/bsd_license
[_recentResults setDelegate:self];
_resultWindow = [self createResultWindow];
_directoryPanel = [self createDirectoryPanel];
_detailsPanel = nil; // Lazily loaded
_detailsPanel = [self createDetailsPanel];
_aboutBox = nil; // Lazily loaded
_preferencesPanel = nil; // Lazily loaded
[[[self directoryPanel] window] makeKeyAndOrderFront:self];
@ -83,8 +83,6 @@ http://www.hardcoded.net/licenses/bsd_license
- (DetailsPanel *)detailsPanel
{
if (!_detailsPanel)
_detailsPanel = [self createDetailsPanel];
return _detailsPanel;
}

View File

@ -9,10 +9,9 @@
from hscommon.notify import Listener
from hscommon.gui.base import NoopGUI
class GUIObject(Listener):
class DupeGuruGUIObject(Listener):
def __init__(self, app):
Listener.__init__(self, app)
self.view = NoopGUI()
self.app = app
def directories_changed(self):

View File

@ -6,15 +6,16 @@
# which should be included with this package. The terms are also available at
# http://www.hardcoded.net/licenses/bsd_license
from .base import GUIObject
from hscommon.gui.base import GUIObject
from .base import DupeGuruGUIObject
class DetailsPanel(GUIObject):
class DetailsPanel(GUIObject, DupeGuruGUIObject):
def __init__(self, app):
GUIObject.__init__(self, app)
GUIObject.__init__(self)
DupeGuruGUIObject.__init__(self, app)
self._table = []
def connect(self):
GUIObject.connect(self)
def _view_updated(self):
self._refresh()
self.view.refresh()

View File

@ -9,7 +9,7 @@
from hscommon.gui.tree import Tree, Node
from ..directories import DirectoryState
from .base import GUIObject
from .base import DupeGuruGUIObject
STATE_ORDER = [DirectoryState.Normal, DirectoryState.Reference, DirectoryState.Excluded]
@ -54,17 +54,16 @@ class DirectoryNode(Node):
self._tree.update_all_states()
class DirectoryTree(GUIObject, Tree):
class DirectoryTree(Tree, DupeGuruGUIObject):
#--- model -> view calls:
# refresh()
# refresh_states() # when only states label need to be refreshed
#
def __init__(self, app):
GUIObject.__init__(self, app)
Tree.__init__(self)
DupeGuruGUIObject.__init__(self, app)
def connect(self):
GUIObject.connect(self)
def _view_updated(self):
self._refresh()
self.view.refresh()

View File

@ -6,6 +6,7 @@
# which should be included with this package. The terms are also available at
# http://www.hardcoded.net/licenses/bsd_license
from hscommon.gui.base import GUIObject
from hscommon.gui.selectable_list import GUISelectableList
class CriterionCategoryList(GUISelectableList):
@ -39,8 +40,9 @@ class PrioritizationList(GUISelectableList):
del prilist[i]
self._refresh_contents()
class PrioritizeDialog:
class PrioritizeDialog(GUIObject):
def __init__(self, app):
GUIObject.__init__(self)
self.app = app
self.categories = [cat(app.results) for cat in app._prioritization_categories()]
self.category_list = CriterionCategoryList(self)
@ -48,6 +50,9 @@ class PrioritizeDialog:
self.criteria_list = GUISelectableList()
self.prioritizations = []
self.prioritization_list = PrioritizationList(self)
#--- Override
def _view_updated(self):
self.category_list.select(0)
#--- Private

View File

@ -21,7 +21,6 @@ class ProblemTable(GUITable):
def __init__(self, problem_dialog):
GUITable.__init__(self)
self.columns = Columns(self)
self.view = None
self.dialog = problem_dialog
#--- Override

View File

@ -11,7 +11,7 @@ from operator import attrgetter
from hscommon.gui.table import GUITable, Row
from hscommon.gui.column import Columns
from .base import GUIObject
from .base import DupeGuruGUIObject
class DupeRow(Row):
def __init__(self, table, group, dupe):
@ -51,20 +51,18 @@ class DupeRow(Row):
self._app.mark_dupe(self._dupe, value)
class ResultTable(GUIObject, GUITable):
class ResultTable(GUITable, DupeGuruGUIObject):
def __init__(self, app):
GUIObject.__init__(self, app)
GUITable.__init__(self)
DupeGuruGUIObject.__init__(self, app)
self.columns = Columns(self, prefaccess=app, savename='ResultTable')
self._power_marker = False
self._delta_values = False
self._sort_descriptors = ('name', True)
#--- Override
def connect(self):
GUIObject.connect(self)
def _view_updated(self):
self._refresh_with_view()
self.columns.restore_columns()
def _restore_selection(self, previous_selection):
if self.app.selected_dupes:

View File

@ -6,11 +6,10 @@
# which should be included with this package. The terms are also available at
# http://www.hardcoded.net/licenses/bsd_license
from .base import GUIObject
from .base import DupeGuruGUIObject
class StatsLabel(GUIObject):
def connect(self):
GUIObject.connect(self)
class StatsLabel(DupeGuruGUIObject):
def _view_updated(self):
self.view.refresh()
@property

View File

@ -18,7 +18,7 @@ import hscommon.util
from hscommon.testutil import CallLogger, eq_, log_calls
from jobprogress.job import Job
from .base import DupeGuru
from .base import DupeGuru, TestApp
from .results_test import GetTestGroups
from .. import app, fs, engine
from ..gui.details_panel import DetailsPanel
@ -32,7 +32,7 @@ def add_fake_files_to_directories(directories, files):
class TestCaseDupeGuru:
def test_apply_filter_calls_results_apply_filter(self, monkeypatch):
dgapp = DupeGuru()
dgapp = TestApp().app
monkeypatch.setattr(dgapp.results, 'apply_filter', log_calls(dgapp.results.apply_filter))
dgapp.apply_filter('foo')
eq_(2, len(dgapp.results.apply_filter.calls))
@ -42,7 +42,7 @@ class TestCaseDupeGuru:
eq_('foo', call['filter_str'])
def test_apply_filter_escapes_regexp(self, monkeypatch):
dgapp = DupeGuru()
dgapp = TestApp().app
monkeypatch.setattr(dgapp.results, 'apply_filter', log_calls(dgapp.results.apply_filter))
dgapp.apply_filter('()[]\\.|+?^abc')
call = dgapp.results.apply_filter.calls[1]
@ -65,7 +65,7 @@ class TestCaseDupeGuru:
# XXX This monkeypatch is temporary. will be fixed in a better monkeypatcher.
monkeypatch.setattr(app, 'smart_copy', hscommon.conflict.smart_copy)
monkeypatch.setattr(os, 'makedirs', lambda path: None) # We don't want the test to create that fake directory
dgapp = DupeGuru()
dgapp = TestApp().app
dgapp.directories.add_path(p)
[f] = dgapp.directories.get_files()
dgapp.copy_or_move(f, True, 'some_destination', 0)
@ -79,7 +79,7 @@ class TestCaseDupeGuru:
sourcepath = tmppath + 'source'
io.mkdir(sourcepath)
io.open(sourcepath + 'myfile', 'w')
app = DupeGuru()
app = TestApp().app
app.directories.add_path(tmppath)
[myfile] = app.directories.get_files()
monkeypatch.setattr(app, 'clean_empty_dirs', log_calls(lambda path: None))
@ -95,7 +95,7 @@ class TestCaseDupeGuru:
# At some point, any() was used in a wrong way that made Scan() wrongly return 1
app = DupeGuru()
app = TestApp().app
f1, f2 = [FakeFile('foo') for i in range(2)]
f1.is_ref, f2.is_ref = (False, False)
assert not (bool(f1) and bool(f2))
@ -109,7 +109,7 @@ class TestCaseDupeGuru:
tmppath = Path(str(tmpdir))
io.open(tmppath + 'myfile', 'w').write('foo')
os.link(str(tmppath + 'myfile'), str(tmppath + 'hardlink'))
app = DupeGuru()
app = TestApp().app
app.directories.add_path(tmppath)
app.scanner.scan_type = ScanType.Contents
app.options['ignore_hardlink_matches'] = True
@ -120,7 +120,7 @@ class TestCaseDupeGuru:
# Issue #140
# It's possible that rename operation has its selected row swept off from under it, thus
# making the selected row None. Don't crash when it happens.
dgapp = DupeGuru()
dgapp = TestApp().app
# selected_row is None because there's no result.
assert not dgapp.result_table.rename_selected('foo') # no crash
@ -130,7 +130,7 @@ class TestCaseDupeGuru_clean_empty_dirs:
monkeypatch.setattr(hscommon.util, 'delete_if_empty', log_calls(lambda path, files_to_delete=[]: None))
# XXX This monkeypatch is temporary. will be fixed in a better monkeypatcher.
monkeypatch.setattr(app, 'delete_if_empty', hscommon.util.delete_if_empty)
self.app = DupeGuru()
self.app = TestApp().app
def test_option_off(self, do_setup):
self.app.clean_empty_dirs(Path('/foo/bar'))
@ -164,20 +164,14 @@ class TestCaseDupeGuru_clean_empty_dirs:
class TestCaseDupeGuruWithResults:
def pytest_funcarg__do_setup(self, request):
# XXX eventually, convert this to TestApp-based tests
self.app = DupeGuru()
app = TestApp()
self.app = app.app
self.objects,self.matches,self.groups = GetTestGroups()
self.app.results.groups = self.groups
self.dpanel = self.app.details_panel
self.dpanel.view = CallLogger()
self.dtree = self.app.directory_tree
self.dtree.view = CallLogger()
self.rtable_gui = CallLogger()
self.rtable = self.app.result_table
self.rtable.view = self.rtable_gui
self.dpanel.connect()
self.dtree.connect()
self.rtable.connect()
self.dpanel = app.dpanel
self.dtree = app.dtree
self.rtable = app.rtable
self.rtable.refresh()
tmpdir = request.getfuncargvalue('tmpdir')
tmppath = Path(str(tmpdir))
io.mkdir(tmppath + 'foo')
@ -422,16 +416,14 @@ class TestCaseDupeGuru_renameSelected:
groups = engine.get_groups(matches)
g = groups[0]
g.prioritize(lambda x:x.name)
app = DupeGuru()
app.results.groups = groups
self.app = app
app = TestApp()
app.app.results.groups = groups
self.app = app.app
self.rtable = app.rtable
self.rtable.refresh()
self.groups = groups
self.p = p
self.files = files
self.rtable_gui = CallLogger()
self.rtable = self.app.result_table
self.rtable.view = self.rtable_gui
self.rtable.connect()
def test_simple(self, do_setup):
app = self.app
@ -477,10 +469,9 @@ class TestAppWithDirectoriesInTree:
io.mkdir(p + 'sub1')
io.mkdir(p + 'sub2')
io.mkdir(p + 'sub3')
self.app = DupeGuru()
self.dtree = self.app.directory_tree
self.dtree.view = CallLogger()
self.dtree.connect()
app = TestApp()
self.app = app.app
self.dtree = app.dtree
self.dtree.add_directory(p)
self.dtree.view.clear_calls()

View File

@ -36,6 +36,9 @@ class DupeGuruView:
def set_default(self, key_name, value):
pass
def show_message(self, msg):
pass
def ask_yes_no(self, prompt):
return True # always answer yes
@ -144,7 +147,11 @@ class TestApp(TestAppBase):
self.rtable = link_gui(self.app.result_table)
self.dtree = link_gui(self.app.directory_tree)
self.dpanel = link_gui(self.app.details_panel)
self.slabel = link_gui(self.app.stats_label)
self.pdialog = PrioritizeDialog(self.app)
link_gui(self.pdialog.category_list)
link_gui(self.pdialog.criteria_list)
link_gui(self.pdialog.prioritization_list)
#--- Helpers
def select_pri_criterion(self, name):

View File

@ -16,13 +16,13 @@ class DetailsDialog(QDialog):
QDialog.__init__(self, parent, Qt.Tool)
self.app = app
self.model = app.model.details_panel
self.model.view = self
self._setupUi()
if self.app.prefs.detailsWindowRect is not None:
self.setGeometry(self.app.prefs.detailsWindowRect)
self.tableModel = DetailsModel(self.model)
# tableView is defined in subclasses
self.tableView.setModel(self.tableModel)
self.model.view = self
self.app.willSavePrefs.connect(self.appWillSavePrefs)