summaryrefslogtreecommitdiff
path: root/gtk/gtkentry.c
diff options
context:
space:
mode:
authorKristian Rietveld <kris@gtk.org>2003-07-11 12:51:24 +0000
committerKristian Rietveld <kristian@src.gnome.org>2003-07-11 12:51:24 +0000
commitedef7d00d99561796ae2a5fba9576ac1eaaba0a1 (patch)
treebccb75e8a7a9e88b89cc9feeb0a4ef2cbc70fae0 /gtk/gtkentry.c
parent8aafd6bb1682ab4c85b78c692c2d8e779d158d7d (diff)
downloadgtk+-edef7d00d99561796ae2a5fba9576ac1eaaba0a1.tar.gz
Landing GtkTreeModelFilter and the completion code. (Test program and
Fri Jul 11 14:32:43 2003 Kristian Rietveld <kris@gtk.org> Landing GtkTreeModelFilter and the completion code. (Test program and documentation will follow next week). * gtk/gtkcellayout.[ch], gtk/gtkentrycompletion.[ch], gtk/gtktreemodelfilter.[ch], gtk/gtkentryprivate.h: new files. * gtkentry.[ch]: added gtk_entry_{get,set}_completion, wrote necessary code to hook up completion. * gtktreeviewcolumn.c: made GtkTreeViewColumn implement the new GtkCellLayout interface. * gtkmarshalers.list: added BOOLEAN:OBJECT,BOXED. * gtk/gtk.h, gtk/Makefile.am, po/POTFILES.in: all updated for the new source files.
Diffstat (limited to 'gtk/gtkentry.c')
-rw-r--r--gtk/gtkentry.c256
1 files changed, 256 insertions, 0 deletions
diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c
index 24fa808771..2ec396e4e4 100644
--- a/gtk/gtkentry.c
+++ b/gtk/gtkentry.c
@@ -47,10 +47,17 @@
#include "gtkstock.h"
#include "gtktextutil.h"
#include "gtkwindow.h"
+#include "gtktreeview.h"
+#include "gtktreeselection.h"
+#include "gtkentryprivate.h"
+#include "gtkcelllayout.h"
+
+#define GTK_ENTRY_COMPLETION_KEY "gtk-entry-completion-key"
#define MIN_ENTRY_WIDTH 150
#define DRAW_TIMEOUT 20
#define INNER_BORDER 2
+#define COMPLETION_TIMEOUT 300
/* Initial size of buffer, in bytes */
#define MIN_SIZE 16
@@ -936,6 +943,8 @@ gtk_entry_finalize (GObject *object)
{
GtkEntry *entry = GTK_ENTRY (object);
+ gtk_entry_set_completion (entry, NULL);
+
if (entry->cached_layout)
g_object_unref (entry->cached_layout);
@@ -1664,6 +1673,7 @@ gtk_entry_focus_out (GtkWidget *widget,
GdkEventFocus *event)
{
GtkEntry *entry = GTK_ENTRY (widget);
+ GtkEntryCompletion *completion;
gtk_widget_queue_draw (widget);
@@ -1675,6 +1685,10 @@ gtk_entry_focus_out (GtkWidget *widget,
g_signal_handlers_disconnect_by_func (gdk_keymap_get_for_display (gtk_widget_get_display (widget)),
gtk_entry_keymap_direction_changed,
entry);
+
+ completion = gtk_entry_get_completion (entry);
+ if (completion)
+ _gtk_entry_completion_popdown (completion);
return FALSE;
}
@@ -4451,3 +4465,245 @@ gtk_entry_pend_cursor_blink (GtkEntry *entry)
show_cursor (entry);
}
}
+
+/* completion */
+static gint
+gtk_entry_completion_timeout (gpointer data)
+{
+ GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (data);
+
+ GDK_THREADS_ENTER ();
+
+ completion->priv->completion_timeout = 0;
+
+ if (strlen (gtk_entry_get_text (GTK_ENTRY (completion->priv->entry))) >= completion->priv->minimum_key_length)
+ {
+ gint matches;
+ gint actions;
+ GtkTreeSelection *s;
+
+ gtk_entry_completion_complete (completion);
+ matches = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->filter_model), NULL);
+
+ gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view)));
+
+ s = gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->action_view));
+
+ gtk_tree_selection_unselect_all (s);
+
+ actions = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->actions), NULL);
+
+ if (matches > 0 || actions > 0)
+ _gtk_entry_completion_popup (completion);
+ }
+
+ GDK_THREADS_LEAVE ();
+
+ return FALSE;
+}
+
+static gboolean
+gtk_entry_completion_key_press (GtkWidget *widget,
+ GdkEventKey *event,
+ gpointer user_data)
+{
+ gint matches, actions = 0;
+ GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data);
+
+ if (!GTK_WIDGET_MAPPED (completion->priv->popup_window))
+ return FALSE;
+
+ matches = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->filter_model), NULL);
+
+ if (completion->priv->actions)
+ actions = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->actions), NULL);
+
+ if (event->keyval == GDK_Up || event->keyval == GDK_Down)
+ {
+ GtkTreePath *path = NULL;
+
+ if (event->keyval == GDK_Up)
+ {
+ completion->priv->current_selected--;
+ if (completion->priv->current_selected < 0)
+ completion->priv->current_selected = 0;
+ }
+ else
+ {
+ completion->priv->current_selected++;
+ if (completion->priv->current_selected >= matches + actions)
+ completion->priv->current_selected = 0;
+ }
+
+ if (completion->priv->current_selected < matches)
+ {
+ gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->action_view)));
+
+ path = gtk_tree_path_new_from_indices (completion->priv->current_selected, -1);
+ gtk_tree_view_set_cursor (GTK_TREE_VIEW (completion->priv->tree_view),
+ path, NULL, FALSE);
+ }
+ else if (completion->priv->current_selected - matches >= 0)
+ {
+ gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view)));
+
+ path = gtk_tree_path_new_from_indices (completion->priv->current_selected - matches, -1);
+ gtk_tree_view_set_cursor (GTK_TREE_VIEW (completion->priv->action_view),
+ path, NULL, FALSE);
+ }
+
+ gtk_tree_path_free (path);
+
+ return TRUE;
+ }
+ else if (event->keyval == GDK_ISO_Enter ||
+ event->keyval == GDK_Return ||
+ event->keyval == GDK_Escape)
+ {
+ _gtk_entry_completion_popdown (completion);
+
+ if (event->keyval == GDK_Escape)
+ return TRUE;
+
+ if (completion->priv->current_selected < matches)
+ {
+ GtkTreeIter iter;
+ GtkTreeModel *model = NULL;
+ GtkTreeSelection *sel;
+ gboolean entry_set;
+
+ sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view));
+ gtk_tree_selection_get_selected (sel, &model, &iter);
+
+ g_signal_emit_by_name (completion, "match_selected",
+ model, &iter, &entry_set);
+
+ if (!entry_set)
+ {
+ gchar *str = NULL;
+
+ gtk_tree_model_get (model, &iter,
+ completion->priv->text_column, &str,
+ -1);
+
+ g_signal_handler_block (widget, completion->priv->changed_id);
+ gtk_entry_set_text (GTK_ENTRY (widget), str);
+ g_signal_handler_unblock (widget, completion->priv->changed_id);
+
+ /* move the cursor to the end */
+ gtk_editable_set_position (GTK_EDITABLE (widget), -1);
+
+ g_free (str);
+ }
+
+ return TRUE;
+ }
+ else if (completion->priv->current_selected - matches >= 0)
+ {
+ GtkTreePath *path;
+
+ path = gtk_tree_path_new_from_indices (completion->priv->current_selected - matches, -1);
+
+ g_signal_emit_by_name (completion, "action_activated",
+ gtk_tree_path_get_indices (path)[0]);
+ gtk_tree_path_free (path);
+ }
+ }
+
+ return FALSE;
+}
+
+static void
+gtk_entry_completion_changed (GtkWidget *entry,
+ gpointer user_data)
+{
+ GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data);
+
+ if (GTK_WIDGET_MAPPED (completion->priv->popup_window))
+ _gtk_entry_completion_popdown (completion);
+
+ /* (re)install completion timeout */
+ if (completion->priv->completion_timeout)
+ g_source_remove (completion->priv->completion_timeout);
+
+ if (!gtk_entry_get_text (GTK_ENTRY (entry)))
+ return;
+
+ /* no need to normalize for this test */
+ if (! strcmp ("", gtk_entry_get_text (GTK_ENTRY (entry))))
+ return;
+
+ completion->priv->completion_timeout =
+ g_timeout_add (COMPLETION_TIMEOUT,
+ gtk_entry_completion_timeout,
+ completion);
+}
+
+void
+gtk_entry_set_completion (GtkEntry *entry,
+ GtkEntryCompletion *completion)
+{
+ GtkEntryCompletion *old;
+
+ g_return_if_fail (GTK_IS_ENTRY (entry));
+ g_return_if_fail (!completion || GTK_IS_ENTRY_COMPLETION (completion));
+
+ old = gtk_entry_get_completion (entry);
+
+ if (old)
+ {
+ if (old->priv->completion_timeout)
+ {
+ g_source_remove (old->priv->completion_timeout);
+ old->priv->completion_timeout = 0;
+ }
+
+ if (GTK_WIDGET_MAPPED (old->priv->popup_window))
+ _gtk_entry_completion_popdown (old);
+
+ gtk_cell_layout_clear (GTK_CELL_LAYOUT (old));
+ old->priv->text_column = -1;
+
+ if (g_signal_handler_is_connected (entry, old->priv->changed_id))
+ g_signal_handler_disconnect (entry, old->priv->changed_id);
+ if (g_signal_handler_is_connected (entry, old->priv->key_press_id))
+ g_signal_handler_disconnect (entry, old->priv->key_press_id);
+
+ old->priv->entry = NULL;
+
+ g_object_unref (old);
+ }
+
+ if (!completion)
+ {
+ g_object_set_data (G_OBJECT (entry), GTK_ENTRY_COMPLETION_KEY, NULL);
+ return;
+ }
+
+ /* hook into the entry */
+ g_object_ref (completion);
+
+ completion->priv->changed_id =
+ g_signal_connect (entry, "changed",
+ G_CALLBACK (gtk_entry_completion_changed), completion);
+
+ completion->priv->key_press_id =
+ g_signal_connect (entry, "key_press_event",
+ G_CALLBACK (gtk_entry_completion_key_press), completion);
+
+ completion->priv->entry = GTK_WIDGET (entry);
+ g_object_set_data (G_OBJECT (entry), GTK_ENTRY_COMPLETION_KEY, completion);
+}
+
+GtkEntryCompletion *
+gtk_entry_get_completion (GtkEntry *entry)
+{
+ GtkEntryCompletion *completion;
+
+ g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
+
+ completion = GTK_ENTRY_COMPLETION (g_object_get_data (G_OBJECT (entry),
+ GTK_ENTRY_COMPLETION_KEY));
+
+ return completion;
+}