1
0
mirror of https://github.com/arsenetar/dupeguru.git synced 2026-01-22 14:41:39 +00:00

Began the transition to a HSOutline based result outline. There's still a lot of glitches, the most glaring one being the lack of support for multiple selection.

This commit is contained in:
Virgil Dupras
2010-02-11 17:52:18 +01:00
parent 87351b5920
commit 42559f13d8
14 changed files with 340 additions and 217 deletions

View File

@@ -104,6 +104,11 @@ class DupeGuru(RegistrableApplication, Broadcaster):
path = Path(str_path)
return fs.get_file(path, self.directories.fileclasses)
def _job_completed(self, jobid):
# Must be called by subclasses when they detect that an async job is completed.
if jobid in (JOB_SCAN, JOB_LOAD, JOB_MOVE, JOB_DELETE):
self.notify('results_changed')
@staticmethod
def _open_path(path):
raise NotImplementedError()
@@ -233,6 +238,7 @@ class DupeGuru(RegistrableApplication, Broadcaster):
if g not in changed_groups:
self.results.make_ref(dupe)
changed_groups.add(g)
self.notify('results_changed')
def open_selected(self):
if self.selected_dupes:
@@ -283,6 +289,11 @@ class DupeGuru(RegistrableApplication, Broadcaster):
self.results.groups = []
self._start_job(JOB_SCAN, do)
def toggle_selected_mark_state(self):
for dupe in self.selected_dupes:
self.results.mark_toggle(dupe)
self.notify('results_changed')
def without_ref(self, dupes):
return [dupe for dupe in dupes if self.results.get_group_of_duplicate(dupe).ref is not dupe]

View File

@@ -162,57 +162,3 @@ class DupeGuru(app.DupeGuru):
def sort_groups(self,key,asc):
self.results.sort_groups(key,asc)
def ToggleSelectedMarkState(self):
for dupe in self.selected_dupes:
self.results.mark_toggle(dupe)
#---Data
def GetOutlineViewMaxLevel(self, tag):
if tag == 0:
return 2
elif tag == 2:
return 1
def GetOutlineViewChildCounts(self, tag, node_path):
if self.progress._job_running:
return []
if tag == 0: #Normal results
assert not node_path # no other value is possible
return [len(g.dupes) for g in self.results.groups]
else: #Power Marker
assert not node_path # no other value is possible
return [0 for d in self.results.dupes]
def GetOutlineViewValues(self, tag, node_path):
if self.progress._job_running:
return
if not node_path:
return
if tag in (0,2): #Normal results / Power Marker
if tag == 0:
g, d = self.GetObjects(node_path)
if (d is None) and (g is not None):
d = g.ref
else:
d = self.results.dupes[node_path[0]]
g = self.results.get_group_of_duplicate(d)
result = self._get_display_info(d, g, self.display_delta_values)
return result
def GetOutlineViewMarked(self, tag, node_path):
# 0=unmarked 1=marked 2=unmarkable
if self.progress._job_running:
return
if not node_path:
return 2
if tag == 0: #Normal results
g, d = self.GetObjects(node_path)
else: #Power Marker
d = self.results.dupes[node_path[0]]
if (d is None) or (not self.results.is_markable(d)):
return 2
elif self.results.is_marked(d):
return 1
else:
return 0

View File

@@ -13,6 +13,7 @@ from hsutil.cocoa.inter import signature, PyOutline, PyGUIObject, PyRegistrable
from .gui.details_panel import DetailsPanel
from .gui.directory_tree import DirectoryTree
from .gui.result_tree import ResultTree
# Fix py2app's problems on relative imports
from core import app, app_cocoa, data, directories, engine, export, ignore, results, fs, scanner
@@ -55,7 +56,7 @@ class PyDupeGuruBase(PyRegistrable):
self.py.PurgeIgnoreList()
def toggleSelectedMark(self):
self.py.ToggleSelectedMarkState()
self.py.toggle_selected_mark_state()
def saveIgnoreList(self):
self.py.save_ignore_list()
@@ -126,21 +127,6 @@ class PyDupeGuruBase(PyRegistrable):
def getOperationalErrorCount(self):
return self.py.last_op_error_count
#---Data
@signature('i@:i')
def getOutlineViewMaxLevel_(self, tag):
return self.py.GetOutlineViewMaxLevel(tag)
@signature('@@:i@')
def getOutlineView_childCountsForPath_(self, tag, node_path):
return self.py.GetOutlineViewChildCounts(tag, node_path)
def getOutlineView_valuesForIndexes_(self, tag, node_path):
return self.py.GetOutlineViewValues(tag, node_path)
def getOutlineView_markedAtIndexes_(self, tag, node_path):
return self.py.GetOutlineViewMarked(tag, node_path)
#---Properties
def setMixFileKind_(self, mix_file_kind):
self.py.scanner.mix_file_kind = mix_file_kind
@@ -164,6 +150,9 @@ class PyDupeGuruBase(PyRegistrable):
def cancelJob(self):
self.py.progress.job_cancelled = True
def jobCompleted_(self, jobid):
self.py._job_completed(jobid)
class PyDetailsPanel(PyGUIObject):
py_class = DetailsPanel
@@ -182,3 +171,25 @@ class PyDirectoryOutline(PyOutline):
def addDirectory_(self, path):
self.py.add_directory(path)
class PyResultOutline(PyOutline):
py_class = ResultTree
@signature('v@:c')
def setPowerMarkerMode_(self, value):
self.py.power_marker = value
@signature('@@:@i')
def valueForPath_column_(self, path, column):
return self.py.get_node_value(path, column)
@signature('c@:@')
def renameSelected_(self, newname):
return self.py.app.RenameSelected(newname)
def sortBy_ascending_(self, key, asc):
self.py.sort(key, asc)
def markSelected(self):
self.py.app.toggle_selected_mark_state()

