1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * Copyright (C) 2013 Intel Corporation
4 *
5 * This library is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation.
8 *
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
12 * for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this library. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Authors: Tristan Van Berkom <tristanvb@openismus.com>
18 */
19
20 #include <libebook/libebook.h>
21
22 #include "cursor-search.h"
23
24 /* GObjectClass */
25 static void cursor_search_finalize (GObject *object);
26 static void cursor_search_get_property (GObject *object,
27 guint property_id,
28 GValue *value,
29 GParamSpec *pspec);
30
31 /* UI Callbacks */
32 static void cursor_search_option_toggled (CursorSearch *search,
33 GtkWidget *item);
34 static void cursor_search_entry_changed (CursorSearch *search,
35 GtkEditable *entry);
36 static void cursor_search_icon_press (CursorSearch *search,
37 GtkEntryIconPosition icon_pos,
38 GdkEvent *event,
39 GtkEntry *entry);
40
41 typedef enum {
42 SEARCH_NAME,
43 SEARCH_PHONE,
44 SEARCH_EMAIL
45 } SearchType;
46
47 struct _CursorSearchPrivate {
48 GtkWidget *popup;
49 GtkWidget *name_radio;
50 GtkWidget *phone_radio;
51 GtkWidget *email_radio;
52
53 SearchType type;
54 gchar *sexp;
55 };
56
57 enum {
58 PROP_0,
59 PROP_SEXP,
60 };
61
62 G_DEFINE_TYPE_WITH_PRIVATE (CursorSearch, cursor_search, GTK_TYPE_SEARCH_ENTRY);
63
64 /************************************************************************
65 * GObjectClass *
66 ************************************************************************/
67 static void
cursor_search_class_init(CursorSearchClass * klass)68 cursor_search_class_init (CursorSearchClass *klass)
69 {
70 GObjectClass *object_class;
71 GtkWidgetClass *widget_class;
72
73 object_class = G_OBJECT_CLASS (klass);
74 object_class->finalize = cursor_search_finalize;
75 object_class->get_property = cursor_search_get_property;
76
77 g_object_class_install_property (
78 object_class,
79 PROP_SEXP,
80 g_param_spec_string (
81 "sexp",
82 "Search Expression",
83 "The active search expression",
84 NULL,
85 G_PARAM_READABLE |
86 G_PARAM_STATIC_STRINGS));
87
88 /* Bind to template */
89 widget_class = GTK_WIDGET_CLASS (klass);
90 gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/evolution/cursor-example/cursor-search.ui");
91 gtk_widget_class_bind_template_child_private (widget_class, CursorSearch, popup);
92 gtk_widget_class_bind_template_child_private (widget_class, CursorSearch, name_radio);
93 gtk_widget_class_bind_template_child_private (widget_class, CursorSearch, phone_radio);
94 gtk_widget_class_bind_template_child_private (widget_class, CursorSearch, email_radio);
95 gtk_widget_class_bind_template_callback (widget_class, cursor_search_option_toggled);
96 gtk_widget_class_bind_template_callback (widget_class, cursor_search_entry_changed);
97 gtk_widget_class_bind_template_callback (widget_class, cursor_search_icon_press);
98 }
99
100 static void
cursor_search_init(CursorSearch * search)101 cursor_search_init (CursorSearch *search)
102 {
103 search->priv = cursor_search_get_instance_private (search);
104
105 gtk_widget_init_template (GTK_WIDGET (search));
106
107 g_object_set (
108 search,
109 "primary-icon-activatable", TRUE,
110 "primary-icon-sensitive", TRUE,
111 NULL);
112 }
113
114 static void
cursor_search_finalize(GObject * object)115 cursor_search_finalize (GObject *object)
116 {
117 CursorSearch *search = CURSOR_SEARCH (object);
118 CursorSearchPrivate *priv = search->priv;
119
120 g_free (priv->sexp);
121
122 G_OBJECT_CLASS (cursor_search_parent_class)->finalize (object);
123 }
124
125 static void
cursor_search_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)126 cursor_search_get_property (GObject *object,
127 guint property_id,
128 GValue *value,
129 GParamSpec *pspec)
130 {
131 CursorSearch *search = CURSOR_SEARCH (object);
132 CursorSearchPrivate *priv = search->priv;
133
134 switch (property_id) {
135 case PROP_SEXP:
136 g_value_set_string (value, priv->sexp);
137 break;
138
139 default:
140 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
141 break;
142
143 }
144 }
145
146 /************************************************************************
147 * UI Callbacks *
148 ************************************************************************/
149 static void
cursor_search_option_toggled(CursorSearch * search,GtkWidget * item)150 cursor_search_option_toggled (CursorSearch *search,
151 GtkWidget *item)
152 {
153 CursorSearchPrivate *priv = search->priv;
154
155 if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (item))) {
156
157 if (item == priv->name_radio)
158 priv->type = SEARCH_NAME;
159 else if (item == priv->phone_radio)
160 priv->type = SEARCH_PHONE;
161 else if (item == priv->email_radio)
162 priv->type = SEARCH_EMAIL;
163
164 /* Refresh the search */
165 cursor_search_entry_changed (search, NULL);
166 }
167 }
168
169 static void
cursor_search_entry_changed(CursorSearch * search,GtkEditable * entry)170 cursor_search_entry_changed (CursorSearch *search,
171 GtkEditable *entry)
172 {
173 CursorSearchPrivate *priv = search->priv;
174 EBookQuery *query = NULL;
175 const gchar *text;
176
177 text = gtk_entry_get_text (GTK_ENTRY (search));
178
179 if (text && text[0]) {
180 switch (priv->type) {
181 case SEARCH_NAME:
182 query = e_book_query_orv (
183 e_book_query_field_test (E_CONTACT_FAMILY_NAME,
184 E_BOOK_QUERY_CONTAINS,
185 text),
186 e_book_query_field_test (E_CONTACT_GIVEN_NAME,
187 E_BOOK_QUERY_CONTAINS,
188 text),
189 NULL);
190 break;
191 case SEARCH_PHONE:
192 query = e_book_query_field_test (
193 E_CONTACT_TEL,
194 E_BOOK_QUERY_CONTAINS,
195 text);
196 break;
197 case SEARCH_EMAIL:
198 query = e_book_query_field_test (
199 E_CONTACT_EMAIL,
200 E_BOOK_QUERY_CONTAINS,
201 text);
202 break;
203 }
204 }
205
206 g_free (priv->sexp);
207
208 if (query) {
209 priv->sexp = e_book_query_to_string (query);
210 e_book_query_unref (query);
211 } else
212 priv->sexp = g_strdup ("");
213
214 g_object_notify (G_OBJECT (search), "sexp");
215 }
216
217 static void
cursor_search_icon_press(CursorSearch * search,GtkEntryIconPosition icon_pos,GdkEvent * event,GtkEntry * entry)218 cursor_search_icon_press (CursorSearch *search,
219 GtkEntryIconPosition icon_pos,
220 GdkEvent *event,
221 GtkEntry *entry)
222 {
223 CursorSearchPrivate *priv = search->priv;
224 GdkEventButton *button_event = (GdkEventButton *) event;
225
226 if (icon_pos == GTK_ENTRY_ICON_PRIMARY)
227 gtk_menu_popup (
228 GTK_MENU (priv->popup),
229 NULL, NULL, NULL, NULL,
230 button_event->button,
231 button_event->time);
232 }
233
234 /************************************************************************
235 * API *
236 ************************************************************************/
237 GtkWidget *
cursor_search_new(void)238 cursor_search_new (void)
239 {
240 return (GtkWidget *) g_object_new (CURSOR_TYPE_SEARCH, NULL);
241 }
242
243 const gchar *
cursor_search_get_sexp(CursorSearch * search)244 cursor_search_get_sexp (CursorSearch *search)
245 {
246 CursorSearchPrivate *priv;
247
248 g_return_val_if_fail (CURSOR_IS_SEARCH (search), NULL);
249
250 priv = search->priv;
251
252 return priv->sexp;
253 }
254