/* * Copyright (C) 2002 Jorn Baayen * Copyright (C) 2003 Marco Pesenti Gritti * Copyright (C) 2003, 2004 Christian Persch * * 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, 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. * * $Id$ */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "find-dialog.h" #include "ephy-file-helpers.h" #include "ephy-prefs.h" #include "ephy-embed.h" #include "ephy-debug.h" #include #define CONF_FIND_MATCH_CASE "/apps/epiphany/dialogs/find_match_case" #define CONF_FIND_AUTOWRAP "/apps/epiphany/dialogs/find_autowrap" #define CONF_FIND_WORD "/apps/epiphany/dialogs/find_word" static void find_dialog_class_init (FindDialogClass *klass); static void find_dialog_init (FindDialog *dialog); static void find_dialog_finalize (GObject *object); /* Glade callbacks */ void find_close_button_clicked_cb (GtkWidget *button, EphyDialog *dialog); void find_next_button_clicked_cb (GtkWidget *button, EphyDialog *dialog); void find_prev_button_clicked_cb (GtkWidget *button, EphyDialog *dialog); void find_entry_changed_cb (GtkWidget *editable, EphyDialog *dialog); void find_check_toggled_cb (GtkWidget *toggle, EphyDialog *dialog); static GObjectClass *parent_class = NULL; #define EPHY_FIND_DIALOG_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_FIND_DIALOG, FindDialogPrivate)) struct FindDialogPrivate { EphyEmbed *old_embed; gboolean initialised; }; enum { WINDOW_PROP, MATCH_CASE_PROP, AUTOWRAP_PROP, WORD_PROP, BACK_BUTTON, FORWARD_BUTTON }; static const EphyDialogProperty properties [] = { { "find_dialog", NULL, PT_NORMAL, 0 }, { "case_check", CONF_FIND_MATCH_CASE, PT_NORMAL, 0 }, { "wrap_check", CONF_FIND_AUTOWRAP, PT_NORMAL, 0 }, { "find_entry", CONF_FIND_WORD, PT_NORMAL, 0 }, { "back_button", NULL, PT_NORMAL, 0 }, { "forward_button", NULL, PT_NORMAL, 0 }, { NULL } }; GType find_dialog_get_type (void) { static GType type = 0; if (G_UNLIKELY (type == 0)) { static const GTypeInfo our_info = { sizeof (FindDialogClass), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) find_dialog_class_init, NULL, NULL, /* class_data */ sizeof (FindDialog), 0, /* n_preallocs */ (GInstanceInitFunc) find_dialog_init }; type = g_type_register_static (EPHY_TYPE_EMBED_DIALOG, "FindDialog", &our_info, 0); } return type; } static void update_navigation_controls (FindDialog *dialog, gboolean prev, gboolean next) { GtkWidget *button; button = ephy_dialog_get_control (EPHY_DIALOG (dialog), properties[BACK_BUTTON].id); gtk_widget_set_sensitive (button, prev); button = ephy_dialog_get_control (EPHY_DIALOG (dialog), properties[FORWARD_BUTTON].id); gtk_widget_set_sensitive (button, next); } static void set_properties (FindDialog *find_dialog) { char *search_string; GValue match_case = {0, }; GValue wrap = {0, }; GValue word = {0, }; gboolean b_match_case; gboolean b_wrap; EphyDialog *dialog = EPHY_DIALOG (find_dialog); EphyEmbed *embed; if (!find_dialog->priv->initialised) return; /* get the search string from the entry field */ ephy_dialog_get_value (dialog, properties[WORD_PROP].id, &word); search_string = g_strdup (g_value_get_string (&word)); g_value_unset (&word); /* don't do null searches */ if (search_string == NULL || search_string[0] == '\0') { update_navigation_controls (find_dialog, FALSE, FALSE); g_free (search_string); return; } ephy_dialog_get_value (dialog, properties[MATCH_CASE_PROP].id, &match_case); b_match_case = g_value_get_boolean (&match_case); g_value_unset (&match_case); ephy_dialog_get_value (dialog, properties[AUTOWRAP_PROP].id, &wrap); b_wrap = g_value_get_boolean (&wrap); g_value_unset (&wrap); embed = ephy_embed_dialog_get_embed (EPHY_EMBED_DIALOG(dialog)); g_return_if_fail (embed != NULL); ephy_embed_find_set_properties (embed, search_string, b_match_case, b_wrap); g_free (search_string); } static void impl_show (EphyDialog *dialog) { EPHY_DIALOG_CLASS (parent_class)->show (dialog); EPHY_FIND_DIALOG (dialog)->priv->initialised = TRUE; set_properties (EPHY_FIND_DIALOG (dialog)); /* Focus the text entry. This will correctly select or leave * unselected the existing text in the entry depending on the * 'gtk-entry-select-on-focus = 0 / 1' setting in user's gtkrc. */ gtk_widget_grab_focus (ephy_dialog_get_control (dialog, properties[WORD_PROP].id)); } static void find_dialog_class_init (FindDialogClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); EphyDialogClass *ephy_dialog_class; parent_class = g_type_class_peek_parent (klass); ephy_dialog_class = EPHY_DIALOG_CLASS (klass); object_class->finalize = find_dialog_finalize; ephy_dialog_class->show = impl_show; g_type_class_add_private (object_class, sizeof (FindDialogPrivate)); } static void sync_page_change (EphyEmbed *embed, const char *address, FindDialog *dialog) { g_return_if_fail (EPHY_IS_EMBED (embed)); update_navigation_controls (dialog, TRUE, TRUE); set_properties (dialog); } static void unset_old_embed (FindDialog *dialog) { if (dialog->priv->old_embed != NULL) { g_signal_handlers_disconnect_by_func (dialog->priv->old_embed, G_CALLBACK (sync_page_change), dialog); g_object_remove_weak_pointer (G_OBJECT (dialog->priv->old_embed), (gpointer *)&dialog->priv->old_embed); dialog->priv->old_embed = NULL; } } static void sync_embed (FindDialog *dialog, GParamSpec *pspec, gpointer data) { EphyEmbed *embed; unset_old_embed (dialog); embed = ephy_embed_dialog_get_embed (EPHY_EMBED_DIALOG (dialog)); g_return_if_fail (EPHY_IS_EMBED (embed)); dialog->priv->old_embed = embed; g_signal_connect (G_OBJECT (embed), "ge_location", G_CALLBACK (sync_page_change), dialog); g_object_add_weak_pointer (G_OBJECT (embed), (gpointer *)&dialog->priv->old_embed); update_navigation_controls (dialog, TRUE, TRUE); set_properties (dialog); } static void find_dialog_init (FindDialog *dialog) { GtkWidget *window; dialog->priv = EPHY_FIND_DIALOG_GET_PRIVATE (dialog); ephy_dialog_construct (EPHY_DIALOG(dialog), properties, ephy_file ("epiphany.glade"), "find_dialog", NULL); update_navigation_controls (dialog, TRUE, TRUE); window = ephy_dialog_get_control (EPHY_DIALOG (dialog), properties[WINDOW_PROP].id); gtk_window_set_icon_name (GTK_WINDOW (window), GTK_STOCK_FIND); g_signal_connect_object (dialog, "notify::embed", G_CALLBACK (sync_embed), NULL, 0); } static void find_dialog_finalize (GObject *object) { FindDialog *dialog; g_return_if_fail (EPHY_IS_FIND_DIALOG (object)); dialog = EPHY_FIND_DIALOG (object); g_signal_handlers_disconnect_by_func (dialog, G_CALLBACK (sync_embed), NULL); unset_old_embed (dialog); G_OBJECT_CLASS (parent_class)->finalize (object); } EphyDialog * find_dialog_new (EphyEmbed *embed) { FindDialog *dialog; dialog = EPHY_FIND_DIALOG (g_object_new (EPHY_TYPE_FIND_DIALOG, "embed", embed, NULL)); return EPHY_DIALOG(dialog); } EphyDialog * find_dialog_new_with_parent (GtkWidget *window, EphyEmbed *embed) { FindDialog *dialog; dialog = EPHY_FIND_DIALOG (g_object_new (EPHY_TYPE_FIND_DIALOG, "embed", embed, "parent-window", window, NULL)); return EPHY_DIALOG(dialog); } static void find_dialog_go_next (FindDialog *dialog) { EphyEmbed *embed; g_return_if_fail (EPHY_IS_FIND_DIALOG (dialog)); embed = ephy_embed_dialog_get_embed (EPHY_EMBED_DIALOG(dialog)); g_return_if_fail (embed != NULL); if (ephy_embed_find_next (embed, FALSE)) { update_navigation_controls (dialog, TRUE, TRUE); } else { update_navigation_controls (dialog, TRUE, FALSE); } } static void find_dialog_go_prev (FindDialog *dialog) { EphyEmbed *embed; g_return_if_fail (EPHY_IS_FIND_DIALOG (dialog)); embed = ephy_embed_dialog_get_embed (EPHY_EMBED_DIALOG(dialog)); g_return_if_fail (embed != NULL); if (ephy_embed_find_next (embed, TRUE)) { update_navigation_controls (dialog, TRUE, TRUE); } else { update_navigation_controls (dialog, FALSE, TRUE); } } void find_close_button_clicked_cb (GtkWidget *button, EphyDialog *dialog) { g_object_unref (dialog); } void find_next_button_clicked_cb (GtkWidget *button, EphyDialog *dialog) { find_dialog_go_next (EPHY_FIND_DIALOG(dialog)); } void find_prev_button_clicked_cb (GtkWidget *button, EphyDialog *dialog) { find_dialog_go_prev (EPHY_FIND_DIALOG(dialog)); } void find_entry_changed_cb (GtkWidget *editable, EphyDialog *dialog) { FindDialog *find_dialog = EPHY_FIND_DIALOG(dialog); update_navigation_controls (find_dialog, TRUE, TRUE); set_properties (find_dialog); } void find_check_toggled_cb (GtkWidget *toggle, EphyDialog *dialog) { FindDialog *find_dialog = EPHY_FIND_DIALOG(dialog); update_navigation_controls (find_dialog, TRUE, TRUE); set_properties (find_dialog); }