summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Alan Fitton <ajf@eth0.org.uk>2011-04-12 10:54:29 +0000
committerGravatar Alan Fitton <ajf@eth0.org.uk>2011-04-12 10:54:29 +0000
commit42eddac0e9f0216175fef223fd9b1023ed502a6e (patch)
tree7fd853c8fdabc678bc1df0f4eb5160420347ac8e
parentf4a194f08d0c48641f5394cd07be61931a432241 (diff)
some quite significant changes to only receive/update recently-active torrents, if enabled. also use a hash table and tree row references for lookup. hopefully performance will be much better for people with large number of torrents.
-rw-r--r--src/protocol-constants.h2
-rw-r--r--src/requests.c12
-rw-r--r--src/requests.h2
-rw-r--r--src/session-get.c2
-rw-r--r--src/torrent.c8
-rw-r--r--src/torrent.h1
-rw-r--r--src/transmission-remote-gtk.schemas13
-rw-r--r--src/trg-client.c3
-rw-r--r--src/trg-client.h10
-rw-r--r--src/trg-files-model.c18
-rw-r--r--src/trg-files-model.h2
-rw-r--r--src/trg-main-window.c101
-rw-r--r--src/trg-main-window.h4
-rw-r--r--src/trg-menu-bar.c25
-rw-r--r--src/trg-peers-model.c16
-rw-r--r--src/trg-preferences-dialog.c76
-rw-r--r--src/trg-preferences-dialog.h2
-rw-r--r--src/trg-preferences.h1
-rw-r--r--src/trg-state-selector.c29
-rw-r--r--src/trg-torrent-add-dialog.c34
-rw-r--r--src/trg-torrent-model.c221
-rw-r--r--src/trg-torrent-model.h5
-rw-r--r--src/trg-torrent-props-dialog.h1
-rw-r--r--src/trg-torrent-tree-view.c12
-rw-r--r--src/trg-trackers-model.c13
-rw-r--r--src/trg-trackers-model.h4
-rw-r--r--src/trg-trackers-tree-view.c2
27 files changed, 433 insertions, 186 deletions
diff --git a/src/protocol-constants.h b/src/protocol-constants.h
index 5299f3b..e61ca50 100644
--- a/src/protocol-constants.h
+++ b/src/protocol-constants.h
@@ -27,7 +27,9 @@
/* torrents */
+#define FIELD_RECENTLY_ACTIVE "recently-active"
#define FIELD_TORRENTS "torrents" /* parent node */
+#define FIELD_REMOVED "removed"
#define FIELD_ANNOUNCE_URL "announceUrl"
#define FIELD_LEFT_UNTIL_DONE "leftUntilDone"
#define FIELD_TOTAL_SIZE "totalSize"
diff --git a/src/requests.c b/src/requests.c
index d3edc3a..4c841e4 100644
--- a/src/requests.c
+++ b/src/requests.c
@@ -110,10 +110,18 @@ JsonNode *torrent_remove(JsonArray * array, gboolean removeData)
return root;
}
-JsonNode *torrent_get(void)
+JsonNode *torrent_get(gboolean recent)
{
JsonNode *root = base_request(METHOD_TORRENT_GET);
+ JsonObject *args = node_get_arguments(root);
JsonArray *fields = json_array_new();
+
+ if (recent) {
+ JsonArray *ids = json_array_new();
+ json_array_add_string_element(ids, FIELD_RECENTLY_ACTIVE);
+ json_object_set_array_member(args, PARAM_IDS, ids);
+ }
+
json_array_add_string_element(fields, FIELD_ETA);
json_array_add_string_element(fields, FIELD_PEERS);
json_array_add_string_element(fields, FIELD_FILES);
@@ -151,7 +159,7 @@ JsonNode *torrent_get(void)
json_array_add_string_element(fields, FIELD_ERRORSTR);
json_array_add_string_element(fields, FIELD_WANTED);
json_array_add_string_element(fields, FIELD_PRIORITIES);
- json_object_set_array_member(node_get_arguments(root),
+ json_object_set_array_member(args,
PARAM_FIELDS, fields);
return root;
}
diff --git a/src/requests.h b/src/requests.h
index 1b53704..b87cf3f 100644
--- a/src/requests.h
+++ b/src/requests.h
@@ -27,7 +27,7 @@ JsonNode *generic_request(gchar * method, JsonArray * array);
JsonNode *session_set(void);
JsonNode *session_get(void);
-JsonNode *torrent_get(void);
+JsonNode *torrent_get(gboolean recent);
JsonNode *torrent_set(JsonArray * array);
JsonNode *torrent_pause(JsonArray * array);
JsonNode *torrent_start(JsonArray * array);
diff --git a/src/session-get.c b/src/session-get.c
index dd4bfa1..848e72a 100644
--- a/src/session-get.c
+++ b/src/session-get.c
@@ -28,7 +28,7 @@ int session_get_version(JsonObject * s, float *version)
{
const gchar *versionStr =
json_object_get_string_member(s, SGET_VERSION);
- return sscanf(versionStr, "%f", version);
+ return sscanf(versionStr, "%g", version);
}
gboolean session_get_pex_enabled(JsonObject * s)
diff --git a/src/torrent.c b/src/torrent.c
index 3c6f0d4..4c35e06 100644
--- a/src/torrent.c
+++ b/src/torrent.c
@@ -265,6 +265,14 @@ const gchar *tracker_get_scrape(JsonObject * t)
return json_object_get_string_member(t, FIELD_SCRAPE);
}
+JsonArray *get_torrents_removed(JsonObject *response)
+{
+ if (G_UNLIKELY(json_object_has_member(response, FIELD_REMOVED)))
+ return json_object_get_array_member(response, FIELD_REMOVED);
+ else
+ return NULL;
+}
+
JsonArray *get_torrents(JsonObject * response)
{
return json_object_get_array_member(response, FIELD_TORRENTS);
diff --git a/src/torrent.h b/src/torrent.h
index 248e0d4..3376dd2 100644
--- a/src/torrent.h
+++ b/src/torrent.h
@@ -74,5 +74,6 @@ gint64 torrent_get_peer_limit(JsonObject * t);
gboolean torrent_has_tracker(JsonObject * t, GRegex * rx, gchar * search);
JsonArray *get_torrents(JsonObject * response);
+JsonArray *get_torrents_removed(JsonObject *response);
#endif /* TORRENT_H_ */
diff --git a/src/transmission-remote-gtk.schemas b/src/transmission-remote-gtk.schemas
index 11415a8..7b56d1a 100644
--- a/src/transmission-remote-gtk.schemas
+++ b/src/transmission-remote-gtk.schemas
@@ -15,6 +15,19 @@
</schema>
<schema>
+ <key>/schemas/apps/transmission-remote-gtk/update-active-only</key>
+ <applyto>/apps/transmission-remote-gtk/update-active-only</applyto>
+ <owner>transmission-remote-gtk</owner>
+ <type>bool</type>
+ <default>0</default>
+
+ <locale name="C">
+ <short>Update Active Only</short>
+ <long>Update Active Only</long>
+ </locale>
+ </schema>
+
+ <schema>
<key>/schemas/apps/transmission-remote-gtk/auto-connect</key>
<applyto>/apps/transmission-remote-gtk/auto-connect</applyto>
<owner>transmission-remote-gtk</owner>
diff --git a/src/trg-client.c b/src/trg-client.c
index 2ed8ffa..d2e0cf3 100644
--- a/src/trg-client.c
+++ b/src/trg-client.c
@@ -45,6 +45,7 @@ trg_client *trg_init_client()
client = g_new0(trg_client, 1);
client->gconf = gconf_client_get_default();
client->updateMutex = g_mutex_new();
+ client->activeOnlyUpdate = gconf_client_get_bool(client->gconf, TRG_GCONF_KEY_UPDATE_ACTIVE_ONLY, NULL);
return client;
}
@@ -56,7 +57,7 @@ void trg_client_set_session(trg_client * tc, JsonObject * session)
if (tc->session != NULL)
json_object_unref(tc->session);
- session_get_version(session, &(tc->version));
+ session_get_version(session, &tc->version);
tc->session = session;
}
diff --git a/src/trg-client.h b/src/trg-client.h
index 51d851d..480d828 100644
--- a/src/trg-client.h
+++ b/src/trg-client.h
@@ -20,6 +20,13 @@
#ifndef TRG_CLIENT_H_
#define TRG_CLIENT_H_
+#define TRANSMISSION_MIN_SUPPORTED 2.0
+
+#define TORRENT_GET_MODE_FIRST 0
+#define TORRENT_GET_MODE_ACTIVE 1
+#define TORRENT_GET_MODE_INTERACTION 2
+#define TORRENT_GET_MODE_UPDATE 3
+
#define TRG_GCONF_SCHEMA_ERROR -1
#define TRG_NO_HOSTNAME_SET -2
@@ -30,6 +37,7 @@
typedef struct {
char *session_id;
+ gboolean activeOnlyUpdate;
gint failCount;
gint interval;
gint64 updateSerial;
@@ -40,7 +48,7 @@ typedef struct {
char *username;
char *password;
char *proxy;
- JsonArray *torrents;
+ GHashTable *torrentTable;
GConfClient *gconf;
GMutex *updateMutex;
} trg_client;
diff --git a/src/trg-files-model.c b/src/trg-files-model.c
index 084997d..ccc4757 100644
--- a/src/trg-files-model.c
+++ b/src/trg-files-model.c
@@ -21,6 +21,7 @@
#include <json-glib/json-glib.h>
#include "trg-files-model.h"
+#include "trg-client.h"
#include "torrent.h"
#include "tfile.h"
#include "util.h"
@@ -129,30 +130,29 @@ trg_files_model_update_foreach(GtkListStore * model,
void
trg_files_model_update(TrgFilesModel * model, gint64 updateSerial,
- JsonObject * t, gboolean first)
+ JsonObject * t, gint mode)
{
TrgFilesModelPrivate *priv = TRG_FILES_MODEL_GET_PRIVATE(model);
- guint j;
-
- if (first)
- gtk_list_store_clear(GTK_LIST_STORE(model));
+ GList *li;
+ gint j = 0;
priv->torrentId = torrent_get_id(t);
priv->priorities = torrent_get_priorities(t);
priv->wanted = torrent_get_wanted(t);
priv->files = torrent_get_files(t);
- if (first == TRUE) {
+ if (mode == TORRENT_GET_MODE_FIRST) {
+ gtk_list_store_clear(GTK_LIST_STORE(model));
priv->accept = TRUE;
- for (j = 0; j < json_array_get_length(priv->files); j++) {
+ for (li = json_array_get_elements(priv->files); li; li = g_list_next(li)) {
JsonObject *file =
- json_node_get_object(json_array_get_element
- (priv->files, j));
+ json_node_get_object((JsonNode*)li->data);
GtkTreeIter filesIter;
trg_files_model_iter_new(model, &filesIter, file, j);
trg_files_model_iter_update(model, &filesIter,
file, priv->wanted,
priv->priorities, j);
+ j++;
}
} else {
gtk_tree_model_foreach(GTK_TREE_MODEL(model),
diff --git a/src/trg-files-model.h b/src/trg-files-model.h
index 76dccf7..c47c361 100644
--- a/src/trg-files-model.h
+++ b/src/trg-files-model.h
@@ -62,7 +62,7 @@ G_END_DECLS enum {
void
trg_files_model_update(TrgFilesModel * model, gint64 updateSerial,
- JsonObject * t, gboolean first);
+ JsonObject * t, gint mode);
gint64 trg_files_model_get_torrent_id(TrgFilesModel * model);
void trg_files_model_set_accept(TrgFilesModel * model, gboolean accept);
diff --git a/src/trg-main-window.c b/src/trg-main-window.c
index f681de5..b1c78d8 100644
--- a/src/trg-main-window.c
+++ b/src/trg-main-window.c
@@ -68,8 +68,7 @@
#include "trg-remote-prefs-dialog.h"
#include "trg-preferences-dialog.h"
-static gboolean update_selected_torrent_notebook(TrgMainWindow * win,
- gboolean first);
+static gboolean update_selected_torrent_notebook(TrgMainWindow * win, gint mode);
static void torrent_event_notification(TrgTorrentModel * model,
gchar * icon, gchar * desc,
gint tmout, gchar * prefKey,
@@ -119,6 +118,7 @@ static void on_torrent_get(JsonObject * response,
int mode, int status, gpointer data);
static void on_torrent_get_first(JsonObject * response, int status,
gpointer data);
+static void on_torrent_get_active(JsonObject *response, int status, gpointer data);
static void on_torrent_get_update(JsonObject * response, int status,
gpointer data);
static void on_torrent_get_interactive(JsonObject * response, int status,
@@ -126,8 +126,7 @@ static void on_torrent_get_interactive(JsonObject * response, int status,
static gboolean trg_update_torrents_timerfunc(gpointer data);
static void trg_main_window_update_notebook_displays(TrgMainWindow * win,
JsonObject * t,
- GtkTreeIter * iter,
- gboolean first);
+ GtkTreeIter * iter, gint mode);
static void open_about_cb(GtkWidget * w, GtkWindow * parent);
static gboolean trg_torrent_tree_view_visible_func(GtkTreeModel * model,
GtkTreeIter * iter,
@@ -165,7 +164,7 @@ static GtkWidget *trg_imagemenuitem_new(GtkMenuShell * shell, char *text,
GCallback cb, gpointer cbdata);
static void set_limit_cb(GtkWidget * w, gpointer data);
static GtkWidget *limit_item_new(TrgMainWindow * win, GtkWidget * menu,
- gint64 currentLimit, gint limit);
+ gint64 currentLimit, gfloat limit);
static GtkWidget *limit_menu_new(TrgMainWindow * win, gchar * title,
gchar * enabledKey, gchar * speedKey,
JsonArray * ids);
@@ -241,8 +240,7 @@ static void trg_main_window_init(TrgMainWindow * self G_GNUC_UNUSED)
{
}
-static gboolean update_selected_torrent_notebook(TrgMainWindow * win,
- gboolean first)
+static gboolean update_selected_torrent_notebook(TrgMainWindow * win, gint mode)
{
TrgMainWindowPrivate *priv;
GtkTreeIter iter;
@@ -261,7 +259,7 @@ static gboolean update_selected_torrent_notebook(TrgMainWindow * win,
}
if ((priv->selectedTorrentId = newFirstSelected) >= 0) {
- trg_main_window_update_notebook_displays(win, json, &iter, first);
+ trg_main_window_update_notebook_displays(win, json, &iter, mode);
return TRUE;
}
@@ -440,7 +438,6 @@ static void resume_all_cb(GtkWidget *w G_GNUC_UNUSED, gpointer data)
{
TrgMainWindowPrivate *priv = TRG_MAIN_WINDOW_GET_PRIVATE(data);
- g_printf("%s\n", __func__);
dispatch_async(priv->client,
torrent_start(NULL),
on_generic_interactive_action, data);
@@ -516,7 +513,7 @@ static void open_local_prefs_cb(GtkWidget * w G_GNUC_UNUSED, gpointer data)
GtkWidget *dlg =
trg_preferences_dialog_get_instance(TRG_MAIN_WINDOW(data),
- priv->client->gconf);
+ priv->client);
gtk_widget_show_all(dlg);
}
@@ -850,15 +847,32 @@ static void on_session_get(JsonObject * response, int status,
newSession = get_arguments(response);
if (client->session == NULL) {
+ float version;
+ if (session_get_version(newSession, &version))
+ {
+ if (version < TRANSMISSION_MIN_SUPPORTED) {
+ gchar *msg = g_strdup_printf(_("This application supports Transmission %.2f and later, you have %.2f."), TRANSMISSION_MIN_SUPPORTED, version);
+ GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(win),
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK, "%s", msg);
+ gtk_window_set_title(GTK_WINDOW(dialog), _("Error"));
+ gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+ g_free(msg);
+ goto out;
+ }
+ }
+
trg_status_bar_connect(priv->statusBar, newSession);
trg_main_window_conn_changed(win, TRUE);
-
- dispatch_async(client, torrent_get(), on_torrent_get_first, data);
+ dispatch_async(client, torrent_get(FALSE), on_torrent_get_first, data);
}
trg_client_set_session(client, newSession);
trg_trackers_tree_view_new_connection(priv->trackersTreeView, client);
+out:
gdk_threads_leave();
json_object_ref(newSession);
response_unref(response);
@@ -871,16 +885,13 @@ on_torrent_get(JsonObject * response, int mode, int status, gpointer data)
trg_client *client = priv->client;
trg_torrent_model_update_stats stats;
- gboolean first;
/* Disconnected between request and response callback */
- if (client->session == NULL) {
+ if (!client->session) {
response_unref(response);
return;
}
- first = (mode == TORRENT_GET_MODE_FIRST);
-
g_mutex_lock(client->updateMutex);
gdk_threads_enter();
@@ -921,9 +932,10 @@ on_torrent_get(JsonObject * response, int mode, int status, gpointer data)
client->updateSerial++;
trg_torrent_model_update(priv->torrentModel, priv->client,
- response, &stats, first);
+ response, &stats, mode);
+ trg_torrent_model_stats_scan(priv->torrentModel, &stats);
- update_selected_torrent_notebook(TRG_MAIN_WINDOW(data), first);
+ update_selected_torrent_notebook(TRG_MAIN_WINDOW(data), mode);
trg_status_bar_update(priv->statusBar, &stats);
@@ -940,6 +952,12 @@ on_torrent_get(JsonObject * response, int mode, int status, gpointer data)
}
static void
+on_torrent_get_active(JsonObject *response, int status, gpointer data)
+{
+ on_torrent_get(response, TORRENT_GET_MODE_ACTIVE, status, data);
+}
+
+static void
on_torrent_get_first(JsonObject * response, int status, gpointer data)
{
on_torrent_get(response, TORRENT_GET_MODE_FIRST, status, data);
@@ -961,8 +979,9 @@ static gboolean trg_update_torrents_timerfunc(gpointer data)
{
TrgMainWindowPrivate *priv = TRG_MAIN_WINDOW_GET_PRIVATE(data);
- if (priv->client->session != NULL)
- dispatch_async(priv->client, torrent_get(), on_torrent_get_update,
+ if (priv->client->session)
+ dispatch_async(priv->client, torrent_get(priv->client->activeOnlyUpdate),
+ priv->client->activeOnlyUpdate ? on_torrent_get_active : on_torrent_get_update,
data);
return FALSE;
@@ -971,19 +990,18 @@ static gboolean trg_update_torrents_timerfunc(gpointer data)
static void
trg_main_window_update_notebook_displays(TrgMainWindow * win,
JsonObject * t,
- GtkTreeIter * iter,
- gboolean first)
+ GtkTreeIter * iter, gint mode)
{
TrgMainWindowPrivate *priv = TRG_MAIN_WINDOW_GET_PRIVATE(win);
trg_client *client = priv->client;
trg_general_panel_update(priv->genDetails, t, iter);
trg_trackers_model_update(priv->trackersModel, client->updateSerial, t,
- first);
+ mode);
trg_files_model_update(priv->filesModel, client->updateSerial, t,
- first);
+ mode);
trg_peers_model_update(priv->peersModel, client->updateSerial, t,
- first);
+ mode);
}
static void open_about_cb(GtkWidget * w G_GNUC_UNUSED, GtkWindow * parent)
@@ -1094,7 +1112,7 @@ trg_dialog_error_handler(TrgMainWindow * win, JsonObject * response,
GTK_DIALOG_MODAL,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_OK, "%s", msg);
- gtk_window_set_title(GTK_WINDOW(dialog), "Error");
+ gtk_window_set_title(GTK_WINDOW(dialog), _("Error"));
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
g_free((gpointer) msg);
@@ -1116,7 +1134,7 @@ torrent_selection_changed(GtkWidget * w G_GNUC_UNUSED, gpointer data)
win = TRG_MAIN_WINDOW(data);
client = priv->client;
- isSelected = update_selected_torrent_notebook(win, TRUE);
+ isSelected = update_selected_torrent_notebook(win, TORRENT_GET_MODE_FIRST);
trg_toolbar_torrent_actions_sensitive(priv->toolBar, isSelected);
trg_menu_bar_torrent_actions_sensitive(priv->menuBar, isSelected);
@@ -1140,7 +1158,7 @@ on_generic_interactive_action(JsonObject * response, int status,
gdk_threads_leave();
if (status == CURLE_OK || status == FAIL_RESPONSE_UNSUCCESSFUL)
- dispatch_async(priv->client, torrent_get(),
+ dispatch_async(priv->client, torrent_get(FALSE),
on_torrent_get_interactive, data);
}
@@ -1248,7 +1266,8 @@ static TrgMenuBar *trg_main_window_menu_bar_new(TrgMainWindow * win)
GObject *b_connect, *b_disconnect, *b_add, *b_resume, *b_pause,
*b_verify, *b_remove, *b_delete, *b_props, *b_local_prefs,
*b_remote_prefs, *b_about, *b_view_states, *b_view_notebook,
- *b_view_stats, *b_add_url, *b_quit, *b_move, *b_reannounce;
+ *b_view_stats, *b_add_url, *b_quit, *b_move, *b_reannounce,
+ *b_pause_all, *b_resume_all;
TrgMenuBar *menuBar;
menuBar = trg_menu_bar_new(win);
@@ -1258,7 +1277,9 @@ static TrgMenuBar *trg_main_window_menu_bar_new(TrgMainWindow * win)
"add-button", &b_add,
"add-url-button", &b_add_url,
"resume-button", &b_resume,
+ "resume-all-button", &b_resume_all,
"pause-button", &b_pause,
+ "pause-all-button", &b_pause_all,
"delete-button", &b_delete,
"remove-button", &b_remove,
"move-button", &b_move,
@@ -1278,7 +1299,9 @@ static TrgMenuBar *trg_main_window_menu_bar_new(TrgMainWindow * win)
g_signal_connect(b_add, "activate", G_CALLBACK(add_cb), win);
g_signal_connect(b_add_url, "activate", G_CALLBACK(add_url_cb), win);
g_signal_connect(b_resume, "activate", G_CALLBACK(resume_cb), win);
+ g_signal_connect(b_resume_all, "activate", G_CALLBACK(resume_all_cb), win);
g_signal_connect(b_pause, "activate", G_CALLBACK(pause_cb), win);
+ g_signal_connect(b_pause_all, "activate", G_CALLBACK(pause_all_cb), win);
g_signal_connect(b_verify, "activate", G_CALLBACK(verify_cb), win);
g_signal_connect(b_reannounce, "activate", G_CALLBACK(reannounce_cb),
win);
@@ -1380,16 +1403,21 @@ static void set_limit_cb(GtkWidget * w, gpointer data)
}
static GtkWidget *limit_item_new(TrgMainWindow * win, GtkWidget * menu,
- gint64 currentLimit, gint limit)
+ gint64 currentLimit, gfloat limit)
{
char speed[32];
GtkWidget *item;
gboolean active = limit < 0 ? FALSE : (currentLimit == (gint64) limit);
- g_snprintf(speed, sizeof(speed), "%d KB/s", limit);
+ if (limit >= 1000)
+ g_snprintf(speed, sizeof(speed), "%.2f MB/s", limit / 1000);
+ else
+ g_snprintf(speed, sizeof(speed), "%.0f KB/s", limit);
+
item = gtk_check_menu_item_new_with_label(speed);
- g_object_set_data(G_OBJECT(item), "limit", GINT_TO_POINTER(limit));
+ /* Yeah, I know it's unsafe to cast from a float to an int, but its safe here */
+ g_object_set_data(G_OBJECT(item), "limit", GINT_TO_POINTER((gint)limit));
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), active);
g_signal_connect(item, "activate", G_CALLBACK(set_limit_cb), win);
@@ -1452,6 +1480,13 @@ static GtkWidget *limit_menu_new(TrgMainWindow * win, gchar * title,
limit_item_new(win, menu, limit, 300);
limit_item_new(win, menu, limit, 400);
limit_item_new(win, menu, limit, 500);
+ limit_item_new(win, menu, limit, 750);
+ limit_item_new(win, menu, limit, 1000);
+ limit_item_new(win, menu, limit, 1250);
+ limit_item_new(win, menu, limit, 1500);
+ limit_item_new(win, menu, limit, 2000);
+ limit_item_new(win, menu, limit, 2500);
+ limit_item_new(win, menu, limit, 3000);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(toplevel), menu);
@@ -1766,6 +1801,8 @@ static GObject *trg_main_window_constructor(GType type,
G_CALLBACK(window_state_event), NULL);
priv->torrentModel = trg_torrent_model_new();
+ priv->client->torrentTable = get_torrent_table(priv->torrentModel);
+
g_signal_connect(priv->torrentModel, "torrent-completed",
G_CALLBACK(on_torrent_completed), self);
g_signal_connect(priv->torrentModel, "torrent-added",
diff --git a/src/trg-main-window.h b/src/trg-main-window.h
index 09a2439..564dc24 100644
--- a/src/trg-main-window.h
+++ b/src/trg-main-window.h
@@ -53,10 +53,6 @@ typedef struct {
GtkWindowClass parent_class;
} TrgMainWindowClass;
-#define TORRENT_GET_MODE_FIRST 0
-#define TORRENT_GET_MODE_INTERACTION 1
-#define TORRENT_GET_MODE_UPDATE 2
-
#define TORRENT_COMPLETE_NOTIFY_TMOUT 8000
#define TORRENT_ADD_NOTIFY_TMOUT 3000
diff --git a/src/trg-menu-bar.c b/src/trg-menu-bar.c
index 9b81154..b86b0c7 100644
--- a/src/trg-menu-bar.c
+++ b/src/trg-menu-bar.c
@@ -31,7 +31,9 @@ enum {
PROP_REMOVE_BUTTON,
PROP_DELETE_BUTTON,
PROP_RESUME_BUTTON,
+ PROP_RESUME_ALL_BUTTON,
PROP_PAUSE_BUTTON,
+ PROP_PAUSE_ALL_BUTTON,
PROP_VERIFY_BUTTON,
PROP_REANNOUNCE_BUTTON,
PROP_PROPS_BUTTON,
@@ -60,6 +62,8 @@ struct _TrgMenuBarPrivate {
GtkWidget *mb_delete;
GtkWidget *mb_resume;
GtkWidget *mb_pause;
+ GtkWidget *mb_resume_all;
+ GtkWidget *mb_pause_all;
GtkWidget *mb_verify;
GtkWidget *mb_reannounce;
GtkWidget *mb_props;
@@ -82,6 +86,8 @@ void trg_menu_bar_connected_change(TrgMenuBar * mb, gboolean connected)
gtk_widget_set_sensitive(priv->mb_disconnect, connected);
gtk_widget_set_sensitive(priv->mb_remote_prefs, connected);
gtk_widget_set_sensitive(priv->mb_view_stats, connected);
+ gtk_widget_set_sensitive(priv->mb_resume_all, connected);
+ gtk_widget_set_sensitive(priv->mb_pause_all, connected);
}
void trg_menu_bar_torrent_actions_sensitive(TrgMenuBar * mb,
@@ -129,9 +135,15 @@ trg_menu_bar_get_property(GObject * object, guint property_id,
case PROP_RESUME_BUTTON:
g_value_set_object(value, priv->mb_resume);
break;
+ case PROP_RESUME_ALL_BUTTON:
+ g_value_set_object(value, priv->mb_resume_all);
+ break;
case PROP_PAUSE_BUTTON:
g_value_set_object(value, priv->mb_pause);
break;
+ case PROP_PAUSE_ALL_BUTTON:
+ g_value_set_object(value, priv->mb_pause_all);
+ break;
case PROP_VERIFY_BUTTON:
g_value_set_object(value, priv->mb_verify);
break;
@@ -312,6 +324,15 @@ GtkWidget *trg_menu_bar_torrent_menu_new(TrgMenuBarPrivate * priv)
_("Remove and Delete"), GTK_STOCK_DELETE,
FALSE);
+ gtk_menu_shell_append(GTK_MENU_SHELL(torrentMenu), gtk_separator_menu_item_new());
+
+ priv->mb_resume_all =
+ trg_menu_bar_item_new(GTK_MENU_SHELL(torrentMenu), _("_Resume All"),
+ GTK_STOCK_MEDIA_PLAY, FALSE);
+ priv->mb_pause_all =
+ trg_menu_bar_item_new(GTK_MENU_SHELL(torrentMenu), _("_Pause All"),
+ GTK_STOCK_MEDIA_PAUSE, FALSE);
+
return torrent;
}
@@ -357,11 +378,15 @@ static void trg_menu_bar_class_init(TrgMenuBarClass * klass)
"delete-button", "Delete Button");
trg_menu_bar_install_widget_prop(object_class, PROP_RESUME_BUTTON,
"resume-button", "Resume Button");
+ trg_menu_bar_install_widget_prop(object_class, PROP_RESUME_ALL_BUTTON,
+ "resume-all-button", "Resume All Button");
trg_menu_bar_install_widget_prop(object_class, PROP_VERIFY_BUTTON,
"verify-button", "Verify Button");
trg_menu_bar_install_widget_prop(object_class, PROP_REANNOUNCE_BUTTON,
"reannounce-button",
"Re-announce Button");
+ trg_menu_bar_install_widget_prop(object_class, PROP_PAUSE_ALL_BUTTON,
+ "pause-all-button", "Pause All Button");
trg_menu_bar_install_widget_prop(object_class, PROP_PAUSE_BUTTON,
"pause-button", "Pause Button");
trg_menu_bar_install_widget_prop(object_class, PROP_PROPS_BUTTON,
diff --git a/src/trg-peers-model.c b/src/trg-peers-model.c
index ee48d4d..a96b44f 100644
--- a/src/trg-peers-model.c
+++ b/src/trg-peers-model.c
@@ -31,6 +31,7 @@
#endif
#include "torrent.h"
+#include "trg-client.h"
#include "tpeer.h"
#include "trg-peers-model.h"
#include "trg-model.h"
@@ -123,7 +124,7 @@ static void resolved_dns_cb(GObject * source_object,
}
void trg_peers_model_update(TrgPeersModel * model, gint64 updateSerial,
- JsonObject * t, gboolean first)
+ JsonObject * t, gint mode)
{
#ifdef HAVE_GEOIP
TrgPeersModelPrivate *priv = TRG_PEERS_MODEL_GET_PRIVATE(model);
@@ -131,23 +132,22 @@ void trg_peers_model_update(TrgPeersModel * model, gint64 updateSerial,
JsonArray *peers;
GtkTreeIter peerIter;
- guint j;
+ GList *li;
gboolean isNew;
peers = torrent_get_peers(t);
- if (first == TRUE)
+ if (mode == TORRENT_GET_MODE_FIRST)
gtk_list_store_clear(GTK_LIST_STORE(model));
- for (j = 0; j < json_array_get_length(peers); j++) {
- JsonObject *peer;
+ for (li = json_array_get_elements(peers); li; li = g_list_next(li)) {
+ JsonObject *peer = json_node_get_object((JsonNode*)li->data);
const gchar *address = NULL, *flagStr;
#ifdef HAVE_GEOIP
const gchar *country = NULL;
#endif
- peer = json_node_get_object(json_array_get_element(peers, j));
- if (first == TRUE
+ if (mode == TORRENT_GET_MODE_FIRST
|| find_existing_peer_item(model, peer, &peerIter) == FALSE) {
gtk_list_store_append(GTK_LIST_STORE(model), &peerIter);
@@ -204,7 +204,7 @@ void trg_peers_model_update(TrgPeersModel * model, gint64 updateSerial,
}
}
- if (first == FALSE)
+ if (mode != TORRENT_GET_MODE_FIRST)
trg_model_remove_removed(GTK_LIST_STORE(model),
PEERSCOL_UPDATESERIAL, updateSerial);
}
diff --git a/src/trg-preferences-dialog.c b/src/trg-preferences-dialog.c
index d3c7979..0563949 100644
--- a/src/trg-preferences-dialog.c
+++ b/src/trg-preferences-dialog.c
@@ -42,7 +42,6 @@ G_DEFINE_TYPE(TrgPreferencesDialog, trg_preferences_dialog,
enum {
PROP_0,
- PROP_GCONF_CLIENT,
PROP_TRG_CLIENT,
PROP_MAIN_WINDOW
};
@@ -50,7 +49,6 @@ enum {
#define GCONF_OBJECT_KEY "gconf-key"
struct _TrgPreferencesDialogPrivate {
- GConfClient *gconf;
TrgMainWindow *win;
trg_client *client;
};
@@ -67,9 +65,6 @@ trg_preferences_dialog_set_property(GObject * object,
TRG_PREFERENCES_DIALOG_GET_PRIVATE(object);
switch (prop_id) {
- case PROP_GCONF_CLIENT:
- priv->gconf = g_value_get_object(value);
- break;
case PROP_MAIN_WINDOW:
priv->win = g_value_get_object(value);
break;
@@ -97,9 +92,6 @@ trg_preferences_dialog_get_property(GObject * object,
TRG_PREFERENCES_DIALOG_GET_PRIVATE(object);
switch (prop_id) {
- case PROP_GCONF_CLIENT:
- g_value_set_object(value, priv->gconf);
- break;
case PROP_MAIN_WINDOW:
g_value_set_object(value, priv->win);
break;
@@ -109,13 +101,16 @@ trg_preferences_dialog_get_property(GObject * object,
}
}
-static void toggled_cb(GtkToggleButton * w, gpointer gconf)
+static void update_activeonly_cb(GtkToggleButton *w, gpointer data)
{
- const char *key;
- gboolean flag;
+ trg_client *client = (trg_client*)data;
+ client->activeOnlyUpdate = gtk_toggle_button_get_active(w);
+}
- key = g_object_get_data(G_OBJECT(w), GCONF_OBJECT_KEY);
- flag = gtk_toggle_button_get_active(w);
+static void toggled_cb(GtkToggleButton * w, gpointer gconf)
+{
+ const char *key = g_object_get_data(G_OBJECT(w), GCONF_OBJECT_KEY);
+ gboolean flag = gtk_toggle_button_get_active(w);
gconf_client_set_bool(GCONF_CLIENT(gconf), key, flag, NULL);
}
@@ -235,12 +230,14 @@ static void toggle_tray_icon(GtkToggleButton * w, gpointer win)
trg_main_window_remove_status_icon(TRG_MAIN_WINDOW(win));
}
-static GtkWidget *trg_prefs_desktopPage(GConfClient * gconf,
+static GtkWidget *trg_prefs_desktopPage(trg_client *client,
TrgMainWindow * win)
{
GtkWidget *tray, *w, *t;
gint row = 0;
+ GConfClient *gconf = client->gconf;
+
t = hig_workarea_create();
hig_workarea_add_section_title(t, &row, _("Features"));
@@ -300,7 +297,7 @@ static GtkWidget *trg_prefs_desktopPage(GConfClient * gconf,
return t;
}
-static GtkWidget *trg_prefs_behaviorPage(GConfClient * gconf)
+static GtkWidget *trg_prefs_behaviorPage(trg_client *client)
{
GtkWidget *w, *t;
gint row = 0;
@@ -309,23 +306,24 @@ static GtkWidget *trg_prefs_behaviorPage(GConfClient * gconf)
hig_workarea_add_section_title(t, &row, _("Torrents"));
- w = new_check_button(gconf, _("Start paused"),
+ w = new_check_button(client->gconf, _("Start paused"),
TRG_GCONF_KEY_START_PAUSED);
hig_workarea_add_wide_control(t, &row, w);
- w = new_check_button(gconf, _("Options dialog on add"),
+ w = new_check_button(client->gconf, _("Options dialog on add"),
TRG_GCONF_KEY_ADD_OPTIONS_DIALOG);
hig_workarea_add_wide_control(t, &row, w);
return t;
}
-static GtkWidget *trg_prefs_serverPage(GConfClient * gconf,
- trg_client * client)
+static GtkWidget *trg_prefs_serverPage(trg_client * client)
{
GtkWidget *w, *t;
gint row = 0;
+ GConfClient *gconf = client->gconf;
+
t = hig_workarea_create();
hig_workarea_add_section_title(t, &row, _("Server"));
@@ -348,6 +346,10 @@ static GtkWidget *trg_prefs_serverPage(GConfClient * gconf,
client);
hig_workarea_add_row(t, &row, _("Update interval:"), w, NULL);
+ w = new_check_button(gconf, _("Update active torrents only"), TRG_GCONF_KEY_UPDATE_ACTIVE_ONLY);
+ g_signal_connect(w, "toggled", G_CALLBACK(update_activeonly_cb), client);
+ hig_workarea_add_wide_control(t, &row, w);
+
hig_workarea_add_section_divider(t, &row);
hig_workarea_add_section_title(t, &row, _("Authentication"));
@@ -393,16 +395,15 @@ static GObject *trg_preferences_dialog_constructor(GType type,
notebook = gtk_notebook_new();
gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
- trg_prefs_serverPage(priv->gconf,
- priv->client),
+ trg_prefs_serverPage(priv->client),
gtk_label_new(_("Connection")));
gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
- trg_prefs_desktopPage(priv->gconf, priv->win),
+ trg_prefs_desktopPage(priv->client, priv->win),
gtk_label_new(_("Desktop")));
gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
- trg_prefs_behaviorPage(priv->gconf),
+ trg_prefs_behaviorPage(priv->client),
gtk_label_new(_("Behavior")));
gtk_container_set_border_width(GTK_CONTAINER(notebook), GUI_PAD);
@@ -415,6 +416,10 @@ static GObject *trg_preferences_dialog_constructor(GType type,
return object;
}
+static void trg_preferences_dialog_init(TrgPreferencesDialog * pref_dlg)
+{
+}
+
static void
trg_preferences_dialog_class_init(TrgPreferencesDialogClass * class)
{
@@ -436,22 +441,6 @@ trg_preferences_dialog_class_init(TrgPreferencesDialogClass * class)
G_PARAM_STATIC_BLURB));
g_object_class_install_property(g_object_class,
- PROP_GCONF_CLIENT,
- g_param_spec_object("gconf-client",
- "GConf Client",
- "GConf Client",
- GCONF_TYPE_CLIENT,
- G_PARAM_READWRITE
- |
- G_PARAM_CONSTRUCT_ONLY
- |
- G_PARAM_STATIC_NAME
- |
- G_PARAM_STATIC_NICK
- |
- G_PARAM_STATIC_BLURB));
-
- g_object_class_install_property(g_object_class,
PROP_MAIN_WINDOW,
g_param_spec_object
("main-window", "Main Window",
@@ -466,18 +455,13 @@ trg_preferences_dialog_class_init(TrgPreferencesDialogClass * class)
sizeof(TrgPreferencesDialogPrivate));
}
-static void trg_preferences_dialog_init(TrgPreferencesDialog * pref_dlg)
-{
-}
-
GtkWidget *trg_preferences_dialog_get_instance(TrgMainWindow * win,
- GConfClient * client)
+ trg_client * client)
{
if (instance == NULL) {
instance = g_object_new(TRG_TYPE_PREFERENCES_DIALOG,
"main-window", win,
- "trg-client", client,
- "gconf-client", client, NULL);
+ "trg-client", client, NULL);
}
return GTK_WIDGET(instance);
diff --git a/src/trg-preferences-dialog.h b/src/trg-preferences-dialog.h
index 5a493b4..d99f911 100644
--- a/src/trg-preferences-dialog.h
+++ b/src/trg-preferences-dialog.h
@@ -50,6 +50,6 @@ struct _TrgPreferencesDialogClass {
GType trg_preferences_dialog_get_type(void);
GtkWidget *trg_preferences_dialog_get_instance(TrgMainWindow * win,
- GConfClient * client);
+ trg_client * client);
G_END_DECLS
#endif /* TRG_PREFERENCES_WINDOW_H_ */
diff --git a/src/trg-preferences.h b/src/trg-preferences.h
index f04657f..bd37195 100644
--- a/src/trg-preferences.h
+++ b/src/trg-preferences.h
@@ -42,6 +42,7 @@
#define TRG_GCONF_KEY_LAST_TORRENT_DIR "/apps/transmission-remote-gtk/last-torrent-dir"
#define TRG_GCONF_KEY_ADD_OPTIONS_DIALOG "/apps/transmission-remote-gtk/add-options-dialog"
#define TRG_GCONF_KEY_START_PAUSED "/apps/transmission-remote-gtk/start-paused"
+#define TRG_GCONF_KEY_UPDATE_ACTIVE_ONLY "/apps/transmission-remote-gtk/update-active-only"
gboolean pref_get_start_paused(GConfClient * gcc);
gboolean pref_get_add_options_dialog(GConfClient * gcc);
diff --git a/src/trg-state-selector.c b/src/trg-state-selector.c
index 80fadde..8a6c4bc 100644
--- a/src/trg-state-selector.c
+++ b/src/trg-state-selector.c
@@ -24,6 +24,7 @@
#include "torrent.h"
#include "trg-state-selector.h"
+#include "trg-torrent-model.h"
#include "util.h"
#include "trg-preferences.h"
#include "trg-client.h"
@@ -216,22 +217,38 @@ void trg_state_selector_update(TrgStateSelector * s)
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(s));
trg_client *client = priv->client;
GtkTreeIter iter;
- int i, j;
+ GList *trackerItem, *li;
+ GList *torrentItemRefs = g_hash_table_get_values(client->torrentTable);
+
struct cruft_remove_args cruft;
if (!client->session)
return;
- for (i = 0; i < json_array_get_length(client->torrents); i++) {
- JsonObject *t = json_array_get_object_element(client->torrents, i);
+ for (li = torrentItemRefs; li; li = g_list_next(li)) {
+ GtkTreeRowReference *rr = (GtkTreeRowReference*)li->data;
+ GtkTreePath *path = gtk_tree_row_reference_get_path(rr);
+ GtkTreeModel *torrentModel = gtk_tree_row_reference_get_model(rr);
+ JsonObject *t = NULL;
gpointer result;
+ if (path) {
+ GtkTreeIter iter;
+ if (gtk_tree_model_get_iter(torrentModel, &iter, path)) {
+ gtk_tree_model_get(torrentModel, &iter, TORRENT_COLUMN_JSON, &t, -1);
+ }
+ gtk_tree_path_free(path);
+ }
+
+ if (!t)
+ continue;
+
if (priv->showTrackers) {
JsonArray *trackers = torrent_get_trackers(t);
- for (j = 0; j < json_array_get_length(trackers); j++) {
+ for (trackerItem = json_array_get_elements(trackers); trackerItem; trackerItem = g_list_next(trackerItem)) {
JsonObject *tracker =
- json_array_get_object_element(trackers, j);
+ json_node_get_object((JsonNode*)trackerItem->data);
const gchar *announceUrl = tracker_get_announce(tracker);
gchar *announceHost =
trg_gregex_get_first(priv->urlHostRegex, announceUrl);
@@ -290,6 +307,8 @@ void trg_state_selector_update(TrgStateSelector * s)
}
}
+ g_list_free(torrentItemRefs);
+
cruft.serial = client->updateSerial;
if (priv->showTrackers) {
diff --git a/src/trg-torrent-add-dialog.c b/src/trg-torrent-add-dialog.c
index 446f41e..06b1c9b 100644
--- a/src/trg-torrent-add-dialog.c
+++ b/src/trg-torrent-add-dialog.c
@@ -189,25 +189,39 @@ static GtkWidget *trg_destination_folder_new(trg_client * client)
{
const gchar *defaultDownDir = json_object_get_string_member(client->session, SGET_DOWNLOAD_DIR);
GtkWidget *combo = gtk_combo_box_entry_new_text();
- int i;
GSList *dirs = NULL;
- GSList *li;
+ GSList *sli;
+ GList *li;
+ GList *torrentItemRefs;
g_slist_str_set_add(&dirs, defaultDownDir);
g_mutex_lock(client->updateMutex);
- for (i = 0; i < json_array_get_length(client->torrents); i++) {
- JsonObject *t = json_node_get_object(json_array_get_element(client->torrents, i));
- const gchar *dd = torrent_get_download_dir(t);
- if (dd) {
- g_printf("dd: %s\n", dd);
- g_slist_str_set_add(&dirs, dd);
+ torrentItemRefs = g_hash_table_get_values(client->torrentTable);
+ for (li = torrentItemRefs; li; li = g_list_next(li)) {
+ GtkTreeRowReference *rr = (GtkTreeRowReference*)li->data;
+ GtkTreeModel *model = gtk_tree_row_reference_get_model(rr);
+ GtkTreePath *path = gtk_tree_row_reference_get_path(rr);
+ JsonObject *t = NULL;
+
+ if (path) {
+ GtkTreeIter iter;
+ if (gtk_tree_model_get_iter(model, &iter, path)) {
+ const gchar *dd;
+ gtk_tree_model_get(model, &iter, TORRENT_COLUMN_JSON, &t, -1);
+ dd = torrent_get_download_dir(t);
+ if (dd)
+ g_slist_str_set_add(&dirs, dd);
+
+ }
+ gtk_tree_path_free(path);
}
}
+ g_list_free(torrentItemRefs);
g_mutex_unlock(client->updateMutex);
- for (li = dirs; li != NULL; li = g_slist_next(li))
- gtk_combo_box_append_text(GTK_COMBO_BOX(combo), (gchar*)li->data);
+ for (sli = dirs; sli != NULL; sli = g_slist_next(sli))
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combo), (gchar*)sli->data);
gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
g_str_slist_free(dirs);
diff --git a/src/trg-torrent-model.c b/src/trg-torrent-model.c
index ca33d6c..12da8de 100644
--- a/src/trg-torrent-model.c
+++ b/src/trg-torrent-model.c
@@ -41,11 +41,27 @@ static guint signals[TMODEL_SIGNAL_COUNT] = { 0 };
G_DEFINE_TYPE(TrgTorrentModel, trg_torrent_model, GTK_TYPE_LIST_STORE)
-static guint32 torrent_get_flags(JsonObject * t, gint64 status,
- trg_torrent_model_update_stats * stats);
+#define TRG_TORRENT_MODEL_GET_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), TRG_TYPE_TORRENT_MODEL, TrgTorrentModelPrivate))
+
+typedef struct _TrgTorrentModelPrivate TrgTorrentModelPrivate;
+
+struct _TrgTorrentModelPrivate {
+ GHashTable *ht;
+};
+
+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);
+}
+
+static guint32 torrent_get_flags(JsonObject * t, gint64 status);
static void
-update_torrent_iter(gint64 serial, TrgTorrentModel * model,
+update_torrent_iter(TrgTorrentModel * model, gint64 serial,
GtkTreeIter * iter, JsonObject * t,
trg_torrent_model_update_stats * stats);
@@ -53,6 +69,9 @@ 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),
@@ -87,17 +106,15 @@ static void trg_torrent_model_count_peers(TrgTorrentModel * model,
{
JsonArray *peers;
gint seeders, leechers;
- guint j;
+ GList *li;
peers = torrent_get_peers(t);
seeders = 0;
leechers = 0;
- for (j = 0; j < json_array_get_length(peers); j++) {
- JsonObject *peer;
-
- peer = json_node_get_object(json_array_get_element(peers, j));
+ for (li = json_array_get_elements(peers); li; li = g_list_next(li)) {
+ JsonObject *peer = json_node_get_object((JsonNode*)li->data);
if (peer_get_is_downloading_from(peer))
seeders++;
@@ -111,8 +128,26 @@ static void trg_torrent_model_count_peers(TrgTorrentModel * model,
TORRENT_COLUMN_LEECHERS, leechers, -1);
}
+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);
+ if (path) {
+ GtkTreeIter iter;
+ if (gtk_tree_model_get_iter(model, &iter, path))
+ gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
+
+ gtk_tree_path_free(path);
+ }
+
+ gtk_tree_row_reference_free(rr);
+}
+
static void trg_torrent_model_init(TrgTorrentModel * self)
{
+ TrgTorrentModelPrivate *priv = TRG_TORRENT_MODEL_GET_PRIVATE(self);
+
GType column_types[TORRENT_COLUMN_COLUMNS];
column_types[TORRENT_COLUMN_ICON] = G_TYPE_STRING;
@@ -136,24 +171,22 @@ static void trg_torrent_model_init(TrgTorrentModel * self)
gtk_list_store_set_column_types(GTK_LIST_STORE(self),
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);
}
-static guint32 torrent_get_flags(JsonObject * t, gint64 status,
- trg_torrent_model_update_stats * stats)
+static guint32 torrent_get_flags(JsonObject * t, gint64 status)
{
guint32 flags = 0;
switch (status) {
case STATUS_DOWNLOADING:
flags |= TORRENT_FLAG_DOWNLOADING;
- stats->down++;
break;
case STATUS_PAUSED:
flags |= TORRENT_FLAG_PAUSED;
- stats->paused++;
break;
case STATUS_SEEDING:
flags |= TORRENT_FLAG_SEEDING;
- stats->seeding++;
break;
case STATUS_CHECKING:
flags |= TORRENT_FLAG_CHECKING;
@@ -175,12 +208,35 @@ static guint32 torrent_get_flags(JsonObject * t, gint64 status,
return flags;
}
+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;
+ guint flags;
+ gtk_tree_model_get(model, iter, TORRENT_COLUMN_FLAGS, &flags, -1);
+ if (flags & TORRENT_FLAG_SEEDING)
+ stats->seeding++;
+ else if (flags & TORRENT_FLAG_DOWNLOADING)
+ stats->down++;
+ else if (flags & TORRENT_FLAG_PAUSED)
+ stats->paused++;
+ return FALSE;
+}
+
+void trg_torrent_model_stats_scan(TrgTorrentModel *model, trg_torrent_model_update_stats *stats)
+{
+ gtk_tree_model_foreach(GTK_TREE_MODEL(model), trg_torrent_model_stats_scan_foreachfunc, stats);
+}
+
static void
-update_torrent_iter(gint64 serial, TrgTorrentModel * model,
+update_torrent_iter(TrgTorrentModel * model, gint64 serial,
GtkTreeIter * iter, JsonObject * t,
trg_torrent_model_update_stats * stats)
{
guint lastFlags, newFlags;
+ JsonObject *lastJson;
gchar *statusString, *statusIcon;
gint64 downRate, upRate, downloaded, uploaded, id, status;
@@ -197,11 +253,14 @@ update_torrent_iter(gint64 serial, TrgTorrentModel * model,
status = torrent_get_status(t);
statusString = torrent_get_status_string(status);
- newFlags = torrent_get_flags(t, status, stats);
+ newFlags = torrent_get_flags(t, status);
statusIcon = torrent_get_status_icon(newFlags);
gtk_tree_model_get(GTK_TREE_MODEL(model), iter,
- TORRENT_COLUMN_FLAGS, &lastFlags, -1);
+ TORRENT_COLUMN_FLAGS, &lastFlags,
+ TORRENT_COLUMN_JSON, &lastJson, -1);
+
+ json_object_ref(t);
#ifdef DEBUG
gtk_list_store_set(GTK_LIST_STORE(model), iter,
@@ -264,6 +323,9 @@ update_torrent_iter(gint64 serial, TrgTorrentModel * model,
TORRENT_COLUMN_UPDATESERIAL, serial, -1);
#endif
+ if (lastJson)
+ json_object_unref(lastJson);
+
if ((lastFlags & TORRENT_FLAG_DOWNLOADING)
&& (newFlags & TORRENT_FLAG_COMPLETE))
g_signal_emit(model, signals[TMODEL_TORRENT_COMPLETED], 0, iter);
@@ -279,50 +341,123 @@ TrgTorrentModel *trg_torrent_model_new(void)
return g_object_new(TRG_TYPE_TORRENT_MODEL, NULL);
}
+struct TrgModelRemoveData {
+ GList *toRemove;
+ gint64 currentSerial;
+};
+
+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)
+{
+ struct TrgModelRemoveData *args = (struct TrgModelRemoveData *)gdata;
+ gint64 rowSerial;
+ gtk_tree_model_get(model, iter, TORRENT_COLUMN_UPDATESERIAL, &rowSerial, -1);
+ if (rowSerial != args->currentSerial) {
+ gint64 *id = g_new(gint64, 1);
+ gtk_tree_model_get(model, iter, TORRENT_COLUMN_ID, id, -1);
+ args->toRemove =
+ g_list_append(args->toRemove, id);
+ }
+
+ return FALSE;
+}
+
+GList *trg_torrent_model_find_removed(GtkTreeModel * model,
+ 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);
+
+ return args.toRemove;
+}
+
void trg_torrent_model_update(TrgTorrentModel * model, trg_client * tc,
JsonObject * response,
trg_torrent_model_update_stats * stats,
- gboolean first)
+ gint mode)
{
- int i;
- JsonArray *newTorrents;
+ TrgTorrentModelPrivate *priv = TRG_TORRENT_MODEL_GET_PRIVATE(model);
+
+ JsonObject *args, *t;
+ GList *li;
+ gint64 id;
+ gint64 *idCopy;
+ JsonArray *newTorrents, *removedTorrents;
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ GtkTreeRowReference *rr;
+ gpointer *result;
gboolean added = FALSE;
+ gboolean removed = FALSE;
- newTorrents = get_torrents(get_arguments(response));
- stats->count = json_array_get_length(newTorrents);
+ args = get_arguments(response);
+ newTorrents = get_torrents(args);
- for (i = 0; i < stats->count; i++) {
- GtkTreeIter iter;
- JsonObject *t;
+ for (li = json_array_get_elements(newTorrents); li; li = g_list_next(li)) {
+ t = json_node_get_object((JsonNode*)li->data);
+ id = torrent_get_id(t);
- t = json_array_get_object_element(newTorrents, i);
+ result = mode == TORRENT_GET_MODE_FIRST ? NULL : g_hash_table_lookup(priv->ht, &id);
- if (first == TRUE
- || find_existing_model_item(GTK_TREE_MODEL(model),
- TORRENT_COLUMN_ID,
- torrent_get_id(t),
- &iter) == FALSE) {
- added = TRUE;
+ if (!result) {
gtk_list_store_append(GTK_LIST_STORE(model), &iter);
- update_torrent_iter(tc->updateSerial, model, &iter, t, stats);
- if (!first)
+ update_torrent_iter(model, tc->updateSerial, &iter, t, stats);
+
+ path = gtk_tree_model_get_path(GTK_TREE_MODEL(model), &iter);
+ rr = gtk_tree_row_reference_new(GTK_TREE_MODEL(model), path);
+ idCopy = g_new(gint64, 1);
+ *idCopy = id;
+ g_hash_table_insert(priv->ht, idCopy, rr);
+ gtk_tree_path_free(path);
+ added = TRUE;
+ if (mode != TORRENT_GET_MODE_FIRST)
g_signal_emit(model, signals[TMODEL_TORRENT_ADDED], 0,
&iter);
} else {
- update_torrent_iter(tc->updateSerial, model, &iter, t, stats);
+ path = gtk_tree_row_reference_get_path((GtkTreeRowReference*)result);
+ if (path) {
+ if (gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, path)) {
+ update_torrent_iter(model, tc->updateSerial, &iter, t, stats);
+ }
+ gtk_tree_path_free(path);
+ }
}
}
- json_array_ref(newTorrents);
-
- if (tc->torrents != NULL)
- json_array_unref(tc->torrents);
-
- tc->torrents = newTorrents;
+ if (mode == TORRENT_GET_MODE_ACTIVE) {
+ removedTorrents = get_torrents_removed(args);
+ if (removedTorrents) {
+ for (li = json_array_get_elements(removedTorrents); li != NULL; li = g_list_next(li)) {
+ id = json_node_get_int((JsonNode*)li->data);
+ g_hash_table_remove(priv->ht, &id);
+ removed = TRUE;
+ }
+ }
+ } else if (mode >= TORRENT_GET_MODE_INTERACTION) {
+ GList *hitlist = trg_torrent_model_find_removed(GTK_TREE_MODEL(model), tc->updateSerial);
+ if (hitlist) {
+ for (li = hitlist; li; li = g_list_next(li)) {
+ g_hash_table_remove(priv->ht, li->data);
+ g_free(li->data);
+ }
+ removed = TRUE;
+ g_list_free(hitlist);
+ }
+ }
- if (trg_model_remove_removed(GTK_LIST_STORE(model),
- TORRENT_COLUMN_UPDATESERIAL,
- tc->updateSerial) > 0 || added)
+ if (added || removed)
g_signal_emit(model, signals[TMODEL_TORRENT_ADDREMOVE], 0);
}
diff --git a/src/trg-torrent-model.h b/src/trg-torrent-model.h
index eb58449..2f9b99a 100644
--- a/src/trg-torrent-model.h
+++ b/src/trg-torrent-model.h
@@ -73,7 +73,10 @@ find_existing_peer_item(GtkListStore * model, JsonObject * p,
void trg_torrent_model_update(TrgTorrentModel * model, trg_client * tc,
JsonObject * response,
trg_torrent_model_update_stats * stats,
- gboolean first);
+ gint mode);
+
+void trg_torrent_model_stats_scan(TrgTorrentModel *model, trg_torrent_model_update_stats *stats);
+GHashTable *get_torrent_table(TrgTorrentModel *model);
enum {
TORRENT_COLUMN_ICON,
diff --git a/src/trg-torrent-props-dialog.h b/src/trg-torrent-props-dialog.h
index e8bce84..9d1efed 100644
--- a/src/trg-torrent-props-dialog.h
+++ b/src/trg-torrent-props-dialog.h
@@ -17,7 +17,6 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-
#ifndef TRG_TORRENT_PROPS_DIALOG_H_
#define TRG_TORRENT_PROPS_DIALOG_H_
diff --git a/src/trg-torrent-tree-view.c b/src/trg-torrent-tree-view.c
index 196a74d..5c22fd4 100644
--- a/src/trg-torrent-tree-view.c
+++ b/src/trg-torrent-tree-view.c
@@ -65,7 +65,6 @@ static void trg_torrent_tree_view_init(TrgTorrentTreeView * tv)
TORRENT_COLUMN_ADDED, -1);
gtk_tree_view_set_search_column(GTK_TREE_VIEW(tv),
TORRENT_COLUMN_NAME);
-
}
gint get_first_selected(trg_client * client, TrgTorrentTreeView * view,
@@ -76,7 +75,6 @@ gint get_first_selected(trg_client * client, TrgTorrentTreeView * view,
GList *selectionList;
GList *firstNode;
gint64 id = -1;
- gint64 updateSerial = -1;
model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
@@ -87,14 +85,8 @@ gint get_first_selected(trg_client * client, TrgTorrentTreeView * view,
if (gtk_tree_model_get_iter
(model, iter, (GtkTreePath *) firstNode->data)) {
gtk_tree_model_get(model, iter, TORRENT_COLUMN_JSON, json,
- TORRENT_COLUMN_ID, &id,
- TORRENT_COLUMN_UPDATESERIAL, &updateSerial,
- -1);
-
- /* This is about to be removed and won't have valid JSON pointed
- * to by the model. */
- if (updateSerial < client->updateSerial)
- id = -1;
+ TORRENT_COLUMN_ID, &id, -1);
+
}
}
diff --git a/src/trg-trackers-model.c b/src/trg-trackers-model.c
index 3ea8254..7a8feb7 100644
--- a/src/trg-trackers-model.c
+++ b/src/trg-trackers-model.c
@@ -22,6 +22,7 @@
#include "config.h"
#include "torrent.h"
+#include "trg-client.h"
#include "trg-model.h"
#include "trg-trackers-model.h"
@@ -49,16 +50,16 @@ gint64 trg_trackers_model_get_torrent_id(TrgTrackersModel * model)
void trg_trackers_model_update(TrgTrackersModel * model,
gint64 updateSerial, JsonObject * t,
- gboolean first)
+ gint mode)
{
TrgTrackersModelPrivate *priv = TRG_TRACKERS_MODEL_GET_PRIVATE(model);
- guint j;
JsonArray *trackers;
+ GList *li;
const gchar *announce;
const gchar *scrape;
- if (first) {
+ if (mode == TORRENT_GET_MODE_FIRST) {
gtk_list_store_clear(GTK_LIST_STORE(model));
priv->torrentId = torrent_get_id(t);
priv->accept = TRUE;
@@ -68,16 +69,16 @@ void trg_trackers_model_update(TrgTrackersModel * model,
trackers = torrent_get_trackers(t);
- for (j = 0; j < json_array_get_length(trackers); j++) {
+ for (li = json_array_get_elements(trackers); li; li = g_list_next(li)) {
GtkTreeIter trackIter;
JsonObject *tracker =
- json_node_get_object(json_array_get_element(trackers, j));
+ json_node_get_object((JsonNode*)li->data);
gint64 trackerId = tracker_get_id(tracker);
announce = tracker_get_announce(tracker);
scrape = tracker_get_scrape(tracker);
- if (first
+ if (mode == TORRENT_GET_MODE_FIRST
|| find_existing_model_item(GTK_TREE_MODEL(model),
TRACKERCOL_ID, trackerId,
&trackIter) == FALSE)
diff --git a/src/trg-trackers-model.h b/src/trg-trackers-model.h
index 324d270..61a64a9 100644
--- a/src/trg-trackers-model.h
+++ b/src/trg-trackers-model.h
@@ -48,9 +48,9 @@ GType trg_trackers_model_get_type(void);
TrgTrackersModel *trg_trackers_model_new(void);
G_END_DECLS
- void trg_trackers_model_update(TrgTrackersModel * model,
+void trg_trackers_model_update(TrgTrackersModel * model,
gint64 updateSerial, JsonObject * t,
- gboolean first);
+ gint mode);
void trg_trackers_model_set_accept(TrgTrackersModel * model,
gboolean accept);
gint64 trg_trackers_model_get_torrent_id(TrgTrackersModel * model);
diff --git a/src/trg-trackers-tree-view.c b/src/trg-trackers-tree-view.c
index f5fe71a..acc20eb 100644
--- a/src/trg-trackers-tree-view.c
+++ b/src/trg-trackers-tree-view.c
@@ -105,7 +105,7 @@ static void trg_tracker_announce_edited(GtkCellRendererText * renderer,
req = torrent_set(torrentIds);
args = node_get_arguments(req);
- if (g_strcmp0(icon, GTK_STOCK_ADD) == 0) {
+ if (!g_strcmp0(icon, GTK_STOCK_ADD)) {
json_array_add_string_element(trackerModifiers, new_text);
json_object_set_array_member(args, "trackerAdd", trackerModifiers);
} else {