* Fixes NB#85194, do not crash when d&d quickly over the same message
[modest] / src / widgets / modest-folder-view.c
index a555d7b..dad2d33 100644 (file)
@@ -49,6 +49,7 @@
 #include <modest-marshal.h>
 #include <modest-icon-names.h>
 #include <modest-tny-account-store.h>
+#include <modest-tny-local-folders-account.h>
 #include <modest-text-utils.h>
 #include <modest-runtime.h>
 #include "modest-folder-view.h"
@@ -401,6 +402,13 @@ text_cell_data  (GtkTreeViewColumn *column,
                                g_free (fname);
                                fname = g_strdup (modest_local_folder_info_get_type_display_name (type));
                        }
+               } else {
+                       /* Sometimes an special folder is reported by the server as
+                          NORMAL, like some versions of Dovecot */
+                       if (type == TNY_FOLDER_TYPE_NORMAL ||
+                           type == TNY_FOLDER_TYPE_UNKNOWN) {
+                               type = modest_tny_folder_guess_folder_type (TNY_FOLDER (instance));
+                       }
                }
 
                /* note: we cannot reliably get the counts from the tree model, we need
@@ -524,9 +532,8 @@ get_folder_icons (TnyFolderType type, GObject *instance)
                *ammc_pixbuf_close = NULL, *avirt_pixbuf_close = NULL;
 
 
-       /* MERGE is not needed anymore as the folder now has the correct type jschmid */
-       /* We include the MERGE type here because it's used to create
-          the local OUTBOX folder */
+       /* Sometimes an special folder is reported by the server as
+          NORMAL, like some versions of Dovecot */
        if (type == TNY_FOLDER_TYPE_NORMAL || 
            type == TNY_FOLDER_TYPE_UNKNOWN) {
                type = modest_tny_folder_guess_folder_type (TNY_FOLDER (instance));             
@@ -1111,7 +1118,6 @@ modest_folder_view_finalize (GObject *obj)
                priv->query = NULL;
        }
 
-/*     modest_folder_view_disable_next_folder_selection (MODEST_FOLDER_VIEW(obj)); */
        if (priv->folder_to_select) {
                g_object_unref (G_OBJECT(priv->folder_to_select));
                priv->folder_to_select = NULL;
@@ -1131,16 +1137,6 @@ modest_folder_view_finalize (GObject *obj)
        }
 
        if (priv->cur_folder_store) {
-               if (TNY_IS_FOLDER(priv->cur_folder_store)) {
-                       ModestMailOperation *mail_op;
-
-                       mail_op = modest_mail_operation_new (NULL);
-                       modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
-                                                        mail_op);
-                       modest_mail_operation_sync_folder (mail_op, TNY_FOLDER (priv->cur_folder_store), FALSE);
-                       g_object_unref (mail_op);
-               }
-
                g_object_unref (priv->cur_folder_store);
                priv->cur_folder_store = NULL;
        }
@@ -1196,6 +1192,8 @@ modest_folder_view_set_account_store (TnyAccountStoreView *self, TnyAccountStore
                                  G_CALLBACK (on_account_changed), self);
 
        modest_folder_view_update_model (MODEST_FOLDER_VIEW (self), account_store);
+       priv->reselect = FALSE;
+       modest_folder_view_select_first_inbox_or_local (MODEST_FOLDER_VIEW (self));
        
        g_object_unref (G_OBJECT (device));
 }
@@ -1255,13 +1253,60 @@ on_account_inserted (TnyAccountStore *account_store,
 }
 
 
