diff options
author | Matthias Clasen <mclasen@redhat.com> | 2004-07-19 18:15:48 +0000 |
---|---|---|
committer | Matthias Clasen <matthiasc@src.gnome.org> | 2004-07-19 18:15:48 +0000 |
commit | 5351a4e444a991bcc3022edb007b047493d86dd1 (patch) | |
tree | e1ce78d7dd1409d1bb9dfd205ef48d8528e21e83 /gtk/gtkentrycompletion.c | |
parent | 23b6bd5378571d027dc03c08843449c130d9fbde (diff) | |
download | gtk+-5351a4e444a991bcc3022edb007b047493d86dd1.tar.gz |
Support inline autocompletion in entries (#135953)
2004-07-19 Matthias Clasen <mclasen@redhat.com>
Support inline autocompletion in entries (#135953)
* gtk/gtkentryprivate.h:
* gtk/gtkentrycompletion.h:
* gtk/gtkentrycompletion.c (gtk_entry_completion_class_init):
Add a new signal ::insert-prefix which can be used to override
the default inline-completion behaviour. Add two new boolean
properties, :popup_completion and :inline_completion which
determine how the possible completions should be presented.
(gtk_entry_completion_insert_prefix): New function to request
a prefix insertion.
* gtk/gtkentry.c: Add the necessary glue for inline completion.
Diffstat (limited to 'gtk/gtkentrycompletion.c')
-rw-r--r-- | gtk/gtkentrycompletion.c | 289 |
1 files changed, 287 insertions, 2 deletions
diff --git a/gtk/gtkentrycompletion.c b/gtk/gtkentrycompletion.c index fc86ac3249..6743647b53 100644 --- a/gtk/gtkentrycompletion.c +++ b/gtk/gtkentrycompletion.c @@ -41,6 +41,7 @@ /* signals */ enum { + INSERT_PREFIX, MATCH_SELECTED, ACTION_ACTIVATED, LAST_SIGNAL @@ -52,7 +53,9 @@ enum PROP_0, PROP_MODEL, PROP_MINIMUM_KEY_LENGTH, - PROP_TEXT_COLUMN + PROP_TEXT_COLUMN, + PROP_INLINE_COMPLETION, + PROP_POPUP_COMPLETION }; #define GTK_ENTRY_COMPLETION_GET_PRIVATE(obj)(G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_ENTRY_COMPLETION, GtkEntryCompletionPrivate)) @@ -128,6 +131,8 @@ static void gtk_entry_completion_action_data_func (GtkTreeViewColumn static gboolean gtk_entry_completion_match_selected (GtkEntryCompletion *completion, GtkTreeModel *model, GtkTreeIter *iter); +static gboolean gtk_entry_completion_real_insert_prefix (GtkEntryCompletion *completion, + gchar *key); static GObjectClass *parent_class = NULL; static guint entry_completion_signals[LAST_SIGNAL] = { 0 }; @@ -185,6 +190,35 @@ gtk_entry_completion_class_init (GtkEntryCompletionClass *klass) object_class->finalize = gtk_entry_completion_finalize; klass->match_selected = gtk_entry_completion_match_selected; + klass->insert_prefix = gtk_entry_completion_real_insert_prefix; + + /** + * GtkEntryCompletion::insert-prefix: + * @widget: the object which received the signal + * @prefix: the common prefix of all possible completions + * + * The ::insert-prefix signal is emitted when the inline autocompletion + * is triggered. The default behaviour is to make the entry display the + * whole prefix and select the newly inserted part. + * + * Applications may connect to this signal in order to insert only a + * smaller part of the @prefix into the entry - e.g. the entry used in + * the #GtkFileChooser inserts only the part of the prefix up to the + * next '/'. + * + * Return value: %TRUE if the signal has been handled + * + * Since: 2.6 + */ + entry_completion_signals[INSERT_PREFIX] = + g_signal_new ("insert_prefix", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkEntryCompletionClass, insert_prefix), + _gtk_boolean_handled_accumulator, NULL, + _gtk_marshal_BOOLEAN__STRING, + G_TYPE_BOOLEAN, 1, + G_TYPE_STRING); /** * GtkEntryCompletion::match-selected: @@ -198,6 +232,8 @@ gtk_entry_completion_class_init (GtkEntryCompletionClass *klass) * @iter. * * Return value: %TRUE if the signal has been handled + * + * Since: 2.4 */ entry_completion_signals[MATCH_SELECTED] = g_signal_new ("match_selected", @@ -217,6 +253,8 @@ gtk_entry_completion_class_init (GtkEntryCompletionClass *klass) * * The ::action-activated signal is emitted when an action * is activated. + * + * Since: 2.4 */ entry_completion_signals[ACTION_ACTIVATED] = g_signal_new ("action_activated", @@ -245,7 +283,7 @@ gtk_entry_completion_class_init (GtkEntryCompletionClass *klass) 1, G_PARAM_READWRITE)); /** - * GtkEntryCompletion::text-column: + * GtkEntryCompletion:text-column: * * The column of the model containing the strings. * @@ -261,6 +299,38 @@ gtk_entry_completion_class_init (GtkEntryCompletionClass *klass) -1, G_PARAM_READWRITE)); + /** + * GtkEntryCompletion:inline_completion: + * + * The boolean :inline_completion property determines whether the + * common prefix of the possible completions should be inserted + * automatically in the entry. + * + * Since: 2.6 + **/ + g_object_class_install_property (object_class, + PROP_INLINE_COMPLETION, + g_param_spec_boolean ("inline_completion", + P_("Inline completion"), + P_("Whether the common prefix should be inserted automatically"), + FALSE, + G_PARAM_READWRITE)); + /** + * GtkEntryCompletion:popup_completion: + * + * The boolean :popup_completion property determines whether the + * possible completions should be shown in a popup window. + * + * Since: 2.6 + **/ + g_object_class_install_property (object_class, + PROP_POPUP_COMPLETION, + g_param_spec_boolean ("popup_completion", + P_("Popup completion"), + P_("Whether the completions should be shown in a popup window"), + TRUE, + G_PARAM_READWRITE)); + g_type_class_add_private (object_class, sizeof (GtkEntryCompletionPrivate)); } @@ -289,6 +359,9 @@ gtk_entry_completion_init (GtkEntryCompletion *completion) priv->minimum_key_length = 1; priv->text_column = -1; + priv->has_completion = FALSE; + priv->inline_completion = FALSE; + priv->popup_completion = TRUE; /* completions */ priv->filter_model = NULL; @@ -410,6 +483,14 @@ gtk_entry_completion_set_property (GObject *object, priv->text_column = g_value_get_int (value); break; + case PROP_INLINE_COMPLETION: + priv->inline_completion = g_value_get_boolean (value); + break; + + case PROP_POPUP_COMPLETION: + priv->popup_completion = g_value_get_boolean (value); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -439,6 +520,14 @@ gtk_entry_completion_get_property (GObject *object, g_value_set_int (value, gtk_entry_completion_get_text_column (completion)); break; + case PROP_INLINE_COMPLETION: + g_value_set_boolean (value, gtk_entry_completion_get_inline_completion (completion)); + break; + + case PROP_POPUP_COMPLETION: + g_value_set_boolean (value, gtk_entry_completion_get_popup_completion (completion)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1320,3 +1409,199 @@ gtk_entry_completion_match_selected (GtkEntryCompletion *completion, return TRUE; } + + +static gchar * +gtk_entry_completion_compute_prefix (GtkEntryCompletion *completion) +{ + GtkTreeIter iter; + gchar *prefix = NULL; + gboolean valid; + + const gchar *key = gtk_entry_get_text (GTK_ENTRY (completion->priv->entry)); + + valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (completion->priv->filter_model), + &iter); + + while (valid) + { + gchar *text; + + gtk_tree_model_get (GTK_TREE_MODEL (completion->priv->filter_model), + &iter, completion->priv->text_column, &text, + -1); + + if (g_str_has_prefix (text, key)) + { + if (!prefix) + prefix = g_strdup (text); + else + { + gchar *p = prefix; + const gchar *q = text; + + while (*p && *p == *q) + { + p++; + q++; + } + + *p = '\0'; + } + } + + g_free (text); + valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (completion->priv->filter_model), + &iter); + } + + return prefix; +} + + +static gboolean +gtk_entry_completion_real_insert_prefix (GtkEntryCompletion *completion, + gchar *prefix) +{ + if (prefix) + { + gint key_len; + gint prefix_len; + gint pos; + const gchar *key; + + prefix_len = g_utf8_strlen (prefix, -1); + + key = gtk_entry_get_text (GTK_ENTRY (completion->priv->entry)); + key_len = g_utf8_strlen (key, -1); + + if (prefix_len > key_len) + { + gtk_editable_insert_text (GTK_EDITABLE (completion->priv->entry), + prefix + key_len, -1, &pos); + gtk_editable_select_region (GTK_EDITABLE (completion->priv->entry), + key_len, prefix_len); + + completion->priv->has_completion = TRUE; + } + } + + return TRUE; +} + +/** + * gtk_entry_completion_insert_prefix: + * @completion: a #GtkEntryCompletion + * + * Requests a prefix insertion. + * + * Since: 2.6 + **/ +void +gtk_entry_completion_insert_prefix (GtkEntryCompletion *completion) +{ + gboolean done; + gchar *prefix; + + g_signal_handler_block (completion->priv->entry, + completion->priv->insert_text_id); + prefix = gtk_entry_completion_compute_prefix (completion); + if (prefix) + { + g_signal_emit (completion, entry_completion_signals[INSERT_PREFIX], + 0, prefix, &done); + g_free (prefix); + } + g_signal_handler_unblock (completion->priv->entry, + completion->priv->insert_text_id); +} + +/** + * gtk_entry_completion_set_inline_completion: + * @completion: a #GtkEntryCompletion + * @inline_completion: %TRUE to do inline completion + * + * Sets whether the common prefix of the possible completions should + * be automatically inserted in the entry. + * + * Since: 2.6 + **/ +void +gtk_entry_completion_set_inline_completion (GtkEntryCompletion *completion, + gboolean inline_completion) +{ + g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion)); + + inline_completion = inline_completion != FALSE; + + if (completion->priv->inline_completion != inline_completion) + { + completion->priv->inline_completion = inline_completion; + + g_object_notify (G_OBJECT (completion), "inline_completion"); + } +} + + +/** + * gtk_entry_completion_get_inline_completion: + * @completion: a #GtkEntryCompletion + * + * Returns whether the common prefix of the possible completions should + * be automatically inserted in the entry. + * + * Return value: %TRUE if inline completion is turned on + * + * Since: 2.6 + **/ +gboolean +gtk_entry_completion_get_inline_completion (GtkEntryCompletion *completion) +{ + g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), FALSE); + + return completion->priv->inline_completion; +} + +/** + * gtk_entry_completion_set_popup_completion: + * @completion: a #GtkEntryCompletion + * @inline_completion: %TRUE to do popup completion + * + * Sets whether the completions should be presented in a popup window. + * + * Since: 2.6 + **/ +void +gtk_entry_completion_set_popup_completion (GtkEntryCompletion *completion, + gboolean popup_completion) +{ + g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion)); + + popup_completion = popup_completion != FALSE; + + if (completion->priv->popup_completion != popup_completion) + { + completion->priv->popup_completion = popup_completion; + + g_object_notify (G_OBJECT (completion), "popup_completion"); + } +} + + +/** + * gtk_entry_completion_get_popup_completion: + * @completion: a #GtkEntryCompletion + * + * Returns whether the completions should be presented in a popup window. + * + * Return value: %TRUE if popup completion is turned on + * + * Since: 2.6 + **/ +gboolean +gtk_entry_completion_get_popup_completion (GtkEntryCompletion *completion) +{ + g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), TRUE); + + return completion->priv->popup_completion; +} |