]> git.0d.be Git - empathy.git/commitdiff
Add search bar in chat text views (#585168)
authorThomas Meire <blackskad@gmail.com>
Tue, 12 Jan 2010 15:34:39 +0000 (15:34 +0000)
committerGuillaume Desmottes <guillaume.desmottes@collabora.co.uk>
Tue, 12 Jan 2010 15:36:01 +0000 (15:36 +0000)
libempathy-gtk/Makefile.am
libempathy-gtk/empathy-chat-text-view.c
libempathy-gtk/empathy-chat.c
libempathy-gtk/empathy-search-bar.c [new file with mode: 0644]
libempathy-gtk/empathy-search-bar.h [new file with mode: 0644]
libempathy-gtk/empathy-search-bar.ui [new file with mode: 0644]
libempathy-gtk/empathy-theme-manager.c
po/POTFILES.in

index 7f73d7c56e08f65643ff9a1f3666237aa65b7e58..2dd50bb6e074c61c4abc4632237d15de1c390c64 100644 (file)
@@ -59,6 +59,7 @@ libempathy_gtk_handwritten_source =                   \
        empathy-notify-manager.c                \
        empathy-presence-chooser.c              \
        empathy-protocol-chooser.c              \
+       empathy-search-bar.c                    \
        empathy-share-my-desktop.c              \
        empathy-smiley-manager.c                \
        empathy-sound.c                         \
@@ -104,6 +105,7 @@ libempathy_gtk_headers =                    \
        empathy-notify-manager.h                \
        empathy-presence-chooser.h              \
        empathy-protocol-chooser.h              \
+       empathy-search-bar.h                    \
        empathy-share-my-desktop.h              \
        empathy-smiley-manager.h                \
        empathy-sound.h                         \
@@ -158,7 +160,8 @@ ui_DATA =                                   \
        empathy-status-preset-dialog.ui         \
        empathy-log-window.ui                   \
        empathy-chat.ui                         \
-       empathy-contact-selector-dialog.ui
+       empathy-contact-selector-dialog.ui      \
+       empathy-search-bar.ui
 
 empathy-gtk-marshal.list: $(libempathy_gtk_la_SOURCES) Makefile.am
        $(QUIET_GEN)( cd $(srcdir) && \
index 4f38865f61d92f438a1e84d778a822cf5eface9d..fcd6ebb3246c8934d584553ef813e24a4c518989 100644 (file)
@@ -880,7 +880,7 @@ chat_text_view_find_previous (EmpathyChatView *view,
                from_start = TRUE;
        }
 
-       if (priv->find_mark_previous) {
+       if (!new_search && priv->find_mark_previous) {
                gtk_text_buffer_get_iter_at_mark (buffer,
                                                  &iter_at_mark,
                                                  priv->find_mark_previous);
@@ -995,7 +995,7 @@ chat_text_view_find_next (EmpathyChatView *view,
                from_start = TRUE;
        }
 
-       if (priv->find_mark_next) {
+       if (!new_search && priv->find_mark_next) {
                gtk_text_buffer_get_iter_at_mark (buffer,
                                                  &iter_at_mark,
                                                  priv->find_mark_next);
@@ -1161,7 +1161,6 @@ chat_text_view_highlight (EmpathyChatView *view,
                                                   &iter_match_end);
 
                iter = iter_match_end;
-               gtk_text_iter_forward_char (&iter);
        }
 }
 
index 02d123b54d231aa5e45b4a937506b944786bc43c..95e9ecbc5441c1b1191f43bc17c730f98c985136 100644 (file)
@@ -48,6 +48,7 @@
 #include "empathy-contact-list-store.h"
 #include "empathy-contact-list-view.h"
 #include "empathy-contact-menu.h"
+#include "empathy-search-bar.h"
 #include "empathy-theme-manager.h"
 #include "empathy-smiley-manager.h"
 #include "empathy-ui-utils.h"
@@ -93,6 +94,7 @@ typedef struct {
        GtkWidget         *label_topic;
        GtkWidget         *contact_list_view;
        GtkWidget         *info_bar_vbox;
+       GtkWidget         *search_bar;
 
        guint              unread_messages;
        /* TRUE if the pending messages can be displayed. This is to avoid to show
@@ -1369,6 +1371,11 @@ chat_input_key_press_event_cb (GtkWidget   *widget,
                gtk_adjustment_set_value (adj, val);
                return TRUE;
        }
+       /* catch ctrl-f to display the search bar */
+       if ((event->state & GDK_CONTROL_MASK) && (event->keyval == GDK_f)) {
+               empathy_search_bar_show (EMPATHY_SEARCH_BAR (priv->search_bar));
+               return TRUE;
+       }
        if (!(event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) &&
            event->keyval == GDK_Tab) {
                GtkTextBuffer *buffer;
@@ -2135,6 +2142,13 @@ chat_create_ui (EmpathyChat *chat)
                           chat->input_text_view);
        gtk_widget_show (chat->input_text_view);
 
+       /* Add the (invisible) search bar */
+       priv->search_bar = empathy_search_bar_new (chat->view);
+       gtk_box_pack_start (GTK_BOX(priv->vbox_left),
+                           priv->search_bar,
+                           FALSE, FALSE, 0);
+       gtk_box_reorder_child (GTK_BOX(priv->vbox_left), priv->search_bar, 1);
+
        /* Initialy hide the topic, will be shown if not empty */
        gtk_widget_hide (priv->hbox_topic);
 
@@ -2150,7 +2164,8 @@ chat_create_ui (EmpathyChat *chat)
                gtk_paned_set_position (GTK_PANED(priv->hpaned), paned_pos);
 
        /* Set widget focus order */
-       list = g_list_append (NULL, priv->scrolled_window_input);
+       list = g_list_append (NULL, priv->search_bar);
+       list = g_list_append (list, priv->scrolled_window_input);
        gtk_container_set_focus_chain (GTK_CONTAINER (priv->vbox_left), list);
        g_list_free (list);
 
diff --git a/libempathy-gtk/empathy-search-bar.c b/libempathy-gtk/empathy-search-bar.c
new file mode 100644 (file)
index 0000000..e4bad3b
--- /dev/null
@@ -0,0 +1,263 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * Copyright (C) 2010 Thomas Meire <blackskad@gmail.com>
+ *
+ * The code contained in this file is free software; you can redistribute
+ * it and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either version
+ * 2.1 of the License, or (at your option) any later version.
+ *
+ * This file 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this code; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include <libempathy/empathy-utils.h>
+
+#include "empathy-chat-view.h"
+#include "empathy-search-bar.h"
+#include "empathy-ui-utils.h"
+
+#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathySearchBar)
+
+G_DEFINE_TYPE (EmpathySearchBar, empathy_search_bar, GTK_TYPE_BIN);
+
+typedef struct _EmpathySearchBarPriv EmpathySearchBarPriv;
+struct _EmpathySearchBarPriv
+{
+  EmpathyChatView *chat_view;
+
+  GtkWidget *search_entry;
+  gchar *last_search;
+
+  GtkWidget *search_close;
+  GtkWidget *search_previous;
+  GtkWidget *search_next;
+  GtkWidget *search_not_found;
+};
+
+GtkWidget *
+empathy_search_bar_new (EmpathyChatView *view)
+{
+  EmpathySearchBar *self = g_object_new (EMPATHY_TYPE_SEARCH_BAR, NULL);
+
+  GET_PRIV (self)->chat_view = view;
+
+  return GTK_WIDGET (self);
+}
+
+static void
+empathy_search_bar_size_request (GtkWidget *widget,
+    GtkRequisition *requisition)
+{
+  GtkBin *bin;
+  GtkWidget *child;
+
+  bin = GTK_BIN (widget);
+  child = gtk_bin_get_child (bin);
+
+  if (child && gtk_widget_get_visible (child))
+    {
+      GtkRequisition child_requisition;
+
+      gtk_widget_size_request (child, &child_requisition);
+
+      requisition->width = child_requisition.width;
+      requisition->height = child_requisition.height;
+    }
+}
+
+static void
+empathy_search_bar_size_allocate (GtkWidget *widget,
+    GtkAllocation *allocation)
+{
+  GtkBin *bin;
+  GtkWidget *child;
+  GtkAllocation child_allocation;
+
+  bin = GTK_BIN (widget);
+  child = gtk_bin_get_child (bin);
+
+  gtk_widget_set_allocation (widget, allocation);
+
+  if (child && gtk_widget_get_visible (child))
+    {
+      child_allocation.x = allocation->x;
+      child_allocation.y = allocation->y;
+      child_allocation.width = MAX (allocation->width, 0);
+      child_allocation.height = MAX (allocation->height, 0);
+
+      gtk_widget_size_allocate (child, &child_allocation);
+    }
+}
+
+static void
+empathy_search_bar_finalize (GObject *object)
+{
+  EmpathySearchBarPriv *priv = GET_PRIV (object);
+
+  g_free (priv->last_search);
+}
+
+static void
+empathy_search_bar_update_buttons (EmpathySearchBar *self)
+{
+  gboolean can_go_forward = FALSE;
+  gboolean can_go_backward = FALSE;
+
+  EmpathySearchBarPriv* priv = GET_PRIV (self);
+
+  /* update previous / next buttons */
+  if (priv->last_search)
+    {
+      empathy_chat_view_find_abilities (priv->chat_view, priv->last_search,
+          &can_go_backward, &can_go_forward);
+    }
+
+  gtk_widget_set_sensitive (priv->search_previous,
+      can_go_backward && !EMP_STR_EMPTY (priv->last_search));
+  gtk_widget_set_sensitive (priv->search_next,
+      can_go_forward && !EMP_STR_EMPTY (priv->last_search));
+}
+
+void
+empathy_search_bar_show (EmpathySearchBar *self)
+{
+  EmpathySearchBarPriv *priv = GET_PRIV (self);
+
+  if (priv->last_search)
+    {
+      /* make sure we have an up to date last_search */
+      g_free (priv->last_search);
+      priv->last_search = gtk_editable_get_chars (
+          GTK_EDITABLE (priv->search_entry), 0, -1);
+    }
+  empathy_chat_view_highlight (priv->chat_view, priv->last_search);
+  empathy_search_bar_update_buttons (self);
+
+  /* grab the focus to the search entry */
+  gtk_widget_grab_focus (priv->search_entry);
+
+  gtk_widget_show (GTK_WIDGET (self));
+}
+
+
+static void
+empathy_search_bar_close_cb (GtkButton *button,
+    gpointer user_data)
+{
+  EmpathySearchBarPriv *priv = GET_PRIV (user_data);
+
+  empathy_chat_view_highlight (priv->chat_view, "");
+  gtk_widget_hide (GTK_WIDGET (user_data));
+
+  /* give the focus back to the focus-chain with the chat view */
+  gtk_widget_grab_focus (GTK_WIDGET (priv->chat_view));
+}
+
+static void
+empathy_search_bar_entry_changed (GtkEditable *entry,
+    gpointer user_data)
+{
+  EmpathySearchBarPriv *priv;
+  gboolean found;
+  gchar *search;
+
+  priv = GET_PRIV (user_data);
+
+  search = gtk_editable_get_chars (entry, 0, -1);
+
+  found = empathy_chat_view_find_previous (priv->chat_view, search, TRUE);
+  gtk_widget_set_visible (priv->search_not_found,
+      !(found || EMP_STR_EMPTY (search)));
+
+  empathy_chat_view_highlight (priv->chat_view, search);
+
+  g_free (priv->last_search);
+  priv->last_search = search;
+
+  empathy_search_bar_update_buttons (EMPATHY_SEARCH_BAR (user_data));
+}
+
+static void
+empathy_search_bar_next_cb (GtkButton *button,
+    gpointer user_data)
+{
+  EmpathySearchBarPriv *priv = GET_PRIV (user_data);
+
+  empathy_chat_view_find_next (priv->chat_view, priv->last_search, FALSE);
+  empathy_search_bar_update_buttons (EMPATHY_SEARCH_BAR (user_data));
+}
+
+static void
+empathy_search_bar_previous_cb (GtkButton *button,
+    gpointer user_data)
+{
+  EmpathySearchBarPriv *priv = GET_PRIV (user_data);
+
+  empathy_chat_view_find_previous (priv->chat_view, priv->last_search, FALSE);
+  empathy_search_bar_update_buttons (EMPATHY_SEARCH_BAR (user_data));
+}
+
+static void
+empathy_search_bar_init (EmpathySearchBar * self)
+{
+  gchar *filename;
+  GtkBuilder *gui;
+  GtkWidget *internal;
+  EmpathySearchBarPriv *priv;
+
+  priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EMPATHY_TYPE_SEARCH_BAR,
+      EmpathySearchBarPriv);
+
+  self->priv = priv;
+
+  filename = empathy_file_lookup ("empathy-search-bar.ui", "libempathy-gtk");
+  gui = empathy_builder_get_file (filename,
+      "search_widget", &internal,
+      "search_close", &priv->search_close,
+      "search_entry", &priv->search_entry,
+      "search_previous", &priv->search_previous,
+      "search_next", &priv->search_next,
+      "search_not_found", &priv->search_not_found,
+      NULL);
+  g_free (filename);
+
+  /* Add the signals */
+  empathy_builder_connect (gui, self,
+      "search_close", "clicked", empathy_search_bar_close_cb,
+      "search_entry", "changed", empathy_search_bar_entry_changed,
+      "search_previous", "clicked", empathy_search_bar_previous_cb,
+      "search_next", "clicked", empathy_search_bar_next_cb,
+      NULL);
+
+  gtk_container_add (GTK_CONTAINER (self), internal);
+  gtk_widget_show_all (internal);
+  gtk_widget_hide (priv->search_not_found);
+  g_object_unref (gui);
+}
+
+static void
+empathy_search_bar_class_init (EmpathySearchBarClass *class)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
+
+  gobject_class->finalize = empathy_search_bar_finalize;
+
+  g_type_class_add_private (gobject_class, sizeof (EmpathySearchBarPriv));
+
+  /* Neither GtkBin nor GtkContainer seems to do this for us :( */
+  widget_class->size_request = empathy_search_bar_size_request;
+  widget_class->size_allocate = empathy_search_bar_size_allocate;
+}
+
diff --git a/libempathy-gtk/empathy-search-bar.h b/libempathy-gtk/empathy-search-bar.h
new file mode 100644 (file)
index 0000000..d4cd042
--- /dev/null
@@ -0,0 +1,64 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * Copyright (C) 2010 Thomas Meire <blackskad@gmail.com>
+ *
+ * The code contained in this file is free software; you can redistribute
+ * it and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either version
+ * 2.1 of the License, or (at your option) any later version.
+ *
+ * This file 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this code; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __EMPATHY_SEARCH_BAR_H__
+#define __EMPATHY_SEARCH_BAR_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "empathy-chat-view.h"
+
+G_BEGIN_DECLS
+
+#define EMPATHY_TYPE_SEARCH_BAR (empathy_search_bar_get_type ())
+#define EMPATHY_SEARCH_BAR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), \
+    EMPATHY_TYPE_SEARCH_BAR, EmpathySearchBar))
+#define EMPATHY_SEARCH_BAR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), \
+    EMPATHY_TYPE_SEARCH_BAR, EmpathySearchBarClass))
+#define EMPATHY_IS_SEARCH_BAR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), \
+    EMPATHY_TYPE_SEARCH_BAR))
+#define EMPATHY_IS_SEARCH_BAR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), \
+    EMPATHY_TYPE_SEARCH_BAR))
+#define EMPATHY_SEARCH_BAR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o),\
+    EMPATHY_TYPE_SEARCH_BAR, EmpathySearchBarClass))
+
+typedef struct _EmpathySearchBar EmpathySearchBar;
+typedef struct _EmpathySearchBarClass EmpathySearchBarClass;
+
+struct _EmpathySearchBar
+{
+  GtkBin parent;
+
+  /*<private>*/
+  gpointer priv;
+};
+
+struct _EmpathySearchBarClass
+{
+  GtkBinClass parent_class;
+};
+
+GType       empathy_search_bar_get_type (void) G_GNUC_CONST;
+GtkWidget * empathy_search_bar_new      (EmpathyChatView  *view);
+void        empathy_search_bar_show     (EmpathySearchBar *searchbar);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_SEARCH_BAR_H__ */
diff --git a/libempathy-gtk/empathy-search-bar.ui b/libempathy-gtk/empathy-search-bar.ui
new file mode 100644 (file)
index 0000000..9768b1e
--- /dev/null
@@ -0,0 +1,110 @@
+<?xml version="1.0"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-naming-policy project-wide -->
+  <object class="GtkHBox" id="search_widget">
+    <property name="visible">True</property>
+    <property name="spacing">6</property>
+    <child>
+      <object class="GtkButton" id="search_close">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">True</property>
+        <property name="image">image1</property>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">False</property>
+        <property name="position">0</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="search_label">
+        <property name="visible">True</property>
+        <property name="label" translatable="yes">Find:</property>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">False</property>
+        <property name="position">1</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkEntry" id="search_entry">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="invisible_char">&#x25CF;</property>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="position">2</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkButton" id="search_previous">
+        <property name="label">Find previous</property>
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">True</property>
+        <property name="image">image3</property>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="position">3</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkButton" id="search_next">
+        <property name="label">Find next</property>
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">True</property>
+        <property name="image">image4</property>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="position">4</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkHBox" id="search_not_found">
+        <property name="spacing">6</property>
+        <child>
+          <object class="GtkImage" id="image2">
+            <property name="visible">True</property>
+            <property name="stock">gtk-dialog-error</property>
+          </object>
+          <packing>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="label1">
+            <property name="visible">True</property>
+            <property name="label" translatable="yes">Phrase not found</property>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="pack_type">end</property>
+        <property name="position">5</property>
+      </packing>
+    </child>
+  </object>
+  <object class="GtkImage" id="image1">
+    <property name="visible">True</property>
+    <property name="stock">gtk-close</property>
+  </object>
+  <object class="GtkImage" id="image3">
+    <property name="visible">True</property>
+    <property name="stock">gtk-go-back</property>
+  </object>
+  <object class="GtkImage" id="image4">
+    <property name="visible">True</property>
+    <property name="stock">gtk-go-forward</property>
+  </object>
+</interface>
index cda978330886b0caa0182c0ff18bdcd790b804cf..905e0bf1dd936c8db21b1415a7c2d44593e182c6 100644 (file)
@@ -115,6 +115,9 @@ theme_manager_create_irc_view (EmpathyThemeManager *manager)
                                        "foreground", "steelblue",
                                        "underline", PANGO_UNDERLINE_SINGLE,
                                        NULL);
+       empathy_chat_text_view_tag_set (view, EMPATHY_CHAT_TEXT_VIEW_TAG_HIGHLIGHT,
+                                       "background", "yellow",
+                                       NULL);
 
        /* Define IRC tags */
        empathy_chat_text_view_tag_set (view, EMPATHY_THEME_IRC_TAG_NICK_SELF,
index 4afc2534105af3b3af4289d99d80b1a834a1bbac..7075d27ae9408e999b5f09d2b2c2494fcb818770 100644 (file)
@@ -43,6 +43,7 @@ libempathy-gtk/empathy-log-window.c
 libempathy-gtk/empathy-new-message-dialog.c
 libempathy-gtk/empathy-new-call-dialog.c
 libempathy-gtk/empathy-presence-chooser.c
+[type: gettext/glade]libempathy-gtk/empathy-search-bar.ui
 libempathy-gtk/empathy-sound.c
 libempathy-gtk/empathy-status-preset-dialog.c
 [type: gettext/glade]libempathy-gtk/empathy-status-preset-dialog.ui