+static gboolean
+same_account_selected (ModestFolderView *self,
+                      TnyAccount *account)
+{
+       ModestFolderViewPrivate *priv;
+       gboolean same_account = FALSE;
+
+       priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
+
+       if (priv->cur_folder_store) {
+               TnyAccount *selected_folder_account = NULL;
+
+               if (TNY_IS_FOLDER (priv->cur_folder_store)) {
+                       selected_folder_account = 
+                               modest_tny_folder_get_account (TNY_FOLDER (priv->cur_folder_store));
+               } else {
+                       selected_folder_account = 
+                               TNY_ACCOUNT (g_object_ref (priv->cur_folder_store));
+               }
+
+               if (selected_folder_account == account)
+                       same_account = TRUE;
+
+               g_object_unref (selected_folder_account);
+       }
+       return same_account;
+}
+
+/**
+ *
+ * Selects the first inbox or the local account in an idle
+ */
+static gboolean
+on_idle_select_first_inbox_or_local (gpointer user_data)
+{
+       ModestFolderView *self = MODEST_FOLDER_VIEW (user_data);
+
+       gdk_threads_enter ();
+       modest_folder_view_select_first_inbox_or_local (self);
+       gdk_threads_leave ();
+
+       return FALSE;
+}
+
 static void
 on_account_changed (TnyAccountStore *account_store, 
                    TnyAccount *tny_account,
                    gpointer user_data)
 {
+       ModestFolderView *self;
        ModestFolderViewPrivate *priv;
        GtkTreeModel *sort_model, *filter_model;
+       GtkTreeSelection *sel;
+       gboolean same_account;
 
        /* Ignore transport account insertions, we're not showing them
           in the folder view */
@@ -1273,7 +1318,7 @@ on_account_changed (TnyAccountStore *account_store,
                return;
        }
 
-
+       self = MODEST_FOLDER_VIEW (user_data);
        priv = MODEST_FOLDER_VIEW_GET_PRIVATE (user_data);
 
        /* Get the inner model */
@@ -1283,13 +1328,20 @@ on_account_changed (TnyAccountStore *account_store,
                return;
        }
 
-
        sort_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (filter_model));
        if (!GTK_IS_TREE_MODEL_SORT(sort_model)) {
                g_warning ("BUG: %s: not a valid sort model", __FUNCTION__);
                return;
        }
 
+       /* Invalidate the cur_folder_store only if the selected folder
+          belongs to the account that is being removed */
+       same_account = same_account_selected (self, tny_account);
+       if (same_account) {
+               sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
+               gtk_tree_selection_unselect_all (sel);
+       }
+
        /* Remove the account from the model */
        tny_list_remove (TNY_LIST (gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (sort_model))),
                         G_OBJECT (tny_account));
@@ -1300,25 +1352,13 @@ on_account_changed (TnyAccountStore *account_store,
 
        /* Refilter the model */
        gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filter_model));
-}
 
-/**
- *
- * Selects the first inbox or the local account in an idle
- */
-static gboolean
-on_idle_select_first_inbox_or_local (gpointer user_data)
-{
-       ModestFolderView *self = MODEST_FOLDER_VIEW (user_data);
-
-       gdk_threads_enter ();
-       modest_folder_view_select_first_inbox_or_local (self);
-       gdk_threads_leave ();
-
-       return FALSE;
+       /* Select the first INBOX if the currently selected folder
+          belongs to the account that is being deleted */
+       if (same_account && !MODEST_IS_TNY_LOCAL_FOLDERS_ACCOUNT (tny_account))
+               g_idle_add (on_idle_select_first_inbox_or_local, self);
 }
 
