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