265950698990b1f6d4382feef1f4cca2b057e8c2
[modest] / src / maemo / modest-platform.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 <config.h>
31 #include <glib/gi18n.h>
32 #include <modest-platform.h>
33 #include <dbus_api/modest-dbus-callbacks.h>
34 #include <libosso.h>
35
36 #ifdef MODEST_HILDON_VERSION_0
37 #include <osso-mime.h>
38 #include <osso-uri.h>
39 #else
40 #include <hildon-mime.h>
41 #include <hildon-uri.h>
42 #endif /*MODEST_HILDON_VERSION_0*/
43
44 #include <tny-maemo-conic-device.h>
45 #include <tny-folder.h>
46 #include <gtk/gtkicontheme.h>
47 #include <hildon-widgets/hildon-banner.h>
48 #include <hildon-widgets/hildon-note.h>
49 #include <gtk/gtkmenuitem.h>
50 #include <gtk/gtkmain.h>
51 #include <string.h>
52
53 gboolean
54 modest_platform_init (void)
55 {       
56         osso_context_t *osso_context =
57                 osso_initialize(PACKAGE, PACKAGE_VERSION,
58                                 TRUE, NULL);    
59         if (!osso_context) {
60                 g_printerr ("modest: failed to acquire osso context\n");
61                 return FALSE;
62         }
63
64         /* Register our D-Bus callbacks, via the osso API: */
65         osso_return_t result = osso_rpc_set_cb_f(osso_context, 
66                                MODEST_DBUS_SERVICE, 
67                                MODEST_DBUS_OBJECT, 
68                                MODEST_DBUS_IFACE,
69                                modest_dbus_req_handler, NULL /* user_data */);
70         if (result != OSSO_OK) {
71                 g_print("Error setting D-BUS callback (%d)\n", result);
72                 return OSSO_ERROR;
73         }
74
75         /* Add handler for Exit D-BUS messages.
76          * Not used because osso_application_set_exit_cb() is deprecated and obsolete:
77         result = osso_application_set_exit_cb(osso_context,
78                                           modest_dbus_exit_event_handler,
79                                           (gpointer) NULL);
80         if (result != OSSO_OK) {
81                 g_print("Error setting exit callback (%d)\n", result);
82                 return OSSO_ERROR;
83         }
84         */
85
86         return TRUE;
87 }
88
89 TnyDevice*
90 modest_platform_get_new_device (void)
91 {
92         return TNY_DEVICE (tny_maemo_conic_device_new ());
93 }
94
95
96 const gchar*
97 guess_mime_type_from_name (const gchar* name)
98 {
99         int i;
100         const gchar* ext;
101         const static gchar* octet_stream= "application/octet-stream";
102         const static gchar* mime_map[][2] = {
103                 { "pdf",  "application/pdf"},
104                 { "doc",  "application/msword"},
105                 { "xls",  "application/excel"},
106                 { "png",  "image/png" },
107                 { "gif",  "image/gif" },
108                 { "jpg",  "image/jpeg"},
109                 { "jpeg", "image/jpeg"},
110                 { "mp3",  "audio/mp3" }
111         };
112
113         if (!name)
114                 return octet_stream;
115         
116         ext = g_strrstr (name, ".");
117         if (!ext)
118                 return octet_stream;
119         
120         for (i = 0; i != G_N_ELEMENTS(mime_map); ++i) {
121                 if (g_ascii_strcasecmp (mime_map[i][0], ext + 1)) /* +1: ignore '.'*/
122                         return mime_map[i][1];
123         }
124         return octet_stream;
125 }
126
127
128 gchar*
129 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
130                                           gchar **effective_mime_type)
131 {
132         GString *mime_str = NULL;
133         gchar *icon_name  = NULL;
134         gchar **icons, **cursor;
135         
136         
137         g_return_val_if_fail (name || mime_type, NULL);
138
139         if (!mime_type || g_ascii_strcasecmp (mime_type, "application/octet-stream")) 
140                 mime_str = g_string_new (guess_mime_type_from_name(name));
141         else {
142                 mime_str = g_string_new (mime_type);
143                 g_string_ascii_down (mime_str);
144         }
145 #ifdef MODEST_HILDON_VERSION_0
146         icons = osso_mime_get_icon_names (mime_str->str, NULL);
147 #else
148         icons = hildon_mime_get_icon_names (mime_str->str, NULL);
149 #endif /*MODEST_HILDON_VERSION_0*/
150         for (cursor = icons; cursor; ++cursor) {
151                 if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default(), *cursor)) {
152                         icon_name = g_strdup (*cursor);
153                         break;
154                 }
155         }
156         g_strfreev (icons);
157
158         if (effective_mime_type)
159                 *effective_mime_type = g_string_free (mime_str, FALSE);
160         else
161                 g_string_free (mime_str, TRUE);
162
163         return icon_name;
164 }
165
166 gboolean 
167 modest_platform_activate_uri (const gchar *uri)
168 {
169         gboolean result;
170
171 #ifdef MODEST_HILDON_VERSION_0
172         result = osso_uri_open (uri, NULL, NULL);
173 #else
174         result = hildon_uri_open (uri, NULL, NULL);
175 #endif
176
177         if (!result)
178                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
179         return result;
180 }
181
182 typedef struct  {
183         GSList * actions;
184         gchar *uri;
185 } ModestPlatformPopupInfo;
186
187 static gboolean
188 delete_uri_popup (GtkWidget *menu,
189                   GdkEvent *event,
190                   gpointer userdata)
191 {
192         ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
193
194         g_free (popup_info->uri);
195 #ifdef MODEST_HILDON_VERSION_0
196         osso_uri_free_actions (popup_info->actions);
197 #else
198         hildon_uri_free_actions (popup_info->actions);
199 #endif
200         return FALSE;
201 }
202
203 static void
204 activate_uri_popup_item (GtkMenuItem *menu_item,
205                          gpointer userdata)
206 {
207         GSList *node;
208         ModestPlatformPopupInfo *popup_info = (ModestPlatformPopupInfo *) userdata;
209         GtkWidget *label;
210
211         label = gtk_bin_get_child (GTK_BIN (menu_item));
212
213         for (node = popup_info->actions; node != NULL; node = g_slist_next (node)) {
214 #ifdef MODEST_HILDON_VERSION_0
215                 OssoURIAction *action = (OssoURIAction *) node->data;
216                 if (strcmp (gtk_label_get_text (GTK_LABEL(label)), osso_uri_action_get_name (action))==0) {
217                         osso_uri_open (popup_info->uri, action, NULL);
218                         break;
219                 }
220 #else
221                 HildonURIAction *action = (HildonURIAction *) node->data;
222                 if (strcmp (gtk_label_get_text (GTK_LABEL(label)), hildon_uri_action_get_name (action))==0) {
223                         hildon_uri_open (popup_info->uri, action, NULL);
224                         break;
225                 }
226 #endif
227         }
228 }
229
230 gboolean 
231 modest_platform_show_uri_popup (const gchar *uri)
232 {
233         gchar *scheme;
234         GSList *actions_list;
235
236         if (uri == NULL)
237                 return FALSE;
238 #ifdef MODEST_HILDON_VERSION_0
239         scheme = osso_uri_get_scheme_from_uri (uri, NULL);
240         actions_list = osso_uri_get_actions (scheme, NULL);
241 #else
242         scheme = hildon_uri_get_scheme_from_uri (uri, NULL);
243         actions_list = hildon_uri_get_actions (scheme, NULL);
244 #endif
245         if (actions_list != NULL) {
246                 GSList *node;
247                 GtkWidget *menu = gtk_menu_new ();
248                 ModestPlatformPopupInfo *popup_info = g_new0 (ModestPlatformPopupInfo, 1);
249
250                 popup_info->actions = actions_list;
251                 popup_info->uri = g_strdup (uri);
252               
253                 for (node = actions_list; node != NULL; node = g_slist_next (node)) {
254                         GtkWidget *menu_item;
255
256 #ifdef MODEST_HILDON_VERSION_0
257                         OssoURIAction *action;
258
259                         action = (OssoURIAction *) node->data;
260                         menu_item = gtk_menu_item_new_with_label (osso_uri_action_get_name (action));
261                         g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item), popup_info);
262                         
263                         if (osso_uri_is_default_action (action, NULL)) {
264                                 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
265                         } else {
266                                 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
267                         }
268 #else
269                         HildonURIAction *action;
270
271                         action = (HildonURIAction *) node->data;
272                         menu_item = gtk_menu_item_new_with_label (hildon_uri_action_get_name (action));
273                         g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (activate_uri_popup_item), popup_info);
274                         
275                         if (hildon_uri_is_default_action (action, NULL)) {
276                                 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
277                         } else {
278                                 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
279                         }
280 #endif
281
282                         gtk_widget_show (menu_item);
283                 }
284                 g_signal_connect (G_OBJECT (menu), "delete-event", G_CALLBACK (delete_uri_popup), popup_info);
285                 gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, gtk_get_current_event_time ());
286                                                   
287         } else {
288                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unsupported_link"));
289         }
290                 
291         g_free (scheme);
292         return TRUE;
293 }
294
295
296 GdkPixbuf*
297 modest_platform_get_icon (const gchar *name)
298 {
299         GError *err = NULL;
300         GdkPixbuf* pixbuf;
301         GtkIconTheme *current_theme;
302
303         g_return_val_if_fail (name, NULL);
304
305         if (g_str_has_suffix (name, ".png")) { /*FIXME: hack*/
306                 pixbuf = gdk_pixbuf_new_from_file (name, &err);
307                 if (!pixbuf) {
308                         g_printerr ("modest: error loading icon '%s': %s\n",
309                                     name, err->message);
310                         g_error_free (err);
311                         return NULL;
312                 }
313                 return pixbuf;
314         }
315
316         current_theme = gtk_icon_theme_get_default ();
317         pixbuf = gtk_icon_theme_load_icon (current_theme, name, 26,
318                                            GTK_ICON_LOOKUP_NO_SVG,
319                                            &err);
320         if (!pixbuf) {
321                 g_printerr ("modest: error loading theme icon '%s': %s\n",
322                             name, err->message);
323                 g_error_free (err);
324         } 
325         return pixbuf;
326 }
327
328 const gchar*
329 modest_platform_get_app_name (void)
330 {
331         return _("mcen_ap_name");
332 }
333
334 static void 
335 entry_insert_text (GtkEditable *editable,
336                    const gchar *text,
337                    gint         length,
338                    gint        *position,
339                    gpointer     data)
340 {
341         gchar *chars;
342         gint chars_length;
343
344         chars = gtk_editable_get_chars (editable, 0, -1);
345         chars_length = strlen (chars);
346
347         /* Show WID-INF036 */
348         if (chars_length == 20) {
349                 hildon_banner_show_information  (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
350                                                  _("mcen_ib_maxchar_reached"));
351         } else {
352                 if (chars_length == 0) {
353                         /* A blank space is not valid as first character */
354                         if (strcmp (text, " ")) {
355                                 GtkWidget *ok_button;
356                                 GList *buttons;
357
358                                 /* Show OK button */
359                                 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (data)->action_area));
360                                 ok_button = GTK_WIDGET (buttons->next->data);
361                                 gtk_widget_set_sensitive (ok_button, TRUE);
362                                 g_list_free (buttons);
363                         }
364                 }
365
366                 /* Write the text in the entry */
367                 g_signal_handlers_block_by_func (editable,
368                                                  (gpointer) entry_insert_text, data);
369                 gtk_editable_insert_text (editable, text, length, position);
370                 g_signal_handlers_unblock_by_func (editable,
371                                                    (gpointer) entry_insert_text, data);
372         }
373         /* Do not allow further processing */
374         g_signal_stop_emission_by_name (editable, "insert_text");
375 }
376
377 static void
378 entry_changed (GtkEditable *editable,
379                gpointer     user_data)
380 {
381         gchar *chars;
382
383         chars = gtk_editable_get_chars (editable, 0, -1);
384
385         /* Dimm OK button */
386         if (strlen (chars) == 0) {
387                 GtkWidget *ok_button;
388                 GList *buttons;
389
390                 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
391                 ok_button = GTK_WIDGET (buttons->next->data);
392                 gtk_widget_set_sensitive (ok_button, FALSE);
393
394                 g_list_free (buttons);
395         }
396         g_free (chars);
397 }
398
399 gint
400 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
401                                        TnyFolderStore *parent_folder,
402                                        gchar *suggested_name,
403                                        gchar **folder_name)
404 {
405         GtkWidget *dialog, *entry, *label, *hbox;
406         gint result;
407
408         /* Ask the user for the folder name */
409         dialog = gtk_dialog_new_with_buttons (_("mcen_ti_new_folder"),
410                                               parent_window,
411                                               GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
412                                               GTK_STOCK_OK,
413                                               GTK_RESPONSE_ACCEPT,
414                                               GTK_STOCK_CANCEL,
415                                               GTK_RESPONSE_REJECT,
416                                               NULL);
417
418         /* Create label and entry */
419         label = gtk_label_new (_("mcen_fi_new_folder_name"));
420         /* TODO: check that the suggested name does not exist */
421         /* We set 21 as maximum because we want to show WID-INF036
422            when the user inputs more that 20 */
423         entry = gtk_entry_new_with_max_length (21);
424         if (suggested_name)
425                 gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
426         else
427                 gtk_entry_set_text (GTK_ENTRY (entry), _("mcen_ia_default_folder_name"));
428         gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
429
430         /* Track entry changes */
431         g_signal_connect (entry,
432                           "insert-text",
433                           G_CALLBACK (entry_insert_text),
434                           dialog);
435         g_signal_connect (entry,
436                           "changed",
437                           G_CALLBACK (entry_changed),
438                           dialog);
439
440         /* Create the hbox */
441         hbox = gtk_hbox_new (FALSE, 12);
442         gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, FALSE, 0);
443         gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, FALSE, 0);
444
445         /* Add hbox to dialog */
446         gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 
447                             hbox, FALSE, FALSE, 0);
448         
449         gtk_widget_show_all (GTK_WIDGET(GTK_DIALOG(dialog)->vbox));
450         
451         result = gtk_dialog_run (GTK_DIALOG(dialog));
452         if (result == GTK_RESPONSE_ACCEPT)
453                 *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
454
455         gtk_widget_destroy (dialog);
456
457         return result;
458 }
459
460 gint
461 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
462                                          ModestConfirmationDialogType type,
463                                          gpointer user_data)
464 {
465         GtkWidget *dialog;
466         gint response;
467         gchar *message = NULL;
468         TnyFolder *folder;
469
470         switch (type) {
471         case MODEST_CONFIRMATION_DELETE_FOLDER:
472                 folder = TNY_FOLDER (user_data);
473                 message = g_strdup_printf (_("mcen_nc_delete_folder_text"), 
474                                            tny_folder_get_name (folder));
475                 break;
476         };
477
478         dialog = hildon_note_new_confirmation (parent_window, message);
479
480         response = gtk_dialog_run (GTK_DIALOG (dialog));
481
482         gtk_widget_destroy (GTK_WIDGET (dialog));
483         g_free (message);
484
485         return response;
486 }
487
488 void
489 modest_platform_run_information_dialog (GtkWindow *parent_window,
490                                         ModestInformationDialogType type)
491 {
492         GtkWidget *dialog;
493         gchar *message = NULL;
494
495         switch (type) {
496         case MODEST_INFORMATION_CREATE_FOLDER:
497                 message = _("mail_in_ui_folder_create_error");
498                 break;
499         case MODEST_INFORMATION_DELETE_FOLDER:
500                 message = _("mail_in_ui_folder_delete_error");
501                 break;
502         };
503
504         dialog = hildon_note_new_information (parent_window, message);
505
506         gtk_dialog_run (GTK_DIALOG (dialog));
507
508         gtk_widget_destroy (GTK_WIDGET (dialog));
509 }