diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/main.c | 8 | ||||
-rw-r--r-- | src/torrent.c | 11 | ||||
-rw-r--r-- | src/torrent.h | 4 | ||||
-rw-r--r-- | src/transmission-remote-gtk.schemas | 13 | ||||
-rw-r--r-- | src/trg-general-panel.c | 47 | ||||
-rw-r--r-- | src/trg-main-window.c | 111 | ||||
-rw-r--r-- | src/trg-main-window.h | 1 | ||||
-rw-r--r-- | src/trg-model.h | 2 | ||||
-rw-r--r-- | src/trg-preferences-dialog.c | 32 | ||||
-rw-r--r-- | src/trg-preferences.h | 10 | ||||
-rw-r--r-- | src/trg-state-selector.c | 251 | ||||
-rw-r--r-- | src/trg-state-selector.h | 16 | ||||
-rw-r--r-- | src/trg-torrent-model.c | 7 | ||||
-rw-r--r-- | src/trg-torrent-model.h | 8 | ||||
-rw-r--r-- | src/trg-torrent-props-dialog.c | 6 | ||||
-rw-r--r-- | src/util.c | 27 | ||||
-rw-r--r-- | src/util.h | 13 |
17 files changed, 398 insertions, 169 deletions
@@ -88,10 +88,10 @@ int main(int argc, char *argv[]) gdk_threads_init(); gtk_init(&argc, &argv); - setlocale( LC_ALL, "" ); - bindtextdomain( GETTEXT_PACKAGE, TRGLOCALEDIR ); - bind_textdomain_codeset( GETTEXT_PACKAGE, "UTF-8" ); - textdomain( GETTEXT_PACKAGE ); + setlocale(LC_ALL, ""); + bindtextdomain(GETTEXT_PACKAGE, TRGLOCALEDIR); + bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); + textdomain(GETTEXT_PACKAGE); textdomain(PACKAGE_NAME); diff --git a/src/torrent.c b/src/torrent.c index c132949..f56c2bc 100644 --- a/src/torrent.c +++ b/src/torrent.c @@ -210,7 +210,7 @@ gchar *torrent_get_status_string(gint64 value) } } -gboolean torrent_has_tracker(JsonObject *t, GRegex *rx, gchar *search) +gboolean torrent_has_tracker(JsonObject * t, GRegex * rx, gchar * search) { JsonArray *trackers = torrent_get_trackers(t); int i; @@ -218,7 +218,8 @@ gboolean torrent_has_tracker(JsonObject *t, GRegex *rx, gchar *search) for (i = 0; i < json_array_get_length(trackers); i++) { JsonObject *tracker = json_array_get_object_element(trackers, i); const gchar *trackerAnnounce = tracker_get_announce(tracker); - gchar *trackerAnnounceHost = trg_uri_host_extract(rx, trackerAnnounce); + gchar *trackerAnnounceHost = + trg_gregex_get_first(rx, trackerAnnounce); int cmpResult = g_strcmp0(trackerAnnounceHost, search); g_free(trackerAnnounceHost); if (cmpResult == 0) @@ -238,6 +239,12 @@ gint64 tracker_get_tier(JsonObject * t) return json_object_get_int_member(t, FIELD_TIER); } +gchar *torrent_get_download_dir_short(JsonObject * t, GRegex * rx) +{ + const gchar *dir = torrent_get_download_dir(t); + return trg_gregex_get_first(rx, dir); +} + gint64 torrent_get_left_until_done(JsonObject * t) { return json_object_get_int_member(t, FIELD_LEFTUNTILDONE); diff --git a/src/torrent.h b/src/torrent.h index 226cd4e..f8f7d47 100644 --- a/src/torrent.h +++ b/src/torrent.h @@ -31,6 +31,7 @@ #define TORRENT_FLAG_DOWNLOADING (1 << 6) /* 0x32 */ #define TORRENT_FLAG_PAUSED (1 << 7) /* 0x64 */ #define FILTER_FLAG_TRACKER (1 << 8) /* 0x128 */ +#define FILTER_FLAG_DIR (1 << 9) /* 0x256 */ gint64 torrent_get_size(JsonObject * t); const gchar *torrent_get_name(JsonObject * t); @@ -41,6 +42,7 @@ gint64 torrent_get_uploaded(JsonObject * t); gint64 torrent_get_downloaded(JsonObject * t); const gchar *torrent_get_errorstr(JsonObject * t); const gchar *torrent_get_download_dir(JsonObject * t); +gchar *torrent_get_download_dir_short(JsonObject * t, GRegex * rx); gint64 torrent_get_have_unchecked(JsonObject * t); gint64 torrent_get_have_valid(JsonObject * t); gint64 torrent_get_status(JsonObject * t); @@ -68,7 +70,7 @@ gboolean torrent_get_download_limited(JsonObject * t); gdouble torrent_get_seed_ratio_limit(JsonObject * t); gint64 torrent_get_seed_ratio_mode(JsonObject * t); gint64 torrent_get_peer_limit(JsonObject * t); -gboolean torrent_has_tracker(JsonObject *t, GRegex *rx, gchar *search); +gboolean torrent_has_tracker(JsonObject * t, GRegex * rx, gchar * search); JsonArray *get_torrents(JsonObject * response); diff --git a/src/transmission-remote-gtk.schemas b/src/transmission-remote-gtk.schemas index def8fe2..6e8f784 100644 --- a/src/transmission-remote-gtk.schemas +++ b/src/transmission-remote-gtk.schemas @@ -28,19 +28,6 @@ </schema> <schema> - <key>/schemas/apps/transmission-remote-gtk/show-graph</key> - <applyto>/apps/transmission-remote-gtk/show-graph</applyto> - <owner>transmission-remote-gtk</owner> - <type>bool</type> - <default>1</default> - - <locale name="C"> - <short>Show graph</short> - <long>Show graph</long> - </locale> - </schema> - - <schema> <key>/schemas/apps/transmission-remote-gtk/ssl</key> <applyto>/apps/transmission-remote-gtk/ssl</applyto> <owner>transmission-remote-gtk</owner> diff --git a/src/trg-general-panel.c b/src/trg-general-panel.c index 3c3b5a2..2e6ed83 100644 --- a/src/trg-general-panel.c +++ b/src/trg-general-panel.c @@ -37,7 +37,8 @@ static void gtk_label_clear(GtkLabel * l); static GtkLabel *gen_panel_label_get_key_label(GtkLabel * l); static GtkLabel *trg_general_panel_add_label(TrgGeneralPanel * gp, - char *key, guint col, guint row); + char *key, guint col, + guint row); G_DEFINE_TYPE(TrgGeneralPanel, trg_general_panel, GTK_TYPE_TABLE) #define TRG_GENERAL_PANEL_GET_PRIVATE(o) \ @@ -186,36 +187,48 @@ void trg_general_panel_update(TrgGeneralPanel * panel, JsonObject * t, gtk_label_set_text(GTK_LABEL(priv->gen_leechers_label), buf); } -static GtkLabel *trg_general_panel_add_label_with_width(TrgGeneralPanel *gp, - char *key, guint col, guint row, gint width) +static GtkLabel *trg_general_panel_add_label_with_width(TrgGeneralPanel * + gp, char *key, + guint col, + guint row, + gint width) { GtkWidget *value, *keyLabel, *alignment; - int startCol = (col == 0) ? 0 : col*2; + int startCol = (col == 0) ? 0 : col * 2; alignment = gtk_alignment_new(0, 0, 0, 0); keyLabel = gtk_label_new(NULL); if (strlen(key) > 0) { gchar *keyMarkup = - g_markup_printf_escaped(strlen(key) > 0 ? "<b>%s:</b>" : "", key); + g_markup_printf_escaped(strlen(key) > 0 ? "<b>%s:</b>" : "", + key); gtk_label_set_markup(GTK_LABEL(keyLabel), keyMarkup); g_free(keyMarkup); } gtk_container_add(GTK_CONTAINER(alignment), keyLabel); - gtk_table_attach(GTK_TABLE(gp), alignment, startCol, startCol+1, row, row+1, GTK_FILL, 0, TRG_GENERAL_PANEL_SPACING_X, TRG_GENERAL_PANEL_SPACING_Y); + gtk_table_attach(GTK_TABLE(gp), alignment, startCol, startCol + 1, row, + row + 1, GTK_FILL, 0, TRG_GENERAL_PANEL_SPACING_X, + TRG_GENERAL_PANEL_SPACING_Y); alignment = gtk_alignment_new(0, 0, 0, 0); value = gtk_label_new(NULL); g_object_set_data(G_OBJECT(value), "key-label", keyLabel); gtk_label_set_selectable(GTK_LABEL(value), TRUE); gtk_container_add(GTK_CONTAINER(alignment), value); - gtk_table_attach(GTK_TABLE(gp), alignment, startCol+1, width < 0 ? TRG_GENERAL_PANEL_COLUMNS_TOTAL-1 : startCol+1+width, row, row+1, GTK_FILL | GTK_SHRINK, 0, TRG_GENERAL_PANEL_SPACING_X, TRG_GENERAL_PANEL_SPACING_Y); + gtk_table_attach(GTK_TABLE(gp), alignment, startCol + 1, + width < + 0 ? TRG_GENERAL_PANEL_COLUMNS_TOTAL - 1 : startCol + + 1 + width, row, row + 1, GTK_FILL | GTK_SHRINK, 0, + TRG_GENERAL_PANEL_SPACING_X, + TRG_GENERAL_PANEL_SPACING_Y); return GTK_LABEL(value); } -static GtkLabel *trg_general_panel_add_label(TrgGeneralPanel *gp, - char *key, guint col, guint row) +static GtkLabel *trg_general_panel_add_label(TrgGeneralPanel * gp, + char *key, guint col, + guint row) { return trg_general_panel_add_label_with_width(gp, key, col, row, 1); } @@ -225,9 +238,8 @@ static void trg_general_panel_init(TrgGeneralPanel * self) TrgGeneralPanelPrivate *priv = TRG_GENERAL_PANEL_GET_PRIVATE(self); int i; - g_object_set(G_OBJECT(self), "n-columns", TRG_GENERAL_PANEL_COLUMNS_TOTAL, - "n-rows", 7, - NULL); + g_object_set(G_OBJECT(self), "n-columns", + TRG_GENERAL_PANEL_COLUMNS_TOTAL, "n-rows", 7, NULL); priv->gen_name_label = trg_general_panel_add_label_with_width(self, _("Name"), 0, 0, -1); @@ -259,12 +271,17 @@ static void trg_general_panel_init(TrgGeneralPanel * self) trg_general_panel_add_label(self, _("Ratio"), 1, 4); priv->gen_downloaddir_label = - trg_general_panel_add_label_with_width(self, _("Location"), 0, 5, -1); + trg_general_panel_add_label_with_width(self, _("Location"), 0, 5, + -1); - priv->gen_error_label = trg_general_panel_add_label_with_width(self, "", 0, 6, -1); + priv->gen_error_label = + trg_general_panel_add_label_with_width(self, "", 0, 6, -1); for (i = 0; i < TRG_GENERAL_PANEL_COLUMNS_TOTAL; i++) - gtk_table_set_col_spacing(GTK_TABLE(self), i, i % 2 == 0 ? TRG_GENERAL_PANEL_WIDTH_FROM_KEY : TRG_GENERAL_PANEL_WIDTH_FROM_VALUE); + gtk_table_set_col_spacing(GTK_TABLE(self), i, + i % 2 == + 0 ? TRG_GENERAL_PANEL_WIDTH_FROM_KEY : + TRG_GENERAL_PANEL_WIDTH_FROM_VALUE); gtk_widget_set_sensitive(GTK_WIDGET(self), FALSE); } diff --git a/src/trg-main-window.c b/src/trg-main-window.c index 1b67687..821f267 100644 --- a/src/trg-main-window.c +++ b/src/trg-main-window.c @@ -72,8 +72,7 @@ static gboolean update_selected_torrent_notebook(TrgMainWindow * win, static void torrent_event_notification(TrgTorrentModel * model, gchar * icon, gchar * desc, gint tmout, gchar * prefKey, - GtkTreeIter * iter, - gpointer data); + GtkTreeIter * iter, gpointer data); static void on_torrent_completed(TrgTorrentModel * model, GtkTreeIter * iter, gpointer data); static void on_torrent_added(TrgTorrentModel * model, GtkTreeIter * iter, @@ -309,21 +308,23 @@ static void on_torrent_completed(TrgTorrentModel * model, GtkTreeIter * iter, gpointer data) { torrent_event_notification(model, GTK_STOCK_APPLY, - "This torrent has completed.", TORRENT_COMPLETE_NOTIFY_TMOUT, + _("This torrent has completed."), + TORRENT_COMPLETE_NOTIFY_TMOUT, TRG_GCONF_KEY_COMPLETE_NOTIFY, iter, data); } -static void on_torrent_addremove(TrgTorrentModel *model, gpointer data) +static void on_torrent_addremove(TrgTorrentModel * model, gpointer data) { TrgMainWindowPrivate *priv = TRG_MAIN_WINDOW_GET_PRIVATE(data); - trg_state_selector_update_trackers(priv->stateSelector, priv->client->torrents, priv->client->updateSerial); + trg_state_selector_update(priv->stateSelector); } static void on_torrent_added(TrgTorrentModel * model, GtkTreeIter * iter, gpointer data) { torrent_event_notification(model, GTK_STOCK_ADD, - "This torrent has been added.", TORRENT_ADD_NOTIFY_TMOUT, + _("This torrent has been added."), + TORRENT_ADD_NOTIFY_TMOUT, TRG_GCONF_KEY_ADD_NOTIFY, iter, data); } @@ -902,14 +903,12 @@ static void on_session_get(JsonObject * response, int status, static void on_torrent_get(JsonObject * response, int mode, int status, gpointer data) { + TrgMainWindowPrivate *priv = TRG_MAIN_WINDOW_GET_PRIVATE(data); + + trg_client *client = priv->client; trg_torrent_model_update_stats stats; - TrgMainWindowPrivate *priv; - trg_client *client; gboolean first; - priv = TRG_MAIN_WINDOW_GET_PRIVATE(data); - client = priv->client; - /* Disconnected between request and response callback */ if (client->session == NULL) { response_unref(response); @@ -1011,11 +1010,8 @@ trg_main_window_update_notebook_displays(TrgMainWindow * win, GtkTreeIter * iter, gboolean first) { - TrgMainWindowPrivate *priv; - trg_client *client; - - priv = TRG_MAIN_WINDOW_GET_PRIVATE(win); - client = priv->client; + TrgMainWindowPrivate *priv = TRG_MAIN_WINDOW_GET_PRIVATE(win); + trg_client *client = priv->client; trg_general_panel_update(priv->genDetails, t, iter); trg_trackers_model_update(priv->trackersModel, client->updateSerial, t, @@ -1039,46 +1035,57 @@ trg_torrent_tree_view_visible_func(GtkTreeModel * model, GtkTreeIter * iter, gpointer data) { guint flags; - gchar *name = NULL; - gboolean visible = TRUE; + gboolean visible; + gchar *name; + const gchar *filterText; TrgMainWindowPrivate *priv = TRG_MAIN_WINDOW_GET_PRIVATE(data); guint32 criteria = trg_state_selector_get_flag(priv->stateSelector); - gtk_tree_model_get(model, iter, - TORRENT_COLUMN_FLAGS, &flags, - TORRENT_COLUMN_NAME, &name, -1); + gtk_tree_model_get(model, iter, TORRENT_COLUMN_FLAGS, &flags, -1); if (criteria != 0) { if (criteria & FILTER_FLAG_TRACKER) { - gchar *text = trg_state_selector_get_selected_text(priv->stateSelector); + gchar *text = + trg_state_selector_get_selected_text(priv->stateSelector); JsonObject *json = NULL; - gtk_tree_model_get(model, iter, TORRENT_COLUMN_JSON, &json, -1); - - if (!torrent_has_tracker(json, trg_state_selector_get_url_host_regex(priv->stateSelector), text)) - visible = FALSE; + gtk_tree_model_get(model, iter, TORRENT_COLUMN_JSON, &json, + -1); + + if (!torrent_has_tracker + (json, + trg_state_selector_get_url_host_regex + (priv->stateSelector), text)) + return FALSE; + } else if (criteria & FILTER_FLAG_DIR) { + gchar *text = + trg_state_selector_get_selected_text(priv->stateSelector); + JsonObject *json = NULL; + gtk_tree_model_get(model, iter, TORRENT_COLUMN_JSON, &json, + -1); + if (g_strcmp0(text, torrent_get_download_dir(json))) + return FALSE; } else if (!(flags & criteria)) { - visible = FALSE; + return FALSE; } } - if (visible && name != NULL) { - const gchar *filterText = - gtk_entry_get_text(GTK_ENTRY(priv->filterEntry)); - if (strlen(filterText) > 0) { - gchar *filterCmp = g_utf8_casefold(filterText, -1); - gchar *nameCmp = g_utf8_casefold(name, -1); + visible = TRUE; + name = NULL; - if (!strstr(nameCmp, filterCmp)) - visible = FALSE; + gtk_tree_model_get(model, iter, TORRENT_COLUMN_NAME, &name, -1); + filterText = gtk_entry_get_text(GTK_ENTRY(priv->filterEntry)); + if (strlen(filterText) > 0) { + gchar *filterCmp = g_utf8_casefold(filterText, -1); + gchar *nameCmp = g_utf8_casefold(name, -1); - g_free(filterCmp); - g_free(nameCmp); - } + if (!strstr(nameCmp, filterCmp)) + visible = FALSE; + g_free(filterCmp); + g_free(nameCmp); } - g_free(name); return visible; @@ -1226,13 +1233,14 @@ void trg_main_window_conn_changed(TrgMainWindow * win, gboolean connected) connected); gtk_widget_set_sensitive(GTK_WIDGET(priv->genDetails), connected);; - if (connected == FALSE) { + if (!connected) { json_object_unref(tc->session); tc->session = NULL; gtk_list_store_clear(GTK_LIST_STORE(priv->torrentModel)); trg_main_window_torrent_scrub(win); trg_torrent_graph_set_nothing(priv->graph); + trg_state_selector_disconnect(priv->stateSelector); } } @@ -1736,6 +1744,12 @@ void trg_main_window_add_status_icon(TrgMainWindow * win) G_CALLBACK(trg_status_icon_popup_menu_cb), win); } +TrgStateSelector *trg_main_window_get_state_selector(TrgMainWindow * win) +{ + TrgMainWindowPrivate *priv = TRG_MAIN_WINDOW_GET_PRIVATE(win); + return priv->stateSelector; +} + static GObject *trg_main_window_constructor(GType type, guint n_construct_properties, @@ -1749,7 +1763,6 @@ static GObject *trg_main_window_constructor(GType type, GtkWidget *toolbarHbox; GtkIconTheme *theme; gint width, height; - GError *error = NULL; gboolean tray; self = TRG_MAIN_WINDOW(G_OBJECT_CLASS @@ -1781,7 +1794,7 @@ static GObject *trg_main_window_constructor(GType type, g_signal_connect(priv->torrentModel, "torrent-added", G_CALLBACK(on_torrent_added), self); g_signal_connect(priv->torrentModel, "torrent-addremove", - G_CALLBACK(on_torrent_addremove), self); + G_CALLBACK(on_torrent_addremove), self); priv->filteredTorrentModel = gtk_tree_model_filter_new(GTK_TREE_MODEL(priv->torrentModel), @@ -1856,9 +1869,10 @@ static GObject *trg_main_window_constructor(GType type, gtk_box_pack_start(GTK_BOX(outerVbox), priv->vpaned, TRUE, TRUE, 0); gtk_paned_pack1(GTK_PANED(priv->vpaned), priv->hpaned, TRUE, TRUE); - priv->stateSelector = trg_state_selector_new(); + priv->stateSelector = trg_state_selector_new(priv->client); gtk_paned_pack1(GTK_PANED(priv->hpaned), - GTK_WIDGET(priv->stateSelector), FALSE, FALSE); + my_scrolledwin_new(GTK_WIDGET(priv->stateSelector)), + FALSE, FALSE); gtk_paned_pack2(GTK_PANED(priv->hpaned), my_scrolledwin_new(GTK_WIDGET @@ -1874,13 +1888,8 @@ static GObject *trg_main_window_constructor(GType type, gtk_paned_pack2(GTK_PANED(priv->vpaned), priv->notebook, FALSE, FALSE); tray = - gconf_client_get_bool(priv->client->gconf, - TRG_GCONF_KEY_SYSTEM_TRAY, &error); - if (error) { - g_error_free(error); - tray = TRUE; - } - + gconf_client_get_bool_or_true(priv->client->gconf, + TRG_GCONF_KEY_SYSTEM_TRAY); if (tray) { trg_main_window_add_status_icon(self); } else { diff --git a/src/trg-main-window.h b/src/trg-main-window.h index cdba421..09a2439 100644 --- a/src/trg-main-window.h +++ b/src/trg-main-window.h @@ -71,6 +71,7 @@ void trg_main_window_add_status_icon(TrgMainWindow * win); void trg_main_window_remove_status_icon(TrgMainWindow * win); void trg_main_window_add_graph(TrgMainWindow * win, gboolean show); void trg_main_window_remove_graph(TrgMainWindow * win); +TrgStateSelector *trg_main_window_get_state_selector(TrgMainWindow * win); G_END_DECLS #endif /* MAIN_WINDOW_H_ */ diff --git a/src/trg-model.h b/src/trg-model.h index 987cfca..9059303 100644 --- a/src/trg-model.h +++ b/src/trg-model.h @@ -23,7 +23,7 @@ #include <gtk/gtk.h> guint trg_model_remove_removed(GtkListStore * model, gint serial_column, - gint64 currentSerial); + gint64 currentSerial); gboolean find_existing_model_item(GtkTreeModel * model, gint search_column, diff --git a/src/trg-preferences-dialog.c b/src/trg-preferences-dialog.c index b4546fa..c20c2cf 100644 --- a/src/trg-preferences-dialog.c +++ b/src/trg-preferences-dialog.c @@ -208,7 +208,23 @@ static GtkWidget *new_entry(GConfClient * gconf, const char *key) return w; } -static void toggle_show_graph(GtkToggleButton * w, gpointer win) +static void toggle_filter_trackers(GtkToggleButton * w, gpointer win) +{ + TrgStateSelector *selector = + trg_main_window_get_state_selector(TRG_MAIN_WINDOW(win)); + trg_state_selector_set_show_trackers(selector, + gtk_toggle_button_get_active(w)); +} + +static void toggle_filter_dirs(GtkToggleButton * w, gpointer win) +{ + TrgStateSelector *selector = + trg_main_window_get_state_selector(TRG_MAIN_WINDOW(win)); + trg_state_selector_set_show_dirs(selector, + gtk_toggle_button_get_active(w)); +} + +static void toggle_graph(GtkToggleButton * w, gpointer win) { if (gtk_toggle_button_get_active(w)) trg_main_window_add_graph(TRG_MAIN_WINDOW(win), TRUE); @@ -234,9 +250,21 @@ static GtkWidget *trg_prefs_desktopPage(GConfClient * gconf, hig_workarea_add_section_title(t, &row, _("Features")); + w = new_check_button(gconf, _("Directory filters"), + TRG_GCONF_KEY_FILTER_DIRS); + g_signal_connect(G_OBJECT(w), "toggled", + G_CALLBACK(toggle_filter_dirs), win); + hig_workarea_add_wide_control(t, &row, w); + + w = new_check_button(gconf, _("Tracker filters"), + TRG_GCONF_KEY_FILTER_TRACKERS); + g_signal_connect(G_OBJECT(w), "toggled", + G_CALLBACK(toggle_filter_trackers), win); + hig_workarea_add_wide_control(t, &row, w); + w = new_check_button(gconf, _("Show graph"), TRG_GCONF_KEY_SHOW_GRAPH); g_signal_connect(G_OBJECT(w), "toggled", - G_CALLBACK(toggle_show_graph), win); + G_CALLBACK(toggle_graph), win); hig_workarea_add_wide_control(t, &row, w); hig_workarea_add_section_title(t, &row, _("System Tray")); diff --git a/src/trg-preferences.h b/src/trg-preferences.h index c2c43b4..6702de0 100644 --- a/src/trg-preferences.h +++ b/src/trg-preferences.h @@ -28,11 +28,13 @@ #define TRG_GCONF_KEY_SSL "/apps/transmission-remote-gtk/ssl" #define TRG_GCONF_KEY_UPDATE_INTERVAL "/apps/transmission-remote-gtk/update-interval" #define TRG_GCONF_KEY_COMPLETE_NOTIFY "/apps/transmission-remote-gtk/complete-notify" -#define TRG_GCONF_KEY_ADD_NOTIFY "/apps/transmission-remote-gtk/add-notify" +#define TRG_GCONF_KEY_ADD_NOTIFY "/apps/transmission-remote-gtk/add-notify" #define TRG_GCONF_KEY_WINDOW_WIDTH "/apps/transmission-remote-gtk/window-width" -#define TRG_GCONF_KEY_WINDOW_HEIGHT "/apps/transmission-remote-gtk/window-height" -#define TRG_GCONF_KEY_SYSTEM_TRAY "/apps/transmission-remote-gtk/system-tray" -#define TRG_GCONF_KEY_SHOW_GRAPH "/apps/transmission-remote-gtk/show-graph" +#define TRG_GCONF_KEY_WINDOW_HEIGHT "/apps/transmission-remote-gtk/window-height" +#define TRG_GCONF_KEY_SYSTEM_TRAY "/apps/transmission-remote-gtk/system-tray" +#define TRG_GCONF_KEY_SHOW_GRAPH "/apps/transmission-remote-gtk/show-graph" #define TRG_GCONF_KEY_SYSTEM_TRAY_MINIMISE "/apps/transmission-remote-gtk/system-tray-minimise" +#define TRG_GCONF_KEY_FILTER_TRACKERS "/apps/transmission-remote-gtk/filter-trackers" +#define TRG_GCONF_KEY_FILTER_DIRS "/apps/transmission-remote-gtk/filter-dirs" #endif /* TRG_PREFERENCES_H_ */ 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, ¤tSerial, -1); + gtk_tree_model_get(model, &iter, STATE_SELECTOR_SERIAL, ¤tSerial, + -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); } diff --git a/src/trg-state-selector.h b/src/trg-state-selector.h index d09d76a..30a1455 100644 --- a/src/trg-state-selector.h +++ b/src/trg-state-selector.h @@ -24,6 +24,8 @@ #include <glib-object.h> #include <json-glib/json-glib.h> +#include "trg-client.h" + enum { STATE_SELECTOR_ICON, STATE_SELECTOR_NAME, @@ -52,16 +54,20 @@ typedef struct { GtkTreeViewClass parent_class; void (*torrent_state_changed) (TrgStateSelector * selector, - guint flag, gpointer data); + guint flag, gpointer data); } TrgStateSelectorClass; GType trg_state_selector_get_type(void); -TrgStateSelector *trg_state_selector_new(void); +TrgStateSelector *trg_state_selector_new(trg_client * client); G_END_DECLS guint32 trg_state_selector_get_flag(TrgStateSelector * s); -void trg_state_selector_update_trackers(TrgStateSelector *s, JsonArray *torrents, gint64 serial); -gchar *trg_state_selector_get_selected_text(TrgStateSelector *s); -GRegex *trg_state_selector_get_url_host_regex(TrgStateSelector *s); +void trg_state_selector_update(TrgStateSelector * s); +gchar *trg_state_selector_get_selected_text(TrgStateSelector * s); +GRegex *trg_state_selector_get_url_host_regex(TrgStateSelector * s); +void trg_state_selector_disconnect(TrgStateSelector * s); +void trg_state_selector_set_show_trackers(TrgStateSelector * s, + gboolean show); +void trg_state_selector_set_show_dirs(TrgStateSelector * s, gboolean show); #endif /* TRG_STATE_LIST_H_ */ diff --git a/src/trg-torrent-model.c b/src/trg-torrent-model.c index 7fa82ae..1753619 100644 --- a/src/trg-torrent-model.c +++ b/src/trg-torrent-model.c @@ -77,8 +77,7 @@ static void trg_torrent_model_class_init(TrgTorrentModelClass * klass) G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(TrgTorrentModelClass, torrent_removed), NULL, - NULL, g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } @@ -319,7 +318,7 @@ void trg_torrent_model_update(TrgTorrentModel * model, trg_client * tc, tc->torrents = newTorrents; if (trg_model_remove_removed(GTK_LIST_STORE(model), - TORRENT_COLUMN_UPDATESERIAL, - tc->updateSerial) > 0 || added) + TORRENT_COLUMN_UPDATESERIAL, + tc->updateSerial) > 0 || added) g_signal_emit(model, signals[TMODEL_TORRENT_ADDREMOVE], 0); } diff --git a/src/trg-torrent-model.h b/src/trg-torrent-model.h index ee064d2..03ee64f 100644 --- a/src/trg-torrent-model.h +++ b/src/trg-torrent-model.h @@ -45,13 +45,11 @@ G_BEGIN_DECLS typedef struct { GtkListStoreClass parent_class; void (*torrent_completed) (TrgTorrentModel * model, - GtkTreeIter * iter, - gpointer data); + GtkTreeIter * iter, gpointer data); void (*torrent_added) (TrgTorrentModel * model, - GtkTreeIter * iter, - gpointer data); + GtkTreeIter * iter, gpointer data); - void (*torrent_removed) (TrgTorrentModel *model, gpointer data); + void (*torrent_removed) (TrgTorrentModel * model, gpointer data); } TrgTorrentModelClass; typedef struct { diff --git a/src/trg-torrent-props-dialog.c b/src/trg-torrent-props-dialog.c index 2851b7c..bf9f096 100644 --- a/src/trg-torrent-props-dialog.c +++ b/src/trg-torrent-props-dialog.c @@ -138,12 +138,10 @@ trg_torrent_props_response_cb(GtkDialog * dlg, gint res_id, (priv->seedRatioLimit), args); json_object_set_int_member(args, FIELD_SEED_RATIO_MODE, gtk_combo_box_get_active(GTK_COMBO_BOX - (priv-> - seedRatioMode))); + (priv->seedRatioMode))); json_object_set_int_member(args, FIELD_BANDWIDTH_PRIORITY, gtk_combo_box_get_active(GTK_COMBO_BOX - (priv-> - bandwidthPriorityCombo)) + (priv->bandwidthPriorityCombo)) - 1); gtk_spin_button_json_int_out(GTK_SPIN_BUTTON @@ -23,6 +23,7 @@ #include <math.h> #include <string.h> +#include <gconf/gconf-client.h> #include <glib/gi18n.h> #include <glib-object.h> #include <curl/curl.h> @@ -36,19 +37,20 @@ GRegex *trg_uri_host_regex_new(void) { - return g_regex_new("^[^:/?#]+:?//([^/?#]*)", 0, 0, NULL); + return g_regex_new("^[^:/?#]+:?//([^/?#]*)", G_REGEX_OPTIMIZE, 0, + NULL); } -gchar *trg_uri_host_extract(GRegex *rx, const gchar *uri) +gchar *trg_gregex_get_first(GRegex * rx, const gchar * src) { GMatchInfo *mi = NULL; - gchar *host = NULL; - g_regex_match (rx, uri, 0, &mi); + gchar *dst = NULL; + g_regex_match(rx, src, 0, &mi); if (mi) { - host = g_match_info_fetch(mi, 1); - g_match_info_free (mi); + dst = g_match_info_fetch(mi, 1); + g_match_info_free(mi); } - return host; + return dst; } void trg_error_dialog(GtkWindow * parent, int status, @@ -66,6 +68,17 @@ void trg_error_dialog(GtkWindow * parent, int status, g_free((gpointer) msg); } +gboolean gconf_client_get_bool_or_true(GConfClient * gconf, gchar * key) +{ + GError *error = NULL; + gboolean value = gconf_client_get_bool(gconf, key, &error); + if (error) { + g_error_free(error); + return TRUE; + } + return value; +} + const gchar *make_error_message(JsonObject * response, int status) { if (status == FAIL_JSON_DECODE) { @@ -22,6 +22,7 @@ #ifndef UTIL_H_ #define UTIL_H_ +#include <gconf/gconf-client.h> #include <glib-object.h> #include <json-glib/json-glib.h> @@ -37,7 +38,13 @@ #define GIGABYTE_FACTOR ( 1024.0 * 1024.0 * 1024.0 ) GRegex *trg_uri_host_regex_new(void); -gchar *trg_uri_host_extract(GRegex *rx, const gchar *uri); +gchar *trg_gregex_get_first(GRegex * rx, const gchar * uri); +gboolean gconf_client_get_bool_or_true(GConfClient * gconf, gchar * key); + +void response_unref(JsonObject * response); +const gchar *make_error_message(JsonObject * response, int status); +void trg_error_dialog(GtkWindow * parent, int status, + JsonObject * response); char *tr_strltime_long(char *buf, gint64 seconds, size_t buflen); char *tr_strltime_short(char *buf, gint64 seconds, size_t buflen); @@ -56,9 +63,5 @@ size_t tr_strlcpy(char *dst, const void *src, size_t siz); double tr_truncd(double x, int decimal_places); int evutil_vsnprintf(char *buf, size_t buflen, const char *format, va_list ap); -void response_unref(JsonObject * response); -const gchar *make_error_message(JsonObject * response, int status); -void trg_error_dialog(GtkWindow * parent, int status, - JsonObject * response); #endif /* UTIL_H_ */ |