summaryrefslogtreecommitdiff
path: root/src/trg-state-selector.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/trg-state-selector.c')
-rw-r--r--src/trg-state-selector.c251
1 files changed, 205 insertions, 46 deletions
diff --git a/src/trg-state-selector.c b/src/trg-state-selector.c
index f20a407..b6447ee 100644
--- a/src/trg-state-selector.c
+++ b/src/trg-state-selector.c
@@ -25,6 +25,8 @@
#include "torrent.h"
#include "trg-state-selector.h"
#include "util.h"
+#include "trg-preferences.h"
+#include "trg-client.h"
enum {
SELECTOR_STATE_CHANGED,
@@ -40,11 +42,15 @@ typedef struct _TrgStateSelectorPrivate TrgStateSelectorPrivate;
struct _TrgStateSelectorPrivate {
guint flag;
+ gboolean showDirs;
+ gboolean showTrackers;
+ trg_client *client;
GHashTable *trackers;
+ GHashTable *directories;
GRegex *urlHostRegex;
};
-GRegex *trg_state_selector_get_url_host_regex(TrgStateSelector *s)
+GRegex *trg_state_selector_get_url_host_regex(TrgStateSelector * s)
{
TrgStateSelectorPrivate *priv = TRG_STATE_SELECTOR_GET_PRIVATE(s);
return priv->urlHostRegex;
@@ -95,7 +101,8 @@ static void state_selection_changed(GtkTreeSelection * selection,
signals[SELECTOR_STATE_CHANGED], 0, priv->flag);
}
-static GtkTreeRowReference *quick_tree_ref_new(GtkTreeModel *model, GtkTreeIter *iter)
+static GtkTreeRowReference *quick_tree_ref_new(GtkTreeModel * model,
+ GtkTreeIter * iter)
{
GtkTreePath *path = gtk_tree_model_get_path(model, iter);
GtkTreeRowReference *rr = gtk_tree_row_reference_new(model, path);
@@ -108,10 +115,12 @@ struct cruft_remove_args {
gint64 serial;
};
-static gboolean trg_state_selector_remove_cruft(gpointer key, gpointer value, gpointer data)
+static gboolean trg_state_selector_remove_cruft(gpointer key,
+ gpointer value,
+ gpointer data)
{
- struct cruft_remove_args *args = (struct cruft_remove_args*)data;
- GtkTreeRowReference *rr = (GtkTreeRowReference*)value;
+ struct cruft_remove_args *args = (struct cruft_remove_args *) data;
+ GtkTreeRowReference *rr = (GtkTreeRowReference *) value;
GtkTreeModel *model = gtk_tree_row_reference_get_model(rr);
GtkTreePath *path = gtk_tree_row_reference_get_path(rr);
gboolean remove;
@@ -120,7 +129,8 @@ static gboolean trg_state_selector_remove_cruft(gpointer key, gpointer value, gp
gint64 currentSerial;
gtk_tree_model_get_iter(model, &iter, path);
- gtk_tree_model_get(model, &iter, STATE_SELECTOR_SERIAL, &currentSerial, -1);
+ gtk_tree_model_get(model, &iter, STATE_SELECTOR_SERIAL, &currentSerial,
+ -1);
remove = (args->serial != currentSerial);
@@ -129,7 +139,7 @@ static gboolean trg_state_selector_remove_cruft(gpointer key, gpointer value, gp
return remove;
}
-gchar *trg_state_selector_get_selected_text(TrgStateSelector *s)
+gchar *trg_state_selector_get_selected_text(TrgStateSelector * s)
{
GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(s));
GtkTreeModel *model;
@@ -142,55 +152,177 @@ gchar *trg_state_selector_get_selected_text(TrgStateSelector *s)
return name;
}
-void trg_state_selector_update_trackers(TrgStateSelector *s, JsonArray *torrents, gint64 serial)
+static void trg_state_selector_update_serial(GtkTreeModel * model,
+ GtkTreeRowReference * rr,
+ gint64 serial)
{
- TrgStateSelectorPrivate *priv = TRG_STATE_SELECTOR_GET_PRIVATE(s);
- GtkTreeModel *model;
GtkTreeIter iter;
- int i, j;
- struct cruft_remove_args cruft;
+ GtkTreePath *path = gtk_tree_row_reference_get_path(rr);
+ gtk_tree_model_get_iter(model, &iter, path);
+ gtk_list_store_set(GTK_LIST_STORE(model), &iter,
+ STATE_SELECTOR_SERIAL, serial, -1);
+ gtk_tree_path_free(path);
+}
- model = gtk_tree_view_get_model(GTK_TREE_VIEW(s));
+static void refresh_statelist_cb(GtkWidget * w, gpointer data)
+{
+ trg_state_selector_update(TRG_STATE_SELECTOR(data));
+}
- for (i = 0; i < json_array_get_length(torrents); i++) {
- JsonObject *t = json_array_get_object_element(torrents, i);
- JsonArray *trackers = torrent_get_trackers(t);
+static void
+view_popup_menu(GtkWidget * treeview, GdkEventButton * event,
+ gpointer data G_GNUC_UNUSED)
+{
+ GtkWidget *menu, *item;
- for (j = 0; j < json_array_get_length(trackers); j++) {
- JsonObject *tracker = json_array_get_object_element(trackers, j);
- const gchar *announceUrl = tracker_get_announce(tracker);
- gchar *announceHost = trg_uri_host_extract(priv->urlHostRegex, announceUrl);
- gpointer result;
+ menu = gtk_menu_new();
- if (!announceHost)
- continue;
+ item = gtk_image_menu_item_new_with_label(GTK_STOCK_REFRESH);
+ gtk_image_menu_item_set_use_stock(GTK_IMAGE_MENU_ITEM(item), TRUE);
+ gtk_image_menu_item_set_always_show_image(GTK_IMAGE_MENU_ITEM
+ (item), TRUE);
+ g_signal_connect(item, "activate", G_CALLBACK(refresh_statelist_cb),
+ treeview);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
- result = g_hash_table_lookup(priv->trackers, announceHost);
+ gtk_widget_show_all(menu);
- if (result)
- {
- GtkTreeRowReference *rr = (GtkTreeRowReference*)result;
- GtkTreePath *path = gtk_tree_row_reference_get_path(rr);
- gtk_tree_model_get_iter(model, &iter, path);
- gtk_list_store_set(GTK_LIST_STORE(model), &iter,
- STATE_SELECTOR_SERIAL, serial, -1);
- gtk_tree_path_free(path);
+ gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
+ (event != NULL) ? event->button : 0,
+ gdk_event_get_time((GdkEvent *) event));
+}
+
+static gboolean view_onPopupMenu(GtkWidget * treeview, gpointer userdata)
+{
+ view_popup_menu(treeview, NULL, userdata);
+ return TRUE;
+}
+
+static gboolean
+view_onButtonPressed(GtkWidget * treeview, GdkEventButton * event,
+ gpointer userdata)
+{
+ if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
+ view_popup_menu(treeview, event, userdata);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void trg_state_selector_update(TrgStateSelector * s)
+{
+ TrgStateSelectorPrivate *priv = TRG_STATE_SELECTOR_GET_PRIVATE(s);
+ GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(s));
+ trg_client *client = priv->client;
+ GtkTreeIter iter;
+ int i, j;
+ struct cruft_remove_args cruft;
+
+ for (i = 0; i < json_array_get_length(client->torrents); i++) {
+ JsonObject *t = json_array_get_object_element(client->torrents, i);
+ gpointer result;
+
+ if (priv->showTrackers) {
+ JsonArray *trackers = torrent_get_trackers(t);
+
+ for (j = 0; j < json_array_get_length(trackers); j++) {
+ JsonObject *tracker =
+ json_array_get_object_element(trackers, j);
+ const gchar *announceUrl = tracker_get_announce(tracker);
+ gchar *announceHost =
+ trg_gregex_get_first(priv->urlHostRegex, announceUrl);
+
+ if (!announceHost)
+ continue;
+
+ result = g_hash_table_lookup(priv->trackers, announceHost);
+
+ if (result) {
+ trg_state_selector_update_serial(model,
+ (GtkTreeRowReference
+ *)
+ result,
+ client->updateSerial);
+ } else {
+ gtk_list_store_insert(GTK_LIST_STORE(model), &iter,
+ 9 +
+ g_hash_table_size(priv->
+ trackers));
+ gtk_list_store_set(GTK_LIST_STORE(model), &iter,
+ STATE_SELECTOR_ICON,
+ GTK_STOCK_NETWORK,
+ STATE_SELECTOR_NAME, announceHost,
+ STATE_SELECTOR_SERIAL,
+ client->updateSerial,
+ STATE_SELECTOR_BIT,
+ FILTER_FLAG_TRACKER, -1);
+ g_hash_table_insert(priv->trackers, announceHost,
+ quick_tree_ref_new(model, &iter));
+ }
+ }
+ }
+
+ if (priv->showDirs) {
+ const gchar *dir = torrent_get_download_dir(t);
+ result = g_hash_table_lookup(priv->directories, dir);
+ if (result) {
+ trg_state_selector_update_serial(model,
+ (GtkTreeRowReference *)
+ result,
+ client->updateSerial);
} else {
gtk_list_store_append(GTK_LIST_STORE(model), &iter);
gtk_list_store_set(GTK_LIST_STORE(model), &iter,
- STATE_SELECTOR_ICON, GTK_STOCK_NETWORK,
- STATE_SELECTOR_NAME, announceHost,
- STATE_SELECTOR_SERIAL, serial,
- STATE_SELECTOR_BIT, FILTER_FLAG_TRACKER, -1);
- g_hash_table_insert(priv->trackers, announceHost, quick_tree_ref_new(model, &iter));
+ STATE_SELECTOR_ICON,
+ GTK_STOCK_DIRECTORY,
+ STATE_SELECTOR_NAME, dir,
+ STATE_SELECTOR_SERIAL,
+ client->updateSerial,
+ STATE_SELECTOR_BIT, FILTER_FLAG_DIR,
+ -1);
+ g_hash_table_insert(priv->directories, g_strdup(dir),
+ quick_tree_ref_new(model, &iter));
}
}
}
- cruft.serial = serial;
- cruft.table = priv->trackers;
+ cruft.serial = client->updateSerial;
+
+ if (priv->showTrackers) {
+ cruft.table = priv->trackers;
+ g_hash_table_foreach_remove(priv->trackers,
+ trg_state_selector_remove_cruft,
+ &cruft);
+ }
+
+ if (priv->showDirs) {
+ cruft.table = priv->directories;
+ g_hash_table_foreach_remove(priv->directories,
+ trg_state_selector_remove_cruft,
+ &cruft);
+ }
+}
+
+void trg_state_selector_set_show_dirs(TrgStateSelector * s, gboolean show)
+{
+ TrgStateSelectorPrivate *priv = TRG_STATE_SELECTOR_GET_PRIVATE(s);
+ priv->showDirs = show;
+ if (!show)
+ g_hash_table_remove_all(priv->directories);
+ else
+ trg_state_selector_update(s);
+}
- g_hash_table_foreach_remove(priv->trackers, trg_state_selector_remove_cruft, &cruft);
+void trg_state_selector_set_show_trackers(TrgStateSelector * s,
+ gboolean show)
+{
+ TrgStateSelectorPrivate *priv = TRG_STATE_SELECTOR_GET_PRIVATE(s);
+ priv->showTrackers = show;
+ if (!show)
+ g_hash_table_remove_all(priv->trackers);
+ else
+ trg_state_selector_update(s);
}
static void trg_state_selector_add_state(GtkListStore * model,
@@ -204,7 +336,7 @@ static void trg_state_selector_add_state(GtkListStore * model,
STATE_SELECTOR_BIT, flag, -1);
}
-static void remove_row_ref_and_free(GtkTreeRowReference *rr)
+static void remove_row_ref_and_free(GtkTreeRowReference * rr)
{
GtkTreeModel *model = gtk_tree_row_reference_get_model(rr);
GtkTreePath *path = gtk_tree_row_reference_get_path(rr);
@@ -216,6 +348,14 @@ static void remove_row_ref_and_free(GtkTreeRowReference *rr)
gtk_tree_row_reference_free(rr);
}
+void trg_state_selector_disconnect(TrgStateSelector * s)
+{
+ TrgStateSelectorPrivate *priv = TRG_STATE_SELECTOR_GET_PRIVATE(s);
+
+ g_hash_table_remove_all(priv->trackers);
+ g_hash_table_remove_all(priv->directories);
+}
+
static void trg_state_selector_init(TrgStateSelector * self)
{
TrgStateSelectorPrivate *priv;
@@ -229,7 +369,12 @@ static void trg_state_selector_init(TrgStateSelector * self)
priv->flag = 0;
priv->urlHostRegex = trg_uri_host_regex_new();
- priv->trackers = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)remove_row_ref_and_free);
+ priv->trackers =
+ g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
+ (GDestroyNotify) remove_row_ref_and_free);
+ priv->directories =
+ g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
+ (GDestroyNotify) remove_row_ref_and_free);
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(self), FALSE);
@@ -268,8 +413,7 @@ static void trg_state_selector_init(TrgStateSelector * self)
_("Seeding"), TORRENT_FLAG_SEEDING);
trg_state_selector_add_state(store, &iter, GTK_STOCK_DIALOG_WARNING,
_("Error"), TORRENT_FLAG_ERROR);
- trg_state_selector_add_state(store, &iter, NULL,
- NULL, 0);
+ trg_state_selector_add_state(store, &iter, NULL, NULL, 0);
gtk_tree_view_set_model(GTK_TREE_VIEW(self), GTK_TREE_MODEL(store));
gtk_tree_view_set_rubber_banding(GTK_TREE_VIEW(self), TRUE);
@@ -280,9 +424,24 @@ static void trg_state_selector_init(TrgStateSelector * self)
g_signal_connect(G_OBJECT(selection), "changed",
G_CALLBACK(state_selection_changed), self);
+ g_signal_connect(self, "button-press-event",
+ G_CALLBACK(view_onButtonPressed), NULL);
+ g_signal_connect(self, "popup-menu", G_CALLBACK(view_onPopupMenu),
+ NULL);
}
-TrgStateSelector *trg_state_selector_new(void)
+TrgStateSelector *trg_state_selector_new(trg_client * client)
{
- return g_object_new(TRG_TYPE_STATE_SELECTOR, NULL);
+ GObject *obj = g_object_new(TRG_TYPE_STATE_SELECTOR, NULL);
+ TrgStateSelectorPrivate *priv = TRG_STATE_SELECTOR_GET_PRIVATE(obj);
+
+ priv->client = client;
+ priv->showDirs =
+ gconf_client_get_bool_or_true(client->gconf,
+ TRG_GCONF_KEY_FILTER_DIRS);
+ priv->showTrackers =
+ gconf_client_get_bool_or_true(client->gconf,
+ TRG_GCONF_KEY_FILTER_TRACKERS);
+
+ return TRG_STATE_SELECTOR(obj);
}