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 | |
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.
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/torrent.c | 5 | ||||
-rw-r--r-- | src/torrent.h | 2 | ||||
-rw-r--r-- | src/trg-cell-renderer-file-icon.c | 157 | ||||
-rw-r--r-- | src/trg-cell-renderer-file-icon.h | 51 | ||||
-rw-r--r-- | src/trg-cell-renderer-priority.c | 11 | ||||
-rw-r--r-- | src/trg-cell-renderer-size.c | 1 | ||||
-rw-r--r-- | src/trg-files-model.c | 267 | ||||
-rw-r--r-- | src/trg-files-model.h | 6 | ||||
-rw-r--r-- | src/trg-files-tree-view.c | 52 | ||||
-rw-r--r-- | src/trg-main-window.c | 18 | ||||
-rw-r--r-- | src/trg-peers-tree-view.c | 2 | ||||
-rw-r--r-- | src/trg-torrent-tree-view.c | 2 | ||||
-rw-r--r-- | src/trg-trackers-tree-view.c | 2 | ||||
-rw-r--r-- | src/trg-tree-view.c | 28 | ||||
-rw-r--r-- | src/trg-tree-view.h | 4 | ||||
-rw-r--r-- | src/util.c | 20 |
17 files changed, 481 insertions, 148 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 7345485..a2243b6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -83,6 +83,7 @@ transmission_remote_gtk_SOURCES = main.c \ trg-cell-renderer-eta.c \ trg-remote-prefs-dialog.c \ trg-cell-renderer-priority.c \ + trg-cell-renderer-file-icon.c \ trg-cell-renderer-epoch.c \ trg-cell-renderer-numgteqthan.c \ trg-torrent-move-dialog.c \ diff --git a/src/torrent.c b/src/torrent.c index c7562a4..ab123c3 100644 --- a/src/torrent.c +++ b/src/torrent.c @@ -606,11 +606,10 @@ gint64 peerfrom_get_lpd(JsonObject * pf) /* files */ -gdouble file_get_progress(JsonObject * f) +gdouble file_get_progress(gint64 length, gint64 completed) { - gint64 length = file_get_length(f); if (length > 0) { - return ((gdouble) file_get_bytes_completed(f) / + return ((gdouble) completed / (gdouble) length) * 100.0; } else { return 0.0; diff --git a/src/torrent.h b/src/torrent.h index daca8c2..7270d6d 100644 --- a/src/torrent.h +++ b/src/torrent.h @@ -118,7 +118,7 @@ gint64 tracker_stats_get_last_scrape_time(JsonObject * t); gint64 file_get_length(JsonObject * f); gint64 file_get_bytes_completed(JsonObject * f); const gchar *file_get_name(JsonObject * f); -gdouble file_get_progress(JsonObject * f); +gdouble file_get_progress(gint64 length, gint64 completed); /* peers */ diff --git a/src/trg-cell-renderer-file-icon.c b/src/trg-cell-renderer-file-icon.c new file mode 100644 index 0000000..de29cb9 --- /dev/null +++ b/src/trg-cell-renderer-file-icon.c @@ -0,0 +1,157 @@ +/* + * transmission-remote-gtk - Transmission RPC client for GTK + * 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-file-icon.h" +#include "util.h" + +enum { + PROP_0, + PROP_FILE_ID, + PROP_FILE_NAME +}; + +G_DEFINE_TYPE(TrgCellRendererFileIcon, trg_cell_renderer_file_icon, + GTK_TYPE_CELL_RENDERER_PIXBUF) +#define TRG_CELL_RENDERER_FILE_ICON_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), TRG_TYPE_CELL_RENDERER_FILE_ICON, TrgCellRendererFileIconPrivate)) +typedef struct _TrgCellRendererFileIconPrivate TrgCellRendererFileIconPrivate; + +struct _TrgCellRendererFileIconPrivate { + gint64 file_id; + gchar *text; +}; + +static void +trg_cell_renderer_file_icon_get_property(GObject * object, guint property_id, + GValue * value, GParamSpec * pspec) +{ + TrgCellRendererFileIconPrivate *priv = + TRG_CELL_RENDERER_FILE_ICON_GET_PRIVATE(object); + switch (property_id) { + case PROP_FILE_ID: + g_value_set_int64(value, priv->file_id); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + break; + } +} + +static void trg_cell_renderer_file_icon_refresh(TrgCellRendererFileIcon *fi) +{ + TrgCellRendererFileIconPrivate *priv = + TRG_CELL_RENDERER_FILE_ICON_GET_PRIVATE(fi); + + if (priv->file_id == -2) { + return; + } else if (priv->file_id == -1) { + g_object_set(fi, "stock-id", GTK_STOCK_DIRECTORY, NULL); + } else if (priv->text) { + gboolean uncertain; + gchar *mimetype = g_content_type_guess(priv->text, NULL, 0, &uncertain); + GIcon *icon = NULL; + + if (!uncertain && mimetype) + icon = g_content_type_get_icon(mimetype); + + g_free(mimetype); + + if (icon) { + g_object_set(fi, "gicon", icon, NULL); + g_object_unref(icon); + } else { + g_object_set(fi, "stock-id", GTK_STOCK_FILE, NULL); + } + } +} + +static void +trg_cell_renderer_file_icon_set_property(GObject * object, guint property_id, + const GValue * value, + GParamSpec * pspec) +{ + TrgCellRendererFileIconPrivate *priv = + TRG_CELL_RENDERER_FILE_ICON_GET_PRIVATE(object); + if (property_id == PROP_FILE_ID) { + priv->file_id = g_value_get_int64(value); + trg_cell_renderer_file_icon_refresh(TRG_CELL_RENDERER_FILE_ICON(object)); + } else if (property_id == PROP_FILE_NAME) { + if (priv->file_id != -1) { + g_free(priv->text); + priv->text = g_strdup(g_value_get_string(value)); + trg_cell_renderer_file_icon_refresh(TRG_CELL_RENDERER_FILE_ICON(object)); + } + } else { + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + } +} + +static void +trg_cell_renderer_file_icon_class_init(TrgCellRendererFileIconClass * klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + + object_class->get_property = trg_cell_renderer_file_icon_get_property; + object_class->set_property = trg_cell_renderer_file_icon_set_property; + + g_object_class_install_property(object_class, + PROP_FILE_ID, + g_param_spec_int64("file-id", + "File ID", + "File ID", + -2, + INT64_MAX, + -2, + G_PARAM_READWRITE + | + G_PARAM_STATIC_NAME + | + G_PARAM_STATIC_NICK + | + G_PARAM_STATIC_BLURB)); + + g_object_class_install_property(object_class, + PROP_FILE_NAME, + g_param_spec_string("file-name", + "Filename", + "Filename", + NULL, + G_PARAM_READWRITE + | + G_PARAM_STATIC_NAME + | + G_PARAM_STATIC_NICK + | + G_PARAM_STATIC_BLURB)); + + g_type_class_add_private(klass, sizeof(TrgCellRendererFileIconPrivate)); +} + +static void trg_cell_renderer_file_icon_init(TrgCellRendererFileIcon * self) +{ +} + +GtkCellRenderer *trg_cell_renderer_file_icon_new(void) +{ + return + GTK_CELL_RENDERER(g_object_new(TRG_TYPE_CELL_RENDERER_FILE_ICON, NULL)); +} diff --git a/src/trg-cell-renderer-file-icon.h b/src/trg-cell-renderer-file-icon.h new file mode 100644 index 0000000..11ef2de --- /dev/null +++ b/src/trg-cell-renderer-file-icon.h @@ -0,0 +1,51 @@ +/* + * transmission-remote-gtk - Transmission RPC client for GTK + * 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_FILE_ICON_H_ +#define TRG_CELL_RENDERER_FILE_ICON_H_ + +#include <glib-object.h> +#include <gtk/gtk.h> + +G_BEGIN_DECLS +#define TRG_TYPE_CELL_RENDERER_FILE_ICON trg_cell_renderer_file_icon_get_type() +#define TRG_CELL_RENDERER_FILE_ICON(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), TRG_TYPE_CELL_RENDERER_FILE_ICON, TrgCellRendererFileIcon)) +#define TRG_CELL_RENDERER_FILE_ICON_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), TRG_TYPE_CELL_RENDERER_FILE_ICON, TrgCellRendererFileIconClass)) +#define TRG_IS_CELL_RENDERER_FILE_ICON(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TRG_TYPE_CELL_RENDERER_FILE_ICON)) +#define TRG_IS_CELL_RENDERER_FILE_ICON_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), TRG_TYPE_CELL_RENDERER_FILE_ICON)) +#define TRG_CELL_RENDERER_FILE_ICON_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), TRG_TYPE_CELL_RENDERER_FILE_ICON, TrgCellRendererFileIconClass)) + typedef struct { + GtkCellRendererPixbuf parent; +} TrgCellRendererFileIcon; + +typedef struct { + GtkCellRendererPixbufClass parent_class; +} TrgCellRendererFileIconClass; + +GType trg_cell_renderer_file_icon_get_type(void); + +GtkCellRenderer *trg_cell_renderer_file_icon_new(void); + +G_END_DECLS +#endif /* TRG_CELL_RENDERER_FILE_ICON_H_ */ diff --git a/src/trg-cell-renderer-priority.c b/src/trg-cell-renderer-priority.c index 14d4763..3a80322 100644 --- a/src/trg-cell-renderer-priority.c +++ b/src/trg-cell-renderer-priority.c @@ -55,6 +55,7 @@ trg_cell_renderer_priority_get_property(GObject * object, break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + break; } } @@ -68,13 +69,15 @@ trg_cell_renderer_priority_set_property(GObject * object, TRG_CELL_RENDERER_PRIORITY_GET_PRIVATE(object); if (property_id == PROP_PRIORITY_VALUE) { - priv->priority_value = g_value_get_int64(value); + priv->priority_value = g_value_get_int(value); if (priv->priority_value == TR_PRI_LOW) { g_object_set(object, "text", _("Low"), NULL); } else if (priv->priority_value == TR_PRI_HIGH) { g_object_set(object, "text", _("High"), NULL); - } else { + } else if (priv->priority_value == TR_PRI_NORMAL){ g_object_set(object, "text", _("Normal"), NULL); + } else { + g_object_set(object, "text", "", NULL); } } else { G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); @@ -91,10 +94,10 @@ trg_cell_renderer_priority_class_init(TrgCellRendererPriorityClass * klass) g_object_class_install_property(object_class, PROP_PRIORITY_VALUE, - g_param_spec_int64 + g_param_spec_int ("priority-value", "Priority Value", - "Priority Value", TR_PRI_LOW, + "Priority Value", -2, TR_PRI_HIGH, TR_PRI_NORMAL, G_PARAM_READWRITE | G_PARAM_STATIC_NAME | diff --git a/src/trg-cell-renderer-size.c b/src/trg-cell-renderer-size.c index 2271d2e..d6d07cb 100644 --- a/src/trg-cell-renderer-size.c +++ b/src/trg-cell-renderer-size.c @@ -50,6 +50,7 @@ trg_cell_renderer_size_get_property(GObject * object, guint property_id, break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + break; } } 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); } diff --git a/src/trg-files-model.h b/src/trg-files-model.h index c47c361..1a68d3b 100644 --- a/src/trg-files-model.h +++ b/src/trg-files-model.h @@ -38,11 +38,11 @@ G_BEGIN_DECLS #define TRG_FILES_MODEL_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), TRG_TYPE_FILES_MODEL, TrgFilesModelClass)) typedef struct { - GtkListStore parent; + GtkTreeStore parent; } TrgFilesModel; typedef struct { - GtkListStoreClass parent_class; + GtkTreeStoreClass parent_class; } TrgFilesModelClass; GType trg_files_model_get_type(void); @@ -50,13 +50,13 @@ GType trg_files_model_get_type(void); TrgFilesModel *trg_files_model_new(void); G_END_DECLS enum { - FILESCOL_ICON, FILESCOL_NAME, FILESCOL_SIZE, FILESCOL_PROGRESS, FILESCOL_ID, FILESCOL_WANTED, FILESCOL_PRIORITY, + FILESCOL_BYTESCOMPLETED, FILESCOL_COLUMNS }; diff --git a/src/trg-files-tree-view.c b/src/trg-files-tree-view.c index b3e4011..4755e5b 100644 --- a/src/trg-files-tree-view.c +++ b/src/trg-files-tree-view.c @@ -45,34 +45,36 @@ static void trg_files_tree_view_class_init(TrgFilesTreeViewClass * klass) g_type_class_add_private(klass, sizeof(TrgFilesTreeViewPrivate)); } -static void set_unwanted_foreachfunc(GtkTreeModel * model, +static void set_wanted_foreachfunc(GtkTreeModel * model, GtkTreePath * path G_GNUC_UNUSED, GtkTreeIter * iter, - gpointer data G_GNUC_UNUSED) + gpointer data) { - gtk_list_store_set(GTK_LIST_STORE(model), iter, FILESCOL_WANTED, - GTK_STOCK_CANCEL, -1); -} + gint id; + gtk_tree_model_get(model, iter, FILESCOL_ID, &id, -1); -static void set_wanted_foreachfunc(GtkTreeModel * model, - GtkTreePath * path G_GNUC_UNUSED, - GtkTreeIter * iter, - gpointer data G_GNUC_UNUSED) -{ - gtk_list_store_set(GTK_LIST_STORE(model), iter, - FILESCOL_WANTED, GTK_STOCK_APPLY, -1); + if (id >= 0) { + gtk_tree_store_set(GTK_TREE_STORE(model), iter, FILESCOL_WANTED, + (gchar*)data, -1); + } } static void set_priority_foreachfunc(GtkTreeModel * model, GtkTreePath * path G_GNUC_UNUSED, GtkTreeIter * iter, gpointer data) { + gint id; GValue value = { 0 }; - g_value_init(&value, G_TYPE_INT64); - g_value_set_int64(&value, (gint64) GPOINTER_TO_INT(data)); - gtk_list_store_set_value(GTK_LIST_STORE(model), iter, - FILESCOL_PRIORITY, &value); + gtk_tree_model_get(model, iter, FILESCOL_ID, &id, -1); + + if(id >= 0) { + g_value_init(&value, G_TYPE_INT64); + g_value_set_int64(&value, (gint64) GPOINTER_TO_INT(data)); + + gtk_tree_store_set_value(GTK_TREE_STORE(model), iter, + FILESCOL_PRIORITY, &value); + } } static void send_updated_file_prefs_foreachfunc(GtkTreeModel * model, @@ -82,11 +84,17 @@ static void send_updated_file_prefs_foreachfunc(GtkTreeModel * model, gpointer data) { JsonObject *args = (JsonObject *) data; - gint64 priority, id; + gint64 priority; + gint id; gchar *wanted; + gtk_tree_model_get(model, iter, FILESCOL_ID, &id, -1); + + if (id < 0) + return; + gtk_tree_model_get(model, iter, FILESCOL_WANTED, &wanted, - FILESCOL_PRIORITY, &priority, FILESCOL_ID, &id, -1); + FILESCOL_PRIORITY, &priority, -1); if (!g_strcmp0(wanted, GTK_STOCK_CANCEL)) add_file_id_to_array(args, FIELD_FILES_UNWANTED, id); @@ -185,7 +193,7 @@ static void set_unwanted(GtkWidget * w G_GNUC_UNUSED, gpointer data) GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data)); gtk_tree_selection_selected_foreach(selection, - set_unwanted_foreachfunc, NULL); + set_wanted_foreachfunc, GTK_STOCK_CANCEL); send_updated_file_prefs(tv); } @@ -195,7 +203,7 @@ static void set_wanted(GtkWidget * w G_GNUC_UNUSED, gpointer data) GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data)); gtk_tree_selection_selected_foreach(selection, - set_wanted_foreachfunc, NULL); + set_wanted_foreachfunc, GTK_STOCK_APPLY); send_updated_file_prefs(tv); } @@ -288,9 +296,9 @@ static void trg_files_tree_view_init(TrgFilesTreeView * self) trg_column_description *desc; desc = - trg_tree_view_reg_column(ttv, TRG_COLTYPE_GICONTEXT, FILESCOL_NAME, + trg_tree_view_reg_column(ttv, TRG_COLTYPE_FILEICONTEXT, FILESCOL_NAME, _("Name"), "name", 0); - desc->model_column_icon = FILESCOL_ICON; + desc->model_column_extra = FILESCOL_ID; trg_tree_view_reg_column(ttv, TRG_COLTYPE_SIZE, FILESCOL_SIZE, _("Size"), "size", 0); diff --git a/src/trg-main-window.c b/src/trg-main-window.c index d55b845..6db4e19 100644 --- a/src/trg-main-window.c +++ b/src/trg-main-window.c @@ -275,12 +275,6 @@ static void trg_main_window_init(TrgMainWindow * self G_GNUC_UNUSED) { } -GtkTreeModel *trg_main_window_get_torrent_model(TrgMainWindow * win) -{ - TrgMainWindowPrivate *priv = TRG_MAIN_WINDOW_GET_PRIVATE(win); - return GTK_TREE_MODEL(priv->torrentModel); -} - gint trg_mw_get_selected_torrent_id(TrgMainWindow * win) { TrgMainWindowPrivate *priv = TRG_MAIN_WINDOW_GET_PRIVATE(win); @@ -308,6 +302,10 @@ static void update_selected_torrent_notebook(TrgMainWindow * win, trg_peers_model_update(priv->peersModel, TRG_TREE_VIEW(priv->peersTreeView), trg_client_get_serial(client), t, mode); + + if (mode == TORRENT_GET_MODE_FIRST) + gtk_tree_view_expand_all(GTK_TREE_VIEW(priv->filesTreeView)); + } else if (id < 0) { trg_main_window_torrent_scrub(win); } @@ -1079,9 +1077,9 @@ static void update_whatever_statusicon(TrgMainWindow * win, #endif } - /* - * The callback for a torrent-get response. - */ +/* + * The callback for a torrent-get response. + */ static gboolean on_torrent_get(gpointer data, int mode) { @@ -1424,7 +1422,7 @@ void trg_main_window_torrent_scrub(TrgMainWindow * win) { TrgMainWindowPrivate *priv = TRG_MAIN_WINDOW_GET_PRIVATE(win); - gtk_list_store_clear(GTK_LIST_STORE(priv->filesModel)); + gtk_tree_store_clear(GTK_TREE_STORE(priv->filesModel)); gtk_list_store_clear(GTK_LIST_STORE(priv->trackersModel)); gtk_list_store_clear(GTK_LIST_STORE(priv->peersModel)); trg_general_panel_clear(priv->genDetails); diff --git a/src/trg-peers-tree-view.c b/src/trg-peers-tree-view.c index ab86d69..20eae98 100644 --- a/src/trg-peers-tree-view.c +++ b/src/trg-peers-tree-view.c @@ -49,7 +49,7 @@ static void trg_peers_tree_view_init(TrgPeersTreeView * self) desc = trg_tree_view_reg_column(ttv, TRG_COLTYPE_STOCKICONTEXT, PEERSCOL_IP, _("IP"), "ip", 0); - desc->model_column_icon = PEERSCOL_ICON; + desc->model_column_extra = PEERSCOL_ICON; trg_tree_view_reg_column(ttv, TRG_COLTYPE_TEXT, PEERSCOL_HOST, _("Host"), "host", 0); diff --git a/src/trg-torrent-tree-view.c b/src/trg-torrent-tree-view.c index a359dff..89885d7 100644 --- a/src/trg-torrent-tree-view.c +++ b/src/trg-torrent-tree-view.c @@ -43,7 +43,7 @@ static void trg_torrent_tree_view_init(TrgTorrentTreeView * tttv) trg_tree_view_reg_column(ttv, TRG_COLTYPE_STOCKICONTEXT, TORRENT_COLUMN_NAME, _("Name"), "name", 0); - desc->model_column_icon = TORRENT_COLUMN_ICON; + desc->model_column_extra = TORRENT_COLUMN_ICON; trg_tree_view_reg_column(ttv, TRG_COLTYPE_SIZE, TORRENT_COLUMN_SIZE, _("Size"), "size", 0); diff --git a/src/trg-trackers-tree-view.c b/src/trg-trackers-tree-view.c index 334b35c..d481f53 100644 --- a/src/trg-trackers-tree-view.c +++ b/src/trg-trackers-tree-view.c @@ -166,7 +166,7 @@ static void trg_trackers_tree_view_init(TrgTrackersTreeView * self) trg_tree_view_reg_column(ttv, TRG_COLTYPE_STOCKICONTEXT, TRACKERCOL_TIER, _("Tier"), "tier", TRG_COLUMN_UNREMOVABLE); - desc->model_column_icon = TRACKERCOL_ICON; + desc->model_column_extra = TRACKERCOL_ICON; desc = trg_tree_view_reg_column(ttv, TRG_COLTYPE_TEXT, diff --git a/src/trg-tree-view.c b/src/trg-tree-view.c index 30db56e..d6c7b93 100644 --- a/src/trg-tree-view.c +++ b/src/trg-tree-view.c @@ -31,6 +31,7 @@ #include "trg-cell-renderer-epoch.h" #include "trg-cell-renderer-priority.h" #include "trg-cell-renderer-numgteqthan.h" +#include "trg-cell-renderer-file-icon.h" /* A subclass of GtkTreeView which allows the user to change column visibility * by right clicking on any column for a menu to hide the clicked column, or @@ -264,7 +265,28 @@ static GtkTreeViewColumn gtk_tree_view_column_pack_start(column, renderer, FALSE); gtk_tree_view_column_set_attributes(column, renderer, renderer_property, - desc->model_column_icon, NULL); + desc->model_column_extra, NULL); + + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(column, renderer, TRUE); + gtk_tree_view_column_set_attributes(column, renderer, "text", + desc->model_column, NULL); + + return column; +} + +static GtkTreeViewColumn + * trg_tree_view_fileicontext_column_new(trg_column_description * desc) +{ + GtkTreeViewColumn *column = gtk_tree_view_column_new(); + GtkCellRenderer *renderer = trg_cell_renderer_file_icon_new(); + + gtk_tree_view_column_set_title(column, desc->header); + gtk_tree_view_column_pack_start(column, renderer, FALSE); + gtk_tree_view_column_set_attributes(column, renderer, + "file-id", + desc->model_column_extra, + "file-name", desc->model_column, NULL); renderer = gtk_cell_renderer_text_new(); gtk_tree_view_column_pack_start(column, renderer, TRUE); @@ -354,8 +376,8 @@ static void trg_tree_view_add_column_after(TrgTreeView * tv, case TRG_COLTYPE_STOCKICONTEXT: column = trg_tree_view_icontext_column_new(desc, "stock-id"); break; - case TRG_COLTYPE_GICONTEXT: - column = trg_tree_view_icontext_column_new(desc, "gicon"); + case TRG_COLTYPE_FILEICONTEXT: + column = trg_tree_view_fileicontext_column_new(desc); break; case TRG_COLTYPE_PRIO: renderer = trg_cell_renderer_priority_new(); diff --git a/src/trg-tree-view.h b/src/trg-tree-view.h index 7332ad6..3460e3c 100644 --- a/src/trg-tree-view.h +++ b/src/trg-tree-view.h @@ -52,7 +52,7 @@ G_END_DECLS GList *trg_tree_view_get_selected_refs_list(GtkTreeView * tv); enum { TRG_COLTYPE_STOCKICONTEXT, - TRG_COLTYPE_GICONTEXT, + TRG_COLTYPE_FILEICONTEXT, TRG_COLTYPE_ICON, TRG_COLTYPE_TEXT, TRG_COLTYPE_SIZE, @@ -68,7 +68,7 @@ enum { typedef struct { gint model_column; - gint model_column_icon; + gint model_column_extra; gchar *header; gchar *id; gint flags; @@ -176,31 +176,11 @@ char *tr_strlsize(char *buf, guint64 size, size_t buflen) { if (!size) g_strlcpy(buf, _("None"), buflen); -#if GLIB_CHECK_VERSION( 2, 16, 0 ) else { char *tmp = g_format_size_for_display(size); g_strlcpy(buf, tmp, buflen); g_free(tmp); } -#else - else if (size < (guint64) KILOBYTE_FACTOR) - g_snprintf(buf, buflen, - ngettext("%'u byte", "%'u bytes", (guint) size), - (guint) size); - else { - gdouble displayed_size; - if (size < (guint64) MEGABYTE_FACTOR) { - displayed_size = (gdouble) size / KILOBYTE_FACTOR; - g_snprintf(buf, buflen, _("%'.1f KB"), displayed_size); - } else if (size < (guint64) GIGABYTE_FACTOR) { - displayed_size = (gdouble) size / MEGABYTE_FACTOR; - g_snprintf(buf, buflen, _("%'.1f MB"), displayed_size); - } else { - displayed_size = (gdouble) size / GIGABYTE_FACTOR; - g_snprintf(buf, buflen, _("%'.1f GB"), displayed_size); - } - } -#endif return buf; } |