2010-02-11 16:52:18 +00:00
|
|
|
# Created By: Virgil Dupras
|
|
|
|
# Created On: 2010-02-11
|
2013-04-28 14:35:51 +00:00
|
|
|
# Copyright 2013 Hardcoded Software (http://www.hardcoded.net)
|
2010-02-11 16:52:18 +00:00
|
|
|
#
|
2010-09-30 10:17:41 +00:00
|
|
|
# This software is licensed under the "BSD" License as described in the "LICENSE" file,
|
2010-02-11 16:52:18 +00:00
|
|
|
# which should be included with this package. The terms are also available at
|
2010-09-30 10:17:41 +00:00
|
|
|
# http://www.hardcoded.net/licenses/bsd_license
|
2010-02-11 16:52:18 +00:00
|
|
|
|
2010-02-12 10:07:33 +00:00
|
|
|
from operator import attrgetter
|
|
|
|
|
2010-11-24 15:12:10 +00:00
|
|
|
from hscommon.gui.table import GUITable, Row
|
2011-11-26 15:55:14 +00:00
|
|
|
from hscommon.gui.column import Columns
|
2010-02-11 16:52:18 +00:00
|
|
|
|
2012-03-13 18:27:08 +00:00
|
|
|
from .base import DupeGuruGUIObject
|
2010-02-11 16:52:18 +00:00
|
|
|
|
2010-09-24 13:48:59 +00:00
|
|
|
class DupeRow(Row):
|
|
|
|
def __init__(self, table, group, dupe):
|
|
|
|
Row.__init__(self, table)
|
|
|
|
self._app = table.app
|
2010-02-11 16:52:18 +00:00
|
|
|
self._group = group
|
|
|
|
self._dupe = dupe
|
2010-02-12 10:21:39 +00:00
|
|
|
self._data = None
|
|
|
|
self._data_delta = None
|
2013-07-28 21:45:23 +00:00
|
|
|
self._delta_columns = None
|
|
|
|
|
|
|
|
def is_cell_delta(self, column_name):
|
|
|
|
"""Returns whether a cell is in delta mode (orange color).
|
|
|
|
|
|
|
|
If the result table is in delta mode, returns True if the column is one of the "delta
|
|
|
|
columns", that is, one of the columns that display a a differential value rather than an
|
|
|
|
absolute value.
|
|
|
|
|
|
|
|
If not, returns True if the dupe's value is different from its ref value.
|
|
|
|
"""
|
|
|
|
if not self.table.delta_values:
|
|
|
|
return False
|
|
|
|
if self.isref:
|
|
|
|
return False
|
|
|
|
if self._delta_columns is None:
|
|
|
|
# table.DELTA_COLUMNS are always "delta"
|
|
|
|
self._delta_columns = self.table.DELTA_COLUMNS.copy()
|
|
|
|
dupe_info = self.data
|
|
|
|
ref_info = self._group.ref.get_display_info(group=self._group, delta=False)
|
|
|
|
for key, value in dupe_info.items():
|
2013-11-23 20:31:20 +00:00
|
|
|
if (key not in self._delta_columns) and (ref_info[key].lower() != value.lower()):
|
2013-07-28 21:45:23 +00:00
|
|
|
self._delta_columns.add(key)
|
|
|
|
return column_name in self._delta_columns
|
2010-02-12 10:21:39 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
def data(self):
|
|
|
|
if self._data is None:
|
2011-09-21 14:26:58 +00:00
|
|
|
self._data = self._app.get_display_info(self._dupe, self._group, False)
|
2010-02-12 10:21:39 +00:00
|
|
|
return self._data
|
|
|
|
|
|
|
|
@property
|
|
|
|
def data_delta(self):
|
|
|
|
if self._data_delta is None:
|
2011-09-21 14:26:58 +00:00
|
|
|
self._data_delta = self._app.get_display_info(self._dupe, self._group, True)
|
2010-02-12 10:21:39 +00:00
|
|
|
return self._data_delta
|
2010-02-11 16:52:18 +00:00
|
|
|
|
2010-09-24 13:48:59 +00:00
|
|
|
@property
|
|
|
|
def isref(self):
|
|
|
|
return self._dupe is self._group.ref
|
|
|
|
|
2010-02-11 16:52:18 +00:00
|
|
|
@property
|
|
|
|
def markable(self):
|
|
|
|
return self._app.results.is_markable(self._dupe)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def marked(self):
|
|
|
|
return self._app.results.is_marked(self._dupe)
|
|
|
|
|
2010-02-12 11:30:00 +00:00
|
|
|
@marked.setter
|
|
|
|
def marked(self, value):
|
|
|
|
self._app.mark_dupe(self._dupe, value)
|
|
|
|
|
2010-02-11 16:52:18 +00:00
|
|
|
|
2012-03-13 18:27:08 +00:00
|
|
|
class ResultTable(GUITable, DupeGuruGUIObject):
|
2011-11-27 17:47:00 +00:00
|
|
|
def __init__(self, app):
|
2010-09-24 13:48:59 +00:00
|
|
|
GUITable.__init__(self)
|
2012-03-13 18:27:08 +00:00
|
|
|
DupeGuruGUIObject.__init__(self, app)
|
2011-11-26 15:55:14 +00:00
|
|
|
self.columns = Columns(self, prefaccess=app, savename='ResultTable')
|
2010-02-11 16:52:18 +00:00
|
|
|
self._power_marker = False
|
2010-02-11 18:22:31 +00:00
|
|
|
self._delta_values = False
|
2011-11-27 17:47:00 +00:00
|
|
|
self._sort_descriptors = ('name', True)
|
2010-02-12 14:39:29 +00:00
|
|
|
|
|
|
|
#--- Override
|
2012-03-13 18:27:08 +00:00
|
|
|
def _view_updated(self):
|
2010-09-26 10:09:50 +00:00
|
|
|
self._refresh_with_view()
|
2010-02-11 16:52:18 +00:00
|
|
|
|
2010-09-24 13:48:59 +00:00
|
|
|
def _restore_selection(self, previous_selection):
|
|
|
|
if self.app.selected_dupes:
|
|
|
|
to_find = set(self.app.selected_dupes)
|
|
|
|
indexes = [i for i, r in enumerate(self) if r._dupe in to_find]
|
|
|
|
self.selected_indexes = indexes
|
|
|
|
|
|
|
|
def _update_selection(self):
|
|
|
|
rows = self.selected_rows
|
|
|
|
self.app._select_dupes(list(map(attrgetter('_dupe'), rows)))
|
2010-02-12 10:07:33 +00:00
|
|
|
|
2010-09-24 13:48:59 +00:00
|
|
|
def _fill(self):
|
2010-02-11 16:52:18 +00:00
|
|
|
if not self.power_marker:
|
|
|
|
for group in self.app.results.groups:
|
2010-09-24 13:48:59 +00:00
|
|
|
self.append(DupeRow(self, group, group.ref))
|
2010-02-11 16:52:18 +00:00
|
|
|
for dupe in group.dupes:
|
2010-09-24 13:48:59 +00:00
|
|
|
self.append(DupeRow(self, group, dupe))
|
2010-02-11 16:52:18 +00:00
|
|
|
else:
|
|
|
|
for dupe in self.app.results.dupes:
|
|
|
|
group = self.app.results.get_group_of_duplicate(dupe)
|
2010-09-24 13:48:59 +00:00
|
|
|
self.append(DupeRow(self, group, dupe))
|
2010-02-11 16:52:18 +00:00
|
|
|
|
2010-09-26 10:09:50 +00:00
|
|
|
def _refresh_with_view(self):
|
|
|
|
self.refresh()
|
|
|
|
self.view.show_selected_row()
|
|
|
|
|
2010-02-12 10:07:33 +00:00
|
|
|
#--- Public
|
2010-09-24 13:48:59 +00:00
|
|
|
def get_row_value(self, index, column):
|
2010-02-11 16:52:18 +00:00
|
|
|
try:
|
2010-09-24 13:48:59 +00:00
|
|
|
row = self[index]
|
2010-02-11 16:52:18 +00:00
|
|
|
except IndexError:
|
|
|
|
return '---'
|
2010-02-11 18:22:31 +00:00
|
|
|
if self.delta_values:
|
2010-09-24 13:48:59 +00:00
|
|
|
return row.data_delta[column]
|
2010-02-11 16:52:18 +00:00
|
|
|
else:
|
2010-09-24 13:48:59 +00:00
|
|
|
return row.data[column]
|
2010-02-11 16:52:18 +00:00
|
|
|
|
2010-02-12 12:52:40 +00:00
|
|
|
def rename_selected(self, newname):
|
2010-09-24 13:48:59 +00:00
|
|
|
row = self.selected_row
|
2011-04-13 14:23:22 +00:00
|
|
|
if row is None:
|
|
|
|
# There's all kinds of way the current row can be swept off during rename. When it
|
|
|
|
# happens, selected_row will be None.
|
|
|
|
return False
|
2010-09-24 13:48:59 +00:00
|
|
|
row._data = None
|
|
|
|
row._data_delta = None
|
2010-02-12 12:52:40 +00:00
|
|
|
return self.app.rename_selected(newname)
|
|
|
|
|
2010-02-11 16:52:18 +00:00
|
|
|
def sort(self, key, asc):
|
|
|
|
if self.power_marker:
|
2010-02-11 18:22:31 +00:00
|
|
|
self.app.results.sort_dupes(key, asc, self.delta_values)
|
2010-02-11 16:52:18 +00:00
|
|
|
else:
|
2010-02-11 18:22:31 +00:00
|
|
|
self.app.results.sort_groups(key, asc)
|
2010-02-11 20:03:22 +00:00
|
|
|
self._sort_descriptors = (key, asc)
|
2010-09-26 10:09:50 +00:00
|
|
|
self._refresh_with_view()
|
2010-02-11 16:52:18 +00:00
|
|
|
|
2010-02-12 10:07:33 +00:00
|
|
|
#--- Properties
|
2010-02-11 16:52:18 +00:00
|
|
|
@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
|
2010-02-11 20:03:22 +00:00
|
|
|
key, asc = self._sort_descriptors
|
|
|
|
self.sort(key, asc)
|
2010-09-26 10:09:50 +00:00
|
|
|
# no need to refresh, it has happened in sort()
|
2010-02-11 16:52:18 +00:00
|
|
|
|
2010-02-11 18:22:31 +00:00
|
|
|
@property
|
|
|
|
def delta_values(self):
|
|
|
|
return self._delta_values
|
|
|
|
|
|
|
|
@delta_values.setter
|
|
|
|
def delta_values(self, value):
|
|
|
|
if value == self._delta_values:
|
|
|
|
return
|
|
|
|
self._delta_values = value
|
2010-09-24 13:48:59 +00:00
|
|
|
self.refresh()
|
2010-02-11 18:22:31 +00:00
|
|
|
|
2010-09-24 13:48:59 +00:00
|
|
|
@property
|
|
|
|
def selected_dupe_count(self):
|
|
|
|
return sum(1 for row in self.selected_rows if not row.isref)
|
|
|
|
|
2010-02-11 16:52:18 +00:00
|
|
|
#--- Event Handlers
|
2010-02-12 10:21:39 +00:00
|
|
|
def marking_changed(self):
|
|
|
|
self.view.invalidate_markings()
|
|
|
|
|
2010-02-11 16:52:18 +00:00
|
|
|
def results_changed(self):
|
2010-09-26 10:09:50 +00:00
|
|
|
self._refresh_with_view()
|
2010-02-11 16:52:18 +00:00
|
|
|
|
2010-02-17 17:05:19 +00:00
|
|
|
def results_changed_but_keep_selection(self):
|
2010-02-13 09:39:54 +00:00
|
|
|
# What we want to to here is that instead of restoring selected *dupes* after refresh, we
|
|
|
|
# restore selected *paths*.
|
2010-09-24 13:48:59 +00:00
|
|
|
indexes = self.selected_indexes
|
2010-11-24 15:12:10 +00:00
|
|
|
self.refresh(refresh_view=False)
|
2010-09-24 13:48:59 +00:00
|
|
|
self.select(indexes)
|
2010-02-13 09:39:54 +00:00
|
|
|
self.view.refresh()
|
|
|
|
|
2011-11-26 15:55:14 +00:00
|
|
|
def save_session(self):
|
|
|
|
self.columns.save_columns()
|
|
|
|
|