aboutsummaryrefslogtreecommitdiffstats
path: root/widgets
diff options
context:
space:
mode:
Diffstat (limited to 'widgets')
-rw-r--r--widgets/text/e-completion-view.c103
-rw-r--r--widgets/text/e-completion-view.h6
-rw-r--r--widgets/text/e-completion.c159
-rw-r--r--widgets/text/e-completion.h4
-rw-r--r--widgets/text/e-entry.c13
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