Fix bug #3881: Keep read thread during update if it is selected.
[claws.git] / src / summaryview.c
index 5fa3e7fd8573f350a754b3782997690e3c3bf810..8335ed94fe49ebe919ababd6f731bcf83fedb956 100644 (file)
@@ -163,7 +163,8 @@ static void summary_update_status   (SummaryView            *summaryview);
 static void summary_status_show                (SummaryView            *summaryview);
 static void summary_set_column_titles  (SummaryView            *summaryview);
 static void summary_set_ctree_from_list        (SummaryView            *summaryview,
-                                        GSList                 *mlist);
+                                        GSList                 *mlist,
+                                        guint                  selected_msgnum);
 static inline void summary_set_header  (SummaryView            *summaryview,
                                         gchar                  *text[],
                                         MsgInfo                *msginfo);
@@ -342,8 +343,8 @@ static gboolean summary_drag_motion_cb(GtkWidget      *widget,
 static void summary_drag_end(GtkWidget *widget,
                                          GdkDragContext *drag_context,
                                          SummaryView    *summaryview);
-/* custom compare functions for sorting */
 
+/* custom compare functions for sorting */
 static gint summary_cmp_by_mark                (GtkCMCList             *clist,
                                         gconstpointer           ptr1,
                                         gconstpointer           ptr2);
@@ -1447,7 +1448,7 @@ gboolean summary_show(SummaryView *summaryview, FolderItem *item)
 
        /* set ctree and hash table from the msginfo list, and
           create the thread */
-       summary_set_ctree_from_list(summaryview, mlist);
+       summary_set_ctree_from_list(summaryview, mlist, selected_msgnum);
 
        g_slist_free(mlist);
 
@@ -1459,7 +1460,14 @@ gboolean summary_show(SummaryView *summaryview, FolderItem *item)
                        if (!summaryview->displayed)
                                messageview_clear(summaryview->messageview);
                        summary_unlock(summaryview);
-                       summary_select_by_msgnum(summaryview, selected_msgnum);
+
+                       if (quicksearch_is_running(summaryview->quicksearch))
+                               summary_select_by_msgnum(summaryview, selected_msgnum,
+                                               OPEN_SELECTED_ON_SEARCH_RESULTS);
+                       else
+                               summary_select_by_msgnum(summaryview, selected_msgnum,
+                                               OPEN_SELECTED_ON_FOLDER_OPEN);
+
                        summary_lock(summaryview);
                        if (!summaryview->selected) {
                                /* no selected message - select first unread
@@ -1472,7 +1480,14 @@ gboolean summary_show(SummaryView *summaryview, FolderItem *item)
                                                 item->sort_type == SORT_DESCENDING
                                                 ? 0 : GTK_CMCLIST(ctree)->rows - 1);
                                summary_unlock(summaryview);
-                               summary_select_node(summaryview, node, 0);
+
+                               if (quicksearch_is_running(summaryview->quicksearch))
+                                       summary_select_node(summaryview, node,
+                                                       OPEN_SELECTED_ON_SEARCH_RESULTS);
+                               else
+                                       summary_select_node(summaryview, node,
+                                                       OPEN_SELECTED_ON_FOLDER_OPEN);
+
                                summary_lock(summaryview);
                        }
                } else {
@@ -1482,7 +1497,7 @@ gboolean summary_show(SummaryView *summaryview, FolderItem *item)
                                        (ctree,
                                         item->sort_type == SORT_DESCENDING
                                         ? 0 : GTK_CMCLIST(ctree)->rows - 1);
-                       summary_select_node(summaryview, node, -1);
+                       summary_select_node(summaryview, node, OPEN_SELECTED_ON_SEARCH_RESULTS);
                }
        } else {
                /* backward compat */
@@ -1504,15 +1519,27 @@ gboolean summary_show(SummaryView *summaryview, FolderItem *item)
                        
                        switch(act) {
                        case ACTION_MARKED:
-                               node = summary_find_next_flagged_msg(summaryview, NULL,
+                               if (summaryview->sort_type == SORT_ASCENDING)
+                                       node = summary_find_next_flagged_msg(summaryview, NULL,
+                                            MSG_MARKED, FALSE);
+                               else
+                                       node = summary_find_prev_flagged_msg(summaryview, NULL,
                                             MSG_MARKED, FALSE);
                                break;
                        case ACTION_NEW:
-                               node = summary_find_next_flagged_msg(summaryview, NULL,
+                               if (summaryview->sort_type == SORT_ASCENDING)
+                                       node = summary_find_next_flagged_msg(summaryview, NULL,
+                                            MSG_NEW, FALSE);
+                               else
+                                       node = summary_find_prev_flagged_msg(summaryview, NULL,
                                             MSG_NEW, FALSE);
                                break;
                        case ACTION_UNREAD:
-                               node = summary_find_next_flagged_msg(summaryview, NULL,
+                               if (summaryview->sort_type == SORT_ASCENDING)
+                                       node = summary_find_next_flagged_msg(summaryview, NULL,
+                                            MSG_UNREAD, FALSE);
+                               else
+                                       node = summary_find_prev_flagged_msg(summaryview, NULL,
                                             MSG_UNREAD, FALSE);
                                break;
                        case ACTION_LAST_OPENED:
@@ -1553,12 +1580,12 @@ gboolean summary_show(SummaryView *summaryview, FolderItem *item)
                if (node) {
                        gint open_selected = -1;
                        if (!is_refresh) {
-                               if (prefs_common.open_selected_on_folder_open)
+                               if (OPEN_SELECTED_ON_FOLDER_OPEN)
                                        open_selected = 1;
                                else
                                        open_selected = 0;
                        }
-                       summary_select_node_no_mark_read(summaryview, node, open_selected);
+                       summary_select_node(summaryview, node, open_selected);
                }
 
                summary_lock(summaryview);
@@ -1820,7 +1847,7 @@ void summary_select_prev(SummaryView *summaryview)
                node = gtkut_ctree_node_next(ctree, node);
 
        if (node && node != summaryview->selected)
-               summary_select_node(summaryview, node, -1);
+               summary_select_node(summaryview, node, OPEN_SELECTED_ON_PREVNEXT);
 }
 
 void summary_select_next(SummaryView *summaryview)
@@ -1834,7 +1861,7 @@ void summary_select_next(SummaryView *summaryview)
                node = gtkut_ctree_node_prev(ctree, node);
 
        if (node && node != summaryview->selected)
-               summary_select_node(summaryview, node, -1);
+               summary_select_node(summaryview, node, OPEN_SELECTED_ON_PREVNEXT);
 }
 
 void summary_select_prev_unread(SummaryView *summaryview)
@@ -1880,7 +1907,7 @@ void summary_select_prev_unread(SummaryView *summaryview)
        if (!node)
                alertpanel_notice(_("No unread messages."));
        else
-               summary_select_node(summaryview, node, -1);
+               summary_select_node(summaryview, node, OPEN_SELECTED_ON_PREVNEXT);
 }
 
 void summary_select_next_unread(SummaryView *summaryview)
@@ -1895,7 +1922,7 @@ void summary_select_next_unread(SummaryView *summaryview)
                        (summaryview, node, MSG_UNREAD, TRUE);
        
        if (node)
-               summary_select_node(summaryview, node, -1);
+               summary_select_node(summaryview, node, OPEN_SELECTED_ON_PREVNEXT);
        else {
                AlertValue val = 0;
 
@@ -1965,7 +1992,7 @@ void summary_select_prev_new(SummaryView *summaryview)
        if (!node)
                alertpanel_notice(_("No new messages."));
        else
-               summary_select_node(summaryview, node, -1);
+               summary_select_node(summaryview, node, OPEN_SELECTED_ON_PREVNEXT);
 }
 
 void summary_select_next_new(SummaryView *summaryview)
@@ -1980,7 +2007,7 @@ void summary_select_next_new(SummaryView *summaryview)
                        (summaryview, node, MSG_NEW, TRUE);
        
        if (node)
-               summary_select_node(summaryview, node, -1);
+               summary_select_node(summaryview, node, OPEN_SELECTED_ON_PREVNEXT);
        else {
                AlertValue val = 0;
 
@@ -2032,7 +2059,7 @@ void summary_select_prev_marked(SummaryView *summaryview)
        if (!node)
                alertpanel_notice(_("No marked messages."));
        else
-               summary_select_node(summaryview, node, -1);
+               summary_select_node(summaryview, node, OPEN_SELECTED_ON_PREVNEXT);
 }
 
 void summary_select_next_marked(SummaryView *summaryview)
@@ -2047,7 +2074,7 @@ void summary_select_next_marked(SummaryView *summaryview)
                        (summaryview, node, MSG_MARKED, TRUE);
        
        if (node)
-               summary_select_node(summaryview, node, -1);
+               summary_select_node(summaryview, node, OPEN_SELECTED_ON_PREVNEXT);
        else {
                AlertValue val = 0;
 
@@ -2099,7 +2126,7 @@ void summary_select_prev_labeled(SummaryView *summaryview)
        if (!node)
                alertpanel_notice(_("No labeled messages."));
        else
-               summary_select_node(summaryview, node, -1);
+               summary_select_node(summaryview, node, OPEN_SELECTED_ON_PREVNEXT);
 }
 
 void summary_select_next_labeled(SummaryView *summaryview)
@@ -2132,7 +2159,7 @@ void summary_select_next_labeled(SummaryView *summaryview)
        if (!node)
                alertpanel_notice(_("No labeled messages."));
        else
-               summary_select_node(summaryview, node, -1);
+               summary_select_node(summaryview, node, OPEN_SELECTED_ON_PREVNEXT);
 }
 
 void summary_select_parent(SummaryView *summaryview)
@@ -2142,23 +2169,16 @@ void summary_select_parent(SummaryView *summaryview)
        if (summaryview->selected)
                node = GTK_CMCTREE_ROW(summaryview->selected)->parent;
        if (node)
-               summary_select_node(summaryview, node, -1);
-}
-
-void summary_select_by_msgnum(SummaryView *summaryview, guint msgnum)
-{
-       GtkCMCTreeNode *node;
-
-       node = summary_find_msg_by_msgnum(summaryview, msgnum);
-       summary_select_node(summaryview, node, 0);
+               summary_select_node(summaryview, node, OPEN_SELECTED_ON_PREVNEXT);
 }
 
-void summary_display_by_msgnum(SummaryView *summaryview, guint msgnum)
+void summary_select_by_msgnum(SummaryView *summaryview, guint msgnum,
+               gboolean show)
 {
        GtkCMCTreeNode *node;
 
        node = summary_find_msg_by_msgnum(summaryview, msgnum);
-       summary_select_node(summaryview, node, 1);
+       summary_select_node(summaryview, node, show);
 }
 
 void summary_select_by_msg_list(SummaryView    *summaryview, GSList *msginfos)
@@ -2210,40 +2230,21 @@ static gboolean summary_select_retry(void *data)
  * summary_select_node:
  * @summaryview: Summary view.
  * @node: Summary tree node.
- * @force_display: -1 unset, 0 don't show the msg, 1 show the msg.
+ * @display_msg: whether to also display the message
  *
  * Select @node (bringing it into view by scrolling and expanding its
- * thread, if necessary) and unselect all others.  If @force_display is
- * 1, display the corresponding message in the message view, if
- * @force_display is -1, obey prefs_common.always_show_msg.
+ * thread, if necessary) and unselect all others.
  **/
