/* * transmission-remote-gtk - A GTK RPC client to Transmission * Copyright (C) 2011-2013 Alan Fitton * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include #include "hig.h" #include "trg-json-widgets.h" #include "trg-preferences-dialog.h" #include "trg-persistent-tree-view.h" #include "trg-main-window.h" #include "trg-prefs.h" #include "util.h" /* UI frontend to modify configurables stored in TrgConf. * To avoid lots of repetitive code, use our own functions for creating widgets * which also create a trg_pref_widget_desc structure and add it to a list. * This contains details of the config key, config flags etc, and a function * pointer for a save/display function. These are all called on save/load. */ #define TRG_PREFERENCES_DIALOG_GET_PRIVATE(object) \ (G_TYPE_INSTANCE_GET_PRIVATE ((object), TRG_TYPE_PREFERENCES_DIALOG, TrgPreferencesDialogPrivate)) G_DEFINE_TYPE(TrgPreferencesDialog, trg_preferences_dialog, GTK_TYPE_DIALOG) enum { PROP_0, PROP_TRG_CLIENT, PROP_MAIN_WINDOW }; struct _TrgPreferencesDialogPrivate { TrgMainWindow *win; TrgClient *client; TrgPrefs *prefs; GtkWidget *profileDelButton; GtkWidget *profileComboBox; GtkWidget *profileNameEntry; GtkWidget *fullUpdateCheck; GList *widgets; GtkWidget *notebook; }; static GObject *instance = NULL; static void trg_pref_widget_desc_free(trg_pref_widget_desc * wd) { g_free(wd->key); g_free(wd); } trg_pref_widget_desc *trg_pref_widget_desc_new(GtkWidget * w, gchar * key, int flags) { trg_pref_widget_desc *desc = g_new0(trg_pref_widget_desc, 1); desc->widget = w; desc->key = g_strdup(key); desc->flags = flags; return desc; } static void trg_pref_widget_refresh(TrgPreferencesDialog * dlg, trg_pref_widget_desc * wd) { TrgPreferencesDialogPrivate *priv = TRG_PREFERENCES_DIALOG_GET_PRIVATE(dlg); wd->refreshFunc(priv->prefs, wd); } static void trg_pref_widget_refresh_all(TrgPreferencesDialog * dlg) { TrgPreferencesDialogPrivate *priv = TRG_PREFERENCES_DIALOG_GET_PRIVATE(dlg); GList *li; for (li = priv->widgets; li; li = g_list_next(li)) trg_pref_widget_refresh(dlg, (trg_pref_widget_desc *) li->data); } static void trg_pref_widget_save(TrgPreferencesDialog * dlg, trg_pref_widget_desc * wd) { TrgPreferencesDialogPrivate *priv = TRG_PREFERENCES_DIALOG_GET_PRIVATE(dlg); wd->saveFunc(priv->prefs, wd); } static void trg_pref_widget_save_all(TrgPreferencesDialog * dlg) { TrgPreferencesDialogPrivate *priv = TRG_PREFERENCES_DIALOG_GET_PRIVATE(dlg); GList *li; if (trg_prefs_get_profile(priv->prefs) == NULL) return; trg_client_configlock(priv->client); for (li = priv->widgets; li; li = g_list_next(li)) { trg_pref_widget_desc *wd = (trg_pref_widget_desc *) li->data; trg_pref_widget_save(dlg, wd); } trg_client_configunlock(priv->client); } static void trg_preferences_dialog_set_property(GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec G_GNUC_UNUSED) { TrgPreferencesDialogPrivate *priv = TRG_PREFERENCES_DIALOG_GET_PRIVATE(object); switch (prop_id) { case PROP_MAIN_WINDOW: priv->win = g_value_get_object(value); break; case PROP_TRG_CLIENT: priv->client = g_value_get_pointer(value); priv->prefs = trg_client_get_prefs(priv->client); break; } } static void trg_preferences_response_cb(GtkDialog * dlg, gint res_id, gpointer data G_GNUC_UNUSED) { TrgPreferencesDialogPrivate *priv = TRG_PREFERENCES_DIALOG_GET_PRIVATE(dlg); GList *li; if (res_id == GTK_RESPONSE_OK) { trg_pref_widget_save_all(TRG_PREFERENCES_DIALOG(dlg)); trg_prefs_save(priv->prefs); } trg_main_window_reload_dir_aliases(priv->win); for (li = priv->widgets; li; li = g_list_next(li)) trg_pref_widget_desc_free((trg_pref_widget_desc *) li->data); g_list_free(priv->widgets); gtk_widget_destroy(GTK_WIDGET(dlg)); instance = NULL; } static void trg_preferences_dialog_get_property(GObject * object, guint prop_id, GValue * value, GParamSpec * pspec G_GNUC_UNUSED) { TrgPreferencesDialogPrivate *priv = TRG_PREFERENCES_DIALOG_GET_PRIVATE(object); switch (prop_id) { case PROP_MAIN_WINDOW: g_value_set_object(value, priv->win); break; case PROP_TRG_CLIENT: g_value_set_pointer(value, priv->client); break; } } static void entry_refresh(TrgPrefs * prefs, void *wdp) { trg_pref_widget_desc *wd = (trg_pref_widget_desc *) wdp; gchar *value = trg_prefs_get_string(prefs, wd->key, wd->flags); if (value) { gtk_entry_set_text(GTK_ENTRY(wd->widget), value); g_free(value); } else { gtk_entry_set_text(GTK_ENTRY(wd->widget), ""); } } static void entry_save(TrgPrefs * prefs, void *wdp) { trg_pref_widget_desc *wd = (trg_pref_widget_desc *) wdp; trg_prefs_set_string(prefs, wd->key, gtk_entry_get_text(GTK_ENTRY(wd->widget)), wd->flags); } static GtkWidget *trgp_entry_new(TrgPreferencesDialog * dlg, gchar * key, int flags) { TrgPreferencesDialogPrivate *priv = TRG_PREFERENCES_DIALOG_GET_PRIVATE(dlg); GtkWidget *w = gtk_entry_new(); trg_pref_widget_desc *wd = trg_pref_widget_desc_new(w, key, flags); wd->saveFunc = &entry_save; wd->refreshFunc = &entry_refresh; entry_refresh(priv->prefs, wd); priv->widgets = g_list_append(priv->widgets, wd); return w; } static void check_refresh(TrgPrefs * prefs, void *wdp) { trg_pref_widget_desc *wd = (trg_pref_widget_desc *) wdp; gboolean value = trg_prefs_get_bool(prefs, wd->key, wd->flags); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wd->widget), value); } static void check_save(TrgPrefs * prefs, void *wdp) { trg_pref_widget_desc *wd = (trg_pref_widget_desc *) wdp; trg_prefs_set_bool(prefs, wd->key, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (wd->widget)), wd->flags); } static void trgp_toggle_dependent(GtkToggleButton * b, gpointer data) { gtk_widget_set_sensitive(GTK_WIDGET(data), gtk_toggle_button_get_active(b)); } static GtkWidget *trgp_check_new(TrgPreferencesDialog * dlg, const char *mnemonic, gchar * key, int flags, GtkToggleButton * dependency) { TrgPreferencesDialogPrivate *priv = TRG_PREFERENCES_DIALOG_GET_PRIVATE(dlg); GtkWidget *w = gtk_check_button_new_with_mnemonic(mnemonic); trg_pref_widget_desc *wd = trg_pref_widget_desc_new(w, key, flags); wd->saveFunc = &check_save; wd->refreshFunc = &check_refresh; check_refresh(priv->prefs, wd); if (dependency) { g_signal_connect(dependency, "toggled", G_CALLBACK(trgp_toggle_dependent), w); gtk_widget_set_sensitive(w, gtk_toggle_button_get_active(dependency)); } priv->widgets = g_list_append(priv->widgets, wd); return w; } static void spin_refresh(TrgPrefs * prefs, void *wdp) { trg_pref_widget_desc *wd = (trg_pref_widget_desc *) wdp; GtkWidget *widget = wd->widget; gint value = trg_prefs_get_int(prefs, wd->key, wd->flags); gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), value); } static void spin_save(TrgPrefs * prefs, void *wdp) { trg_pref_widget_desc *wd = (trg_pref_widget_desc *) wdp; trg_prefs_set_int(prefs, wd->key, gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON (wd->widget)), wd->flags); } static GtkWidget *trgp_spin_new(TrgPreferencesDialog * dlg, gchar * key, int low, int high, int step, int flags, GtkToggleButton * dependency) { TrgPreferencesDialogPrivate *priv = TRG_PREFERENCES_DIALOG_GET_PRIVATE(dlg); GtkWidget *w = gtk_spin_button_new_with_range(low, high, step); trg_pref_widget_desc *wd = trg_pref_widget_desc_new(w, key, flags); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(w), 0); wd->saveFunc = &spin_save; wd->refreshFunc = &spin_refresh; if (dependency) { g_signal_connect(dependency, "toggled", G_CALLBACK(trgp_toggle_dependent), w); gtk_widget_set_sensitive(w, gtk_toggle_button_get_active(dependency)); } spin_refresh(priv->prefs, wd); priv->widgets = g_list_append(priv->widgets, wd); return w; } 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)); } #if TRG_WITH_GRAPH 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); else trg_main_window_remove_graph(TRG_MAIN_WINDOW(win)); } #endif static void toggle_tray_icon(GtkToggleButton * w, gpointer win) { if (gtk_toggle_button_get_active(w)) trg_main_window_add_status_icon(TRG_MAIN_WINDOW(win)); else trg_main_window_remove_status_icon(TRG_MAIN_WINDOW(win)); } static void menu_bar_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 view_states_toggled_cb(GtkToggleButton * w, gpointer data) { GtkWidget *scroll = gtk_widget_get_parent(GTK_WIDGET (trg_main_window_get_state_selector (TRG_MAIN_WINDOW(data)))); trg_widget_set_visible(scroll, gtk_toggle_button_get_active(w)); } static void notebook_toggled_cb(GtkToggleButton * b, gpointer data) { trg_main_window_notebook_set_visible(TRG_MAIN_WINDOW(data), gtk_toggle_button_get_active(b)); } static void trgp_double_special_dependent(GtkWidget * widget, gpointer data) { TrgPreferencesDialogPrivate *priv = TRG_PREFERENCES_DIALOG_GET_PRIVATE(gtk_widget_get_toplevel (widget)); gtk_widget_set_sensitive(GTK_WIDGET(data), gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget)) && gtk_widget_get_sensitive (priv->fullUpdateCheck) && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (priv-> fullUpdateCheck))); } static GtkWidget *trg_prefs_generalPage(TrgPreferencesDialog * dlg) { TrgPreferencesDialogPrivate *priv = TRG_PREFERENCES_DIALOG_GET_PRIVATE(dlg); GtkWidget *w, *activeOnly, *t; guint row = 0; t = hig_workarea_create(); hig_workarea_add_section_title(t, &row, _("Updates")); activeOnly = w = trgp_check_new(dlg, _("Update active torrents only"), TRG_PREFS_KEY_UPDATE_ACTIVE_ONLY, TRG_PREFS_PROFILE, NULL); hig_workarea_add_wide_control(t, &row, w); priv->fullUpdateCheck = trgp_check_new(dlg, _ ("Full update every (?) updates"), TRG_PREFS_ACTIVEONLY_FULLSYNC_ENABLED, TRG_PREFS_PROFILE, GTK_TOGGLE_BUTTON(activeOnly)); w = trgp_spin_new(dlg, TRG_PREFS_ACTIVEONLY_FULLSYNC_EVERY, 2, INT_MAX, 1, TRG_PREFS_PROFILE, GTK_TOGGLE_BUTTON(priv->fullUpdateCheck)); g_signal_connect(activeOnly, "toggled", G_CALLBACK(trgp_double_special_dependent), w); hig_workarea_add_row_w(t, &row, priv->fullUpdateCheck, w, NULL); w = trgp_spin_new(dlg, TRG_PREFS_KEY_UPDATE_INTERVAL, 1, INT_MAX, 1, TRG_PREFS_PROFILE, NULL); hig_workarea_add_row(t, &row, _("Update interval:"), w, NULL); w = trgp_spin_new(dlg, TRG_PREFS_KEY_MINUPDATE_INTERVAL, 1, INT_MAX, 1, TRG_PREFS_PROFILE, NULL); hig_workarea_add_row(t, &row, _("Minimised update interval:"), w, NULL); w = trgp_spin_new(dlg, TRG_PREFS_KEY_SESSION_UPDATE_INTERVAL, 1, INT_MAX, 1, TRG_PREFS_PROFILE, NULL); hig_workarea_add_row(t, &row, _("Session update interval:"), w, NULL); hig_workarea_add_section_title(t, &row, _("Torrents")); w = trgp_check_new(dlg, _("Start paused"), TRG_PREFS_KEY_START_PAUSED, TRG_PREFS_GLOBAL, NULL); hig_workarea_add_wide_control(t, &row, w); w = trgp_check_new(dlg, _("Options dialog on add"), TRG_PREFS_KEY_ADD_OPTIONS_DIALOG, TRG_PREFS_GLOBAL, NULL); hig_workarea_add_wide_control(t, &row, w); w = trgp_check_new(dlg, _("Delete local .torrent file after adding"), TRG_PREFS_KEY_DELETE_LOCAL_TORRENT, TRG_PREFS_GLOBAL, NULL); hig_workarea_add_wide_control(t, &row, w); return t; } static void profile_changed_cb(GtkWidget * w, gpointer data) { TrgPreferencesDialogPrivate *priv = TRG_PREFERENCES_DIALOG_GET_PRIVATE(data); GtkTreeModel *model = gtk_combo_box_get_model(GTK_COMBO_BOX(w)); gint n_children = gtk_tree_model_iter_n_children(model, NULL); GtkTreeIter iter; JsonObject *profile; trg_pref_widget_save_all(TRG_PREFERENCES_DIALOG(data)); if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(w), &iter)) { gtk_tree_model_get(model, &iter, 0, &profile, -1); trg_prefs_set_profile(priv->prefs, profile); trg_pref_widget_refresh_all(TRG_PREFERENCES_DIALOG(data)); gtk_widget_set_sensitive(priv->profileDelButton, n_children > 1); } else { gtk_widget_set_sensitive(priv->profileDelButton, FALSE); gtk_combo_box_set_active(GTK_COMBO_BOX(w), 0); } } static void trg_prefs_profile_combo_populate(TrgPreferencesDialog * dialog, GtkComboBox * combo, TrgPrefs * prefs) { TrgPreferencesDialogPrivate *priv = TRG_PREFERENCES_DIALOG_GET_PRIVATE(dialog); gint profile_id = trg_prefs_get_int(prefs, TRG_PREFS_KEY_PROFILE_ID, TRG_PREFS_GLOBAL); GtkListStore *store = GTK_LIST_STORE(gtk_combo_box_get_model(combo)); GList *profiles = json_array_get_elements(trg_prefs_get_profiles(prefs)); GList *li; int i = 0; for (li = profiles; li; li = g_list_next(li)) { JsonObject *profile = json_node_get_object((JsonNode *) li->data); const gchar *name_value; GtkTreeIter iter; if (json_object_has_member(profile, TRG_PREFS_KEY_PROFILE_NAME)) { name_value = json_object_get_string_member(profile, TRG_PREFS_KEY_PROFILE_NAME); } else { name_value = _(TRG_PROFILE_NAME_DEFAULT); } gtk_list_store_insert_with_values(store, &iter, INT_MAX, 0, profile, 1, name_value, -1); if (i == profile_id) gtk_combo_box_set_active_iter(combo, &iter); i++; } gtk_widget_set_sensitive(priv->profileDelButton, g_list_length(profiles) > 1); g_list_free(profiles); } static GtkWidget *trg_prefs_profile_combo_new(TrgClient * tc) { GtkWidget *w; GtkCellRenderer *r; GtkListStore *store = gtk_list_store_new(2, G_TYPE_POINTER, G_TYPE_STRING); w = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store)); r = gtk_cell_renderer_text_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(w), r, FALSE); gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(w), r, "text", 1); return w; } static void name_changed_cb(GtkWidget * w, gpointer data) { TrgPreferencesDialogPrivate *priv = TRG_PREFERENCES_DIALOG_GET_PRIVATE(data); GtkTreeIter iter; GtkTreeModel *model; GtkComboBox *combo; combo = GTK_COMBO_BOX(priv->profileComboBox); model = gtk_combo_box_get_model(combo); if (gtk_combo_box_get_active_iter(combo, &iter)) { gtk_list_store_set(GTK_LIST_STORE(model), &iter, 1, gtk_entry_get_text(GTK_ENTRY(w)), -1); } } static void del_profile_cb(GtkWidget * w, gpointer data) { GtkWidget *win = gtk_widget_get_toplevel(w); TrgPreferencesDialogPrivate *priv = TRG_PREFERENCES_DIALOG_GET_PRIVATE(win); TrgPrefs *prefs = priv->prefs; GtkComboBox *combo = GTK_COMBO_BOX(data); GtkTreeModel *profileModel = gtk_combo_box_get_model(combo); GtkTreeIter iter; JsonObject *profile; if (gtk_combo_box_get_active_iter(combo, &iter)) { gtk_tree_model_get(profileModel, &iter, 0, &profile, -1); trg_prefs_del_profile(prefs, profile); trg_prefs_set_profile(prefs, NULL); gtk_list_store_remove(GTK_LIST_STORE(profileModel), &iter); gtk_combo_box_set_active(combo, 0); } } static void add_profile_cb(GtkWidget * w, gpointer data) { GtkWidget *win = gtk_widget_get_toplevel(w); TrgPreferencesDialogPrivate *priv = TRG_PREFERENCES_DIALOG_GET_PRIVATE(win); GtkComboBox *combo = GTK_COMBO_BOX(data); GtkTreeModel *profileModel = gtk_combo_box_get_model(combo); GtkTreeIter iter; JsonObject *profile = trg_prefs_new_profile(priv->prefs); gtk_list_store_insert_with_values(GTK_LIST_STORE(profileModel), &iter, INT_MAX, 0, profile, 1, _(TRG_PROFILE_NAME_DEFAULT), -1); gtk_combo_box_set_active_iter(combo, &iter); } static GtkWidget *trg_prefs_openExecPage(TrgPreferencesDialog * dlg) { TrgPreferencesDialogPrivate *priv = TRG_PREFERENCES_DIALOG_GET_PRIVATE(dlg); GtkWidget *t; TrgPersistentTreeView *ptv; GtkListStore *model; trg_pref_widget_desc *wd; guint row = 0; t = hig_workarea_create(); hig_workarea_add_section_title(t, &row, _("Commands")); model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); ptv = trg_persistent_tree_view_new(priv->prefs, model, TRG_PREFS_KEY_EXEC_COMMANDS, TRG_PREFS_CONNECTION); trg_persistent_tree_view_set_add_select(ptv, trg_persistent_tree_view_add_column (ptv, 0, TRG_PREFS_SUBKEY_LABEL, _("Label"))); trg_persistent_tree_view_add_column(ptv, 1, TRG_PREFS_KEY_EXEC_COMMANDS_SUBKEY_CMD, _("Command")); wd = trg_persistent_tree_view_get_widget_desc(ptv); trg_pref_widget_refresh(dlg, wd); priv->widgets = g_list_append(priv->widgets, wd); hig_workarea_add_wide_tall_control(t, &row, GTK_WIDGET(ptv)); return t; } #ifdef HAVE_RSS static GtkWidget *trg_prefs_rss_page(TrgPreferencesDialog * dlg) { TrgPreferencesDialogPrivate *priv = TRG_PREFERENCES_DIALOG_GET_PRIVATE(dlg); GtkWidget *t; guint row = 0; TrgPersistentTreeView *ptv; trg_pref_widget_desc *wd; GtkListStore *model; t = hig_workarea_create(); hig_workarea_add_section_title(t, &row, _("RSS Feeds")); model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); ptv = trg_persistent_tree_view_new(priv->prefs, model, TRG_PREFS_KEY_RSS, TRG_PREFS_GLOBAL); trg_persistent_tree_view_set_add_select(ptv, trg_persistent_tree_view_add_column (ptv, 0, TRG_PREFS_RSS_SUBKEY_ID, _("Name"))); trg_persistent_tree_view_add_column(ptv, 1, TRG_PREFS_RSS_SUBKEY_URL, _("URL")); wd = trg_persistent_tree_view_get_widget_desc(ptv); trg_pref_widget_refresh(dlg, wd); priv->widgets = g_list_append(priv->widgets, wd); hig_workarea_add_wide_tall_control(t, &row, GTK_WIDGET(ptv)); return t; } #endif static GtkWidget *trg_prefs_dirsPage(TrgPreferencesDialog * dlg) { TrgPreferencesDialogPrivate *priv = TRG_PREFERENCES_DIALOG_GET_PRIVATE(dlg); GtkWidget *t; TrgPersistentTreeView *ptv; GtkListStore *model; trg_pref_widget_desc *wd; guint row = 0; t = hig_workarea_create(); hig_workarea_add_section_title(t, &row, _("Remote Download Directories")); model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); ptv = trg_persistent_tree_view_new(priv->prefs, model, TRG_PREFS_KEY_DESTINATIONS, TRG_PREFS_CONNECTION); trg_persistent_tree_view_set_add_select(ptv, trg_persistent_tree_view_add_column (ptv, 0, TRG_PREFS_SUBKEY_LABEL, _("Label"))); trg_persistent_tree_view_add_column(ptv, 1, TRG_PREFS_KEY_DESTINATIONS_SUBKEY_DIR, _("Directory")); wd = trg_persistent_tree_view_get_widget_desc(ptv); trg_pref_widget_refresh(dlg, wd); priv->widgets = g_list_append(priv->widgets, wd); hig_workarea_add_wide_tall_control(t, &row, GTK_WIDGET(ptv)); return t; } static GtkWidget *trg_prefs_viewPage(TrgPreferencesDialog * dlg) { TrgPreferencesDialogPrivate *priv = TRG_PREFERENCES_DIALOG_GET_PRIVATE(dlg); GtkWidget *w, *dep, *t, *tray; guint row = 0; gboolean _is_unity = is_unity(); t = hig_workarea_create(); hig_workarea_add_section_title(t, &row, _("View")); dep = w = trgp_check_new(dlg, _("State selector"), TRG_PREFS_KEY_SHOW_STATE_SELECTOR, TRG_PREFS_GLOBAL, NULL); g_signal_connect(G_OBJECT(w), "toggled", G_CALLBACK(view_states_toggled_cb), priv->win); hig_workarea_add_wide_control(t, &row, w); w = trgp_check_new(dlg, _("Directory filters"), TRG_PREFS_KEY_FILTER_DIRS, TRG_PREFS_GLOBAL, GTK_TOGGLE_BUTTON(dep)); g_signal_connect(G_OBJECT(w), "toggled", G_CALLBACK(menu_bar_toggle_filter_dirs), priv->win); hig_workarea_add_wide_control(t, &row, w); w = trgp_check_new(dlg, _("Tracker filters"), TRG_PREFS_KEY_FILTER_TRACKERS, TRG_PREFS_GLOBAL, GTK_TOGGLE_BUTTON(dep)); g_signal_connect(G_OBJECT(w), "toggled", G_CALLBACK(toggle_filter_trackers), priv->win); hig_workarea_add_wide_control(t, &row, w); w = trgp_check_new(dlg, _("Torrent Details"), TRG_PREFS_KEY_SHOW_NOTEBOOK, TRG_PREFS_GLOBAL, NULL); g_signal_connect(G_OBJECT(w), "toggled", G_CALLBACK(notebook_toggled_cb), priv->win); hig_workarea_add_wide_control(t, &row, w); #if TRG_WITH_GRAPH w = trgp_check_new(dlg, _("Show graph"), TRG_PREFS_KEY_SHOW_GRAPH, TRG_PREFS_GLOBAL, GTK_TOGGLE_BUTTON(w)); g_signal_connect(G_OBJECT(w), "toggled", G_CALLBACK(toggle_graph), priv->win); hig_workarea_add_wide_control(t, &row, w); #endif #ifndef HAVE_LIBAPPINDICATOR if (!_is_unity) { #endif hig_workarea_add_section_title(t, &row, _("System Tray")); tray = trgp_check_new(dlg, _("Show in system tray"), TRG_PREFS_KEY_SYSTEM_TRAY, TRG_PREFS_GLOBAL, NULL); g_signal_connect(G_OBJECT(tray), "toggled", G_CALLBACK(toggle_tray_icon), priv->win); hig_workarea_add_wide_control(t, &row, tray); if (!_is_unity) { w = trgp_check_new(dlg, _("Minimise to system tray"), TRG_PREFS_KEY_SYSTEM_TRAY_MINIMISE, TRG_PREFS_GLOBAL, NULL); gtk_widget_set_sensitive(w, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(tray))); g_signal_connect(G_OBJECT(tray), "toggled", G_CALLBACK(toggle_active_arg_is_sensitive), w); hig_workarea_add_wide_control(t, &row, w); } #ifndef HAVE_LIBAPPINDICATOR } #endif #ifdef HAVE_LIBNOTIFY hig_workarea_add_section_title(t, &row, _("Notifications")); w = trgp_check_new(dlg, _("Torrent added notifications"), TRG_PREFS_KEY_ADD_NOTIFY, TRG_PREFS_GLOBAL, NULL); hig_workarea_add_wide_control(t, &row, w); w = trgp_check_new(dlg, _("Torrent complete notifications"), TRG_PREFS_KEY_COMPLETE_NOTIFY, TRG_PREFS_GLOBAL, NULL); hig_workarea_add_wide_control(t, &row, w); #endif return t; } static GtkWidget *trg_prefs_serverPage(TrgPreferencesDialog * dlg) { TrgPreferencesDialogPrivate *priv = TRG_PREFERENCES_DIALOG_GET_PRIVATE(dlg); TrgPrefs *prefs = priv->prefs; GtkWidget *w, *t, *frame, *frameHbox, *profileLabel; GtkWidget *profileButtonsHbox; guint row = 0; t = hig_workarea_create(); /* Profile */ priv->profileNameEntry = trgp_entry_new(dlg, TRG_PREFS_KEY_PROFILE_NAME, TRG_PREFS_PROFILE); priv->profileComboBox = trg_prefs_profile_combo_new(priv->client); profileLabel = gtk_label_new(_("Profile: ")); profileButtonsHbox = trg_hbox_new(FALSE, 0); w = gtk_button_new_from_stock(GTK_STOCK_NEW); g_signal_connect(w, "clicked", G_CALLBACK(add_profile_cb), priv->profileComboBox); gtk_box_pack_start(GTK_BOX(profileButtonsHbox), w, FALSE, FALSE, 4); priv->profileDelButton = gtk_button_new_from_stock(GTK_STOCK_DELETE); g_signal_connect(priv->profileDelButton, "clicked", G_CALLBACK(del_profile_cb), priv->profileComboBox); gtk_widget_set_sensitive(priv->profileDelButton, FALSE); gtk_box_pack_start(GTK_BOX(profileButtonsHbox), priv->profileDelButton, FALSE, FALSE, 4); trg_prefs_profile_combo_populate(dlg, GTK_COMBO_BOX(priv->profileComboBox), prefs); g_signal_connect(G_OBJECT(priv->profileComboBox), "changed", G_CALLBACK(profile_changed_cb), dlg); /* Name */ g_signal_connect(priv->profileNameEntry, "changed", G_CALLBACK(name_changed_cb), dlg); hig_workarea_add_row(t, &row, _("Name:"), priv->profileNameEntry, NULL); hig_workarea_add_wide_control(t, &row, profileButtonsHbox); hig_workarea_add_section_title(t, &row, _("Connection")); w = trgp_entry_new(dlg, TRG_PREFS_KEY_HOSTNAME, TRG_PREFS_PROFILE); hig_workarea_add_row(t, &row, _("Host:"), w, NULL); w = trgp_spin_new(dlg, TRG_PREFS_KEY_PORT, 1, 65535, 1, TRG_PREFS_PROFILE, NULL); hig_workarea_add_row(t, &row, _("Port:"), w, NULL); w = trgp_entry_new(dlg, TRG_PREFS_KEY_RPC_URL_PATH, TRG_PREFS_PROFILE); hig_workarea_add_row(t, &row, _("RPC URL Path:"), w, NULL); w = trgp_entry_new(dlg, TRG_PREFS_KEY_USERNAME, TRG_PREFS_PROFILE); hig_workarea_add_row(t, &row, _("Username:"), w, NULL); w = trgp_entry_new(dlg, TRG_PREFS_KEY_PASSWORD, TRG_PREFS_PROFILE); gtk_entry_set_visibility(GTK_ENTRY(w), FALSE); hig_workarea_add_row(t, &row, _("Password:"), w, NULL); w = trgp_check_new(dlg, _("Automatically connect"), TRG_PREFS_KEY_AUTO_CONNECT, TRG_PREFS_PROFILE, NULL); hig_workarea_add_wide_control(t, &row, w); #ifndef CURL_NO_SSL w = trgp_check_new(dlg, _("SSL"), TRG_PREFS_KEY_SSL, TRG_PREFS_PROFILE, NULL); hig_workarea_add_wide_control(t, &row, w); w = trgp_check_new(dlg, _("Validate SSL Certificate"), TRG_PREFS_KEY_SSL_VALIDATE, TRG_PREFS_PROFILE, w); hig_workarea_add_wide_control(t, &row, w); #endif w = trgp_spin_new(dlg, TRG_PREFS_KEY_TIMEOUT, 1, 3600, 1, TRG_PREFS_PROFILE, NULL); hig_workarea_add_row(t, &row, _("Timeout:"), w, NULL); w = trgp_spin_new(dlg, TRG_PREFS_KEY_RETRIES, 0, 3600, 1, TRG_PREFS_PROFILE, NULL); hig_workarea_add_row(t, &row, _("Retries:"), w, NULL); frame = gtk_frame_new(NULL); frameHbox = trg_hbox_new(FALSE, 2); gtk_box_pack_start(GTK_BOX(frameHbox), profileLabel, FALSE, FALSE, 2); gtk_box_pack_start(GTK_BOX(frameHbox), priv->profileComboBox, FALSE, FALSE, 4); gtk_frame_set_label_widget(GTK_FRAME(frame), frameHbox); gtk_container_set_border_width(GTK_CONTAINER(frame), 5); gtk_container_add(GTK_CONTAINER(frame), t); return frame; } static GObject *trg_preferences_dialog_constructor(GType type, guint n_construct_properties, GObjectConstructParam * construct_params) { GObject *object; TrgPreferencesDialogPrivate *priv; GtkWidget *notebook, *contentvbox; object = G_OBJECT_CLASS (trg_preferences_dialog_parent_class)->constructor(type, n_construct_properties, construct_params); priv = TRG_PREFERENCES_DIALOG_GET_PRIVATE(object); contentvbox = gtk_dialog_get_content_area(GTK_DIALOG(object)); gtk_window_set_transient_for(GTK_WINDOW(object), GTK_WINDOW(priv->win)); gtk_window_set_destroy_with_parent(GTK_WINDOW(object), TRUE); gtk_dialog_add_button(GTK_DIALOG(object), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE); gtk_dialog_add_button(GTK_DIALOG(object), GTK_STOCK_OK, GTK_RESPONSE_OK); gtk_dialog_set_default_response(GTK_DIALOG(object), GTK_RESPONSE_OK); gtk_window_set_title(GTK_WINDOW(object), _("Local Preferences")); gtk_container_set_border_width(GTK_CONTAINER(object), GUI_PAD); g_signal_connect(G_OBJECT(object), "response", G_CALLBACK(trg_preferences_response_cb), NULL); notebook = priv->notebook = gtk_notebook_new(); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), trg_prefs_serverPage(TRG_PREFERENCES_DIALOG (object)), gtk_label_new(_("Connection"))); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), trg_prefs_generalPage(TRG_PREFERENCES_DIALOG (object)), gtk_label_new(_("General"))); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), trg_prefs_viewPage(TRG_PREFERENCES_DIALOG (object)), gtk_label_new(_("View"))); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), trg_prefs_openExecPage(TRG_PREFERENCES_DIALOG (object)), gtk_label_new(_("Actions"))); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), trg_prefs_dirsPage(TRG_PREFERENCES_DIALOG (object)), gtk_label_new(_("Directories"))); #ifdef HAVE_RSS gtk_notebook_append_page(GTK_NOTEBOOK(notebook), trg_prefs_rss_page(TRG_PREFERENCES_DIALOG (object)), gtk_label_new(_("RSS Feeds"))); #endif gtk_container_set_border_width(GTK_CONTAINER(notebook), GUI_PAD); gtk_box_pack_start(GTK_BOX(contentvbox), notebook, TRUE, TRUE, 0); return object; } void trg_preferences_dialog_set_page(TrgPreferencesDialog *pref_dlg, guint page) { TrgPreferencesDialogPrivate *priv = TRG_PREFERENCES_DIALOG_GET_PRIVATE(pref_dlg); gtk_notebook_set_current_page(GTK_NOTEBOOK(priv->notebook), page); } static void trg_preferences_dialog_init(TrgPreferencesDialog * pref_dlg) { } static void trg_preferences_dialog_class_init(TrgPreferencesDialogClass * class) { GObjectClass *g_object_class = (GObjectClass *) class; g_object_class->constructor = trg_preferences_dialog_constructor; g_object_class->set_property = trg_preferences_dialog_set_property; g_object_class->get_property = trg_preferences_dialog_get_property; g_object_class_install_property(g_object_class, PROP_TRG_CLIENT, g_param_spec_pointer("trg-client", "TClient", "Client", G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); g_object_class_install_property(g_object_class, PROP_MAIN_WINDOW, g_param_spec_object("main-window", "Main Window", "Main Window", TRG_TYPE_MAIN_WINDOW, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); g_type_class_add_private(g_object_class, sizeof(TrgPreferencesDialogPrivate)); } GtkWidget *trg_preferences_dialog_get_instance(TrgMainWindow * win, TrgClient * client) { if (!instance) instance = g_object_new(TRG_TYPE_PREFERENCES_DIALOG, "main-window", win, "trg-client", client, NULL); return GTK_WIDGET(instance); }