From fa53a069d4fdd27e68dcef1a9987369d98eb9b24 Mon Sep 17 00:00:00 2001 From: Shibby Date: Thu, 17 Oct 2013 11:08:32 +0200 Subject: [PATCH] Transmission: update to 2.82 --- release/src/router/transmission/NEWS | 26 + release/src/router/transmission/configure | 24 +- release/src/router/transmission/configure.ac | 4 +- release/src/router/transmission/gtk/favicon.c | 4 +- release/src/router/transmission/gtk/file-list.c | 2064 ++++++++++---------- release/src/router/transmission/gtk/main.c | 5 +- release/src/router/transmission/gtk/open-dialog.c | 1077 +++++----- release/src/router/transmission/gtk/relocate.c | 8 +- release/src/router/transmission/gtk/tr-core.c | 8 +- release/src/router/transmission/gtk/tr-icon.c | 4 +- release/src/router/transmission/gtk/tr-prefs.c | 3 +- release/src/router/transmission/gtk/tr-window.c | 6 +- release/src/router/transmission/gtk/util.c | 20 +- release/src/router/transmission/gtk/util.h | 19 +- .../transmission/libtransmission/announcer-udp.c | 3 +- .../transmission/libtransmission/announcer.c | 13 +- .../router/transmission/libtransmission/bitfield.c | 9 +- .../transmission/libtransmission/clients-test.c | 1 + .../router/transmission/libtransmission/clients.c | 7 +- .../transmission/libtransmission/completion.h | 8 +- .../router/transmission/libtransmission/fdlimit.c | 26 +- .../transmission/libtransmission/handshake.c | 77 +- .../transmission/libtransmission/platform-quota.c | 6 +- .../router/transmission/libtransmission/resume.c | 4 +- .../router/transmission/libtransmission/rpcimpl.c | 8 +- .../router/transmission/libtransmission/session.c | 35 +- .../router/transmission/libtransmission/session.h | 4 +- .../router/transmission/libtransmission/torrent.c | 39 +- .../router/transmission/libtransmission/version.h | 20 +- .../src/router/transmission/libtransmission/web.c | 6 +- .../router/transmission/libtransmission/webseed.c | 4 +- .../src/router/transmission/macosx/Controller.m | 4 +- release/src/router/transmission/qt/README.txt | 4 +- release/src/router/transmission/qt/about.cc | 12 +- release/src/router/transmission/qt/add-data.cc | 4 +- release/src/router/transmission/qt/app.cc | 26 +- release/src/router/transmission/qt/details.cc | 4 +- release/src/router/transmission/qt/favicon.cc | 6 +- release/src/router/transmission/qt/file-tree.cc | 11 +- release/src/router/transmission/qt/filterbar.cc | 8 +- .../src/router/transmission/qt/freespace-label.cc | 2 + .../src/router/transmission/qt/freespace-label.h | 2 +- release/src/router/transmission/qt/mainwin.cc | 6 +- release/src/router/transmission/qt/make-dialog.cc | 11 +- release/src/router/transmission/qt/options.cc | 6 +- release/src/router/transmission/qt/prefs-dialog.cc | 17 +- release/src/router/transmission/qt/qtr.pro | 6 +- release/src/router/transmission/qt/session.cc | 6 +- release/src/router/transmission/qt/squeezelabel.h | 2 +- .../src/router/transmission/qt/torrent-model.cc | 7 +- release/src/router/transmission/qt/utils.h | 12 +- release/src/router/transmission/qt/watchdir.cc | 6 +- release/src/router/transmission/web/index.html | 4 +- 53 files changed, 1915 insertions(+), 1793 deletions(-) rewrite release/src/router/transmission/gtk/file-list.c (73%) rewrite release/src/router/transmission/gtk/open-dialog.c (85%) rewrite release/src/router/transmission/libtransmission/version.h (82%) diff --git a/release/src/router/transmission/NEWS b/release/src/router/transmission/NEWS index def7717908..9a6832f7c7 100644 --- a/release/src/router/transmission/NEWS +++ b/release/src/router/transmission/NEWS @@ -1,3 +1,29 @@ +=== Transmission 2.82 (2013/08/08) === +[http://trac.transmissionbt.com/query?milestone=2.82&group=component&order=severity All tickets closed by this release] +==== All Platforms ==== + * Fix webseed crash + * Fix crash when adding UDP trackers whose host's canonical name couldn't be found + * Fix crash when sending handshakes to some peers immediately after adding a magnet link + * Fix crash when parsing incoming encrypted handshakes when the user is removing the related torrent + * Add safeguard to prevent zombie processes after running a script when a torrent finishes downloading + * Fix "bad file descriptor" error + * Queued torrents no longer show up as paused after exiting & restarting + * Fix 2.81 compilation error on OpenBSD + * Don't misidentify Tixati as BitTornado +==== Mac Client ==== + * Fix bug that had slow download speeds until editing preferences +==== GTK+ Client ==== + * Fix crash that occurred in some cases after using Torrent > Set Location + * Fix crash where on_app_exit() got called twice in a row + * Fix 2.81 compilation error on older versions of glib + * Can now open folders that have a '#' in their names + * Silence gobject warning when updating a blocklist from URL +==== Qt Client ==== + * Qt 5 support +==== Web Client ==== + * Fix syntax error in index.html's meta name="viewport" + * Fix file uploading issue in Internet Explorer 11 + === Transmission 2.81 (2013/07/17) === [http://trac.transmissionbt.com/query?milestone=2.81&group=component&order=severity All tickets closed by this release] ==== All Platforms ==== diff --git a/release/src/router/transmission/configure b/release/src/router/transmission/configure index 01eb60a4c4..88186ed853 100755 --- a/release/src/router/transmission/configure +++ b/release/src/router/transmission/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for transmission 2.81. +# Generated by GNU Autoconf 2.69 for transmission 2.82. # # Report bugs to . # @@ -590,8 +590,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='transmission' PACKAGE_TARNAME='transmission' -PACKAGE_VERSION='2.81' -PACKAGE_STRING='transmission 2.81' +PACKAGE_VERSION='2.82' +PACKAGE_STRING='transmission 2.82' PACKAGE_BUGREPORT='http://trac.transmissionbt.com/newticket' PACKAGE_URL='' @@ -1456,7 +1456,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures transmission 2.81 to adapt to many kinds of systems. +\`configure' configures transmission 2.82 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1526,7 +1526,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of transmission 2.81:";; + short | recursive ) echo "Configuration of transmission 2.82:";; esac cat <<\_ACEOF @@ -1678,7 +1678,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -transmission configure 2.81 +transmission configure 2.82 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2214,7 +2214,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by transmission $as_me 2.81, which was +It was created by transmission $as_me 2.82, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2562,9 +2562,9 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $ ac_compiler_gnu=$ac_cv_c_compiler_gnu -USERAGENT_PREFIX=2.81 +USERAGENT_PREFIX=2.82 -PEERID_PREFIX=-TR2810- +PEERID_PREFIX=-TR2820- # Check whether --enable-silent-rules was given. @@ -3086,7 +3086,7 @@ fi # Define the identity of the package. PACKAGE='transmission' - VERSION='2.81' + VERSION='2.82' cat >>confdefs.h <<_ACEOF @@ -20674,7 +20674,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by transmission $as_me 2.81, which was +This file was extended by transmission $as_me 2.82, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -20731,7 +20731,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -transmission config.status 2.81 +transmission config.status 2.82 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/release/src/router/transmission/configure.ac b/release/src/router/transmission/configure.ac index 8b6b403e41..118a75e6ad 100644 --- a/release/src/router/transmission/configure.ac +++ b/release/src/router/transmission/configure.ac @@ -3,8 +3,8 @@ dnl STATUS: "X" for prerelease beta builds, dnl "Z" for unsupported trunk builds, dnl "0" for stable, supported releases dnl these should be the only two lines you need to change -m4_define([user_agent_prefix],[2.81]) -m4_define([peer_id_prefix],[-TR2810-]) +m4_define([user_agent_prefix],[2.82]) +m4_define([peer_id_prefix],[-TR2820-]) AC_INIT([transmission],[user_agent_prefix],[http://trac.transmissionbt.com/newticket]) AC_SUBST(USERAGENT_PREFIX,[user_agent_prefix]) diff --git a/release/src/router/transmission/gtk/favicon.c b/release/src/router/transmission/gtk/favicon.c index 7cb5d5e741..71522107df 100644 --- a/release/src/router/transmission/gtk/favicon.c +++ b/release/src/router/transmission/gtk/favicon.c @@ -7,7 +7,7 @@ * This exemption does not extend to derived works not owned by * the Transmission project. * - * $Id: favicon.c 14070 2013-04-13 20:25:28Z jordan $ + * $Id: favicon.c 14133 2013-07-20 16:37:59Z jordan $ */ #include /* g_remove () */ @@ -124,7 +124,7 @@ favicon_web_done_idle_cb (gpointer vfav) g_free (fav); } - return FALSE; + return G_SOURCE_REMOVE; } static void diff --git a/release/src/router/transmission/gtk/file-list.c b/release/src/router/transmission/gtk/file-list.c dissimilarity index 73% index e1ca95ec01..512cad0fa4 100644 --- a/release/src/router/transmission/gtk/file-list.c +++ b/release/src/router/transmission/gtk/file-list.c @@ -1,1028 +1,1036 @@ -/* - * This file Copyright (C) Mnemosyne LLC - * - * This file is licensed by the GPL version 2. Works owned by the - * Transmission project are granted a special exemption to clause 2 (b) - * so that the bulk of its code can remain under the MIT license. - * This exemption does not extend to derived works not owned by - * the Transmission project. - * - * $Id: file-list.c 14018 2013-02-14 15:17:42Z jordan $ - */ - -#include -#include -#include -#include -#include - -#include -#include - -#include "file-list.h" -#include "hig.h" -#include "icons.h" -#include "tr-prefs.h" -#include "util.h" - -#define TR_DOWNLOAD_KEY "tr-download-key" -#define TR_COLUMN_ID_KEY "tr-model-column-id-key" -#define TR_PRIORITY_KEY "tr-priority-key" - -enum -{ - /* these two fields could be any number at all so long as they're not - * TR_PRI_LOW, TR_PRI_NORMAL, TR_PRI_HIGH, TRUE, or FALSE */ - NOT_SET = 1000, - MIXED = 1001 -}; - -enum -{ - FC_ICON, - FC_LABEL, - FC_LABEL_ESC, - FC_PROG, - FC_INDEX, - FC_SIZE, - FC_SIZE_STR, - FC_HAVE, - FC_PRIORITY, - FC_ENABLED, - N_FILE_COLS -}; - -typedef struct -{ - TrCore * core; - GtkWidget * top; - GtkWidget * view; - GtkTreeModel * model; /* same object as store, but recast */ - GtkTreeStore * store; /* same object as model, but recast */ - int torrentId; - guint timeout_tag; -} -FileData; - -static void -clearData (FileData * data) -{ - data->torrentId = -1; - - if (data->timeout_tag) { - g_source_remove (data->timeout_tag); - data->timeout_tag = 0; - } -} - -static void -freeData (gpointer data) -{ - clearData (data); - g_free (data); -} - -/*** -**** -***/ - -struct RefreshData -{ - int sort_column_id; - gboolean resort_needed; - - tr_file_stat * refresh_file_stat; - tr_torrent * tor; - - FileData * file_data; -}; - -static gboolean -refreshFilesForeach (GtkTreeModel * model, - GtkTreePath * path UNUSED, - GtkTreeIter * iter, - gpointer gdata) -{ - struct RefreshData * refresh_data = gdata; - FileData * data = refresh_data->file_data; - unsigned int index; - uint64_t size; - uint64_t old_have; - int old_prog; - int old_priority; - int old_enabled; - const gboolean is_file = !gtk_tree_model_iter_has_child (model, iter); - - gtk_tree_model_get (model, iter, FC_ENABLED, &old_enabled, - FC_PRIORITY, &old_priority, - FC_INDEX, &index, - FC_HAVE, &old_have, - FC_SIZE, &size, - FC_PROG, &old_prog, - -1); - - if (is_file) - { - tr_torrent * tor = refresh_data->tor; - const tr_info * inf = tr_torrentInfo (tor); - const int enabled = !inf->files[index].dnd; - const int priority = inf->files[index].priority; - const uint64_t have = refresh_data->refresh_file_stat[index].bytesCompleted; - const int prog = size ? (int)((100.0*have)/size) : 1; - - if ((priority!=old_priority) || (enabled!=old_enabled) || (have!=old_have) || (prog!=old_prog)) - { - /* Changing a value in the sort column can trigger a resort - * which breaks this foreach () call. (See #3529) - * As a workaround: if that's about to happen, temporarily disable - * sorting until we finish walking the tree. */ - if (!refresh_data->resort_needed) - { - if ((refresh_data->resort_needed = - ((refresh_data->sort_column_id==FC_PRIORITY) && (priority!=old_priority)) || - ((refresh_data->sort_column_id==FC_ENABLED) && (enabled!=old_enabled)))) - { - refresh_data->resort_needed = TRUE; - gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (data->model), - GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, - GTK_SORT_ASCENDING); - } - } - - gtk_tree_store_set (data->store, iter, FC_PRIORITY, priority, - FC_ENABLED, enabled, - FC_HAVE, have, - FC_PROG, prog, - -1); - } - } - else - { - GtkTreeIter child; - uint64_t sub_size = 0; - uint64_t have = 0; - int prog; - int enabled = NOT_SET; - int priority = NOT_SET; - - /* since gtk_tree_model_foreach () is depth-first, we can - * get the `sub' info by walking the immediate children */ - - if (gtk_tree_model_iter_children (model, &child, iter)) do - { - int child_enabled; - int child_priority; - int64_t child_have, child_size; - - gtk_tree_model_get (model, &child, FC_SIZE, &child_size, - FC_HAVE, &child_have, - FC_PRIORITY, &child_priority, - FC_ENABLED, &child_enabled, - -1); - - if ((child_enabled != FALSE) && (child_enabled != NOT_SET)) - { - sub_size += child_size; - have += child_have; - } - - if (enabled == NOT_SET) - enabled = child_enabled; - else if (enabled != child_enabled) - enabled = MIXED; - - if (priority == NOT_SET) - priority = child_priority; - else if (priority != child_priority) - priority = MIXED; - } - while (gtk_tree_model_iter_next (model, &child)); - - prog = sub_size ? (int)((100.0*have)/sub_size) : 1; - - if ((size!=sub_size) || (have!=old_have) - || (priority!=old_priority) - || (enabled!=old_enabled) - || (prog!=old_prog)) - { - char size_str[64]; - tr_strlsize (size_str, sub_size, sizeof size_str); - gtk_tree_store_set (data->store, iter, FC_SIZE, sub_size, - FC_SIZE_STR, size_str, - FC_HAVE, have, - FC_PRIORITY, priority, - FC_ENABLED, enabled, - FC_PROG, prog, - -1); - } - } - - return FALSE; /* keep walking */ -} - -static void -gtr_tree_model_foreach_postorder_subtree (GtkTreeModel * model, - GtkTreeIter * parent, - GtkTreeModelForeachFunc func, - gpointer data) -{ - GtkTreeIter child; - if (gtk_tree_model_iter_children (model, &child, parent)) do - gtr_tree_model_foreach_postorder_subtree (model, &child, func, data); - while (gtk_tree_model_iter_next (model, &child)); - if (parent) - func (model, NULL, parent, data); -} - -static void -gtr_tree_model_foreach_postorder (GtkTreeModel * model, - GtkTreeModelForeachFunc func, - gpointer data) -{ - GtkTreeIter iter; - if (gtk_tree_model_iter_nth_child (model, &iter, NULL, 0)) do - gtr_tree_model_foreach_postorder_subtree (model, &iter, func, data); - while (gtk_tree_model_iter_next (model, &iter)); -} - -static void -refresh (FileData * data) -{ - tr_torrent * tor = gtr_core_find_torrent (data->core, data->torrentId); - - if (tor == NULL) - { - gtr_file_list_clear (data->top); - } - else - { - GtkSortType order; - int sort_column_id; - tr_file_index_t fileCount; - struct RefreshData refresh_data; - GtkTreeSortable * sortable = GTK_TREE_SORTABLE (data->model); - gtk_tree_sortable_get_sort_column_id (sortable, &sort_column_id, &order); - - refresh_data.sort_column_id = sort_column_id; - refresh_data.resort_needed = FALSE; - refresh_data.refresh_file_stat = tr_torrentFiles (tor, &fileCount); - refresh_data.tor = tor; - refresh_data.file_data = data; - - gtr_tree_model_foreach_postorder (data->model, refreshFilesForeach, &refresh_data); - - if (refresh_data.resort_needed) - gtk_tree_sortable_set_sort_column_id (sortable, sort_column_id, order); - - tr_torrentFilesFree (refresh_data.refresh_file_stat, fileCount); - } -} - -static gboolean -refreshModel (gpointer file_data) -{ - refresh (file_data); - - return G_SOURCE_CONTINUE; -} - -/*** -**** -***/ - -struct ActiveData -{ - GtkTreeSelection * sel; - GArray * array; -}; - -static gboolean -getSelectedFilesForeach (GtkTreeModel * model, - GtkTreePath * path UNUSED, - GtkTreeIter * iter, - gpointer gdata) -{ - const gboolean is_file = !gtk_tree_model_iter_has_child (model, iter); - - if (is_file) - { - struct ActiveData * data = gdata; - - /* active means: if it's selected or any ancestor is selected */ - - gboolean is_active = gtk_tree_selection_iter_is_selected (data->sel, iter); - - if (!is_active) - { - GtkTreeIter walk = *iter; - GtkTreeIter parent; - while (!is_active && gtk_tree_model_iter_parent (model, &parent, &walk)) - { - is_active = gtk_tree_selection_iter_is_selected (data->sel, &parent); - walk = parent; - } - } - - if (is_active) - { - unsigned int i; - gtk_tree_model_get (model, iter, FC_INDEX, &i, -1); - g_array_append_val (data->array, i); - } - } - - return FALSE; /* keep walking */ -} - -static GArray* -getSelectedFilesAndDescendants (GtkTreeView * view) -{ - struct ActiveData data; - - data.sel = gtk_tree_view_get_selection (view); - data.array = g_array_new (FALSE, FALSE, sizeof (tr_file_index_t)); - gtk_tree_model_foreach (gtk_tree_view_get_model (view), - getSelectedFilesForeach, &data); - return data.array; -} - -struct SubtreeForeachData -{ - GArray * array; - GtkTreePath * path; -}; - -static gboolean -getSubtreeForeach (GtkTreeModel * model, - GtkTreePath * path, - GtkTreeIter * iter, - gpointer gdata) -{ - const gboolean is_file = !gtk_tree_model_iter_has_child (model, iter); - - if (is_file) - { - struct SubtreeForeachData * data = gdata; - - if (!gtk_tree_path_compare (path, data->path) || gtk_tree_path_is_descendant (path, data->path)) - { - unsigned int i; - gtk_tree_model_get (model, iter, FC_INDEX, &i, -1); - g_array_append_val (data->array, i); - } - } - - return FALSE; /* keep walking */ -} - -static void -getSubtree (GtkTreeView * view, GtkTreePath * path, GArray * indices) -{ - struct SubtreeForeachData tmp; - tmp.array = indices; - tmp.path = path; - gtk_tree_model_foreach (gtk_tree_view_get_model (view), getSubtreeForeach, &tmp); -} - -/* if `path' is a selected row, all selected rows are returned. - * otherwise, only the row indicated by `path' is returned. - * this is for toggling all the selected rows' states in a batch. - */ -static GArray* -getActiveFilesForPath (GtkTreeView * view, GtkTreePath * path) -{ - GArray * indices; - GtkTreeSelection * sel = gtk_tree_view_get_selection (view); - - if (gtk_tree_selection_path_is_selected (sel, path)) - { - /* clicked in a selected row... use the current selection */ - indices = getSelectedFilesAndDescendants (view); - } - else - { - /* clicked OUTSIDE of the selected row... just use the clicked row */ - indices = g_array_new (FALSE, FALSE, sizeof (tr_file_index_t)); - getSubtree (view, path, indices); - } - - return indices; -} - -/*** -**** -***/ - -void -gtr_file_list_clear (GtkWidget * w) -{ - gtr_file_list_set_torrent (w, -1); -} - -struct build_data -{ - GtkWidget * w; - tr_torrent * tor; - GtkTreeIter * iter; - GtkTreeStore * store; -}; - -struct row_struct -{ - uint64_t length; - char * name; - int index; -}; - -static void -buildTree (GNode * node, gpointer gdata) -{ - char size_str[64]; - GtkTreeIter child_iter; - struct build_data * build = gdata; - struct row_struct *child_data = node->data; - const gboolean isLeaf = node->children == NULL; - - const char * mime_type = isLeaf ? gtr_get_mime_type_from_filename (child_data->name) : DIRECTORY_MIME_TYPE; - GdkPixbuf * icon = gtr_get_mime_type_icon (mime_type, GTK_ICON_SIZE_MENU, build->w); - const tr_info * inf = tr_torrentInfo (build->tor); - const int priority = isLeaf ? inf->files[ child_data->index ].priority : 0; - const gboolean enabled = isLeaf ? !inf->files[ child_data->index ].dnd : TRUE; - char * name_esc = g_markup_escape_text (child_data->name, -1); - - tr_strlsize (size_str, child_data->length, sizeof size_str); - - gtk_tree_store_insert_with_values (build->store, &child_iter, build->iter, INT_MAX, - FC_INDEX, child_data->index, - FC_LABEL, child_data->name, - FC_LABEL_ESC, name_esc, - FC_SIZE, child_data->length, - FC_SIZE_STR, size_str, - FC_ICON, icon, - FC_PRIORITY, priority, - FC_ENABLED, enabled, - -1); - - if (!isLeaf) - { - struct build_data b = *build; - b.iter = &child_iter; - g_node_children_foreach (node, G_TRAVERSE_ALL, buildTree, &b); - } - - g_free (name_esc); - g_object_unref (icon); - - /* we're done with this node */ - g_free (child_data->name); - g_free (child_data); -} - -static GNode* -find_child (GNode* parent, const char * name) -{ - GNode * child = parent->children; - while (child) { - const struct row_struct * child_data = child->data; - if ((*child_data->name == *name) && !g_strcmp0 (child_data->name, name)) - break; - child = child->next; - } - return child; -} - -void -gtr_file_list_set_torrent (GtkWidget * w, int torrentId) -{ - GtkTreeStore * store; - FileData * data = g_object_get_data (G_OBJECT (w), "file-data"); - - /* unset the old fields */ - clearData (data); - - /* instantiate the model */ - store = gtk_tree_store_new (N_FILE_COLS, - GDK_TYPE_PIXBUF, /* icon */ - G_TYPE_STRING, /* label */ - G_TYPE_STRING, /* label esc */ - G_TYPE_INT, /* prog [0..100] */ - G_TYPE_UINT, /* index */ - G_TYPE_UINT64, /* size */ - G_TYPE_STRING, /* size str */ - G_TYPE_UINT64, /* have */ - G_TYPE_INT, /* priority */ - G_TYPE_INT); /* dl enabled */ - - data->store = store; - data->model = GTK_TREE_MODEL (store); - data->torrentId = torrentId; - - /* populate the model */ - if (torrentId > 0) - { - tr_torrent * tor = gtr_core_find_torrent (data->core, torrentId); - if (tor != NULL) - { - tr_file_index_t i; - const tr_info * inf = tr_torrentInfo (tor); - struct row_struct * root_data; - GNode * root; - struct build_data build; - - /* build a GNode tree of the files */ - root_data = g_new0 (struct row_struct, 1); - root_data->name = g_strdup (tr_torrentName (tor)); - root_data->index = -1; - root_data->length = 0; - root = g_node_new (root_data); - for (i=0; ifileCount; ++i) { - int j; - GNode * parent = root; - const tr_file * file = &inf->files[i]; - char ** tokens = g_strsplit (file->name, G_DIR_SEPARATOR_S, 0); - for (j=0; tokens[j]; ++j) { - const gboolean isLeaf = tokens[j+1] == NULL; - const char * name = tokens[j]; - GNode * node = find_child (parent, name); - if (node == NULL) { - struct row_struct * row = g_new (struct row_struct, 1); - row->name = g_strdup (name); - row->index = isLeaf ? (int)i : -1; - row->length = isLeaf ? file->length : 0; - node = g_node_new (row); - g_node_append (parent, node); - } - parent = node; - } - g_strfreev (tokens); - } - - /* now, add them to the model */ - build.w = w; - build.tor = tor; - build.store = data->store; - build.iter = NULL; - g_node_children_foreach (root, G_TRAVERSE_ALL, buildTree, &build); - - /* cleanup */ - g_node_destroy (root); - g_free (root_data->name); - g_free (root_data); - } - - refresh (data); - data->timeout_tag = gdk_threads_add_timeout_seconds (SECONDARY_WINDOW_REFRESH_INTERVAL_SECONDS, refreshModel, data); - } - - gtk_tree_view_set_model (GTK_TREE_VIEW (data->view), data->model); - gtk_tree_view_expand_all (GTK_TREE_VIEW (data->view)); - g_object_unref (data->model); -} - -/*** -**** -***/ - -static void -renderDownload (GtkTreeViewColumn * column UNUSED, - GtkCellRenderer * renderer, - GtkTreeModel * model, - GtkTreeIter * iter, - gpointer data UNUSED) -{ - gboolean enabled; - gtk_tree_model_get (model, iter, FC_ENABLED, &enabled, -1); - g_object_set (renderer, "inconsistent", (enabled==MIXED), - "active", (enabled==TRUE), - NULL); -} - -static void -renderPriority (GtkTreeViewColumn * column UNUSED, - GtkCellRenderer * renderer, - GtkTreeModel * model, - GtkTreeIter * iter, - gpointer data UNUSED) -{ - int priority; - const char * text; - gtk_tree_model_get (model, iter, FC_PRIORITY, &priority, -1); - switch (priority) { - case TR_PRI_HIGH: text = _("High"); break; - case TR_PRI_NORMAL: text = _("Normal"); break; - case TR_PRI_LOW: text = _("Low"); break; - default: text = _("Mixed"); break; - } - g_object_set (renderer, "text", text, NULL); -} - -/* build a filename from tr_torrentGetCurrentDir () + the model's FC_LABELs */ -static char* -buildFilename (tr_torrent * tor, GtkTreeModel * model, - GtkTreePath * path, GtkTreeIter * iter) -{ - char * ret; - GtkTreeIter child; - GtkTreeIter parent = *iter; - int n = gtk_tree_path_get_depth (path); - char ** tokens = g_new0 (char*, n + 2); - tokens[0] = g_strdup (tr_torrentGetCurrentDir (tor)); - do { - child = parent; - gtk_tree_model_get (model, &child, FC_LABEL, &tokens[n--], -1); - } while (gtk_tree_model_iter_parent (model, &parent, &child)); - ret = g_build_filenamev (tokens); - g_strfreev (tokens); - return ret; -} - -static gboolean -onRowActivated (GtkTreeView * view, GtkTreePath * path, - GtkTreeViewColumn * col UNUSED, gpointer gdata) -{ - gboolean handled = FALSE; - FileData * data = gdata; - tr_torrent * tor = gtr_core_find_torrent (data->core, data->torrentId); - - if (tor != NULL) - { - GtkTreeIter iter; - GtkTreeModel * model = gtk_tree_view_get_model (view); - - if (gtk_tree_model_get_iter (model, &iter, path)) - { - int prog; - char * filename = buildFilename (tor, model, path, &iter); - gtk_tree_model_get (model, &iter, FC_PROG, &prog, -1); - - /* if the file's not done, walk up the directory tree until we find - * an ancestor that exists, and open that instead */ - if (filename && (prog<100 || !g_file_test (filename, G_FILE_TEST_EXISTS))) do - { - char * tmp = g_path_get_dirname (filename); - g_free (filename); - filename = tmp; - } - while (filename && *filename && !g_file_test (filename, G_FILE_TEST_EXISTS)); - - if ((handled = filename && *filename)) - gtr_open_file (filename); - } - } - - return handled; -} - -static gboolean -onViewPathToggled (GtkTreeView * view, - GtkTreeViewColumn * col, - GtkTreePath * path, - FileData * data) -{ - int cid; - tr_torrent * tor; - gboolean handled = FALSE; - - if (!col || !path) - return FALSE; - - cid = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (col), TR_COLUMN_ID_KEY)); - tor = gtr_core_find_torrent (data->core, data->torrentId); - if ((tor != NULL) && ((cid == FC_PRIORITY) || (cid == FC_ENABLED))) - { - GtkTreeIter iter; - GArray * indices = getActiveFilesForPath (view, path); - GtkTreeModel * model = data->model; - - gtk_tree_model_get_iter (model, &iter, path); - - if (cid == FC_PRIORITY) - { - int priority; - gtk_tree_model_get (model, &iter, FC_PRIORITY, &priority, -1); - switch (priority) { - case TR_PRI_NORMAL: priority = TR_PRI_HIGH; break; - case TR_PRI_HIGH: priority = TR_PRI_LOW; break; - default: priority = TR_PRI_NORMAL; break; - } - tr_torrentSetFilePriorities (tor, - (tr_file_index_t *) indices->data, - (tr_file_index_t) indices->len, - priority); - } - else - { - int enabled; - gtk_tree_model_get (model, &iter, FC_ENABLED, &enabled, -1); - enabled = !enabled; - - tr_torrentSetFileDLs (tor, - (tr_file_index_t *) indices->data, - (tr_file_index_t) indices->len, - enabled); - } - - refresh (data); - g_array_free (indices, TRUE); - handled = TRUE; - } - - return handled; -} - -/** - * @note 'col' and 'path' are assumed not to be NULL. - */ -static gboolean -getAndSelectEventPath (GtkTreeView * treeview, - GdkEventButton * event, - GtkTreeViewColumn ** col, - GtkTreePath ** path) -{ - GtkTreeSelection * sel; - - if (gtk_tree_view_get_path_at_pos (treeview, - event->x, event->y, - path, col, NULL, NULL)) - { - sel = gtk_tree_view_get_selection (treeview); - if (!gtk_tree_selection_path_is_selected (sel, *path)) - { - gtk_tree_selection_unselect_all (sel); - gtk_tree_selection_select_path (sel, *path); - } - return TRUE; - } - - return FALSE; -} - -static gboolean -onViewButtonPressed (GtkWidget * w, GdkEventButton * event, gpointer gdata) -{ - GtkTreeViewColumn * col; - GtkTreePath * path = NULL; - gboolean handled = FALSE; - GtkTreeView * treeview = GTK_TREE_VIEW (w); - FileData * data = gdata; - - if ((event->type == GDK_BUTTON_PRESS) - && (event->button == 1) - && ! (event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) - && getAndSelectEventPath (treeview, event, &col, &path)) - { - handled = onViewPathToggled (treeview, col, path, data); - - if (path != NULL) - gtk_tree_path_free (path); - } - - return handled; -} - -struct rename_data -{ - int error; - char * newname; - char * path_string; - FileData * file_data; -}; - -static int -on_rename_done_idle (struct rename_data * data) -{ - if (data->error == 0) - { - GtkTreeIter iter; - - if (gtk_tree_model_get_iter_from_string (data->file_data->model, &iter, data->path_string)) - gtk_tree_store_set (data->file_data->store, &iter, FC_LABEL, data->newname, -1); - } - else - { - GtkWidget * w = gtk_message_dialog_new ( - GTK_WINDOW (gtk_widget_get_toplevel(data->file_data->top)), - GTK_DIALOG_MODAL, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_CLOSE, - _("Unable to rename file as \"%s\": %s"), - data->newname, - tr_strerror(data->error)); - gtk_message_dialog_format_secondary_text ( - GTK_MESSAGE_DIALOG (w), "%s", - _("Please correct the errors and try again.")); - gtk_dialog_run (GTK_DIALOG (w)); - gtk_widget_destroy (w); - } - - /* cleanup */ - g_free (data->path_string); - g_free (data->newname); - g_free (data); - return G_SOURCE_REMOVE; -} - -static void -on_rename_done (tr_torrent * tor G_GNUC_UNUSED, - const char * oldpath G_GNUC_UNUSED, - const char * newname G_GNUC_UNUSED, - int error, - struct rename_data * rename_data) -{ - rename_data->error = error; - gdk_threads_add_idle ((GSourceFunc)on_rename_done_idle, rename_data); -} - -static void -cell_edited_callback (GtkCellRendererText * cell G_GNUC_UNUSED, - gchar * path_string, - gchar * newname, - FileData * data) -{ - tr_torrent * tor; - GString * oldpath; - GtkTreeIter iter; - struct rename_data * rename_data; - - tor = gtr_core_find_torrent (data->core, data->torrentId); - if (tor == NULL) - return; - if (!gtk_tree_model_get_iter_from_string (data->model, &iter, path_string)) - return; - - /* build oldpath */ - oldpath = g_string_new (NULL); - for (;;) - { - char * token = NULL; - GtkTreeIter child; - gtk_tree_model_get (data->model, &iter, FC_LABEL, &token, -1); - g_string_prepend (oldpath, token); - g_free (token); - - child = iter; - if (!gtk_tree_model_iter_parent (data->model, &iter, &child)) - break; - - g_string_prepend_c (oldpath, G_DIR_SEPARATOR); - } - - /* do the renaming */ - rename_data = g_new0 (struct rename_data, 1); - rename_data->newname = g_strdup (newname); - rename_data->file_data = data; - rename_data->path_string = g_strdup (path_string); - tr_torrentRenamePath (tor, oldpath->str, newname, (tr_torrent_rename_done_func*)on_rename_done, rename_data); - - /* cleanup */ - g_string_free (oldpath, TRUE); -} - - -GtkWidget * -gtr_file_list_new (TrCore * core, int torrentId) -{ - int size; - int width; - GtkWidget * ret; - GtkWidget * view; - GtkWidget * scroll; - GtkCellRenderer * rend; - GtkTreeSelection * sel; - GtkTreeViewColumn * col; - GtkTreeView * tree_view; - const char * title; - PangoLayout * pango_layout; - PangoContext * pango_context; - PangoFontDescription * pango_font_description; - FileData * data = g_new0 (FileData, 1); - - data->core = core; - - /* create the view */ - view = gtk_tree_view_new (); - tree_view = GTK_TREE_VIEW (view); - gtk_tree_view_set_rules_hint (tree_view, TRUE); - gtk_container_set_border_width (GTK_CONTAINER (view), GUI_PAD_BIG); - g_signal_connect (view, "button-press-event", - G_CALLBACK (onViewButtonPressed), data); - g_signal_connect (view, "row_activated", - G_CALLBACK (onRowActivated), data); - g_signal_connect (view, "button-release-event", - G_CALLBACK (on_tree_view_button_released), NULL); - - - pango_context = gtk_widget_create_pango_context (view); - pango_font_description = pango_font_description_copy (pango_context_get_font_description (pango_context)); - size = pango_font_description_get_size (pango_font_description); - pango_font_description_set_size (pango_font_description, size * 0.8); - g_object_unref (G_OBJECT (pango_context)); - - /* set up view */ - sel = gtk_tree_view_get_selection (tree_view); - gtk_tree_selection_set_mode (sel, GTK_SELECTION_MULTIPLE); - gtk_tree_view_expand_all (tree_view); - gtk_tree_view_set_search_column (tree_view, FC_LABEL); - - /* add file column */ - col = GTK_TREE_VIEW_COLUMN (g_object_new (GTK_TYPE_TREE_VIEW_COLUMN, - "expand", TRUE, - "title", _("Name"), - NULL)); - gtk_tree_view_column_set_resizable (col, TRUE); - rend = gtk_cell_renderer_pixbuf_new (); - gtk_tree_view_column_pack_start (col, rend, FALSE); - gtk_tree_view_column_add_attribute (col, rend, "pixbuf", FC_ICON); - /* add text renderer */ - rend = gtk_cell_renderer_text_new (); - g_object_set (rend, "editable", TRUE, NULL); - g_object_set (rend, "ellipsize", PANGO_ELLIPSIZE_END, "font-desc", pango_font_description, NULL); - g_signal_connect (rend, "edited", (GCallback)cell_edited_callback, data); - gtk_tree_view_column_pack_start (col, rend, TRUE); - gtk_tree_view_column_set_attributes (col, rend, "text", FC_LABEL, NULL); - gtk_tree_view_column_set_sort_column_id (col, FC_LABEL); - gtk_tree_view_append_column (tree_view, col); - - /* add "size" column */ - title = _("Size"); - rend = gtk_cell_renderer_text_new (); - g_object_set (rend, "alignment", PANGO_ALIGN_RIGHT, - "font-desc", pango_font_description, - "xpad", GUI_PAD, - "xalign", 1.0f, - "yalign", 0.5f, - NULL); - col = gtk_tree_view_column_new_with_attributes (title, rend, NULL); - gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_GROW_ONLY); - gtk_tree_view_column_set_sort_column_id (col, FC_SIZE); - gtk_tree_view_column_set_attributes (col, rend, "text", FC_SIZE_STR, NULL); - gtk_tree_view_append_column (tree_view, col); - - /* add "progress" column */ - title = _("Have"); - pango_layout = gtk_widget_create_pango_layout (view, title); - pango_layout_get_pixel_size (pango_layout, &width, NULL); - width += 30; /* room for the sort indicator */ - g_object_unref (G_OBJECT (pango_layout)); - rend = gtk_cell_renderer_progress_new (); - col = gtk_tree_view_column_new_with_attributes (title, rend, "value", FC_PROG, NULL); - gtk_tree_view_column_set_fixed_width (col, width); - gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_FIXED); - gtk_tree_view_column_set_sort_column_id (col, FC_PROG); - gtk_tree_view_append_column (tree_view, col); - - /* add "enabled" column */ - title = _("Download"); - pango_layout = gtk_widget_create_pango_layout (view, title); - pango_layout_get_pixel_size (pango_layout, &width, NULL); - width += 30; /* room for the sort indicator */ - g_object_unref (G_OBJECT (pango_layout)); - rend = gtk_cell_renderer_toggle_new (); - col = gtk_tree_view_column_new_with_attributes (title, rend, NULL); - g_object_set_data (G_OBJECT (col), TR_COLUMN_ID_KEY, - GINT_TO_POINTER (FC_ENABLED)); - gtk_tree_view_column_set_fixed_width (col, width); - gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_FIXED); - gtk_tree_view_column_set_cell_data_func (col, rend, renderDownload, NULL, NULL); - gtk_tree_view_column_set_sort_column_id (col, FC_ENABLED); - gtk_tree_view_append_column (tree_view, col); - - /* add priority column */ - title = _("Priority"); - pango_layout = gtk_widget_create_pango_layout (view, title); - pango_layout_get_pixel_size (pango_layout, &width, NULL); - width += 30; /* room for the sort indicator */ - g_object_unref (G_OBJECT (pango_layout)); - rend = gtk_cell_renderer_text_new (); - g_object_set (rend, "xalign", (gfloat)0.5, "yalign", (gfloat)0.5, NULL); - col = gtk_tree_view_column_new_with_attributes (title, rend, NULL); - g_object_set_data (G_OBJECT (col), TR_COLUMN_ID_KEY, - GINT_TO_POINTER (FC_PRIORITY)); - gtk_tree_view_column_set_fixed_width (col, width); - gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_FIXED); - gtk_tree_view_column_set_sort_column_id (col, FC_PRIORITY); - gtk_tree_view_column_set_cell_data_func (col, rend, renderPriority, NULL, NULL); - gtk_tree_view_append_column (tree_view, col); - - /* add tooltip to tree */ - gtk_tree_view_set_tooltip_column (tree_view, FC_LABEL_ESC); - - /* create the scrolled window and stick the view in it */ - scroll = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), - GTK_SHADOW_IN); - gtk_container_add (GTK_CONTAINER (scroll), view); - gtk_widget_set_size_request (scroll, -1, 200); - - ret = scroll; - data->view = view; - data->top = scroll; - g_object_set_data_full (G_OBJECT (ret), "file-data", data, freeData); - gtr_file_list_set_torrent (ret, torrentId); - - pango_font_description_free (pango_font_description); - return ret; -} +/* + * This file Copyright (C) Mnemosyne LLC + * + * This file is licensed by the GPL version 2. Works owned by the + * Transmission project are granted a special exemption to clause 2 (b) + * so that the bulk of its code can remain under the MIT license. + * This exemption does not extend to derived works not owned by + * the Transmission project. + * + * $Id: file-list.c 14132 2013-07-20 16:19:15Z jordan $ + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "file-list.h" +#include "hig.h" +#include "icons.h" +#include "tr-prefs.h" +#include "util.h" + +#define TR_DOWNLOAD_KEY "tr-download-key" +#define TR_COLUMN_ID_KEY "tr-model-column-id-key" +#define TR_PRIORITY_KEY "tr-priority-key" + +enum +{ + /* these two fields could be any number at all so long as they're not + * TR_PRI_LOW, TR_PRI_NORMAL, TR_PRI_HIGH, TRUE, or FALSE */ + NOT_SET = 1000, + MIXED = 1001 +}; + +enum +{ + FC_ICON, + FC_LABEL, + FC_LABEL_ESC, + FC_PROG, + FC_INDEX, + FC_SIZE, + FC_SIZE_STR, + FC_HAVE, + FC_PRIORITY, + FC_ENABLED, + N_FILE_COLS +}; + +typedef struct +{ + TrCore * core; + GtkWidget * top; + GtkWidget * view; + GtkTreeModel * model; /* same object as store, but recast */ + GtkTreeStore * store; /* same object as model, but recast */ + int torrentId; + guint timeout_tag; +} +FileData; + +static void +clearData (FileData * data) +{ + data->torrentId = -1; + + if (data->timeout_tag) + { + g_source_remove (data->timeout_tag); + data->timeout_tag = 0; + } +} + +static void +freeData (gpointer data) +{ + clearData (data); + g_free (data); +} + +/*** +**** +***/ + +struct RefreshData +{ + int sort_column_id; + gboolean resort_needed; + + tr_file_stat * refresh_file_stat; + tr_torrent * tor; + + FileData * file_data; +}; + +static gboolean +refreshFilesForeach (GtkTreeModel * model, + GtkTreePath * path UNUSED, + GtkTreeIter * iter, + gpointer gdata) +{ + struct RefreshData * refresh_data = gdata; + FileData * data = refresh_data->file_data; + unsigned int index; + uint64_t size; + uint64_t old_have; + int old_prog; + int old_priority; + int old_enabled; + const gboolean is_file = !gtk_tree_model_iter_has_child (model, iter); + + gtk_tree_model_get (model, iter, FC_ENABLED, &old_enabled, + FC_PRIORITY, &old_priority, + FC_INDEX, &index, + FC_HAVE, &old_have, + FC_SIZE, &size, + FC_PROG, &old_prog, + -1); + + if (is_file) + { + tr_torrent * tor = refresh_data->tor; + const tr_info * inf = tr_torrentInfo (tor); + const int enabled = !inf->files[index].dnd; + const int priority = inf->files[index].priority; + const uint64_t have = refresh_data->refresh_file_stat[index].bytesCompleted; + const int prog = size ? (int)((100.0*have)/size) : 1; + + if ((priority!=old_priority) || (enabled!=old_enabled) || (have!=old_have) || (prog!=old_prog)) + { + /* Changing a value in the sort column can trigger a resort + * which breaks this foreach () call. (See #3529) + * As a workaround: if that's about to happen, temporarily disable + * sorting until we finish walking the tree. */ + if (!refresh_data->resort_needed) + { + if ((refresh_data->resort_needed = + ((refresh_data->sort_column_id==FC_PRIORITY) && (priority!=old_priority)) || + ((refresh_data->sort_column_id==FC_ENABLED) && (enabled!=old_enabled)))) + { + refresh_data->resort_needed = TRUE; + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (data->model), + GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, + GTK_SORT_ASCENDING); + } + } + + gtk_tree_store_set (data->store, iter, FC_PRIORITY, priority, + FC_ENABLED, enabled, + FC_HAVE, have, + FC_PROG, prog, + -1); + } + } + else + { + GtkTreeIter child; + uint64_t sub_size = 0; + uint64_t have = 0; + int prog; + int enabled = NOT_SET; + int priority = NOT_SET; + + /* since gtk_tree_model_foreach () is depth-first, we can + * get the `sub' info by walking the immediate children */ + + if (gtk_tree_model_iter_children (model, &child, iter)) do + { + int child_enabled; + int child_priority; + int64_t child_have, child_size; + + gtk_tree_model_get (model, &child, FC_SIZE, &child_size, + FC_HAVE, &child_have, + FC_PRIORITY, &child_priority, + FC_ENABLED, &child_enabled, + -1); + + if ((child_enabled != FALSE) && (child_enabled != NOT_SET)) + { + sub_size += child_size; + have += child_have; + } + + if (enabled == NOT_SET) + enabled = child_enabled; + else if (enabled != child_enabled) + enabled = MIXED; + + if (priority == NOT_SET) + priority = child_priority; + else if (priority != child_priority) + priority = MIXED; + } + while (gtk_tree_model_iter_next (model, &child)); + + prog = sub_size ? (int)((100.0*have)/sub_size) : 1; + + if ((size!=sub_size) || (have!=old_have) + || (priority!=old_priority) + || (enabled!=old_enabled) + || (prog!=old_prog)) + { + char size_str[64]; + tr_strlsize (size_str, sub_size, sizeof size_str); + gtk_tree_store_set (data->store, iter, FC_SIZE, sub_size, + FC_SIZE_STR, size_str, + FC_HAVE, have, + FC_PRIORITY, priority, + FC_ENABLED, enabled, + FC_PROG, prog, + -1); + } + } + + return FALSE; /* keep walking */ +} + +static void +gtr_tree_model_foreach_postorder_subtree (GtkTreeModel * model, + GtkTreeIter * parent, + GtkTreeModelForeachFunc func, + gpointer data) +{ + GtkTreeIter child; + if (gtk_tree_model_iter_children (model, &child, parent)) do + gtr_tree_model_foreach_postorder_subtree (model, &child, func, data); + while (gtk_tree_model_iter_next (model, &child)); + if (parent) + func (model, NULL, parent, data); +} + +static void +gtr_tree_model_foreach_postorder (GtkTreeModel * model, + GtkTreeModelForeachFunc func, + gpointer data) +{ + GtkTreeIter iter; + if (gtk_tree_model_iter_nth_child (model, &iter, NULL, 0)) do + gtr_tree_model_foreach_postorder_subtree (model, &iter, func, data); + while (gtk_tree_model_iter_next (model, &iter)); +} + +static void +refresh (FileData * data) +{ + tr_torrent * tor = gtr_core_find_torrent (data->core, data->torrentId); + + if (tor == NULL) + { + gtr_file_list_clear (data->top); + } + else + { + GtkSortType order; + int sort_column_id; + tr_file_index_t fileCount; + struct RefreshData refresh_data; + GtkTreeSortable * sortable = GTK_TREE_SORTABLE (data->model); + gtk_tree_sortable_get_sort_column_id (sortable, &sort_column_id, &order); + + refresh_data.sort_column_id = sort_column_id; + refresh_data.resort_needed = FALSE; + refresh_data.refresh_file_stat = tr_torrentFiles (tor, &fileCount); + refresh_data.tor = tor; + refresh_data.file_data = data; + + gtr_tree_model_foreach_postorder (data->model, refreshFilesForeach, &refresh_data); + + if (refresh_data.resort_needed) + gtk_tree_sortable_set_sort_column_id (sortable, sort_column_id, order); + + tr_torrentFilesFree (refresh_data.refresh_file_stat, fileCount); + } +} + +static gboolean +refreshModel (gpointer file_data) +{ + refresh (file_data); + + return G_SOURCE_CONTINUE; +} + +/*** +**** +***/ + +struct ActiveData +{ + GtkTreeSelection * sel; + GArray * array; +}; + +static gboolean +getSelectedFilesForeach (GtkTreeModel * model, + GtkTreePath * path UNUSED, + GtkTreeIter * iter, + gpointer gdata) +{ + const gboolean is_file = !gtk_tree_model_iter_has_child (model, iter); + + if (is_file) + { + struct ActiveData * data = gdata; + + /* active means: if it's selected or any ancestor is selected */ + gboolean is_active = gtk_tree_selection_iter_is_selected (data->sel, iter); + + if (!is_active) + { + GtkTreeIter walk = *iter; + GtkTreeIter parent; + while (!is_active && gtk_tree_model_iter_parent (model, &parent, &walk)) + { + is_active = gtk_tree_selection_iter_is_selected (data->sel, &parent); + walk = parent; + } + } + + if (is_active) + { + unsigned int i; + gtk_tree_model_get (model, iter, FC_INDEX, &i, -1); + g_array_append_val (data->array, i); + } + } + + return FALSE; /* keep walking */ +} + +static GArray* +getSelectedFilesAndDescendants (GtkTreeView * view) +{ + struct ActiveData data; + + data.sel = gtk_tree_view_get_selection (view); + data.array = g_array_new (FALSE, FALSE, sizeof (tr_file_index_t)); + gtk_tree_model_foreach (gtk_tree_view_get_model (view), + getSelectedFilesForeach, &data); + return data.array; +} + +struct SubtreeForeachData +{ + GArray * array; + GtkTreePath * path; +}; + +static gboolean +getSubtreeForeach (GtkTreeModel * model, + GtkTreePath * path, + GtkTreeIter * iter, + gpointer gdata) +{ + const gboolean is_file = !gtk_tree_model_iter_has_child (model, iter); + + if (is_file) + { + struct SubtreeForeachData * data = gdata; + + if (!gtk_tree_path_compare (path, data->path) || gtk_tree_path_is_descendant (path, data->path)) + { + unsigned int i; + gtk_tree_model_get (model, iter, FC_INDEX, &i, -1); + g_array_append_val (data->array, i); + } + } + + return FALSE; /* keep walking */ +} + +static void +getSubtree (GtkTreeView * view, GtkTreePath * path, GArray * indices) +{ + struct SubtreeForeachData tmp; + tmp.array = indices; + tmp.path = path; + gtk_tree_model_foreach (gtk_tree_view_get_model (view), getSubtreeForeach, &tmp); +} + +/* if `path' is a selected row, all selected rows are returned. + * otherwise, only the row indicated by `path' is returned. + * this is for toggling all the selected rows' states in a batch. + */ +static GArray* +getActiveFilesForPath (GtkTreeView * view, GtkTreePath * path) +{ + GArray * indices; + GtkTreeSelection * sel = gtk_tree_view_get_selection (view); + + if (gtk_tree_selection_path_is_selected (sel, path)) + { + /* clicked in a selected row... use the current selection */ + indices = getSelectedFilesAndDescendants (view); + } + else + { + /* clicked OUTSIDE of the selected row... just use the clicked row */ + indices = g_array_new (FALSE, FALSE, sizeof (tr_file_index_t)); + getSubtree (view, path, indices); + } + + return indices; +} + +/*** +**** +***/ + +void +gtr_file_list_clear (GtkWidget * w) +{ + gtr_file_list_set_torrent (w, -1); +} + +struct build_data +{ + GtkWidget * w; + tr_torrent * tor; + GtkTreeIter * iter; + GtkTreeStore * store; +}; + +struct row_struct +{ + uint64_t length; + char * name; + int index; +}; + +static void +buildTree (GNode * node, gpointer gdata) +{ + char size_str[64]; + GtkTreeIter child_iter; + struct build_data * build = gdata; + struct row_struct *child_data = node->data; + const gboolean isLeaf = node->children == NULL; + + const char * mime_type = isLeaf ? gtr_get_mime_type_from_filename (child_data->name) : DIRECTORY_MIME_TYPE; + GdkPixbuf * icon = gtr_get_mime_type_icon (mime_type, GTK_ICON_SIZE_MENU, build->w); + const tr_info * inf = tr_torrentInfo (build->tor); + const int priority = isLeaf ? inf->files[ child_data->index ].priority : 0; + const gboolean enabled = isLeaf ? !inf->files[ child_data->index ].dnd : TRUE; + char * name_esc = g_markup_escape_text (child_data->name, -1); + + tr_strlsize (size_str, child_data->length, sizeof size_str); + + gtk_tree_store_insert_with_values (build->store, &child_iter, build->iter, INT_MAX, + FC_INDEX, child_data->index, + FC_LABEL, child_data->name, + FC_LABEL_ESC, name_esc, + FC_SIZE, child_data->length, + FC_SIZE_STR, size_str, + FC_ICON, icon, + FC_PRIORITY, priority, + FC_ENABLED, enabled, + -1); + + if (!isLeaf) + { + struct build_data b = *build; + b.iter = &child_iter; + g_node_children_foreach (node, G_TRAVERSE_ALL, buildTree, &b); + } + + g_free (name_esc); + g_object_unref (icon); + + /* we're done with this node */ + g_free (child_data->name); + g_free (child_data); +} + +static GNode* +find_child (GNode* parent, const char * name) +{ + GNode * child = parent->children; + + while (child) + { + const struct row_struct * child_data = child->data; + if ((*child_data->name == *name) && !g_strcmp0 (child_data->name, name)) + break; + child = child->next; + } + + return child; +} + +void +gtr_file_list_set_torrent (GtkWidget * w, int torrentId) +{ + GtkTreeStore * store; + FileData * data = g_object_get_data (G_OBJECT (w), "file-data"); + + /* unset the old fields */ + clearData (data); + + /* instantiate the model */ + store = gtk_tree_store_new (N_FILE_COLS, + GDK_TYPE_PIXBUF, /* icon */ + G_TYPE_STRING, /* label */ + G_TYPE_STRING, /* label esc */ + G_TYPE_INT, /* prog [0..100] */ + G_TYPE_UINT, /* index */ + G_TYPE_UINT64, /* size */ + G_TYPE_STRING, /* size str */ + G_TYPE_UINT64, /* have */ + G_TYPE_INT, /* priority */ + G_TYPE_INT); /* dl enabled */ + + data->store = store; + data->model = GTK_TREE_MODEL (store); + data->torrentId = torrentId; + + /* populate the model */ + if (torrentId > 0) + { + tr_torrent * tor = gtr_core_find_torrent (data->core, torrentId); + if (tor != NULL) + { + tr_file_index_t i; + const tr_info * inf = tr_torrentInfo (tor); + struct row_struct * root_data; + GNode * root; + struct build_data build; + + /* build a GNode tree of the files */ + root_data = g_new0 (struct row_struct, 1); + root_data->name = g_strdup (tr_torrentName (tor)); + root_data->index = -1; + root_data->length = 0; + root = g_node_new (root_data); + for (i=0; ifileCount; ++i) + { + int j; + GNode * parent = root; + const tr_file * file = &inf->files[i]; + char ** tokens = g_strsplit (file->name, G_DIR_SEPARATOR_S, 0); + for (j=0; tokens[j]; ++j) + { + const gboolean isLeaf = tokens[j+1] == NULL; + const char * name = tokens[j]; + GNode * node = find_child (parent, name); + if (node == NULL) + { + struct row_struct * row = g_new (struct row_struct, 1); + row->name = g_strdup (name); + row->index = isLeaf ? (int)i : -1; + row->length = isLeaf ? file->length : 0; + node = g_node_new (row); + g_node_append (parent, node); + } + parent = node; + } + g_strfreev (tokens); + } + + /* now, add them to the model */ + build.w = w; + build.tor = tor; + build.store = data->store; + build.iter = NULL; + g_node_children_foreach (root, G_TRAVERSE_ALL, buildTree, &build); + + /* cleanup */ + g_node_destroy (root); + g_free (root_data->name); + g_free (root_data); + } + + refresh (data); + data->timeout_tag = gdk_threads_add_timeout_seconds (SECONDARY_WINDOW_REFRESH_INTERVAL_SECONDS, refreshModel, data); + } + + gtk_tree_view_set_model (GTK_TREE_VIEW (data->view), data->model); + gtk_tree_view_expand_all (GTK_TREE_VIEW (data->view)); + g_object_unref (data->model); +} + +/*** +**** +***/ + +static void +renderDownload (GtkTreeViewColumn * column UNUSED, + GtkCellRenderer * renderer, + GtkTreeModel * model, + GtkTreeIter * iter, + gpointer data UNUSED) +{ + gboolean enabled; + gtk_tree_model_get (model, iter, FC_ENABLED, &enabled, -1); + g_object_set (renderer, "inconsistent", (enabled==MIXED), + "active", (enabled==TRUE), + NULL); +} + +static void +renderPriority (GtkTreeViewColumn * column UNUSED, + GtkCellRenderer * renderer, + GtkTreeModel * model, + GtkTreeIter * iter, + gpointer data UNUSED) +{ + int priority; + const char * text; + gtk_tree_model_get (model, iter, FC_PRIORITY, &priority, -1); + switch (priority) + { + case TR_PRI_HIGH: text = _("High"); break; + case TR_PRI_NORMAL: text = _("Normal"); break; + case TR_PRI_LOW: text = _("Low"); break; + default: text = _("Mixed"); break; + } + g_object_set (renderer, "text", text, NULL); +} + +/* build a filename from tr_torrentGetCurrentDir () + the model's FC_LABELs */ +static char* +buildFilename (tr_torrent * tor, GtkTreeModel * model, + GtkTreePath * path, GtkTreeIter * iter) +{ + char * ret; + GtkTreeIter child; + GtkTreeIter parent = *iter; + int n = gtk_tree_path_get_depth (path); + char ** tokens = g_new0 (char*, n + 2); + tokens[0] = g_strdup (tr_torrentGetCurrentDir (tor)); + do { + child = parent; + gtk_tree_model_get (model, &child, FC_LABEL, &tokens[n--], -1); + } while (gtk_tree_model_iter_parent (model, &parent, &child)); + ret = g_build_filenamev (tokens); + g_strfreev (tokens); + return ret; +} + +static gboolean +onRowActivated (GtkTreeView * view, GtkTreePath * path, + GtkTreeViewColumn * col UNUSED, gpointer gdata) +{ + gboolean handled = FALSE; + FileData * data = gdata; + tr_torrent * tor = gtr_core_find_torrent (data->core, data->torrentId); + + if (tor != NULL) + { + GtkTreeIter iter; + GtkTreeModel * model = gtk_tree_view_get_model (view); + + if (gtk_tree_model_get_iter (model, &iter, path)) + { + int prog; + char * filename = buildFilename (tor, model, path, &iter); + gtk_tree_model_get (model, &iter, FC_PROG, &prog, -1); + + /* if the file's not done, walk up the directory tree until we find + * an ancestor that exists, and open that instead */ + if (filename && (prog<100 || !g_file_test (filename, G_FILE_TEST_EXISTS))) do + { + char * tmp = g_path_get_dirname (filename); + g_free (filename); + filename = tmp; + } + while (filename && *filename && !g_file_test (filename, G_FILE_TEST_EXISTS)); + + if ((handled = filename && *filename)) + gtr_open_file (filename); + } + } + + return handled; +} + +static gboolean +onViewPathToggled (GtkTreeView * view, + GtkTreeViewColumn * col, + GtkTreePath * path, + FileData * data) +{ + int cid; + tr_torrent * tor; + gboolean handled = FALSE; + + if (!col || !path) + return FALSE; + + cid = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (col), TR_COLUMN_ID_KEY)); + tor = gtr_core_find_torrent (data->core, data->torrentId); + if ((tor != NULL) && ((cid == FC_PRIORITY) || (cid == FC_ENABLED))) + { + GtkTreeIter iter; + GArray * indices = getActiveFilesForPath (view, path); + GtkTreeModel * model = data->model; + + gtk_tree_model_get_iter (model, &iter, path); + + if (cid == FC_PRIORITY) + { + int priority; + gtk_tree_model_get (model, &iter, FC_PRIORITY, &priority, -1); + switch (priority) + { + case TR_PRI_NORMAL: priority = TR_PRI_HIGH; break; + case TR_PRI_HIGH: priority = TR_PRI_LOW; break; + default: priority = TR_PRI_NORMAL; break; + } + tr_torrentSetFilePriorities (tor, + (tr_file_index_t *) indices->data, + (tr_file_index_t) indices->len, + priority); + } + else + { + int enabled; + gtk_tree_model_get (model, &iter, FC_ENABLED, &enabled, -1); + enabled = !enabled; + + tr_torrentSetFileDLs (tor, + (tr_file_index_t *) indices->data, + (tr_file_index_t) indices->len, + enabled); + } + + refresh (data); + g_array_free (indices, TRUE); + handled = TRUE; + } + + return handled; +} + +/** + * @note 'col' and 'path' are assumed not to be NULL. + */ +static gboolean +getAndSelectEventPath (GtkTreeView * treeview, + GdkEventButton * event, + GtkTreeViewColumn ** col, + GtkTreePath ** path) +{ + GtkTreeSelection * sel; + + if (gtk_tree_view_get_path_at_pos (treeview, + event->x, event->y, + path, col, NULL, NULL)) + { + sel = gtk_tree_view_get_selection (treeview); + if (!gtk_tree_selection_path_is_selected (sel, *path)) + { + gtk_tree_selection_unselect_all (sel); + gtk_tree_selection_select_path (sel, *path); + } + return TRUE; + } + + return FALSE; +} + +static gboolean +onViewButtonPressed (GtkWidget * w, GdkEventButton * event, gpointer gdata) +{ + GtkTreeViewColumn * col; + GtkTreePath * path = NULL; + gboolean handled = FALSE; + GtkTreeView * treeview = GTK_TREE_VIEW (w); + FileData * data = gdata; + + if ((event->type == GDK_BUTTON_PRESS) + && (event->button == 1) + && ! (event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) + && getAndSelectEventPath (treeview, event, &col, &path)) + { + handled = onViewPathToggled (treeview, col, path, data); + + if (path != NULL) + gtk_tree_path_free (path); + } + + return handled; +} + +struct rename_data +{ + int error; + char * newname; + char * path_string; + FileData * file_data; +}; + +static int +on_rename_done_idle (struct rename_data * data) +{ + if (data->error == 0) + { + GtkTreeIter iter; + + if (gtk_tree_model_get_iter_from_string (data->file_data->model, &iter, data->path_string)) + gtk_tree_store_set (data->file_data->store, &iter, FC_LABEL, data->newname, -1); + } + else + { + GtkWidget * w = gtk_message_dialog_new ( + GTK_WINDOW (gtk_widget_get_toplevel(data->file_data->top)), + GTK_DIALOG_MODAL, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + _("Unable to rename file as \"%s\": %s"), + data->newname, + tr_strerror(data->error)); + gtk_message_dialog_format_secondary_text ( + GTK_MESSAGE_DIALOG (w), "%s", + _("Please correct the errors and try again.")); + gtk_dialog_run (GTK_DIALOG (w)); + gtk_widget_destroy (w); + } + + /* cleanup */ + g_free (data->path_string); + g_free (data->newname); + g_free (data); + return G_SOURCE_REMOVE; +} + +static void +on_rename_done (tr_torrent * tor G_GNUC_UNUSED, + const char * oldpath G_GNUC_UNUSED, + const char * newname G_GNUC_UNUSED, + int error, + struct rename_data * rename_data) +{ + rename_data->error = error; + gdk_threads_add_idle ((GSourceFunc)on_rename_done_idle, rename_data); +} + +static void +cell_edited_callback (GtkCellRendererText * cell G_GNUC_UNUSED, + gchar * path_string, + gchar * newname, + FileData * data) +{ + tr_torrent * tor; + GString * oldpath; + GtkTreeIter iter; + struct rename_data * rename_data; + + tor = gtr_core_find_torrent (data->core, data->torrentId); + if (tor == NULL) + return; + if (!gtk_tree_model_get_iter_from_string (data->model, &iter, path_string)) + return; + + /* build oldpath */ + oldpath = g_string_new (NULL); + for (;;) + { + char * token = NULL; + GtkTreeIter child; + gtk_tree_model_get (data->model, &iter, FC_LABEL, &token, -1); + g_string_prepend (oldpath, token); + g_free (token); + + child = iter; + if (!gtk_tree_model_iter_parent (data->model, &iter, &child)) + break; + + g_string_prepend_c (oldpath, G_DIR_SEPARATOR); + } + + /* do the renaming */ + rename_data = g_new0 (struct rename_data, 1); + rename_data->newname = g_strdup (newname); + rename_data->file_data = data; + rename_data->path_string = g_strdup (path_string); + tr_torrentRenamePath (tor, oldpath->str, newname, (tr_torrent_rename_done_func*)on_rename_done, rename_data); + + /* cleanup */ + g_string_free (oldpath, TRUE); +} + + +GtkWidget * +gtr_file_list_new (TrCore * core, int torrentId) +{ + int size; + int width; + GtkWidget * ret; + GtkWidget * view; + GtkWidget * scroll; + GtkCellRenderer * rend; + GtkTreeSelection * sel; + GtkTreeViewColumn * col; + GtkTreeView * tree_view; + const char * title; + PangoLayout * pango_layout; + PangoContext * pango_context; + PangoFontDescription * pango_font_description; + FileData * data = g_new0 (FileData, 1); + + data->core = core; + + /* create the view */ + view = gtk_tree_view_new (); + tree_view = GTK_TREE_VIEW (view); + gtk_tree_view_set_rules_hint (tree_view, TRUE); + gtk_container_set_border_width (GTK_CONTAINER (view), GUI_PAD_BIG); + g_signal_connect (view, "button-press-event", + G_CALLBACK (onViewButtonPressed), data); + g_signal_connect (view, "row_activated", + G_CALLBACK (onRowActivated), data); + g_signal_connect (view, "button-release-event", + G_CALLBACK (on_tree_view_button_released), NULL); + + + pango_context = gtk_widget_create_pango_context (view); + pango_font_description = pango_font_description_copy (pango_context_get_font_description (pango_context)); + size = pango_font_description_get_size (pango_font_description); + pango_font_description_set_size (pango_font_description, size * 0.8); + g_object_unref (G_OBJECT (pango_context)); + + /* set up view */ + sel = gtk_tree_view_get_selection (tree_view); + gtk_tree_selection_set_mode (sel, GTK_SELECTION_MULTIPLE); + gtk_tree_view_expand_all (tree_view); + gtk_tree_view_set_search_column (tree_view, FC_LABEL); + + /* add file column */ + col = GTK_TREE_VIEW_COLUMN (g_object_new (GTK_TYPE_TREE_VIEW_COLUMN, + "expand", TRUE, + "title", _("Name"), + NULL)); + gtk_tree_view_column_set_resizable (col, TRUE); + rend = gtk_cell_renderer_pixbuf_new (); + gtk_tree_view_column_pack_start (col, rend, FALSE); + gtk_tree_view_column_add_attribute (col, rend, "pixbuf", FC_ICON); + /* add text renderer */ + rend = gtk_cell_renderer_text_new (); + g_object_set (rend, "editable", TRUE, NULL); + g_object_set (rend, "ellipsize", PANGO_ELLIPSIZE_END, "font-desc", pango_font_description, NULL); + g_signal_connect (rend, "edited", (GCallback)cell_edited_callback, data); + gtk_tree_view_column_pack_start (col, rend, TRUE); + gtk_tree_view_column_set_attributes (col, rend, "text", FC_LABEL, NULL); + gtk_tree_view_column_set_sort_column_id (col, FC_LABEL); + gtk_tree_view_append_column (tree_view, col); + + /* add "size" column */ + title = _("Size"); + rend = gtk_cell_renderer_text_new (); + g_object_set (rend, "alignment", PANGO_ALIGN_RIGHT, + "font-desc", pango_font_description, + "xpad", GUI_PAD, + "xalign", 1.0f, + "yalign", 0.5f, + NULL); + col = gtk_tree_view_column_new_with_attributes (title, rend, NULL); + gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_GROW_ONLY); + gtk_tree_view_column_set_sort_column_id (col, FC_SIZE); + gtk_tree_view_column_set_attributes (col, rend, "text", FC_SIZE_STR, NULL); + gtk_tree_view_append_column (tree_view, col); + + /* add "progress" column */ + title = _("Have"); + pango_layout = gtk_widget_create_pango_layout (view, title); + pango_layout_get_pixel_size (pango_layout, &width, NULL); + width += 30; /* room for the sort indicator */ + g_object_unref (G_OBJECT (pango_layout)); + rend = gtk_cell_renderer_progress_new (); + col = gtk_tree_view_column_new_with_attributes (title, rend, "value", FC_PROG, NULL); + gtk_tree_view_column_set_fixed_width (col, width); + gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_FIXED); + gtk_tree_view_column_set_sort_column_id (col, FC_PROG); + gtk_tree_view_append_column (tree_view, col); + + /* add "enabled" column */ + title = _("Download"); + pango_layout = gtk_widget_create_pango_layout (view, title); + pango_layout_get_pixel_size (pango_layout, &width, NULL); + width += 30; /* room for the sort indicator */ + g_object_unref (G_OBJECT (pango_layout)); + rend = gtk_cell_renderer_toggle_new (); + col = gtk_tree_view_column_new_with_attributes (title, rend, NULL); + g_object_set_data (G_OBJECT (col), TR_COLUMN_ID_KEY, + GINT_TO_POINTER (FC_ENABLED)); + gtk_tree_view_column_set_fixed_width (col, width); + gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_FIXED); + gtk_tree_view_column_set_cell_data_func (col, rend, renderDownload, NULL, NULL); + gtk_tree_view_column_set_sort_column_id (col, FC_ENABLED); + gtk_tree_view_append_column (tree_view, col); + + /* add priority column */ + title = _("Priority"); + pango_layout = gtk_widget_create_pango_layout (view, title); + pango_layout_get_pixel_size (pango_layout, &width, NULL); + width += 30; /* room for the sort indicator */ + g_object_unref (G_OBJECT (pango_layout)); + rend = gtk_cell_renderer_text_new (); + g_object_set (rend, "xalign", (gfloat)0.5, "yalign", (gfloat)0.5, NULL); + col = gtk_tree_view_column_new_with_attributes (title, rend, NULL); + g_object_set_data (G_OBJECT (col), TR_COLUMN_ID_KEY, + GINT_TO_POINTER (FC_PRIORITY)); + gtk_tree_view_column_set_fixed_width (col, width); + gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_FIXED); + gtk_tree_view_column_set_sort_column_id (col, FC_PRIORITY); + gtk_tree_view_column_set_cell_data_func (col, rend, renderPriority, NULL, NULL); + gtk_tree_view_append_column (tree_view, col); + + /* add tooltip to tree */ + gtk_tree_view_set_tooltip_column (tree_view, FC_LABEL_ESC); + + /* create the scrolled window and stick the view in it */ + scroll = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), + GTK_SHADOW_IN); + gtk_container_add (GTK_CONTAINER (scroll), view); + gtk_widget_set_size_request (scroll, -1, 200); + + ret = scroll; + data->view = view; + data->top = scroll; + g_object_set_data_full (G_OBJECT (ret), "file-data", data, freeData); + gtr_file_list_set_torrent (ret, torrentId); + + pango_font_description_free (pango_font_description); + return ret; +} diff --git a/release/src/router/transmission/gtk/main.c b/release/src/router/transmission/gtk/main.c index c5b318c27f..a011bb8c66 100644 --- a/release/src/router/transmission/gtk/main.c +++ b/release/src/router/transmission/gtk/main.c @@ -1,5 +1,5 @@ /****************************************************************************** - * $Id: main.c 14112 2013-07-08 19:34:58Z jordan $ + * $Id: main.c 14154 2013-08-05 02:39:30Z jordan $ * * Copyright (c) Transmission authors and contributors * @@ -944,6 +944,9 @@ on_app_exit (gpointer vdata) struct cbdata * cbdata = vdata; struct session_close_struct * session_close_data; + if (cbdata->is_closing) + return; + cbdata->is_closing = true; /* stop the update timer */ diff --git a/release/src/router/transmission/gtk/open-dialog.c b/release/src/router/transmission/gtk/open-dialog.c dissimilarity index 85% index 4df9806f90..5f5104adbf 100644 --- a/release/src/router/transmission/gtk/open-dialog.c +++ b/release/src/router/transmission/gtk/open-dialog.c @@ -1,537 +1,540 @@ -/* - * This file Copyright (C) Mnemosyne LLC - * - * This file is licensed by the GPL version 2. Works owned by the - * Transmission project are granted a special exemption to clause 2 (b) - * so that the bulk of its code can remain under the MIT license. - * This exemption does not extend to derived works not owned by - * the Transmission project. - * - * $Id: open-dialog.c 14077 2013-05-22 20:35:38Z jordan $ - */ - -#include -#include - -#include - -#include -#include /* tr_is_same_file () */ - -#include "conf.h" -#include "file-list.h" -#include "hig.h" -#include "open-dialog.h" -#include "tr-prefs.h" -#include "util.h" /* gtr_priority_combo_get_value () */ - -/**** -***** -****/ - -#define N_RECENT 4 - -static GSList* -get_recent_destinations (void) -{ - int i; - GSList * list = NULL; - - for (i=0; inext) - l->data = g_strdup (l->data); - - /* save the first N_RECENT directories */ - for (l=list, i=0; l && (inext) { - char key[64]; - g_snprintf (key, sizeof (key), "recent-download-dir-%d", i + 1); - gtr_pref_string_set (tr_quark_new(key,-1), l->data); - } - gtr_pref_save (gtr_core_session (core)); - - /* cleanup */ - g_slist_foreach (list, (GFunc)g_free, NULL); - g_slist_free (list); -} - -/**** -***** -****/ - -struct OpenData -{ - TrCore * core; - GtkWidget * file_list; - GtkWidget * run_check; - GtkWidget * trash_check; - GtkWidget * priority_combo; - GtkWidget * freespace_label; - char * filename; - char * downloadDir; - tr_torrent * tor; - tr_ctor * ctor; -}; - -static void -removeOldTorrent (struct OpenData * o) -{ - if (o->tor) - { - gtr_file_list_clear (o->file_list); - tr_torrentRemove (o->tor, FALSE, NULL); - o->tor = NULL; - } -} - -static void -addResponseCB (GtkDialog * dialog, - gint response, - gpointer gdata) -{ - struct OpenData * o = gdata; - - if (o->tor) - { - if (response != GTK_RESPONSE_ACCEPT) - { - removeOldTorrent (o); - } - else - { - tr_torrentSetPriority (o->tor, gtr_priority_combo_get_value (GTK_COMBO_BOX (o->priority_combo))); - - if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (o->run_check))) - tr_torrentStart (o->tor); - - gtr_core_add_torrent (o->core, o->tor, FALSE); - - if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (o->trash_check))) - gtr_file_trash_or_remove (o->filename); - - save_recent_destination (o->core, o->downloadDir); - } - } - - tr_ctorFree (o->ctor); - g_free (o->filename); - g_free (o->downloadDir); - g_free (o); - gtk_widget_destroy (GTK_WIDGET (dialog)); -} - -static void -updateTorrent (struct OpenData * o) -{ - const gboolean isLocalFile = tr_ctorGetSourceFile (o->ctor) != NULL; - gtk_widget_set_sensitive (o->trash_check, isLocalFile); - - if (!o->tor) - { - gtr_file_list_clear (o->file_list); - gtk_widget_set_sensitive (o->file_list, FALSE); - } - else - { - tr_torrentSetDownloadDir (o->tor, o->downloadDir); - gtk_widget_set_sensitive (o->file_list, tr_torrentHasMetadata (o->tor)); - gtr_file_list_set_torrent (o->file_list, tr_torrentId (o->tor)); - tr_torrentVerify (o->tor, NULL, NULL); - } -} - -/** - * When the source .torrent file is deleted - * (such as, if it was a temp file that a web browser passed to us), - * gtk invokes this callback and `filename' will be NULL. - * The `filename' tests here are to prevent us from losing the current - * metadata when that happens. - */ -static void -sourceChanged (GtkFileChooserButton * b, gpointer gdata) -{ - struct OpenData * o = gdata; - char * filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (b)); - - /* maybe instantiate a torrent */ - if (filename || !o->tor) - { - int err = 0; - int new_file = 0; - int duplicate_id = 0; - tr_torrent * torrent; - - if (filename && (!o->filename || !tr_is_same_file (filename, o->filename))) - { - g_free (o->filename); - o->filename = g_strdup (filename); - tr_ctorSetMetainfoFromFile (o->ctor, o->filename); - new_file = 1; - } - - tr_ctorSetDownloadDir (o->ctor, TR_FORCE, o->downloadDir); - tr_ctorSetPaused (o->ctor, TR_FORCE, TRUE); - tr_ctorSetDeleteSource (o->ctor, FALSE); - - if ((torrent = tr_torrentNew (o->ctor, &err, &duplicate_id))) - { - removeOldTorrent (o); - o->tor = torrent; - } - else if (new_file) - { - tr_torrent * tor; - - if (duplicate_id) - tor = gtr_core_find_torrent (o->core, duplicate_id); - else - tor = NULL; - - gtr_add_torrent_error_dialog (GTK_WIDGET (b), err, tor, o->filename); - } - - updateTorrent (o); - } - - g_free (filename); -} - -static void -downloadDirChanged (GtkFileChooserButton * b, gpointer gdata) -{ - struct OpenData * data = gdata; - char * fname = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (b)); - - if (fname && (!data->downloadDir || !tr_is_same_file (fname, data->downloadDir))) - { - g_free (data->downloadDir); - data->downloadDir = g_strdup (fname); - updateTorrent (data); - - gtr_freespace_label_set_dir (data->freespace_label, data->downloadDir); - } - - g_free (fname); -} - -static void -addTorrentFilters (GtkFileChooser * chooser) -{ - GtkFileFilter * filter; - - filter = gtk_file_filter_new (); - gtk_file_filter_set_name (filter, _("Torrent files")); - gtk_file_filter_add_pattern (filter, "*.torrent"); - gtk_file_chooser_add_filter (chooser, filter); - - filter = gtk_file_filter_new (); - gtk_file_filter_set_name (filter, _("All files")); - gtk_file_filter_add_pattern (filter, "*"); - gtk_file_chooser_add_filter (chooser, filter); -} - -/**** -***** -****/ - -GtkWidget* -gtr_torrent_options_dialog_new (GtkWindow * parent, TrCore * core, tr_ctor * ctor) -{ - const char * str; - GtkWidget * w; - GtkWidget * d; - GtkGrid * grid; - int row; - GtkWidget * l; - GtkWidget * source_chooser; - struct OpenData * data; - bool flag; - GSList * list; - GSList * walk; - - /* make the dialog */ - d = gtk_dialog_new_with_buttons (_("Torrent Options"), parent, - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, - NULL); - gtk_dialog_set_default_response (GTK_DIALOG (d), - GTK_RESPONSE_ACCEPT); - gtk_dialog_set_alternative_button_order (GTK_DIALOG (d), - GTK_RESPONSE_ACCEPT, - GTK_RESPONSE_CANCEL, - -1); - - if (tr_ctorGetDownloadDir (ctor, TR_FORCE, &str)) - g_assert_not_reached (); - g_assert (str); - - data = g_new0 (struct OpenData, 1); - data->core = core; - data->ctor = ctor; - data->filename = g_strdup (tr_ctorGetSourceFile (ctor)); - data->downloadDir = g_strdup (str); - data->file_list = gtr_file_list_new (core, 0); - str = _("Mo_ve .torrent file to the trash"); - data->trash_check = gtk_check_button_new_with_mnemonic (str); - str = _("_Start when added"); - data->run_check = gtk_check_button_new_with_mnemonic (str); - - w = data->priority_combo = gtr_priority_combo_new (); - gtr_priority_combo_set_value (GTK_COMBO_BOX (w), TR_PRI_NORMAL); - - g_signal_connect (G_OBJECT (d), "response", - G_CALLBACK (addResponseCB), data); - - row = 0; - grid = GTK_GRID (gtk_grid_new ()); - gtk_container_set_border_width (GTK_CONTAINER (grid), GUI_PAD_BIG); - gtk_grid_set_row_spacing (grid, GUI_PAD); - gtk_grid_set_column_spacing (grid, GUI_PAD_BIG); - - // "torrent file" row - l = gtk_label_new_with_mnemonic (_("_Torrent file:")); - gtk_misc_set_alignment (GTK_MISC (l), 0.0f, 0.5f); - gtk_grid_attach (grid, l, 0, row, 1, 1); - w = gtk_file_chooser_button_new (_("Select Source File"), - GTK_FILE_CHOOSER_ACTION_OPEN); - source_chooser = w; - gtk_widget_set_hexpand (w, TRUE); - gtk_grid_attach_next_to (grid, w, l, GTK_POS_RIGHT, 1, 1); - gtk_label_set_mnemonic_widget (GTK_LABEL (l), w); - addTorrentFilters (GTK_FILE_CHOOSER (w)); - g_signal_connect (w, "selection-changed", - G_CALLBACK (sourceChanged), data); - - // "destination folder" row - row++; - l = gtk_label_new_with_mnemonic (_("_Destination folder:")); - gtk_misc_set_alignment (GTK_MISC (l), 0.0f, 0.5f); - gtk_grid_attach (grid, l, 0, row, 1, 1); - w = gtk_file_chooser_button_new (_("Select Destination Folder"), - GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER); - if (!gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (w), - data->downloadDir)) - g_warning ("couldn't select '%s'", data->downloadDir); - list = get_recent_destinations (); - for (walk = list; walk; walk = walk->next) - gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (w), walk->data, NULL); - g_slist_free (list); - gtk_grid_attach_next_to (grid, w, l, GTK_POS_RIGHT, 1, 1); - gtk_label_set_mnemonic_widget (GTK_LABEL (l), w); - g_signal_connect (w, "selection-changed", - G_CALLBACK (downloadDirChanged), data); - - row++; - l = data->freespace_label = gtr_freespace_label_new (core, data->downloadDir); - gtk_widget_set_margin_bottom (l, GUI_PAD_BIG); - gtk_misc_set_alignment (GTK_MISC (l), 1.0f, 0.5f); - gtk_grid_attach (grid, l, 0, row, 2, 1); - - - // file list row - row++; - w = data->file_list; - gtk_widget_set_vexpand (w, TRUE); - gtk_widget_set_size_request (w, 466u, 300u); - gtk_grid_attach (grid, w, 0, row, 2, 1); - - // torrent priority row - row++; - l = gtk_label_new_with_mnemonic (_("Torrent _priority:")); - gtk_misc_set_alignment (GTK_MISC (l), 0.0f, 0.5f); - gtk_grid_attach (grid, l, 0, row, 1, 1); - w = data->priority_combo; - gtk_label_set_mnemonic_widget (GTK_LABEL (l), w); - gtk_grid_attach_next_to (grid, w, l, GTK_POS_RIGHT, 1, 1); - - // torrent priority row - row++; - w = data->run_check; - if (tr_ctorGetPaused (ctor, TR_FORCE, &flag)) - g_assert_not_reached (); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), !flag); - gtk_grid_attach (grid, w, 0, row, 2, 1); - - // "trash .torrent file" row - row++; - w = data->trash_check; - if (tr_ctorGetDeleteSource (ctor, &flag)) - g_assert_not_reached (); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), flag); - gtk_grid_attach (grid, w, 0, row, 2, 1); - - /* trigger sourceChanged, either directly or indirectly, - * so that it creates the tor/gtor objects */ - w = source_chooser; - if (data->filename) - gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (w), data->filename); - else - sourceChanged (GTK_FILE_CHOOSER_BUTTON (w), data); - - gtr_dialog_set_content (GTK_DIALOG (d), GTK_WIDGET (grid)); - w = gtk_dialog_get_widget_for_response (GTK_DIALOG (d), GTK_RESPONSE_ACCEPT); - gtk_widget_grab_focus (w); - return d; -} - -/**** -***** -****/ - -static void -onOpenDialogResponse (GtkDialog * dialog, int response, gpointer core) -{ - char * folder; - - /* remember this folder the next time we use this dialog */ - folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog)); - gtr_pref_string_set (TR_KEY_open_dialog_dir, folder); - g_free (folder); - - if (response == GTK_RESPONSE_ACCEPT) - { - GtkFileChooser * chooser = GTK_FILE_CHOOSER (dialog); - GtkWidget * w = gtk_file_chooser_get_extra_widget (chooser); - GtkToggleButton * tb = GTK_TOGGLE_BUTTON (w); - const gboolean do_start = gtr_pref_flag_get (TR_KEY_start_added_torrents); - const gboolean do_prompt = gtk_toggle_button_get_active (tb); - const gboolean do_notify = FALSE; - GSList * files = gtk_file_chooser_get_files (chooser); - - gtr_core_add_files (core, files, do_start, do_prompt, do_notify); - g_slist_foreach (files, (GFunc)g_object_unref, NULL); - g_slist_free (files); - } - - gtk_widget_destroy (GTK_WIDGET (dialog)); -} - -GtkWidget* -gtr_torrent_open_from_file_dialog_new (GtkWindow * parent, TrCore * core) -{ - GtkWidget * w; - GtkWidget * c; - const char * folder; - - w = gtk_file_chooser_dialog_new (_("Open a Torrent"), parent, - GTK_FILE_CHOOSER_ACTION_OPEN, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, - NULL); - gtk_dialog_set_alternative_button_order (GTK_DIALOG (w), - GTK_RESPONSE_ACCEPT, - GTK_RESPONSE_CANCEL, - -1); - gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (w), TRUE); - addTorrentFilters (GTK_FILE_CHOOSER (w)); - g_signal_connect (w, "response", G_CALLBACK (onOpenDialogResponse), core); - - if ((folder = gtr_pref_string_get (TR_KEY_open_dialog_dir))) - gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (w), folder); - - c = gtk_check_button_new_with_mnemonic (_("Show _options dialog")); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (c), - gtr_pref_flag_get (TR_KEY_show_options_window)); - gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (w), c); - gtk_widget_show (c); - - return w; -} - -/*** -**** -***/ - -static void -onOpenURLResponse (GtkDialog * dialog, int response, gpointer user_data) -{ - bool handled = false; - - if (response == GTK_RESPONSE_ACCEPT) - { - GtkWidget * e = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), "url-entry")); - char * url = g_strdup (gtk_entry_get_text (GTK_ENTRY (e))); - g_strstrip (url); - - if (url) { - handled = gtr_core_add_from_url (user_data, url); - if (!handled) - gtr_unrecognized_url_dialog (GTK_WIDGET (dialog), url); - g_free (url); - } - } - else if (response == GTK_RESPONSE_CANCEL) - { - handled = TRUE; - } - - if (handled) - gtk_widget_destroy (GTK_WIDGET (dialog)); -} - -GtkWidget* -gtr_torrent_open_from_url_dialog_new (GtkWindow * parent, TrCore * core) -{ - guint row; - GtkWidget * e; - GtkWidget * t; - GtkWidget * w; - - w = gtk_dialog_new_with_buttons (_("Open URL"), parent, - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, - NULL); - gtk_dialog_set_alternative_button_order (GTK_DIALOG (w), - GTK_RESPONSE_ACCEPT, - GTK_RESPONSE_CANCEL, - -1); - g_signal_connect (w, "response", G_CALLBACK (onOpenURLResponse), core); - - row = 0; - t = hig_workarea_create (); - hig_workarea_add_section_title (t, &row, _("Open torrent from URL")); - e = gtk_entry_new (); - gtk_widget_set_size_request (e, 400, -1); - gtr_paste_clipboard_url_into_entry (e); - g_object_set_data (G_OBJECT (w), "url-entry", e); - hig_workarea_add_row (t, &row, _("_URL"), e, NULL); - - gtr_dialog_set_content (GTK_DIALOG (w), t); - - if (gtk_entry_get_text_length (GTK_ENTRY (e)) == 0) - gtk_widget_grab_focus (e); - else - gtk_widget_grab_focus (gtk_dialog_get_widget_for_response (GTK_DIALOG (w), GTK_RESPONSE_ACCEPT)); - - return w; -} +/* + * This file Copyright (C) Mnemosyne LLC + * + * This file is licensed by the GPL version 2. Works owned by the + * Transmission project are granted a special exemption to clause 2 (b) + * so that the bulk of its code can remain under the MIT license. + * This exemption does not extend to derived works not owned by + * the Transmission project. + * + * $Id: open-dialog.c 14132 2013-07-20 16:19:15Z jordan $ + */ + +#include +#include + +#include + +#include +#include /* tr_is_same_file () */ + +#include "conf.h" +#include "file-list.h" +#include "hig.h" +#include "open-dialog.h" +#include "tr-prefs.h" +#include "util.h" /* gtr_priority_combo_get_value () */ + +/**** +***** +****/ + +#define N_RECENT 4 + +static GSList* +get_recent_destinations (void) +{ + int i; + GSList * list = NULL; + + for (i=0; inext) + l->data = g_strdup (l->data); + + /* save the first N_RECENT directories */ + for (l=list, i=0; l && (inext) + { + char key[64]; + g_snprintf (key, sizeof (key), "recent-download-dir-%d", i + 1); + gtr_pref_string_set (tr_quark_new(key,-1), l->data); + } + gtr_pref_save (gtr_core_session (core)); + + /* cleanup */ + g_slist_foreach (list, (GFunc)g_free, NULL); + g_slist_free (list); +} + +/**** +***** +****/ + +struct OpenData +{ + TrCore * core; + GtkWidget * file_list; + GtkWidget * run_check; + GtkWidget * trash_check; + GtkWidget * priority_combo; + GtkWidget * freespace_label; + char * filename; + char * downloadDir; + tr_torrent * tor; + tr_ctor * ctor; +}; + +static void +removeOldTorrent (struct OpenData * o) +{ + if (o->tor) + { + gtr_file_list_clear (o->file_list); + tr_torrentRemove (o->tor, FALSE, NULL); + o->tor = NULL; + } +} + +static void +addResponseCB (GtkDialog * dialog, + gint response, + gpointer gdata) +{ + struct OpenData * o = gdata; + + if (o->tor) + { + if (response != GTK_RESPONSE_ACCEPT) + { + removeOldTorrent (o); + } + else + { + tr_torrentSetPriority (o->tor, gtr_priority_combo_get_value (GTK_COMBO_BOX (o->priority_combo))); + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (o->run_check))) + tr_torrentStart (o->tor); + + gtr_core_add_torrent (o->core, o->tor, FALSE); + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (o->trash_check))) + gtr_file_trash_or_remove (o->filename); + + save_recent_destination (o->core, o->downloadDir); + } + } + + tr_ctorFree (o->ctor); + g_free (o->filename); + g_free (o->downloadDir); + g_free (o); + gtk_widget_destroy (GTK_WIDGET (dialog)); +} + +static void +updateTorrent (struct OpenData * o) +{ + const gboolean isLocalFile = tr_ctorGetSourceFile (o->ctor) != NULL; + gtk_widget_set_sensitive (o->trash_check, isLocalFile); + + if (!o->tor) + { + gtr_file_list_clear (o->file_list); + gtk_widget_set_sensitive (o->file_list, FALSE); + } + else + { + tr_torrentSetDownloadDir (o->tor, o->downloadDir); + gtk_widget_set_sensitive (o->file_list, tr_torrentHasMetadata (o->tor)); + gtr_file_list_set_torrent (o->file_list, tr_torrentId (o->tor)); + tr_torrentVerify (o->tor, NULL, NULL); + } +} + +/** + * When the source .torrent file is deleted + * (such as, if it was a temp file that a web browser passed to us), + * gtk invokes this callback and `filename' will be NULL. + * The `filename' tests here are to prevent us from losing the current + * metadata when that happens. + */ +static void +sourceChanged (GtkFileChooserButton * b, gpointer gdata) +{ + struct OpenData * o = gdata; + char * filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (b)); + + /* maybe instantiate a torrent */ + if (filename || !o->tor) + { + int err = 0; + int new_file = 0; + int duplicate_id = 0; + tr_torrent * torrent; + + if (filename && (!o->filename || !tr_is_same_file (filename, o->filename))) + { + g_free (o->filename); + o->filename = g_strdup (filename); + tr_ctorSetMetainfoFromFile (o->ctor, o->filename); + new_file = 1; + } + + tr_ctorSetDownloadDir (o->ctor, TR_FORCE, o->downloadDir); + tr_ctorSetPaused (o->ctor, TR_FORCE, TRUE); + tr_ctorSetDeleteSource (o->ctor, FALSE); + + if ((torrent = tr_torrentNew (o->ctor, &err, &duplicate_id))) + { + removeOldTorrent (o); + o->tor = torrent; + } + else if (new_file) + { + tr_torrent * tor; + + if (duplicate_id) + tor = gtr_core_find_torrent (o->core, duplicate_id); + else + tor = NULL; + + gtr_add_torrent_error_dialog (GTK_WIDGET (b), err, tor, o->filename); + } + + updateTorrent (o); + } + + g_free (filename); +} + +static void +downloadDirChanged (GtkFileChooserButton * b, gpointer gdata) +{ + struct OpenData * data = gdata; + char * fname = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (b)); + + if (fname && (!data->downloadDir || !tr_is_same_file (fname, data->downloadDir))) + { + g_free (data->downloadDir); + data->downloadDir = g_strdup (fname); + updateTorrent (data); + + gtr_freespace_label_set_dir (data->freespace_label, data->downloadDir); + } + + g_free (fname); +} + +static void +addTorrentFilters (GtkFileChooser * chooser) +{ + GtkFileFilter * filter; + + filter = gtk_file_filter_new (); + gtk_file_filter_set_name (filter, _("Torrent files")); + gtk_file_filter_add_pattern (filter, "*.torrent"); + gtk_file_chooser_add_filter (chooser, filter); + + filter = gtk_file_filter_new (); + gtk_file_filter_set_name (filter, _("All files")); + gtk_file_filter_add_pattern (filter, "*"); + gtk_file_chooser_add_filter (chooser, filter); +} + +/**** +***** +****/ + +GtkWidget* +gtr_torrent_options_dialog_new (GtkWindow * parent, TrCore * core, tr_ctor * ctor) +{ + const char * str; + GtkWidget * w; + GtkWidget * d; + GtkGrid * grid; + int row; + GtkWidget * l; + GtkWidget * source_chooser; + struct OpenData * data; + bool flag; + GSList * list; + GSList * walk; + + /* make the dialog */ + d = gtk_dialog_new_with_buttons (_("Torrent Options"), parent, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, + NULL); + gtk_dialog_set_default_response (GTK_DIALOG (d), + GTK_RESPONSE_ACCEPT); + gtk_dialog_set_alternative_button_order (GTK_DIALOG (d), + GTK_RESPONSE_ACCEPT, + GTK_RESPONSE_CANCEL, + -1); + + if (tr_ctorGetDownloadDir (ctor, TR_FORCE, &str)) + g_assert_not_reached (); + g_assert (str); + + data = g_new0 (struct OpenData, 1); + data->core = core; + data->ctor = ctor; + data->filename = g_strdup (tr_ctorGetSourceFile (ctor)); + data->downloadDir = g_strdup (str); + data->file_list = gtr_file_list_new (core, 0); + str = _("Mo_ve .torrent file to the trash"); + data->trash_check = gtk_check_button_new_with_mnemonic (str); + str = _("_Start when added"); + data->run_check = gtk_check_button_new_with_mnemonic (str); + + w = data->priority_combo = gtr_priority_combo_new (); + gtr_priority_combo_set_value (GTK_COMBO_BOX (w), TR_PRI_NORMAL); + + g_signal_connect (G_OBJECT (d), "response", + G_CALLBACK (addResponseCB), data); + + row = 0; + grid = GTK_GRID (gtk_grid_new ()); + gtk_container_set_border_width (GTK_CONTAINER (grid), GUI_PAD_BIG); + gtk_grid_set_row_spacing (grid, GUI_PAD); + gtk_grid_set_column_spacing (grid, GUI_PAD_BIG); + + /* "torrent file" row */ + l = gtk_label_new_with_mnemonic (_("_Torrent file:")); + gtk_misc_set_alignment (GTK_MISC (l), 0.0f, 0.5f); + gtk_grid_attach (grid, l, 0, row, 1, 1); + w = gtk_file_chooser_button_new (_("Select Source File"), + GTK_FILE_CHOOSER_ACTION_OPEN); + source_chooser = w; + gtk_widget_set_hexpand (w, TRUE); + gtk_grid_attach_next_to (grid, w, l, GTK_POS_RIGHT, 1, 1); + gtk_label_set_mnemonic_widget (GTK_LABEL (l), w); + addTorrentFilters (GTK_FILE_CHOOSER (w)); + g_signal_connect (w, "selection-changed", + G_CALLBACK (sourceChanged), data); + + /* "destination folder" row */ + row++; + l = gtk_label_new_with_mnemonic (_("_Destination folder:")); + gtk_misc_set_alignment (GTK_MISC (l), 0.0f, 0.5f); + gtk_grid_attach (grid, l, 0, row, 1, 1); + w = gtk_file_chooser_button_new (_("Select Destination Folder"), + GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER); + if (!gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (w), + data->downloadDir)) + g_warning ("couldn't select '%s'", data->downloadDir); + list = get_recent_destinations (); + for (walk = list; walk; walk = walk->next) + gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (w), walk->data, NULL); + g_slist_free (list); + gtk_grid_attach_next_to (grid, w, l, GTK_POS_RIGHT, 1, 1); + gtk_label_set_mnemonic_widget (GTK_LABEL (l), w); + g_signal_connect (w, "selection-changed", + G_CALLBACK (downloadDirChanged), data); + + row++; + l = data->freespace_label = gtr_freespace_label_new (core, data->downloadDir); + gtk_widget_set_margin_bottom (l, GUI_PAD_BIG); + gtk_misc_set_alignment (GTK_MISC (l), 1.0f, 0.5f); + gtk_grid_attach (grid, l, 0, row, 2, 1); + + + /* file list row */ + row++; + w = data->file_list; + gtk_widget_set_vexpand (w, TRUE); + gtk_widget_set_size_request (w, 466u, 300u); + gtk_grid_attach (grid, w, 0, row, 2, 1); + + /* torrent priority row */ + row++; + l = gtk_label_new_with_mnemonic (_("Torrent _priority:")); + gtk_misc_set_alignment (GTK_MISC (l), 0.0f, 0.5f); + gtk_grid_attach (grid, l, 0, row, 1, 1); + w = data->priority_combo; + gtk_label_set_mnemonic_widget (GTK_LABEL (l), w); + gtk_grid_attach_next_to (grid, w, l, GTK_POS_RIGHT, 1, 1); + + /* torrent priority row */ + row++; + w = data->run_check; + if (tr_ctorGetPaused (ctor, TR_FORCE, &flag)) + g_assert_not_reached (); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), !flag); + gtk_grid_attach (grid, w, 0, row, 2, 1); + + /* "trash .torrent file" row */ + row++; + w = data->trash_check; + if (tr_ctorGetDeleteSource (ctor, &flag)) + g_assert_not_reached (); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), flag); + gtk_grid_attach (grid, w, 0, row, 2, 1); + + /* trigger sourceChanged, either directly or indirectly, + * so that it creates the tor/gtor objects */ + w = source_chooser; + if (data->filename) + gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (w), data->filename); + else + sourceChanged (GTK_FILE_CHOOSER_BUTTON (w), data); + + gtr_dialog_set_content (GTK_DIALOG (d), GTK_WIDGET (grid)); + w = gtk_dialog_get_widget_for_response (GTK_DIALOG (d), GTK_RESPONSE_ACCEPT); + gtk_widget_grab_focus (w); + return d; +} + +/**** +***** +****/ + +static void +onOpenDialogResponse (GtkDialog * dialog, int response, gpointer core) +{ + char * folder; + + /* remember this folder the next time we use this dialog */ + folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog)); + gtr_pref_string_set (TR_KEY_open_dialog_dir, folder); + g_free (folder); + + if (response == GTK_RESPONSE_ACCEPT) + { + GtkFileChooser * chooser = GTK_FILE_CHOOSER (dialog); + GtkWidget * w = gtk_file_chooser_get_extra_widget (chooser); + GtkToggleButton * tb = GTK_TOGGLE_BUTTON (w); + const gboolean do_start = gtr_pref_flag_get (TR_KEY_start_added_torrents); + const gboolean do_prompt = gtk_toggle_button_get_active (tb); + const gboolean do_notify = FALSE; + GSList * files = gtk_file_chooser_get_files (chooser); + + gtr_core_add_files (core, files, do_start, do_prompt, do_notify); + g_slist_foreach (files, (GFunc)g_object_unref, NULL); + g_slist_free (files); + } + + gtk_widget_destroy (GTK_WIDGET (dialog)); +} + +GtkWidget* +gtr_torrent_open_from_file_dialog_new (GtkWindow * parent, TrCore * core) +{ + GtkWidget * w; + GtkWidget * c; + const char * folder; + + w = gtk_file_chooser_dialog_new (_("Open a Torrent"), parent, + GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, + NULL); + gtk_dialog_set_alternative_button_order (GTK_DIALOG (w), + GTK_RESPONSE_ACCEPT, + GTK_RESPONSE_CANCEL, + -1); + gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (w), TRUE); + addTorrentFilters (GTK_FILE_CHOOSER (w)); + g_signal_connect (w, "response", G_CALLBACK (onOpenDialogResponse), core); + + if ((folder = gtr_pref_string_get (TR_KEY_open_dialog_dir))) + gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (w), folder); + + c = gtk_check_button_new_with_mnemonic (_("Show _options dialog")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (c), + gtr_pref_flag_get (TR_KEY_show_options_window)); + gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (w), c); + gtk_widget_show (c); + + return w; +} + +/*** +**** +***/ + +static void +onOpenURLResponse (GtkDialog * dialog, int response, gpointer user_data) +{ + bool handled = false; + + if (response == GTK_RESPONSE_ACCEPT) + { + GtkWidget * e = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), "url-entry")); + char * url = g_strdup (gtk_entry_get_text (GTK_ENTRY (e))); + g_strstrip (url); + + if (url) + { + handled = gtr_core_add_from_url (user_data, url); + if (!handled) + gtr_unrecognized_url_dialog (GTK_WIDGET (dialog), url); + g_free (url); + } + } + else if (response == GTK_RESPONSE_CANCEL) + { + handled = TRUE; + } + + if (handled) + gtk_widget_destroy (GTK_WIDGET (dialog)); +} + +GtkWidget* +gtr_torrent_open_from_url_dialog_new (GtkWindow * parent, TrCore * core) +{ + guint row; + GtkWidget * e; + GtkWidget * t; + GtkWidget * w; + + w = gtk_dialog_new_with_buttons (_("Open URL"), parent, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, + NULL); + gtk_dialog_set_alternative_button_order (GTK_DIALOG (w), + GTK_RESPONSE_ACCEPT, + GTK_RESPONSE_CANCEL, + -1); + g_signal_connect (w, "response", G_CALLBACK (onOpenURLResponse), core); + + row = 0; + t = hig_workarea_create (); + hig_workarea_add_section_title (t, &row, _("Open torrent from URL")); + e = gtk_entry_new (); + gtk_widget_set_size_request (e, 400, -1); + gtr_paste_clipboard_url_into_entry (e); + g_object_set_data (G_OBJECT (w), "url-entry", e); + hig_workarea_add_row (t, &row, _("_URL"), e, NULL); + + gtr_dialog_set_content (GTK_DIALOG (w), t); + + if (gtk_entry_get_text_length (GTK_ENTRY (e)) == 0) + gtk_widget_grab_focus (e); + else + gtk_widget_grab_focus (gtk_dialog_get_widget_for_response (GTK_DIALOG (w), GTK_RESPONSE_ACCEPT)); + + return w; +} diff --git a/release/src/router/transmission/gtk/relocate.c b/release/src/router/transmission/gtk/relocate.c index 441e462562..0705fda9f7 100644 --- a/release/src/router/transmission/gtk/relocate.c +++ b/release/src/router/transmission/gtk/relocate.c @@ -7,7 +7,7 @@ * This exemption does not extend to derived works not owned by * the Transmission project. * - * $Id: relocate.c 13761 2013-01-04 19:45:39Z jordan $ + * $Id: relocate.c 14132 2013-07-20 16:19:15Z jordan $ */ #include @@ -28,6 +28,7 @@ struct relocate_dialog_data { int done; bool do_move; + guint timer; TrCore * core; GSList * torrent_ids; GtkWidget * message_dialog; @@ -38,6 +39,7 @@ static void data_free (gpointer gdata) { struct relocate_dialog_data * data = gdata; + g_source_remove (data->timer); g_slist_free (data->torrent_ids); g_free (data); } @@ -85,7 +87,7 @@ onTimer (gpointer gdata) gtk_dialog_run (GTK_DIALOG (w)); gtk_widget_destroy (GTK_WIDGET (data->message_dialog)); } - else if (done == TR_LOC_DONE) + else if (done == TR_LOC_DONE) { if (data->torrent_ids != NULL) startMovingNextTorrent (data); @@ -127,8 +129,8 @@ onResponse (GtkDialog * dialog, int response, gpointer unused UNUSED) /* start the move and periodically check its status */ data->message_dialog = w; data->done = TR_LOC_DONE; + data->timer = gdk_threads_add_timeout_seconds (1, onTimer, data); onTimer (data); - gdk_threads_add_timeout_seconds (1, onTimer, data); } else { diff --git a/release/src/router/transmission/gtk/tr-core.c b/release/src/router/transmission/gtk/tr-core.c index f8f2143ea0..b19f26bd7b 100644 --- a/release/src/router/transmission/gtk/tr-core.c +++ b/release/src/router/transmission/gtk/tr-core.c @@ -1,5 +1,5 @@ /****************************************************************************** - * $Id: tr-core.c 14077 2013-05-22 20:35:38Z jordan $ + * $Id: tr-core.c 14133 2013-07-20 16:37:59Z jordan $ * * Copyright (c) Transmission authors and contributors * @@ -933,7 +933,7 @@ on_torrent_completeness_changed_idle (gpointer gdata) gtr_notify_torrent_completed (data->core, data->torrent_id); g_object_unref (G_OBJECT (data->core)); g_free (data); - return FALSE; + return G_SOURCE_REMOVE; } /* this is called in the libtransmission thread, *NOT* the GTK+ thread, @@ -1019,7 +1019,7 @@ on_torrent_metadata_changed_idle (gpointer gdata) /* cleanup */ g_object_unref (G_OBJECT (data->core)); g_free (data); - return FALSE; + return G_SOURCE_REMOVE; } /* this is called in the libtransmission thread, *NOT* the GTK+ thread, @@ -1746,7 +1746,7 @@ core_read_rpc_response_idle (void * vresponse) tr_variantFree (&top); evbuffer_free (response); - return FALSE; + return G_SOURCE_REMOVE; } static void diff --git a/release/src/router/transmission/gtk/tr-icon.c b/release/src/router/transmission/gtk/tr-icon.c index 7f408c7032..d2375b9c61 100644 --- a/release/src/router/transmission/gtk/tr-icon.c +++ b/release/src/router/transmission/gtk/tr-icon.c @@ -7,7 +7,7 @@ * This exemption does not extend to derived works not owned by * the Transmission project. * - * $Id: tr-icon.c 14115 2013-07-09 22:44:24Z jordan $ + * $Id: tr-icon.c 14142 2013-07-24 00:13:31Z jordan $ */ #include @@ -21,7 +21,7 @@ #include "tr-icon.h" #include "util.h" -static G_DEFINE_QUARK (tr-core, core) +static TR_DEFINE_QUARK (tr_core, core) #define ICON_NAME "transmission" diff --git a/release/src/router/transmission/gtk/tr-prefs.c b/release/src/router/transmission/gtk/tr-prefs.c index 087dc7b093..9269755298 100644 --- a/release/src/router/transmission/gtk/tr-prefs.c +++ b/release/src/router/transmission/gtk/tr-prefs.c @@ -7,7 +7,7 @@ * This exemption does not extend to derived works not owned by * the Transmission project. * - * $Id: tr-prefs.c 14059 2013-04-10 02:12:19Z jordan $ + * $Id: tr-prefs.c 14149 2013-07-27 18:20:32Z jordan $ */ #include /* isspace */ @@ -462,6 +462,7 @@ onBlocklistUpdateResponse (GtkDialog * dialog, gint response UNUSED, gpointer gd gtk_widget_set_sensitive (data->updateBlocklistButton, TRUE); data->updateBlocklistDialog = NULL; g_signal_handler_disconnect (data->core, data->updateBlocklistTag); + data->updateBlocklistTag = 0; } /* core says the blocklist was updated */ diff --git a/release/src/router/transmission/gtk/tr-window.c b/release/src/router/transmission/gtk/tr-window.c index 595ddba685..f4cedfcc66 100644 --- a/release/src/router/transmission/gtk/tr-window.c +++ b/release/src/router/transmission/gtk/tr-window.c @@ -1,5 +1,5 @@ /****************************************************************************** - * $Id: tr-window.c 14115 2013-07-09 22:44:24Z jordan $ + * $Id: tr-window.c 14142 2013-07-24 00:13:31Z jordan $ * * Copyright (c) Transmission authors and contributors * @@ -66,7 +66,7 @@ typedef struct } PrivateData; -static G_DEFINE_QUARK (private-data, private_data) +static TR_DEFINE_QUARK (private_data, private_data) static PrivateData* get_private_data (GtkWindow * w) @@ -361,7 +361,7 @@ onAltSpeedToggledIdle (gpointer vp) gboolean b = tr_sessionUsesAltSpeed (gtr_core_session (p->core)); gtr_core_set_pref_bool (p->core, TR_KEY_alt_speed_enabled, b); - return FALSE; + return G_SOURCE_REMOVE; } static void diff --git a/release/src/router/transmission/gtk/util.c b/release/src/router/transmission/gtk/util.c index ea121c282d..965553afb8 100644 --- a/release/src/router/transmission/gtk/util.c +++ b/release/src/router/transmission/gtk/util.c @@ -7,7 +7,7 @@ * This exemption does not extend to derived works not owned by * the Transmission project. * - * $Id: util.c 14115 2013-07-09 22:44:24Z jordan $ + * $Id: util.c 14143 2013-07-24 17:11:21Z jordan $ */ #include /* isxdigit () */ @@ -361,21 +361,11 @@ gtr_get_help_uri (void) void gtr_open_file (const char * path) { - char * uri; - - if (g_path_is_absolute (path)) - { - uri = g_strdup_printf ("file://%s", path); - } - else - { - char * cwd = g_get_current_dir (); - uri = g_strdup_printf ("file://%s/%s", cwd, path); - g_free (cwd); - } - + GFile * file = g_file_new_for_path (path); + gchar * uri = g_file_get_uri (file); gtr_open_uri (uri); g_free (uri); + g_object_unref (file); } void @@ -664,7 +654,7 @@ freespace_label_data_free (gpointer gdata) g_free (data); } -static G_DEFINE_QUARK (freespace-label-data, freespace_label_data) +static TR_DEFINE_QUARK (freespace_label_data, freespace_label_data) static void on_freespace_label_core_destroyed (gpointer gdata, GObject * dead_core G_GNUC_UNUSED) diff --git a/release/src/router/transmission/gtk/util.h b/release/src/router/transmission/gtk/util.h index 03c81cdd16..9526ad5a54 100644 --- a/release/src/router/transmission/gtk/util.h +++ b/release/src/router/transmission/gtk/util.h @@ -7,7 +7,7 @@ * This exemption does not extend to derived works not owned by * the Transmission project. * - * $Id: util.h 14077 2013-05-22 20:35:38Z jordan $ + * $Id: util.h 14142 2013-07-24 00:13:31Z jordan $ */ #ifndef GTR_UTIL_H @@ -37,6 +37,23 @@ extern const char * speed_M_str; extern const char * speed_G_str; extern const char * speed_T_str; +#if GLIB_CHECK_VERSION(2,33,12) + #define TR_DEFINE_QUARK G_DEFINE_QUARK +#else + #define TR_DEFINE_QUARK(QN, q_n) \ + GQuark \ + q_n##_quark (void) \ + { \ + static GQuark q; \ + \ + if G_UNLIKELY (q == 0) \ + q = g_quark_from_static_string (#QN); \ + \ + return q; \ + } +#endif + + /* macro to shut up "unused parameter" warnings */ #ifndef UNUSED #define UNUSED G_GNUC_UNUSED diff --git a/release/src/router/transmission/libtransmission/announcer-udp.c b/release/src/router/transmission/libtransmission/announcer-udp.c index 997f80b043..61c0113eef 100644 --- a/release/src/router/transmission/libtransmission/announcer-udp.c +++ b/release/src/router/transmission/libtransmission/announcer-udp.c @@ -7,7 +7,7 @@ * This exemption does not extend to derived works not owned by * the Transmission project. * - * $Id: announcer-udp.c 13965 2013-02-04 20:46:16Z jordan $ + * $Id: announcer-udp.c 14135 2013-07-20 23:29:42Z jordan $ */ #define __LIBTRANSMISSION_ANNOUNCER_MODULE___ @@ -680,7 +680,6 @@ tau_tracker_upkeep (struct tau_tracker * tracker) struct evutil_addrinfo hints; memset (&hints, 0, sizeof (hints)); hints.ai_family = AF_UNSPEC; - hints.ai_flags = EVUTIL_AI_CANONNAME; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; tracker->is_asking_dns = true; diff --git a/release/src/router/transmission/libtransmission/announcer.c b/release/src/router/transmission/libtransmission/announcer.c index 0ce9eb9027..d78afb1072 100644 --- a/release/src/router/transmission/libtransmission/announcer.c +++ b/release/src/router/transmission/libtransmission/announcer.c @@ -7,7 +7,7 @@ * This exemption does not extend to derived works not owned by * the Transmission project. * - * $Id: announcer.c 14124 2013-07-16 00:13:30Z jordan $ + * $Id: announcer.c 14138 2013-07-21 21:11:54Z jordan $ */ #include @@ -964,11 +964,12 @@ getRetryInterval (const tr_tracker * t) { switch (t->consecutiveFailures) { - case 0: return 20; - case 1: return tr_cryptoWeakRandInt (60) + (60 * 5); - case 2: return tr_cryptoWeakRandInt (60) + (60 * 15); - case 3: return tr_cryptoWeakRandInt (60) + (60 * 30); - case 4: return tr_cryptoWeakRandInt (60) + (60 * 60); + case 0: return 0; + case 1: return 20; + case 2: return tr_cryptoWeakRandInt (60) + (60 * 5); + case 3: return tr_cryptoWeakRandInt (60) + (60 * 15); + case 4: return tr_cryptoWeakRandInt (60) + (60 * 30); + case 5: return tr_cryptoWeakRandInt (60) + (60 * 60); default: return tr_cryptoWeakRandInt (60) + (60 * 120); } } diff --git a/release/src/router/transmission/libtransmission/bitfield.c b/release/src/router/transmission/libtransmission/bitfield.c index 0d0ac9ff15..a92e25f97b 100644 --- a/release/src/router/transmission/libtransmission/bitfield.c +++ b/release/src/router/transmission/libtransmission/bitfield.c @@ -7,7 +7,7 @@ * This exemption does not extend to derived works not owned by * the Transmission project. * - * $Id: bitfield.c 13655 2012-12-13 02:00:45Z jordan $ + * $Id: bitfield.c 14151 2013-07-29 04:19:15Z jordan $ */ #include @@ -179,9 +179,12 @@ set_all_true (uint8_t * array, size_t bit_count) const uint8_t val = 0xFF; const size_t n = get_bytes_needed (bit_count); - memset (array, val, n-1); + if (n > 0) + { + memset (array, val, n-1); - array[n-1] = val << (n*8 - bit_count); + array[n-1] = val << (n*8 - bit_count); + } } void* diff --git a/release/src/router/transmission/libtransmission/clients-test.c b/release/src/router/transmission/libtransmission/clients-test.c index 2139ec29e3..518d356c54 100644 --- a/release/src/router/transmission/libtransmission/clients-test.c +++ b/release/src/router/transmission/libtransmission/clients-test.c @@ -18,6 +18,7 @@ main (void) TEST_CLIENT ("-TR0072-", "Transmission 0.72"); TEST_CLIENT ("-TR111Z-", "Transmission 1.11+"); TEST_CLIENT ("O1008132", "Osprey 1.0.0"); + TEST_CLIENT ("TIX0193-", "Tixati 1.93"); /* gobbledygook */ TEST_CLIENT ("-IIO\x10\x2D\x04-", "-IIO%10-%04-"); diff --git a/release/src/router/transmission/libtransmission/clients.c b/release/src/router/transmission/libtransmission/clients.c index 541ca3e873..47c49db1c9 100644 --- a/release/src/router/transmission/libtransmission/clients.c +++ b/release/src/router/transmission/libtransmission/clients.c @@ -7,7 +7,7 @@ * This exemption does not extend to derived works not owned by * the Transmission project. * - * $Id: clients.c 13954 2013-02-04 16:23:33Z jordan $ + * $Id: clients.c 14152 2013-07-29 04:29:22Z jordan $ */ /* thanks amc1! */ @@ -415,8 +415,13 @@ tr_clientForId (char * buf, size_t buflen, const void * id_in) { four_digits (buf, buflen, "BT Next Evolution", id+3); } + else if (!memcmp (id, "TIX", 3)) + { + two_major_two_minor (buf, buflen, "Tixati", id+3); + } /* Shad0w-style */ + if (!*buf) { int a, b, c; if (strchr ("AOQRSTU", id[0]) diff --git a/release/src/router/transmission/libtransmission/completion.h b/release/src/router/transmission/libtransmission/completion.h index dd33b6b226..1b3f38329d 100644 --- a/release/src/router/transmission/libtransmission/completion.h +++ b/release/src/router/transmission/libtransmission/completion.h @@ -7,7 +7,7 @@ * This exemption does not extend to derived works not owned by * the Transmission project. * - * $Id: completion.h 13625 2012-12-05 17:29:46Z jordan $ + * $Id: completion.h 14151 2013-07-29 04:19:15Z jordan $ */ #ifndef __TRANSMISSION__ @@ -91,12 +91,14 @@ tr_cpHaveTotal (const tr_completion * cp) static inline bool tr_cpHasAll (const tr_completion * cp) { - return tr_bitfieldHasAll (&cp->blockBitfield); + return tr_torrentHasMetadata (cp->tor) + && tr_bitfieldHasAll (&cp->blockBitfield); } static inline bool tr_cpHasNone (const tr_completion * cp) { - return tr_bitfieldHasNone (&cp->blockBitfield); + return !tr_torrentHasMetadata (cp->tor) + || tr_bitfieldHasNone (&cp->blockBitfield); } /** diff --git a/release/src/router/transmission/libtransmission/fdlimit.c b/release/src/router/transmission/libtransmission/fdlimit.c index 3982d26ff3..389f804dbb 100644 --- a/release/src/router/transmission/libtransmission/fdlimit.c +++ b/release/src/router/transmission/libtransmission/fdlimit.c @@ -7,7 +7,7 @@ * This exemption does not extend to derived works not owned by * the Transmission project. * - * $Id: fdlimit.c 13905 2013-01-31 05:05:44Z jordan $ + * $Id: fdlimit.c 14147 2013-07-27 16:18:12Z jordan $ */ #ifdef HAVE_POSIX_FADVISE @@ -335,7 +335,8 @@ cached_file_open (struct tr_cached_file * o, { int flags; struct stat sb; - bool alreadyExisted; + bool already_existed; + bool resize_needed; /* create subfolders, if any */ if (writable) @@ -351,12 +352,16 @@ cached_file_open (struct tr_cached_file * o, tr_free (dir); } - alreadyExisted = !stat (filename, &sb) && S_ISREG (sb.st_mode); + already_existed = !stat (filename, &sb) && S_ISREG (sb.st_mode); - if (writable && !alreadyExisted && (allocation == TR_PREALLOCATE_FULL)) + if (writable && !already_existed && (allocation == TR_PREALLOCATE_FULL)) if (preallocate_file_full (filename, file_size)) tr_logAddDebug ("Preallocated file \"%s\"", filename); + /* we can't resize the file w/o write permissions */ + resize_needed = already_existed && (file_size < (uint64_t)sb.st_size); + writable |= resize_needed; + /* open the file */ flags = writable ? (O_RDWR | O_CREAT) : O_RDONLY; flags |= O_LARGEFILE | O_BINARY | O_SEQUENTIAL; @@ -375,17 +380,14 @@ cached_file_open (struct tr_cached_file * o, * http://trac.transmissionbt.com/ticket/2228 * https://bugs.launchpad.net/ubuntu/+source/transmission/+bug/318249 */ - if (alreadyExisted && (file_size < (uint64_t)sb.st_size)) + if (resize_needed && (ftruncate (o->fd, file_size) == -1)) { - if (ftruncate (o->fd, file_size) == -1) - { - const int err = errno; - tr_logAddError (_("Couldn't truncate \"%1$s\": %2$s"), filename, tr_strerror (err)); - return err; - } + const int err = errno; + tr_logAddError (_("Couldn't truncate \"%1$s\": %2$s"), filename, tr_strerror (err)); + return err; } - if (writable && !alreadyExisted && (allocation == TR_PREALLOCATE_SPARSE)) + if (writable && !already_existed && (allocation == TR_PREALLOCATE_SPARSE)) preallocate_file_sparse (o->fd, file_size); /* Many (most?) clients request blocks in ascending order, diff --git a/release/src/router/transmission/libtransmission/handshake.c b/release/src/router/transmission/libtransmission/handshake.c index 9c76d7a634..a7d9ea33ba 100644 --- a/release/src/router/transmission/libtransmission/handshake.c +++ b/release/src/router/transmission/libtransmission/handshake.c @@ -7,7 +7,7 @@ * This exemption does not extend to derived works not owned by * the Transmission project. * - * $Id: handshake.c 13933 2013-02-02 13:42:50Z jordan $ + * $Id: handshake.c 14155 2013-08-05 04:39:43Z jordan $ */ #include @@ -188,33 +188,49 @@ setReadState (tr_handshake * handshake, handshake_state_t state) setState (handshake, state); } -static void +static bool buildHandshakeMessage (tr_handshake * handshake, uint8_t * buf) { - uint8_t * walk = buf; - const uint8_t * torrentHash = tr_cryptoGetTorrentHash (handshake->crypto); - tr_torrent * tor = tr_torrentFindFromHash (handshake->session, torrentHash); - const unsigned char * peer_id = tr_torrentGetPeerId (tor); - - memcpy (walk, HANDSHAKE_NAME, HANDSHAKE_NAME_LEN); - walk += HANDSHAKE_NAME_LEN; - memset (walk, 0, HANDSHAKE_FLAGS_LEN); - HANDSHAKE_SET_LTEP (walk); - HANDSHAKE_SET_FASTEXT (walk); - - /* Note that this doesn't depend on whether the torrent is private. - * We don't accept DHT peers for a private torrent, - * but we participate in the DHT regardless. */ - if (tr_dhtEnabled (handshake->session)) - HANDSHAKE_SET_DHT (walk); - - walk += HANDSHAKE_FLAGS_LEN; - memcpy (walk, torrentHash, SHA_DIGEST_LENGTH); - walk += SHA_DIGEST_LENGTH; - memcpy (walk, peer_id, PEER_ID_LEN); - walk += PEER_ID_LEN; - - assert (walk - buf == HANDSHAKE_SIZE); + const unsigned char * peer_id = NULL; + const uint8_t * torrentHash; + tr_torrent * tor; + bool success; + + if ((torrentHash = tr_cryptoGetTorrentHash (handshake->crypto))) + if ((tor = tr_torrentFindFromHash (handshake->session, torrentHash))) + peer_id = tr_torrentGetPeerId (tor); + + if (peer_id == NULL) + { + success = false; + } + else + { + uint8_t * walk = buf; + + memcpy (walk, HANDSHAKE_NAME, HANDSHAKE_NAME_LEN); + walk += HANDSHAKE_NAME_LEN; + memset (walk, 0, HANDSHAKE_FLAGS_LEN); + HANDSHAKE_SET_LTEP (walk); + HANDSHAKE_SET_FASTEXT (walk); + + /* Note that this doesn't depend on whether the torrent is private. + * We don't accept DHT peers for a private torrent, + * but we participate in the DHT regardless. */ + if (tr_dhtEnabled (handshake->session)) + HANDSHAKE_SET_DHT (walk); + + walk += HANDSHAKE_FLAGS_LEN; + memcpy (walk, torrentHash, SHA_DIGEST_LENGTH); + walk += SHA_DIGEST_LENGTH; + memcpy (walk, peer_id, PEER_ID_LEN); + walk += PEER_ID_LEN; + + assert (walk - buf == HANDSHAKE_SIZE); + success = true; + } + + return success; } static int tr_handshakeDone (tr_handshake * handshake, @@ -455,7 +471,8 @@ readYb (tr_handshake * handshake, struct evbuffer * inbuf) /* ENCRYPT len (IA)), ENCRYPT (IA) */ { uint8_t msg[HANDSHAKE_SIZE]; - buildHandshakeMessage (handshake, msg); + if (!buildHandshakeMessage (handshake, msg)) + return tr_handshakeDone (handshake, false); evbuffer_add_uint16 (outbuf, sizeof (msg)); evbuffer_add (outbuf, msg, sizeof (msg)); @@ -670,7 +687,8 @@ readHandshake (tr_handshake * handshake, if (!handshake->haveSentBitTorrentHandshake) { uint8_t msg[HANDSHAKE_SIZE]; - buildHandshakeMessage (handshake, msg); + if (!buildHandshakeMessage (handshake, msg)) + return tr_handshakeDone (handshake, false); tr_peerIoWriteBytes (handshake->io, msg, sizeof (msg), false); handshake->haveSentBitTorrentHandshake = 1; } @@ -920,7 +938,8 @@ readIA (tr_handshake * handshake, /* send our handshake */ { uint8_t msg[HANDSHAKE_SIZE]; - buildHandshakeMessage (handshake, msg); + if (!buildHandshakeMessage (handshake, msg)) + return tr_handshakeDone (handshake, false); evbuffer_add (outbuf, msg, sizeof (msg)); handshake->haveSentBitTorrentHandshake = 1; diff --git a/release/src/router/transmission/libtransmission/platform-quota.c b/release/src/router/transmission/libtransmission/platform-quota.c index 035590e6fb..1b8a33bd29 100644 --- a/release/src/router/transmission/libtransmission/platform-quota.c +++ b/release/src/router/transmission/libtransmission/platform-quota.c @@ -18,7 +18,7 @@ #ifndef WIN32 #include /* types needed by quota.h */ - #ifdef __FreeBSD__ + #if defined(__FreeBSD__) || defined(__OpenBSD__) #include /* quotactl() */ #elif defined (__sun) #include /* quotactl */ @@ -203,7 +203,7 @@ getquota (const char * device) int64_t freespace; int64_t spaceused; -#if defined(__FreeBSD__) || defined(SYS_DARWIN) +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(SYS_DARWIN) if (quotactl(device, QCMD(Q_GETQUOTA, USRQUOTA), getuid(), (caddr_t) &dq) == 0) { #elif defined(__sun) @@ -235,7 +235,7 @@ getquota (const char * device) /* No quota enabled for this user */ return -1; } -#if defined(__FreeBSD__) +#if defined(__FreeBSD__) || defined(__OpenBSD__) spaceused = (int64_t) dq.dqb_curblocks >> 1; #elif defined(SYS_DARWIN) spaceused = (int64_t) dq.dqb_curbytes; diff --git a/release/src/router/transmission/libtransmission/resume.c b/release/src/router/transmission/libtransmission/resume.c index ba126b0c13..7d3ce40098 100644 --- a/release/src/router/transmission/libtransmission/resume.c +++ b/release/src/router/transmission/libtransmission/resume.c @@ -7,7 +7,7 @@ * This exemption does not extend to derived works not owned by * the Transmission project. * - * $Id: resume.c 14080 2013-05-23 03:20:18Z jordan $ + * $Id: resume.c 14136 2013-07-21 14:58:24Z jordan $ */ #include @@ -778,7 +778,7 @@ loadFromFile (tr_torrent * tor, uint64_t fieldsToLoad) if ((fieldsToLoad & TR_FR_RUN) && tr_variantDictFindBool (&top, TR_KEY_paused, &boolVal)) { - tor->isRunning = !boolVal; + tor->isRunning = !boolVal && !tor->isQueued; fieldsLoaded |= TR_FR_RUN; } diff --git a/release/src/router/transmission/libtransmission/rpcimpl.c b/release/src/router/transmission/libtransmission/rpcimpl.c index d91b49506f..120fb68950 100644 --- a/release/src/router/transmission/libtransmission/rpcimpl.c +++ b/release/src/router/transmission/libtransmission/rpcimpl.c @@ -7,7 +7,7 @@ * This exemption does not extend to derived works not owned by * the Transmission project. * - * $Id: rpcimpl.c 14116 2013-07-10 22:28:40Z jordan $ + * $Id: rpcimpl.c 14130 2013-07-20 15:37:13Z jordan $ */ #include @@ -181,11 +181,7 @@ getTorrents (tr_session * session, } else /* all of them */ { - tr_torrent * tor = NULL; - const int n = tr_sessionCountTorrents (session); - torrents = tr_new0 (tr_torrent *, n); - while ((tor = tr_torrentNext (session, tor))) - torrents[torrentCount++] = tor; + torrents = tr_sessionGetTorrents (session, &torrentCount); } *setmeCount = torrentCount; diff --git a/release/src/router/transmission/libtransmission/session.c b/release/src/router/transmission/libtransmission/session.c index 65dc413dfa..413897b9f5 100644 --- a/release/src/router/transmission/libtransmission/session.c +++ b/release/src/router/transmission/libtransmission/session.c @@ -7,7 +7,7 @@ * This exemption does not extend to derived works not owned by * the Transmission project. * - * $Id: session.c 14114 2013-07-09 17:05:32Z jordan $ + * $Id: session.c 14148 2013-07-27 17:48:59Z jordan $ */ #include @@ -1740,6 +1740,28 @@ tr_sessionCountTorrents (const tr_session * session) return tr_isSession (session) ? session->torrentCount : 0; } +tr_torrent ** +tr_sessionGetTorrents (tr_session * session, int * setme_n) +{ + int i; + int n; + tr_torrent ** torrents; + tr_torrent * tor; + + assert (tr_isSession (session)); + assert (setme_n != NULL); + + n = tr_sessionCountTorrents (session); + *setme_n = n; + + torrents = tr_new (tr_torrent *, n); + tor = NULL; + for (i=0; itorrentCount; - torrents = tr_new (tr_torrent *, session->torrentCount); - for (i=0; itorrentCount); + n = tr_sessionCountTorrents (session); + candidates = tr_new (struct TorrentAndPosition, n); i = 0; tor = NULL; while ((tor = tr_torrentNext (session, tor))) diff --git a/release/src/router/transmission/libtransmission/session.h b/release/src/router/transmission/libtransmission/session.h index 7b20d7f2d5..069189b251 100644 --- a/release/src/router/transmission/libtransmission/session.h +++ b/release/src/router/transmission/libtransmission/session.h @@ -7,7 +7,7 @@ * This exemption does not extend to derived works not owned by * the Transmission project. * - * $Id: session.h 14023 2013-02-15 01:52:47Z jordan $ + * $Id: session.h 14130 2013-07-20 15:37:13Z jordan $ */ #ifndef __TRANSMISSION__ @@ -263,6 +263,8 @@ struct tr_bindsockets * tr_sessionGetBindSockets (tr_session *); int tr_sessionCountTorrents (const tr_session * session); +tr_torrent ** tr_sessionGetTorrents (tr_session * session, int * setme_n); + enum { SESSION_MAGIC_NUMBER = 3845, diff --git a/release/src/router/transmission/libtransmission/torrent.c b/release/src/router/transmission/libtransmission/torrent.c index e0a8331450..e5d96c9d91 100644 --- a/release/src/router/transmission/libtransmission/torrent.c +++ b/release/src/router/transmission/libtransmission/torrent.c @@ -7,7 +7,7 @@ * This exemption does not extend to derived works not owned by * the Transmission project. * - * $Id: torrent.c 14125 2013-07-16 00:50:45Z jordan $ + * $Id: torrent.c 14156 2013-08-05 13:07:23Z jordan $ */ #include /* signal () */ @@ -17,7 +17,6 @@ #include /* wait () */ #else #include - #define waitpid(pid, status, options) _cwait (status, pid, WAIT_CHILD) #endif #include /* stat */ #include @@ -2073,7 +2072,18 @@ tr_torrentClearIdleLimitHitCallback (tr_torrent * torrent) static void onSigCHLD (int i UNUSED) { - waitpid (-1, NULL, WNOHANG); +#ifdef WIN32 + + _cwait (NULL, -1, WAIT_CHILD); + +#else + + int rc; + do + rc = waitpid (-1, NULL, WNOHANG); + while (rc>0 || (rc==-1 && errno==EINTR)); + +#endif } static void @@ -3390,20 +3400,14 @@ compareTorrentByQueuePosition (const void * va, const void * vb) static bool queueIsSequenced (tr_session * session) { - int i ; - int n ; - bool is_sequenced = true; - tr_torrent * tor; - tr_torrent ** tmp = tr_new (tr_torrent *, session->torrentCount); + int i; + int n; + bool is_sequenced; + tr_torrent ** torrents; - /* get all the torrents */ n = 0; - tor = NULL; - while ((tor = tr_torrentNext (session, tor))) - tmp[n++] = tor; - - /* sort them by position */ - qsort (tmp, n, sizeof (tr_torrent *), compareTorrentByQueuePosition); + torrents = tr_sessionGetTorrents (session, &n); + qsort (torrents, n, sizeof (tr_torrent *), compareTorrentByQueuePosition); #if 0 fprintf (stderr, "%s", "queue: "); @@ -3413,11 +3417,12 @@ queueIsSequenced (tr_session * session) #endif /* test them */ + is_sequenced = true; for (i=0; is_sequenced && iqueuePosition != i) + if (torrents[i]->queuePosition != i) is_sequenced = false; - tr_free (tmp); + tr_free (torrents); return is_sequenced; } #endif diff --git a/release/src/router/transmission/libtransmission/version.h b/release/src/router/transmission/libtransmission/version.h dissimilarity index 82% index 3439090c27..3a179bb681 100644 --- a/release/src/router/transmission/libtransmission/version.h +++ b/release/src/router/transmission/libtransmission/version.h @@ -1,10 +1,10 @@ -#define PEERID_PREFIX "-TR2810-" -#define USERAGENT_PREFIX "2.81" -#define SVN_REVISION "14128" -#define SVN_REVISION_NUM 14128 -#define SHORT_VERSION_STRING "2.81" -#define LONG_VERSION_STRING "2.81 (14128)" -#define VERSION_STRING_INFOPLIST 2.81 -#define MAJOR_VERSION 2 -#define MINOR_VERSION 81 -#define TR_STABLE_RELEASE 1 +#define PEERID_PREFIX "-TR2820-" +#define USERAGENT_PREFIX "2.82" +#define SVN_REVISION "14160" +#define SVN_REVISION_NUM 14160 +#define SHORT_VERSION_STRING "2.82" +#define LONG_VERSION_STRING "2.82 (14160)" +#define VERSION_STRING_INFOPLIST 2.82 +#define MAJOR_VERSION 2 +#define MINOR_VERSION 82 +#define TR_STABLE_RELEASE 1 diff --git a/release/src/router/transmission/libtransmission/web.c b/release/src/router/transmission/libtransmission/web.c index 310146e8e5..d79be0d1b2 100644 --- a/release/src/router/transmission/libtransmission/web.c +++ b/release/src/router/transmission/libtransmission/web.c @@ -7,9 +7,10 @@ * This exemption does not extend to derived works not owned by * the Transmission project. * - * $Id: web.c 14075 2013-05-22 19:02:07Z jordan $ + * $Id: web.c 14140 2013-07-24 00:00:03Z jordan $ */ +#include #include /* strlen (), strstr () */ #include /* getenv () */ @@ -494,12 +495,14 @@ tr_webThreadFunc (void * vsession) long req_bytes_sent; CURL * e = msg->easy_handle; curl_easy_getinfo (e, CURLINFO_PRIVATE, (void*)&task); + assert (e == task->curl_easy); curl_easy_getinfo (e, CURLINFO_RESPONSE_CODE, &task->code); curl_easy_getinfo (e, CURLINFO_REQUEST_SIZE, &req_bytes_sent); curl_easy_getinfo (e, CURLINFO_TOTAL_TIME, &total_time); task->did_connect = task->code>0 || req_bytes_sent>0; task->did_timeout = !task->code && (total_time >= task->timeout_secs); curl_multi_remove_handle (multi, e); + tr_list_remove_data (&paused_easy_handles, e); curl_easy_cleanup (e); tr_runInEventThread (task->session, task_finish_func, task); --taskCount; @@ -518,6 +521,7 @@ tr_webThreadFunc (void * vsession) } /* cleanup */ + tr_list_free (&paused_easy_handles, NULL); curl_multi_cleanup (multi); tr_lockFree (web->taskLock); tr_free (web->cookie_filename); diff --git a/release/src/router/transmission/libtransmission/webseed.c b/release/src/router/transmission/libtransmission/webseed.c index 24fcc7a44f..820e0bce9f 100644 --- a/release/src/router/transmission/libtransmission/webseed.c +++ b/release/src/router/transmission/libtransmission/webseed.c @@ -7,7 +7,7 @@ * This exemption does not extend to derived works not owned by * the Transmission project. * - * $Id: webseed.c 14070 2013-04-13 20:25:28Z jordan $ + * $Id: webseed.c 14134 2013-07-20 16:45:02Z jordan $ */ #include /* strlen () */ @@ -324,7 +324,7 @@ on_idle (tr_webseed * w) w->retry_challenge = running_tasks + w->idle_connections + 1; } - if (tor && tor->isRunning && !tr_torrentIsSeed (tor) && want) + if (tor && tor->isRunning && !tr_torrentIsSeed (tor) && (want > 0)) { int i; int got = 0; diff --git a/release/src/router/transmission/macosx/Controller.m b/release/src/router/transmission/macosx/Controller.m index d967ce87e9..e742d45dfe 100644 --- a/release/src/router/transmission/macosx/Controller.m +++ b/release/src/router/transmission/macosx/Controller.m @@ -1,5 +1,5 @@ /****************************************************************************** - * $Id: Controller.m 14044 2013-03-07 04:27:31Z livings124 $ + * $Id: Controller.m 14153 2013-08-03 01:24:42Z livings124 $ * * Copyright (c) 2005-2012 Transmission authors and contributors * @@ -255,7 +255,7 @@ static void sleepCallback(void * controller, io_service_t y, natural_t messageTy [fDefaults objectForKey: @"SpeedLimitAutoOffDate"]]); tr_variantDictAddInt(&settings, TR_KEY_alt_speed_time_day, [fDefaults integerForKey: @"SpeedLimitAutoDay"]); - tr_variantDictAddInt(&settings, TR_KEY_downloadSpeed, [fDefaults integerForKey: @"DownloadLimit"]); + tr_variantDictAddInt(&settings, TR_KEY_speed_limit_down, [fDefaults integerForKey: @"DownloadLimit"]); tr_variantDictAddBool(&settings, TR_KEY_speed_limit_down_enabled, [fDefaults boolForKey: @"CheckDownload"]); tr_variantDictAddInt(&settings, TR_KEY_speed_limit_up, [fDefaults integerForKey: @"UploadLimit"]); tr_variantDictAddBool(&settings, TR_KEY_speed_limit_up_enabled, [fDefaults boolForKey: @"CheckUpload"]); diff --git a/release/src/router/transmission/qt/README.txt b/release/src/router/transmission/qt/README.txt index 0053274a91..b0efa35c88 100644 --- a/release/src/router/transmission/qt/README.txt +++ b/release/src/router/transmission/qt/README.txt @@ -36,9 +36,9 @@ BUILDING ON OS X BUILDING ON UNIX - 1. Prerequisites: Qt >= 4.6 and its development packages + 1. Prerequisites: Qt >= 5 and its development packages 2. Build Transmission as normal - 3. In the qt/ directory, type "qmake qtr.pro" or "qmake-qt4 qtr.pro" + 3. In the qt/ directory, type "qmake qtr.pro" or "qmake-qt5 qtr.pro" 4. In the qt/ directory, type "make" 5. In the qt/ directory, as root, type "INSTALL_ROOT=/usr make install" (Feel free to replace /usr with /usr/local or /opt or whatever) diff --git a/release/src/router/transmission/qt/about.cc b/release/src/router/transmission/qt/about.cc index 5ab4528d81..6ab81a70ea 100644 --- a/release/src/router/transmission/qt/about.cc +++ b/release/src/router/transmission/qt/about.cc @@ -7,7 +7,7 @@ * * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * - * $Id: about.cc 13869 2013-01-26 01:19:54Z jordan $ + * $Id: about.cc 14150 2013-07-27 21:58:14Z jordan $ */ #include @@ -37,21 +37,21 @@ AboutDialog :: AboutDialog (QWidget * parent): QVBoxLayout * v = new QVBoxLayout (this); l = new QLabel; - l->setPixmap (QPixmap (QString::fromAscii (":/icons/transmission-48.png"))); + l->setPixmap (QPixmap (QString::fromUtf8 (":/icons/transmission-48.png"))); l->setAlignment (Qt::AlignCenter); v->addWidget (l); QFont f (font ()); f.setWeight (QFont::Bold); f.setPointSize (int (f.pointSize () * 1.2)); - l = new QLabel (tr ("Transmission %1").arg (QString::fromAscii (LONG_VERSION_STRING))); + l = new QLabel (tr ("Transmission %1").arg (QString::fromUtf8 (LONG_VERSION_STRING))); l->setAlignment (Qt::AlignCenter); l->setFont (f); l->setMargin (8); v->addWidget (l); l = new QLabel (tr ("A fast and easy BitTorrent client")); - l->setStyleSheet (QString::fromAscii ("text-align: center")); + l->setStyleSheet (QString::fromUtf8 ("text-align: center")); l->setAlignment (Qt::AlignCenter); v->addWidget (l); @@ -59,7 +59,7 @@ AboutDialog :: AboutDialog (QWidget * parent): l->setAlignment (Qt::AlignCenter); v->addWidget (l); - l = new QLabel (QString::fromAscii ("http://www.transmissionbt.com/")); + l = new QLabel (QString::fromUtf8 ("http://www.transmissionbt.com/")); l->setOpenExternalLinks (true); l->setAlignment (Qt::AlignCenter); v->addWidget (l); @@ -89,7 +89,7 @@ AboutDialog :: showCredits () QMessageBox::about ( this, tr ("Credits"), - QString::fromAscii ("Jordan Lee (Backend; Daemon; GTK+; Qt)\n" + QString::fromUtf8 ("Jordan Lee (Backend; Daemon; GTK+; Qt)\n" "Michell Livingston (OS X)\n")); } diff --git a/release/src/router/transmission/qt/add-data.cc b/release/src/router/transmission/qt/add-data.cc index 53c5783303..960c8d7e20 100644 --- a/release/src/router/transmission/qt/add-data.cc +++ b/release/src/router/transmission/qt/add-data.cc @@ -7,7 +7,7 @@ * * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * - * $Id: add-data.cc 13667 2012-12-14 04:34:42Z jordan $ + * $Id: add-data.cc 14150 2013-07-27 21:58:14Z jordan $ */ #include @@ -43,7 +43,7 @@ AddData :: set( const QString& key ) } else if( Utils::isHexHashcode( key ) ) { - magnet = QString::fromAscii("magnet:?xt=urn:btih:") + key; + magnet = QString::fromUtf8("magnet:?xt=urn:btih:") + key; type = MAGNET; } else diff --git a/release/src/router/transmission/qt/app.cc b/release/src/router/transmission/qt/app.cc index cfea6d45dd..92b882b280 100644 --- a/release/src/router/transmission/qt/app.cc +++ b/release/src/router/transmission/qt/app.cc @@ -7,7 +7,7 @@ * * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * - * $Id: app.cc 14002 2013-02-09 23:11:17Z jordan $ + * $Id: app.cc 14150 2013-07-27 21:58:14Z jordan $ */ #include @@ -45,9 +45,9 @@ namespace { - const QString DBUS_SERVICE = QString::fromAscii ("com.transmissionbt.Transmission" ); - const QString DBUS_OBJECT_PATH = QString::fromAscii ("/com/transmissionbt/Transmission"); - const QString DBUS_INTERFACE = QString::fromAscii ("com.transmissionbt.Transmission" ); + const QString DBUS_SERVICE = QString::fromUtf8 ("com.transmissionbt.Transmission" ); + const QString DBUS_OBJECT_PATH = QString::fromUtf8 ("/com/transmissionbt/Transmission"); + const QString DBUS_INTERFACE = QString::fromUtf8 ("com.transmissionbt.Transmission" ); const char * MY_READABLE_NAME ("transmission-qt"); @@ -89,7 +89,7 @@ MyApp :: MyApp (int& argc, char ** argv): QApplication (argc, argv), myLastFullUpdateTime (0) { - const QString MY_CONFIG_NAME = QString::fromAscii ("transmission"); + const QString MY_CONFIG_NAME = QString::fromUtf8 ("transmission"); setApplicationName (MY_CONFIG_NAME); @@ -108,7 +108,7 @@ MyApp :: MyApp (int& argc, char ** argv): QList sizes; sizes << 16 << 22 << 24 << 32 << 48 << 64 << 72 << 96 << 128 << 192 << 256; foreach (int size, sizes) - icon.addPixmap (QPixmap (QString::fromAscii (":/icons/transmission-%1.png").arg (size))); + icon.addPixmap (QPixmap (QString::fromUtf8 (":/icons/transmission-%1.png").arg (size))); setWindowIcon (icon); // parse the command-line arguments @@ -464,15 +464,15 @@ MyApp :: raise () bool MyApp :: notify (const QString& title, const QString& body) const { - const QString dbusServiceName = QString::fromAscii ("org.freedesktop.Notifications"); - const QString dbusInterfaceName = QString::fromAscii ("org.freedesktop.Notifications"); - const QString dbusPath = QString::fromAscii ("/org/freedesktop/Notifications"); + const QString dbusServiceName = QString::fromUtf8 ("org.freedesktop.Notifications"); + const QString dbusInterfaceName = QString::fromUtf8 ("org.freedesktop.Notifications"); + const QString dbusPath = QString::fromUtf8 ("/org/freedesktop/Notifications"); - QDBusMessage m = QDBusMessage::createMethodCall (dbusServiceName, dbusPath, dbusInterfaceName, QString::fromAscii ("Notify")); + QDBusMessage m = QDBusMessage::createMethodCall (dbusServiceName, dbusPath, dbusInterfaceName, QString::fromUtf8 ("Notify")); QList args; - args.append (QString::fromAscii ("Transmission")); // app_name + args.append (QString::fromUtf8 ("Transmission")); // app_name args.append (0U); // replaces_id - args.append (QString::fromAscii ("transmission")); // icon + args.append (QString::fromUtf8 ("transmission")); // icon args.append (title); // summary args.append (body); // body args.append (QStringList ()); // actions - unused for plain passive popups @@ -510,7 +510,7 @@ main (int argc, char * argv[]) QDBusMessage request = QDBusMessage::createMethodCall (DBUS_SERVICE, DBUS_OBJECT_PATH, DBUS_INTERFACE, - QString::fromAscii ("AddMetainfo")); + QString::fromUtf8 ("AddMetainfo")); QList arguments; AddData a (addme[i]); switch (a.type) diff --git a/release/src/router/transmission/qt/details.cc b/release/src/router/transmission/qt/details.cc index c32ac94354..6deecc8eda 100644 --- a/release/src/router/transmission/qt/details.cc +++ b/release/src/router/transmission/qt/details.cc @@ -7,7 +7,7 @@ * * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * - * $Id: details.cc 13943 2013-02-03 19:13:04Z jordan $ + * $Id: details.cc 14150 2013-07-27 21:58:14Z jordan $ */ #include @@ -867,7 +867,7 @@ Details :: refresh () foreach (QChar ch, code) { QString txt; - switch (ch.toAscii ()) + switch (ch.unicode ()) { case 'O': txt = tr ("Optimistic unchoke"); break; case 'D': txt = tr ("Downloading from this peer"); break; diff --git a/release/src/router/transmission/qt/favicon.cc b/release/src/router/transmission/qt/favicon.cc index c6d1bbb758..72c29d3d44 100644 --- a/release/src/router/transmission/qt/favicon.cc +++ b/release/src/router/transmission/qt/favicon.cc @@ -7,14 +7,14 @@ * * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * - * $Id: favicon.cc 11522 2010-12-12 16:43:19Z charles $ + * $Id: favicon.cc 14150 2013-07-27 21:58:14Z jordan $ */ -#include #include #include #include #include +#include #include "favicon.h" @@ -40,7 +40,7 @@ Favicons :: ~Favicons( ) QString Favicons :: getCacheDir( ) { - const QString base = QDesktopServices::storageLocation( QDesktopServices::CacheLocation ); + const QString base = QStandardPaths::writableLocation (QStandardPaths::CacheLocation); return QDir( base ).absoluteFilePath( "favicons" ); } diff --git a/release/src/router/transmission/qt/file-tree.cc b/release/src/router/transmission/qt/file-tree.cc index bb9ba35d58..2ff609b340 100644 --- a/release/src/router/transmission/qt/file-tree.cc +++ b/release/src/router/transmission/qt/file-tree.cc @@ -7,7 +7,7 @@ * * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * - * $Id: file-tree.cc 14073 2013-04-24 22:56:28Z jordan $ + * $Id: file-tree.cc 14150 2013-07-27 21:58:14Z jordan $ */ #include @@ -436,7 +436,6 @@ FileTreeModel :: setData (const QModelIndex& index, const QVariant& newname, int if (role == Qt::EditRole) { QString oldpath; - QModelIndex walk = index; FileTreeItem * item = itemFromIndex (index); while (item && !item->name().isEmpty()) @@ -575,9 +574,9 @@ FileTreeModel :: clearSubtree (const QModelIndex& top) void FileTreeModel :: clear () { + beginResetModel (); clearSubtree (QModelIndex()); - - reset (); + endResetModel (); } FileTreeItem * @@ -613,7 +612,7 @@ FileTreeModel :: addFile (int fileIndex, { bool added = false; FileTreeItem * item; - QStringList tokens = filename.split (QChar::fromAscii('/')); + QStringList tokens = filename.split (QChar::fromLatin1('/')); item = findItemForFileIndex (fileIndex); @@ -886,7 +885,7 @@ FileTreeView :: FileTreeView (QWidget * parent, bool isEditable): for (int i=0; isetResizeMode(i, QHeaderView::Interactive); + header()->setSectionResizeMode(i, QHeaderView::Interactive); } connect (this, SIGNAL(clicked(const QModelIndex&)), diff --git a/release/src/router/transmission/qt/filterbar.cc b/release/src/router/transmission/qt/filterbar.cc index 5a49134ccf..dac8302d31 100644 --- a/release/src/router/transmission/qt/filterbar.cc +++ b/release/src/router/transmission/qt/filterbar.cc @@ -7,9 +7,15 @@ * * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * - * $Id: filterbar.cc 13939 2013-02-03 12:31:44Z jordan $ + * $Id: filterbar.cc 14150 2013-07-27 21:58:14Z jordan $ */ +#include +#include +#include +#include +#include +#include #include #include diff --git a/release/src/router/transmission/qt/freespace-label.cc b/release/src/router/transmission/qt/freespace-label.cc index ec98576c38..3a612d3c2c 100644 --- a/release/src/router/transmission/qt/freespace-label.cc +++ b/release/src/router/transmission/qt/freespace-label.cc @@ -73,6 +73,8 @@ FreespaceLabel :: onTimer () void FreespaceLabel :: onSessionExecuted (int64_t tag, const QString& result, struct tr_variant * arguments) { + Q_UNUSED (result); + if (tag != myTag) return; diff --git a/release/src/router/transmission/qt/freespace-label.h b/release/src/router/transmission/qt/freespace-label.h index d280ed2e8f..e79cc9c461 100644 --- a/release/src/router/transmission/qt/freespace-label.h +++ b/release/src/router/transmission/qt/freespace-label.h @@ -16,7 +16,7 @@ #include #include -#include +#include class Session; diff --git a/release/src/router/transmission/qt/mainwin.cc b/release/src/router/transmission/qt/mainwin.cc index 0a0d8c5462..2696dc6e23 100644 --- a/release/src/router/transmission/qt/mainwin.cc +++ b/release/src/router/transmission/qt/mainwin.cc @@ -7,13 +7,17 @@ * * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * - * $Id: mainwin.cc 14098 2013-06-26 01:48:47Z jordan $ + * $Id: mainwin.cc 14150 2013-07-27 21:58:14Z jordan $ */ #include #include #include +#include +#include +#include +#include #include #include diff --git a/release/src/router/transmission/qt/make-dialog.cc b/release/src/router/transmission/qt/make-dialog.cc index ffa666d922..5d14250102 100644 --- a/release/src/router/transmission/qt/make-dialog.cc +++ b/release/src/router/transmission/qt/make-dialog.cc @@ -7,7 +7,7 @@ * * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * - * $Id: make-dialog.cc 13859 2013-01-24 15:34:45Z jordan $ + * $Id: make-dialog.cc 14150 2013-07-27 21:58:14Z jordan $ */ #include @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -342,7 +343,7 @@ MakeDialog :: MakeDialog( Session & session, QWidget * parent ): const QPixmap folderPixmap = folderIcon.pixmap( iconSize ); QPushButton * b = new QPushButton; b->setIcon( folderPixmap ); - b->setStyleSheet( QString::fromAscii( "text-align: left; padding-left: 5; padding-right: 5" ) ); + b->setStyleSheet( QString::fromUtf8( "text-align: left; padding-left: 5; padding-right: 5" ) ); myDestination = QDir::homePath(); b->setText( myDestination ); connect( b, SIGNAL(clicked(bool)), @@ -356,7 +357,7 @@ MakeDialog :: MakeDialog( Session & session, QWidget * parent ): myFolderButton = new QPushButton; myFolderButton->setIcon( folderPixmap ); myFolderButton->setText( tr( "(None)" ) ); - myFolderButton->setStyleSheet( QString::fromAscii( "text-align: left; padding-left: 5; padding-right: 5" ) ); + myFolderButton->setStyleSheet( QString::fromUtf8( "text-align: left; padding-left: 5; padding-right: 5" ) ); connect( myFolderButton, SIGNAL(clicked(bool)), this, SLOT(onFolderClicked(void)) ); hig->addRow( myFolderRadio, myFolderButton ); @@ -371,7 +372,7 @@ MakeDialog :: MakeDialog( Session & session, QWidget * parent ): myFileButton = new QPushButton; myFileButton->setText( tr( "(None)" ) ); myFileButton->setIcon( filePixmap ); - myFileButton->setStyleSheet( QString::fromAscii( "text-align: left; padding-left: 5; padding-right: 5" ) ); + myFileButton->setStyleSheet( QString::fromUtf8( "text-align: left; padding-left: 5; padding-right: 5" ) ); connect( myFileButton, SIGNAL(clicked(bool)), this, SLOT(onFileClicked(void)) ); hig->addRow( myFileRadio, myFileButton ); @@ -384,7 +385,7 @@ MakeDialog :: MakeDialog( Session & session, QWidget * parent ): hig->addSectionTitle( tr( "Properties" ) ); hig->addWideControl( myTrackerEdit = new ShortPlainTextEdit ); - const int height = fontMetrics().size( 0, QString::fromAscii("\n\n\n\n") ).height( ); + const int height = fontMetrics().size( 0, QString::fromUtf8("\n\n\n\n") ).height( ); myTrackerEdit->setMinimumHeight( height ); hig->addTallRow( tr( "&Trackers:" ), myTrackerEdit ); QLabel * l = new QLabel( tr( "To add a backup URL, add it on the line after the primary URL.\nTo add another primary URL, add it after a blank line." ) ); diff --git a/release/src/router/transmission/qt/options.cc b/release/src/router/transmission/qt/options.cc index 969ee1b8ae..2445de1635 100644 --- a/release/src/router/transmission/qt/options.cc +++ b/release/src/router/transmission/qt/options.cc @@ -7,7 +7,7 @@ * * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * - * $Id: options.cc 14010 2013-02-10 22:44:25Z jordan $ + * $Id: options.cc 14150 2013-07-27 21:58:14Z jordan $ */ #include @@ -124,7 +124,7 @@ Options :: Options (Session& session, const Prefs& prefs, const AddData& addme, { p = mySourceButton = new QPushButton; p->setIcon (filePixmap); - p->setStyleSheet (QString::fromAscii ("text-align: left; padding-left: 5; padding-right: 5")); + p->setStyleSheet (QString::fromUtf8 ("text-align: left; padding-left: 5; padding-right: 5")); p->installEventFilter (this); w = p; connect (p, SIGNAL (clicked (bool)), this, SLOT (onFilenameClicked ())); @@ -139,7 +139,7 @@ Options :: Options (Session& session, const Prefs& prefs, const AddData& addme, connect (e, SIGNAL(editingFinished()), this, SLOT(onSourceEditingFinished())); } - const int width = fontMetrics.size (0, QString::fromAscii ("This is a pretty long torrent filename indeed.torrent")).width (); + const int width = fontMetrics.size (0, QString::fromUtf8 ("This is a pretty long torrent filename indeed.torrent")).width (); w->setMinimumWidth (width); layout->addWidget (w, row, 1); l->setBuddy (w); diff --git a/release/src/router/transmission/qt/prefs-dialog.cc b/release/src/router/transmission/qt/prefs-dialog.cc index f3c4123f0d..6bd8076036 100644 --- a/release/src/router/transmission/qt/prefs-dialog.cc +++ b/release/src/router/transmission/qt/prefs-dialog.cc @@ -7,7 +7,7 @@ * * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * - * $Id: prefs-dialog.cc 13991 2013-02-09 04:05:03Z jordan $ + * $Id: prefs-dialog.cc 14150 2013-07-27 21:58:14Z jordan $ */ #include @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -135,7 +134,7 @@ PrefsDialog :: timeEditNew( int key ) { const int minutes( myPrefs.getInt( key ) ); QTimeEdit * e = new QTimeEdit( ); - e->setDisplayFormat( QString::fromAscii( "hh:mm" ) ); + e->setDisplayFormat( QString::fromUtf8( "hh:mm" ) ); e->setProperty( PREF_KEY, key ); e->setTime( QTime().addSecs( minutes * 60 ) ); myWidgets.insert( key, e ); @@ -233,11 +232,11 @@ PrefsDialog :: createSpeedTab( ) QHBoxLayout * h = new QHBoxLayout; h->setSpacing( HIG :: PAD ); QLabel * label = new QLabel; - label->setPixmap( QPixmap( QString::fromAscii( ":/icons/alt-limit-off.png" ) ) ); + label->setPixmap( QPixmap( QString::fromUtf8( ":/icons/alt-limit-off.png" ) ) ); label->setAlignment( Qt::AlignLeft|Qt::AlignVCenter ); h->addWidget( label ); label = new QLabel( tr( "Alternative Speed Limits" ) ); - label->setStyleSheet( QString::fromAscii( "font: bold" ) ); + label->setStyleSheet( QString::fromUtf8( "font: bold" ) ); label->setAlignment( Qt::AlignLeft|Qt::AlignVCenter ); h->addWidget( label ); hig->addSectionTitle( h ); @@ -572,7 +571,7 @@ PrefsDialog :: createDownloadingTab( ) l = checkBoxNew( tr( "Automatically add .torrent files &from:" ), Prefs::DIR_WATCH_ENABLED ); b = myWatchButton = new QPushButton; b->setIcon( folderPixmap ); - b->setStyleSheet( QString::fromAscii( "text-align: left; padding-left: 5; padding-right: 5" ) ); + b->setStyleSheet( QString::fromUtf8( "text-align: left; padding-left: 5; padding-right: 5" ) ); connect( b, SIGNAL(clicked(bool)), this, SLOT(onWatchClicked(void)) ); hig->addRow( l, b ); enableBuddyWhenChecked( qobject_cast(l), b ); @@ -585,7 +584,7 @@ PrefsDialog :: createDownloadingTab( ) b = myDestinationButton = new QPushButton; b->setIcon( folderPixmap ); - b->setStyleSheet( QString::fromAscii( "text-align: left; padding-left: 5; padding-right: 5" ) ); + b->setStyleSheet( QString::fromUtf8( "text-align: left; padding-left: 5; padding-right: 5" ) ); connect( b, SIGNAL(clicked(bool)), this, SLOT(onDestinationClicked(void)) ); hig->addRow( tr( "Save to &Location:" ), b ); @@ -610,7 +609,7 @@ PrefsDialog :: createDownloadingTab( ) l = myIncompleteCheckbox = checkBoxNew( tr( "Keep &incomplete files in:" ), Prefs::INCOMPLETE_DIR_ENABLED ); b = myIncompleteButton = new QPushButton; b->setIcon( folderPixmap ); - b->setStyleSheet( QString::fromAscii( "text-align: left; padding-left: 5; padding-right: 5" ) ); + b->setStyleSheet( QString::fromUtf8( "text-align: left; padding-left: 5; padding-right: 5" ) ); connect( b, SIGNAL(clicked(bool)), this, SLOT(onIncompleteClicked(void)) ); hig->addRow( myIncompleteCheckbox, b ); enableBuddyWhenChecked( qobject_cast(l), b ); @@ -618,7 +617,7 @@ PrefsDialog :: createDownloadingTab( ) l = myTorrentDoneScriptCheckbox = checkBoxNew( tr( "Call scrip&t when torrent is completed:" ), Prefs::SCRIPT_TORRENT_DONE_ENABLED ); b = myTorrentDoneScriptButton = new QPushButton; b->setIcon( filePixmap ); - b->setStyleSheet( QString::fromAscii( "text-align: left; padding-left: 5; padding-right: 5" ) ); + b->setStyleSheet( QString::fromUtf8( "text-align: left; padding-left: 5; padding-right: 5" ) ); connect( b, SIGNAL(clicked(bool)), this, SLOT(onScriptClicked(void)) ); hig->addRow( myTorrentDoneScriptCheckbox, b ); enableBuddyWhenChecked( qobject_cast(l), b ); diff --git a/release/src/router/transmission/qt/qtr.pro b/release/src/router/transmission/qt/qtr.pro index aaae24441f..27dc22b9d6 100644 --- a/release/src/router/transmission/qt/qtr.pro +++ b/release/src/router/transmission/qt/qtr.pro @@ -1,7 +1,7 @@ TARGET = transmission-qt NAME = "Transmission" DESCRIPTION = "Transmission: a fast, easy, and free BitTorrent client" -VERSION = 2.00 +VERSION = 2.81 LICENSE = "GPL" target.path = /bin @@ -11,8 +11,8 @@ unix: INSTALLS += man man.path = /share/man/man1/ man.files = transmission-qt.1 -CONFIG += qt qdbus thread debug link_pkgconfig -QT += network +CONFIG += qt thread debug link_pkgconfig +QT += network dbus widgets PKGCONFIG = fontconfig libcurl openssl libevent TRANSMISSION_TOP = .. diff --git a/release/src/router/transmission/qt/session.cc b/release/src/router/transmission/qt/session.cc index f39877566f..6c365a8d28 100644 --- a/release/src/router/transmission/qt/session.cc +++ b/release/src/router/transmission/qt/session.cc @@ -7,7 +7,7 @@ * * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * - * $Id: session.cc 13991 2013-02-09 04:05:03Z jordan $ + * $Id: session.cc 14150 2013-07-27 21:58:14Z jordan $ */ #include @@ -690,11 +690,11 @@ Session :: exec (const char * json) { QNetworkRequest request; request.setUrl (myUrl); - request.setRawHeader ("User-Agent", QString (QCoreApplication::instance ()->applicationName () + "/" + LONG_VERSION_STRING).toAscii ()); + request.setRawHeader ("User-Agent", QString (QCoreApplication::instance ()->applicationName () + "/" + LONG_VERSION_STRING).toUtf8 ()); request.setRawHeader ("Content-Type", "application/json; charset=UTF-8"); if (!mySessionId.isEmpty ()) - request.setRawHeader (TR_RPC_SESSION_ID_HEADER, mySessionId.toAscii ()); + request.setRawHeader (TR_RPC_SESSION_ID_HEADER, mySessionId.toUtf8 ()); const QByteArray requestData (json); QNetworkReply * reply = networkAccessManager ()->post (request, requestData); diff --git a/release/src/router/transmission/qt/squeezelabel.h b/release/src/router/transmission/qt/squeezelabel.h index 3c254702db..b5c0b7b283 100644 --- a/release/src/router/transmission/qt/squeezelabel.h +++ b/release/src/router/transmission/qt/squeezelabel.h @@ -42,7 +42,7 @@ #ifndef SQUEEZELABEL_H #define SQUEEZELABEL_H -#include +#include class SqueezeLabel : public QLabel { diff --git a/release/src/router/transmission/qt/torrent-model.cc b/release/src/router/transmission/qt/torrent-model.cc index 56c1e724ee..832aaf4d7b 100644 --- a/release/src/router/transmission/qt/torrent-model.cc +++ b/release/src/router/transmission/qt/torrent-model.cc @@ -7,7 +7,7 @@ * * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * - * $Id: torrent-model.cc 13982 2013-02-07 21:07:16Z jordan $ + * $Id: torrent-model.cc 14150 2013-07-27 21:58:14Z jordan $ */ #include @@ -22,11 +22,14 @@ void TorrentModel :: clear( ) { + beginResetModel (); + myIdToRow.clear( ); myIdToTorrent.clear( ); foreach( Torrent * tor, myTorrents ) delete tor; myTorrents.clear( ); - reset( ); + + endResetModel (); } int diff --git a/release/src/router/transmission/qt/utils.h b/release/src/router/transmission/qt/utils.h index a0654f3d65..a8e5bf681f 100644 --- a/release/src/router/transmission/qt/utils.h +++ b/release/src/router/transmission/qt/utils.h @@ -7,7 +7,7 @@ * * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * - * $Id: utils.h 13448 2012-08-19 16:12:20Z jordan $ + * $Id: utils.h 14150 2013-07-27 21:58:14Z jordan $ */ #ifndef QTR_UTILS @@ -42,20 +42,20 @@ class Utils: public QObject /// URLs /// - static bool isMagnetLink( const QString& s ) { return s.startsWith( QString::fromAscii( "magnet:?" ) ); } + static bool isMagnetLink( const QString& s ) { return s.startsWith( QString::fromUtf8( "magnet:?" ) ); } static bool isHexHashcode( const QString& s ) { if( s.length() != 40 ) return false; - foreach( QChar ch, s ) if( !isxdigit( ch.toAscii() ) ) return false; + foreach( QChar ch, s ) if( !isxdigit( ch.unicode() ) ) return false; return true; } static bool isUriWithSupportedScheme( const QString& s ) { - static const QString ftp = QString::fromAscii( "ftp://" ); - static const QString http = QString::fromAscii( "http://" ); - static const QString https = QString::fromAscii( "https://" ); + static const QString ftp = QString::fromUtf8( "ftp://" ); + static const QString http = QString::fromUtf8( "http://" ); + static const QString https = QString::fromUtf8( "https://" ); return s.startsWith(http) || s.startsWith(https) || s.startsWith(ftp); } diff --git a/release/src/router/transmission/qt/watchdir.cc b/release/src/router/transmission/qt/watchdir.cc index 4691eae7f9..ff51c391fa 100644 --- a/release/src/router/transmission/qt/watchdir.cc +++ b/release/src/router/transmission/qt/watchdir.cc @@ -7,7 +7,7 @@ * * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * - * $Id: watchdir.cc 12697 2011-08-20 05:19:27Z jordan $ + * $Id: watchdir.cc 14150 2013-07-27 21:58:14Z jordan $ */ #include @@ -52,7 +52,7 @@ WatchDir :: metainfoTest( const QString& filename ) const const int err = tr_torrentParse( ctor, &inf ); if( err ) ret = ERROR; - else if( myModel.hasTorrent( QString::fromAscii( inf.hashString ) ) ) + else if( myModel.hasTorrent( QString::fromUtf8( inf.hashString ) ) ) ret = DUPLICATE; else ret = OK; @@ -106,7 +106,7 @@ WatchDir :: watcherActivated( const QString& path ) // try to add any new files which end in .torrent const QSet newFiles( files - myWatchDirFiles ); - const QString torrentSuffix = QString::fromAscii( ".torrent" ); + const QString torrentSuffix = QString::fromUtf8( ".torrent" ); foreach( QString name, newFiles ) { if( name.endsWith( torrentSuffix, Qt::CaseInsensitive ) ) { const QString filename = dir.absoluteFilePath( name ); diff --git a/release/src/router/transmission/web/index.html b/release/src/router/transmission/web/index.html index 6483c1691a..5b8027a308 100755 --- a/release/src/router/transmission/web/index.html +++ b/release/src/router/transmission/web/index.html @@ -2,8 +2,8 @@ - - + + -- 2.11.4.GIT