summaryrefslogtreecommitdiff
path: root/src/trg-files-model.c
diff options
context:
space:
mode:
authorGravatar Alan Fitton <ajf@eth0.org.uk>2011-12-21 00:32:54 +0000
committerGravatar Alan Fitton <ajf@eth0.org.uk>2011-12-21 00:32:54 +0000
commitec64e995ab1467596e75fb0aebda63bb047aefa5 (patch)
tree07d4d1f73b33085b8f87d9c0ae56a2548a1bc9be /src/trg-files-model.c
parent980ecb422cb29f93f5fe51b633be46cde36cedc6 (diff)
file trees :D may do cascading priority changes sometime, but this is a start. also use GTK_STOCK_FILE if mime/extension detection fails.
Diffstat (limited to 'src/trg-files-model.c')
-rw-r--r--src/trg-files-model.c267
1 files changed, 190 insertions, 77 deletions
diff --git a/src/trg-files-model.c b/src/trg-files-model.c
index 990c89b..e1f4d6a 100644
--- a/src/trg-files-model.c
+++ b/src/trg-files-model.c
@@ -1,5 +1,5 @@
/*
- * transmission-remote-gtk - Transmission RPC client for GTK
+ * 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
@@ -27,120 +27,239 @@
#include "trg-files-model.h"
-G_DEFINE_TYPE(TrgFilesModel, trg_files_model, GTK_TYPE_LIST_STORE)
+G_DEFINE_TYPE(TrgFilesModel, trg_files_model, GTK_TYPE_TREE_STORE)
#define TRG_FILES_MODEL_GET_PRIVATE(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), TRG_TYPE_FILES_MODEL, TrgFilesModelPrivate))
typedef struct _TrgFilesModelPrivate TrgFilesModelPrivate;
struct _TrgFilesModelPrivate {
gint64 torrentId;
+ guint n_items;
JsonArray *wanted;
JsonArray *priorities;
gboolean accept;
};
-static void trg_files_model_iter_new(TrgFilesModel * model,
- GtkTreeIter * iter, JsonObject * file,
- int id)
-{
- gchar *mimetype;
-
- gtk_list_store_append(GTK_LIST_STORE(model), iter);
- gtk_list_store_set(GTK_LIST_STORE(model), iter,
- FILESCOL_NAME, file_get_name(file),
- FILESCOL_SIZE, file_get_length(file),
- FILESCOL_ID, id, -1);
-
- mimetype = g_content_type_guess(file_get_name(file), NULL, 0, NULL);
- if (mimetype) {
- GIcon *icon = g_content_type_get_icon(mimetype);
- if (icon) {
- gtk_list_store_set(GTK_LIST_STORE(model), iter,
- FILESCOL_ICON, icon, -1);
- g_object_unref(icon);
+static void iter_to_row_reference(GtkTreeModel *model, GtkTreeIter *iter,
+ GtkTreeRowReference **rr) {
+ GtkTreePath *path = gtk_tree_model_get_path(model, iter);
+
+ if (*rr)
+ gtk_tree_row_reference_free(*rr);
+
+ *rr = gtk_tree_row_reference_new(model, path);
+ gtk_tree_path_free(path);
+}
+
+static void rowref_to_iter(GtkTreeModel *model, GtkTreeRowReference *rr,
+ GtkTreeIter *iter) {
+ GtkTreePath *path = gtk_tree_row_reference_get_path(rr);
+ gtk_tree_model_get_iter(model, iter, path);
+ gtk_tree_path_free(path);
+}
+
+static gboolean trg_files_update_new_parents(GtkTreeModel *model,
+ GtkTreePath *path, GtkTreeIter *iter, gpointer data) {
+ GtkTreeIter *descendentIter = (GtkTreeIter*) data;
+ GtkTreePath *descendentPath = gtk_tree_model_get_path(model,
+ descendentIter);
+
+ if (gtk_tree_path_is_ancestor(path, descendentPath)
+ && gtk_tree_model_get_iter(model, descendentIter, descendentPath)) {
+ gint64 size, oldSize;
+ gtk_tree_model_get(model, descendentIter, FILESCOL_SIZE, &size, -1);
+ gtk_tree_model_get(model, iter, FILESCOL_SIZE, &oldSize, -1);
+ gtk_tree_store_set(GTK_TREE_STORE(model), iter, FILESCOL_SIZE,
+ size + oldSize, -1);
+ }
+
+ gtk_tree_path_free(descendentPath);
+
+ return FALSE;
+}
+
+struct updateAllArgs {
+ GtkTreeIter *descendentIter;
+ gint64 increment;
+};
+
+static gboolean trg_files_update_all_parents(GtkTreeModel *model,
+ GtkTreePath *path, GtkTreeIter *iter, gpointer data) {
+ struct updateAllArgs *args = (struct updateAllArgs*) data;
+ GtkTreePath *descendentPath = gtk_tree_model_get_path(model,
+ args->descendentIter);
+
+ if (gtk_tree_path_is_ancestor(path, descendentPath)) {
+ gint64 lastCompleted, newCompleted, length;
+ gtk_tree_model_get(model, iter, FILESCOL_BYTESCOMPLETED, &lastCompleted,
+ FILESCOL_SIZE, &length, -1);
+ newCompleted = lastCompleted + args->increment;
+ gtk_tree_store_set(GTK_TREE_STORE(model), iter, FILESCOL_BYTESCOMPLETED,
+ newCompleted, FILESCOL_PROGRESS,
+ file_get_progress(length, newCompleted), -1);
+ }
+
+ gtk_tree_path_free(descendentPath);
+
+ return FALSE;
+}
+
+static void trg_files_model_iter_new(TrgFilesModel * model, GtkTreeIter * iter,
+ JsonObject * file, gint id) {
+ TrgFilesModelPrivate *priv = TRG_FILES_MODEL_GET_PRIVATE(model);
+ gchar **elements = g_strsplit(file_get_name(file), "/", -1);
+ gchar *existingName;
+ gint i, existingId;
+ GtkTreeRowReference *parentRowRef = NULL;
+ GtkTreeIter parentIter;
+
+ for (i = 0; elements[i]; i++) {
+ GtkTreeIter *found = NULL;
+
+ if (parentRowRef)
+ rowref_to_iter(GTK_TREE_MODEL(model), parentRowRef, &parentIter);
+
+ /* If this is the last component of the path, create a file node. */
+
+ if (!elements[i + 1]) {
+ gtk_tree_store_append(GTK_TREE_STORE(model), iter,
+ parentRowRef ? &parentIter : NULL);
+ gtk_tree_store_set(GTK_TREE_STORE(model), iter, FILESCOL_NAME,
+ elements[i], FILESCOL_SIZE, file_get_length(file),
+ FILESCOL_ID, id, -1);
+
+ if (parentRowRef) {
+ gtk_tree_model_foreach(GTK_TREE_MODEL(model),
+ trg_files_update_new_parents, iter);
+ }
+
+ break;
+ }
+
+ /* Search for the directory this files goes under, under the saved
+ * GtkTreeRowReferece *parent. */
+
+ if (gtk_tree_model_iter_children(GTK_TREE_MODEL(model), iter,
+ parentRowRef ? &parentIter : NULL)) {
+ do {
+ gtk_tree_model_get(GTK_TREE_MODEL(model), iter, FILESCOL_NAME,
+ &existingName, FILESCOL_ID, &existingId, -1);
+
+ if (existingId == -1 && !g_strcmp0(elements[i], existingName)) {
+ found = iter;
+ iter_to_row_reference(GTK_TREE_MODEL(model), iter,
+ &parentRowRef);
+ }
+
+ g_free(existingName);
+
+ if (found)
+ break;
+ } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(model), iter));
+ }
+
+ if (!found) {
+ gtk_tree_store_append(GTK_TREE_STORE(model), iter,
+ parentRowRef ? &parentIter : NULL);
+ gtk_tree_store_set(GTK_TREE_STORE(model), iter, FILESCOL_PRIORITY,
+ -2, FILESCOL_ID, -1, FILESCOL_NAME, elements[i], -1);
+ iter_to_row_reference(GTK_TREE_MODEL(model), iter, &parentRowRef);
}
}
- g_free(mimetype);
+ if (parentRowRef)
+ gtk_tree_row_reference_free(parentRowRef);
+
+ g_strfreev(elements);
+ priv->n_items++;
}
-void trg_files_model_set_accept(TrgFilesModel * model, gboolean accept)
-{
+void trg_files_model_set_accept(TrgFilesModel * model, gboolean accept) {
TrgFilesModelPrivate *priv = TRG_FILES_MODEL_GET_PRIVATE(model);
priv->accept = accept;
}
-static void
-trg_files_model_iter_update(TrgFilesModel * model,
- GtkTreeIter * filesIter, JsonObject * file,
- JsonArray * wantedArray,
- JsonArray * prioritiesArray, int id)
-{
+static void trg_files_model_iter_update(TrgFilesModel * model,
+ GtkTreeIter * filesIter, gboolean isFirst, JsonObject * file,
+ JsonArray * wantedArray, JsonArray * prioritiesArray, int id) {
TrgFilesModelPrivate *priv = TRG_FILES_MODEL_GET_PRIVATE(model);
- gboolean wanted = json_node_get_int(json_array_get_element
- (wantedArray, id)) == 1;
- gint64 priority =
- json_node_get_int(json_array_get_element(prioritiesArray, id));
- gdouble progress = file_get_progress(file);
+ gint64 fileLength = file_get_length(file);
+ gint64 fileCompleted = file_get_bytes_completed(file);
+
+ gboolean wanted = json_node_get_int(json_array_get_element(wantedArray, id))
+ == 1;
+ gint64 priority = json_node_get_int(
+ json_array_get_element(prioritiesArray, id));
+ gdouble progress = file_get_progress(fileLength, fileCompleted);
+
+ struct updateAllArgs args;
+ args.descendentIter = filesIter;
+
+ if (isFirst) {
+ args.increment = fileLength;
+ } else {
+ gint64 lastCompleted;
+ gtk_tree_model_get(GTK_TREE_MODEL(model), filesIter,
+ FILESCOL_BYTESCOMPLETED, &lastCompleted, -1);
+ args.increment = fileCompleted - lastCompleted;
+ }
+
+ gtk_tree_store_set(GTK_TREE_STORE(model), filesIter, FILESCOL_PROGRESS,
+ progress, FILESCOL_BYTESCOMPLETED, fileCompleted, -1);
- gtk_list_store_set(GTK_LIST_STORE(model), filesIter,
- FILESCOL_PROGRESS, progress, -1);
+ gtk_tree_model_foreach(GTK_TREE_MODEL(model), trg_files_update_all_parents,
+ &args);
if (priv->accept) {
- gtk_list_store_set(GTK_LIST_STORE(model), filesIter,
- FILESCOL_WANTED,
- wanted ? GTK_STOCK_APPLY : GTK_STOCK_CANCEL,
- FILESCOL_PRIORITY, priority, -1);
+ gtk_tree_store_set(GTK_TREE_STORE(model), filesIter, FILESCOL_WANTED,
+ wanted ? GTK_STOCK_APPLY : GTK_STOCK_CANCEL
+ , FILESCOL_PRIORITY, priority, -1);
+
}
}
-static void trg_files_model_class_init(TrgFilesModelClass * klass)
-{
+static void trg_files_model_class_init(TrgFilesModelClass * klass) {
g_type_class_add_private(klass, sizeof(TrgFilesModelPrivate));
}
-static void trg_files_model_init(TrgFilesModel * self)
-{
+static void trg_files_model_init(TrgFilesModel * self) {
TrgFilesModelPrivate *priv = TRG_FILES_MODEL_GET_PRIVATE(self);
GType column_types[FILESCOL_COLUMNS];
priv->accept = TRUE;
- column_types[FILESCOL_ICON] = G_TYPE_ICON;
column_types[FILESCOL_NAME] = G_TYPE_STRING;
column_types[FILESCOL_SIZE] = G_TYPE_INT64;
column_types[FILESCOL_PROGRESS] = G_TYPE_DOUBLE;
column_types[FILESCOL_ID] = G_TYPE_INT;
column_types[FILESCOL_WANTED] = G_TYPE_STRING;
column_types[FILESCOL_PRIORITY] = G_TYPE_INT64;
+ column_types[FILESCOL_BYTESCOMPLETED] = G_TYPE_INT64;
- gtk_list_store_set_column_types(GTK_LIST_STORE(self),
- FILESCOL_COLUMNS, column_types);
+ gtk_tree_store_set_column_types(GTK_TREE_STORE(self), FILESCOL_COLUMNS,
+ column_types);
}
-gboolean
-trg_files_model_update_foreach(GtkListStore * model,
- GtkTreePath * path G_GNUC_UNUSED,
- GtkTreeIter * iter, GList * files)
-{
+gboolean trg_files_model_update_foreach(GtkListStore * model,
+ GtkTreePath * path G_GNUC_UNUSED, GtkTreeIter * iter, GList * files) {
TrgFilesModelPrivate *priv = TRG_FILES_MODEL_GET_PRIVATE(model);
JsonObject *file;
gint id;
gtk_tree_model_get(GTK_TREE_MODEL(model), iter, FILESCOL_ID, &id, -1);
- file = json_node_get_object(g_list_nth_data(files, id));
- trg_files_model_iter_update(TRG_FILES_MODEL(model), iter, file,
- priv->wanted, priv->priorities, id);
+ if (id >= 0) {
+ file = json_node_get_object(g_list_nth_data(files, id));
+ trg_files_model_iter_update(TRG_FILES_MODEL(model), iter, FALSE, file,
+ priv->wanted, priv->priorities, id);
+ }
return FALSE;
}
-void
-trg_files_model_update(TrgFilesModel * model, gint64 updateSerial,
- JsonObject * t, gint mode)
-{
+void trg_files_model_update(TrgFilesModel * model, gint64 updateSerial,
+ JsonObject * t, gint mode) {
TrgFilesModelPrivate *priv = TRG_FILES_MODEL_GET_PRIVATE(model);
GList *filesList, *li;
GtkTreeIter filesIter;
@@ -154,32 +273,28 @@ trg_files_model_update(TrgFilesModel * model, gint64 updateSerial,
filesList = json_array_get_elements(torrent_get_files(t));
if (mode == TORRENT_GET_MODE_FIRST) {
- gtk_list_store_clear(GTK_LIST_STORE(model));
+ gtk_tree_store_clear(GTK_TREE_STORE(model));
priv->accept = TRUE;
for (li = filesList; li; li = g_list_next(li)) {
file = json_node_get_object((JsonNode *) li->data);
trg_files_model_iter_new(model, &filesIter, file, j);
- trg_files_model_iter_update(model, &filesIter,
- file, priv->wanted,
- priv->priorities, j);
+ trg_files_model_iter_update(model, &filesIter, TRUE, file,
+ priv->wanted, priv->priorities, j);
j++;
}
} else {
- gint n_existing =
- gtk_tree_model_iter_n_children(GTK_TREE_MODEL(model), NULL);
guint n_updates = g_list_length(filesList);
gtk_tree_model_foreach(GTK_TREE_MODEL(model),
- (GtkTreeModelForeachFunc)
- trg_files_model_update_foreach, filesList);
- if (n_updates > n_existing) {
- gint n_new = n_updates - n_existing;
+ (GtkTreeModelForeachFunc) trg_files_model_update_foreach,
+ filesList);
+ if (n_updates > priv->n_items) {
+ gint n_new = n_updates - priv->n_items;
for (j = n_updates - n_new; j < n_updates; j++) {
file = json_node_get_object(g_list_nth_data(filesList, j));
trg_files_model_iter_new(model, &filesIter, file, j);
- trg_files_model_iter_update(model, &filesIter,
- file, priv->wanted,
- priv->priorities, j);
+ trg_files_model_iter_update(model, &filesIter, TRUE, file,
+ priv->wanted, priv->priorities, j);
}
}
}
@@ -187,13 +302,11 @@ trg_files_model_update(TrgFilesModel * model, gint64 updateSerial,
g_list_free(filesList);
}
-gint64 trg_files_model_get_torrent_id(TrgFilesModel * model)
-{
+gint64 trg_files_model_get_torrent_id(TrgFilesModel * model) {
TrgFilesModelPrivate *priv = TRG_FILES_MODEL_GET_PRIVATE(model);
return priv->torrentId;
}
-TrgFilesModel *trg_files_model_new(void)
-{
+TrgFilesModel *trg_files_model_new(void) {
return g_object_new(TRG_TYPE_FILES_MODEL, NULL);
}