-static void summary_select_node_real(SummaryView *summaryview, GtkCMCTreeNode *node,
-                        gint force_display, gboolean ignore_mark_read);
 
 void summary_select_node(SummaryView *summaryview, GtkCMCTreeNode *node,
-                        gint force_display)
-{
-       summary_select_node_real(summaryview, node, force_display, FALSE);
-
-}
-
-void summary_select_node_no_mark_read(SummaryView *summaryview, GtkCMCTreeNode *node,
-                        gint force_display, gboolean ignore_mark_read)
-{
-       summary_select_node_real(summaryview, node, force_display, TRUE);
-
-}
-
-static void summary_select_node_real(SummaryView *summaryview, GtkCMCTreeNode *node,
-                        gint force_display, gboolean ignore_mark_read)
+                        gboolean display_msg)
 {
        GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
-       gboolean display_msg;
-       
-       display_msg = force_display > -1? force_display :
-               (prefs_common.always_show_msg == OPENMSG_YES) ||
-               ((prefs_common.always_show_msg == OPENMSG_WHEN_VIEW_VISIBLE &&
-                               messageview_is_visible(summaryview->messageview)));
+
+       /* If msgview is hidden, we never want to automatically display
+        * a selected message, since that would unhide the msgview. */
+       if (!messageview_is_visible(summaryview->messageview))
+               display_msg = FALSE;
 
        if (summary_is_locked(summaryview)
        && !GTK_SCTREE(ctree)->selecting_range
@@ -2268,8 +2269,6 @@ static void summary_select_node_real(SummaryView *summaryview, GtkCMCTreeNode *n
        if (!summaryview->folder_item)
                return;
        if (node) {
-               if (!ignore_mark_read)
-                       summary_cancel_mark_read_timeout(summaryview);
                gtkut_ctree_expand_parent_all(ctree, node);
 
                summary_lock(summaryview);
@@ -3092,6 +3091,35 @@ static gboolean summary_thread_is_read(GNode *gnode)
     return all_read;
 }
 
+typedef struct  _ThreadSelectedData {
+       guint msgnum;
+       gboolean is_selected;
+} ThreadSelectedData;
+
+static gboolean summary_update_is_selected(GNode *gnode, gpointer data)
+{
+       ThreadSelectedData *selected = (ThreadSelectedData *)data;
+       MsgInfo *msginfo = (MsgInfo *)gnode->data;
+
+       if (msginfo->msgnum == selected->msgnum) {
+               selected->is_selected = TRUE;
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
+static gboolean summary_thread_is_selected(GNode *gnode, guint selected_msgnum)
+{
+       ThreadSelectedData selected;
+
+       selected.msgnum = selected_msgnum;
+       selected.is_selected = FALSE;
+       g_node_traverse(gnode, G_IN_ORDER, G_TRAVERSE_ALL, -1,
+                       summary_update_is_selected, &selected);
+       return selected.is_selected;
+}
+
 static gboolean summary_insert_gnode_func(GtkCMCTree *ctree, guint depth, GNode *gnode,
                                   GtkCMCTreeNode *cnode, gpointer data)
 {
@@ -3143,7 +3171,7 @@ static gboolean summary_insert_gnode_func(GtkCMCTree *ctree, guint depth, GNode
 }
 
 static void summary_set_ctree_from_list(SummaryView *summaryview,
-                                       GSList *mlist)
+                                       GSList *mlist, guint selected_msgnum)
 {
        GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
        MsgInfo *msginfo;
@@ -3186,14 +3214,14 @@ static void summary_set_ctree_from_list(SummaryView *summaryview,
                
                for (gnode = root->children; gnode != NULL;
                     gnode = gnode->next) {
-            if (!summaryview->folder_item->hide_read_threads ||
-                    !summary_thread_is_read(gnode))
-            {
-                summary_find_thread_age(gnode);
-                node = gtk_sctree_insert_gnode
-                    (ctree, NULL, node, gnode,
-                     summary_insert_gnode_func, summaryview);
-            }
+                       if (!summaryview->folder_item->hide_read_threads ||
+                           !summary_thread_is_read(gnode) ||
+                           summary_thread_is_selected(gnode, selected_msgnum)) {
+                               summary_find_thread_age(gnode);
+                               node = gtk_sctree_insert_gnode
+                                       (ctree, NULL, node, gnode,
+                                        summary_insert_gnode_func, summaryview);
+                       }
                }
 
                g_node_destroy(root);
@@ -4190,7 +4218,7 @@ void summary_mark_all_unread(SummaryView *summaryview, gboolean ask_if_needed)
        /* ask_if_needed is FALSE when user-asking is performed by caller,
           commonly when the caller is a mark-as-unread-recursive func */
        if (ask_if_needed && prefs_common.ask_mark_all_read) {
-               val = alertpanel_full(_("FOO Mark all as unread"),
+               val = alertpanel_full(_("Mark all as unread"),
                          _("Do you really want to mark all mails in this folder as unread?"),
                          GTK_STOCK_NO, GTK_STOCK_YES, NULL,
                          TRUE, NULL, ALERT_QUESTION, G_ALERTDEFAULT);
@@ -4458,7 +4486,7 @@ void summary_delete(SummaryView *summaryview)
                if (!node || prefs_common.next_on_delete == FALSE)
                        node = summary_find_next_msg(summaryview, sel_last,TRUE);
        }
-       summary_select_node(summaryview, node, -1);
+       summary_select_node(summaryview, node, OPEN_SELECTED_ON_DELETEMOVE);
        
        if (prefs_common.immediate_exec || folder_has_parent_of_type(item, F_TRASH)) {
                summary_execute(summaryview);
@@ -4615,7 +4643,7 @@ void summary_move_selected_to(SummaryView *summaryview, FolderItem *to_folder)
                        if (!node || prefs_common.next_on_delete == FALSE)
                                node = summary_find_next_msg(summaryview, sel_last,TRUE);
                }
-               summary_select_node(summaryview, node, -1);
+               summary_select_node(summaryview, node, OPEN_SELECTED_ON_DELETEMOVE);
                summary_status_show(summaryview);
        }
        
@@ -4623,7 +4651,7 @@ void summary_move_selected_to(SummaryView *summaryview, FolderItem *to_folder)
                GtkCMCTreeNode *node = gtk_cmctree_node_nth (GTK_CMCTREE(summaryview->ctree), 
                                                         GTK_CMCLIST(summaryview->ctree)->rows - 1);
                if (node)
-                       summary_select_node(summaryview, node, -1);
+                       summary_select_node(summaryview, node, OPEN_SELECTED_ON_DELETEMOVE);
        }
 
 }
@@ -4635,7 +4663,12 @@ void summary_move_to(SummaryView *summaryview)
        if (!summaryview->folder_item ||
            FOLDER_TYPE(summaryview->folder_item->folder) == F_NEWS) return;
 
-       to_folder = foldersel_folder_sel(NULL, FOLDER_SEL_MOVE, NULL, FALSE);
+       to_folder = foldersel_folder_sel(NULL, FOLDER_SEL_MOVE, NULL, FALSE,
+                       ngettext(
+                               "Select folder to move selected message to",
+                               "Select folder to move selected messages to",
+                               g_list_length(GTK_CMCLIST(summaryview->ctree)->selection))
+       );
        summary_move_selected_to(summaryview, to_folder);
 }
 
@@ -4715,7 +4748,12 @@ void summary_copy_to(SummaryView *summaryview)
 
        if (!summaryview->folder_item) return;
 
-       to_folder = foldersel_folder_sel(NULL, FOLDER_SEL_COPY, NULL, FALSE);
+       to_folder = foldersel_folder_sel(NULL, FOLDER_SEL_COPY, NULL, FALSE,
+                       ngettext(
+                               "Select folder to copy selected message to",
+                               "Select folder to copy selected messages to",
+                               g_list_length(GTK_CMCLIST(summaryview->ctree)->selection))
+       );
        summary_copy_selected_to(summaryview, to_folder);
 }
 
@@ -4994,7 +5032,7 @@ gboolean summary_execute(SummaryView *summaryview)
 
        if (new_selected) {
                summary_unlock(summaryview);
-               summary_select_node(summaryview, new_selected, -1);
+               summary_select_node(summaryview, new_selected, OPEN_SELECTED_ON_DELETEMOVE);
                summary_lock(summaryview);
        }
 
@@ -5094,7 +5132,7 @@ gboolean summary_expunge(SummaryView *summaryview)
 
        if (new_selected) {
                summary_unlock(summaryview);
-               summary_select_node(summaryview, new_selected, -1);
+               summary_select_node(summaryview, new_selected, OPEN_SELECTED_ON_DELETEMOVE);
                summary_lock(summaryview);
        }
 
@@ -5550,7 +5588,7 @@ void summary_collapse_threads(SummaryView *summaryview)
        while (node && GTK_CMCTREE_ROW(node)->parent) {
                focus_node = node = GTK_CMCTREE_ROW(node)->parent;
        }
-       summary_select_node(summaryview, node, -1);
+       summary_select_node(summaryview, node, OPEN_SELECTED_ON_DIRECTIONAL);
        node = GTK_CMCTREE_NODE(GTK_CMCLIST(ctree)->row_list);
        while (node) {
                if (GTK_CMCTREE_ROW(node)->children) {
@@ -6609,7 +6647,7 @@ void summary_set_column_order(SummaryView *summaryview)
 
        summary_show(summaryview, item);
 
-       summary_select_by_msgnum(summaryview, selected_msgnum);
+       summary_select_by_msgnum(summaryview, selected_msgnum, FALSE);
 
        summaryview->selected = summary_find_msg_by_msgnum(summaryview, selected_msgnum);
        summaryview->displayed = summary_find_msg_by_msgnum(summaryview, displayed_msgnum);
@@ -6831,7 +6869,7 @@ static gboolean summary_key_pressed(GtkWidget *widget, GdkEventKey *event,
                                if (gtk_cmctree_node_is_visible(GTK_CMCTREE(ctree), next) != GTK_VISIBILITY_FULL)
                                        gtkut_ctree_node_move_if_on_the_edge(GTK_CMCTREE(ctree), next, -1);
                                if (!mod_pressed)
-                                       summary_select_node(summaryview, summaryview->selected, -1);
+                                       summary_select_node(summaryview, summaryview->selected, OPEN_SELECTED_ON_DIRECTIONAL);
                                summaryview->selected = next;
                        }
                }
@@ -7103,6 +7141,19 @@ GSList *summary_get_selection(SummaryView *summaryview)
        return g_slist_reverse(msginfo_list);
 }
 
+/*
+ * \brief get number of messages currently selected in SummaryView
+ *
+ * \param summaryview
+ *
+ * \return number of messages currently selected
+ */
+guint summary_get_selection_count(SummaryView *summaryview)
+{
+       cm_return_val_if_fail(summaryview != NULL, 0);
+       return g_list_length(GTK_CMCLIST(summaryview->ctree)->selection);
+}
+
 static void summary_sort_by_column_click(SummaryView *summaryview,
                                         FolderSortKey sort_key)
 {
@@ -8099,7 +8150,8 @@ static gboolean summary_update_folder_item_hook(gpointer source, gpointer data)
        cm_return_val_if_fail(hookdata->item != NULL, FALSE);
        cm_return_val_if_fail(summaryview != NULL, FALSE);
 
-       if (hookdata->update_flags & F_ITEM_UPDATE_NAME) {
+       if (hookdata->item == summaryview->folder_item &&
+           hookdata->update_flags & F_ITEM_UPDATE_NAME) {
                gchar *name = folder_item_get_name(hookdata->item);
                gtk_label_set_text(GTK_LABEL(summaryview->statlabel_folder), name);
                g_free(name);
@@ -8157,7 +8209,7 @@ static void summary_find_answers (SummaryView *summaryview, MsgInfo *msg)
 
        node = gtk_cmctree_node_nth(GTK_CMCTREE(summaryview->ctree), 0);
        if (node)
-               summary_select_node(summaryview, node, 1);
+               summary_select_node(summaryview, node, OPEN_SELECTED_ON_SEARCH_RESULTS);
 }
 
 gint summaryview_export_mbox_list(SummaryView *summaryview)