diff options
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/trg-cell-renderer-counter.c | 136 | ||||
-rw-r--r-- | src/trg-cell-renderer-counter.h | 51 | ||||
-rw-r--r-- | src/trg-main-window.c | 11 | ||||
-rw-r--r-- | src/trg-peers-model.c | 5 | ||||
-rw-r--r-- | src/trg-state-selector.c | 465 | ||||
-rw-r--r-- | src/trg-state-selector.h | 3 | ||||
-rw-r--r-- | src/trg-torrent-model.c | 501 | ||||
-rw-r--r-- | src/trg-torrent-model.h | 10 |
9 files changed, 659 insertions, 524 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index c978ea5..9ec2231 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -79,6 +79,7 @@ transmission_remote_gtk_SOURCES = main.c \ trg-torrent-add-url-dialog.c \ trg-json-widgets.c \ trg-cell-renderer-speed.c \ + trg-cell-renderer-counter.c \ trg-cell-renderer-size.c \ trg-cell-renderer-ratio.c \ trg-cell-renderer-eta.c \ diff --git a/src/trg-cell-renderer-counter.c b/src/trg-cell-renderer-counter.c new file mode 100644 index 0000000..0548023 --- /dev/null +++ b/src/trg-cell-renderer-counter.c @@ -0,0 +1,136 @@ +/* + * transmission-remote-gtk - A GTK RPC client to Transmission + * Copyright (C) 2011 Alan Fitton + + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <stdint.h> +#include <gtk/gtk.h> + +#include "trg-cell-renderer-counter.h" +#include "util.h" + +enum { + PROP_0, PROP_STATE_LABEL, PROP_STATE_COUNT +}; + +G_DEFINE_TYPE(TrgCellRendererCounter, trg_cell_renderer_counter, + GTK_TYPE_CELL_RENDERER_TEXT) +#define TRG_CELL_RENDERER_COUNTER_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), TRG_TYPE_CELL_RENDERER_COUNTER, TrgCellRendererCounterPrivate)) +typedef struct _TrgCellRendererCounterPrivate TrgCellRendererCounterPrivate; + +struct _TrgCellRendererCounterPrivate { + gint count; + gchar *originalLabel; +}; + +static void trg_cell_renderer_counter_get_property(GObject * object, + guint property_id, GValue * value, GParamSpec * pspec) { + TrgCellRendererCounterPrivate *priv = + TRG_CELL_RENDERER_COUNTER_GET_PRIVATE(object); + switch (property_id) { + case PROP_STATE_COUNT: + g_value_set_int(value, priv->count); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + break; + } +} + +static void trg_cell_renderer_counter_refresh(TrgCellRendererCounter *cr) { + TrgCellRendererCounterPrivate *priv = + TRG_CELL_RENDERER_COUNTER_GET_PRIVATE(cr); + if (priv->originalLabel && priv->count > 0) { + gchar *counterLabel = g_strdup_printf("%s <span size=\"small\">(%d)</span>", priv->originalLabel, + priv->count); + g_object_set(cr, "markup", counterLabel, NULL); + g_free(counterLabel); + } else { + g_object_set(cr, "text", priv->originalLabel, NULL); + } +} + +static void trg_cell_renderer_counter_set_property(GObject * object, + guint property_id, const GValue * value, GParamSpec * pspec) { + TrgCellRendererCounterPrivate *priv = + TRG_CELL_RENDERER_COUNTER_GET_PRIVATE(object); + + if (property_id == PROP_STATE_LABEL) { + g_free(priv->originalLabel); + priv->originalLabel = g_strdup(g_value_get_string(value)); + trg_cell_renderer_counter_refresh(TRG_CELL_RENDERER_COUNTER(object)); + } else if (property_id == PROP_STATE_COUNT) { + gint newCount = g_value_get_int(value); + if (priv->count != newCount) { + priv->count = newCount; + trg_cell_renderer_counter_refresh( + TRG_CELL_RENDERER_COUNTER(object)); + } + } else { + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + } +} + +static void trg_cell_renderer_counter_dispose(GObject * object) { + TrgCellRendererCounterPrivate *priv = + TRG_CELL_RENDERER_COUNTER_GET_PRIVATE(object); + g_free(priv->originalLabel); + G_OBJECT_CLASS(trg_cell_renderer_counter_parent_class)->dispose(object); +} + +static void trg_cell_renderer_counter_class_init( + TrgCellRendererCounterClass * klass) { + GObjectClass *object_class = G_OBJECT_CLASS(klass); + + object_class->get_property = trg_cell_renderer_counter_get_property; + object_class->set_property = trg_cell_renderer_counter_set_property; + object_class->dispose = trg_cell_renderer_counter_dispose; + + g_object_class_install_property( + object_class, + PROP_STATE_COUNT, + g_param_spec_int( + "state-count", + "State Count", + "State Count", + -1, + INT_MAX, + -1, + G_PARAM_READWRITE | G_PARAM_STATIC_NAME + | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); + + g_object_class_install_property( + object_class, + PROP_STATE_LABEL, + g_param_spec_string( + "state-label", + "State Label", + "State Label", + NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_NAME + | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); + + g_type_class_add_private(klass, sizeof(TrgCellRendererCounterPrivate)); +} + +static void trg_cell_renderer_counter_init(TrgCellRendererCounter * self) { +} + +GtkCellRenderer *trg_cell_renderer_counter_new(void) { + return GTK_CELL_RENDERER(g_object_new(TRG_TYPE_CELL_RENDERER_COUNTER, NULL)); +} diff --git a/src/trg-cell-renderer-counter.h b/src/trg-cell-renderer-counter.h new file mode 100644 index 0000000..5ecaba8 --- /dev/null +++ b/src/trg-cell-renderer-counter.h @@ -0,0 +1,51 @@ +/* + * transmission-remote-gtk - A GTK RPC client to Transmission + * Copyright (C) 2011 Alan Fitton + + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef TRG_CELL_RENDERER_COUNTER_H_ +#define TRG_CELL_RENDERER_COUNTER_H_ + +#include <glib-object.h> +#include <gtk/gtk.h> + +G_BEGIN_DECLS +#define TRG_TYPE_CELL_RENDERER_COUNTER trg_cell_renderer_counter_get_type() +#define TRG_CELL_RENDERER_COUNTER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), TRG_TYPE_CELL_RENDERER_COUNTER, TrgCellRendererCounter)) +#define TRG_CELL_RENDERER_COUNTER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), TRG_TYPE_CELL_RENDERER_COUNTER, TrgCellRendererCounterClass)) +#define TRG_IS_CELL_RENDERER_COUNTER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TRG_TYPE_CELL_RENDERER_COUNTER)) +#define TRG_IS_CELL_RENDERER_COUNTER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), TRG_TYPE_CELL_RENDERER_COUNTER)) +#define TRG_CELL_RENDERER_COUNTER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), TRG_TYPE_CELL_RENDERER_COUNTER, TrgCellRendererCounterClass)) + typedef struct { + GtkCellRendererText parent; +} TrgCellRendererCounter; + +typedef struct { + GtkCellRendererTextClass parent_class; +} TrgCellRendererCounterClass; + +GType trg_cell_renderer_counter_get_type(void); + +GtkCellRenderer *trg_cell_renderer_counter_new(void); + +G_END_DECLS +#endif /* TRG_CELL_RENDERER_COUNTER_H_ */ diff --git a/src/trg-main-window.c b/src/trg-main-window.c index 2e45d52..5461fb3 100644 --- a/src/trg-main-window.c +++ b/src/trg-main-window.c @@ -365,12 +365,6 @@ static void on_torrent_completed(TrgTorrentModel * model, #endif } -static void on_update_filters(TrgTorrentModel * model, gpointer data) -{ - TrgMainWindowPrivate *priv = TRG_MAIN_WINDOW_GET_PRIVATE(data); - trg_state_selector_update(priv->stateSelector); -} - static void on_torrent_added(TrgTorrentModel * model, GtkTreeIter * iter, gpointer data) { @@ -1141,7 +1135,6 @@ static gboolean on_torrent_get(gpointer data, int mode) stats = trg_torrent_model_update(priv->torrentModel, client, response->obj, mode); - trg_state_selector_stats_update(priv->stateSelector, stats); update_selected_torrent_notebook(win, mode, priv->selectedTorrentId); trg_status_bar_update(priv->statusBar, stats, client); update_whatever_statusicon(win, @@ -2377,8 +2370,6 @@ static GObject *trg_main_window_constructor(GType type, G_CALLBACK(on_torrent_completed), self); g_signal_connect(priv->torrentModel, "torrent-added", G_CALLBACK(on_torrent_added), self); - g_signal_connect(priv->torrentModel, "update-filters", - G_CALLBACK(on_update_filters), self); priv->sortedTorrentModel = gtk_tree_model_sort_new_with_model(GTK_TREE_MODEL @@ -2435,7 +2426,7 @@ static GObject *trg_main_window_constructor(GType type, gtk_box_pack_start(GTK_BOX(outerVbox), priv->vpaned, TRUE, TRUE, 0); gtk_paned_pack1(GTK_PANED(priv->vpaned), priv->hpaned, TRUE, TRUE); - priv->stateSelector = trg_state_selector_new(priv->client); + priv->stateSelector = trg_state_selector_new(priv->client, priv->torrentModel); priv->stateSelectorScroller = my_scrolledwin_new(GTK_WIDGET(priv->stateSelector)); gtk_paned_pack1(GTK_PANED(priv->hpaned), priv->stateSelectorScroller, diff --git a/src/trg-peers-model.c b/src/trg-peers-model.c index 86574fd..17df900 100644 --- a/src/trg-peers-model.c +++ b/src/trg-peers-model.c @@ -64,14 +64,17 @@ gboolean find_existing_peer_item_foreachfunc(GtkTreeModel * model, gpointer data) { struct peerAndIter *pi = (struct peerAndIter *) data; - gchar *ip; + gtk_tree_model_get(model, iter, PEERSCOL_IP, &ip, -1); + if (g_strcmp0(ip, pi->ip) == 0) { pi->iter = *iter; pi->found = TRUE; } + g_free(ip); + return pi->found; } diff --git a/src/trg-state-selector.c b/src/trg-state-selector.c index 1fd0367..413c8fc 100644 --- a/src/trg-state-selector.c +++ b/src/trg-state-selector.c @@ -23,6 +23,7 @@ #include <gtk/gtk.h> #include "torrent.h" +#include "trg-cell-renderer-counter.h" #include "trg-state-selector.h" #include "trg-torrent-model.h" #include "util.h" @@ -30,13 +31,11 @@ #include "trg-client.h" enum { - SELECTOR_STATE_CHANGED, - SELECTOR_SIGNAL_COUNT + SELECTOR_STATE_CHANGED, SELECTOR_SIGNAL_COUNT }; enum { - PROP_0, - PROP_CLIENT + PROP_0, PROP_CLIENT }; static guint signals[SELECTOR_SIGNAL_COUNT] = { 0 }; @@ -58,23 +57,29 @@ struct _TrgStateSelectorPrivate { gint n_categories; GtkListStore *store; GtkTreeRowReference *error_rr; + GtkTreeRowReference *all_rr; + GtkTreeRowReference *paused_rr; + GtkTreeRowReference *down_rr; + GtkTreeRowReference *seeding_rr; + GtkTreeRowReference *complete_rr; + GtkTreeRowReference *incomplete_rr; + GtkTreeRowReference *checking_rr; + GtkTreeRowReference *active_rr; + GtkTreeRowReference *seed_wait_rr; + GtkTreeRowReference *down_wait_rr; }; -GRegex *trg_state_selector_get_url_host_regex(TrgStateSelector * s) -{ +GRegex *trg_state_selector_get_url_host_regex(TrgStateSelector * s) { TrgStateSelectorPrivate *priv = TRG_STATE_SELECTOR_GET_PRIVATE(s); return priv->urlHostRegex; } -guint32 trg_state_selector_get_flag(TrgStateSelector * s) -{ +guint32 trg_state_selector_get_flag(TrgStateSelector * s) { TrgStateSelectorPrivate *priv = TRG_STATE_SELECTOR_GET_PRIVATE(s); return priv->flag; } -static void state_selection_changed(GtkTreeSelection * selection, - gpointer data) -{ +static void state_selection_changed(GtkTreeSelection * selection, gpointer data) { TrgStateSelectorPrivate *priv; GtkTreeIter iter; GtkTreeModel *stateModel; @@ -83,21 +88,20 @@ static void state_selection_changed(GtkTreeSelection * selection, priv = TRG_STATE_SELECTOR_GET_PRIVATE(data); if (gtk_tree_selection_get_selected(selection, &stateModel, &iter)) - gtk_tree_model_get(stateModel, &iter, STATE_SELECTOR_BIT, - &priv->flag, STATE_SELECTOR_INDEX, &index, -1); + gtk_tree_model_get(stateModel, &iter, STATE_SELECTOR_BIT, &priv->flag, + STATE_SELECTOR_INDEX, &index, -1); else priv->flag = 0; trg_prefs_set_int(priv->prefs, TRG_PREFS_STATE_SELECTOR_LAST, index, - TRG_PREFS_GLOBAL); + TRG_PREFS_GLOBAL); - g_signal_emit(TRG_STATE_SELECTOR(data), - signals[SELECTOR_STATE_CHANGED], 0, priv->flag); + g_signal_emit(TRG_STATE_SELECTOR(data), signals[SELECTOR_STATE_CHANGED], 0, + priv->flag); } static GtkTreeRowReference *quick_tree_ref_new(GtkTreeModel * model, - GtkTreeIter * iter) -{ + GtkTreeIter * iter) { GtkTreePath *path = gtk_tree_model_get_path(model, iter); GtkTreeRowReference *rr = gtk_tree_row_reference_new(model, path); gtk_tree_path_free(path); @@ -109,10 +113,8 @@ struct cruft_remove_args { gint64 serial; }; -static gboolean trg_state_selector_remove_cruft(gpointer key, - gpointer value, - gpointer data) -{ +static gboolean trg_state_selector_remove_cruft(gpointer key, gpointer value, + gpointer data) { struct cruft_remove_args *args = (struct cruft_remove_args *) data; GtkTreeRowReference *rr = (GtkTreeRowReference *) value; GtkTreeModel *model = gtk_tree_row_reference_get_model(rr); @@ -123,8 +125,7 @@ static gboolean trg_state_selector_remove_cruft(gpointer key, gint64 currentSerial; gtk_tree_model_get_iter(model, &iter, path); - gtk_tree_model_get(model, &iter, STATE_SELECTOR_SERIAL, ¤tSerial, - -1); + gtk_tree_model_get(model, &iter, STATE_SELECTOR_SERIAL, ¤tSerial, -1); remove = (args->serial != currentSerial); @@ -133,8 +134,7 @@ static gboolean trg_state_selector_remove_cruft(gpointer key, return remove; } -gchar *trg_state_selector_get_selected_text(TrgStateSelector * s) -{ +gchar *trg_state_selector_get_selected_text(TrgStateSelector * s) { GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(s)); GtkTreeModel *model; GtkTreeIter iter; @@ -147,25 +147,21 @@ gchar *trg_state_selector_get_selected_text(TrgStateSelector * s) } static void trg_state_selector_update_serial(GtkTreeModel * model, - GtkTreeRowReference * rr, - gint64 serial) -{ + GtkTreeRowReference * rr, gint64 serial) { GtkTreeIter iter; GtkTreePath *path = gtk_tree_row_reference_get_path(rr); gtk_tree_model_get_iter(model, &iter, path); gtk_list_store_set(GTK_LIST_STORE(model), &iter, STATE_SELECTOR_SERIAL, - serial, -1); + serial, -1); gtk_tree_path_free(path); } -static void refresh_statelist_cb(GtkWidget * w, gpointer data) -{ +static void refresh_statelist_cb(GtkWidget * w, gpointer data) { trg_state_selector_update(TRG_STATE_SELECTOR(data)); } static void view_popup_menu(GtkWidget * treeview, GdkEventButton * event, - gpointer data G_GNUC_UNUSED) -{ + gpointer data G_GNUC_UNUSED) { GtkWidget *menu, *item; menu = gtk_menu_new(); @@ -173,28 +169,25 @@ static void view_popup_menu(GtkWidget * treeview, GdkEventButton * event, item = gtk_image_menu_item_new_with_label(GTK_STOCK_REFRESH); gtk_image_menu_item_set_use_stock(GTK_IMAGE_MENU_ITEM(item), TRUE); gtk_image_menu_item_set_always_show_image(GTK_IMAGE_MENU_ITEM - (item), TRUE); + (item), TRUE); g_signal_connect(item, "activate", G_CALLBACK(refresh_statelist_cb), - treeview); + treeview); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); gtk_widget_show_all(menu); gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, - (event != NULL) ? event->button : 0, - gdk_event_get_time((GdkEvent *) event)); -} + (event != NULL) ? event->button : 0, + gdk_event_get_time((GdkEvent *) event)); + } -static gboolean view_onPopupMenu(GtkWidget * treeview, gpointer userdata) -{ +static gboolean view_onPopupMenu(GtkWidget * treeview, gpointer userdata) { view_popup_menu(treeview, NULL, userdata); return TRUE; } static gboolean view_onButtonPressed(GtkWidget * treeview, - GdkEventButton * event, - gpointer userdata) -{ + GdkEventButton * event, gpointer userdata) { if (event->type == GDK_BUTTON_PRESS && event->button == 3) { view_popup_menu(treeview, event, userdata); return TRUE; @@ -211,10 +204,7 @@ struct state_find_pos { }; static gboolean trg_state_selector_find_pos_foreach(GtkTreeModel * model, - GtkTreePath * path, - GtkTreeIter * iter, - gpointer data) -{ + GtkTreePath * path, GtkTreeIter * iter, gpointer data) { struct state_find_pos *args = (struct state_find_pos *) data; gchar *name; gboolean res; @@ -222,8 +212,7 @@ static gboolean trg_state_selector_find_pos_foreach(GtkTreeModel * model, if (args->pos < args->offset) { args->pos++; return FALSE; - } else if (args->range >= 0 - && args->pos > args->offset + args->range - 1) { + } else if (args->range >= 0 && args->pos > args->offset + args->range - 1) { return TRUE; } @@ -238,9 +227,7 @@ static gboolean trg_state_selector_find_pos_foreach(GtkTreeModel * model, } static void trg_state_selector_insert(TrgStateSelector * s, int offset, - gint range, const gchar * name, - GtkTreeIter * iter) -{ + gint range, const gchar * name, GtkTreeIter * iter) { GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(s)); struct state_find_pos args; @@ -249,13 +236,11 @@ static void trg_state_selector_insert(TrgStateSelector * s, int offset, args.range = range; args.name = name; - gtk_tree_model_foreach(model, trg_state_selector_find_pos_foreach, - &args); + gtk_tree_model_foreach(model, trg_state_selector_find_pos_foreach, &args); gtk_list_store_insert(GTK_LIST_STORE(model), iter, args.pos); } -void trg_state_selector_update(TrgStateSelector * s) -{ +void trg_state_selector_update(TrgStateSelector * s) { TrgStateSelectorPrivate *priv = TRG_STATE_SELECTOR_GET_PRIVATE(s); GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(s)); TrgClient *client = priv->client; @@ -272,8 +257,8 @@ void trg_state_selector_update(TrgStateSelector * s) if (!trg_client_is_connected(client)) return; - torrentItemRefs = - g_hash_table_get_values(trg_client_get_torrent_table(client)); + torrentItemRefs = g_hash_table_get_values( + trg_client_get_torrent_table(client)); for (li = torrentItemRefs; li; li = g_list_next(li)) { JsonObject *t = NULL; @@ -284,7 +269,7 @@ void trg_state_selector_update(TrgStateSelector * s) if (path) { if (gtk_tree_model_get_iter(torrentModel, &torrentIter, path)) { gtk_tree_model_get(torrentModel, &torrentIter, - TORRENT_COLUMN_JSON, &t, -1); + TORRENT_COLUMN_JSON, &t, -1); } gtk_tree_path_free(path); } @@ -293,17 +278,15 @@ void trg_state_selector_update(TrgStateSelector * s) continue; if (priv->showTrackers) { - trackersList - = json_array_get_elements(torrent_get_tracker_stats(t)); - for (trackerItem = trackersList; trackerItem; trackerItem - = g_list_next(trackerItem)) { - JsonObject *tracker = json_node_get_object((JsonNode *) - trackerItem->data); - const gchar *announceUrl = - tracker_stats_get_announce(tracker); - gchar *announceHost = - trg_gregex_get_first(priv->urlHostRegex, - announceUrl); + trackersList = json_array_get_elements( + torrent_get_tracker_stats(t)); + for (trackerItem = trackersList; trackerItem; + trackerItem = g_list_next(trackerItem)) { + JsonObject *tracker = json_node_get_object( + (JsonNode *) trackerItem->data); + const gchar *announceUrl = tracker_stats_get_announce(tracker); + gchar *announceHost = trg_gregex_get_first(priv->urlHostRegex, + announceUrl); if (!announceHost) continue; @@ -312,25 +295,20 @@ void trg_state_selector_update(TrgStateSelector * s) if (result) { trg_state_selector_update_serial(model, - (GtkTreeRowReference - *) result, - updateSerial); + (GtkTreeRowReference *) result, updateSerial); g_free(announceHost); } else { trg_state_selector_insert(s, priv->n_categories, - g_hash_table_size - (priv->trackers), - announceHost, &iter); + g_hash_table_size(priv->trackers), announceHost, + &iter); gtk_list_store_set(GTK_LIST_STORE(model), &iter, - STATE_SELECTOR_ICON, - GTK_STOCK_NETWORK, - STATE_SELECTOR_NAME, announceHost, - STATE_SELECTOR_SERIAL, updateSerial, - STATE_SELECTOR_BIT, - FILTER_FLAG_TRACKER, - STATE_SELECTOR_INDEX, 0, -1); + STATE_SELECTOR_ICON, GTK_STOCK_NETWORK, + STATE_SELECTOR_NAME, announceHost, + STATE_SELECTOR_SERIAL, updateSerial, + STATE_SELECTOR_BIT, FILTER_FLAG_TRACKER, + STATE_SELECTOR_INDEX, 0, -1); g_hash_table_insert(priv->trackers, announceHost, - quick_tree_ref_new(model, &iter)); + quick_tree_ref_new(model, &iter)); } } g_list_free(trackersList); @@ -339,28 +317,23 @@ void trg_state_selector_update(TrgStateSelector * s) if (priv->showDirs) { gchar *dir; gtk_tree_model_get(torrentModel, &torrentIter, - TORRENT_COLUMN_DOWNLOADDIR_SHORT, &dir, -1); + TORRENT_COLUMN_DOWNLOADDIR_SHORT, &dir, -1); result = g_hash_table_lookup(priv->directories, dir); if (result) { trg_state_selector_update_serial(model, - (GtkTreeRowReference *) - result, updateSerial); + (GtkTreeRowReference *) result, updateSerial); } else { trg_state_selector_insert(s, - priv->n_categories + - g_hash_table_size - (priv->trackers), -1, dir, - &iter); + priv->n_categories + g_hash_table_size(priv->trackers), + -1, dir, &iter); gtk_list_store_set(GTK_LIST_STORE(model), &iter, - STATE_SELECTOR_ICON, - GTK_STOCK_DIRECTORY, - STATE_SELECTOR_NAME, dir, - STATE_SELECTOR_SERIAL, updateSerial, - STATE_SELECTOR_BIT, FILTER_FLAG_DIR, - STATE_SELECTOR_INDEX, 0, -1); + STATE_SELECTOR_ICON, GTK_STOCK_DIRECTORY, + STATE_SELECTOR_NAME, dir, STATE_SELECTOR_SERIAL, + updateSerial, STATE_SELECTOR_BIT, FILTER_FLAG_DIR, + STATE_SELECTOR_INDEX, 0, -1); g_hash_table_insert(priv->directories, g_strdup(dir), - quick_tree_ref_new(model, &iter)); + quick_tree_ref_new(model, &iter)); } g_free(dir); @@ -374,20 +347,17 @@ void trg_state_selector_update(TrgStateSelector * s) if (priv->showTrackers) { cruft.table = priv->trackers; g_hash_table_foreach_remove(priv->trackers, - trg_state_selector_remove_cruft, - &cruft); + trg_state_selector_remove_cruft, &cruft); } if (priv->showDirs) { cruft.table = priv->directories; g_hash_table_foreach_remove(priv->directories, - trg_state_selector_remove_cruft, - &cruft); + trg_state_selector_remove_cruft, &cruft); } } -void trg_state_selector_set_show_dirs(TrgStateSelector * s, gboolean show) -{ +void trg_state_selector_set_show_dirs(TrgStateSelector * s, gboolean show) { TrgStateSelectorPrivate *priv = TRG_STATE_SELECTOR_GET_PRIVATE(s); priv->showDirs = show; if (!show) @@ -396,9 +366,15 @@ void trg_state_selector_set_show_dirs(TrgStateSelector * s, gboolean show) trg_state_selector_update(s); } -void trg_state_selector_set_show_trackers(TrgStateSelector * s, - gboolean show) -{ +static void on_torrents_state_change(TrgTorrentModel * model, + guint whatsChanged, gpointer data) { + TrgStateSelector *selector = TRG_STATE_SELECTOR(data); + trg_state_selector_update(selector); + trg_state_selector_stats_update(selector, + trg_torrent_model_get_stats(model)); +} + +void trg_state_selector_set_show_trackers(TrgStateSelector * s, gboolean show) { TrgStateSelectorPrivate *priv = TRG_STATE_SELECTOR_GET_PRIVATE(s); priv->showTrackers = show; if (!show) @@ -408,14 +384,11 @@ void trg_state_selector_set_show_trackers(TrgStateSelector * s, } static void trg_state_selector_add_state(TrgStateSelector * selector, - GtkTreeIter * iter, gint pos, - gchar * icon, gchar * name, - guint32 flag) -{ - TrgStateSelectorPrivate *priv = - TRG_STATE_SELECTOR_GET_PRIVATE(selector); + GtkTreeIter * iter, gint pos, gchar * icon, gchar * name, guint32 flag, + GtkTreeRowReference **rr) { + TrgStateSelectorPrivate *priv = TRG_STATE_SELECTOR_GET_PRIVATE(selector); GtkListStore *model = - GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(selector))); + GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(selector))); if (pos < 0) gtk_list_store_append(priv->store, iter); @@ -423,17 +396,17 @@ static void trg_state_selector_add_state(TrgStateSelector * selector, gtk_list_store_insert(priv->store, iter, pos); gtk_list_store_set(model, iter, STATE_SELECTOR_ICON, icon, - STATE_SELECTOR_NAME, name, STATE_SELECTOR_BIT, flag, - STATE_SELECTOR_INDEX, - gtk_tree_model_iter_n_children(GTK_TREE_MODEL - (model), NULL) - 1, - -1); + STATE_SELECTOR_NAME, name, STATE_SELECTOR_BIT, flag, + STATE_SELECTOR_INDEX, gtk_tree_model_iter_n_children(GTK_TREE_MODEL + (model), NULL) - 1, -1); + + if (rr) + *rr = quick_tree_ref_new(GTK_TREE_MODEL(model), iter); priv->n_categories++; } -static void remove_row_ref_and_free(GtkTreeRowReference * rr) -{ +static void remove_row_ref_and_free(GtkTreeRowReference * rr) { GtkTreeModel *model = gtk_tree_row_reference_get_model(rr); GtkTreePath *path = gtk_tree_row_reference_get_path(rr); GtkTreeIter iter; @@ -444,27 +417,53 @@ static void remove_row_ref_and_free(GtkTreeRowReference * rr) gtk_tree_row_reference_free(rr); } +static void trg_state_selector_update_stat(GtkTreeRowReference *rr, gint count) { + if (rr) { + GValue gvalue = { 0 }; + GtkTreeIter iter; + GtkTreePath *path = gtk_tree_row_reference_get_path(rr); + GtkTreeModel *model = gtk_tree_row_reference_get_model(rr); + + gtk_tree_model_get_iter(model, &iter, path); + + g_value_init(&gvalue, G_TYPE_INT); + g_value_set_int(&gvalue, count); + gtk_list_store_set_value(GTK_LIST_STORE(model), &iter, + STATE_SELECTOR_COUNT, &gvalue); + + gtk_tree_path_free(path); + } +} + void trg_state_selector_stats_update(TrgStateSelector * s, - trg_torrent_model_update_stats * - stats) -{ + trg_torrent_model_update_stats * stats) { TrgStateSelectorPrivate *priv = TRG_STATE_SELECTOR_GET_PRIVATE(s); GtkTreeIter iter; if (stats->error > 0 && !priv->error_rr) { trg_state_selector_add_state(s, &iter, priv->n_categories - 1, - GTK_STOCK_DIALOG_WARNING, _("Error"), - TORRENT_FLAG_ERROR); - priv->error_rr = - quick_tree_ref_new(GTK_TREE_MODEL(priv->store), &iter); + GTK_STOCK_DIALOG_WARNING, _("Error"), TORRENT_FLAG_ERROR, + &priv->error_rr); + } else if (stats->error < 1 && priv->error_rr) { remove_row_ref_and_free(priv->error_rr); priv->error_rr = NULL; priv->n_categories--; } + + trg_state_selector_update_stat(priv->all_rr, stats->count); + trg_state_selector_update_stat(priv->down_rr, stats->down); + trg_state_selector_update_stat(priv->seeding_rr, stats->seeding); + trg_state_selector_update_stat(priv->error_rr, stats->error); + trg_state_selector_update_stat(priv->paused_rr, stats->paused); + trg_state_selector_update_stat(priv->complete_rr, stats->complete); + trg_state_selector_update_stat(priv->incomplete_rr, stats->incomplete); + trg_state_selector_update_stat(priv->active_rr, stats->active); + trg_state_selector_update_stat(priv->checking_rr, stats->checking); + trg_state_selector_update_stat(priv->down_wait_rr, stats->down_wait); + trg_state_selector_update_stat(priv->seed_wait_rr, stats->seed_wait); } -void trg_state_selector_disconnect(TrgStateSelector * s) -{ +void trg_state_selector_disconnect(TrgStateSelector * s) { TrgStateSelectorPrivate *priv = TRG_STATE_SELECTOR_GET_PRIVATE(s); if (priv->error_rr) { @@ -475,23 +474,32 @@ void trg_state_selector_disconnect(TrgStateSelector * s) g_hash_table_remove_all(priv->trackers); g_hash_table_remove_all(priv->directories); + + trg_state_selector_update_stat(priv->all_rr, -1); + trg_state_selector_update_stat(priv->down_rr, -1); + trg_state_selector_update_stat(priv->seeding_rr, -1); + trg_state_selector_update_stat(priv->error_rr, -1); + trg_state_selector_update_stat(priv->paused_rr, -1); + trg_state_selector_update_stat(priv->complete_rr, -1); + trg_state_selector_update_stat(priv->incomplete_rr, -1); + trg_state_selector_update_stat(priv->active_rr, -1); + trg_state_selector_update_stat(priv->checking_rr, -1); } -static void trg_state_selector_init(TrgStateSelector * self) -{ +static void trg_state_selector_init(TrgStateSelector * self) { } -TrgStateSelector *trg_state_selector_new(TrgClient * client) -{ - return g_object_new(TRG_TYPE_STATE_SELECTOR, "client", client, NULL); +TrgStateSelector *trg_state_selector_new(TrgClient * client, + TrgTorrentModel *tmodel) { + TrgStateSelector *selector = g_object_new(TRG_TYPE_STATE_SELECTOR, "client", + client, NULL); + g_signal_connect(tmodel, "torrents-state-change", + G_CALLBACK(on_torrents_state_change), selector); + return selector; } static GObject *trg_state_selector_constructor(GType type, - guint - n_construct_properties, - GObjectConstructParam * - construct_params) -{ + guint n_construct_properties, GObjectConstructParam * construct_params) { GObject *object; TrgStateSelector *selector; TrgStateSelectorPrivate *priv; @@ -503,20 +511,17 @@ static GObject *trg_state_selector_constructor(GType type, GtkTreeSelection *selection; object = G_OBJECT_CLASS - (trg_state_selector_parent_class)->constructor(type, - n_construct_properties, - construct_params); + (trg_state_selector_parent_class)->constructor(type, + n_construct_properties, construct_params); selector = TRG_STATE_SELECTOR(object); priv = TRG_STATE_SELECTOR_GET_PRIVATE(object); priv->urlHostRegex = trg_uri_host_regex_new(); priv->trackers = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, - (GDestroyNotify) - remove_row_ref_and_free); - priv->directories = - g_hash_table_new_full(g_str_hash, g_str_equal, g_free, - (GDestroyNotify) remove_row_ref_and_free); + (GDestroyNotify) remove_row_ref_and_free); + priv->directories = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, + (GDestroyNotify) remove_row_ref_and_free); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(object), FALSE); @@ -525,110 +530,95 @@ static GObject *trg_state_selector_constructor(GType type, renderer = gtk_cell_renderer_pixbuf_new(); gtk_tree_view_column_pack_start(column, renderer, FALSE); g_object_set(renderer, "stock-size", 4, NULL); - gtk_tree_view_column_set_attributes(column, renderer, "stock-id", STATE_SELECTOR_ICON, - NULL); + gtk_tree_view_column_set_attributes(column, renderer, "stock-id", + STATE_SELECTOR_ICON, NULL); - renderer = gtk_cell_renderer_text_new(); + renderer = trg_cell_renderer_counter_new(); gtk_tree_view_column_pack_start(column, renderer, TRUE); - gtk_tree_view_column_set_attributes(column, renderer, "text", STATE_SELECTOR_NAME, NULL); + gtk_tree_view_column_set_attributes(column, renderer, "state-label", + STATE_SELECTOR_NAME, "state-count", STATE_SELECTOR_COUNT, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(object), column); - store = priv->store = - gtk_list_store_new(STATE_SELECTOR_COLUMNS, G_TYPE_STRING, - G_TYPE_STRING, G_TYPE_UINT, G_TYPE_INT64, - G_TYPE_UINT); + store = priv->store = gtk_list_store_new(STATE_SELECTOR_COLUMNS, + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_UINT, G_TYPE_INT64, + G_TYPE_UINT); gtk_tree_view_set_model(GTK_TREE_VIEW(object), GTK_TREE_MODEL(store)); - trg_state_selector_add_state(selector, &iter, -1, GTK_STOCK_ABOUT, - _("All"), 0); + trg_state_selector_add_state(selector, &iter, -1, GTK_STOCK_ABOUT, _("All"), + 0, &priv->all_rr); trg_state_selector_add_state(selector, &iter, -1, GTK_STOCK_GO_DOWN, - _("Downloading"), - TORRENT_FLAG_DOWNLOADING); - trg_state_selector_add_state(selector, &iter, -1, - GTK_STOCK_MEDIA_REWIND, _("Queue Down"), - TORRENT_FLAG_DOWNLOADING_WAIT); + _("Downloading"), TORRENT_FLAG_DOWNLOADING, &priv->down_rr); + trg_state_selector_add_state(selector, &iter, -1, GTK_STOCK_MEDIA_REWIND, + _("Queue Down"), TORRENT_FLAG_DOWNLOADING_WAIT, &priv->down_wait_rr); trg_state_selector_add_state(selector, &iter, -1, GTK_STOCK_GO_UP, - _("Seeding"), TORRENT_FLAG_SEEDING); - trg_state_selector_add_state(selector, &iter, -1, - GTK_STOCK_MEDIA_FORWARD, _("Queue Up"), - TORRENT_FLAG_SEEDING_WAIT); - trg_state_selector_add_state(selector, &iter, -1, - GTK_STOCK_MEDIA_PAUSE, _("Paused"), - TORRENT_FLAG_PAUSED); + _("Seeding"), TORRENT_FLAG_SEEDING, &priv->seeding_rr); + trg_state_selector_add_state(selector, &iter, -1, GTK_STOCK_MEDIA_FORWARD, + _("Queue Up"), TORRENT_FLAG_SEEDING_WAIT, &priv->seed_wait_rr); + trg_state_selector_add_state(selector, &iter, -1, GTK_STOCK_MEDIA_PAUSE, + _("Paused"), TORRENT_FLAG_PAUSED, &priv->paused_rr); trg_state_selector_add_state(selector, &iter, -1, GTK_STOCK_APPLY, - _("Complete"), TORRENT_FLAG_COMPLETE); + _("Complete"), TORRENT_FLAG_COMPLETE, &priv->complete_rr); trg_state_selector_add_state(selector, &iter, -1, GTK_STOCK_SELECT_ALL, - _("Incomplete"), TORRENT_FLAG_INCOMPLETE); + _("Incomplete"), TORRENT_FLAG_INCOMPLETE, &priv->incomplete_rr); trg_state_selector_add_state(selector, &iter, -1, GTK_STOCK_NETWORK, - _("Active"), TORRENT_FLAG_ACTIVE); + _("Active"), TORRENT_FLAG_ACTIVE, &priv->active_rr); trg_state_selector_add_state(selector, &iter, -1, GTK_STOCK_REFRESH, - _("Checking"), TORRENT_FLAG_CHECKING_ANY); - trg_state_selector_add_state(selector, &iter, -1, NULL, NULL, 0); + _("Checking"), TORRENT_FLAG_CHECKING_ANY, &priv->checking_rr); + trg_state_selector_add_state(selector, &iter, -1, NULL, NULL, 0, NULL); gtk_tree_view_set_rubber_banding(GTK_TREE_VIEW(object), TRUE); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(object)); g_signal_connect(G_OBJECT(selection), "changed", - G_CALLBACK(state_selection_changed), object); + G_CALLBACK(state_selection_changed), object); g_signal_connect(object, "button-press-event", - G_CALLBACK(view_onButtonPressed), NULL); - g_signal_connect(object, "popup-menu", G_CALLBACK(view_onPopupMenu), - NULL); + G_CALLBACK(view_onButtonPressed), NULL); + g_signal_connect(object, "popup-menu", G_CALLBACK(view_onPopupMenu), NULL); - gtk_tree_view_set_search_column(GTK_TREE_VIEW(object), - STATE_SELECTOR_NAME); + gtk_tree_view_set_search_column(GTK_TREE_VIEW(object), STATE_SELECTOR_NAME); index = trg_prefs_get_int(priv->prefs, TRG_PREFS_STATE_SELECTOR_LAST, - TRG_PREFS_GLOBAL); - if (index > 0 && gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), - &iter, NULL, index)) { - GtkTreeSelection *selection = - gtk_tree_view_get_selection(GTK_TREE_VIEW(object)); + TRG_PREFS_GLOBAL); + if (index > 0 + && gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &iter, NULL, + index)) { + GtkTreeSelection *selection = gtk_tree_view_get_selection( + GTK_TREE_VIEW(object)); gtk_tree_selection_select_iter(selection, &iter); } - priv->showDirs = - trg_prefs_get_bool(priv->prefs, TRG_PREFS_KEY_FILTER_DIRS, - TRG_PREFS_GLOBAL); - priv->showTrackers = - trg_prefs_get_bool(priv->prefs, TRG_PREFS_KEY_FILTER_TRACKERS, - TRG_PREFS_GLOBAL); + priv->showDirs = trg_prefs_get_bool(priv->prefs, TRG_PREFS_KEY_FILTER_DIRS, + TRG_PREFS_GLOBAL); + priv->showTrackers = trg_prefs_get_bool(priv->prefs, + TRG_PREFS_KEY_FILTER_TRACKERS, TRG_PREFS_GLOBAL); return object; } void trg_state_selector_set_queues_enabled(TrgStateSelector * s, - gboolean enabled) -{ + gboolean enabled) { TrgStateSelectorPrivate *priv = TRG_STATE_SELECTOR_GET_PRIVATE(s); - GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(s)); GtkTreeIter iter; if (enabled) { trg_state_selector_add_state(s, &iter, 2, GTK_STOCK_MEDIA_REWIND, - _("Queue Down"), - TORRENT_FLAG_DOWNLOADING_WAIT); + _("Queue Down"), TORRENT_FLAG_DOWNLOADING_WAIT, &priv->down_wait_rr); trg_state_selector_add_state(s, &iter, 4, GTK_STOCK_MEDIA_FORWARD, - _("Queue Up"), - TORRENT_FLAG_SEEDING_WAIT); + _("Queue Up"), TORRENT_FLAG_SEEDING_WAIT, &priv->seed_wait_rr); } else { - gtk_tree_model_iter_nth_child(model, &iter, NULL, 4); - gtk_list_store_remove(GTK_LIST_STORE(model), &iter); - - gtk_tree_model_iter_nth_child(model, &iter, NULL, 2); - gtk_list_store_remove(GTK_LIST_STORE(model), &iter); + remove_row_ref_and_free(priv->seed_wait_rr); + remove_row_ref_and_free(priv->down_wait_rr); + priv->down_wait_rr = NULL; + priv->seed_wait_rr = NULL; priv->n_categories -= 2; } } -static void trg_state_selector_get_property(GObject * object, - guint property_id, - GValue * value, - GParamSpec * pspec) -{ +static void trg_state_selector_get_property(GObject * object, guint property_id, + GValue * value, GParamSpec * pspec) { TrgStateSelectorPrivate *priv = TRG_STATE_SELECTOR_GET_PRIVATE(object); switch (property_id) { case PROP_CLIENT: @@ -640,12 +630,8 @@ static void trg_state_selector_get_property(GObject * object, } } -static void trg_state_selector_set_property(GObject * object, - guint prop_id, - const GValue * value, - GParamSpec * - pspec G_GNUC_UNUSED) -{ +static void trg_state_selector_set_property(GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec G_GNUC_UNUSED) { TrgStateSelectorPrivate *priv = TRG_STATE_SELECTOR_GET_PRIVATE(object); switch (prop_id) { @@ -656,40 +642,31 @@ static void trg_state_selector_set_property(GObject * object, } } -static void trg_state_selector_class_init(TrgStateSelectorClass * klass) -{ +static void trg_state_selector_class_init(TrgStateSelectorClass * klass) { GObjectClass *object_class = G_OBJECT_CLASS(klass); object_class->constructor = trg_state_selector_constructor; object_class->set_property = trg_state_selector_set_property; object_class->get_property = trg_state_selector_get_property; signals[SELECTOR_STATE_CHANGED] = g_signal_new("torrent-state-changed", - G_TYPE_FROM_CLASS - (object_class), - G_SIGNAL_RUN_LAST | - G_SIGNAL_ACTION, - G_STRUCT_OFFSET - (TrgStateSelectorClass, - torrent_state_changed), - NULL, NULL, - g_cclosure_marshal_VOID__UINT, - G_TYPE_NONE, 1, - G_TYPE_UINT); - - g_object_class_install_property(object_class, - PROP_CLIENT, - g_param_spec_object("client", - "Client", - "Client", - TRG_TYPE_CLIENT, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY - | - G_PARAM_STATIC_NAME - | - G_PARAM_STATIC_NICK - | - G_PARAM_STATIC_BLURB)); + G_TYPE_FROM_CLASS + (object_class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET + (TrgStateSelectorClass, + torrent_state_changed), NULL, NULL, + g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); + + g_object_class_install_property( + object_class, + PROP_CLIENT, + g_param_spec_object( + "client", + "Client", + "Client", + TRG_TYPE_CLIENT, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY + | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK + | G_PARAM_STATIC_BLURB)); g_type_class_add_private(klass, sizeof(TrgStateSelectorPrivate)); } diff --git a/src/trg-state-selector.h b/src/trg-state-selector.h index 11b97a4..f002b3b 100644 --- a/src/trg-state-selector.h +++ b/src/trg-state-selector.h @@ -29,6 +29,7 @@ enum { STATE_SELECTOR_ICON, STATE_SELECTOR_NAME, + STATE_SELECTOR_COUNT, STATE_SELECTOR_BIT, STATE_SELECTOR_SERIAL, STATE_SELECTOR_INDEX, @@ -60,7 +61,7 @@ typedef struct { } TrgStateSelectorClass; GType trg_state_selector_get_type(void); -TrgStateSelector *trg_state_selector_new(TrgClient * client); +TrgStateSelector *trg_state_selector_new(TrgClient * client, TrgTorrentModel *tmodel); G_END_DECLS guint32 trg_state_selector_get_flag(TrgStateSelector * s); void trg_state_selector_update(TrgStateSelector * s); diff --git a/src/trg-torrent-model.c b/src/trg-torrent-model.c index 3dd7f9f..e46b876 100644 --- a/src/trg-torrent-model.c +++ b/src/trg-torrent-model.c @@ -54,7 +54,7 @@ enum { TMODEL_TORRENT_COMPLETED, TMODEL_TORRENT_ADDED, - TMODEL_UPDATE_FILTERS, + TMODEL_STATE_CHANGED, TMODEL_SIGNAL_COUNT }; @@ -73,8 +73,7 @@ struct _TrgTorrentModelPrivate { trg_torrent_model_update_stats stats; }; -static void trg_torrent_model_dispose(GObject * object) -{ +static void trg_torrent_model_dispose(GObject * object) { TrgTorrentModelPrivate *priv = TRG_TORRENT_MODEL_GET_PRIVATE(object); g_hash_table_destroy(priv->ht); G_OBJECT_CLASS(trg_torrent_model_parent_class)->dispose(object); @@ -82,69 +81,49 @@ static void trg_torrent_model_dispose(GObject * object) static void update_torrent_iter(TrgTorrentModel * model, TrgClient * tc, gint64 rpcv, - gint64 serial, GtkTreeIter * iter, JsonObject * t, - trg_torrent_model_update_stats * stats, - gboolean * updateFilters); + gint64 serial, GtkTreeIter * iter, JsonObject * t, + trg_torrent_model_update_stats * stats, guint *whatsChanged); -static void trg_torrent_model_class_init(TrgTorrentModelClass * klass) -{ +static void trg_torrent_model_class_init(TrgTorrentModelClass * klass) { GObjectClass *object_class = G_OBJECT_CLASS(klass); g_type_class_add_private(klass, sizeof(TrgTorrentModelPrivate)); object_class->dispose = trg_torrent_model_dispose; signals[TMODEL_TORRENT_COMPLETED] = g_signal_new("torrent-completed", - G_TYPE_FROM_CLASS - (object_class), - G_SIGNAL_RUN_LAST | - G_SIGNAL_ACTION, - G_STRUCT_OFFSET - (TrgTorrentModelClass, - torrent_completed), - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, - G_TYPE_POINTER); + G_TYPE_FROM_CLASS + (object_class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET + (TrgTorrentModelClass, + torrent_completed), NULL, NULL, + g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); signals[TMODEL_TORRENT_ADDED] = g_signal_new("torrent-added", - G_TYPE_FROM_CLASS - (object_class), - G_SIGNAL_RUN_LAST | - G_SIGNAL_ACTION, - G_STRUCT_OFFSET - (TrgTorrentModelClass, - torrent_added), NULL, - NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, - G_TYPE_POINTER); - - signals[TMODEL_UPDATE_FILTERS] = g_signal_new("update-filters", - G_TYPE_FROM_CLASS - (object_class), - G_SIGNAL_RUN_LAST | - G_SIGNAL_ACTION, - G_STRUCT_OFFSET - (TrgTorrentModelClass, - torrent_removed), NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + G_TYPE_FROM_CLASS + (object_class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET + (TrgTorrentModelClass, + torrent_added), NULL, NULL, + g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); + + signals[TMODEL_STATE_CHANGED] = g_signal_new("torrents-state-change", + G_TYPE_FROM_CLASS + (object_class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET + (TrgTorrentModelClass, + torrent_removed), NULL, NULL, g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, 1, G_TYPE_UINT); } -trg_torrent_model_update_stats *trg_torrent_model_get_stats(TrgTorrentModel - * model) -{ +trg_torrent_model_update_stats *trg_torrent_model_get_stats( + TrgTorrentModel * model) { TrgTorrentModelPrivate *priv = TRG_TORRENT_MODEL_GET_PRIVATE(model); return &(priv->stats); } static void trg_torrent_model_count_peers(TrgTorrentModel * model, - GtkTreeIter * iter, - JsonObject * t) -{ - GList *trackersList = - json_array_get_elements(torrent_get_tracker_stats(t)); + GtkTreeIter * iter, JsonObject * t) { + GList *trackersList = json_array_get_elements(torrent_get_tracker_stats(t)); gint seeders = 0; gint leechers = 0; gint downloads = 0; @@ -161,12 +140,11 @@ static void trg_torrent_model_count_peers(TrgTorrentModel * model, g_list_free(trackersList); gtk_list_store_set(GTK_LIST_STORE(model), iter, TORRENT_COLUMN_SEEDS, - seeders, TORRENT_COLUMN_LEECHERS, leechers, - TORRENT_COLUMN_DOWNLOADS, downloads, -1); + seeders, TORRENT_COLUMN_LEECHERS, leechers, + TORRENT_COLUMN_DOWNLOADS, downloads, -1); } -static void trg_torrent_model_ref_free(gpointer data) -{ +static void trg_torrent_model_ref_free(gpointer data) { GtkTreeRowReference *rr = (GtkTreeRowReference *) data; GtkTreeModel *model = gtk_tree_row_reference_get_model(rr); GtkTreePath *path = gtk_tree_row_reference_get_path(rr); @@ -174,14 +152,13 @@ static void trg_torrent_model_ref_free(gpointer data) GtkTreeIter iter; JsonObject *json; if (gtk_tree_model_get_iter(model, &iter, path)) { - gtk_tree_model_get(model, &iter, TORRENT_COLUMN_JSON, &json, - -1); + gtk_tree_model_get(model, &iter, TORRENT_COLUMN_JSON, &json, -1); json_object_unref(json); g_object_set_data(G_OBJECT(model), PROP_REMOVE_IN_PROGRESS, - GINT_TO_POINTER(TRUE)); + GINT_TO_POINTER(TRUE)); gtk_list_store_remove(GTK_LIST_STORE(model), &iter); g_object_set_data(G_OBJECT(model), PROP_REMOVE_IN_PROGRESS, - GINT_TO_POINTER(FALSE)); + GINT_TO_POINTER(FALSE)); } gtk_tree_path_free(path); @@ -190,8 +167,7 @@ static void trg_torrent_model_ref_free(gpointer data) gtk_tree_row_reference_free(rr); } -static void trg_torrent_model_init(TrgTorrentModel * self) -{ +static void trg_torrent_model_init(TrgTorrentModel * self) { TrgTorrentModelPrivate *priv = TRG_TORRENT_MODEL_GET_PRIVATE(self); GType column_types[TORRENT_COLUMN_COLUMNS]; @@ -234,43 +210,35 @@ static void trg_torrent_model_init(TrgTorrentModel * self) column_types[TORRENT_COLUMN_LASTACTIVE] = G_TYPE_INT64; gtk_list_store_set_column_types(GTK_LIST_STORE(self), - TORRENT_COLUMN_COLUMNS, column_types); + TORRENT_COLUMN_COLUMNS, column_types); priv->ht = g_hash_table_new_full(g_int64_hash, g_int64_equal, - (GDestroyNotify) g_free, - trg_torrent_model_ref_free); + (GDestroyNotify) g_free, trg_torrent_model_ref_free); g_object_set_data(G_OBJECT(self), PROP_REMOVE_IN_PROGRESS, - GINT_TO_POINTER(FALSE)); + GINT_TO_POINTER(FALSE)); priv->urlHostRegex = trg_uri_host_regex_new(); } -gboolean trg_torrent_model_is_remove_in_progress(TrgTorrentModel * model) -{ +gboolean trg_torrent_model_is_remove_in_progress(TrgTorrentModel * model) { return (gboolean) GPOINTER_TO_INT(g_object_get_data - (G_OBJECT(model), - PROP_REMOVE_IN_PROGRESS)); + (G_OBJECT(model), + PROP_REMOVE_IN_PROGRESS)); } -static gboolean -trg_torrent_model_reload_dir_aliases_foreachfunc(GtkTreeModel * model, - GtkTreePath * - path G_GNUC_UNUSED, - GtkTreeIter * iter, - gpointer gdata) -{ +static gboolean trg_torrent_model_reload_dir_aliases_foreachfunc( + GtkTreeModel * model, GtkTreePath * path G_GNUC_UNUSED, + GtkTreeIter * iter, gpointer gdata) { gchar *downloadDir, *shortDownloadDir; - gtk_tree_model_get(model, iter, TORRENT_COLUMN_DOWNLOADDIR, - &downloadDir, -1); + gtk_tree_model_get(model, iter, TORRENT_COLUMN_DOWNLOADDIR, &downloadDir, + -1); - shortDownloadDir = - shorten_download_dir((TrgClient *) gdata, downloadDir); + shortDownloadDir = shorten_download_dir((TrgClient *) gdata, downloadDir); gtk_list_store_set(GTK_LIST_STORE(model), iter, - TORRENT_COLUMN_DOWNLOADDIR_SHORT, shortDownloadDir, - -1); + TORRENT_COLUMN_DOWNLOADDIR_SHORT, shortDownloadDir, -1); g_free(downloadDir); g_free(shortDownloadDir); @@ -278,57 +246,68 @@ trg_torrent_model_reload_dir_aliases_foreachfunc(GtkTreeModel * model, return FALSE; } -void trg_torrent_model_reload_dir_aliases(TrgClient * tc, - GtkTreeModel * model) -{ +void trg_torrent_model_reload_dir_aliases(TrgClient * tc, GtkTreeModel * model) { gtk_tree_model_foreach(model, - trg_torrent_model_reload_dir_aliases_foreachfunc, - tc); + trg_torrent_model_reload_dir_aliases_foreachfunc, tc); } -static gboolean trg_torrent_model_stats_scan_foreachfunc(GtkTreeModel * - model, - GtkTreePath * - path - G_GNUC_UNUSED, - GtkTreeIter * - iter, - gpointer gdata) -{ +static gboolean trg_torrent_model_stats_scan_foreachfunc(GtkTreeModel * model, + GtkTreePath * path G_GNUC_UNUSED, GtkTreeIter * iter, gpointer gdata) { trg_torrent_model_update_stats *stats = - (trg_torrent_model_update_stats *) gdata; + (trg_torrent_model_update_stats *) gdata; guint flags; gtk_tree_model_get(model, iter, TORRENT_COLUMN_FLAGS, &flags, -1); - if (flags & TORRENT_FLAG_SEEDING) + if (flags & TORRENT_FLAG_SEEDING + ) stats->seeding++; - else if (flags & TORRENT_FLAG_DOWNLOADING) + else if (flags & TORRENT_FLAG_DOWNLOADING + ) stats->down++; - else if (flags & TORRENT_FLAG_PAUSED) + else if (flags & TORRENT_FLAG_PAUSED + ) stats->paused++; - if (flags & TORRENT_FLAG_ERROR) + if (flags & TORRENT_FLAG_ERROR + ) stats->error++; + if (flags & TORRENT_FLAG_COMPLETE + ) + stats->complete++; + else + stats->incomplete++; + + if (flags & TORRENT_FLAG_CHECKING + ) + stats->checking++; + + if (flags & TORRENT_FLAG_ACTIVE + ) + stats->active++; + + if (flags & TORRENT_FLAG_SEEDING_WAIT) + stats->seed_wait++; + + if (flags & TORRENT_FLAG_DOWNLOADING_WAIT) + stats->down_wait++; + stats->count++; return FALSE; } -void trg_torrent_model_remove_all(TrgTorrentModel * model) -{ +void trg_torrent_model_remove_all(TrgTorrentModel * model) { TrgTorrentModelPrivate *priv = TRG_TORRENT_MODEL_GET_PRIVATE(model); g_hash_table_remove_all(priv->ht); gtk_list_store_clear(GTK_LIST_STORE(model)); } -gchar *shorten_download_dir(TrgClient * tc, const gchar * downloadDir) -{ +gchar *shorten_download_dir(TrgClient * tc, const gchar * downloadDir) { TrgPrefs *prefs = trg_client_get_prefs(tc); - JsonArray *labels = - trg_prefs_get_array(prefs, TRG_PREFS_KEY_DESTINATIONS, - TRG_PREFS_CONNECTION); + JsonArray *labels = trg_prefs_get_array(prefs, TRG_PREFS_KEY_DESTINATIONS, + TRG_PREFS_CONNECTION); JsonObject *session = trg_client_get_session(tc); const gchar *defaultDownloadDir = session_get_download_dir(session); gchar *shortDownloadDir = NULL; @@ -338,15 +317,13 @@ gchar *shorten_download_dir(TrgClient * tc, const gchar * downloadDir) if (labelsList) { GList *li; for (li = labelsList; li; li = g_list_next(li)) { - JsonObject *labelObj = json_node_get_object((JsonNode *) - li->data); - const gchar *labelDir = - json_object_get_string_member(labelObj, - TRG_PREFS_KEY_DESTINATIONS_SUBKEY_DIR); + JsonObject *labelObj = json_node_get_object( + (JsonNode *) li->data); + const gchar *labelDir = json_object_get_string_member(labelObj, + TRG_PREFS_KEY_DESTINATIONS_SUBKEY_DIR); if (!g_strcmp0(downloadDir, labelDir)) { - const gchar *labelLabel = - json_object_get_string_member(labelObj, - TRG_PREFS_SUBKEY_LABEL); + const gchar *labelLabel = json_object_get_string_member( + labelObj, TRG_PREFS_SUBKEY_LABEL); shortDownloadDir = g_strdup(labelLabel); break; } @@ -374,13 +351,9 @@ gchar *shorten_download_dir(TrgClient * tc, const gchar * downloadDir) return g_strdup(downloadDir); } -static inline void update_torrent_iter(TrgTorrentModel * model, - TrgClient * tc, gint64 rpcv, - gint64 serial, GtkTreeIter * iter, - JsonObject * t, - trg_torrent_model_update_stats * - stats, gboolean * updateFilters) -{ +static inline void update_torrent_iter(TrgTorrentModel * model, TrgClient * tc, + gint64 rpcv, gint64 serial, GtkTreeIter * iter, JsonObject * t, + trg_torrent_model_update_stats * stats, guint *whatsChanged) { TrgTorrentModelPrivate *priv = TRG_TORRENT_MODEL_GET_PRIVATE(model); GtkListStore *ls = GTK_LIST_STORE(model); guint lastFlags, newFlags; @@ -413,165 +386,161 @@ static inline void update_torrent_iter(TrgTorrentModel * model, trackerStats = torrent_get_tracker_stats(t); gtk_tree_model_get(GTK_TREE_MODEL(model), iter, TORRENT_COLUMN_FLAGS, - &lastFlags, TORRENT_COLUMN_JSON, &lastJson, - TORRENT_COLUMN_DOWNLOADDIR, &lastDownloadDir, -1); + &lastFlags, TORRENT_COLUMN_JSON, &lastJson, + TORRENT_COLUMN_DOWNLOADDIR, &lastDownloadDir, -1); json_object_ref(t); if (json_array_get_length(trackerStats) > 0) { - JsonObject *firstTracker = - json_array_get_object_element(trackerStats, - 0); + JsonObject *firstTracker = json_array_get_object_element(trackerStats, + 0); firstTrackerHost = trg_gregex_get_first(priv->urlHostRegex, - tracker_stats_get_host - (firstTracker)); + tracker_stats_get_host(firstTracker)); } lpd = peerfrom_get_lpd(pf); if (newFlags & TORRENT_FLAG_ACTIVE) { if (lpd >= 0) { - peerSources = - g_strdup_printf("%ld / %ld / %ld / %ld / %ld / %ld / %ld", - peerfrom_get_trackers(pf), - peerfrom_get_incoming(pf), - peerfrom_get_ltep(pf), - peerfrom_get_dht(pf), peerfrom_get_pex(pf), - lpd, peerfrom_get_resume(pf)); + peerSources = g_strdup_printf( + "%ld / %ld / %ld / %ld / %ld / %ld / %ld", + peerfrom_get_trackers(pf), peerfrom_get_incoming(pf), + peerfrom_get_ltep(pf), peerfrom_get_dht(pf), + peerfrom_get_pex(pf), lpd, peerfrom_get_resume(pf)); } else { - peerSources = - g_strdup_printf("%ld / %ld / %ld / %ld / %ld / N/A / %ld", - peerfrom_get_trackers(pf), - peerfrom_get_incoming(pf), - peerfrom_get_ltep(pf), - peerfrom_get_dht(pf), peerfrom_get_pex(pf), - peerfrom_get_resume(pf)); + peerSources = g_strdup_printf( + "%ld / %ld / %ld / %ld / %ld / N/A / %ld", + peerfrom_get_trackers(pf), peerfrom_get_incoming(pf), + peerfrom_get_ltep(pf), peerfrom_get_dht(pf), + peerfrom_get_pex(pf), peerfrom_get_resume(pf)); } } #ifdef DEBUG gtk_list_store_set(ls, iter, TORRENT_COLUMN_ICON, statusIcon, -1); gtk_list_store_set(ls, iter, - TORRENT_COLUMN_NAME, torrent_get_name(t), -1); + TORRENT_COLUMN_NAME, torrent_get_name(t), -1); gtk_list_store_set(ls, iter, - TORRENT_COLUMN_SIZE, torrent_get_size(t), -1); + TORRENT_COLUMN_SIZE, torrent_get_size(t), -1); gtk_list_store_set(ls, iter, - TORRENT_COLUMN_DONE, - (newFlags & TORRENT_FLAG_CHECKING) ? - torrent_get_recheck_progress(t) - : torrent_get_percent_done(t), -1); + TORRENT_COLUMN_DONE, + (newFlags & TORRENT_FLAG_CHECKING) ? + torrent_get_recheck_progress(t) + : torrent_get_percent_done(t), -1); gtk_list_store_set(ls, iter, TORRENT_COLUMN_STATUS, statusString, -1); gtk_list_store_set(ls, iter, TORRENT_COLUMN_DOWNSPEED, downRate, -1); gtk_list_store_set(ls, iter, TORRENT_COLUMN_FLAGS, newFlags, -1); gtk_list_store_set(ls, iter, TORRENT_COLUMN_UPSPEED, upRate, -1); gtk_list_store_set(ls, iter, TORRENT_COLUMN_ETA, - torrent_get_eta(t), -1); + torrent_get_eta(t), -1); gtk_list_store_set(ls, iter, TORRENT_COLUMN_UPLOADED, uploaded, -1); gtk_list_store_set(ls, iter, - TORRENT_COLUMN_DOWNLOADED, downloaded, -1); + TORRENT_COLUMN_DOWNLOADED, downloaded, -1); gtk_list_store_set(ls, iter, TORRENT_COLUMN_RATIO, - uploaded > 0 - && downloaded > - 0 ? (double) uploaded / (double) downloaded : 0, - -1); + uploaded > 0 + && downloaded > + 0 ? (double) uploaded / (double) downloaded : 0, + -1); gtk_list_store_set(ls, iter, TORRENT_COLUMN_ID, id, -1); gtk_list_store_set(ls, iter, TORRENT_COLUMN_JSON, t, -1); gtk_list_store_set(ls, iter, TORRENT_COLUMN_UPDATESERIAL, serial, -1); gtk_list_store_set(ls, iter, - TORRENT_COLUMN_ADDED, torrent_get_added_date(t), - -1); + TORRENT_COLUMN_ADDED, torrent_get_added_date(t), + -1); gtk_list_store_set(ls, iter, TORRENT_COLUMN_DOWNLOADDIR, - downloadDir, -1); + downloadDir, -1); gtk_list_store_set(ls, iter, TORRENT_COLUMN_BANDWIDTH_PRIORITY, - torrent_get_bandwidth_priority(t), -1); + torrent_get_bandwidth_priority(t), -1); gtk_list_store_set(ls, iter, TORRENT_COLUMN_DONE_DATE, - torrent_get_done_date(t), -1); + torrent_get_done_date(t), -1); gtk_list_store_set(ls, iter, TORRENT_COLUMN_FROMPEX, - peerfrom_get_pex(pf), -1); + peerfrom_get_pex(pf), -1); gtk_list_store_set(ls, iter, TORRENT_COLUMN_FROMDHT, - peerfrom_get_dht(pf), -1); + peerfrom_get_dht(pf), -1); gtk_list_store_set(ls, iter, TORRENT_COLUMN_FROMTRACKERS, - peerfrom_get_trackers(pf), -1); + peerfrom_get_trackers(pf), -1); gtk_list_store_set(ls, iter, TORRENT_COLUMN_FROMLTEP, - peerfrom_get_ltep(pf), -1); + peerfrom_get_ltep(pf), -1); gtk_list_store_set(ls, iter, TORRENT_COLUMN_FROMRESUME, - peerfrom_get_resume(pf), -1); + peerfrom_get_resume(pf), -1); gtk_list_store_set(ls, iter, TORRENT_COLUMN_FROMINCOMING, - peerfrom_get_incoming(pf), -1); + peerfrom_get_incoming(pf), -1); gtk_list_store_set(ls, iter, TORRENT_COLUMN_PEER_SOURCES, - peerSources, -1); + peerSources, -1); gtk_list_store_set(ls, iter, TORRENT_COLUMN_PEERS_CONNECTED, - torrent_get_peers_connected(t), -1); + torrent_get_peers_connected(t), -1); gtk_list_store_set(ls, iter, TORRENT_COLUMN_PEERS_TO_US, - torrent_get_peers_sending_to_us(t), -1); + torrent_get_peers_sending_to_us(t), -1); gtk_list_store_set(ls, iter, TORRENT_COLUMN_PEERS_FROM_US, - torrent_get_peers_getting_from_us(t), -1); + torrent_get_peers_getting_from_us(t), -1); gtk_list_store_set(ls, iter, TORRENT_COLUMN_TRACKERHOST, - firstTrackerHost ? firstTrackerHost : "", -1); + firstTrackerHost ? firstTrackerHost : "", -1); gtk_list_store_set(ls, iter, TORRENT_COLUMN_QUEUE_POSITION, - torrent_get_queue_position(t), -1); + torrent_get_queue_position(t), -1); gtk_list_store_set(ls, iter, TORRENT_COLUMN_LASTACTIVE, - torrent_get_activity_date(t), -1); + torrent_get_activity_date(t), -1); #else gtk_list_store_set(ls, iter, TORRENT_COLUMN_ICON, statusIcon, - TORRENT_COLUMN_ADDED, torrent_get_added_date(t), - TORRENT_COLUMN_DONE_DATE, torrent_get_done_date(t), - TORRENT_COLUMN_NAME, torrent_get_name(t), - TORRENT_COLUMN_SIZE, torrent_get_size(t), - TORRENT_COLUMN_DONE, - (newFlags & TORRENT_FLAG_CHECKING) ? - torrent_get_recheck_progress(t) - : torrent_get_percent_done(t), - TORRENT_COLUMN_STATUS, statusString, - TORRENT_COLUMN_DOWNSPEED, downRate, - TORRENT_COLUMN_FLAGS, newFlags, - TORRENT_COLUMN_UPSPEED, upRate, TORRENT_COLUMN_ETA, - torrent_get_eta(t), TORRENT_COLUMN_UPLOADED, - uploaded, TORRENT_COLUMN_DOWNLOADED, downloaded, - TORRENT_COLUMN_FROMPEX, peerfrom_get_pex(pf), - TORRENT_COLUMN_FROMDHT, peerfrom_get_dht(pf), - TORRENT_COLUMN_FROMTRACKERS, - peerfrom_get_trackers(pf), TORRENT_COLUMN_FROMLTEP, - peerfrom_get_ltep(pf), TORRENT_COLUMN_FROMRESUME, - peerfrom_get_resume(pf), - TORRENT_COLUMN_FROMINCOMING, - peerfrom_get_incoming(pf), - TORRENT_COLUMN_PEER_SOURCES, peerSources, - TORRENT_COLUMN_PEERS_CONNECTED, - torrent_get_peers_connected(t), - TORRENT_COLUMN_PEERS_TO_US, - torrent_get_peers_sending_to_us(t), - TORRENT_COLUMN_PEERS_FROM_US, - torrent_get_peers_getting_from_us(t), - TORRENT_COLUMN_QUEUE_POSITION, - torrent_get_queue_position(t), - TORRENT_COLUMN_LASTACTIVE, - torrent_get_activity_date(t), TORRENT_COLUMN_RATIO, - uploaded > 0 - && downloaded > - 0 ? (double) uploaded / (double) downloaded : 0, - TORRENT_COLUMN_DOWNLOADDIR, downloadDir, - TORRENT_COLUMN_BANDWIDTH_PRIORITY, - torrent_get_bandwidth_priority(t), - TORRENT_COLUMN_ID, id, TORRENT_COLUMN_JSON, t, - TORRENT_COLUMN_TRACKERHOST, - firstTrackerHost ? firstTrackerHost : "", - TORRENT_COLUMN_UPDATESERIAL, serial, -1); + TORRENT_COLUMN_ADDED, torrent_get_added_date(t), + TORRENT_COLUMN_DONE_DATE, torrent_get_done_date(t), + TORRENT_COLUMN_NAME, torrent_get_name(t), TORRENT_COLUMN_SIZE, + torrent_get_size(t), TORRENT_COLUMN_DONE, + (newFlags & TORRENT_FLAG_CHECKING) ? + torrent_get_recheck_progress(t) + : torrent_get_percent_done(t), + TORRENT_COLUMN_STATUS, statusString, + TORRENT_COLUMN_DOWNSPEED, downRate, + TORRENT_COLUMN_FLAGS, newFlags, + TORRENT_COLUMN_UPSPEED, upRate, TORRENT_COLUMN_ETA, + torrent_get_eta(t), TORRENT_COLUMN_UPLOADED, + uploaded, TORRENT_COLUMN_DOWNLOADED, downloaded, + TORRENT_COLUMN_FROMPEX, peerfrom_get_pex(pf), + TORRENT_COLUMN_FROMDHT, peerfrom_get_dht(pf), + TORRENT_COLUMN_FROMTRACKERS, + peerfrom_get_trackers(pf), TORRENT_COLUMN_FROMLTEP, + peerfrom_get_ltep(pf), TORRENT_COLUMN_FROMRESUME, + peerfrom_get_resume(pf), + TORRENT_COLUMN_FROMINCOMING, + peerfrom_get_incoming(pf), + TORRENT_COLUMN_PEER_SOURCES, peerSources, + TORRENT_COLUMN_PEERS_CONNECTED, + torrent_get_peers_connected(t), + TORRENT_COLUMN_PEERS_TO_US, + torrent_get_peers_sending_to_us(t), + TORRENT_COLUMN_PEERS_FROM_US, + torrent_get_peers_getting_from_us(t), + TORRENT_COLUMN_QUEUE_POSITION, + torrent_get_queue_position(t), + TORRENT_COLUMN_LASTACTIVE, + torrent_get_activity_date(t), TORRENT_COLUMN_RATIO, + uploaded > 0 + && downloaded > + 0 ? (double) uploaded / (double) downloaded : 0, + TORRENT_COLUMN_DOWNLOADDIR, downloadDir, + TORRENT_COLUMN_BANDWIDTH_PRIORITY, + torrent_get_bandwidth_priority(t), + TORRENT_COLUMN_ID, id, TORRENT_COLUMN_JSON, t, + TORRENT_COLUMN_TRACKERHOST, + firstTrackerHost ? firstTrackerHost : "", + TORRENT_COLUMN_UPDATESERIAL, serial, -1); #endif if (!lastDownloadDir || g_strcmp0(downloadDir, lastDownloadDir)) { gchar *shortDownloadDir = shorten_download_dir(tc, downloadDir); gtk_list_store_set(ls, iter, TORRENT_COLUMN_DOWNLOADDIR_SHORT, - shortDownloadDir, -1); + shortDownloadDir, -1); g_free(shortDownloadDir); - *updateFilters = TRUE; + *whatsChanged |= TORRENT_UPDATE_PATH_CHANGE; } if (lastJson) json_object_unref(lastJson); if ((lastFlags & TORRENT_FLAG_DOWNLOADING) - && (newFlags & TORRENT_FLAG_COMPLETE)) + && (newFlags & TORRENT_FLAG_COMPLETE)) g_signal_emit(model, signals[TMODEL_TORRENT_COMPLETED], 0, iter); + if (lastFlags != newFlags) + *whatsChanged |= TORRENT_UPDATE_STATE_CHANGE; + trg_torrent_model_count_peers(model, iter, t); if (firstTrackerHost) @@ -585,8 +554,7 @@ static inline void update_torrent_iter(TrgTorrentModel * model, g_free(statusIcon); } -TrgTorrentModel *trg_torrent_model_new(void) -{ +TrgTorrentModel *trg_torrent_model_new(void) { return g_object_new(TRG_TYPE_TORRENT_MODEL, NULL); } @@ -595,23 +563,18 @@ struct TrgModelRemoveData { gint64 currentSerial; }; -GHashTable *get_torrent_table(TrgTorrentModel * model) -{ +GHashTable *get_torrent_table(TrgTorrentModel * model) { TrgTorrentModelPrivate *priv = TRG_TORRENT_MODEL_GET_PRIVATE(model); return priv->ht; } gboolean trg_model_find_removed_foreachfunc(GtkTreeModel * model, - GtkTreePath * - path G_GNUC_UNUSED, - GtkTreeIter * iter, - gpointer gdata) -{ + GtkTreePath * path G_GNUC_UNUSED, GtkTreeIter * iter, gpointer gdata) { struct TrgModelRemoveData *args = (struct TrgModelRemoveData *) gdata; gint64 rowSerial; - gtk_tree_model_get(model, iter, TORRENT_COLUMN_UPDATESERIAL, - &rowSerial, -1); + gtk_tree_model_get(model, iter, TORRENT_COLUMN_UPDATESERIAL, &rowSerial, + -1); if (rowSerial != args->currentSerial) { gint64 *id = g_new(gint64, 1); @@ -623,21 +586,19 @@ gboolean trg_model_find_removed_foreachfunc(GtkTreeModel * model, } GList *trg_torrent_model_find_removed(GtkTreeModel * model, - gint64 currentSerial) -{ + gint64 currentSerial) { struct TrgModelRemoveData args; args.toRemove = NULL; args.currentSerial = currentSerial; gtk_tree_model_foreach(GTK_TREE_MODEL(model), - trg_model_find_removed_foreachfunc, &args); + trg_model_find_removed_foreachfunc, &args); return args.toRemove; } gboolean get_torrent_data(GHashTable * table, gint64 id, JsonObject ** t, - GtkTreeIter * out_iter) -{ + GtkTreeIter * out_iter) { gpointer result = g_hash_table_lookup(table, &id); gboolean found = FALSE; @@ -651,8 +612,7 @@ gboolean get_torrent_data(GHashTable * table, gint64 id, JsonObject ** t, if (out_iter) *out_iter = iter; if (t) - gtk_tree_model_get(model, &iter, TORRENT_COLUMN_JSON, t, - -1); + gtk_tree_model_get(model, &iter, TORRENT_COLUMN_JSON, t, -1); found = TRUE; gtk_tree_path_free(path); } @@ -661,13 +621,16 @@ gboolean get_torrent_data(GHashTable * table, gint64 id, JsonObject ** t, return found; } -trg_torrent_model_update_stats *trg_torrent_model_update(TrgTorrentModel * - model, - TrgClient * tc, - JsonObject * - response, - gint mode) -{ +static void trg_torrent_model_stat_counts_clear( + trg_torrent_model_update_stats *stats) { + stats->count = stats->down = stats->error = stats->paused = stats->seeding = + stats->complete = stats->incomplete = stats->active = + stats->checking = stats->seed_wait = stats->down_wait = 0; +} + +trg_torrent_model_update_stats *trg_torrent_model_update( + TrgTorrentModel * model, TrgClient * tc, JsonObject * response, + gint mode) { TrgTorrentModelPrivate *priv = TRG_TORRENT_MODEL_GET_PRIVATE(model); GList *torrentList; @@ -680,28 +643,30 @@ trg_torrent_model_update_stats *trg_torrent_model_update(TrgTorrentModel * GtkTreePath *path; GtkTreeRowReference *rr; gpointer *result; - gboolean updateFilters = FALSE; + guint whatsChanged = 0; gint64 rpcv = trg_client_get_rpc_version(tc); args = get_arguments(response); torrentList = json_array_get_elements(get_torrents(args)); - memset(&(priv->stats), 0, sizeof(trg_torrent_model_update_stats)); + priv->stats.downRateTotal = 0; + priv->stats.upRateTotal = 0; for (li = torrentList; li; li = g_list_next(li)) { t = json_node_get_object((JsonNode *) li->data); id = torrent_get_id(t); result = - mode == TORRENT_GET_MODE_FIRST ? NULL : - g_hash_table_lookup(priv->ht, &id); + mode == TORRENT_GET_MODE_FIRST ? NULL : + g_hash_table_lookup(priv->ht, &id); if (!result) { gtk_list_store_append(GTK_LIST_STORE(model), &iter); + whatsChanged |= TORRENT_UPDATE_ADDREMOVE; update_torrent_iter(model, tc, rpcv, trg_client_get_serial(tc), - &iter, t, &(priv->stats), &updateFilters); + &iter, t, &(priv->stats), &whatsChanged); path = gtk_tree_model_get_path(GTK_TREE_MODEL(model), &iter); rr = gtk_tree_row_reference_new(GTK_TREE_MODEL(model), path); @@ -709,18 +674,19 @@ trg_torrent_model_update_stats *trg_torrent_model_update(TrgTorrentModel * *idCopy = id; g_hash_table_insert(priv->ht, idCopy, rr); gtk_tree_path_free(path); - if (mode != TORRENT_GET_MODE_FIRST) - g_signal_emit(model, signals[TMODEL_TORRENT_ADDED], 0, - &iter); + + if (mode != TORRENT_GET_MODE_FIRST + ) + g_signal_emit(model, signals[TMODEL_TORRENT_ADDED], 0, &iter); } else { - path = gtk_tree_row_reference_get_path((GtkTreeRowReference *) - result); + path = gtk_tree_row_reference_get_path( + (GtkTreeRowReference *) result); if (path) { if (gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, - path)) { + path)) { update_torrent_iter(model, tc, rpcv, - trg_client_get_serial(tc), &iter, - t, &(priv->stats), &updateFilters); + trg_client_get_serial(tc), &iter, t, &(priv->stats), + &whatsChanged); } gtk_tree_path_free(path); } @@ -730,15 +696,14 @@ trg_torrent_model_update_stats *trg_torrent_model_update(TrgTorrentModel * g_list_free(torrentList); if (mode == TORRENT_GET_MODE_UPDATE) { - GList *hitlist = - trg_torrent_model_find_removed(GTK_TREE_MODEL(model), - trg_client_get_serial(tc)); + GList *hitlist = trg_torrent_model_find_removed(GTK_TREE_MODEL(model), + trg_client_get_serial(tc)); if (hitlist) { for (li = hitlist; li; li = g_list_next(li)) { g_hash_table_remove(priv->ht, li->data); g_free(li->data); } - updateFilters = TRUE; + whatsChanged |= TORRENT_UPDATE_ADDREMOVE; g_list_free(hitlist); } } else if (mode > TORRENT_GET_MODE_FIRST) { @@ -748,18 +713,18 @@ trg_torrent_model_update_stats *trg_torrent_model_update(TrgTorrentModel * for (li = hitlist; li; li = g_list_next(li)) { id = json_node_get_int((JsonNode *) li->data); g_hash_table_remove(priv->ht, &id); - updateFilters = TRUE; + whatsChanged |= TORRENT_UPDATE_ADDREMOVE; } g_list_free(hitlist); } } - if (updateFilters) - g_signal_emit(model, signals[TMODEL_UPDATE_FILTERS], 0); - - gtk_tree_model_foreach(GTK_TREE_MODEL(model), - trg_torrent_model_stats_scan_foreachfunc, - &(priv->stats)); + if (whatsChanged != 0) { + trg_torrent_model_stat_counts_clear(&priv->stats); + gtk_tree_model_foreach(GTK_TREE_MODEL(model), + trg_torrent_model_stats_scan_foreachfunc, &(priv->stats)); + g_signal_emit(model, signals[TMODEL_STATE_CHANGED], 0, whatsChanged); + } return &(priv->stats); } diff --git a/src/trg-torrent-model.h b/src/trg-torrent-model.h index 2a108c9..f245455 100644 --- a/src/trg-torrent-model.h +++ b/src/trg-torrent-model.h @@ -59,8 +59,18 @@ typedef struct { gint paused; gint count; gint error; + gint complete; + gint incomplete; + gint checking; + gint active; + gint seed_wait; + gint down_wait; } trg_torrent_model_update_stats; +#define TORRENT_UPDATE_STATE_CHANGE (1 << 0) +#define TORRENT_UPDATE_PATH_CHANGE (1 << 1) +#define TORRENT_UPDATE_ADDREMOVE (1 << 2) + GType trg_torrent_model_get_type(void); TrgTorrentModel *trg_torrent_model_new(); |