1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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.
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.
31 #include <glib/gi18n.h>
33 #include <modest-platform.h>
34 #include <modest-defs.h>
35 #include <modest-scrollable.h>
36 #include <modest-runtime.h>
37 #include <modest-main-window.h>
38 #include <modest-header-view.h>
39 #include "modest-widget-memory.h"
40 #include <modest-utils.h>
41 #include <tny-camel-folder.h>
42 #include <tny-simple-list.h>
43 #include <tny-merge-folder.h>
44 #include <tny-error.h>
45 #include <tny-folder.h>
46 #include <tny-account-store-view.h>
47 #include <tny-gnome-device.h>
49 #include <modest-text-utils.h>
50 #include "modest-tny-folder.h"
51 #include "modest-tny-account.h"
53 #include <libgnomevfs/gnome-vfs-mime-utils.h>
54 #include <modest-account-settings-dialog.h>
55 #include <modest-easysetup-wizard-dialog.h>
56 #include "widgets/modest-window-mgr.h"
57 #include <modest-datetime-formatter.h>
58 #include "modest-header-window.h"
59 #include <modest-folder-window.h>
60 #include <modest-account-mgr.h>
61 #include <modest-account-mgr-helpers.h>
62 #include <modest-ui-constants.h>
63 #include <modest-icon-names.h>
64 #include <modest-count-stream.h>
65 #include <modest-gtk-details-dialog.h>
69 #define HILDON_OSSO_URI_ACTION "uri-action"
70 #define URI_ACTION_COPY "copy:"
71 #define MODEST_NOTIFICATION_CATEGORY "email-message"
72 #define MODEST_NEW_MAIL_LIGHTING_PATTERN "PatternChatAndEmail"
74 #define COMMON_FOLDER_DIALOG_ENTRY "entry"
75 #define COMMON_FOLDER_DIALOG_ACCOUNT_PICKER "account-picker"
76 #define FOLDER_PICKER_CURRENT_FOLDER "current-folder"
77 #define FOLDER_PICKER_ORIGINAL_ACCOUNT "original-account"
79 static gboolean ca_con_opened = FALSE;
82 static void modest_platform_play_email_tone (void);
86 on_modest_conf_update_interval_changed (ModestConf* self,
88 ModestConfEvent event,
89 ModestConfNotificationId id,
92 g_return_if_fail (key);
94 if (strcmp (key, MODEST_CONF_UPDATE_INTERVAL) == 0) {
95 const guint update_interval_minutes =
96 modest_conf_get_int (self, MODEST_CONF_UPDATE_INTERVAL, NULL);
97 modest_platform_set_update_interval (update_interval_minutes);
104 check_required_files (void)
107 FILE *mcc_file = modest_utils_open_mcc_mapping_file ();
110 g_printerr ("modest: check for mcc file (for LANG) failed\n");
116 if (access(MODEST_PROVIDER_DATA_FILE, R_OK) != 0 &&
117 access(MODEST_FALLBACK_PROVIDER_DATA_FILE, R_OK) != 0) {
118 g_printerr ("modest: cannot find providers data\n");
126 /* the gpointer here is the osso_context. */
128 modest_platform_init (int argc, char *argv[])
132 if (!check_required_files ()) {
133 g_printerr ("modest: missing required files\n");
137 /* Make sure that the update interval is changed whenever its gconf key
139 /* CAUTION: we're not using here the
140 modest_conf_listen_to_namespace because we know that there
141 are other parts of Modest listening for this namespace, so
142 we'll receive the notifications anyway. We basically do not
143 use it because there is no easy way to do the
144 modest_conf_forget_namespace */
145 ModestConf *conf = modest_runtime_get_conf ();
146 g_signal_connect (G_OBJECT(conf),
148 G_CALLBACK (on_modest_conf_update_interval_changed),
151 /* only force the setting of the default interval, if there are actually
153 acc_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), TRUE);
155 /* Get the initial update interval from gconf: */
156 on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
157 MODEST_CONF_EVENT_KEY_CHANGED, 0, NULL);
158 modest_account_mgr_free_account_names (acc_names);
165 modest_platform_uninit (void)
174 modest_platform_get_new_device (void)
176 return TNY_DEVICE (tny_gnome_device_new ());
180 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
181 gchar **effective_mime_type)
184 g_warning ("Not implemented %s", __FUNCTION__);
193 modest_platform_activate_uri (const gchar *uri)
195 g_warning ("Not implemented %s", __FUNCTION__);
202 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
204 g_warning ("Not implemented %s", __FUNCTION__);
210 modest_platform_show_uri_popup (const gchar *uri)
212 g_warning ("Not implemented %s", __FUNCTION__);
219 modest_platform_get_icon (const gchar *name, guint icon_size)
221 g_warning ("Not implemented %s", __FUNCTION__);
227 modest_platform_get_app_name (void)
229 return _("mcen_ap_name");
233 entry_insert_text (GtkEditable *editable,
242 chars = gtk_editable_get_chars (editable, 0, -1);
243 chars_length = g_utf8_strlen (chars, -1);
246 /* Show WID-INF036 */
247 if (chars_length >= 20) {
248 modest_platform_information_banner (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
249 _CS("ckdg_ib_maximum_characters_reached"));
251 if (modest_text_utils_is_forbidden_char (*text, FOLDER_NAME_FORBIDDEN_CHARS)) {
255 tmp = g_strndup (folder_name_forbidden_chars,
256 FOLDER_NAME_FORBIDDEN_CHARS_LENGTH);
257 msg = g_strdup_printf (_CS("ckdg_ib_illegal_characters_entered"), tmp);
258 modest_platform_information_banner (gtk_widget_get_parent (GTK_WIDGET (data)),
264 modest_platform_information_banner (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
265 _CS("ckdg_ib_maximum_characters_reached"));
267 /* Write the text in the entry if it's valid */
268 g_signal_handlers_block_by_func (editable,
269 (gpointer) entry_insert_text, data);
270 gtk_editable_insert_text (editable, text, length, position);
271 g_signal_handlers_unblock_by_func (editable,
272 (gpointer) entry_insert_text, data);
275 /* Do not allow further processing */
276 g_signal_stop_emission_by_name (editable, "insert_text");
280 entry_changed (GtkEditable *editable,
284 GtkWidget *ok_button;
287 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
288 ok_button = GTK_WIDGET (buttons->data);
290 chars = gtk_editable_get_chars (editable, 0, -1);
291 g_return_if_fail (chars != NULL);
294 if (g_utf8_strlen (chars,-1) >= 20) {
295 modest_platform_information_banner (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
296 _CS("ckdg_ib_maximum_characters_reached"));
298 gtk_widget_set_sensitive (ok_button, modest_text_utils_validate_folder_name(chars));
301 g_list_free (buttons);
308 on_response (GtkDialog *dialog,
312 GtkWidget *entry, *picker;
313 TnyFolderStore *parent;
314 const gchar *new_name;
317 if (response != GTK_RESPONSE_ACCEPT)
321 entry = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY);
322 picker = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER);
324 parent = TNY_FOLDER_STORE (user_data);
325 new_name = gtk_entry_get_text (GTK_ENTRY (entry));
329 parent = g_object_get_data (G_OBJECT (picker), FOLDER_PICKER_CURRENT_FOLDER);
331 /* Look for another folder with the same name */
332 if (!TNY_IS_MERGE_FOLDER (parent) &&
333 modest_tny_folder_has_subfolder_with_name (parent, new_name, TRUE))
337 if (TNY_IS_ACCOUNT (parent) &&
338 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (parent)) &&
339 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (parent),
347 modest_platform_information_banner (gtk_widget_get_parent (GTK_WIDGET (dialog)),
348 NULL, _CS("ckdg_ib_folder_already_exists"));
349 /* Select the text */
350 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
351 gtk_widget_grab_focus (entry);
352 /* Do not close the dialog */
353 g_signal_stop_emission_by_name (dialog, "response");
357 typedef struct _FolderChooserData {
358 TnyFolderStore *store;
363 folder_chooser_activated (ModestFolderView *folder_view,
364 TnyFolderStore *folder,
365 FolderChooserData *userdata)
367 userdata->store = folder;
368 gtk_dialog_response (GTK_DIALOG (userdata->dialog), GTK_RESPONSE_OK);
371 static TnyFolderStore *
372 folder_chooser_dialog_run (ModestFolderView *original,
373 TnyFolderStore *current,
376 GtkWidget *folder_view;
377 FolderChooserData userdata = {NULL, NULL};
378 GtkWidget *scrollable;
379 const gchar *visible_id = NULL;
381 userdata.dialog = gtk_dialog_new ();
382 scrollable = modest_toolkit_factory_create_scrollable (modest_runtime_get_toolkit_factory ());
383 folder_view = modest_platform_create_folder_view (NULL);
385 gtk_window_set_title (GTK_WINDOW (userdata.dialog), _FM("ckdg_ti_change_folder"));
387 modest_folder_view_copy_model (MODEST_FOLDER_VIEW (original),
388 MODEST_FOLDER_VIEW (folder_view));
390 if (TNY_IS_ACCOUNT (current)) {
391 /* Local folders and MMC account are always shown
392 along with the currently visible server account */
393 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (current)) ||
394 modest_tny_account_is_memory_card_account (TNY_ACCOUNT (current)))
395 visible_id = g_object_get_data ((GObject *) picker, FOLDER_PICKER_ORIGINAL_ACCOUNT);
397 visible_id = tny_account_get_id (TNY_ACCOUNT (current));
398 } else if (TNY_IS_FOLDER (current)) {
400 account = modest_tny_folder_get_account ((TnyFolder *) current);
402 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (account)) ||
403 modest_tny_account_is_memory_card_account (TNY_ACCOUNT (account))) {
404 visible_id = g_object_get_data ((GObject *) picker, FOLDER_PICKER_ORIGINAL_ACCOUNT);
406 visible_id = tny_account_get_id (account);
408 g_object_unref (account);
412 modest_folder_view_get_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(original));
415 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(folder_view),
418 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (userdata.dialog)->vbox), scrollable);
419 gtk_container_add (GTK_CONTAINER (scrollable), folder_view);
420 gtk_widget_set_size_request (scrollable, -1, 320);
422 gtk_widget_show (folder_view);
423 gtk_widget_show (scrollable);
424 gtk_widget_show (userdata.dialog);
425 g_signal_connect (G_OBJECT (folder_view), "folder-activated",
426 G_CALLBACK (folder_chooser_activated),
427 (gpointer) &userdata);
429 gtk_dialog_run (GTK_DIALOG (userdata.dialog));
430 gtk_widget_destroy (userdata.dialog);
432 return userdata.store;
436 folder_store_get_display_name (TnyFolderStore *store)
438 if (TNY_IS_ACCOUNT (store)) {
439 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
440 return modest_conf_get_string (modest_runtime_get_conf(),
441 MODEST_CONF_DEVICE_NAME, NULL);
443 return g_strdup (tny_account_get_name (TNY_ACCOUNT (store)));
446 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
448 fname = g_strdup (tny_folder_get_name (TNY_FOLDER (store)));
449 type = tny_folder_get_folder_type (TNY_FOLDER (store));
450 if (modest_tny_folder_is_local_folder (TNY_FOLDER (store)) ||
451 modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
452 type = modest_tny_folder_get_local_or_mmc_folder_type (TNY_FOLDER (store));
453 if (type != TNY_FOLDER_TYPE_UNKNOWN) {
455 fname = g_strdup (modest_local_folder_info_get_type_display_name (type));
458 /* Sometimes an special folder is reported by the server as
459 NORMAL, like some versions of Dovecot */
460 if (type == TNY_FOLDER_TYPE_NORMAL ||
461 type == TNY_FOLDER_TYPE_UNKNOWN) {
462 type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
466 if (type == TNY_FOLDER_TYPE_INBOX) {
468 fname = g_strdup (_("mcen_me_folder_inbox"));
475 get_image_for_folder_store (TnyFolderStore *store,
479 const gchar *icon_name = NULL;
480 GtkWidget *image = NULL;
482 if (TNY_IS_ACCOUNT (store)) {
483 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
484 icon_name = MODEST_FOLDER_ICON_LOCAL_FOLDERS;
485 else if (modest_tny_account_is_memory_card_account (TNY_ACCOUNT (store)))
486 icon_name = MODEST_FOLDER_ICON_MMC;
488 icon_name = MODEST_FOLDER_ICON_ACCOUNT;
490 TnyFolderType type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
491 if (modest_tny_folder_is_remote_folder (TNY_FOLDER (store))) {
493 case TNY_FOLDER_TYPE_INBOX:
494 icon_name = MODEST_FOLDER_ICON_INBOX;
497 icon_name = MODEST_FOLDER_ICON_REMOTE_FOLDER;
499 } else if (modest_tny_folder_is_local_folder (TNY_FOLDER (store))) {
501 case TNY_FOLDER_TYPE_OUTBOX:
502 icon_name = MODEST_FOLDER_ICON_OUTBOX;
504 case TNY_FOLDER_TYPE_DRAFTS:
505 icon_name = MODEST_FOLDER_ICON_DRAFTS;
507 case TNY_FOLDER_TYPE_SENT:
508 icon_name = MODEST_FOLDER_ICON_SENT;
511 icon_name = MODEST_FOLDER_ICON_NORMAL;
513 } else if (modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
514 icon_name = MODEST_FOLDER_ICON_MMC_FOLDER;
519 pixbuf = modest_platform_get_icon (icon_name, size);
522 image = gtk_image_new_from_pixbuf (pixbuf);
523 g_object_unref (pixbuf);
530 folder_picker_set_store (GtkButton *button, TnyFolderStore *store)
535 g_object_set_data (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER, NULL);
539 g_object_set_data_full (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER,
540 g_object_ref (store),
541 (GDestroyNotify) g_object_unref);
542 name = folder_store_get_display_name (store);
543 gtk_button_set_label (GTK_BUTTON (button), name);
547 image = get_image_for_folder_store (store, MODEST_ICON_SIZE_SMALL);
549 gtk_button_set_image (GTK_BUTTON (button), image);
553 /* Always returns DUPs so you must free the returned value */
555 get_next_folder_name (const gchar *suggested_name,
556 TnyFolderStore *suggested_folder)
558 const gchar *default_name = _FM("ckdg_va_new_folder_name_stub");
560 gchar *real_suggested_name;
562 if (suggested_name !=NULL) {
563 return g_strdup (suggested_name);
566 for(i = 0; i < 100; ++ i) {
567 gboolean exists = FALSE;
570 real_suggested_name = g_strdup (default_name);
572 real_suggested_name = g_strdup_printf ("%s(%d)",
573 _FM("ckdg_va_new_folder_name_stub"),
575 exists = modest_tny_folder_has_subfolder_with_name (suggested_folder,
582 g_free (real_suggested_name);
585 /* Didn't find a free number */
587 real_suggested_name = g_strdup (default_name);
589 return real_suggested_name;
593 ModestFolderView *folder_view;
595 } FolderPickerHelper;
598 folder_picker_clicked (GtkButton *button,
599 FolderPickerHelper *helper)
601 TnyFolderStore *store, *current;
603 current = g_object_get_data (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER);
605 store = folder_chooser_dialog_run (helper->folder_view, current, button);
607 const gchar *current_name;
608 gboolean exists = FALSE;
610 folder_picker_set_store (GTK_BUTTON (button), store);
612 /* Update the name of the folder */
613 current_name = gtk_entry_get_text (helper->entry);
615 if (TNY_IS_FOLDER_STORE (store))
616 exists = modest_tny_folder_has_subfolder_with_name (store,
620 gchar *new_name = get_next_folder_name (NULL, store);
621 gtk_entry_set_text (helper->entry, new_name);
628 folder_picker_new (TnyFolderStore *suggested, FolderPickerHelper *helper)
631 const gchar *acc_id = NULL;
633 button = gtk_button_new ();
635 gtk_misc_set_alignment (GTK_MISC (button), 0.0, 0.5);
639 folder_picker_set_store (GTK_BUTTON (button), suggested);
641 if (TNY_IS_ACCOUNT (suggested)) {
642 if (!modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (suggested)) &&
643 !modest_tny_account_is_memory_card_account (TNY_ACCOUNT (suggested)))
644 acc_id = tny_account_get_id ((TnyAccount *) suggested);
646 TnyAccount *account = modest_tny_folder_get_account ((TnyFolder *) suggested);
648 acc_id = tny_account_get_id ((TnyAccount *) account);
649 g_object_unref (account);
655 acc_id = modest_folder_view_get_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(helper->folder_view));
657 g_object_set_data_full (G_OBJECT (button), FOLDER_PICKER_ORIGINAL_ACCOUNT,
658 g_strdup (acc_id), (GDestroyNotify) g_free);
661 g_signal_connect (G_OBJECT (button), "clicked",
662 G_CALLBACK (folder_picker_clicked),
670 modest_platform_run_folder_common_dialog (GtkWindow *parent_window,
671 TnyFolderStore *suggested_parent,
672 const gchar *dialog_title,
673 const gchar *label_text,
674 const gchar *suggested_name,
676 gboolean show_parent,
678 TnyFolderStore **parent)
680 GtkWidget *accept_btn = NULL;
681 GtkWidget *dialog, *entry = NULL, *label_entry = NULL, *label_location = NULL, *hbox;
682 GtkWidget *account_picker = NULL;
683 GList *buttons = NULL;
685 GtkSizeGroup *sizegroup;
686 ModestFolderView *folder_view;
687 ModestWindow *folder_window;
688 ModestWindowMgr *window_mgr;
689 FolderPickerHelper *helper = NULL;
690 GtkWidget *top_vbox, *top_align;
692 window_mgr = modest_runtime_get_window_mgr ();
693 folder_window = modest_window_mgr_get_folder_window (window_mgr);
694 g_return_val_if_fail (MODEST_IS_FOLDER_WINDOW (folder_window), GTK_RESPONSE_NONE);
696 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (folder_window));
698 top_vbox = gtk_vbox_new (FALSE, 0);
699 top_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
700 gtk_alignment_set_padding (GTK_ALIGNMENT (top_align), 0, 0, MODEST_MARGIN_DOUBLE, 0);
702 /* Ask the user for the folder name */
703 dialog = gtk_dialog_new_with_buttons (dialog_title,
705 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
706 _FM("ckdg_bd_new_folder_dialog_ok"),
710 /* Add accept button (with unsensitive handler) */
711 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
712 accept_btn = GTK_WIDGET (buttons->data);
714 sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
717 label_entry = gtk_label_new (label_text);
718 entry = modest_toolkit_factory_create_entry (modest_runtime_get_toolkit_factory ());
719 gtk_entry_set_max_length (GTK_ENTRY (entry), 20);
721 gtk_misc_set_alignment (GTK_MISC (label_entry), 0.0, 0.5);
722 gtk_size_group_add_widget (sizegroup, label_entry);
725 gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
727 gtk_entry_set_text (GTK_ENTRY (entry), _FM("ckdg_va_new_folder_name_stub"));
728 gtk_entry_set_width_chars (GTK_ENTRY (entry),
729 MAX (g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (entry)), -1),
730 g_utf8_strlen (_FM("ckdg_va_new_folder_name_stub"), -1)));
731 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
736 label_location = gtk_label_new (_FM("ckdg_fi_new_folder_location"));
738 gtk_misc_set_alignment (GTK_MISC (label_location), 0.0, 0.5);
739 gtk_size_group_add_widget (sizegroup, label_location);
741 helper = g_slice_new0 (FolderPickerHelper);
742 helper->folder_view = folder_view;
743 helper->entry = (GtkEntry *) entry;
745 account_picker = folder_picker_new (suggested_parent, helper);
748 g_object_unref (sizegroup);
750 /* Connect to the response method to avoid closing the dialog
751 when an invalid name is selected*/
752 g_signal_connect (dialog,
754 G_CALLBACK (on_response),
758 /* Track entry changes */
759 g_signal_connect (entry,
761 G_CALLBACK (entry_insert_text),
763 g_signal_connect (entry,
765 G_CALLBACK (entry_changed),
770 /* Some locales like pt_BR need this to get the full window
772 gtk_widget_set_size_request (GTK_WIDGET (dialog), 300, -1);
774 /* Create the hbox */
776 hbox = gtk_hbox_new (FALSE, 12);
777 gtk_box_pack_start (GTK_BOX (hbox), label_entry, FALSE, FALSE, 0);
778 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
780 /* Add hbox to dialog */
781 gtk_box_pack_start (GTK_BOX (top_vbox),
782 hbox, FALSE, FALSE, 0);
783 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY, entry);
787 hbox = gtk_hbox_new (FALSE, 12);
788 gtk_box_pack_start (GTK_BOX (hbox), label_location, FALSE, FALSE, 0);
789 gtk_box_pack_start (GTK_BOX (hbox), account_picker, TRUE, TRUE, 0);
791 /* Add hbox to dialog */
792 gtk_box_pack_start (GTK_BOX (top_vbox),
793 hbox, FALSE, FALSE, 0);
794 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER, account_picker);
796 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
797 GTK_WINDOW (dialog), parent_window);
799 gtk_container_add (GTK_CONTAINER (top_align), top_vbox);
800 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), top_align, TRUE, TRUE, 0);
802 gtk_widget_show_all (GTK_WIDGET(dialog));
804 result = gtk_dialog_run (GTK_DIALOG(dialog));
805 if (result == GTK_RESPONSE_ACCEPT) {
807 *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
809 *parent = g_object_get_data (G_OBJECT (account_picker), FOLDER_PICKER_CURRENT_FOLDER);
811 g_object_ref (*parent);
815 gtk_widget_destroy (dialog);
818 g_slice_free (FolderPickerHelper, helper);
820 while (gtk_events_pending ())
821 gtk_main_iteration ();
827 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
828 TnyFolderStore *suggested_folder,
829 gchar *suggested_name,
831 TnyFolderStore **parent_folder)
833 gchar *real_suggested_name = NULL;
835 ModestTnyAccountStore *acc_store;
837 gboolean do_free = FALSE;
839 real_suggested_name = get_next_folder_name ((const gchar *) suggested_name,
842 /* In hildon 2.2 we always suggest the archive folder as parent */
843 if (!suggested_folder) {
844 acc_store = modest_runtime_get_account_store ();
845 account = modest_tny_account_store_get_mmc_folders_account (acc_store);
847 suggested_folder = (TnyFolderStore *)
848 modest_tny_account_get_special_folder (account,
849 TNY_FOLDER_TYPE_ARCHIVE);
850 g_object_unref (account);
855 /* If there is not archive folder then fallback to local folders account */
856 if (!suggested_folder) {
858 suggested_folder = (TnyFolderStore *)
859 modest_tny_account_store_get_local_folders_account (acc_store);
862 result = modest_platform_run_folder_common_dialog (parent_window,
864 _HL("ckdg_ti_new_folder"),
865 _FM("ckdg_fi_new_folder_name"),
873 g_object_unref (suggested_folder);
875 g_free(real_suggested_name);
881 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
882 TnyFolderStore *parent_folder,
883 const gchar *suggested_name,
886 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
888 return modest_platform_run_folder_common_dialog (parent_window,
890 _HL("ckdg_ti_rename_folder"),
891 _HL("ckdg_fi_rename_name"),
902 on_destroy_dialog (GtkWidget *dialog)
904 /* This could happen when the dialogs get programatically
905 hidden or destroyed (for example when closing the
906 application while a dialog is being shown) */
907 if (!GTK_IS_WIDGET (dialog))
910 gtk_widget_destroy (dialog);
912 if (gtk_events_pending ())
913 gtk_main_iteration ();
917 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
918 const gchar *message)
923 dialog = gtk_message_dialog_new (parent_window, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
924 GTK_MESSAGE_QUESTION,
925 GTK_BUTTONS_OK_CANCEL,
927 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
928 GTK_WINDOW (dialog), parent_window);
930 response = gtk_dialog_run (GTK_DIALOG (dialog));
932 on_destroy_dialog (dialog);
938 modest_platform_run_confirmation_dialog_with_buttons (GtkWindow *parent_window,
939 const gchar *message,
940 const gchar *button_accept,
941 const gchar *button_cancel)
946 dialog = gtk_message_dialog_new (parent_window, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
947 GTK_MESSAGE_QUESTION,
950 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
951 button_accept, GTK_RESPONSE_ACCEPT,
952 button_cancel, GTK_RESPONSE_CANCEL,
955 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
956 GTK_WINDOW (dialog), parent_window);
958 response = gtk_dialog_run (GTK_DIALOG (dialog));
960 on_destroy_dialog (dialog);
966 modest_platform_run_information_dialog (GtkWindow *parent_window,
967 const gchar *message,
972 note = gtk_message_dialog_new (parent_window, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
977 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
978 GTK_WINDOW (note), parent_window);
981 gtk_dialog_run (GTK_DIALOG (note));
983 on_destroy_dialog (note);
985 g_signal_connect_swapped (note,
987 G_CALLBACK (on_destroy_dialog),
990 gtk_widget_show_all (note);
994 typedef struct _ConnectAndWaitData {
996 GMainLoop *wait_loop;
997 gboolean has_callback;
999 } ConnectAndWaitData;
1003 quit_wait_loop (TnyAccount *account,
1004 ConnectAndWaitData *data)
1006 /* Set the has_callback to TRUE (means that the callback was
1007 executed and wake up every code waiting for cond to be
1009 g_mutex_lock (data->mutex);
1010 data->has_callback = TRUE;
1011 if (data->wait_loop)
1012 g_main_loop_quit (data->wait_loop);
1013 g_mutex_unlock (data->mutex);
1017 on_connection_status_changed (TnyAccount *account,
1018 TnyConnectionStatus status,
1021 TnyConnectionStatus conn_status;
1022 ConnectAndWaitData *data;
1024 /* Ignore if reconnecting or disconnected */
1025 conn_status = tny_account_get_connection_status (account);
1026 if (conn_status == TNY_CONNECTION_STATUS_RECONNECTING ||
1027 conn_status == TNY_CONNECTION_STATUS_DISCONNECTED)
1030 /* Remove the handler */
1031 data = (ConnectAndWaitData *) user_data;
1032 g_signal_handler_disconnect (account, data->handler);
1034 /* Quit from wait loop */
1035 quit_wait_loop (account, (ConnectAndWaitData *) user_data);
1039 on_tny_camel_account_set_online_cb (TnyCamelAccount *account,
1044 /* Quit from wait loop */
1045 quit_wait_loop (TNY_ACCOUNT (account), (ConnectAndWaitData *) user_data);
1049 modest_platform_connect_and_wait (GtkWindow *parent_window,
1050 TnyAccount *account)
1052 gboolean device_online;
1054 TnyConnectionStatus conn_status;
1055 gboolean user_requested;
1057 device = modest_runtime_get_device();
1058 device_online = tny_device_is_online (device);
1060 /* Whether the connection is user requested or automatically
1061 requested, for example via D-Bus */
1062 user_requested = (parent_window) ? TRUE : FALSE;
1064 /* If there is no account check only the device status */
1069 /* TODO: should show connection dialog through gnome device */
1073 /* Return if the account is already connected */
1074 conn_status = tny_account_get_connection_status (account);
1075 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
1082 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1084 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1085 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1086 /* This must be a maildir account, which does not require a connection: */
1091 return modest_platform_connect_and_wait (parent_window, account);
1095 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1098 return TRUE; /* Maybe it is something local. */
1100 gboolean result = TRUE;
1101 if (TNY_IS_FOLDER (folder_store)) {
1102 /* Get the folder's parent account: */
1103 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1104 if (account != NULL) {
1105 result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1106 g_object_unref (account);
1108 } else if (TNY_IS_ACCOUNT (folder_store)) {
1109 /* Use the folder store as an account: */
1110 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1117 modest_platform_create_sort_dialog (GtkWindow *parent_window)
1125 modest_platform_set_update_interval (guint minutes)
1131 modest_platform_push_email_notification(void)
1137 modest_platform_on_new_headers_received (GList *URI_list,
1138 gboolean show_visual)
1144 modest_platform_remove_new_mail_notifications (gboolean only_visuals)
1152 modest_platform_get_global_settings_dialog ()
1158 modest_platform_show_help (GtkWindow *parent_window,
1159 const gchar *help_id)
1165 modest_platform_show_search_messages (GtkWindow *parent_window)
1171 modest_platform_show_addressbook (GtkWindow *parent_window)
1177 modest_platform_create_folder_view_full (TnyFolderStoreQuery *query, gboolean do_refresh)
1179 GtkWidget *widget = modest_folder_view_new_full (query, do_refresh);
1181 /* Show one account by default */
1182 modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1183 MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1189 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1191 return modest_platform_create_folder_view_full (query, TRUE);
1195 banner_finish (gpointer data, GObject *object)
1197 ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1198 modest_window_mgr_unregister_banner (mgr);
1199 g_object_unref (mgr);
1203 modest_platform_information_banner (GtkWidget *parent,
1204 const gchar *icon_name,
1211 modest_platform_system_banner (GtkWidget *parent,
1212 const gchar *icon_name,
1219 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1220 const gchar *icon_name,
1228 modest_platform_animation_banner (GtkWidget *parent,
1229 const gchar *animation_name,
1238 TnyAccount *account;
1241 } CheckAccountIdleData;
1243 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1246 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1248 gboolean stop_trying = FALSE;
1249 g_return_val_if_fail (data && data->account, FALSE);
1251 if (data && data->account &&
1252 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1253 * after which the account is likely to be usable, or never likely to be usable soon: */
1254 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1256 data->is_online = TRUE;
1260 /* Give up if we have tried too many times: */
1261 if (data->count_tries >= NUMBER_OF_TRIES) {
1264 /* Wait for another timeout: */
1265 ++(data->count_tries);
1270 /* Allow the function that requested this idle callback to continue: */
1272 g_main_loop_quit (data->loop);
1275 g_object_unref (data->account);
1277 return FALSE; /* Don't call this again. */
1279 return TRUE; /* Call this timeout callback again. */
1283 /* Return TRUE immediately if the account is already online,
1284 * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as
1285 * soon as the account is online, or FALSE if the account does
1286 * not become online in the NUMBER_OF_TRIES seconds.
1287 * This is useful when the D-Bus method was run immediately after
1288 * the application was started (when using D-Bus activation),
1289 * because the account usually takes a short time to go online.
1290 * The return value is maybe not very useful.
1293 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1297 g_return_val_if_fail (account, FALSE);
1299 if (!tny_device_is_online (modest_runtime_get_device())) {
1300 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1304 /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1305 * so we avoid wait unnecessarily: */
1306 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1309 /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED,
1310 * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that
1311 * we want to avoid. */
1312 if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1315 /* This blocks on the result: */
1316 CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1317 data->is_online = FALSE;
1318 data->account = account;
1319 g_object_ref (data->account);
1320 data->count_tries = 0;
1322 GMainContext *context = NULL; /* g_main_context_new (); */
1323 data->loop = g_main_loop_new (context, FALSE /* not running */);
1325 g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1327 /* This main loop will run until the idle handler has stopped it: */
1328 g_main_loop_run (data->loop);
1330 g_main_loop_unref (data->loop);
1331 /* g_main_context_unref (context); */
1333 is_online = data->is_online;
1334 g_slice_free (CheckAccountIdleData, data);
1342 on_cert_dialog_response (GtkDialog *dialog, gint response_id, const gchar* cert)
1344 /* GTK_RESPONSE_HELP means we need to show the certificate */
1345 if (response_id == GTK_RESPONSE_APPLY) {
1348 /* Do not close the dialog */
1349 g_signal_stop_emission_by_name (dialog, "response");
1351 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);
1352 modest_platform_run_information_dialog (NULL, msg, TRUE);
1358 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1359 const gchar *certificate)
1365 gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1368 /* We use GTK_RESPONSE_APPLY because we want the button in the
1369 middle of OK and CANCEL the same as the browser does for
1370 example. With GTK_RESPONSE_HELP the view button is aligned
1371 to the left while the other two to the right */
1372 note = gtk_message_dialog_new (
1374 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1375 GTK_MESSAGE_QUESTION,
1378 gtk_dialog_add_buttons (GTK_DIALOG (note),
1379 _HL("wdgt_bd_yes"), GTK_RESPONSE_OK,
1380 _HL("wdgt_bd_view"), GTK_RESPONSE_APPLY, /* abusing this... */
1381 _HL("wdgt_bd_no"), GTK_RESPONSE_CANCEL,
1384 g_signal_connect (G_OBJECT(note), "response",
1385 G_CALLBACK(on_cert_dialog_response),
1386 (gpointer) certificate);
1388 response = gtk_dialog_run(GTK_DIALOG(note));
1390 on_destroy_dialog (note);
1393 return response == GTK_RESPONSE_OK;
1397 modest_platform_run_alert_dialog (const gchar* prompt,
1398 gboolean is_question)
1401 gboolean retval = TRUE;
1404 /* The Tinymail documentation says that we should show Yes and No buttons,
1405 * when it is a question.
1406 * Obviously, we need tinymail to use more specific error codes instead,
1407 * so we know what buttons to show. */
1408 dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1409 GTK_MESSAGE_QUESTION,
1413 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
1414 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
1416 on_destroy_dialog (dialog);
1418 /* Just show the error text and use the default response: */
1419 modest_platform_run_information_dialog (NULL,
1427 GtkWindow *parent_window;
1428 ModestConnectedPerformer callback;
1429 TnyAccount *account;
1436 on_went_online_info_free (OnWentOnlineInfo *info)
1438 /* And if we cleanup, we DO cleanup :-) */
1441 g_object_unref (info->device);
1444 if (info->parent_window)
1445 g_object_unref (info->parent_window);
1447 g_object_unref (info->account);
1449 g_slice_free (OnWentOnlineInfo, info);
1451 /* We're done ... */
1457 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
1459 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1461 /* Now it's really time to callback to the caller. If going online didn't succeed,
1462 * err will be set. We don't free it, Tinymail does that! If a cancel happened,
1463 * canceled will be set. Etcetera etcetera. */
1465 if (info->callback) {
1466 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1469 /* This is our last call, we must cleanup here if we didn't yet do that */
1470 on_went_online_info_free (info);
1476 modest_platform_connect_and_perform (GtkWindow *parent_window,
1478 TnyAccount *account,
1479 ModestConnectedPerformer callback,
1482 gboolean device_online;
1484 TnyConnectionStatus conn_status;
1485 OnWentOnlineInfo *info;
1487 device = modest_runtime_get_device();
1488 device_online = tny_device_is_online (device);
1490 /* If there is no account check only the device status */
1493 if (device_online) {
1495 /* We promise to instantly perform the callback, so ... */
1497 callback (FALSE, NULL, parent_window, account, user_data);
1504 /* The other code has no more reason to run. This is all that we can do for the
1505 * caller (he should have given us a nice and clean account instance!). We
1506 * can't do magic, we don't know what account he intends to bring online. So
1507 * we'll just bring the device online (and await his false bug report). */
1513 /* Return if the account is already connected */
1515 conn_status = tny_account_get_connection_status (account);
1516 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
1518 /* We promise to instantly perform the callback, so ... */
1520 callback (FALSE, NULL, parent_window, account, user_data);
1526 if (device_online) {
1529 /* If the device is online, we'll just connect the account */
1531 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1532 on_account_went_online, info);
1535 /* The info gets freed by on_account_went_online or on_conic_device_went_online
1536 * in both situations, go look if you don't believe me! */
1542 modest_platform_connect_if_remote_and_perform (GtkWindow *parent_window,
1544 TnyFolderStore *folder_store,
1545 ModestConnectedPerformer callback,
1548 TnyAccount *account = NULL;
1550 if (!folder_store ||
1551 (TNY_IS_MERGE_FOLDER (folder_store) &&
1552 (tny_folder_get_folder_type (TNY_FOLDER(folder_store)) == TNY_FOLDER_TYPE_OUTBOX))) {
1554 /* We promise to instantly perform the callback, so ... */
1556 GError *error = NULL;
1557 g_set_error (&error, TNY_ERROR_DOMAIN, TNY_SERVICE_ERROR_UNKNOWN,
1558 "Unable to move or not found folder");
1559 callback (FALSE, error, parent_window, NULL, user_data);
1560 g_error_free (error);
1564 } else if (TNY_IS_FOLDER (folder_store)) {
1565 /* Get the folder's parent account: */
1566 account = tny_folder_get_account (TNY_FOLDER (folder_store));
1567 } else if (TNY_IS_ACCOUNT (folder_store)) {
1568 /* Use the folder store as an account: */
1569 account = TNY_ACCOUNT (g_object_ref (folder_store));
1572 if (account && (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE)) {
1573 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1574 /* No need to connect a local account */
1576 callback (FALSE, NULL, parent_window, account, user_data);
1581 modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
1585 g_object_unref (account);
1589 src_account_connect_performer (gboolean canceled,
1591 GtkWindow *parent_window,
1592 TnyAccount *src_account,
1595 DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
1597 if (canceled || err) {
1598 /* If there was any error call the user callback */
1599 info->callback (canceled, err, parent_window, src_account, info->data);
1601 /* Connect the destination account */
1602 modest_platform_connect_if_remote_and_perform (parent_window, TRUE,
1603 TNY_FOLDER_STORE (info->dst_account),
1604 info->callback, info->data);
1607 /* Free the info object */
1608 g_object_unref (info->dst_account);
1609 g_slice_free (DoubleConnectionInfo, info);
1614 modest_platform_double_connect_and_perform (GtkWindow *parent_window,
1616 TnyFolderStore *folder_store,
1617 DoubleConnectionInfo *connect_info)
1619 modest_platform_connect_if_remote_and_perform(parent_window,
1622 src_account_connect_performer,
1627 modest_platform_get_account_settings_wizard (void)
1629 ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
1631 return GTK_WIDGET (dialog);
1635 modest_platform_get_current_connection (void)
1637 TnyDevice *device = NULL;
1638 ModestConnectedVia retval = MODEST_CONNECTED_VIA_ANY;
1640 device = modest_runtime_get_device ();
1642 if (!tny_device_is_online (device))
1643 return MODEST_CONNECTED_VIA_ANY;
1645 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX; /* assume WLAN (fast) internet */
1652 modest_platform_check_memory_low (ModestWindow *win,
1660 modest_platform_run_folder_details_dialog (GtkWindow *parent_window,
1666 dialog = modest_toolkit_factory_create_details_dialog_with_folder (modest_runtime_get_toolkit_factory (),
1667 parent_window, folder);
1670 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1671 GTK_WINDOW (dialog),
1673 gtk_widget_show_all (dialog);
1675 g_signal_connect_swapped (dialog, "response",
1676 G_CALLBACK (gtk_widget_destroy),
1680 typedef struct _HeaderDetailsGetSizeInfo {
1684 } HeaderDetailsGetSizeInfo;
1687 header_details_dialog_destroy (gpointer userdata,
1690 HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) userdata;
1692 info->dialog = NULL;
1696 idle_get_mime_part_size_cb (gpointer userdata)
1698 HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) userdata;
1699 gdk_threads_enter ();
1701 if (info->dialog && GTK_WIDGET_VISIBLE (info->dialog)) {
1702 modest_details_dialog_set_message_size (MODEST_DETAILS_DIALOG (info->dialog),
1707 g_object_weak_unref (G_OBJECT (info->dialog), header_details_dialog_destroy, info);
1708 info->dialog = NULL;
1710 g_object_unref (info->part);
1711 g_slice_free (HeaderDetailsGetSizeInfo, info);
1713 gdk_threads_leave ();
1719 get_mime_part_size_thread (gpointer thr_user_data)
1721 HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) thr_user_data;
1723 TnyStream *count_stream;
1725 count_stream = modest_count_stream_new ();
1726 result = tny_mime_part_decode_to_stream (info->part, count_stream, NULL);
1727 info->total = modest_count_stream_get_count(MODEST_COUNT_STREAM (count_stream));
1728 if (info->total == 0) {
1729 modest_count_stream_reset_count(MODEST_COUNT_STREAM (count_stream));
1730 result = tny_mime_part_write_to_stream (info->part, count_stream, NULL);
1731 info->total = modest_count_stream_get_count(MODEST_COUNT_STREAM (count_stream));
1734 /* if there was an error, don't set the size (this is pretty uncommon) */
1736 g_warning ("%s: error while writing mime part to stream\n", __FUNCTION__);
1738 g_idle_add (idle_get_mime_part_size_cb, info);
1744 modest_platform_run_header_details_dialog (GtkWindow *parent_window,
1746 gboolean async_get_size,
1752 dialog = modest_toolkit_factory_create_details_dialog_with_header (modest_runtime_get_toolkit_factory (),
1753 parent_window, header, !async_get_size);
1755 if (async_get_size && msg && TNY_IS_MSG (msg)) {
1756 HeaderDetailsGetSizeInfo *info;
1757 info = g_slice_new (HeaderDetailsGetSizeInfo);
1758 info->dialog = dialog;
1760 info->part = TNY_MIME_PART (g_object_ref (msg));
1762 g_object_weak_ref (G_OBJECT (dialog), header_details_dialog_destroy, info);
1763 g_thread_create (get_mime_part_size_thread, info, FALSE, NULL);
1767 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1768 GTK_WINDOW (dialog),
1770 gtk_widget_show_all (dialog);
1772 g_signal_connect_swapped (dialog, "response",
1773 G_CALLBACK (gtk_widget_destroy),
1778 modest_platform_play_email_tone (void)
1783 #define MOVE_TO_DIALOG_FOLDER_VIEW "folder-view"
1784 #define MOVE_TO_DIALOG_BACK_BUTTON "back-button"
1785 #define MOVE_TO_DIALOG_ACTION_BUTTON "action-button"
1786 #define MOVE_TO_DIALOG_SHOWING_FOLDERS "showing-folders"
1787 #define MOVE_TO_DIALOG_SCROLLABLE "scrollable"
1788 #define MOVE_TO_FOLDER_SEPARATOR "/"
1791 translate_path (gchar **path)
1796 gboolean add_separator;
1798 parts = g_strsplit (*path, MOVE_TO_FOLDER_SEPARATOR, 0);
1802 output = g_string_new ("");
1803 add_separator = FALSE;
1805 while (*current != NULL) {
1806 TnyFolderType folder_type;
1809 if (add_separator) {
1810 output = g_string_append (output, MOVE_TO_FOLDER_SEPARATOR);
1812 add_separator = TRUE;
1815 downcase = g_ascii_strdown (*current, -1);
1816 folder_type = modest_local_folder_info_get_type (downcase);
1817 if (strcmp (downcase, "inbox") == 0) {
1818 output = g_string_append (output, _("mcen_me_folder_inbox"));
1819 } else if (folder_type == TNY_FOLDER_TYPE_ARCHIVE ||
1820 folder_type == TNY_FOLDER_TYPE_DRAFTS ||
1821 folder_type == TNY_FOLDER_TYPE_SENT ||
1822 folder_type == TNY_FOLDER_TYPE_OUTBOX) {
1823 output = g_string_append (output, modest_local_folder_info_get_type_display_name (folder_type));
1825 output = g_string_append (output, *current);
1833 *path = g_string_free (output, FALSE);
1837 move_to_dialog_set_selected_folder_store (GtkWidget *dialog,
1838 TnyFolderStore *folder_store)
1840 GtkWidget *action_button;
1841 GtkWidget *image = NULL;
1842 TnyAccount *account;
1843 gchar *account_name = NULL, *short_name = NULL;
1845 action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
1847 /* Get account name */
1848 if (TNY_IS_FOLDER (folder_store))
1849 account = tny_folder_get_account (TNY_FOLDER (folder_store));
1851 account = g_object_ref (folder_store);
1853 if (modest_tny_account_is_virtual_local_folders (account))
1854 account_name = modest_conf_get_string (modest_runtime_get_conf(),
1855 MODEST_CONF_DEVICE_NAME, NULL);
1858 account_name = g_strdup (tny_account_get_name (account));
1860 g_object_unref (account);
1862 /* Set title of button: account or folder name */
1863 if (TNY_IS_FOLDER (folder_store))
1864 short_name = folder_store_get_display_name (folder_store);
1866 short_name = g_strdup (account_name);
1868 gtk_button_set_label (GTK_BUTTON (action_button), short_name);
1870 /* Set value of button, folder full name */
1871 if (TNY_IS_CAMEL_FOLDER (folder_store)) {
1872 const gchar *camel_full_name;
1873 gchar *last_slash, *full_name;
1875 camel_full_name = tny_camel_folder_get_full_name (TNY_CAMEL_FOLDER (folder_store));
1876 last_slash = g_strrstr (camel_full_name, "/");
1878 gchar *prefix = g_strndup (camel_full_name, last_slash - camel_full_name + 1);
1879 full_name = g_strconcat (account_name, MOVE_TO_FOLDER_SEPARATOR, prefix, short_name, NULL);
1882 full_name = g_strconcat (account_name, MOVE_TO_FOLDER_SEPARATOR,
1886 translate_path (&full_name);
1887 gtk_button_set_label (GTK_BUTTON (action_button), full_name);
1890 g_free (account_name);
1891 g_free (short_name);
1893 /* Set image for the button */
1894 image = get_image_for_folder_store (folder_store, MODEST_ICON_SIZE_BIG);
1896 gtk_button_set_image (GTK_BUTTON (action_button), image);
1900 move_to_dialog_show_accounts (GtkWidget *dialog)
1902 GtkWidget *back_button;
1903 GtkWidget *folder_view;
1904 GtkWidget *scrollable;
1905 GtkWidget *action_button;
1907 back_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
1908 action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
1909 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
1910 scrollable = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SCROLLABLE));
1912 gtk_widget_set_sensitive (back_button, FALSE);
1913 gtk_widget_set_sensitive (action_button, FALSE);
1915 /* Need to set this here, otherwise callbacks called because
1916 of filtering won't perform correctly */
1917 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS, GINT_TO_POINTER (FALSE));
1919 /* Reset action button */
1920 gtk_button_set_label (GTK_BUTTON (action_button), NULL);
1921 gtk_button_set_image (GTK_BUTTON (action_button), NULL);
1923 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view), NULL);
1924 modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), TRUE);
1925 modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ALL);
1926 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
1927 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
1928 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
1929 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
1930 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
1931 MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
1932 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
1933 MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
1934 modest_scrollable_jump_to (MODEST_SCROLLABLE (scrollable), 0, 0);
1938 move_to_dialog_show_folders (GtkWidget *dialog, TnyFolderStore *folder_store)
1940 GtkWidget *back_button;
1941 GtkWidget *folder_view;
1942 TnyAccount *account;
1943 const gchar *account_id;
1944 GtkWidget *scrollable;
1945 GtkWidget *action_button;
1948 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
1950 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
1952 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
1954 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SCROLLABLE));
1956 gtk_widget_set_sensitive (back_button, TRUE);
1957 gtk_widget_set_sensitive (action_button, TRUE);
1959 /* Need to set this here, otherwise callbacks called because
1960 of filtering won't perform correctly */
1961 g_object_set_data (G_OBJECT (dialog),
1962 MOVE_TO_DIALOG_SHOWING_FOLDERS,
1963 GINT_TO_POINTER (TRUE));
1965 account = TNY_ACCOUNT (folder_store);
1966 if (modest_tny_account_is_virtual_local_folders (account)) {
1967 account_id = tny_account_get_id (account);
1968 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
1969 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
1970 } else if (modest_tny_account_is_memory_card_account (account)) {
1971 account_id = tny_account_get_id (account);
1972 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
1973 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
1975 account_id = tny_account_get_id (account);
1976 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
1977 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
1978 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
1979 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
1982 move_to_dialog_set_selected_folder_store (dialog, folder_store);
1983 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view),
1986 modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), FALSE);
1987 modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1988 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
1989 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
1990 modest_scrollable_jump_to (MODEST_SCROLLABLE (scrollable), 0, 0);
1994 on_move_to_dialog_back_clicked (GtkButton *button,
1997 GtkWidget *dialog = (GtkWidget *) userdata;
1999 /* Back to show accounts */
2000 move_to_dialog_show_accounts (dialog);
2004 on_move_to_dialog_row_activated (GtkTreeView *tree_view,
2006 GtkTreeViewColumn *column,
2009 TnyFolderStore *selected = NULL;
2011 GtkWidget *folder_view;
2012 gboolean showing_folders;
2014 dialog = (GtkWidget *) user_data;
2015 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog),
2016 MOVE_TO_DIALOG_SHOWING_FOLDERS));
2018 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog),
2019 MOVE_TO_DIALOG_FOLDER_VIEW));
2021 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2025 if (!showing_folders) {
2026 gboolean valid = TRUE;
2028 if (TNY_IS_ACCOUNT (selected) &&
2029 modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (selected))) {
2030 ModestProtocolType protocol_type;
2032 protocol_type = modest_tny_account_get_protocol_type (TNY_ACCOUNT (selected));
2033 valid = !modest_protocol_registry_protocol_type_has_tag
2034 (modest_runtime_get_protocol_registry (),
2036 MODEST_PROTOCOL_REGISTRY_STORE_FORBID_INCOMING_XFERS);
2039 move_to_dialog_show_folders (dialog, selected);
2041 move_to_dialog_set_selected_folder_store (dialog, selected);
2043 g_object_unref (selected);
2047 on_move_to_dialog_selection_changed (GtkTreeSelection *selection,
2050 gboolean showing_folders;
2053 dialog = (GtkWidget *) user_data;
2054 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2055 if (showing_folders) {
2056 TnyFolderStore *selected;
2057 GtkWidget *folder_view;
2059 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2060 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2063 move_to_dialog_set_selected_folder_store (dialog, selected);
2064 g_object_unref (selected);
2070 on_move_to_dialog_action_clicked (GtkButton *selection,
2074 gboolean showing_folders;
2076 dialog = (GtkWidget *) user_data;
2077 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2078 if (showing_folders) {
2079 TnyFolderStore *selected;
2080 GtkWidget *folder_view;
2082 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2083 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2086 /* It's not possible to select root folders as
2087 targets unless they're the local account or
2088 the memory card account */
2089 if ((TNY_IS_FOLDER (selected) && !TNY_IS_MERGE_FOLDER (selected)) ||
2090 (TNY_IS_ACCOUNT (selected) &&
2091 (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (selected)) ||
2092 modest_tny_account_is_memory_card_account (TNY_ACCOUNT (selected)))))
2093 gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
2094 g_object_unref (selected);
2100 move_to_dialog_activity_changed (ModestFolderView *folder_view, gboolean activity, GtkDialog *dialog)
2105 modest_platform_create_move_to_dialog (GtkWindow *parent_window,
2106 GtkWidget **folder_view)
2108 GtkWidget *dialog, *folder_view_container;
2110 GtkWidget *buttons_hbox;
2111 GtkWidget *back_button;
2112 GdkPixbuf *back_pixbuf;
2113 GtkWidget *top_vbox;
2114 GtkWidget *action_button;
2115 GtkTreeSelection *selection;
2117 /* Create dialog. We cannot use a touch selector because we
2118 need to use here the folder view widget directly */
2119 dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
2120 GTK_WINDOW (parent_window),
2121 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR |
2122 GTK_DIALOG_DESTROY_WITH_PARENT,
2123 _FM ("ckdg_bd_change_folder_new_folder"),
2124 MODEST_GTK_RESPONSE_NEW_FOLDER,
2127 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
2128 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_NONE);
2129 top_vbox = gtk_vbox_new (FALSE, MODEST_MARGIN_HALF);
2131 /* Create folder view */
2132 *folder_view = modest_platform_create_folder_view_full (NULL, FALSE);
2133 g_signal_connect (G_OBJECT (*folder_view), "activity-changed", G_CALLBACK (move_to_dialog_activity_changed),
2136 modest_folder_view_set_cell_style (MODEST_FOLDER_VIEW (*folder_view),
2137 MODEST_FOLDER_VIEW_CELL_STYLE_COMPACT);
2138 modest_folder_view_show_message_count (MODEST_FOLDER_VIEW (*folder_view),
2140 tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (*folder_view),
2141 (TnyAccountStore *) modest_runtime_get_account_store ());
2143 buttons_hbox = gtk_hbox_new (FALSE, MODEST_MARGIN_HALF);
2144 back_button = gtk_button_new ();
2145 back_pixbuf = modest_platform_get_icon (_FM("filemanager_folder_up"), MODEST_ICON_SIZE_BIG);
2147 gtk_button_set_image (GTK_BUTTON (back_button), gtk_image_new_from_pixbuf (back_pixbuf));
2148 g_object_unref (back_pixbuf);
2151 action_button = gtk_button_new ();
2152 gtk_button_set_alignment (GTK_BUTTON (action_button), 0.0, 0.5);
2154 gtk_box_pack_start (GTK_BOX (buttons_hbox), back_button, FALSE, FALSE, 0);
2155 gtk_box_pack_start (GTK_BOX (buttons_hbox), action_button, TRUE, TRUE, 0);
2156 gtk_widget_set_sensitive (GTK_WIDGET (back_button), FALSE);
2157 gtk_widget_set_sensitive (GTK_WIDGET (action_button), FALSE);
2158 gtk_box_pack_start (GTK_BOX (top_vbox), buttons_hbox, FALSE, FALSE, 0);
2160 /* Create scrollable and add it to the dialog */
2161 folder_view_container = modest_toolkit_factory_create_scrollable (modest_runtime_get_toolkit_factory ());
2162 gtk_container_add (GTK_CONTAINER (folder_view_container), *folder_view);
2163 gtk_box_pack_start (GTK_BOX (top_vbox), folder_view_container, TRUE, TRUE, 0);
2165 gtk_container_add (GTK_CONTAINER (align), top_vbox);
2166 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), align, TRUE, TRUE, 0);
2168 gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
2170 gtk_widget_show (GTK_DIALOG (dialog)->vbox);
2171 gtk_widget_show (folder_view_container);
2172 gtk_widget_show (align);
2173 gtk_widget_show (top_vbox);
2174 gtk_widget_show (*folder_view);
2175 gtk_widget_show_all (back_button);
2176 gtk_widget_show (action_button);
2177 gtk_widget_show (buttons_hbox);
2178 gtk_widget_show (dialog);
2180 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW, *folder_view);
2181 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON, back_button);
2182 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON, action_button);
2183 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SCROLLABLE, folder_view_container);
2185 /* Simulate the behaviour of a HildonPickerDialog by emitting
2186 a response when a folder is selected */
2187 g_signal_connect (*folder_view, "row-activated",
2188 G_CALLBACK (on_move_to_dialog_row_activated),
2191 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (*folder_view));
2192 g_signal_connect (selection, "changed",
2193 G_CALLBACK (on_move_to_dialog_selection_changed),
2196 g_signal_connect (action_button, "clicked",
2197 G_CALLBACK (on_move_to_dialog_action_clicked),
2200 g_signal_connect (back_button, "clicked",
2201 G_CALLBACK (on_move_to_dialog_back_clicked),
2204 move_to_dialog_show_accounts (dialog);
2210 modest_platform_get_list_to_move (ModestWindow *window)
2212 TnyList *list = NULL;
2214 if (MODEST_IS_HEADER_WINDOW (window)) {
2215 ModestHeaderView *header_view;
2217 header_view = modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window));
2218 list = modest_header_view_get_selected_headers (header_view);
2219 } else if (MODEST_IS_FOLDER_WINDOW (window)) {
2220 ModestFolderView *folder_view;
2221 TnyFolderStore *selected_folder;
2223 list = TNY_LIST (tny_simple_list_new ());
2224 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window));
2225 selected_folder = modest_folder_view_get_selected (folder_view);
2226 if (selected_folder) {
2227 tny_list_prepend (list, G_OBJECT (selected_folder));
2228 g_object_unref (selected_folder);
2231 } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
2234 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (window));
2236 list = TNY_LIST (tny_simple_list_new ());
2237 tny_list_prepend (list, G_OBJECT (header));
2238 g_object_unref (header);
2241 g_return_val_if_reached (NULL);