Revert stable sort and speedup commits.
This commit is contained in:
parent
8a72187998
commit
8f71b8d5c6
|
@ -2,10 +2,8 @@
|
||||||
==== Core ====
|
==== Core ====
|
||||||
* Catch & log KeyError when removing a torrent from the queued torrents set
|
* Catch & log KeyError when removing a torrent from the queued torrents set
|
||||||
|
|
||||||
=== GtkUI ===
|
==== GtkUI ====
|
||||||
* Add move completed option to add torrent dialog
|
* Add move completed option to add torrent dialog
|
||||||
* Remove jitter in torrent list order, make order stable between sorts
|
|
||||||
* Improve update speed and responsiveness (especially with large number of torrents)
|
|
||||||
|
|
||||||
=== Deluge 1.3.5 (09 April 2012) ===
|
=== Deluge 1.3.5 (09 April 2012) ===
|
||||||
==== Core ====
|
==== Core ====
|
||||||
|
|
|
@ -213,11 +213,6 @@ 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)
|
||||||
|
|
||||||
|
@ -236,48 +231,14 @@ 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:
|
|
||||||
hash1 = model[iter1][self.unique_column_id]
|
|
||||||
hash2 = model[iter2][self.unique_column_id]
|
|
||||||
if hash1 in self.last_sort_order and hash2 in self.last_sort_order:
|
|
||||||
result = cmp(self.last_sort_order[hash1],
|
|
||||||
self.last_sort_order[hash2])
|
|
||||||
if result == 0 and self.default_sort_column_id:
|
|
||||||
result = cmp(model[iter1][self.default_sort_column_id],
|
|
||||||
model[iter2][self.default_sort_column_id])
|
|
||||||
|
|
||||||
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():
|
||||||
sort_func = column.sort_func or self.generic_sort_func
|
if column.sort_func:
|
||||||
self.model_filter.set_sort_func(
|
self.model_filter.set_sort_func(
|
||||||
column.sort_id,
|
column.sort_id,
|
||||||
self.stabilize_sort_func(sort_func),
|
column.sort_func,
|
||||||
column.sort_id)
|
column.sort_id)
|
||||||
|
|
||||||
def create_column_state(self, column, position=None):
|
def create_column_state(self, column, position=None):
|
||||||
|
@ -480,8 +441,7 @@ 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, default=True, unique=False,
|
column_type=None, sort_func=None, default=True):
|
||||||
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 = []
|
||||||
|
@ -506,11 +466,6 @@ 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()
|
||||||
|
|
||||||
|
@ -563,10 +518,6 @@ class ListView:
|
||||||
column.connect('button-press-event',
|
column.connect('button-press-event',
|
||||||
self.on_treeview_header_right_clicked)
|
self.on_treeview_header_right_clicked)
|
||||||
|
|
||||||
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:
|
||||||
|
@ -604,15 +555,13 @@ 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, default=True, unique=False,
|
sort_func=None, default=True):
|
||||||
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, default=default, unique=unique,
|
sort_func=sort_func, default=default)
|
||||||
default_sort=default_sort)
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -655,15 +604,14 @@ 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,
|
||||||
default=True, default_sort=False):
|
default=True):
|
||||||
"""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, default=default,
|
function=function, pixbuf=0, text=1, default=default)
|
||||||
default_sort=default_sort)
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
@ -228,15 +228,14 @@ class TorrentView(listview.ListView, component.Component):
|
||||||
self.window.main_glade.get_widget("menu_columns"))
|
self.window.main_glade.get_widget("menu_columns"))
|
||||||
|
|
||||||
# Add the columns to the listview
|
# Add the columns to the listview
|
||||||
self.add_text_column("torrent_id", hidden=True, unique=True)
|
self.add_text_column("torrent_id", hidden=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"])
|
||||||
|
@ -314,12 +313,18 @@ class TorrentView(listview.ListView, component.Component):
|
||||||
component.get("SessionProxy").get_torrents_status({}, []).addCallback(self._on_session_state)
|
component.get("SessionProxy").get_torrents_status({}, []).addCallback(self._on_session_state)
|
||||||
|
|
||||||
def _on_session_state(self, state):
|
def _on_session_state(self, state):
|
||||||
self.add_rows(state)
|
self.treeview.freeze_child_notify()
|
||||||
|
model = self.treeview.get_model()
|
||||||
|
for torrent_id in state:
|
||||||
|
self.add_row(torrent_id, update=False)
|
||||||
|
self.mark_dirty(torrent_id)
|
||||||
|
self.treeview.set_model(model)
|
||||||
|
self.treeview.thaw_child_notify()
|
||||||
self.got_state = True
|
self.got_state = True
|
||||||
# Update the view right away with our status
|
# Update the view right away with our status
|
||||||
self.status = state
|
self.status = state
|
||||||
self.set_columns_to_update()
|
self.set_columns_to_update()
|
||||||
self.update_view(first_run=True)
|
self.update_view()
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
"""Stops the torrentview"""
|
"""Stops the torrentview"""
|
||||||
|
@ -394,78 +399,40 @@ class TorrentView(listview.ListView, component.Component):
|
||||||
# Send a status request
|
# Send a status request
|
||||||
gobject.idle_add(self.send_status_request)
|
gobject.idle_add(self.send_status_request)
|
||||||
|
|
||||||
|
def update_view(self, columns=None):
|
||||||
def update_view(self, first_run=False):
|
"""Update the view. If columns is not None, it will attempt to only
|
||||||
"""Update the view."""
|
update those columns selected.
|
||||||
|
"""
|
||||||
filter_column = self.columns["filter"].column_indices[0]
|
filter_column = self.columns["filter"].column_indices[0]
|
||||||
|
# Update the torrent view model with data we've received
|
||||||
status = self.status
|
status = self.status
|
||||||
sort_settings = (None, None)
|
|
||||||
model = self.treeview.get_model()
|
|
||||||
|
|
||||||
self.treeview.freeze_child_notify()
|
|
||||||
|
|
||||||
if first_run:
|
|
||||||
# Disable sort if it's the first run.
|
|
||||||
sort_settings = model.get_sort_column_id()
|
|
||||||
model.set_default_sort_func(lambda *unused: 0)
|
|
||||||
model.set_sort_column_id(-1, gtk.SORT_ASCENDING)
|
|
||||||
|
|
||||||
# Create a list of tuples with the index of the column, and the column name
|
|
||||||
fields_to_update = []
|
|
||||||
for column in self.columns_to_update:
|
|
||||||
column_index = self.get_column_index(column)
|
|
||||||
for i, status_field in enumerate(self.columns[column].status_field):
|
|
||||||
fields_to_update.append((column_index[i], status_field))
|
|
||||||
|
|
||||||
for row in self.liststore:
|
for row in self.liststore:
|
||||||
torrent_id = row[self.columns["torrent_id"].column_indices[0]]
|
torrent_id = row[self.columns["torrent_id"].column_indices[0]]
|
||||||
# Do not test if the torrent_id is in status. Instead
|
|
||||||
# we expect the torrent_id to be in status and prev_status,
|
|
||||||
# as it will be as long as the list isn't changed by the user
|
|
||||||
torrent_id_in_status = False
|
|
||||||
try:
|
|
||||||
torrent_status = status[torrent_id]
|
|
||||||
torrent_id_in_status = True
|
|
||||||
if torrent_status == self.prev_status[torrent_id]:
|
|
||||||
if row[filter_column] is False:
|
|
||||||
row[filter_column] = True
|
|
||||||
# The status dict is the same, so do not update this torrent
|
|
||||||
continue
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if not torrent_id_in_status:
|
if not torrent_id in status.keys():
|
||||||
if row[filter_column] is True:
|
|
||||||
row[filter_column] = False
|
row[filter_column] = False
|
||||||
else:
|
else:
|
||||||
if row[filter_column] is False:
|
|
||||||
row[filter_column] = True
|
row[filter_column] = True
|
||||||
to_update = []
|
if torrent_id in self.prev_status and status[torrent_id] == self.prev_status[torrent_id]:
|
||||||
# Add all the values that have changed to the list
|
# The status dict is the same, so do not update
|
||||||
for i, status_field in fields_to_update:
|
|
||||||
try:
|
|
||||||
if not status[torrent_id].has_key(status_field):
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# Set values for each column in the row
|
||||||
|
for column in self.columns_to_update:
|
||||||
|
column_index = self.get_column_index(column)
|
||||||
|
for i, status_field in enumerate(self.columns[column].status_field):
|
||||||
|
if status_field in status[torrent_id]:
|
||||||
|
try:
|
||||||
|
# Only update if different
|
||||||
row_value = status[torrent_id][status_field]
|
row_value = status[torrent_id][status_field]
|
||||||
if row[i] != row_value:
|
if row[column_index[i]] != row_value:
|
||||||
to_update.append(i)
|
row[column_index[i]] = row_value
|
||||||
to_update.append(row_value)
|
|
||||||
except KeyError, e:
|
|
||||||
# if status_field in status[torrent_id] -> False
|
|
||||||
pass
|
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
log.debug("%s", e)
|
log.debug("%s", e)
|
||||||
# Update all the changed values of the row
|
|
||||||
if to_update:
|
|
||||||
self.liststore.set(row.iter, *to_update)
|
|
||||||
|
|
||||||
if sort_settings[0] is not None:
|
|
||||||
# Reenable sorting
|
|
||||||
model.set_sort_column_id(*sort_settings)
|
|
||||||
model.set_default_sort_func(None)
|
|
||||||
|
|
||||||
self.treeview.thaw_child_notify()
|
|
||||||
component.get("MenuBar").update_menu()
|
component.get("MenuBar").update_menu()
|
||||||
|
|
||||||
self.prev_status = status
|
self.prev_status = status
|
||||||
|
|
||||||
def _on_get_torrents_status(self, status):
|
def _on_get_torrents_status(self, status):
|
||||||
|
@ -495,15 +462,6 @@ class TorrentView(listview.ListView, component.Component):
|
||||||
if update:
|
if update:
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def add_rows(self, state):
|
|
||||||
"""Adds all the torrents from state to self.liststore"""
|
|
||||||
torrent_id_column = self.columns["torrent_id"].column_indices[0]
|
|
||||||
dirty_column = self.columns["dirty"].column_indices[0]
|
|
||||||
for i, torrent_id in enumerate(state):
|
|
||||||
# Insert a new row to the liststore
|
|
||||||
row = self.liststore.append()
|
|
||||||
self.liststore.set(row, torrent_id_column, torrent_id, dirty_column, True)
|
|
||||||
|
|
||||||
def remove_row(self, torrent_id):
|
def remove_row(self, torrent_id):
|
||||||
"""Removes a row with torrent_id"""
|
"""Removes a row with torrent_id"""
|
||||||
for row in self.liststore:
|
for row in self.liststore:
|
||||||
|
|
Loading…
Reference in New Issue