From 78544223ad29c9e74282134663370c3c71360f1b Mon Sep 17 00:00:00 2001 From: Jon Trowbridge Date: Fri, 10 Aug 2001 22:36:41 +0000 Subject: Removed comment about the need to resolve nicknames properly, because we 2001-08-10 Jon Trowbridge * e-msg-composer-hdrs.c (set_recipients): Removed comment about the need to resolve nicknames properly, because we now do that. 2001-08-10 Jon Trowbridge * e-filter-bar.h: Set the subitems to NULL in the pre-defined ESearchBarItems. * e-filter-bar.c (rule_editor_clicked): Set the ESearchBarItem's subitems to NULL. (build_items): Set the ESearchBarItem's subitems to NULL. (e_filter_bar_new): Set the ESearchBarItem's subitems to NULL. * e-search-bar.c: Added support for subitems, so that a search option can key off of another option menu rather than just an entry. 2001-08-10 Jon Trowbridge * gui/component/addressbook.c: Set the ESearchBarItem subitems explicitly to NULL. 2001-08-10 Jon Trowbridge * gui/cal-search-bar.c: Where we have ESearchBarItems, set their subitems to NULL. 2001-08-10 Jon Trowbridge * folder-browser.c: Set our ESearchBarItems subitems to NULL. svn path=/trunk/; revision=11904 --- widgets/misc/ChangeLog | 14 +++ widgets/misc/e-filter-bar.c | 6 +- widgets/misc/e-filter-bar.h | 8 +- widgets/misc/e-search-bar.c | 265 +++++++++++++++++++++++++++++++++++++++----- widgets/misc/e-search-bar.h | 18 ++- 5 files changed, 279 insertions(+), 32 deletions(-) (limited to 'widgets') diff --git a/widgets/misc/ChangeLog b/widgets/misc/ChangeLog index a4a4c01e45..12b2d6dd29 100644 --- a/widgets/misc/ChangeLog +++ b/widgets/misc/ChangeLog @@ -1,3 +1,17 @@ +2001-08-10 Jon Trowbridge + + * e-filter-bar.h: Set the subitems to NULL in the pre-defined + ESearchBarItems. + + * e-filter-bar.c (rule_editor_clicked): Set the ESearchBarItem's + subitems to NULL. + (build_items): Set the ESearchBarItem's subitems to NULL. + (e_filter_bar_new): Set the ESearchBarItem's subitems to NULL. + + * e-search-bar.c: Added support for subitems, so that a search + option can key off of another option menu rather than just an + entry. + 2001-08-10 Jeffrey Stedfast * e-search-bar.c (impl_destroy): Don't forget to unref stuff here diff --git a/widgets/misc/e-filter-bar.c b/widgets/misc/e-filter-bar.c index 42ec5279e0..80fcc0b3f7 100644 --- a/widgets/misc/e-filter-bar.c +++ b/widgets/misc/e-filter-bar.c @@ -97,6 +97,7 @@ rule_editor_clicked (GtkWidget *dialog, int button, void *data) item.text = rule->name; item.id = efb->menu_base + efb->menu_rules->len; + item.subitems = NULL; g_ptr_array_add (efb->menu_rules, rule); @@ -303,6 +304,7 @@ build_items (ESearchBar *esb, ESearchBarItem *items, int type, int *start, GPtrA /* and add ours */ item.id = 0; item.text = NULL; + item.subitems = NULL; g_array_append_vals (menu, &item, 1); source = FILTER_SOURCE_INCOMING; } else { @@ -312,6 +314,7 @@ build_items (ESearchBar *esb, ESearchBarItem *items, int type, int *start, GPtrA while ((rule = rule_context_next_rule (efb->context, rule, source))) { item.id = id++; item.text = rule->name; + item.subitems = NULL; g_array_append_vals (menu, &item, 1); g_ptr_array_add (rules, rule); } @@ -324,6 +327,7 @@ build_items (ESearchBar *esb, ESearchBarItem *items, int type, int *start, GPtrA item.id = -1; item.text = NULL; + item.subitems = NULL; g_array_append_vals (menu, &item, 1); return menu; @@ -455,7 +459,7 @@ e_filter_bar_new (RuleContext *context, const char *systemrules, const char *use EFilterBarConfigRule config, void *data) { EFilterBar *bar; - ESearchBarItem item = { NULL, -1 }; + ESearchBarItem item = { NULL, -1, NULL }; bar = gtk_type_new (e_filter_bar_get_type ()); diff --git a/widgets/misc/e-filter-bar.h b/widgets/misc/e-filter-bar.h index bd91362c3c..87cecf2488 100644 --- a/widgets/misc/e-filter-bar.h +++ b/widgets/misc/e-filter-bar.h @@ -91,10 +91,10 @@ enum { E_FILTERBAR_LAST_ID = -6, }; -#define E_FILTERBAR_SAVE { N_("Add to Saved Searches"), E_FILTERBAR_SAVE_ID } -#define E_FILTERBAR_RESET { N_("Clear"), E_FILTERBAR_RESET_ID } -#define E_FILTERBAR_EDIT { N_("Edit..."), E_FILTERBAR_EDIT_ID } -#define E_FILTERBAR_ADVANCED { N_("Advanced..."), E_FILTERBAR_ADVANCED_ID } +#define E_FILTERBAR_SAVE { N_("Add to Saved Searches"), E_FILTERBAR_SAVE_ID, NULL } +#define E_FILTERBAR_RESET { N_("Clear"), E_FILTERBAR_RESET_ID, NULL } +#define E_FILTERBAR_EDIT { N_("Edit..."), E_FILTERBAR_EDIT_ID, NULL } +#define E_FILTERBAR_ADVANCED { N_("Advanced..."), E_FILTERBAR_ADVANCED_ID, NULL } #ifdef JUST_FOR_TRANSLATORS const char * strings[] = { diff --git a/widgets/misc/e-search-bar.c b/widgets/misc/e-search-bar.c index 19fc41aa71..9461bbecb4 100644 --- a/widgets/misc/e-search-bar.c +++ b/widgets/misc/e-search-bar.c @@ -5,8 +5,10 @@ * Copyright (C) 2000, 2001 Ximian, Inc. * * Authors: - * Chris Lahey + * Chris Lahey * Ettore Perazzoli + * Jon Trowbridge + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -30,6 +32,7 @@ #include #include #include +#include #include #include @@ -56,6 +59,7 @@ static GtkHBoxClass *parent_class = NULL; enum { ARG_0, ARG_OPTION_CHOICE, + ARG_SUBOPTION_CHOICE, ARG_TEXT, }; @@ -65,6 +69,11 @@ enum { static void emit_query_changed (ESearchBar *esb) { + if (esb->pending_change) { + gtk_idle_remove (esb->pending_change); + esb->pending_change = 0; + } + gtk_signal_emit (GTK_OBJECT (esb), esb_signals [QUERY_CHANGED]); } @@ -91,19 +100,110 @@ menubar_activated_cb (GtkWidget *widget, ESearchBar *esb) } static void -option_activated_cb (GtkWidget *widget, ESearchBar *esb) +entry_activated_cb (GtkWidget *widget, + ESearchBar *esb) { - int id; + emit_query_changed (esb); +} - id = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (widget), "EsbChoiceId")); +static void +subitem_activated_cb (GtkWidget *widget, ESearchBar *esb) +{ + gint id, subid; + + id = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (widget), "EsbItemId")); + subid = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (widget), "EsbSubitemId")); esb->option_choice = id; + esb->suboption_choice = subid; emit_query_changed (esb); } static void -entry_activated_cb (GtkWidget *widget, ESearchBar *esb) +activate_by_subitems (ESearchBar *esb, gint item_id, ESearchBarSubitem *subitems) { + if (subitems == NULL) { + /* This item uses the entry. */ + + if (esb->entry == NULL) { + esb->entry = gtk_entry_new(); + gtk_object_ref (GTK_OBJECT (esb->entry)); + gtk_signal_connect (GTK_OBJECT (esb->entry), "activate", + GTK_SIGNAL_FUNC (entry_activated_cb), esb); + gtk_widget_show(esb->entry); + + esb->suboption_choice = 0; + } + + if (esb->suboption_choice >= 0) { + + if (esb->suboption != NULL) { + gtk_container_remove (GTK_CONTAINER (esb->entry_box), esb->suboption); + } + + gtk_container_add (GTK_CONTAINER (esb->entry_box), esb->entry); + } + + gtk_entry_set_text (GTK_ENTRY (esb->entry), ""); + + esb->suboption_choice = -1; + + } else { + + GtkWidget *menu; + GtkWidget *menu_item; + gint i; + + if (esb->suboption == NULL) { + esb->suboption = gtk_option_menu_new (); + gtk_object_ref (GTK_OBJECT (esb->suboption)); + gtk_widget_show (esb->suboption); + } + + esb->suboption_menu = menu = gtk_menu_new (); + for (i = 0; subitems[i].id != -1; ++i) { + menu_item = gtk_menu_item_new_with_label (_(subitems[i].text)); + + gtk_object_set_data (GTK_OBJECT (menu_item), "EsbItemId", GINT_TO_POINTER (item_id)); + gtk_object_set_data (GTK_OBJECT (menu_item), "EsbSubitemId", GINT_TO_POINTER (subitems[i].id)); + + gtk_signal_connect (GTK_OBJECT (menu_item), + "activate", + GTK_SIGNAL_FUNC (subitem_activated_cb), + esb); + + gtk_widget_show (menu_item); + gtk_menu_append (GTK_MENU (menu), menu_item); + } + + gtk_option_menu_remove_menu (GTK_OPTION_MENU (esb->suboption)); + gtk_option_menu_set_menu (GTK_OPTION_MENU (esb->suboption), menu); + + if (esb->entry != NULL) { + gtk_container_remove (GTK_CONTAINER (esb->entry_box), esb->entry); + } + + gtk_container_add (GTK_CONTAINER (esb->entry_box), esb->suboption); + + esb->suboption_choice = 0; + } + + if (esb->activate_button) { + gtk_widget_set_sensitive (esb->activate_button, subitems == NULL); + } +} + +static void +option_activated_cb (GtkWidget *widget, + ESearchBar *esb) +{ + int id; + + id = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (widget), "EsbChoiceId")); + + activate_by_subitems (esb, id, gtk_object_get_data (GTK_OBJECT (widget), "EsbChoiceSubitems")); + + esb->option_choice = id; emit_query_changed (esb); } @@ -133,6 +233,42 @@ put_in_spacer_widget (GtkWidget *widget) return holder; } +static ESearchBarSubitem * +copy_subitems (ESearchBarSubitem *subitems) +{ + gint i, N; + ESearchBarSubitem *copy; + + if (subitems == NULL) + return NULL; + + for (N=0; subitems[N].id != -1; ++N); + copy = g_new (ESearchBarSubitem, N+1); + + for (i=0; ioption_menu = menu = gtk_menu_new (); for (i = 0; items[i].id != -1; i++) { GtkWidget *item; + ESearchBarSubitem *subitems = NULL; if (items[i].text) { char *str; @@ -228,10 +365,22 @@ set_option (ESearchBar *esb, ESearchBarItem *items) gtk_object_set_data (GTK_OBJECT (item), "EsbChoiceId", GINT_TO_POINTER(items[i].id)); + if (items[i].subitems != NULL) { + subitems = copy_subitems (items[i].subitems); + esb->subitem_garbage = g_list_prepend (esb->subitem_garbage, subitems); + } + + gtk_object_set_data (GTK_OBJECT (item), "EsbChoiceSubitems", subitems); + + if (i == 0) { + activate_by_subitems (esb, items[i].id, subitems); + } + gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (option_activated_cb), esb); } + gtk_widget_show_all (menu); gtk_option_menu_set_menu (GTK_OPTION_MENU (esb->option), menu); @@ -249,16 +398,6 @@ set_option (ESearchBar *esb, ESearchBarItem *items) gtk_container_set_border_width (GTK_CONTAINER (esb->dropdown), GTK_CONTAINER (esb->option)->border_width); } -static void -add_entry (ESearchBar *esb) -{ - esb->entry = gtk_entry_new (); - gtk_signal_connect (GTK_OBJECT (esb->entry), "activate", - GTK_SIGNAL_FUNC (entry_activated_cb), esb); - gtk_widget_show (esb->entry); - gtk_box_pack_start (GTK_BOX (esb), esb->entry, TRUE, TRUE, 0); -} - static void add_activate_button (ESearchBar *esb) { @@ -319,6 +458,10 @@ impl_get_arg (GtkObject *object, GtkArg *arg, guint arg_id) GTK_VALUE_ENUM (*arg) = e_search_bar_get_option_choice (esb); break; + case ARG_SUBOPTION_CHOICE: + GTK_VALUE_ENUM (*arg) = e_search_bar_get_suboption_choice (esb); + break; + case ARG_TEXT: GTK_VALUE_STRING (*arg) = e_search_bar_get_text (esb); break; @@ -344,6 +487,15 @@ impl_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) gtk_option_menu_set_history (GTK_OPTION_MENU (esb->option), row); emit_query_changed (esb); break; + + case ARG_SUBOPTION_CHOICE: + esb->suboption_choice = GTK_VALUE_ENUM (*arg); + row = find_id (esb->suboption_menu, esb->suboption_choice, "EsbSubitemId", NULL); + if (row == -1) + row = 0; + gtk_option_menu_set_history (GTK_OPTION_MENU (esb->suboption), row); + emit_query_changed (esb); + break; case ARG_TEXT: e_utf8_gtk_editable_set_text (GTK_EDITABLE (esb->entry), GTK_VALUE_STRING (*arg)); @@ -362,15 +514,30 @@ impl_destroy (GtkObject *object) g_return_if_fail (object != NULL); g_return_if_fail (E_IS_SEARCH_BAR (object)); - + + /* Should we really be unrefing all of these widgets? */ gtk_object_unref (GTK_OBJECT (esb->dropdown)); gtk_object_unref (GTK_OBJECT (esb->option)); - gtk_object_unref (GTK_OBJECT (esb->entry)); + + /* These two we do need to unref, because we explicitly hold + references to them. */ + if (esb->entry) + gtk_object_unref (GTK_OBJECT (esb->entry)); + if (esb->suboption) + gtk_object_unref (GTK_OBJECT (esb->suboption)); gtk_object_unref (GTK_OBJECT (esb->dropdown_holder)); gtk_object_unref (GTK_OBJECT (esb->option_menu)); gtk_object_unref (GTK_OBJECT (esb->dropdown_menu)); - + + g_list_foreach (esb->subitem_garbage, (GFunc) free_subitems, NULL); + g_list_free (esb->subitem_garbage); + + if (esb->pending_change) { + gtk_idle_remove (esb->pending_change); + esb->pending_change = 0; + } + if (GTK_OBJECT_CLASS (parent_class)->destroy) GTK_OBJECT_CLASS (parent_class)->destroy (object); } @@ -394,6 +561,8 @@ class_init (ESearchBarClass *klass) gtk_object_add_arg_type ("ESearchBar::option_choice", GTK_TYPE_ENUM, GTK_ARG_READWRITE, ARG_OPTION_CHOICE); + gtk_object_add_arg_type ("ESearchBar::suboption_choice", GTK_TYPE_ENUM, + GTK_ARG_READWRITE, ARG_SUBOPTION_CHOICE); gtk_object_add_arg_type ("ESearchBar::text", GTK_TYPE_STRING, GTK_ARG_READWRITE, ARG_TEXT); @@ -424,11 +593,21 @@ init (ESearchBar *esb) esb->entry = NULL; esb->option_choice = 0; + esb->suboption_choice = 0; } /* Object construction. */ +static gint +idle_change_hack (gpointer ptr) +{ + ESearchBar *esb = E_SEARCH_BAR (ptr); + esb->pending_change = 0; + emit_query_changed (esb); + return FALSE; +} + void e_search_bar_construct (ESearchBar *search_bar, ESearchBarItem *menu_items, @@ -440,14 +619,30 @@ e_search_bar_construct (ESearchBar *search_bar, g_return_if_fail (option_items != NULL); gtk_box_set_spacing (GTK_BOX (search_bar), 1); - + e_search_bar_set_menu (search_bar, menu_items); - + + search_bar->entry_box = gtk_hbox_new (0, FALSE); + e_search_bar_set_option (search_bar, option_items); - - add_entry (search_bar); - + + gtk_widget_show (search_bar->entry_box); + gtk_box_pack_start (GTK_BOX(search_bar), search_bar->entry_box, TRUE, TRUE, 0); + add_activate_button (search_bar); + + /* + * If the default choice for the option menu has subitems, then we need to + * activate the search immediately. However, the developer won't have + * connected to the changed signal until after the object is constructed, + * so we can't emit here. Thus we launch a one-shot idle function that will + * emit the changed signal, so that the proper callback will get invoked. + */ + if (search_bar->suboption_choice >= 0) { + gtk_widget_set_sensitive (search_bar->activate_button, FALSE); + + search_bar->pending_change = gtk_idle_add (idle_change_hack, search_bar); + } } void @@ -547,6 +742,25 @@ e_search_bar_get_option_choice (ESearchBar *search_bar) return search_bar->option_choice; } +/** + * e_search_bar_get_suboption_choice: + * @search_bar: A search bar. + * + * Queries the currently selected item in the suboptions menu of a search bar. + * + * Return value: Identifier of the selected item in the suboptions menu. + * If the search bar currently contains an entry rather than a a suboption menu, + * a value less than zero is returned. + **/ +int +e_search_bar_get_suboption_choice (ESearchBar *search_bar) +{ + g_return_val_if_fail (search_bar != NULL, -1); + g_return_val_if_fail (E_IS_SEARCH_BAR (search_bar), -1); + + return search_bar->suboption_choice; +} + /** * e_search_bar_get_text: * @search_bar: A search bar. @@ -554,7 +768,8 @@ e_search_bar_get_option_choice (ESearchBar *search_bar) * Queries the text of the entry line in a search bar. * * Return value: The text string that is in the entry line of the search bar. - * This must be freed using g_free(). + * This must be freed using g_free(). If a suboption menu is active instead + * of an entry, NULL is returned. **/ char * e_search_bar_get_text (ESearchBar *search_bar) @@ -562,5 +777,5 @@ e_search_bar_get_text (ESearchBar *search_bar) g_return_val_if_fail (search_bar != NULL, NULL); g_return_val_if_fail (E_IS_SEARCH_BAR (search_bar), NULL); - return e_utf8_gtk_editable_get_text (GTK_EDITABLE (search_bar->entry)); + return search_bar->suboption_choice < 0 ? e_utf8_gtk_editable_get_text (GTK_EDITABLE (search_bar->entry)) : NULL; } diff --git a/widgets/misc/e-search-bar.h b/widgets/misc/e-search-bar.h index 3ca381f92e..10c4eef8db 100644 --- a/widgets/misc/e-search-bar.h +++ b/widgets/misc/e-search-bar.h @@ -47,6 +47,12 @@ extern "C" { typedef struct { char *text; int id; +} ESearchBarSubitem; + +typedef struct { + char *text; + int id; + ESearchBarSubitem *subitems; } ESearchBarItem; typedef struct _ESearchBar ESearchBar; @@ -60,14 +66,21 @@ struct _ESearchBar GtkWidget *dropdown; GtkWidget *option; GtkWidget *entry; + GtkWidget *suboption; /* an option menu for the choices associated with some options */ + /* PRIVATE */ GtkWidget *dropdown_holder; /* holds the dropdown */ GtkWidget *option_menu; + GtkWidget *suboption_menu; GtkWidget *dropdown_menu; GtkWidget *activate_button; + GtkWidget *entry_box; + GList *subitem_garbage; + guint pending_change; int option_choice; + int suboption_choice; /* < 0 if the entry widget is active */ }; struct _ESearchBarClass @@ -95,8 +108,9 @@ GtkWidget *e_search_bar_new (ESearchBarItem *menu_items, void e_search_bar_set_menu_sensitive(ESearchBar *search_bar, int id, gboolean state); -int e_search_bar_get_option_choice (ESearchBar *search_bar); -char *e_search_bar_get_text (ESearchBar *search_bar); +int e_search_bar_get_option_choice (ESearchBar *search_bar); +int e_search_bar_get_suboption_choice (ESearchBar *search_bar); +char *e_search_bar_get_text (ESearchBar *search_bar); #ifdef __cplusplus } -- cgit v1.2.3