From b6bb8fb323f3885e106c0606de050c0437ccf81f Mon Sep 17 00:00:00 2001 From: Patrick Griffis Date: Wed, 17 Feb 2016 10:09:31 -0500 Subject: Redesign destination combobox --- src/trg-destination-combo.c | 286 ++++++++++++++++-------------------------- src/trg-destination-combo.h | 24 +--- src/trg-torrent-move-dialog.c | 5 +- 3 files changed, 113 insertions(+), 202 deletions(-) (limited to 'src') diff --git a/src/trg-destination-combo.c b/src/trg-destination-combo.c index 0bbd983..a361bae 100644 --- a/src/trg-destination-combo.c +++ b/src/trg-destination-combo.c @@ -30,25 +30,24 @@ #include "trg-destination-combo.h" #include "util.h" -G_DEFINE_TYPE(TrgDestinationCombo, trg_destination_combo, - 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; +struct _TrgDestinationCombo { + GtkComboBox parent_instance; +}; -struct _TrgDestinationComboPrivate { +typedef struct { TrgClient *client; gchar *last_selection; - GtkWidget *entry; - GtkCellRenderer *text_renderer; -}; +} TrgDestinationComboPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE(TrgDestinationCombo, trg_destination_combo, + GTK_TYPE_COMBO_BOX) enum { PROP_0, PROP_CLIENT, PROP_LAST_SELECTION }; enum { - DEST_DEFAULT, DEST_LABEL, DEST_EXISTING, DEST_USERADD + DEST_DEFAULT, DEST_LABEL, DEST_EXISTING }; enum { @@ -58,7 +57,7 @@ enum { static void trg_destination_combo_finalize(GObject * object) { TrgDestinationComboPrivate *priv = - TRG_DESTINATION_COMBO_GET_PRIVATE(object); + trg_destination_combo_get_instance_private(TRG_DESTINATION_COMBO(object)); g_free(priv->last_selection); } @@ -68,7 +67,7 @@ trg_destination_combo_get_property(GObject * object, GValue * value, GParamSpec * pspec) { TrgDestinationComboPrivate *priv = - TRG_DESTINATION_COMBO_GET_PRIVATE(object); + trg_destination_combo_get_instance_private(TRG_DESTINATION_COMBO(object)); switch (property_id) { case PROP_CLIENT: g_value_set_pointer(value, priv->client); @@ -89,7 +88,7 @@ trg_destination_combo_set_property(GObject * object, GParamSpec * pspec) { TrgDestinationComboPrivate *priv = - TRG_DESTINATION_COMBO_GET_PRIVATE(object); + trg_destination_combo_get_instance_private(TRG_DESTINATION_COMBO(object)); switch (property_id) { case PROP_CLIENT: priv->client = g_value_get_pointer(value); @@ -119,7 +118,7 @@ static gboolean g_slist_str_set_add(GSList ** list, const gchar * string) void trg_destination_combo_save_selection(TrgDestinationCombo * combo_box) { TrgDestinationComboPrivate *priv = - TRG_DESTINATION_COMBO_GET_PRIVATE(combo_box); + trg_destination_combo_get_instance_private(combo_box); GtkTreeIter iter; if (priv->last_selection @@ -130,47 +129,16 @@ void trg_destination_combo_save_selection(TrgDestinationCombo * combo_box) TrgPrefs *prefs = trg_client_get_prefs(priv->client); gchar *text; - gtk_tree_model_get(model, &iter, DEST_COLUMN_LABEL, &text, -1); + gtk_tree_model_get(model, &iter, DEST_COLUMN_DIR, &text, -1); trg_prefs_set_string(prefs, priv->last_selection, text, TRG_PREFS_CONNECTION); g_free(text); } } -static void -gtk_combo_box_entry_active_changed(GtkComboBox * combo_box, - gpointer user_data) +static inline GtkEntry *trg_destination_combo_get_entry(TrgDestinationCombo * combo) { - GtkTreeModel *model; - GtkTreeIter iter; - gboolean editableEntry = TRUE; - - if (gtk_combo_box_get_active_iter(combo_box, &iter)) { - GtkEntry *entry = - trg_destination_combo_get_entry(TRG_DESTINATION_COMBO - (combo_box)); - - if (entry) { - GValue value = G_VALUE_INIT; - guint type; - - model = gtk_combo_box_get_model(combo_box); - - gtk_tree_model_get_value(model, &iter, DEST_COLUMN_LABEL, - &value); - gtk_tree_model_get(model, &iter, DEST_COLUMN_TYPE, &type, -1); - - g_object_set_property(G_OBJECT(entry), "text", &value); - g_value_unset(&value); - - if (type == DEST_LABEL) - editableEntry = FALSE; - } - } - gtk_editable_set_editable(GTK_EDITABLE - (trg_destination_combo_get_entry - (TRG_DESTINATION_COMBO(combo_box))), - editableEntry); + return GTK_ENTRY(gtk_bin_get_child(GTK_BIN(combo))); } gboolean trg_destination_combo_has_text(TrgDestinationCombo * combo) @@ -181,29 +149,6 @@ gboolean trg_destination_combo_has_text(TrgDestinationCombo * combo) return strlen(text) > 0; } -GtkEntry *trg_destination_combo_get_entry(TrgDestinationCombo * combo) -{ - TrgDestinationComboPrivate *priv = - TRG_DESTINATION_COMBO_GET_PRIVATE(combo); - return GTK_ENTRY(priv->entry); -} - -static void -add_entry_cb(GtkEntry * entry, - GtkEntryIconPosition icon_pos, - GdkEvent * event, gpointer user_data) -{ - GtkComboBox *combo = GTK_COMBO_BOX(user_data); - GtkTreeModel *model = gtk_combo_box_get_model(combo); - GtkTreeIter iter; - - gtk_list_store_insert_with_values(GTK_LIST_STORE(model), &iter, - INT_MAX, DEST_COLUMN_LABEL, "", - DEST_COLUMN_DIR, "", - DEST_COLUMN_TYPE, DEST_USERADD, -1); - gtk_combo_box_set_active_iter(combo, &iter); -} - struct findDupeArg { const gchar *dir; gboolean isDupe; @@ -226,12 +171,11 @@ trg_destination_combo_insert_check_dupe_foreach(GtkTreeModel * model, static void trg_destination_combo_insert(GtkComboBox * box, const gchar * label, - const gchar * dir, guint type, - const gchar * lastDestination) + const gchar * dir, + guint type) { GtkTreeModel *model = gtk_combo_box_get_model(box); gchar *comboLabel; - GtkTreeIter iter; if (type == DEST_EXISTING) { struct findDupeArg args; @@ -248,110 +192,88 @@ trg_destination_combo_insert(GtkComboBox * box, comboLabel = label ? g_strdup_printf("%s (%s)", label, dir) : g_strdup(dir); - gtk_list_store_insert_with_values(GTK_LIST_STORE(model), &iter, - INT_MAX, DEST_COLUMN_LABEL, - comboLabel, DEST_COLUMN_DIR, dir, + gtk_list_store_insert_with_values(GTK_LIST_STORE(model), NULL, -1, + DEST_COLUMN_LABEL, comboLabel, + DEST_COLUMN_DIR, dir, DEST_COLUMN_TYPE, type, -1); - - if (lastDestination && !g_strcmp0(lastDestination, comboLabel)) - gtk_combo_box_set_active_iter(box, &iter); - g_free(comboLabel); } -static GObject *trg_destination_combo_constructor(GType type, - guint - n_construct_properties, - GObjectConstructParam * - construct_params) +gchar *trg_destination_combo_get_dir(TrgDestinationCombo * combo) { - GObject *object = G_OBJECT_CLASS - (trg_destination_combo_parent_class)->constructor(type, - n_construct_properties, - construct_params); - TrgDestinationComboPrivate *priv = - TRG_DESTINATION_COMBO_GET_PRIVATE(object); + GtkTreeModel *model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo)); + GtkTreeIter iter; + if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo), &iter)) { + gchar *value; + guint type; + + gtk_tree_model_get(model, &iter, DEST_COLUMN_TYPE, &type, -1); + + if (type == DEST_LABEL) { + gtk_tree_model_get(model, &iter, DEST_COLUMN_DIR, &value, -1); + return value; + } + } + + return + g_strdup(gtk_entry_get_text + (trg_destination_combo_get_entry(combo))); +} + +static void +load_directory_model(TrgDestinationCombo *self) +{ + TrgDestinationComboPrivate *priv = trg_destination_combo_get_instance_private(self); TrgClient *client = priv->client; TrgPrefs *prefs = trg_client_get_prefs(client); GSList *dirs = NULL, *sli; GList *li, *list; - GtkTreeRowReference *rr; - GtkTreeModel *model; - GtkTreePath *path; - GtkListStore *comboModel; + JsonArray *savedDestinations; gchar *defaultDir; - gchar *lastDestination = NULL; - - comboModel = gtk_list_store_new(N_DEST_COLUMNS, G_TYPE_STRING, - G_TYPE_STRING, G_TYPE_UINT); - gtk_combo_box_set_model(GTK_COMBO_BOX(object), - GTK_TREE_MODEL(comboModel)); - g_object_unref(comboModel); - - g_signal_connect(object, "changed", - G_CALLBACK(gtk_combo_box_entry_active_changed), NULL); - - priv->entry = gtk_entry_new(); - gtk_container_add(GTK_CONTAINER(object), priv->entry); - - priv->text_renderer = gtk_cell_renderer_text_new(); - gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(object), - priv->text_renderer, TRUE); - - gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(object), - priv->text_renderer, "text", 0, NULL); - - g_slist_foreach(dirs, (GFunc) g_free, NULL); - g_slist_free(dirs); - - gtk_entry_set_icon_from_stock(GTK_ENTRY(priv->entry), - GTK_ENTRY_ICON_SECONDARY, - GTK_STOCK_CLEAR); - - g_signal_connect(priv->entry, "icon-release", - G_CALLBACK(add_entry_cb), object); + /* Add default dir */ defaultDir = g_strdup(session_get_download_dir(trg_client_get_session(client))); rm_trailing_slashes(defaultDir); + trg_destination_combo_insert(GTK_COMBO_BOX(self), + NULL, + defaultDir, DEST_DEFAULT); + g_free (defaultDir); + + + /* Add saved dirs */ savedDestinations = trg_prefs_get_array(prefs, TRG_PREFS_KEY_DESTINATIONS, TRG_PREFS_CONNECTION); - - if (priv->last_selection) - lastDestination = trg_prefs_get_string(prefs, priv->last_selection, - TRG_PREFS_CONNECTION); - - trg_destination_combo_insert(GTK_COMBO_BOX(object), - NULL, - defaultDir, DEST_DEFAULT, - lastDestination); - gtk_combo_box_set_active(GTK_COMBO_BOX(object), 0); - if (savedDestinations) { list = json_array_get_elements(savedDestinations); if (list) { for (li = list; li; li = g_list_next(li)) { JsonObject *obj = json_node_get_object((JsonNode *) li->data); - trg_destination_combo_insert(GTK_COMBO_BOX(object), + trg_destination_combo_insert(GTK_COMBO_BOX(self), json_object_get_string_member - (obj, TRG_PREFS_SUBKEY_LABEL), - json_object_get_string_member - (obj, - TRG_PREFS_KEY_DESTINATIONS_SUBKEY_DIR), - DEST_LABEL, lastDestination); + (obj, TRG_PREFS_SUBKEY_LABEL), + json_object_get_string_member + (obj, TRG_PREFS_KEY_DESTINATIONS_SUBKEY_DIR), + DEST_LABEL); } g_list_free(list); } } + + /* Add all previously used download dirs */ list = g_hash_table_get_values(trg_client_get_torrent_table(client)); for (li = list; li; li = g_list_next(li)) { + GtkTreeRowReference *rr; + GtkTreeModel *model; + GtkTreePath *path; + rr = (GtkTreeRowReference *) li->data; model = gtk_tree_row_reference_get_model(rr); path = gtk_tree_row_reference_get_path(rr); @@ -376,38 +298,48 @@ static GObject *trg_destination_combo_constructor(GType type, } for (sli = dirs; sli; sli = g_slist_next(sli)) - trg_destination_combo_insert(GTK_COMBO_BOX(object), + trg_destination_combo_insert(GTK_COMBO_BOX(self), NULL, (gchar *) sli->data, - DEST_EXISTING, lastDestination); + DEST_EXISTING); + g_slist_free_full (dirs, g_free); g_list_free(list); - g_free(defaultDir); - g_free(lastDestination); +} - return object; +static void set_text_column(GtkCellLayout *layout, guint col) +{ + GList *cells = gtk_cell_layout_get_cells (layout); + g_assert (cells != NULL); + gtk_cell_layout_set_attributes (layout, GTK_CELL_RENDERER(cells->data), "text", col, NULL); + g_list_free (cells); } -gchar *trg_destination_combo_get_dir(TrgDestinationCombo * combo) +static void trg_destination_combo_constructed(GObject *object) { - GtkTreeModel *model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo)); - GtkTreeIter iter; + TrgDestinationCombo *self = TRG_DESTINATION_COMBO (object); + TrgDestinationComboPrivate *priv = + trg_destination_combo_get_instance_private(self); + TrgPrefs *prefs = trg_client_get_prefs(priv->client); - if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo), &iter)) { - gchar *value; - guint type; + G_OBJECT_CLASS(trg_destination_combo_parent_class)->constructed(object); - gtk_tree_model_get(model, &iter, DEST_COLUMN_TYPE, &type, -1); + load_directory_model (self); + set_text_column (GTK_CELL_LAYOUT(self), DEST_COLUMN_LABEL); - if (type == DEST_LABEL) { - gtk_tree_model_get(model, &iter, DEST_COLUMN_DIR, &value, -1); - return g_strdup(value); - } + /* Must be set after constructed */ + if (priv->last_selection) { + /* Restore any previous selection */ + char *lastDestination = trg_prefs_get_string(prefs, priv->last_selection, + TRG_PREFS_CONNECTION); + if (!gtk_combo_box_set_active_id (GTK_COMBO_BOX(object), lastDestination)) + g_warning ("Last selection was not a valid ID"); + g_free(lastDestination); + } + else { + /* DefaultDir is the first item otherwise */ + gtk_combo_box_set_active (GTK_COMBO_BOX(object), 0); } - - return - g_strdup(gtk_entry_get_text - (trg_destination_combo_get_entry(combo))); } static void @@ -415,27 +347,19 @@ trg_destination_combo_class_init(TrgDestinationComboClass * klass) { GObjectClass *object_class = G_OBJECT_CLASS(klass); - g_type_class_add_private(klass, sizeof(TrgDestinationComboPrivate)); - object_class->get_property = trg_destination_combo_get_property; object_class->set_property = trg_destination_combo_set_property; object_class->finalize = trg_destination_combo_finalize; - object_class->constructor = trg_destination_combo_constructor; + object_class->constructed = trg_destination_combo_constructed; g_object_class_install_property(object_class, PROP_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_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property(object_class, PROP_LAST_SELECTION, @@ -445,19 +369,25 @@ trg_destination_combo_class_init(TrgDestinationComboClass * klass) "LastSelectionKey", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB)); + G_PARAM_STATIC_STRINGS)); } static void trg_destination_combo_init(TrgDestinationCombo * self) { + GtkListStore *store; + + store = gtk_list_store_new(N_DEST_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT); + gtk_combo_box_set_model(GTK_COMBO_BOX(self), GTK_TREE_MODEL(store)); + gtk_combo_box_set_id_column (GTK_COMBO_BOX(self), DEST_COLUMN_DIR); + gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX(self), DEST_COLUMN_LABEL); + g_object_unref(store); } GtkWidget *trg_destination_combo_new(TrgClient * client, const gchar * lastSelectionKey) { return GTK_WIDGET(g_object_new(TRG_TYPE_DESTINATION_COMBO, + "has-entry", TRUE, "trg-client", client, "last-selection-key", lastSelectionKey, NULL)); diff --git a/src/trg-destination-combo.h b/src/trg-destination-combo.h index 9ab5076..9ece8cc 100644 --- a/src/trg-destination-combo.h +++ b/src/trg-destination-combo.h @@ -26,32 +26,14 @@ #include "trg-client.h" G_BEGIN_DECLS -#define TRG_TYPE_DESTINATION_COMBO trg_destination_combo_get_type() -#define TRG_DESTINATION_COMBO(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), TRG_TYPE_DESTINATION_COMBO, TrgDestinationCombo)) -#define TRG_DESTINATION_COMBO_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), TRG_TYPE_DESTINATION_COMBO, TrgDestinationComboClass)) -#define TRG_IS_DESTINATION_COMBO(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TRG_TYPE_DESTINATION_COMBO)) -#define TRG_IS_DESTINATION_COMBO_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), TRG_TYPE_DESTINATION_COMBO)) -#define TRG_DESTINATION_COMBO_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), TRG_TYPE_DESTINATION_COMBO, TrgDestinationComboClass)) - typedef struct { - GtkComboBox parent; -} TrgDestinationCombo; - -typedef struct { - GtkComboBoxClass parent_class; -} TrgDestinationComboClass; - -GType trg_destination_combo_get_type(void); + +#define TRG_TYPE_DESTINATION_COMBO (trg_destination_combo_get_type()) +G_DECLARE_FINAL_TYPE(TrgDestinationCombo, trg_destination_combo, TRG, DESTINATION_COMBO, GtkComboBox) GtkWidget *trg_destination_combo_new(TrgClient * client, const gchar * lastSelectionKey); gchar *trg_destination_combo_get_dir(TrgDestinationCombo * combo); gboolean trg_destination_combo_has_text(TrgDestinationCombo * combo); -GtkEntry *trg_destination_combo_get_entry(TrgDestinationCombo * combo); void trg_destination_combo_save_selection(TrgDestinationCombo * combo_box); G_END_DECLS diff --git a/src/trg-torrent-move-dialog.c b/src/trg-torrent-move-dialog.c index 555ea09..fec1932 100644 --- a/src/trg-torrent-move-dialog.c +++ b/src/trg-torrent-move-dialog.c @@ -80,7 +80,7 @@ trg_torrent_move_response_cb(GtkDialog * dlg, gint res_id, gpointer data) gtk_widget_destroy(GTK_WIDGET(dlg)); } -static void location_changed(GtkWidget * w, gpointer data) +static void location_changed(GtkComboBox * w, gpointer data) { TrgTorrentMoveDialogPrivate *priv = TRG_TORRENT_MOVE_DIALOG_GET_PRIVATE(data); @@ -114,8 +114,7 @@ static GObject *trg_torrent_move_dialog_constructor(GType type, w = priv->location_combo = trg_destination_combo_new(priv->client, TRG_PREFS_KEY_LAST_MOVE_DESTINATION); - g_signal_connect(trg_destination_combo_get_entry - (TRG_DESTINATION_COMBO(w)), "changed", + g_signal_connect(w, "changed", G_CALLBACK(location_changed), object); hig_workarea_add_row(t, &row, _("Location:"), w, NULL); -- cgit v1.2.3