printf (" Configuration directory: %s\n", str);
if (tr_variantDictFindStr (args, TR_KEY_download_dir, &str, NULL))
printf (" Download directory: %s\n", str);
- if (tr_variantDictFindInt (args, TR_KEY_download_dir_free_space, &i))
- printf (" Download directory free space: %s\n", strlsize (buf, i, sizeof buf));
if (tr_variantDictFindInt (args, TR_KEY_peer_port, &i))
printf (" Listenport: %" PRId64 "\n", i);
if (tr_variantDictFindBool (args, TR_KEY_port_forwarding_enabled, &boolVal))
"cache-size-mb" | number | maximum size of the disk cache (MB)
"config-dir" | string | location of transmission's configuration directory
"download-dir" | string | default path to download torrents
- "download-dir-free-space" | number | number of free bytes available in download-dir, or -1 if it can't be calculated
"download-queue-size" | number | max number of torrents to download at once (see download-queue-enabled)
"download-queue-enabled" | boolean | if true, limit how many torrents can be downloaded at once
"dht-enabled" | boolean | true means allow dht in public torrents
Method name: "session-set"
Request arguments: one or more of 4.1's arguments, except: "blocklist-size",
- "config-dir", "download-dir-free-space", "rpc-version",
- "rpc-version-minimum", and "version"
+ "config-dir", "rpc-version", "rpc-version-minimum", and
+ "version"
Response arguments: none
4.1.2. Accessors
Response arguments: none
+4.7. Free Space
+
+ This method tests how much free space is available in a
+ client-specified folder.
+
+ Method name: "free-space"
+
+ Request arguments:
+
+ string | value type & description
+ ------------+----------------------------------------------------------
+ "path" | string the directory to query
+
+ Response arguments:
+
+ string | value type & description
+ ------------+----------------------------------------------------------
+ "path" | string same as the Request argument
+ "size-bytes"| number the size, in bytes, of the free space in that directory
+
+
5.0. Protocol Versions
The following changes have been made to the RPC interface:
| | yes | | new method "queue-move-bottom"
| | yes | | new method "torrent-start-now"
------+---------+-----------+--------------------------+-------------------------------
- 15 | 2.80 | yes | torrent-get | new arg "etaIdle"
+ 15 | 2.80 | NO | session-get | removed arg "download-dir-free-space"
+ | | yes | torrent-get | new arg "etaIdle"
| | yes | torrent-rename-path | new method
+ | | yes | free-space | new method
GtkWidget * run_check;
GtkWidget * trash_check;
GtkWidget * priority_combo;
+ GtkWidget * freespace_label;
char * filename;
char * downloadDir;
tr_torrent * tor;
g_free (data->downloadDir);
data->downloadDir = g_strdup (fname);
updateTorrent (data);
+
+ gtr_freespace_label_set_dir (data->freespace_label, data->downloadDir);
}
g_free (fname);
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;
#include "tr-prefs.h"
#include "util.h"
+/**
+***
+**/
+
+struct prefs_dialog_data
+{
+ TrCore * core;
+ gulong core_prefs_tag;
+
+ GtkWidget * freespace_label;
+
+ GtkWidget * port_label;
+ GtkWidget * port_button;
+ GtkWidget * port_spin;
+};
+
+
/**
***
**/
****/
static GtkWidget*
-downloadingPage (GObject * core)
+downloadingPage (GObject * core, struct prefs_dialog_data * data)
{
GtkWidget * t;
GtkWidget * w;
w = new_path_chooser_button (TR_KEY_download_dir, core);
hig_workarea_add_row (t, &row, _("Save to _Location:"), w, NULL);
+ l = data->freespace_label = gtr_freespace_label_new (TR_CORE(core), NULL);
+ gtk_misc_set_alignment (GTK_MISC (l), 1.0f, 0.5f);
+ hig_workarea_add_wide_control (t, &row, l);
+
hig_workarea_add_section_divider (t, &row);
hig_workarea_add_section_title (t, &row, _("Download Queue"));
*****
****/
+static void
+on_prefs_dialog_destroyed (gpointer gdata, GObject * dead_dialog G_GNUC_UNUSED)
+{
+ struct prefs_dialog_data * data = gdata;
+
+ if (data->core_prefs_tag > 0)
+ g_signal_handler_disconnect (data->core, data->core_prefs_tag);
+
+ g_free (data);
+}
+
+static void
+on_core_prefs_changed (TrCore * core, const tr_quark key, gpointer gdata)
+{
+ struct prefs_dialog_data * data = gdata;
+
+#if 0
+ if (key == TR_KEY_peer_port)
+ {
+ gtr_label_set_text (GTK_LABEL (data->port_label), _("Status unknown"));
+ gtk_widget_set_sensitive (data->port_button, TRUE);
+ gtk_widget_set_sensitive (data->port_spin, TRUE);
+ }
+#endif
+ if (key == TR_KEY_download_dir)
+ {
+ const char * downloadDir = tr_sessionGetDownloadDir (gtr_core_session (core));
+ gtr_freespace_label_set_dir (data->freespace_label, downloadDir);
+ }
+}
+
GtkWidget *
gtr_prefs_dialog_new (GtkWindow * parent, GObject * core)
{
+ size_t i;
GtkWidget * d;
GtkWidget * n;
+ struct prefs_dialog_data * data;
+ const tr_quark prefs_quarks[] = { TR_KEY_peer_port, TR_KEY_download_dir };
+
+ data = g_new0 (struct prefs_dialog_data, 1);
+ data->core = TR_CORE (core);
+ data->core_prefs_tag = g_signal_connect (TR_CORE (core), "prefs-changed", G_CALLBACK (on_core_prefs_changed), data);
d = gtk_dialog_new_with_buttons (_("Transmission Preferences"),
parent,
GTK_STOCK_HELP, GTK_RESPONSE_HELP,
GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
NULL);
+ g_object_weak_ref (G_OBJECT(d), on_prefs_dialog_destroyed, data);
gtk_window_set_role (GTK_WINDOW (d), "transmission-preferences-dialog");
gtk_container_set_border_width (GTK_CONTAINER (d), GUI_PAD);
gtk_notebook_append_page (GTK_NOTEBOOK (n), speedPage (core),
gtk_label_new (_("Speed")));
- gtk_notebook_append_page (GTK_NOTEBOOK (n), downloadingPage (core),
+ gtk_notebook_append_page (GTK_NOTEBOOK (n), downloadingPage (core, data),
gtk_label_new (C_("Gerund", "Downloading")));
gtk_notebook_append_page (GTK_NOTEBOOK (n), seedingPage (core),
gtk_label_new (C_("Gerund", "Seeding")));
gtk_notebook_append_page (GTK_NOTEBOOK (n), remotePage (core),
gtk_label_new (_("Remote")));
+ /* init from prefs keys */
+ for (i=0; i<sizeof(prefs_quarks)/sizeof(prefs_quarks[0]); ++i)
+ on_core_prefs_changed (TR_CORE(core), prefs_quarks[i], data);
+
g_signal_connect (d, "response", G_CALLBACK (response_cb), core);
gtr_dialog_set_content (GTK_DIALOG (d), n);
return d;
GtkLabel * ul_lb;
GtkLabel * dl_lb;
GtkLabel * stats_lb;
- GtkLabel * freespace_lb;
- GtkWidget * freespace_icon;
GtkWidget * alt_speed_image;
GtkWidget * alt_speed_button;
GtkWidget * options_menu;
gtk_grid_attach_next_to (grid, w, sibling, GTK_POS_RIGHT, 1, 1);
sibling = w;
- /* freespace */
- w = gtk_image_new_from_stock (GTK_STOCK_HARDDISK, GTK_ICON_SIZE_MENU);
- p->freespace_icon = w;
- g_object_set (G_OBJECT(w), "margin-left", GUI_PAD, NULL);
- gtk_grid_attach_next_to (grid, w, sibling, GTK_POS_RIGHT, 1, 1);
- sibling = w;
- w = gtk_label_new (NULL);
- g_object_set (G_OBJECT(w), "margin-left", GUI_PAD_BIG*2, NULL);
- p->freespace_lb = GTK_LABEL (w);
- gtk_label_set_single_line_mode (p->freespace_lb, TRUE);
- gtk_grid_attach_next_to (grid, w, sibling, GTK_POS_RIGHT, 1, 1);
- sibling = w;
-
- /* spacer */
- w = gtk_alignment_new (0.0f, 0.0f, 0.0f, 0.0f);
- gtk_widget_set_hexpand (w, TRUE);
- gtk_grid_attach_next_to (grid, w, sibling, GTK_POS_RIGHT, 1, 1);
- sibling = w;
-
/* download */
w = dl_lb = gtk_label_new (NULL);
p->dl_lb = GTK_LABEL (w);
return self;
}
-static void
-updateFreeSpace (PrivateData * p)
-{
- GtkWidget * w;
- bool visible = false;
-
- g_return_if_fail (p != NULL);
-
- w = GTK_WIDGET (p->freespace_lb);
-
- if (p->core != NULL)
- {
- tr_session * session = gtr_core_session (p->core);
- const int64_t n = tr_sessionGetDownloadDirFreeSpace (session);
- const char * downloadDir = tr_sessionGetDownloadDir (session);
-
- visible = n >= 0;
-
- if (visible)
- {
- char * str;
- char sizeStr[32];
-
- tr_strlsize (sizeStr, n, sizeof(sizeStr));
-
- str = g_strdup_printf (_("%s Free"), sizeStr);
- gtk_label_set_text (p->freespace_lb, str);
- g_free (str);
-
- str = g_strdup_printf (_("Download folder \"%1$s\" has %2$s free"), downloadDir, sizeStr);
- gtk_widget_set_tooltip_text (w, str);
- g_free (str);
- }
- }
-
- gtk_widget_set_visible (w, visible);
- gtk_widget_set_visible (p->freespace_icon, visible);
-}
-
static void
updateStats (PrivateData * p)
{
{
updateSpeeds (p);
updateStats (p);
- updateFreeSpace (p);
}
}
#include "conf.h"
#include "hig.h"
+#include "tr-core.h"
#include "tr-prefs.h"
#include "util.h"
if (tr_strcmp0 (oldstr, newstr))
gtk_label_set_text (lb, newstr);
}
+
+/***
+****
+***/
+
+struct freespace_label_data
+{
+ guint timer_id;
+ TrCore * core;
+ GtkLabel * label;
+ char * dir;
+};
+
+static void on_freespace_label_core_destroyed (gpointer gdata, GObject * dead_core);
+static void on_freespace_label_destroyed (gpointer gdata, GObject * dead_label);
+
+static void
+freespace_label_data_free (gpointer gdata)
+{
+ struct freespace_label_data * data = gdata;
+
+ if (data->core != NULL)
+ g_object_weak_unref (G_OBJECT(data->core), on_freespace_label_core_destroyed, data);
+
+ if (data->label != NULL)
+ g_object_weak_ref (G_OBJECT(data->label), on_freespace_label_destroyed, data);
+
+ g_source_remove (data->timer_id);
+ g_free (data->dir);
+ g_free (data);
+}
+
+static GQuark
+freespace_label_data_quark (void)
+{
+ static GQuark q = 0;
+
+ if (G_UNLIKELY(!q))
+ q = g_quark_from_static_string ("data");
+
+ return q;
+}
+
+static void
+on_freespace_label_core_destroyed (gpointer gdata, GObject * dead_core G_GNUC_UNUSED)
+{
+ struct freespace_label_data * data = gdata;
+ data->core = NULL;
+ freespace_label_data_free (data);
+}
+
+static void
+on_freespace_label_destroyed (gpointer gdata, GObject * dead_label G_GNUC_UNUSED)
+{
+ struct freespace_label_data * data = gdata;
+ data->label = NULL;
+ freespace_label_data_free (data);
+}
+
+static gboolean
+on_freespace_timer (gpointer gdata)
+{
+ char text[128];
+ char markup[128];
+ int64_t bytes;
+ tr_session * session;
+ struct freespace_label_data * data = gdata;
+
+ session = gtr_core_session (data->core);
+ bytes = tr_sessionGetDirFreeSpace (session, data->dir);
+
+ if (bytes < 0)
+ {
+ g_snprintf (text, sizeof(text), _("Error"));
+ }
+ else
+ {
+ char size[128];
+ tr_strlsize (size, bytes, sizeof(size));
+ g_snprintf (text, sizeof(text), _("%s free"), size);
+ }
+
+ g_snprintf (markup, sizeof(markup), "<i>%s</i>", text);
+ gtk_label_set_markup (data->label, markup);
+
+ return G_SOURCE_CONTINUE;
+}
+
+GtkWidget *
+gtr_freespace_label_new (struct _TrCore * core, const char * dir)
+{
+ struct freespace_label_data * data;
+
+ data = g_new0 (struct freespace_label_data, 1);
+ data->timer_id = g_timeout_add_seconds (3, on_freespace_timer, data);
+ data->core = core;
+ data->label = GTK_LABEL (gtk_label_new (NULL));
+ data->dir = g_strdup (dir);
+
+ /* when either the core or the label is destroyed, stop updating */
+ g_object_weak_ref (G_OBJECT(core), on_freespace_label_core_destroyed, data);
+ g_object_weak_ref (G_OBJECT(data->label), on_freespace_label_destroyed, data);
+
+ g_object_set_qdata (G_OBJECT(data->label), freespace_label_data_quark (), data);
+ on_freespace_timer (data);
+ return GTK_WIDGET (data->label);
+}
+
+void
+gtr_freespace_label_set_dir (GtkWidget * label, const char * dir)
+{
+ struct freespace_label_data * data;
+
+ data = g_object_get_qdata (G_OBJECT(label), freespace_label_data_quark ());
+
+ tr_free (data->dir);
+ data->dir = g_strdup (dir);
+ on_freespace_timer (data);
+}
****
***/
+struct _TrCore;
+
+GtkWidget * gtr_freespace_label_new (struct _TrCore * core, const char * dir);
+
+void gtr_freespace_label_set_dir (GtkWidget * label, const char * dir);
+
+/***
+****
+***/
+
void gtr_unrecognized_url_dialog (GtkWidget * parent, const char * url);
void gtr_http_failure_dialog (GtkWidget * parent, const char * url, long response_code);
#endif
#include <assert.h>
+#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <xfs/xqm.h>
#endif
+#include <event2/util.h> /* evutil_ascii_strcasecmp () */
+
#include "transmission.h"
#include "session.h"
#include "list.h"
***/
#ifndef WIN32
-static char *
+static const char *
getdev (const char * path)
{
#ifdef HAVE_GETMNTENT
#endif
}
-static char *
+static const char *
getfstype (const char * device)
{
#endif
}
-static char *
+static const char *
getblkdev (const char * path)
{
char * c;
char * dir;
- char * device;
+ const char * device;
dir = tr_strdup(path);
}
static int64_t
-getquota (char * device)
+getquota (const char * device)
{
struct dqblk dq;
int64_t limit;
#endif /* WIN32 */
static int64_t
-tr_getQuotaFreeSpace (const char * path, char * device, char * fstype)
+tr_getQuotaFreeSpace (const struct tr_device_info * info)
{
- int64_t ret=-1;
+ int64_t ret = -1;
#ifndef WIN32
- /* save device for future use */
- if (!*device)
- {
- char * d = getblkdev (path);
- if (d == NULL)
- return ret;
- tr_strlcpy (device, d, PATH_MAX + 1);
- }
-
- /* save FS type for future use */
- if (!*fstype)
- {
- char * fs = getfstype (device);
- if (fs != NULL)
- tr_strlcpy (fstype, fs, PATH_MAX + 1);
- }
-
- if (strcasecmp(fstype, "xfs") == 0)
+ if (info->fstype && !evutil_ascii_strcasecmp(info->fstype, "xfs"))
{
#ifdef HAVE_XQM
- ret = getxfsquota(device);
+ ret = getxfsquota (info->device);
#endif
}
else
{
- ret = getquota(device);
+ ret = getquota (info->device);
}
-
#endif /* WIN32 */
+
return ret;
}
#endif
}
+struct tr_device_info *
+tr_device_info_create (const char * path)
+{
+ struct tr_device_info * info;
+
+ info = tr_new0 (struct tr_device_info, 1);
+ info->path = tr_strdup (path);
+ info->device = tr_strdup (getblkdev (path));
+ info->fstype = tr_strdup (getfstype (path));
+
+ return info;
+}
+
+void
+tr_device_info_free (struct tr_device_info * info)
+{
+ if (info != NULL)
+ {
+ tr_free (info->fstype);
+ tr_free (info->device);
+ tr_free (info->path);
+ tr_free (info);
+ }
+}
+
int64_t
-tr_getFreeSpace (const char * path, char * device, char * fstype)
+tr_device_info_get_free_space (const struct tr_device_info * info)
{
- int64_t i = tr_getQuotaFreeSpace (path, device, fstype);
+ int64_t free_space;
- if (i < 0)
- i = tr_getDiskFreeSpace (path);
+ if ((info == NULL) || (info->path == NULL))
+ {
+ errno = EINVAL;
+ free_space = -1;
+ }
+ else
+ {
+ free_space = tr_getQuotaFreeSpace (info);
+
+ if (free_space < 0)
+ free_space = tr_getDiskFreeSpace (info->path);
+ }
- return i;
+ return free_space;
}
/***
/** @brief return the directory where the Web Client's web ui files are kept */
const char * tr_getWebClientDir (const tr_session *);
+struct tr_device_info
+{
+ char * path;
+ char * device;
+ char * fstype;
+};
+
+struct tr_device_info * tr_device_info_create (const char * path);
+
/** If the disk quota is enabled and readable, this returns how much is available in the quota.
Otherwise, it returns how much is available on the disk, or -1 on error. */
-int64_t tr_getFreeSpace (const char * path, char * device, char * fstype);
+int64_t tr_device_info_get_free_space (const struct tr_device_info * info);
+
+void tr_device_info_free (struct tr_device_info * info);
/** @} */
{ "done-date", 9 },
{ "doneDate", 8 },
{ "download-dir", 12 },
- { "download-dir-free-space", 23 },
{ "download-queue-enabled", 22 },
{ "download-queue-size", 19 },
{ "downloadCount", 13 },
TR_KEY_done_date,
TR_KEY_doneDate,
TR_KEY_download_dir,
- TR_KEY_download_dir_free_space,
TR_KEY_download_queue_enabled,
TR_KEY_download_queue_size,
TR_KEY_downloadCount,
check (tr_variantDictFind (args, TR_KEY_config_dir) != NULL);
check (tr_variantDictFind (args, TR_KEY_dht_enabled) != NULL);
check (tr_variantDictFind (args, TR_KEY_download_dir) != NULL);
- check (tr_variantDictFind (args, TR_KEY_download_dir_free_space) != NULL);
check (tr_variantDictFind (args, TR_KEY_download_queue_enabled) != NULL);
check (tr_variantDictFind (args, TR_KEY_download_queue_size) != NULL);
check (tr_variantDictFind (args, TR_KEY_encryption) != NULL);
static const char*
sessionSet (tr_session * session,
- tr_variant * args_in,
- tr_variant * args_out UNUSED,
+ tr_variant * args_in,
+ tr_variant * args_out UNUSED,
struct tr_rpc_idle_data * idle_data UNUSED)
{
int64_t i;
tr_variantDictAddStr (d, TR_KEY_download_dir, tr_sessionGetDownloadDir (s));
tr_variantDictAddBool (d, TR_KEY_download_queue_enabled, tr_sessionGetQueueEnabled (s, TR_DOWN));
tr_variantDictAddInt (d, TR_KEY_download_queue_size, tr_sessionGetQueueSize (s, TR_DOWN));
- tr_variantDictAddInt (d, TR_KEY_download_dir_free_space, tr_sessionGetDownloadDirFreeSpace (s));
tr_variantDictAddInt (d, TR_KEY_peer_limit_global, tr_sessionGetPeerLimit (s));
tr_variantDictAddInt (d, TR_KEY_peer_limit_per_torrent, tr_sessionGetPeerLimitPerTorrent (s));
tr_variantDictAddStr (d, TR_KEY_incomplete_dir, tr_sessionGetIncompleteDir (s));
return NULL;
}
+static const char*
+freeSpace (tr_session * session,
+ tr_variant * args_in,
+ tr_variant * args_out,
+ struct tr_rpc_idle_data * idle_data UNUSED)
+{
+ int tmperr;
+ const char * path = NULL;
+ const char * err = NULL;
+ int64_t free_space = -1;
+
+ /* get the free space */
+ tr_variantDictFindStr (args_in, TR_KEY_path, &path, NULL);
+ tmperr = errno;
+ errno = 0;
+ free_space = tr_sessionGetDirFreeSpace (session, path);
+ if (free_space < 0)
+ err = tr_strerror (errno);
+ errno = tmperr;
+
+ /* response */
+ if (path != NULL)
+ tr_variantDictAddStr (args_out, TR_KEY_path, path);
+ tr_variantDictAddInt (args_out, TR_KEY_size_bytes, free_space);
+ return err;
+}
+
/***
****
***/
{
{ "port-test", false, portTest },
{ "blocklist-update", false, blocklistUpdate },
+ { "free-space", true, freeSpace },
{ "session-close", true, sessionClose },
{ "session-get", true, sessionGet },
{ "session-set", true, sessionSet },
tr_variantDictAddBool (d, TR_KEY_dht_enabled, s->isDHTEnabled);
tr_variantDictAddBool (d, TR_KEY_utp_enabled, s->isUTPEnabled);
tr_variantDictAddBool (d, TR_KEY_lpd_enabled, s->isLPDEnabled);
- tr_variantDictAddStr (d, TR_KEY_download_dir, s->downloadDir);
+ tr_variantDictAddStr (d, TR_KEY_download_dir, tr_sessionGetDownloadDir (s));
tr_variantDictAddInt (d, TR_KEY_download_queue_size, tr_sessionGetQueueSize (s, TR_DOWN));
tr_variantDictAddBool (d, TR_KEY_download_queue_enabled, tr_sessionGetQueueEnabled (s, TR_DOWN));
tr_variantDictAddInt (d, TR_KEY_speed_limit_down, tr_sessionGetSpeedLimit_KBps (s, TR_DOWN));
void
tr_sessionSetDownloadDir (tr_session * session, const char * dir)
{
- assert (tr_isSession (session));
+ struct tr_device_info * info = NULL;
- if (session->downloadDir != dir)
- {
- tr_free (session->downloadDir);
- session->downloadDir = tr_strdup (dir);
- memset (session->downloadDirBlkDev, 0, sizeof(session->downloadDirBlkDev));
- memset (session->downloadDirFsType, 0, sizeof(session->downloadDirFsType));
- }
+ assert (tr_isSession (session));
+
+ if (dir != NULL)
+ info = tr_device_info_create (dir);
+ tr_device_info_free (session->downloadDir);
+ session->downloadDir = info;
}
const char *
tr_sessionGetDownloadDir (const tr_session * session)
{
- assert (tr_isSession (session));
+ const char * dir = NULL;
- return session->downloadDir;
+ assert (tr_isSession (session));
+
+ if ((session != NULL) && (session->downloadDir != NULL))
+ dir = session->downloadDir->path;
+
+ return dir;
}
int64_t
-tr_sessionGetDownloadDirFreeSpace (tr_session * session)
+tr_sessionGetDirFreeSpace (tr_session * session, const char * dir)
{
- assert (tr_isSession (session));
+ int64_t free_space;
+
+ if (!tr_strcmp0 (dir, tr_sessionGetDownloadDir (session)))
+ free_space = tr_device_info_get_free_space (session->downloadDir);
+ else
+ free_space = tr_getDirFreeSpace (dir);
- return tr_getFreeSpace (session->downloadDir,
- session->downloadDirBlkDev,
- session->downloadDirFsType);
+ return free_space;
}
/***
tr_variantFree (session->metainfoLookup);
tr_free (session->metainfoLookup);
}
+ tr_device_info_free (session->downloadDir);
tr_free (session->torrentDoneScript);
tr_free (session->tag);
tr_free (session->configDir);
tr_free (session->resumeDir);
tr_free (session->torrentDir);
- tr_free (session->downloadDir);
tr_free (session->incompleteDir);
tr_free (session->blocklist_url);
tr_free (session->peer_congestion_algorithm);
struct tr_bindsockets;
struct tr_cache;
struct tr_fdInfo;
+struct tr_device_info;
typedef void (tr_web_config_func)(tr_session * session, void * curl_pointer, const char * url, void * user_data);
char * tag;
char * configDir;
- char * downloadDir;
- char downloadDirBlkDev[TR_PATH_MAX + 1];
- char downloadDirFsType[TR_PATH_MAX + 1];
char * resumeDir;
char * torrentDir;
char * incompleteDir;
char * blocklist_url;
+ struct tr_device_info * downloadDir;
+
struct tr_list * blocklists;
struct tr_peerMgr * peerMgr;
struct tr_shared * shared;
tr_ctorSetDeleteSource (ctor, tr_sessionGetDeleteSource (session));
tr_ctorSetPaused (ctor, TR_FALLBACK, tr_sessionGetPaused (session));
tr_ctorSetPeerLimit (ctor, TR_FALLBACK, session->peerLimitPerTorrent);
- tr_ctorSetDownloadDir (ctor, TR_FALLBACK, session->downloadDir);
+ tr_ctorSetDownloadDir (ctor, TR_FALLBACK, tr_sessionGetDownloadDir(session));
}
tr_ctorSetSave (ctor, true);
return ctor;
int
tr_torrentId (const tr_torrent * tor)
{
- return tor->uniqueId;
+ return tor ? tor->uniqueId : -1;
}
tr_torrent*
const char * tr_sessionGetDownloadDir (const tr_session * session);
/**
- * @brief Get available disk space (in bytes) for the default download folder.
+ * @brief Get available disk space (in bytes) for the specified directory.
* @return zero or positive integer on success, -1 in case of error.
*/
-int64_t tr_sessionGetDownloadDirFreeSpace (tr_session * session);
+int64_t tr_sessionGetDirFreeSpace (tr_session * session, const char * dir);
/**
* @brief Set the torrent's bandwidth priority.
return ok;
}
+int64_t
+tr_getDirFreeSpace (const char * dir)
+{
+ int64_t free_space;
+
+ if (!dir || !*dir)
+ {
+ errno = EINVAL;
+ free_space = -1;
+ }
+ else
+ {
+ struct tr_device_info * info;
+ info = tr_device_info_create (dir);
+ free_space = tr_device_info_get_free_space (info);
+ tr_device_info_free (info);
+ }
+
+ return free_space;
+}
+
/****
*****
****/
bool tr_fileExists (const char * filename, time_t * mtime);
+/**
+ * @brief Get available disk space (in bytes) for the specified folder.
+ * @return zero or positive integer on success, -1 in case of error.
+ */
+int64_t tr_getDirFreeSpace (const char * path);
+
struct event;
--- /dev/null
+/*
+ * This file Copyright (C) Mnemosyne LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ *
+ * $Id:$
+ */
+
+#include <libtransmission/transmission.h>
+#include <libtransmission/variant.h>
+
+#include "formatter.h"
+#include "freespace-label.h"
+#include "session.h"
+
+namespace
+{
+ static const int INTERVAL_MSEC = 5000;
+}
+
+FreespaceLabel :: FreespaceLabel (Session & session,
+ const QString & path,
+ QWidget * parent):
+ QLabel (parent),
+ mySession (session),
+ myTag (-1),
+ myPath (path),
+ myTimer (this)
+{
+ myTimer.setSingleShot (false);
+ myTimer.setInterval (INTERVAL_MSEC);
+ myTimer.start ();
+
+ connect (&myTimer, SIGNAL(timeout()), this, SLOT(onTimer()));
+
+ connect (&mySession, SIGNAL(executed(int64_t, const QString&, struct tr_variant*)),
+ this, SLOT(onSessionExecuted(int64_t, const QString&, struct tr_variant*)));
+
+ onTimer ();
+}
+
+void
+FreespaceLabel :: onTimer ()
+{
+ const int64_t tag = mySession.getUniqueTag ();
+ const QByteArray myPathUtf8 = myPath.toUtf8 ();
+
+ myTag = tag;
+ tr_variant top;
+ tr_variantInitDict (&top, 3);
+ tr_variantDictAddStr (&top, TR_KEY_method, "free-space");
+ tr_variantDictAddInt (&top, TR_KEY_tag, tag);
+ tr_variant * args = tr_variantDictAddDict (&top, TR_KEY_arguments, 1);
+ tr_variantDictAddStr (args, TR_KEY_path, myPathUtf8.constData());
+ mySession.exec (&top);
+ tr_variantFree (&top);
+}
+
+void
+FreespaceLabel :: onSessionExecuted (int64_t tag, const QString& result, struct tr_variant * arguments)
+{
+ if (tag != myTag)
+ return;
+
+ QString str;
+
+ // update the label
+ int64_t bytes = -1;
+ tr_variantDictFindInt (arguments, TR_KEY_size_bytes, &bytes);
+ if (bytes < 0)
+ str = tr("Error: %1").arg(result);
+ else
+ str = tr("%1 free").arg(Formatter::sizeToString (bytes));
+ setText (QString("<i>%1</i>").arg(str));
+
+ // update the tooltip
+ size_t len = 0;
+ const char * path = 0;
+ tr_variantDictFindStr (arguments, TR_KEY_path, &path, &len);
+ str = QString::fromUtf8 (path, len);
+ setToolTip (str);
+}
--- /dev/null
+/*
+ * This file Copyright (C) Mnemosyne LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ *
+ * $Id:$
+ */
+
+#ifndef QTR_FREESPACE_LABEL_H
+#define QTR_FREESPACE_LABEL_H
+
+#include <QString>
+#include <QTimer>
+
+#include <QtGui/QLabel>
+
+class Session;
+
+class FreespaceLabel: public QLabel
+{
+ Q_OBJECT
+
+ public:
+ FreespaceLabel (Session&, const QString& path, QWidget *parent=0);
+ virtual ~FreespaceLabel () {}
+ void setPath (const QString& folder) { myPath=folder; onTimer(); }
+
+ private:
+ Session& mySession;
+ int64_t myTag;
+ QString myPath;
+ QTimer myTimer;
+
+ private slots:
+ void onSessionExecuted (int64_t tag, const QString& result, struct tr_variant * arguments);
+ void onTimer ();
+};
+
+#endif // QTR_FREESPACE_LABEL_H
+
connect (&mySession, SIGNAL (sourceChanged ()), this, SLOT (onSessionSourceChanged ()));
connect (&mySession, SIGNAL (statsUpdated ()), this, SLOT (refreshStatusBar ()));
- connect (&mySession, SIGNAL (sessionUpdated ()), this, SLOT (refreshFreeSpace ()));
connect (&mySession, SIGNAL (dataReadProgress ()), this, SLOT (dataReadProgress ()));
connect (&mySession, SIGNAL (dataSendProgress ()), this, SLOT (dataSendProgress ()));
connect (&mySession, SIGNAL (httpAuthenticationRequired ()), this, SLOT (wrongAuthentication ()));
refreshActionSensitivitySoon ();
refreshTrayIconSoon ();
refreshStatusBar ();
- refreshFreeSpace ();
refreshTitle ();
}
l = myNetworkLabel = new QLabel;
h->addWidget (l);
- h->addStretch (1);
-
- l = myFreeSpaceIconLabel = new QLabel (this);
- l->setPixmap (getStockIcon ("drive-harddisk", QStyle::SP_DriveHDIcon).pixmap (smallIconSize));
- h->addWidget (l);
- l = myFreeSpaceTextLabel = new QLabel (this);
- const int minimumFreeSpaceWidth = l->fontMetrics ().width (Formatter::sizeToString (1024 * 1024));
- l->setMinimumWidth (minimumFreeSpaceWidth);
- h->addWidget (l);
-
h->addStretch (1);
l = myDownloadSpeedLabel = new QLabel (this);
setWindowTitle (title);
}
-void
-TrMainWindow :: refreshFreeSpace ()
-{
- const int64_t bytes (mySession.downloadDirFreeSpace ());
-
- if (bytes >= 0)
- {
- const QString sizeStr = Formatter::sizeToString (bytes);
-
- const QString tip = tr ("Download folder \"%1\" has %2 free")
- .arg (myPrefs.getString (Prefs::DOWNLOAD_DIR))
- .arg (sizeStr);
-
- myFreeSpaceTextLabel->setText (tr("%1 Free").arg(sizeStr));
- myFreeSpaceTextLabel->setToolTip (tip);
- myFreeSpaceIconLabel->setToolTip (tip);
- }
-
- myFreeSpaceTextLabel->setVisible (bytes >= 0);
- myFreeSpaceIconLabel->setVisible (bytes >= 0);
-}
-
void
TrMainWindow :: refreshTrayIconSoon ()
{
void showTotalTransfer ();
void showSessionRatio ();
void showSessionTransfer ();
- void refreshFreeSpace ();
void refreshTitle ();
void refreshStatusBar ();
void refreshTrayIcon ();
QLabel * myStatsLabel;
QLabel * myDownloadSpeedLabel;
QLabel * myUploadSpeedLabel;
- QLabel * myFreeSpaceTextLabel;
- QLabel * myFreeSpaceIconLabel;
QLabel * myNetworkLabel;
public slots:
#include "add-data.h"
#include "file-tree.h"
+#include "freespace-label.h"
#include "hig.h"
#include "options.h"
#include "prefs.h"
l = new QLabel( tr( "&Destination folder:" ) );
layout->addWidget( l, ++row, 0, Qt::AlignLeft );
+ const QString downloadDir (prefs.getString (Prefs::DOWNLOAD_DIR));
if( session.isLocal( ) )
{
- myDestination.setPath( prefs.getString( Prefs :: DOWNLOAD_DIR ) );
+ myDestination.setPath (downloadDir);
p = myDestinationButton = new QPushButton;
p->setIcon( folderPixmap );
p->setStyleSheet( "text-align: left; padding-left: 5; padding-right: 5" );
else
{
QLineEdit * e = myDestinationEdit = new QLineEdit;
- e->setText( prefs.getString( Prefs :: DOWNLOAD_DIR ) );
+ e->setText (downloadDir);
layout->addWidget( e, row, 1 );
l->setBuddy( e );
}
+ l = myFreespaceLabel = new FreespaceLabel (mySession, downloadDir, this);
+ layout->addWidget (l, ++row, 0, 1, 2, Qt::Alignment (Qt::AlignRight | Qt::AlignTop));
+ layout->setRowMinimumHeight (row, l->height() + HIG::PAD);
+
myTree = new FileTreeView (0, false);
layout->addWidget( myTree, ++row, 0, 1, 2 );
if( !session.isLocal( ) )
connect( b, SIGNAL(accepted()), this, SLOT(onAccepted()) );
layout->addWidget( b, ++row, 0, 1, 2 );
- layout->setRowStretch( 2, 2 );
+ layout->setRowStretch( 3, 2 );
layout->setColumnStretch( 1, 2 );
layout->setSpacing( HIG :: PAD );
}
void
-Options :: onDestinationsSelected( const QStringList& destinations )
+Options :: onDestinationsSelected (const QStringList& destinations)
{
- if( destinations.size() == 1 )
+ if (destinations.size() == 1)
{
- const QString& destination( destinations.first( ) );
- myDestination.setPath( destination );
- refreshDestinationButton( );
+ const QString& destination (destinations.first ());
+ myFreespaceLabel->setPath (destination);
+ myDestination.setPath (destination);
+ refreshDestinationButton ();
}
}
#include <QDir>
#include <QVector>
#include <QMap>
-#include <QPushButton>
#include <QString>
#include <QStringList>
#include <QCryptographicHash>
#include "add-data.h" // AddData
#include "file-tree.h" // FileList
-class FileTreeView;
-class Prefs;
class QCheckBox;
class QComboBox;
+class QPushButton;
+
+class FileTreeView;
+class FreespaceLabel;
+class Prefs;
class Session;
extern "C" { struct tr_variant; };
bool myHaveInfo;
tr_info myInfo;
FileTreeView * myTree;
+ FreespaceLabel * myFreespaceLabel;
QCheckBox * myStartCheck;
QCheckBox * myTrashCheck;
QComboBox * myPriorityCombo;
#include <QTimer>
#include <QVBoxLayout>
+#include "freespace-label.h"
#include "formatter.h"
#include "hig.h"
#include "prefs.h"
connect( b, SIGNAL(clicked(bool)), this, SLOT(onDestinationClicked(void)) );
hig->addRow( tr( "Save to &Location:" ), b );
+ const QString downloadDir (myPrefs.getString(Prefs::DOWNLOAD_DIR));
+ l = myFreespaceLabel = new FreespaceLabel (mySession, downloadDir, this);
+ QHBoxLayout * h = new QHBoxLayout ();
+ h->addStretch (1);
+ h->addWidget (l);
+ hig->addWideControl (h);
+
hig->addSectionDivider( );
hig->addSectionTitle( tr( "Download Queue" ) );
break;
case Prefs :: DOWNLOAD_DIR: {
- QString path( myPrefs.getString( key ) );
+ const QString path( myPrefs.getString( key ) );
myDestinationButton->setText( QFileInfo(path).fileName() );
+ myFreespaceLabel->setPath (path);
break;
}
class QMessageBox;
class QHttp;
+class FreespaceLabel;
class Prefs;
class Session;
QWidgetList mySchedWidgets;
QWidgetList myBlockWidgets;
QWidgetList myUnsupportedWhenRemote;
+ FreespaceLabel * myFreespaceLabel;
int myBlocklistHttpTag;
QHttp * myBlocklistHttp;
file-tree.cc \
filterbar.cc \
filters.cc \
+ freespace-label.cc \
formatter.cc \
hig.cc \
license.cc \
myPrefs (prefs),
mySession (0),
myConfigDir (QString::fromUtf8 (configDir)),
- myNAM (0),
- myDownloadDirFreeSpace (-1)
+ myNAM (0)
{
myStats.ratio = TR_RATIO_NA;
myStats.uploadedBytes = 0;
if (tr_variantDictFindStr (d, TR_KEY_version, &str, NULL) && (mySessionVersion != str))
mySessionVersion = str;
- if (tr_variantDictFindInt (d, TR_KEY_download_dir_free_space, &i) && (myDownloadDirFreeSpace != i))
- myDownloadDirFreeSpace = i;
-
//std::cerr << "Session :: updateInfo end" << std::endl;
connect (&myPrefs, SIGNAL (changed (int)), this, SLOT (updatePref (int)));
const struct tr_session_stats& getStats () const { return myStats; }
const struct tr_session_stats& getCumulativeStats () const { return myCumulativeStats; }
const QString& sessionVersion () const { return mySessionVersion; }
- int64_t downloadDirFreeSpace () const { return myDownloadDirFreeSpace; }
public:
int64_t blocklistSize () const { return myBlocklistSize; }
struct tr_session_stats myStats;
struct tr_session_stats myCumulativeStats;
QString mySessionVersion;
- int64_t myDownloadDirFreeSpace;
};
#endif