/** * @file * Display a dialog to let the user search through results. * * @author Jeremy A. Mowery jmowery@tresys.com * @author Jason Tang jtang@tresys.com * @author Brandon Whalen bwhalen@tresys.com * @author Randy Wicks rwicks@tresys.com * * Copyright (C) 2005-2007 Tresys Technology, LLC * * 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 */ #include #include "find_dialog.h" #include "utilgui.h" #include #include #include #include #include struct find_dialog { toplevel_t *top; GladeXML *xml; /** offset to start searching from if searching up and the * start of the offset to select from */ gint start_offset; /** the offset to start searching from if searching down and * the offset to end selecting from */ gint end_offset; /** the main window */ GtkDialog *w; GtkEntry *entry; GtkRadioButton *forward, *reverse; }; static void find_dialog_search(find_dialog_t * f) { GtkTextView *view = toplevel_get_text_view(f->top); GtkTextBuffer *tb = gtk_text_view_get_buffer(view); GtkTextMark *mark = gtk_text_buffer_get_insert(tb); GtkTextIter iter, start, end; const gchar *search_text = gtk_entry_get_text(f->entry); gboolean text_found; /* if nothing is selected then start the search from the * cursor. otherwise, if searching forward then start search * at the end of the selection, else set start to beginning of * selection */ if (!gtk_text_buffer_get_selection_bounds(tb, &start, &end)) { gtk_text_buffer_get_iter_at_mark(tb, &iter, mark); } else { if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(f->forward))) { iter = end; } else { iter = start; } } if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(f->forward))) { text_found = gtk_text_iter_forward_search(&iter, search_text, GTK_TEXT_SEARCH_VISIBLE_ONLY, &start, &end, NULL); if (!text_found) { /* wrap search */ gtk_text_buffer_get_start_iter(tb, &iter); text_found = gtk_text_iter_forward_search(&iter, search_text, GTK_TEXT_SEARCH_VISIBLE_ONLY, &start, &end, NULL); } } else { text_found = gtk_text_iter_backward_search(&iter, search_text, GTK_TEXT_SEARCH_VISIBLE_ONLY, &start, &end, NULL); if (!text_found) { /* wrap search */ gtk_text_buffer_get_end_iter(tb, &iter); text_found = gtk_text_iter_backward_search(&iter, search_text, GTK_TEXT_SEARCH_VISIBLE_ONLY, &start, &end, NULL); } } if (!text_found) { GString *string = g_string_new(""); g_string_printf(string, "Text \"%s\" not found.", search_text); util_message(GTK_WINDOW(f->w), GTK_MESSAGE_INFO, string->str); g_string_free(string, TRUE); } else { gtk_text_view_scroll_to_iter(view, &start, 0.0, FALSE, 0.0, 0.5); if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(f->forward))) { gtk_text_buffer_select_range(tb, &end, &start); } else { gtk_text_buffer_select_range(tb, &start, &end); } } } static void find_dialog_on_response(GtkDialog * dialog __attribute__ ((unused)), gint response, gpointer user_data) { find_dialog_t *f = (find_dialog_t *) user_data; if (response == GTK_RESPONSE_CLOSE) { gtk_widget_hide(GTK_WIDGET(f->w)); } else if (response == GTK_RESPONSE_OK) { find_dialog_search(f); } } static gboolean find_dialog_on_key_press_event(GtkWidget * widget __attribute__ ((unused)), GdkEventKey * event, gpointer user_data) { find_dialog_t *f = (find_dialog_t *) user_data; if (event->keyval == GDK_Escape) { gtk_widget_hide(GTK_WIDGET(f->w)); return TRUE; } return FALSE; } static void find_dialog_on_entry_activate(GtkEntry * entry __attribute__ ((unused)), gpointer user_data) { find_dialog_t *f = (find_dialog_t *) user_data; find_dialog_search(f); } find_dialog_t *find_dialog_create(toplevel_t * top) { find_dialog_t *f; int error = 0; if ((f = calloc(1, sizeof(*f))) == NULL) { error = errno; goto cleanup; } f->top = top; f->xml = glade_xml_new(toplevel_get_glade_xml(f->top), "find_dialog", NULL); f->w = GTK_DIALOG(glade_xml_get_widget(f->xml, "find_dialog")); assert(f->w != NULL); gtk_window_set_transient_for(GTK_WINDOW(f->w), toplevel_get_window(f->top)); g_signal_connect_swapped(G_OBJECT(f->w), "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), f->w); g_signal_connect(G_OBJECT(f->w), "response", G_CALLBACK(find_dialog_on_response), f); g_signal_connect(G_OBJECT(f->w), "key-press-event", G_CALLBACK(find_dialog_on_key_press_event), f); f->entry = GTK_ENTRY(glade_xml_get_widget(f->xml, "find entry")); f->forward = GTK_RADIO_BUTTON(glade_xml_get_widget(f->xml, "find forward radio")); f->reverse = GTK_RADIO_BUTTON(glade_xml_get_widget(f->xml, "find reverse radio")); assert(f->entry != NULL && f->forward != NULL && f->reverse != NULL); /* connect the text entry callback events */ g_signal_connect(G_OBJECT(f->entry), "activate", G_CALLBACK(find_dialog_on_entry_activate), f); cleanup: if (error != 0) { find_dialog_destroy(&f); errno = error; return NULL; } return f; } void find_dialog_destroy(find_dialog_t ** f) { if (f != NULL && *f != NULL) { free(*f); *f = NULL; } } void find_dialog_show(find_dialog_t * f) { gtk_widget_show(GTK_WIDGET(f->w)); gtk_widget_grab_focus(GTK_WIDGET(f->entry)); gtk_editable_set_position(GTK_EDITABLE(f->entry), -1); gtk_editable_select_region(GTK_EDITABLE(f->entry), 0, -1); gtk_window_present(GTK_WINDOW(f->w)); }