/* gdict-source-dialog.c - source dialog * * This file is part of MATE Dictionary * * Copyright (C) 2005 Emmanuele Bassi * * 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 St, Fifth Floor, Boston, MA * 02110-1301, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include #include "gdict-source-dialog.h" #include "gdict-common.h" #define GDICT_SOURCE_UI PKGDATADIR "/mate-dictionary-source.ui" #define GET_WIDGET(x) (GTK_WIDGET (gtk_builder_get_object (dialog->builder, (x)))) #define GET_EDITABLE(x) (GTK_EDITABLE (gtk_builder_get_object (dialog->builder, (x)))) /********************* * GdictSourceDialog * *********************/ struct _GdictSourceDialog { GtkDialog parent_instance; GtkBuilder *builder; GSettings *settings; GdictSourceLoader *loader; GdictSource *source; gchar *source_name; GdictContext *context; GdictSourceDialogAction action; GdictSourceTransport transport; GtkWidget *add_button; GtkWidget *close_button; GtkWidget *cancel_button; GtkWidget *help_button; GtkWidget *db_chooser; GtkWidget *strat_chooser; GtkWidget *transport_combo; }; struct _GdictSourceDialogClass { GtkDialogClass parent_class; }; enum { PROP_0, PROP_SOURCE_LOADER, PROP_SOURCE_NAME, PROP_ACTION }; G_DEFINE_TYPE (GdictSourceDialog, gdict_source_dialog, GTK_TYPE_DIALOG); static void set_source_loader (GdictSourceDialog *dialog, GdictSourceLoader *loader) { if (dialog->loader) g_object_unref (dialog->loader); dialog->loader = g_object_ref (loader); } static void transport_combo_changed_cb (GtkWidget *widget, gpointer user_data) { GdictSourceDialog *dialog = GDICT_SOURCE_DIALOG (user_data); gint transport; transport = gtk_combo_box_get_active (GTK_COMBO_BOX (widget)); if (transport == dialog->transport) return; if (transport == GDICT_SOURCE_TRANSPORT_DICTD) { gtk_widget_show (GET_WIDGET ("hostname_label")); gtk_widget_show (GET_WIDGET ("hostname_entry")); gtk_widget_show (GET_WIDGET ("port_label")); gtk_widget_show (GET_WIDGET ("port_entry")); if (dialog->action == GDICT_SOURCE_DIALOG_CREATE) { gtk_widget_set_sensitive (dialog->add_button, TRUE); dialog->transport = GDICT_SOURCE_TRANSPORT_DICTD; } } else { gtk_widget_hide (GET_WIDGET ("hostname_label")); gtk_widget_hide (GET_WIDGET ("hostname_entry")); gtk_widget_hide (GET_WIDGET ("port_label")); gtk_widget_hide (GET_WIDGET ("port_entry")); if (dialog->action == GDICT_SOURCE_DIALOG_CREATE) { gtk_widget_set_sensitive (dialog->add_button, FALSE); dialog->transport = GDICT_SOURCE_TRANSPORT_INVALID; } } } static gchar * get_text_from_entry (GdictSourceDialog *dialog, const gchar *entry_name) { GtkWidget *entry; gchar *retval; entry = GET_WIDGET (entry_name); if (!entry) return NULL; retval = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1); return retval; } static void set_text_to_entry (GdictSourceDialog *dialog, const gchar *entry_name, const gchar *text) { GtkWidget *entry; entry = GET_WIDGET (entry_name); if (!entry) return; gtk_entry_set_text (GTK_ENTRY (entry), text); } static void set_transport_settings (GdictSourceDialog *dialog) { switch (dialog->transport) { case GDICT_SOURCE_TRANSPORT_DICTD: { GdictClientContext *context; const gchar *hostname; gchar *port_str; guint port; context = GDICT_CLIENT_CONTEXT (dialog->context); hostname = gdict_client_context_get_hostname (context); port = gdict_client_context_get_port (context); port_str = g_strdup_printf ("%d", port); set_text_to_entry (dialog, "hostname_entry", hostname); set_text_to_entry (dialog, "port_entry", port_str); gtk_widget_show (GET_WIDGET ("hostname_label")); gtk_widget_show (GET_WIDGET ("hostname_entry")); gtk_widget_show (GET_WIDGET ("port_label")); gtk_widget_show (GET_WIDGET ("port_entry")); g_free (port_str); } break; case GDICT_SOURCE_TRANSPORT_INVALID: default: break; } } static void update_dialog_ui (GdictSourceDialog *dialog) { GdictSource *source; /* TODO - add code to update the contents of the dialog depending * on the action; if we are in _CREATE, no action is needed */ switch (dialog->action) { case GDICT_SOURCE_DIALOG_VIEW: case GDICT_SOURCE_DIALOG_EDIT: if (!dialog->source_name) { g_warning ("Attempting to retrieve source, but no " "source name has been defined. Aborting..."); return; } source = gdict_source_loader_get_source (dialog->loader, dialog->source_name); if (!source) { g_warning ("Attempting to retrieve source, but no " "source named `%s' was found. Aborting...", dialog->source_name); return; } g_object_ref (source); dialog->source = source; set_text_to_entry (dialog, "description_entry", gdict_source_get_description (source)); dialog->transport = gdict_source_get_transport (source); gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->transport_combo), (gint) dialog->transport); /* set the context for the database and strategy choosers */ dialog->context = gdict_source_get_context (source); if (!dialog->context) { g_warning ("Attempting to retrieve the context, but " "none was found for source `%s'.", dialog->source_name); return; } set_transport_settings (dialog); gdict_database_chooser_set_context (GDICT_DATABASE_CHOOSER (dialog->db_chooser), dialog->context); gdict_database_chooser_refresh (GDICT_DATABASE_CHOOSER (dialog->db_chooser)); gdict_strategy_chooser_set_context (GDICT_STRATEGY_CHOOSER (dialog->strat_chooser), dialog->context); gdict_strategy_chooser_refresh (GDICT_STRATEGY_CHOOSER (dialog->strat_chooser)); break; case GDICT_SOURCE_DIALOG_CREATE: /* DICTD transport is default */ gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->transport_combo), 0); g_signal_emit_by_name (dialog->transport_combo, "changed"); break; default: g_assert_not_reached (); break; } } static void build_new_source (GdictSourceDialog *dialog) { GdictSource *source; gchar *name, *text; GdictSourceTransport transport; gchar *host, *port; gchar *data; gsize length; GError *error; gchar *filename; GdictDatabaseChooser *db_chooser; GdictStrategyChooser *strat_chooser; source = gdict_source_new (); /* use the timestamp and the pid to get a unique name */ name = g_strdup_printf ("source-%lu-%u", (gulong) time (NULL), (guint) getpid ()); gdict_source_set_name (source, name); g_free (name); text = get_text_from_entry (dialog, "description_entry"); gdict_source_set_description (source, text); g_free (text); db_chooser = GDICT_DATABASE_CHOOSER (dialog->db_chooser); text = gdict_database_chooser_get_current_database (db_chooser); gdict_source_set_database (source, text); g_free (text); strat_chooser = GDICT_STRATEGY_CHOOSER (dialog->strat_chooser); text = gdict_strategy_chooser_get_current_strategy (strat_chooser); gdict_source_set_strategy (source, text); g_free (text); /* get the selected transport id */ transport = dialog->transport; switch (transport) { case GDICT_SOURCE_TRANSPORT_DICTD: host = get_text_from_entry (dialog, "hostname_entry"); port = get_text_from_entry (dialog, "port_entry"); gdict_source_set_transport (source, GDICT_SOURCE_TRANSPORT_DICTD, "hostname", host, "port", atoi (port), NULL); g_free (host); g_free (port); break; case GDICT_SOURCE_TRANSPORT_INVALID: default: g_warning ("Invalid transport"); return; } error = NULL; data = gdict_source_to_data (source, &length, &error); if (error) { gdict_show_gerror_dialog (GTK_WINDOW (dialog), _("Unable to create a source file"), error); g_object_unref (source); return; } name = g_strdup_printf ("%s.desktop", gdict_source_get_name (source)); filename = g_build_filename (g_get_user_config_dir (), "mate", "mate-dictionary", name, NULL); g_free (name); g_file_set_contents (filename, data, length, &error); if (error) gdict_show_gerror_dialog (GTK_WINDOW (dialog), _("Unable to save source file"), error); g_free (filename); g_free (data); g_object_unref (source); } static void save_source (GdictSourceDialog *dialog) { GdictSource *source; GdictDatabaseChooser *db_chooser; GdictStrategyChooser *strat_chooser; gchar *name, *text; GdictSourceTransport transport; gchar *host, *port; gchar *data; gsize length; GError *error; gchar *filename; source = gdict_source_loader_get_source (dialog->loader, dialog->source_name); if (!source) { g_warning ("Attempting to save source `%s', but no " "source for that name was found.", dialog->source_name); return; } text = get_text_from_entry (dialog, "description_entry"); gdict_source_set_description (source, text); g_free (text); db_chooser = GDICT_DATABASE_CHOOSER (dialog->db_chooser); text = gdict_database_chooser_get_current_database (db_chooser); gdict_source_set_database (source, text); g_free (text); strat_chooser = GDICT_STRATEGY_CHOOSER (dialog->strat_chooser); text = gdict_strategy_chooser_get_current_strategy (strat_chooser); gdict_source_set_strategy (source, text); g_free (text); /* get the selected transport id */ transport = dialog->transport; switch (transport) { case GDICT_SOURCE_TRANSPORT_DICTD: host = get_text_from_entry (dialog, "hostname_entry"); port = get_text_from_entry (dialog, "port_entry"); gdict_source_set_transport (source, GDICT_SOURCE_TRANSPORT_DICTD, "hostname", host, "port", atoi (port), NULL); g_free (host); g_free (port); break; case GDICT_SOURCE_TRANSPORT_INVALID: default: g_warning ("Invalid transport"); return; } error = NULL; data = gdict_source_to_data (source, &length, &error); if (error) { gdict_show_gerror_dialog (GTK_WINDOW (dialog), _("Unable to create a source file"), error); g_object_unref (source); return; } name = g_strdup_printf ("%s.desktop", gdict_source_get_name (source)); filename = g_build_filename (g_get_user_config_dir (), "mate", "mate-dictionary", name, NULL); g_free (name); g_file_set_contents (filename, data, length, &error); if (error) gdict_show_gerror_dialog (GTK_WINDOW (dialog), _("Unable to save source file"), error); g_free (filename); g_free (data); g_object_unref (source); } static void gdict_source_dialog_response_cb (GtkDialog *dialog, gint response_id, gpointer user_data) { GError *err = NULL; switch (response_id) { case GTK_RESPONSE_ACCEPT: build_new_source (GDICT_SOURCE_DIALOG (dialog)); break; case GTK_RESPONSE_HELP: gtk_show_uri_on_window (GTK_WINDOW (dialog), "help:mate-dictionary/mate-dictionary-add-source", gtk_get_current_event_time (), &err); if (err) { gdict_show_gerror_dialog (GTK_WINDOW (dialog), _("There was an error while displaying help"), err); } /* we don't want the dialog to close itself */ g_signal_stop_emission_by_name (dialog, "response"); break; case GTK_RESPONSE_CLOSE: save_source (GDICT_SOURCE_DIALOG (dialog)); break; case GTK_RESPONSE_CANCEL: break; default: break; } } static void gdict_source_dialog_finalize (GObject *object) { GdictSourceDialog *dialog = GDICT_SOURCE_DIALOG (object); if (dialog->settings) g_object_unref (dialog->settings); if (dialog->builder) g_object_unref (dialog->builder); if (dialog->source_name) g_free (dialog->source_name); if (dialog->source) g_object_unref (dialog->source); if (dialog->loader) g_object_unref (dialog->loader); G_OBJECT_CLASS (gdict_source_dialog_parent_class)->finalize (object); } static void gdict_source_dialog_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GdictSourceDialog *dialog = GDICT_SOURCE_DIALOG (object); switch (prop_id) { case PROP_SOURCE_LOADER: set_source_loader (dialog, g_value_get_object (value)); break; case PROP_SOURCE_NAME: g_free (dialog->source_name); dialog->source_name = g_strdup (g_value_get_string (value)); break; case PROP_ACTION: dialog->action = (GdictSourceDialogAction) g_value_get_int (value); break; default: break; } } static void gdict_source_dialog_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GdictSourceDialog *dialog = GDICT_SOURCE_DIALOG (object); switch (prop_id) { case PROP_SOURCE_LOADER: g_value_set_object (value, dialog->loader); break; case PROP_SOURCE_NAME: g_value_set_string (value, dialog->source_name); break; case PROP_ACTION: g_value_set_int (value, dialog->action); break; default: break; } } static GObject * gdict_source_dialog_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_params) { GObject *object; GdictSourceDialog *dialog; GError *error = NULL; object = G_OBJECT_CLASS (gdict_source_dialog_parent_class)->constructor (type, n_construct_properties, construct_params); dialog = GDICT_SOURCE_DIALOG (object); gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 2); /* get the UI from the GtkBuilder file */ dialog->builder = gtk_builder_new (); gtk_builder_add_from_file (dialog->builder, GDICT_SOURCE_UI, &error); if (error) { g_critical ("Unable to load the user interface definition file: %s", error->message); g_error_free (error); g_assert_not_reached (); } /* the main widget */ gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), GET_WIDGET ("source_root")); /* the transport combo changes the UI by changing the visible widgets * bound to the transport's own options. */ dialog->transport_combo = GET_WIDGET ("transport_combo"); g_signal_connect (dialog->transport_combo, "changed", G_CALLBACK (transport_combo_changed_cb), dialog); /* the help button is always visible */ dialog->help_button = gtk_dialog_add_button (GTK_DIALOG (dialog), "gtk-help", GTK_RESPONSE_HELP); dialog->db_chooser = gdict_database_chooser_new (); gtk_box_pack_start (GTK_BOX (GET_WIDGET ("db-box")), dialog->db_chooser, TRUE, TRUE, 0); gtk_widget_show (dialog->db_chooser); dialog->strat_chooser = gdict_strategy_chooser_new (); gtk_box_pack_start (GTK_BOX (GET_WIDGET ("strat-box")), dialog->strat_chooser, TRUE, TRUE, 0); gtk_widget_show (dialog->strat_chooser); /* the UI changes depending on the action that the source dialog * should perform */ switch (dialog->action) { case GDICT_SOURCE_DIALOG_VIEW: /* disable every editable widget */ gtk_editable_set_editable (GET_EDITABLE ("name_entry"), FALSE); gtk_editable_set_editable (GET_EDITABLE ("description_entry"), FALSE); gtk_editable_set_editable (GET_EDITABLE ("hostname_entry"), FALSE); gtk_editable_set_editable (GET_EDITABLE ("port_entry"), FALSE); gtk_widget_set_sensitive (dialog->transport_combo, FALSE); /* we just allow closing the dialog */ dialog->close_button = gtk_dialog_add_button (GTK_DIALOG (dialog), "gtk-close", GTK_RESPONSE_CLOSE); break; case GDICT_SOURCE_DIALOG_CREATE: dialog->cancel_button = gtk_dialog_add_button (GTK_DIALOG (dialog), "gtk-cancel", GTK_RESPONSE_CANCEL); dialog->add_button = gtk_dialog_add_button (GTK_DIALOG (dialog), "gtk-add", GTK_RESPONSE_ACCEPT); /* the "add" button sensitivity is controlled by the transport_combo * since it's the only setting that makes a source usable. */ gtk_widget_set_sensitive (dialog->add_button, FALSE); break; case GDICT_SOURCE_DIALOG_EDIT: dialog->cancel_button = gtk_dialog_add_button (GTK_DIALOG (dialog), "gtk-cancel", GTK_RESPONSE_CANCEL); dialog->close_button = gtk_dialog_add_button (GTK_DIALOG (dialog), "gtk-close", GTK_RESPONSE_CLOSE); break; default: g_assert_not_reached (); break; } /* this will take care of updating the contents of the dialog * based on the action */ update_dialog_ui (dialog); return object; } static void gdict_source_dialog_class_init (GdictSourceDialogClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->constructor = gdict_source_dialog_constructor; gobject_class->set_property = gdict_source_dialog_set_property; gobject_class->get_property = gdict_source_dialog_get_property; gobject_class->finalize = gdict_source_dialog_finalize; g_object_class_install_property (gobject_class, PROP_SOURCE_LOADER, g_param_spec_object ("source-loader", "Source Loader", "The GdictSourceLoader used by the application", GDICT_TYPE_SOURCE_LOADER, (G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY))); g_object_class_install_property (gobject_class, PROP_SOURCE_NAME, g_param_spec_string ("source-name", "Source Name", "The source name", NULL, (G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT))); g_object_class_install_property (gobject_class, PROP_ACTION, g_param_spec_int ("action", "Action", "The action the source dialog should perform", -1, GDICT_SOURCE_DIALOG_EDIT, GDICT_SOURCE_DIALOG_VIEW, (G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY))); } static void gdict_source_dialog_init (GdictSourceDialog *dialog) { gtk_widget_set_size_request (GTK_WIDGET (dialog), 400, 300); gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); dialog->transport = GDICT_SOURCE_TRANSPORT_INVALID; g_signal_connect (dialog, "response", G_CALLBACK (gdict_source_dialog_response_cb), NULL); } GtkWidget * gdict_source_dialog_new (GtkWindow *parent, const gchar *title, GdictSourceDialogAction action, GdictSourceLoader *loader, const gchar *source_name) { GtkWidget *retval; g_return_val_if_fail ((parent == NULL || GTK_IS_WINDOW (parent)), NULL); g_return_val_if_fail (GDICT_IS_SOURCE_LOADER (loader), NULL); retval = g_object_new (GDICT_TYPE_SOURCE_DIALOG, "source-loader", loader, "source-name", source_name, "action", action, "title", title, NULL); if (parent) { gtk_window_set_transient_for (GTK_WINDOW (retval), parent); gtk_window_set_destroy_with_parent (GTK_WINDOW (retval), TRUE); gtk_window_set_screen (GTK_WINDOW (retval), gtk_widget_get_screen (GTK_WIDGET (parent))); } return retval; }