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>
66 #include <modest-default-global-settings-dialog.h>
68 #include "widgets/modest-toolkit-utils.h"
69 #include <modest-shell-banner.h>
71 #define HILDON_OSSO_URI_ACTION "uri-action"
72 #define URI_ACTION_COPY "copy:"
73 #define MODEST_NOTIFICATION_CATEGORY "email-message"
74 #define MODEST_NEW_MAIL_LIGHTING_PATTERN "PatternChatAndEmail"
76 #define COMMON_FOLDER_DIALOG_ENTRY "entry"
77 #define COMMON_FOLDER_DIALOG_ACCOUNT_PICKER "account-picker"
78 #define FOLDER_PICKER_CURRENT_FOLDER "current-folder"
79 #define FOLDER_PICKER_ORIGINAL_ACCOUNT "original-account"
82 on_modest_conf_update_interval_changed (ModestConf* self,
84 ModestConfEvent event,
85 ModestConfNotificationId id,
88 g_return_if_fail (key);
90 if (strcmp (key, MODEST_CONF_UPDATE_INTERVAL) == 0) {
91 const guint update_interval_minutes =
92 modest_conf_get_int (self, MODEST_CONF_UPDATE_INTERVAL, NULL);
93 modest_platform_set_update_interval (update_interval_minutes);
100 check_required_files (void)
103 FILE *mcc_file = modest_utils_open_mcc_mapping_file ();
106 g_printerr ("modest: check for mcc file (for LANG) failed\n");
112 if (access(MODEST_PROVIDER_DATA_FILE, R_OK) != 0 &&
113 access(MODEST_FALLBACK_PROVIDER_DATA_FILE, R_OK) != 0) {
114 g_printerr ("modest: cannot find providers data\n");
122 /* the gpointer here is the osso_context. */
124 modest_platform_init (int argc, char *argv[])
128 if (!check_required_files ()) {
129 g_printerr ("modest: missing required files\n");
133 /* Make sure that the update interval is changed whenever its gconf key
135 /* CAUTION: we're not using here the
136 modest_conf_listen_to_namespace because we know that there
137 are other parts of Modest listening for this namespace, so
138 we'll receive the notifications anyway. We basically do not
139 use it because there is no easy way to do the
140 modest_conf_forget_namespace */
141 ModestConf *conf = modest_runtime_get_conf ();
142 g_signal_connect (G_OBJECT(conf),
144 G_CALLBACK (on_modest_conf_update_interval_changed),
147 /* only force the setting of the default interval, if there are actually
149 acc_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), TRUE);
151 /* Get the initial update interval from gconf: */
152 on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
153 MODEST_CONF_EVENT_KEY_CHANGED, 0, NULL);
154 modest_account_mgr_free_account_names (acc_names);
161 modest_platform_uninit (void)
170 modest_platform_get_new_device (void)
172 return TNY_DEVICE (tny_gnome_device_new ());
176 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
177 gchar **effective_mime_type)
179 gchar *icon_name = NULL;
182 gchar **icon_names, **cursor;
184 if (!mime_type || g_ascii_strcasecmp (mime_type, "application/octet-stream") == 0)
185 content_type = g_content_type_guess (name, NULL, 0, NULL);
187 content_type = g_content_type_from_mime_type (mime_type);
191 content_type = g_content_type_from_mime_type ("application/octet-stream");
193 icon = g_content_type_get_icon (content_type);
194 if (!G_THEMED_ICON (icon))
197 g_object_get (G_OBJECT (icon), "names", &icon_names, NULL);
199 for (cursor = icon_names; cursor; ++cursor) {
200 if (!g_ascii_strcasecmp (*cursor, "gnome-mime-message") ||
201 !g_ascii_strcasecmp (*cursor, "gnome-mime-message-rfc822")) {
202 icon_name = g_strdup ("stock_message-display");
204 } else if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default(), *cursor)) {
205 icon_name = g_strdup (*cursor);
209 g_strfreev (icon_names);
218 modest_platform_activate_uri (const gchar *uri)
220 GAppLaunchContext *al_context;
223 al_context = gdk_app_launch_context_new ();
224 retval = g_app_info_launch_default_for_uri (uri, al_context, NULL);
225 g_object_unref (al_context);
232 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
239 GAppLaunchContext *al_context;
241 content_type = g_content_type_from_mime_type (mime_type);
245 app_info = g_app_info_get_default_for_type (content_type, FALSE);
246 g_free (content_type);
248 content_type = g_content_type_guess (path, NULL, 0, NULL);
252 app_info = g_app_info_get_default_for_type (content_type, FALSE);
253 g_free (content_type);
260 file = g_file_new_for_path (path);
261 list = g_list_prepend (NULL, file);
262 al_context = gdk_app_launch_context_new ();
263 retval = g_app_info_launch (app_info, list, al_context, NULL);
264 g_object_unref (al_context);
267 g_object_unref (file);
273 modest_platform_show_uri_popup (const gchar *uri)
275 g_warning ("Not implemented %s", __FUNCTION__);
282 modest_platform_get_icon (const gchar *name, guint icon_size)
284 return gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
292 modest_platform_get_app_name (void)
294 return _("mcen_ap_name");
298 entry_insert_text (GtkEditable *editable,
307 chars = gtk_editable_get_chars (editable, 0, -1);
308 chars_length = g_utf8_strlen (chars, -1);
311 /* Show WID-INF036 */
312 if (chars_length >= 20) {
313 modest_platform_information_banner (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
314 _CS("ckdg_ib_maximum_characters_reached"));
316 if (modest_text_utils_is_forbidden_char (*text, FOLDER_NAME_FORBIDDEN_CHARS)) {
320 tmp = g_strndup (folder_name_forbidden_chars,
321 FOLDER_NAME_FORBIDDEN_CHARS_LENGTH);
322 msg = g_strdup_printf (_CS("ckdg_ib_illegal_characters_entered"), tmp);
323 modest_platform_information_banner (gtk_widget_get_parent (GTK_WIDGET (data)),
329 modest_platform_information_banner (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
330 _CS("ckdg_ib_maximum_characters_reached"));
332 /* Write the text in the entry if it's valid */
333 g_signal_handlers_block_by_func (editable,
334 (gpointer) entry_insert_text, data);
335 gtk_editable_insert_text (editable, text, length, position);
336 g_signal_handlers_unblock_by_func (editable,
337 (gpointer) entry_insert_text, data);
340 /* Do not allow further processing */
341 g_signal_stop_emission_by_name (editable, "insert_text");
345 entry_changed (GtkEditable *editable,
349 GtkWidget *ok_button;
352 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
353 ok_button = GTK_WIDGET (buttons->data);
355 chars = gtk_editable_get_chars (editable, 0, -1);
356 g_return_if_fail (chars != NULL);
359 if (g_utf8_strlen (chars,-1) >= 20) {
360 modest_platform_information_banner (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
361 _CS("ckdg_ib_maximum_characters_reached"));
363 gtk_widget_set_sensitive (ok_button, modest_text_utils_validate_folder_name(chars));
366 g_list_free (buttons);
373 on_response (GtkDialog *dialog,
377 GtkWidget *entry, *picker;
378 TnyFolderStore *parent;
379 const gchar *new_name;
382 if (response != GTK_RESPONSE_ACCEPT)
386 entry = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY);
387 picker = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER);
389 parent = TNY_FOLDER_STORE (user_data);
390 new_name = gtk_entry_get_text (GTK_ENTRY (entry));
394 parent = g_object_get_data (G_OBJECT (picker), FOLDER_PICKER_CURRENT_FOLDER);
396 /* Look for another folder with the same name */
397 if (!TNY_IS_MERGE_FOLDER (parent) &&
398 modest_tny_folder_has_subfolder_with_name (parent, new_name, TRUE))
402 if (TNY_IS_ACCOUNT (parent) &&
403 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (parent)) &&
404 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (parent),
412 modest_platform_information_banner (gtk_widget_get_parent (GTK_WIDGET (dialog)),
413 NULL, _CS("ckdg_ib_folder_already_exists"));
414 /* Select the text */
415 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
416 gtk_widget_grab_focus (entry);
417 /* Do not close the dialog */
418 g_signal_stop_emission_by_name (dialog, "response");
422 typedef struct _FolderChooserData {
423 TnyFolderStore *store;
428 folder_chooser_activated (ModestFolderView *folder_view,
429 TnyFolderStore *folder,
430 FolderChooserData *userdata)
432 userdata->store = folder;
433 gtk_dialog_response (GTK_DIALOG (userdata->dialog), GTK_RESPONSE_OK);
436 static TnyFolderStore *
437 folder_chooser_dialog_run (ModestFolderView *original,
438 TnyFolderStore *current,
441 GtkWidget *folder_view;
442 FolderChooserData userdata = {NULL, NULL};
443 GtkWidget *scrollable;
444 const gchar *visible_id = NULL;
446 userdata.dialog = gtk_dialog_new ();
447 scrollable = modest_toolkit_factory_create_scrollable (modest_runtime_get_toolkit_factory ());
448 folder_view = modest_platform_create_folder_view (NULL);
450 gtk_window_set_title (GTK_WINDOW (userdata.dialog), _FM("ckdg_ti_change_folder"));
452 modest_folder_view_copy_model (MODEST_FOLDER_VIEW (original),
453 MODEST_FOLDER_VIEW (folder_view));
455 if (TNY_IS_ACCOUNT (current)) {
456 /* Local folders and MMC account are always shown
457 along with the currently visible server account */
458 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (current)) ||
459 modest_tny_account_is_memory_card_account (TNY_ACCOUNT (current)))
460 visible_id = g_object_get_data ((GObject *) picker, FOLDER_PICKER_ORIGINAL_ACCOUNT);
462 visible_id = tny_account_get_id (TNY_ACCOUNT (current));
463 } else if (TNY_IS_FOLDER (current)) {
465 account = modest_tny_folder_get_account ((TnyFolder *) current);
467 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (account)) ||
468 modest_tny_account_is_memory_card_account (TNY_ACCOUNT (account))) {
469 visible_id = g_object_get_data ((GObject *) picker, FOLDER_PICKER_ORIGINAL_ACCOUNT);
471 visible_id = tny_account_get_id (account);
473 g_object_unref (account);
477 modest_folder_view_get_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(original));
480 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(folder_view),
483 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (userdata.dialog)->vbox), scrollable);
484 gtk_container_add (GTK_CONTAINER (scrollable), folder_view);
485 gtk_widget_set_size_request (scrollable, -1, 320);
487 gtk_widget_show (folder_view);
488 gtk_widget_show (scrollable);
489 gtk_widget_show (userdata.dialog);
490 g_signal_connect (G_OBJECT (folder_view), "folder-activated",
491 G_CALLBACK (folder_chooser_activated),
492 (gpointer) &userdata);
494 gtk_dialog_run (GTK_DIALOG (userdata.dialog));
495 gtk_widget_destroy (userdata.dialog);
497 return userdata.store;
501 folder_store_get_display_name (TnyFolderStore *store)
503 if (TNY_IS_ACCOUNT (store)) {
504 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
505 return modest_conf_get_string (modest_runtime_get_conf(),
506 MODEST_CONF_DEVICE_NAME, NULL);
508 return g_strdup (tny_account_get_name (TNY_ACCOUNT (store)));
511 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
513 fname = g_strdup (tny_folder_get_name (TNY_FOLDER (store)));
514 type = tny_folder_get_folder_type (TNY_FOLDER (store));
515 if (modest_tny_folder_is_local_folder (TNY_FOLDER (store)) ||
516 modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
517 type = modest_tny_folder_get_local_or_mmc_folder_type (TNY_FOLDER (store));
518 if (type != TNY_FOLDER_TYPE_UNKNOWN) {
520 fname = g_strdup (modest_local_folder_info_get_type_display_name (type));
523 /* Sometimes an special folder is reported by the server as
524 NORMAL, like some versions of Dovecot */
525 if (type == TNY_FOLDER_TYPE_NORMAL ||
526 type == TNY_FOLDER_TYPE_UNKNOWN) {
527 type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
531 if (type == TNY_FOLDER_TYPE_INBOX) {
533 fname = g_strdup (_("mcen_me_folder_inbox"));
540 get_image_for_folder_store (TnyFolderStore *store,
544 const gchar *icon_name = NULL;
545 GtkWidget *image = NULL;
547 if (TNY_IS_ACCOUNT (store)) {
548 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
549 icon_name = MODEST_FOLDER_ICON_LOCAL_FOLDERS;
550 else if (modest_tny_account_is_memory_card_account (TNY_ACCOUNT (store)))
551 icon_name = MODEST_FOLDER_ICON_MMC;
553 icon_name = MODEST_FOLDER_ICON_ACCOUNT;
555 TnyFolderType type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
556 if (modest_tny_folder_is_remote_folder (TNY_FOLDER (store))) {
558 case TNY_FOLDER_TYPE_INBOX:
559 icon_name = MODEST_FOLDER_ICON_INBOX;
562 icon_name = MODEST_FOLDER_ICON_REMOTE_FOLDER;
564 } else if (modest_tny_folder_is_local_folder (TNY_FOLDER (store))) {
566 case TNY_FOLDER_TYPE_OUTBOX:
567 icon_name = MODEST_FOLDER_ICON_OUTBOX;
569 case TNY_FOLDER_TYPE_DRAFTS:
570 icon_name = MODEST_FOLDER_ICON_DRAFTS;
572 case TNY_FOLDER_TYPE_SENT:
573 icon_name = MODEST_FOLDER_ICON_SENT;
576 icon_name = MODEST_FOLDER_ICON_NORMAL;
578 } else if (modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
579 icon_name = MODEST_FOLDER_ICON_MMC_FOLDER;
584 pixbuf = modest_platform_get_icon (icon_name, size);
587 image = gtk_image_new_from_pixbuf (pixbuf);
588 g_object_unref (pixbuf);
595 folder_picker_set_store (GtkButton *button, TnyFolderStore *store)
600 g_object_set_data (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER, NULL);
604 g_object_set_data_full (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER,
605 g_object_ref (store),
606 (GDestroyNotify) g_object_unref);
607 name = folder_store_get_display_name (store);
608 gtk_button_set_label (GTK_BUTTON (button), name);
612 image = get_image_for_folder_store (store, MODEST_ICON_SIZE_SMALL);
614 gtk_button_set_image (GTK_BUTTON (button), image);
618 /* Always returns DUPs so you must free the returned value */
620 get_next_folder_name (const gchar *suggested_name,
621 TnyFolderStore *suggested_folder)
623 const gchar *default_name = _FM("ckdg_va_new_folder_name_stub");
625 gchar *real_suggested_name;
627 if (suggested_name !=NULL) {
628 return g_strdup (suggested_name);
631 for(i = 0; i < 100; ++ i) {
632 gboolean exists = FALSE;
635 real_suggested_name = g_strdup (default_name);
637 real_suggested_name = g_strdup_printf ("%s(%d)",
638 _FM("ckdg_va_new_folder_name_stub"),
640 exists = modest_tny_folder_has_subfolder_with_name (suggested_folder,
647 g_free (real_suggested_name);
650 /* Didn't find a free number */
652 real_suggested_name = g_strdup (default_name);
654 return real_suggested_name;
658 ModestFolderView *folder_view;
660 } FolderPickerHelper;
663 folder_picker_clicked (GtkButton *button,
664 FolderPickerHelper *helper)
666 TnyFolderStore *store, *current;
668 current = g_object_get_data (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER);
670 store = folder_chooser_dialog_run (helper->folder_view, current, button);
672 const gchar *current_name;
673 gboolean exists = FALSE;
675 folder_picker_set_store (GTK_BUTTON (button), store);
677 /* Update the name of the folder */
678 current_name = gtk_entry_get_text (helper->entry);
680 if (TNY_IS_FOLDER_STORE (store))
681 exists = modest_tny_folder_has_subfolder_with_name (store,
685 gchar *new_name = get_next_folder_name (NULL, store);
686 gtk_entry_set_text (helper->entry, new_name);
693 folder_picker_new (TnyFolderStore *suggested, FolderPickerHelper *helper)
696 const gchar *acc_id = NULL;
698 button = gtk_button_new ();
700 gtk_misc_set_alignment (GTK_MISC (button), 0.0, 0.5);
704 folder_picker_set_store (GTK_BUTTON (button), suggested);
706 if (TNY_IS_ACCOUNT (suggested)) {
707 if (!modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (suggested)) &&
708 !modest_tny_account_is_memory_card_account (TNY_ACCOUNT (suggested)))
709 acc_id = tny_account_get_id ((TnyAccount *) suggested);
711 TnyAccount *account = modest_tny_folder_get_account ((TnyFolder *) suggested);
713 acc_id = tny_account_get_id ((TnyAccount *) account);
714 g_object_unref (account);
720 acc_id = modest_folder_view_get_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(helper->folder_view));
722 g_object_set_data_full (G_OBJECT (button), FOLDER_PICKER_ORIGINAL_ACCOUNT,
723 g_strdup (acc_id), (GDestroyNotify) g_free);
726 g_signal_connect (G_OBJECT (button), "clicked",
727 G_CALLBACK (folder_picker_clicked),
735 modest_platform_run_folder_common_dialog (GtkWindow *parent_window,
736 TnyFolderStore *suggested_parent,
737 const gchar *dialog_title,
738 const gchar *label_text,
739 const gchar *suggested_name,
741 gboolean show_parent,
743 TnyFolderStore **parent)
745 GtkWidget *accept_btn = NULL;
746 GtkWidget *dialog, *entry = NULL, *label_entry = NULL, *label_location = NULL, *hbox;
747 GtkWidget *account_picker = NULL;
748 GList *buttons = NULL;
750 GtkSizeGroup *sizegroup;
751 ModestFolderView *folder_view;
752 ModestWindow *folder_window;
753 ModestWindowMgr *window_mgr;
754 FolderPickerHelper *helper = NULL;
755 GtkWidget *top_vbox, *top_align;
757 window_mgr = modest_runtime_get_window_mgr ();
758 folder_window = modest_window_mgr_get_folder_window (window_mgr);
759 g_return_val_if_fail (MODEST_IS_FOLDER_WINDOW (folder_window), GTK_RESPONSE_NONE);
761 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (folder_window));
763 top_vbox = gtk_vbox_new (FALSE, 0);
764 top_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
765 gtk_alignment_set_padding (GTK_ALIGNMENT (top_align), 0, 0, MODEST_MARGIN_DOUBLE, 0);
767 /* Ask the user for the folder name */
768 dialog = gtk_dialog_new_with_buttons (dialog_title,
770 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
771 _FM("ckdg_bd_new_folder_dialog_ok"),
775 /* Add accept button (with unsensitive handler) */
776 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
777 accept_btn = GTK_WIDGET (buttons->data);
779 sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
782 label_entry = gtk_label_new (label_text);
783 entry = modest_toolkit_factory_create_entry (modest_runtime_get_toolkit_factory ());
784 gtk_entry_set_max_length (GTK_ENTRY (entry), 20);
786 gtk_misc_set_alignment (GTK_MISC (label_entry), 0.0, 0.5);
787 gtk_size_group_add_widget (sizegroup, label_entry);
790 gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
792 gtk_entry_set_text (GTK_ENTRY (entry), _FM("ckdg_va_new_folder_name_stub"));
793 gtk_entry_set_width_chars (GTK_ENTRY (entry),
794 MAX (g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (entry)), -1),
795 g_utf8_strlen (_FM("ckdg_va_new_folder_name_stub"), -1)));
796 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
801 label_location = gtk_label_new (_FM("ckdg_fi_new_folder_location"));
803 gtk_misc_set_alignment (GTK_MISC (label_location), 0.0, 0.5);
804 gtk_size_group_add_widget (sizegroup, label_location);
806 helper = g_slice_new0 (FolderPickerHelper);
807 helper->folder_view = folder_view;
808 helper->entry = (GtkEntry *) entry;
810 account_picker = folder_picker_new (suggested_parent, helper);
813 g_object_unref (sizegroup);
815 /* Connect to the response method to avoid closing the dialog
816 when an invalid name is selected*/
817 g_signal_connect (dialog,
819 G_CALLBACK (on_response),
823 /* Track entry changes */
824 g_signal_connect (entry,
826 G_CALLBACK (entry_insert_text),
828 g_signal_connect (entry,
830 G_CALLBACK (entry_changed),
835 /* Some locales like pt_BR need this to get the full window
837 gtk_widget_set_size_request (GTK_WIDGET (dialog), 300, -1);
839 /* Create the hbox */
841 hbox = gtk_hbox_new (FALSE, 12);
842 gtk_box_pack_start (GTK_BOX (hbox), label_entry, FALSE, FALSE, 0);
843 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
845 /* Add hbox to dialog */
846 gtk_box_pack_start (GTK_BOX (top_vbox),
847 hbox, FALSE, FALSE, 0);
848 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY, entry);
852 hbox = gtk_hbox_new (FALSE, 12);
853 gtk_box_pack_start (GTK_BOX (hbox), label_location, FALSE, FALSE, 0);
854 gtk_box_pack_start (GTK_BOX (hbox), account_picker, TRUE, TRUE, 0);
856 /* Add hbox to dialog */
857 gtk_box_pack_start (GTK_BOX (top_vbox),
858 hbox, FALSE, FALSE, 0);
859 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER, account_picker);
861 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
862 GTK_WINDOW (dialog), parent_window);
864 gtk_container_add (GTK_CONTAINER (top_align), top_vbox);
865 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), top_align, TRUE, TRUE, 0);
867 gtk_widget_show_all (GTK_WIDGET(dialog));
869 result = gtk_dialog_run (GTK_DIALOG(dialog));
870 if (result == GTK_RESPONSE_ACCEPT) {
872 *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
874 *parent = g_object_get_data (G_OBJECT (account_picker), FOLDER_PICKER_CURRENT_FOLDER);
876 g_object_ref (*parent);
880 gtk_widget_destroy (dialog);
883 g_slice_free (FolderPickerHelper, helper);
885 while (gtk_events_pending ())
886 gtk_main_iteration ();
892 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
893 TnyFolderStore *suggested_folder,
894 gchar *suggested_name,
896 TnyFolderStore **parent_folder)
898 gchar *real_suggested_name = NULL;
900 ModestTnyAccountStore *acc_store;
902 gboolean do_free = FALSE;
904 real_suggested_name = get_next_folder_name ((const gchar *) suggested_name,
907 /* In hildon 2.2 we always suggest the archive folder as parent */
908 if (!suggested_folder) {
909 acc_store = modest_runtime_get_account_store ();
910 account = modest_tny_account_store_get_mmc_folders_account (acc_store);
912 suggested_folder = (TnyFolderStore *)
913 modest_tny_account_get_special_folder (account,
914 TNY_FOLDER_TYPE_ARCHIVE);
915 g_object_unref (account);
920 /* If there is not archive folder then fallback to local folders account */
921 if (!suggested_folder) {
923 suggested_folder = (TnyFolderStore *)
924 modest_tny_account_store_get_local_folders_account (acc_store);
927 result = modest_platform_run_folder_common_dialog (parent_window,
929 _HL_TITLE_NEW_FOLDER,
930 _FM("ckdg_fi_new_folder_name"),
938 g_object_unref (suggested_folder);
940 g_free(real_suggested_name);
946 modest_platform_run_rename_folder_dialog (ModestWindow *parent_window,
947 TnyFolderStore *parent_folder,
948 const gchar *suggested_name,
951 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
953 return modest_platform_run_folder_common_dialog (gtk_widget_get_toplevel (GTK_WIDGET (parent_window)),
955 _HL_TITLE_RENAME_FOLDER,
967 on_destroy_dialog (GtkWidget *dialog)
969 /* This could happen when the dialogs get programatically
970 hidden or destroyed (for example when closing the
971 application while a dialog is being shown) */
972 if (!GTK_IS_WIDGET (dialog))
975 gtk_widget_destroy (dialog);
977 if (gtk_events_pending ())
978 gtk_main_iteration ();
982 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
983 const gchar *message)
988 dialog = gtk_message_dialog_new (parent_window, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
989 GTK_MESSAGE_QUESTION,
990 GTK_BUTTONS_OK_CANCEL,
992 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
993 GTK_WINDOW (dialog), parent_window);
995 response = gtk_dialog_run (GTK_DIALOG (dialog));
997 on_destroy_dialog (dialog);
1003 modest_platform_run_confirmation_dialog_with_buttons (GtkWindow *parent_window,
1004 const gchar *message,
1005 const gchar *button_accept,
1006 const gchar *button_cancel)
1011 dialog = gtk_message_dialog_new (parent_window, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1012 GTK_MESSAGE_QUESTION,
1015 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
1016 button_accept, GTK_RESPONSE_ACCEPT,
1017 button_cancel, GTK_RESPONSE_CANCEL,
1020 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1021 GTK_WINDOW (dialog), parent_window);
1023 response = gtk_dialog_run (GTK_DIALOG (dialog));
1025 on_destroy_dialog (dialog);
1031 modest_platform_run_information_dialog (GtkWindow *parent_window,
1032 const gchar *message,
1037 note = gtk_message_dialog_new (parent_window, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1042 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1043 GTK_WINDOW (note), parent_window);
1046 gtk_dialog_run (GTK_DIALOG (note));
1048 on_destroy_dialog (note);
1050 g_signal_connect_swapped (note,
1052 G_CALLBACK (on_destroy_dialog),
1055 gtk_widget_show_all (note);
1059 typedef struct _ConnectAndWaitData {
1061 GMainLoop *wait_loop;
1062 gboolean has_callback;
1064 } ConnectAndWaitData;
1068 modest_platform_connect_and_wait (GtkWindow *parent_window,
1069 TnyAccount *account)
1071 gboolean device_online;
1073 TnyConnectionStatus conn_status;
1074 gboolean user_requested;
1076 device = modest_runtime_get_device();
1077 device_online = tny_device_is_online (device);
1079 /* Whether the connection is user requested or automatically
1080 requested, for example via D-Bus */
1081 user_requested = (parent_window) ? TRUE : FALSE;
1083 /* If there is no account check only the device status */
1088 /* TODO: should show connection dialog through gnome device */
1092 /* Return if the account is already connected */
1093 conn_status = tny_account_get_connection_status (account);
1094 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
1101 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1103 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1104 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1105 /* This must be a maildir account, which does not require a connection: */
1110 return modest_platform_connect_and_wait (parent_window, account);
1114 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1117 return TRUE; /* Maybe it is something local. */
1119 gboolean result = TRUE;
1120 if (TNY_IS_FOLDER (folder_store)) {
1121 /* Get the folder's parent account: */
1122 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1123 if (account != NULL) {
1124 result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1125 g_object_unref (account);
1127 } else if (TNY_IS_ACCOUNT (folder_store)) {
1128 /* Use the folder store as an account: */
1129 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1136 modest_platform_create_sort_dialog (GtkWindow *parent_window)
1144 modest_platform_set_update_interval (guint minutes)
1150 modest_platform_push_email_notification(void)
1156 modest_platform_on_new_headers_received (GList *URI_list,
1157 gboolean show_visual)
1163 modest_platform_remove_new_mail_notifications (gboolean only_visuals)
1171 modest_platform_get_global_settings_dialog ()
1173 return modest_default_global_settings_dialog_new ();
1177 modest_platform_show_help (GtkWindow *parent_window,
1178 const gchar *help_id)
1184 modest_platform_show_search_messages (GtkWindow *parent_window)
1190 modest_platform_show_addressbook (GtkWindow *parent_window)
1196 modest_platform_create_folder_view_full (TnyFolderStoreQuery *query, gboolean do_refresh)
1198 GtkWidget *widget = modest_folder_view_new_full (query, do_refresh);
1200 /* Show one account by default */
1201 modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1202 MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1208 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1210 return modest_platform_create_folder_view_full (query, TRUE);
1214 banner_finish (gpointer data, GObject *object)
1216 ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1217 modest_window_mgr_unregister_banner (mgr);
1218 g_object_unref (mgr);
1222 modest_platform_information_banner (GtkWidget *parent,
1223 const gchar *icon_name,
1228 banner = modest_shell_banner_new (parent);
1229 modest_shell_banner_set_icon (MODEST_SHELL_BANNER (banner), icon_name);
1230 modest_shell_banner_set_text (MODEST_SHELL_BANNER (banner), text);
1236 modest_platform_system_banner (GtkWidget *parent,
1237 const gchar *icon_name,
1240 modest_platform_information_banner (parent, icon_name, text);
1244 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1245 const gchar *icon_name,
1251 banner = modest_shell_banner_new_with_timeout (parent, timeout);
1252 modest_shell_banner_set_icon (MODEST_SHELL_BANNER (banner), icon_name);
1253 modest_shell_banner_set_text (MODEST_SHELL_BANNER (banner), text);
1259 modest_platform_animation_banner (GtkWidget *parent,
1260 const gchar *animation_name,
1265 banner = modest_shell_banner_new_with_timeout (parent, 0);
1266 modest_shell_banner_set_animation (MODEST_SHELL_BANNER (banner), animation_name);
1267 modest_shell_banner_set_text (MODEST_SHELL_BANNER (banner), text);
1275 TnyAccount *account;
1278 } CheckAccountIdleData;
1280 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1283 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1285 gboolean stop_trying = FALSE;
1286 g_return_val_if_fail (data && data->account, FALSE);
1288 if (data && data->account &&
1289 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1290 * after which the account is likely to be usable, or never likely to be usable soon: */
1291 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1293 data->is_online = TRUE;
1297 /* Give up if we have tried too many times: */
1298 if (data->count_tries >= NUMBER_OF_TRIES) {
1301 /* Wait for another timeout: */
1302 ++(data->count_tries);
1307 /* Allow the function that requested this idle callback to continue: */
1309 g_main_loop_quit (data->loop);
1312 g_object_unref (data->account);
1314 return FALSE; /* Don't call this again. */
1316 return TRUE; /* Call this timeout callback again. */
1320 /* Return TRUE immediately if the account is already online,
1321 * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as
1322 * soon as the account is online, or FALSE if the account does
1323 * not become online in the NUMBER_OF_TRIES seconds.
1324 * This is useful when the D-Bus method was run immediately after
1325 * the application was started (when using D-Bus activation),
1326 * because the account usually takes a short time to go online.
1327 * The return value is maybe not very useful.
1330 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1334 g_return_val_if_fail (account, FALSE);
1336 if (!tny_device_is_online (modest_runtime_get_device())) {
1337 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1341 /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1342 * so we avoid wait unnecessarily: */
1343 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1346 /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED,
1347 * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that
1348 * we want to avoid. */
1349 if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1352 /* This blocks on the result: */
1353 CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1354 data->is_online = FALSE;
1355 data->account = account;
1356 g_object_ref (data->account);
1357 data->count_tries = 0;
1359 GMainContext *context = NULL; /* g_main_context_new (); */
1360 data->loop = g_main_loop_new (context, FALSE /* not running */);
1362 g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1364 /* This main loop will run until the idle handler has stopped it: */
1365 g_main_loop_run (data->loop);
1367 g_main_loop_unref (data->loop);
1368 /* g_main_context_unref (context); */
1370 is_online = data->is_online;
1371 g_slice_free (CheckAccountIdleData, data);
1379 on_cert_dialog_response (GtkDialog *dialog, gint response_id, const gchar* cert)
1381 /* GTK_RESPONSE_HELP means we need to show the certificate */
1382 if (response_id == GTK_RESPONSE_APPLY) {
1385 /* Do not close the dialog */
1386 g_signal_stop_emission_by_name (dialog, "response");
1388 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);
1389 modest_platform_run_information_dialog (NULL, msg, TRUE);
1395 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1396 const gchar *certificate)
1402 gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1405 /* We use GTK_RESPONSE_APPLY because we want the button in the
1406 middle of OK and CANCEL the same as the browser does for
1407 example. With GTK_RESPONSE_HELP the view button is aligned
1408 to the left while the other two to the right */
1409 note = gtk_message_dialog_new (
1411 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1412 GTK_MESSAGE_QUESTION,
1415 gtk_dialog_add_buttons (GTK_DIALOG (note),
1416 _HL_YES, GTK_RESPONSE_OK,
1417 _HL_VIEW, GTK_RESPONSE_APPLY, /* abusing this... */
1418 _HL_NO, GTK_RESPONSE_CANCEL,
1421 g_signal_connect (G_OBJECT(note), "response",
1422 G_CALLBACK(on_cert_dialog_response),
1423 (gpointer) certificate);
1425 response = gtk_dialog_run(GTK_DIALOG(note));
1427 on_destroy_dialog (note);
1430 return response == GTK_RESPONSE_OK;
1434 modest_platform_run_alert_dialog (const gchar* prompt,
1435 gboolean is_question)
1438 gboolean retval = TRUE;
1441 /* The Tinymail documentation says that we should show Yes and No buttons,
1442 * when it is a question.
1443 * Obviously, we need tinymail to use more specific error codes instead,
1444 * so we know what buttons to show. */
1445 dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1446 GTK_MESSAGE_QUESTION,
1450 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
1451 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
1453 on_destroy_dialog (dialog);
1455 /* Just show the error text and use the default response: */
1456 modest_platform_run_information_dialog (NULL,
1464 GtkWindow *parent_window;
1465 ModestConnectedPerformer callback;
1466 TnyAccount *account;
1473 on_went_online_info_free (OnWentOnlineInfo *info)
1475 /* And if we cleanup, we DO cleanup :-) */
1478 g_object_unref (info->device);
1481 if (info->parent_window)
1482 g_object_unref (info->parent_window);
1484 g_object_unref (info->account);
1486 g_slice_free (OnWentOnlineInfo, info);
1488 /* We're done ... */
1494 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
1496 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1498 /* Now it's really time to callback to the caller. If going online didn't succeed,
1499 * err will be set. We don't free it, Tinymail does that! If a cancel happened,
1500 * canceled will be set. Etcetera etcetera. */
1502 if (info->callback) {
1503 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1506 /* This is our last call, we must cleanup here if we didn't yet do that */
1507 on_went_online_info_free (info);
1513 modest_platform_connect_and_perform (GtkWindow *parent_window,
1515 TnyAccount *account,
1516 ModestConnectedPerformer callback,
1519 gboolean device_online;
1521 TnyConnectionStatus conn_status;
1523 device = modest_runtime_get_device();
1524 device_online = tny_device_is_online (device);
1526 /* If there is no account check only the device status */
1529 if (device_online) {
1531 /* We promise to instantly perform the callback, so ... */
1533 callback (FALSE, NULL, parent_window, account, user_data);
1540 /* The other code has no more reason to run. This is all that we can do for the
1541 * caller (he should have given us a nice and clean account instance!). We
1542 * can't do magic, we don't know what account he intends to bring online. So
1543 * we'll just bring the device online (and await his false bug report). */
1549 /* Return if the account is already connected */
1551 conn_status = tny_account_get_connection_status (account);
1552 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
1554 /* We promise to instantly perform the callback, so ... */
1556 callback (FALSE, NULL, parent_window, account, user_data);
1562 if (!device_online) {
1563 OnWentOnlineInfo *info = NULL;
1565 info = g_slice_new0 (OnWentOnlineInfo);
1567 info->device = NULL;
1569 info->account = TNY_ACCOUNT (g_object_ref (account));
1572 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
1574 info->parent_window = NULL;
1576 /* So we'll put the callback away for later ... */
1577 info->user_data = user_data;
1578 info->callback = callback;
1580 /* If the device is online, we'll just connect the account */
1581 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1582 on_account_went_online, info);
1585 /* The info gets freed by on_account_went_online or on_conic_device_went_online
1586 * in both situations, go look if you don't believe me! */
1590 modest_platform_connect_if_remote_and_perform (GtkWindow *parent_window,
1592 TnyFolderStore *folder_store,
1593 ModestConnectedPerformer callback,
1596 TnyAccount *account = NULL;
1598 if (!folder_store ||
1599 (TNY_IS_MERGE_FOLDER (folder_store) &&
1600 (tny_folder_get_folder_type (TNY_FOLDER(folder_store)) == TNY_FOLDER_TYPE_OUTBOX))) {
1602 /* We promise to instantly perform the callback, so ... */
1604 GError *error = NULL;
1605 g_set_error (&error, TNY_ERROR_DOMAIN, TNY_SERVICE_ERROR_UNKNOWN,
1606 "Unable to move or not found folder");
1607 callback (FALSE, error, parent_window, NULL, user_data);
1608 g_error_free (error);
1612 } else if (TNY_IS_FOLDER (folder_store)) {
1613 /* Get the folder's parent account: */
1614 account = tny_folder_get_account (TNY_FOLDER (folder_store));
1615 } else if (TNY_IS_ACCOUNT (folder_store)) {
1616 /* Use the folder store as an account: */
1617 account = TNY_ACCOUNT (g_object_ref (folder_store));
1620 if (account && (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE)) {
1621 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1622 /* No need to connect a local account */
1624 callback (FALSE, NULL, parent_window, account, user_data);
1629 modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
1633 g_object_unref (account);
1637 src_account_connect_performer (gboolean canceled,
1639 GtkWindow *parent_window,
1640 TnyAccount *src_account,
1643 DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
1645 if (canceled || err) {
1646 /* If there was any error call the user callback */
1647 info->callback (canceled, err, parent_window, src_account, info->data);
1649 /* Connect the destination account */
1650 modest_platform_connect_if_remote_and_perform (parent_window, TRUE,
1651 TNY_FOLDER_STORE (info->dst_account),
1652 info->callback, info->data);
1655 /* Free the info object */
1656 g_object_unref (info->dst_account);
1657 g_slice_free (DoubleConnectionInfo, info);
1662 modest_platform_double_connect_and_perform (GtkWindow *parent_window,
1664 TnyFolderStore *folder_store,
1665 DoubleConnectionInfo *connect_info)
1667 modest_platform_connect_if_remote_and_perform(parent_window,
1670 src_account_connect_performer,
1675 modest_platform_get_account_settings_wizard (void)
1677 ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
1679 return GTK_WIDGET (dialog);
1683 modest_platform_get_current_connection (void)
1685 TnyDevice *device = NULL;
1686 ModestConnectedVia retval = MODEST_CONNECTED_VIA_ANY;
1688 device = modest_runtime_get_device ();
1690 if (!tny_device_is_online (device))
1691 return MODEST_CONNECTED_VIA_ANY;
1693 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX; /* assume WLAN (fast) internet */
1700 modest_platform_check_memory_low (ModestWindow *win,
1708 modest_platform_run_folder_details_dialog (GtkWindow *parent_window,
1714 dialog = modest_toolkit_factory_create_details_dialog_with_folder (modest_runtime_get_toolkit_factory (),
1715 parent_window, folder);
1718 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1719 GTK_WINDOW (dialog),
1721 gtk_widget_show_all (dialog);
1723 g_signal_connect_swapped (dialog, "response",
1724 G_CALLBACK (gtk_widget_destroy),
1728 typedef struct _HeaderDetailsGetSizeInfo {
1732 } HeaderDetailsGetSizeInfo;
1735 header_details_dialog_destroy (gpointer userdata,
1738 HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) userdata;
1740 info->dialog = NULL;
1744 idle_get_mime_part_size_cb (gpointer userdata)
1746 HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) userdata;
1747 gdk_threads_enter ();
1749 if (info->dialog && GTK_WIDGET_VISIBLE (info->dialog)) {
1750 modest_details_dialog_set_message_size (MODEST_DETAILS_DIALOG (info->dialog),
1755 g_object_weak_unref (G_OBJECT (info->dialog), header_details_dialog_destroy, info);
1756 info->dialog = NULL;
1758 g_object_unref (info->part);
1759 g_slice_free (HeaderDetailsGetSizeInfo, info);
1761 gdk_threads_leave ();
1767 get_mime_part_size_thread (gpointer thr_user_data)
1769 HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) thr_user_data;
1771 TnyStream *count_stream;
1773 count_stream = modest_count_stream_new ();
1774 result = tny_mime_part_decode_to_stream (info->part, count_stream, NULL);
1775 info->total = modest_count_stream_get_count(MODEST_COUNT_STREAM (count_stream));
1776 if (info->total == 0) {
1777 modest_count_stream_reset_count(MODEST_COUNT_STREAM (count_stream));
1778 result = tny_mime_part_write_to_stream (info->part, count_stream, NULL);
1779 info->total = modest_count_stream_get_count(MODEST_COUNT_STREAM (count_stream));
1782 /* if there was an error, don't set the size (this is pretty uncommon) */
1784 g_warning ("%s: error while writing mime part to stream\n", __FUNCTION__);
1786 g_idle_add (idle_get_mime_part_size_cb, info);
1792 modest_platform_run_header_details_dialog (GtkWindow *parent_window,
1794 gboolean async_get_size,
1800 dialog = modest_toolkit_factory_create_details_dialog_with_header (modest_runtime_get_toolkit_factory (),
1801 parent_window, header, !async_get_size);
1803 if (async_get_size && msg && TNY_IS_MSG (msg)) {
1804 HeaderDetailsGetSizeInfo *info;
1805 info = g_slice_new (HeaderDetailsGetSizeInfo);
1806 info->dialog = dialog;
1808 info->part = TNY_MIME_PART (g_object_ref (msg));
1810 g_object_weak_ref (G_OBJECT (dialog), header_details_dialog_destroy, info);
1811 g_thread_create (get_mime_part_size_thread, info, FALSE, NULL);
1815 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1816 GTK_WINDOW (dialog),
1818 gtk_widget_show_all (dialog);
1820 g_signal_connect_swapped (dialog, "response",
1821 G_CALLBACK (gtk_widget_destroy),
1825 #define MOVE_TO_DIALOG_FOLDER_VIEW "folder-view"
1826 #define MOVE_TO_DIALOG_BACK_BUTTON "back-button"
1827 #define MOVE_TO_DIALOG_ACTION_BUTTON "action-button"
1828 #define MOVE_TO_DIALOG_SHOWING_FOLDERS "showing-folders"
1829 #define MOVE_TO_DIALOG_SCROLLABLE "scrollable"
1830 #define MOVE_TO_FOLDER_SEPARATOR "/"
1833 translate_path (gchar **path)
1838 gboolean add_separator;
1840 parts = g_strsplit (*path, MOVE_TO_FOLDER_SEPARATOR, 0);
1844 output = g_string_new ("");
1845 add_separator = FALSE;
1847 while (*current != NULL) {
1848 TnyFolderType folder_type;
1851 if (add_separator) {
1852 output = g_string_append (output, MOVE_TO_FOLDER_SEPARATOR);
1854 add_separator = TRUE;
1857 downcase = g_ascii_strdown (*current, -1);
1858 folder_type = modest_local_folder_info_get_type (downcase);
1859 if (strcmp (downcase, "inbox") == 0) {
1860 output = g_string_append (output, _("mcen_me_folder_inbox"));
1861 } else if (folder_type == TNY_FOLDER_TYPE_ARCHIVE ||
1862 folder_type == TNY_FOLDER_TYPE_DRAFTS ||
1863 folder_type == TNY_FOLDER_TYPE_SENT ||
1864 folder_type == TNY_FOLDER_TYPE_OUTBOX) {
1865 output = g_string_append (output, modest_local_folder_info_get_type_display_name (folder_type));
1867 output = g_string_append (output, *current);
1875 *path = g_string_free (output, FALSE);
1879 move_to_dialog_set_selected_folder_store (GtkWidget *dialog,
1880 TnyFolderStore *folder_store)
1882 GtkWidget *action_button;
1883 GtkWidget *image = NULL;
1884 TnyAccount *account;
1885 gchar *account_name = NULL, *short_name = NULL;
1887 action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
1889 /* Get account name */
1890 if (TNY_IS_FOLDER (folder_store))
1891 account = tny_folder_get_account (TNY_FOLDER (folder_store));
1893 account = g_object_ref (folder_store);
1895 if (modest_tny_account_is_virtual_local_folders (account))
1896 account_name = modest_conf_get_string (modest_runtime_get_conf(),
1897 MODEST_CONF_DEVICE_NAME, NULL);
1900 account_name = g_strdup (tny_account_get_name (account));
1902 g_object_unref (account);
1904 /* Set title of button: account or folder name */
1905 if (TNY_IS_FOLDER (folder_store))
1906 short_name = folder_store_get_display_name (folder_store);
1908 short_name = g_strdup (account_name);
1910 gtk_button_set_label (GTK_BUTTON (action_button), short_name);
1912 /* Set value of button, folder full name */
1913 if (TNY_IS_CAMEL_FOLDER (folder_store)) {
1914 const gchar *camel_full_name;
1915 gchar *last_slash, *full_name;
1917 camel_full_name = tny_camel_folder_get_full_name (TNY_CAMEL_FOLDER (folder_store));
1918 last_slash = g_strrstr (camel_full_name, "/");
1920 gchar *prefix = g_strndup (camel_full_name, last_slash - camel_full_name + 1);
1921 full_name = g_strconcat (account_name, MOVE_TO_FOLDER_SEPARATOR, prefix, short_name, NULL);
1924 full_name = g_strconcat (account_name, MOVE_TO_FOLDER_SEPARATOR,
1928 translate_path (&full_name);
1929 gtk_button_set_label (GTK_BUTTON (action_button), full_name);
1932 g_free (account_name);
1933 g_free (short_name);
1935 /* Set image for the button */
1936 image = get_image_for_folder_store (folder_store, MODEST_ICON_SIZE_BIG);
1938 gtk_button_set_image (GTK_BUTTON (action_button), image);
1942 move_to_dialog_show_accounts (GtkWidget *dialog)
1944 GtkWidget *back_button;
1945 GtkWidget *folder_view;
1946 GtkWidget *scrollable;
1947 GtkWidget *action_button;
1949 back_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
1950 action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
1951 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
1952 scrollable = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SCROLLABLE));
1954 gtk_widget_set_sensitive (back_button, FALSE);
1955 gtk_widget_set_sensitive (action_button, FALSE);
1957 /* Need to set this here, otherwise callbacks called because
1958 of filtering won't perform correctly */
1959 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS, GINT_TO_POINTER (FALSE));
1961 /* Reset action button */
1962 gtk_button_set_label (GTK_BUTTON (action_button), NULL);
1963 gtk_button_set_image (GTK_BUTTON (action_button), NULL);
1965 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view), NULL);
1966 modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), TRUE);
1967 modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ALL);
1968 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
1969 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
1970 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
1971 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
1972 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
1973 MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
1974 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
1975 MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
1976 modest_scrollable_jump_to (MODEST_SCROLLABLE (scrollable), 0, 0);
1980 move_to_dialog_show_folders (GtkWidget *dialog, TnyFolderStore *folder_store)
1982 GtkWidget *back_button;
1983 GtkWidget *folder_view;
1984 TnyAccount *account;
1985 const gchar *account_id;
1986 GtkWidget *scrollable;
1987 GtkWidget *action_button;
1990 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
1992 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
1994 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
1996 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SCROLLABLE));
1998 gtk_widget_set_sensitive (back_button, TRUE);
1999 gtk_widget_set_sensitive (action_button, TRUE);
2001 /* Need to set this here, otherwise callbacks called because
2002 of filtering won't perform correctly */
2003 g_object_set_data (G_OBJECT (dialog),
2004 MOVE_TO_DIALOG_SHOWING_FOLDERS,
2005 GINT_TO_POINTER (TRUE));
2007 account = TNY_ACCOUNT (folder_store);
2008 if (modest_tny_account_is_virtual_local_folders (account)) {
2009 account_id = tny_account_get_id (account);
2010 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2011 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2012 } else if (modest_tny_account_is_memory_card_account (account)) {
2013 account_id = tny_account_get_id (account);
2014 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2015 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2017 account_id = tny_account_get_id (account);
2018 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2019 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2020 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2021 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2024 move_to_dialog_set_selected_folder_store (dialog, folder_store);
2025 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view),
2028 modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), FALSE);
2029 modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
2030 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
2031 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
2032 modest_scrollable_jump_to (MODEST_SCROLLABLE (scrollable), 0, 0);
2036 on_move_to_dialog_back_clicked (GtkButton *button,
2039 GtkWidget *dialog = (GtkWidget *) userdata;
2041 /* Back to show accounts */
2042 move_to_dialog_show_accounts (dialog);
2046 on_move_to_dialog_row_activated (GtkTreeView *tree_view,
2048 GtkTreeViewColumn *column,
2051 TnyFolderStore *selected = NULL;
2053 GtkWidget *folder_view;
2054 gboolean showing_folders;
2056 dialog = (GtkWidget *) user_data;
2057 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog),
2058 MOVE_TO_DIALOG_SHOWING_FOLDERS));
2060 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog),
2061 MOVE_TO_DIALOG_FOLDER_VIEW));
2063 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2067 if (!showing_folders) {
2068 gboolean valid = TRUE;
2070 if (TNY_IS_ACCOUNT (selected) &&
2071 modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (selected))) {
2072 ModestProtocolType protocol_type;
2074 protocol_type = modest_tny_account_get_protocol_type (TNY_ACCOUNT (selected));
2075 valid = !modest_protocol_registry_protocol_type_has_tag
2076 (modest_runtime_get_protocol_registry (),
2078 MODEST_PROTOCOL_REGISTRY_STORE_FORBID_INCOMING_XFERS);
2081 move_to_dialog_show_folders (dialog, selected);
2083 move_to_dialog_set_selected_folder_store (dialog, selected);
2085 g_object_unref (selected);
2089 on_move_to_dialog_selection_changed (GtkTreeSelection *selection,
2092 gboolean showing_folders;
2095 dialog = (GtkWidget *) user_data;
2096 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2097 if (showing_folders) {
2098 TnyFolderStore *selected;
2099 GtkWidget *folder_view;
2101 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2102 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2105 move_to_dialog_set_selected_folder_store (dialog, selected);
2106 g_object_unref (selected);
2112 on_move_to_dialog_action_clicked (GtkButton *selection,
2116 gboolean showing_folders;
2118 dialog = (GtkWidget *) user_data;
2119 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2120 if (showing_folders) {
2121 TnyFolderStore *selected;
2122 GtkWidget *folder_view;
2124 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2125 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2128 /* It's not possible to select root folders as
2129 targets unless they're the local account or
2130 the memory card account */
2131 if ((TNY_IS_FOLDER (selected) && !TNY_IS_MERGE_FOLDER (selected)) ||
2132 (TNY_IS_ACCOUNT (selected) &&
2133 (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (selected)) ||
2134 modest_tny_account_is_memory_card_account (TNY_ACCOUNT (selected)))))
2135 gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
2136 g_object_unref (selected);
2142 move_to_dialog_activity_changed (ModestFolderView *folder_view, gboolean activity, GtkDialog *dialog)
2147 modest_platform_create_move_to_dialog (GtkWindow *parent_window,
2148 GtkWidget **folder_view)
2150 GtkWidget *dialog, *folder_view_container;
2152 GtkWidget *buttons_hbox;
2153 GtkWidget *back_button;
2154 GdkPixbuf *back_pixbuf;
2155 GtkWidget *top_vbox;
2156 GtkWidget *action_button;
2157 GtkTreeSelection *selection;
2159 /* Create dialog. We cannot use a touch selector because we
2160 need to use here the folder view widget directly */
2161 dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
2162 GTK_WINDOW (parent_window),
2163 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR |
2164 GTK_DIALOG_DESTROY_WITH_PARENT,
2165 _FM ("ckdg_bd_change_folder_new_folder"),
2166 MODEST_GTK_RESPONSE_NEW_FOLDER,
2169 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
2170 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_NONE);
2171 top_vbox = gtk_vbox_new (FALSE, MODEST_MARGIN_HALF);
2173 /* Create folder view */
2174 *folder_view = modest_platform_create_folder_view_full (NULL, FALSE);
2175 g_signal_connect (G_OBJECT (*folder_view), "activity-changed", G_CALLBACK (move_to_dialog_activity_changed),
2178 modest_folder_view_set_cell_style (MODEST_FOLDER_VIEW (*folder_view),
2179 MODEST_FOLDER_VIEW_CELL_STYLE_COMPACT);
2180 modest_folder_view_show_message_count (MODEST_FOLDER_VIEW (*folder_view),
2182 tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (*folder_view),
2183 (TnyAccountStore *) modest_runtime_get_account_store ());
2185 buttons_hbox = gtk_hbox_new (FALSE, MODEST_MARGIN_HALF);
2186 back_button = gtk_button_new ();
2187 back_pixbuf = modest_platform_get_icon (_FM("filemanager_folder_up"), MODEST_ICON_SIZE_BIG);
2189 gtk_button_set_image (GTK_BUTTON (back_button), gtk_image_new_from_pixbuf (back_pixbuf));
2190 g_object_unref (back_pixbuf);
2193 action_button = gtk_button_new ();
2194 gtk_button_set_alignment (GTK_BUTTON (action_button), 0.0, 0.5);
2196 gtk_box_pack_start (GTK_BOX (buttons_hbox), back_button, FALSE, FALSE, 0);
2197 gtk_box_pack_start (GTK_BOX (buttons_hbox), action_button, TRUE, TRUE, 0);
2198 gtk_widget_set_sensitive (GTK_WIDGET (back_button), FALSE);
2199 gtk_widget_set_sensitive (GTK_WIDGET (action_button), FALSE);
2200 gtk_box_pack_start (GTK_BOX (top_vbox), buttons_hbox, FALSE, FALSE, 0);
2202 /* Create scrollable and add it to the dialog */
2203 folder_view_container = modest_toolkit_factory_create_scrollable (modest_runtime_get_toolkit_factory ());
2204 gtk_container_add (GTK_CONTAINER (folder_view_container), *folder_view);
2205 gtk_box_pack_start (GTK_BOX (top_vbox), folder_view_container, TRUE, TRUE, 0);
2207 gtk_container_add (GTK_CONTAINER (align), top_vbox);
2208 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), align, TRUE, TRUE, 0);
2210 gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
2212 gtk_widget_show (GTK_DIALOG (dialog)->vbox);
2213 gtk_widget_show (folder_view_container);
2214 gtk_widget_show (align);
2215 gtk_widget_show (top_vbox);
2216 gtk_widget_show (*folder_view);
2217 gtk_widget_show_all (back_button);
2218 gtk_widget_show (action_button);
2219 gtk_widget_show (buttons_hbox);
2220 gtk_widget_show (dialog);
2222 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW, *folder_view);
2223 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON, back_button);
2224 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON, action_button);
2225 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SCROLLABLE, folder_view_container);
2227 /* Simulate the behaviour of a HildonPickerDialog by emitting
2228 a response when a folder is selected */
2229 g_signal_connect (*folder_view, "row-activated",
2230 G_CALLBACK (on_move_to_dialog_row_activated),
2233 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (*folder_view));
2234 g_signal_connect (selection, "changed",
2235 G_CALLBACK (on_move_to_dialog_selection_changed),
2238 g_signal_connect (action_button, "clicked",
2239 G_CALLBACK (on_move_to_dialog_action_clicked),
2242 g_signal_connect (back_button, "clicked",
2243 G_CALLBACK (on_move_to_dialog_back_clicked),
2246 move_to_dialog_show_accounts (dialog);
2252 modest_platform_get_list_to_move (ModestWindow *window)
2254 TnyList *list = NULL;
2256 if (MODEST_IS_HEADER_WINDOW (window)) {
2257 ModestHeaderView *header_view;
2259 header_view = modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window));
2260 list = modest_header_view_get_selected_headers (header_view);
2261 } else if (MODEST_IS_FOLDER_WINDOW (window)) {
2262 ModestFolderView *folder_view;
2263 TnyFolderStore *selected_folder;
2265 list = TNY_LIST (tny_simple_list_new ());
2266 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window));
2267 selected_folder = modest_folder_view_get_selected (folder_view);
2268 if (selected_folder) {
2269 tny_list_prepend (list, G_OBJECT (selected_folder));
2270 g_object_unref (selected_folder);
2273 } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
2276 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (window));
2278 list = TNY_LIST (tny_simple_list_new ());
2279 tny_list_prepend (list, G_OBJECT (header));
2280 g_object_unref (header);
2283 g_return_val_if_reached (NULL);