Implement pseudo stable sort in the gtk torrent view.
This commit is contained in:
parent
dd511df194
commit
1daae0135d
|
@ -222,6 +222,11 @@ class ListView:
|
||||||
# their columns prior to having the state list saved on shutdown.
|
# their columns prior to having the state list saved on shutdown.
|
||||||
self.removed_columns_state = []
|
self.removed_columns_state = []
|
||||||
|
|
||||||
|
# Since gtk TreeModelSort doesn't do stable sort, remember last sort order so we can
|
||||||
|
self.last_sort_order = {}
|
||||||
|
self.unique_column_id = None
|
||||||
|
self.default_sort_column_id = None
|
||||||
|
|
||||||
# Create the model filter and column
|
# Create the model filter and column
|
||||||
self.add_bool_column("filter", hidden=True)
|
self.add_bool_column("filter", hidden=True)
|
||||||
|
|
||||||
|
@ -240,15 +245,49 @@ class ListView:
|
||||||
if sort_info and sort_info[0] and sort_info[1] > -1:
|
if sort_info and sort_info[0] and sort_info[1] > -1:
|
||||||
self.model_filter.set_sort_column_id(sort_info[0], sort_info[1])
|
self.model_filter.set_sort_column_id(sort_info[0], sort_info[1])
|
||||||
self.set_sort_functions()
|
self.set_sort_functions()
|
||||||
|
self.model_filter.connect("sort-column-changed", self.on_model_sort_changed)
|
||||||
|
self.model_filter.connect("row-inserted", self.on_model_row_inserted)
|
||||||
self.treeview.set_model(self.model_filter)
|
self.treeview.set_model(self.model_filter)
|
||||||
|
|
||||||
|
def on_model_sort_changed(self, model):
|
||||||
|
if self.unique_column_id:
|
||||||
|
self.last_sort_order = {}
|
||||||
|
def record_position(model, path, iter, data):
|
||||||
|
self.last_sort_order[model[iter][self.unique_column_id]] = path[0]
|
||||||
|
model.foreach(record_position, None)
|
||||||
|
|
||||||
|
def on_model_row_inserted(self, model, path, iter):
|
||||||
|
if self.unique_column_id:
|
||||||
|
self.last_sort_order.setdefault(
|
||||||
|
model[iter][self.unique_column_id], len(model) - 1)
|
||||||
|
|
||||||
|
def stabilize_sort_func(self, sort_func):
|
||||||
|
def stabilized(model, iter1, iter2, data):
|
||||||
|
result = sort_func(model, iter1, iter2, data)
|
||||||
|
if result == 0 and self.unique_column_id:
|
||||||
|
unique1 = model[iter1][self.unique_column_id]
|
||||||
|
unique2 = model[iter2][self.unique_column_id]
|
||||||
|
if unique1 in self.last_sort_order and unique2 in self.last_sort_order:
|
||||||
|
result = cmp(self.last_sort_order[unique1],
|
||||||
|
self.last_sort_order[unique2])
|
||||||
|
# If all else fails, fall back to sorting by unique column
|
||||||
|
if result == 0:
|
||||||
|
result = cmp(unique1, unique2)
|
||||||
|
|
||||||
|
return result
|
||||||
|
return stabilized
|
||||||
|
|
||||||
|
def generic_sort_func(self, model, iter1, iter2, data):
|
||||||
|
return cmp(model[iter1][data], model[iter2][data])
|
||||||
|
|
||||||
def set_sort_functions(self):
|
def set_sort_functions(self):
|
||||||
|
self.model_filter.set_default_sort_func(None)
|
||||||
for column in self.columns.values():
|
for column in self.columns.values():
|
||||||
if column.sort_func:
|
sort_func = column.sort_func or self.generic_sort_func
|
||||||
self.model_filter.set_sort_func(
|
self.model_filter.set_sort_func(
|
||||||
column.sort_id,
|
column.sort_id,
|
||||||
column.sort_func,
|
self.stabilize_sort_func(sort_func),
|
||||||
column.sort_id)
|
column.sort_id)
|
||||||
|
|
||||||
def create_column_state(self, column, position=None):
|
def create_column_state(self, column, position=None):
|
||||||
if not position:
|
if not position:
|
||||||
|
@ -450,7 +489,8 @@ class ListView:
|
||||||
|
|
||||||
def add_column(self, header, render, col_types, hidden, position,
|
def add_column(self, header, render, col_types, hidden, position,
|
||||||
status_field, sortid, text=0, value=0, pixbuf=0, function=None,
|
status_field, sortid, text=0, value=0, pixbuf=0, function=None,
|
||||||
column_type=None, sort_func=None, tooltip=None, default=True):
|
column_type=None, sort_func=None, tooltip=None, default=True,
|
||||||
|
unique=False, default_sort=False):
|
||||||
"""Adds a column to the ListView"""
|
"""Adds a column to the ListView"""
|
||||||
# Add the column types to liststore_columns
|
# Add the column types to liststore_columns
|
||||||
column_indices = []
|
column_indices = []
|
||||||
|
@ -475,6 +515,11 @@ class ListView:
|
||||||
self.columns[header].sort_func = sort_func
|
self.columns[header].sort_func = sort_func
|
||||||
self.columns[header].sort_id = column_indices[sortid]
|
self.columns[header].sort_id = column_indices[sortid]
|
||||||
|
|
||||||
|
if unique:
|
||||||
|
self.unique_column_id = column_indices[sortid]
|
||||||
|
if default_sort:
|
||||||
|
self.default_sort_column_id = column_indices[sortid]
|
||||||
|
|
||||||
# Create a new list with the added column
|
# Create a new list with the added column
|
||||||
self.create_new_liststore()
|
self.create_new_liststore()
|
||||||
|
|
||||||
|
@ -530,6 +575,11 @@ class ListView:
|
||||||
if tooltip:
|
if tooltip:
|
||||||
column.get_widget().set_tooltip_markup(tooltip)
|
column.get_widget().set_tooltip_markup(tooltip)
|
||||||
|
|
||||||
|
if default_sort:
|
||||||
|
if self.model_filter.get_sort_column_id()[0] is None:
|
||||||
|
self.model_filter.set_sort_column_id(column_indices[sortid],
|
||||||
|
gtk.SORT_ASCENDING)
|
||||||
|
|
||||||
# Check for loaded state and apply
|
# Check for loaded state and apply
|
||||||
column_in_state = False
|
column_in_state = False
|
||||||
if self.state != None:
|
if self.state != None:
|
||||||
|
@ -569,13 +619,15 @@ class ListView:
|
||||||
|
|
||||||
def add_text_column(self, header, col_type=str, hidden=False, position=None,
|
def add_text_column(self, header, col_type=str, hidden=False, position=None,
|
||||||
status_field=None, sortid=0, column_type="text",
|
status_field=None, sortid=0, column_type="text",
|
||||||
sort_func=None, tooltip=None, default=True):
|
sort_func=None, tooltip=None, default=True, unique=False,
|
||||||
|
default_sort=False):
|
||||||
"""Add a text column to the listview. Only the header name is required.
|
"""Add a text column to the listview. Only the header name is required.
|
||||||
"""
|
"""
|
||||||
render = gtk.CellRendererText()
|
render = gtk.CellRendererText()
|
||||||
self.add_column(header, render, col_type, hidden, position,
|
self.add_column(header, render, col_type, hidden, position,
|
||||||
status_field, sortid, column_type=column_type,
|
status_field, sortid, column_type=column_type,
|
||||||
sort_func=sort_func, tooltip=tooltip, default=default)
|
sort_func=sort_func, tooltip=tooltip, default=default,
|
||||||
|
unique=unique, default_sort=default_sort)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -619,14 +671,15 @@ class ListView:
|
||||||
def add_texticon_column(self, header, col_types=[str, str], sortid=1,
|
def add_texticon_column(self, header, col_types=[str, str], sortid=1,
|
||||||
hidden=False, position=None, status_field=None,
|
hidden=False, position=None, status_field=None,
|
||||||
column_type="texticon", function=None,
|
column_type="texticon", function=None,
|
||||||
tooltip=None, default=True):
|
tooltip=None, default=True, default_sort=False):
|
||||||
"""Adds a texticon column to the listview."""
|
"""Adds a texticon column to the listview."""
|
||||||
render1 = gtk.CellRendererPixbuf()
|
render1 = gtk.CellRendererPixbuf()
|
||||||
render2 = gtk.CellRendererText()
|
render2 = gtk.CellRendererText()
|
||||||
|
|
||||||
self.add_column(header, (render1, render2), col_types, hidden, position,
|
self.add_column(header, (render1, render2), col_types, hidden, position,
|
||||||
status_field, sortid, column_type=column_type,
|
status_field, sortid, column_type=column_type,
|
||||||
function=function, pixbuf=0, text=1, tooltip=tooltip, default=default)
|
function=function, pixbuf=0, text=1, tooltip=tooltip,
|
||||||
|
default=default, default_sort=default_sort)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
@ -348,14 +348,15 @@ class TorrentView(listview.ListView, component.Component):
|
||||||
self.register_checklist_menu(self.window.main_builder.get_object("menu_columns"))
|
self.register_checklist_menu(self.window.main_builder.get_object("menu_columns"))
|
||||||
|
|
||||||
# Add the columns to the listview
|
# Add the columns to the listview
|
||||||
self.add_text_column("torrent_id", hidden=True)
|
self.add_text_column("torrent_id", hidden=True, unique=True)
|
||||||
self.add_bool_column("dirty", hidden=True)
|
self.add_bool_column("dirty", hidden=True)
|
||||||
self.add_func_column("#", cell_data_queue, [int],
|
self.add_func_column("#", cell_data_queue, [int],
|
||||||
status_field=["queue"],
|
status_field=["queue"],
|
||||||
sort_func=queue_column_sort)
|
sort_func=queue_column_sort)
|
||||||
self.add_texticon_column(_("Name"),
|
self.add_texticon_column(_("Name"),
|
||||||
status_field=["state", "name"],
|
status_field=["state", "name"],
|
||||||
function=cell_data_statusicon)
|
function=cell_data_statusicon,
|
||||||
|
default_sort=True)
|
||||||
self.add_func_column(_("Size"), listview.cell_data_size,
|
self.add_func_column(_("Size"), listview.cell_data_size,
|
||||||
[gobject.TYPE_UINT64],
|
[gobject.TYPE_UINT64],
|
||||||
status_field=["total_wanted"])
|
status_field=["total_wanted"])
|
||||||
|
|
Loading…
Reference in New Issue