summaryrefslogtreecommitdiff
path: root/src/trg-torrent-model.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/trg-torrent-model.c')
-rw-r--r--src/trg-torrent-model.c297
1 files changed, 297 insertions, 0 deletions
diff --git a/src/trg-torrent-model.c b/src/trg-torrent-model.c
new file mode 100644
index 0000000..3bf8229
--- /dev/null
+++ b/src/trg-torrent-model.c
@@ -0,0 +1,297 @@
+/*
+ * transmission-remote-gtk - Transmission RPC client for GTK
+ * Copyright (C) 2010 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 <string.h>
+#include <gtk/gtk.h>
+#include <json-glib/json-glib.h>
+
+#include "torrent.h"
+#include "tpeer.h"
+#include "json.h"
+#include "trg-torrent-model.h"
+#include "protocol-constants.h"
+#include "trg-model.h"
+#include "util.h"
+
+enum {
+ TMODEL_TORRENT_COMPLETED,
+ TMODEL_SIGNAL_COUNT
+};
+
+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,
+ TrgTorrentModelClassUpdateStats * stats);
+
+static void
+update_torrent_iter(gint64 serial, TrgTorrentModel * model,
+ GtkTreeIter * iter, JsonObject * t,
+ TrgTorrentModelClassUpdateStats * stats);
+
+static gboolean
+find_existing_torrent_item_foreachfunc(GtkTreeModel * model,
+ GtkTreePath * path,
+ GtkTreeIter * iter, gpointer data);
+
+static gboolean
+find_existing_torrent_item(TrgTorrentModel * model, JsonObject * t,
+ GtkTreeIter * iter);
+
+static void trg_torrent_model_class_init(TrgTorrentModelClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+ 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);
+
+}
+
+static void trg_torrent_module_count_peers(TrgTorrentModel * model,
+ GtkTreeIter * iter,
+ JsonObject * t)
+{
+ JsonArray *peers;
+ gint seeders, leechers, j;
+
+ 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));
+
+ if (peer_get_is_downloading_from(peer))
+ seeders++;
+
+ if (peer_get_is_uploading_to(peer))
+ leechers++;
+ }
+
+ gtk_list_store_set(GTK_LIST_STORE(model), iter,
+ TORRENT_COLUMN_SEEDS, seeders,
+ TORRENT_COLUMN_LEECHERS, leechers, -1);
+}
+
+static void trg_torrent_model_init(TrgTorrentModel * self)
+{
+ GType column_types[TORRENT_COLUMN_COLUMNS];
+
+ column_types[TORRENT_COLUMN_ICON] = G_TYPE_STRING;
+ column_types[TORRENT_COLUMN_NAME] = G_TYPE_STRING;
+ column_types[TORRENT_COLUMN_SIZE] = G_TYPE_INT64;
+ column_types[TORRENT_COLUMN_DONE] = G_TYPE_DOUBLE;
+ column_types[TORRENT_COLUMN_STATUS] = G_TYPE_STRING;
+ column_types[TORRENT_COLUMN_SEEDS] = G_TYPE_INT;
+ column_types[TORRENT_COLUMN_LEECHERS] = G_TYPE_INT;
+ column_types[TORRENT_COLUMN_DOWNSPEED] = G_TYPE_INT64;
+ column_types[TORRENT_COLUMN_UPSPEED] = G_TYPE_INT64;
+ column_types[TORRENT_COLUMN_ETA] = G_TYPE_INT64;
+ column_types[TORRENT_COLUMN_UPLOADED] = G_TYPE_INT64;
+ column_types[TORRENT_COLUMN_DOWNLOADED] = G_TYPE_INT64;
+ column_types[TORRENT_COLUMN_RATIO] = G_TYPE_DOUBLE;
+ column_types[TORRENT_COLUMN_ID] = G_TYPE_INT;
+ column_types[TORRENT_COLUMN_JSON] = G_TYPE_POINTER;
+ column_types[TORRENT_COLUMN_UPDATESERIAL] = G_TYPE_INT64;
+ column_types[TORRENT_COLUMN_FLAGS] = G_TYPE_INT;
+
+ gtk_list_store_set_column_types(GTK_LIST_STORE(self),
+ TORRENT_COLUMN_COLUMNS, column_types);
+}
+
+static guint32 torrent_get_flags(JsonObject * t, gint64 status,
+ TrgTorrentModelClassUpdateStats * stats)
+{
+ 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;
+ break;
+ case STATUS_WAITING_TO_CHECK:
+ flags |= TORRENT_FLAG_WAITING_CHECK;
+ flags |= TORRENT_FLAG_CHECKING;
+ break;
+ }
+
+ if (torrent_get_is_finished(t) == TRUE)
+ flags |= TORRENT_FLAG_COMPLETE;
+ else
+ flags |= TORRENT_FLAG_INCOMPLETE;
+
+ if (strlen(torrent_get_errorstr(t)) > 0)
+ flags |= TORRENT_FLAG_ERROR;
+
+ return flags;
+}
+
+static void
+update_torrent_iter(gint64 serial, TrgTorrentModel * model,
+ GtkTreeIter * iter, JsonObject * t,
+ TrgTorrentModelClassUpdateStats * stats)
+{
+ guint lastFlags, newFlags;
+ gchar *statusString, *statusIcon;
+ gint64 downRate, upRate, downloaded, uploaded, id, status;
+
+ downRate = torrent_get_rate_down(t);
+ stats->downRateTotal += downRate;
+
+ upRate = torrent_get_rate_up(t);
+ stats->upRateTotal += upRate;
+
+ uploaded = torrent_get_uploaded(t);
+ downloaded = torrent_get_downloaded(t);
+
+ id = torrent_get_id(t);
+
+ status = torrent_get_status(t);
+ statusString = torrent_get_status_string(status);
+ newFlags = torrent_get_flags(t, status, stats);
+ statusIcon = torrent_get_status_icon(newFlags);
+
+ gtk_tree_model_get(GTK_TREE_MODEL(model), iter,
+ TORRENT_COLUMN_FLAGS, &lastFlags, -1);
+
+ gtk_list_store_set(GTK_LIST_STORE(model), iter,
+ TORRENT_COLUMN_ICON, statusIcon,
+ TORRENT_COLUMN_NAME, torrent_get_name(t),
+ TORRENT_COLUMN_SIZE, torrent_get_size(t),
+ TORRENT_COLUMN_DONE,
+ 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_RATIO,
+ uploaded >
+ 0 ? (double) uploaded / (double) downloaded : 0,
+ TORRENT_COLUMN_ID, id, TORRENT_COLUMN_JSON, t,
+ TORRENT_COLUMN_UPDATESERIAL, serial, -1);
+
+
+ if ((lastFlags & TORRENT_FLAG_DOWNLOADING) ==
+ TORRENT_FLAG_DOWNLOADING
+ && (newFlags & TORRENT_FLAG_COMPLETE) == TORRENT_FLAG_COMPLETE)
+ g_signal_emit(model, signals[TMODEL_TORRENT_COMPLETED], 0, iter);
+
+ trg_torrent_module_count_peers(model, iter, t);
+
+ g_free(statusString);
+ g_free(statusIcon);
+}
+
+TrgTorrentModel *trg_torrent_model_new(void)
+{
+ return g_object_new(TRG_TYPE_TORRENT_MODEL, NULL);
+}
+
+static gboolean
+find_existing_torrent_item_foreachfunc(GtkTreeModel * model,
+ GtkTreePath * path,
+ GtkTreeIter * iter, gpointer data)
+{
+ struct idAndIter *ii;
+ gint currentId;
+
+ ii = (struct idAndIter *) data;
+
+ gtk_tree_model_get(model, iter, TORRENT_COLUMN_ID, &currentId, -1);
+ if (currentId == ii->id) {
+ ii->iter = iter;
+ return ii->found = TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+find_existing_torrent_item(TrgTorrentModel * model, JsonObject * t,
+ GtkTreeIter * iter)
+{
+ struct idAndIter ii;
+ ii.id = torrent_get_id(t);
+ ii.found = FALSE;
+ gtk_tree_model_foreach(GTK_TREE_MODEL(model),
+ find_existing_torrent_item_foreachfunc, &ii);
+ if (ii.found == TRUE)
+ *iter = *(ii.iter);
+ return ii.found;
+}
+
+void trg_torrent_model_update(TrgTorrentModel * model, trg_client * tc,
+ JsonObject * response,
+ TrgTorrentModelClassUpdateStats * stats,
+ gboolean first)
+{
+ int i;
+ JsonArray *newTorrents;
+
+ newTorrents = get_torrents(get_arguments(response));
+
+ stats->count = json_array_get_length(newTorrents);
+
+ for (i = 0; i < stats->count; i++) {
+ GtkTreeIter iter;
+ JsonObject *t;
+
+ t = json_array_get_object_element(newTorrents, i);
+
+ if (first == TRUE
+ || find_existing_torrent_item(model, t, &iter) == FALSE)
+ gtk_list_store_append(GTK_LIST_STORE(model), &iter);
+
+ update_torrent_iter(tc->updateSerial, model, &iter, t, stats);
+ }
+
+ json_array_ref(newTorrents);
+
+ if (tc->torrents != NULL)
+ json_array_unref(tc->torrents);
+
+ tc->torrents = newTorrents;
+
+ trg_model_remove_removed(GTK_LIST_STORE(model),
+ TORRENT_COLUMN_UPDATESERIAL,
+ tc->updateSerial);
+}