Modified webpage: now tinymail repository is in gitorious.
[modest] / src / widgets / modest-signature-editor-dialog.c
1 /* Copyright (c) 2006, 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 "modest-signature-editor-dialog.h"
31 #include "widgets/modest-ui-constants.h"
32 #include "widgets/modest-validating-entry.h"
33 #include "modest-runtime.h"
34 #include <modest-account-mgr-helpers.h>
35 #include <gtk/gtkhbox.h>
36 #include <gtk/gtkvbox.h>
37 #include <gtk/gtktextview.h>
38 #include <gtk/gtklabel.h>
39 #include <modest-scrollable.h>
40 #include <modest-toolkit-factory.h>
41 #include <gtk/gtkstock.h>
42 #include <glib/gi18n.h>
43 #include "modest-text-utils.h"
44 #ifdef MODEST_TOOLKIT_HILDON2
45 #include <hildon/hildon.h>
46 #endif
47
48 G_DEFINE_TYPE (ModestSignatureEditorDialog, modest_signature_editor_dialog, GTK_TYPE_DIALOG);
49
50 #define SIGNATURE_EDITOR_DIALOG_GET_PRIVATE(o) \
51         (G_TYPE_INSTANCE_GET_PRIVATE ((o), MODEST_TYPE_SIGNATURE_EDITOR_DIALOG, ModestSignatureEditorDialogPrivate))
52
53 typedef struct _ModestSignatureEditorDialogPrivate ModestSignatureEditorDialogPrivate;
54
55 struct _ModestSignatureEditorDialogPrivate
56 {
57         GtkWidget *checkbox_use;
58         GtkWidget *label;
59         GtkWidget *scrollable;
60         GtkWidget *textview;
61
62         guint correct_scroll_idle;
63 };
64
65 static void text_buffer_end_user_action (GtkTextBuffer *buffer,
66                                          ModestSignatureEditorDialog *userdata);
67
68 static void
69 modest_signature_editor_dialog_get_property (GObject *object, guint property_id,
70                                                                                                                         GValue *value, GParamSpec *pspec)
71 {
72         switch (property_id) {
73         default:
74                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
75         }
76 }
77
78 static void
79 modest_signature_editor_dialog_set_property (GObject *object, guint property_id,
80                                                                                                                         const GValue *value, GParamSpec *pspec)
81 {
82         switch (property_id) {
83         default:
84                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
85         }
86 }
87
88 static void
89 modest_signature_editor_dialog_dispose (GObject *object)
90 {
91         if (G_OBJECT_CLASS (modest_signature_editor_dialog_parent_class)->dispose)
92                 G_OBJECT_CLASS (modest_signature_editor_dialog_parent_class)->dispose (object);
93 }
94
95 static void
96 modest_signature_editor_dialog_finalize (GObject *object)
97 {
98         ModestSignatureEditorDialogPrivate *priv;
99
100         priv = SIGNATURE_EDITOR_DIALOG_GET_PRIVATE (object);
101
102         if (priv->correct_scroll_idle > 0) {
103                 g_source_remove (priv->correct_scroll_idle);
104                 priv->correct_scroll_idle = 0;
105         }
106         G_OBJECT_CLASS (modest_signature_editor_dialog_parent_class)->finalize (object);
107 }
108
109 static void
110 modest_signature_editor_dialog_class_init (ModestSignatureEditorDialogClass *klass)
111 {
112         GObjectClass *object_class = G_OBJECT_CLASS (klass);
113
114         g_type_class_add_private (klass, sizeof (ModestSignatureEditorDialogPrivate));
115
116         object_class->get_property = modest_signature_editor_dialog_get_property;
117         object_class->set_property = modest_signature_editor_dialog_set_property;
118         object_class->dispose = modest_signature_editor_dialog_dispose;
119         object_class->finalize = modest_signature_editor_dialog_finalize;
120 }
121
122 static void
123 enable_widgets (ModestSignatureEditorDialog *self)
124 {
125         ModestSignatureEditorDialogPrivate *priv = 
126                 SIGNATURE_EDITOR_DIALOG_GET_PRIVATE (self);
127                 
128         const gboolean enable = modest_togglable_get_active (priv->checkbox_use);
129         gtk_widget_set_sensitive (priv->label, enable);
130         gtk_widget_set_sensitive (priv->textview, enable);
131         gtk_text_view_set_editable (GTK_TEXT_VIEW (priv->textview), enable);
132 }
133
134 static void
135 on_toggle_button_changed (GtkWidget *togglebutton, gpointer user_data)
136 {
137         ModestSignatureEditorDialog *self = MODEST_SIGNATURE_EDITOR_DIALOG (user_data);
138         enable_widgets (self);
139 }
140
141 static void
142 modest_signature_editor_dialog_init (ModestSignatureEditorDialog *self)
143 {
144         ModestSignatureEditorDialogPrivate *priv = 
145                 SIGNATURE_EDITOR_DIALOG_GET_PRIVATE (self);
146         GtkWidget *top_box, *align;
147         
148         gtk_window_set_title (GTK_WINDOW (self), _("mcen_ti_email_signatures_edit_title"));
149                 
150         GtkWidget *box = GTK_DIALOG(self)->vbox; /* gtk_vbox_new (FALSE, MODEST_MARGIN_HALF); */
151         top_box = gtk_vbox_new (FALSE, 0);
152
153         priv->checkbox_use = modest_toolkit_factory_create_check_button (modest_runtime_get_toolkit_factory (),
154                                                                          _("mcen_fi_email_signatures_use_signature"));
155         gtk_box_pack_start (GTK_BOX (top_box), priv->checkbox_use, FALSE, FALSE, 0);
156         gtk_widget_show (priv->checkbox_use);
157         
158         g_signal_connect (G_OBJECT (priv->checkbox_use), "toggled",
159                           G_CALLBACK (on_toggle_button_changed), self);         
160         
161         priv->label = gtk_label_new (""); /* Set in modest_signature_editor_dialog_set_settings(). */
162         gtk_misc_set_alignment (GTK_MISC (priv->label), 0.0, 0.0);
163         gtk_misc_set_padding (GTK_MISC (priv->label), MODEST_MARGIN_DOUBLE, MODEST_MARGIN_DOUBLE);
164         gtk_box_pack_start (GTK_BOX (top_box), priv->label, FALSE, FALSE, 0);
165         gtk_widget_show (priv->label);
166         
167         priv->textview = modest_toolkit_factory_create_text_view (modest_runtime_get_toolkit_factory ());
168         gtk_widget_show (priv->textview);
169         GtkTextBuffer *buffer = modest_text_view_get_buffer (priv->textview);
170         gtk_text_buffer_set_text (buffer, _("mcen_va_default_signature_tablet"), -1); /* Default, as per the UI spec. */
171         gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->textview), GTK_WRAP_WORD_CHAR);
172         gtk_box_pack_start (GTK_BOX (top_box), priv->textview, TRUE, TRUE, 0);
173
174         g_signal_connect (G_OBJECT (buffer), "end-user-action",
175                           G_CALLBACK (text_buffer_end_user_action), self);
176
177 #ifndef MODEST_TOOLKIT_HILDON2
178         gtk_dialog_add_button (GTK_DIALOG (self), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
179 #endif
180         
181         /* Add the buttons: */
182         gtk_dialog_add_button (GTK_DIALOG (self), _HL_SAVE, GTK_RESPONSE_OK);
183
184         align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
185         gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, MODEST_MARGIN_DOUBLE, 0);
186         gtk_widget_show (align);
187         gtk_container_add (GTK_CONTAINER (align), top_box);
188         
189         gtk_widget_show (top_box);
190
191         priv->scrollable = modest_toolkit_factory_create_scrollable (modest_runtime_get_toolkit_factory ());
192         modest_scrollable_add_with_viewport (MODEST_SCROLLABLE (priv->scrollable), align);
193         gtk_container_add (GTK_CONTAINER (GTK_DIALOG (self)->vbox), priv->scrollable);
194         gtk_widget_show (priv->scrollable);             
195
196         gtk_widget_show (box);
197         gtk_widget_set_size_request (GTK_WIDGET (self), 
198 #ifdef MODEST_TOOLKIT_HILDON2
199                                      -1,
200 #else
201                                      MODEST_DIALOG_WINDOW_MAX_WIDTH,
202 #endif
203                                      MODEST_DIALOG_WINDOW_MAX_HEIGHT);
204         
205         /* When this window is shown, hibernation should not be possible, 
206          * because there is no sensible way to save the state: */
207         modest_window_mgr_prevent_hibernation_while_window_is_shown (
208                 modest_runtime_get_window_mgr (), GTK_WINDOW (self)); 
209
210         priv->correct_scroll_idle = 0;
211         
212 }
213
214 ModestSignatureEditorDialog*
215 modest_signature_editor_dialog_new (void)
216 {
217         return g_object_new (MODEST_TYPE_SIGNATURE_EDITOR_DIALOG, NULL);
218 }
219
220 void
221 modest_signature_editor_dialog_set_settings (
222         ModestSignatureEditorDialog *window, gboolean use_signature, const gchar* signature, 
223         const gchar* account_title)
224 {
225         ModestSignatureEditorDialogPrivate *priv = 
226                 SIGNATURE_EDITOR_DIALOG_GET_PRIVATE (window);
227
228         /* This causes a warning because of the %s in the translation, but not in the original string: */
229         gchar* label_text = g_strdup_printf (_("mcen_ia_email_signatures_edit_dlg_label"), 
230                 account_title);
231         gtk_label_set_text (GTK_LABEL (priv->label), label_text);
232         gtk_label_set_ellipsize (GTK_LABEL (priv->label),  PANGO_ELLIPSIZE_END);
233         g_free (label_text);
234         
235         modest_togglable_set_active (priv->checkbox_use, use_signature);
236         
237         GtkTextBuffer *buffer = modest_text_view_get_buffer (priv->textview);
238         if (signature && signature[0] != '\0')
239                 gtk_text_buffer_set_text (buffer, signature, -1);
240         else
241                 gtk_text_buffer_set_text (buffer, _("mcen_va_default_signature_tablet"), -1); /* Default, as per the UI spec. */
242                 
243         enable_widgets (window);
244 }
245
246 /*
247  * The result must be freed with g_free(). */
248 gchar*
249 modest_signature_editor_dialog_get_settings (
250         ModestSignatureEditorDialog *window, gboolean* use_signature)
251 {
252         ModestSignatureEditorDialogPrivate *priv = 
253                 SIGNATURE_EDITOR_DIALOG_GET_PRIVATE (window);
254                 
255         g_assert(use_signature);
256         
257         *use_signature = modest_togglable_get_active (priv->checkbox_use);
258                         
259         GtkTextBuffer *buffer = modest_text_view_get_buffer (priv->textview);
260         
261         GtkTextIter start, end;
262         gtk_text_buffer_get_bounds (buffer, &start, &end);
263         return gtk_text_buffer_get_text (buffer, &start, &end, TRUE);
264 }
265
266 static gboolean 
267 correct_scroll_idle_func (gpointer userdata)
268 {
269         ModestSignatureEditorDialog *self = (ModestSignatureEditorDialog *) userdata;
270         ModestSignatureEditorDialogPrivate *priv;
271         GtkTextBuffer *buffer;
272         GtkTextIter iter;
273         GdkRectangle rectangle;
274         gint offset_min, offset_max;
275         GtkTextMark *insert;
276         GtkAdjustment *vadj;
277
278         /* It could happen that the window was already closed */
279         if (!GTK_WIDGET_VISIBLE (self))
280                 return FALSE;
281
282         priv = SIGNATURE_EDITOR_DIALOG_GET_PRIVATE(self);
283         buffer = modest_text_view_get_buffer (priv->textview);
284
285         insert = gtk_text_buffer_get_insert (buffer);
286         gtk_text_buffer_get_iter_at_mark (buffer, &iter, insert);
287
288         gtk_text_view_get_iter_location (GTK_TEXT_VIEW (priv->textview), &iter, &rectangle);
289         offset_min = priv->textview->allocation.y + rectangle.y;
290         offset_max = offset_min + rectangle.height;
291
292         vadj = modest_scrollable_get_vadjustment (MODEST_SCROLLABLE (priv->scrollable));
293         offset_min = MAX (offset_min - 48, 0);
294         offset_max = MIN (offset_max + 48, vadj->upper);
295
296         if ((offset_min < vadj->value) || (offset_max > vadj->value + vadj->page_size)) {
297                 /* We check if the current center of the visible area is already matching the center
298                    of the selection */
299                 gint offset_center;
300                 gint center_top, center_bottom;
301
302                 offset_center = (offset_min + offset_max) / 2;
303                 center_top = vadj->value + vadj->page_size / 3;
304                 center_bottom = vadj->value + vadj->page_size * 2 / 3;
305
306                 if ((offset_center < center_top) ||
307                     (offset_center > center_bottom))
308                         modest_scrollable_scroll_to (MODEST_SCROLLABLE (priv->scrollable), -1, offset_center);
309         }
310
311         priv->correct_scroll_idle = 0;
312         return FALSE;
313 }
314
315 static void correct_scroll (ModestSignatureEditorDialog *self)
316 {
317         ModestSignatureEditorDialogPrivate *priv;
318
319         priv = SIGNATURE_EDITOR_DIALOG_GET_PRIVATE(self);
320
321         if (!gtk_widget_is_focus (priv->textview))
322                 return;
323
324         if (priv->correct_scroll_idle > 0) {
325                 return;
326         }
327
328         priv->correct_scroll_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
329                                                      (GSourceFunc) correct_scroll_idle_func,
330                                                      g_object_ref (self),
331                                                      g_object_unref);
332 }
333
334 static void
335 text_buffer_end_user_action (GtkTextBuffer *buffer,
336                              ModestSignatureEditorDialog *userdata)
337 {
338
339         correct_scroll (userdata);
340 }
341