diff options
author | Alan Fitton <ajf@eth0.org.uk> | 2011-12-21 00:32:54 +0000 |
---|---|---|
committer | Alan Fitton <ajf@eth0.org.uk> | 2011-12-21 00:32:54 +0000 |
commit | ec64e995ab1467596e75fb0aebda63bb047aefa5 (patch) | |
tree | 07d4d1f73b33085b8f87d9c0ae56a2548a1bc9be /src/trg-files-model.c | |
parent | 980ecb422cb29f93f5fe51b633be46cde36cedc6 (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.c | 267 |
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); } |