* src/modest-address-book.h:
[modest] / src / widgets / modest-recpt-editor.c
1 /* Copyright (c) 2007, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <config.h>
31
32 #include <glib/gi18n-lib.h>
33
34 #include <gtk/gtkscrolledwindow.h>
35 #include <gtk/gtktextview.h>
36 #include <gtk/gtkimage.h>
37 #include <gtk/gtkbutton.h>
38
39 #include <modest-text-utils.h>
40 #include <modest-recpt-editor.h>
41 #include <modest-scroll-text.h>
42 #include <pango/pango-attributes.h>
43 #include <string.h>
44
45 static GObjectClass *parent_class = NULL;
46
47 #define RECIPIENT_TAG_ID "recpt-id"
48
49 /* signals */
50 enum {
51         OPEN_ADDRESSBOOK_SIGNAL,
52         LAST_SIGNAL
53 };
54
55 typedef struct _ModestRecptEditorPrivate ModestRecptEditorPrivate;
56
57 struct _ModestRecptEditorPrivate
58 {
59         GtkWidget *text_view;
60         GtkWidget *abook_button;
61         GtkWidget *scrolled_window;
62         gchar *recipients;
63 };
64
65 #define MODEST_RECPT_EDITOR_GET_PRIVATE(o)      \
66         (G_TYPE_INSTANCE_GET_PRIVATE ((o), MODEST_TYPE_RECPT_EDITOR, ModestRecptEditorPrivate))
67
68 static guint signals[LAST_SIGNAL] = {0};
69
70 /* static functions: GObject */
71 static void modest_recpt_editor_instance_init (GTypeInstance *instance, gpointer g_class);
72 static void modest_recpt_editor_finalize (GObject *object);
73 static void modest_recpt_editor_class_init (ModestRecptEditorClass *klass);
74
75 /* widget events */
76 static void modest_recpt_editor_on_abook_clicked (GtkButton *button,
77                                                   ModestRecptEditor *editor);
78
79 /**
80  * modest_recpt_editor_new:
81  *
82  * Return value: a new #ModestRecptEditor instance implemented for Gtk+
83  **/
84 GtkWidget*
85 modest_recpt_editor_new (void)
86 {
87         ModestRecptEditor *self = g_object_new (MODEST_TYPE_RECPT_EDITOR, 
88                                                 "homogeneous", FALSE,
89                                                 "spacing", 1,
90                                                 NULL);
91
92         return GTK_WIDGET (self);
93 }
94
95 void
96 modest_recpt_editor_set_recipients (ModestRecptEditor *recpt_editor, const gchar *recipients)
97 {
98         ModestRecptEditorPrivate *priv;
99         GtkTextBuffer *buffer = NULL;
100
101         g_return_if_fail (MODEST_IS_RECPT_EDITOR (recpt_editor));
102         priv = MODEST_RECPT_EDITOR_GET_PRIVATE (recpt_editor);
103
104         buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->text_view));
105
106         gtk_text_buffer_set_text (buffer, recipients, -1);
107         if (GTK_WIDGET_REALIZED (recpt_editor))
108                 gtk_widget_queue_resize (GTK_WIDGET (recpt_editor));
109
110 }
111
112 void
113 modest_recpt_editor_add_recipients (ModestRecptEditor *recpt_editor, const gchar *recipients)
114 {
115         ModestRecptEditorPrivate *priv;
116         GtkTextBuffer *buffer = NULL;
117         GtkTextIter iter;
118         gchar * string_to_add;
119
120         g_return_if_fail (MODEST_IS_RECPT_EDITOR (recpt_editor));
121         priv = MODEST_RECPT_EDITOR_GET_PRIVATE (recpt_editor);
122
123         if (recipients == NULL)
124                 return;
125
126         buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->text_view));
127
128         if (gtk_text_buffer_get_char_count (buffer) > 0) {
129                 string_to_add = g_strconcat (";\n", recipients, NULL);
130         } else {
131                 string_to_add = g_strdup (recipients);
132         }
133
134         gtk_text_buffer_get_end_iter (buffer, &iter);
135
136         gtk_text_buffer_insert (buffer, &iter, recipients, -1);
137         if (GTK_WIDGET_REALIZED (recpt_editor))
138                 gtk_widget_queue_resize (GTK_WIDGET (recpt_editor));
139
140 }
141
142 void 
143 modest_recpt_editor_add_resolved_recipient (ModestRecptEditor *recpt_editor, GSList *email_list, const gchar * recipient_id)
144 {
145         ModestRecptEditorPrivate *priv;
146         GtkTextBuffer *buffer = NULL;
147         GtkTextIter start, end, iter;
148         GtkTextTag *tag = NULL;
149         gboolean is_first_recipient = TRUE;
150         GSList *node;
151       
152         g_return_if_fail (MODEST_IS_RECPT_EDITOR (recpt_editor));
153         priv = MODEST_RECPT_EDITOR_GET_PRIVATE (recpt_editor);
154
155         buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->text_view));
156
157         gtk_text_buffer_get_bounds (buffer, &start, &end);
158         if (!gtk_text_iter_equal (&start, &end))
159                 gtk_text_buffer_insert (buffer, &end, ";\n", -1);
160
161         gtk_text_buffer_get_end_iter (buffer, &iter);
162
163         tag = gtk_text_buffer_create_tag (buffer, NULL, 
164                                           "underline", PANGO_UNDERLINE_SINGLE,
165                                           "wrap-mode", GTK_WRAP_NONE,
166                                           "editable", TRUE, NULL);
167
168         g_object_set_data (G_OBJECT (tag), "recipient-tag-id", GINT_TO_POINTER (RECIPIENT_TAG_ID));
169         g_object_set_data_full (G_OBJECT (tag), "recipient-id", g_strdup (recipient_id), (GDestroyNotify) g_free);
170
171         for (node = email_list; node != NULL; node = g_slist_next (node)) {
172                 gchar *recipient = (gchar *) email_list->data;
173
174                 if ((recipient) && (strlen (recipient) != 0)) {
175
176                         if (!is_first_recipient) {
177                                 gtk_text_buffer_insert (buffer, &iter, ";\n", -1);
178                         } else {
179                                 is_first_recipient = FALSE;
180                         }
181
182                         gtk_text_buffer_insert_with_tags (buffer, &iter, recipient, -1, tag, NULL);
183                 }
184         }
185
186 }
187
188
189 const gchar *
190 modest_recpt_editor_get_recipients (ModestRecptEditor *recpt_editor)
191 {
192         ModestRecptEditorPrivate *priv;
193         GtkTextBuffer *buffer = NULL;
194         GtkTextIter start, end;
195         gchar *c;
196
197         g_return_val_if_fail (MODEST_IS_RECPT_EDITOR (recpt_editor), NULL);
198         priv = MODEST_RECPT_EDITOR_GET_PRIVATE (recpt_editor);
199
200         if (priv->recipients != NULL) {
201                 g_free (priv->recipients);
202                 priv->recipients = NULL;
203         }
204
205         buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->text_view));
206
207         gtk_text_buffer_get_start_iter (buffer, &start);
208         gtk_text_buffer_get_end_iter (buffer, &end);
209
210         priv->recipients = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
211         for (c = priv->recipients; *c == '\0'; c++) {
212                 if (*c == '\n')
213                         *c = ' ';
214         }
215
216         return priv->recipients;
217
218 }
219
220 static void
221 modest_recpt_editor_instance_init (GTypeInstance *instance, gpointer g_class)
222 {
223         ModestRecptEditorPrivate *priv;
224         GtkWidget *abook_icon;
225
226         priv = MODEST_RECPT_EDITOR_GET_PRIVATE (instance);
227
228         priv->abook_button = gtk_button_new ();
229         gtk_button_set_relief (GTK_BUTTON (priv->abook_button), GTK_RELIEF_NONE);
230         gtk_button_set_focus_on_click (GTK_BUTTON (priv->abook_button), FALSE);
231         gtk_button_set_alignment (GTK_BUTTON (priv->abook_button), 1.0, 1.0);
232         abook_icon = gtk_image_new_from_icon_name ("qgn_list_gene_contacts", GTK_ICON_SIZE_BUTTON);
233         gtk_container_add (GTK_CONTAINER (priv->abook_button), abook_icon);
234
235         priv->text_view = gtk_text_view_new ();
236         priv->scrolled_window = modest_scroll_text_new (GTK_TEXT_VIEW (priv->text_view), 5);
237         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scrolled_window), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
238         gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scrolled_window), GTK_SHADOW_IN);
239 /*      gtk_container_add (GTK_CONTAINER (priv->scrolled_window), priv->text_view); */
240
241         gtk_box_pack_start (GTK_BOX (instance), priv->scrolled_window, TRUE, TRUE, 0);
242 /*      gtk_box_pack_start (GTK_BOX (instance), priv->text_view, TRUE, TRUE, 0); */
243         gtk_box_pack_end (GTK_BOX (instance), priv->abook_button, FALSE, FALSE, 0);
244
245         gtk_text_view_set_accepts_tab (GTK_TEXT_VIEW (priv->text_view), FALSE);
246         gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (priv->text_view), TRUE);
247         gtk_text_view_set_editable (GTK_TEXT_VIEW (priv->text_view), TRUE);
248
249         gtk_text_view_set_justification (GTK_TEXT_VIEW (priv->text_view), GTK_JUSTIFY_LEFT);
250         gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->text_view), GTK_WRAP_CHAR);
251
252         gtk_widget_set_size_request (priv->text_view, 75, -1);
253
254         g_signal_connect (G_OBJECT (priv->abook_button), "clicked", G_CALLBACK (modest_recpt_editor_on_abook_clicked), instance);
255
256         return;
257 }
258
259 void
260 modest_recpt_editor_set_field_size_group (ModestRecptEditor *recpt_editor, GtkSizeGroup *size_group)
261 {
262         ModestRecptEditorPrivate *priv;
263
264         g_return_if_fail (MODEST_IS_RECPT_EDITOR (recpt_editor));
265         g_return_if_fail (GTK_IS_SIZE_GROUP (size_group));
266         priv = MODEST_RECPT_EDITOR_GET_PRIVATE (recpt_editor);
267
268         gtk_size_group_add_widget (size_group, priv->scrolled_window);
269 }
270
271 static void
272 modest_recpt_editor_on_abook_clicked (GtkButton *button, ModestRecptEditor *editor)
273 {
274         g_return_if_fail (MODEST_IS_RECPT_EDITOR (editor));
275
276         g_signal_emit_by_name (G_OBJECT (editor), "open-addressbook");
277 }
278
279 static void
280 modest_recpt_editor_finalize (GObject *object)
281 {
282         (*parent_class->finalize) (object);
283
284         return;
285 }
286
287 static void 
288 modest_recpt_editor_class_init (ModestRecptEditorClass *klass)
289 {
290         GObjectClass *object_class;
291         GtkWidgetClass *widget_class;
292
293         parent_class = g_type_class_peek_parent (klass);
294         object_class = (GObjectClass*) klass;
295         widget_class = GTK_WIDGET_CLASS (klass);
296
297         object_class->finalize = modest_recpt_editor_finalize;
298
299         g_type_class_add_private (object_class, sizeof (ModestRecptEditorPrivate));
300
301         signals[OPEN_ADDRESSBOOK_SIGNAL] = 
302                 g_signal_new ("open-addressbook",
303                               G_TYPE_FROM_CLASS (object_class),
304                               G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
305                               G_STRUCT_OFFSET (ModestRecptEditorClass, open_addressbook),
306                               NULL, NULL,
307                               g_cclosure_marshal_VOID__VOID,
308                               G_TYPE_NONE, 0);
309
310         return;
311 }
312
313 GType 
314 modest_recpt_editor_get_type (void)
315 {
316         static GType type = 0;
317
318         if (G_UNLIKELY(type == 0))
319         {
320                 static const GTypeInfo info = 
321                 {
322                   sizeof (ModestRecptEditorClass),
323                   NULL,   /* base_init */
324                   NULL,   /* base_finalize */
325                   (GClassInitFunc) modest_recpt_editor_class_init,   /* class_init */
326                   NULL,   /* class_finalize */
327                   NULL,   /* class_data */
328                   sizeof (ModestRecptEditor),
329                   0,      /* n_preallocs */
330                   modest_recpt_editor_instance_init    /* instance_init */
331                 };
332
333                 type = g_type_register_static (GTK_TYPE_HBOX,
334                         "ModestRecptEditor",
335                         &info, 0);
336
337         }
338
339         return type;
340 }