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_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_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_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_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_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_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_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_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,
773 _FM_NEW_FOLDER_DIALOG_OK,
777 /* Add accept button (with unsensitive handler) */
778 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
779 accept_btn = GTK_WIDGET (buttons->data);
781 sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
784 label_entry = gtk_label_new (label_text);
785 entry = modest_toolkit_factory_create_entry (modest_runtime_get_toolkit_factory ());
786 gtk_entry_set_max_length (GTK_ENTRY (entry), 20);
788 gtk_misc_set_alignment (GTK_MISC (label_entry), 0.0, 0.5);
789 gtk_size_group_add_widget (sizegroup, label_entry);
792 gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
794 gtk_entry_set_text (GTK_ENTRY (entry), _FM_NEW_FOLDER_NAME_STUB);
795 gtk_entry_set_width_chars (GTK_ENTRY (entry),
796 MAX (g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (entry)), -1),
797 g_utf8_strlen (_FM_NEW_FOLDER_NAME_STUB, -1)));
798 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
803 label_location = gtk_label_new (_FM_NEW_FOLDER_LOCATION);
805 gtk_misc_set_alignment (GTK_MISC (label_location), 0.0, 0.5);
806 gtk_size_group_add_widget (sizegroup, label_location);
808 helper = g_slice_new0 (FolderPickerHelper);
809 helper->folder_view = folder_view;
810 helper->entry = (GtkEntry *) entry;
812 account_picker = folder_picker_new (suggested_parent, helper);
815 g_object_unref (sizegroup);
817 /* Connect to the response method to avoid closing the dialog
818 when an invalid name is selected*/
819 g_signal_connect (dialog,
821 G_CALLBACK (on_response),
825 /* Track entry changes */
826 g_signal_connect (entry,
828 G_CALLBACK (entry_insert_text),
830 g_signal_connect (entry,
832 G_CALLBACK (entry_changed),
837 /* Some locales like pt_BR need this to get the full window
839 gtk_widget_set_size_request (GTK_WIDGET (dialog), 300, -1);
841 /* Create the hbox */
843 hbox = gtk_hbox_new (FALSE, 12);
844 gtk_box_pack_start (GTK_BOX (hbox), label_entry, FALSE, FALSE, 0);
845 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
847 /* Add hbox to dialog */
848 gtk_box_pack_start (GTK_BOX (top_vbox),
849 hbox, FALSE, FALSE, 0);
850 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY, entry);
854 hbox = gtk_hbox_new (FALSE, 12);
855 gtk_box_pack_start (GTK_BOX (hbox), label_location, FALSE, FALSE, 0);
856 gtk_box_pack_start (GTK_BOX (hbox), account_picker, TRUE, TRUE, 0);
858 /* Add hbox to dialog */
859 gtk_box_pack_start (GTK_BOX (top_vbox),
860 hbox, FALSE, FALSE, 0);
861 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER, account_picker);
863 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
864 GTK_WINDOW (dialog), parent_window);
866 gtk_container_add (GTK_CONTAINER (top_align), top_vbox);
867 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), top_align, TRUE, TRUE, 0);
869 gtk_widget_show_all (GTK_WIDGET(dialog));
871 result = gtk_dialog_run (GTK_DIALOG(dialog));
872 if (result == GTK_RESPONSE_ACCEPT) {
874 *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
876 *parent = g_object_get_data (G_OBJECT (account_picker), FOLDER_PICKER_CURRENT_FOLDER);
878 g_object_ref (*parent);
882 gtk_widget_destroy (dialog);
885 g_slice_free (FolderPickerHelper, helper);
887 while (gtk_events_pending ())
888 gtk_main_iteration ();
894 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
895 TnyFolderStore *suggested_folder,
896 gchar *suggested_name,
898 TnyFolderStore **parent_folder)
900 gchar *real_suggested_name = NULL;
902 ModestTnyAccountStore *acc_store;
904 gboolean do_free = FALSE;
906 real_suggested_name = get_next_folder_name ((const gchar *) suggested_name,
909 /* In hildon 2.2 we always suggest the archive folder as parent */
910 if (!suggested_folder) {
911 acc_store = modest_runtime_get_account_store ();
912 account = modest_tny_account_store_get_mmc_folders_account (acc_store);
914 suggested_folder = (TnyFolderStore *)
915 modest_tny_account_get_special_folder (account,
916 TNY_FOLDER_TYPE_ARCHIVE);
917 g_object_unref (account);
922 /* If there is not archive folder then fallback to local folders account */
923 if (!suggested_folder) {
925 suggested_folder = (TnyFolderStore *)
926 modest_tny_account_store_get_local_folders_account (acc_store);
929 result = modest_platform_run_folder_common_dialog (parent_window,
931 _HL_TITLE_NEW_FOLDER,
940 g_object_unref (suggested_folder);
942 g_free(real_suggested_name);
948 modest_platform_run_rename_folder_dialog (ModestWindow *parent_window,
949 TnyFolderStore *parent_folder,
950 const gchar *suggested_name,
955 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
957 toplevel = (GtkWindow *) gtk_widget_get_toplevel (GTK_WIDGET (parent_window));
958 return modest_platform_run_folder_common_dialog (toplevel,
960 _HL_TITLE_RENAME_FOLDER,
972 on_destroy_dialog (GtkWidget *dialog)
974 /* This could happen when the dialogs get programatically
975 hidden or destroyed (for example when closing the
976 application while a dialog is being shown) */
977 if (!GTK_IS_WIDGET (dialog))
980 gtk_widget_destroy (dialog);
982 if (gtk_events_pending ())
983 gtk_main_iteration ();
987 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
988 const gchar *message)
993 dialog = gtk_message_dialog_new (parent_window, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
994 GTK_MESSAGE_QUESTION,
995 GTK_BUTTONS_OK_CANCEL,
997 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
998 GTK_WINDOW (dialog), parent_window);
1000 response = gtk_dialog_run (GTK_DIALOG (dialog));
1002 on_destroy_dialog (dialog);
1008 modest_platform_run_confirmation_dialog_with_buttons (GtkWindow *parent_window,
1009 const gchar *message,
1010 const gchar *button_accept,
1011 const gchar *button_cancel)
1016 dialog = gtk_message_dialog_new (parent_window, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1017 GTK_MESSAGE_QUESTION,
1020 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
1021 button_accept, GTK_RESPONSE_ACCEPT,
1022 button_cancel, GTK_RESPONSE_CANCEL,
1025 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1026 GTK_WINDOW (dialog), parent_window);
1028 response = gtk_dialog_run (GTK_DIALOG (dialog));
1030 on_destroy_dialog (dialog);
1036 modest_platform_run_information_dialog (GtkWindow *parent_window,
1037 const gchar *message,
1042 note = gtk_message_dialog_new (parent_window, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1047 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1048 GTK_WINDOW (note), parent_window);
1051 gtk_dialog_run (GTK_DIALOG (note));
1053 on_destroy_dialog (note);
1055 g_signal_connect_swapped (note,
1057 G_CALLBACK (on_destroy_dialog),
1060 gtk_widget_show_all (note);
1064 typedef struct _ConnectAndWaitData {
1066 GMainLoop *wait_loop;
1067 gboolean has_callback;
1069 } ConnectAndWaitData;
1073 modest_platform_connect_and_wait (GtkWindow *parent_window,
1074 TnyAccount *account)
1076 gboolean device_online;
1078 TnyConnectionStatus conn_status;
1079 gboolean user_requested;
1081 device = modest_runtime_get_device();
1082 device_online = tny_device_is_online (device);
1084 /* Whether the connection is user requested or automatically
1085 requested, for example via D-Bus */
1086 user_requested = (parent_window) ? TRUE : FALSE;
1088 /* If there is no account check only the device status */
1093 /* TODO: should show connection dialog through gnome device */
1097 /* Return if the account is already connected */
1098 conn_status = tny_account_get_connection_status (account);
1099 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
1106 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1108 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1109 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1110 /* This must be a maildir account, which does not require a connection: */
1115 return modest_platform_connect_and_wait (parent_window, account);
1119 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1122 return TRUE; /* Maybe it is something local. */
1124 gboolean result = TRUE;
1125 if (TNY_IS_FOLDER (folder_store)) {
1126 /* Get the folder's parent account: */
1127 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1128 if (account != NULL) {
1129 result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1130 g_object_unref (account);
1132 } else if (TNY_IS_ACCOUNT (folder_store)) {
1133 /* Use the folder store as an account: */
1134 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1141 modest_platform_create_sort_dialog (GtkWindow *parent_window)
1149 modest_platform_set_update_interval (guint minutes)
1155 modest_platform_push_email_notification(void)
1161 modest_platform_on_new_headers_received (GList *URI_list,
1162 gboolean show_visual)
1168 modest_platform_remove_new_mail_notifications (gboolean only_visuals)
1176 modest_platform_get_global_settings_dialog ()
1178 return modest_default_global_settings_dialog_new ();
1182 modest_platform_show_help (GtkWindow *parent_window,
1183 const gchar *help_id)
1189 modest_platform_show_search_messages (GtkWindow *parent_window)
1195 modest_platform_show_addressbook (GtkWindow *parent_window)
1201 modest_platform_create_folder_view_full (TnyFolderStoreQuery *query, gboolean do_refresh)
1203 GtkWidget *widget = modest_folder_view_new_full (query, do_refresh);
1205 /* Show one account by default */
1206 modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1207 MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1213 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1215 return modest_platform_create_folder_view_full (query, TRUE);
1219 banner_finish (gpointer data, GObject *object)
1221 ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1222 modest_window_mgr_unregister_banner (mgr);
1223 g_object_unref (mgr);
1227 modest_platform_information_banner (GtkWidget *parent,
1228 const gchar *icon_name,
1233 banner = modest_shell_banner_new (parent);
1234 modest_shell_banner_set_icon (MODEST_SHELL_BANNER (banner), icon_name);
1235 modest_shell_banner_set_text (MODEST_SHELL_BANNER (banner), text);
1241 modest_platform_system_banner (GtkWidget *parent,
1242 const gchar *icon_name,
1245 modest_platform_information_banner (parent, icon_name, text);
1249 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1250 const gchar *icon_name,
1256 banner = modest_shell_banner_new_with_timeout (parent, timeout);
1257 modest_shell_banner_set_icon (MODEST_SHELL_BANNER (banner), icon_name);
1258 modest_shell_banner_set_text (MODEST_SHELL_BANNER (banner), text);
1264 modest_platform_animation_banner (GtkWidget *parent,
1265 const gchar *animation_name,
1270 banner = modest_shell_banner_new_with_timeout (parent, 0);
1271 modest_shell_banner_set_animation (MODEST_SHELL_BANNER (banner), animation_name);
1272 modest_shell_banner_set_text (MODEST_SHELL_BANNER (banner), text);
1280 TnyAccount *account;
1283 } CheckAccountIdleData;
1285 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1288 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1290 gboolean stop_trying = FALSE;
1291 g_return_val_if_fail (data && data->account, FALSE);
1293 if (data && data->account &&
1294 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1295 * after which the account is likely to be usable, or never likely to be usable soon: */
1296 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1298 data->is_online = TRUE;
1302 /* Give up if we have tried too many times: */
1303 if (data->count_tries >= NUMBER_OF_TRIES) {
1306 /* Wait for another timeout: */
1307 ++(data->count_tries);
1312 /* Allow the function that requested this idle callback to continue: */
1314 g_main_loop_quit (data->loop);
1317 g_object_unref (data->account);
1319 return FALSE; /* Don't call this again. */
1321 return TRUE; /* Call this timeout callback again. */
1325 /* Return TRUE immediately if the account is already online,
1326 * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as
1327 * soon as the account is online, or FALSE if the account does
1328 * not become online in the NUMBER_OF_TRIES seconds.
1329 * This is useful when the D-Bus method was run immediately after
1330 * the application was started (when using D-Bus activation),
1331 * because the account usually takes a short time to go online.
1332 * The return value is maybe not very useful.
1335 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1339 g_return_val_if_fail (account, FALSE);
1341 if (!tny_device_is_online (modest_runtime_get_device())) {
1342 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1346 /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1347 * so we avoid wait unnecessarily: */
1348 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1351 /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED,
1352 * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that
1353 * we want to avoid. */
1354 if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1357 /* This blocks on the result: */
1358 CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1359 data->is_online = FALSE;
1360 data->account = account;
1361 g_object_ref (data->account);
1362 data->count_tries = 0;
1364 GMainContext *context = NULL; /* g_main_context_new (); */
1365 data->loop = g_main_loop_new (context, FALSE /* not running */);
1367 g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1369 /* This main loop will run until the idle handler has stopped it: */
1370 g_main_loop_run (data->loop);
1372 g_main_loop_unref (data->loop);
1373 /* g_main_context_unref (context); */
1375 is_online = data->is_online;
1376 g_slice_free (CheckAccountIdleData, data);
1384 on_cert_dialog_response (GtkDialog *dialog, gint response_id, const gchar* cert)
1386 /* GTK_RESPONSE_HELP means we need to show the certificate */
1387 if (response_id == GTK_RESPONSE_APPLY) {
1390 /* Do not close the dialog */
1391 g_signal_stop_emission_by_name (dialog, "response");
1393 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);
1394 modest_platform_run_information_dialog (NULL, msg, TRUE);
1400 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1401 const gchar *certificate)
1407 gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1410 /* We use GTK_RESPONSE_APPLY because we want the button in the
1411 middle of OK and CANCEL the same as the browser does for
1412 example. With GTK_RESPONSE_HELP the view button is aligned
1413 to the left while the other two to the right */
1414 note = gtk_message_dialog_new (
1416 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1417 GTK_MESSAGE_QUESTION,
1420 gtk_dialog_add_buttons (GTK_DIALOG (note),
1421 _HL_YES, GTK_RESPONSE_OK,
1422 _HL_VIEW, GTK_RESPONSE_APPLY, /* abusing this... */
1423 _HL_NO, GTK_RESPONSE_CANCEL,
1426 g_signal_connect (G_OBJECT(note), "response",
1427 G_CALLBACK(on_cert_dialog_response),
1428 (gpointer) certificate);
1430 response = gtk_dialog_run(GTK_DIALOG(note));
1432 on_destroy_dialog (note);
1435 return response == GTK_RESPONSE_OK;
1439 modest_platform_run_alert_dialog (const gchar* prompt,
1440 gboolean is_question)
1443 gboolean retval = TRUE;
1446 /* The Tinymail documentation says that we should show Yes and No buttons,
1447 * when it is a question.
1448 * Obviously, we need tinymail to use more specific error codes instead,
1449 * so we know what buttons to show. */
1450 dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1451 GTK_MESSAGE_QUESTION,
1455 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
1456 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
1458 on_destroy_dialog (dialog);
1460 /* Just show the error text and use the default response: */
1461 modest_platform_run_information_dialog (NULL,
1469 ModestWindow *parent_window;
1470 ModestConnectedPerformer callback;
1471 TnyAccount *account;
1478 on_went_online_info_free (OnWentOnlineInfo *info)
1480 /* And if we cleanup, we DO cleanup :-) */
1483 g_object_unref (info->device);
1486 if (info->parent_window)
1487 g_object_unref (info->parent_window);
1489 g_object_unref (info->account);
1491 g_slice_free (OnWentOnlineInfo, info);
1493 /* We're done ... */
1499 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
1501 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1503 /* Now it's really time to callback to the caller. If going online didn't succeed,
1504 * err will be set. We don't free it, Tinymail does that! If a cancel happened,
1505 * canceled will be set. Etcetera etcetera. */
1507 if (info->callback) {
1508 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1511 /* This is our last call, we must cleanup here if we didn't yet do that */
1512 on_went_online_info_free (info);
1518 modest_platform_connect_and_perform (ModestWindow *parent_window,
1520 TnyAccount *account,
1521 ModestConnectedPerformer callback,
1524 gboolean device_online;
1526 TnyConnectionStatus conn_status;
1528 device = modest_runtime_get_device();
1529 device_online = tny_device_is_online (device);
1531 /* If there is no account check only the device status */
1534 if (device_online) {
1536 /* We promise to instantly perform the callback, so ... */
1538 callback (FALSE, NULL, parent_window, account, user_data);
1545 /* The other code has no more reason to run. This is all that we can do for the
1546 * caller (he should have given us a nice and clean account instance!). We
1547 * can't do magic, we don't know what account he intends to bring online. So
1548 * we'll just bring the device online (and await his false bug report). */
1554 /* Return if the account is already connected */
1556 conn_status = tny_account_get_connection_status (account);
1557 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
1559 /* We promise to instantly perform the callback, so ... */
1561 callback (FALSE, NULL, parent_window, account, user_data);
1567 if (!device_online) {
1568 OnWentOnlineInfo *info = NULL;
1570 info = g_slice_new0 (OnWentOnlineInfo);
1572 info->device = NULL;
1574 info->account = TNY_ACCOUNT (g_object_ref (account));
1577 info->parent_window = (ModestWindow *) g_object_ref (parent_window);
1579 info->parent_window = NULL;
1581 /* So we'll put the callback away for later ... */
1582 info->user_data = user_data;
1583 info->callback = callback;
1585 /* If the device is online, we'll just connect the account */
1586 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1587 on_account_went_online, info);
1590 /* The info gets freed by on_account_went_online or on_conic_device_went_online
1591 * in both situations, go look if you don't believe me! */
1595 modest_platform_connect_if_remote_and_perform (ModestWindow *parent_window,
1597 TnyFolderStore *folder_store,
1598 ModestConnectedPerformer callback,
1601 TnyAccount *account = NULL;
1603 if (!folder_store ||
1604 (TNY_IS_MERGE_FOLDER (folder_store) &&
1605 (tny_folder_get_folder_type (TNY_FOLDER(folder_store)) == TNY_FOLDER_TYPE_OUTBOX))) {
1607 /* We promise to instantly perform the callback, so ... */
1609 GError *error = NULL;
1610 g_set_error (&error, TNY_ERROR_DOMAIN, TNY_SERVICE_ERROR_UNKNOWN,
1611 "Unable to move or not found folder");
1612 callback (FALSE, error, parent_window, NULL, user_data);
1613 g_error_free (error);
1617 } else if (TNY_IS_FOLDER (folder_store)) {
1618 /* Get the folder's parent account: */
1619 account = tny_folder_get_account (TNY_FOLDER (folder_store));
1620 } else if (TNY_IS_ACCOUNT (folder_store)) {
1621 /* Use the folder store as an account: */
1622 account = TNY_ACCOUNT (g_object_ref (folder_store));
1625 if (account && (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE)) {
1626 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1627 /* No need to connect a local account */
1629 callback (FALSE, NULL, parent_window, account, user_data);
1634 modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
1638 g_object_unref (account);
1642 src_account_connect_performer (gboolean canceled,
1644 ModestWindow *parent_window,
1645 TnyAccount *src_account,
1648 DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
1650 if (canceled || err) {
1651 /* If there was any error call the user callback */
1652 info->callback (canceled, err, parent_window, src_account, info->data);
1654 /* Connect the destination account */
1655 modest_platform_connect_if_remote_and_perform (parent_window, TRUE,
1656 TNY_FOLDER_STORE (info->dst_account),
1657 info->callback, info->data);
1660 /* Free the info object */
1661 g_object_unref (info->dst_account);
1662 g_slice_free (DoubleConnectionInfo, info);
1667 modest_platform_double_connect_and_perform (ModestWindow *parent_window,
1669 TnyFolderStore *folder_store,
1670 DoubleConnectionInfo *connect_info)
1672 modest_platform_connect_if_remote_and_perform(parent_window,
1675 src_account_connect_performer,
1680 modest_platform_get_account_settings_wizard (void)
1682 ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
1684 return GTK_WIDGET (dialog);
1688 modest_platform_get_current_connection (void)
1690 TnyDevice *device = NULL;
1691 ModestConnectedVia retval = MODEST_CONNECTED_VIA_ANY;
1693 device = modest_runtime_get_device ();
1695 if (!tny_device_is_online (device))
1696 return MODEST_CONNECTED_VIA_ANY;
1698 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX; /* assume WLAN (fast) internet */
1705 modest_platform_check_memory_low (ModestWindow *win,
1713 modest_platform_run_folder_details_dialog (GtkWindow *parent_window,
1719 dialog = modest_toolkit_factory_create_details_dialog_with_folder (modest_runtime_get_toolkit_factory (),
1720 parent_window, folder);
1723 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1724 GTK_WINDOW (dialog),
1726 gtk_widget_show_all (dialog);
1728 g_signal_connect_swapped (dialog, "response",
1729 G_CALLBACK (gtk_widget_destroy),
1733 typedef struct _HeaderDetailsGetSizeInfo {
1737 } HeaderDetailsGetSizeInfo;
1740 header_details_dialog_destroy (gpointer userdata,
1743 HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) userdata;
1745 info->dialog = NULL;
1749 idle_get_mime_part_size_cb (gpointer userdata)
1751 HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) userdata;
1752 gdk_threads_enter ();
1754 if (info->dialog && GTK_WIDGET_VISIBLE (info->dialog)) {
1755 modest_details_dialog_set_message_size (MODEST_DETAILS_DIALOG (info->dialog),
1760 g_object_weak_unref (G_OBJECT (info->dialog), header_details_dialog_destroy, info);
1761 info->dialog = NULL;
1763 g_object_unref (info->part);
1764 g_slice_free (HeaderDetailsGetSizeInfo, info);
1766 gdk_threads_leave ();
1772 get_mime_part_size_thread (gpointer thr_user_data)
1774 HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) thr_user_data;
1776 TnyStream *count_stream;
1778 count_stream = modest_count_stream_new ();
1779 result = tny_mime_part_decode_to_stream (info->part, count_stream, NULL);
1780 info->total = modest_count_stream_get_count(MODEST_COUNT_STREAM (count_stream));
1781 if (info->total == 0) {
1782 modest_count_stream_reset_count(MODEST_COUNT_STREAM (count_stream));
1783 result = tny_mime_part_write_to_stream (info->part, count_stream, NULL);
1784 info->total = modest_count_stream_get_count(MODEST_COUNT_STREAM (count_stream));
1787 /* if there was an error, don't set the size (this is pretty uncommon) */
1789 g_warning ("%s: error while writing mime part to stream\n", __FUNCTION__);
1791 g_idle_add (idle_get_mime_part_size_cb, info);
1797 modest_platform_run_header_details_dialog (GtkWindow *parent_window,
1799 gboolean async_get_size,
1805 dialog = modest_toolkit_factory_create_details_dialog_with_header (modest_runtime_get_toolkit_factory (),
1806 parent_window, header, !async_get_size);
1808 if (async_get_size && msg && TNY_IS_MSG (msg)) {
1809 HeaderDetailsGetSizeInfo *info;
1810 info = g_slice_new (HeaderDetailsGetSizeInfo);
1811 info->dialog = dialog;
1813 info->part = TNY_MIME_PART (g_object_ref (msg));
1815 g_object_weak_ref (G_OBJECT (dialog), header_details_dialog_destroy, info);
1816 g_thread_create (get_mime_part_size_thread, info, FALSE, NULL);
1820 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1821 GTK_WINDOW (dialog),
1823 gtk_widget_show_all (dialog);
1825 g_signal_connect_swapped (dialog, "response",
1826 G_CALLBACK (gtk_widget_destroy),
1830 #define MOVE_TO_DIALOG_FOLDER_VIEW "folder-view"
1831 #define MOVE_TO_DIALOG_BACK_BUTTON "back-button"
1832 #define MOVE_TO_DIALOG_ACTION_BUTTON "action-button"
1833 #define MOVE_TO_DIALOG_SHOWING_FOLDERS "showing-folders"
1834 #define MOVE_TO_DIALOG_SCROLLABLE "scrollable"
1835 #define MOVE_TO_FOLDER_SEPARATOR "/"
1838 translate_path (gchar **path)
1843 gboolean add_separator;
1845 parts = g_strsplit (*path, MOVE_TO_FOLDER_SEPARATOR, 0);
1849 output = g_string_new ("");
1850 add_separator = FALSE;
1852 while (*current != NULL) {
1853 TnyFolderType folder_type;
1856 if (add_separator) {
1857 output = g_string_append (output, MOVE_TO_FOLDER_SEPARATOR);
1859 add_separator = TRUE;
1862 downcase = g_ascii_strdown (*current, -1);
1863 folder_type = modest_local_folder_info_get_type (downcase);
1864 if (strcmp (downcase, "inbox") == 0) {
1865 output = g_string_append (output, _("mcen_me_folder_inbox"));
1866 } else if (folder_type == TNY_FOLDER_TYPE_ARCHIVE ||
1867 folder_type == TNY_FOLDER_TYPE_DRAFTS ||
1868 folder_type == TNY_FOLDER_TYPE_SENT ||
1869 folder_type == TNY_FOLDER_TYPE_OUTBOX) {
1870 output = g_string_append (output, modest_local_folder_info_get_type_display_name (folder_type));
1872 output = g_string_append (output, *current);
1880 *path = g_string_free (output, FALSE);
1884 move_to_dialog_set_selected_folder_store (GtkWidget *dialog,
1885 TnyFolderStore *folder_store)
1887 GtkWidget *action_button;
1888 GtkWidget *image = NULL;
1889 TnyAccount *account;
1890 gchar *account_name = NULL, *short_name = NULL;
1892 action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
1894 /* Get account name */
1895 if (TNY_IS_FOLDER (folder_store))
1896 account = tny_folder_get_account (TNY_FOLDER (folder_store));
1898 account = g_object_ref (folder_store);
1900 if (modest_tny_account_is_virtual_local_folders (account))
1901 account_name = modest_conf_get_string (modest_runtime_get_conf(),
1902 MODEST_CONF_DEVICE_NAME, NULL);
1905 account_name = g_strdup (tny_account_get_name (account));
1907 g_object_unref (account);
1909 /* Set title of button: account or folder name */
1910 if (TNY_IS_FOLDER (folder_store))
1911 short_name = folder_store_get_display_name (folder_store);
1913 short_name = g_strdup (account_name);
1915 gtk_button_set_label (GTK_BUTTON (action_button), short_name);
1917 /* Set value of button, folder full name */
1918 if (TNY_IS_CAMEL_FOLDER (folder_store)) {
1919 const gchar *camel_full_name;
1920 gchar *last_slash, *full_name;
1922 camel_full_name = tny_camel_folder_get_full_name (TNY_CAMEL_FOLDER (folder_store));
1923 last_slash = g_strrstr (camel_full_name, "/");
1925 gchar *prefix = g_strndup (camel_full_name, last_slash - camel_full_name + 1);
1926 full_name = g_strconcat (account_name, MOVE_TO_FOLDER_SEPARATOR, prefix, short_name, NULL);
1929 full_name = g_strconcat (account_name, MOVE_TO_FOLDER_SEPARATOR,
1933 translate_path (&full_name);
1934 gtk_button_set_label (GTK_BUTTON (action_button), full_name);
1937 g_free (account_name);
1938 g_free (short_name);
1940 /* Set image for the button */
1941 image = get_image_for_folder_store (folder_store, MODEST_ICON_SIZE_BIG);
1943 gtk_button_set_image (GTK_BUTTON (action_button), image);
1947 move_to_dialog_show_accounts (GtkWidget *dialog)
1949 GtkWidget *back_button;
1950 GtkWidget *folder_view;
1951 GtkWidget *scrollable;
1952 GtkWidget *action_button;
1954 back_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
1955 action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
1956 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
1957 scrollable = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SCROLLABLE));
1959 gtk_widget_set_sensitive (back_button, FALSE);
1960 gtk_widget_set_sensitive (action_button, FALSE);
1962 /* Need to set this here, otherwise callbacks called because
1963 of filtering won't perform correctly */
1964 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS, GINT_TO_POINTER (FALSE));
1966 /* Reset action button */
1967 gtk_button_set_label (GTK_BUTTON (action_button), NULL);
1968 gtk_button_set_image (GTK_BUTTON (action_button), NULL);
1970 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view), NULL);
1971 modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), TRUE);
1972 modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ALL);
1973 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
1974 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
1975 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
1976 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
1977 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
1978 MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
1979 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
1980 MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
1981 modest_scrollable_jump_to (MODEST_SCROLLABLE (scrollable), 0, 0);
1985 move_to_dialog_show_folders (GtkWidget *dialog, TnyFolderStore *folder_store)
1987 GtkWidget *back_button;
1988 GtkWidget *folder_view;
1989 TnyAccount *account;
1990 const gchar *account_id;
1991 GtkWidget *scrollable;
1992 GtkWidget *action_button;
1995 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
1997 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
1999 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2001 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SCROLLABLE));
2003 gtk_widget_set_sensitive (back_button, TRUE);
2004 gtk_widget_set_sensitive (action_button, TRUE);
2006 /* Need to set this here, otherwise callbacks called because
2007 of filtering won't perform correctly */
2008 g_object_set_data (G_OBJECT (dialog),
2009 MOVE_TO_DIALOG_SHOWING_FOLDERS,
2010 GINT_TO_POINTER (TRUE));
2012 account = TNY_ACCOUNT (folder_store);
2013 if (modest_tny_account_is_virtual_local_folders (account)) {
2014 account_id = tny_account_get_id (account);
2015 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2016 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2017 } else if (modest_tny_account_is_memory_card_account (account)) {
2018 account_id = tny_account_get_id (account);
2019 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2020 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2022 account_id = tny_account_get_id (account);
2023 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2024 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
2025 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
2026 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
2029 move_to_dialog_set_selected_folder_store (dialog, folder_store);
2030 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view),
2033 modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), FALSE);
2034 modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
2035 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
2036 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
2037 modest_scrollable_jump_to (MODEST_SCROLLABLE (scrollable), 0, 0);
2041 on_move_to_dialog_back_clicked (GtkButton *button,
2044 GtkWidget *dialog = (GtkWidget *) userdata;
2046 /* Back to show accounts */
2047 move_to_dialog_show_accounts (dialog);
2051 on_move_to_dialog_row_activated (GtkTreeView *tree_view,
2053 GtkTreeViewColumn *column,
2056 TnyFolderStore *selected = NULL;
2058 GtkWidget *folder_view;
2059 gboolean showing_folders;
2061 dialog = (GtkWidget *) user_data;
2062 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog),
2063 MOVE_TO_DIALOG_SHOWING_FOLDERS));
2065 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog),
2066 MOVE_TO_DIALOG_FOLDER_VIEW));
2068 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2072 if (!showing_folders) {
2073 gboolean valid = TRUE;
2075 if (TNY_IS_ACCOUNT (selected) &&
2076 modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (selected))) {
2077 ModestProtocolType protocol_type;
2079 protocol_type = modest_tny_account_get_protocol_type (TNY_ACCOUNT (selected));
2080 valid = !modest_protocol_registry_protocol_type_has_tag
2081 (modest_runtime_get_protocol_registry (),
2083 MODEST_PROTOCOL_REGISTRY_STORE_FORBID_INCOMING_XFERS);
2086 move_to_dialog_show_folders (dialog, selected);
2088 move_to_dialog_set_selected_folder_store (dialog, selected);
2090 g_object_unref (selected);
2094 on_move_to_dialog_selection_changed (GtkTreeSelection *selection,
2097 gboolean showing_folders;
2100 dialog = (GtkWidget *) user_data;
2101 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2102 if (showing_folders) {
2103 TnyFolderStore *selected;
2104 GtkWidget *folder_view;
2106 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2107 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2110 move_to_dialog_set_selected_folder_store (dialog, selected);
2111 g_object_unref (selected);
2117 on_move_to_dialog_action_clicked (GtkButton *selection,
2121 gboolean showing_folders;
2123 dialog = (GtkWidget *) user_data;
2124 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2125 if (showing_folders) {
2126 TnyFolderStore *selected;
2127 GtkWidget *folder_view;
2129 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2130 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2133 /* It's not possible to select root folders as
2134 targets unless they're the local account or
2135 the memory card account */
2136 if ((TNY_IS_FOLDER (selected) && !TNY_IS_MERGE_FOLDER (selected)) ||
2137 (TNY_IS_ACCOUNT (selected) &&
2138 (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (selected)) ||
2139 modest_tny_account_is_memory_card_account (TNY_ACCOUNT (selected)))))
2140 gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
2141 g_object_unref (selected);
2147 move_to_dialog_activity_changed (ModestFolderView *folder_view, gboolean activity, GtkDialog *dialog)
2152 modest_platform_create_move_to_dialog (GtkWindow *parent_window,
2153 GtkWidget **folder_view)
2155 GtkWidget *dialog, *folder_view_container;
2157 GtkWidget *buttons_hbox;
2158 GtkWidget *back_button;
2159 GdkPixbuf *back_pixbuf;
2160 GtkWidget *top_vbox;
2161 GtkWidget *action_button;
2162 GtkTreeSelection *selection;
2164 /* Create dialog. We cannot use a touch selector because we
2165 need to use here the folder view widget directly */
2166 dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
2167 GTK_WINDOW (parent_window),
2168 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR |
2169 GTK_DIALOG_DESTROY_WITH_PARENT,
2170 _FM_CHANGE_FOLDER_NEW_FOLDER,
2171 MODEST_GTK_RESPONSE_NEW_FOLDER,
2174 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
2175 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_NONE);
2176 top_vbox = gtk_vbox_new (FALSE, MODEST_MARGIN_HALF);
2178 /* Create folder view */
2179 *folder_view = modest_platform_create_folder_view_full (NULL, FALSE);
2180 g_signal_connect (G_OBJECT (*folder_view), "activity-changed", G_CALLBACK (move_to_dialog_activity_changed),
2183 modest_folder_view_set_cell_style (MODEST_FOLDER_VIEW (*folder_view),
2184 MODEST_FOLDER_VIEW_CELL_STYLE_COMPACT);
2185 modest_folder_view_show_message_count (MODEST_FOLDER_VIEW (*folder_view),
2187 tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (*folder_view),
2188 (TnyAccountStore *) modest_runtime_get_account_store ());
2190 buttons_hbox = gtk_hbox_new (FALSE, MODEST_MARGIN_HALF);
2191 back_button = gtk_button_new ();
2192 back_pixbuf = modest_platform_get_icon (_FM_FOLDER_UP, MODEST_ICON_SIZE_BIG);
2194 gtk_button_set_image (GTK_BUTTON (back_button), gtk_image_new_from_pixbuf (back_pixbuf));
2195 g_object_unref (back_pixbuf);
2198 action_button = gtk_button_new ();
2199 gtk_button_set_alignment (GTK_BUTTON (action_button), 0.0, 0.5);
2201 gtk_box_pack_start (GTK_BOX (buttons_hbox), back_button, FALSE, FALSE, 0);
2202 gtk_box_pack_start (GTK_BOX (buttons_hbox), action_button, TRUE, TRUE, 0);
2203 gtk_widget_set_sensitive (GTK_WIDGET (back_button), FALSE);
2204 gtk_widget_set_sensitive (GTK_WIDGET (action_button), FALSE);
2205 gtk_box_pack_start (GTK_BOX (top_vbox), buttons_hbox, FALSE, FALSE, 0);
2207 /* Create scrollable and add it to the dialog */
2208 folder_view_container = modest_toolkit_factory_create_scrollable (modest_runtime_get_toolkit_factory ());
2209 gtk_container_add (GTK_CONTAINER (folder_view_container), *folder_view);
2210 gtk_box_pack_start (GTK_BOX (top_vbox), folder_view_container, TRUE, TRUE, 0);
2212 gtk_container_add (GTK_CONTAINER (align), top_vbox);
2213 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), align, TRUE, TRUE, 0);
2215 gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
2217 gtk_widget_show (GTK_DIALOG (dialog)->vbox);
2218 gtk_widget_show (folder_view_container);
2219 gtk_widget_show (align);
2220 gtk_widget_show (top_vbox);
2221 gtk_widget_show (*folder_view);
2222 gtk_widget_show_all (back_button);
2223 gtk_widget_show (action_button);
2224 gtk_widget_show (buttons_hbox);
2225 gtk_widget_show (dialog);
2227 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW, *folder_view);
2228 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON, back_button);
2229 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON, action_button);
2230 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SCROLLABLE, folder_view_container);
2232 /* Simulate the behaviour of a HildonPickerDialog by emitting
2233 a response when a folder is selected */
2234 g_signal_connect (*folder_view, "row-activated",
2235 G_CALLBACK (on_move_to_dialog_row_activated),
2238 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (*folder_view));
2239 g_signal_connect (selection, "changed",
2240 G_CALLBACK (on_move_to_dialog_selection_changed),
2243 g_signal_connect (action_button, "clicked",
2244 G_CALLBACK (on_move_to_dialog_action_clicked),
2247 g_signal_connect (back_button, "clicked",
2248 G_CALLBACK (on_move_to_dialog_back_clicked),
2251 move_to_dialog_show_accounts (dialog);
2257 modest_platform_get_list_to_move (ModestWindow *window)
2259 TnyList *list = NULL;
2261 if (MODEST_IS_HEADER_WINDOW (window)) {
2262 ModestHeaderView *header_view;
2264 header_view = modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window));
2265 list = modest_header_view_get_selected_headers (header_view);
2266 } else if (MODEST_IS_FOLDER_WINDOW (window)) {
2267 ModestFolderView *folder_view;
2268 TnyFolderStore *selected_folder;
2270 list = TNY_LIST (tny_simple_list_new ());
2271 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window));
2272 selected_folder = modest_folder_view_get_selected (folder_view);
2273 if (selected_folder) {
2274 tny_list_prepend (list, G_OBJECT (selected_folder));
2275 g_object_unref (selected_folder);
2278 } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
2281 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (window));
2283 list = TNY_LIST (tny_simple_list_new ());
2284 tny_list_prepend (list, G_OBJECT (header));
2285 g_object_unref (header);
2288 g_return_val_if_reached (NULL);