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"
80 on_modest_conf_update_interval_changed (ModestConf* self,
82 ModestConfEvent event,
83 ModestConfNotificationId id,
86 g_return_if_fail (key);
88 if (strcmp (key, MODEST_CONF_UPDATE_INTERVAL) == 0) {
89 const guint update_interval_minutes =
90 modest_conf_get_int (self, MODEST_CONF_UPDATE_INTERVAL, NULL);
91 modest_platform_set_update_interval (update_interval_minutes);
98 check_required_files (void)
101 FILE *mcc_file = modest_utils_open_mcc_mapping_file ();
104 g_printerr ("modest: check for mcc file (for LANG) failed\n");
110 if (access(MODEST_PROVIDER_DATA_FILE, R_OK) != 0 &&
111 access(MODEST_FALLBACK_PROVIDER_DATA_FILE, R_OK) != 0) {
112 g_printerr ("modest: cannot find providers data\n");
120 /* the gpointer here is the osso_context. */
122 modest_platform_init (int argc, char *argv[])
126 if (!check_required_files ()) {
127 g_printerr ("modest: missing required files\n");
131 /* Make sure that the update interval is changed whenever its gconf key
133 /* CAUTION: we're not using here the
134 modest_conf_listen_to_namespace because we know that there
135 are other parts of Modest listening for this namespace, so
136 we'll receive the notifications anyway. We basically do not
137 use it because there is no easy way to do the
138 modest_conf_forget_namespace */
139 ModestConf *conf = modest_runtime_get_conf ();
140 g_signal_connect (G_OBJECT(conf),
142 G_CALLBACK (on_modest_conf_update_interval_changed),
145 /* only force the setting of the default interval, if there are actually
147 acc_names = modest_account_mgr_account_names (modest_runtime_get_account_mgr(), TRUE);
149 /* Get the initial update interval from gconf: */
150 on_modest_conf_update_interval_changed(conf, MODEST_CONF_UPDATE_INTERVAL,
151 MODEST_CONF_EVENT_KEY_CHANGED, 0, NULL);
152 modest_account_mgr_free_account_names (acc_names);
159 modest_platform_uninit (void)
168 modest_platform_get_new_device (void)
170 return TNY_DEVICE (tny_gnome_device_new ());
174 modest_platform_get_file_icon_name (const gchar* name, const gchar* mime_type,
175 gchar **effective_mime_type)
178 g_warning ("Not implemented %s", __FUNCTION__);
187 modest_platform_activate_uri (const gchar *uri)
189 g_warning ("Not implemented %s", __FUNCTION__);
196 modest_platform_activate_file (const gchar *path, const gchar *mime_type)
198 g_warning ("Not implemented %s", __FUNCTION__);
204 modest_platform_show_uri_popup (const gchar *uri)
206 g_warning ("Not implemented %s", __FUNCTION__);
213 modest_platform_get_icon (const gchar *name, guint icon_size)
215 return gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
223 modest_platform_get_app_name (void)
225 return _("mcen_ap_name");
229 entry_insert_text (GtkEditable *editable,
238 chars = gtk_editable_get_chars (editable, 0, -1);
239 chars_length = g_utf8_strlen (chars, -1);
242 /* Show WID-INF036 */
243 if (chars_length >= 20) {
244 modest_platform_information_banner (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
245 _CS("ckdg_ib_maximum_characters_reached"));
247 if (modest_text_utils_is_forbidden_char (*text, FOLDER_NAME_FORBIDDEN_CHARS)) {
251 tmp = g_strndup (folder_name_forbidden_chars,
252 FOLDER_NAME_FORBIDDEN_CHARS_LENGTH);
253 msg = g_strdup_printf (_CS("ckdg_ib_illegal_characters_entered"), tmp);
254 modest_platform_information_banner (gtk_widget_get_parent (GTK_WIDGET (data)),
260 modest_platform_information_banner (gtk_widget_get_parent (GTK_WIDGET (data)), NULL,
261 _CS("ckdg_ib_maximum_characters_reached"));
263 /* Write the text in the entry if it's valid */
264 g_signal_handlers_block_by_func (editable,
265 (gpointer) entry_insert_text, data);
266 gtk_editable_insert_text (editable, text, length, position);
267 g_signal_handlers_unblock_by_func (editable,
268 (gpointer) entry_insert_text, data);
271 /* Do not allow further processing */
272 g_signal_stop_emission_by_name (editable, "insert_text");
276 entry_changed (GtkEditable *editable,
280 GtkWidget *ok_button;
283 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (user_data)->action_area));
284 ok_button = GTK_WIDGET (buttons->data);
286 chars = gtk_editable_get_chars (editable, 0, -1);
287 g_return_if_fail (chars != NULL);
290 if (g_utf8_strlen (chars,-1) >= 20) {
291 modest_platform_information_banner (gtk_widget_get_parent (GTK_WIDGET (user_data)), NULL,
292 _CS("ckdg_ib_maximum_characters_reached"));
294 gtk_widget_set_sensitive (ok_button, modest_text_utils_validate_folder_name(chars));
297 g_list_free (buttons);
304 on_response (GtkDialog *dialog,
308 GtkWidget *entry, *picker;
309 TnyFolderStore *parent;
310 const gchar *new_name;
313 if (response != GTK_RESPONSE_ACCEPT)
317 entry = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY);
318 picker = g_object_get_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER);
320 parent = TNY_FOLDER_STORE (user_data);
321 new_name = gtk_entry_get_text (GTK_ENTRY (entry));
325 parent = g_object_get_data (G_OBJECT (picker), FOLDER_PICKER_CURRENT_FOLDER);
327 /* Look for another folder with the same name */
328 if (!TNY_IS_MERGE_FOLDER (parent) &&
329 modest_tny_folder_has_subfolder_with_name (parent, new_name, TRUE))
333 if (TNY_IS_ACCOUNT (parent) &&
334 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (parent)) &&
335 modest_tny_local_folders_account_folder_name_in_use (MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (parent),
343 modest_platform_information_banner (gtk_widget_get_parent (GTK_WIDGET (dialog)),
344 NULL, _CS("ckdg_ib_folder_already_exists"));
345 /* Select the text */
346 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
347 gtk_widget_grab_focus (entry);
348 /* Do not close the dialog */
349 g_signal_stop_emission_by_name (dialog, "response");
353 typedef struct _FolderChooserData {
354 TnyFolderStore *store;
359 folder_chooser_activated (ModestFolderView *folder_view,
360 TnyFolderStore *folder,
361 FolderChooserData *userdata)
363 userdata->store = folder;
364 gtk_dialog_response (GTK_DIALOG (userdata->dialog), GTK_RESPONSE_OK);
367 static TnyFolderStore *
368 folder_chooser_dialog_run (ModestFolderView *original,
369 TnyFolderStore *current,
372 GtkWidget *folder_view;
373 FolderChooserData userdata = {NULL, NULL};
374 GtkWidget *scrollable;
375 const gchar *visible_id = NULL;
377 userdata.dialog = gtk_dialog_new ();
378 scrollable = modest_toolkit_factory_create_scrollable (modest_runtime_get_toolkit_factory ());
379 folder_view = modest_platform_create_folder_view (NULL);
381 gtk_window_set_title (GTK_WINDOW (userdata.dialog), _FM("ckdg_ti_change_folder"));
383 modest_folder_view_copy_model (MODEST_FOLDER_VIEW (original),
384 MODEST_FOLDER_VIEW (folder_view));
386 if (TNY_IS_ACCOUNT (current)) {
387 /* Local folders and MMC account are always shown
388 along with the currently visible server account */
389 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (current)) ||
390 modest_tny_account_is_memory_card_account (TNY_ACCOUNT (current)))
391 visible_id = g_object_get_data ((GObject *) picker, FOLDER_PICKER_ORIGINAL_ACCOUNT);
393 visible_id = tny_account_get_id (TNY_ACCOUNT (current));
394 } else if (TNY_IS_FOLDER (current)) {
396 account = modest_tny_folder_get_account ((TnyFolder *) current);
398 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (account)) ||
399 modest_tny_account_is_memory_card_account (TNY_ACCOUNT (account))) {
400 visible_id = g_object_get_data ((GObject *) picker, FOLDER_PICKER_ORIGINAL_ACCOUNT);
402 visible_id = tny_account_get_id (account);
404 g_object_unref (account);
408 modest_folder_view_get_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(original));
411 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(folder_view),
414 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (userdata.dialog)->vbox), scrollable);
415 gtk_container_add (GTK_CONTAINER (scrollable), folder_view);
416 gtk_widget_set_size_request (scrollable, -1, 320);
418 gtk_widget_show (folder_view);
419 gtk_widget_show (scrollable);
420 gtk_widget_show (userdata.dialog);
421 g_signal_connect (G_OBJECT (folder_view), "folder-activated",
422 G_CALLBACK (folder_chooser_activated),
423 (gpointer) &userdata);
425 gtk_dialog_run (GTK_DIALOG (userdata.dialog));
426 gtk_widget_destroy (userdata.dialog);
428 return userdata.store;
432 folder_store_get_display_name (TnyFolderStore *store)
434 if (TNY_IS_ACCOUNT (store)) {
435 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
436 return modest_conf_get_string (modest_runtime_get_conf(),
437 MODEST_CONF_DEVICE_NAME, NULL);
439 return g_strdup (tny_account_get_name (TNY_ACCOUNT (store)));
442 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
444 fname = g_strdup (tny_folder_get_name (TNY_FOLDER (store)));
445 type = tny_folder_get_folder_type (TNY_FOLDER (store));
446 if (modest_tny_folder_is_local_folder (TNY_FOLDER (store)) ||
447 modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
448 type = modest_tny_folder_get_local_or_mmc_folder_type (TNY_FOLDER (store));
449 if (type != TNY_FOLDER_TYPE_UNKNOWN) {
451 fname = g_strdup (modest_local_folder_info_get_type_display_name (type));
454 /* Sometimes an special folder is reported by the server as
455 NORMAL, like some versions of Dovecot */
456 if (type == TNY_FOLDER_TYPE_NORMAL ||
457 type == TNY_FOLDER_TYPE_UNKNOWN) {
458 type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
462 if (type == TNY_FOLDER_TYPE_INBOX) {
464 fname = g_strdup (_("mcen_me_folder_inbox"));
471 get_image_for_folder_store (TnyFolderStore *store,
475 const gchar *icon_name = NULL;
476 GtkWidget *image = NULL;
478 if (TNY_IS_ACCOUNT (store)) {
479 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (store)))
480 icon_name = MODEST_FOLDER_ICON_LOCAL_FOLDERS;
481 else if (modest_tny_account_is_memory_card_account (TNY_ACCOUNT (store)))
482 icon_name = MODEST_FOLDER_ICON_MMC;
484 icon_name = MODEST_FOLDER_ICON_ACCOUNT;
486 TnyFolderType type = modest_tny_folder_guess_folder_type (TNY_FOLDER (store));
487 if (modest_tny_folder_is_remote_folder (TNY_FOLDER (store))) {
489 case TNY_FOLDER_TYPE_INBOX:
490 icon_name = MODEST_FOLDER_ICON_INBOX;
493 icon_name = MODEST_FOLDER_ICON_REMOTE_FOLDER;
495 } else if (modest_tny_folder_is_local_folder (TNY_FOLDER (store))) {
497 case TNY_FOLDER_TYPE_OUTBOX:
498 icon_name = MODEST_FOLDER_ICON_OUTBOX;
500 case TNY_FOLDER_TYPE_DRAFTS:
501 icon_name = MODEST_FOLDER_ICON_DRAFTS;
503 case TNY_FOLDER_TYPE_SENT:
504 icon_name = MODEST_FOLDER_ICON_SENT;
507 icon_name = MODEST_FOLDER_ICON_NORMAL;
509 } else if (modest_tny_folder_is_memory_card_folder (TNY_FOLDER (store))) {
510 icon_name = MODEST_FOLDER_ICON_MMC_FOLDER;
515 pixbuf = modest_platform_get_icon (icon_name, size);
518 image = gtk_image_new_from_pixbuf (pixbuf);
519 g_object_unref (pixbuf);
526 folder_picker_set_store (GtkButton *button, TnyFolderStore *store)
531 g_object_set_data (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER, NULL);
535 g_object_set_data_full (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER,
536 g_object_ref (store),
537 (GDestroyNotify) g_object_unref);
538 name = folder_store_get_display_name (store);
539 gtk_button_set_label (GTK_BUTTON (button), name);
543 image = get_image_for_folder_store (store, MODEST_ICON_SIZE_SMALL);
545 gtk_button_set_image (GTK_BUTTON (button), image);
549 /* Always returns DUPs so you must free the returned value */
551 get_next_folder_name (const gchar *suggested_name,
552 TnyFolderStore *suggested_folder)
554 const gchar *default_name = _FM("ckdg_va_new_folder_name_stub");
556 gchar *real_suggested_name;
558 if (suggested_name !=NULL) {
559 return g_strdup (suggested_name);
562 for(i = 0; i < 100; ++ i) {
563 gboolean exists = FALSE;
566 real_suggested_name = g_strdup (default_name);
568 real_suggested_name = g_strdup_printf ("%s(%d)",
569 _FM("ckdg_va_new_folder_name_stub"),
571 exists = modest_tny_folder_has_subfolder_with_name (suggested_folder,
578 g_free (real_suggested_name);
581 /* Didn't find a free number */
583 real_suggested_name = g_strdup (default_name);
585 return real_suggested_name;
589 ModestFolderView *folder_view;
591 } FolderPickerHelper;
594 folder_picker_clicked (GtkButton *button,
595 FolderPickerHelper *helper)
597 TnyFolderStore *store, *current;
599 current = g_object_get_data (G_OBJECT (button), FOLDER_PICKER_CURRENT_FOLDER);
601 store = folder_chooser_dialog_run (helper->folder_view, current, button);
603 const gchar *current_name;
604 gboolean exists = FALSE;
606 folder_picker_set_store (GTK_BUTTON (button), store);
608 /* Update the name of the folder */
609 current_name = gtk_entry_get_text (helper->entry);
611 if (TNY_IS_FOLDER_STORE (store))
612 exists = modest_tny_folder_has_subfolder_with_name (store,
616 gchar *new_name = get_next_folder_name (NULL, store);
617 gtk_entry_set_text (helper->entry, new_name);
624 folder_picker_new (TnyFolderStore *suggested, FolderPickerHelper *helper)
627 const gchar *acc_id = NULL;
629 button = gtk_button_new ();
631 gtk_misc_set_alignment (GTK_MISC (button), 0.0, 0.5);
635 folder_picker_set_store (GTK_BUTTON (button), suggested);
637 if (TNY_IS_ACCOUNT (suggested)) {
638 if (!modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (suggested)) &&
639 !modest_tny_account_is_memory_card_account (TNY_ACCOUNT (suggested)))
640 acc_id = tny_account_get_id ((TnyAccount *) suggested);
642 TnyAccount *account = modest_tny_folder_get_account ((TnyFolder *) suggested);
644 acc_id = tny_account_get_id ((TnyAccount *) account);
645 g_object_unref (account);
651 acc_id = modest_folder_view_get_account_id_of_visible_server_account (MODEST_FOLDER_VIEW(helper->folder_view));
653 g_object_set_data_full (G_OBJECT (button), FOLDER_PICKER_ORIGINAL_ACCOUNT,
654 g_strdup (acc_id), (GDestroyNotify) g_free);
657 g_signal_connect (G_OBJECT (button), "clicked",
658 G_CALLBACK (folder_picker_clicked),
666 modest_platform_run_folder_common_dialog (GtkWindow *parent_window,
667 TnyFolderStore *suggested_parent,
668 const gchar *dialog_title,
669 const gchar *label_text,
670 const gchar *suggested_name,
672 gboolean show_parent,
674 TnyFolderStore **parent)
676 GtkWidget *accept_btn = NULL;
677 GtkWidget *dialog, *entry = NULL, *label_entry = NULL, *label_location = NULL, *hbox;
678 GtkWidget *account_picker = NULL;
679 GList *buttons = NULL;
681 GtkSizeGroup *sizegroup;
682 ModestFolderView *folder_view;
683 ModestWindow *folder_window;
684 ModestWindowMgr *window_mgr;
685 FolderPickerHelper *helper = NULL;
686 GtkWidget *top_vbox, *top_align;
688 window_mgr = modest_runtime_get_window_mgr ();
689 folder_window = modest_window_mgr_get_folder_window (window_mgr);
690 g_return_val_if_fail (MODEST_IS_FOLDER_WINDOW (folder_window), GTK_RESPONSE_NONE);
692 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (folder_window));
694 top_vbox = gtk_vbox_new (FALSE, 0);
695 top_align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
696 gtk_alignment_set_padding (GTK_ALIGNMENT (top_align), 0, 0, MODEST_MARGIN_DOUBLE, 0);
698 /* Ask the user for the folder name */
699 dialog = gtk_dialog_new_with_buttons (dialog_title,
701 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT,
702 _FM("ckdg_bd_new_folder_dialog_ok"),
706 /* Add accept button (with unsensitive handler) */
707 buttons = gtk_container_get_children (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area));
708 accept_btn = GTK_WIDGET (buttons->data);
710 sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
713 label_entry = gtk_label_new (label_text);
714 entry = modest_toolkit_factory_create_entry (modest_runtime_get_toolkit_factory ());
715 gtk_entry_set_max_length (GTK_ENTRY (entry), 20);
717 gtk_misc_set_alignment (GTK_MISC (label_entry), 0.0, 0.5);
718 gtk_size_group_add_widget (sizegroup, label_entry);
721 gtk_entry_set_text (GTK_ENTRY (entry), suggested_name);
723 gtk_entry_set_text (GTK_ENTRY (entry), _FM("ckdg_va_new_folder_name_stub"));
724 gtk_entry_set_width_chars (GTK_ENTRY (entry),
725 MAX (g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (entry)), -1),
726 g_utf8_strlen (_FM("ckdg_va_new_folder_name_stub"), -1)));
727 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
732 label_location = gtk_label_new (_FM("ckdg_fi_new_folder_location"));
734 gtk_misc_set_alignment (GTK_MISC (label_location), 0.0, 0.5);
735 gtk_size_group_add_widget (sizegroup, label_location);
737 helper = g_slice_new0 (FolderPickerHelper);
738 helper->folder_view = folder_view;
739 helper->entry = (GtkEntry *) entry;
741 account_picker = folder_picker_new (suggested_parent, helper);
744 g_object_unref (sizegroup);
746 /* Connect to the response method to avoid closing the dialog
747 when an invalid name is selected*/
748 g_signal_connect (dialog,
750 G_CALLBACK (on_response),
754 /* Track entry changes */
755 g_signal_connect (entry,
757 G_CALLBACK (entry_insert_text),
759 g_signal_connect (entry,
761 G_CALLBACK (entry_changed),
766 /* Some locales like pt_BR need this to get the full window
768 gtk_widget_set_size_request (GTK_WIDGET (dialog), 300, -1);
770 /* Create the hbox */
772 hbox = gtk_hbox_new (FALSE, 12);
773 gtk_box_pack_start (GTK_BOX (hbox), label_entry, FALSE, FALSE, 0);
774 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
776 /* Add hbox to dialog */
777 gtk_box_pack_start (GTK_BOX (top_vbox),
778 hbox, FALSE, FALSE, 0);
779 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ENTRY, entry);
783 hbox = gtk_hbox_new (FALSE, 12);
784 gtk_box_pack_start (GTK_BOX (hbox), label_location, FALSE, FALSE, 0);
785 gtk_box_pack_start (GTK_BOX (hbox), account_picker, TRUE, TRUE, 0);
787 /* Add hbox to dialog */
788 gtk_box_pack_start (GTK_BOX (top_vbox),
789 hbox, FALSE, FALSE, 0);
790 g_object_set_data (G_OBJECT (dialog), COMMON_FOLDER_DIALOG_ACCOUNT_PICKER, account_picker);
792 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
793 GTK_WINDOW (dialog), parent_window);
795 gtk_container_add (GTK_CONTAINER (top_align), top_vbox);
796 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), top_align, TRUE, TRUE, 0);
798 gtk_widget_show_all (GTK_WIDGET(dialog));
800 result = gtk_dialog_run (GTK_DIALOG(dialog));
801 if (result == GTK_RESPONSE_ACCEPT) {
803 *folder_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
805 *parent = g_object_get_data (G_OBJECT (account_picker), FOLDER_PICKER_CURRENT_FOLDER);
807 g_object_ref (*parent);
811 gtk_widget_destroy (dialog);
814 g_slice_free (FolderPickerHelper, helper);
816 while (gtk_events_pending ())
817 gtk_main_iteration ();
823 modest_platform_run_new_folder_dialog (GtkWindow *parent_window,
824 TnyFolderStore *suggested_folder,
825 gchar *suggested_name,
827 TnyFolderStore **parent_folder)
829 gchar *real_suggested_name = NULL;
831 ModestTnyAccountStore *acc_store;
833 gboolean do_free = FALSE;
835 real_suggested_name = get_next_folder_name ((const gchar *) suggested_name,
838 /* In hildon 2.2 we always suggest the archive folder as parent */
839 if (!suggested_folder) {
840 acc_store = modest_runtime_get_account_store ();
841 account = modest_tny_account_store_get_mmc_folders_account (acc_store);
843 suggested_folder = (TnyFolderStore *)
844 modest_tny_account_get_special_folder (account,
845 TNY_FOLDER_TYPE_ARCHIVE);
846 g_object_unref (account);
851 /* If there is not archive folder then fallback to local folders account */
852 if (!suggested_folder) {
854 suggested_folder = (TnyFolderStore *)
855 modest_tny_account_store_get_local_folders_account (acc_store);
858 result = modest_platform_run_folder_common_dialog (parent_window,
860 _HL("ckdg_ti_new_folder"),
861 _FM("ckdg_fi_new_folder_name"),
869 g_object_unref (suggested_folder);
871 g_free(real_suggested_name);
877 modest_platform_run_rename_folder_dialog (ModestWindow *parent_window,
878 TnyFolderStore *parent_folder,
879 const gchar *suggested_name,
882 g_return_val_if_fail (TNY_IS_FOLDER_STORE (parent_folder), GTK_RESPONSE_REJECT);
884 return modest_platform_run_folder_common_dialog (modest_toolkit_utils_parent_window (GTK_WIDGET (parent_window)),
886 _HL("ckdg_ti_rename_folder"),
887 _HL("ckdg_fi_rename_name"),
898 on_destroy_dialog (GtkWidget *dialog)
900 /* This could happen when the dialogs get programatically
901 hidden or destroyed (for example when closing the
902 application while a dialog is being shown) */
903 if (!GTK_IS_WIDGET (dialog))
906 gtk_widget_destroy (dialog);
908 if (gtk_events_pending ())
909 gtk_main_iteration ();
913 modest_platform_run_confirmation_dialog (GtkWindow *parent_window,
914 const gchar *message)
919 dialog = gtk_message_dialog_new (parent_window, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
920 GTK_MESSAGE_QUESTION,
921 GTK_BUTTONS_OK_CANCEL,
923 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
924 GTK_WINDOW (dialog), parent_window);
926 response = gtk_dialog_run (GTK_DIALOG (dialog));
928 on_destroy_dialog (dialog);
934 modest_platform_run_confirmation_dialog_with_buttons (GtkWindow *parent_window,
935 const gchar *message,
936 const gchar *button_accept,
937 const gchar *button_cancel)
942 dialog = gtk_message_dialog_new (parent_window, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
943 GTK_MESSAGE_QUESTION,
946 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
947 button_accept, GTK_RESPONSE_ACCEPT,
948 button_cancel, GTK_RESPONSE_CANCEL,
951 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
952 GTK_WINDOW (dialog), parent_window);
954 response = gtk_dialog_run (GTK_DIALOG (dialog));
956 on_destroy_dialog (dialog);
962 modest_platform_run_information_dialog (GtkWindow *parent_window,
963 const gchar *message,
968 note = gtk_message_dialog_new (parent_window, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
973 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
974 GTK_WINDOW (note), parent_window);
977 gtk_dialog_run (GTK_DIALOG (note));
979 on_destroy_dialog (note);
981 g_signal_connect_swapped (note,
983 G_CALLBACK (on_destroy_dialog),
986 gtk_widget_show_all (note);
990 typedef struct _ConnectAndWaitData {
992 GMainLoop *wait_loop;
993 gboolean has_callback;
995 } ConnectAndWaitData;
999 modest_platform_connect_and_wait (GtkWindow *parent_window,
1000 TnyAccount *account)
1002 gboolean device_online;
1004 TnyConnectionStatus conn_status;
1005 gboolean user_requested;
1007 device = modest_runtime_get_device();
1008 device_online = tny_device_is_online (device);
1010 /* Whether the connection is user requested or automatically
1011 requested, for example via D-Bus */
1012 user_requested = (parent_window) ? TRUE : FALSE;
1014 /* If there is no account check only the device status */
1019 /* TODO: should show connection dialog through gnome device */
1023 /* Return if the account is already connected */
1024 conn_status = tny_account_get_connection_status (account);
1025 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED)
1032 modest_platform_connect_and_wait_if_network_account (GtkWindow *parent_window, TnyAccount *account)
1034 if (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE) {
1035 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1036 /* This must be a maildir account, which does not require a connection: */
1041 return modest_platform_connect_and_wait (parent_window, account);
1045 modest_platform_connect_and_wait_if_network_folderstore (GtkWindow *parent_window, TnyFolderStore *folder_store)
1048 return TRUE; /* Maybe it is something local. */
1050 gboolean result = TRUE;
1051 if (TNY_IS_FOLDER (folder_store)) {
1052 /* Get the folder's parent account: */
1053 TnyAccount *account = tny_folder_get_account(TNY_FOLDER (folder_store));
1054 if (account != NULL) {
1055 result = modest_platform_connect_and_wait_if_network_account (NULL, account);
1056 g_object_unref (account);
1058 } else if (TNY_IS_ACCOUNT (folder_store)) {
1059 /* Use the folder store as an account: */
1060 result = modest_platform_connect_and_wait_if_network_account (NULL, TNY_ACCOUNT (folder_store));
1067 modest_platform_create_sort_dialog (GtkWindow *parent_window)
1075 modest_platform_set_update_interval (guint minutes)
1081 modest_platform_push_email_notification(void)
1087 modest_platform_on_new_headers_received (GList *URI_list,
1088 gboolean show_visual)
1094 modest_platform_remove_new_mail_notifications (gboolean only_visuals)
1102 modest_platform_get_global_settings_dialog ()
1108 modest_platform_show_help (GtkWindow *parent_window,
1109 const gchar *help_id)
1115 modest_platform_show_search_messages (GtkWindow *parent_window)
1121 modest_platform_show_addressbook (GtkWindow *parent_window)
1127 modest_platform_create_folder_view_full (TnyFolderStoreQuery *query, gboolean do_refresh)
1129 GtkWidget *widget = modest_folder_view_new_full (query, do_refresh);
1131 /* Show one account by default */
1132 modest_folder_view_set_style (MODEST_FOLDER_VIEW (widget),
1133 MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1139 modest_platform_create_folder_view (TnyFolderStoreQuery *query)
1141 return modest_platform_create_folder_view_full (query, TRUE);
1145 banner_finish (gpointer data, GObject *object)
1147 ModestWindowMgr *mgr = (ModestWindowMgr *) data;
1148 modest_window_mgr_unregister_banner (mgr);
1149 g_object_unref (mgr);
1153 modest_platform_information_banner (GtkWidget *parent,
1154 const gchar *icon_name,
1161 modest_platform_system_banner (GtkWidget *parent,
1162 const gchar *icon_name,
1169 modest_platform_information_banner_with_timeout (GtkWidget *parent,
1170 const gchar *icon_name,
1178 modest_platform_animation_banner (GtkWidget *parent,
1179 const gchar *animation_name,
1188 TnyAccount *account;
1191 } CheckAccountIdleData;
1193 #define NUMBER_OF_TRIES 10 /* Try approx every second, ten times. */
1196 on_timeout_check_account_is_online(CheckAccountIdleData* data)
1198 gboolean stop_trying = FALSE;
1199 g_return_val_if_fail (data && data->account, FALSE);
1201 if (data && data->account &&
1202 /* We want to wait until TNY_CONNECTION_STATUS_INIT has changed to something else,
1203 * after which the account is likely to be usable, or never likely to be usable soon: */
1204 (tny_account_get_connection_status (data->account) != TNY_CONNECTION_STATUS_INIT) )
1206 data->is_online = TRUE;
1210 /* Give up if we have tried too many times: */
1211 if (data->count_tries >= NUMBER_OF_TRIES) {
1214 /* Wait for another timeout: */
1215 ++(data->count_tries);
1220 /* Allow the function that requested this idle callback to continue: */
1222 g_main_loop_quit (data->loop);
1225 g_object_unref (data->account);
1227 return FALSE; /* Don't call this again. */
1229 return TRUE; /* Call this timeout callback again. */
1233 /* Return TRUE immediately if the account is already online,
1234 * otherwise check every second for NUMBER_OF_TRIES seconds and return TRUE as
1235 * soon as the account is online, or FALSE if the account does
1236 * not become online in the NUMBER_OF_TRIES seconds.
1237 * This is useful when the D-Bus method was run immediately after
1238 * the application was started (when using D-Bus activation),
1239 * because the account usually takes a short time to go online.
1240 * The return value is maybe not very useful.
1243 modest_platform_check_and_wait_for_account_is_online(TnyAccount *account)
1247 g_return_val_if_fail (account, FALSE);
1249 if (!tny_device_is_online (modest_runtime_get_device())) {
1250 printf ("DEBUG: %s: device is offline.\n", __FUNCTION__);
1254 /* The local_folders account never seems to leave TNY_CONNECTION_STATUS_INIT,
1255 * so we avoid wait unnecessarily: */
1256 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1259 /* The POP & IMAP store accounts seem to be TNY_CONNECTION_STATUS_DISCONNECTED,
1260 * and that seems to be an OK time to use them. Maybe it's just TNY_CONNECTION_STATUS_INIT that
1261 * we want to avoid. */
1262 if (tny_account_get_connection_status (account) != TNY_CONNECTION_STATUS_INIT)
1265 /* This blocks on the result: */
1266 CheckAccountIdleData *data = g_slice_new0 (CheckAccountIdleData);
1267 data->is_online = FALSE;
1268 data->account = account;
1269 g_object_ref (data->account);
1270 data->count_tries = 0;
1272 GMainContext *context = NULL; /* g_main_context_new (); */
1273 data->loop = g_main_loop_new (context, FALSE /* not running */);
1275 g_timeout_add (1000, (GSourceFunc)(on_timeout_check_account_is_online), data);
1277 /* This main loop will run until the idle handler has stopped it: */
1278 g_main_loop_run (data->loop);
1280 g_main_loop_unref (data->loop);
1281 /* g_main_context_unref (context); */
1283 is_online = data->is_online;
1284 g_slice_free (CheckAccountIdleData, data);
1292 on_cert_dialog_response (GtkDialog *dialog, gint response_id, const gchar* cert)
1294 /* GTK_RESPONSE_HELP means we need to show the certificate */
1295 if (response_id == GTK_RESPONSE_APPLY) {
1298 /* Do not close the dialog */
1299 g_signal_stop_emission_by_name (dialog, "response");
1301 msg = g_strdup_printf (_("mcen_ni_view_unknown_certificate"), cert);
1302 modest_platform_run_information_dialog (NULL, msg, TRUE);
1308 modest_platform_run_certificate_confirmation_dialog (const gchar* server_name,
1309 const gchar *certificate)
1315 gchar *question = g_strdup_printf (_("mcen_nc_unknown_certificate"),
1318 /* We use GTK_RESPONSE_APPLY because we want the button in the
1319 middle of OK and CANCEL the same as the browser does for
1320 example. With GTK_RESPONSE_HELP the view button is aligned
1321 to the left while the other two to the right */
1322 note = gtk_message_dialog_new (
1324 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1325 GTK_MESSAGE_QUESTION,
1328 gtk_dialog_add_buttons (GTK_DIALOG (note),
1329 _HL("wdgt_bd_yes"), GTK_RESPONSE_OK,
1330 _HL("wdgt_bd_view"), GTK_RESPONSE_APPLY, /* abusing this... */
1331 _HL("wdgt_bd_no"), GTK_RESPONSE_CANCEL,
1334 g_signal_connect (G_OBJECT(note), "response",
1335 G_CALLBACK(on_cert_dialog_response),
1336 (gpointer) certificate);
1338 response = gtk_dialog_run(GTK_DIALOG(note));
1340 on_destroy_dialog (note);
1343 return response == GTK_RESPONSE_OK;
1347 modest_platform_run_alert_dialog (const gchar* prompt,
1348 gboolean is_question)
1351 gboolean retval = TRUE;
1354 /* The Tinymail documentation says that we should show Yes and No buttons,
1355 * when it is a question.
1356 * Obviously, we need tinymail to use more specific error codes instead,
1357 * so we know what buttons to show. */
1358 dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1359 GTK_MESSAGE_QUESTION,
1363 const int response = gtk_dialog_run (GTK_DIALOG (dialog));
1364 retval = (response == GTK_RESPONSE_YES) || (response == GTK_RESPONSE_OK);
1366 on_destroy_dialog (dialog);
1368 /* Just show the error text and use the default response: */
1369 modest_platform_run_information_dialog (NULL,
1377 GtkWindow *parent_window;
1378 ModestConnectedPerformer callback;
1379 TnyAccount *account;
1386 on_went_online_info_free (OnWentOnlineInfo *info)
1388 /* And if we cleanup, we DO cleanup :-) */
1391 g_object_unref (info->device);
1394 if (info->parent_window)
1395 g_object_unref (info->parent_window);
1397 g_object_unref (info->account);
1399 g_slice_free (OnWentOnlineInfo, info);
1401 /* We're done ... */
1407 on_account_went_online (TnyCamelAccount *account, gboolean canceled, GError *err, gpointer user_data)
1409 OnWentOnlineInfo *info = (OnWentOnlineInfo *) user_data;
1411 /* Now it's really time to callback to the caller. If going online didn't succeed,
1412 * err will be set. We don't free it, Tinymail does that! If a cancel happened,
1413 * canceled will be set. Etcetera etcetera. */
1415 if (info->callback) {
1416 info->callback (canceled, err, info->parent_window, info->account, info->user_data);
1419 /* This is our last call, we must cleanup here if we didn't yet do that */
1420 on_went_online_info_free (info);
1426 modest_platform_connect_and_perform (GtkWindow *parent_window,
1428 TnyAccount *account,
1429 ModestConnectedPerformer callback,
1432 gboolean device_online;
1434 TnyConnectionStatus conn_status;
1436 device = modest_runtime_get_device();
1437 device_online = tny_device_is_online (device);
1439 /* If there is no account check only the device status */
1442 if (device_online) {
1444 /* We promise to instantly perform the callback, so ... */
1446 callback (FALSE, NULL, parent_window, account, user_data);
1453 /* The other code has no more reason to run. This is all that we can do for the
1454 * caller (he should have given us a nice and clean account instance!). We
1455 * can't do magic, we don't know what account he intends to bring online. So
1456 * we'll just bring the device online (and await his false bug report). */
1462 /* Return if the account is already connected */
1464 conn_status = tny_account_get_connection_status (account);
1465 if (device_online && conn_status == TNY_CONNECTION_STATUS_CONNECTED) {
1467 /* We promise to instantly perform the callback, so ... */
1469 callback (FALSE, NULL, parent_window, account, user_data);
1475 if (!device_online) {
1476 OnWentOnlineInfo *info = NULL;
1478 info = g_slice_new0 (OnWentOnlineInfo);
1480 info->device = NULL;
1482 info->account = TNY_ACCOUNT (g_object_ref (account));
1485 info->parent_window = (GtkWindow *) g_object_ref (parent_window);
1487 info->parent_window = NULL;
1489 /* So we'll put the callback away for later ... */
1490 info->user_data = user_data;
1491 info->callback = callback;
1493 /* If the device is online, we'll just connect the account */
1494 tny_camel_account_set_online (TNY_CAMEL_ACCOUNT (account), TRUE,
1495 on_account_went_online, info);
1498 /* The info gets freed by on_account_went_online or on_conic_device_went_online
1499 * in both situations, go look if you don't believe me! */
1503 modest_platform_connect_if_remote_and_perform (GtkWindow *parent_window,
1505 TnyFolderStore *folder_store,
1506 ModestConnectedPerformer callback,
1509 TnyAccount *account = NULL;
1511 if (!folder_store ||
1512 (TNY_IS_MERGE_FOLDER (folder_store) &&
1513 (tny_folder_get_folder_type (TNY_FOLDER(folder_store)) == TNY_FOLDER_TYPE_OUTBOX))) {
1515 /* We promise to instantly perform the callback, so ... */
1517 GError *error = NULL;
1518 g_set_error (&error, TNY_ERROR_DOMAIN, TNY_SERVICE_ERROR_UNKNOWN,
1519 "Unable to move or not found folder");
1520 callback (FALSE, error, parent_window, NULL, user_data);
1521 g_error_free (error);
1525 } else if (TNY_IS_FOLDER (folder_store)) {
1526 /* Get the folder's parent account: */
1527 account = tny_folder_get_account (TNY_FOLDER (folder_store));
1528 } else if (TNY_IS_ACCOUNT (folder_store)) {
1529 /* Use the folder store as an account: */
1530 account = TNY_ACCOUNT (g_object_ref (folder_store));
1533 if (account && (tny_account_get_account_type (account) == TNY_ACCOUNT_TYPE_STORE)) {
1534 if (!modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1535 /* No need to connect a local account */
1537 callback (FALSE, NULL, parent_window, account, user_data);
1542 modest_platform_connect_and_perform (parent_window, force, account, callback, user_data);
1546 g_object_unref (account);
1550 src_account_connect_performer (gboolean canceled,
1552 GtkWindow *parent_window,
1553 TnyAccount *src_account,
1556 DoubleConnectionInfo *info = (DoubleConnectionInfo *) user_data;
1558 if (canceled || err) {
1559 /* If there was any error call the user callback */
1560 info->callback (canceled, err, parent_window, src_account, info->data);
1562 /* Connect the destination account */
1563 modest_platform_connect_if_remote_and_perform (parent_window, TRUE,
1564 TNY_FOLDER_STORE (info->dst_account),
1565 info->callback, info->data);
1568 /* Free the info object */
1569 g_object_unref (info->dst_account);
1570 g_slice_free (DoubleConnectionInfo, info);
1575 modest_platform_double_connect_and_perform (GtkWindow *parent_window,
1577 TnyFolderStore *folder_store,
1578 DoubleConnectionInfo *connect_info)
1580 modest_platform_connect_if_remote_and_perform(parent_window,
1583 src_account_connect_performer,
1588 modest_platform_get_account_settings_wizard (void)
1590 ModestEasysetupWizardDialog *dialog = modest_easysetup_wizard_dialog_new ();
1592 return GTK_WIDGET (dialog);
1596 modest_platform_get_current_connection (void)
1598 TnyDevice *device = NULL;
1599 ModestConnectedVia retval = MODEST_CONNECTED_VIA_ANY;
1601 device = modest_runtime_get_device ();
1603 if (!tny_device_is_online (device))
1604 return MODEST_CONNECTED_VIA_ANY;
1606 retval = MODEST_CONNECTED_VIA_WLAN_OR_WIMAX; /* assume WLAN (fast) internet */
1613 modest_platform_check_memory_low (ModestWindow *win,
1621 modest_platform_run_folder_details_dialog (GtkWindow *parent_window,
1627 dialog = modest_toolkit_factory_create_details_dialog_with_folder (modest_runtime_get_toolkit_factory (),
1628 parent_window, folder);
1631 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1632 GTK_WINDOW (dialog),
1634 gtk_widget_show_all (dialog);
1636 g_signal_connect_swapped (dialog, "response",
1637 G_CALLBACK (gtk_widget_destroy),
1641 typedef struct _HeaderDetailsGetSizeInfo {
1645 } HeaderDetailsGetSizeInfo;
1648 header_details_dialog_destroy (gpointer userdata,
1651 HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) userdata;
1653 info->dialog = NULL;
1657 idle_get_mime_part_size_cb (gpointer userdata)
1659 HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) userdata;
1660 gdk_threads_enter ();
1662 if (info->dialog && GTK_WIDGET_VISIBLE (info->dialog)) {
1663 modest_details_dialog_set_message_size (MODEST_DETAILS_DIALOG (info->dialog),
1668 g_object_weak_unref (G_OBJECT (info->dialog), header_details_dialog_destroy, info);
1669 info->dialog = NULL;
1671 g_object_unref (info->part);
1672 g_slice_free (HeaderDetailsGetSizeInfo, info);
1674 gdk_threads_leave ();
1680 get_mime_part_size_thread (gpointer thr_user_data)
1682 HeaderDetailsGetSizeInfo *info = (HeaderDetailsGetSizeInfo *) thr_user_data;
1684 TnyStream *count_stream;
1686 count_stream = modest_count_stream_new ();
1687 result = tny_mime_part_decode_to_stream (info->part, count_stream, NULL);
1688 info->total = modest_count_stream_get_count(MODEST_COUNT_STREAM (count_stream));
1689 if (info->total == 0) {
1690 modest_count_stream_reset_count(MODEST_COUNT_STREAM (count_stream));
1691 result = tny_mime_part_write_to_stream (info->part, count_stream, NULL);
1692 info->total = modest_count_stream_get_count(MODEST_COUNT_STREAM (count_stream));
1695 /* if there was an error, don't set the size (this is pretty uncommon) */
1697 g_warning ("%s: error while writing mime part to stream\n", __FUNCTION__);
1699 g_idle_add (idle_get_mime_part_size_cb, info);
1705 modest_platform_run_header_details_dialog (GtkWindow *parent_window,
1707 gboolean async_get_size,
1713 dialog = modest_toolkit_factory_create_details_dialog_with_header (modest_runtime_get_toolkit_factory (),
1714 parent_window, header, !async_get_size);
1716 if (async_get_size && msg && TNY_IS_MSG (msg)) {
1717 HeaderDetailsGetSizeInfo *info;
1718 info = g_slice_new (HeaderDetailsGetSizeInfo);
1719 info->dialog = dialog;
1721 info->part = TNY_MIME_PART (g_object_ref (msg));
1723 g_object_weak_ref (G_OBJECT (dialog), header_details_dialog_destroy, info);
1724 g_thread_create (get_mime_part_size_thread, info, FALSE, NULL);
1728 modest_window_mgr_set_modal (modest_runtime_get_window_mgr (),
1729 GTK_WINDOW (dialog),
1731 gtk_widget_show_all (dialog);
1733 g_signal_connect_swapped (dialog, "response",
1734 G_CALLBACK (gtk_widget_destroy),
1738 #define MOVE_TO_DIALOG_FOLDER_VIEW "folder-view"
1739 #define MOVE_TO_DIALOG_BACK_BUTTON "back-button"
1740 #define MOVE_TO_DIALOG_ACTION_BUTTON "action-button"
1741 #define MOVE_TO_DIALOG_SHOWING_FOLDERS "showing-folders"
1742 #define MOVE_TO_DIALOG_SCROLLABLE "scrollable"
1743 #define MOVE_TO_FOLDER_SEPARATOR "/"
1746 translate_path (gchar **path)
1751 gboolean add_separator;
1753 parts = g_strsplit (*path, MOVE_TO_FOLDER_SEPARATOR, 0);
1757 output = g_string_new ("");
1758 add_separator = FALSE;
1760 while (*current != NULL) {
1761 TnyFolderType folder_type;
1764 if (add_separator) {
1765 output = g_string_append (output, MOVE_TO_FOLDER_SEPARATOR);
1767 add_separator = TRUE;
1770 downcase = g_ascii_strdown (*current, -1);
1771 folder_type = modest_local_folder_info_get_type (downcase);
1772 if (strcmp (downcase, "inbox") == 0) {
1773 output = g_string_append (output, _("mcen_me_folder_inbox"));
1774 } else if (folder_type == TNY_FOLDER_TYPE_ARCHIVE ||
1775 folder_type == TNY_FOLDER_TYPE_DRAFTS ||
1776 folder_type == TNY_FOLDER_TYPE_SENT ||
1777 folder_type == TNY_FOLDER_TYPE_OUTBOX) {
1778 output = g_string_append (output, modest_local_folder_info_get_type_display_name (folder_type));
1780 output = g_string_append (output, *current);
1788 *path = g_string_free (output, FALSE);
1792 move_to_dialog_set_selected_folder_store (GtkWidget *dialog,
1793 TnyFolderStore *folder_store)
1795 GtkWidget *action_button;
1796 GtkWidget *image = NULL;
1797 TnyAccount *account;
1798 gchar *account_name = NULL, *short_name = NULL;
1800 action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
1802 /* Get account name */
1803 if (TNY_IS_FOLDER (folder_store))
1804 account = tny_folder_get_account (TNY_FOLDER (folder_store));
1806 account = g_object_ref (folder_store);
1808 if (modest_tny_account_is_virtual_local_folders (account))
1809 account_name = modest_conf_get_string (modest_runtime_get_conf(),
1810 MODEST_CONF_DEVICE_NAME, NULL);
1813 account_name = g_strdup (tny_account_get_name (account));
1815 g_object_unref (account);
1817 /* Set title of button: account or folder name */
1818 if (TNY_IS_FOLDER (folder_store))
1819 short_name = folder_store_get_display_name (folder_store);
1821 short_name = g_strdup (account_name);
1823 gtk_button_set_label (GTK_BUTTON (action_button), short_name);
1825 /* Set value of button, folder full name */
1826 if (TNY_IS_CAMEL_FOLDER (folder_store)) {
1827 const gchar *camel_full_name;
1828 gchar *last_slash, *full_name;
1830 camel_full_name = tny_camel_folder_get_full_name (TNY_CAMEL_FOLDER (folder_store));
1831 last_slash = g_strrstr (camel_full_name, "/");
1833 gchar *prefix = g_strndup (camel_full_name, last_slash - camel_full_name + 1);
1834 full_name = g_strconcat (account_name, MOVE_TO_FOLDER_SEPARATOR, prefix, short_name, NULL);
1837 full_name = g_strconcat (account_name, MOVE_TO_FOLDER_SEPARATOR,
1841 translate_path (&full_name);
1842 gtk_button_set_label (GTK_BUTTON (action_button), full_name);
1845 g_free (account_name);
1846 g_free (short_name);
1848 /* Set image for the button */
1849 image = get_image_for_folder_store (folder_store, MODEST_ICON_SIZE_BIG);
1851 gtk_button_set_image (GTK_BUTTON (action_button), image);
1855 move_to_dialog_show_accounts (GtkWidget *dialog)
1857 GtkWidget *back_button;
1858 GtkWidget *folder_view;
1859 GtkWidget *scrollable;
1860 GtkWidget *action_button;
1862 back_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
1863 action_button = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
1864 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
1865 scrollable = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SCROLLABLE));
1867 gtk_widget_set_sensitive (back_button, FALSE);
1868 gtk_widget_set_sensitive (action_button, FALSE);
1870 /* Need to set this here, otherwise callbacks called because
1871 of filtering won't perform correctly */
1872 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS, GINT_TO_POINTER (FALSE));
1874 /* Reset action button */
1875 gtk_button_set_label (GTK_BUTTON (action_button), NULL);
1876 gtk_button_set_image (GTK_BUTTON (action_button), NULL);
1878 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view), NULL);
1879 modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), TRUE);
1880 modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ALL);
1881 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
1882 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
1883 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
1884 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
1885 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view),
1886 MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
1887 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
1888 MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
1889 modest_scrollable_jump_to (MODEST_SCROLLABLE (scrollable), 0, 0);
1893 move_to_dialog_show_folders (GtkWidget *dialog, TnyFolderStore *folder_store)
1895 GtkWidget *back_button;
1896 GtkWidget *folder_view;
1897 TnyAccount *account;
1898 const gchar *account_id;
1899 GtkWidget *scrollable;
1900 GtkWidget *action_button;
1903 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON));
1905 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON));
1907 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
1909 GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SCROLLABLE));
1911 gtk_widget_set_sensitive (back_button, TRUE);
1912 gtk_widget_set_sensitive (action_button, TRUE);
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),
1917 MOVE_TO_DIALOG_SHOWING_FOLDERS,
1918 GINT_TO_POINTER (TRUE));
1920 account = TNY_ACCOUNT (folder_store);
1921 if (modest_tny_account_is_virtual_local_folders (account)) {
1922 account_id = tny_account_get_id (account);
1923 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
1924 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
1925 } else if (modest_tny_account_is_memory_card_account (account)) {
1926 account_id = tny_account_get_id (account);
1927 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
1928 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
1930 account_id = tny_account_get_id (account);
1931 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
1932 MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS);
1933 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view),
1934 MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS);
1937 move_to_dialog_set_selected_folder_store (dialog, folder_store);
1938 modest_folder_view_set_account_id_of_visible_server_account (MODEST_FOLDER_VIEW (folder_view),
1941 modest_folder_view_show_non_move_folders (MODEST_FOLDER_VIEW (folder_view), FALSE);
1942 modest_folder_view_set_style (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
1943 modest_folder_view_set_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS);
1944 modest_folder_view_unset_filter (MODEST_FOLDER_VIEW (folder_view), MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS);
1945 modest_scrollable_jump_to (MODEST_SCROLLABLE (scrollable), 0, 0);
1949 on_move_to_dialog_back_clicked (GtkButton *button,
1952 GtkWidget *dialog = (GtkWidget *) userdata;
1954 /* Back to show accounts */
1955 move_to_dialog_show_accounts (dialog);
1959 on_move_to_dialog_row_activated (GtkTreeView *tree_view,
1961 GtkTreeViewColumn *column,
1964 TnyFolderStore *selected = NULL;
1966 GtkWidget *folder_view;
1967 gboolean showing_folders;
1969 dialog = (GtkWidget *) user_data;
1970 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog),
1971 MOVE_TO_DIALOG_SHOWING_FOLDERS));
1973 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog),
1974 MOVE_TO_DIALOG_FOLDER_VIEW));
1976 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
1980 if (!showing_folders) {
1981 gboolean valid = TRUE;
1983 if (TNY_IS_ACCOUNT (selected) &&
1984 modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (selected))) {
1985 ModestProtocolType protocol_type;
1987 protocol_type = modest_tny_account_get_protocol_type (TNY_ACCOUNT (selected));
1988 valid = !modest_protocol_registry_protocol_type_has_tag
1989 (modest_runtime_get_protocol_registry (),
1991 MODEST_PROTOCOL_REGISTRY_STORE_FORBID_INCOMING_XFERS);
1994 move_to_dialog_show_folders (dialog, selected);
1996 move_to_dialog_set_selected_folder_store (dialog, selected);
1998 g_object_unref (selected);
2002 on_move_to_dialog_selection_changed (GtkTreeSelection *selection,
2005 gboolean showing_folders;
2008 dialog = (GtkWidget *) user_data;
2009 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2010 if (showing_folders) {
2011 TnyFolderStore *selected;
2012 GtkWidget *folder_view;
2014 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2015 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2018 move_to_dialog_set_selected_folder_store (dialog, selected);
2019 g_object_unref (selected);
2025 on_move_to_dialog_action_clicked (GtkButton *selection,
2029 gboolean showing_folders;
2031 dialog = (GtkWidget *) user_data;
2032 showing_folders = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SHOWING_FOLDERS));
2033 if (showing_folders) {
2034 TnyFolderStore *selected;
2035 GtkWidget *folder_view;
2037 folder_view = GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW));
2038 selected = modest_folder_view_get_selected (MODEST_FOLDER_VIEW (folder_view));
2041 /* It's not possible to select root folders as
2042 targets unless they're the local account or
2043 the memory card account */
2044 if ((TNY_IS_FOLDER (selected) && !TNY_IS_MERGE_FOLDER (selected)) ||
2045 (TNY_IS_ACCOUNT (selected) &&
2046 (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (selected)) ||
2047 modest_tny_account_is_memory_card_account (TNY_ACCOUNT (selected)))))
2048 gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
2049 g_object_unref (selected);
2055 move_to_dialog_activity_changed (ModestFolderView *folder_view, gboolean activity, GtkDialog *dialog)
2060 modest_platform_create_move_to_dialog (GtkWindow *parent_window,
2061 GtkWidget **folder_view)
2063 GtkWidget *dialog, *folder_view_container;
2065 GtkWidget *buttons_hbox;
2066 GtkWidget *back_button;
2067 GdkPixbuf *back_pixbuf;
2068 GtkWidget *top_vbox;
2069 GtkWidget *action_button;
2070 GtkTreeSelection *selection;
2072 /* Create dialog. We cannot use a touch selector because we
2073 need to use here the folder view widget directly */
2074 dialog = gtk_dialog_new_with_buttons (_("mcen_ti_moveto_folders_title"),
2075 GTK_WINDOW (parent_window),
2076 GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR |
2077 GTK_DIALOG_DESTROY_WITH_PARENT,
2078 _FM ("ckdg_bd_change_folder_new_folder"),
2079 MODEST_GTK_RESPONSE_NEW_FOLDER,
2082 align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
2083 gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, MODEST_MARGIN_DOUBLE, MODEST_MARGIN_NONE);
2084 top_vbox = gtk_vbox_new (FALSE, MODEST_MARGIN_HALF);
2086 /* Create folder view */
2087 *folder_view = modest_platform_create_folder_view_full (NULL, FALSE);
2088 g_signal_connect (G_OBJECT (*folder_view), "activity-changed", G_CALLBACK (move_to_dialog_activity_changed),
2091 modest_folder_view_set_cell_style (MODEST_FOLDER_VIEW (*folder_view),
2092 MODEST_FOLDER_VIEW_CELL_STYLE_COMPACT);
2093 modest_folder_view_show_message_count (MODEST_FOLDER_VIEW (*folder_view),
2095 tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (*folder_view),
2096 (TnyAccountStore *) modest_runtime_get_account_store ());
2098 buttons_hbox = gtk_hbox_new (FALSE, MODEST_MARGIN_HALF);
2099 back_button = gtk_button_new ();
2100 back_pixbuf = modest_platform_get_icon (_FM("filemanager_folder_up"), MODEST_ICON_SIZE_BIG);
2102 gtk_button_set_image (GTK_BUTTON (back_button), gtk_image_new_from_pixbuf (back_pixbuf));
2103 g_object_unref (back_pixbuf);
2106 action_button = gtk_button_new ();
2107 gtk_button_set_alignment (GTK_BUTTON (action_button), 0.0, 0.5);
2109 gtk_box_pack_start (GTK_BOX (buttons_hbox), back_button, FALSE, FALSE, 0);
2110 gtk_box_pack_start (GTK_BOX (buttons_hbox), action_button, TRUE, TRUE, 0);
2111 gtk_widget_set_sensitive (GTK_WIDGET (back_button), FALSE);
2112 gtk_widget_set_sensitive (GTK_WIDGET (action_button), FALSE);
2113 gtk_box_pack_start (GTK_BOX (top_vbox), buttons_hbox, FALSE, FALSE, 0);
2115 /* Create scrollable and add it to the dialog */
2116 folder_view_container = modest_toolkit_factory_create_scrollable (modest_runtime_get_toolkit_factory ());
2117 gtk_container_add (GTK_CONTAINER (folder_view_container), *folder_view);
2118 gtk_box_pack_start (GTK_BOX (top_vbox), folder_view_container, TRUE, TRUE, 0);
2120 gtk_container_add (GTK_CONTAINER (align), top_vbox);
2121 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), align, TRUE, TRUE, 0);
2123 gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 300);
2125 gtk_widget_show (GTK_DIALOG (dialog)->vbox);
2126 gtk_widget_show (folder_view_container);
2127 gtk_widget_show (align);
2128 gtk_widget_show (top_vbox);
2129 gtk_widget_show (*folder_view);
2130 gtk_widget_show_all (back_button);
2131 gtk_widget_show (action_button);
2132 gtk_widget_show (buttons_hbox);
2133 gtk_widget_show (dialog);
2135 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_FOLDER_VIEW, *folder_view);
2136 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_BACK_BUTTON, back_button);
2137 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_ACTION_BUTTON, action_button);
2138 g_object_set_data (G_OBJECT (dialog), MOVE_TO_DIALOG_SCROLLABLE, folder_view_container);
2140 /* Simulate the behaviour of a HildonPickerDialog by emitting
2141 a response when a folder is selected */
2142 g_signal_connect (*folder_view, "row-activated",
2143 G_CALLBACK (on_move_to_dialog_row_activated),
2146 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (*folder_view));
2147 g_signal_connect (selection, "changed",
2148 G_CALLBACK (on_move_to_dialog_selection_changed),
2151 g_signal_connect (action_button, "clicked",
2152 G_CALLBACK (on_move_to_dialog_action_clicked),
2155 g_signal_connect (back_button, "clicked",
2156 G_CALLBACK (on_move_to_dialog_back_clicked),
2159 move_to_dialog_show_accounts (dialog);
2165 modest_platform_get_list_to_move (ModestWindow *window)
2167 TnyList *list = NULL;
2169 if (MODEST_IS_HEADER_WINDOW (window)) {
2170 ModestHeaderView *header_view;
2172 header_view = modest_header_window_get_header_view (MODEST_HEADER_WINDOW (window));
2173 list = modest_header_view_get_selected_headers (header_view);
2174 } else if (MODEST_IS_FOLDER_WINDOW (window)) {
2175 ModestFolderView *folder_view;
2176 TnyFolderStore *selected_folder;
2178 list = TNY_LIST (tny_simple_list_new ());
2179 folder_view = modest_folder_window_get_folder_view (MODEST_FOLDER_WINDOW (window));
2180 selected_folder = modest_folder_view_get_selected (folder_view);
2181 if (selected_folder) {
2182 tny_list_prepend (list, G_OBJECT (selected_folder));
2183 g_object_unref (selected_folder);
2186 } else if (MODEST_IS_MSG_VIEW_WINDOW (window)) {
2189 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (window));
2191 list = TNY_LIST (tny_simple_list_new ());
2192 tny_list_prepend (list, G_OBJECT (header));
2193 g_object_unref (header);
2196 g_return_val_if_reached (NULL);