/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */ /* Copyright (C) 2006 Carlos Garnacho * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * * Authors: Carlos Garnacho Parro */ #include #include #include "locations-combo.h" #include "gst.h" #define GST_LOCATIONS_COMBO_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GST_TYPE_LOCATIONS_COMBO, GstLocationsComboPrivate)) typedef struct _GstLocationsComboPrivate GstLocationsComboPrivate; struct _GstLocationsComboPrivate { GstTool *tool; GtkTreeModel *model; GtkWidget *combo; GtkWidget *save_button; GtkWidget *delete_button; GtkWidget *save_dialog; GtkWidget *location_entry; }; enum { PROP_0, PROP_TOOL, PROP_COMBO, PROP_SAVE, PROP_DELETE }; static void gst_locations_combo_class_init (GstLocationsComboClass *class); static void gst_locations_combo_init (GstLocationsCombo *combo); static void gst_locations_combo_finalize (GObject *object); static void gst_locations_combo_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void gst_locations_combo_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static GObject* gst_locations_combo_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_params); static void gst_locations_combo_changed (GstNetworkLocations *locations); G_DEFINE_TYPE (GstLocationsCombo, gst_locations_combo, GST_TYPE_NETWORK_LOCATIONS); static void gst_locations_combo_class_init (GstLocationsComboClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); GstNetworkLocationsClass *locations_class = GST_NETWORK_LOCATIONS_CLASS (class); object_class->finalize = gst_locations_combo_finalize; object_class->get_property = gst_locations_combo_get_property; object_class->set_property = gst_locations_combo_set_property; object_class->constructor = gst_locations_combo_constructor; locations_class->changed = gst_locations_combo_changed; g_object_class_install_property (object_class, PROP_TOOL, g_param_spec_object ("tool", "Tool", "Tool", GST_TYPE_TOOL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_COMBO, g_param_spec_object ("combo", "Combo", "Combo", GTK_TYPE_COMBO_BOX, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_SAVE, g_param_spec_object ("save", "Save", "Save", GTK_TYPE_BUTTON, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_DELETE, g_param_spec_object ("delete", "Delete", "Delete", GTK_TYPE_BUTTON, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_type_class_add_private (object_class, sizeof (GstLocationsComboPrivate)); } static void gst_locations_combo_init (GstLocationsCombo *combo) { GstLocationsComboPrivate *priv; combo->_priv = priv = GST_LOCATIONS_COMBO_GET_PRIVATE (combo); priv->model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING)); } static void gst_locations_combo_finalize (GObject *object) { GstLocationsComboPrivate *priv; priv = GST_LOCATIONS_COMBO_GET_PRIVATE (object); if (priv->combo) g_object_unref (priv->combo); if (priv->save_button) g_object_unref (priv->save_button); if (priv->delete_button) g_object_unref (priv->delete_button); if (priv->model) g_object_unref (priv->model); } static void gst_locations_combo_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GstLocationsComboPrivate *priv; g_return_if_fail (GST_IS_LOCATIONS_COMBO (object)); priv = GST_LOCATIONS_COMBO_GET_PRIVATE (object); switch (prop_id) { case PROP_TOOL: priv->tool = GST_TOOL (g_value_get_object (value)); break; case PROP_COMBO: priv->combo = GTK_WIDGET (g_value_dup_object (value)); break; case PROP_SAVE: priv->save_button = GTK_WIDGET (g_value_dup_object (value)); break; case PROP_DELETE: priv->delete_button = GTK_WIDGET (g_value_dup_object (value)); break; } } static void gst_locations_combo_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GstLocationsComboPrivate *priv; g_return_if_fail (GST_IS_LOCATIONS_COMBO (object)); priv = GST_LOCATIONS_COMBO_GET_PRIVATE (object); switch (prop_id) { case PROP_TOOL: g_value_set_object (value, priv->tool); break; case PROP_COMBO: g_value_set_object (value, priv->combo); break; case PROP_SAVE: g_value_set_object (value, priv->save_button); break; case PROP_DELETE: g_value_set_object (value, priv->delete_button); break; } } static void on_combo_changed (GtkWidget *widget, gpointer data) { GstLocationsComboPrivate *priv; GstNetworkLocations *locations; GtkTreeModel *model; GtkTreeIter iter; gchar *str; locations = GST_NETWORK_LOCATIONS (data); priv = GST_LOCATIONS_COMBO (data)->_priv; model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget)); if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter)) { gtk_tree_model_get (model, &iter, 0, &str, -1); gst_network_locations_set_location (locations, str); gst_tool_update_gui (priv->tool); gst_tool_commit (priv->tool, locations->hosts_config); gst_tool_commit_async (priv->tool, locations->ifaces_config, _("Changing network location"), NULL, NULL); g_free (str); } } static void on_dialog_entry_changed (GtkWidget *widget, gpointer data) { const gchar *text; text = gtk_entry_get_text (GTK_ENTRY (widget)); gtk_widget_set_sensitive (GTK_WIDGET (data), (text && *text)); } static gboolean check_save_location (GstLocationsCombo *combo, const gchar *name) { GstLocationsComboPrivate *priv; GList *names, *elem; gboolean found = FALSE; GtkWidget *dialog; gint response; priv = (GstLocationsComboPrivate *) combo->_priv; names = elem = gst_network_locations_get_names (GST_NETWORK_LOCATIONS (combo)); while (elem && !found) { if (strcmp (elem->data, name) == 0) found = TRUE; elem = elem->next; } g_list_foreach (names, (GFunc) g_free, NULL); g_list_free (names); if (!found) return TRUE; dialog = gtk_message_dialog_new (GTK_WINDOW (priv->tool->main_dialog), GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, _("There is already a location with the same name")); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), _("Overwrite it?")); response = gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); return (response == GTK_RESPONSE_YES); } static void select_matching_profile (GstLocationsCombo *combo) { GstLocationsComboPrivate *priv; GtkTreeIter iter; gchar *current; gchar *profile; gboolean valid; priv = combo->_priv; valid = gtk_tree_model_get_iter_first (priv->model, &iter); current = gst_network_locations_get_current (GST_NETWORK_LOCATIONS (combo)); while (valid) { gtk_tree_model_get (priv->model, &iter, 0, &profile, -1); if (profile && current && strcmp (profile, current) == 0) { gtk_combo_box_set_active_iter (GTK_COMBO_BOX (priv->combo), &iter); valid = FALSE; } else valid = gtk_tree_model_iter_next (priv->model, &iter); g_free (profile); } g_free (current); } static void on_save_dialog_response (GtkWidget *widget, gint response, gpointer data) { GstLocationsCombo *combo = GST_LOCATIONS_COMBO (data); GstLocationsComboPrivate *priv = GST_LOCATIONS_COMBO_GET_PRIVATE (combo); const gchar *name; if (response == GTK_RESPONSE_OK) { name = gtk_entry_get_text (GTK_ENTRY (priv->location_entry)); /* check if the location already exists * and ask the user if necessary */ if (check_save_location (combo, name)) { /* save the data and hide the dialog */ gtk_widget_hide (priv->save_dialog); gst_network_locations_save_current (GST_NETWORK_LOCATIONS (combo), name); select_matching_profile (combo); } else gtk_widget_grab_focus (priv->location_entry); } else gtk_widget_hide (priv->save_dialog); } static gboolean on_save_dialog_delete_event (GtkWidget *widget, GdkEvent *event, gpointer data) { /* block the event */ return TRUE; } static void on_save_button_clicked (GtkWidget *widget, gpointer data) { GstLocationsCombo *combo; GstLocationsComboPrivate *priv; GtkTreeModel *model; GtkTreeIter iter; gchar *name; combo = GST_LOCATIONS_COMBO (data); priv = GST_LOCATIONS_COMBO_GET_PRIVATE (combo); if (!priv->save_dialog) { GtkWidget *hbox, *label, *button; priv->save_dialog = gtk_dialog_new_with_buttons (_("Save location"), GTK_WINDOW (priv->tool->main_dialog), GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR, NULL); gtk_dialog_add_button (GTK_DIALOG (priv->save_dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); button = gtk_dialog_add_button (GTK_DIALOG (priv->save_dialog), GTK_STOCK_SAVE, GTK_RESPONSE_OK); gtk_dialog_set_default_response (GTK_DIALOG (priv->save_dialog), GTK_RESPONSE_OK); gtk_widget_set_sensitive (button, FALSE); g_signal_connect (G_OBJECT (priv->save_dialog), "response", G_CALLBACK (on_save_dialog_response), combo); g_signal_connect (G_OBJECT (priv->save_dialog), "delete-event", G_CALLBACK (on_save_dialog_delete_event), combo); label = gtk_label_new_with_mnemonic (_("_Location name:")); priv->location_entry = gtk_entry_new (); gtk_entry_set_activates_default (GTK_ENTRY (priv->location_entry), TRUE); gtk_label_set_mnemonic_widget (GTK_LABEL (label), priv->location_entry); g_signal_connect (G_OBJECT (priv->location_entry), "changed", G_CALLBACK (on_dialog_entry_changed), button); hbox = gtk_hbox_new (FALSE, 6); gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), priv->location_entry, TRUE, TRUE, 0); gtk_widget_show_all (hbox); gtk_container_add (GTK_CONTAINER (GTK_DIALOG (priv->save_dialog)->vbox), hbox); } model = gtk_combo_box_get_model (GTK_COMBO_BOX (priv->combo)); /* set the current location by default */ if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (priv->combo), &iter)) { gtk_tree_model_get (model, &iter, 0, &name, -1); gtk_entry_set_text (GTK_ENTRY (priv->location_entry), name); g_free (name); } else gtk_entry_set_text (GTK_ENTRY (priv->location_entry), ""); gtk_widget_grab_focus (priv->location_entry); gtk_widget_show (priv->save_dialog); } static void on_delete_button_clicked (GtkWidget *widget, gpointer data) { GstLocationsComboPrivate *priv; GtkTreeIter iter; GtkWidget *dialog; gint response; gchar *name; priv = GST_LOCATIONS_COMBO_GET_PRIVATE (data); if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (priv->combo), &iter)) { gtk_tree_model_get (priv->model, &iter, 0, &name, -1); dialog = gtk_message_dialog_new (GTK_WINDOW (priv->tool->main_dialog), GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, _("Do you want to delete location \"%s\"?"), name); response = gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); if (response == GTK_RESPONSE_YES) gst_network_locations_delete_location (GST_NETWORK_LOCATIONS (data), name); } } static void fill_model (GstLocationsCombo *combo, GtkTreeModel *model) { GList *names; GtkTreeIter iter; gtk_list_store_clear (GTK_LIST_STORE (model)); names = gst_network_locations_get_names (GST_NETWORK_LOCATIONS (combo)); while (names) { gtk_list_store_append (GTK_LIST_STORE (model), &iter); gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, names->data, -1); names = names->next; } g_list_foreach (names, (GFunc) g_free, NULL); g_list_free (names); } static GObject* gst_locations_combo_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_params) { GObject *object; GstLocationsComboPrivate *priv; GtkCellRenderer *renderer; object = (* G_OBJECT_CLASS (gst_locations_combo_parent_class)->constructor) (type, n_construct_properties, construct_params); priv = GST_LOCATIONS_COMBO_GET_PRIVATE (object); gtk_combo_box_set_model (GTK_COMBO_BOX (priv->combo), priv->model); fill_model (GST_LOCATIONS_COMBO (object), priv->model); select_matching_profile (GST_LOCATIONS_COMBO (object)); renderer = gtk_cell_renderer_text_new (); gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (priv->combo), renderer, TRUE); gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (priv->combo), renderer, "text", 0, NULL); g_signal_connect (G_OBJECT (priv->combo), "changed", G_CALLBACK (on_combo_changed), object); g_signal_connect (G_OBJECT (priv->save_button), "clicked", G_CALLBACK (on_save_button_clicked), object); g_signal_connect (G_OBJECT (priv->delete_button), "clicked", G_CALLBACK (on_delete_button_clicked), object); return object; } static void gst_locations_combo_changed (GstNetworkLocations *locations) { GstLocationsComboPrivate *priv; priv = GST_LOCATIONS_COMBO_GET_PRIVATE (locations); fill_model (GST_LOCATIONS_COMBO (locations), priv->model); g_signal_handlers_block_by_func (priv->combo, on_combo_changed, locations); select_matching_profile (GST_LOCATIONS_COMBO (locations)); g_signal_handlers_unblock_by_func (priv->combo, on_combo_changed, locations); } GstLocationsCombo* gst_locations_combo_new (GstTool *tool, GtkWidget *combo, GtkWidget *save, GtkWidget *delete) { return g_object_new (GST_TYPE_LOCATIONS_COMBO, "tool", tool, "combo", combo, "save", save, "delete", delete, NULL); }