1 /*
2 *
3 * This program is free software; you can redistribute it and/or modify it
4 * under the terms of the GNU Lesser General Public License as published by
5 * the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful, but
8 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
9 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
10 * for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public License
13 * along with this program; if not, see <http://www.gnu.org/licenses/>.
14 *
15 *
16 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
17 *
18 */
19
20 #include "evolution-config.h"
21
22 #include "e-msg-composer.h"
23 #include "e-composer-name-header.h"
24
25 #include <glib/gi18n.h>
26
27 /* XXX Temporary kludge */
28 #include "addressbook/gui/contact-editor/e-contact-editor.h"
29 #include "addressbook/gui/contact-list-editor/e-contact-list-editor.h"
30
31 #define E_COMPOSER_NAME_HEADER_GET_PRIVATE(obj) \
32 (G_TYPE_INSTANCE_GET_PRIVATE \
33 ((obj), E_TYPE_COMPOSER_NAME_HEADER, EComposerNameHeaderPrivate))
34
35 /* Convenience macro */
36 #define E_COMPOSER_NAME_HEADER_GET_ENTRY(header) \
37 (E_NAME_SELECTOR_ENTRY (E_COMPOSER_HEADER (header)->input_widget))
38
39 enum {
40 PROP_0,
41 PROP_NAME_SELECTOR
42 };
43
44 struct _EComposerNameHeaderPrivate {
45 ENameSelector *name_selector;
46 guint destination_index;
47 };
48
G_DEFINE_TYPE(EComposerNameHeader,e_composer_name_header,E_TYPE_COMPOSER_HEADER)49 G_DEFINE_TYPE (
50 EComposerNameHeader,
51 e_composer_name_header,
52 E_TYPE_COMPOSER_HEADER)
53
54 static gpointer
55 contact_editor_fudge_new (EBookClient *book_client,
56 EContact *contact,
57 gboolean is_new,
58 gboolean editable)
59 {
60 EABEditor *editor;
61 EShell *shell = e_shell_get_default ();
62
63 /* XXX Putting this function signature in libedataserverui
64 * was a terrible idea. Now we're stuck with it. */
65
66 editor = e_contact_editor_new (shell, book_client, contact, is_new, editable);
67 eab_editor_show (editor);
68
69 return editor;
70 }
71
72 static gpointer
contact_list_editor_fudge_new(EBookClient * book_client,EContact * contact,gboolean is_new,gboolean editable)73 contact_list_editor_fudge_new (EBookClient *book_client,
74 EContact *contact,
75 gboolean is_new,
76 gboolean editable)
77 {
78 EABEditor *editor;
79 EShell *shell = e_shell_get_default ();
80
81 /* XXX Putting this function signature in libedataserverui
82 * was a terrible idea. Now we're stuck with it. */
83
84 editor = e_contact_list_editor_new (shell, book_client, contact, is_new, editable);
85 eab_editor_show (editor);
86
87 return editor;
88 }
89
90 static void
composer_name_header_entry_changed_cb(ENameSelectorEntry * entry,EComposerNameHeader * header)91 composer_name_header_entry_changed_cb (ENameSelectorEntry *entry,
92 EComposerNameHeader *header)
93 {
94 g_signal_emit_by_name (header, "changed");
95 }
96
97 static gboolean
composer_name_header_entry_query_tooltip_cb(GtkEntry * entry,gint x,gint y,gboolean keyboard_mode,GtkTooltip * tooltip)98 composer_name_header_entry_query_tooltip_cb (GtkEntry *entry,
99 gint x,
100 gint y,
101 gboolean keyboard_mode,
102 GtkTooltip *tooltip)
103 {
104 const gchar *text;
105
106 text = gtk_entry_get_text (entry);
107
108 if (keyboard_mode || text == NULL || *text == '\0')
109 return FALSE;
110
111 gtk_tooltip_set_text (tooltip, text);
112
113 return TRUE;
114 }
115
116 static void
composer_name_header_visible_changed_cb(EComposerNameHeader * header)117 composer_name_header_visible_changed_cb (EComposerNameHeader *header)
118 {
119 const gchar *label;
120 EComposerNameHeaderPrivate *priv;
121 ENameSelectorDialog *dialog;
122
123 priv = E_COMPOSER_NAME_HEADER_GET_PRIVATE (header);
124 label = e_composer_header_get_label (E_COMPOSER_HEADER (header));
125 dialog = e_name_selector_peek_dialog (priv->name_selector);
126
127 e_name_selector_dialog_set_section_visible (
128 dialog, label,
129 e_composer_header_get_visible (E_COMPOSER_HEADER (header)));
130 }
131
132 static void
composer_name_header_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)133 composer_name_header_set_property (GObject *object,
134 guint property_id,
135 const GValue *value,
136 GParamSpec *pspec)
137 {
138 EComposerNameHeaderPrivate *priv;
139
140 priv = E_COMPOSER_NAME_HEADER_GET_PRIVATE (object);
141
142 switch (property_id) {
143 case PROP_NAME_SELECTOR: /* construct only */
144 g_return_if_fail (priv->name_selector == NULL);
145 priv->name_selector = g_value_dup_object (value);
146 return;
147 }
148
149 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
150 }
151
152 static void
composer_name_header_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)153 composer_name_header_get_property (GObject *object,
154 guint property_id,
155 GValue *value,
156 GParamSpec *pspec)
157 {
158 switch (property_id) {
159 case PROP_NAME_SELECTOR: /* construct only */
160 g_value_set_object (
161 value,
162 e_composer_name_header_get_name_selector (
163 E_COMPOSER_NAME_HEADER (object)));
164 return;
165 }
166
167 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
168 }
169
170 static void
composer_name_header_dispose(GObject * object)171 composer_name_header_dispose (GObject *object)
172 {
173 EComposerNameHeaderPrivate *priv;
174
175 priv = E_COMPOSER_NAME_HEADER_GET_PRIVATE (object);
176 g_clear_object (&priv->name_selector);
177
178 /* Chain up to parent's dispose() method. */
179 G_OBJECT_CLASS (e_composer_name_header_parent_class)->dispose (object);
180 }
181
182 static void
composer_name_header_constructed(GObject * object)183 composer_name_header_constructed (GObject *object)
184 {
185 EComposerNameHeaderPrivate *priv;
186 ENameSelectorModel *model;
187 ENameSelectorEntry *entry;
188 GList *sections;
189 const gchar *label;
190
191 /* Input widget must be set before chaining up. */
192
193 priv = E_COMPOSER_NAME_HEADER_GET_PRIVATE (object);
194 g_return_if_fail (E_IS_NAME_SELECTOR (priv->name_selector));
195
196 model = e_name_selector_peek_model (priv->name_selector);
197 label = e_composer_header_get_label (E_COMPOSER_HEADER (object));
198 g_return_if_fail (label != NULL);
199
200 sections = e_name_selector_model_list_sections (model);
201 priv->destination_index = g_list_length (sections);
202 e_name_selector_model_add_section (model, label, label, NULL);
203 g_list_foreach (sections, (GFunc) g_free, NULL);
204 g_list_free (sections);
205
206 entry = E_NAME_SELECTOR_ENTRY (
207 e_name_selector_peek_section_list (
208 priv->name_selector, label));
209
210 e_name_selector_entry_set_contact_editor_func (
211 entry, contact_editor_fudge_new);
212 e_name_selector_entry_set_contact_list_editor_func (
213 entry, contact_list_editor_fudge_new);
214
215 g_signal_connect (
216 entry, "changed",
217 G_CALLBACK (composer_name_header_entry_changed_cb), object);
218 g_signal_connect (
219 entry, "query-tooltip",
220 G_CALLBACK (composer_name_header_entry_query_tooltip_cb),
221 NULL);
222 E_COMPOSER_HEADER (object)->input_widget = GTK_WIDGET (g_object_ref_sink (entry));
223
224 e_signal_connect_notify_swapped (
225 object, "notify::visible",
226 G_CALLBACK (composer_name_header_visible_changed_cb), object);
227
228 /* Chain up to parent's constructed() method. */
229 G_OBJECT_CLASS (e_composer_name_header_parent_class)->constructed (object);
230
231 e_composer_header_set_title_tooltip (
232 E_COMPOSER_HEADER (object),
233 _("Click here for the address book"));
234 }
235
236 static void
composer_name_header_clicked(EComposerHeader * header)237 composer_name_header_clicked (EComposerHeader *header)
238 {
239 EComposerNameHeaderPrivate *priv;
240 ENameSelectorDialog *dialog;
241
242 priv = E_COMPOSER_NAME_HEADER_GET_PRIVATE (header);
243
244 dialog = e_name_selector_peek_dialog (priv->name_selector);
245 e_name_selector_dialog_set_destination_index (
246 dialog, priv->destination_index);
247 e_name_selector_show_dialog (
248 priv->name_selector, header->title_widget);
249 gtk_dialog_run (GTK_DIALOG (dialog));
250 gtk_widget_hide (GTK_WIDGET (dialog));
251 }
252
253 static void
e_composer_name_header_class_init(EComposerNameHeaderClass * class)254 e_composer_name_header_class_init (EComposerNameHeaderClass *class)
255 {
256 GObjectClass *object_class;
257 EComposerHeaderClass *header_class;
258
259 g_type_class_add_private (class, sizeof (EComposerNameHeaderPrivate));
260
261 object_class = G_OBJECT_CLASS (class);
262 object_class->set_property = composer_name_header_set_property;
263 object_class->get_property = composer_name_header_get_property;
264 object_class->dispose = composer_name_header_dispose;
265 object_class->constructed = composer_name_header_constructed;
266
267 header_class = E_COMPOSER_HEADER_CLASS (class);
268 header_class->clicked = composer_name_header_clicked;
269
270 g_object_class_install_property (
271 object_class,
272 PROP_NAME_SELECTOR,
273 g_param_spec_object (
274 "name-selector",
275 NULL,
276 NULL,
277 E_TYPE_NAME_SELECTOR,
278 G_PARAM_READWRITE |
279 G_PARAM_CONSTRUCT_ONLY));
280 }
281
282 static void
e_composer_name_header_init(EComposerNameHeader * header)283 e_composer_name_header_init (EComposerNameHeader *header)
284 {
285 header->priv = E_COMPOSER_NAME_HEADER_GET_PRIVATE (header);
286 }
287
288 EComposerHeader *
e_composer_name_header_new(ESourceRegistry * registry,const gchar * label,ENameSelector * name_selector)289 e_composer_name_header_new (ESourceRegistry *registry,
290 const gchar *label,
291 ENameSelector *name_selector)
292 {
293 g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
294 g_return_val_if_fail (E_IS_NAME_SELECTOR (name_selector), NULL);
295
296 return g_object_new (
297 E_TYPE_COMPOSER_NAME_HEADER,
298 "label", label, "button", TRUE,
299 "name-selector", name_selector,
300 "registry", registry, NULL);
301 }
302
303 ENameSelector *
e_composer_name_header_get_name_selector(EComposerNameHeader * header)304 e_composer_name_header_get_name_selector (EComposerNameHeader *header)
305 {
306 g_return_val_if_fail (E_IS_COMPOSER_NAME_HEADER (header), NULL);
307
308 return header->priv->name_selector;
309 }
310
311 EDestination **
e_composer_name_header_get_destinations(EComposerNameHeader * header)312 e_composer_name_header_get_destinations (EComposerNameHeader *header)
313 {
314 EDestinationStore *store;
315 EDestination **destinations;
316 ENameSelectorEntry *entry;
317 GList *list, *iter;
318 gint ii = 0;
319
320 g_return_val_if_fail (E_IS_COMPOSER_NAME_HEADER (header), NULL);
321
322 entry = E_COMPOSER_NAME_HEADER_GET_ENTRY (header);
323 store = e_name_selector_entry_peek_destination_store (entry);
324
325 list = e_destination_store_list_destinations (store);
326 destinations = g_new0 (EDestination *, g_list_length (list) + 1);
327
328 for (iter = list; iter != NULL; iter = iter->next)
329 destinations[ii++] = g_object_ref (iter->data);
330
331 g_list_free (list);
332
333 /* free with e_destination_freev() */
334 return destinations;
335 }
336
337 void
e_composer_name_header_add_destinations(EComposerNameHeader * header,EDestination ** destinations)338 e_composer_name_header_add_destinations (EComposerNameHeader *header,
339 EDestination **destinations)
340 {
341 EDestinationStore *store;
342 ENameSelectorEntry *entry;
343 gint ii;
344
345 g_return_if_fail (E_IS_COMPOSER_NAME_HEADER (header));
346
347 entry = E_COMPOSER_NAME_HEADER_GET_ENTRY (header);
348 store = e_name_selector_entry_peek_destination_store (entry);
349
350 if (destinations == NULL)
351 return;
352
353 for (ii = 0; destinations[ii] != NULL; ii++)
354 e_destination_store_append_destination (
355 store, destinations[ii]);
356 }
357
358 void
e_composer_name_header_set_destinations(EComposerNameHeader * header,EDestination ** destinations)359 e_composer_name_header_set_destinations (EComposerNameHeader *header,
360 EDestination **destinations)
361 {
362 EDestinationStore *store;
363 ENameSelectorEntry *entry;
364 GList *list, *iter;
365
366 g_return_if_fail (E_IS_COMPOSER_NAME_HEADER (header));
367
368 entry = E_COMPOSER_NAME_HEADER_GET_ENTRY (header);
369 store = e_name_selector_entry_peek_destination_store (entry);
370
371 /* Clear the destination store. */
372 list = e_destination_store_list_destinations (store);
373 for (iter = list; iter != NULL; iter = iter->next)
374 e_destination_store_remove_destination (store, iter->data);
375 g_list_free (list);
376
377 e_composer_name_header_add_destinations (header, destinations);
378 }
379