From b7df74e8f5a7e6f948c63da3a7a3808fcc108935 Mon Sep 17 00:00:00 2001 From: wwp Date: Mon, 12 Dec 2016 15:17:15 +0100 Subject: [PATCH] Add new mark-all-unread (and recursively when relevant) action to folder context menu, message list and main window menu. --- src/folderutils.c | 66 ++++++++++++++++++++++++- src/folderutils.h | 2 + src/folderview.c | 121 +++++++++++++++++++++++++++++++++++++++------- src/mainwindow.c | 20 ++++++-- src/summaryview.c | 72 ++++++++++++++++----------- src/summaryview.h | 5 +- 6 files changed, 230 insertions(+), 56 deletions(-) diff --git a/src/folderutils.c b/src/folderutils.c index 0a272292f..939b0196e 100644 --- a/src/folderutils.c +++ b/src/folderutils.c @@ -132,7 +132,7 @@ void folderutils_mark_all_read(FolderItem *item) if (mainwin && mainwin->summaryview && mainwin->summaryview->folder_item == item) { debug_print("folder opened, using summary\n"); - summary_mark_all_read(mainwin->summaryview); + summary_mark_all_read(mainwin->summaryview, TRUE); } else { msglist = folder_item_get_msg_list(item); debug_print("got msglist %p\n", msglist); @@ -159,6 +159,46 @@ void folderutils_mark_all_read(FolderItem *item) folder_item_update_thaw(); } +void folderutils_mark_all_unread(FolderItem *item) +{ + MsgInfoList *msglist, *cur; + MainWindow *mainwin = mainwindow_get_mainwindow(); + int i = 0, m = 0; + debug_print("marking all unread in item %s\n", (item==NULL)?"NULL":item->name); + cm_return_if_fail(item != NULL); + + + folder_item_update_freeze(); + if (mainwin && mainwin->summaryview && + mainwin->summaryview->folder_item == item) { + debug_print("folder opened, using summary\n"); + summary_mark_all_read(mainwin->summaryview, FALSE); + } else { + msglist = folder_item_get_msg_list(item); + debug_print("got msglist %p\n", msglist); + if (msglist == NULL) { + folder_item_update_thaw(); + return; + } + folder_item_set_batch(item, TRUE); + for (cur = msglist; cur != NULL; cur = g_slist_next(cur)) { + MsgInfo *msginfo = cur->data; + + if (!(msginfo->flags.perm_flags & MSG_UNREAD)) { + procmsg_msginfo_set_flags(msginfo, MSG_UNREAD, 0); + m++; + } + i++; + procmsg_msginfo_free(&msginfo); + } + folder_item_set_batch(item, FALSE); + folder_item_close(item); + debug_print("marked %d messages out of %d as unread\n", m, i); + g_slist_free(msglist); + } + folder_item_update_thaw(); +} + void folderutils_mark_all_read_recursive(FolderItem *item) { GNode *node; @@ -182,3 +222,27 @@ void folderutils_mark_all_read_recursive(FolderItem *item) } } } + +void folderutils_mark_all_unread_recursive(FolderItem *item) +{ + GNode *node; + + cm_return_if_fail(item != NULL); + + folderutils_mark_all_unread(item); + + cm_return_if_fail(item->folder != NULL); + cm_return_if_fail(item->folder->node != NULL); + + node = item->folder->node; + node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item); + node = node->children; + + while (node != NULL) { + if (node->data != NULL) { + FolderItem *sub_item = (FolderItem *) node->data; + node = node->next; + folderutils_mark_all_unread_recursive(sub_item); + } + } +} diff --git a/src/folderutils.h b/src/folderutils.h index ca404c59d..64a5c2eae 100644 --- a/src/folderutils.h +++ b/src/folderutils.h @@ -30,6 +30,8 @@ typedef enum { gint folderutils_delete_duplicates(FolderItem *item, DeleteDuplicatesMode mode); void folderutils_mark_all_read (FolderItem *item); +void folderutils_mark_all_unread (FolderItem *item); void folderutils_mark_all_read_recursive (FolderItem *item); +void folderutils_mark_all_unread_recursive (FolderItem *item); #endif /* FOLDERUTILS_H */ diff --git a/src/folderview.c b/src/folderview.c index 8469ee9b2..3fe8ccc21 100644 --- a/src/folderview.c +++ b/src/folderview.c @@ -169,14 +169,19 @@ static void folderview_col_resized (GtkCMCList *clist, gint width, FolderView *folderview); -static void mark_all_read_handler (GtkAction *action, +static void mark_all_read_unread_handler (GtkAction *action, gpointer data, - gboolean recursive); + gboolean recursive, + gboolean read); static void mark_all_read_cb (GtkAction *action, gpointer data); +static void mark_all_unread_cb (GtkAction *action, + gpointer data); static void mark_all_read_recursive_cb (GtkAction *action, gpointer data); +static void mark_all_unread_recursive_cb (GtkAction *action, + gpointer data); static void folderview_empty_trash_cb (GtkAction *action, gpointer data); @@ -240,7 +245,9 @@ static GtkActionEntry folderview_common_popup_entries[] = { {"FolderViewPopup", NULL, "FolderViewPopup" }, {"FolderViewPopup/MarkAllRead", NULL, N_("Mark all re_ad"), NULL, NULL, G_CALLBACK(mark_all_read_cb) }, + {"FolderViewPopup/MarkAllUnread", NULL, N_("Mark all u_nread"), NULL, NULL, G_CALLBACK(mark_all_unread_cb) }, {"FolderViewPopup/MarkAllReadRec", NULL, N_("Mark all read recursi_vely"), NULL, NULL, G_CALLBACK(mark_all_read_recursive_cb) }, + {"FolderViewPopup/MarkAllUnreadRec", NULL, N_("Mark all unread recursi_vely"), NULL, NULL, G_CALLBACK(mark_all_unread_recursive_cb) }, {"FolderViewPopup/---", NULL, "---" }, {"FolderViewPopup/RunProcessing", NULL, N_("R_un processing rules"), NULL, NULL, G_CALLBACK(folderview_run_processing_cb) }, {"FolderViewPopup/SearchFolder", NULL, N_("_Search folder..."), NULL, NULL, G_CALLBACK(folderview_search_cb) }, @@ -825,33 +832,54 @@ void folderview_select(FolderView *folderview, FolderItem *item) static void mark_all_read_cb(GtkAction *action, gpointer data) { - mark_all_read_handler(action, data, FALSE); + mark_all_read_unread_handler(action, data, FALSE, TRUE); +} + +static void mark_all_unread_cb(GtkAction *action, gpointer data) +{ + mark_all_read_unread_handler(action, data, FALSE, FALSE); } static void mark_all_read_recursive_cb(GtkAction *action, gpointer data) { - mark_all_read_handler(action, data, TRUE); + mark_all_read_unread_handler(action, data, TRUE, TRUE); } -static void mark_all_read_handler(GtkAction *action, gpointer data, gboolean recursive) +static void mark_all_unread_recursive_cb(GtkAction *action, gpointer data) +{ + mark_all_read_unread_handler(action, data, TRUE, FALSE); +} + +static void mark_all_read_unread_handler(GtkAction *action, gpointer data, + gboolean recursive, gboolean read) { FolderView *folderview = (FolderView *)data; FolderItem *item; AlertValue val; gchar *message; + gchar *title; item = folderview_get_selected_item(folderview); if (item == NULL) return; - message = recursive? _("Do you really want to mark all mails in this " - "folder and its sub-folders as read?") : - _("Do you really want to mark all mails in this " - "folder as read?"); + if (read) { + title = _("Mark all as read"); + message = recursive? _("Do you really want to mark all mails in this " + "folder and its sub-folders as read?") : + _("Do you really want to mark all mails in this " + "folder as read?"); + } else { + title = _("Mark all as unread"); + message = recursive? _("Do you really want to mark all mails in this " + "folder and its sub-folders as unread?") : + _("Do you really want to mark all mails in this " + "folder as unread?"); + } if (folderview->summaryview->folder_item != item && prefs_common.ask_mark_all_read) { - val = alertpanel_full(_("Mark all as read"), - message, GTK_STOCK_NO, GTK_STOCK_YES, NULL, + val = alertpanel_full(title, message, + GTK_STOCK_NO, GTK_STOCK_YES, NULL, TRUE, NULL, ALERT_QUESTION, G_ALERTDEFAULT); if ((val & ~G_ALERTDISABLE) != G_ALERTALTERNATE) @@ -866,11 +894,17 @@ static void mark_all_read_handler(GtkAction *action, gpointer data, gboolean rec else summary_freeze(folderview->summaryview); - if (recursive) - folderutils_mark_all_read_recursive(item); - else - folderutils_mark_all_read(item); - + if (read) { + if (recursive) + folderutils_mark_all_read_recursive(item); + else + folderutils_mark_all_read(item); + } else { + if (recursive) + folderutils_mark_all_unread_recursive(item); + else + folderutils_mark_all_unread(item); + } if (folderview->summaryview->folder_item != item && !recursive) summary_unlock(folderview->summaryview); else @@ -1355,6 +1389,52 @@ static gboolean folderview_have_unread_children(FolderView *folderview, return folderview_have_unread_children_sub(folderview, item, FALSE); } +static gboolean folderview_have_read_children_sub(FolderView *folderview, + FolderItem *item, + gboolean in_sub) +{ + GNode *node = NULL; + + if (!item || !item->folder || !item->folder->node) { + return FALSE; + } + + node = item->folder->node; + + node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item); + node = node->children; + + if (in_sub && + (((item->total_msgs > 0) && + (item->unread_msgs != (item->total_msgs - item->ignored_msgs))))) { + return TRUE; + } + + while (node != NULL) { + if (node && node->data) { + FolderItem *next_item = (FolderItem*) node->data; + node = node->next; + if (folderview_have_read_children_sub(folderview, + next_item, + TRUE)) { + return TRUE; + } + } + } + +debug_print("-> false 2 %s\n", item->name); + return FALSE; +} + +static gboolean folderview_have_read_children(FolderView *folderview, + FolderItem *item) +{ +gboolean ret; + ret = folderview_have_read_children_sub(folderview, item, FALSE); +debug_print("-> %s 0 (%d)\n", ret?"true":"false", ret); + return ret; +} + static gboolean folderview_have_matching_children_sub(FolderView *folderview, FolderItem *item, gboolean in_sub) @@ -1874,7 +1954,9 @@ static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row, fpopup->add_menuitems(ui_manager, item); MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "MarkAllRead", "FolderViewPopup/MarkAllRead", GTK_UI_MANAGER_MENUITEM) + MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "MarkAllUnread", "FolderViewPopup/MarkAllUnread", GTK_UI_MANAGER_MENUITEM) MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "MarkAllReadRec", "FolderViewPopup/MarkAllReadRec", GTK_UI_MANAGER_MENUITEM) + MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "MarkAllUnreadRec", "FolderViewPopup/MarkAllUnreadRec", GTK_UI_MANAGER_MENUITEM) MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "Separator1", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR) MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "RunProcessing", "FolderViewPopup/RunProcessing", GTK_UI_MANAGER_MENUITEM) MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SearchFolder", "FolderViewPopup/SearchFolder", GTK_UI_MANAGER_MENUITEM) @@ -1904,9 +1986,12 @@ static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row, #define SET_SENS(name, sens) \ cm_menu_set_sensitive_full(ui_manager, "Popup/"name, sens) - SET_SENS("FolderViewPopup/MarkAllRead", item->unread_msgs >= 1); + SET_SENS("FolderViewPopup/MarkAllRead", item->unread_msgs > 0); + SET_SENS("FolderViewPopup/MarkAllUnread", (item->total_msgs > 0) && + (item->unread_msgs != (item->total_msgs - item->ignored_msgs))); SET_SENS("FolderViewPopup/MarkAllReadRec", folderview_have_unread_children(folderview,item)); - SET_SENS("FolderViewPopup/SearchFolder", item->total_msgs >= 1 && + SET_SENS("FolderViewPopup/MarkAllUnreadRec", folderview_have_read_children(folderview,item)); + SET_SENS("FolderViewPopup/SearchFolder", item->total_msgs > 0 && folderview->selected == folderview->opened); SET_SENS("FolderViewPopup/Properties", TRUE); diff --git a/src/mainwindow.c b/src/mainwindow.c index e03c55e2a..15004885a 100644 --- a/src/mainwindow.c +++ b/src/mainwindow.c @@ -231,6 +231,8 @@ static void mark_as_read_cb (GtkAction *action, gpointer data); static void mark_all_read_cb (GtkAction *action, gpointer data); +static void mark_all_unread_cb (GtkAction *action, + gpointer data); static void mark_as_spam_cb (GtkAction *action, gpointer data); static void mark_as_ham_cb (GtkAction *action, @@ -704,6 +706,7 @@ static GtkActionEntry mainwin_entries[] = {"Message/Mark/MarkRead", NULL, N_("Mark as rea_d"), NULL, NULL, G_CALLBACK(mark_as_read_cb) }, /* separation */ {"Message/Mark/MarkAllRead", NULL, N_("Mark all read"), NULL, NULL, G_CALLBACK(mark_all_read_cb) }, + {"Message/Mark/MarkAllUnread", NULL, N_("Mark all unread"), NULL, NULL, G_CALLBACK(mark_all_unread_cb) }, /* separation */ {"Message/Mark/IgnoreThread", NULL, N_("Ignore thread"), NULL, NULL, G_CALLBACK(ignore_thread_cb) }, {"Message/Mark/UnignoreThread", NULL, N_("Unignore thread"), NULL, NULL, G_CALLBACK(unignore_thread_cb) }, @@ -1788,6 +1791,7 @@ MainWindow *main_window_create() MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menu/Message/Mark", "MarkRead", "Message/Mark/MarkRead", GTK_UI_MANAGER_MENUITEM) MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menu/Message/Mark", "Separator2", "Message/Mark/---", GTK_UI_MANAGER_SEPARATOR) MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menu/Message/Mark", "MarkAllRead", "Message/Mark/MarkAllRead", GTK_UI_MANAGER_MENUITEM) + MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menu/Message/Mark", "MarkAllUnread", "Message/Mark/MarkAllUnread", GTK_UI_MANAGER_MENUITEM) MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menu/Message/Mark", "Separator3", "Message/Mark/---", GTK_UI_MANAGER_SEPARATOR) MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menu/Message/Mark", "IgnoreThread", "Message/Mark/IgnoreThread", GTK_UI_MANAGER_MENUITEM) MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menu/Message/Mark", "UnignoreThread", "Message/Mark/UnignoreThread", GTK_UI_MANAGER_MENUITEM) @@ -4461,22 +4465,28 @@ static void unmark_cb(GtkAction *action, gpointer data) summary_unmark(mainwin->summaryview); } -static void mark_as_unread_cb(GtkAction *action, gpointer data) +static void mark_as_read_cb(GtkAction *action, gpointer data) { MainWindow *mainwin = (MainWindow *)data; - summary_mark_as_unread(mainwin->summaryview); + summary_mark_as_read(mainwin->summaryview, TRUE); } -static void mark_as_read_cb(GtkAction *action, gpointer data) +static void mark_as_unread_cb(GtkAction *action, gpointer data) { MainWindow *mainwin = (MainWindow *)data; - summary_mark_as_read(mainwin->summaryview); + summary_mark_as_read(mainwin->summaryview, FALSE); } static void mark_all_read_cb(GtkAction *action, gpointer data) { MainWindow *mainwin = (MainWindow *)data; - summary_mark_all_read(mainwin->summaryview); + summary_mark_all_read(mainwin->summaryview, TRUE); +} + +static void mark_all_unread_cb(GtkAction *action, gpointer data) +{ + MainWindow *mainwin = (MainWindow *)data; + summary_mark_all_read(mainwin->summaryview, FALSE); } static void mark_as_spam_cb(GtkAction *action, gpointer data) diff --git a/src/summaryview.c b/src/summaryview.c index f1353249c..4739b66c2 100644 --- a/src/summaryview.c +++ b/src/summaryview.c @@ -4025,7 +4025,25 @@ static void summary_mark_row_as_read(SummaryView *summaryview, msginfo->msgnum); } -void summary_mark_as_read(SummaryView *summaryview) +static void summary_mark_row_as_unread(SummaryView *summaryview, + GtkCMCTreeNode *row) +{ + GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree); + MsgInfo *msginfo; + + msginfo = gtk_cmctree_node_get_row_data(ctree, row); + cm_return_if_fail(msginfo); + + if(MSG_IS_NEW(msginfo->flags) || MSG_IS_UNREAD(msginfo->flags)) + return; + + summary_msginfo_set_flags(msginfo, MSG_UNREAD, 0); + summary_set_row_marks(summaryview, row); + debug_print("Message %d is marked as unread\n", + msginfo->msgnum); +} + +void summary_mark_as_read(SummaryView *summaryview, gboolean read) { GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree); GList *cur; @@ -4036,8 +4054,12 @@ void summary_mark_as_read(SummaryView *summaryview) START_LONG_OPERATION(summaryview, FALSE); folder_item_set_batch(summaryview->folder_item, TRUE); for (cur = GTK_CMCLIST(ctree)->selection; cur != NULL && cur->data != NULL; cur = cur->next) - summary_mark_row_as_read(summaryview, - GTK_CMCTREE_NODE(cur->data)); + if (read) + summary_mark_row_as_read(summaryview, + GTK_CMCTREE_NODE(cur->data)); + else + summary_mark_row_as_unread(summaryview, + GTK_CMCTREE_NODE(cur->data)); folder_item_set_batch(summaryview->folder_item, FALSE); END_LONG_OPERATION(summaryview); @@ -4078,17 +4100,26 @@ void summary_msgs_unlock(SummaryView *summaryview) summary_status_show(summaryview); } -void summary_mark_all_read(SummaryView *summaryview) +void summary_mark_all_read(SummaryView *summaryview, gboolean read) { GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree); GtkCMCTreeNode *node; AlertValue val; gboolean froze = FALSE; + gchar *message; + gchar *title; + + if (read) { + title = _("Mark all as read"); + message = _("Do you really want to mark all mails in this folder as read?"); + } else { + title = _("Mark all as unread"); + message = _("Do you really want to mark all mails in this folder as unread?"); + } if (prefs_common.ask_mark_all_read) { - val = alertpanel_full(_("Mark all as read"), - _("Do you really want to mark all mails in this " - "folder as read?"), GTK_STOCK_NO, GTK_STOCK_YES, NULL, + val = alertpanel_full(title, message, + GTK_STOCK_NO, GTK_STOCK_YES, NULL, TRUE, NULL, ALERT_QUESTION, G_ALERTDEFAULT); if ((val & ~G_ALERTDISABLE) != G_ALERTALTERNATE) @@ -4103,7 +4134,10 @@ void summary_mark_all_read(SummaryView *summaryview) folder_item_set_batch(summaryview->folder_item, TRUE); for (node = GTK_CMCTREE_NODE(GTK_CMCLIST(ctree)->row_list); node != NULL; node = gtkut_ctree_node_next(ctree, node)) - summary_mark_row_as_read(summaryview, node); + if (read) + summary_mark_row_as_read(summaryview, node); + else + summary_mark_row_as_unread(summaryview, node); folder_item_set_batch(summaryview->folder_item, FALSE); for (node = GTK_CMCTREE_NODE(GTK_CMCLIST(ctree)->row_list); node != NULL; node = gtkut_ctree_node_next(ctree, node)) { @@ -4183,27 +4217,6 @@ void summary_mark_as_spam(SummaryView *summaryview, guint action, GtkWidget *wid } -static void summary_mark_row_as_unread(SummaryView *summaryview, - GtkCMCTreeNode *row) -{ - GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree); - MsgInfo *msginfo; - - msginfo = gtk_cmctree_node_get_row_data(ctree, row); - cm_return_if_fail(msginfo); - if (MSG_IS_DELETED(msginfo->flags)) { - procmsg_msginfo_set_to_folder(msginfo, NULL); - summary_msginfo_unset_flags(msginfo, MSG_DELETED, 0); - summaryview->deleted--; - } - - summary_msginfo_set_flags(msginfo, MSG_UNREAD, 0); - debug_print("Message %d is marked as unread\n", - msginfo->msgnum); - - summary_set_row_marks(summaryview, row); -} - void summary_mark_as_unread(SummaryView *summaryview) { GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree); @@ -7750,6 +7763,7 @@ void summary_toggle_watch_thread(SummaryView *summaryview) summary_watch_thread(summaryview); } + void summary_toggle_show_read_messages(SummaryView *summaryview) { FolderItemUpdateData source; diff --git a/src/summaryview.h b/src/summaryview.h index ba24099d5..dee8068f2 100644 --- a/src/summaryview.h +++ b/src/summaryview.h @@ -272,11 +272,10 @@ void summary_save_as (SummaryView *summaryview); void summary_print (SummaryView *summaryview); void summary_mark (SummaryView *summaryview); void summary_unmark (SummaryView *summaryview); -void summary_mark_as_unread (SummaryView *summaryview); -void summary_mark_as_read (SummaryView *summaryview); +void summary_mark_as_read (SummaryView *summaryview, gboolean); void summary_msgs_lock (SummaryView *summaryview); void summary_msgs_unlock (SummaryView *summaryview); -void summary_mark_all_read (SummaryView *summaryview); +void summary_mark_all_read (SummaryView *summaryview, gboolean); void summary_mark_as_spam (SummaryView *summaryview, guint action, GtkWidget *widget); -- 2.25.1