/** * erwin - really simple html editor * Copyright (C) 2004 Adrian Reber * * 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 * * $Id: searchbar.c,v 1.9 2005/01/19 20:57:39 adrian Exp $ * * $Author: adrian $ */ #include #include #include "erwin.h" #include "erwindef.h" #include "erwinfunctions.h" #include #include #include #include #define REACHED_END "Reached end of page, continued from top" #define REACHED_TOP "Reached top of page, continued from bottom" void searchbar_unfocus_focus() { focus_text_view(); if (globals.searchbar_visible) { gtk_window_set_focus(GTK_WINDOW(globals.main_window), globals.search_entry); gtk_editable_set_position(GTK_EDITABLE(globals.search_entry), -1); } } void highlight_text(gchar * find) { GtkTextIter match_start, match_end, start, end; int pos = 0; GtkSourceSearchFlags flags = GTK_SOURCE_SEARCH_VISIBLE_ONLY | GTK_SOURCE_SEARCH_TEXT_ONLY; GtkTextTagTable *tag_table = NULL; if (rendered()) return; tag_table = gtk_text_buffer_get_tag_table(get_text_buffer()); gtk_text_buffer_get_start_iter(get_text_buffer(), &start); gtk_text_buffer_get_end_iter(get_text_buffer(), &end); gtk_text_buffer_remove_tag_by_name(get_text_buffer(), "red_background", &start, &end); if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(globals.highlight))) { searchbar_unfocus_focus(); return; } while (strlen(find) != 0 && gtk_text_iter_forward_search(&start, find, flags, &match_start, &match_end, NULL)) { pos = gtk_text_iter_get_offset(&match_end); if (!gtk_text_iter_has_tag(&match_start, gtk_text_tag_table_lookup (tag_table, "yellow_background"))) { gtk_text_buffer_delete(get_text_buffer(), &match_start, &match_end); gtk_text_buffer_insert_with_tags_by_name(get_text_buffer(), &match_start, find, -1, "red_background", NULL); } gtk_text_buffer_get_start_iter(get_text_buffer(), &start); gtk_text_iter_set_offset(&start, pos); gtk_text_buffer_get_start_iter(get_text_buffer(), &match_start); gtk_text_buffer_get_start_iter(get_text_buffer(), &match_end); } searchbar_unfocus_focus(); } void single_search(gchar * find, GtkEditable * editable) { static GtkTextIter match_start, match_end, start, end, search_start; static gchar *last_find = NULL; int pos = 0; int pos2 = 0; GtkSourceSearchFlags flags = GTK_SOURCE_SEARCH_VISIBLE_ONLY | GTK_SOURCE_SEARCH_TEXT_ONLY; GtkTextTagTable *tag_table = NULL; gboolean tag_found; gboolean wrapped = FALSE; gboolean found; GdkColor color; struct document *document; if (rendered()) return; tag_table = gtk_text_buffer_get_tag_table(get_text_buffer()); document = (g_list_nth(documents, gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook_main))))->data; while (1) { /* get cursor posistion */ gtk_text_buffer_get_iter_at_mark(get_text_buffer(), &search_start, gtk_text_buffer_get_mark(get_text_buffer(), "insert")); if (last_find) { /* are we searching for the same string as last time */ if (!strcmp(find, last_find)) { /* the last occurence is marked with with a yellow background... go there */ if (globals.search_previous) tag_found = gtk_text_iter_backward_to_tag_toggle(&search_start, gtk_text_tag_table_lookup (tag_table, "yellow_background")); else tag_found = gtk_text_iter_forward_to_tag_toggle(&search_start, gtk_text_tag_table_lookup (tag_table, "yellow_background")); if (!tag_found) /* the last search didn't mark anything yellow... starting search from cursor position */ gtk_text_buffer_get_iter_at_mark(get_text_buffer(), &search_start, gtk_text_buffer_get_mark (get_text_buffer(), "insert")); } free(last_find); } last_find = strdup(find); /* remove the old tags, don't need them anymore */ gtk_text_buffer_get_start_iter(get_text_buffer(), &start); gtk_text_buffer_get_end_iter(get_text_buffer(), &end); gtk_text_buffer_remove_tag_by_name(get_text_buffer(), "yellow_background", &start, &end); /* if the search wrapped... start from the beginning of the buffer */ if (wrapped) { if (globals.search_previous) search_start = end; else search_start = start; } _DEBUG_ fprintf(stderr, "%s:starting search at: %d\n", PACKAGE, gtk_text_iter_get_offset(&search_start)); /* finally searching for the string */ if (globals.search_previous) found = gtk_text_iter_backward_search(&search_start, last_find, flags, &match_start, &match_end, NULL); else found = gtk_text_iter_forward_search(&search_start, last_find, flags, &match_start, &match_end, NULL); if (strlen(last_find) != 0 && found) { _DEBUG_ fprintf(stderr, "%s:start: %d:end: %d\n", PACKAGE, gtk_text_iter_get_offset(&match_start), gtk_text_iter_get_offset(&match_end)); pos = gtk_text_iter_get_offset(&match_end); pos2 = gtk_text_iter_get_offset(&match_start); gtk_text_buffer_delete(get_text_buffer(), &match_start, &match_end); gtk_text_buffer_insert_with_tags_by_name(get_text_buffer(), &match_start, find, -1, "yellow_background", NULL); gtk_text_buffer_get_start_iter(get_text_buffer(), &start); gtk_text_iter_set_offset(&start, pos); gtk_text_buffer_get_start_iter(get_text_buffer(), &match_end); gtk_text_iter_set_offset(&match_end, pos2); gtk_text_buffer_place_cursor(get_text_buffer(), &match_end); gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(document->text_view), &match_end, FALSE, 0, 0, 0); gtk_text_buffer_get_start_iter(get_text_buffer(), &match_start); gtk_text_buffer_get_start_iter(get_text_buffer(), &match_end); break; } if (wrapped) break; wrapped = TRUE; } if (wrapped && found && find[0] != 0) gtk_widget_show_all(globals.search_wrapped); else gtk_widget_hide(globals.search_wrapped); if (!found && find[0] != 0) { color.red = 65535; color.green = 26214; color.blue = 26214; gtk_widget_modify_bg(GTK_WIDGET(editable), GTK_STATE_NORMAL, &color); gtk_widget_modify_base(GTK_WIDGET(editable), GTK_STATE_NORMAL, &color); gtk_widget_show_all(globals.not_found); } else { gtk_widget_hide(globals.not_found); gtk_widget_modify_bg(GTK_WIDGET(editable), GTK_STATE_NORMAL, NULL); gtk_widget_modify_base(GTK_WIDGET(editable), GTK_STATE_NORMAL, NULL); } searchbar_unfocus_focus(); } void searchbar_search(GtkEditable * editable, gpointer user_data) { gchar *search = gtk_editable_get_chars(editable, 0, -1); globals.buffer_not_changed = TRUE; _DEBUG_ fprintf(stderr, "%s:searching for:%s\n", PACKAGE, search); if (!user_data) single_search(search, editable); highlight_text(search); globals.buffer_not_changed = FALSE; g_free(search); } void searchbutton_pressed(GtkButton * button, gpointer user_data) { gtk_label_set_text(GTK_LABEL(globals.search_wrapped_label), REACHED_END); globals.search_previous = 0; searchbar_search((GtkEditable *) user_data, NULL); globals.search_previous = 0; } void searchbutton_prev_pressed(GtkButton * button, gpointer user_data) { gtk_label_set_text(GTK_LABEL(globals.search_wrapped_label), REACHED_TOP); globals.search_previous = 1; searchbar_search((GtkEditable *) user_data, NULL); globals.search_previous = 0; } void higlightbutton_pressed(GtkButton * button, gpointer user_data) { searchbar_search((GtkEditable *) user_data, user_data); } gboolean close_search(GtkAccelGroup * accel_group, GObject * acceleratable, guint keyval, GdkModifierType modifier, gpointer data) { GtkTextIter start, end; if (rendered()) return TRUE; gtk_text_buffer_get_start_iter(get_text_buffer(), &start); gtk_text_buffer_get_end_iter(get_text_buffer(), &end); if (globals.search_box) gtk_widget_hide(globals.search_box); globals.searchbar_visible = 0; gtk_text_buffer_remove_tag_by_name(get_text_buffer(), "red_background", &start, &end); gtk_text_buffer_remove_tag_by_name(get_text_buffer(), "yellow_background", &start, &end); focus_text_view(); return TRUE; } void searchbar() { static GtkWidget *entry = NULL; GtkWidget *hbox; GtkWidget *label; GtkWidget *search_button; GtkWidget *search_button_prev; if (globals.searchbar_visible) { searchbar_search(GTK_EDITABLE(entry), NULL); gtk_window_set_focus(GTK_WINDOW(globals.main_window), entry); return; } if (!globals.search_box) { hbox = gtk_hbox_new(FALSE, 2); globals.search_box = hbox; } if (!entry) { /* Close Button */ search_button= gtk_button_new(); label = gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_SMALL_TOOLBAR); gtk_container_add(GTK_CONTAINER(search_button), label); gtk_box_pack_start(GTK_BOX(globals.search_box), search_button, FALSE, FALSE, 1); g_signal_connect(G_OBJECT(search_button), "clicked", G_CALLBACK(close_search), NULL); gtk_button_set_relief(GTK_BUTTON(search_button), GTK_RELIEF_NONE); gtk_widget_show_all(search_button); label = gtk_label_new("Find: "); gtk_widget_show(label); gtk_box_pack_start(GTK_BOX(globals.search_box), label, FALSE, FALSE, 1); entry = gtk_entry_new(); globals.search_entry = entry; gtk_box_pack_start(GTK_BOX(globals.search_box), entry, FALSE, FALSE, 1); gtk_box_pack_start(GTK_BOX(globals.notebook_box), globals.search_box, FALSE, FALSE, 1); gtk_widget_show(entry); hbox = gtk_hbox_new(FALSE, 1); /* Find Next Button */ label = gtk_label_new("Find Next"); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); label = gtk_image_new_from_stock(GTK_STOCK_GO_DOWN, GTK_ICON_SIZE_SMALL_TOOLBAR); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); search_button = gtk_button_new(); gtk_container_add(GTK_CONTAINER(search_button), hbox); gtk_widget_show_all(search_button); gtk_button_set_relief(GTK_BUTTON(search_button), GTK_RELIEF_NONE); /* Find Previous Button */ hbox = gtk_hbox_new(FALSE, 1); label = gtk_label_new("Find Previous"); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); label = gtk_image_new_from_stock(GTK_STOCK_GO_UP, GTK_ICON_SIZE_SMALL_TOOLBAR); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); search_button_prev = gtk_button_new(); gtk_container_add(GTK_CONTAINER(search_button_prev), hbox); gtk_widget_show_all(search_button_prev); gtk_button_set_relief(GTK_BUTTON(search_button_prev), GTK_RELIEF_NONE); /* Highlight Check Button */ hbox = gtk_hbox_new(FALSE, 1); label = gtk_label_new("Highlight"); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); globals.highlight = gtk_check_button_new(); gtk_container_add(GTK_CONTAINER(globals.highlight), hbox); gtk_widget_show_all(globals.highlight); /* Search Wrapped Label */ globals.search_wrapped = gtk_hbox_new(FALSE, 1); label = gtk_image_new_from_stock(GTK_STOCK_REFRESH, GTK_ICON_SIZE_SMALL_TOOLBAR); gtk_box_pack_start(GTK_BOX(globals.search_wrapped), label, FALSE, FALSE, 0); globals.search_wrapped_label = gtk_label_new(REACHED_END); gtk_box_pack_start(GTK_BOX(globals.search_wrapped), globals.search_wrapped_label, FALSE, FALSE, 0); /* Not Found Label */ globals.not_found = gtk_hbox_new(FALSE, 1); label = gtk_image_new_from_stock(GTK_STOCK_DIALOG_ERROR, GTK_ICON_SIZE_SMALL_TOOLBAR); gtk_box_pack_start(GTK_BOX(globals.not_found), label, FALSE, FALSE, 0); label = gtk_label_new("Phrase not found"); gtk_box_pack_start(GTK_BOX(globals.not_found), label, FALSE, FALSE, 0); /* Pack It */ gtk_box_pack_start(GTK_BOX(globals.search_box), search_button, FALSE, FALSE, 1); gtk_box_pack_start(GTK_BOX(globals.search_box), search_button_prev, FALSE, FALSE, 1); gtk_box_pack_start(GTK_BOX(globals.search_box), globals.highlight, FALSE, FALSE, 1); gtk_box_pack_start(GTK_BOX(globals.search_box), globals.search_wrapped, FALSE, FALSE, 1); gtk_box_pack_start(GTK_BOX(globals.search_box), globals.not_found, FALSE, FALSE, 1); /* Connect Signals */ g_signal_connect(G_OBJECT(globals.highlight), "clicked", G_CALLBACK(higlightbutton_pressed), entry); g_signal_connect(G_OBJECT(search_button), "clicked", G_CALLBACK(searchbutton_pressed), entry); g_signal_connect(G_OBJECT(search_button_prev), "clicked", G_CALLBACK(searchbutton_prev_pressed), entry); g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(searchbar_search), NULL); gtk_widget_add_accelerator(search_button, "clicked", globals.accel_group, GDK_Return, 0, 0); } gtk_widget_show(globals.search_box); gtk_widget_hide(globals.search_wrapped); gtk_widget_hide(globals.not_found); gtk_widget_modify_bg(entry, GTK_STATE_NORMAL, NULL); gtk_widget_modify_base(entry, GTK_STATE_NORMAL, NULL); gtk_window_set_focus(GTK_WINDOW(globals.main_window), entry); globals.searchbar_visible = 1; searchbar_search(GTK_EDITABLE(entry), entry); /* select the text if available */ if (strlen(gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1)) != 0) gtk_editable_select_region(GTK_EDITABLE(entry), 0, -1); }