1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <glib/gi18n.h>
33 #include <modest-platform.h>
34 #include <modest-defs.h>
35 #include <modest-scrollable.h>
36 #include <modest-runtime.h>
37 #include <modest-main-window.h>
38 #include <modest-header-view.h>
39 #include "modest-widget-memory.h"
40 #include <modest-utils.h>
41 #include <tny-camel-folder.h>
42 #include <tny-simple-list.h>
43 #include <tny-merge-folder.h>
44 #include <tny-error.h>
45 #include <tny-folder.h>
46 #include <tny-account-store-view.h>
47 #include <tny-gnome-device.h>
49 #include <modest-text-utils.h>
50 #include "modest-tny-folder.h"
51 #include "modest-tny-account.h"
53 #include <libgnomevfs/gnome-vfs-mime-utils.h>
54 #include <modest-account-settings-dialog.h>
55 #include <modest-easysetup-wizard-dialog.h>
56 #include "widgets/modest-window-mgr.h"
57 #include <modest-datetime-formatter.h>
58 #include "modest-header-window.h"
59 #include <modest-folder-window.h>
60 #include <modest-account-mgr.h>
61 #include <modest-account-mgr-helpers.h>
62 #include <modest-ui-constants.h>
63 #include <modest-icon-names.h>
64 #include <modest-count-stream.h>
65 #include <modest-gtk-details-dialog.h>
69 #define HILDON_OSSO_URI_ACTION "uri-action"
70 #define URI_ACTION_COPY "copy:"
71 #define MODEST_NOTIFICATION_CATEGORY "email-message"
72 #define MODEST_NEW_MAIL_LIGHTING_PATTERN "PatternChatAndEmail"
74 #define COMMON_FOLDER_DIALOG_ENTRY "entry"
75 #define COMMON_FOLDER_DIALOG_ACCOUNT_PICKER "account-picker"
76 #define FOLDER_PICKER_CURRENT_FOLDER "current-folder"
77 #define FOLDER_PICKER_ORIGINAL_ACCOUNT "original-account"
79 static gboolean ca_con_opened = FALSE;
82 static void modest_platform_play_email_tone (void);
86 on_modest_conf_update_interval_changed (ModestConf* self,
88 ModestConfEvent event,
89 ModestConfNotificationId id,
92 g_return_if_fail (key);
94 if (strcmp (key, MODEST_CONF_UPDATE_INTERVAL) == 0) {
95 const guint update_interval_minutes =
96 modest_conf_get_int (self, MODEST_CONF_UPDATE_INTERVAL, NULL);
97 modest_platform_set_update_interval (update_interval_minutes);
104 check_required_files (void)
106 FILE *mcc_file = modest_utils_open_mcc_mapping_file ();
109 g_printerr ("modest: check for mcc file (for LANG) failed\n");
115 if (access(MODEST_PROVIDER_DATA_FILE, R_OK) != 0 &&
116 access(MODEST_FALLBACK_PROVIDER_DATA_FILE, R_OK) != 0) {
117 g_printerr ("modest: cannot find providers data\n");
125 /* the gpointer here is the osso_context. */
127 modest_platform_init (int argc, char *argv[])
131 if (!check_required_files ()) {
132 g_printerr ("modest: missing required files\n");
136 /* Make sure that the update interval is changed whenever its gconf key
138 /* CAUTION: we're not using here the
139 modest_conf_listen_to_namespace because we know that there
140 are other parts of Modest listening for this namespace, so
141 we'll receive the notifications anyway. We basically do not
142 use it because there is no easy way to do the
143 modest_conf_forget_namespace */
144 ModestConf *conf = modest_runtime_get_conf ();
145 g_signal_connect (G_OBJECT(conf),
147 G_CALLBACK (on_modest_conf_update_interval_changed),
150 /* only force the setting of the default interval, if there are actually
152 acc_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), TRUE);
154 /* Get the initial update interval from gconf: */
155 on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
156 MODEST_CONF_EVENT_KEY_CHANGED, 0, NULL);
157 modest_account_mgr_free_account_names (acc_names);
164 modest_platform_uninit (void)
173 modest_platform_get_new_device (void)
175 return TNY_DEVICE (tny_gnome_device_new ());
179 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
180 gchar **effective_mime_type)
183 g_warning ("Not implemented %s", __FUNCTION__);
192 modest_platform_activate_uri (const gchar *uri)
194 g_warning ("Not implemented %s", __FUNCTION__);
201 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
203 g_warning ("Not implemented %s", __FUNCTION__);
209 modest_platform_show_uri_popup (const gchar *uri)
211 g_warning ("Not implemented %s", __FUNCTION__);
218 modest_platform_get_icon (const gchar *name, guint icon_size)
220 g_warning ("Not implemented %s", __FUNCTION__);
226 modest_platform_get_app_name (void)
228 return _("mcen_ap_name");
232 entry_insert_text (GtkEditable *editable,
241 chars = gtk_editable_get_chars (editable, 0, -1);
242 chars_length = g_utf8_strlen (chars, -1);
245 /* Show WID-INF036 */
246 if (chars_length >= 20) {
247 modest_platform_information_banner (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
248 _CS("ckdg_ib_maximum_characters_reached"));
250 if (modest_text_utils_is_forbidden_char (*text, FOLDER_NAME_FORBIDDEN_CHARS)) {
254 tmp = g_strndup (folder_name_forbidden_chars,
255 FOLDER_NAME_FORBIDDEN_CHARS_LENGTH);
256 msg = g_strdup_printf (_CS("ckdg_ib_illegal_characters_entered"), tmp);
257 modest_platform_information_banner (gtk_widget_get_parent (GTK_WIDGET (data)),
263 modest_platform_information_banner (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
264 _CS("ckdg_ib_maximum_characters_reached"));
266 /* Write the text in the entry if it's valid */
267 g_signal_handlers_block_by_func (editable,
268 (gpointer) entry_insert_text, data);
269 gtk_editable_insert_text (editable, text, length, position);
270 g_signal_handlers_unblock_by_func (editable,
271 (gpointer) entry_insert_text, data);
274 /* Do not allow further processing */
275 g_signal_stop_emission_by_name (editable, "insert_text");
279 entry_changed (GtkEditable *editable,
283 GtkWidget *ok_button;
286 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
287 ok_button = GTK_WIDGET (buttons->data);
289 chars = gtk_editable_get_chars (editable, 0, -1);
290 g_return_if_fail (chars != NULL);
293 if (g_utf8_strlen (chars,-1) >= 20) {
294 modest_platform_information_banner (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
295 _CS("ckdg_ib_maximum_characters_reached"));
297 gtk_widget_set_sensitive (ok_button, modest_text_utils_validate_folder_name(chars));
300 g_list_free (buttons);
307 on_response (GtkDialog *dialog,
311 GtkWidget *entry, *picker;
312 TnyFolderStore *parent;
313 const gchar *new_name;
316 if (response != GTK_RESPONSE_ACCEPT)
320 entry = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY);
321 picker = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER);
323 parent = TNY_FOLDER_STORE (user_data);
324 new_name = gtk_entry_get_text (GTK_ENTRY (entry));
328 parent = g_object_get_data (G_OBJECT (picker), FOLDER_PICKER_CURRENT_FOLDER);
330 /* Look for another folder with the same name */
331 if (!TNY_IS_MERGE_FOLDER (parent) &&
332 modest_tny_folder_has_subfolder_with_name (parent, new_name, TRUE))
336 if (TNY_IS_ACCOUNT (parent) &&
337 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (parent)) &&
338 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (parent),
346 modest_platform_information_banner (gtk_widget_get_parent (GTK_WIDGET (dialog)),
347 NULL, _CS("ckdg_ib_folder_already_exists"));
348 /* Select the text */
349 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
350 gtk_widget_grab_focus (entry);
351 /* Do not close the dialog */
352 g_signal_stop_emission_by_name (dialog, "response");
356 typedef struct _FolderChooserData {
357 TnyFolderStore *store;
362 folder_chooser_activated (ModestFolderView *folder_view,
363 TnyFolderStore *folder,
364 FolderChooserData *userdata)
366 userdata->store = folder;
367 gtk_dialog_response (GTK_DIALOG (userdata->dialog), GTK_RESPONSE_OK);
370 static TnyFolderStore *
371 folder_chooser_dialog_run (ModestFolderView *original,
372 TnyFolderStore *current,
375 GtkWidget *folder_view;
376 FolderChooserData userdata = {NULL, NULL};
377 GtkWidget *scrollable;
378 const gchar *visible_id = NULL;
380 userdata.dialog = gtk_dialog_new ();
381 scrollable = modest_toolkit_factory_create_scrollable (modest_runtime_get_toolkit_factory ());
382 folder_view = modest_platform_create_folder_view (NULL);
384 gtk_window_set_title (GTK_WINDOW (userdata.dialog), _FM("ckdg_ti_change_folder"));
386 modest_folder_view_copy_model (MODEST_FOLDER_VIEW (original),
387 MODEST_FOLDER_VIEW (folder_view));
389 if (TNY_IS_ACCOUNT (current)) {
390 /* Local folders and MMC account are always shown
391 along with the currently visible server account */
392 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (current)) ||
393 modest_tny_account_is_memory_card_account (TNY_ACCOUNT (current)))
394 visible_id = g_object_get_data ((GObject *) picker, FOLDER_PICKER_ORIGINAL_ACCOUNT);
396 visible_id = tny_account_get_id (TNY_ACCOUNT (current));
397 } else if (TNY_IS_FOLDER (current)) {
399 account = modest_tny_folder_get_account ((TnyFolder *) current);
401 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (account)) ||
402 modest_tny_account_is_memory_card_account (TNY_ACCOUNT (account))) {
403 visible_id = g_object_get_data ((GObject *) picker, FOLDER_PICKER_ORIGINAL_ACCOUNT);
405 visible_id = tny_account_get_id (account);
407 g_object_unref (account);
411 modest_folder_view_get_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(original));
414 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(folder_view),
417 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (userdata.dialog)->vbox), scrollable);
418 gtk_container_add (GTK_CONTAINER (scrollable), folder_view);
419 gtk_widget_set_size_request (scrollable, -1, 320);
421 gtk_widget_show (folder_view);
422 gtk_widget_show (scrollable);
423 gtk_widget_show (userdata.dialog);
424 g_signal_connect (G_OBJECT (folder_view), "folder-activated",
425 G_CALLBACK (folder_chooser_activated),
426 (gpointer) &userdata);
428 gtk_dialog_run (GTK_DIALOG (userdata.dialog));
429 gtk_widget_destroy (userdata.dialog);
431 return userdata.store;
435 folder_store_get_display_name (TnyFolderStore *store)
437 if (TNY_IS_ACCOUNT (store)) {
438 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
439 return modest_conf_get_string (modest_runtime_get_conf(),
440 MODEST_CONF_DEVICE_NAME, NULL);
442 return g_strdup (tny_account_get_name (TNY_ACCOUNT (store)));
445 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
447 fname = g_strdup (tny_folder_get_name (TNY_FOLDER (store)));
448 type = tny_folder_get_folder_type (TNY_FOLDER (store));
449 if (modest_tny_folder_is_local_folder (TNY_FOLDER (store)) ||
450 modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
451 type = modest_tny_folder_get_local_or_mmc_folder_type (TNY_FOLDER (store));
452 if (type != TNY_FOLDER_TYPE_UNKNOWN) {
454 fname = g_strdup (modest_local_folder_info_get_type_display_name (type));
457 /* Sometimes an special folder is reported by the server as
458 NORMAL, like some versions of Dovecot */
459 if (type == TNY_FOLDER_TYPE_NORMAL ||
460 type == TNY_FOLDER_TYPE_UNKNOWN) {
461 type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
465 if (type == TNY_FOLDER_TYPE_INBOX) {
467 fname = g_strdup (_("mcen_me_folder_inbox"));
474 get_image_for_folder_store (TnyFolderStore *store,
478 const gchar *icon_name = NULL;
479 GtkWidget *image = NULL;
481 if (TNY_IS_ACCOUNT (store)) {
482 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
483 icon_name = MODEST_FOLDER_ICON_LOCAL_FOLDERS;
484 else if (modest_tny_account_is_memory_card_account (TNY_ACCOUNT (store)))
485 icon_name = MODEST_FOLDER_ICON_MMC;
487 icon_name = MODEST_FOLDER_ICON_ACCOUNT;
489 TnyFolderType type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
490 if (modest_tny_folder_is_remote_folder (TNY_FOLDER (store))) {
492 case TNY_FOLDER_TYPE_INBOX:
493 icon_name = MODEST_FOLDER_ICON_INBOX;
496 icon_name = MODEST_FOLDER_ICON_REMOTE_FOLDER;
498 } else if (modest_tny_folder_is_local_folder (TNY_FOLDER (store))) {
500 case TNY_FOLDER_TYPE_OUTBOX:
501 icon_name = MODEST_FOLDER_ICON_OUTBOX;
503 case TNY_FOLDER_TYPE_DRAFTS:
504 icon_name = MODEST_FOLDER_ICON_DRAFTS;
506 case TNY_FOLDER_TYPE_SENT:
507 icon_name = MODEST_FOLDER_ICON_SENT;
510 icon_name = MODEST_FOLDER_ICON_NORMAL;
512 } else if (modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
513 icon_name = MODEST_FOLDER_ICON_MMC_FOLDER;
518 pixbuf = modest_platform_get_icon (icon_name, size);
521 image = gtk_image_new_from_pixbuf (pixbuf);
522 g_object_unref (pixbuf);
529 folder_picker_set_store (GtkButton *button, TnyFolderStore *store)
534 g_object_set_data (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER, NULL);
538 g_object_set_data_full (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER,
539 g_object_ref (store),
540 (GDestroyNotify) g_object_unref);
541 name = folder_store_get_display_name (store);
542 gtk_button_set_label (GTK_BUTTON (button), name);
546 image = get_image_for_folder_store (store, MODEST_ICON_SIZE_SMALL);
548 gtk_button_set_image (GTK_BUTTON (button), image);
552 /* Always returns DUPs so you must free the returned value */
554 get_next_folder_name (const gchar *suggested_name,
555 TnyFolderStore *suggested_folder)
557 const gchar *default_name = _FM("ckdg_va_new_folder_name_stub");
559 gchar *real_suggested_name;
561 if (suggested_name !=NULL) {
562 return g_strdup (suggested_name);
565 for(i = 0; i < 100; ++ i) {
566 gboolean exists = FALSE;
569 real_suggested_name = g_strdup (default_name);
571 real_suggested_name = g_strdup_printf ("%s(%d)",
572 _FM("ckdg_va_new_folder_name_stub"),
574 exists = modest_tny_folder_has_subfolder_with_name (suggested_folder,
581 g_free (real_suggested_name);
584 /* Didn't find a free number */
586 real_suggested_name = g_strdup (default_name);
588 return real_suggested_name;
592 ModestFolderView *folder_view;
594 } FolderPickerHelper;
597 folder_picker_clicked (GtkButton *button,
598 FolderPickerHelper *helper)
600 TnyFolderStore *store, *current;
602 current = g_object_get_data (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER);
604 store = folder_chooser_dialog_run (helper->folder_view, current, button);
606 const gchar *current_name;
607 gboolean exists = FALSE;
609 folder_picker_set_store (GTK_BUTTON (button), store);
611 /* Update the name of the folder */
612 current_name = gtk_entry_get_text (helper->entry);
614 if (TNY_IS_FOLDER_STORE (store))
615 exists = modest_tny_folder_has_subfolder_with_name (store,
619 gchar *new_name = get_next_folder_name (NULL, store);
620 gtk_entry_set_text (helper->entry, new_name);
627 folder_picker_new (TnyFolderStore *suggested, FolderPickerHelper *helper)
630 const gchar *acc_id = NULL;
632 button = gtk_button_new ();
634 gtk_misc_set_alignment (GTK_MISC (button), 0.0, 0.5);
638 folder_picker_set_store (GTK_BUTTON (button), suggested);
640 if (TNY_IS_ACCOUNT (suggested)) {
641 if (!modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (suggested)) &&
642 !modest_tny_account_is_memory_card_account (TNY_ACCOUNT (suggested)))
643 acc_id = tny_account_get_id ((TnyAccount *) suggested);
645 TnyAccount *account = modest_tny_folder_get_account ((TnyFolder *) suggested);
647 acc_id = tny_account_get_id ((TnyAccount *) account);
648 g_object_unref (account);
654 acc_id = modest_folder_view_get_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(helper->folder_view));
656 g_object_set_data_full (G_OBJECT (button), FOLDER_PICKER_ORIGINAL_ACCOUNT,
657 g_strdup (acc_id), (GDestroyNotify) g_free);
660 g_signal_connect (G_OBJECT (button), "clicked",
661 G_CALLBACK (folder_picker_clicked),
669 modest_platform_run_folder_common_dialog (GtkWindow *parent_window,
670 TnyFolderStore *suggested_parent,
671 const gchar *dialog_title,
672 const gchar *label_text,
673 const gchar *suggested_name,
675 gboolean show_parent,
677 TnyFolderStore **parent)
679 GtkWidget *accept_btn = NULL;
680 GtkWidget *dialog, *entry = NULL, *label_entry = NULL, *label_location = NULL, *hbox;
681 GtkWidget *account_picker = NULL;
682 GList *buttons = NULL;
684 GtkSizeGroup *sizegroup;
685 ModestFolderView *folder_view;
686 ModestWindow *folder_window;
687 ModestWindowMgr *window_mgr;
688 FolderPickerHelper *helper = NULL;
689 GtkWidget *top_vbox, *top_align;
691 window_mgr = modest_runtime_get_window_mgr ();
692 folder_window = modest_window_mgr_get_folder_window (window_mgr);
693 g_return_val_if_fail (MODEST_IS_FOLDER_WINDOW (folder_window), GTK_RESPONSE_NONE);
695 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (folder_window));
697 top_vbox = gtk_vbox_new (FALSE, 0);
698 top_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
699 gtk_alignment_set_padding (GTK_ALIGNMENT (top_align), 0, 0, MODEST_MARGIN_DOUBLE, 0);
701 /* Ask the user for the folder name */
702 dialog = gtk_dialog_new_with_buttons (dialog_title,
704 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
705 _FM("ckdg_bd_new_folder_dialog_ok"),
709 /* Add accept button (with unsensitive handler) */
710 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
711 accept_btn = GTK_WIDGET (buttons->data);
713 sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
716 label_entry = gtk_label_new (label_text);
717 entry = modest_toolkit_factory_create_entry (modest_runtime_get_toolkit_factory ());
718 gtk_entry_set_max_length (GTK_ENTRY (entry), 20);
720 gtk_misc_set_alignment (GTK_MISC (label_entry), 0.0, 0.5);
721 gtk_size_group_add_widget (sizegroup, label_entry);
724 gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
726 gtk_entry_set_text (GTK_ENTRY (entry), _FM("ckdg_va_new_folder_name_stub"));
727 gtk_entry_set_width_chars (GTK_ENTRY (entry),
728 MAX (g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (entry)), -1),
729 g_utf8_strlen (_FM("ckdg_va_new_folder_name_stub"), -1)));
730 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
735 label_location = gtk_label_new (_FM("ckdg_fi_new_folder_location"));
737 gtk_misc_set_alignment (GTK_MISC (label_location), 0.0, 0.5);
738 gtk_size_group_add_widget (sizegroup, label_location);
740 helper = g_slice_new0 (FolderPickerHelper);
741 helper->folder_view = folder_view;
742 helper->entry = (GtkEntry *) entry;
744 account_picker = folder_picker_new (suggested_parent, helper);
747 g_object_unref (sizegroup);
749 /* Connect to the response method to avoid closing the dialog
750 when an invalid name is selected*/
751 g_signal_connect (dialog,
753 G_CALLBACK (on_response),
757 /* Track entry changes */
758 g_signal_connect (entry,
760 G_CALLBACK (entry_insert_text),
762 g_signal_connect (entry,
764 G_CALLBACK (entry_changed),
769 /* Some locales like pt_BR need this to get the full window
771 gtk_widget_set_size_request (GTK_WIDGET (dialog), 300, -1);
773 /* Create the hbox */
775 hbox = gtk_hbox_new (FALSE, 12);
776 gtk_box_pack_start (GTK_BOX (hbox), label_entry, FALSE, FALSE, 0);
777 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
779 /* Add hbox to dialog */
780 gtk_box_pack_start (GTK_BOX (top_vbox),
781 hbox, FALSE, FALSE, 0);
782 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY, entry);
786 hbox = gtk_hbox_new (FALSE, 12);
787 gtk_box_pack_start (GTK_BOX (hbox), label_location, FALSE, FALSE, 0);
788 gtk_box_pack_start (GTK_BOX (hbox), account_picker, TRUE, TRUE, 0);
790 /* Add hbox to dialog */
791 gtk_box_pack_start (GTK_BOX (top_vbox),
792 hbox, FALSE, FALSE, 0);
793 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER, account_picker);
795 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
796 GTK_WINDOW (dialog), parent_window);
798 gtk_container_add (GTK_CONTAINER (top_align), top_vbox);
799 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), top_align, TRUE, TRUE, 0);
801 gtk_widget_show_all (GTK_WIDGET(dialog));
803 result = gtk_dialog_run (GTK_DIALOG(dialog));
804 if (result == GTK_RESPONSE_ACCEPT) {
806 *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
808 *parent = g_object_get_data (G_OBJECT (account_picker), FOLDER_PICKER_CURRENT_FOLDER);
810 g_object_ref (*parent);
814 gtk_widget_destroy (dialog);
817 g_slice_free (FolderPickerHelper, helper);
819 while (gtk_events_pending ())
820 gtk_main_iteration ();
826 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
827 TnyFolderStore *suggested_folder,
828 gchar *suggested_name,
830 TnyFolderStore **parent_folder)
832 gchar *real_suggested_name = NULL;
834 ModestTnyAccountStore *acc_store;
836 gboolean do_free = FALSE;
838 real_suggested_name = get_next_folder_name ((const gchar *) suggested_name,
841 /* In hildon 2.2 we always suggest the archive folder as parent */
842 if (!suggested_folder) {
843 acc_store = modest_runtime_get_account_store ();
844 account = modest_tny_account_store_get_mmc_folders_account (acc_store);
846 suggested_folder = (TnyFolderStore *)
847 modest_tny_account_get_special_folder (account,
848 TNY_FOLDER_TYPE_ARCHIVE);
849 g_object_unref (account);
854 /* If there is not archive folder then fallback to local folders account */
855 if (!suggested_folder) {
857 suggested_folder = (TnyFolderStore *)
858 modest_tny_account_store_get_local_folders_account (acc_store);
861 result = modest_platform_run_folder_common_dialog (parent_window,
863 _HL("ckdg_ti_new_folder"),
864 _FM("ckdg_fi_new_folder_name"),
872 g_object_unref (suggested_folder);
874 g_free(real_suggested_name);
880 modest_platform_run_rename_folder_dialog (GtkWindow *parent_window,
881 TnyFolderStore *parent_folder,
882 const gchar *suggested_name,
885 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
887 return modest_platform_run_folder_common_dialog (parent_window,
889 _HL("ckdg_ti_rename_folder"),
890 _HL("ckdg_fi_rename_name"),
901 on_destroy_dialog (GtkWidget *dialog)
903 /* This could happen when the dialogs get programatically
904 hidden or destroyed (for example when closing the
905 application while a dialog is being shown) */
906 if (!GTK_IS_WIDGET (dialog))
909 gtk_widget_destroy (dialog);
911 if (gtk_events_pending ())
912 gtk_main_iteration ();
916 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
917 const gchar *message)
922 dialog = gtk_message_dialog_new (parent_window, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
923 GTK_MESSAGE_QUESTION,
924 GTK_BUTTONS_OK_CANCEL,
926 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
927 GTK_WINDOW (dialog), parent_window);
929 response = gtk_dialog_run (GTK_DIALOG (dialog));
931 on_destroy_dialog (dialog);
937 modest_platform_run_confirmation_dialog_with_buttons (GtkWindow *parent_window,
938 const gchar *message,
939 const gchar *button_accept,
940 const gchar *button_cancel)
945 dialog = gtk_message_dialog_new (parent_window, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
946 GTK_MESSAGE_QUESTION,
949 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
950 button_accept, GTK_RESPONSE_ACCEPT,
951 button_cancel, GTK_RESPONSE_CANCEL,
954 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
955 GTK_WINDOW (dialog), parent_window);
957 response = gtk_dialog_run (GTK_DIALOG (dialog));
959 on_destroy_dialog (dialog);
965 modest_platform_run_information_dialog (GtkWindow *parent_window,
966 const gchar *message,
971 note = gtk_message_dialog_new (parent_window, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
976 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
977 GTK_WINDOW (note), parent_window);
980 gtk_dialog_run (GTK_DIALOG (note));
982 on_destroy_dialog (note);
984 g_signal_connect_swapped (note,
986 G_CALLBACK (on_destroy_dialog),
989 gtk_widget_show_all (note);
993 typedef struct _ConnectAndWaitData {
995 GMainLoop *wait_loop;
996 gboolean has_callback;
998 } ConnectAndWaitData;
1002 quit_wait_loop (TnyAccount *account,
1003 ConnectAndWaitData *data)
1005 /* Set the has_callback to TRUE (means that the callback was
1006 executed and wake up every code waiting for cond to be
1008 g_mutex_lock (data->mutex);
1009 data->has_callback = TRUE;
1010 if (data->wait_loop)
1011 g_main_loop_quit (data->wait_loop);
1012 g_mutex_unlock (data->mutex);
1016 on_connection_status_changed (TnyAccount *account,
1017 TnyConnectionStatus status,
1020 TnyConnectionStatus conn_status;
1021 ConnectAndWaitData *data;
1023 /* Ignore if reconnecting or disconnected */
1024 conn_status = tny_account_get_connection_status (account);
1025 if (conn_status == TNY_CONNECTION_STATUS_RECONNECTING ||
1026 conn_status == TNY_CONNECTION_STATUS_DISCONNECTED)
1029 /* Remove the handler */
1030 data = (ConnectAndWaitData *) user_data;
1031 g_signal_handler_disconnect (account, data->handler);
1033 /* Quit from wait loop */
1034 quit_wait_loop (account, (ConnectAndWaitData *) user_data);
1038 on_tny_camel_account_set_online_cb (TnyCamelAccount *account,
1043 /* Quit from wait loop */
1044 quit_wait_loop (TNY_ACCOUNT (account), (ConnectAndWaitData *) user_data);
1048 modest_platform_connect_and_wait (GtkWindow *parent_window,
1049 TnyAccount *account)
1051 gboolean device_online;
1053 TnyConnectionStatus conn_status;
1054 gboolean user_requested;
1056 device = modest_runtime_get_device();
1057 device_online = tny_device_is_online (device);
1059 /* Whether the connection is user requested or automatically
1060 requested, for example via D-Bus */
1061 user_requested = (parent_window) ? TRUE : FALSE;
1063 /* If there is no account check only the device status */
1068 /* TODO: should show connection dialog through gnome device */
1072 /* Return if the account is already connected */
1073 conn_status = tny_account_get_connection_status (account);
1074 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
1081 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1083 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1084 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1085 /* This must be a maildir account, which does not require a connection: */
1090 return modest_platform_connect_and_wait (parent_window, account);
1094 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1097 return TRUE; /* Maybe it is something local. */
1099 gboolean result = TRUE;
1100 if (TNY_IS_FOLDER (folder_store)) {
1101 /* Get the folder's parent account: */
1102 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1103 if (account != NULL) {
1104 result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1105 g_object_unref (account);
1107 } else if (TNY_IS_ACCOUNT (folder_store)) {
1108 /* Use the folder store as an account: */
1109 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1116 modest_platform_create_sort_dialog (GtkWindow *parent_window)
1124 modest_platform_set_update_interval (guint minutes)
1130 modest_platform_push_email_notification(void)
1136 modest_platform_on_new_headers_received (GList *URI_list,
1137 gboolean show_visual)
1143 modest_platform_remove_new_mail_notifications (gboolean only_visuals)
1151 modest_platform_get_global_settings_dialog ()
1157 modest_platform_show_help (GtkWindow *parent_window,
1158 const gchar *help_id)
1164 modest_platform_show_search_messages (GtkWindow *parent_window)
1170 modest_platform_show_addressbook (GtkWindow *parent_window)
1176 modest_platform_create_folder_view_full (TnyFolderStoreQuery *query, gboolean do_refresh)
1178 GtkWidget *widget = modest_folder_view_new_full (query, do_refresh);
1180 /* Show one account by default */
1181 modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1182 MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1188 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1190 return modest_platform_create_folder_view_full (query, TRUE);
1194 banner_finish (gpointer data, GObject *object)
1196 ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1197 modest_window_mgr_unregister_banner (mgr);
1198 g_object_unref (mgr);
1202 modest_platform_information_banner (GtkWidget *parent,
1203 const gchar *icon_name,
1210 modest_platform_system_banner (GtkWidget *parent,
1211 const gchar *icon_name,
1218 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1219 const gchar *icon_name,
1227 modest_platform_animation_banner (GtkWidget *parent,
1228 const gchar *animation_name,
1237 TnyAccount *account;
1240 } CheckAccountIdleData;
1242 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1245 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1247 gboolean stop_trying = FALSE;
1248 g_return_val_if_fail (data && data->account, FALSE);
1250 if (data && data->account &&
1251 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1252 * after which the account is likely to be usable, or never likely to be usable soon: */
1253 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1255 data->is_online = TRUE;
1259 /* Give up if we have tried too many times: */
1260 if (data->count_tries >= NUMBER_OF_TRIES) {
1263 /* Wait for another timeout: */
1264 ++(data->count_tries);
1269 /* Allow the function that requested this idle callback to continue: */
1271 g_main_loop_quit (data->loop);
1274 g_object_unref (data->account);
1276 return FALSE; /* Don't call this again. */
1278 return TRUE; /* Call this timeout callback again. */
1282 /* Return TRUE immediately if the account is already online,
1283 * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as
1284 * soon as the account is online, or FALSE if the account does
1285 * not become online in the NUMBER_OF_TRIES seconds.
1286 * This is useful when the D-Bus method was run immediately after
1287 * the application was started (when using D-Bus activation),
1288 * because the account usually takes a short time to go online.
1289 * The return value is maybe not very useful.
1292 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1296 g_return_val_if_fail (account, FALSE);
1298 if (!tny_device_is_online (modest_runtime_get_device())) {
1299 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1303 /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1304 * so we avoid wait unnecessarily: */
1305 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1308 /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED,
1309 * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that
1310 * we want to avoid. */
1311 if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1314 /* This blocks on the result: */
1315 CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1316 data->is_online = FALSE;
1317 data->account = account;
1318 g_object_ref (data->account);
1319 data->count_tries = 0;
1321 GMainContext *context = NULL; /* g_main_context_new (); */
1322 data->loop = g_main_loop_new (context, FALSE /* not running */);
1324 g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1326 /* This main loop will run until the idle handler has stopped it: */
1327 g_main_loop_run (data->loop);
1329 g_main_loop_unref (data->loop);
1330 /* g_main_context_unref (context); */
1332 is_online = data->is_online;
1333 g_slice_free (CheckAccountIdleData, data);
1341 on_cert_dialog_response (GtkDialog *dialog, gint response_id, const gchar* cert)
1343 /* GTK_RESPONSE_HELP means we need to show the certificate */
1344 if (response_id == GTK_RESPONSE_APPLY) {
1347 /* Do not close the dialog */
1348 g_signal_stop_emission_by_name (dialog, "response");
1350 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);
1351 modest_platform_run_information_dialog (NULL, msg, TRUE);
1357 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1358 const gchar *certificate)
1364 gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1367 /* We use GTK_RESPONSE_APPLY because we want the button in the
1368 middle of OK and CANCEL the same as the browser does for
1369 example. With GTK_RESPONSE_HELP the view button is aligned
1370 to the left while the other two to the right */
1371 note = gtk_message_dialog_new (
1373 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1374 GTK_MESSAGE_QUESTION,
1377 gtk_dialog_add_buttons (GTK_DIALOG (note),
1378 _HL("wdgt_bd_yes"), GTK_RESPONSE_OK,
1379 _HL("wdgt_bd_view"), GTK_RESPONSE_APPLY, /* abusing this... */
1380 _HL("wdgt_bd_no"), GTK_RESPONSE_CANCEL,
1383 g_signal_connect (G_OBJECT(note), "response",
1384 G_CALLBACK(on_cert_dialog_response),
1385 (gpointer) certificate);
1387 response = gtk_dialog_run(GTK_DIALOG(note));
1389 on_destroy_dialog (note);
1392 return response == GTK_RESPONSE_OK;
1396 modest_platform_run_alert_dialog (const gchar* prompt,
1397 gboolean is_question)
1400 gboolean retval = TRUE;
1403 /* The Tinymail documentation says that we should show Yes and No buttons,
1404 * when it is a question.
1405 * Obviously, we need tinymail to use more specific error codes instead,
1406 * so we know what buttons to show. */
1407 dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1408 GTK_MESSAGE_QUESTION,
1412 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
1413 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
1415 on_destroy_dialog (dialog);
1417 /* Just show the error text and use the default response: */
1418 modest_platform_run_information_dialog (GTK_WINDOW (top_win),
1426 GtkWindow *parent_window;
1427 ModestConnectedPerformer callback;
1428 TnyAccount *account;
1435 on_went_online_info_free (OnWentOnlineInfo *info)
1437 /* And if we cleanup, we DO cleanup :-) */
1440 g_object_unref (info->device);
1443 if (info->parent_window)
1444 g_object_unref (info->parent_window);
1446 g_object_unref (info->account);
1448 g_slice_free (OnWentOnlineInfo, info);
1450 /* We're done ... */
1456 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
1458 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1460 /* Now it's really time to callback to the caller. If going online didn't succeed,
1461 * err will be set. We don't free it, Tinymail does that! If a cancel happened,
1462 * canceled will be set. Etcetera etcetera. */
1464 if (info->callback) {
1465 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1468 /* This is our last call, we must cleanup here if we didn't yet do that */
1469 on_went_online_info_free (info);
1475 modest_platform_connect_and_perform (GtkWindow *parent_window,
1477 TnyAccount *account,
1478 ModestConnectedPerformer callback,
1481 gboolean device_online;
1483 TnyConnectionStatus conn_status;
1484 OnWentOnlineInfo *info;
1486 device = modest_runtime_get_device();
1487 device_online = tny_device_is_online (device);
1489 /* If there is no account check only the device status */
1492 if (device_online) {
1494 /* We promise to instantly perform the callback, so ... */
1496 callback (FALSE, NULL, parent_window, account, user_data);
1503 /* The other code has no more reason to run. This is all that we can do for the
1504 * caller (he should have given us a nice and clean account instance!). We
1505 * can't do magic, we don't know what account he intends to bring online. So
1506 * we'll just bring the device online (and await his false bug report). */
1512 /* Return if the account is already connected */
1514 conn_status = tny_account_get_connection_status (account);
1515 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
1517 /* We promise to instantly perform the callback, so ... */
1519 callback (FALSE, NULL, parent_window, account, user_data);
1525 if (device_online) {
1528 /* If the device is online, we'll just connect the account */
1530 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1531 on_account_went_online, info);
1534 /* The info gets freed by on_account_went_online or on_conic_device_went_online
1535 * in both situations, go look if you don't believe me! */
1541 modest_platform_connect_if_remote_and_perform (GtkWindow *parent_window,
1543 TnyFolderStore *folder_store,
1544 ModestConnectedPerformer callback,
1547 TnyAccount *account = NULL;
1549 if (!folder_store ||
1550 (TNY_IS_MERGE_FOLDER (folder_store) &&
1551 (tny_folder_get_folder_type (TNY_FOLDER(folder_store)) == TNY_FOLDER_TYPE_OUTBOX))) {
1553 /* We promise to instantly perform the callback, so ... */
1555 GError *error = NULL;
1556 g_set_error (&error, TNY_ERROR_DOMAIN, TNY_SERVICE_ERROR_UNKNOWN,
1557 "Unable to move or not found folder");
1558 callback (FALSE, error, parent_window, NULL, user_data);
1559 g_error_free (error);
1563 } else if (TNY_IS_FOLDER (folder_store)) {
1564 /* Get the folder's parent account: */
1565 account = tny_folder_get_account (TNY_FOLDER (folder_store));
1566 } else if (TNY_IS_ACCOUNT (folder_store)) {
1567 /* Use the folder store as an account: */
1568 account = TNY_ACCOUNT (g_object_ref (folder_store));
1571 if (account && (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE)) {
1572 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1573 /* No need to connect a local account */
1575 callback (FALSE, NULL, parent_window, account, user_data);
1580 modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
1584 g_object_unref (account);
1588 src_account_connect_performer (gboolean canceled,
1590 GtkWindow *parent_window,
1591 TnyAccount *src_account,
1594 DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
1596 if (canceled || err) {
1597 /* If there was any error call the user callback */
1598 info->callback (canceled, err, parent_window, src_account, info->data);
1600 /* Connect the destination account */
1601 modest_platform_connect_if_remote_and_perform (parent_window, TRUE,
1602 TNY_FOLDER_STORE (info->dst_account),
1603 info->callback, info->data);
1606 /* Free the info object */
1607 g_object_unref (info->dst_account);
1608 g_slice_free (DoubleConnectionInfo, info);
1613 modest_platform_double_connect_and_perform (GtkWindow *parent_window,
1615 TnyFolderStore *folder_store,
1616 DoubleConnectionInfo *connect_info)
1618 modest_platform_connect_if_remote_and_perform(parent_window,
1621 src_account_connect_performer,
1626 modest_platform_get_account_settings_wizard (void)
1628 ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
1630 return GTK_WIDGET (dialog);
1634 modest_platform_get_current_connection (void)
1636 TnyDevice *device = NULL;
1637 ModestConnectedVia retval = MODEST_CONNECTED_VIA_ANY;
1639 device = modest_runtime_get_device ();
1641 if (!tny_device_is_online (device))
1642 return MODEST_CONNECTED_VIA_ANY;
1644 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX; /* assume WLAN (fast) internet */
1651 modest_platform_check_memory_low (ModestWindow *win,
1659 modest_platform_run_folder_details_dialog (GtkWindow *parent_window,
1665 dialog = modest_toolkit_factory_create_details_dialog_with_folder (modest_runtime_get_toolkit_factory (),
1666 parent_window, folder);
1669 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1670 GTK_WINDOW (dialog),
1672 gtk_widget_show_all (dialog);
1674 g_signal_connect_swapped (dialog, "response",
1675 G_CALLBACK (gtk_widget_destroy),
1679 typedef struct _HeaderDetailsGetSizeInfo {
1683 } HeaderDetailsGetSizeInfo;
1686 header_details_dialog_destroy (gpointer userdata,
1689 HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) userdata;
1691 info->dialog = NULL;
1695 idle_get_mime_part_size_cb (gpointer userdata)
1697 HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) userdata;
1698 gdk_threads_enter ();
1700 if (info->dialog && GTK_WIDGET_VISIBLE (info->dialog)) {
1701 modest_details_dialog_set_message_size (MODEST_DETAILS_DIALOG (info->dialog),
1706 g_object_weak_unref (G_OBJECT (info->dialog), header_details_dialog_destroy, info);
1707 info->dialog = NULL;
1709 g_object_unref (info->part);
1710 g_slice_free (HeaderDetailsGetSizeInfo, info);
1712 gdk_threads_leave ();
1718 get_mime_part_size_thread (gpointer thr_user_data)
1720 HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) thr_user_data;
1722 TnyStream *count_stream;
1724 count_stream = modest_count_stream_new ();
1725 result = tny_mime_part_decode_to_stream (info->part, count_stream, NULL);
1726 info->total = modest_count_stream_get_count(MODEST_COUNT_STREAM (count_stream));
1727 if (info->total == 0) {
1728 modest_count_stream_reset_count(MODEST_COUNT_STREAM (count_stream));
1729 result = tny_mime_part_write_to_stream (info->part, count_stream, NULL);
1730 info->total = modest_count_stream_get_count(MODEST_COUNT_STREAM (count_stream));
1733 /* if there was an error, don't set the size (this is pretty uncommon) */
1735 g_warning ("%s: error while writing mime part to stream\n", __FUNCTION__);
1737 g_idle_add (idle_get_mime_part_size_cb, info);
1743 modest_platform_run_header_details_dialog (GtkWindow *parent_window,
1745 gboolean async_get_size,
1751 dialog = modest_toolkit_factory_create_details_dialog_with_header (modest_runtime_get_toolkit_factory (),
1752 parent_window, header, !async_get_size);
1754 if (async_get_size && msg && TNY_IS_MSG (msg)) {
1755 HeaderDetailsGetSizeInfo *info;
1756 info = g_slice_new (HeaderDetailsGetSizeInfo);
1757 info->dialog = dialog;
1759 info->part = TNY_MIME_PART (g_object_ref (msg));
1761 g_object_weak_ref (G_OBJECT (dialog), header_details_dialog_destroy, info);
1762 g_thread_create (get_mime_part_size_thread, info, FALSE, NULL);
1766 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1767 GTK_WINDOW (dialog),
1769 gtk_widget_show_all (dialog);
1771 g_signal_connect_swapped (dialog, "response",
1772 G_CALLBACK (gtk_widget_destroy),
1777 modest_platform_play_email_tone (void)
1782 #define MOVE_TO_DIALOG_FOLDER_VIEW "folder-view"
1783 #define MOVE_TO_DIALOG_BACK_BUTTON "back-button"
1784 #define MOVE_TO_DIALOG_ACTION_BUTTON "action-button"
1785 #define MOVE_TO_DIALOG_SHOWING_FOLDERS "showing-folders"
1786 #define MOVE_TO_DIALOG_SCROLLABLE "scrollable"
1787 #define MOVE_TO_FOLDER_SEPARATOR "/"
1790 translate_path (gchar **path)
1795 gboolean add_separator;
1797 parts = g_strsplit (*path, MOVE_TO_FOLDER_SEPARATOR, 0);
1801 output = g_string_new ("");
1802 add_separator = FALSE;
1804 while (*current != NULL) {
1805 TnyFolderType folder_type;
1808 if (add_separator) {
1809 output = g_string_append (output, MOVE_TO_FOLDER_SEPARATOR);
1811 add_separator = TRUE;
1814 downcase = g_ascii_strdown (*current, -1);
1815 folder_type = modest_local_folder_info_get_type (downcase);
1816 if (strcmp (downcase, "inbox") == 0) {
1817 output = g_string_append (output, _("mcen_me_folder_inbox"));
1818 } else if (folder_type == TNY_FOLDER_TYPE_ARCHIVE ||
1819 folder_type == TNY_FOLDER_TYPE_DRAFTS ||
1820 folder_type == TNY_FOLDER_TYPE_SENT ||
1821 folder_type == TNY_FOLDER_TYPE_OUTBOX) {
1822 output = g_string_append (output, modest_local_folder_info_get_type_display_name (folder_type));
1824 output = g_string_append (output, *current);
1832 *path = g_string_free (output, FALSE);
1836 move_to_dialog_set_selected_folder_store (GtkWidget *dialog,
1837 TnyFolderStore *folder_store)
1839 GtkWidget *action_button;
1840 GtkWidget *image = NULL;
1841 TnyAccount *account;
1842 gchar *account_name = NULL, *short_name = NULL;
1844 action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
1846 /* Get account name */
1847 if (TNY_IS_FOLDER (folder_store))
1848 account = tny_folder_get_account (TNY_FOLDER (folder_store));
1850 account = g_object_ref (folder_store);
1852 if (modest_tny_account_is_virtual_local_folders (account))
1853 account_name = modest_conf_get_string (modest_runtime_get_conf(),
1854 MODEST_CONF_DEVICE_NAME, NULL);
1857 account_name = g_strdup (tny_account_get_name (account));
1859 g_object_unref (account);
1861 /* Set title of button: account or folder name */
1862 if (TNY_IS_FOLDER (folder_store))
1863 short_name = folder_store_get_display_name (folder_store);
1865 short_name = g_strdup (account_name);
1867 gtk_button_set_label (GTK_BUTTON (action_button), short_name);
1869 /* Set value of button, folder full name */
1870 if (TNY_IS_CAMEL_FOLDER (folder_store)) {
1871 const gchar *camel_full_name;
1872 gchar *last_slash, *full_name;
1874 camel_full_name = tny_camel_folder_get_full_name (TNY_CAMEL_FOLDER (folder_store));
1875 last_slash = g_strrstr (camel_full_name, "/");
1877 gchar *prefix = g_strndup (camel_full_name, last_slash - camel_full_name + 1);
1878 full_name = g_strconcat (account_name, MOVE_TO_FOLDER_SEPARATOR, prefix, short_name, NULL);
1881 full_name = g_strconcat (account_name, MOVE_TO_FOLDER_SEPARATOR,
1885 translate_path (&full_name);
1886 gtk_button_set_label (GTK_BUTTON (action_button), full_name);
1889 g_free (account_name);
1890 g_free (short_name);
1892 /* Set image for the button */
1893 image = get_image_for_folder_store (folder_store, MODEST_ICON_SIZE_BIG);
1895 gtk_button_set_image (GTK_BUTTON (action_button), image);
1899 move_to_dialog_show_accounts (GtkWidget *dialog)
1901 GtkWidget *back_button;
1902 GtkWidget *folder_view;
1903 GtkWidget *scrollable;
1904 GtkWidget *action_button;
1906 back_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
1907 action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
1908 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
1909 scrollable = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SCROLLABLE));
1911 gtk_widget_set_sensitive (back_button, FALSE);
1912 gtk_widget_set_sensitive (action_button, FALSE);
1914 /* Need to set this here, otherwise callbacks called because
1915 of filtering won't perform correctly */
1916 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS, GINT_TO_POINTER (FALSE));
1918 /* Reset action button */
1919 gtk_button_set_label (GTK_BUTTON (action_button), NULL);
1920 gtk_button_set_image (GTK_BUTTON (action_button), NULL);
1922 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view), NULL);
1923 modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), TRUE);
1924 modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ALL);
1925 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
1926 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
1927 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
1928 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
1929 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
1930 MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
1931 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
1932 MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
1933 modest_scrollable_jump_to (MODEST_SCROLLABLE (scrollable), 0, 0);
1937 move_to_dialog_show_folders (GtkWidget *dialog, TnyFolderStore *folder_store)
1939 GtkWidget *back_button;
1940 GtkWidget *folder_view;
1941 TnyAccount *account;
1942 const gchar *account_id;
1943 GtkWidget *scrollable;
1944 GtkWidget *action_button;
1947 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
1949 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
1951 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
1953 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SCROLLABLE));
1955 gtk_widget_set_sensitive (back_button, TRUE);
1956 gtk_widget_set_sensitive (action_button, TRUE);
1958 /* Need to set this here, otherwise callbacks called because
1959 of filtering won't perform correctly */
1960 g_object_set_data (G_OBJECT (dialog),
1961 MOVE_TO_DIALOG_SHOWING_FOLDERS,
1962 GINT_TO_POINTER (TRUE));
1964 account = TNY_ACCOUNT (folder_store);
1965 if (modest_tny_account_is_virtual_local_folders (account)) {
1966 account_id = tny_account_get_id (account);
1967 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
1968 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
1969 } else if (modest_tny_account_is_memory_card_account (account)) {
1970 account_id = tny_account_get_id (account);
1971 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
1972 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
1974 account_id = tny_account_get_id (account);
1975 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
1976 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
1977 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
1978 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
1981 move_to_dialog_set_selected_folder_store (dialog, folder_store);
1982 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view),
1985 modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), FALSE);
1986 modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1987 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
1988 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
1989 modest_scrollable_jump_to (MODEST_SCROLLABLE (scrollable), 0, 0);
1993 on_move_to_dialog_back_clicked (GtkButton *button,
1996 GtkWidget *dialog = (GtkWidget *) userdata;
1998 /* Back to show accounts */
1999 move_to_dialog_show_accounts (dialog);
2003 on_move_to_dialog_row_activated (GtkTreeView *tree_view,
2005 GtkTreeViewColumn *column,
2008 TnyFolderStore *selected = NULL;
2010 GtkWidget *folder_view;
2011 gboolean showing_folders;
2013 dialog = (GtkWidget *) user_data;
2014 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog),
2015 MOVE_TO_DIALOG_SHOWING_FOLDERS));
2017 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog),
2018 MOVE_TO_DIALOG_FOLDER_VIEW));
2020 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2024 if (!showing_folders) {
2025 gboolean valid = TRUE;
2027 if (TNY_IS_ACCOUNT (selected) &&
2028 modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (selected))) {
2029 ModestProtocolType protocol_type;
2031 protocol_type = modest_tny_account_get_protocol_type (TNY_ACCOUNT (selected));
2032 valid = !modest_protocol_registry_protocol_type_has_tag
2033 (modest_runtime_get_protocol_registry (),
2035 MODEST_PROTOCOL_REGISTRY_STORE_FORBID_INCOMING_XFERS);
2038 move_to_dialog_show_folders (dialog, selected);
2040 move_to_dialog_set_selected_folder_store (dialog, selected);
2042 g_object_unref (selected);
2046 on_move_to_dialog_selection_changed (GtkTreeSelection *selection,
2049 gboolean showing_folders;
2052 dialog = (GtkWidget *) user_data;
2053 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2054 if (showing_folders) {
2055 TnyFolderStore *selected;
2056 GtkWidget *folder_view;
2058 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2059 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2062 move_to_dialog_set_selected_folder_store (dialog, selected);
2063 g_object_unref (selected);
2069 on_move_to_dialog_action_clicked (GtkButton *selection,
2073 gboolean showing_folders;
2075 dialog = (GtkWidget *) user_data;
2076 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2077 if (showing_folders) {
2078 TnyFolderStore *selected;
2079 GtkWidget *folder_view;
2081 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2082 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2085 /* It's not possible to select root folders as
2086 targets unless they're the local account or
2087 the memory card account */
2088 if ((TNY_IS_FOLDER (selected) && !TNY_IS_MERGE_FOLDER (selected)) ||
2089 (TNY_IS_ACCOUNT (selected) &&
2090 (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (selected)) ||
2091 modest_tny_account_is_memory_card_account (TNY_ACCOUNT (selected)))))
2092 gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
2093 g_object_unref (selected);
2099 move_to_dialog_activity_changed (ModestFolderView *folder_view, gboolean activity, GtkDialog *dialog)
2104 modest_platform_create_move_to_dialog (GtkWindow *parent_window,
2105 GtkWidget **folder_view)
2107 GtkWidget *dialog, *folder_view_container;
2109 GtkWidget *buttons_hbox;
2110 GtkWidget *back_button;
2111 GdkPixbuf *back_pixbuf;
2112 GtkWidget *top_vbox;
2113 GtkWidget *action_button;
2114 GtkTreeSelection *selection;
2116 /* Create dialog. We cannot use a touch selector because we
2117 need to use here the folder view widget directly */
2118 dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
2119 GTK_WINDOW (parent_window),
2120 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR |
2121 GTK_DIALOG_DESTROY_WITH_PARENT,
2122 _FM ("ckdg_bd_change_folder_new_folder"),
2123 MODEST_GTK_RESPONSE_NEW_FOLDER,
2126 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
2127 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_NONE);
2128 top_vbox = gtk_vbox_new (FALSE, MODEST_MARGIN_HALF);
2130 /* Create folder view */
2131 *folder_view = modest_platform_create_folder_view_full (NULL, FALSE);
2132 g_signal_connect (G_OBJECT (*folder_view), "activity-changed", G_CALLBACK (move_to_dialog_activity_changed),
2135 modest_folder_view_set_cell_style (MODEST_FOLDER_VIEW (*folder_view),
2136 MODEST_FOLDER_VIEW_CELL_STYLE_COMPACT);
2137 modest_folder_view_show_message_count (MODEST_FOLDER_VIEW (*folder_view),
2139 tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (*folder_view),
2140 (TnyAccountStore *) modest_runtime_get_account_store ());
2142 buttons_hbox = gtk_hbox_new (FALSE, MODEST_MARGIN_HALF);
2143 back_button = gtk_button_new ();
2144 back_pixbuf = modest_platform_get_icon (_FM("filemanager_folder_up"), MODEST_ICON_SIZE_BIG);
2146 gtk_button_set_image (GTK_BUTTON (back_button), gtk_image_new_from_pixbuf (back_pixbuf));
2147 g_object_unref (back_pixbuf);
2150 action_button = gtk_button_new ();
2151 gtk_button_set_alignment (GTK_BUTTON (action_button), 0.0, 0.5);
2153 gtk_box_pack_start (GTK_BOX (buttons_hbox), back_button, FALSE, FALSE, 0);
2154 gtk_box_pack_start (GTK_BOX (buttons_hbox), action_button, TRUE, TRUE, 0);
2155 gtk_widget_set_sensitive (GTK_WIDGET (back_button), FALSE);
2156 gtk_widget_set_sensitive (GTK_WIDGET (action_button), FALSE);
2157 gtk_box_pack_start (GTK_BOX (top_vbox), buttons_hbox, FALSE, FALSE, 0);
2159 /* Create scrollable and add it to the dialog */
2160 folder_view_container = modest_toolkit_factory_create_scrollable (modest_runtime_get_toolkit_factory ());
2161 gtk_container_add (GTK_CONTAINER (folder_view_container), *folder_view);
2162 gtk_box_pack_start (GTK_BOX (top_vbox), folder_view_container, TRUE, TRUE, 0);
2164 gtk_container_add (GTK_CONTAINER (align), top_vbox);
2165 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), align, TRUE, TRUE, 0);
2167 gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
2169 gtk_widget_show (GTK_DIALOG (dialog)->vbox);
2170 gtk_widget_show (folder_view_container);
2171 gtk_widget_show (align);
2172 gtk_widget_show (top_vbox);
2173 gtk_widget_show (*folder_view);
2174 gtk_widget_show_all (back_button);
2175 gtk_widget_show (action_button);
2176 gtk_widget_show (buttons_hbox);
2177 gtk_widget_show (dialog);
2179 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW, *folder_view);
2180 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON, back_button);
2181 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON, action_button);
2182 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SCROLLABLE, folder_view_container);
2184 /* Simulate the behaviour of a HildonPickerDialog by emitting
2185 a response when a folder is selected */
2186 g_signal_connect (*folder_view, "row-activated",
2187 G_CALLBACK (on_move_to_dialog_row_activated),
2190 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (*folder_view));
2191 g_signal_connect (selection, "changed",
2192 G_CALLBACK (on_move_to_dialog_selection_changed),
2195 g_signal_connect (action_button, "clicked",
2196 G_CALLBACK (on_move_to_dialog_action_clicked),
2199 g_signal_connect (back_button, "clicked",
2200 G_CALLBACK (on_move_to_dialog_back_clicked),
2203 move_to_dialog_show_accounts (dialog);
2209 modest_platform_get_list_to_move (ModestWindow *window)
2211 TnyList *list = NULL;
2213 if (MODEST_IS_HEADER_WINDOW (window)) {
2214 ModestHeaderView *header_view;
2216 header_view = modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window));
2217 list = modest_header_view_get_selected_headers (header_view);
2218 } else if (MODEST_IS_FOLDER_WINDOW (window)) {
2219 ModestFolderView *folder_view;
2220 TnyFolderStore *selected_folder;
2222 list = TNY_LIST (tny_simple_list_new ());
2223 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window));
2224 selected_folder = modest_folder_view_get_selected (folder_view);
2225 if (selected_folder) {
2226 tny_list_prepend (list, G_OBJECT (selected_folder));
2227 g_object_unref (selected_folder);
2230 } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
2233 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (window));
2235 list = TNY_LIST (tny_simple_list_new ());
2236 tny_list_prepend (list, G_OBJECT (header));
2237 g_object_unref (header);
2240 g_return_val_if_reached (NULL);