diff --git a/core/gui/prioritize_dialog.py b/core/gui/prioritize_dialog.py index e4704e83..d459396d 100644 --- a/core/gui/prioritize_dialog.py +++ b/core/gui/prioritize_dialog.py @@ -8,7 +8,7 @@ from hscommon.gui.selectable_list import SelectableList -from ..prioritize import KindCategory +from ..prioritize import all_categories class CriterionCategoryList(SelectableList): def __init__(self, dialog): @@ -22,29 +22,27 @@ class CriterionCategoryList(SelectableList): class PrioritizeDialog: def __init__(self, view, app): self.app = app - self.categories = [KindCategory(app.results)] + self.categories = [cat(app.results) for cat in all_categories()] self.category_list = CriterionCategoryList(self) self.criteria = [] self.criteria_list = SelectableList() self.prioritizations = [] + self.prioritization_list = SelectableList() #--- Private def _sort_key(self, dupe): - # Our sort key consists of a tuple of inverted bool values represented as ints. When a dupe - # fits a criteria, we want it at the top of the listm and thus we'll give it the value 0. - # When the dupe doesn't fit a criteria, we ant it at the bottom, and we give the value 1. - result = (crit.test_dupe(dupe) for crit in self.prioritizations) - return tuple((0 if value else 1) for value in result) + return tuple(crit.sort_key(dupe) for crit in self.prioritizations) #--- Public def select_category(self, category): self.criteria = category.criteria_list() - self.criteria_list[:] = [c.value for c in self.criteria] + self.criteria_list[:] = [c.display_value for c in self.criteria] def add_selected(self): # Add selected criteria in criteria_list to prioritization_list. crit = self.criteria[self.criteria_list.selected_index] self.prioritizations.append(crit) + self.prioritization_list[:] = [crit.display for crit in self.prioritizations] def perform_reprioritization(self): self.app.reprioritize_groups(self._sort_key) diff --git a/core/prioritize.py b/core/prioritize.py index 0f973121..66e2e295 100644 --- a/core/prioritize.py +++ b/core/prioritize.py @@ -15,30 +15,76 @@ class CriterionCategory: self.results = results #--- Virtual - def _extract_value(self, dupe): + def extract_value(self, dupe): raise NotImplementedError() + def format_value(self, value): + return value + #--- Public + def sort_key(self, dupe, crit_value): + # Use this sort key when the order in the list depends on whether or not the dupe meets the + # criteria. If it does, we return 0 (top of the list), if it doesn't, we return 1. + if self.extract_value(dupe) == crit_value: + return 0 + else: + return 1 + def criteria_list(self): dupes = flatten(g[:] for g in self.results.groups) - values = dedupe(self._extract_value(d) for d in dupes) + values = dedupe(self.extract_value(d) for d in dupes) return [Criterion(self, value) for value in values] class Criterion: def __init__(self, category, value): self.category = category self.value = value + self.display_value = category.format_value(value) - def test_dupe(self, dupe): - return self.category._extract_value(dupe) == self.value + def sort_key(self, dupe): + return self.category.sort_key(dupe, self.value) @property def display(self): - return "{} ({})".format(self.category, self.value) + return "{} ({})".format(self.category.NAME, self.value) class KindCategory(CriterionCategory): NAME = "Kind" - def _extract_value(self, dupe): + def extract_value(self, dupe): return dupe.extension + +class FolderCategory(CriterionCategory): + NAME = "Folder" + + def extract_value(self, dupe): + return dupe.folder_path + + def format_value(self, value): + return str(value) + +class NumericalCategory(CriterionCategory): + HIGHEST = 0 + LOWEST = 1 + + def format_value(self, value): + return "Highest" if value == self.HIGHEST else "Lowest" + + def sort_key(self, dupe, crit_value): + value = self.extract_value(dupe) + if crit_value == self.HIGHEST: # we want highest values on top + value *= -1 + return value + + def criteria_list(self): + return [Criterion(self, self.HIGHEST), Criterion(self, self.LOWEST)] + +class SizeCategory(NumericalCategory): + NAME = "Size" + + def extract_value(self, dupe): + return dupe.size + +def all_categories(): + return [KindCategory, FolderCategory, SizeCategory] diff --git a/core/tests/base.py b/core/tests/base.py index 87aaeec8..593b173f 100644 --- a/core/tests/base.py +++ b/core/tests/base.py @@ -42,8 +42,8 @@ class NamedObject: def __init__(self, name="foobar", with_words=False, size=1, folder=None): self.name = name if folder is None: - folder = Path('basepath') - self._folder = folder + folder = 'basepath' + self._folder = Path(folder) self.size = size self.md5partial = name self.md5 = name diff --git a/core/tests/prioritize_test.py b/core/tests/prioritize_test.py index a0e8f39d..ae8cc94e 100644 --- a/core/tests/prioritize_test.py +++ b/core/tests/prioritize_test.py @@ -32,7 +32,9 @@ def app_with_dupes(dupes): def app_normal_results(): # Just some results, with different extensions and size, for good measure. dupes = [ - [no('foo1.ext1', size=1), no('foo2.ext2', size=2)], + [ + no('foo1.ext1', size=1, folder='folder1'), + no('foo2.ext2', size=2, folder='folder2')], ] return app_with_dupes(dupes) @@ -43,7 +45,7 @@ def test_kind_subcrit(app): eq_(app.pdialog.criteria_list[:], ['ext1', 'ext2']) @with_app(app_normal_results) -def test_perform_reprioritization(app): +def test_kind_reprioritization(app): # Just a simple test of the system as a whole. # select a criterion, and perform re-prioritization and see if it worked. app.select_pri_criterion("Kind") @@ -51,3 +53,44 @@ def test_perform_reprioritization(app): app.pdialog.add_selected() app.pdialog.perform_reprioritization() eq_(app.rtable[0].data[0], 'foo2.ext2') + +@with_app(app_normal_results) +def test_folder_subcrit(app): + app.select_pri_criterion("Folder") + eq_(app.pdialog.criteria_list[:], ['folder1', 'folder2']) + +@with_app(app_normal_results) +def test_folder_reprioritization(app): + app.select_pri_criterion("Folder") + app.pdialog.criteria_list.select([1]) # folder2 + app.pdialog.add_selected() + app.pdialog.perform_reprioritization() + eq_(app.rtable[0].data[0], 'foo2.ext2') + +@with_app(app_normal_results) +def test_prilist_display(app): + # The prioritization list displays selected criteria correctly. + app.select_pri_criterion("Kind") + app.pdialog.criteria_list.select([1]) # ext2 + app.pdialog.add_selected() + app.select_pri_criterion("Folder") + app.pdialog.criteria_list.select([1]) # folder2 + app.pdialog.add_selected() + expected = [ + "Kind (ext2)", + "Folder (folder2)", + ] + eq_(app.pdialog.prioritization_list[:], expected) + +@with_app(app_normal_results) +def test_size_subcrit(app): + app.select_pri_criterion("Size") + eq_(app.pdialog.criteria_list[:], ['Highest', 'Lowest']) + +@with_app(app_normal_results) +def test_size_reprioritization(app): + app.select_pri_criterion("Size") + app.pdialog.criteria_list.select([0]) # highest + app.pdialog.add_selected() + app.pdialog.perform_reprioritization() + eq_(app.rtable[0].data[0], 'foo2.ext2')