diff options
Diffstat (limited to 'widgets')
-rw-r--r-- | widgets/text/e-completion-view.c | 103 | ||||
-rw-r--r-- | widgets/text/e-completion-view.h | 6 | ||||
-rw-r--r-- | widgets/text/e-completion.c | 159 | ||||
-rw-r--r-- | widgets/text/e-completion.h | 4 | ||||
-rw-r--r-- | widgets/text/e-entry.c | 13 |
5 files changed, 199 insertions, 86 deletions
diff --git a/widgets/text/e-completion-view.c b/widgets/text/e-completion-view.c index 464b52c8a0..fc10ff7b66 100644 --- a/widgets/text/e-completion-view.c +++ b/widgets/text/e-completion-view.c @@ -287,6 +287,7 @@ static void e_completion_view_init (ECompletionView *completion) { completion->border_width = 2; + completion->choices = g_ptr_array_new (); } static void @@ -297,6 +298,8 @@ e_completion_view_destroy (GtkObject *object) e_completion_view_disconnect (cv); e_completion_view_clear_choices (cv); + g_ptr_array_free (cv->choices, TRUE); + if (cv->key_widget) { gtk_signal_disconnect (GTK_OBJECT (cv->key_widget), cv->key_signal_id); gtk_object_unref (GTK_OBJECT (cv->key_widget)); @@ -326,11 +329,17 @@ e_completion_view_disconnect (ECompletionView *cv) gtk_signal_disconnect (GTK_OBJECT (cv->completion), cv->cancel_signal_id); if (cv->end_signal_id) gtk_signal_disconnect (GTK_OBJECT (cv->completion), cv->end_signal_id); - + if (cv->clear_signal_id) + gtk_signal_disconnect (GTK_OBJECT (cv->completion), cv->clear_signal_id); + if (cv->lost_signal_id) + gtk_signal_disconnect (GTK_OBJECT (cv->completion), cv->lost_signal_id); + cv->begin_signal_id = 0; cv->comp_signal_id = 0; cv->restart_signal_id = 0; cv->end_signal_id = 0; + cv->clear_signal_id = 0; + cv->lost_signal_id = 0; } static ETable * @@ -342,19 +351,18 @@ e_completion_view_table (ECompletionView *cv) static void e_completion_view_clear_choices (ECompletionView *cv) { - GList *i; + ECompletionMatch *match; + GPtrArray *m; + int i; - g_return_if_fail (cv != NULL); g_return_if_fail (E_IS_COMPLETION_VIEW (cv)); - for (i = cv->choices; i != NULL; i = g_list_next (i)) { - e_completion_match_unref ((ECompletionMatch *) i->data); + m = cv->choices; + for (i = 0; i < m->len; i++) { + match = g_ptr_array_index (m, i); + e_completion_match_unref (match); } - - g_list_free (cv->choices); - cv->choices = NULL; - - cv->choice_count = 0; + g_ptr_array_set_size (m, 0); } static void @@ -368,7 +376,13 @@ e_completion_view_set_cursor_row (ECompletionView *cv, gint r) g_return_if_fail (cv != NULL); g_return_if_fail (E_IS_COMPLETION_VIEW (cv)); - g_return_if_fail (r < cv->choice_count); +#ifndef G_DISABLE_CHECKS + /* choices->len is unsigned, but it is reasonable for r to be + * < 0 */ + if (r > 0) { + g_return_if_fail (r < cv->choices->len); + } +#endif adj = e_scroll_frame_get_vadjustment (E_SCROLL_FRAME (cv->table)); @@ -392,12 +406,12 @@ e_completion_view_set_cursor_row (ECompletionView *cv, gint r) if (r == 0) { gtk_adjustment_set_value (adj, adj->lower); return; - } else if (r == cv->choice_count - 1) { + } else if (r == cv->choices->len - 1) { gtk_adjustment_set_value (adj, adj->upper - adj->page_size); return; } - fracline = ((adj->upper - adj->lower - adj->page_size) / cv->choice_count) / 4; + fracline = ((adj->upper - adj->lower - adj->page_size) / (gint)cv->choices->len) / 4; while (iteration_count < 100) { x = GTK_LAYOUT(table->table_canvas)->hadjustment->value; @@ -424,7 +438,9 @@ e_completion_view_set_cursor_row (ECompletionView *cv, gint r) static void e_completion_view_select (ECompletionView *cv, gint r) { - ECompletionMatch *match = (ECompletionMatch *) g_list_nth_data (cv->choices, r); + ECompletionMatch *match; + + match = g_ptr_array_index (cv->choices, r); cv->selection = r; e_completion_view_set_cursor_row (cv, r); @@ -496,8 +512,8 @@ e_completion_view_key_press_handler (GtkWidget *w, GdkEventKey *key_event, gpoin cv->selection += dir; - if (cv->selection >= cv->choice_count) { - cv->selection = cv->choice_count - 1; + if (cv->selection >= (int)cv->choices->len) { + cv->selection = cv->choices->len - 1; /* Don't re-emit the browse signal */ goto stop_emission; } @@ -506,7 +522,7 @@ e_completion_view_key_press_handler (GtkWidget *w, GdkEventKey *key_event, gpoin if (cv->selection >= 0) gtk_signal_emit (GTK_OBJECT (cv), e_completion_view_signals[E_COMPLETION_VIEW_BROWSE], - g_list_nth_data (cv->choices, cv->selection)); + g_ptr_array_index (cv->choices, cv->selection)); else gtk_signal_emit (GTK_OBJECT (cv), e_completion_view_signals[E_COMPLETION_VIEW_UNBROWSE]); @@ -554,12 +570,11 @@ static void completion_cb (ECompletion *completion, ECompletionMatch *match, gpointer user_data) { ECompletionView *cv = E_COMPLETION_VIEW (user_data); - gint r = cv->choice_count; - gboolean first = (cv->choices == NULL); + gint r = cv->choices->len; + gboolean first = (cv->choices->len == 0); - cv->choices = g_list_append (cv->choices, match); e_completion_match_ref (match); - ++cv->choice_count; + g_ptr_array_add (cv->choices, match); e_table_model_row_inserted (cv->model, r); @@ -581,6 +596,38 @@ end_completion_cb (ECompletion *completion, gpointer user_data) gtk_signal_emit (GTK_OBJECT (cv), e_completion_view_signals[E_COMPLETION_VIEW_FULL]); } +static void +clear_completion_cb (ECompletion *completion, gpointer user_data) +{ + ECompletionView *cv = E_COMPLETION_VIEW (user_data); + + e_completion_view_clear_choices (cv); + cv->have_all_choices = FALSE; + + e_table_model_changed (cv->model); +} + +static void +lost_completion_cb (ECompletion *completion, ECompletionMatch *match, gpointer user_data) +{ + ECompletionView *cv = E_COMPLETION_VIEW (user_data); + int i; + GPtrArray *c = cv->choices; + + for (i = 0; i < c->len; i++) + if (g_ptr_array_index (c, i) == match) + break; + + g_return_if_fail (i == c->len); + + /* FIXME: do remove_index_fast(), then row_changed and + * row_deleted (if there are more than 1 row still) */ + g_ptr_array_remove_index (c, i); + e_table_model_row_deleted (cv->model, i); + + e_completion_match_unref (match); +} + /*** Table Callbacks ***/ static char *simple_spec = @@ -604,7 +651,7 @@ static gint table_row_count (ETableModel *etm, gpointer data) { ECompletionView *cv = E_COMPLETION_VIEW (data); - return cv->choice_count; + return cv->choices->len; } static gboolean @@ -619,7 +666,7 @@ table_value_at (ETableModel *etm, gint c, gint r, gpointer data) ECompletionView *cv = E_COMPLETION_VIEW (data); ECompletionMatch *match; - match = (ECompletionMatch *) g_list_nth_data (cv->choices, r); + match = g_ptr_array_index (cv->choices, r); return (gpointer) e_completion_match_get_menu_text (match); } @@ -674,6 +721,14 @@ e_completion_view_construct (ECompletionView *cv, ECompletion *completion) "end_completion", GTK_SIGNAL_FUNC (end_completion_cb), cv); + cv->clear_signal_id = gtk_signal_connect (GTK_OBJECT (completion), + "clear_completion", + GTK_SIGNAL_FUNC (clear_completion_cb), + cv); + cv->lost_signal_id = gtk_signal_connect (GTK_OBJECT (completion), + "lost_completion", + GTK_SIGNAL_FUNC (lost_completion_cb), + cv); cv->model = e_table_simple_new (table_col_count, table_row_count, @@ -796,7 +851,7 @@ e_completion_view_set_width (ECompletionView *cv, gint width) y += w->allocation.y; lines = 5; /* default maximum */ - lines = MIN (lines, cv->choice_count); + lines = MIN (lines, cv->choices->len); drop_room = (gdk_screen_height () - y) / (double)line_height; drop_room = MAX (drop_room, 1); diff --git a/widgets/text/e-completion-view.h b/widgets/text/e-completion-view.h index ee18420fef..66be5a68ad 100644 --- a/widgets/text/e-completion-view.h +++ b/widgets/text/e-completion-view.h @@ -51,12 +51,16 @@ struct _ECompletionView { ETableModel *model; GtkWidget *table; + GPtrArray *choices; + ECompletion *completion; guint begin_signal_id; guint comp_signal_id; guint restart_signal_id; guint cancel_signal_id; guint end_signal_id; + guint clear_signal_id; + guint lost_signal_id; GtkWidget *key_widget; guint key_signal_id; @@ -64,8 +68,6 @@ struct _ECompletionView { gint complete_key; gint uncomplete_key; - GList *choices; - gint choice_count; gboolean have_all_choices; gboolean editable; diff --git a/widgets/text/e-completion.c b/widgets/text/e-completion.c index 0ede90a088..af3676e3ce 100644 --- a/widgets/text/e-completion.c +++ b/widgets/text/e-completion.c @@ -37,6 +37,8 @@ enum { E_COMPLETION_RESTART_COMPLETION, E_COMPLETION_CANCEL_COMPLETION, E_COMPLETION_END_COMPLETION, + E_COMPLETION_CLEAR_COMPLETION, + E_COMPLETION_LOST_COMPLETION, E_COMPLETION_LAST_SIGNAL }; @@ -45,10 +47,9 @@ static guint e_completion_signals[E_COMPLETION_LAST_SIGNAL] = { 0 }; struct _ECompletionPrivate { gboolean searching; gchar *search_text; + GPtrArray *matches; gint pos; gint limit; - gint match_count; - GList *matches; double min_score, max_score; }; @@ -56,8 +57,6 @@ static void e_completion_class_init (ECompletionClass *klass); static void e_completion_init (ECompletion *complete); static void e_completion_destroy (GtkObject *object); -static void match_list_free (GList *); - static void e_completion_add_match (ECompletion *complete, ECompletionMatch *); static void e_completion_clear_matches (ECompletion *complete); static gboolean e_completion_sort (ECompletion *complete); @@ -138,6 +137,22 @@ e_completion_class_init (ECompletionClass *klass) gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); + e_completion_signals[E_COMPLETION_CLEAR_COMPLETION] = + gtk_signal_new ("clear_completion", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (ECompletionClass, clear_completion), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); + + e_completion_signals[E_COMPLETION_LOST_COMPLETION] = + gtk_signal_new ("lost_completion", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (ECompletionClass, lost_completion), + gtk_marshal_NONE__POINTER, + GTK_TYPE_NONE, 1, GTK_TYPE_POINTER); + gtk_object_class_add_signals (object_class, e_completion_signals, E_COMPLETION_LAST_SIGNAL); object_class->destroy = e_completion_destroy; @@ -147,6 +162,7 @@ static void e_completion_init (ECompletion *complete) { complete->priv = g_new0 (struct _ECompletionPrivate, 1); + complete->priv->matches = g_ptr_array_new (); } static void @@ -159,6 +175,9 @@ e_completion_destroy (GtkObject *object) e_completion_clear_matches (complete); + g_ptr_array_free (complete->priv->matches, TRUE); + complete->priv->matches = NULL; + g_free (complete->priv); complete->priv = NULL; @@ -167,23 +186,14 @@ e_completion_destroy (GtkObject *object) } static void -match_list_free (GList *i) -{ - while (i) { - e_completion_match_unref ((ECompletionMatch *) i->data); - i = g_list_next (i); - } -} - -static void e_completion_add_match (ECompletion *complete, ECompletionMatch *match) { g_return_if_fail (complete && E_IS_COMPLETION (complete)); g_return_if_fail (match != NULL); - complete->priv->matches = g_list_append (complete->priv->matches, match); + g_ptr_array_add (complete->priv->matches, match); - if (complete->priv->match_count == 0) { + if (complete->priv->matches->len == 1) { complete->priv->min_score = complete->priv->max_score = match->score; @@ -193,24 +203,39 @@ e_completion_add_match (ECompletion *complete, ECompletionMatch *match) complete->priv->max_score = MAX (complete->priv->max_score, match->score); } - - ++complete->priv->match_count; } static void e_completion_clear_matches (ECompletion *complete) { - match_list_free (complete->priv->matches); - g_list_free (complete->priv->matches); - complete->priv->matches = NULL; + ECompletionMatch *match; + GPtrArray *m; + int i; - complete->priv->match_count = 0; + g_return_if_fail (E_IS_COMPLETION (complete)); + + m = complete->priv->matches; + for (i = 0; i < m->len; i++) { + match = g_ptr_array_index (m, i); + e_completion_match_unref (match); + } + g_ptr_array_set_size (m, 0); complete->priv->min_score = 0; complete->priv->max_score = 0; } void +e_completion_clear (ECompletion *complete) +{ + g_return_if_fail (E_IS_COMPLETION (complete)); + + /* FIXME: do we really want _clear and _clear_matches() ? */ + e_completion_clear_matches (complete); + gtk_signal_emit (GTK_OBJECT (complete), e_completion_signals[E_COMPLETION_CLEAR_COMPLETION]); +} + +void e_completion_begin_search (ECompletion *complete, const gchar *text, gint pos, gint limit) { g_return_if_fail (complete != NULL); @@ -282,13 +307,14 @@ e_completion_match_count (ECompletion *complete) g_return_val_if_fail (complete != NULL, 0); g_return_val_if_fail (E_IS_COMPLETION (complete), 0); - return complete->priv->match_count; + return complete->priv->matches->len; } void e_completion_foreach_match (ECompletion *complete, ECompletionMatchFn fn, gpointer closure) { - GList *i; + GPtrArray *m; + int i; g_return_if_fail (complete != NULL); g_return_if_fail (E_IS_COMPLETION (complete)); @@ -296,9 +322,9 @@ e_completion_foreach_match (ECompletion *complete, ECompletionMatchFn fn, gpoint if (fn == NULL) return; - for (i = complete->priv->matches; i != NULL; i = g_list_next (i)) { - fn ((ECompletionMatch *) i->data, closure); - } + m = complete->priv->matches; + for (i = 0; i < m->len; i++) + fn (g_ptr_array_index (m, i), closure); } ECompletion * @@ -310,32 +336,30 @@ e_completion_new (void) static gboolean e_completion_sort (ECompletion *complete) { - GList *sort_list = NULL, *i, *j; + GPtrArray *m; + int i; + GList *sort_list = NULL, *j; gboolean diff; - gint count; - for (i = complete->priv->matches; i != NULL; i = g_list_next (i)) { - sort_list = g_list_append (sort_list, i->data); - } + m = complete->priv->matches; + for (i = 0; i < m->len; i++) + sort_list = g_list_append (sort_list, + g_ptr_array_index (m, i)); + sort_list = g_list_sort (sort_list, (GCompareFunc) e_completion_match_compare_alpha); diff = FALSE; - count = 0; - i = complete->priv->matches; - j = sort_list; - while (i && j && !diff && count < complete->priv->limit) { - - if (i->data != j->data) - diff = TRUE; - i = g_list_next (i); - j = g_list_next (j); - ++count; + for (i=0, j=sort_list; i < m->len; i++, j = g_list_next (j)) { + if (g_ptr_array_index (m, i) == j->data) + continue; + + diff = TRUE; + g_ptr_array_index (m, i) = j->data; } - g_list_free (complete->priv->matches); - complete->priv->matches = sort_list; + g_list_free (sort_list); return diff; } @@ -344,17 +368,18 @@ e_completion_sort (ECompletion *complete) static void e_completion_restart (ECompletion *complete) { - GList *i; - gint count = 0; + GPtrArray *m; + gint i, count; gtk_signal_emit (GTK_OBJECT (complete), e_completion_signals[E_COMPLETION_RESTART_COMPLETION]); - i = complete->priv->matches; - while (i != NULL && count < complete->priv->limit) { - ECompletionMatch *m = (ECompletionMatch *) i->data; - gtk_signal_emit (GTK_OBJECT (complete), e_completion_signals[E_COMPLETION_COMPLETION], m); - i = g_list_next (i); - ++count; + m = complete->priv->matches; + for (i = count = 0; + i < m->len && count < complete->priv->limit; + i++, count++) { + gtk_signal_emit (GTK_OBJECT (complete), + e_completion_signals[E_COMPLETION_COMPLETION], + g_ptr_array_index (m, i)); } } @@ -370,16 +395,37 @@ e_completion_found_match (ECompletion *complete, ECompletionMatch *match) return; } - e_completion_add_match (complete, match); - - /* For now, do nothing when we hit the limit --- just don't announce the incoming matches. */ - if (complete->priv->match_count >= complete->priv->limit) { + /* For now, do nothing when we hit the limit --- just don't + * announce the incoming matches. */ + if (complete->priv->matches->len >= complete->priv->limit) { e_completion_match_unref (match); return; } + e_completion_add_match (complete, match); + gtk_signal_emit (GTK_OBJECT (complete), e_completion_signals[E_COMPLETION_COMPLETION], match); +} + +/* to optimize this, make the match a hash table */ +void +e_completion_lost_match (ECompletion *complete, ECompletionMatch *match) +{ + gboolean removed; + + g_return_if_fail (E_IS_COMPLETION (complete)); + g_return_if_fail (match != NULL); + + /* FIXME: remove fast */ + removed = g_ptr_array_remove (complete->priv->matches, + match); + + /* maybe just return here? */ + g_return_if_fail (removed); + + gtk_signal_emit (GTK_OBJECT (complete), e_completion_signals[E_COMPLETION_LOST_COMPLETION], match); + e_completion_match_unref (match); } void @@ -389,6 +435,9 @@ e_completion_end_search (ECompletion *complete) g_return_if_fail (E_IS_COMPLETION (complete)); g_return_if_fail (complete->priv->searching); + /* our table model should be sorted by a non-visible column of + * doubles (the score) rather than whatever we are doing + */ /* If sorting by score accomplishes anything, issue a restart right before we end. */ if (e_completion_sort (complete)) e_completion_restart (complete); diff --git a/widgets/text/e-completion.h b/widgets/text/e-completion.h index 4a06059065..522876730c 100644 --- a/widgets/text/e-completion.h +++ b/widgets/text/e-completion.h @@ -59,6 +59,8 @@ struct _ECompletionClass { void (*restart_completion) (ECompletion *comp); void (*cancel_completion) (ECompletion *comp); void (*end_completion) (ECompletion *comp); + void (*clear_completion) (ECompletion *comp); + void (*lost_completion) (ECompletion *comp, ECompletionMatch *match); }; GtkType e_completion_get_type (void); @@ -80,6 +82,8 @@ ECompletion *e_completion_new (void); or very bad things might happen. */ void e_completion_found_match (ECompletion *comp, ECompletionMatch *); +void e_completion_lost_match (ECompletion *comp, ECompletionMatch *); +void e_completion_clear (ECompletion *comp); void e_completion_end_search (ECompletion *comp); END_GNOME_DECLS diff --git a/widgets/text/e-entry.c b/widgets/text/e-entry.c index b47e6c8ddd..120db13637 100644 --- a/widgets/text/e-entry.c +++ b/widgets/text/e-entry.c @@ -211,10 +211,13 @@ e_entry_text_keypress (EText *text, guint keyval, guint state, EEntry *entry) if (e_entry_is_empty (entry)) { e_entry_cancel_delayed_completion (entry); e_entry_show_popup (entry, FALSE); - } else if (entry->priv->popup_is_visible) { - e_entry_start_delayed_completion (entry, 1); - } else if (entry->priv->completion) - e_entry_start_delayed_completion (entry, entry->priv->completion_delay); + } else if (entry->priv->completion_delay >= 0) { + int delay; + delay = entry->priv->popup_is_visible + ? 1 + : entry->priv->completion_delay; + e_entry_start_delayed_completion (entry, delay); + } } entry->priv->changed_since_keypress = FALSE; } @@ -612,7 +615,7 @@ full_cb (ECompletionView *view, gpointer user_data) { EEntry *entry = E_ENTRY (user_data); - e_entry_show_popup (entry, view->choice_count > 0); + e_entry_show_popup (entry, view->choices->len > 0); } static void |