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"
70 #define HILDON_OSSO_URI_ACTION "uri-action"
71 #define URI_ACTION_COPY "copy:"
72 #define MODEST_NOTIFICATION_CATEGORY "email-message"
73 #define MODEST_NEW_MAIL_LIGHTING_PATTERN "PatternChatAndEmail"
75 #define COMMON_FOLDER_DIALOG_ENTRY "entry"
76 #define COMMON_FOLDER_DIALOG_ACCOUNT_PICKER "account-picker"
77 #define FOLDER_PICKER_CURRENT_FOLDER "current-folder"
78 #define FOLDER_PICKER_ORIGINAL_ACCOUNT "original-account"
81 on_modest_conf_update_interval_changed (ModestConf* self,
83 ModestConfEvent event,
84 ModestConfNotificationId id,
87 g_return_if_fail (key);
89 if (strcmp (key, MODEST_CONF_UPDATE_INTERVAL) == 0) {
90 const guint update_interval_minutes =
91 modest_conf_get_int (self, MODEST_CONF_UPDATE_INTERVAL, NULL);
92 modest_platform_set_update_interval (update_interval_minutes);
99 check_required_files (void)
102 FILE *mcc_file = modest_utils_open_mcc_mapping_file ();
105 g_printerr ("modest: check for mcc file (for LANG) failed\n");
111 if (access(MODEST_PROVIDER_DATA_FILE, R_OK) != 0 &&
112 access(MODEST_FALLBACK_PROVIDER_DATA_FILE, R_OK) != 0) {
113 g_printerr ("modest: cannot find providers data\n");
121 /* the gpointer here is the osso_context. */
123 modest_platform_init (int argc, char *argv[])
127 if (!check_required_files ()) {
128 g_printerr ("modest: missing required files\n");
132 /* Make sure that the update interval is changed whenever its gconf key
134 /* CAUTION: we're not using here the
135 modest_conf_listen_to_namespace because we know that there
136 are other parts of Modest listening for this namespace, so
137 we'll receive the notifications anyway. We basically do not
138 use it because there is no easy way to do the
139 modest_conf_forget_namespace */
140 ModestConf *conf = modest_runtime_get_conf ();
141 g_signal_connect (G_OBJECT(conf),
143 G_CALLBACK (on_modest_conf_update_interval_changed),
146 /* only force the setting of the default interval, if there are actually
148 acc_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), TRUE);
150 /* Get the initial update interval from gconf: */
151 on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
152 MODEST_CONF_EVENT_KEY_CHANGED, 0, NULL);
153 modest_account_mgr_free_account_names (acc_names);
160 modest_platform_uninit (void)
169 modest_platform_get_new_device (void)
171 return TNY_DEVICE (tny_gnome_device_new ());
175 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
176 gchar **effective_mime_type)
179 g_warning ("Not implemented %s", __FUNCTION__);
188 modest_platform_activate_uri (const gchar *uri)
190 g_warning ("Not implemented %s", __FUNCTION__);
197 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
199 g_warning ("Not implemented %s", __FUNCTION__);
205 modest_platform_show_uri_popup (const gchar *uri)
207 g_warning ("Not implemented %s", __FUNCTION__);
214 modest_platform_get_icon (const gchar *name, guint icon_size)
216 return gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
224 modest_platform_get_app_name (void)
226 return _("mcen_ap_name");
230 entry_insert_text (GtkEditable *editable,
239 chars = gtk_editable_get_chars (editable, 0, -1);
240 chars_length = g_utf8_strlen (chars, -1);
243 /* Show WID-INF036 */
244 if (chars_length >= 20) {
245 modest_platform_information_banner (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
246 _CS("ckdg_ib_maximum_characters_reached"));
248 if (modest_text_utils_is_forbidden_char (*text, FOLDER_NAME_FORBIDDEN_CHARS)) {
252 tmp = g_strndup (folder_name_forbidden_chars,
253 FOLDER_NAME_FORBIDDEN_CHARS_LENGTH);
254 msg = g_strdup_printf (_CS("ckdg_ib_illegal_characters_entered"), tmp);
255 modest_platform_information_banner (gtk_widget_get_parent (GTK_WIDGET (data)),
261 modest_platform_information_banner (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
262 _CS("ckdg_ib_maximum_characters_reached"));
264 /* Write the text in the entry if it's valid */
265 g_signal_handlers_block_by_func (editable,
266 (gpointer) entry_insert_text, data);
267 gtk_editable_insert_text (editable, text, length, position);
268 g_signal_handlers_unblock_by_func (editable,
269 (gpointer) entry_insert_text, data);
272 /* Do not allow further processing */
273 g_signal_stop_emission_by_name (editable, "insert_text");
277 entry_changed (GtkEditable *editable,
281 GtkWidget *ok_button;
284 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
285 ok_button = GTK_WIDGET (buttons->data);
287 chars = gtk_editable_get_chars (editable, 0, -1);
288 g_return_if_fail (chars != NULL);
291 if (g_utf8_strlen (chars,-1) >= 20) {
292 modest_platform_information_banner (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
293 _CS("ckdg_ib_maximum_characters_reached"));
295 gtk_widget_set_sensitive (ok_button, modest_text_utils_validate_folder_name(chars));
298 g_list_free (buttons);
305 on_response (GtkDialog *dialog,
309 GtkWidget *entry, *picker;
310 TnyFolderStore *parent;
311 const gchar *new_name;
314 if (response != GTK_RESPONSE_ACCEPT)
318 entry = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY);
319 picker = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER);
321 parent = TNY_FOLDER_STORE (user_data);
322 new_name = gtk_entry_get_text (GTK_ENTRY (entry));
326 parent = g_object_get_data (G_OBJECT (picker), FOLDER_PICKER_CURRENT_FOLDER);
328 /* Look for another folder with the same name */
329 if (!TNY_IS_MERGE_FOLDER (parent) &&
330 modest_tny_folder_has_subfolder_with_name (parent, new_name, TRUE))
334 if (TNY_IS_ACCOUNT (parent) &&
335 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (parent)) &&
336 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (parent),
344 modest_platform_information_banner (gtk_widget_get_parent (GTK_WIDGET (dialog)),
345 NULL, _CS("ckdg_ib_folder_already_exists"));
346 /* Select the text */
347 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
348 gtk_widget_grab_focus (entry);
349 /* Do not close the dialog */
350 g_signal_stop_emission_by_name (dialog, "response");
354 typedef struct _FolderChooserData {
355 TnyFolderStore *store;
360 folder_chooser_activated (ModestFolderView *folder_view,
361 TnyFolderStore *folder,
362 FolderChooserData *userdata)
364 userdata->store = folder;
365 gtk_dialog_response (GTK_DIALOG (userdata->dialog), GTK_RESPONSE_OK);
368 static TnyFolderStore *
369 folder_chooser_dialog_run (ModestFolderView *original,
370 TnyFolderStore *current,
373 GtkWidget *folder_view;
374 FolderChooserData userdata = {NULL, NULL};
375 GtkWidget *scrollable;
376 const gchar *visible_id = NULL;
378 userdata.dialog = gtk_dialog_new ();
379 scrollable = modest_toolkit_factory_create_scrollable (modest_runtime_get_toolkit_factory ());
380 folder_view = modest_platform_create_folder_view (NULL);
382 gtk_window_set_title (GTK_WINDOW (userdata.dialog), _FM("ckdg_ti_change_folder"));
384 modest_folder_view_copy_model (MODEST_FOLDER_VIEW (original),
385 MODEST_FOLDER_VIEW (folder_view));
387 if (TNY_IS_ACCOUNT (current)) {
388 /* Local folders and MMC account are always shown
389 along with the currently visible server account */
390 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (current)) ||
391 modest_tny_account_is_memory_card_account (TNY_ACCOUNT (current)))
392 visible_id = g_object_get_data ((GObject *) picker, FOLDER_PICKER_ORIGINAL_ACCOUNT);
394 visible_id = tny_account_get_id (TNY_ACCOUNT (current));
395 } else if (TNY_IS_FOLDER (current)) {
397 account = modest_tny_folder_get_account ((TnyFolder *) current);
399 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (account)) ||
400 modest_tny_account_is_memory_card_account (TNY_ACCOUNT (account))) {
401 visible_id = g_object_get_data ((GObject *) picker, FOLDER_PICKER_ORIGINAL_ACCOUNT);
403 visible_id = tny_account_get_id (account);
405 g_object_unref (account);
409 modest_folder_view_get_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(original));
412 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(folder_view),
415 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (userdata.dialog)->vbox), scrollable);
416 gtk_container_add (GTK_CONTAINER (scrollable), folder_view);
417 gtk_widget_set_size_request (scrollable, -1, 320);
419 gtk_widget_show (folder_view);
420 gtk_widget_show (scrollable);
421 gtk_widget_show (userdata.dialog);
422 g_signal_connect (G_OBJECT (folder_view), "folder-activated",
423 G_CALLBACK (folder_chooser_activated),
424 (gpointer) &userdata);
426 gtk_dialog_run (GTK_DIALOG (userdata.dialog));
427 gtk_widget_destroy (userdata.dialog);
429 return userdata.store;
433 folder_store_get_display_name (TnyFolderStore *store)
435 if (TNY_IS_ACCOUNT (store)) {
436 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
437 return modest_conf_get_string (modest_runtime_get_conf(),
438 MODEST_CONF_DEVICE_NAME, NULL);
440 return g_strdup (tny_account_get_name (TNY_ACCOUNT (store)));
443 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
445 fname = g_strdup (tny_folder_get_name (TNY_FOLDER (store)));
446 type = tny_folder_get_folder_type (TNY_FOLDER (store));
447 if (modest_tny_folder_is_local_folder (TNY_FOLDER (store)) ||
448 modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
449 type = modest_tny_folder_get_local_or_mmc_folder_type (TNY_FOLDER (store));
450 if (type != TNY_FOLDER_TYPE_UNKNOWN) {
452 fname = g_strdup (modest_local_folder_info_get_type_display_name (type));
455 /* Sometimes an special folder is reported by the server as
456 NORMAL, like some versions of Dovecot */
457 if (type == TNY_FOLDER_TYPE_NORMAL ||
458 type == TNY_FOLDER_TYPE_UNKNOWN) {
459 type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
463 if (type == TNY_FOLDER_TYPE_INBOX) {
465 fname = g_strdup (_("mcen_me_folder_inbox"));
472 get_image_for_folder_store (TnyFolderStore *store,
476 const gchar *icon_name = NULL;
477 GtkWidget *image = NULL;
479 if (TNY_IS_ACCOUNT (store)) {
480 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
481 icon_name = MODEST_FOLDER_ICON_LOCAL_FOLDERS;
482 else if (modest_tny_account_is_memory_card_account (TNY_ACCOUNT (store)))
483 icon_name = MODEST_FOLDER_ICON_MMC;
485 icon_name = MODEST_FOLDER_ICON_ACCOUNT;
487 TnyFolderType type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
488 if (modest_tny_folder_is_remote_folder (TNY_FOLDER (store))) {
490 case TNY_FOLDER_TYPE_INBOX:
491 icon_name = MODEST_FOLDER_ICON_INBOX;
494 icon_name = MODEST_FOLDER_ICON_REMOTE_FOLDER;
496 } else if (modest_tny_folder_is_local_folder (TNY_FOLDER (store))) {
498 case TNY_FOLDER_TYPE_OUTBOX:
499 icon_name = MODEST_FOLDER_ICON_OUTBOX;
501 case TNY_FOLDER_TYPE_DRAFTS:
502 icon_name = MODEST_FOLDER_ICON_DRAFTS;
504 case TNY_FOLDER_TYPE_SENT:
505 icon_name = MODEST_FOLDER_ICON_SENT;
508 icon_name = MODEST_FOLDER_ICON_NORMAL;
510 } else if (modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
511 icon_name = MODEST_FOLDER_ICON_MMC_FOLDER;
516 pixbuf = modest_platform_get_icon (icon_name, size);
519 image = gtk_image_new_from_pixbuf (pixbuf);
520 g_object_unref (pixbuf);
527 folder_picker_set_store (GtkButton *button, TnyFolderStore *store)
532 g_object_set_data (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER, NULL);
536 g_object_set_data_full (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER,
537 g_object_ref (store),
538 (GDestroyNotify) g_object_unref);
539 name = folder_store_get_display_name (store);
540 gtk_button_set_label (GTK_BUTTON (button), name);
544 image = get_image_for_folder_store (store, MODEST_ICON_SIZE_SMALL);
546 gtk_button_set_image (GTK_BUTTON (button), image);
550 /* Always returns DUPs so you must free the returned value */
552 get_next_folder_name (const gchar *suggested_name,
553 TnyFolderStore *suggested_folder)
555 const gchar *default_name = _FM("ckdg_va_new_folder_name_stub");
557 gchar *real_suggested_name;
559 if (suggested_name !=NULL) {
560 return g_strdup (suggested_name);
563 for(i = 0; i < 100; ++ i) {
564 gboolean exists = FALSE;
567 real_suggested_name = g_strdup (default_name);
569 real_suggested_name = g_strdup_printf ("%s(%d)",
570 _FM("ckdg_va_new_folder_name_stub"),
572 exists = modest_tny_folder_has_subfolder_with_name (suggested_folder,
579 g_free (real_suggested_name);
582 /* Didn't find a free number */
584 real_suggested_name = g_strdup (default_name);
586 return real_suggested_name;
590 ModestFolderView *folder_view;
592 } FolderPickerHelper;
595 folder_picker_clicked (GtkButton *button,
596 FolderPickerHelper *helper)
598 TnyFolderStore *store, *current;
600 current = g_object_get_data (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER);
602 store = folder_chooser_dialog_run (helper->folder_view, current, button);
604 const gchar *current_name;
605 gboolean exists = FALSE;
607 folder_picker_set_store (GTK_BUTTON (button), store);
609 /* Update the name of the folder */
610 current_name = gtk_entry_get_text (helper->entry);
612 if (TNY_IS_FOLDER_STORE (store))
613 exists = modest_tny_folder_has_subfolder_with_name (store,
617 gchar *new_name = get_next_folder_name (NULL, store);
618 gtk_entry_set_text (helper->entry, new_name);
625 folder_picker_new (TnyFolderStore *suggested, FolderPickerHelper *helper)
628 const gchar *acc_id = NULL;
630 button = gtk_button_new ();
632 gtk_misc_set_alignment (GTK_MISC (button), 0.0, 0.5);
636 folder_picker_set_store (GTK_BUTTON (button), suggested);
638 if (TNY_IS_ACCOUNT (suggested)) {
639 if (!modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (suggested)) &&
640 !modest_tny_account_is_memory_card_account (TNY_ACCOUNT (suggested)))
641 acc_id = tny_account_get_id ((TnyAccount *) suggested);
643 TnyAccount *account = modest_tny_folder_get_account ((TnyFolder *) suggested);
645 acc_id = tny_account_get_id ((TnyAccount *) account);
646 g_object_unref (account);
652 acc_id = modest_folder_view_get_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(helper->folder_view));
654 g_object_set_data_full (G_OBJECT (button), FOLDER_PICKER_ORIGINAL_ACCOUNT,
655 g_strdup (acc_id), (GDestroyNotify) g_free);
658 g_signal_connect (G_OBJECT (button), "clicked",
659 G_CALLBACK (folder_picker_clicked),
667 modest_platform_run_folder_common_dialog (GtkWindow *parent_window,
668 TnyFolderStore *suggested_parent,
669 const gchar *dialog_title,
670 const gchar *label_text,
671 const gchar *suggested_name,
673 gboolean show_parent,
675 TnyFolderStore **parent)
677 GtkWidget *accept_btn = NULL;
678 GtkWidget *dialog, *entry = NULL, *label_entry = NULL, *label_location = NULL, *hbox;
679 GtkWidget *account_picker = NULL;
680 GList *buttons = NULL;
682 GtkSizeGroup *sizegroup;
683 ModestFolderView *folder_view;
684 ModestWindow *folder_window;
685 ModestWindowMgr *window_mgr;
686 FolderPickerHelper *helper = NULL;
687 GtkWidget *top_vbox, *top_align;
689 window_mgr = modest_runtime_get_window_mgr ();
690 folder_window = modest_window_mgr_get_folder_window (window_mgr);
691 g_return_val_if_fail (MODEST_IS_FOLDER_WINDOW (folder_window), GTK_RESPONSE_NONE);
693 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (folder_window));
695 top_vbox = gtk_vbox_new (FALSE, 0);
696 top_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
697 gtk_alignment_set_padding (GTK_ALIGNMENT (top_align), 0, 0, MODEST_MARGIN_DOUBLE, 0);
699 /* Ask the user for the folder name */
700 dialog = gtk_dialog_new_with_buttons (dialog_title,
702 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
703 _FM("ckdg_bd_new_folder_dialog_ok"),
707 /* Add accept button (with unsensitive handler) */
708 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
709 accept_btn = GTK_WIDGET (buttons->data);
711 sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
714 label_entry = gtk_label_new (label_text);
715 entry = modest_toolkit_factory_create_entry (modest_runtime_get_toolkit_factory ());
716 gtk_entry_set_max_length (GTK_ENTRY (entry), 20);
718 gtk_misc_set_alignment (GTK_MISC (label_entry), 0.0, 0.5);
719 gtk_size_group_add_widget (sizegroup, label_entry);
722 gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
724 gtk_entry_set_text (GTK_ENTRY (entry), _FM("ckdg_va_new_folder_name_stub"));
725 gtk_entry_set_width_chars (GTK_ENTRY (entry),
726 MAX (g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (entry)), -1),
727 g_utf8_strlen (_FM("ckdg_va_new_folder_name_stub"), -1)));
728 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
733 label_location = gtk_label_new (_FM("ckdg_fi_new_folder_location"));
735 gtk_misc_set_alignment (GTK_MISC (label_location), 0.0, 0.5);
736 gtk_size_group_add_widget (sizegroup, label_location);
738 helper = g_slice_new0 (FolderPickerHelper);
739 helper->folder_view = folder_view;
740 helper->entry = (GtkEntry *) entry;
742 account_picker = folder_picker_new (suggested_parent, helper);
745 g_object_unref (sizegroup);
747 /* Connect to the response method to avoid closing the dialog
748 when an invalid name is selected*/
749 g_signal_connect (dialog,
751 G_CALLBACK (on_response),
755 /* Track entry changes */
756 g_signal_connect (entry,
758 G_CALLBACK (entry_insert_text),
760 g_signal_connect (entry,
762 G_CALLBACK (entry_changed),
767 /* Some locales like pt_BR need this to get the full window
769 gtk_widget_set_size_request (GTK_WIDGET (dialog), 300, -1);
771 /* Create the hbox */
773 hbox = gtk_hbox_new (FALSE, 12);
774 gtk_box_pack_start (GTK_BOX (hbox), label_entry, FALSE, FALSE, 0);
775 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
777 /* Add hbox to dialog */
778 gtk_box_pack_start (GTK_BOX (top_vbox),
779 hbox, FALSE, FALSE, 0);
780 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY, entry);
784 hbox = gtk_hbox_new (FALSE, 12);
785 gtk_box_pack_start (GTK_BOX (hbox), label_location, FALSE, FALSE, 0);
786 gtk_box_pack_start (GTK_BOX (hbox), account_picker, TRUE, TRUE, 0);
788 /* Add hbox to dialog */
789 gtk_box_pack_start (GTK_BOX (top_vbox),
790 hbox, FALSE, FALSE, 0);
791 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER, account_picker);
793 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
794 GTK_WINDOW (dialog), parent_window);
796 gtk_container_add (GTK_CONTAINER (top_align), top_vbox);
797 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), top_align, TRUE, TRUE, 0);
799 gtk_widget_show_all (GTK_WIDGET(dialog));
801 result = gtk_dialog_run (GTK_DIALOG(dialog));
802 if (result == GTK_RESPONSE_ACCEPT) {
804 *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
806 *parent = g_object_get_data (G_OBJECT (account_picker), FOLDER_PICKER_CURRENT_FOLDER);
808 g_object_ref (*parent);
812 gtk_widget_destroy (dialog);
815 g_slice_free (FolderPickerHelper, helper);
817 while (gtk_events_pending ())
818 gtk_main_iteration ();
824 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
825 TnyFolderStore *suggested_folder,
826 gchar *suggested_name,
828 TnyFolderStore **parent_folder)
830 gchar *real_suggested_name = NULL;
832 ModestTnyAccountStore *acc_store;
834 gboolean do_free = FALSE;
836 real_suggested_name = get_next_folder_name ((const gchar *) suggested_name,
839 /* In hildon 2.2 we always suggest the archive folder as parent */
840 if (!suggested_folder) {
841 acc_store = modest_runtime_get_account_store ();
842 account = modest_tny_account_store_get_mmc_folders_account (acc_store);
844 suggested_folder = (TnyFolderStore *)
845 modest_tny_account_get_special_folder (account,
846 TNY_FOLDER_TYPE_ARCHIVE);
847 g_object_unref (account);
852 /* If there is not archive folder then fallback to local folders account */
853 if (!suggested_folder) {
855 suggested_folder = (TnyFolderStore *)
856 modest_tny_account_store_get_local_folders_account (acc_store);
859 result = modest_platform_run_folder_common_dialog (parent_window,
861 _HL_TITLE_NEW_FOLDER,
862 _FM("ckdg_fi_new_folder_name"),
870 g_object_unref (suggested_folder);
872 g_free(real_suggested_name);
878 modest_platform_run_rename_folder_dialog (ModestWindow *parent_window,
879 TnyFolderStore *parent_folder,
880 const gchar *suggested_name,
883 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
885 return modest_platform_run_folder_common_dialog (gtk_widget_get_toplevel (GTK_WIDGET (parent_window)),
887 _HL_TITLE_RENAME_FOLDER,
899 on_destroy_dialog (GtkWidget *dialog)
901 /* This could happen when the dialogs get programatically
902 hidden or destroyed (for example when closing the
903 application while a dialog is being shown) */
904 if (!GTK_IS_WIDGET (dialog))
907 gtk_widget_destroy (dialog);
909 if (gtk_events_pending ())
910 gtk_main_iteration ();
914 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
915 const gchar *message)
920 dialog = gtk_message_dialog_new (parent_window, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
921 GTK_MESSAGE_QUESTION,
922 GTK_BUTTONS_OK_CANCEL,
924 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
925 GTK_WINDOW (dialog), parent_window);
927 response = gtk_dialog_run (GTK_DIALOG (dialog));
929 on_destroy_dialog (dialog);
935 modest_platform_run_confirmation_dialog_with_buttons (GtkWindow *parent_window,
936 const gchar *message,
937 const gchar *button_accept,
938 const gchar *button_cancel)
943 dialog = gtk_message_dialog_new (parent_window, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
944 GTK_MESSAGE_QUESTION,
947 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
948 button_accept, GTK_RESPONSE_ACCEPT,
949 button_cancel, GTK_RESPONSE_CANCEL,
952 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
953 GTK_WINDOW (dialog), parent_window);
955 response = gtk_dialog_run (GTK_DIALOG (dialog));
957 on_destroy_dialog (dialog);
963 modest_platform_run_information_dialog (GtkWindow *parent_window,
964 const gchar *message,
969 note = gtk_message_dialog_new (parent_window, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
974 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
975 GTK_WINDOW (note), parent_window);
978 gtk_dialog_run (GTK_DIALOG (note));
980 on_destroy_dialog (note);
982 g_signal_connect_swapped (note,
984 G_CALLBACK (on_destroy_dialog),
987 gtk_widget_show_all (note);
991 typedef struct _ConnectAndWaitData {
993 GMainLoop *wait_loop;
994 gboolean has_callback;
996 } ConnectAndWaitData;
1000 modest_platform_connect_and_wait (GtkWindow *parent_window,
1001 TnyAccount *account)
1003 gboolean device_online;
1005 TnyConnectionStatus conn_status;
1006 gboolean user_requested;
1008 device = modest_runtime_get_device();
1009 device_online = tny_device_is_online (device);
1011 /* Whether the connection is user requested or automatically
1012 requested, for example via D-Bus */
1013 user_requested = (parent_window) ? TRUE : FALSE;
1015 /* If there is no account check only the device status */
1020 /* TODO: should show connection dialog through gnome device */
1024 /* Return if the account is already connected */
1025 conn_status = tny_account_get_connection_status (account);
1026 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
1033 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1035 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1036 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1037 /* This must be a maildir account, which does not require a connection: */
1042 return modest_platform_connect_and_wait (parent_window, account);
1046 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1049 return TRUE; /* Maybe it is something local. */
1051 gboolean result = TRUE;
1052 if (TNY_IS_FOLDER (folder_store)) {
1053 /* Get the folder's parent account: */
1054 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1055 if (account != NULL) {
1056 result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1057 g_object_unref (account);
1059 } else if (TNY_IS_ACCOUNT (folder_store)) {
1060 /* Use the folder store as an account: */
1061 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1068 modest_platform_create_sort_dialog (GtkWindow *parent_window)
1076 modest_platform_set_update_interval (guint minutes)
1082 modest_platform_push_email_notification(void)
1088 modest_platform_on_new_headers_received (GList *URI_list,
1089 gboolean show_visual)
1095 modest_platform_remove_new_mail_notifications (gboolean only_visuals)
1103 modest_platform_get_global_settings_dialog ()
1105 return modest_default_global_settings_dialog_new ();
1109 modest_platform_show_help (GtkWindow *parent_window,
1110 const gchar *help_id)
1116 modest_platform_show_search_messages (GtkWindow *parent_window)
1122 modest_platform_show_addressbook (GtkWindow *parent_window)
1128 modest_platform_create_folder_view_full (TnyFolderStoreQuery *query, gboolean do_refresh)
1130 GtkWidget *widget = modest_folder_view_new_full (query, do_refresh);
1132 /* Show one account by default */
1133 modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1134 MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1140 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1142 return modest_platform_create_folder_view_full (query, TRUE);
1146 banner_finish (gpointer data, GObject *object)
1148 ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1149 modest_window_mgr_unregister_banner (mgr);
1150 g_object_unref (mgr);
1154 modest_platform_information_banner (GtkWidget *parent,
1155 const gchar *icon_name,
1162 modest_platform_system_banner (GtkWidget *parent,
1163 const gchar *icon_name,
1170 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1171 const gchar *icon_name,
1179 modest_platform_animation_banner (GtkWidget *parent,
1180 const gchar *animation_name,
1189 TnyAccount *account;
1192 } CheckAccountIdleData;
1194 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1197 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1199 gboolean stop_trying = FALSE;
1200 g_return_val_if_fail (data && data->account, FALSE);
1202 if (data && data->account &&
1203 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1204 * after which the account is likely to be usable, or never likely to be usable soon: */
1205 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1207 data->is_online = TRUE;
1211 /* Give up if we have tried too many times: */
1212 if (data->count_tries >= NUMBER_OF_TRIES) {
1215 /* Wait for another timeout: */
1216 ++(data->count_tries);
1221 /* Allow the function that requested this idle callback to continue: */
1223 g_main_loop_quit (data->loop);
1226 g_object_unref (data->account);
1228 return FALSE; /* Don't call this again. */
1230 return TRUE; /* Call this timeout callback again. */
1234 /* Return TRUE immediately if the account is already online,
1235 * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as
1236 * soon as the account is online, or FALSE if the account does
1237 * not become online in the NUMBER_OF_TRIES seconds.
1238 * This is useful when the D-Bus method was run immediately after
1239 * the application was started (when using D-Bus activation),
1240 * because the account usually takes a short time to go online.
1241 * The return value is maybe not very useful.
1244 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1248 g_return_val_if_fail (account, FALSE);
1250 if (!tny_device_is_online (modest_runtime_get_device())) {
1251 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1255 /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1256 * so we avoid wait unnecessarily: */
1257 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1260 /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED,
1261 * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that
1262 * we want to avoid. */
1263 if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1266 /* This blocks on the result: */
1267 CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1268 data->is_online = FALSE;
1269 data->account = account;
1270 g_object_ref (data->account);
1271 data->count_tries = 0;
1273 GMainContext *context = NULL; /* g_main_context_new (); */
1274 data->loop = g_main_loop_new (context, FALSE /* not running */);
1276 g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1278 /* This main loop will run until the idle handler has stopped it: */
1279 g_main_loop_run (data->loop);
1281 g_main_loop_unref (data->loop);
1282 /* g_main_context_unref (context); */
1284 is_online = data->is_online;
1285 g_slice_free (CheckAccountIdleData, data);
1293 on_cert_dialog_response (GtkDialog *dialog, gint response_id, const gchar* cert)
1295 /* GTK_RESPONSE_HELP means we need to show the certificate */
1296 if (response_id == GTK_RESPONSE_APPLY) {
1299 /* Do not close the dialog */
1300 g_signal_stop_emission_by_name (dialog, "response");
1302 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);
1303 modest_platform_run_information_dialog (NULL, msg, TRUE);
1309 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1310 const gchar *certificate)
1316 gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1319 /* We use GTK_RESPONSE_APPLY because we want the button in the
1320 middle of OK and CANCEL the same as the browser does for
1321 example. With GTK_RESPONSE_HELP the view button is aligned
1322 to the left while the other two to the right */
1323 note = gtk_message_dialog_new (
1325 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1326 GTK_MESSAGE_QUESTION,
1329 gtk_dialog_add_buttons (GTK_DIALOG (note),
1330 _HL_YES, GTK_RESPONSE_OK,
1331 _HL_VIEW, GTK_RESPONSE_APPLY, /* abusing this... */
1332 _HL_NO, GTK_RESPONSE_CANCEL,
1335 g_signal_connect (G_OBJECT(note), "response",
1336 G_CALLBACK(on_cert_dialog_response),
1337 (gpointer) certificate);
1339 response = gtk_dialog_run(GTK_DIALOG(note));
1341 on_destroy_dialog (note);
1344 return response == GTK_RESPONSE_OK;
1348 modest_platform_run_alert_dialog (const gchar* prompt,
1349 gboolean is_question)
1352 gboolean retval = TRUE;
1355 /* The Tinymail documentation says that we should show Yes and No buttons,
1356 * when it is a question.
1357 * Obviously, we need tinymail to use more specific error codes instead,
1358 * so we know what buttons to show. */
1359 dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1360 GTK_MESSAGE_QUESTION,
1364 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
1365 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
1367 on_destroy_dialog (dialog);
1369 /* Just show the error text and use the default response: */
1370 modest_platform_run_information_dialog (NULL,
1378 GtkWindow *parent_window;
1379 ModestConnectedPerformer callback;
1380 TnyAccount *account;
1387 on_went_online_info_free (OnWentOnlineInfo *info)
1389 /* And if we cleanup, we DO cleanup :-) */
1392 g_object_unref (info->device);
1395 if (info->parent_window)
1396 g_object_unref (info->parent_window);
1398 g_object_unref (info->account);
1400 g_slice_free (OnWentOnlineInfo, info);
1402 /* We're done ... */
1408 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
1410 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1412 /* Now it's really time to callback to the caller. If going online didn't succeed,
1413 * err will be set. We don't free it, Tinymail does that! If a cancel happened,
1414 * canceled will be set. Etcetera etcetera. */
1416 if (info->callback) {
1417 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1420 /* This is our last call, we must cleanup here if we didn't yet do that */
1421 on_went_online_info_free (info);
1427 modest_platform_connect_and_perform (GtkWindow *parent_window,
1429 TnyAccount *account,
1430 ModestConnectedPerformer callback,
1433 gboolean device_online;
1435 TnyConnectionStatus conn_status;
1437 device = modest_runtime_get_device();
1438 device_online = tny_device_is_online (device);
1440 /* If there is no account check only the device status */
1443 if (device_online) {
1445 /* We promise to instantly perform the callback, so ... */
1447 callback (FALSE, NULL, parent_window, account, user_data);
1454 /* The other code has no more reason to run. This is all that we can do for the
1455 * caller (he should have given us a nice and clean account instance!). We
1456 * can't do magic, we don't know what account he intends to bring online. So
1457 * we'll just bring the device online (and await his false bug report). */
1463 /* Return if the account is already connected */
1465 conn_status = tny_account_get_connection_status (account);
1466 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
1468 /* We promise to instantly perform the callback, so ... */
1470 callback (FALSE, NULL, parent_window, account, user_data);
1476 if (!device_online) {
1477 OnWentOnlineInfo *info = NULL;
1479 info = g_slice_new0 (OnWentOnlineInfo);
1481 info->device = NULL;
1483 info->account = TNY_ACCOUNT (g_object_ref (account));
1486 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
1488 info->parent_window = NULL;
1490 /* So we'll put the callback away for later ... */
1491 info->user_data = user_data;
1492 info->callback = callback;
1494 /* If the device is online, we'll just connect the account */
1495 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1496 on_account_went_online, info);
1499 /* The info gets freed by on_account_went_online or on_conic_device_went_online
1500 * in both situations, go look if you don't believe me! */
1504 modest_platform_connect_if_remote_and_perform (GtkWindow *parent_window,
1506 TnyFolderStore *folder_store,
1507 ModestConnectedPerformer callback,
1510 TnyAccount *account = NULL;
1512 if (!folder_store ||
1513 (TNY_IS_MERGE_FOLDER (folder_store) &&
1514 (tny_folder_get_folder_type (TNY_FOLDER(folder_store)) == TNY_FOLDER_TYPE_OUTBOX))) {
1516 /* We promise to instantly perform the callback, so ... */
1518 GError *error = NULL;
1519 g_set_error (&error, TNY_ERROR_DOMAIN, TNY_SERVICE_ERROR_UNKNOWN,
1520 "Unable to move or not found folder");
1521 callback (FALSE, error, parent_window, NULL, user_data);
1522 g_error_free (error);
1526 } else if (TNY_IS_FOLDER (folder_store)) {
1527 /* Get the folder's parent account: */
1528 account = tny_folder_get_account (TNY_FOLDER (folder_store));
1529 } else if (TNY_IS_ACCOUNT (folder_store)) {
1530 /* Use the folder store as an account: */
1531 account = TNY_ACCOUNT (g_object_ref (folder_store));
1534 if (account && (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE)) {
1535 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1536 /* No need to connect a local account */
1538 callback (FALSE, NULL, parent_window, account, user_data);
1543 modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
1547 g_object_unref (account);
1551 src_account_connect_performer (gboolean canceled,
1553 GtkWindow *parent_window,
1554 TnyAccount *src_account,
1557 DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
1559 if (canceled || err) {
1560 /* If there was any error call the user callback */
1561 info->callback (canceled, err, parent_window, src_account, info->data);
1563 /* Connect the destination account */
1564 modest_platform_connect_if_remote_and_perform (parent_window, TRUE,
1565 TNY_FOLDER_STORE (info->dst_account),
1566 info->callback, info->data);
1569 /* Free the info object */
1570 g_object_unref (info->dst_account);
1571 g_slice_free (DoubleConnectionInfo, info);
1576 modest_platform_double_connect_and_perform (GtkWindow *parent_window,
1578 TnyFolderStore *folder_store,
1579 DoubleConnectionInfo *connect_info)
1581 modest_platform_connect_if_remote_and_perform(parent_window,
1584 src_account_connect_performer,
1589 modest_platform_get_account_settings_wizard (void)
1591 ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
1593 return GTK_WIDGET (dialog);
1597 modest_platform_get_current_connection (void)
1599 TnyDevice *device = NULL;
1600 ModestConnectedVia retval = MODEST_CONNECTED_VIA_ANY;
1602 device = modest_runtime_get_device ();
1604 if (!tny_device_is_online (device))
1605 return MODEST_CONNECTED_VIA_ANY;
1607 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX; /* assume WLAN (fast) internet */
1614 modest_platform_check_memory_low (ModestWindow *win,
1622 modest_platform_run_folder_details_dialog (GtkWindow *parent_window,
1628 dialog = modest_toolkit_factory_create_details_dialog_with_folder (modest_runtime_get_toolkit_factory (),
1629 parent_window, folder);
1632 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1633 GTK_WINDOW (dialog),
1635 gtk_widget_show_all (dialog);
1637 g_signal_connect_swapped (dialog, "response",
1638 G_CALLBACK (gtk_widget_destroy),
1642 typedef struct _HeaderDetailsGetSizeInfo {
1646 } HeaderDetailsGetSizeInfo;
1649 header_details_dialog_destroy (gpointer userdata,
1652 HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) userdata;
1654 info->dialog = NULL;
1658 idle_get_mime_part_size_cb (gpointer userdata)
1660 HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) userdata;
1661 gdk_threads_enter ();
1663 if (info->dialog && GTK_WIDGET_VISIBLE (info->dialog)) {
1664 modest_details_dialog_set_message_size (MODEST_DETAILS_DIALOG (info->dialog),
1669 g_object_weak_unref (G_OBJECT (info->dialog), header_details_dialog_destroy, info);
1670 info->dialog = NULL;
1672 g_object_unref (info->part);
1673 g_slice_free (HeaderDetailsGetSizeInfo, info);
1675 gdk_threads_leave ();
1681 get_mime_part_size_thread (gpointer thr_user_data)
1683 HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) thr_user_data;
1685 TnyStream *count_stream;
1687 count_stream = modest_count_stream_new ();
1688 result = tny_mime_part_decode_to_stream (info->part, count_stream, NULL);
1689 info->total = modest_count_stream_get_count(MODEST_COUNT_STREAM (count_stream));
1690 if (info->total == 0) {
1691 modest_count_stream_reset_count(MODEST_COUNT_STREAM (count_stream));
1692 result = tny_mime_part_write_to_stream (info->part, count_stream, NULL);
1693 info->total = modest_count_stream_get_count(MODEST_COUNT_STREAM (count_stream));
1696 /* if there was an error, don't set the size (this is pretty uncommon) */
1698 g_warning ("%s: error while writing mime part to stream\n", __FUNCTION__);
1700 g_idle_add (idle_get_mime_part_size_cb, info);
1706 modest_platform_run_header_details_dialog (GtkWindow *parent_window,
1708 gboolean async_get_size,
1714 dialog = modest_toolkit_factory_create_details_dialog_with_header (modest_runtime_get_toolkit_factory (),
1715 parent_window, header, !async_get_size);
1717 if (async_get_size && msg && TNY_IS_MSG (msg)) {
1718 HeaderDetailsGetSizeInfo *info;
1719 info = g_slice_new (HeaderDetailsGetSizeInfo);
1720 info->dialog = dialog;
1722 info->part = TNY_MIME_PART (g_object_ref (msg));
1724 g_object_weak_ref (G_OBJECT (dialog), header_details_dialog_destroy, info);
1725 g_thread_create (get_mime_part_size_thread, info, FALSE, NULL);
1729 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1730 GTK_WINDOW (dialog),
1732 gtk_widget_show_all (dialog);
1734 g_signal_connect_swapped (dialog, "response",
1735 G_CALLBACK (gtk_widget_destroy),
1739 #define MOVE_TO_DIALOG_FOLDER_VIEW "folder-view"
1740 #define MOVE_TO_DIALOG_BACK_BUTTON "back-button"
1741 #define MOVE_TO_DIALOG_ACTION_BUTTON "action-button"
1742 #define MOVE_TO_DIALOG_SHOWING_FOLDERS "showing-folders"
1743 #define MOVE_TO_DIALOG_SCROLLABLE "scrollable"
1744 #define MOVE_TO_FOLDER_SEPARATOR "/"
1747 translate_path (gchar **path)
1752 gboolean add_separator;
1754 parts = g_strsplit (*path, MOVE_TO_FOLDER_SEPARATOR, 0);
1758 output = g_string_new ("");
1759 add_separator = FALSE;
1761 while (*current != NULL) {
1762 TnyFolderType folder_type;
1765 if (add_separator) {
1766 output = g_string_append (output, MOVE_TO_FOLDER_SEPARATOR);
1768 add_separator = TRUE;
1771 downcase = g_ascii_strdown (*current, -1);
1772 folder_type = modest_local_folder_info_get_type (downcase);
1773 if (strcmp (downcase, "inbox") == 0) {
1774 output = g_string_append (output, _("mcen_me_folder_inbox"));
1775 } else if (folder_type == TNY_FOLDER_TYPE_ARCHIVE ||
1776 folder_type == TNY_FOLDER_TYPE_DRAFTS ||
1777 folder_type == TNY_FOLDER_TYPE_SENT ||
1778 folder_type == TNY_FOLDER_TYPE_OUTBOX) {
1779 output = g_string_append (output, modest_local_folder_info_get_type_display_name (folder_type));
1781 output = g_string_append (output, *current);
1789 *path = g_string_free (output, FALSE);
1793 move_to_dialog_set_selected_folder_store (GtkWidget *dialog,
1794 TnyFolderStore *folder_store)
1796 GtkWidget *action_button;
1797 GtkWidget *image = NULL;
1798 TnyAccount *account;
1799 gchar *account_name = NULL, *short_name = NULL;
1801 action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
1803 /* Get account name */
1804 if (TNY_IS_FOLDER (folder_store))
1805 account = tny_folder_get_account (TNY_FOLDER (folder_store));
1807 account = g_object_ref (folder_store);
1809 if (modest_tny_account_is_virtual_local_folders (account))
1810 account_name = modest_conf_get_string (modest_runtime_get_conf(),
1811 MODEST_CONF_DEVICE_NAME, NULL);
1814 account_name = g_strdup (tny_account_get_name (account));
1816 g_object_unref (account);
1818 /* Set title of button: account or folder name */
1819 if (TNY_IS_FOLDER (folder_store))
1820 short_name = folder_store_get_display_name (folder_store);
1822 short_name = g_strdup (account_name);
1824 gtk_button_set_label (GTK_BUTTON (action_button), short_name);
1826 /* Set value of button, folder full name */
1827 if (TNY_IS_CAMEL_FOLDER (folder_store)) {
1828 const gchar *camel_full_name;
1829 gchar *last_slash, *full_name;
1831 camel_full_name = tny_camel_folder_get_full_name (TNY_CAMEL_FOLDER (folder_store));
1832 last_slash = g_strrstr (camel_full_name, "/");
1834 gchar *prefix = g_strndup (camel_full_name, last_slash - camel_full_name + 1);
1835 full_name = g_strconcat (account_name, MOVE_TO_FOLDER_SEPARATOR, prefix, short_name, NULL);
1838 full_name = g_strconcat (account_name, MOVE_TO_FOLDER_SEPARATOR,
1842 translate_path (&full_name);
1843 gtk_button_set_label (GTK_BUTTON (action_button), full_name);
1846 g_free (account_name);
1847 g_free (short_name);
1849 /* Set image for the button */
1850 image = get_image_for_folder_store (folder_store, MODEST_ICON_SIZE_BIG);
1852 gtk_button_set_image (GTK_BUTTON (action_button), image);
1856 move_to_dialog_show_accounts (GtkWidget *dialog)
1858 GtkWidget *back_button;
1859 GtkWidget *folder_view;
1860 GtkWidget *scrollable;
1861 GtkWidget *action_button;
1863 back_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
1864 action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
1865 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
1866 scrollable = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SCROLLABLE));
1868 gtk_widget_set_sensitive (back_button, FALSE);
1869 gtk_widget_set_sensitive (action_button, FALSE);
1871 /* Need to set this here, otherwise callbacks called because
1872 of filtering won't perform correctly */
1873 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS, GINT_TO_POINTER (FALSE));
1875 /* Reset action button */
1876 gtk_button_set_label (GTK_BUTTON (action_button), NULL);
1877 gtk_button_set_image (GTK_BUTTON (action_button), NULL);
1879 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view), NULL);
1880 modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), TRUE);
1881 modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ALL);
1882 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
1883 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
1884 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
1885 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
1886 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
1887 MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
1888 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
1889 MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
1890 modest_scrollable_jump_to (MODEST_SCROLLABLE (scrollable), 0, 0);
1894 move_to_dialog_show_folders (GtkWidget *dialog, TnyFolderStore *folder_store)
1896 GtkWidget *back_button;
1897 GtkWidget *folder_view;
1898 TnyAccount *account;
1899 const gchar *account_id;
1900 GtkWidget *scrollable;
1901 GtkWidget *action_button;
1904 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
1906 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
1908 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
1910 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SCROLLABLE));
1912 gtk_widget_set_sensitive (back_button, TRUE);
1913 gtk_widget_set_sensitive (action_button, TRUE);
1915 /* Need to set this here, otherwise callbacks called because
1916 of filtering won't perform correctly */
1917 g_object_set_data (G_OBJECT (dialog),
1918 MOVE_TO_DIALOG_SHOWING_FOLDERS,
1919 GINT_TO_POINTER (TRUE));
1921 account = TNY_ACCOUNT (folder_store);
1922 if (modest_tny_account_is_virtual_local_folders (account)) {
1923 account_id = tny_account_get_id (account);
1924 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
1925 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
1926 } else if (modest_tny_account_is_memory_card_account (account)) {
1927 account_id = tny_account_get_id (account);
1928 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
1929 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
1931 account_id = tny_account_get_id (account);
1932 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
1933 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
1934 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
1935 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
1938 move_to_dialog_set_selected_folder_store (dialog, folder_store);
1939 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view),
1942 modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), FALSE);
1943 modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1944 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
1945 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
1946 modest_scrollable_jump_to (MODEST_SCROLLABLE (scrollable), 0, 0);
1950 on_move_to_dialog_back_clicked (GtkButton *button,
1953 GtkWidget *dialog = (GtkWidget *) userdata;
1955 /* Back to show accounts */
1956 move_to_dialog_show_accounts (dialog);
1960 on_move_to_dialog_row_activated (GtkTreeView *tree_view,
1962 GtkTreeViewColumn *column,
1965 TnyFolderStore *selected = NULL;
1967 GtkWidget *folder_view;
1968 gboolean showing_folders;
1970 dialog = (GtkWidget *) user_data;
1971 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog),
1972 MOVE_TO_DIALOG_SHOWING_FOLDERS));
1974 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog),
1975 MOVE_TO_DIALOG_FOLDER_VIEW));
1977 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
1981 if (!showing_folders) {
1982 gboolean valid = TRUE;
1984 if (TNY_IS_ACCOUNT (selected) &&
1985 modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (selected))) {
1986 ModestProtocolType protocol_type;
1988 protocol_type = modest_tny_account_get_protocol_type (TNY_ACCOUNT (selected));
1989 valid = !modest_protocol_registry_protocol_type_has_tag
1990 (modest_runtime_get_protocol_registry (),
1992 MODEST_PROTOCOL_REGISTRY_STORE_FORBID_INCOMING_XFERS);
1995 move_to_dialog_show_folders (dialog, selected);
1997 move_to_dialog_set_selected_folder_store (dialog, selected);
1999 g_object_unref (selected);
2003 on_move_to_dialog_selection_changed (GtkTreeSelection *selection,
2006 gboolean showing_folders;
2009 dialog = (GtkWidget *) user_data;
2010 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2011 if (showing_folders) {
2012 TnyFolderStore *selected;
2013 GtkWidget *folder_view;
2015 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2016 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2019 move_to_dialog_set_selected_folder_store (dialog, selected);
2020 g_object_unref (selected);
2026 on_move_to_dialog_action_clicked (GtkButton *selection,
2030 gboolean showing_folders;
2032 dialog = (GtkWidget *) user_data;
2033 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2034 if (showing_folders) {
2035 TnyFolderStore *selected;
2036 GtkWidget *folder_view;
2038 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2039 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2042 /* It's not possible to select root folders as
2043 targets unless they're the local account or
2044 the memory card account */
2045 if ((TNY_IS_FOLDER (selected) && !TNY_IS_MERGE_FOLDER (selected)) ||
2046 (TNY_IS_ACCOUNT (selected) &&
2047 (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (selected)) ||
2048 modest_tny_account_is_memory_card_account (TNY_ACCOUNT (selected)))))
2049 gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
2050 g_object_unref (selected);
2056 move_to_dialog_activity_changed (ModestFolderView *folder_view, gboolean activity, GtkDialog *dialog)
2061 modest_platform_create_move_to_dialog (GtkWindow *parent_window,
2062 GtkWidget **folder_view)
2064 GtkWidget *dialog, *folder_view_container;
2066 GtkWidget *buttons_hbox;
2067 GtkWidget *back_button;
2068 GdkPixbuf *back_pixbuf;
2069 GtkWidget *top_vbox;
2070 GtkWidget *action_button;
2071 GtkTreeSelection *selection;
2073 /* Create dialog. We cannot use a touch selector because we
2074 need to use here the folder view widget directly */
2075 dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
2076 GTK_WINDOW (parent_window),
2077 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR |
2078 GTK_DIALOG_DESTROY_WITH_PARENT,
2079 _FM ("ckdg_bd_change_folder_new_folder"),
2080 MODEST_GTK_RESPONSE_NEW_FOLDER,
2083 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
2084 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_NONE);
2085 top_vbox = gtk_vbox_new (FALSE, MODEST_MARGIN_HALF);
2087 /* Create folder view */
2088 *folder_view = modest_platform_create_folder_view_full (NULL, FALSE);
2089 g_signal_connect (G_OBJECT (*folder_view), "activity-changed", G_CALLBACK (move_to_dialog_activity_changed),
2092 modest_folder_view_set_cell_style (MODEST_FOLDER_VIEW (*folder_view),
2093 MODEST_FOLDER_VIEW_CELL_STYLE_COMPACT);
2094 modest_folder_view_show_message_count (MODEST_FOLDER_VIEW (*folder_view),
2096 tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (*folder_view),
2097 (TnyAccountStore *) modest_runtime_get_account_store ());
2099 buttons_hbox = gtk_hbox_new (FALSE, MODEST_MARGIN_HALF);
2100 back_button = gtk_button_new ();
2101 back_pixbuf = modest_platform_get_icon (_FM("filemanager_folder_up"), MODEST_ICON_SIZE_BIG);
2103 gtk_button_set_image (GTK_BUTTON (back_button), gtk_image_new_from_pixbuf (back_pixbuf));
2104 g_object_unref (back_pixbuf);
2107 action_button = gtk_button_new ();
2108 gtk_button_set_alignment (GTK_BUTTON (action_button), 0.0, 0.5);
2110 gtk_box_pack_start (GTK_BOX (buttons_hbox), back_button, FALSE, FALSE, 0);
2111 gtk_box_pack_start (GTK_BOX (buttons_hbox), action_button, TRUE, TRUE, 0);
2112 gtk_widget_set_sensitive (GTK_WIDGET (back_button), FALSE);
2113 gtk_widget_set_sensitive (GTK_WIDGET (action_button), FALSE);
2114 gtk_box_pack_start (GTK_BOX (top_vbox), buttons_hbox, FALSE, FALSE, 0);
2116 /* Create scrollable and add it to the dialog */
2117 folder_view_container = modest_toolkit_factory_create_scrollable (modest_runtime_get_toolkit_factory ());
2118 gtk_container_add (GTK_CONTAINER (folder_view_container), *folder_view);
2119 gtk_box_pack_start (GTK_BOX (top_vbox), folder_view_container, TRUE, TRUE, 0);
2121 gtk_container_add (GTK_CONTAINER (align), top_vbox);
2122 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), align, TRUE, TRUE, 0);
2124 gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
2126 gtk_widget_show (GTK_DIALOG (dialog)->vbox);
2127 gtk_widget_show (folder_view_container);
2128 gtk_widget_show (align);
2129 gtk_widget_show (top_vbox);
2130 gtk_widget_show (*folder_view);
2131 gtk_widget_show_all (back_button);
2132 gtk_widget_show (action_button);
2133 gtk_widget_show (buttons_hbox);
2134 gtk_widget_show (dialog);
2136 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW, *folder_view);
2137 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON, back_button);
2138 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON, action_button);
2139 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SCROLLABLE, folder_view_container);
2141 /* Simulate the behaviour of a HildonPickerDialog by emitting
2142 a response when a folder is selected */
2143 g_signal_connect (*folder_view, "row-activated",
2144 G_CALLBACK (on_move_to_dialog_row_activated),
2147 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (*folder_view));
2148 g_signal_connect (selection, "changed",
2149 G_CALLBACK (on_move_to_dialog_selection_changed),
2152 g_signal_connect (action_button, "clicked",
2153 G_CALLBACK (on_move_to_dialog_action_clicked),
2156 g_signal_connect (back_button, "clicked",
2157 G_CALLBACK (on_move_to_dialog_back_clicked),
2160 move_to_dialog_show_accounts (dialog);
2166 modest_platform_get_list_to_move (ModestWindow *window)
2168 TnyList *list = NULL;
2170 if (MODEST_IS_HEADER_WINDOW (window)) {
2171 ModestHeaderView *header_view;
2173 header_view = modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window));
2174 list = modest_header_view_get_selected_headers (header_view);
2175 } else if (MODEST_IS_FOLDER_WINDOW (window)) {
2176 ModestFolderView *folder_view;
2177 TnyFolderStore *selected_folder;
2179 list = TNY_LIST (tny_simple_list_new ());
2180 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window));
2181 selected_folder = modest_folder_view_get_selected (folder_view);
2182 if (selected_folder) {
2183 tny_list_prepend (list, G_OBJECT (selected_folder));
2184 g_object_unref (selected_folder);
2187 } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
2190 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (window));
2192 list = TNY_LIST (tny_simple_list_new ());
2193 tny_list_prepend (list, G_OBJECT (header));
2194 g_object_unref (header);
2197 g_return_val_if_reached (NULL);