View File

@@ -21,3 +21,6 @@ class GUIObject(Listener):
def dupes_selected(self):
pass
def results_changed(self):
pass

98
core/gui/result_tree.py Normal file
View File

@@ -0,0 +1,98 @@
# -*- coding: utf-8 -*-
# Created By: Virgil Dupras
# Created On: 2010-02-11
# Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
#
# This software is licensed under the "HS" License as described in the "LICENSE" file,
# which should be included with this package. The terms are also available at
# http://www.hardcoded.net/licenses/hs_license
from hsgui.tree import Tree, Node
from .base import GUIObject
class DupeNode(Node):
def __init__(self, app, group, dupe):
Node.__init__(self, '')
self._app = app
self._group = group
self._dupe = dupe
self.data = app._get_display_info(dupe, group, False)
self.data_delta = app._get_display_info(dupe, group, True)
@property
def markable(self):
return self._app.results.is_markable(self._dupe)
@property
def marked(self):
return self._app.results.is_marked(self._dupe)
class ResultTree(GUIObject, Tree):
def __init__(self, view, app):
GUIObject.__init__(self, view, app)
Tree.__init__(self)
self._power_marker = False
self.connect()
self._refresh()
self.view.refresh()
def _refresh(self):
self.clear()
if not self.power_marker:
for group in self.app.results.groups:
group_node = DupeNode(self.app, group, group.ref)
self.append(group_node)
for dupe in group.dupes:
group_node.append(DupeNode(self.app, group, dupe))
else:
for dupe in self.app.results.dupes:
group = self.app.results.get_group_of_duplicate(dupe)
self.append(DupeNode(self.app, group, dupe))
if self.app.selected_dupes:
to_find = self.app.selected_dupes[0]
node = self.find(lambda n: n is not self and n._dupe is to_find)
self.selected = node
def get_node_value(self, path, column):
try:
node = self.get_node(path)
except IndexError:
return '---'
if self.app.display_delta_values:
return node.data_delta[column]
else:
return node.data[column]
def sort(self, key, asc):
if self.power_marker:
self.app.sort_dupes(key, asc)
else:
self.app.sort_groups(key, asc)
@property
def power_marker(self):
return self._power_marker
@power_marker.setter
def power_marker(self, value):
if value == self._power_marker:
return
self._power_marker = value
self._refresh()
self.view.refresh()
@Tree.selected.setter
def selected(self, node):
self._selected = node
if node is None:
self.app._select_dupes([])
else:
self.app._select_dupes([node._dupe])
#--- Event Handlers
def results_changed(self):
self._refresh()
self.view.refresh()

View File

@@ -243,16 +243,16 @@ class TCDupeGuru(TestCase):
def test_toggleSelectedMark(self):
app = self.app
objects = self.objects
app.ToggleSelectedMarkState()
self.assertEqual(0,app.results.mark_count)
app.toggle_selected_mark_state()
eq_(app.results.mark_count, 0)
app.SelectPowerMarkerNodePaths(r2np([0,2]))
app.ToggleSelectedMarkState()
self.assertEqual(2,app.results.mark_count)
self.assert_(not app.results.is_marked(objects[0]))
self.assert_(app.results.is_marked(objects[1]))
self.assert_(not app.results.is_marked(objects[2]))
self.assert_(not app.results.is_marked(objects[3]))
self.assert_(app.results.is_marked(objects[4]))
app.toggle_selected_mark_state()
eq_(app.results.mark_count, 2)
assert not app.results.is_marked(objects[0])
assert app.results.is_marked(objects[1])
assert not app.results.is_marked(objects[2])
assert not app.results.is_marked(objects[3])
assert app.results.is_marked(objects[4])
def test_refreshDetailsWithSelected(self):
self.app.SelectPowerMarkerNodePaths(r2np([0,2]))