diff options
author | Matthew Barnes <mbarnes@redhat.com> | 2009-06-09 12:28:07 +0800 |
---|---|---|
committer | Matthew Barnes <mbarnes@redhat.com> | 2009-06-09 18:36:56 +0800 |
commit | df17adc5aa4ff6af69686d0957e1ab6dfa58732d (patch) | |
tree | f681bbb06fc307633e2f751780a582dd625093c5 | |
parent | 2f4139e59919afdab0bcf2ca9ca91d168515b43f (diff) | |
download | gsoc2013-evolution-df17adc5aa4ff6af69686d0957e1ab6dfa58732d.tar.gz gsoc2013-evolution-df17adc5aa4ff6af69686d0957e1ab6dfa58732d.tar.zst gsoc2013-evolution-df17adc5aa4ff6af69686d0957e1ab6dfa58732d.zip |
Search bar improvements.
Split the search entry into a new widget to manage hints (EHintedEntry).
Let the search entry expand to use available horizontal space.
-rw-r--r-- | addressbook/gui/component/e-book-shell-view-actions.c | 25 | ||||
-rw-r--r-- | calendar/module/e-cal-shell-view-actions.c | 25 | ||||
-rw-r--r-- | calendar/module/e-memo-shell-view-actions.c | 25 | ||||
-rw-r--r-- | calendar/module/e-task-shell-view-actions.c | 25 | ||||
-rw-r--r-- | doc/reference/shell/Makefile.am | 2 | ||||
-rw-r--r-- | doc/reference/shell/tmpl/e-shell-content.sgml | 5 | ||||
-rw-r--r-- | mail/e-mail-shell-view-actions.c | 34 | ||||
-rw-r--r-- | mail/e-mail-shell-view-private.h | 3 | ||||
-rw-r--r-- | shell/e-shell-content.c | 183 | ||||
-rw-r--r-- | shell/e-shell-content.h | 3 | ||||
-rw-r--r-- | widgets/misc/Makefile.am | 2 | ||||
-rw-r--r-- | widgets/misc/e-hinted-entry.c | 298 | ||||
-rw-r--r-- | widgets/misc/e-hinted-entry.h | 73 |
13 files changed, 612 insertions, 91 deletions
diff --git a/addressbook/gui/component/e-book-shell-view-actions.c b/addressbook/gui/component/e-book-shell-view-actions.c index 35d0e8f8c8..73766c7df3 100644 --- a/addressbook/gui/component/e-book-shell-view-actions.c +++ b/addressbook/gui/component/e-book-shell-view-actions.c @@ -451,6 +451,29 @@ action_contact_save_as_cb (GtkAction *action, } static void +action_contact_search_cb (GtkRadioAction *action, + GtkRadioAction *current, + EBookShellView *book_shell_view) +{ + EShellView *shell_view; + EShellContent *shell_content; + const gchar *search_hint; + + /* XXX Figure out a way to handle this in EShellContent + * instead of every shell view having to handle it. + * The problem is EShellContent does not know what + * the search option actions are for this view. It + * would have to dig up the popup menu and retrieve + * the action for each menu item. Seems messy. */ + + shell_view = E_SHELL_VIEW (book_shell_view); + shell_content = e_shell_view_get_shell_content (shell_view); + + search_hint = gtk_action_get_label (GTK_ACTION (current)); + e_shell_content_set_search_hint (shell_content, search_hint); +} + +static void action_contact_select_all_cb (GtkAction *action, EBookShellView *book_shell_view) { @@ -865,7 +888,7 @@ e_book_shell_view_actions_init (EBookShellView *book_shell_view) action_group, contact_search_entries, G_N_ELEMENTS (contact_search_entries), CONTACT_SEARCH_NAME_CONTAINS, - NULL, NULL); + G_CALLBACK (action_contact_search_cb), book_shell_view); /* Lockdown Printing Actions */ action_group = ACTION_GROUP (LOCKDOWN_PRINTING); diff --git a/calendar/module/e-cal-shell-view-actions.c b/calendar/module/e-cal-shell-view-actions.c index a5d0dd826b..5f5380d919 100644 --- a/calendar/module/e-cal-shell-view-actions.c +++ b/calendar/module/e-cal-shell-view-actions.c @@ -297,6 +297,29 @@ action_calendar_rename_cb (GtkAction *action, } static void +action_calendar_search_cb (GtkRadioAction *action, + GtkRadioAction *current, + ECalShellView *cal_shell_view) +{ + EShellView *shell_view; + EShellContent *shell_content; + const gchar *search_hint; + + /* XXX Figure out a way to handle this in EShellContent + * instead of every shell view having to handle it. + * The problem is EShellContent does not know what + * the search option actions are for this view. It + * would have to dig up the popup menu and retrieve + * the action for each menu item. Seems messy. */ + + shell_view = E_SHELL_VIEW (cal_shell_view); + shell_content = e_shell_view_get_shell_content (shell_view); + + search_hint = gtk_action_get_label (GTK_ACTION (current)); + e_shell_content_set_search_hint (shell_content, search_hint); +} + +static void action_calendar_select_one_cb (GtkAction *action, ECalShellView *cal_shell_view) { @@ -1051,7 +1074,7 @@ e_cal_shell_view_actions_init (ECalShellView *cal_shell_view) action_group, calendar_search_entries, G_N_ELEMENTS (calendar_search_entries), CALENDAR_SEARCH_SUMMARY_CONTAINS, - NULL, NULL); + G_CALLBACK (action_calendar_search_cb), cal_shell_view); /* Lockdown Printing Actions */ action_group = ACTION_GROUP (LOCKDOWN_PRINTING); diff --git a/calendar/module/e-memo-shell-view-actions.c b/calendar/module/e-memo-shell-view-actions.c index ab0b9f0fe3..855a7b18b4 100644 --- a/calendar/module/e-memo-shell-view-actions.c +++ b/calendar/module/e-memo-shell-view-actions.c @@ -505,6 +505,29 @@ action_memo_save_as_cb (GtkAction *action, } static void +action_memo_search_cb (GtkRadioAction *action, + GtkRadioAction *current, + EMemoShellView *memo_shell_view) +{ + EShellView *shell_view; + EShellContent *shell_content; + const gchar *search_hint; + + /* XXX Figure out a way to handle this in EShellContent + * instead of every shell view having to handle it. + * The problem is EShellContent does not know what + * the search option actions are for this view. It + * would have to dig up the popup menu and retrieve + * the action for each menu item. Seems messy. */ + + shell_view = E_SHELL_VIEW (memo_shell_view); + shell_content = e_shell_view_get_shell_content (shell_view); + + search_hint = gtk_action_get_label (GTK_ACTION (current)); + e_shell_content_set_search_hint (shell_content, search_hint); +} + +static void action_search_execute_cb (GtkAction *action, EMemoShellView *memo_shell_view) { @@ -803,7 +826,7 @@ e_memo_shell_view_actions_init (EMemoShellView *memo_shell_view) action_group, memo_search_entries, G_N_ELEMENTS (memo_search_entries), MEMO_SEARCH_SUMMARY_CONTAINS, - NULL, NULL); + G_CALLBACK (action_memo_search_cb), memo_shell_view); /* Lockdown Printing Actions */ action_group = ACTION_GROUP (LOCKDOWN_PRINTING); diff --git a/calendar/module/e-task-shell-view-actions.c b/calendar/module/e-task-shell-view-actions.c index 4645ac0e56..8431b64624 100644 --- a/calendar/module/e-task-shell-view-actions.c +++ b/calendar/module/e-task-shell-view-actions.c @@ -646,6 +646,29 @@ action_task_save_as_cb (GtkAction *action, g_free (string); } +static void +action_task_search_cb (GtkRadioAction *action, + GtkRadioAction *current, + ETaskShellView *task_shell_view) +{ + EShellView *shell_view; + EShellContent *shell_content; + const gchar *search_hint; + + /* XXX Figure out a way to handle this in EShellContent + * instead of every shell view having to handle it. + * The problem is EShellContent does not know what + * the search option actions are for this view. It + * would have to dig up the popup menu and retrieve + * the action for each menu item. Seems messy. */ + + shell_view = E_SHELL_VIEW (task_shell_view); + shell_content = e_shell_view_get_shell_content (shell_view); + + search_hint = gtk_action_get_label (GTK_ACTION (current)); + e_shell_content_set_search_hint (shell_content, search_hint); +} + static GtkActionEntry task_entries[] = { { "task-assign", @@ -1005,7 +1028,7 @@ e_task_shell_view_actions_init (ETaskShellView *task_shell_view) action_group, task_search_entries, G_N_ELEMENTS (task_search_entries), TASK_SEARCH_SUMMARY_CONTAINS, - NULL, NULL); + G_CALLBACK (action_task_search_cb), task_shell_view); /* Lockdown Printing Actions */ action_group = ACTION_GROUP (LOCKDOWN_PRINTING); diff --git a/doc/reference/shell/Makefile.am b/doc/reference/shell/Makefile.am index 69d047b6d3..0084a0f7c2 100644 --- a/doc/reference/shell/Makefile.am +++ b/doc/reference/shell/Makefile.am @@ -123,8 +123,8 @@ GTKDOC_LIBS= \ $(top_builddir)/widgets/misc/.libs/e-action-combo-box.o \ $(top_builddir)/widgets/misc/.libs/e-activity.o \ $(top_builddir)/widgets/misc/.libs/e-activity-proxy.o \ - $(top_builddir)/widgets/misc/.libs/e-icon-entry.o \ $(top_builddir)/widgets/misc/.libs/e-gui-utils.o \ + $(top_builddir)/widgets/misc/.libs/e-hinted-entry.o \ $(top_builddir)/widgets/misc/.libs/e-menu-tool-button.o \ $(top_builddir)/widgets/misc/.libs/e-online-button.o \ $(top_builddir)/widgets/misc/.libs/e-popup-menu.o \ diff --git a/doc/reference/shell/tmpl/e-shell-content.sgml b/doc/reference/shell/tmpl/e-shell-content.sgml index e89f928c7c..0ddc175d77 100644 --- a/doc/reference/shell/tmpl/e-shell-content.sgml +++ b/doc/reference/shell/tmpl/e-shell-content.sgml @@ -58,6 +58,11 @@ EShellContent </para> +<!-- ##### ARG EShellContent:search-hint ##### --> +<para> + +</para> + <!-- ##### ARG EShellContent:search-rule ##### --> <para> diff --git a/mail/e-mail-shell-view-actions.c b/mail/e-mail-shell-view-actions.c index 3d0b76d176..6e4e7fdc8c 100644 --- a/mail/e-mail-shell-view-actions.c +++ b/mail/e-mail-shell-view-actions.c @@ -613,6 +613,29 @@ action_mail_preview_cb (GtkToggleAction *action, } static void +action_mail_search_cb (GtkRadioAction *action, + GtkRadioAction *current, + EMailShellView *mail_shell_view) +{ + EShellView *shell_view; + EShellContent *shell_content; + const gchar *search_hint; + + /* XXX Figure out a way to handle this in EShellContent + * instead of every shell view having to handle it. + * The problem is EShellContent does not know what + * the search option actions are for this view. It + * would have to dig up the popup menu and retrieve + * the action for each menu item. Seems messy. */ + + shell_view = E_SHELL_VIEW (mail_shell_view); + shell_content = e_shell_view_get_shell_content (shell_view); + + search_hint = gtk_action_get_label (GTK_ACTION (current)); + e_shell_content_set_search_hint (shell_content, search_hint); +} + +static void action_mail_show_hidden_cb (GtkAction *action, EMailShellView *mail_shell_view) { @@ -1360,14 +1383,7 @@ static GtkRadioActionEntry mail_scope_entries[] = { N_("Current Folder"), NULL, NULL, /* XXX Add a tooltip! */ - MAIL_SCOPE_CURRENT_FOLDER }, - - { "mail-scope-current-message", - NULL, - N_("Current Message"), - NULL, - NULL, /* XXX Add a tooltip! */ - MAIL_SCOPE_CURRENT_MESSAGE } + MAIL_SCOPE_CURRENT_FOLDER } }; void @@ -1409,7 +1425,7 @@ e_mail_shell_view_actions_init (EMailShellView *mail_shell_view) action_group, mail_search_entries, G_N_ELEMENTS (mail_search_entries), MAIL_SEARCH_SUBJECT_OR_SENDER_CONTAINS, - NULL, NULL); + G_CALLBACK (action_mail_search_cb), mail_shell_view); gtk_action_group_add_radio_actions ( action_group, mail_scope_entries, G_N_ELEMENTS (mail_scope_entries), diff --git a/mail/e-mail-shell-view-private.h b/mail/e-mail-shell-view-private.h index 4b27c4c541..13c76c7cfe 100644 --- a/mail/e-mail-shell-view-private.h +++ b/mail/e-mail-shell-view-private.h @@ -113,8 +113,7 @@ enum { enum { MAIL_SCOPE_CURRENT_FOLDER, MAIL_SCOPE_CURRENT_ACCOUNT, - MAIL_SCOPE_ALL_ACCOUNTS, - MAIL_SCOPE_CURRENT_MESSAGE + MAIL_SCOPE_ALL_ACCOUNTS }; struct _EMailShellViewPrivate { diff --git a/shell/e-shell-content.c b/shell/e-shell-content.c index 00172ea5f5..216520fbb4 100644 --- a/shell/e-shell-content.c +++ b/shell/e-shell-content.c @@ -26,6 +26,7 @@ #include "e-util/e-binding.h" #include "filter/rule-editor.h" #include "widgets/misc/e-action-combo-box.h" +#include "widgets/misc/e-hinted-entry.h" #include "e-shell-backend.h" #include "e-shell-view.h" @@ -64,6 +65,7 @@ enum { PROP_FILTER_VALUE, PROP_FILTER_VISIBLE, PROP_SEARCH_CONTEXT, + PROP_SEARCH_HINT, PROP_SEARCH_RULE, PROP_SEARCH_TEXT, PROP_SEARCH_VISIBLE, @@ -96,8 +98,6 @@ action_search_execute_cb (GtkAction *action, EShellView *shell_view; EShellWindow *shell_window; GtkWidget *widget; - const GdkColor *base_color; - const GdkColor *text_color; const gchar *search_text; /* EShellView subclasses are responsible for actually @@ -110,22 +110,25 @@ action_search_execute_cb (GtkAction *action, return; widget = shell_content->priv->search_entry; + search_text = e_shell_content_get_search_text (shell_content); if (search_text != NULL && *search_text != '\0') { GtkStyle *style; + const GdkColor *color; + + style = gtk_widget_get_style (widget); + color = &style->base[GTK_STATE_SELECTED]; + gtk_widget_modify_base (widget, GTK_STATE_NORMAL, color); - style = gtk_widget_get_default_style (); - base_color = &style->base[GTK_STATE_SELECTED]; - text_color = &style->text[GTK_STATE_SELECTED]; + style = gtk_widget_get_style (widget); + color = &style->text[GTK_STATE_SELECTED]; + gtk_widget_modify_text (widget, GTK_STATE_NORMAL, color); } else { - base_color = NULL; - text_color = NULL; + /* Text color will be updated when we move the focus. */ + gtk_widget_modify_base (widget, GTK_STATE_NORMAL, NULL); } - gtk_widget_modify_base (widget, GTK_STATE_NORMAL, base_color); - gtk_widget_modify_text (widget, GTK_STATE_NORMAL, text_color); - action = E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window); gtk_action_set_sensitive (action, TRUE); @@ -157,30 +160,6 @@ shell_content_entry_activated_cb (EShellContent *shell_content, gtk_action_activate (action); } -static gboolean -shell_content_entry_focus_in_cb (EShellContent *shell_content, - GdkEventFocus *focus_event, - GtkWidget *entry) -{ - /* Clear the "background" text. */ - if (shell_content->priv->search_state == GTK_STATE_INSENSITIVE) - gtk_entry_set_text (GTK_ENTRY (entry), ""); - - gtk_widget_modify_base (entry, GTK_STATE_NORMAL, NULL); - gtk_widget_modify_text (entry, GTK_STATE_NORMAL, NULL); - - return FALSE; -} - -static gboolean -shell_content_entry_focus_out_cb (EShellContent *shell_content, - GdkEventFocus *focus_event, - GtkWidget *entry) -{ - /* FIXME */ - return FALSE; -} - static void shell_content_entry_icon_press_cb (EShellContent *shell_content, GtkEntryIconPosition icon_pos, @@ -351,6 +330,12 @@ shell_content_set_property (GObject *object, g_value_get_boolean (value)); return; + case PROP_SEARCH_HINT: + e_shell_content_set_search_hint ( + E_SHELL_CONTENT (object), + g_value_get_string (value)); + return; + case PROP_SEARCH_RULE: e_shell_content_set_search_rule ( E_SHELL_CONTENT (object), @@ -428,6 +413,12 @@ shell_content_get_property (GObject *object, E_SHELL_CONTENT (object))); return; + case PROP_SEARCH_HINT: + g_value_set_string ( + value, e_shell_content_get_search_hint ( + E_SHELL_CONTENT (object))); + return; + case PROP_SEARCH_RULE: g_value_set_object ( value, e_shell_content_get_search_rule ( @@ -564,6 +555,9 @@ shell_content_constructed (GObject *object) e_binding_new ( G_OBJECT (action), "stock-id", G_OBJECT (widget), "secondary-icon-stock"); + e_binding_new ( + G_OBJECT (action), "tooltip", + G_OBJECT (widget), "secondary-icon-tooltip-text"); action = E_SHELL_WINDOW_ACTION_SEARCH_EXECUTE (shell_window); g_signal_connect ( @@ -577,6 +571,9 @@ shell_content_constructed (GObject *object) e_binding_new ( G_OBJECT (action), "stock-id", G_OBJECT (widget), "primary-icon-stock"); + e_binding_new ( + G_OBJECT (action), "tooltip", + G_OBJECT (widget), "primary-icon-tooltip-text"); widget = shell_content->priv->search_bar; gtk_size_group_add_widget (size_group, widget); @@ -748,6 +745,16 @@ shell_content_class_init (EShellContentClass *class) g_object_class_install_property ( object_class, + PROP_SEARCH_HINT, + g_param_spec_string ( + "search-hint", + NULL, + NULL, + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, PROP_SEARCH_RULE, g_param_spec_object ( "search-rule", @@ -827,7 +834,6 @@ shell_content_init (EShellContent *shell_content) { GtkBox *box; GtkLabel *label; - GtkWidget *mnemonic; GtkWidget *widget; shell_content->priv = E_SHELL_CONTENT_GET_PRIVATE (shell_content); @@ -836,15 +842,21 @@ shell_content_init (EShellContent *shell_content) /*** Build the Search Bar ***/ - widget = gtk_hbox_new (FALSE, 3); + widget = gtk_hbox_new (FALSE, 24); gtk_widget_set_parent (widget, GTK_WIDGET (shell_content)); shell_content->priv->search_bar = g_object_ref_sink (widget); gtk_widget_show (widget); - box = GTK_BOX (widget); - /* Filter Combo Widgets */ + box = GTK_BOX (shell_content->priv->search_bar); + + widget = gtk_hbox_new (FALSE, 3); + gtk_box_pack_start (box, widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + box = GTK_BOX (widget); + /* Translators: The "Show:" label precedes a combo box that * allows the user to filter the current view. Examples of * items that appear in the combo box are "Unread Messages", @@ -862,27 +874,28 @@ shell_content_init (EShellContent *shell_content) shell_content->priv->filter_combo_box = g_object_ref (widget); gtk_widget_show (widget); - /* Scope Combo Widgets */ + /* Search Entry Widgets */ - widget = e_action_combo_box_new (); - gtk_box_pack_end (box, widget, FALSE, FALSE, 0); - shell_content->priv->scope_combo_box = g_object_ref (widget); + box = GTK_BOX (shell_content->priv->search_bar); + + widget = gtk_hbox_new (FALSE, 3); + gtk_box_pack_start (box, widget, TRUE, TRUE, 0); gtk_widget_show (widget); - mnemonic = widget; + box = GTK_BOX (widget); /* Translators: This is part of the quick search interface. * example: Search: [_______________] in [ Current Folder ] */ - widget = gtk_label_new_with_mnemonic (_("i_n")); - gtk_label_set_mnemonic_widget (GTK_LABEL (widget), mnemonic); - gtk_box_pack_end (box, widget, FALSE, FALSE, 0); - shell_content->priv->scope_label = g_object_ref (widget); + widget = gtk_label_new_with_mnemonic (_("Sear_ch:")); + gtk_box_pack_start (box, widget, FALSE, FALSE, 0); + shell_content->priv->search_label = g_object_ref (widget); gtk_widget_show (widget); - /* Search Entry Widgets */ + label = GTK_LABEL (widget); - widget = gtk_entry_new (); - gtk_box_pack_end (box, widget, FALSE, FALSE, 0); + widget = e_hinted_entry_new (); + gtk_label_set_mnemonic_widget (label, widget); + gtk_box_pack_start (box, widget, TRUE, TRUE, 0); shell_content->priv->search_entry = g_object_ref (widget); shell_content->priv->search_state = GTK_STATE_NORMAL; gtk_widget_show (widget); @@ -893,16 +906,6 @@ shell_content_init (EShellContent *shell_content) shell_content); g_signal_connect_swapped ( - widget, "focus-in-event", - G_CALLBACK (shell_content_entry_focus_in_cb), - shell_content); - - g_signal_connect_swapped ( - widget, "focus-out-event", - G_CALLBACK (shell_content_entry_focus_out_cb), - shell_content); - - g_signal_connect_swapped ( widget, "icon-press", G_CALLBACK (shell_content_entry_icon_press_cb), shell_content); @@ -917,14 +920,21 @@ shell_content_init (EShellContent *shell_content) G_CALLBACK (shell_content_entry_key_press_cb), shell_content); - mnemonic = widget; + /* Scope Combo Widgets */ /* Translators: This is part of the quick search interface. * example: Search: [_______________] in [ Current Folder ] */ - widget = gtk_label_new_with_mnemonic (_("Sear_ch:")); - gtk_label_set_mnemonic_widget (GTK_LABEL (label), mnemonic); - gtk_box_pack_end (box, widget, FALSE, FALSE, 0); - shell_content->priv->search_label = g_object_ref (widget); + widget = gtk_label_new_with_mnemonic (_("i_n")); + gtk_box_pack_start (box, widget, FALSE, FALSE, 0); + shell_content->priv->scope_label = g_object_ref (widget); + gtk_widget_show (widget); + + label = GTK_LABEL (widget); + + widget = e_action_combo_box_new (); + gtk_label_set_mnemonic_widget (label, widget); + gtk_box_pack_start (box, widget, FALSE, FALSE, 0); + shell_content->priv->scope_combo_box = g_object_ref (widget); gtk_widget_show (widget); } @@ -1124,6 +1134,33 @@ e_shell_content_get_search_context (EShellContent *shell_content) return shell_content->priv->search_context; } +const gchar * +e_shell_content_get_search_hint (EShellContent *shell_content) +{ + EHintedEntry *entry; + + g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL); + + entry = E_HINTED_ENTRY (shell_content->priv->search_entry); + + return e_hinted_entry_get_hint (entry); +} + +void +e_shell_content_set_search_hint (EShellContent *shell_content, + const gchar *search_hint) +{ + EHintedEntry *entry; + + g_return_if_fail (E_IS_SHELL_CONTENT (shell_content)); + + entry = E_HINTED_ENTRY (shell_content->priv->search_entry); + + e_hinted_entry_set_hint (entry, search_hint); + + g_object_notify (G_OBJECT (shell_content), "search-hint"); +} + FilterRule * e_shell_content_get_search_rule (EShellContent *shell_content) { @@ -1154,30 +1191,26 @@ e_shell_content_set_search_rule (EShellContent *shell_content, const gchar * e_shell_content_get_search_text (EShellContent *shell_content) { - GtkEntry *entry; + EHintedEntry *entry; g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL); - if (shell_content->priv->search_state == GTK_STATE_INSENSITIVE) - return ""; - - entry = GTK_ENTRY (shell_content->priv->search_entry); + entry = E_HINTED_ENTRY (shell_content->priv->search_entry); - return gtk_entry_get_text (entry); + return e_hinted_entry_get_text (entry); } void e_shell_content_set_search_text (EShellContent *shell_content, const gchar *search_text) { - GtkEntry *entry; + EHintedEntry *entry; g_return_if_fail (E_IS_SHELL_CONTENT (shell_content)); - entry = GTK_ENTRY (shell_content->priv->search_entry); - search_text = (search_text != NULL) ? search_text : ""; + entry = E_HINTED_ENTRY (shell_content->priv->search_entry); - gtk_entry_set_text (entry, search_text); + e_hinted_entry_set_text (entry, search_text); g_object_notify (G_OBJECT (shell_content), "search-text"); } diff --git a/shell/e-shell-content.h b/shell/e-shell-content.h index 2259dbd972..af2799c7d4 100644 --- a/shell/e-shell-content.h +++ b/shell/e-shell-content.h @@ -106,6 +106,9 @@ void e_shell_content_add_filter_separator_after gint action_value); RuleContext * e_shell_content_get_search_context (EShellContent *shell_content); +const gchar * e_shell_content_get_search_hint (EShellContent *shell_content); +void e_shell_content_set_search_hint (EShellContent *shell_content, + const gchar *search_hint); FilterRule * e_shell_content_get_search_rule (EShellContent *shell_content); void e_shell_content_set_search_rule (EShellContent *shell_content, FilterRule *search_rule); diff --git a/widgets/misc/Makefile.am b/widgets/misc/Makefile.am index 56a927041e..cbbd283fb2 100644 --- a/widgets/misc/Makefile.am +++ b/widgets/misc/Makefile.am @@ -60,6 +60,7 @@ widgetsinclude_HEADERS = \ e-dateedit.h \ e-file-activity.h \ e-gui-utils.h \ + e-hinted-entry.h \ e-hsv-utils.h \ e-image-chooser.h \ e-map.h \ @@ -122,6 +123,7 @@ libemiscwidgets_la_SOURCES = \ e-dateedit.c \ e-file-activity.c \ e-gui-utils.c \ + e-hinted-entry.c \ e-hsv-utils.c \ e-image-chooser.c \ e-map.c \ diff --git a/widgets/misc/e-hinted-entry.c b/widgets/misc/e-hinted-entry.c new file mode 100644 index 0000000000..ca75e85297 --- /dev/null +++ b/widgets/misc/e-hinted-entry.c @@ -0,0 +1,298 @@ +/* + * e-hinted-entry.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include "e-hinted-entry.h" + +#define E_HINTED_ENTRY_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_HINTED_ENTRY, EHintedEntryPrivate)) + +struct _EHintedEntryPrivate { + gchar *hint; + guint hint_shown : 1; +}; + +enum { + PROP_0, + PROP_HINT, + PROP_HINT_SHOWN +}; + +static gpointer parent_class; + +static void +hinted_entry_hide_hint (EHintedEntry *entry) +{ + gtk_entry_set_text (GTK_ENTRY (entry), ""); + + gtk_widget_modify_text (GTK_WIDGET (entry), GTK_STATE_NORMAL, NULL); + + entry->priv->hint_shown = FALSE; + + g_object_notify (G_OBJECT (entry), "hint-shown"); +} + +static void +hinted_entry_show_hint (EHintedEntry *entry) +{ + GtkStyle *style; + const GdkColor *color; + const gchar *hint; + + hint = e_hinted_entry_get_hint (entry); + gtk_entry_set_text (GTK_ENTRY (entry), hint); + + style = gtk_widget_get_style (GTK_WIDGET (entry)); + color = &style->text[GTK_STATE_INSENSITIVE]; + gtk_widget_modify_text (GTK_WIDGET (entry), GTK_STATE_NORMAL, color); + + entry->priv->hint_shown = TRUE; + + g_object_notify (G_OBJECT (entry), "hint-shown"); +} + +static void +hinted_entry_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_HINT: + e_hinted_entry_set_hint ( + E_HINTED_ENTRY (object), + g_value_get_string (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +hinted_entry_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_HINT: + g_value_set_string ( + value, e_hinted_entry_get_hint ( + E_HINTED_ENTRY (object))); + return; + + case PROP_HINT_SHOWN: + g_value_set_boolean ( + value, e_hinted_entry_get_hint_shown ( + E_HINTED_ENTRY (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +hinted_entry_finalize (GObject *object) +{ + EHintedEntryPrivate *priv; + + priv = E_HINTED_ENTRY_GET_PRIVATE (object); + + g_free (priv->hint); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static gboolean +hinted_entry_focus_in_event (GtkWidget *widget, + GdkEventFocus *event) +{ + EHintedEntry *entry = E_HINTED_ENTRY (widget); + + if (e_hinted_entry_get_hint_shown (entry)) + hinted_entry_hide_hint (entry); + + /* Chain up to parent's focus_in_event() method. */ + return GTK_WIDGET_CLASS (parent_class)-> + focus_in_event (widget, event); +} + +static gboolean +hinted_entry_focus_out_event (GtkWidget *widget, + GdkEventFocus *event) +{ + EHintedEntry *entry = E_HINTED_ENTRY (widget); + const gchar *text; + + text = e_hinted_entry_get_text (entry); + + if (text == NULL || *text == '\0') + hinted_entry_show_hint (E_HINTED_ENTRY (widget)); + + /* Chain up to parent's focus_out_event() method. */ + return GTK_WIDGET_CLASS (parent_class)-> + focus_out_event (widget, event); +} + +static void +hinted_entry_class_init (EHintedEntryClass *class) +{ + GObjectClass *object_class; + GtkWidgetClass *widget_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EHintedEntryPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = hinted_entry_set_property; + object_class->get_property = hinted_entry_get_property; + object_class->finalize = hinted_entry_finalize; + + widget_class = GTK_WIDGET_CLASS (class); + widget_class->focus_in_event = hinted_entry_focus_in_event; + widget_class->focus_out_event = hinted_entry_focus_out_event; + + g_object_class_install_property ( + object_class, + PROP_HINT, + g_param_spec_string ( + "hint", + "Hint", + NULL, + NULL, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_HINT_SHOWN, + g_param_spec_boolean ( + "hint-shown", + "Hint Shown", + NULL, + FALSE, + G_PARAM_READABLE)); +} + +static void +hinted_entry_init (EHintedEntry *entry) +{ + entry->priv = E_HINTED_ENTRY_GET_PRIVATE (entry); + entry->priv->hint = g_strdup (""); /* hint must never be NULL */ +} + +GType +e_hinted_entry_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (EHintedEntryClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) hinted_entry_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EHintedEntry), + 0, /* n_preallocs */ + (GInstanceInitFunc) hinted_entry_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + GTK_TYPE_ENTRY, "EHintedEntry", &type_info, 0); + } + + return type; +} + +GtkWidget * +e_hinted_entry_new (void) +{ + return g_object_new (E_TYPE_HINTED_ENTRY, NULL); +} + +const gchar * +e_hinted_entry_get_hint (EHintedEntry *entry) +{ + g_return_val_if_fail (E_IS_HINTED_ENTRY (entry), NULL); + + return entry->priv->hint; +} + +void +e_hinted_entry_set_hint (EHintedEntry *entry, + const gchar *hint) +{ + g_return_if_fail (E_IS_HINTED_ENTRY (entry)); + + if (hint == NULL) + hint = ""; + + g_free (entry->priv->hint); + entry->priv->hint = g_strdup (hint); + + if (e_hinted_entry_get_hint_shown (entry)) + gtk_entry_set_text (GTK_ENTRY (entry), hint); + + g_object_notify (G_OBJECT (entry), "hint"); +} + +gboolean +e_hinted_entry_get_hint_shown (EHintedEntry *entry) +{ + g_return_val_if_fail (E_IS_HINTED_ENTRY (entry), FALSE); + + return entry->priv->hint_shown; +} + +const gchar * +e_hinted_entry_get_text (EHintedEntry *entry) +{ + /* XXX This clumsily overrides gtk_entry_get_text(). */ + + g_return_val_if_fail (E_IS_HINTED_ENTRY (entry), NULL); + + if (e_hinted_entry_get_hint_shown (entry)) + return ""; + + return gtk_entry_get_text (GTK_ENTRY (entry)); +} + +void +e_hinted_entry_set_text (EHintedEntry *entry, + const gchar *text) +{ + /* XXX This clumsily overrides gtk_entry_set_text(). */ + + g_return_if_fail (E_IS_HINTED_ENTRY (entry)); + + if (text == NULL) + text = ""; + + if (*text == '\0' && !GTK_WIDGET_HAS_FOCUS (entry)) + hinted_entry_show_hint (entry); + else { + hinted_entry_hide_hint (entry); + gtk_entry_set_text (GTK_ENTRY (entry), text); + } +} diff --git a/widgets/misc/e-hinted-entry.h b/widgets/misc/e-hinted-entry.h new file mode 100644 index 0000000000..02379d4ad7 --- /dev/null +++ b/widgets/misc/e-hinted-entry.h @@ -0,0 +1,73 @@ +/* + * e-hinted-entry.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef E_HINTED_ENTRY_H +#define E_HINTED_ENTRY_H + +#include <gtk/gtk.h> + +/* Standard GObject macros */ +#define E_TYPE_HINTED_ENTRY \ + (e_hinted_entry_get_type ()) +#define E_HINTED_ENTRY(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_HINTED_ENTRY, EHintedEntry)) +#define E_HINTED_ENTRY_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_HINTED_ENTRY, EHintedEntryClass)) +#define E_IS_HINTED_ENTRY(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_HINTED_ENTRY)) +#define E_IS_HINTED_ENTRY_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_HINTED_ENTRY)) +#define E_HINTED_ENTRY_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_HINTED_ENTRY, EHintedEntryClass)) + +G_BEGIN_DECLS + +typedef struct _EHintedEntry EHintedEntry; +typedef struct _EHintedEntryClass EHintedEntryClass; +typedef struct _EHintedEntryPrivate EHintedEntryPrivate; + +struct _EHintedEntry { + GtkEntry parent; + EHintedEntryPrivate *priv; +}; + +struct _EHintedEntryClass { + GtkEntryClass parent_class; +}; + +GType e_hinted_entry_get_type (void); +GtkWidget * e_hinted_entry_new (void); +const gchar * e_hinted_entry_get_hint (EHintedEntry *entry); +void e_hinted_entry_set_hint (EHintedEntry *entry, + const gchar *hint); +gboolean e_hinted_entry_get_hint_shown (EHintedEntry *entry); +const gchar * e_hinted_entry_get_text (EHintedEntry *entry); +void e_hinted_entry_set_text (EHintedEntry *entry, + const gchar *text); + +G_END_DECLS + +#endif /* E_HINTED_ENTRY_H */ |