From 34c56c7db7c57f5db0184489d01866902e992300 Mon Sep 17 00:00:00 2001 From: Alan Fitton Date: Fri, 21 Oct 2011 23:12:21 +0000 Subject: make the execute command tree view in preferences a generic widget, the "persistent tree view" --- src/Makefile.am | 1 + src/trg-client.c | 12 ++ src/trg-client.h | 2 + src/trg-destination-combo.c | 22 ++- src/trg-destination-combo.h | 1 + src/trg-persistent-tree-view.c | 368 +++++++++++++++++++++++++++++++++++++++++ src/trg-persistent-tree-view.h | 77 +++++++++ src/trg-preferences-dialog.c | 220 +++++------------------- src/trg-preferences-dialog.h | 3 + src/trg-prefs.h | 5 +- src/trg-torrent-add-dialog.c | 4 +- src/trg-torrent-move-dialog.c | 4 +- 12 files changed, 534 insertions(+), 185 deletions(-) create mode 100644 src/trg-persistent-tree-view.c create mode 100644 src/trg-persistent-tree-view.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 476bab0..5c5741d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -39,6 +39,7 @@ transmission_remote_gtk_SOURCES = main.c \ trg-peers-model.c \ trg-peers-tree-view.c \ trg-model.c \ + trg-persistent-tree-view.c \ trg-files-model.c \ trg-files-tree-view.c \ trg-state-selector.c \ diff --git a/src/trg-client.c b/src/trg-client.c index 2d3fbe6..2f42d99 100644 --- a/src/trg-client.c +++ b/src/trg-client.c @@ -386,6 +386,12 @@ void trg_client_updatelock(TrgClient *tc) g_mutex_lock(priv->updateMutex); } +void trg_client_configlock(TrgClient *tc) +{ + TrgClientPrivate *priv = TRG_CLIENT_GET_PRIVATE(tc); + g_mutex_lock(priv->configMutex); +} + guint trg_client_get_failcount(TrgClient *tc) { TrgClientPrivate *priv = TRG_CLIENT_GET_PRIVATE(tc); @@ -410,6 +416,12 @@ void trg_client_updateunlock(TrgClient *tc) g_mutex_unlock(priv->updateMutex); } +void trg_client_configunlock(TrgClient *tc) +{ + TrgClientPrivate *priv = TRG_CLIENT_GET_PRIVATE(tc); + g_mutex_unlock(priv->configMutex); +} + /* formerly http.c */ void trg_response_free(trg_response *response) diff --git a/src/trg-client.h b/src/trg-client.h index 0091598..cf3e04f 100644 --- a/src/trg-client.h +++ b/src/trg-client.h @@ -159,6 +159,8 @@ void trg_client_status_change(TrgClient *tc, gboolean connected); gboolean trg_client_is_connected(TrgClient *tc); void trg_client_updateunlock(TrgClient *tc); void trg_client_updatelock(TrgClient *tc); +void trg_client_configunlock(TrgClient *tc); +void trg_client_configlock(TrgClient *tc); guint trg_client_inc_failcount(TrgClient *tc); guint trg_client_get_failcount(TrgClient *tc); void trg_client_reset_failcount(TrgClient *tc); diff --git a/src/trg-destination-combo.c b/src/trg-destination-combo.c index 976e3bb..5fe32b0 100644 --- a/src/trg-destination-combo.c +++ b/src/trg-destination-combo.c @@ -26,7 +26,7 @@ #include "util.h" G_DEFINE_TYPE(TrgDestinationCombo, trg_destination_combo, - GTK_TYPE_COMBO_BOX_ENTRY) + GTK_TYPE_COMBO_BOX) #define TRG_DESTINATION_COMBO_GET_PRIVATE(o) \ (G_TYPE_INSTANCE_GET_PRIVATE ((o), TRG_TYPE_DESTINATION_COMBO, TrgDestinationComboPrivate)) typedef struct _TrgDestinationComboPrivate TrgDestinationComboPrivate; @@ -104,7 +104,7 @@ static GObject *trg_destination_combo_constructor(GType type, GSList *sli; GList *li; GList *torrentItemRefs; - + GtkCellRenderer *renderer; GtkTreeRowReference *rr; GtkTreeModel *model; GtkTreePath *path; @@ -115,7 +115,7 @@ static GObject *trg_destination_combo_constructor(GType type, g_strdup(session_get_download_dir(trg_client_get_session(client))); rm_trailing_slashes(defaultDownDir); - comboModel = gtk_list_store_new(1, G_TYPE_STRING); + comboModel = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); trg_client_updatelock(client); torrentItemRefs = g_hash_table_get_values(trg_client_get_torrent_table(client)); @@ -150,12 +150,15 @@ static GObject *trg_destination_combo_constructor(GType type, for (sli = dirs; sli; sli = g_slist_next(sli)) gtk_list_store_insert_with_values(comboModel, NULL, INT_MAX, 0, - (gchar *) sli->data, -1); + (gchar *) sli->data, + 1, (gchar *) sli->data, -1); gtk_combo_box_set_model(GTK_COMBO_BOX(object), GTK_TREE_MODEL(comboModel)); - gtk_combo_box_entry_set_text_column(GTK_COMBO_BOX_ENTRY(object), 0); + renderer = gtk_cell_renderer_text_new(); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(object), renderer, TRUE); + gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(object), renderer, "text", 0, NULL); g_object_unref(comboModel); g_slist_foreach(dirs, (GFunc)g_free, NULL); @@ -164,6 +167,15 @@ static GObject *trg_destination_combo_constructor(GType type, return object; } +gchar *trg_destination_combo_get_dir(TrgDestinationCombo *combo) +{ + GtkTreeIter iter; + gchar *value; + gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo), &iter); + gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(combo)), &iter, 1, &value, -1); + return value; +} + static void trg_destination_combo_class_init(TrgDestinationComboClass * klass) { diff --git a/src/trg-destination-combo.h b/src/trg-destination-combo.h index c5926a9..6412018 100644 --- a/src/trg-destination-combo.h +++ b/src/trg-destination-combo.h @@ -48,6 +48,7 @@ typedef struct { GType trg_destination_combo_get_type(void); GtkWidget *trg_destination_combo_new(TrgClient * client); +gchar *trg_destination_combo_get_dir(TrgDestinationCombo *combo); G_END_DECLS #endif /* TRG_DESTINATION_COMBO_H_ */ diff --git a/src/trg-persistent-tree-view.c b/src/trg-persistent-tree-view.c new file mode 100644 index 0000000..48cf908 --- /dev/null +++ b/src/trg-persistent-tree-view.c @@ -0,0 +1,368 @@ +/* + * transmission-remote-gtk - A GTK RPC client to Transmission + * Copyright (C) 2011 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 + +#include "trg-prefs.h" +#include "trg-persistent-tree-view.h" +#include "trg-preferences-dialog.h" +#include "util.h" + +G_DEFINE_TYPE (TrgPersistentTreeView, trg_persistent_tree_view, GTK_TYPE_VBOX) + +#define GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), TRG_TYPE_PERSISTENT_TREE_VIEW, TrgPersistentTreeViewPrivate)) + +typedef struct _TrgPersistentTreeViewPrivate TrgPersistentTreeViewPrivate; + +enum { + PROP_0, PROP_PREFS, PROP_KEY, PROP_MODEL +}; + +struct _TrgPersistentTreeViewPrivate { + TrgPrefs *prefs; + gchar *key; + GSList *columns; + GtkTreeView *tv; + JsonArray *ja; + GtkWidget *delButton; + trg_pref_widget_desc *wd; + GtkTreeModel *model; + trg_persistent_tree_view_column *addSelect; +}; + +static void selection_changed(GtkTreeSelection *selection, gpointer data) { + TrgPersistentTreeViewPrivate *priv = GET_PRIVATE(data); + + if (gtk_tree_selection_get_selected(selection, NULL, NULL)) + gtk_widget_set_sensitive(priv->delButton, TRUE); + else + gtk_widget_set_sensitive(priv->delButton, FALSE); +} + +static void trg_persistent_tree_view_edit(GtkCellRendererText * renderer, + gchar * path, gchar * new_text, gpointer user_data) { + trg_persistent_tree_view_column *cd = + (trg_persistent_tree_view_column*) user_data; + TrgPersistentTreeViewPrivate *priv = GET_PRIVATE(cd->tv); + GtkTreeModel *model = gtk_tree_view_get_model(priv->tv); + GtkTreeIter iter; + + gtk_tree_model_get_iter_from_string(model, &iter, path); + gtk_list_store_set(GTK_LIST_STORE(model), &iter, cd->index, new_text, -1); +} + +static void trg_persistent_tree_view_refresh(TrgPrefs *prefs, void *wdp) { + trg_pref_widget_desc *wd = (trg_pref_widget_desc*) wdp; + TrgPersistentTreeViewPrivate *priv = GET_PRIVATE(wd->widget); + GtkListStore *model = GTK_LIST_STORE(gtk_tree_view_get_model(priv->tv)); + GtkTreeIter iter; + JsonArray *ja; + GList *ja_list, *li; + GSList *sli; + + ja = trg_prefs_get_array(prefs, wd->key, wd->flags); + + gtk_list_store_clear(model); + + if (!ja) + return; + + ja_list = json_array_get_elements(ja); + + for (li = ja_list; li; li = g_list_next(li)) { + JsonNode *ja_node = (JsonNode*) li->data; + JsonObject *jobj = json_node_get_object(ja_node); + gtk_list_store_append(model, &iter); + for (sli = priv->columns; sli; sli = g_slist_next(sli)) { + trg_persistent_tree_view_column *cd = + (trg_persistent_tree_view_column*) sli->data; + gtk_list_store_set(model, &iter, cd->index, + json_object_get_string_member(jobj, cd->key), -1); + } + } + + g_list_free(ja_list); +} + +static gboolean trg_persistent_tree_view_save_foreachfunc(GtkTreeModel *model, + GtkTreePath *path, GtkTreeIter *iter, gpointer data) { + TrgPersistentTreeViewPrivate *priv = GET_PRIVATE(data); + JsonObject *new = json_object_new(); + gchar *value; + GSList *li; + + for (li = priv->columns; li; li = g_slist_next(li)) { + trg_persistent_tree_view_column *cd = + (trg_persistent_tree_view_column*) li->data; + gtk_tree_model_get(model, iter, cd->index, &value, -1); + json_object_set_string_member(new, cd->key, value); + g_free(value); + } + + json_array_add_object_element(priv->ja, new); + + return FALSE; +} + +static void trg_persistent_tree_view_save(TrgPrefs *prefs, void *wdp) { + trg_pref_widget_desc *wd = (trg_pref_widget_desc*) wdp; + TrgPersistentTreeViewPrivate *priv = GET_PRIVATE(wd->widget); + GtkTreeModel *model = gtk_tree_view_get_model(priv->tv); + + JsonNode *node = trg_prefs_get_value(prefs, wd->key, JSON_NODE_ARRAY, + wd->flags | TRG_PREFS_REPLACENODE); + + priv->ja = json_array_new(); + + gtk_tree_model_foreach(model, trg_persistent_tree_view_save_foreachfunc, + wd->widget); + json_node_take_array(node, priv->ja); + + trg_prefs_changed_emit_signal(prefs, wd->key); +} + +void trg_persistent_tree_view_build(TrgPersistentTreeView *ptv) { + TrgPersistentTreeViewPrivate *priv = GET_PRIVATE(ptv); + GSList *li; + GtkCellRenderer *renderer; + + for (li = priv->columns; li; li = g_slist_next(li)) { + trg_persistent_tree_view_column *cd = + (trg_persistent_tree_view_column*) li->data; + renderer = gtk_cell_renderer_text_new(); + g_object_set(G_OBJECT(renderer), "editable", TRUE, NULL); + g_signal_connect(renderer, "edited", + G_CALLBACK(trg_persistent_tree_view_edit), cd); + cd->column = gtk_tree_view_column_new_with_attributes(cd->label, + renderer, "text", cd->index, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(priv->tv), cd->column); + } +} + +trg_persistent_tree_view_column *trg_persistent_tree_view_add_column( + TrgPersistentTreeView *ptv, gint index, const gchar *key, + const gchar *label) { + TrgPersistentTreeViewPrivate *priv = GET_PRIVATE(ptv); + trg_persistent_tree_view_column *cd = + g_new0(trg_persistent_tree_view_column, 1); + + cd->key = g_strdup(key); + cd->label = g_strdup(label); + cd->index = index; + cd->tv = ptv; + + priv->columns = g_slist_append(priv->columns, cd); + + return cd; +} + +static GtkTreeView *trg_persistent_tree_view_tree_view_new( + TrgPersistentTreeView *ptv, GtkTreeModel *model) { + GtkTreeView *tv = GTK_TREE_VIEW(gtk_tree_view_new_with_model(model)); + GtkTreeSelection *selection; + + g_object_unref(G_OBJECT(model)); + + gtk_tree_view_set_rubber_banding(tv, TRUE); + //gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tv), FALSE); + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tv)); + + g_signal_connect(G_OBJECT(selection), "changed", + G_CALLBACK(selection_changed), ptv); + + return tv; +} + +static void trg_persistent_tree_view_add_cb(GtkWidget *w, gpointer data) { + TrgPersistentTreeViewPrivate *priv = GET_PRIVATE(data); + GtkTreeModel *model = gtk_tree_view_get_model(priv->tv); + GtkTreeIter iter; + GtkTreePath *path; + + gtk_list_store_append(GTK_LIST_STORE(model), &iter); + path = gtk_tree_model_get_path(model, &iter); + + if (priv->addSelect) + gtk_tree_view_set_cursor(priv->tv, path, priv->addSelect->column, TRUE); + + gtk_tree_path_free(path); +} + +static void trg_persistent_tree_view_del_cb(GtkWidget *w, gpointer data) { + TrgPersistentTreeViewPrivate *priv = GET_PRIVATE(data); + GtkTreeSelection *selection = gtk_tree_view_get_selection(priv->tv); + GtkTreeModel *model; + GtkTreeIter iter; + + if (gtk_tree_selection_get_selected(selection, &model, &iter)) + gtk_list_store_remove(GTK_LIST_STORE(model), &iter); +} + +static void trg_persistent_tree_view_get_property(GObject *object, + guint property_id, GValue *value, GParamSpec *pspec) { + switch (property_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void trg_persistent_tree_view_set_property(GObject *object, + guint property_id, const GValue *value, GParamSpec *pspec) { + TrgPersistentTreeViewPrivate *priv = GET_PRIVATE(object); + switch (property_id) { + case PROP_PREFS: + priv->prefs = g_value_get_object(value); + break; + case PROP_KEY: + priv->key = g_value_get_pointer(value); + break; + case PROP_MODEL: + priv->model = g_value_get_object(value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void trg_persistent_tree_view_finalize(GObject *object) { + TrgPersistentTreeViewPrivate *priv = GET_PRIVATE(object); + GSList *li; + for (li = priv->columns; li; li = g_slist_next(li)) { + trg_persistent_tree_view_column *cd = + (trg_persistent_tree_view_column*) li->data; + g_free(cd->key); + g_free(cd->label); + g_free(cd); + } + g_slist_free(priv->columns); + G_OBJECT_CLASS (trg_persistent_tree_view_parent_class)->finalize(object); +} + +trg_pref_widget_desc* trg_persistent_tree_view_get_widget_desc( + TrgPersistentTreeView* ptv) { + TrgPersistentTreeViewPrivate *priv = GET_PRIVATE(ptv); + return priv->wd; +} + +void trg_persistent_tree_view_set_add_select(TrgPersistentTreeView *ptv, + trg_persistent_tree_view_column *cd) { + TrgPersistentTreeViewPrivate *priv = GET_PRIVATE(ptv); + priv->addSelect = cd; +} + +static GObject *trg_persistent_tree_view_constructor(GType type, + guint n_construct_properties, GObjectConstructParam * construct_params) { + GObject *object; + TrgPersistentTreeViewPrivate *priv; + GtkWidget *hbox, *w; + + object = G_OBJECT_CLASS + (trg_persistent_tree_view_parent_class)->constructor(type, + n_construct_properties, construct_params); + priv = GET_PRIVATE(object); + + hbox = gtk_hbox_new(FALSE, 0); + + w = gtk_button_new_from_stock(GTK_STOCK_ADD); + g_signal_connect(w, "clicked", G_CALLBACK(trg_persistent_tree_view_add_cb), object); + gtk_box_pack_start(GTK_BOX(hbox), w, FALSE, FALSE, 4); + + w = priv->delButton = gtk_button_new_from_stock(GTK_STOCK_DELETE); + gtk_widget_set_sensitive(w, FALSE); + g_signal_connect(w, "clicked", G_CALLBACK(trg_persistent_tree_view_del_cb), object); + gtk_box_pack_start(GTK_BOX(hbox), w, FALSE, FALSE, 4); + + priv->tv = trg_persistent_tree_view_tree_view_new( + TRG_PERSISTENT_TREE_VIEW(object), priv->model); + gtk_box_pack_start(GTK_BOX(object), + my_scrolledwin_new(GTK_WIDGET(priv->tv)), TRUE, TRUE, 4); + gtk_box_pack_start(GTK_BOX(object), hbox, FALSE, FALSE, 4); + + priv->wd = trg_pref_widget_desc_new(GTK_WIDGET(priv->tv), priv->key, + TRG_PREFS_PROFILE); + priv->wd->widget = GTK_WIDGET(object); + priv->wd->saveFunc = &trg_persistent_tree_view_save; + priv->wd->refreshFunc = &trg_persistent_tree_view_refresh; + + //trg_persistent_tree_view_refresh(priv->prefs, wd); + + return object; +} + +static void trg_persistent_tree_view_class_init( + TrgPersistentTreeViewClass *klass) { + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private(klass, sizeof(TrgPersistentTreeViewPrivate)); + + object_class->get_property = trg_persistent_tree_view_get_property; + object_class->set_property = trg_persistent_tree_view_set_property; + object_class->finalize = trg_persistent_tree_view_finalize; + object_class->constructor = trg_persistent_tree_view_constructor; + + g_object_class_install_property( + object_class, + PROP_KEY, + g_param_spec_pointer( + "conf-key", + "Conf Key", + "Conf Key", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY + | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK + | G_PARAM_STATIC_BLURB)); + + g_object_class_install_property( + object_class, + PROP_PREFS, + g_param_spec_object( + "prefs", + "Prefs", + "Prefs", + TRG_TYPE_PREFS, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY + | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK + | G_PARAM_STATIC_BLURB)); + + g_object_class_install_property( + object_class, + PROP_MODEL, + g_param_spec_object( + "persistent-model", + "Persistent Model", + "Persistent Model", + GTK_TYPE_LIST_STORE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY + | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK + | G_PARAM_STATIC_BLURB)); +} + +static void trg_persistent_tree_view_init(TrgPersistentTreeView *self) { +} + +TrgPersistentTreeView* +trg_persistent_tree_view_new(TrgPrefs *prefs, GtkListStore *model, + const gchar *key) { + GObject *obj = g_object_new(TRG_TYPE_PERSISTENT_TREE_VIEW, "prefs", prefs, + "conf-key", key, "persistent-model", model, NULL); + + return TRG_PERSISTENT_TREE_VIEW(obj); +} diff --git a/src/trg-persistent-tree-view.h b/src/trg-persistent-tree-view.h new file mode 100644 index 0000000..2664946 --- /dev/null +++ b/src/trg-persistent-tree-view.h @@ -0,0 +1,77 @@ +/* + * transmission-remote-gtk - A GTK RPC client to Transmission + * Copyright (C) 2011 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. + */ + +#ifndef _TRG_PERSISTENT_TREE_VIEW +#define _TRG_PERSISTENT_TREE_VIEW + +#include +#include + +#include "trg-preferences-dialog.h" + +G_BEGIN_DECLS + +#define TRG_TYPE_PERSISTENT_TREE_VIEW trg_persistent_tree_view_get_type() + +#define TRG_PERSISTENT_TREE_VIEW(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), TRG_TYPE_PERSISTENT_TREE_VIEW, TrgPersistentTreeView)) + +#define TRG_PERSISTENT_TREE_VIEW_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), TRG_TYPE_PERSISTENT_TREE_VIEW, TrgPersistentTreeViewClass)) + +#define TRG_IS_PERSISTENT_TREE_VIEW(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TRG_TYPE_PERSISTENT_TREE_VIEW)) + +#define TRG_IS_PERSISTENT_TREE_VIEW_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), TRG_TYPE_PERSISTENT_TREE_VIEW)) + +#define TRG_PERSISTENT_TREE_VIEW_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), TRG_TYPE_PERSISTENT_TREE_VIEW, TrgPersistentTreeViewClass)) + +typedef struct { + GtkVBox parent; +} TrgPersistentTreeView; + +typedef struct { + GtkTreeViewClass parent_class; +} TrgPersistentTreeViewClass; + +GType trg_persistent_tree_view_get_type (void); + +typedef struct { + GtkTreeViewColumn *column; + gchar *key; + gchar *label; + TrgPersistentTreeView *tv; + gint index; +} trg_persistent_tree_view_column; + +TrgPersistentTreeView* +trg_persistent_tree_view_new (TrgPrefs *prefs, GtkListStore *model, const gchar *key); +trg_pref_widget_desc* trg_persistent_tree_view_get_widget_desc(TrgPersistentTreeView* ptv); +void trg_persistent_tree_view_set_add_select(TrgPersistentTreeView *ptv, trg_persistent_tree_view_column *cd); +trg_persistent_tree_view_column *trg_persistent_tree_view_add_column(TrgPersistentTreeView *ptv, + gint index, + const gchar *key, + const gchar *label); +void trg_persistent_tree_view_build(TrgPersistentTreeView *ptv); + +G_END_DECLS + +#endif /* _TRG_PERSISTENT_TREE_VIEW */ diff --git a/src/trg-preferences-dialog.c b/src/trg-preferences-dialog.c index 91b36ebb..e729300 100644 --- a/src/trg-preferences-dialog.c +++ b/src/trg-preferences-dialog.c @@ -30,6 +30,7 @@ #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" @@ -52,9 +53,6 @@ struct _TrgPreferencesDialogPrivate { GtkWidget *profileComboBox; GtkWidget *profileNameEntry; GtkWidget *fullUpdateCheck; - GtkWidget *execDelButton; - GtkWidget *etv; - GtkTreeViewColumn *etvLabelColumn; GList *widgets; }; @@ -65,7 +63,7 @@ static void trg_pref_widget_desc_free(trg_pref_widget_desc *wd) { g_free(wd); } -static trg_pref_widget_desc* trg_pref_widget_desc_new(GtkWidget *w, gchar *key, +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; @@ -98,15 +96,17 @@ static void trg_pref_widget_save(TrgPreferencesDialog *dlg, 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; - GList *li; + 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, @@ -545,200 +545,64 @@ static void trgp_double_special_dependent(GtkWidget *widget, gpointer data) { GTK_TOGGLE_BUTTON(priv->fullUpdateCheck))); } -static void exec_selection_changed(GtkTreeSelection *selection, gpointer data) { - TrgPreferencesDialogPrivate *priv = - TRG_PREFERENCES_DIALOG_GET_PRIVATE(data); - - if (gtk_tree_selection_get_selected(selection, NULL, NULL)) - gtk_widget_set_sensitive(priv->execDelButton, TRUE); - else - gtk_widget_set_sensitive(priv->execDelButton, FALSE); -} - -static void trg_etc_edited(GtkCellRendererText * renderer, gchar * path, - gchar * new_text, gint model_column, gpointer user_data) { - GtkTreeModel *model = GTK_TREE_MODEL(user_data); - GtkTreeIter iter; - - gtk_tree_model_get_iter_from_string(model, &iter, path); - gtk_list_store_set(GTK_LIST_STORE(model), &iter, model_column, new_text, -1); -} - -static void trg_etv_label_edited(GtkCellRendererText * renderer, gchar * path, - gchar * new_text, gpointer user_data) { - trg_etc_edited(renderer, path, new_text, 0, user_data); -} - -static void trg_etv_cmd_edited(GtkCellRendererText * renderer, gchar * path, - gchar * new_text, gpointer user_data) { - trg_etc_edited(renderer, path, new_text, 1, user_data); -} - -static void trg_prefs_etv_refresh(TrgPrefs *prefs, void *wdp) { - trg_pref_widget_desc *wd = (trg_pref_widget_desc*) wdp; - GtkListStore *model = - GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(wd->widget))); - GtkTreeIter iter; - JsonArray *ja; - GList *ja_list, *li; - - ja = trg_prefs_get_array(prefs, wd->key, wd->flags); - gtk_list_store_clear(model); - - if (!ja) - return; - - ja_list = json_array_get_elements(ja); - - for (li = ja_list; li; li = g_list_next(li)) { - JsonNode *ja_node = (JsonNode*) li->data; - JsonObject *jobj = json_node_get_object(ja_node); - gtk_list_store_append(model, &iter); - gtk_list_store_set(model, &iter, 0, - json_object_get_string_member(jobj, TRG_PREFS_KEY_EXEC_COMMANDS_SUBKEY_LABEL), 1, - json_object_get_string_member(jobj, TRG_PREFS_KEY_EXEC_COMMANDS_SUBKEY_CMD), -1); - } - - g_list_free(ja_list); -} - -static gboolean trg_prefs_etc_save_foreachfunc(GtkTreeModel *model, - GtkTreePath *path, GtkTreeIter *iter, gpointer data) { - gchar *label, *cmd; - JsonArray *ja = (JsonArray*) data; - JsonObject *new = json_object_new(); - - gtk_tree_model_get(model, iter, 0, &label, 1, &cmd, -1); - - json_object_set_string_member(new, TRG_PREFS_KEY_EXEC_COMMANDS_SUBKEY_LABEL, label); - json_object_set_string_member(new, TRG_PREFS_KEY_EXEC_COMMANDS_SUBKEY_CMD, cmd); - - json_array_add_object_element(ja, new); - - g_free(label); - g_free(cmd); - - return FALSE; -} - -static void trg_prefs_etv_save(TrgPrefs *prefs, void *wdp) { - trg_pref_widget_desc *wd = (trg_pref_widget_desc*) wdp; - JsonNode *node = trg_prefs_get_value(prefs, wd->key, JSON_NODE_ARRAY, - wd->flags | TRG_PREFS_REPLACENODE); - JsonArray *ja = json_array_new(); - GtkTreeView *tv = GTK_TREE_VIEW(wd->widget); - GtkTreeModel *model = gtk_tree_view_get_model(tv); - - gtk_tree_model_foreach(model, trg_prefs_etc_save_foreachfunc, ja); - json_node_take_array(node, ja); - trg_prefs_changed_emit_signal(prefs, wd->key); -} - -static GtkWidget *trg_prefs_execTreeView(TrgPreferencesDialog *dlg) { +static GtkWidget *trg_prefs_openExecPage(TrgPreferencesDialog *dlg) { TrgPreferencesDialogPrivate *priv = TRG_PREFERENCES_DIALOG_GET_PRIVATE(dlg); - GtkListStore *model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); - GtkWidget *tv = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model)); - GtkTreeViewColumn *column; - GtkCellRenderer *renderer; - GtkTreeSelection *selection; + GtkWidget *t; + TrgPersistentTreeView *ptv; + GtkListStore *model; trg_pref_widget_desc *wd; + gint row = 0; - g_object_unref(G_OBJECT(model)); - - gtk_tree_view_set_rubber_banding(GTK_TREE_VIEW(tv), TRUE); - //gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tv), FALSE); - - renderer = gtk_cell_renderer_text_new(); - g_object_set(G_OBJECT(renderer), "editable", TRUE, NULL); - g_signal_connect(renderer, "edited", - G_CALLBACK(trg_etv_label_edited), model); - column = priv->etvLabelColumn = gtk_tree_view_column_new_with_attributes( - _("Label"), renderer, "text", 0, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(tv), column); - - renderer = gtk_cell_renderer_text_new(); - g_object_set(G_OBJECT(renderer), "editable", TRUE, NULL); - g_signal_connect(renderer, "edited", - G_CALLBACK(trg_etv_cmd_edited), model); - column = gtk_tree_view_column_new_with_attributes(_("Command"), renderer, - "text", 1, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(tv), column); + t = hig_workarea_create(); - selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tv)); + hig_workarea_add_section_title(t, &row, _("Remote Commands")); - g_signal_connect(G_OBJECT(selection), "changed", - G_CALLBACK(exec_selection_changed), dlg); + model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); - wd = trg_pref_widget_desc_new(tv, TRG_PREFS_KEY_EXEC_COMMANDS, - TRG_PREFS_PROFILE); - wd->saveFunc = &trg_prefs_etv_save; - wd->refreshFunc = &trg_prefs_etv_refresh; + ptv = trg_persistent_tree_view_new(priv->prefs, model, TRG_PREFS_KEY_EXEC_COMMANDS); + 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_persistent_tree_view_build(ptv); + trg_pref_widget_refresh(dlg, wd); priv->widgets = g_list_append(priv->widgets, wd); - trg_prefs_etv_refresh(priv->prefs, wd); - - return tv; -} - -static void trg_prefs_add_exec_cb(GtkWidget *w, gpointer data) { - TrgPreferencesDialogPrivate *priv = - TRG_PREFERENCES_DIALOG_GET_PRIVATE(data); - GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(priv->etv)); - GtkTreeIter iter; - GtkTreePath *path; - - gtk_list_store_append(GTK_LIST_STORE(model), &iter); - path = gtk_tree_model_get_path(model, &iter); - gtk_tree_view_set_cursor(GTK_TREE_VIEW(priv->etv), path, - priv->etvLabelColumn, TRUE); - gtk_tree_path_free(path); -} - -static void trg_prefs_del_exec_cb(GtkWidget *w, gpointer data) { - GtkTreeView *tv = GTK_TREE_VIEW(data); - GtkTreeSelection *selection = gtk_tree_view_get_selection(tv); - GtkTreeModel *model; - GtkTreeIter iter; + gtk_table_attach(GTK_TABLE(t), GTK_WIDGET(ptv), 1, 2, row, + row + 1, GTK_EXPAND | GTK_SHRINK | GTK_FILL, + GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0); - if (gtk_tree_selection_get_selected(selection, &model, &iter)) - gtk_list_store_remove(GTK_LIST_STORE(model), &iter); + return t; } -static GtkWidget *trg_prefs_openExecPage(TrgPreferencesDialog *dlg) { +static GtkWidget *trg_prefs_dirsPage(TrgPreferencesDialog *dlg) { TrgPreferencesDialogPrivate *priv = TRG_PREFERENCES_DIALOG_GET_PRIVATE(dlg); - GtkWidget *t, *hbox, *w; + GtkWidget *t; + TrgPersistentTreeView *ptv; + GtkListStore *model; + trg_pref_widget_desc *wd; gint row = 0; t = hig_workarea_create(); - //frame = gtk_frame_new("Profile name..."); + hig_workarea_add_section_title(t, &row, _("Destinations")); - hig_workarea_add_section_title(t, &row, _("Remote Commands")); + model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); - priv->etv = trg_prefs_execTreeView(dlg); + ptv = trg_persistent_tree_view_new(priv->prefs, model, TRG_PREFS_KEY_DESTINATIONS); + 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_persistent_tree_view_build(ptv); + trg_pref_widget_refresh(dlg, wd); + priv->widgets = g_list_append(priv->widgets, wd); - gtk_table_attach(GTK_TABLE(t), my_scrolledwin_new(priv->etv), 1, 2, row, + gtk_table_attach(GTK_TABLE(t), GTK_WIDGET(ptv), 1, 2, row, row + 1, GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0); - row++; - - hbox = gtk_hbox_new(FALSE, 0); - w = gtk_button_new_from_stock(GTK_STOCK_ADD); - g_signal_connect(w, "clicked", G_CALLBACK(trg_prefs_add_exec_cb), dlg); - gtk_box_pack_start(GTK_BOX(hbox), w, FALSE, FALSE, 4); - - w = priv->execDelButton = gtk_button_new_from_stock(GTK_STOCK_DELETE); - gtk_widget_set_sensitive(w, FALSE); - g_signal_connect(w, "clicked", G_CALLBACK(trg_prefs_del_exec_cb), priv->etv); - gtk_box_pack_start(GTK_BOX(hbox), w, FALSE, FALSE, 4); - - hig_workarea_add_wide_control(t, &row, hbox); - - //gtk_container_add(GTK_CONTAINER(frame), t); - //return frame; - return t; } @@ -887,6 +751,10 @@ static GObject *trg_preferences_dialog_constructor(GType type, trg_prefs_openExecPage(TRG_PREFERENCES_DIALOG(object)), gtk_label_new(_("Remote Execute"))); + /*gtk_notebook_append_page(GTK_NOTEBOOK(notebook), + trg_prefs_dirsPage(TRG_PREFERENCES_DIALOG(object)), + gtk_label_new(_("Directories")));*/ + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), trg_prefs_desktopPage(TRG_PREFERENCES_DIALOG(object)), gtk_label_new(_("Desktop"))); diff --git a/src/trg-preferences-dialog.h b/src/trg-preferences-dialog.h index 8b90284..92190a6 100644 --- a/src/trg-preferences-dialog.h +++ b/src/trg-preferences-dialog.h @@ -58,5 +58,8 @@ GType trg_preferences_dialog_get_type(void); GtkWidget *trg_preferences_dialog_get_instance(TrgMainWindow * win, TrgClient * client); +trg_pref_widget_desc* trg_pref_widget_desc_new(GtkWidget *w, gchar *key, + int flags); + G_END_DECLS #endif /* TRG_PREFERENCES_WINDOW_H_ */ diff --git a/src/trg-prefs.h b/src/trg-prefs.h index d340d8a..61ac369 100644 --- a/src/trg-prefs.h +++ b/src/trg-prefs.h @@ -67,9 +67,12 @@ #define TRG_PREFS_KEY_TV_WIDTHS "widths" #define TRG_PREFS_KEY_NOTEBOOK_PANED_POS "notebook-paned-pos" #define TRG_PREFS_KEY_STATES_PANED_POS "states-paned-pos" +#define TRG_PREFS_SUBKEY_LABEL "label" #define TRG_PREFS_KEY_EXEC_COMMANDS "exec-commands" #define TRG_PREFS_KEY_EXEC_COMMANDS_SUBKEY_CMD "cmd" -#define TRG_PREFS_KEY_EXEC_COMMANDS_SUBKEY_LABEL "label" +#define TRG_PREFS_KEY_DESTINATIONS "destinations" +#define TRG_PREFS_KEY_DESTINATIONS_SUBKEY_DIR "dir" + #define TRG_PREFS_NOFLAGS (1 << 0) /* 0x00 */ #define TRG_PREFS_GLOBAL (1 << 1) /* 0x01 */ diff --git a/src/trg-torrent-add-dialog.c b/src/trg-torrent-add-dialog.c index 2e8ccf9..9589751 100644 --- a/src/trg-torrent-add-dialog.c +++ b/src/trg-torrent-add-dialog.c @@ -231,7 +231,7 @@ trg_torrent_add_response_cb(GtkDialog * dlg, gint res_id, gpointer data) gtk_combo_box_get_active(GTK_COMBO_BOX(priv->priority_combo)) - 1; gchar *dir = - gtk_combo_box_get_active_text(GTK_COMBO_BOX(priv->dest_combo)); + trg_destination_combo_get_dir(TRG_DESTINATION_COMBO(priv->dest_combo)); if (g_slist_length(priv->filenames) == 1) { JsonNode *req = @@ -258,6 +258,8 @@ trg_torrent_add_response_cb(GtkDialog * dlg, gint res_id, gpointer data) launch_add_thread(args); } + + g_free(dir); } else { g_str_slist_free(priv->filenames); } diff --git a/src/trg-torrent-move-dialog.c b/src/trg-torrent-move-dialog.c index c742e98..8ea6802 100644 --- a/src/trg-torrent-move-dialog.c +++ b/src/trg-torrent-move-dialog.c @@ -60,14 +60,14 @@ trg_torrent_move_response_cb(GtkDialog * dlg, gint res_id, gpointer data) if (res_id == GTK_RESPONSE_ACCEPT) { gchar *location = - gtk_combo_box_get_active_text(GTK_COMBO_BOX + trg_destination_combo_get_dir(TRG_DESTINATION_COMBO (priv->location_combo)); JsonNode *request = torrent_set_location(priv->ids, location, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->move_check))); - request_set_tag_from_ids(request, priv->ids); g_free(location); + request_set_tag_from_ids(request, priv->ids); dispatch_async(priv->client, request, on_generic_interactive_action, data); } else { -- cgit v1.2.3