-
 static void
 on_account_removed (TnyAccountStore *account_store, 
                    TnyAccount *account,
@@ -1328,7 +1368,7 @@ on_account_removed (TnyAccountStore *account_store,
        ModestFolderViewPrivate *priv;
        GtkTreeModel *sort_model, *filter_model;
        GtkTreeSelection *sel = NULL;
-       gboolean same_account_selected = FALSE;
+       gboolean same_account = FALSE;
 
        /* Ignore transport account removals, we're not showing them
           in the folder view */
@@ -1345,23 +1385,10 @@ on_account_removed (TnyAccountStore *account_store,
 
        /* Invalidate the cur_folder_store only if the selected folder
           belongs to the account that is being removed */
-       if (priv->cur_folder_store) {
-               TnyAccount *selected_folder_account = NULL;
-
-               if (TNY_IS_FOLDER (priv->cur_folder_store)) {
-                       selected_folder_account = 
-                               tny_folder_get_account (TNY_FOLDER (priv->cur_folder_store));
-               } else {
-                       selected_folder_account = 
-                               TNY_ACCOUNT (g_object_ref (priv->cur_folder_store));
-               }
-
-               if (selected_folder_account == account) {
-                       sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
-                       gtk_tree_selection_unselect_all (sel);
-                       same_account_selected = TRUE;
-               }
-               g_object_unref (selected_folder_account);
+       same_account = same_account_selected (self, account);
+       if (same_account) {
+               sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
+               gtk_tree_selection_unselect_all (sel);
        }
 
        /* Invalidate row to select only if the folder to select
@@ -1412,7 +1439,7 @@ on_account_removed (TnyAccountStore *account_store,
 
        /* Select the first INBOX if the currently selected folder
           belongs to the account that is being deleted */
-       if (same_account_selected)
+       if (same_account)
                g_idle_add (on_idle_select_first_inbox_or_local, self);
 }
 
@@ -1713,14 +1740,18 @@ on_selection_changed (GtkTreeSelection *sel, gpointer user_data)
        
        /* Current folder was unselected */
        if (priv->cur_folder_store) {
-               g_signal_emit (G_OBJECT(tree_view), signals[FOLDER_SELECTION_CHANGED_SIGNAL], 0,
-                      priv->cur_folder_store, FALSE);
-
+               /* We must do this firstly because a libtinymail-camel
+                  implementation detail. If we issue the signal
+                  before doing the sync_async, then that signal could
+                  cause (and it actually does it) a free of the
+                  summary of the folder (because the main window will
+                  clear the headers view */
                if (TNY_IS_FOLDER(priv->cur_folder_store))
                        tny_folder_sync_async (TNY_FOLDER(priv->cur_folder_store),
                                               FALSE, NULL, NULL, NULL);
 
-               /* FALSE --> don't expunge the messages */
+               g_signal_emit (G_OBJECT(tree_view), signals[FOLDER_SELECTION_CHANGED_SIGNAL], 0,
+                      priv->cur_folder_store, FALSE);
 
                g_object_unref (priv->cur_folder_store);
                priv->cur_folder_store = NULL;
@@ -1982,7 +2013,7 @@ xfer_folder_cb (ModestMailOperation *mail_op,
        if (new_folder) {       
                /* Select the folder */
                modest_folder_view_select_folder (MODEST_FOLDER_VIEW (user_data), 
-                                                 new_folder, TRUE);
+                                                 new_folder, FALSE);
        }
 }
 
@@ -2056,6 +2087,12 @@ drag_and_drop_from_header_view (GtkTreeModel *source_model,
        }
        g_strfreev (uris);
 
+       /* This could happen ig we perform a d&d very quickly over the
+          same row that row could dissapear because message is
+          transferred */
+       if (!TNY_IS_FOLDER (src_folder))
+               goto cleanup;
+
        /* Get the target folder */
        gtk_tree_model_get_iter (dest_model, &dest_iter, dest_row);
        gtk_tree_model_get (dest_model, &dest_iter, 
@@ -2850,7 +2887,6 @@ on_row_inserted_maybe_select_folder (GtkTreeModel *tree_model,
                priv->folder_to_select = g_object_ref (instance);
        }
        g_object_unref (instance);
-
        
        if (priv->folder_to_select) {
                
@@ -2865,8 +2901,7 @@ on_row_inserted_maybe_select_folder (GtkTreeModel *tree_model,
                        gtk_tree_selection_select_iter (sel, iter);
                        gtk_tree_view_set_cursor (GTK_TREE_VIEW(self), path, NULL, FALSE);
 
-                       gtk_tree_path_free (path);
-               
+                       gtk_tree_path_free (path);              
                }
 
                /* Disable next */