[libgda] GdaBrowser: reworked search in text in separate widget
- From: Vivien Malerba <vivien src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libgda] GdaBrowser: reworked search in text in separate widget
- Date: Wed, 15 Jun 2011 19:41:57 +0000 (UTC)
commit 49505b6bf9cfb4accab1b4b7ab3054ca95446c31
Author: Vivien Malerba <malerba gnome-db org>
Date: Wed Jun 15 21:41:09 2011 +0200
GdaBrowser: reworked search in text in separate widget
tools/browser/Makefile.am | 4 +-
tools/browser/ldap-browser/class-properties.c | 138 +++++++----
tools/browser/ldap-browser/entry-properties.c | 204 +---------------
tools/browser/text-search.c | 311 +++++++++++++++++++++++++
tools/browser/text-search.h | 52 ++++
5 files changed, 464 insertions(+), 245 deletions(-)
---
diff --git a/tools/browser/Makefile.am b/tools/browser/Makefile.am
index 80a54ac..22f0741 100644
--- a/tools/browser/Makefile.am
+++ b/tools/browser/Makefile.am
@@ -84,7 +84,9 @@ libbrowser_la_SOURCES=\
mgr-favorites.h \
mgr-favorites.c \
browser-stock-icons.c \
- browser-stock-icons.h
+ browser-stock-icons.h \
+ text-search.c \
+ text-search.h
gda_browser_5_0_SOURCES=\
main.c
diff --git a/tools/browser/ldap-browser/class-properties.c b/tools/browser/ldap-browser/class-properties.c
index 6f1cfa5..8be9077 100644
--- a/tools/browser/ldap-browser/class-properties.c
+++ b/tools/browser/ldap-browser/class-properties.c
@@ -21,16 +21,20 @@
#include <gtk/gtk.h>
#include "class-properties.h"
#include "marshal.h"
+#include "../text-search.h"
struct _ClassPropertiesPrivate {
BrowserConnection *bcnc;
+ GtkTextView *view;
GtkTextBuffer *text;
gboolean hovering_over_link;
+
+ GtkWidget *text_search;
};
static void class_properties_class_init (ClassPropertiesClass *klass);
-static void class_properties_init (ClassProperties *eprop, ClassPropertiesClass *klass);
+static void class_properties_init (ClassProperties *cprop, ClassPropertiesClass *klass);
static void class_properties_dispose (GObject *object);
static GObjectClass *parent_class = NULL;
@@ -68,24 +72,24 @@ class_properties_class_init (ClassPropertiesClass *klass)
static void
-class_properties_init (ClassProperties *eprop, G_GNUC_UNUSED ClassPropertiesClass *klass)
+class_properties_init (ClassProperties *cprop, G_GNUC_UNUSED ClassPropertiesClass *klass)
{
- eprop->priv = g_new0 (ClassPropertiesPrivate, 1);
- eprop->priv->hovering_over_link = FALSE;
+ cprop->priv = g_new0 (ClassPropertiesPrivate, 1);
+ cprop->priv->hovering_over_link = FALSE;
}
static void
class_properties_dispose (GObject *object)
{
- ClassProperties *eprop = (ClassProperties *) object;
+ ClassProperties *cprop = (ClassProperties *) object;
/* free memory */
- if (eprop->priv) {
- if (eprop->priv->bcnc) {
- g_object_unref (eprop->priv->bcnc);
+ if (cprop->priv) {
+ if (cprop->priv->bcnc) {
+ g_object_unref (cprop->priv->bcnc);
}
- g_free (eprop->priv);
- eprop->priv = NULL;
+ g_free (cprop->priv);
+ cprop->priv = NULL;
}
parent_class->dispose (object);
@@ -114,10 +118,12 @@ class_properties_get_type (void)
return type;
}
-static gboolean key_press_event (GtkWidget *text_view, GdkEventKey *event, ClassProperties *eprop);
-static gboolean event_after (GtkWidget *text_view, GdkEvent *ev, ClassProperties *eprop);
-static gboolean motion_notify_event (GtkWidget *text_view, GdkEventMotion *event, ClassProperties *eprop);
-static gboolean visibility_notify_event (GtkWidget *text_view, GdkEventVisibility *event, ClassProperties *eprop);
+static gboolean key_press_event (GtkWidget *text_view, GdkEventKey *event, ClassProperties *cprop);
+static gboolean event_after (GtkWidget *text_view, GdkEvent *ev, ClassProperties *cprop);
+static gboolean motion_notify_event (GtkWidget *text_view, GdkEventMotion *event, ClassProperties *cprop);
+static gboolean visibility_notify_event (GtkWidget *text_view, GdkEventVisibility *event, ClassProperties *cprop);
+
+static void show_search_bar (ClassProperties *cprop);
/**
* class_properties_new:
@@ -127,11 +133,11 @@ static gboolean visibility_notify_event (GtkWidget *text_view, GdkEventVisibilit
GtkWidget *
class_properties_new (BrowserConnection *bcnc)
{
- ClassProperties *eprop;
+ ClassProperties *cprop;
g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
- eprop = CLASS_PROPERTIES (g_object_new (CLASS_PROPERTIES_TYPE, NULL));
- eprop->priv->bcnc = g_object_ref (bcnc);
+ cprop = CLASS_PROPERTIES (g_object_new (CLASS_PROPERTIES_TYPE, NULL));
+ cprop->priv->bcnc = g_object_ref (bcnc);
GtkWidget *sw;
sw = gtk_scrolled_window_new (NULL, NULL);
@@ -139,7 +145,7 @@ class_properties_new (BrowserConnection *bcnc)
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
- gtk_box_pack_start (GTK_BOX (eprop), sw, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (cprop), sw, TRUE, TRUE, 0);
GtkWidget *textview;
textview = gtk_text_view_new ();
@@ -148,35 +154,36 @@ class_properties_new (BrowserConnection *bcnc)
gtk_text_view_set_right_margin (GTK_TEXT_VIEW (textview), 5);
gtk_text_view_set_editable (GTK_TEXT_VIEW (textview), FALSE);
gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (textview), FALSE);
- eprop->priv->text = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
+ cprop->priv->text = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
+ cprop->priv->view = GTK_TEXT_VIEW (textview);
gtk_widget_show_all (sw);
- gtk_text_buffer_create_tag (eprop->priv->text, "section",
+ gtk_text_buffer_create_tag (cprop->priv->text, "section",
"weight", PANGO_WEIGHT_BOLD,
"foreground", "blue", NULL);
- gtk_text_buffer_create_tag (eprop->priv->text, "error",
+ gtk_text_buffer_create_tag (cprop->priv->text, "error",
"foreground", "red", NULL);
- gtk_text_buffer_create_tag (eprop->priv->text, "data",
+ gtk_text_buffer_create_tag (cprop->priv->text, "data",
"left-margin", 20, NULL);
- gtk_text_buffer_create_tag (eprop->priv->text, "starter",
+ gtk_text_buffer_create_tag (cprop->priv->text, "starter",
"indent", -10,
"left-margin", 20, NULL);
g_signal_connect (textview, "key-press-event",
- G_CALLBACK (key_press_event), eprop);
+ G_CALLBACK (key_press_event), cprop);
g_signal_connect (textview, "event-after",
- G_CALLBACK (event_after), eprop);
+ G_CALLBACK (event_after), cprop);
g_signal_connect (textview, "motion-notify-event",
- G_CALLBACK (motion_notify_event), eprop);
+ G_CALLBACK (motion_notify_event), cprop);
g_signal_connect (textview, "visibility-notify-event",
- G_CALLBACK (visibility_notify_event), eprop);
+ G_CALLBACK (visibility_notify_event), cprop);
- class_properties_set_class (eprop, NULL);
+ class_properties_set_class (cprop, NULL);
- return (GtkWidget*) eprop;
+ return (GtkWidget*) cprop;
}
static GdkCursor *hand_cursor = NULL;
@@ -187,7 +194,7 @@ static GdkCursor *regular_cursor = NULL;
* typically used by web browsers.
*/
static void
-set_cursor_if_appropriate (GtkTextView *text_view, gint x, gint y, ClassProperties *eprop)
+set_cursor_if_appropriate (GtkTextView *text_view, gint x, gint y, ClassProperties *cprop)
{
GSList *tags = NULL, *tagp = NULL;
GtkTextIter iter;
@@ -205,10 +212,10 @@ set_cursor_if_appropriate (GtkTextView *text_view, gint x, gint y, ClassProperti
}
}
- if (hovering != eprop->priv->hovering_over_link) {
- eprop->priv->hovering_over_link = hovering;
+ if (hovering != cprop->priv->hovering_over_link) {
+ cprop->priv->hovering_over_link = hovering;
- if (eprop->priv->hovering_over_link) {
+ if (cprop->priv->hovering_over_link) {
if (! hand_cursor)
hand_cursor = gdk_cursor_new (GDK_HAND2);
gdk_window_set_cursor (gtk_text_view_get_window (text_view,
@@ -234,7 +241,7 @@ set_cursor_if_appropriate (GtkTextView *text_view, gint x, gint y, ClassProperti
*/
static gboolean
visibility_notify_event (GtkWidget *text_view, G_GNUC_UNUSED GdkEventVisibility *event,
- ClassProperties *eprop)
+ ClassProperties *cprop)
{
gint wx, wy, bx, by;
@@ -244,7 +251,7 @@ visibility_notify_event (GtkWidget *text_view, G_GNUC_UNUSED GdkEventVisibility
GTK_TEXT_WINDOW_WIDGET,
wx, wy, &bx, &by);
- set_cursor_if_appropriate (GTK_TEXT_VIEW (text_view), bx, by, eprop);
+ set_cursor_if_appropriate (GTK_TEXT_VIEW (text_view), bx, by, cprop);
return FALSE;
}
@@ -253,7 +260,7 @@ visibility_notify_event (GtkWidget *text_view, G_GNUC_UNUSED GdkEventVisibility
* Update the cursor image if the pointer moved.
*/
static gboolean
-motion_notify_event (GtkWidget *text_view, GdkEventMotion *event, ClassProperties *eprop)
+motion_notify_event (GtkWidget *text_view, GdkEventMotion *event, ClassProperties *cprop)
{
gint x, y;
@@ -261,7 +268,7 @@ motion_notify_event (GtkWidget *text_view, GdkEventMotion *event, ClassPropertie
GTK_TEXT_WINDOW_WIDGET,
event->x, event->y, &x, &y);
- set_cursor_if_appropriate (GTK_TEXT_VIEW (text_view), x, y, eprop);
+ set_cursor_if_appropriate (GTK_TEXT_VIEW (text_view), x, y, cprop);
gdk_window_get_pointer (gtk_widget_get_window (text_view), NULL, NULL, NULL);
@@ -273,7 +280,7 @@ motion_notify_event (GtkWidget *text_view, GdkEventMotion *event, ClassPropertie
* by the data attached to it.
*/
static void
-follow_if_link (G_GNUC_UNUSED GtkWidget *text_view, GtkTextIter *iter, ClassProperties *eprop)
+follow_if_link (G_GNUC_UNUSED GtkWidget *text_view, GtkTextIter *iter, ClassProperties *cprop)
{
GSList *tags = NULL, *tagp = NULL;
@@ -284,7 +291,7 @@ follow_if_link (G_GNUC_UNUSED GtkWidget *text_view, GtkTextIter *iter, ClassProp
dn = g_object_get_data (G_OBJECT (tag), "class");
if (dn)
- g_signal_emit (eprop, class_properties_signals [OPEN_CLASS], 0, dn);
+ g_signal_emit (cprop, class_properties_signals [OPEN_CLASS], 0, dn);
}
if (tags)
@@ -296,7 +303,7 @@ follow_if_link (G_GNUC_UNUSED GtkWidget *text_view, GtkTextIter *iter, ClassProp
* Links can also be activated by clicking.
*/
static gboolean
-event_after (GtkWidget *text_view, GdkEvent *ev, ClassProperties *eprop)
+event_after (GtkWidget *text_view, GdkEvent *ev, ClassProperties *cprop)
{
GtkTextIter start, end, iter;
GtkTextBuffer *buffer;
@@ -324,7 +331,7 @@ event_after (GtkWidget *text_view, GdkEvent *ev, ClassProperties *eprop)
gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (text_view), &iter, x, y);
- follow_if_link (text_view, &iter, eprop);
+ follow_if_link (text_view, &iter, cprop);
return FALSE;
}
@@ -333,7 +340,7 @@ event_after (GtkWidget *text_view, GdkEvent *ev, ClassProperties *eprop)
* Links can be activated by pressing Enter.
*/
static gboolean
-key_press_event (GtkWidget *text_view, GdkEventKey *event, ClassProperties *eprop)
+key_press_event (GtkWidget *text_view, GdkEventKey *event, ClassProperties *cprop)
{
GtkTextIter iter;
GtkTextBuffer *buffer;
@@ -344,9 +351,19 @@ key_press_event (GtkWidget *text_view, GdkEventKey *event, ClassProperties *epro
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
gtk_text_buffer_get_iter_at_mark (buffer, &iter,
gtk_text_buffer_get_insert (buffer));
- follow_if_link (text_view, &iter, eprop);
+ follow_if_link (text_view, &iter, cprop);
break;
-
+ case GDK_KEY_F:
+ case GDK_KEY_f:
+ if (event->state & GDK_CONTROL_MASK) {
+ show_search_bar (cprop);
+ return TRUE;
+ }
+ break;
+ case GDK_KEY_slash:
+ show_search_bar (cprop);
+ return TRUE;
+ break;
default:
break;
}
@@ -355,23 +372,23 @@ key_press_event (GtkWidget *text_view, GdkEventKey *event, ClassProperties *epro
/**
* class_properties_set_class:
- * @eprop: a #ClassProperties widget
+ * @cprop: a #ClassProperties widget
* @classname: a DN to display information for
*
* Adjusts the display to show @classname's properties
*/
void
-class_properties_set_class (ClassProperties *eprop, const gchar *classname)
+class_properties_set_class (ClassProperties *cprop, const gchar *classname)
{
- g_return_if_fail (IS_CLASS_PROPERTIES (eprop));
+ g_return_if_fail (IS_CLASS_PROPERTIES (cprop));
GtkTextBuffer *tbuffer;
GtkTextIter start, end;
GdaLdapClass *lcl;
GtkTextIter current;
- gint i;
+ guint i;
- tbuffer = eprop->priv->text;
+ tbuffer = cprop->priv->text;
gtk_text_buffer_get_start_iter (tbuffer, &start);
gtk_text_buffer_get_end_iter (tbuffer, &end);
gtk_text_buffer_delete (tbuffer, &start, &end);
@@ -379,9 +396,9 @@ class_properties_set_class (ClassProperties *eprop, const gchar *classname)
if (!classname || !*classname)
return;
- lcl = browser_connection_get_class_info (eprop->priv->bcnc, classname);
+ lcl = browser_connection_get_class_info (cprop->priv->bcnc, classname);
if (!lcl) {
- browser_show_message (GTK_WINDOW (gtk_widget_get_toplevel ((GtkWidget*) eprop)),
+ browser_show_message (GTK_WINDOW (gtk_widget_get_toplevel ((GtkWidget*) cprop)),
"%s", _("Could not get information about LDAP class"));
return;
}
@@ -569,4 +586,23 @@ class_properties_set_class (ClassProperties *eprop, const gchar *classname)
gtk_text_buffer_insert (tbuffer, ¤t, "\n", -1);
}
}
+
+ if (cprop->priv->text_search && gtk_widget_get_visible (cprop->priv->text_search))
+ text_search_rerun (TEXT_SEARCH (cprop->priv->text_search));
+}
+
+static void
+show_search_bar (ClassProperties *cprop)
+{
+ if (! cprop->priv->text_search) {
+ cprop->priv->text_search = text_search_new (GTK_TEXT_VIEW (cprop->priv->view));
+ gtk_box_pack_start (GTK_BOX (cprop), cprop->priv->text_search, FALSE, FALSE, 0);
+ gtk_widget_show (cprop->priv->text_search);
+ }
+ else {
+ gtk_widget_show (cprop->priv->text_search);
+ text_search_rerun (TEXT_SEARCH (cprop->priv->text_search));
+ }
+
+ gtk_widget_grab_focus (cprop->priv->text_search);
}
diff --git a/tools/browser/ldap-browser/entry-properties.c b/tools/browser/ldap-browser/entry-properties.c
index df12256..661e98b 100644
--- a/tools/browser/ldap-browser/entry-properties.c
+++ b/tools/browser/ldap-browser/entry-properties.c
@@ -23,6 +23,7 @@
#include "marshal.h"
#include <time.h>
#include <libgda-ui/libgda-ui.h>
+#include "../text-search.h"
struct _EntryPropertiesPrivate {
BrowserConnection *bcnc;
@@ -31,11 +32,7 @@ struct _EntryPropertiesPrivate {
GtkTextBuffer *text;
gboolean hovering_over_link;
- GtkWidget *search_bar;
- GtkWidget *search_entry;
- GtkToggleButton *search_sensitive;
- GList *search_marks;
- GList *current_mark; /* in @search_marks */
+ GtkWidget *text_search;
/* coordinates of mouse */
gint bx;
@@ -46,9 +43,6 @@ static void entry_properties_class_init (EntryPropertiesClass *klass);
static void entry_properties_init (EntryProperties *eprop, EntryPropertiesClass *klass);
static void entry_properties_dispose (GObject *object);
-static void search_text_changed_cb (GtkEntry *entry, EntryProperties *eprop);
-
-
static GObjectClass *parent_class = NULL;
/* signals */
@@ -111,9 +105,6 @@ entry_properties_dispose (GObject *object)
g_object_unref (eprop->priv->bcnc);
}
- if (eprop->priv->search_marks)
- g_list_free (eprop->priv->search_marks);
-
g_free (eprop->priv);
eprop->priv = NULL;
}
@@ -204,9 +195,6 @@ entry_properties_new (BrowserConnection *bcnc)
"indent", -10,
"left-margin", 20, NULL);
- gtk_text_buffer_create_tag (eprop->priv->text, "search",
- "background", "yellow", NULL);
-
g_signal_connect (textview, "key-press-event",
G_CALLBACK (key_press_event), eprop);
g_signal_connect (textview, "event-after",
@@ -933,8 +921,8 @@ info_fetch_cb (BrowserConnection *bcnc, gpointer out_result, EntryProperties *ep
browser_show_message (GTK_WINDOW (gtk_widget_get_toplevel ((GtkWidget*) eprop)),
"%s", _("Could not get information about LDAP entry"));
- if (eprop->priv->search_bar && gtk_widget_get_visible (eprop->priv->search_bar))
- search_text_changed_cb (GTK_ENTRY (eprop->priv->search_entry), eprop);
+ if (eprop->priv->text_search && gtk_widget_get_visible (eprop->priv->text_search))
+ text_search_rerun (TEXT_SEARCH (eprop->priv->text_search));
g_object_unref (eprop);
}
@@ -970,188 +958,18 @@ entry_properties_set_dn (EntryProperties *eprop, const gchar *dn)
}
}
-/*
- * Search capabilities
- */
-static void
-search_text_changed_cb (GtkEntry *entry, EntryProperties *eprop)
-{
- GtkTextIter iter, siter, end;
- GtkTextBuffer *buffer;
- const gchar *search_text, *sptr;
- gboolean sensitive;
-
- buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (eprop->priv->view));
-
- /* clean all previous search result */
- gtk_text_buffer_get_bounds (buffer, &iter, &end);
- gtk_text_buffer_remove_tag_by_name (buffer, "search", &iter, &end);
- eprop->priv->current_mark = NULL;
- if (eprop->priv->search_marks) {
- GList *list;
- for (list = eprop->priv->search_marks; list; list = list->next)
- gtk_text_buffer_delete_mark (buffer, GTK_TEXT_MARK (list->data));
-
- g_list_free (eprop->priv->search_marks);
- eprop->priv->search_marks = NULL;
- }
-
- gtk_text_buffer_get_start_iter (buffer, &iter);
- search_text = gtk_entry_get_text (entry);
-
- if (!search_text || !*search_text)
- return;
-
- sensitive = gtk_toggle_button_get_active (eprop->priv->search_sensitive);
-
- while (1) {
- gboolean high = TRUE;
- siter = iter;
- sptr = search_text;
-
- /* search for @search_text starting from the @siter position */
- while (1) {
- gunichar c1, c2;
- c1 = gtk_text_iter_get_char (&siter);
- c2 = g_utf8_get_char (sptr);
- if (!sensitive) {
- c1 = g_unichar_tolower (c1);
- c2 = g_unichar_tolower (c2);
- }
- if (c1 != c2) {
- high = FALSE;
- break;
- }
-
- sptr = g_utf8_find_next_char (sptr, NULL);
- if (!sptr || !*sptr)
- break;
-
- if (! gtk_text_iter_forward_char (&siter)) {
- high = FALSE;
- break;
- }
- }
- if (high) {
- if (gtk_text_iter_forward_char (&siter)) {
- GtkTextMark *mark;
- gtk_text_buffer_apply_tag_by_name (buffer, "search", &iter, &siter);
- mark = gtk_text_buffer_create_mark (buffer, NULL, &iter, FALSE);
- eprop->priv->search_marks = g_list_prepend (eprop->priv->search_marks,
- mark);
- }
- iter = siter;
- }
- else {
- if (! gtk_text_iter_forward_char (&iter))
- break;
- }
- }
-
- if (eprop->priv->search_marks) {
- eprop->priv->search_marks = g_list_reverse (eprop->priv->search_marks);
- eprop->priv->current_mark = eprop->priv->search_marks;
- gtk_text_view_scroll_mark_onscreen (eprop->priv->view,
- GTK_TEXT_MARK (eprop->priv->current_mark->data));
- }
-}
-
-static void
-sensitive_toggled_cb (G_GNUC_UNUSED GtkToggleButton *button, EntryProperties *eprop)
-{
- search_text_changed_cb (GTK_ENTRY (eprop->priv->search_entry), eprop);
-}
-
-static void
-hide_search_bar (EntryProperties *eprop)
-{
- GtkTextIter start, end;
- GtkTextBuffer *buffer;
-
- /* clean all previous search result */
- buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (eprop->priv->view));
- gtk_text_buffer_get_bounds (buffer, &start, &end);
- gtk_text_buffer_remove_tag_by_name (buffer, "search", &start, &end);
-
- if (eprop->priv->search_marks) {
- GList *list;
- for (list = eprop->priv->search_marks; list; list = list->next)
- gtk_text_buffer_delete_mark (buffer, GTK_TEXT_MARK (list->data));
-
- g_list_free (eprop->priv->search_marks);
- eprop->priv->search_marks = NULL;
- }
- eprop->priv->current_mark = NULL;
-
- gtk_widget_hide (eprop->priv->search_bar);
-}
-
-static void
-go_back_search_cb (G_GNUC_UNUSED GtkButton *button, EntryProperties *eprop)
-{
- if (eprop->priv->current_mark && eprop->priv->current_mark->prev) {
- eprop->priv->current_mark = eprop->priv->current_mark->prev;
- gtk_text_view_scroll_mark_onscreen (eprop->priv->view,
- GTK_TEXT_MARK (eprop->priv->current_mark->data));
- }
-}
-
-static void
-go_forward_search_cb (G_GNUC_UNUSED GtkButton *button, EntryProperties *eprop)
-{
- if (eprop->priv->current_mark && eprop->priv->current_mark->next) {
- eprop->priv->current_mark = eprop->priv->current_mark->next;
- gtk_text_view_scroll_mark_onscreen (eprop->priv->view,
- GTK_TEXT_MARK (eprop->priv->current_mark->data));
- }
-}
-
static void
show_search_bar (EntryProperties *eprop)
{
- if (! eprop->priv->search_bar) {
- GtkWidget *hbox, *wid;
- hbox = gtk_hbox_new (FALSE, 5);
- eprop->priv->search_bar = hbox;
-
- wid = browser_make_small_button (FALSE, FALSE, NULL, GTK_STOCK_CLOSE,
- _("Hide search toolbar"));
- gtk_box_pack_start (GTK_BOX (hbox), wid, FALSE, FALSE, 0);
- g_signal_connect_swapped (wid, "clicked",
- G_CALLBACK (hide_search_bar), eprop);
-
- wid = gtk_label_new (_("Search:"));
- gtk_box_pack_start (GTK_BOX (hbox), wid, FALSE, FALSE, 0);
-
- wid = gtk_entry_new ();
- gtk_box_pack_start (GTK_BOX (hbox), wid, TRUE, TRUE, 0);
- eprop->priv->search_entry = wid;
- g_signal_connect (wid, "changed",
- G_CALLBACK (search_text_changed_cb), eprop);
-
- wid = browser_make_small_button (FALSE, FALSE, NULL, GTK_STOCK_GO_BACK, NULL);
- gtk_box_pack_start (GTK_BOX (hbox), wid, FALSE, FALSE, 0);
- g_signal_connect (wid, "clicked",
- G_CALLBACK (go_back_search_cb), eprop);
-
- wid = browser_make_small_button (FALSE, FALSE, NULL, GTK_STOCK_GO_FORWARD, NULL);
- gtk_box_pack_start (GTK_BOX (hbox), wid, FALSE, FALSE, 0);
- g_signal_connect (wid, "clicked",
- G_CALLBACK (go_forward_search_cb), eprop);
-
- wid = gtk_check_button_new_with_label (_("Case sensitive"));
- gtk_box_pack_start (GTK_BOX (hbox), wid, FALSE, FALSE, 0);
- eprop->priv->search_sensitive = GTK_TOGGLE_BUTTON (wid);
- g_signal_connect (wid, "toggled",
- G_CALLBACK (sensitive_toggled_cb), eprop);
-
- gtk_box_pack_start (GTK_BOX (eprop), eprop->priv->search_bar, FALSE, FALSE, 0);
- gtk_widget_show_all (eprop->priv->search_bar);
+ if (! eprop->priv->text_search) {
+ eprop->priv->text_search = text_search_new (eprop->priv->view);
+ gtk_box_pack_start (GTK_BOX (eprop), eprop->priv->text_search, FALSE, FALSE, 0);
+ gtk_widget_show (eprop->priv->text_search);
}
else {
- gtk_widget_show (eprop->priv->search_bar);
- search_text_changed_cb (GTK_ENTRY (eprop->priv->search_entry), eprop);
+ gtk_widget_show (eprop->priv->text_search);
+ text_search_rerun (TEXT_SEARCH (eprop->priv->text_search));
}
- gtk_widget_grab_focus (eprop->priv->search_entry);
+ gtk_widget_grab_focus (eprop->priv->text_search);
}
diff --git a/tools/browser/text-search.c b/tools/browser/text-search.c
new file mode 100644
index 0000000..b8f150a
--- /dev/null
+++ b/tools/browser/text-search.c
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2011 Vivien Malerba <malerba gnome-db org>
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <glib/gi18n-lib.h>
+#include <string.h>
+#include "text-search.h"
+#include "support.h"
+
+struct _TextSearchPrivate {
+ GtkTextView *view;
+ GtkTextBuffer *text;
+ GtkWidget *search_entry;
+ GtkToggleButton *search_sensitive;
+ GList *search_marks;
+ GList *current_mark; /* in @search_marks */
+};
+
+static void text_search_class_init (TextSearchClass *klass);
+static void text_search_init (TextSearch *tsearch, TextSearchClass *klass);
+static void text_search_dispose (GObject *object);
+static void text_search_grab_focus (GtkWidget *widget);
+
+static GObjectClass *parent_class = NULL;
+
+/*
+ * TextSearch class implementation
+ */
+
+static void
+text_search_class_init (TextSearchClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+ GTK_WIDGET_CLASS (klass)->grab_focus = text_search_grab_focus;
+ object_class->dispose = text_search_dispose;
+}
+
+static void
+text_search_init (TextSearch *tsearch, G_GNUC_UNUSED TextSearchClass *klass)
+{
+ tsearch->priv = g_new0 (TextSearchPrivate, 1);
+}
+
+static void
+text_search_dispose (GObject *object)
+{
+ TextSearch *tsearch = (TextSearch *) object;
+
+ /* free memory */
+ if (tsearch->priv) {
+ g_object_unref ((GObject*) tsearch->priv->view);
+ if (tsearch->priv->search_marks)
+ g_list_free (tsearch->priv->search_marks);
+
+ g_free (tsearch->priv);
+ tsearch->priv = NULL;
+ }
+
+ parent_class->dispose (object);
+}
+
+static void
+text_search_grab_focus (GtkWidget *widget)
+{
+ gtk_widget_grab_focus (TEXT_SEARCH (widget)->priv->search_entry);
+}
+
+GType
+text_search_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo info = {
+ sizeof (TextSearchClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) text_search_class_init,
+ NULL,
+ NULL,
+ sizeof (TextSearch),
+ 0,
+ (GInstanceInitFunc) text_search_init,
+ 0
+ };
+
+ type = g_type_register_static (GTK_TYPE_HBOX, "TextSearch", &info, 0);
+ }
+ return type;
+}
+
+static void
+search_text_changed_cb (GtkEntry *entry, TextSearch *tsearch)
+{
+ GtkTextIter iter, siter, end;
+ GtkTextBuffer *buffer;
+ const gchar *search_text, *sptr;
+ gboolean sensitive;
+
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tsearch->priv->view));
+
+ /* clean all previous search result */
+ gtk_text_buffer_get_bounds (buffer, &iter, &end);
+ gtk_text_buffer_remove_tag_by_name (buffer, "search", &iter, &end);
+ tsearch->priv->current_mark = NULL;
+ if (tsearch->priv->search_marks) {
+ GList *list;
+ for (list = tsearch->priv->search_marks; list; list = list->next)
+ gtk_text_buffer_delete_mark (buffer, GTK_TEXT_MARK (list->data));
+
+ g_list_free (tsearch->priv->search_marks);
+ tsearch->priv->search_marks = NULL;
+ }
+
+ gtk_text_buffer_get_start_iter (buffer, &iter);
+ search_text = gtk_entry_get_text (entry);
+
+ if (!search_text || !*search_text)
+ return;
+
+ sensitive = gtk_toggle_button_get_active (tsearch->priv->search_sensitive);
+
+ while (1) {
+ gboolean high = TRUE;
+ siter = iter;
+ sptr = search_text;
+
+ /* search for @search_text starting from the @siter position */
+ while (1) {
+ gunichar c1, c2;
+ c1 = gtk_text_iter_get_char (&siter);
+ c2 = g_utf8_get_char (sptr);
+ if (!sensitive) {
+ c1 = g_unichar_tolower (c1);
+ c2 = g_unichar_tolower (c2);
+ }
+ if (c1 != c2) {
+ high = FALSE;
+ break;
+ }
+
+ sptr = g_utf8_find_next_char (sptr, NULL);
+ if (!sptr || !*sptr)
+ break;
+
+ if (! gtk_text_iter_forward_char (&siter)) {
+ high = FALSE;
+ break;
+ }
+ }
+ if (high) {
+ if (gtk_text_iter_forward_char (&siter)) {
+ GtkTextMark *mark;
+ gtk_text_buffer_apply_tag_by_name (buffer, "search", &iter, &siter);
+ mark = gtk_text_buffer_create_mark (buffer, NULL, &iter, FALSE);
+ tsearch->priv->search_marks = g_list_prepend (tsearch->priv->search_marks,
+ mark);
+ }
+ iter = siter;
+ }
+ else {
+ if (! gtk_text_iter_forward_char (&iter))
+ break;
+ }
+ }
+
+ if (tsearch->priv->search_marks) {
+ tsearch->priv->search_marks = g_list_reverse (tsearch->priv->search_marks);
+ tsearch->priv->current_mark = tsearch->priv->search_marks;
+ gtk_text_view_scroll_mark_onscreen (tsearch->priv->view,
+ GTK_TEXT_MARK (tsearch->priv->current_mark->data));
+ }
+}
+
+static void
+sensitive_toggled_cb (G_GNUC_UNUSED GtkToggleButton *button, TextSearch *tsearch)
+{
+ search_text_changed_cb (GTK_ENTRY (tsearch->priv->search_entry), tsearch);
+}
+
+static void
+hide_search_bar (TextSearch *tsearch)
+{
+ GtkTextIter start, end;
+ GtkTextBuffer *buffer;
+
+ /* clean all previous search result */
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tsearch->priv->view));
+ gtk_text_buffer_get_bounds (buffer, &start, &end);
+ gtk_text_buffer_remove_tag_by_name (buffer, "search", &start, &end);
+
+ if (tsearch->priv->search_marks) {
+ GList *list;
+ for (list = tsearch->priv->search_marks; list; list = list->next)
+ gtk_text_buffer_delete_mark (buffer, GTK_TEXT_MARK (list->data));
+
+ g_list_free (tsearch->priv->search_marks);
+ tsearch->priv->search_marks = NULL;
+ }
+ tsearch->priv->current_mark = NULL;
+
+ gtk_widget_hide (GTK_WIDGET (tsearch));
+}
+
+static void
+go_back_search_cb (G_GNUC_UNUSED GtkButton *button, TextSearch *tsearch)
+{
+ if (tsearch->priv->current_mark && tsearch->priv->current_mark->prev) {
+ tsearch->priv->current_mark = tsearch->priv->current_mark->prev;
+ gtk_text_view_scroll_mark_onscreen (tsearch->priv->view,
+ GTK_TEXT_MARK (tsearch->priv->current_mark->data));
+ }
+}
+
+static void
+go_forward_search_cb (G_GNUC_UNUSED GtkButton *button, TextSearch *tsearch)
+{
+ if (tsearch->priv->current_mark && tsearch->priv->current_mark->next) {
+ tsearch->priv->current_mark = tsearch->priv->current_mark->next;
+ gtk_text_view_scroll_mark_onscreen (tsearch->priv->view,
+ GTK_TEXT_MARK (tsearch->priv->current_mark->data));
+ }
+}
+
+/**
+ * text_search_new:
+ *
+ * Returns: a new #GtkWidget
+ */
+GtkWidget *
+text_search_new (GtkTextView *view)
+{
+ g_return_val_if_fail (GTK_IS_TEXT_VIEW (view), NULL);
+
+ TextSearch *tsearch;
+ GtkWidget *wid;
+
+ tsearch = TEXT_SEARCH (g_object_new (TEXT_SEARCH_TYPE, "spacing", 5,
+ "homogeneous", FALSE, NULL));
+ tsearch->priv->view = view;
+ g_object_ref ((GObject*) tsearch->priv->view);
+ tsearch->priv->text = gtk_text_view_get_buffer (view);
+
+ gtk_text_buffer_create_tag (tsearch->priv->text, "search",
+ "background", "yellow", NULL);
+
+ wid = browser_make_small_button (FALSE, FALSE, NULL, GTK_STOCK_CLOSE,
+ _("Hide search toolbar"));
+ gtk_box_pack_start (GTK_BOX (tsearch), wid, FALSE, FALSE, 0);
+ g_signal_connect_swapped (wid, "clicked",
+ G_CALLBACK (hide_search_bar), tsearch);
+
+ wid = gtk_label_new (_("Search:"));
+ gtk_box_pack_start (GTK_BOX (tsearch), wid, FALSE, FALSE, 0);
+
+ wid = gtk_entry_new ();
+ gtk_box_pack_start (GTK_BOX (tsearch), wid, TRUE, TRUE, 0);
+ tsearch->priv->search_entry = wid;
+ gtk_container_set_focus_child (GTK_CONTAINER (tsearch), tsearch->priv->search_entry);
+ g_signal_connect (wid, "changed",
+ G_CALLBACK (search_text_changed_cb), tsearch);
+
+ wid = browser_make_small_button (FALSE, FALSE, NULL, GTK_STOCK_GO_BACK, NULL);
+ gtk_box_pack_start (GTK_BOX (tsearch), wid, FALSE, FALSE, 0);
+ g_signal_connect (wid, "clicked",
+ G_CALLBACK (go_back_search_cb), tsearch);
+
+ wid = browser_make_small_button (FALSE, FALSE, NULL, GTK_STOCK_GO_FORWARD, NULL);
+ gtk_box_pack_start (GTK_BOX (tsearch), wid, FALSE, FALSE, 0);
+ g_signal_connect (wid, "clicked",
+ G_CALLBACK (go_forward_search_cb), tsearch);
+
+ wid = gtk_check_button_new_with_label (_("Case sensitive"));
+ gtk_box_pack_start (GTK_BOX (tsearch), wid, FALSE, FALSE, 0);
+ tsearch->priv->search_sensitive = GTK_TOGGLE_BUTTON (wid);
+ g_signal_connect (wid, "toggled",
+ G_CALLBACK (sensitive_toggled_cb), tsearch);
+
+ gtk_widget_show_all ((GtkWidget*) tsearch);
+ gtk_widget_hide ((GtkWidget*) tsearch);
+
+ return (GtkWidget*) tsearch;
+}
+
+/**
+ * text_search_rerun:
+ *
+ * To be executed when the #GtkTextView's contents has changed
+ */
+void
+text_search_rerun (TextSearch *tsearch)
+{
+ g_return_if_fail (IS_TEXT_SEARCH (tsearch));
+ search_text_changed_cb (GTK_ENTRY (tsearch->priv->search_entry), tsearch);
+}
diff --git a/tools/browser/text-search.h b/tools/browser/text-search.h
new file mode 100644
index 0000000..001e0c8
--- /dev/null
+++ b/tools/browser/text-search.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2011 Vivien Malerba <malerba gnome-db org>
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __TEXT_EDITOR_H__
+#define __TEXT_EDITOR_H__
+
+#include <gtk/gtk.h>
+#include <libgda/libgda.h>
+
+G_BEGIN_DECLS
+
+#define TEXT_SEARCH_TYPE (text_search_get_type())
+#define TEXT_SEARCH(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, TEXT_SEARCH_TYPE, TextSearch))
+#define TEXT_SEARCH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST (klass, TEXT_SEARCH_TYPE, TextSearchClass))
+#define IS_TEXT_SEARCH(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, TEXT_SEARCH_TYPE))
+#define IS_TEXT_SEARCH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TEXT_SEARCH_TYPE))
+
+typedef struct _TextSearch TextSearch;
+typedef struct _TextSearchClass TextSearchClass;
+typedef struct _TextSearchPrivate TextSearchPrivate;
+
+struct _TextSearch {
+ GtkHBox parent;
+ TextSearchPrivate *priv;
+};
+
+struct _TextSearchClass {
+ GtkVBoxClass parent_class;
+};
+
+GType text_search_get_type (void) G_GNUC_CONST;
+GtkWidget *text_search_new (GtkTextView *view);
+void text_search_rerun (TextSearch *tsearch);
+
+G_END_DECLS
+
+#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]