a73b1eec22
message_actions_execute() eventually calls summary_show() to redisplay current folder in summaryview. This causes a summary_clear(), which frees all MsgInfos from the local linked list in mainwin_actions_execute(). This list is then used to restore summaryview selection, but at this point, all its members point to already freed memory. We solve this by increasing each MsgInfo's reference count, so that they do not get freed, and we free them after we're done with them. Note: procmsg_msginfo_free() should probably be renamed to procmsg_msginfo_unref()
8555 lines
261 KiB
C
8555 lines
261 KiB
C
/*
|
|
* Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
|
|
* Copyright (C) 1999-2016 Hiroyuki Yamamoto and the Claws Mail team
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "defs.h"
|
|
|
|
#include <glib.h>
|
|
#include <glib/gi18n.h>
|
|
#include <gdk/gdkkeysyms.h>
|
|
#include <gtk/gtk.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
|
|
#include "main.h"
|
|
#include "menu.h"
|
|
#include "mbox.h"
|
|
#include "mainwindow.h"
|
|
#include "folderview.h"
|
|
#include "summaryview.h"
|
|
#include "messageview.h"
|
|
#include "mimeview.h"
|
|
#include "foldersel.h"
|
|
#include "procmsg.h"
|
|
#include "procheader.h"
|
|
#include "sourcewindow.h"
|
|
#include "prefs_common.h"
|
|
#include "prefs_summary_column.h"
|
|
#include "prefs_summary_open.h"
|
|
#include "prefs_filtering.h"
|
|
#include "account.h"
|
|
#include "compose.h"
|
|
#include "file-utils.h"
|
|
#include "utils.h"
|
|
#include "gtkutils.h"
|
|
#include "stock_pixmap.h"
|
|
#include "filesel.h"
|
|
#include "alertpanel.h"
|
|
#include "inputdialog.h"
|
|
#include "statusbar.h"
|
|
#include "folder.h"
|
|
#include "colorlabel.h"
|
|
#include "inc.h"
|
|
#include "imap.h"
|
|
#ifndef USE_ALT_ADDRBOOK
|
|
#include "addressbook.h"
|
|
#else
|
|
#include "addressbook-dbus.h"
|
|
#include "addressadd.h"
|
|
#endif
|
|
#include "addr_compl.h"
|
|
#include "folder_item_prefs.h"
|
|
#include "filtering.h"
|
|
#include "string_match.h"
|
|
#include "toolbar.h"
|
|
#include "news.h"
|
|
#include "hooks.h"
|
|
#include "description_window.h"
|
|
#include "folderutils.h"
|
|
#include "quicksearch.h"
|
|
#include "partial_download.h"
|
|
#include "tags.h"
|
|
#include "timing.h"
|
|
#include "log.h"
|
|
#include "edittags.h"
|
|
#include "manual.h"
|
|
#include "manage_window.h"
|
|
#include "avatars.h"
|
|
|
|
#define SUMMARY_COL_MARK_WIDTH 10
|
|
#define SUMMARY_COL_STATUS_WIDTH 13
|
|
#define SUMMARY_COL_LOCKED_WIDTH 13
|
|
#define SUMMARY_COL_MIME_WIDTH 11
|
|
|
|
static int normal_row_height = -1;
|
|
static GtkStyle *bold_style;
|
|
|
|
static GdkPixbuf *markxpm;
|
|
static GdkPixbuf *deletedxpm;
|
|
static GdkPixbuf *movedxpm;
|
|
static GdkPixbuf *copiedxpm;
|
|
|
|
static GdkPixbuf *newxpm;
|
|
static GdkPixbuf *unreadxpm;
|
|
static GdkPixbuf *repliedxpm;
|
|
static GdkPixbuf *forwardedxpm;
|
|
static GdkPixbuf *repliedandforwardedxpm;
|
|
static GdkPixbuf *ignorethreadxpm;
|
|
static GdkPixbuf *watchthreadxpm;
|
|
static GdkPixbuf *lockedxpm;
|
|
static GdkPixbuf *spamxpm;
|
|
|
|
static GdkPixbuf *clipxpm;
|
|
static GdkPixbuf *keyxpm;
|
|
static GdkPixbuf *clipkeyxpm;
|
|
static GdkPixbuf *keysignxpm;
|
|
static GdkPixbuf *gpgsignedxpm;
|
|
static GdkPixbuf *clipgpgsignedxpm;
|
|
|
|
static void summary_free_msginfo_func (GtkCMCTree *ctree,
|
|
GtkCMCTreeNode *node,
|
|
gpointer data);
|
|
static void summary_set_marks_func (GtkCMCTree *ctree,
|
|
GtkCMCTreeNode *node,
|
|
gpointer data);
|
|
|
|
void summary_set_menu_sensitive (SummaryView *summaryview);
|
|
guint summary_get_msgnum (SummaryView *summaryview,
|
|
GtkCMCTreeNode *node);
|
|
|
|
|
|
static void summary_set_hide_menu (SummaryView *summaryview,
|
|
const gchar *menu_item,
|
|
guint action);
|
|
|
|
static GtkCMCTreeNode *summary_find_prev_msg
|
|
(SummaryView *summaryview,
|
|
GtkCMCTreeNode *current_node,
|
|
gboolean start_from_prev);
|
|
static GtkCMCTreeNode *summary_find_next_msg
|
|
(SummaryView *summaryview,
|
|
GtkCMCTreeNode *current_node,
|
|
gboolean start_from_next);
|
|
|
|
static GtkCMCTreeNode *summary_find_prev_flagged_msg
|
|
(SummaryView *summaryview,
|
|
GtkCMCTreeNode *current_node,
|
|
MsgPermFlags flags,
|
|
gboolean start_from_prev);
|
|
static GtkCMCTreeNode *summary_find_next_flagged_msg
|
|
(SummaryView *summaryview,
|
|
GtkCMCTreeNode *current_node,
|
|
MsgPermFlags flags,
|
|
gboolean start_from_next);
|
|
|
|
static GtkCMCTreeNode *summary_find_msg_by_msgnum
|
|
(SummaryView *summaryview,
|
|
guint msgnum);
|
|
|
|
static void summary_update_status (SummaryView *summaryview);
|
|
|
|
/* display functions */
|
|
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,
|
|
guint selected_msgnum);
|
|
static inline void summary_set_header (SummaryView *summaryview,
|
|
gchar *text[],
|
|
MsgInfo *msginfo);
|
|
static void summary_display_msg (SummaryView *summaryview,
|
|
GtkCMCTreeNode *row);
|
|
static void summary_display_msg_full (SummaryView *summaryview,
|
|
GtkCMCTreeNode *row,
|
|
gboolean new_window,
|
|
gboolean all_headers);
|
|
static void summary_set_row_marks (SummaryView *summaryview,
|
|
GtkCMCTreeNode *row);
|
|
|
|
static gboolean summary_set_row_tag (SummaryView *summaryview,
|
|
GtkCMCTreeNode *row,
|
|
gboolean refresh,
|
|
gboolean set,
|
|
gint id);
|
|
/* message handling */
|
|
static void summary_mark_row (SummaryView *summaryview,
|
|
GtkCMCTreeNode *row);
|
|
static void summary_lock_row (SummaryView *summaryview,
|
|
GtkCMCTreeNode *row);
|
|
static void summary_unlock_row (SummaryView *summaryview,
|
|
GtkCMCTreeNode *row);
|
|
static void summary_mark_row_as_read (SummaryView *summaryview,
|
|
GtkCMCTreeNode *row);
|
|
static void summary_mark_row_as_unread (SummaryView *summaryview,
|
|
GtkCMCTreeNode *row);
|
|
static gboolean summary_mark_all_read_confirm(gboolean ask_if_needed);
|
|
static gboolean summary_mark_all_unread_confirm(gboolean ask_if_needed);
|
|
static void summary_delete_row (SummaryView *summaryview,
|
|
GtkCMCTreeNode *row);
|
|
static void summary_unmark_row (SummaryView *summaryview,
|
|
GtkCMCTreeNode *row);
|
|
static void summary_move_row_to (SummaryView *summaryview,
|
|
GtkCMCTreeNode *row,
|
|
FolderItem *to_folder);
|
|
static void summary_copy_row_to (SummaryView *summaryview,
|
|
GtkCMCTreeNode *row,
|
|
FolderItem *to_folder);
|
|
|
|
static gint summary_execute_move (SummaryView *summaryview);
|
|
static void summary_execute_move_func (GtkCMCTree *ctree,
|
|
GtkCMCTreeNode *node,
|
|
gpointer data);
|
|
static void summary_execute_copy (SummaryView *summaryview);
|
|
static void summary_execute_copy_func (GtkCMCTree *ctree,
|
|
GtkCMCTreeNode *node,
|
|
gpointer data);
|
|
static void summary_execute_delete (SummaryView *summaryview);
|
|
static void summary_execute_delete_func (GtkCMCTree *ctree,
|
|
GtkCMCTreeNode *node,
|
|
gpointer data);
|
|
static void summary_execute_expunge (SummaryView *summaryview);
|
|
|
|
static void summary_thread_init (SummaryView *summaryview);
|
|
|
|
static void summary_unthread_for_exec (SummaryView *summaryview);
|
|
static void summary_unthread_for_exec_func (GtkCMCTree *ctree,
|
|
GtkCMCTreeNode *node,
|
|
gpointer data);
|
|
|
|
void summary_simplify_subject(SummaryView *summaryview, gchar * rexp,
|
|
GSList * mlist);
|
|
|
|
static void summary_filter_func (MsgInfo *msginfo,
|
|
PrefsAccount *ac_prefs);
|
|
|
|
static void summary_colorlabel_menu_item_activate_cb
|
|
(GtkWidget *widget,
|
|
gpointer data);
|
|
static void summary_colorlabel_menu_item_activate_item_cb
|
|
(GtkMenuItem *label_menu_item,
|
|
gpointer data);
|
|
static void summary_colorlabel_menu_create(SummaryView *summaryview,
|
|
gboolean refresh);
|
|
static void summary_tags_menu_item_activate_cb
|
|
(GtkWidget *widget,
|
|
gpointer data);
|
|
static void summary_tags_menu_item_activate_item_cb
|
|
(GtkMenuItem *label_menu_item,
|
|
gpointer data);
|
|
static void summary_tags_menu_create(SummaryView *summaryview,
|
|
gboolean refresh);
|
|
|
|
static GtkWidget *summary_ctree_create (SummaryView *summaryview);
|
|
|
|
/* callback functions */
|
|
static gint summary_toggle_pressed (GtkWidget *eventbox,
|
|
GdkEventButton *event,
|
|
SummaryView *summaryview);
|
|
#ifdef GENERIC_UMPC
|
|
static void summary_toggle_multiple_pressed
|
|
(GtkWidget *widget,
|
|
SummaryView *summaryview);
|
|
#endif
|
|
static gint summary_folder_eventbox_pressed
|
|
(GtkWidget *eventbox,
|
|
GdkEventButton *event,
|
|
SummaryView *summaryview);
|
|
static gboolean summary_button_pressed (GtkWidget *ctree,
|
|
GdkEventButton *event,
|
|
SummaryView *summaryview);
|
|
static gboolean summary_button_released (GtkWidget *ctree,
|
|
GdkEventButton *event,
|
|
SummaryView *summaryview);
|
|
static gboolean summary_key_pressed (GtkWidget *ctree,
|
|
GdkEventKey *event,
|
|
SummaryView *summaryview);
|
|
static void summary_tree_expanded (GtkCMCTree *ctree,
|
|
GtkCMCTreeNode *node,
|
|
SummaryView *summaryview);
|
|
static void summary_tree_collapsed (GtkCMCTree *ctree,
|
|
GtkCMCTreeNode *node,
|
|
SummaryView *summaryview);
|
|
static void summary_selected (GtkCMCTree *ctree,
|
|
GtkCMCTreeNode *row,
|
|
gint column,
|
|
SummaryView *summaryview);
|
|
static void summary_unselected (GtkCMCTree *ctree,
|
|
GtkCMCTreeNode *row,
|
|
gint column,
|
|
SummaryView *summaryview);
|
|
static void summary_col_resized (GtkCMCList *clist,
|
|
gint column,
|
|
gint width,
|
|
SummaryView *summaryview);
|
|
static void summary_mark_clicked (GtkWidget *button,
|
|
SummaryView *summaryview);
|
|
static void summary_status_clicked (GtkWidget *button,
|
|
SummaryView *summaryview);
|
|
static void summary_mime_clicked (GtkWidget *button,
|
|
SummaryView *summaryview);
|
|
static void summary_num_clicked (GtkWidget *button,
|
|
SummaryView *summaryview);
|
|
static void summary_score_clicked (GtkWidget *button,
|
|
SummaryView *summaryview);
|
|
static void summary_size_clicked (GtkWidget *button,
|
|
SummaryView *summaryview);
|
|
static void summary_date_clicked (GtkWidget *button,
|
|
SummaryView *summaryview);
|
|
static void summary_from_clicked (GtkWidget *button,
|
|
SummaryView *summaryview);
|
|
static void summary_to_clicked (GtkWidget *button,
|
|
SummaryView *summaryview);
|
|
static void summary_subject_clicked (GtkWidget *button,
|
|
SummaryView *summaryview);
|
|
static void summary_score_clicked (GtkWidget *button,
|
|
SummaryView *summaryview);
|
|
static void summary_locked_clicked (GtkWidget *button,
|
|
SummaryView *summaryview);
|
|
static void summary_tags_clicked (GtkWidget *button,
|
|
SummaryView *summaryview);
|
|
|
|
static void summary_start_drag (GtkWidget *widget,
|
|
int button,
|
|
GdkEvent *event,
|
|
SummaryView *summaryview);
|
|
static void summary_drag_data_get (GtkWidget *widget,
|
|
GdkDragContext *drag_context,
|
|
GtkSelectionData *selection_data,
|
|
guint info,
|
|
guint time,
|
|
SummaryView *summaryview);
|
|
static void summary_drag_data_received(GtkWidget *widget,
|
|
GdkDragContext *drag_context,
|
|
gint x,
|
|
gint y,
|
|
GtkSelectionData *data,
|
|
guint info,
|
|
guint time,
|
|
SummaryView *summaryview);
|
|
static gboolean summary_drag_motion_cb(GtkWidget *widget,
|
|
GdkDragContext *context,
|
|
gint x,
|
|
gint y,
|
|
guint time,
|
|
SummaryView *summaryview);
|
|
static void summary_drag_end(GtkWidget *widget,
|
|
GdkDragContext *drag_context,
|
|
SummaryView *summaryview);
|
|
|
|
/* custom compare functions for sorting */
|
|
static gint summary_cmp_by_mark (GtkCMCList *clist,
|
|
gconstpointer ptr1,
|
|
gconstpointer ptr2);
|
|
static gint summary_cmp_by_status (GtkCMCList *clist,
|
|
gconstpointer ptr1,
|
|
gconstpointer ptr2);
|
|
static gint summary_cmp_by_mime (GtkCMCList *clist,
|
|
gconstpointer ptr1,
|
|
gconstpointer ptr2);
|
|
static gint summary_cmp_by_num (GtkCMCList *clist,
|
|
gconstpointer ptr1,
|
|
gconstpointer ptr2);
|
|
static gint summary_cmp_by_size (GtkCMCList *clist,
|
|
gconstpointer ptr1,
|
|
gconstpointer ptr2);
|
|
static gint summary_cmp_by_date (GtkCMCList *clist,
|
|
gconstpointer ptr1,
|
|
gconstpointer ptr2);
|
|
static gint summary_cmp_by_thread_date (GtkCMCList *clist,
|
|
gconstpointer ptr1,
|
|
gconstpointer ptr2);
|
|
static gint summary_cmp_by_from (GtkCMCList *clist,
|
|
gconstpointer ptr1,
|
|
gconstpointer ptr2);
|
|
static gint summary_cmp_by_simplified_subject
|
|
(GtkCMCList *clist,
|
|
gconstpointer ptr1,
|
|
gconstpointer ptr2);
|
|
static gint summary_cmp_by_score (GtkCMCList *clist,
|
|
gconstpointer ptr1,
|
|
gconstpointer ptr2);
|
|
static gint summary_cmp_by_label (GtkCMCList *clist,
|
|
gconstpointer ptr1,
|
|
gconstpointer ptr2);
|
|
static gint summary_cmp_by_to (GtkCMCList *clist,
|
|
gconstpointer ptr1,
|
|
gconstpointer ptr2);
|
|
static gint summary_cmp_by_subject (GtkCMCList *clist,
|
|
gconstpointer ptr1,
|
|
gconstpointer ptr2);
|
|
static gint summary_cmp_by_locked (GtkCMCList *clist,
|
|
gconstpointer ptr1,
|
|
gconstpointer ptr2);
|
|
static gint summary_cmp_by_tags (GtkCMCList *clist,
|
|
gconstpointer ptr1,
|
|
gconstpointer ptr2);
|
|
|
|
static void quicksearch_execute_cb (QuickSearch *quicksearch,
|
|
gpointer data);
|
|
|
|
static void tog_searchbar_cb (GtkWidget *w,
|
|
gpointer data);
|
|
|
|
static void summary_find_answers (SummaryView *summaryview,
|
|
MsgInfo *msg);
|
|
|
|
static gboolean summary_update_msg (gpointer source, gpointer data);
|
|
static gboolean summary_update_folder_item_hook(gpointer source, gpointer data);
|
|
static gboolean summary_update_folder_hook(gpointer source, gpointer data);
|
|
static void summary_set_colorlabel_color (GtkCMCTree *ctree,
|
|
GtkCMCTreeNode *node,
|
|
guint labelcolor);
|
|
static void summary_thread_build(SummaryView *summaryview);
|
|
|
|
GtkTargetEntry summary_drag_types[3] =
|
|
{
|
|
{"text/uri-list", 0, TARGET_MAIL_URI_LIST},
|
|
{"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY},
|
|
{"claws-mail/msg-path-list", 0, TARGET_MAIL_CM_PATH_LIST},
|
|
};
|
|
|
|
static void summary_reply_cb(GtkAction *gaction, gpointer data);
|
|
|
|
/* Only submenus and specifically-handled menu entries here */
|
|
static GtkActionEntry summary_popup_entries[] =
|
|
{
|
|
{"SummaryViewPopup", NULL, "SummaryViewPopup", NULL, NULL, NULL },
|
|
{"SummaryViewPopup/Reply", NULL, N_("_Reply"), NULL, NULL, G_CALLBACK(summary_reply_cb) }, /* COMPOSE_REPLY */
|
|
{"SummaryViewPopup/ReplyTo", NULL, N_("Repl_y to"), NULL, NULL, NULL },
|
|
{"SummaryViewPopup/ReplyTo/All", NULL, N_("_All"), NULL, NULL, G_CALLBACK(summary_reply_cb) }, /* COMPOSE_REPLY_TO_ALL */
|
|
{"SummaryViewPopup/ReplyTo/Sender", NULL, N_("_Sender"), NULL, NULL, G_CALLBACK(summary_reply_cb) }, /* COMPOSE_REPLY_TO_SENDER */
|
|
{"SummaryViewPopup/ReplyTo/List", NULL, N_("Mailing _list"), NULL, NULL, G_CALLBACK(summary_reply_cb) }, /* COMPOSE_REPLY_TO_LIST */
|
|
|
|
{"SummaryViewPopup/Forward", NULL, N_("_Forward"), NULL, NULL, G_CALLBACK(summary_reply_cb) }, /* COMPOSE_FORWARD_INLINE */
|
|
{"SummaryViewPopup/ForwardAtt", NULL, N_("For_ward as attachment"), NULL, NULL, G_CALLBACK(summary_reply_cb) }, /* COMPOSE_FORWARD_AS_ATTACH */
|
|
{"SummaryViewPopup/Redirect", NULL, N_("Redirec_t"), NULL, NULL, G_CALLBACK(summary_reply_cb) }, /* COMPOSE_REDIRECT */
|
|
{"SummaryViewPopup/Mark", NULL, N_("_Mark"), NULL, NULL, NULL },
|
|
{"SummaryViewPopup/ColorLabel", NULL, N_("Color la_bel"), NULL, NULL, NULL },
|
|
{"SummaryViewPopup/Tags", NULL, N_("Ta_gs"), NULL, NULL, NULL },
|
|
{"SummaryViewPopup/CreateFilterRule", NULL, N_("Create _filter rule"), NULL, NULL, NULL },
|
|
#ifndef GENERIC_UMPC
|
|
{"SummaryViewPopup/CreateProcessingRule", NULL, N_("Create processing rule"), NULL, NULL, NULL },
|
|
#endif
|
|
{"SummaryViewPopup/View", NULL, N_("_View"), NULL, NULL, NULL },
|
|
};
|
|
|
|
static void summary_header_lock_sorting_cb(GtkAction *gaction, gpointer data);
|
|
static void summary_header_set_displayed_columns_cb(GtkAction *gaction, gpointer data);
|
|
|
|
static GtkActionEntry summary_header_popup_entries[] =
|
|
{
|
|
{"SummaryViewHeaderPopup", NULL, "SummaryViewHeaderPopup", NULL, NULL, NULL },
|
|
{"SummaryViewHeaderPopup/SetDisplayedColumns", NULL, N_("_Set displayed columns"), NULL, NULL, G_CALLBACK(summary_header_set_displayed_columns_cb) }
|
|
};
|
|
|
|
static GtkToggleActionEntry summary_header_popup_toggle_entries[] =
|
|
{
|
|
{"SummaryViewHeaderPopup/LockColumnHeaders", NULL, N_("_Lock column headers"), NULL, NULL, G_CALLBACK(summary_header_lock_sorting_cb), FALSE }
|
|
};
|
|
|
|
static const gchar *const col_label[N_SUMMARY_COLS] = {
|
|
"", /* S_COL_MARK */
|
|
N_("S"), /* S_COL_STATUS */
|
|
"", /* S_COL_MIME */
|
|
N_("Subject"), /* S_COL_SUBJECT */
|
|
N_("From"), /* S_COL_FROM */
|
|
N_("To"), /* S_COL_TO */
|
|
N_("Date"), /* S_COL_DATE */
|
|
N_("Size"), /* S_COL_SIZE */
|
|
N_("#"), /* S_COL_NUMBER */
|
|
N_("Score"), /* S_COL_SCORE */
|
|
"", /* S_COL_LOCKED */
|
|
N_("Tags"), /* S_COL_TAGS */
|
|
};
|
|
|
|
void summary_freeze(SummaryView *summaryview)
|
|
{
|
|
if (summaryview)
|
|
gtk_cmclist_freeze(GTK_CMCLIST(summaryview->ctree));
|
|
}
|
|
|
|
void summary_thaw(SummaryView *summaryview)
|
|
{
|
|
if (summaryview)
|
|
gtk_cmclist_thaw(GTK_CMCLIST(summaryview->ctree));
|
|
}
|
|
|
|
void summary_thaw_with_status(SummaryView *summaryview)
|
|
{
|
|
if (summaryview) {
|
|
summary_status_show(summaryview);
|
|
gtk_cmclist_thaw(GTK_CMCLIST(summaryview->ctree));
|
|
}
|
|
}
|
|
|
|
void summary_grab_focus(SummaryView *summaryview)
|
|
{
|
|
if (summaryview)
|
|
gtk_widget_grab_focus(summaryview->ctree);
|
|
}
|
|
|
|
GtkWidget *summary_get_main_widget(SummaryView *summaryview)
|
|
{
|
|
if (summaryview)
|
|
return summaryview->ctree;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
#define START_LONG_OPERATION(summaryview,force_freeze) { \
|
|
summary_lock(summaryview); \
|
|
main_window_cursor_wait(summaryview->mainwin); \
|
|
if (force_freeze || sc_g_list_bigger(GTK_CMCLIST(summaryview->ctree)->selection, 1)) {\
|
|
froze = TRUE; \
|
|
summary_freeze(summaryview); \
|
|
} \
|
|
folder_item_update_freeze(); \
|
|
inc_lock(); \
|
|
hooks_unregister_hook(MSGINFO_UPDATE_HOOKLIST, \
|
|
summaryview->msginfo_update_callback_id); \
|
|
}
|
|
#define END_LONG_OPERATION(summaryview) { \
|
|
inc_unlock(); \
|
|
folder_item_update_thaw(); \
|
|
if (froze) \
|
|
summary_thaw(summaryview); \
|
|
main_window_cursor_normal(summaryview->mainwin); \
|
|
summary_unlock(summaryview); \
|
|
summaryview->msginfo_update_callback_id = \
|
|
hooks_register_hook(MSGINFO_UPDATE_HOOKLIST, \
|
|
summary_update_msg, (gpointer) summaryview); \
|
|
}
|
|
|
|
SummaryView *summary_create(MainWindow *mainwin)
|
|
{
|
|
SummaryView *summaryview;
|
|
GtkWidget *vbox;
|
|
GtkWidget *scrolledwin;
|
|
GtkWidget *ctree;
|
|
GtkWidget *hbox;
|
|
GtkWidget *hbox_l;
|
|
GtkWidget *stat_box;
|
|
GtkWidget *stat_box2;
|
|
GtkWidget *stat_vbox;
|
|
GtkWidget *statlabel_folder;
|
|
GtkWidget *statlabel_select;
|
|
GtkWidget *statlabel_msgs;
|
|
GtkWidget *hbox_spc;
|
|
GtkWidget *toggle_eventbox;
|
|
#ifdef GENERIC_UMPC
|
|
GtkWidget *multiple_sel_togbtn;
|
|
#endif
|
|
GtkWidget *toggle_arrow;
|
|
GtkWidget *toggle_search;
|
|
QuickSearch *quicksearch;
|
|
|
|
debug_print("Creating summary view...\n");
|
|
summaryview = g_new0(SummaryView, 1);
|
|
|
|
#define SUMMARY_VBOX_SPACING 3
|
|
vbox = gtk_vbox_new(FALSE, SUMMARY_VBOX_SPACING);
|
|
|
|
/* create status label */
|
|
hbox = gtk_hbox_new(FALSE, 0);
|
|
gtk_widget_show(hbox);
|
|
|
|
stat_vbox = gtk_vbox_new(FALSE, 0);
|
|
gtk_widget_show(stat_vbox);
|
|
|
|
stat_box = gtk_hbox_new(FALSE, 0);
|
|
gtk_widget_show(stat_box);
|
|
|
|
stat_box2 = gtk_hbox_new(FALSE, 0);
|
|
gtk_widget_show(stat_box2);
|
|
|
|
toggle_search = gtk_toggle_button_new();
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle_search),
|
|
prefs_common.show_searchbar);
|
|
gtk_widget_set_can_focus(toggle_search, FALSE);
|
|
gtk_widget_show(toggle_search);
|
|
|
|
CLAWS_SET_TIP(toggle_search, _("Toggle quick search bar"));
|
|
|
|
gtk_box_pack_start(GTK_BOX(hbox), toggle_search, FALSE, FALSE, 2);
|
|
|
|
gtk_box_pack_start(GTK_BOX(hbox), stat_vbox, TRUE, TRUE, 0);
|
|
gtk_box_pack_start(GTK_BOX(stat_vbox), stat_box, TRUE, TRUE, 0);
|
|
gtk_box_pack_start(GTK_BOX(stat_vbox), stat_box2, TRUE, TRUE, 0);
|
|
|
|
hbox_l = gtk_hbox_new(FALSE, 0);
|
|
gtk_widget_show(hbox_l);
|
|
gtk_box_pack_start(GTK_BOX(stat_box), hbox_l, TRUE, TRUE, 0);
|
|
|
|
statlabel_folder = gtk_label_new("");
|
|
gtk_widget_show(statlabel_folder);
|
|
gtk_box_pack_start(GTK_BOX(hbox_l), statlabel_folder, FALSE, FALSE, 2);
|
|
statlabel_select = gtk_label_new("");
|
|
gtk_widget_show(statlabel_select);
|
|
gtk_box_pack_start(GTK_BOX(hbox_l), statlabel_select, FALSE, FALSE, 12);
|
|
|
|
/* toggle view button */
|
|
toggle_eventbox = gtk_event_box_new();
|
|
gtk_widget_show(toggle_eventbox);
|
|
|
|
gtk_box_pack_end(GTK_BOX(hbox), toggle_eventbox, FALSE, FALSE, 4);
|
|
|
|
toggle_arrow = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT);
|
|
gtk_widget_show(toggle_arrow);
|
|
gtk_container_add(GTK_CONTAINER(toggle_eventbox), toggle_arrow);
|
|
g_signal_connect(G_OBJECT(toggle_eventbox), "button_press_event",
|
|
G_CALLBACK(summary_toggle_pressed),
|
|
summaryview);
|
|
|
|
#ifdef GENERIC_UMPC
|
|
multiple_sel_togbtn = gtk_toggle_button_new();
|
|
gtk_widget_show(multiple_sel_togbtn);
|
|
gtk_box_pack_end(GTK_BOX(hbox), multiple_sel_togbtn, FALSE, FALSE, 4);
|
|
CLAWS_SET_TIP(multiple_sel_togbtn,
|
|
_("Toggle multiple selection"));
|
|
g_signal_connect(G_OBJECT(multiple_sel_togbtn), "toggled",
|
|
G_CALLBACK(summary_toggle_multiple_pressed),
|
|
summaryview);
|
|
#endif
|
|
|
|
statlabel_msgs = gtk_label_new("");
|
|
gtk_widget_show(statlabel_msgs);
|
|
gtk_box_pack_end(GTK_BOX(stat_box), statlabel_msgs, FALSE, FALSE, 4);
|
|
|
|
hbox_spc = gtk_hbox_new(FALSE, 0);
|
|
gtk_widget_show(hbox_spc);
|
|
gtk_box_pack_end(GTK_BOX(hbox), hbox_spc, FALSE, FALSE, 6);
|
|
|
|
scrolledwin = gtk_scrolled_window_new(NULL, NULL);
|
|
gtk_widget_show(scrolledwin);
|
|
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
|
|
GTK_POLICY_AUTOMATIC,
|
|
GTK_POLICY_AUTOMATIC);
|
|
summaryview->mainwidget_book = gtk_notebook_new();
|
|
gtk_notebook_set_show_tabs(GTK_NOTEBOOK(summaryview->mainwidget_book), FALSE);
|
|
gtk_notebook_set_show_border(GTK_NOTEBOOK(summaryview->mainwidget_book), FALSE);
|
|
#ifndef GENERIC_UMPC
|
|
gtk_container_add(GTK_CONTAINER(summaryview->mainwidget_book),
|
|
scrolledwin);
|
|
gtk_box_pack_start(GTK_BOX(vbox), summaryview->mainwidget_book, TRUE, TRUE, 0);
|
|
#endif
|
|
|
|
ctree = summary_ctree_create(summaryview);
|
|
gtk_widget_show(ctree);
|
|
|
|
gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
|
|
GTK_CMCLIST(ctree)->hadjustment);
|
|
gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
|
|
GTK_CMCLIST(ctree)->vadjustment);
|
|
gtk_container_add(GTK_CONTAINER(scrolledwin), ctree);
|
|
|
|
/* status label */
|
|
gtk_widget_show_all(stat_vbox);
|
|
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
|
|
|
|
/* quick search */
|
|
quicksearch = quicksearch_new();
|
|
gtk_box_pack_start(GTK_BOX(vbox), quicksearch_get_widget(quicksearch), FALSE, FALSE, 0);
|
|
|
|
#ifdef GENERIC_UMPC
|
|
gtk_container_add(GTK_CONTAINER(summaryview->mainwidget_book),
|
|
scrolledwin);
|
|
gtk_box_pack_start(GTK_BOX(vbox), summaryview->mainwidget_book, TRUE, TRUE, 0);
|
|
#endif
|
|
quicksearch_set_execute_callback(quicksearch, quicksearch_execute_cb, summaryview);
|
|
|
|
g_signal_connect (G_OBJECT(toggle_search), "toggled",
|
|
G_CALLBACK(tog_searchbar_cb), summaryview);
|
|
|
|
/* create popup menu */
|
|
|
|
gtk_action_group_add_actions(mainwin->action_group,
|
|
summary_popup_entries,
|
|
G_N_ELEMENTS(summary_popup_entries),
|
|
(gpointer)summaryview);
|
|
|
|
gtk_action_group_add_actions(mainwin->action_group,
|
|
summary_header_popup_entries,
|
|
G_N_ELEMENTS(summary_header_popup_entries),
|
|
(gpointer)summaryview);
|
|
|
|
gtk_action_group_add_toggle_actions(mainwin->action_group,
|
|
summary_header_popup_toggle_entries,
|
|
G_N_ELEMENTS(summary_header_popup_toggle_entries),
|
|
(gpointer)summaryview);
|
|
|
|
summaryview->ui_manager = gtk_ui_manager_new();
|
|
summaryview->action_group = cm_menu_create_action_group_full(summaryview->ui_manager,"Menu", summary_popup_entries,
|
|
G_N_ELEMENTS(summary_popup_entries), (gpointer)summaryview);
|
|
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus", "SummaryViewPopup", "SummaryViewPopup", GTK_UI_MANAGER_MENU)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup", "Reply", "SummaryViewPopup/Reply", GTK_UI_MANAGER_MENUITEM)
|
|
#ifndef GENERIC_UMPC
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup", "ReplyTo", "SummaryViewPopup/ReplyTo", GTK_UI_MANAGER_MENU)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup", "Separator1", "Message/---", GTK_UI_MANAGER_SEPARATOR)
|
|
#endif
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup", "Forward", "SummaryViewPopup/Forward", GTK_UI_MANAGER_MENUITEM)
|
|
#ifndef GENERIC_UMPC
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup", "ForwardAtt", "SummaryViewPopup/ForwardAtt", GTK_UI_MANAGER_MENUITEM)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup", "Redirect", "SummaryViewPopup/Redirect", GTK_UI_MANAGER_MENUITEM)
|
|
#endif
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup", "Separator2", "Message/---", GTK_UI_MANAGER_SEPARATOR)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup", "Move", "Message/Move", GTK_UI_MANAGER_MENUITEM)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup", "Copy", "Message/Copy", GTK_UI_MANAGER_MENUITEM)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup", "Trash", "Message/Trash", GTK_UI_MANAGER_MENUITEM)
|
|
#ifndef GENERIC_UMPC
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup", "Delete", "Message/Delete", GTK_UI_MANAGER_MENUITEM)
|
|
#endif
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup", "Separator3", "Message/---", GTK_UI_MANAGER_SEPARATOR)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup", "Mark", "SummaryViewPopup/Mark", GTK_UI_MANAGER_MENU)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup", "ColorLabel", "SummaryViewPopup/ColorLabel", GTK_UI_MANAGER_MENU)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup", "Tags", "SummaryViewPopup/Tags", GTK_UI_MANAGER_MENU)
|
|
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup", "Separator4", "Message/---", GTK_UI_MANAGER_SEPARATOR)
|
|
#ifndef GENERIC_UMPC
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup", "AddSenderToAB", "Tools/AddSenderToAB", GTK_UI_MANAGER_MENUITEM)
|
|
#endif
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup", "CreateFilterRule", "SummaryViewPopup/CreateFilterRule", GTK_UI_MANAGER_MENU)
|
|
#ifndef GENERIC_UMPC
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup", "CreateProcessingRule", "SummaryViewPopup/CreateProcessingRule", GTK_UI_MANAGER_MENU)
|
|
#endif
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup", "Separator5", "Tools/---", GTK_UI_MANAGER_SEPARATOR)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup", "View", "SummaryViewPopup/View", GTK_UI_MANAGER_MENU)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup", "SaveAs", "File/SaveAs", GTK_UI_MANAGER_MENUITEM)
|
|
#ifndef GENERIC_UMPC
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup", "Print", "File/Print", GTK_UI_MANAGER_MENUITEM)
|
|
#endif
|
|
/* last separator, for plugins */
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup", "Separator6", "File/---", GTK_UI_MANAGER_SEPARATOR)
|
|
|
|
/* submenus - replyto */
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/ReplyTo", "All", "SummaryViewPopup/ReplyTo/All", GTK_UI_MANAGER_MENUITEM)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/ReplyTo", "Sender", "SummaryViewPopup/ReplyTo/Sender", GTK_UI_MANAGER_MENUITEM)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/ReplyTo", "MailingList", "SummaryViewPopup/ReplyTo/List", GTK_UI_MANAGER_MENUITEM)
|
|
|
|
/* submenus - mark */
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/Mark", "Mark", "Message/Mark/Mark", GTK_UI_MANAGER_MENUITEM)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/Mark", "Unmark", "Message/Mark/Unmark", GTK_UI_MANAGER_MENUITEM)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/Mark", "Separator1", "Message/Mark/---", GTK_UI_MANAGER_SEPARATOR)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/Mark", "MarkRead", "Message/Mark/MarkRead", GTK_UI_MANAGER_MENUITEM)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/Mark", "MarkUnread", "Message/Mark/MarkUnread", GTK_UI_MANAGER_MENUITEM)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/Mark", "Separator2", "Message/Mark/---", GTK_UI_MANAGER_SEPARATOR)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/Mark", "MarkAllRead", "Message/Mark/MarkAllRead", GTK_UI_MANAGER_MENUITEM)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/Mark", "MarkAllUnread", "Message/Mark/MarkAllUnread", GTK_UI_MANAGER_MENUITEM)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/Mark", "Separator3", "Message/Mark/---", GTK_UI_MANAGER_SEPARATOR)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/Mark", "IgnoreThread", "Message/Mark/IgnoreThread", GTK_UI_MANAGER_MENUITEM)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/Mark", "UnignoreThread", "Message/Mark/UnignoreThread", GTK_UI_MANAGER_MENUITEM)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/Mark", "WatchThread", "Message/Mark/WatchThread", GTK_UI_MANAGER_MENUITEM)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/Mark", "UnwatchThread", "Message/Mark/UnwatchThread", GTK_UI_MANAGER_MENUITEM)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/Mark", "Separator4", "Message/Mark/---", GTK_UI_MANAGER_SEPARATOR)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/Mark", "MarkSpam", "Message/Mark/MarkSpam", GTK_UI_MANAGER_MENUITEM)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/Mark", "MarkHam", "Message/Mark/MarkHam", GTK_UI_MANAGER_MENUITEM)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/Mark", "Separator5", "Message/Mark/---", GTK_UI_MANAGER_SEPARATOR)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/Mark", "Lock", "Message/Mark/Lock", GTK_UI_MANAGER_MENUITEM)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/Mark", "Unlock", "Message/Mark/Unlock", GTK_UI_MANAGER_MENUITEM)
|
|
|
|
/* submenus - colorlabel and tags are dynamic */
|
|
/* submenus - createfilterrule */
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/CreateFilterRule", "Automatically", "Tools/CreateFilterRule/Automatically", GTK_UI_MANAGER_MENUITEM)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/CreateFilterRule", "ByFrom", "Tools/CreateFilterRule/ByFrom", GTK_UI_MANAGER_MENUITEM)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/CreateFilterRule", "ByTo", "Tools/CreateFilterRule/ByTo", GTK_UI_MANAGER_MENUITEM)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/CreateFilterRule", "BySubject", "Tools/CreateFilterRule/BySubject", GTK_UI_MANAGER_MENUITEM)
|
|
|
|
#ifndef GENERIC_UMPC
|
|
/* submenus - createprocessingrule */
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/CreateProcessingRule", "Automatically", "Tools/CreateProcessingRule/Automatically", GTK_UI_MANAGER_MENUITEM)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/CreateProcessingRule", "ByFrom", "Tools/CreateProcessingRule/ByFrom", GTK_UI_MANAGER_MENUITEM)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/CreateProcessingRule", "ByTo", "Tools/CreateProcessingRule/ByTo", GTK_UI_MANAGER_MENUITEM)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/CreateProcessingRule", "BySubject", "Tools/CreateProcessingRule/BySubject", GTK_UI_MANAGER_MENUITEM)
|
|
#endif
|
|
|
|
/* submenus - view */
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/View", "OpenNewWindow", "View/OpenNewWindow", GTK_UI_MANAGER_MENUITEM)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/View", "MessageSource", "View/MessageSource", GTK_UI_MANAGER_MENUITEM)
|
|
#ifndef GENERIC_UMPC
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewPopup/View", "AllHeaders", "View/AllHeaders", GTK_UI_MANAGER_MENUITEM)
|
|
#endif
|
|
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus", "SummaryViewHeaderPopup", "SummaryViewHeaderPopup", GTK_UI_MANAGER_MENU)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewHeaderPopup", "LockColumnHeaders", "SummaryViewHeaderPopup/LockColumnHeaders", GTK_UI_MANAGER_MENUITEM)
|
|
MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menus/SummaryViewHeaderPopup", "SetDisplayedColumns", "SummaryViewHeaderPopup/SetDisplayedColumns", GTK_UI_MANAGER_MENUITEM)
|
|
|
|
summaryview->popupmenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
|
|
gtk_ui_manager_get_widget(mainwin->ui_manager, "/Menus/SummaryViewPopup")) );
|
|
summaryview->headerpopupmenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
|
|
gtk_ui_manager_get_widget(mainwin->ui_manager, "/Menus/SummaryViewHeaderPopup")) );
|
|
|
|
summaryview->vbox = vbox;
|
|
summaryview->scrolledwin = scrolledwin;
|
|
summaryview->ctree = ctree;
|
|
summaryview->hbox = hbox;
|
|
summaryview->hbox_l = hbox_l;
|
|
summaryview->hbox_spc = hbox_spc;
|
|
summaryview->stat_box = stat_box;
|
|
summaryview->stat_box2 = stat_box2;
|
|
summaryview->statlabel_folder = statlabel_folder;
|
|
summaryview->statlabel_select = statlabel_select;
|
|
summaryview->statlabel_msgs = statlabel_msgs;
|
|
summaryview->toggle_eventbox = toggle_eventbox;
|
|
summaryview->toggle_arrow = toggle_arrow;
|
|
#ifdef GENERIC_UMPC
|
|
summaryview->multiple_sel_togbtn = multiple_sel_togbtn;
|
|
#endif
|
|
summaryview->toggle_search = toggle_search;
|
|
summaryview->lock_count = 0;
|
|
summaryview->msginfo_update_callback_id =
|
|
hooks_register_hook(MSGINFO_UPDATE_HOOKLIST, summary_update_msg, (gpointer) summaryview);
|
|
summaryview->folder_item_update_callback_id =
|
|
hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST,
|
|
summary_update_folder_item_hook,
|
|
(gpointer) summaryview);
|
|
summaryview->folder_update_callback_id =
|
|
hooks_register_hook(FOLDER_UPDATE_HOOKLIST,
|
|
summary_update_folder_hook,
|
|
(gpointer) summaryview);
|
|
|
|
summaryview->target_list = gtk_target_list_new(summary_drag_types, 3);
|
|
|
|
summaryview->quicksearch = quicksearch;
|
|
|
|
/* CLAWS: need this to get the SummaryView * from
|
|
* the CList */
|
|
g_object_set_data(G_OBJECT(ctree), "summaryview", (gpointer)summaryview);
|
|
|
|
gtk_widget_show_all(vbox);
|
|
|
|
gtk_widget_show(vbox);
|
|
|
|
if (prefs_common.show_searchbar)
|
|
quicksearch_show(quicksearch);
|
|
else
|
|
quicksearch_hide(quicksearch);
|
|
|
|
if (prefs_common.layout_mode == WIDE_MSGLIST_LAYOUT ||
|
|
prefs_common.layout_mode == SMALL_LAYOUT)
|
|
gtk_widget_hide(summaryview->toggle_eventbox);
|
|
|
|
return summaryview;
|
|
}
|
|
|
|
void summary_relayout(SummaryView *summaryview)
|
|
{
|
|
gtk_widget_realize(summaryview->stat_box);
|
|
|
|
g_object_ref(summaryview->hbox_l);
|
|
g_object_ref(summaryview->statlabel_msgs);
|
|
|
|
gtkut_container_remove(GTK_CONTAINER(
|
|
gtk_widget_get_parent(summaryview->hbox_l)), summaryview->hbox_l);
|
|
gtkut_container_remove(GTK_CONTAINER(
|
|
gtk_widget_get_parent(summaryview->statlabel_msgs)), summaryview->statlabel_msgs);
|
|
|
|
switch (prefs_common.layout_mode) {
|
|
case NORMAL_LAYOUT:
|
|
case WIDE_LAYOUT:
|
|
case WIDE_MSGLIST_LAYOUT:
|
|
gtk_box_pack_start(GTK_BOX(summaryview->stat_box), summaryview->hbox_l, TRUE, TRUE, 0);
|
|
gtk_box_pack_end(GTK_BOX(summaryview->stat_box), summaryview->statlabel_msgs, FALSE, FALSE, 4);
|
|
gtk_widget_show_all(summaryview->stat_box);
|
|
gtk_widget_show_all(summaryview->stat_box2);
|
|
if (prefs_common.layout_mode == WIDE_MSGLIST_LAYOUT ||
|
|
prefs_common.layout_mode == SMALL_LAYOUT)
|
|
gtk_widget_hide(summaryview->toggle_eventbox);
|
|
else
|
|
gtk_widget_show(summaryview->toggle_eventbox);
|
|
break;
|
|
case VERTICAL_LAYOUT:
|
|
case SMALL_LAYOUT:
|
|
gtk_box_pack_start(GTK_BOX(summaryview->stat_box), summaryview->hbox_l, TRUE, TRUE, 0);
|
|
gtk_box_pack_start(GTK_BOX(summaryview->stat_box2), summaryview->statlabel_msgs, FALSE, FALSE, 4);
|
|
gtk_widget_show_all(summaryview->stat_box);
|
|
gtk_widget_show_all(summaryview->stat_box2);
|
|
if (prefs_common.layout_mode == SMALL_LAYOUT) {
|
|
gtk_widget_hide(summaryview->toggle_eventbox);
|
|
gtk_widget_hide(summaryview->statlabel_msgs);
|
|
} else {
|
|
gtk_widget_show(summaryview->toggle_eventbox);
|
|
gtk_widget_show(summaryview->statlabel_msgs);
|
|
}
|
|
|
|
break;
|
|
}
|
|
summary_set_column_order(summaryview);
|
|
|
|
g_object_unref(summaryview->hbox_l);
|
|
g_object_unref(summaryview->statlabel_msgs);
|
|
quicksearch_relayout(summaryview->quicksearch);
|
|
if (prefs_common.show_searchbar)
|
|
quicksearch_show(summaryview->quicksearch);
|
|
else
|
|
quicksearch_hide(summaryview->quicksearch);
|
|
}
|
|
|
|
static void summary_set_fonts(SummaryView *summaryview)
|
|
{
|
|
PangoFontDescription *font_desc;
|
|
gint size;
|
|
|
|
font_desc = pango_font_description_from_string(NORMAL_FONT);
|
|
if (font_desc) {
|
|
gtk_widget_modify_font(summaryview->ctree, font_desc);
|
|
pango_font_description_free(font_desc);
|
|
}
|
|
|
|
if (!bold_style) {
|
|
bold_style = gtk_style_copy
|
|
(gtk_widget_get_style(summaryview->ctree));
|
|
|
|
if (prefs_common.derive_from_normal_font || !BOLD_FONT) {
|
|
font_desc = pango_font_description_from_string(NORMAL_FONT);
|
|
if (font_desc) {
|
|
pango_font_description_free(bold_style->font_desc);
|
|
bold_style->font_desc = font_desc;
|
|
}
|
|
pango_font_description_set_weight
|
|
(bold_style->font_desc, PANGO_WEIGHT_BOLD);
|
|
} else {
|
|
font_desc = pango_font_description_from_string(BOLD_FONT);
|
|
if (font_desc) {
|
|
pango_font_description_free(bold_style->font_desc);
|
|
bold_style->font_desc = font_desc;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (prefs_common.derive_from_normal_font || !SMALL_FONT) {
|
|
font_desc = pango_font_description_new();
|
|
size = pango_font_description_get_size
|
|
(gtk_widget_get_style(summaryview->ctree)->font_desc);
|
|
pango_font_description_set_size(font_desc, size * PANGO_SCALE_SMALL);
|
|
} else {
|
|
font_desc = pango_font_description_from_string(SMALL_FONT);
|
|
}
|
|
if (font_desc) {
|
|
gtk_widget_modify_font(summaryview->statlabel_folder, font_desc);
|
|
gtk_widget_modify_font(summaryview->statlabel_select, font_desc);
|
|
gtk_widget_modify_font(summaryview->statlabel_msgs, font_desc);
|
|
pango_font_description_free(font_desc);
|
|
}
|
|
|
|
}
|
|
|
|
static void summary_set_folder_pixmap(SummaryView *summaryview, StockPixmap icon)
|
|
{
|
|
GtkWidget *pixmap;
|
|
if (!summaryview->folder_pixmap_eventbox) {
|
|
summaryview->folder_pixmap_eventbox = gtk_event_box_new();
|
|
gtk_widget_show(summaryview->folder_pixmap_eventbox);
|
|
gtk_box_pack_start(GTK_BOX(summaryview->hbox_l), summaryview->folder_pixmap_eventbox, FALSE, FALSE, 4);
|
|
gtk_box_reorder_child(GTK_BOX(summaryview->hbox_l), summaryview->folder_pixmap_eventbox, 0); /* search_toggle before */
|
|
g_signal_connect(G_OBJECT(summaryview->folder_pixmap_eventbox), "button_press_event",
|
|
G_CALLBACK(summary_folder_eventbox_pressed),
|
|
summaryview);
|
|
}
|
|
if (summaryview->folder_pixmap)
|
|
gtk_widget_destroy(summaryview->folder_pixmap);
|
|
|
|
pixmap = stock_pixmap_widget(icon);
|
|
gtk_container_add(GTK_CONTAINER(summaryview->folder_pixmap_eventbox), pixmap);
|
|
gtk_widget_show(pixmap);
|
|
summaryview->folder_pixmap = pixmap;
|
|
}
|
|
|
|
void summary_init(SummaryView *summaryview)
|
|
{
|
|
GtkWidget *pixmap;
|
|
|
|
gtk_widget_realize(summaryview->ctree);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_MARK, &markxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_DELETED, &deletedxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_NEW, &newxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_UNREAD, &unreadxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_REPLIED, &repliedxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_FORWARDED, &forwardedxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_REPLIED_AND_FORWARDED, &repliedandforwardedxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_CLIP, &clipxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_LOCKED, &lockedxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_IGNORETHREAD, &ignorethreadxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_WATCHTHREAD, &watchthreadxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_CLIP_KEY, &clipkeyxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_KEY_SIGN, &keysignxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_KEY, &keyxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_GPG_SIGNED, &gpgsignedxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_CLIP_GPG_SIGNED, &clipgpgsignedxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_SPAM, &spamxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_MOVED, &movedxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_COPIED, &copiedxpm);
|
|
|
|
summary_set_fonts(summaryview);
|
|
|
|
summary_set_folder_pixmap(summaryview, STOCK_PIXMAP_DIR_OPEN);
|
|
|
|
pixmap = stock_pixmap_widget(STOCK_PIXMAP_QUICKSEARCH);
|
|
gtk_container_add (GTK_CONTAINER(summaryview->toggle_search), pixmap);
|
|
gtk_widget_show(pixmap);
|
|
summaryview->quick_search_pixmap = pixmap;
|
|
|
|
#ifdef GENERIC_UMPC
|
|
pixmap = stock_pixmap_widget(STOCK_PIXMAP_SELECTION);
|
|
gtk_container_add(GTK_CONTAINER(summaryview->multiple_sel_togbtn), pixmap);
|
|
gtk_widget_show(pixmap);
|
|
summaryview->multiple_sel_image = pixmap;
|
|
#endif
|
|
|
|
/* Init summaryview prefs */
|
|
summaryview->sort_key = SORT_BY_NONE;
|
|
summaryview->sort_type = SORT_ASCENDING;
|
|
|
|
/* Init summaryview extra data */
|
|
summaryview->simplify_subject_preg = NULL;
|
|
summary_clear_list(summaryview);
|
|
summary_set_column_titles(summaryview);
|
|
summary_colorlabel_menu_create(summaryview, FALSE);
|
|
summary_tags_menu_create(summaryview, FALSE);
|
|
main_create_mailing_list_menu (summaryview->mainwin, NULL);
|
|
summary_set_menu_sensitive(summaryview);
|
|
|
|
summaryview->header_menu_lock = FALSE;
|
|
}
|
|
|
|
#define CURRENTLY_DISPLAYED(m) \
|
|
( (m->msgnum == displayed_msgnum) \
|
|
&& (!g_ascii_strcasecmp(m->folder->name,item->name)) )
|
|
|
|
#define FOLDER_SHOWS_TO_HDR(i) \
|
|
( i && (folder_has_parent_of_type(i, F_OUTBOX) \
|
|
|| folder_has_parent_of_type(i, F_DRAFT) \
|
|
|| folder_has_parent_of_type(i, F_QUEUE)) )
|
|
|
|
static void summary_switch_from_to(SummaryView *summaryview, FolderItem *item)
|
|
{
|
|
gboolean show_from = FALSE, show_to = FALSE;
|
|
gboolean showing_from = FALSE, showing_to = FALSE;
|
|
gint from_pos = 0, to_pos = 0;
|
|
SummaryColumnState *col_state = summaryview->col_state;
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
|
|
if (!item || ((prefs_common.layout_mode == VERTICAL_LAYOUT || prefs_common.layout_mode == SMALL_LAYOUT) && prefs_common.two_line_vert) )
|
|
return;
|
|
if (FOLDER_SHOWS_TO_HDR(item))
|
|
show_to = TRUE;
|
|
else
|
|
show_from = TRUE;
|
|
|
|
from_pos = summaryview->col_pos[S_COL_FROM];
|
|
to_pos = summaryview->col_pos[S_COL_TO];
|
|
showing_from = col_state[from_pos].visible;
|
|
showing_to = col_state[to_pos].visible;
|
|
|
|
if (showing_from && showing_to) {
|
|
debug_print("showing both\n");
|
|
return;
|
|
}
|
|
|
|
if (!showing_from && !showing_to) {
|
|
debug_print("showing none\n");
|
|
return;
|
|
}
|
|
|
|
debug_print("showing %s %s, must show %s %s\n",
|
|
showing_from?"From":"",
|
|
showing_to?"To":"",
|
|
show_from?"From":"",
|
|
show_to?"To":"");
|
|
|
|
if (showing_from == show_from && showing_to == show_to)
|
|
return;
|
|
/* else we'll switch both */
|
|
|
|
debug_print("switching columns\n");
|
|
col_state[from_pos].type = S_COL_TO;
|
|
col_state[from_pos].visible = show_to;
|
|
|
|
col_state[to_pos].type = S_COL_FROM;
|
|
col_state[to_pos].visible = show_from;
|
|
|
|
summaryview->col_pos[S_COL_TO] = from_pos;
|
|
summaryview->col_pos[S_COL_FROM] = to_pos;
|
|
|
|
gtk_cmclist_set_column_visibility
|
|
(GTK_CMCLIST(ctree), from_pos, col_state[from_pos].visible);
|
|
gtk_cmclist_set_column_visibility
|
|
(GTK_CMCLIST(ctree), to_pos, col_state[to_pos].visible);
|
|
|
|
summary_set_column_titles(summaryview);
|
|
}
|
|
|
|
static void summaryview_reset_recursive_folder_match(SummaryView *summaryview)
|
|
{
|
|
GSList *cur;
|
|
|
|
for (cur = summaryview->recursive_matched_folders; cur != NULL; cur = cur->next) {
|
|
folderview_update_search_icon(cur->data, FALSE);
|
|
}
|
|
|
|
g_slist_free(summaryview->recursive_matched_folders);
|
|
summaryview->recursive_matched_folders = NULL;
|
|
summaryview->search_root_folder = NULL;
|
|
}
|
|
|
|
static gboolean summaryview_quicksearch_recursive_progress(gpointer data, guint at, guint matched, guint total)
|
|
{
|
|
QuickSearch *search = (QuickSearch*) data;
|
|
gint interval = quicksearch_is_fast(search) ? 5000 : 100;
|
|
|
|
statusbar_progress_all(at, total, interval);
|
|
if (at % interval == 0)
|
|
GTK_EVENTS_FLUSH();
|
|
|
|
if (matched > 0)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void summaryview_quicksearch_recurse_step(SummaryView *summaryview, FolderItem *item)
|
|
{
|
|
MsgInfoList *msgs = NULL;
|
|
gboolean result = TRUE;
|
|
|
|
statusbar_print_all(_("Searching in %s... \n"),
|
|
item->path ? item->path : "(null)");
|
|
folder_item_update_freeze();
|
|
|
|
quicksearch_set_on_progress_cb(summaryview->quicksearch, summaryview_quicksearch_recursive_progress, summaryview->quicksearch);
|
|
if (!quicksearch_run_on_folder(summaryview->quicksearch, item, &msgs))
|
|
result = FALSE;
|
|
|
|
result = result && msgs != NULL;
|
|
|
|
if (msgs != NULL)
|
|
procmsg_msg_list_free(msgs);
|
|
|
|
folder_item_update_thaw();
|
|
statusbar_progress_all(0, 0, 0);
|
|
statusbar_pop_all();
|
|
|
|
if (result) {
|
|
summaryview->recursive_matched_folders = g_slist_prepend(
|
|
summaryview->recursive_matched_folders, item);
|
|
|
|
folderview_update_search_icon(item, TRUE);
|
|
}
|
|
}
|
|
|
|
static void summaryview_quicksearch_search_subfolders(SummaryView *summaryview, FolderItem *folder_item)
|
|
{
|
|
FolderItem *cur = NULL;
|
|
GNode *node = folder_item->node->children;
|
|
|
|
if (!prefs_common.summary_quicksearch_recurse
|
|
|| !quicksearch_has_sat_predicate(summaryview->quicksearch)
|
|
|| quicksearch_is_in_typing(summaryview->quicksearch))
|
|
return;
|
|
|
|
for (; node != NULL; node = node->next) {
|
|
if (!quicksearch_has_sat_predicate(summaryview->quicksearch))
|
|
return;
|
|
|
|
cur = FOLDER_ITEM(node->data);
|
|
summaryview_quicksearch_recurse_step(summaryview, cur);
|
|
if (cur->node->children)
|
|
summaryview_quicksearch_search_subfolders(summaryview, cur);
|
|
}
|
|
}
|
|
|
|
static void summaryview_quicksearch_recurse(SummaryView *summaryview)
|
|
{
|
|
if (!prefs_common.summary_quicksearch_recurse
|
|
|| !quicksearch_has_sat_predicate(summaryview->quicksearch)
|
|
|| summaryview->folder_item == NULL) {
|
|
return;
|
|
}
|
|
START_TIMING("");
|
|
main_window_cursor_wait(summaryview->mainwin);
|
|
|
|
summaryview_reset_recursive_folder_match(summaryview);
|
|
summaryview->search_root_folder = summaryview->folder_item;
|
|
|
|
summaryview_quicksearch_search_subfolders(summaryview, summaryview->folder_item);
|
|
|
|
main_window_cursor_normal(summaryview->mainwin);
|
|
END_TIMING();
|
|
}
|
|
|
|
static gboolean summary_check_consistency(FolderItem *item, GSList *mlist)
|
|
{
|
|
int u = 0, n = 0, m = 0, t = 0, r = 0, f = 0, l = 0, i = 0, w = 0;
|
|
GSList *cur;
|
|
START_TIMING("");
|
|
for(cur = mlist ; cur != NULL && cur->data != NULL ; cur = g_slist_next(cur)) {
|
|
MsgInfo * msginfo = (MsgInfo *) cur->data;
|
|
t++;
|
|
if (MSG_IS_NEW(msginfo->flags))
|
|
n++;
|
|
if (MSG_IS_UNREAD(msginfo->flags))
|
|
u++;
|
|
if (MSG_IS_MARKED(msginfo->flags))
|
|
m++;
|
|
if (MSG_IS_REPLIED(msginfo->flags))
|
|
r++;
|
|
if (MSG_IS_FORWARDED(msginfo->flags))
|
|
f++;
|
|
if (MSG_IS_LOCKED(msginfo->flags))
|
|
l++;
|
|
if (MSG_IS_IGNORE_THREAD(msginfo->flags))
|
|
i++;
|
|
if (MSG_IS_WATCH_THREAD(msginfo->flags))
|
|
w++;
|
|
}
|
|
if (t != item->total_msgs
|
|
|| n != item->new_msgs
|
|
|| u != item->unread_msgs
|
|
|| m != item->marked_msgs
|
|
|| r != item->replied_msgs
|
|
|| f != item->forwarded_msgs
|
|
|| l != item->locked_msgs
|
|
|| i != item->ignored_msgs
|
|
|| w != item->watched_msgs
|
|
|| (m == 0 && item->unreadmarked_msgs != 0)
|
|
|| item->unreadmarked_msgs < 0) {
|
|
debug_print("Inconsistency\n");
|
|
folder_item_scan_full(item, FALSE);
|
|
END_TIMING();
|
|
return FALSE;
|
|
}
|
|
END_TIMING();
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean summaryview_search_root_progress(gpointer data, guint at, guint matched, guint total)
|
|
{
|
|
SummaryView *summaryview = (SummaryView*) data;
|
|
|
|
gint interval = quicksearch_is_fast(summaryview->quicksearch) ? 5000 : 100;
|
|
|
|
statusbar_progress_all(at, total, interval);
|
|
|
|
if (at % interval == 0)
|
|
GTK_EVENTS_FLUSH();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean summary_show(SummaryView *summaryview, FolderItem *item)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GtkCMCTreeNode *node = NULL;
|
|
GSList *mlist = NULL;
|
|
gchar *buf;
|
|
gboolean is_refresh;
|
|
guint selected_msgnum = 0;
|
|
guint displayed_msgnum = 0;
|
|
GSList *cur;
|
|
GSList *not_killed;
|
|
gboolean hidden_removed = FALSE;
|
|
|
|
if (summary_is_locked(summaryview)) return FALSE;
|
|
|
|
if (!summaryview->mainwin)
|
|
return FALSE;
|
|
START_TIMING("");
|
|
summary_switch_from_to(summaryview, item);
|
|
|
|
inc_lock();
|
|
summary_lock(summaryview);
|
|
|
|
menu_set_sensitive_all(GTK_MENU_SHELL(summaryview->popupmenu), TRUE);
|
|
|
|
utils_free_regex();
|
|
|
|
is_refresh = (item == summaryview->folder_item) ? TRUE : FALSE;
|
|
|
|
if (item && item->folder->klass->item_opened) {
|
|
item->folder->klass->item_opened(item);
|
|
}
|
|
|
|
if (!is_refresh) {
|
|
main_create_mailing_list_menu (summaryview->mainwin, NULL);
|
|
if (prefs_common.layout_mode == SMALL_LAYOUT) {
|
|
if (item) {
|
|
mainwindow_enter_folder(summaryview->mainwin);
|
|
gtk_widget_grab_focus(summaryview->ctree);
|
|
}
|
|
}
|
|
}
|
|
if (!prefs_common.summary_quicksearch_sticky
|
|
&& (!prefs_common.summary_quicksearch_recurse
|
|
|| !quicksearch_has_sat_predicate(summaryview->quicksearch)
|
|
|| (item && !folder_is_child_of(item, summaryview->search_root_folder)))
|
|
&& !quicksearch_is_running(summaryview->quicksearch)
|
|
&& !is_refresh) {
|
|
quicksearch_set(summaryview->quicksearch, prefs_common.summary_quicksearch_type, "");
|
|
}
|
|
|
|
/* STATUSBAR_POP(summaryview->mainwin); */
|
|
|
|
if (is_refresh) {
|
|
selected_msgnum = summary_get_msgnum(summaryview,
|
|
summaryview->selected);
|
|
displayed_msgnum = summary_get_msgnum(summaryview,
|
|
summaryview->displayed);
|
|
}
|
|
|
|
/* process the marks if any */
|
|
if (!is_refresh &&
|
|
(summaryview->mainwin->lock_count == 0 &&
|
|
(summaryview->moved > 0 || summaryview->copied > 0))) {
|
|
AlertValue val;
|
|
gboolean changed = FALSE;
|
|
|
|
val = alertpanel(_("Process mark"),
|
|
_("Some marks are left. Process them?"),
|
|
GTK_STOCK_NO, GTK_STOCK_YES, GTK_STOCK_CANCEL, ALERTFOCUS_FIRST);
|
|
if (G_ALERTALTERNATE == val) {
|
|
summary_unlock(summaryview);
|
|
summary_execute(summaryview);
|
|
summary_lock(summaryview);
|
|
changed = TRUE;
|
|
} else if (G_ALERTDEFAULT == val) {
|
|
/* DO NOTHING */
|
|
} else {
|
|
summary_unlock(summaryview);
|
|
inc_unlock();
|
|
END_TIMING();
|
|
return FALSE;
|
|
}
|
|
if (changed || !quicksearch_has_sat_predicate(summaryview->quicksearch))
|
|
folder_update_op_count();
|
|
}
|
|
|
|
summary_freeze(summaryview);
|
|
|
|
summary_clear_list(summaryview);
|
|
|
|
buf = NULL;
|
|
if (!item || !item->path || !folder_item_parent(item) || item->no_select) {
|
|
g_free(buf);
|
|
debug_print("empty folder (%p %s %p %d)\n",
|
|
item,
|
|
(item && item->path)?item->path:"(null)",
|
|
item?folder_item_parent(item):0x0,
|
|
item?item->no_select:FALSE);
|
|
summary_set_hide_menu(summaryview, "/Menu/View/HideReadMessages", FALSE);
|
|
summary_set_hide_menu(summaryview, "/Menu/View/HideDelMessages", FALSE);
|
|
summary_set_hide_menu(summaryview, "/Menu/View/HideReadThreads", FALSE);
|
|
summary_clear_all(summaryview);
|
|
summaryview->folder_item = item;
|
|
summary_thaw(summaryview);
|
|
summary_unlock(summaryview);
|
|
inc_unlock();
|
|
END_TIMING();
|
|
return TRUE;
|
|
}
|
|
g_free(buf);
|
|
|
|
if (!is_refresh)
|
|
messageview_clear(summaryview->messageview);
|
|
|
|
summaryview->folder_item = item;
|
|
item->opened = TRUE;
|
|
|
|
buf = g_strdup_printf(_("Scanning folder (%s)..."), item->path);
|
|
debug_print("%s\n", buf);
|
|
STATUSBAR_PUSH(summaryview->mainwin, buf);
|
|
g_free(buf);
|
|
|
|
main_window_cursor_wait(summaryview->mainwin);
|
|
|
|
mlist = folder_item_get_msg_list(item);
|
|
|
|
if (!summary_check_consistency(item, mlist)) {
|
|
debug_print("reloading due to inconsistency\n");
|
|
procmsg_msg_list_free(mlist);
|
|
mlist = folder_item_get_msg_list(item);
|
|
}
|
|
|
|
if (quicksearch_has_sat_predicate(summaryview->quicksearch)) {
|
|
procmsg_msg_list_free(mlist);
|
|
mlist = NULL;
|
|
|
|
START_TIMING("quicksearch");
|
|
|
|
statusbar_print_all(_("Searching in %s... \n"),
|
|
summaryview->folder_item->path ?
|
|
summaryview->folder_item->path : "(null)");
|
|
|
|
folder_item_update_freeze();
|
|
|
|
quicksearch_set_on_progress_cb(summaryview->quicksearch, summaryview_search_root_progress, summaryview);
|
|
quicksearch_run_on_folder(summaryview->quicksearch, summaryview->folder_item, &mlist);
|
|
|
|
folder_item_update_thaw();
|
|
statusbar_progress_all(0, 0, 0);
|
|
statusbar_pop_all();
|
|
|
|
if (!quicksearch_has_sat_predicate(summaryview->quicksearch)) {
|
|
debug_print("search cancelled!\n");
|
|
summary_thaw(summaryview);
|
|
STATUSBAR_POP(summaryview->mainwin);
|
|
main_window_cursor_normal(summaryview->mainwin);
|
|
summary_unlock(summaryview);
|
|
inc_unlock();
|
|
summary_show(summaryview, summaryview->folder_item);
|
|
END_TIMING();
|
|
return FALSE;
|
|
}
|
|
END_TIMING();
|
|
}
|
|
|
|
if ((summaryview->folder_item->hide_read_msgs
|
|
|| summaryview->folder_item->hide_del_msgs
|
|
|| summaryview->folder_item->hide_read_threads) &&
|
|
quicksearch_has_sat_predicate(summaryview->quicksearch) == FALSE) {
|
|
GSList *not_killed;
|
|
|
|
summary_set_hide_menu(summaryview, "/Menu/View/HideReadMessages",
|
|
summaryview->folder_item->hide_read_msgs);
|
|
summary_set_hide_menu(summaryview, "/Menu/View/HideDelMessages",
|
|
summaryview->folder_item->hide_del_msgs);
|
|
summary_set_hide_menu(summaryview, "/Menu/View/HideReadThreads",
|
|
summaryview->folder_item->hide_read_threads);
|
|
not_killed = NULL;
|
|
for(cur = mlist ; cur != NULL && cur->data != NULL ; cur = g_slist_next(cur)) {
|
|
MsgInfo * msginfo = (MsgInfo *) cur->data;
|
|
|
|
if (!msginfo->hidden) {
|
|
if (MSG_IS_DELETED(msginfo->flags) && summaryview->folder_item->hide_del_msgs) {
|
|
procmsg_msginfo_free(&msginfo);
|
|
continue;
|
|
}
|
|
if (summaryview->folder_item->hide_read_msgs) {
|
|
if (MSG_IS_UNREAD(msginfo->flags) &&
|
|
!MSG_IS_IGNORE_THREAD(msginfo->flags))
|
|
not_killed = g_slist_prepend(not_killed, msginfo);
|
|
else if (MSG_IS_MARKED(msginfo->flags) ||
|
|
MSG_IS_LOCKED(msginfo->flags))
|
|
not_killed = g_slist_prepend(not_killed, msginfo);
|
|
else if (is_refresh &&
|
|
(msginfo->msgnum == selected_msgnum ||
|
|
msginfo->msgnum == displayed_msgnum))
|
|
not_killed = g_slist_prepend(not_killed, msginfo);
|
|
else
|
|
procmsg_msginfo_free(&msginfo);
|
|
} else {
|
|
not_killed = g_slist_prepend(not_killed, msginfo);
|
|
}
|
|
} else
|
|
procmsg_msginfo_free(&msginfo);
|
|
}
|
|
hidden_removed = TRUE;
|
|
g_slist_free(mlist);
|
|
mlist = not_killed;
|
|
} else {
|
|
summary_set_hide_menu(summaryview, "/Menu/View/HideReadMessages",
|
|
FALSE);
|
|
summary_set_hide_menu(summaryview, "/Menu/View/HideDelMessages",
|
|
FALSE);
|
|
summary_set_hide_menu(summaryview, "/Menu/View/HideReadThreads",
|
|
FALSE);
|
|
}
|
|
|
|
if (!hidden_removed) {
|
|
START_TIMING("removing hidden");
|
|
not_killed = NULL;
|
|
for(cur = mlist ; cur != NULL && cur->data != NULL ; cur = g_slist_next(cur)) {
|
|
MsgInfo * msginfo = (MsgInfo *) cur->data;
|
|
|
|
if (!msginfo->hidden)
|
|
not_killed = g_slist_prepend(not_killed, msginfo);
|
|
else
|
|
procmsg_msginfo_free(&msginfo);
|
|
}
|
|
g_slist_free(mlist);
|
|
mlist = not_killed;
|
|
END_TIMING();
|
|
}
|
|
|
|
STATUSBAR_POP(summaryview->mainwin);
|
|
|
|
/* set ctree and hash table from the msginfo list, and
|
|
create the thread */
|
|
summary_set_ctree_from_list(summaryview, mlist, selected_msgnum);
|
|
|
|
g_slist_free(mlist);
|
|
|
|
if (is_refresh) {
|
|
if (!quicksearch_is_in_typing(summaryview->quicksearch)) {
|
|
summaryview->displayed =
|
|
summary_find_msg_by_msgnum(summaryview,
|
|
displayed_msgnum);
|
|
if (!summaryview->displayed)
|
|
messageview_clear(summaryview->messageview);
|
|
summary_unlock(summaryview);
|
|
|
|
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,
|
|
FALSE);
|
|
|
|
summary_lock(summaryview);
|
|
if (!summaryview->selected) {
|
|
/* no selected message - select first unread
|
|
message, but do not display it */
|
|
node = summary_find_next_flagged_msg(summaryview, NULL,
|
|
MSG_UNREAD, FALSE);
|
|
if (node == NULL && GTK_CMCLIST(ctree)->row_list != NULL)
|
|
node = gtk_cmctree_node_nth
|
|
(ctree,
|
|
item->sort_type == SORT_DESCENDING
|
|
? 0 : GTK_CMCLIST(ctree)->rows - 1);
|
|
summary_unlock(summaryview);
|
|
|
|
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 {
|
|
/* just select first/last */
|
|
if (GTK_CMCLIST(ctree)->row_list != NULL)
|
|
node = gtk_cmctree_node_nth
|
|
(ctree,
|
|
item->sort_type == SORT_DESCENDING
|
|
? 0 : GTK_CMCLIST(ctree)->rows - 1);
|
|
summary_select_node(summaryview, node, OPEN_SELECTED_ON_SEARCH_RESULTS);
|
|
}
|
|
} else {
|
|
/* backward compat */
|
|
int i = 0;
|
|
gboolean set = FALSE, stop = FALSE;
|
|
for (i = 0; i < 6; i++) {
|
|
EntryAction act = prefs_common.summary_select_prio[i];
|
|
|
|
if (act != ACTION_UNSET) {
|
|
set = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (!set)
|
|
prefs_summary_open_set_defaults();
|
|
|
|
for (i = 0; i < 6 && node == NULL; i++) {
|
|
EntryAction act = prefs_common.summary_select_prio[i];
|
|
|
|
switch(act) {
|
|
case ACTION_OLDEST_MARKED:
|
|
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_NEWEST_MARKED:
|
|
if (summaryview->sort_type == SORT_ASCENDING)
|
|
node = summary_find_prev_flagged_msg(summaryview, NULL,
|
|
MSG_MARKED, FALSE);
|
|
else
|
|
node = summary_find_next_flagged_msg(summaryview, NULL,
|
|
MSG_MARKED, FALSE);
|
|
break;
|
|
case ACTION_OLDEST_NEW:
|
|
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_NEWEST_NEW:
|
|
if (summaryview->sort_type == SORT_ASCENDING)
|
|
node = summary_find_prev_flagged_msg(summaryview, NULL,
|
|
MSG_NEW, FALSE);
|
|
else
|
|
node = summary_find_next_flagged_msg(summaryview, NULL,
|
|
MSG_NEW, FALSE);
|
|
break;
|
|
case ACTION_OLDEST_UNREAD:
|
|
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_NEWEST_UNREAD:
|
|
if (summaryview->sort_type == SORT_ASCENDING)
|
|
node = summary_find_prev_flagged_msg(summaryview, NULL,
|
|
MSG_UNREAD, FALSE);
|
|
else
|
|
node = summary_find_next_flagged_msg(summaryview, NULL,
|
|
MSG_UNREAD, FALSE);
|
|
break;
|
|
case ACTION_LAST_OPENED:
|
|
if (summaryview->folder_item) {
|
|
node = summary_find_msg_by_msgnum(summaryview,
|
|
summaryview->folder_item->last_seen);
|
|
}
|
|
break;
|
|
case ACTION_NEWEST_LIST:
|
|
if (GTK_CMCLIST(ctree)->row_list != NULL) {
|
|
node = gtk_cmctree_node_nth
|
|
(ctree,
|
|
item->sort_type == SORT_DESCENDING
|
|
? 0 : GTK_CMCLIST(ctree)->rows - 1);
|
|
}
|
|
break;
|
|
case ACTION_OLDEST_LIST:
|
|
if (GTK_CMCLIST(ctree)->row_list != NULL) {
|
|
node = gtk_cmctree_node_nth
|
|
(ctree,
|
|
item->sort_type == SORT_ASCENDING
|
|
? 0 : GTK_CMCLIST(ctree)->rows - 1);
|
|
}
|
|
break;
|
|
case ACTION_NOTHING:
|
|
case ACTION_UNSET:
|
|
node = NULL;
|
|
stop = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (stop || node)
|
|
break;
|
|
}
|
|
|
|
summary_unlock(summaryview);
|
|
|
|
if (node) {
|
|
gint open_selected = -1;
|
|
if (!is_refresh) {
|
|
if (OPEN_SELECTED_ON_FOLDER_OPEN)
|
|
open_selected = 1;
|
|
else
|
|
open_selected = 0;
|
|
}
|
|
summary_select_node(summaryview, node, open_selected);
|
|
}
|
|
|
|
summary_lock(summaryview);
|
|
}
|
|
|
|
summary_status_show(summaryview);
|
|
summary_set_menu_sensitive(summaryview);
|
|
toolbar_main_set_sensitive(summaryview->mainwin);
|
|
|
|
summary_thaw(summaryview);
|
|
debug_print("\n");
|
|
STATUSBAR_PUSH(summaryview->mainwin, _("Done."));
|
|
STATUSBAR_POP(summaryview->mainwin);
|
|
main_window_cursor_normal(summaryview->mainwin);
|
|
summary_unlock(summaryview);
|
|
inc_unlock();
|
|
END_TIMING();
|
|
return TRUE;
|
|
}
|
|
|
|
#undef CURRENTLY_DISPLAYED
|
|
|
|
static void summary_cancel_mark_read_timeout(SummaryView *summaryview) {
|
|
if (summaryview->mark_as_read_timeout_tag != 0) {
|
|
g_source_remove(summaryview->mark_as_read_timeout_tag);
|
|
summaryview->mark_as_read_timeout_tag = 0;
|
|
}
|
|
}
|
|
|
|
void summary_clear_list(SummaryView *summaryview)
|
|
{
|
|
GtkCMCList *clist = GTK_CMCLIST(summaryview->ctree);
|
|
gint optimal_width;
|
|
|
|
summary_freeze(summaryview);
|
|
|
|
gtk_cmctree_pre_recursive(GTK_CMCTREE(summaryview->ctree),
|
|
NULL, summary_free_msginfo_func, NULL);
|
|
|
|
if (summaryview->folder_item) {
|
|
summaryview->folder_item->opened = FALSE;
|
|
summaryview->folder_item = NULL;
|
|
}
|
|
|
|
summary_cancel_mark_read_timeout(summaryview);
|
|
|
|
summaryview->display_msg = FALSE;
|
|
|
|
summaryview->selected = NULL;
|
|
summaryview->displayed = NULL;
|
|
summaryview->total_size = 0;
|
|
summaryview->deleted = summaryview->moved = 0;
|
|
summaryview->copied = 0;
|
|
if (summaryview->msgid_table) {
|
|
g_hash_table_destroy(summaryview->msgid_table);
|
|
summaryview->msgid_table = NULL;
|
|
}
|
|
if (summaryview->subject_table) {
|
|
g_hash_table_destroy(summaryview->subject_table);
|
|
summaryview->subject_table = NULL;
|
|
}
|
|
summaryview->mlist = NULL;
|
|
|
|
gtk_cmclist_clear(clist);
|
|
if (summaryview->col_pos[S_COL_SUBJECT] == N_SUMMARY_COLS - 1) {
|
|
optimal_width = gtk_cmclist_optimal_column_width
|
|
(clist, summaryview->col_pos[S_COL_SUBJECT]);
|
|
gtk_cmclist_set_column_width
|
|
(clist, summaryview->col_pos[S_COL_SUBJECT],
|
|
optimal_width);
|
|
}
|
|
|
|
summary_thaw(summaryview);
|
|
}
|
|
|
|
void summary_clear_all(SummaryView *summaryview)
|
|
{
|
|
messageview_clear(summaryview->messageview);
|
|
summary_clear_list(summaryview);
|
|
summary_set_menu_sensitive(summaryview);
|
|
toolbar_main_set_sensitive(summaryview->mainwin);
|
|
summary_status_show(summaryview);
|
|
}
|
|
|
|
void summary_lock(SummaryView *summaryview)
|
|
{
|
|
summaryview->lock_count++;
|
|
}
|
|
|
|
void summary_unlock(SummaryView *summaryview)
|
|
{
|
|
if (summaryview->lock_count)
|
|
summaryview->lock_count--;
|
|
}
|
|
|
|
gboolean summary_is_locked(SummaryView *summaryview)
|
|
{
|
|
return summaryview->lock_count > 0;
|
|
}
|
|
|
|
SummarySelection summary_get_selection_type(SummaryView *summaryview)
|
|
{
|
|
GtkCMCList *clist = GTK_CMCLIST(summaryview->ctree);
|
|
SummarySelection selection;
|
|
|
|
if (!clist->row_list)
|
|
selection = SUMMARY_NONE;
|
|
else if (!clist->selection)
|
|
selection = SUMMARY_SELECTED_NONE;
|
|
else if (!clist->selection->next)
|
|
selection = SUMMARY_SELECTED_SINGLE;
|
|
else
|
|
selection = SUMMARY_SELECTED_MULTIPLE;
|
|
|
|
return selection;
|
|
}
|
|
|
|
/*!
|
|
*\return MsgInfo * Selected message if there's one selected;
|
|
* if multiple selected, or none, return NULL.
|
|
*/
|
|
MsgInfo *summary_get_selected_msg(SummaryView *summaryview)
|
|
{
|
|
/* summaryview->selected may be valid when multiple
|
|
* messages were selected */
|
|
GList *sellist = GTK_CMCLIST(summaryview->ctree)->selection;
|
|
|
|
if (sellist == NULL || sellist->next)
|
|
return NULL;
|
|
|
|
return GTKUT_CTREE_NODE_GET_ROW_DATA(sellist->data);
|
|
}
|
|
|
|
GSList *summary_get_selected_msg_list(SummaryView *summaryview)
|
|
{
|
|
GSList *mlist = NULL;
|
|
GList *cur;
|
|
MsgInfo *msginfo;
|
|
|
|
for (cur = GTK_CMCLIST(summaryview->ctree)->selection; cur != NULL && cur->data != NULL;
|
|
cur = cur->next) {
|
|
msginfo = GTKUT_CTREE_NODE_GET_ROW_DATA(cur->data);
|
|
mlist = g_slist_prepend(mlist,
|
|
procmsg_msginfo_new_ref(msginfo));
|
|
}
|
|
|
|
mlist = g_slist_reverse(mlist);
|
|
|
|
return mlist;
|
|
}
|
|
|
|
void summary_set_menu_sensitive(SummaryView *summaryview)
|
|
{
|
|
SensitiveCondMask state;
|
|
gboolean sensitive;
|
|
gint i;
|
|
|
|
#ifndef GENERIC_UMPC
|
|
#define N_ENTRIES 39
|
|
#else
|
|
#define N_ENTRIES 28
|
|
#endif
|
|
static struct {
|
|
const gchar *entry;
|
|
SensitiveCondMask cond;
|
|
} entry[N_ENTRIES];
|
|
|
|
i = 0;
|
|
#define FILL_TABLE(entry_str, ...) \
|
|
do { \
|
|
entry[i].entry = (const gchar *) entry_str; entry[i++].cond = main_window_get_mask(__VA_ARGS__, -1); \
|
|
} while (0)
|
|
|
|
FILL_TABLE("Menus/SummaryViewPopup/Reply", M_HAVE_ACCOUNT, M_TARGET_EXIST);
|
|
#ifndef GENERIC_UMPC
|
|
FILL_TABLE("Menus/SummaryViewPopup/ReplyTo", M_HAVE_ACCOUNT, M_TARGET_EXIST);
|
|
FILL_TABLE("Menus/SummaryViewPopup/ReplyTo/All", M_HAVE_ACCOUNT, M_TARGET_EXIST);
|
|
FILL_TABLE("Menus/SummaryViewPopup/ReplyTo/Sender", M_HAVE_ACCOUNT, M_TARGET_EXIST);
|
|
FILL_TABLE("Menus/SummaryViewPopup/ReplyTo/MailingList", M_HAVE_ACCOUNT, M_TARGET_EXIST);
|
|
#endif
|
|
|
|
FILL_TABLE("Menus/SummaryViewPopup/Forward", M_HAVE_ACCOUNT, M_TARGET_EXIST);
|
|
#ifndef GENERIC_UMPC
|
|
FILL_TABLE("Menus/SummaryViewPopup/ForwardAtt", M_HAVE_ACCOUNT, M_TARGET_EXIST);
|
|
FILL_TABLE("Menus/SummaryViewPopup/Redirect", M_HAVE_ACCOUNT, M_TARGET_EXIST);
|
|
#endif
|
|
|
|
FILL_TABLE("Menus/SummaryViewPopup/Move", M_TARGET_EXIST, M_ALLOW_DELETE, M_NOT_NEWS);
|
|
FILL_TABLE("Menus/SummaryViewPopup/Copy", M_TARGET_EXIST, M_EXEC);
|
|
FILL_TABLE("Menus/SummaryViewPopup/Trash", M_TARGET_EXIST, M_ALLOW_DELETE, M_NOT_NEWS, M_NOT_TRASH);
|
|
#ifndef GENERIC_UMPC
|
|
FILL_TABLE("Menus/SummaryViewPopup/Delete", M_TARGET_EXIST, M_ALLOW_DELETE);
|
|
#endif
|
|
|
|
FILL_TABLE("Menus/SummaryViewPopup/Mark", M_TARGET_EXIST);
|
|
FILL_TABLE("Menus/SummaryViewPopup/Mark/Mark", M_TARGET_EXIST);
|
|
FILL_TABLE("Menus/SummaryViewPopup/Mark/Unmark", M_TARGET_EXIST);
|
|
FILL_TABLE("Menus/SummaryViewPopup/Mark/MarkRead", M_TARGET_EXIST);
|
|
FILL_TABLE("Menus/SummaryViewPopup/Mark/MarkUnread", M_TARGET_EXIST);
|
|
FILL_TABLE("Menus/SummaryViewPopup/Mark/MarkAllRead", M_TARGET_EXIST);
|
|
FILL_TABLE("Menus/SummaryViewPopup/Mark/MarkAllUnread", M_TARGET_EXIST);
|
|
FILL_TABLE("Menus/SummaryViewPopup/Mark/IgnoreThread", M_TARGET_EXIST);
|
|
FILL_TABLE("Menus/SummaryViewPopup/Mark/UnignoreThread", M_TARGET_EXIST);
|
|
FILL_TABLE("Menus/SummaryViewPopup/Mark/WatchThread", M_TARGET_EXIST);
|
|
FILL_TABLE("Menus/SummaryViewPopup/Mark/UnwatchThread", M_TARGET_EXIST);
|
|
FILL_TABLE("Menus/SummaryViewPopup/Mark/Lock", M_TARGET_EXIST);
|
|
FILL_TABLE("Menus/SummaryViewPopup/Mark/Unlock", M_TARGET_EXIST);
|
|
FILL_TABLE("Menus/SummaryViewPopup/Mark/MarkSpam", M_TARGET_EXIST, M_CAN_LEARN_SPAM);
|
|
FILL_TABLE("Menus/SummaryViewPopup/Mark/MarkHam", M_TARGET_EXIST, M_CAN_LEARN_SPAM);
|
|
FILL_TABLE("Menus/SummaryViewPopup/ColorLabel", M_TARGET_EXIST);
|
|
FILL_TABLE("Menus/SummaryViewPopup/Tags", M_TARGET_EXIST);
|
|
|
|
#ifndef GENERIC_UMPC
|
|
FILL_TABLE("Menus/SummaryViewPopup/AddSenderToAB", M_SINGLE_TARGET_EXIST);
|
|
#endif
|
|
FILL_TABLE("Menus/SummaryViewPopup/CreateFilterRule", M_SINGLE_TARGET_EXIST, M_UNLOCKED);
|
|
#ifndef GENERIC_UMPC
|
|
FILL_TABLE("Menus/SummaryViewPopup/CreateProcessingRule", M_SINGLE_TARGET_EXIST, M_UNLOCKED);
|
|
#endif
|
|
|
|
FILL_TABLE("Menus/SummaryViewPopup/View", M_SINGLE_TARGET_EXIST);
|
|
FILL_TABLE("Menus/SummaryViewPopup/View/OpenNewWindow", M_SINGLE_TARGET_EXIST);
|
|
FILL_TABLE("Menus/SummaryViewPopup/View/MessageSource", M_SINGLE_TARGET_EXIST);
|
|
#ifndef GENERIC_UMPC
|
|
FILL_TABLE("Menus/SummaryViewPopup/View/AllHeaders", M_SINGLE_TARGET_EXIST);
|
|
#endif
|
|
FILL_TABLE("Menus/SummaryViewPopup/SaveAs", M_TARGET_EXIST);
|
|
#ifndef GENERIC_UMPC
|
|
FILL_TABLE("Menus/SummaryViewPopup/Print", M_TARGET_EXIST);
|
|
#endif
|
|
FILL_TABLE(NULL, -1);
|
|
#undef FILL_TABLE
|
|
if (i != N_ENTRIES)
|
|
g_error("summaryview menu entry table size mismatch (%d/%d)", i, N_ENTRIES);
|
|
#undef ENTRIES
|
|
|
|
main_window_set_menu_sensitive(summaryview->mainwin);
|
|
|
|
state = main_window_get_current_state(summaryview->mainwin);
|
|
|
|
for (i = 0; entry[i].entry != NULL; i++) {
|
|
sensitive = ((entry[i].cond & state) == entry[i].cond);
|
|
cm_menu_set_sensitive_full(summaryview->mainwin->ui_manager, entry[i].entry, sensitive);
|
|
}
|
|
|
|
summary_lock(summaryview);
|
|
#ifndef GENERIC_UMPC
|
|
if (summaryview->messageview
|
|
&& summaryview->messageview->mimeview
|
|
&& summaryview->messageview->mimeview->textview)
|
|
cm_toggle_menu_set_active_full(summaryview->mainwin->ui_manager, "Menus/SummaryViewPopup/View/AllHeaders",
|
|
prefs_common.show_all_headers);
|
|
#endif
|
|
summary_unlock(summaryview);
|
|
}
|
|
void summary_select_prev(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTreeNode *node = summaryview->selected;
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
|
|
if (summaryview->sort_type == SORT_ASCENDING)
|
|
node = gtkut_ctree_node_prev(ctree, node);
|
|
else
|
|
node = gtkut_ctree_node_next(ctree, node);
|
|
|
|
if (node && node != summaryview->selected)
|
|
summary_select_node(summaryview, node, OPEN_SELECTED_ON_PREVNEXT);
|
|
}
|
|
|
|
void summary_select_next(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTreeNode *node = summaryview->selected;
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
|
|
if (summaryview->sort_type == SORT_ASCENDING)
|
|
node = gtkut_ctree_node_next(ctree, node);
|
|
else
|
|
node = gtkut_ctree_node_prev(ctree, node);
|
|
|
|
if (node && node != summaryview->selected)
|
|
summary_select_node(summaryview, node, OPEN_SELECTED_ON_PREVNEXT);
|
|
}
|
|
|
|
void summary_select_prev_unread(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTreeNode *node;
|
|
|
|
if (summaryview->sort_type == SORT_ASCENDING)
|
|
node = summary_find_prev_flagged_msg
|
|
(summaryview, summaryview->selected, MSG_UNREAD, TRUE);
|
|
else
|
|
node = summary_find_next_flagged_msg
|
|
(summaryview, summaryview->selected, MSG_UNREAD, TRUE);
|
|
|
|
if (!node || node == summaryview->selected) {
|
|
AlertValue val = 0;
|
|
|
|
switch (prefs_common.next_unread_msg_dialog) {
|
|
case NEXTUNREADMSGDIALOG_ALWAYS:
|
|
val = alertpanel(_("No more unread messages"),
|
|
_("No unread message found. "
|
|
"Search from the end?"),
|
|
GTK_STOCK_NO, GTK_STOCK_YES, NULL, ALERTFOCUS_SECOND);
|
|
break;
|
|
case NEXTUNREADMSGDIALOG_ASSUME_YES:
|
|
val = G_ALERTALTERNATE;
|
|
break;
|
|
case NEXTUNREADMSGDIALOG_ASSUME_NO:
|
|
val = !G_ALERTALTERNATE;
|
|
break;
|
|
default:
|
|
debug_print(
|
|
_("Internal error: unexpected value for prefs_common.next_unread_msg_dialog\n"));
|
|
}
|
|
if (val != G_ALERTALTERNATE) return;
|
|
if (summaryview->sort_type == SORT_ASCENDING)
|
|
node = summary_find_prev_flagged_msg(summaryview, NULL,
|
|
MSG_UNREAD, FALSE);
|
|
else
|
|
node = summary_find_next_flagged_msg(summaryview, NULL,
|
|
MSG_UNREAD, FALSE);
|
|
}
|
|
|
|
if (!node)
|
|
alertpanel_notice(_("No unread messages."));
|
|
else
|
|
summary_select_node(summaryview, node, OPEN_SELECTED_ON_PREVNEXT);
|
|
}
|
|
|
|
void summary_select_next_unread(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTreeNode *node = summaryview->selected;
|
|
|
|
if (summaryview->sort_type == SORT_ASCENDING)
|
|
node = summary_find_next_flagged_msg
|
|
(summaryview, node, MSG_UNREAD, TRUE);
|
|
else
|
|
node = summary_find_prev_flagged_msg
|
|
(summaryview, node, MSG_UNREAD, TRUE);
|
|
|
|
if (node)
|
|
summary_select_node(summaryview, node, OPEN_SELECTED_ON_PREVNEXT);
|
|
else {
|
|
AlertValue val = 0;
|
|
|
|
switch (prefs_common.next_unread_msg_dialog) {
|
|
case NEXTUNREADMSGDIALOG_ALWAYS:
|
|
val = alertpanel(_("No more unread messages"),
|
|
_("No unread message found. "
|
|
"Go to next folder?"),
|
|
GTK_STOCK_NO, GTK_STOCK_YES, NULL, ALERTFOCUS_SECOND);
|
|
break;
|
|
case NEXTUNREADMSGDIALOG_ASSUME_YES:
|
|
val = G_ALERTALTERNATE;
|
|
break;
|
|
case NEXTUNREADMSGDIALOG_ASSUME_NO:
|
|
val = G_ALERTOTHER;
|
|
break;
|
|
default:
|
|
debug_print(
|
|
_("Internal error: unexpected value for prefs_common.next_unread_msg_dialog\n"));
|
|
}
|
|
|
|
if (val == G_ALERTALTERNATE)
|
|
folderview_select_next_with_flag(summaryview->folderview, MSG_UNREAD);
|
|
}
|
|
}
|
|
|
|
void summary_select_prev_new(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTreeNode *node;
|
|
|
|
if (summaryview->sort_type == SORT_ASCENDING)
|
|
node = summary_find_prev_flagged_msg
|
|
(summaryview, summaryview->selected, MSG_NEW, TRUE);
|
|
else
|
|
node = summary_find_next_flagged_msg
|
|
(summaryview, summaryview->selected, MSG_NEW, TRUE);
|
|
|
|
if (!node || node == summaryview->selected) {
|
|
AlertValue val = 0;
|
|
|
|
switch (prefs_common.next_unread_msg_dialog) {
|
|
case NEXTUNREADMSGDIALOG_ALWAYS:
|
|
val = alertpanel(_("No more new messages"),
|
|
_("No new message found. "
|
|
"Search from the end?"),
|
|
GTK_STOCK_NO, GTK_STOCK_YES, NULL, ALERTFOCUS_SECOND);
|
|
break;
|
|
case NEXTUNREADMSGDIALOG_ASSUME_YES:
|
|
val = G_ALERTALTERNATE;
|
|
break;
|
|
case NEXTUNREADMSGDIALOG_ASSUME_NO:
|
|
val = !G_ALERTALTERNATE;
|
|
break;
|
|
default:
|
|
debug_print(
|
|
_("Internal error: unexpected value for prefs_common.next_unread_msg_dialog\n"));
|
|
}
|
|
if (val != G_ALERTALTERNATE) return;
|
|
if (summaryview->sort_type == SORT_ASCENDING)
|
|
node = summary_find_prev_flagged_msg(summaryview, NULL,
|
|
MSG_NEW, FALSE);
|
|
else
|
|
node = summary_find_next_flagged_msg(summaryview, NULL,
|
|
MSG_NEW, FALSE);
|
|
}
|
|
|
|
if (!node)
|
|
alertpanel_notice(_("No new messages."));
|
|
else
|
|
summary_select_node(summaryview, node, OPEN_SELECTED_ON_PREVNEXT);
|
|
}
|
|
|
|
void summary_select_next_new(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTreeNode *node = summaryview->selected;
|
|
|
|
if (summaryview->sort_type == SORT_ASCENDING)
|
|
node = summary_find_next_flagged_msg
|
|
(summaryview, node, MSG_NEW, TRUE);
|
|
else
|
|
node = summary_find_prev_flagged_msg
|
|
(summaryview, node, MSG_NEW, TRUE);
|
|
|
|
if (node)
|
|
summary_select_node(summaryview, node, OPEN_SELECTED_ON_PREVNEXT);
|
|
else {
|
|
AlertValue val = 0;
|
|
|
|
switch (prefs_common.next_unread_msg_dialog) {
|
|
case NEXTUNREADMSGDIALOG_ALWAYS:
|
|
val = alertpanel(_("No more new messages"),
|
|
_("No new message found. "
|
|
"Go to next folder?"),
|
|
GTK_STOCK_NO, GTK_STOCK_YES, NULL, ALERTFOCUS_SECOND);
|
|
break;
|
|
case NEXTUNREADMSGDIALOG_ASSUME_YES:
|
|
val = G_ALERTALTERNATE;
|
|
break;
|
|
case NEXTUNREADMSGDIALOG_ASSUME_NO:
|
|
val = G_ALERTOTHER;
|
|
break;
|
|
default:
|
|
debug_print(
|
|
_("Internal error: unexpected value for prefs_common.next_unread_msg_dialog\n"));
|
|
}
|
|
if (val == G_ALERTALTERNATE)
|
|
folderview_select_next_with_flag(summaryview->folderview, MSG_NEW);
|
|
}
|
|
}
|
|
|
|
void summary_select_prev_marked(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTreeNode *node;
|
|
|
|
if (summaryview->sort_type == SORT_ASCENDING)
|
|
node = summary_find_prev_flagged_msg
|
|
(summaryview, summaryview->selected, MSG_MARKED, TRUE);
|
|
else
|
|
node = summary_find_next_flagged_msg
|
|
(summaryview, summaryview->selected, MSG_MARKED, TRUE);
|
|
|
|
if (!node) {
|
|
AlertValue val;
|
|
|
|
val = alertpanel(_("No more marked messages"),
|
|
_("No marked message found. "
|
|
"Search from the end?"),
|
|
GTK_STOCK_NO, GTK_STOCK_YES, NULL, ALERTFOCUS_SECOND);
|
|
if (val != G_ALERTALTERNATE) return;
|
|
node = summary_find_prev_flagged_msg(summaryview, NULL,
|
|
MSG_MARKED, TRUE);
|
|
}
|
|
|
|
if (!node)
|
|
alertpanel_notice(_("No marked messages."));
|
|
else
|
|
summary_select_node(summaryview, node, OPEN_SELECTED_ON_PREVNEXT);
|
|
}
|
|
|
|
void summary_select_next_marked(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTreeNode *node = summaryview->selected;
|
|
|
|
if (summaryview->sort_type == SORT_ASCENDING)
|
|
node = summary_find_next_flagged_msg
|
|
(summaryview, node, MSG_MARKED, TRUE);
|
|
else
|
|
node = summary_find_prev_flagged_msg
|
|
(summaryview, node, MSG_MARKED, TRUE);
|
|
|
|
if (node)
|
|
summary_select_node(summaryview, node, OPEN_SELECTED_ON_PREVNEXT);
|
|
else {
|
|
AlertValue val = 0;
|
|
|
|
switch (prefs_common.next_unread_msg_dialog) {
|
|
case NEXTUNREADMSGDIALOG_ALWAYS:
|
|
val = alertpanel(_("No more marked messages"),
|
|
_("No marked message found. "
|
|
"Go to next folder?"),
|
|
GTK_STOCK_NO, GTK_STOCK_YES, NULL, ALERTFOCUS_SECOND);
|
|
break;
|
|
case NEXTUNREADMSGDIALOG_ASSUME_YES:
|
|
val = G_ALERTALTERNATE;
|
|
break;
|
|
case NEXTUNREADMSGDIALOG_ASSUME_NO:
|
|
val = G_ALERTOTHER;
|
|
break;
|
|
default:
|
|
debug_print(
|
|
_("Internal error: unexpected value for prefs_common.next_unread_msg_dialog\n"));
|
|
}
|
|
if (val == G_ALERTALTERNATE)
|
|
folderview_select_next_with_flag(summaryview->folderview, MSG_MARKED);
|
|
}
|
|
}
|
|
|
|
void summary_select_prev_labeled(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTreeNode *node;
|
|
|
|
if (summaryview->sort_type == SORT_ASCENDING)
|
|
node = summary_find_prev_flagged_msg
|
|
(summaryview, summaryview->selected, MSG_CLABEL_FLAG_MASK, TRUE);
|
|
else
|
|
node = summary_find_next_flagged_msg
|
|
(summaryview, summaryview->selected, MSG_CLABEL_FLAG_MASK, TRUE);
|
|
|
|
if (!node) {
|
|
AlertValue val;
|
|
|
|
val = alertpanel(_("No more labeled messages"),
|
|
_("No labeled message found. "
|
|
"Search from the end?"),
|
|
GTK_STOCK_NO, GTK_STOCK_YES, NULL, ALERTFOCUS_SECOND);
|
|
if (val != G_ALERTALTERNATE) return;
|
|
node = summary_find_prev_flagged_msg(summaryview, NULL,
|
|
MSG_CLABEL_FLAG_MASK, TRUE);
|
|
}
|
|
|
|
if (!node)
|
|
alertpanel_notice(_("No labeled messages."));
|
|
else
|
|
summary_select_node(summaryview, node, OPEN_SELECTED_ON_PREVNEXT);
|
|
}
|
|
|
|
void summary_select_next_labeled(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTreeNode *node;
|
|
|
|
if (summaryview->sort_type == SORT_ASCENDING)
|
|
node = summary_find_next_flagged_msg
|
|
(summaryview, summaryview->selected, MSG_CLABEL_FLAG_MASK, TRUE);
|
|
else
|
|
node = summary_find_prev_flagged_msg
|
|
(summaryview, summaryview->selected, MSG_CLABEL_FLAG_MASK, TRUE);
|
|
|
|
if (!node) {
|
|
AlertValue val;
|
|
|
|
val = alertpanel(_("No more labeled messages"),
|
|
_("No labeled message found. "
|
|
"Search from the beginning?"),
|
|
GTK_STOCK_NO, GTK_STOCK_YES, NULL, ALERTFOCUS_SECOND);
|
|
if (val != G_ALERTALTERNATE) return;
|
|
if (summaryview->sort_type == SORT_ASCENDING)
|
|
node = summary_find_next_flagged_msg(summaryview, NULL,
|
|
MSG_CLABEL_FLAG_MASK, TRUE);
|
|
else
|
|
node = summary_find_prev_flagged_msg(summaryview, NULL,
|
|
MSG_CLABEL_FLAG_MASK, TRUE);
|
|
}
|
|
|
|
if (!node)
|
|
alertpanel_notice(_("No labeled messages."));
|
|
else
|
|
summary_select_node(summaryview, node, OPEN_SELECTED_ON_PREVNEXT);
|
|
}
|
|
|
|
void summary_select_parent(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTreeNode *node = NULL;
|
|
|
|
if (summaryview->selected)
|
|
node = GTK_CMCTREE_ROW(summaryview->selected)->parent;
|
|
if (node)
|
|
summary_select_node(summaryview, node, OPEN_SELECTED_ON_PREVNEXT);
|
|
}
|
|
|
|
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, show);
|
|
}
|
|
|
|
void summary_select_by_msg_list(SummaryView *summaryview, GSList *msginfos)
|
|
{
|
|
GtkCMCTree *ctree;
|
|
GSList *msgnum_list, *walk;
|
|
gboolean froze = FALSE;
|
|
|
|
ctree = GTK_CMCTREE(summaryview->ctree);
|
|
|
|
msgnum_list = procmsg_get_number_list_for_msgs(msginfos);
|
|
|
|
START_LONG_OPERATION(summaryview, FALSE);
|
|
for(walk = msgnum_list; walk; walk = walk->next) {
|
|
GtkCMCTreeNode *node;
|
|
node = summary_find_msg_by_msgnum(summaryview, GPOINTER_TO_UINT(walk->data));
|
|
if (node != NULL)
|
|
gtk_cmctree_select(ctree, node);
|
|
}
|
|
END_LONG_OPERATION(summaryview);
|
|
g_slist_free(msgnum_list);
|
|
}
|
|
|
|
typedef struct _PostponedSelectData
|
|
{
|
|
GtkCMCTree *ctree;
|
|
GtkCMCTreeNode *row;
|
|
GtkCMCTreeNode *node;
|
|
GtkScrollType type;
|
|
gint column;
|
|
SummaryView *summaryview;
|
|
gboolean display_msg;
|
|
} PostponedSelectData;
|
|
|
|
static gboolean summary_select_retry(void *data)
|
|
{
|
|
PostponedSelectData *psdata = (PostponedSelectData *)data;
|
|
debug_print("trying again\n");
|
|
if (psdata->row)
|
|
summary_selected(psdata->ctree, psdata->row,
|
|
psdata->column, psdata->summaryview);
|
|
else if (psdata->node)
|
|
summary_select_node(psdata->summaryview, psdata->node,
|
|
psdata->display_msg);
|
|
g_free(psdata);
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* summary_select_node:
|
|
* @summaryview: Summary view.
|
|
* @node: Summary tree node.
|
|
* @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.
|
|
**/
|
|
|
|
void summary_select_node(SummaryView *summaryview, GtkCMCTreeNode *node,
|
|
gboolean display_msg)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
|
|
/* 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
|
|
&& summaryview->messageview->mimeview
|
|
&& summaryview->messageview->mimeview->type == MIMEVIEW_TEXT
|
|
&& summaryview->messageview->mimeview->textview->loading) {
|
|
PostponedSelectData *data = g_new0(PostponedSelectData, 1);
|
|
summaryview->messageview->mimeview->textview->stop_loading = TRUE;
|
|
|
|
data->ctree = ctree;
|
|
data->row = NULL;
|
|
data->node = node;
|
|
data->summaryview = summaryview;
|
|
data->display_msg = display_msg;
|
|
debug_print("postponing open of message till end of load\n");
|
|
g_timeout_add(100, summary_select_retry, data);
|
|
return;
|
|
}
|
|
if (summary_is_locked(summaryview)) {
|
|
return;
|
|
}
|
|
if (!summaryview->folder_item)
|
|
return;
|
|
if (node) {
|
|
gtkut_ctree_expand_parent_all(ctree, node);
|
|
|
|
summary_lock(summaryview);
|
|
GTK_EVENTS_FLUSH();
|
|
summary_unlock(summaryview);
|
|
|
|
/* If quicksearch has focus, let's keep it there. */
|
|
if (!quicksearch_has_focus(summaryview->quicksearch))
|
|
summary_grab_focus(summaryview);
|
|
|
|
gtkut_ctree_node_move_if_on_the_edge(ctree, node, -1);
|
|
|
|
if (display_msg && summaryview->displayed == node)
|
|
summaryview->displayed = NULL;
|
|
summaryview->display_msg = display_msg;
|
|
gtk_sctree_select(GTK_SCTREE(ctree), node);
|
|
if (summaryview->selected == NULL)
|
|
summaryview->selected = node;
|
|
}
|
|
}
|
|
|
|
guint summary_get_msgnum(SummaryView *summaryview, GtkCMCTreeNode *node)
|
|
{
|
|
GtkCMCTree *ctree =NULL;
|
|
MsgInfo *msginfo;
|
|
|
|
if (!summaryview)
|
|
return 0;
|
|
ctree = GTK_CMCTREE(summaryview->ctree);
|
|
if (!node)
|
|
return 0;
|
|
msginfo = gtk_cmctree_node_get_row_data(ctree, node);
|
|
if (msginfo)
|
|
return msginfo->msgnum;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
static GtkCMCTreeNode *summary_find_prev_msg(SummaryView *summaryview,
|
|
GtkCMCTreeNode *current_node,
|
|
gboolean start_from_prev)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GtkCMCTreeNode *node;
|
|
MsgInfo *msginfo;
|
|
|
|
if (current_node) {
|
|
if (start_from_prev)
|
|
node = gtkut_ctree_node_prev(ctree, current_node);
|
|
else
|
|
node = current_node;
|
|
} else
|
|
node = gtk_cmctree_node_nth(ctree, GTK_CMCLIST(ctree)->rows - 1);
|
|
|
|
for (; node != NULL; node = gtkut_ctree_node_prev(ctree, node)) {
|
|
msginfo = gtk_cmctree_node_get_row_data(ctree, node);
|
|
if (msginfo && !MSG_IS_DELETED(msginfo->flags)) break;
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
static GtkCMCTreeNode *summary_find_next_msg(SummaryView *summaryview,
|
|
GtkCMCTreeNode *current_node,
|
|
gboolean start_from_next)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GtkCMCTreeNode *node;
|
|
MsgInfo *msginfo;
|
|
|
|
if (current_node) {
|
|
if (start_from_next)
|
|
node = gtkut_ctree_node_next(ctree, current_node);
|
|
else
|
|
node = current_node;
|
|
} else
|
|
node = GTK_CMCTREE_NODE(GTK_CMCLIST(ctree)->row_list);
|
|
|
|
for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
|
|
msginfo = gtk_cmctree_node_get_row_data(ctree, node);
|
|
if (msginfo && !MSG_IS_DELETED(msginfo->flags)
|
|
&& !MSG_IS_MOVE(msginfo->flags)) break;
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
static GtkCMCTreeNode *summary_find_prev_flagged_msg(SummaryView *summaryview,
|
|
GtkCMCTreeNode *current_node,
|
|
MsgPermFlags flags,
|
|
gboolean start_from_prev)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GtkCMCTreeNode *node;
|
|
MsgInfo *msginfo;
|
|
|
|
if (current_node) {
|
|
if (start_from_prev)
|
|
node = gtkut_ctree_node_prev(ctree, current_node);
|
|
else
|
|
node = current_node;
|
|
} else
|
|
node = gtk_cmctree_node_nth(ctree, GTK_CMCLIST(ctree)->rows - 1);
|
|
|
|
for (; node != NULL; node = gtkut_ctree_node_prev(ctree, node)) {
|
|
msginfo = gtk_cmctree_node_get_row_data(ctree, node);
|
|
if (msginfo && (msginfo->flags.perm_flags & flags) != 0) break;
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
static GtkCMCTreeNode *summary_find_next_flagged_msg(SummaryView *summaryview,
|
|
GtkCMCTreeNode *current_node,
|
|
MsgPermFlags flags,
|
|
gboolean start_from_next)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GtkCMCTreeNode *node;
|
|
MsgInfo *msginfo;
|
|
|
|
if (current_node) {
|
|
if (start_from_next)
|
|
node = gtkut_ctree_node_next(ctree, current_node);
|
|
else
|
|
node = current_node;
|
|
} else
|
|
node = GTK_CMCTREE_NODE(GTK_CMCLIST(ctree)->row_list);
|
|
|
|
for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
|
|
msginfo = gtk_cmctree_node_get_row_data(ctree, node);
|
|
/* Find msg with matching flags but ignore messages with
|
|
ignore flags, if searching for new or unread messages */
|
|
if ((msginfo && (msginfo->flags.perm_flags & flags) != 0) &&
|
|
!(((flags & (MSG_NEW | MSG_UNREAD)) != 0) && MSG_IS_IGNORE_THREAD(msginfo->flags))
|
|
)
|
|
break;
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
static GtkCMCTreeNode *summary_find_msg_by_msgnum(SummaryView *summaryview,
|
|
guint msgnum)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GtkCMCTreeNode *node;
|
|
MsgInfo *msginfo;
|
|
|
|
node = GTK_CMCTREE_NODE(GTK_CMCLIST(ctree)->row_list);
|
|
|
|
for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
|
|
msginfo = gtk_cmctree_node_get_row_data(ctree, node);
|
|
if (msginfo && msginfo->msgnum == msgnum) break;
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
static guint attract_hash_func(gconstpointer key)
|
|
{
|
|
gchar *str;
|
|
gchar *p;
|
|
guint h;
|
|
|
|
Xstrdup_a(str, (const gchar *)key, return 0);
|
|
trim_subject(str);
|
|
|
|
p = str;
|
|
h = *p;
|
|
|
|
if (h) {
|
|
for (p += 1; *p != '\0'; p++)
|
|
h = (h << 5) - h + *p;
|
|
}
|
|
|
|
return h;
|
|
}
|
|
|
|
static gint attract_compare_func(gconstpointer a, gconstpointer b)
|
|
{
|
|
return subject_compare((const gchar *)a, (const gchar *)b) == 0;
|
|
}
|
|
|
|
void summary_attract_by_subject(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GtkCMCList *clist = GTK_CMCLIST(ctree);
|
|
GtkCMCTreeNode *src_node;
|
|
GtkCMCTreeNode *dst_node, *sibling;
|
|
GtkCMCTreeNode *tmp;
|
|
MsgInfo *src_msginfo, *dst_msginfo;
|
|
GHashTable *subject_table;
|
|
|
|
debug_print("Attracting messages by subject...\n");
|
|
STATUSBAR_PUSH(summaryview->mainwin,
|
|
_("Attracting messages by subject..."));
|
|
|
|
main_window_cursor_wait(summaryview->mainwin);
|
|
summary_freeze(summaryview);
|
|
|
|
subject_table = g_hash_table_new(attract_hash_func,
|
|
attract_compare_func);
|
|
|
|
for (src_node = GTK_CMCTREE_NODE(clist->row_list);
|
|
src_node != NULL;
|
|
src_node = tmp) {
|
|
tmp = GTK_CMCTREE_ROW(src_node)->sibling;
|
|
src_msginfo = GTKUT_CTREE_NODE_GET_ROW_DATA(src_node);
|
|
if (!src_msginfo) continue;
|
|
if (!src_msginfo->subject) continue;
|
|
|
|
/* find attracting node */
|
|
dst_node = g_hash_table_lookup(subject_table,
|
|
src_msginfo->subject);
|
|
|
|
if (dst_node) {
|
|
dst_msginfo = GTKUT_CTREE_NODE_GET_ROW_DATA(dst_node);
|
|
|
|
/* if the time difference is more than 20 days,
|
|
don't attract */
|
|
if (ABS(src_msginfo->date_t - dst_msginfo->date_t)
|
|
> 60 * 60 * 24 * 20)
|
|
continue;
|
|
|
|
sibling = GTK_CMCTREE_ROW(dst_node)->sibling;
|
|
if (src_node != sibling)
|
|
gtk_cmctree_move(ctree, src_node, NULL, sibling);
|
|
}
|
|
|
|
g_hash_table_insert(subject_table,
|
|
src_msginfo->subject, src_node);
|
|
}
|
|
|
|
g_hash_table_destroy(subject_table);
|
|
|
|
gtk_cmctree_node_moveto(ctree, summaryview->selected, 0, 0.5, 0);
|
|
|
|
summary_thaw(summaryview);
|
|
|
|
debug_print("Attracting messages by subject done.\n");
|
|
STATUSBAR_POP(summaryview->mainwin);
|
|
|
|
main_window_cursor_normal(summaryview->mainwin);
|
|
}
|
|
|
|
static void summary_free_msginfo_func(GtkCMCTree *ctree, GtkCMCTreeNode *node,
|
|
gpointer data)
|
|
{
|
|
MsgInfo *msginfo = gtk_cmctree_node_get_row_data(ctree, node);
|
|
|
|
if (msginfo)
|
|
procmsg_msginfo_free(&msginfo);
|
|
}
|
|
|
|
static void summary_set_marks_func(GtkCMCTree *ctree, GtkCMCTreeNode *node,
|
|
gpointer data)
|
|
{
|
|
SummaryView *summaryview = data;
|
|
MsgInfo *msginfo;
|
|
|
|
msginfo = gtk_cmctree_node_get_row_data(ctree, node);
|
|
|
|
cm_return_if_fail(msginfo != NULL);
|
|
|
|
if (MSG_IS_DELETED(msginfo->flags))
|
|
summaryview->deleted++;
|
|
|
|
summaryview->total_size += msginfo->size;
|
|
|
|
summary_set_row_marks(summaryview, node);
|
|
}
|
|
|
|
static void summary_update_status(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GtkCMCTreeNode *node;
|
|
MsgInfo *msginfo;
|
|
|
|
summaryview->total_size =
|
|
summaryview->deleted = summaryview->moved = summaryview->copied = 0;
|
|
|
|
for (node = GTK_CMCTREE_NODE(GTK_CMCLIST(ctree)->row_list);
|
|
node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
|
|
msginfo = GTKUT_CTREE_NODE_GET_ROW_DATA(node);
|
|
|
|
if (!msginfo)
|
|
continue;
|
|
|
|
if (MSG_IS_DELETED(msginfo->flags))
|
|
summaryview->deleted++;
|
|
if (MSG_IS_MOVE(msginfo->flags))
|
|
summaryview->moved++;
|
|
if (MSG_IS_COPY(msginfo->flags))
|
|
summaryview->copied++;
|
|
summaryview->total_size += msginfo->size;
|
|
}
|
|
}
|
|
|
|
static void summary_status_show(SummaryView *summaryview)
|
|
{
|
|
gchar *str;
|
|
gchar *del, *mv, *cp;
|
|
gchar *sel;
|
|
gchar *spc;
|
|
gchar *itstr;
|
|
GList *rowlist, *cur;
|
|
guint n_selected = 0, n_new = 0, n_unread = 0, n_total = 0;
|
|
guint n_marked = 0, n_replied = 0, n_forwarded = 0, n_locked = 0, n_ignored = 0, n_watched = 0;
|
|
goffset sel_size = 0, n_size = 0;
|
|
MsgInfo *msginfo;
|
|
gchar *name;
|
|
gchar *tooltip;
|
|
|
|
if (!summaryview->folder_item) {
|
|
gtk_label_set_text(GTK_LABEL(summaryview->statlabel_folder), "");
|
|
gtk_label_set_text(GTK_LABEL(summaryview->statlabel_select), "");
|
|
gtk_label_set_text(GTK_LABEL(summaryview->statlabel_msgs), "");
|
|
toolbar_main_set_sensitive(summaryview->mainwin);
|
|
return;
|
|
}
|
|
|
|
rowlist = GTK_CMCLIST(summaryview->ctree)->selection;
|
|
for (cur = rowlist; cur != NULL && cur->data != NULL; cur = cur->next) {
|
|
msginfo = gtk_cmctree_node_get_row_data
|
|
(GTK_CMCTREE(summaryview->ctree),
|
|
GTK_CMCTREE_NODE(cur->data));
|
|
if (msginfo) {
|
|
sel_size += msginfo->size;
|
|
n_selected++;
|
|
}
|
|
}
|
|
|
|
if (summaryview->folder_item->hide_read_msgs
|
|
|| summaryview->folder_item->hide_del_msgs
|
|
|| summaryview->folder_item->hide_read_threads
|
|
|| quicksearch_has_sat_predicate(summaryview->quicksearch)) {
|
|
rowlist = GTK_CMCLIST(summaryview->ctree)->row_list;
|
|
for (cur = rowlist; cur != NULL && cur->data != NULL; cur = cur->next) {
|
|
msginfo = gtk_cmctree_node_get_row_data
|
|
(GTK_CMCTREE(summaryview->ctree),
|
|
GTK_CMCTREE_NODE(cur));
|
|
if (msginfo) {
|
|
n_size += msginfo->size;
|
|
n_total++;
|
|
if (MSG_IS_NEW(msginfo->flags))
|
|
n_new++;
|
|
if (MSG_IS_UNREAD(msginfo->flags))
|
|
n_unread++;
|
|
if (MSG_IS_MARKED(msginfo->flags))
|
|
n_marked++;
|
|
if (MSG_IS_REPLIED(msginfo->flags))
|
|
n_replied++;
|
|
if (MSG_IS_FORWARDED(msginfo->flags))
|
|
n_forwarded++;
|
|
if (MSG_IS_LOCKED(msginfo->flags))
|
|
n_locked++;
|
|
if (MSG_IS_IGNORE_THREAD(msginfo->flags))
|
|
n_ignored++;
|
|
if (MSG_IS_WATCH_THREAD(msginfo->flags))
|
|
n_watched++;
|
|
}
|
|
}
|
|
} else {
|
|
n_new = summaryview->folder_item->new_msgs;
|
|
n_unread = summaryview->folder_item->unread_msgs;
|
|
n_marked = summaryview->folder_item->marked_msgs;
|
|
n_replied = summaryview->folder_item->replied_msgs;
|
|
n_forwarded = summaryview->folder_item->forwarded_msgs;
|
|
n_locked = summaryview->folder_item->locked_msgs;
|
|
n_ignored = summaryview->folder_item->ignored_msgs;
|
|
n_watched = summaryview->folder_item->watched_msgs;
|
|
n_total = summaryview->folder_item->total_msgs;
|
|
n_size = summaryview->total_size;
|
|
}
|
|
|
|
name = folder_item_get_name(summaryview->folder_item);
|
|
gtk_label_set_text(GTK_LABEL(summaryview->statlabel_folder), name);
|
|
g_free(name);
|
|
|
|
if (summaryview->deleted)
|
|
del = g_strdup_printf(_("%d deleted"), summaryview->deleted);
|
|
else
|
|
del = g_strdup("");
|
|
if (summaryview->moved)
|
|
mv = g_strdup_printf(_("%s%d moved"),
|
|
summaryview->deleted ? _(", ") : "",
|
|
summaryview->moved);
|
|
else
|
|
mv = g_strdup("");
|
|
if (summaryview->copied)
|
|
cp = g_strdup_printf(_("%s%d copied"),
|
|
summaryview->deleted ||
|
|
summaryview->moved ? _(", ") : "",
|
|
summaryview->copied);
|
|
else
|
|
cp = g_strdup("");
|
|
|
|
if (summaryview->deleted || summaryview->moved || summaryview->copied)
|
|
spc = " ";
|
|
else
|
|
spc = "";
|
|
|
|
if (n_selected) {
|
|
sel = g_strdup_printf(" (%s)", to_human_readable((goffset)sel_size));
|
|
itstr = g_strdup_printf(ngettext(" item selected"," items selected", n_selected));
|
|
} else {
|
|
sel = g_strdup("");
|
|
itstr = g_strdup("");
|
|
}
|
|
|
|
if (prefs_common.layout_mode != SMALL_LAYOUT) {
|
|
str = g_strconcat(n_selected ? itos(n_selected) : "",
|
|
itstr, sel, spc, del, mv, cp, NULL);
|
|
g_free(sel);
|
|
g_free(del);
|
|
g_free(mv);
|
|
g_free(cp);
|
|
g_free(itstr);
|
|
|
|
gtk_label_set_text(GTK_LABEL(summaryview->statlabel_select), str);
|
|
g_free(str);
|
|
|
|
str = g_strdup_printf(_("%d new, %d unread, %d total (%s)"),
|
|
n_new, n_unread, n_total,
|
|
to_human_readable((goffset)n_size));
|
|
|
|
|
|
gtk_label_set_text(GTK_LABEL(summaryview->statlabel_msgs), str);
|
|
g_free(str);
|
|
tooltip = g_strdup_printf("<b>%s</b>\n"
|
|
"<b>%s</b> %d\n"
|
|
"<b>%s</b> %d\n"
|
|
"<b>%s</b> %d\n"
|
|
"<b>%s</b> %s\n\n"
|
|
"<b>%s</b> %d\n"
|
|
"<b>%s</b> %d\n"
|
|
"<b>%s</b> %d\n"
|
|
"<b>%s</b> %d\n"
|
|
"<b>%s</b> %d\n"
|
|
"<b>%s</b> %d",
|
|
_("Message summary"),
|
|
_("New:"), n_new,
|
|
_("Unread:"), n_unread,
|
|
_("Total:"), n_total,
|
|
_("Size:"), to_human_readable((goffset)n_size),
|
|
_("Marked:"), n_marked,
|
|
_("Replied:"), n_replied,
|
|
_("Forwarded:"), n_forwarded,
|
|
_("Locked:"), n_locked,
|
|
_("Ignored:"), n_ignored,
|
|
_("Watched:"), n_watched);
|
|
|
|
gtk_widget_set_tooltip_markup(GTK_WIDGET(summaryview->statlabel_msgs),
|
|
tooltip);
|
|
g_free(tooltip);
|
|
} else {
|
|
gchar *ssize, *tsize;
|
|
if (n_selected) {
|
|
ssize = g_strdup(to_human_readable((goffset)sel_size));
|
|
tsize = g_strdup(to_human_readable((goffset)n_size));
|
|
str = g_strdup_printf(_("%d/%d selected (%s/%s), %d unread"),
|
|
n_selected, n_total, ssize, tsize, n_unread);
|
|
g_free(ssize);
|
|
g_free(tsize);
|
|
} else
|
|
str = g_strdup_printf(_("%d new, %d unread, %d total (%s)"),
|
|
n_new, n_unread, n_total, to_human_readable((goffset)n_size));
|
|
g_free(sel);
|
|
g_free(del);
|
|
g_free(mv);
|
|
g_free(cp);
|
|
g_free(itstr);
|
|
|
|
gtk_label_set_text(GTK_LABEL(summaryview->statlabel_select), str);
|
|
g_free(str);
|
|
}
|
|
|
|
summary_set_menu_sensitive(summaryview);
|
|
toolbar_main_set_sensitive(summaryview->mainwin);
|
|
}
|
|
|
|
static void summary_set_column_titles(SummaryView *summaryview)
|
|
{
|
|
GtkCMCList *clist = GTK_CMCLIST(summaryview->ctree);
|
|
FolderItem *item = summaryview->folder_item;
|
|
GtkWidget *hbox;
|
|
GtkWidget *label;
|
|
GtkWidget *arrow;
|
|
gint pos;
|
|
const gchar *title;
|
|
SummaryColumnType type;
|
|
GtkJustification justify;
|
|
|
|
static FolderSortKey sort_by[N_SUMMARY_COLS] = {
|
|
SORT_BY_MARK,
|
|
SORT_BY_STATUS,
|
|
SORT_BY_MIME,
|
|
SORT_BY_SUBJECT,
|
|
SORT_BY_FROM,
|
|
SORT_BY_TO,
|
|
SORT_BY_DATE,
|
|
SORT_BY_SIZE,
|
|
SORT_BY_NUMBER,
|
|
SORT_BY_SCORE,
|
|
SORT_BY_LOCKED,
|
|
SORT_BY_TAGS
|
|
};
|
|
|
|
for (pos = 0; pos < N_SUMMARY_COLS; pos++) {
|
|
type = summaryview->col_state[pos].type;
|
|
|
|
/* CLAWS: mime and unread are single char headers */
|
|
justify = (type == S_COL_NUMBER || type == S_COL_SIZE)
|
|
? GTK_JUSTIFY_RIGHT : GTK_JUSTIFY_LEFT;
|
|
|
|
switch (type) {
|
|
case S_COL_SUBJECT:
|
|
case S_COL_FROM:
|
|
case S_COL_TO:
|
|
case S_COL_DATE:
|
|
case S_COL_NUMBER:
|
|
if(type == S_COL_FROM && item != NULL &&
|
|
FOLDER_SHOWS_TO_HDR(item) &&
|
|
!summaryview->col_state[summaryview->col_pos[S_COL_TO]].visible)
|
|
type = S_COL_TO;
|
|
if(type == S_COL_NUMBER)
|
|
title = gettext(col_label[type]);
|
|
else
|
|
title = prefs_common_translated_header_name(col_label[type]);
|
|
break;
|
|
default:
|
|
title = gettext(col_label[type]);
|
|
}
|
|
|
|
if (type == S_COL_MIME) {
|
|
label = gtk_image_new_from_pixbuf(clipxpm);
|
|
gtk_widget_show(label);
|
|
gtk_cmclist_set_column_widget(clist, pos, label);
|
|
gtk_sctree_set_column_tooltip(GTK_SCTREE(clist), pos, _("Attachment"));
|
|
continue;
|
|
} else if (type == S_COL_MARK) {
|
|
label = gtk_image_new_from_pixbuf(markxpm);
|
|
gtk_widget_show(label);
|
|
gtk_cmclist_set_column_widget(clist, pos, label);
|
|
gtk_sctree_set_column_tooltip(GTK_SCTREE(clist), pos, _("Mark"));
|
|
continue;
|
|
} else if (type == S_COL_LOCKED) {
|
|
label = gtk_image_new_from_pixbuf(lockedxpm);
|
|
gtk_widget_show(label);
|
|
gtk_cmclist_set_column_widget(clist, pos, label);
|
|
gtk_sctree_set_column_tooltip(GTK_SCTREE(clist), pos, _("Locked"));
|
|
continue;
|
|
} else if (type == S_COL_STATUS) {
|
|
gtk_cmclist_set_column_title(clist, pos, title);
|
|
gtk_sctree_set_column_tooltip(GTK_SCTREE(clist), pos, _("Status"));
|
|
continue;
|
|
}
|
|
|
|
hbox = gtk_hbox_new(FALSE, 4);
|
|
label = gtk_label_new(title);
|
|
#ifdef GENERIC_UMPC
|
|
gtk_widget_set_size_request(hbox, -1, 20);
|
|
#endif
|
|
|
|
if (justify == GTK_JUSTIFY_RIGHT)
|
|
gtk_box_pack_end(GTK_BOX(hbox), label,
|
|
FALSE, FALSE, 0);
|
|
else
|
|
gtk_box_pack_start(GTK_BOX(hbox), label,
|
|
FALSE, FALSE, 0);
|
|
|
|
if (summaryview->sort_key == sort_by[type] ||
|
|
(summaryview->sort_key == SORT_BY_THREAD_DATE &&
|
|
sort_by[SORT_BY_DATE] && type == S_COL_DATE)) {
|
|
arrow = gtk_arrow_new
|
|
(summaryview->sort_type == SORT_ASCENDING
|
|
? GTK_ARROW_DOWN : GTK_ARROW_UP,
|
|
GTK_SHADOW_IN);
|
|
gtk_widget_set_size_request(GTK_WIDGET(arrow), 10, 10);
|
|
if (justify == GTK_JUSTIFY_RIGHT)
|
|
gtk_box_pack_start(GTK_BOX(hbox), arrow,
|
|
FALSE, FALSE, 0);
|
|
else
|
|
gtk_box_pack_end(GTK_BOX(hbox), arrow,
|
|
FALSE, FALSE, 0);
|
|
}
|
|
|
|
gtk_widget_show_all(hbox);
|
|
gtk_cmclist_set_column_widget(clist, pos, hbox);
|
|
}
|
|
}
|
|
|
|
void summary_reflect_tags_changes(SummaryView *summaryview)
|
|
{
|
|
GtkMenuShell *menu;
|
|
GList *children, *cur;
|
|
GtkCMCTreeNode *node;
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
gboolean froze = FALSE;
|
|
gboolean redisplay = FALSE;
|
|
|
|
/* re-create colorlabel submenu */
|
|
menu = GTK_MENU_SHELL(summaryview->tags_menu);
|
|
cm_return_if_fail(menu != NULL);
|
|
|
|
/* clear items. get item pointers. */
|
|
children = gtk_container_get_children(GTK_CONTAINER(menu));
|
|
for (cur = children; cur != NULL && cur->data != NULL; cur = cur->next) {
|
|
gtk_menu_item_set_submenu(GTK_MENU_ITEM(cur->data), NULL);
|
|
}
|
|
g_list_free(children);
|
|
summary_tags_menu_create(summaryview, TRUE);
|
|
|
|
START_LONG_OPERATION(summaryview, TRUE);
|
|
for (node = GTK_CMCTREE_NODE(GTK_CMCLIST(ctree)->row_list); node != NULL;
|
|
node = gtkut_ctree_node_next(ctree, node)) {
|
|
redisplay |= summary_set_row_tag(summaryview,
|
|
node, TRUE, FALSE, 0);
|
|
}
|
|
END_LONG_OPERATION(summaryview);
|
|
if (redisplay)
|
|
summary_redisplay_msg(summaryview);
|
|
}
|
|
|
|
|
|
void summary_reflect_prefs(void)
|
|
{
|
|
static gchar *last_smallfont = NULL;
|
|
static gchar *last_normalfont = NULL;
|
|
static gchar *last_boldfont = NULL;
|
|
static gboolean last_derive = 0;
|
|
gboolean update_font = FALSE;
|
|
SummaryView *summaryview = NULL;
|
|
|
|
if (!mainwindow_get_mainwindow())
|
|
return;
|
|
summaryview = mainwindow_get_mainwindow()->summaryview;
|
|
|
|
if (!last_smallfont || strcmp(last_smallfont, SMALL_FONT) ||
|
|
!last_normalfont || strcmp(last_normalfont, NORMAL_FONT) ||
|
|
!last_boldfont || strcmp(last_boldfont, BOLD_FONT) ||
|
|
last_derive != prefs_common.derive_from_normal_font)
|
|
update_font = TRUE;
|
|
|
|
g_free(last_smallfont);
|
|
last_smallfont = g_strdup(SMALL_FONT);
|
|
g_free(last_normalfont);
|
|
last_normalfont = g_strdup(NORMAL_FONT);
|
|
g_free(last_boldfont);
|
|
last_boldfont = g_strdup(BOLD_FONT);
|
|
last_derive = prefs_common.derive_from_normal_font;
|
|
|
|
#define STYLE_FREE(s) \
|
|
if (s != NULL) { \
|
|
g_object_unref(s); \
|
|
s = NULL; \
|
|
}
|
|
|
|
if (update_font) {
|
|
STYLE_FREE(bold_style);
|
|
STYLE_FREE(bold_style);
|
|
summary_set_fonts(summaryview);
|
|
}
|
|
|
|
#undef STYLE_FREE
|
|
|
|
summary_set_column_titles(summaryview);
|
|
summary_relayout(summaryview);
|
|
|
|
if (summaryview->folder_item)
|
|
summary_show(summaryview, summaryview->folder_item);
|
|
}
|
|
|
|
void summary_sort(SummaryView *summaryview,
|
|
FolderSortKey sort_key, FolderSortType sort_type)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GtkCMCList *clist = GTK_CMCLIST(summaryview->ctree);
|
|
GtkCMCListCompareFunc cmp_func = NULL;
|
|
START_TIMING("");
|
|
g_signal_handlers_block_by_func(G_OBJECT(summaryview->ctree),
|
|
G_CALLBACK(summary_tree_expanded), summaryview);
|
|
summary_freeze(summaryview);
|
|
|
|
switch (sort_key) {
|
|
case SORT_BY_MARK:
|
|
cmp_func = (GtkCMCListCompareFunc)summary_cmp_by_mark;
|
|
break;
|
|
case SORT_BY_STATUS:
|
|
cmp_func = (GtkCMCListCompareFunc)summary_cmp_by_status;
|
|
break;
|
|
case SORT_BY_MIME:
|
|
cmp_func = (GtkCMCListCompareFunc)summary_cmp_by_mime;
|
|
break;
|
|
case SORT_BY_NUMBER:
|
|
cmp_func = (GtkCMCListCompareFunc)summary_cmp_by_num;
|
|
break;
|
|
case SORT_BY_SIZE:
|
|
cmp_func = (GtkCMCListCompareFunc)summary_cmp_by_size;
|
|
break;
|
|
case SORT_BY_DATE:
|
|
cmp_func = (GtkCMCListCompareFunc)summary_cmp_by_date;
|
|
break;
|
|
case SORT_BY_THREAD_DATE:
|
|
cmp_func = (GtkCMCListCompareFunc)summary_cmp_by_thread_date;
|
|
break;
|
|
case SORT_BY_FROM:
|
|
cmp_func = (GtkCMCListCompareFunc)summary_cmp_by_from;
|
|
break;
|
|
case SORT_BY_SUBJECT:
|
|
if (summaryview->simplify_subject_preg)
|
|
cmp_func = (GtkCMCListCompareFunc)summary_cmp_by_simplified_subject;
|
|
else
|
|
cmp_func = (GtkCMCListCompareFunc)summary_cmp_by_subject;
|
|
break;
|
|
case SORT_BY_SCORE:
|
|
cmp_func = (GtkCMCListCompareFunc)summary_cmp_by_score;
|
|
break;
|
|
case SORT_BY_LABEL:
|
|
cmp_func = (GtkCMCListCompareFunc)summary_cmp_by_label;
|
|
break;
|
|
case SORT_BY_TO:
|
|
cmp_func = (GtkCMCListCompareFunc)summary_cmp_by_to;
|
|
break;
|
|
case SORT_BY_LOCKED:
|
|
cmp_func = (GtkCMCListCompareFunc)summary_cmp_by_locked;
|
|
break;
|
|
case SORT_BY_TAGS:
|
|
cmp_func = (GtkCMCListCompareFunc)summary_cmp_by_tags;
|
|
break;
|
|
case SORT_BY_NONE:
|
|
break;
|
|
default:
|
|
goto unlock;
|
|
}
|
|
|
|
summaryview->sort_key = sort_key;
|
|
summaryview->sort_type = sort_type;
|
|
|
|
summary_set_column_titles(summaryview);
|
|
summary_set_menu_sensitive(summaryview);
|
|
|
|
/* allow fallback to don't sort */
|
|
if (summaryview->sort_key == SORT_BY_NONE)
|
|
goto unlock;
|
|
|
|
if (cmp_func != NULL) {
|
|
debug_print("Sorting summary...\n");
|
|
STATUSBAR_PUSH(summaryview->mainwin, _("Sorting summary..."));
|
|
|
|
main_window_cursor_wait(summaryview->mainwin);
|
|
|
|
gtk_cmclist_set_compare_func(clist, cmp_func);
|
|
|
|
gtk_cmclist_set_sort_type(clist, (GtkSortType)sort_type);
|
|
gtk_sctree_sort_recursive(ctree, NULL);
|
|
|
|
gtk_cmctree_node_moveto(ctree, summaryview->selected, 0, 0.5, 0);
|
|
|
|
main_window_cursor_normal(summaryview->mainwin);
|
|
|
|
debug_print("Sorting summary done.\n");
|
|
STATUSBAR_POP(summaryview->mainwin);
|
|
}
|
|
unlock:
|
|
summary_thaw(summaryview);
|
|
g_signal_handlers_unblock_by_func(G_OBJECT(summaryview->ctree),
|
|
G_CALLBACK(summary_tree_expanded), summaryview);
|
|
END_TIMING();
|
|
}
|
|
|
|
static gboolean summary_update_thread_age(GNode *node, gpointer data)
|
|
{
|
|
MsgInfo *msginfo = node->data;
|
|
time_t *most_recent = (time_t *)data;
|
|
|
|
if (msginfo->date_t > *most_recent) {
|
|
*most_recent = msginfo->date_t;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static void summary_find_thread_age(GNode *gnode)
|
|
{
|
|
MsgInfo *msginfo = (MsgInfo *)gnode->data;
|
|
time_t most_recent;
|
|
|
|
if (!msginfo)
|
|
return;
|
|
most_recent = msginfo->thread_date = msginfo->date_t;
|
|
|
|
g_node_traverse(gnode, G_IN_ORDER, G_TRAVERSE_ALL, -1, summary_update_thread_age, &most_recent);
|
|
|
|
msginfo->thread_date = most_recent;
|
|
}
|
|
|
|
static gboolean summary_update_is_read(GNode *node, gpointer data)
|
|
{
|
|
MsgInfo *msginfo = node->data;
|
|
gboolean *all_read = (gboolean *)data;
|
|
|
|
if (MSG_IS_UNREAD(msginfo->flags)) {
|
|
*all_read = FALSE;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean summary_thread_is_read(GNode *gnode)
|
|
{
|
|
MsgInfo *msginfo = (MsgInfo *)gnode->data;
|
|
gboolean all_read = TRUE;
|
|
|
|
if (!msginfo)
|
|
return all_read;
|
|
|
|
g_node_traverse(gnode, G_IN_ORDER, G_TRAVERSE_ALL, -1, summary_update_is_read, &all_read);
|
|
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)
|
|
{
|
|
SummaryView *summaryview = (SummaryView *)data;
|
|
MsgInfo *msginfo = (MsgInfo *)gnode->data;
|
|
gchar *text[N_SUMMARY_COLS];
|
|
gint *col_pos = summaryview->col_pos;
|
|
const gchar *msgid = msginfo->msgid;
|
|
GHashTable *msgid_table = summaryview->msgid_table;
|
|
gboolean vert_layout = (prefs_common.layout_mode == VERTICAL_LAYOUT);
|
|
gboolean small_layout = (prefs_common.layout_mode == SMALL_LAYOUT);
|
|
|
|
summary_set_header(summaryview, text, msginfo);
|
|
|
|
gtk_cmctree_set_node_info(ctree, cnode, text[col_pos[S_COL_SUBJECT]], 2,
|
|
NULL, NULL, FALSE, summaryview->threaded && !summaryview->thread_collapsed);
|
|
#define SET_TEXT(col) { \
|
|
gtk_cmctree_node_set_text(ctree, cnode, col_pos[col], \
|
|
text[col_pos[col]]); \
|
|
}
|
|
|
|
if (summaryview->col_state[summaryview->col_pos[S_COL_NUMBER]].visible)
|
|
SET_TEXT(S_COL_NUMBER);
|
|
if (summaryview->col_state[summaryview->col_pos[S_COL_SCORE]].visible)
|
|
SET_TEXT(S_COL_SCORE);
|
|
if (summaryview->col_state[summaryview->col_pos[S_COL_SIZE]].visible)
|
|
SET_TEXT(S_COL_SIZE);
|
|
if (summaryview->col_state[summaryview->col_pos[S_COL_DATE]].visible)
|
|
SET_TEXT(S_COL_DATE);
|
|
if (summaryview->col_state[summaryview->col_pos[S_COL_FROM]].visible)
|
|
SET_TEXT(S_COL_FROM);
|
|
if (summaryview->col_state[summaryview->col_pos[S_COL_TO]].visible)
|
|
SET_TEXT(S_COL_TO);
|
|
if (summaryview->col_state[summaryview->col_pos[S_COL_TAGS]].visible)
|
|
SET_TEXT(S_COL_TAGS);
|
|
|
|
if ((vert_layout || small_layout) && prefs_common.two_line_vert)
|
|
g_free(text[summaryview->col_pos[S_COL_SUBJECT]]);
|
|
|
|
#undef SET_TEXT
|
|
|
|
GTKUT_CTREE_NODE_SET_ROW_DATA(cnode, msginfo);
|
|
summary_set_marks_func(ctree, cnode, summaryview);
|
|
|
|
if (msgid && msgid[0] != '\0')
|
|
g_hash_table_insert(msgid_table, (gchar *)msgid, cnode);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void summary_set_ctree_from_list(SummaryView *summaryview,
|
|
GSList *mlist, guint selected_msgnum)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
MsgInfo *msginfo;
|
|
GtkCMCTreeNode *node = NULL;
|
|
GHashTable *msgid_table;
|
|
GHashTable *subject_table = NULL;
|
|
GSList * cur;
|
|
gboolean vert_layout = (prefs_common.layout_mode == VERTICAL_LAYOUT);
|
|
gboolean small_layout = (prefs_common.layout_mode == SMALL_LAYOUT);
|
|
START_TIMING("");
|
|
|
|
if (!mlist) return;
|
|
|
|
debug_print("Setting summary from message data...\n");
|
|
STATUSBAR_PUSH(summaryview->mainwin,
|
|
_("Setting summary from message data..."));
|
|
gdk_flush();
|
|
|
|
g_signal_handlers_block_by_func(G_OBJECT(ctree),
|
|
G_CALLBACK(summary_tree_expanded), summaryview);
|
|
|
|
msgid_table = g_hash_table_new(g_str_hash, g_str_equal);
|
|
summaryview->msgid_table = msgid_table;
|
|
|
|
if (prefs_common.thread_by_subject) {
|
|
subject_table = g_hash_table_new(g_str_hash, g_str_equal);
|
|
summaryview->subject_table = subject_table;
|
|
} else {
|
|
summaryview->subject_table = NULL;
|
|
}
|
|
|
|
if (prefs_common.use_addr_book)
|
|
start_address_completion(NULL);
|
|
|
|
if (summaryview->threaded) {
|
|
GNode *root, *gnode;
|
|
START_TIMING("threaded");
|
|
root = procmsg_get_thread_tree(mlist);
|
|
|
|
|
|
for (gnode = root->children; gnode != NULL;
|
|
gnode = gnode->next) {
|
|
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);
|
|
|
|
END_TIMING();
|
|
} else {
|
|
gchar *text[N_SUMMARY_COLS];
|
|
START_TIMING("unthreaded");
|
|
cur = mlist;
|
|
for (; mlist != NULL; mlist = mlist->next) {
|
|
msginfo = (MsgInfo *)mlist->data;
|
|
|
|
summary_set_header(summaryview, text, msginfo);
|
|
|
|
node = gtk_sctree_insert_node
|
|
(ctree, NULL, node, text, 2,
|
|
NULL, NULL,
|
|
FALSE, FALSE);
|
|
if ((vert_layout || small_layout) && prefs_common.two_line_vert)
|
|
g_free(text[summaryview->col_pos[S_COL_SUBJECT]]);
|
|
|
|
GTKUT_CTREE_NODE_SET_ROW_DATA(node, msginfo);
|
|
summary_set_marks_func(ctree, node, summaryview);
|
|
|
|
if (msginfo->msgid && msginfo->msgid[0] != '\0')
|
|
g_hash_table_insert(msgid_table,
|
|
msginfo->msgid, node);
|
|
|
|
if (prefs_common.thread_by_subject)
|
|
subject_table_insert(subject_table,
|
|
msginfo->subject,
|
|
node);
|
|
}
|
|
mlist = cur;
|
|
END_TIMING();
|
|
}
|
|
|
|
if (prefs_common.enable_hscrollbar &&
|
|
summaryview->col_pos[S_COL_SUBJECT] == N_SUMMARY_COLS - 1) {
|
|
gint optimal_width;
|
|
|
|
optimal_width = gtk_cmclist_optimal_column_width
|
|
(GTK_CMCLIST(ctree), summaryview->col_pos[S_COL_SUBJECT]);
|
|
gtk_cmclist_set_column_width(GTK_CMCLIST(ctree),
|
|
summaryview->col_pos[S_COL_SUBJECT],
|
|
optimal_width);
|
|
}
|
|
|
|
if (prefs_common.use_addr_book)
|
|
end_address_completion();
|
|
|
|
debug_print("Setting summary from message data done.\n");
|
|
STATUSBAR_POP(summaryview->mainwin);
|
|
if (debug_get_mode()) {
|
|
debug_print("\tmsgid hash table size = %d\n",
|
|
g_hash_table_size(msgid_table));
|
|
if (prefs_common.thread_by_subject)
|
|
debug_print("\tsubject hash table size = %d\n",
|
|
g_hash_table_size(subject_table));
|
|
}
|
|
|
|
summary_sort(summaryview, summaryview->sort_key, summaryview->sort_type);
|
|
|
|
node = GTK_CMCTREE_NODE(GTK_CMCLIST(ctree)->row_list);
|
|
|
|
if (prefs_common.bold_unread) {
|
|
START_TIMING("bold_unread");
|
|
while (node) {
|
|
GtkCMCTreeNode *next = GTK_CMCTREE_NODE_NEXT(node);
|
|
if (GTK_CMCTREE_ROW(node)->children)
|
|
summary_set_row_marks(summaryview, node);
|
|
node = next;
|
|
}
|
|
END_TIMING();
|
|
}
|
|
|
|
g_signal_handlers_unblock_by_func(G_OBJECT(ctree),
|
|
G_CALLBACK(summary_tree_expanded), summaryview);
|
|
END_TIMING();
|
|
}
|
|
|
|
static gchar *summary_complete_address(const gchar *addr)
|
|
{
|
|
gint count;
|
|
gchar *res, *tmp, *email_addr;
|
|
|
|
if (addr == NULL || !strchr(addr, '@'))
|
|
return NULL;
|
|
|
|
Xstrdup_a(email_addr, addr, return NULL);
|
|
extract_address(email_addr);
|
|
if (!*email_addr)
|
|
return NULL;
|
|
|
|
/*
|
|
* completion stuff must be already initialized
|
|
*/
|
|
res = NULL;
|
|
if (1 < (count = complete_address(email_addr))) {
|
|
tmp = get_complete_address(1);
|
|
res = procheader_get_fromname(tmp);
|
|
g_free(tmp);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
static inline void summary_set_header(SummaryView *summaryview, gchar *text[],
|
|
MsgInfo *msginfo)
|
|
{
|
|
static gchar date_modified[80];
|
|
static gchar col_score[11];
|
|
static gchar from_buf[BUFFSIZE], to_buf[BUFFSIZE];
|
|
static gchar tmp1[BUFFSIZE], tmp2[BUFFSIZE], tmp3[BUFFSIZE];
|
|
gint *col_pos = summaryview->col_pos;
|
|
gchar *from_text = NULL, *to_text = NULL, *tags_text = NULL;
|
|
gboolean should_swap = FALSE;
|
|
gboolean vert_layout = (prefs_common.layout_mode == VERTICAL_LAYOUT);
|
|
gboolean small_layout = (prefs_common.layout_mode == SMALL_LAYOUT);
|
|
static const gchar *color_dim_rgb = NULL;
|
|
if (!color_dim_rgb)
|
|
color_dim_rgb = gtkut_gdk_rgba_to_string(&summaryview->color_dim);
|
|
text[col_pos[S_COL_FROM]] = "";
|
|
text[col_pos[S_COL_TO]] = "";
|
|
text[col_pos[S_COL_SUBJECT]]= "";
|
|
text[col_pos[S_COL_MARK]] = "";
|
|
text[col_pos[S_COL_STATUS]] = "";
|
|
text[col_pos[S_COL_MIME]] = "";
|
|
text[col_pos[S_COL_LOCKED]] = "";
|
|
text[col_pos[S_COL_DATE]] = "";
|
|
text[col_pos[S_COL_TAGS]] = "";
|
|
if (summaryview->col_state[summaryview->col_pos[S_COL_NUMBER]].visible)
|
|
text[col_pos[S_COL_NUMBER]] = itos(msginfo->msgnum);
|
|
else
|
|
text[col_pos[S_COL_NUMBER]] = "";
|
|
|
|
/* slow! */
|
|
if (summaryview->col_state[summaryview->col_pos[S_COL_SIZE]].visible)
|
|
text[col_pos[S_COL_SIZE]] = to_human_readable(msginfo->size);
|
|
else
|
|
text[col_pos[S_COL_SIZE]] = "";
|
|
|
|
if (summaryview->col_state[summaryview->col_pos[S_COL_SCORE]].visible)
|
|
text[col_pos[S_COL_SCORE]] = itos_buf(col_score, msginfo->score);
|
|
else
|
|
text[col_pos[S_COL_SCORE]] = "";
|
|
|
|
if (summaryview->col_state[summaryview->col_pos[S_COL_TAGS]].visible) {
|
|
tags_text = procmsg_msginfo_get_tags_str(msginfo);
|
|
if (!tags_text) {
|
|
text[col_pos[S_COL_TAGS]] = "-";
|
|
} else {
|
|
strncpy2(tmp1, tags_text, sizeof(tmp1));
|
|
tmp1[sizeof(tmp1)-1]='\0';
|
|
g_free(tags_text);
|
|
text[col_pos[S_COL_TAGS]] = tmp1;
|
|
}
|
|
} else
|
|
text[col_pos[S_COL_TAGS]] = "";
|
|
|
|
/* slow! */
|
|
if (summaryview->col_state[summaryview->col_pos[S_COL_DATE]].visible ||
|
|
((vert_layout || small_layout) && prefs_common.two_line_vert)) {
|
|
if (msginfo->date_t && msginfo->date_t > 0) {
|
|
procheader_date_get_localtime(date_modified,
|
|
sizeof(date_modified),
|
|
msginfo->date_t);
|
|
text[col_pos[S_COL_DATE]] = date_modified;
|
|
} else if (msginfo->date)
|
|
text[col_pos[S_COL_DATE]] = msginfo->date;
|
|
else
|
|
text[col_pos[S_COL_DATE]] = _("(No Date)");
|
|
}
|
|
|
|
if (prefs_common.swap_from && msginfo->from && msginfo->to
|
|
&& !summaryview->col_state[summaryview->col_pos[S_COL_TO]].visible) {
|
|
gchar *addr = NULL;
|
|
|
|
addr = g_strdup(msginfo->from);
|
|
|
|
if (addr) {
|
|
extract_address(addr);
|
|
if (account_find_from_address(addr, FALSE)) {
|
|
should_swap = TRUE;
|
|
}
|
|
g_free(addr);
|
|
}
|
|
}
|
|
|
|
if (!prefs_common.use_addr_book) {
|
|
if (prefs_common.summary_from_show == SHOW_NAME)
|
|
from_text = msginfo->fromname;
|
|
else if (prefs_common.summary_from_show == SHOW_BOTH)
|
|
from_text = msginfo->from;
|
|
else {
|
|
from_text = msginfo->from;
|
|
extract_address(from_text);
|
|
}
|
|
if (!from_text)
|
|
from_text = _("(No From)");
|
|
} else {
|
|
gchar *tmp = summary_complete_address(msginfo->from);
|
|
if (tmp) {
|
|
strncpy2(from_buf, tmp, sizeof(from_buf));
|
|
g_free(tmp);
|
|
from_text = from_buf;
|
|
} else {
|
|
if (prefs_common.summary_from_show == SHOW_NAME)
|
|
from_text = msginfo->fromname;
|
|
else if (prefs_common.summary_from_show == SHOW_BOTH)
|
|
from_text = msginfo->from;
|
|
else {
|
|
from_text = msginfo->from;
|
|
if (from_text)
|
|
extract_address(from_text);
|
|
}
|
|
if (!from_text)
|
|
from_text = _("(No From)");
|
|
}
|
|
}
|
|
|
|
to_text = msginfo->to ? msginfo->to :
|
|
(msginfo->cc ? msginfo->cc :
|
|
(msginfo->newsgroups ? msginfo->newsgroups : NULL
|
|
)
|
|
);
|
|
|
|
if (!to_text)
|
|
to_text = _("(No Recipient)");
|
|
else {
|
|
if (prefs_common.summary_from_show == SHOW_NAME) {
|
|
gchar *tmp = procheader_get_fromname(to_text);
|
|
/* need to keep to_text pointing to stack, so heap-allocated
|
|
* string from procheader_get_fromname() will be copied to to_buf */
|
|
if (tmp != NULL) {
|
|
strncpy2(to_buf, tmp, sizeof(to_buf));
|
|
g_free(tmp);
|
|
to_text = to_buf;
|
|
}
|
|
} else if (prefs_common.summary_from_show == SHOW_ADDR)
|
|
extract_address(to_text);
|
|
}
|
|
|
|
text[col_pos[S_COL_TO]] = to_text;
|
|
if (!should_swap) {
|
|
text[col_pos[S_COL_FROM]] = from_text;
|
|
} else {
|
|
if (prefs_common.use_addr_book) {
|
|
gchar *tmp = summary_complete_address(to_text);
|
|
/* need to keep to_text pointing to stack, so heap-allocated
|
|
* string from summary_complete_address() will be copied to to_buf */
|
|
if (tmp) {
|
|
strncpy2(to_buf, tmp, sizeof(to_buf));
|
|
g_free(tmp);
|
|
to_text = to_buf;
|
|
} else {
|
|
to_text = to_text ? to_text : _("(No From)");
|
|
}
|
|
}
|
|
snprintf(tmp2, BUFFSIZE-1, "➜ %s", to_text);
|
|
tmp2[BUFFSIZE-1]='\0';
|
|
text[col_pos[S_COL_FROM]] = tmp2;
|
|
}
|
|
|
|
if (summaryview->simplify_subject_preg != NULL)
|
|
text[col_pos[S_COL_SUBJECT]] = msginfo->subject ?
|
|
string_remove_match(tmp3, BUFFSIZE, msginfo->subject,
|
|
summaryview->simplify_subject_preg) :
|
|
_("(No Subject)");
|
|
else
|
|
text[col_pos[S_COL_SUBJECT]] = msginfo->subject ? msginfo->subject :
|
|
_("(No Subject)");
|
|
if ((vert_layout || small_layout) && prefs_common.two_line_vert) {
|
|
if (!FOLDER_SHOWS_TO_HDR(summaryview->folder_item)) {
|
|
gchar *tmp = g_markup_printf_escaped(g_strconcat("%s\n",
|
|
"<span color='%s' style='italic'>",
|
|
_("From: %s, on %s"), "</span>", NULL),
|
|
text[col_pos[S_COL_SUBJECT]],
|
|
color_dim_rgb,
|
|
text[col_pos[S_COL_FROM]],
|
|
text[col_pos[S_COL_DATE]]);
|
|
text[col_pos[S_COL_SUBJECT]] = tmp;
|
|
} else {
|
|
gchar *tmp = g_markup_printf_escaped(g_strconcat("%s\n",
|
|
"<span color='%s' style='italic'>",
|
|
_("To: %s, on %s"), "</span>", NULL),
|
|
text[col_pos[S_COL_SUBJECT]],
|
|
color_dim_rgb,
|
|
text[col_pos[S_COL_TO]],
|
|
text[col_pos[S_COL_DATE]]);
|
|
text[col_pos[S_COL_SUBJECT]] = tmp;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void summary_display_msg(SummaryView *summaryview, GtkCMCTreeNode *row)
|
|
{
|
|
summary_display_msg_full(summaryview, row, FALSE, FALSE);
|
|
}
|
|
|
|
static gboolean defer_change(gpointer data);
|
|
typedef struct _ChangeData {
|
|
MsgInfo *info;
|
|
gint op; /* 0, 1, 2 for unset, set, change */
|
|
MsgPermFlags set_flags;
|
|
MsgTmpFlags set_tmp_flags;
|
|
MsgPermFlags unset_flags;
|
|
MsgTmpFlags unset_tmp_flags;
|
|
} ChangeData;
|
|
|
|
static void summary_msginfo_unset_flags(MsgInfo *msginfo, MsgPermFlags flags, MsgTmpFlags tmp_flags)
|
|
{
|
|
if (!msginfo->folder || !msginfo->folder->processing_pending) {
|
|
debug_print("flags: doing unset now\n");
|
|
procmsg_msginfo_unset_flags(msginfo, flags, tmp_flags);
|
|
} else {
|
|
ChangeData *unset_data = g_new0(ChangeData, 1);
|
|
unset_data->info = msginfo;
|
|
unset_data->op = 0;
|
|
unset_data->unset_flags = flags;
|
|
unset_data->unset_tmp_flags = tmp_flags;
|
|
debug_print("flags: deferring unset\n");
|
|
g_timeout_add(100, defer_change, unset_data);
|
|
}
|
|
}
|
|
|
|
static void summary_msginfo_set_flags(MsgInfo *msginfo, MsgPermFlags flags, MsgTmpFlags tmp_flags)
|
|
{
|
|
if (!msginfo->folder || !msginfo->folder->processing_pending) {
|
|
debug_print("flags: doing set now\n");
|
|
procmsg_msginfo_set_flags(msginfo, flags, tmp_flags);
|
|
} else {
|
|
ChangeData *set_data = g_new0(ChangeData, 1);
|
|
set_data->info = msginfo;
|
|
set_data->op = 1;
|
|
set_data->set_flags = flags;
|
|
set_data->set_tmp_flags = tmp_flags;
|
|
debug_print("flags: deferring set\n");
|
|
g_timeout_add(100, defer_change, set_data);
|
|
}
|
|
}
|
|
|
|
static void summary_msginfo_change_flags(MsgInfo *msginfo,
|
|
MsgPermFlags add_flags, MsgTmpFlags add_tmp_flags,
|
|
MsgPermFlags rem_flags, MsgTmpFlags rem_tmp_flags)
|
|
{
|
|
if (!msginfo->folder || !msginfo->folder->processing_pending) {
|
|
debug_print("flags: doing change now\n");
|
|
procmsg_msginfo_change_flags(msginfo, add_flags, add_tmp_flags,
|
|
rem_flags, rem_tmp_flags);
|
|
} else {
|
|
ChangeData *change_data = g_new0(ChangeData, 1);
|
|
change_data->info = msginfo;
|
|
change_data->op = 2;
|
|
change_data->set_flags = add_flags;
|
|
change_data->set_tmp_flags = add_tmp_flags;
|
|
change_data->unset_flags = rem_flags;
|
|
change_data->unset_tmp_flags = rem_tmp_flags;
|
|
debug_print("flags: deferring change\n");
|
|
g_timeout_add(100, defer_change, change_data);
|
|
}
|
|
}
|
|
|
|
gboolean defer_change(gpointer data)
|
|
{
|
|
ChangeData *chg = (ChangeData *)data;
|
|
if (chg->info->folder && chg->info->folder->processing_pending) {
|
|
debug_print("flags: trying later\n");
|
|
return TRUE; /* try again */
|
|
} else {
|
|
debug_print("flags: finally doing it\n");
|
|
switch(chg->op) {
|
|
case 0:
|
|
procmsg_msginfo_unset_flags(chg->info, chg->unset_flags, chg->unset_tmp_flags);
|
|
break;
|
|
case 1:
|
|
procmsg_msginfo_set_flags(chg->info, chg->set_flags, chg->set_tmp_flags);
|
|
break;
|
|
case 2:
|
|
procmsg_msginfo_change_flags(chg->info, chg->set_flags, chg->set_tmp_flags,
|
|
chg->unset_flags, chg->unset_tmp_flags);
|
|
break;
|
|
default:
|
|
g_warning("unknown change op");
|
|
}
|
|
g_free(chg);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static void msginfo_mark_as_read (SummaryView *summaryview, MsgInfo *msginfo,
|
|
GtkCMCTreeNode *row)
|
|
{
|
|
cm_return_if_fail(summaryview != NULL);
|
|
cm_return_if_fail(msginfo != NULL);
|
|
cm_return_if_fail(row != NULL);
|
|
|
|
if (MSG_IS_NEW(msginfo->flags) || MSG_IS_UNREAD(msginfo->flags)) {
|
|
summary_msginfo_unset_flags
|
|
(msginfo, MSG_NEW | MSG_UNREAD, 0);
|
|
summary_set_row_marks(summaryview, row);
|
|
summary_status_show(summaryview);
|
|
}
|
|
}
|
|
|
|
typedef struct {
|
|
MsgInfo *msginfo;
|
|
SummaryView *summaryview;
|
|
} MarkAsReadData;
|
|
|
|
static int msginfo_mark_as_read_timeout(void *data)
|
|
{
|
|
MarkAsReadData *mdata = (MarkAsReadData *)data;
|
|
if (!mdata)
|
|
return FALSE;
|
|
|
|
summary_lock(mdata->summaryview);
|
|
if (mdata->msginfo == summary_get_selected_msg(mdata->summaryview))
|
|
msginfo_mark_as_read(mdata->summaryview, mdata->msginfo,
|
|
mdata->summaryview->selected);
|
|
procmsg_msginfo_free(&(mdata->msginfo));
|
|
|
|
mdata->summaryview->mark_as_read_timeout_tag = 0;
|
|
summary_unlock(mdata->summaryview);
|
|
|
|
g_free(mdata);
|
|
return FALSE;
|
|
}
|
|
|
|
static void summary_display_msg_full(SummaryView *summaryview,
|
|
GtkCMCTreeNode *row,
|
|
gboolean new_window, gboolean all_headers)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
MsgInfo *msginfo;
|
|
gint val;
|
|
START_TIMING("");
|
|
if (!new_window) {
|
|
if (summaryview->displayed == row &&
|
|
messageview_is_visible(summaryview->messageview))
|
|
return;
|
|
else if (summaryview->messageview)
|
|
summaryview->messageview->filtered = FALSE;
|
|
}
|
|
cm_return_if_fail(row != NULL);
|
|
|
|
if (summary_is_locked(summaryview)) return;
|
|
summary_lock(summaryview);
|
|
|
|
STATUSBAR_POP(summaryview->mainwin);
|
|
GTK_EVENTS_FLUSH();
|
|
|
|
msginfo = gtk_cmctree_node_get_row_data(ctree, row);
|
|
|
|
if (!msginfo) {
|
|
debug_print("NULL msginfo\n");
|
|
summary_unlock(summaryview);
|
|
END_TIMING();
|
|
return;
|
|
}
|
|
|
|
if (new_window && prefs_common.layout_mode != SMALL_LAYOUT) {
|
|
MessageView *msgview;
|
|
|
|
msgview = messageview_create_with_new_window(summaryview->mainwin);
|
|
val = messageview_show(msgview, msginfo, all_headers);
|
|
} else {
|
|
MessageView *msgview;
|
|
|
|
if (prefs_common.layout_mode == SMALL_LAYOUT) {
|
|
if (summaryview->ext_messageview == NULL)
|
|
summaryview->ext_messageview = messageview_create_with_new_window(summaryview->mainwin);
|
|
else
|
|
gtkut_window_popup(summaryview->ext_messageview->window);
|
|
msgview = summaryview->ext_messageview;
|
|
summaryview->displayed = row;
|
|
val = messageview_show(msgview, msginfo, all_headers);
|
|
if (mimeview_tree_is_empty(msgview->mimeview))
|
|
gtk_widget_grab_focus(summaryview->ctree);
|
|
gtkut_ctree_node_move_if_on_the_edge(ctree, row,
|
|
GTK_CMCLIST(summaryview->ctree)->focus_row);
|
|
} else {
|
|
msgview = summaryview->messageview;
|
|
summaryview->displayed = row;
|
|
if (!messageview_is_visible(msgview) &&
|
|
gtk_window_is_active(GTK_WINDOW(summaryview->mainwin->window))) {
|
|
main_window_toggle_message_view(summaryview->mainwin);
|
|
GTK_EVENTS_FLUSH();
|
|
}
|
|
val = messageview_show(msgview, msginfo, all_headers);
|
|
if (mimeview_tree_is_empty(msgview->mimeview))
|
|
gtk_widget_grab_focus(summaryview->ctree);
|
|
gtkut_ctree_node_move_if_on_the_edge(ctree, row,
|
|
GTK_CMCLIST(summaryview->ctree)->focus_row);
|
|
}
|
|
}
|
|
|
|
if (val == 0 && MSG_IS_UNREAD(msginfo->flags)) {
|
|
if (!prefs_common.mark_as_read_on_new_window &&
|
|
prefs_common.mark_as_read_delay) {
|
|
MarkAsReadData *data = g_new0(MarkAsReadData, 1);
|
|
data->summaryview = summaryview;
|
|
data->msginfo = procmsg_msginfo_new_ref(msginfo);
|
|
if (summaryview->mark_as_read_timeout_tag != 0)
|
|
g_source_remove(summaryview->mark_as_read_timeout_tag);
|
|
summaryview->mark_as_read_timeout_tag =
|
|
g_timeout_add_seconds(prefs_common.mark_as_read_delay,
|
|
msginfo_mark_as_read_timeout, data);
|
|
} else if (new_window || !prefs_common.mark_as_read_on_new_window) {
|
|
msginfo_mark_as_read(summaryview, msginfo, row);
|
|
}
|
|
}
|
|
|
|
summary_set_menu_sensitive(summaryview);
|
|
toolbar_main_set_sensitive(summaryview->mainwin);
|
|
messageview_set_menu_sensitive(summaryview->messageview);
|
|
|
|
summary_unlock(summaryview);
|
|
END_TIMING();
|
|
}
|
|
|
|
void summary_display_msg_selected(SummaryView *summaryview,
|
|
gboolean all_headers)
|
|
{
|
|
if (summary_is_locked(summaryview)) return;
|
|
summaryview->displayed = NULL;
|
|
summary_display_msg_full(summaryview, summaryview->selected, FALSE,
|
|
all_headers);
|
|
}
|
|
|
|
void summary_redisplay_msg(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTreeNode *node;
|
|
|
|
if (summaryview->displayed) {
|
|
node = summaryview->displayed;
|
|
summaryview->displayed = NULL;
|
|
summary_display_msg(summaryview, node);
|
|
}
|
|
}
|
|
|
|
void summary_open_msg(SummaryView *summaryview)
|
|
{
|
|
if (!summaryview->selected) return;
|
|
|
|
/* CLAWS: if separate message view, don't open a new window
|
|
* but rather use the current separated message view */
|
|
summary_display_msg_full(summaryview, summaryview->selected,
|
|
TRUE, FALSE);
|
|
}
|
|
|
|
void summary_view_source(SummaryView * summaryview)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
MsgInfo *msginfo;
|
|
SourceWindow *srcwin;
|
|
|
|
if (!summaryview->selected) return;
|
|
|
|
srcwin = source_window_create();
|
|
msginfo = gtk_cmctree_node_get_row_data(ctree, summaryview->selected);
|
|
source_window_show_msg(srcwin, msginfo);
|
|
source_window_show(srcwin);
|
|
}
|
|
|
|
void summary_reedit(SummaryView *summaryview)
|
|
{
|
|
MsgInfo *msginfo;
|
|
|
|
if (!summaryview->selected) return;
|
|
if (!summaryview->folder_item) return;
|
|
if (!FOLDER_SHOWS_TO_HDR(summaryview->folder_item))
|
|
return;
|
|
|
|
msginfo = gtk_cmctree_node_get_row_data(GTK_CMCTREE(summaryview->ctree),
|
|
summaryview->selected);
|
|
if (!msginfo) return;
|
|
|
|
compose_reedit(msginfo, FALSE);
|
|
}
|
|
|
|
gboolean summary_is_list(SummaryView *summaryview)
|
|
{
|
|
return (gtk_notebook_get_current_page(
|
|
GTK_NOTEBOOK(summaryview->mainwidget_book)) == 0);
|
|
}
|
|
|
|
void summary_toggle_view(SummaryView *summaryview)
|
|
{
|
|
if (prefs_common.layout_mode == SMALL_LAYOUT)
|
|
return;
|
|
if (summary_is_locked(summaryview))
|
|
return;
|
|
if (!messageview_is_visible(summaryview->messageview) &&
|
|
summaryview->selected && summary_is_list(summaryview))
|
|
summary_display_msg(summaryview,
|
|
summaryview->selected);
|
|
else
|
|
main_window_toggle_message_view(summaryview->mainwin);
|
|
}
|
|
|
|
static gboolean summary_search_unread_recursive(GtkCMCTree *ctree,
|
|
GtkCMCTreeNode *node)
|
|
{
|
|
MsgInfo *msginfo;
|
|
|
|
if (node) {
|
|
msginfo = gtk_cmctree_node_get_row_data(ctree, node);
|
|
if (msginfo && MSG_IS_UNREAD(msginfo->flags) && !MSG_IS_IGNORE_THREAD(msginfo->flags))
|
|
return TRUE;
|
|
node = GTK_CMCTREE_ROW(node)->children;
|
|
} else
|
|
node = GTK_CMCTREE_NODE(GTK_CMCLIST(ctree)->row_list);
|
|
|
|
while (node) {
|
|
if (summary_search_unread_recursive(ctree, node) == TRUE)
|
|
return TRUE;
|
|
node = GTK_CMCTREE_ROW(node)->sibling;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean summary_have_unread_children(SummaryView *summaryview,
|
|
GtkCMCTreeNode *node)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
|
|
if (!node) return FALSE;
|
|
|
|
node = GTK_CMCTREE_ROW(node)->children;
|
|
|
|
while (node) {
|
|
if (summary_search_unread_recursive(ctree, node) == TRUE)
|
|
return TRUE;
|
|
node = GTK_CMCTREE_ROW(node)->sibling;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static void summary_set_row_marks(SummaryView *summaryview, GtkCMCTreeNode *row)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GtkStyle *style = NULL;
|
|
MsgInfo *msginfo;
|
|
MsgFlags flags;
|
|
gint *col_pos = summaryview->col_pos;
|
|
|
|
msginfo = gtk_cmctree_node_get_row_data(ctree, row);
|
|
if (!msginfo) return;
|
|
|
|
flags = msginfo->flags;
|
|
|
|
gtk_cmctree_node_set_foreground(ctree, row, NULL);
|
|
|
|
/* set new/unread column */
|
|
if (MSG_IS_IGNORE_THREAD(flags)) {
|
|
gtk_cmctree_node_set_pixbuf(ctree, row, col_pos[S_COL_STATUS],
|
|
ignorethreadxpm);
|
|
} else if (MSG_IS_WATCH_THREAD(flags)) {
|
|
gtk_cmctree_node_set_pixbuf(ctree, row, col_pos[S_COL_STATUS],
|
|
watchthreadxpm);
|
|
} else if (MSG_IS_SPAM(flags)) {
|
|
gtk_cmctree_node_set_pixbuf(ctree, row, col_pos[S_COL_STATUS],
|
|
spamxpm);
|
|
} else if (MSG_IS_NEW(flags)) {
|
|
gtk_cmctree_node_set_pixbuf(ctree, row, col_pos[S_COL_STATUS],
|
|
newxpm);
|
|
} else if (MSG_IS_UNREAD(flags)) {
|
|
gtk_cmctree_node_set_pixbuf(ctree, row, col_pos[S_COL_STATUS],
|
|
unreadxpm);
|
|
} else if (MSG_IS_REPLIED(flags) && MSG_IS_FORWARDED(flags)) {
|
|
gtk_cmctree_node_set_pixbuf(ctree, row, col_pos[S_COL_STATUS],
|
|
repliedandforwardedxpm);
|
|
} else if (MSG_IS_REPLIED(flags)) {
|
|
gtk_cmctree_node_set_pixbuf(ctree, row, col_pos[S_COL_STATUS],
|
|
repliedxpm);
|
|
} else if (MSG_IS_FORWARDED(flags)) {
|
|
gtk_cmctree_node_set_pixbuf(ctree, row, col_pos[S_COL_STATUS],
|
|
forwardedxpm);
|
|
} else {
|
|
gtk_cmctree_node_set_text(ctree, row, col_pos[S_COL_STATUS],
|
|
"");
|
|
}
|
|
|
|
if (prefs_common.bold_unread &&
|
|
((MSG_IS_UNREAD(flags) && !MSG_IS_IGNORE_THREAD(flags)) ||
|
|
(!GTK_CMCTREE_ROW(row)->expanded &&
|
|
GTK_CMCTREE_ROW(row)->children &&
|
|
summary_have_unread_children(summaryview, row))))
|
|
style = bold_style;
|
|
|
|
/* set mark column */
|
|
if (MSG_IS_DELETED(flags)) {
|
|
gtk_cmctree_node_set_pixbuf(ctree, row, col_pos[S_COL_MARK],
|
|
deletedxpm);
|
|
if (style)
|
|
style = bold_style;
|
|
gtk_cmctree_node_set_foreground
|
|
(ctree, row, &summaryview->color_dim);
|
|
} else if (MSG_IS_MARKED(flags)) {
|
|
gtk_cmctree_node_set_pixbuf(ctree, row, col_pos[S_COL_MARK],
|
|
markxpm);
|
|
} else if (MSG_IS_MOVE(flags)) {
|
|
gtk_cmctree_node_set_pixbuf(ctree, row, col_pos[S_COL_MARK],
|
|
movedxpm);
|
|
if (!msginfo->to_folder ||
|
|
!folder_has_parent_of_type(msginfo->to_folder, F_TRASH)) {
|
|
if (style)
|
|
style = bold_style;
|
|
gtk_cmctree_node_set_foreground
|
|
(ctree, row, &summaryview->color_marked);
|
|
} else {
|
|
if (style)
|
|
style = bold_style;
|
|
gtk_cmctree_node_set_foreground
|
|
(ctree, row, &summaryview->color_dim);
|
|
}
|
|
} else if (MSG_IS_COPY(flags)) {
|
|
gtk_cmctree_node_set_pixbuf(ctree, row, col_pos[S_COL_MARK],
|
|
copiedxpm);
|
|
if (style)
|
|
style = bold_style;
|
|
gtk_cmctree_node_set_foreground
|
|
(ctree, row, &summaryview->color_marked);
|
|
} else {
|
|
gtk_cmctree_node_set_text(ctree, row, col_pos[S_COL_MARK], "");
|
|
}
|
|
|
|
if (MSG_IS_LOCKED(flags)) {
|
|
gtk_cmctree_node_set_pixbuf(ctree, row, col_pos[S_COL_LOCKED],
|
|
lockedxpm);
|
|
}
|
|
else {
|
|
gtk_cmctree_node_set_text(ctree, row, col_pos[S_COL_LOCKED], "");
|
|
}
|
|
|
|
if (MSG_IS_WITH_ATTACHMENT(flags) && MSG_IS_SIGNED(flags)) {
|
|
gtk_cmctree_node_set_pixbuf(ctree, row, col_pos[S_COL_MIME],
|
|
clipgpgsignedxpm);
|
|
} else if (MSG_IS_SIGNED(flags)) {
|
|
if (MSG_IS_ENCRYPTED(flags)) {
|
|
gtk_cmctree_node_set_pixbuf(ctree, row, col_pos[S_COL_MIME],
|
|
keysignxpm);
|
|
} else {
|
|
gtk_cmctree_node_set_pixbuf(ctree, row, col_pos[S_COL_MIME],
|
|
gpgsignedxpm);
|
|
}
|
|
} else if (MSG_IS_WITH_ATTACHMENT(flags) && MSG_IS_ENCRYPTED(flags)) {
|
|
gtk_cmctree_node_set_pixbuf(ctree, row, col_pos[S_COL_MIME],
|
|
clipkeyxpm);
|
|
} else if (MSG_IS_ENCRYPTED(flags)) {
|
|
gtk_cmctree_node_set_pixbuf(ctree, row, col_pos[S_COL_MIME],
|
|
keyxpm);
|
|
} else if (MSG_IS_WITH_ATTACHMENT(flags)) {
|
|
gtk_cmctree_node_set_pixbuf(ctree, row, col_pos[S_COL_MIME],
|
|
clipxpm);
|
|
} else {
|
|
gtk_cmctree_node_set_text(ctree, row, col_pos[S_COL_MIME], "");
|
|
}
|
|
|
|
gtk_cmctree_node_set_row_style(ctree, row, style);
|
|
|
|
if (MSG_GET_COLORLABEL(flags))
|
|
summary_set_colorlabel_color(ctree, row, MSG_GET_COLORLABEL_VALUE(flags));
|
|
}
|
|
|
|
static void summary_mark_row(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))
|
|
summaryview->deleted--;
|
|
if (MSG_IS_MOVE(msginfo->flags))
|
|
summaryview->moved--;
|
|
if (MSG_IS_COPY(msginfo->flags))
|
|
summaryview->copied--;
|
|
|
|
procmsg_msginfo_set_to_folder(msginfo, NULL);
|
|
summary_msginfo_change_flags(msginfo, MSG_MARKED, 0, MSG_DELETED,
|
|
MSG_MOVE | MSG_COPY | MSG_MOVE_DONE);
|
|
summary_set_row_marks(summaryview, row);
|
|
debug_print("Message %s/%d is marked\n", msginfo->folder->path, msginfo->msgnum);
|
|
}
|
|
|
|
static void summary_lock_row(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))
|
|
summaryview->deleted--;
|
|
if (MSG_IS_MOVE(msginfo->flags)) {
|
|
summaryview->moved--;
|
|
}
|
|
if (MSG_IS_COPY(msginfo->flags)) {
|
|
summaryview->copied--;
|
|
}
|
|
procmsg_msginfo_set_to_folder(msginfo, NULL);
|
|
summary_msginfo_change_flags(msginfo, MSG_LOCKED, 0, MSG_DELETED,
|
|
MSG_MOVE | MSG_COPY | MSG_MOVE_DONE);
|
|
|
|
summary_set_row_marks(summaryview, row);
|
|
debug_print("Message %d is locked\n", msginfo->msgnum);
|
|
}
|
|
|
|
static void summary_unlock_row(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_LOCKED(msginfo->flags))
|
|
return;
|
|
procmsg_msginfo_set_to_folder(msginfo, NULL);
|
|
summary_msginfo_unset_flags(msginfo, MSG_LOCKED, 0);
|
|
summary_set_row_marks(summaryview, row);
|
|
debug_print("Message %d is unlocked\n", msginfo->msgnum);
|
|
}
|
|
|
|
void summary_mark(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GList *cur;
|
|
gboolean froze = FALSE;
|
|
|
|
if (summary_is_locked(summaryview))
|
|
return;
|
|
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(summaryview, GTK_CMCTREE_NODE(cur->data));
|
|
folder_item_set_batch(summaryview->folder_item, FALSE);
|
|
END_LONG_OPERATION(summaryview);
|
|
|
|
summary_status_show(summaryview);
|
|
}
|
|
|
|
static void summary_mark_row_as_read(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_unset_flags(msginfo, MSG_NEW | MSG_UNREAD, 0);
|
|
summary_set_row_marks(summaryview, row);
|
|
debug_print("Message %d is marked as read\n",
|
|
msginfo->msgnum);
|
|
}
|
|
|
|
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)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GList *cur;
|
|
gboolean froze = FALSE;
|
|
|
|
if (summary_is_locked(summaryview))
|
|
return;
|
|
|
|
if ((summaryview->folder_item->total_msgs == (gint)g_list_length(GTK_CMCLIST(ctree)->selection) &&
|
|
summaryview->folder_item->total_msgs > 1) &&
|
|
!summary_mark_all_read_confirm(TRUE))
|
|
return;
|
|
|
|
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));
|
|
folder_item_set_batch(summaryview->folder_item, FALSE);
|
|
END_LONG_OPERATION(summaryview);
|
|
|
|
summary_status_show(summaryview);
|
|
}
|
|
|
|
void summary_mark_as_unread(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GList *cur;
|
|
gboolean froze = FALSE;
|
|
|
|
if (summary_is_locked(summaryview))
|
|
return;
|
|
|
|
if ((summaryview->folder_item->total_msgs == (gint)g_list_length(GTK_CMCLIST(ctree)->selection) &&
|
|
summaryview->folder_item->total_msgs > 1) &&
|
|
!summary_mark_all_unread_confirm(TRUE))
|
|
return;
|
|
|
|
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_unread(summaryview,
|
|
GTK_CMCTREE_NODE(cur->data));
|
|
folder_item_set_batch(summaryview->folder_item, FALSE);
|
|
END_LONG_OPERATION(summaryview);
|
|
|
|
summary_status_show(summaryview);
|
|
}
|
|
|
|
void summary_msgs_lock(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GList *cur;
|
|
gboolean froze = FALSE;
|
|
|
|
if (summary_is_locked(summaryview))
|
|
return;
|
|
START_LONG_OPERATION(summaryview, FALSE);
|
|
for (cur = GTK_CMCLIST(ctree)->selection; cur != NULL && cur->data != NULL; cur = cur->next)
|
|
summary_lock_row(summaryview,
|
|
GTK_CMCTREE_NODE(cur->data));
|
|
END_LONG_OPERATION(summaryview);
|
|
|
|
summary_status_show(summaryview);
|
|
}
|
|
|
|
void summary_msgs_unlock(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GList *cur;
|
|
gboolean froze = FALSE;
|
|
|
|
if (summary_is_locked(summaryview))
|
|
return;
|
|
START_LONG_OPERATION(summaryview, FALSE);
|
|
for (cur = GTK_CMCLIST(ctree)->selection; cur != NULL && cur->data != NULL; cur = cur->next)
|
|
summary_unlock_row(summaryview,
|
|
GTK_CMCTREE_NODE(cur->data));
|
|
END_LONG_OPERATION(summaryview);
|
|
|
|
summary_status_show(summaryview);
|
|
}
|
|
|
|
static gboolean summary_mark_all_read_confirm(gboolean ask_if_needed)
|
|
{
|
|
/* ask_if_needed is FALSE when user-asking is performed by caller,
|
|
commonly when the caller is a mark-as-read-recursive func */
|
|
if (ask_if_needed && prefs_common.ask_mark_all_read) {
|
|
AlertValue 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, ALERTFOCUS_FIRST,
|
|
TRUE, NULL, ALERT_QUESTION);
|
|
|
|
if ((val & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
|
|
return FALSE;
|
|
else if (val & G_ALERTDISABLE)
|
|
prefs_common.ask_mark_all_read = FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void summary_mark_all_read(SummaryView *summaryview, gboolean ask_if_needed)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GtkCMCTreeNode *node;
|
|
gboolean froze = FALSE;
|
|
|
|
if (summary_is_locked(summaryview))
|
|
return;
|
|
|
|
if (!summary_mark_all_read_confirm(ask_if_needed))
|
|
return;
|
|
|
|
START_LONG_OPERATION(summaryview, TRUE);
|
|
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);
|
|
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)) {
|
|
if (!GTK_CMCTREE_ROW(node)->expanded)
|
|
summary_set_row_marks(summaryview, node);
|
|
}
|
|
END_LONG_OPERATION(summaryview);
|
|
|
|
summary_status_show(summaryview);
|
|
}
|
|
|
|
static gboolean summary_mark_all_unread_confirm(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) {
|
|
AlertValue 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, ALERTFOCUS_FIRST,
|
|
TRUE, NULL, ALERT_QUESTION);
|
|
|
|
if ((val & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
|
|
return FALSE;
|
|
else if (val & G_ALERTDISABLE)
|
|
prefs_common.ask_mark_all_read = FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void summary_mark_all_unread(SummaryView *summaryview, gboolean ask_if_needed)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GtkCMCTreeNode *node;
|
|
gboolean froze = FALSE;
|
|
|
|
if (summary_is_locked(summaryview))
|
|
return;
|
|
|
|
if (!summary_mark_all_unread_confirm(ask_if_needed))
|
|
return;
|
|
|
|
START_LONG_OPERATION(summaryview, TRUE);
|
|
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_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)) {
|
|
if (!GTK_CMCTREE_ROW(node)->expanded)
|
|
summary_set_row_marks(summaryview, node);
|
|
}
|
|
END_LONG_OPERATION(summaryview);
|
|
|
|
summary_status_show(summaryview);
|
|
}
|
|
|
|
void summary_mark_as_spam(SummaryView *summaryview, guint action, GtkWidget *widget)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GList *cur;
|
|
gboolean is_spam = action;
|
|
GSList *msgs = NULL;
|
|
gboolean immediate_exec = prefs_common.immediate_exec;
|
|
gboolean moved = FALSE;
|
|
gboolean froze = FALSE;
|
|
|
|
|
|
if (summary_is_locked(summaryview))
|
|
return;
|
|
|
|
prefs_common.immediate_exec = FALSE;
|
|
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) {
|
|
GtkCMCTreeNode *row = GTK_CMCTREE_NODE(cur->data);
|
|
MsgInfo *msginfo = gtk_cmctree_node_get_row_data(ctree, row);
|
|
if (msginfo)
|
|
msgs = g_slist_prepend(msgs, msginfo);
|
|
}
|
|
|
|
if (procmsg_spam_learner_learn(NULL, msgs, is_spam) == 0) {
|
|
for (cur = GTK_CMCLIST(ctree)->selection; cur != NULL && cur->data != NULL; cur = cur->next) {
|
|
GtkCMCTreeNode *row = GTK_CMCTREE_NODE(cur->data);
|
|
MsgInfo *msginfo = gtk_cmctree_node_get_row_data(ctree, row);
|
|
if (!msginfo)
|
|
continue;
|
|
if (is_spam) {
|
|
summary_msginfo_change_flags(msginfo, MSG_SPAM, 0, MSG_NEW|MSG_UNREAD, 0);
|
|
if (procmsg_spam_get_folder(msginfo) != summaryview->folder_item) {
|
|
summary_move_row_to(summaryview, row,
|
|
procmsg_spam_get_folder(msginfo));
|
|
moved = TRUE;
|
|
}
|
|
} else {
|
|
summary_msginfo_unset_flags(msginfo, MSG_SPAM, 0);
|
|
}
|
|
summaryview->display_msg = prefs_common.always_show_msg;
|
|
|
|
summary_set_row_marks(summaryview, row);
|
|
}
|
|
} else {
|
|
log_error(LOG_PROTOCOL, _("An error happened while learning.\n"));
|
|
}
|
|
|
|
prefs_common.immediate_exec = immediate_exec;
|
|
folder_item_set_batch(summaryview->folder_item, FALSE);
|
|
END_LONG_OPERATION(summaryview);
|
|
|
|
if (prefs_common.immediate_exec && moved) {
|
|
summary_execute(summaryview);
|
|
}
|
|
|
|
if (!moved && msgs) {
|
|
MsgInfo *msginfo = (MsgInfo *)msgs->data;
|
|
toolbar_set_learn_button
|
|
(summaryview->mainwin->toolbar,
|
|
MSG_IS_SPAM(msginfo->flags)?LEARN_HAM:LEARN_SPAM);
|
|
}
|
|
g_slist_free(msgs);
|
|
|
|
summary_status_show(summaryview);
|
|
}
|
|
|
|
static gboolean check_permission(SummaryView *summaryview, MsgInfo * msginfo)
|
|
{
|
|
GList * cur;
|
|
gboolean found;
|
|
|
|
switch (FOLDER_TYPE(summaryview->folder_item->folder)) {
|
|
|
|
case F_NEWS:
|
|
|
|
/*
|
|
security : checks if one the accounts correspond to
|
|
the author of the post
|
|
*/
|
|
|
|
found = FALSE;
|
|
for(cur = account_get_list() ; cur != NULL ; cur = cur->next) {
|
|
PrefsAccount * account;
|
|
gchar * from_name;
|
|
|
|
account = cur->data;
|
|
if (account->name && *account->name)
|
|
from_name =
|
|
g_strdup_printf("%s <%s>",
|
|
account->name,
|
|
account->address);
|
|
else
|
|
from_name =
|
|
g_strdup_printf("%s",
|
|
account->address);
|
|
|
|
if (g_utf8_collate(from_name, msginfo->from) == 0) {
|
|
g_free(from_name);
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
g_free(from_name);
|
|
}
|
|
|
|
if (!found) {
|
|
alertpanel_error(_("You're not the author of the article."));
|
|
}
|
|
|
|
return found;
|
|
|
|
default:
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
static void summary_delete_row(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_LOCKED(msginfo->flags)) return;
|
|
|
|
if (MSG_IS_DELETED(msginfo->flags)) return;
|
|
|
|
if (MSG_IS_MOVE(msginfo->flags))
|
|
summaryview->moved--;
|
|
if (MSG_IS_COPY(msginfo->flags))
|
|
summaryview->copied--;
|
|
|
|
procmsg_msginfo_set_to_folder(msginfo, NULL);
|
|
summary_msginfo_change_flags(msginfo, MSG_DELETED, 0, MSG_MARKED,
|
|
MSG_MOVE | MSG_COPY | MSG_MOVE_DONE);
|
|
summaryview->deleted++;
|
|
|
|
if (!prefs_common.immediate_exec &&
|
|
!folder_has_parent_of_type(summaryview->folder_item, F_TRASH)) {
|
|
summary_set_row_marks(summaryview, row);
|
|
}
|
|
debug_print("Message %s/%d is set to delete\n",
|
|
msginfo->folder->path, msginfo->msgnum);
|
|
}
|
|
|
|
void summary_cancel(SummaryView *summaryview)
|
|
{
|
|
MsgInfo * msginfo;
|
|
|
|
msginfo = gtk_cmctree_node_get_row_data(GTK_CMCTREE(summaryview->ctree),
|
|
summaryview->selected);
|
|
if (!msginfo) return;
|
|
|
|
if (!check_permission(summaryview, msginfo))
|
|
return;
|
|
|
|
news_cancel_article(summaryview->folder_item->folder, msginfo);
|
|
|
|
if (summary_is_locked(summaryview)) return;
|
|
|
|
summary_lock(summaryview);
|
|
|
|
summary_freeze(summaryview);
|
|
|
|
summary_update_status(summaryview);
|
|
summary_status_show(summaryview);
|
|
|
|
summary_thaw(summaryview);
|
|
|
|
summary_unlock(summaryview);
|
|
}
|
|
|
|
void summary_delete(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
FolderItem *item = summaryview->folder_item;
|
|
GList *cur;
|
|
GtkCMCTreeNode *sel_last = NULL;
|
|
GtkCMCTreeNode *node;
|
|
AlertValue aval;
|
|
MsgInfo *msginfo;
|
|
gboolean froze = FALSE;
|
|
|
|
if (!item) return;
|
|
|
|
if (summary_is_locked(summaryview)) return;
|
|
|
|
if (!summaryview->folder_item) return;
|
|
|
|
START_LONG_OPERATION(summaryview, FALSE);
|
|
|
|
if (!prefs_common.live_dangerously) {
|
|
gchar *buf = NULL;
|
|
guint num = g_list_length(GTK_CMCLIST(summaryview->ctree)->selection);
|
|
buf = g_strdup_printf(ngettext(
|
|
"Do you really want to delete the selected message?",
|
|
"Do you really want to delete the %d selected messages?", num),
|
|
num);
|
|
aval = alertpanel(ngettext("Delete message", "Delete messages", num),
|
|
buf,
|
|
GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_SECOND);
|
|
g_free(buf);
|
|
if (aval != G_ALERTALTERNATE) {
|
|
END_LONG_OPERATION(summaryview);
|
|
return;
|
|
}
|
|
}
|
|
|
|
for (cur = GTK_CMCLIST(ctree)->selection; cur != NULL && cur->data != NULL;
|
|
cur = cur->next) {
|
|
GtkCMCTreeNode *row = GTK_CMCTREE_NODE(cur->data);
|
|
msginfo = gtk_cmctree_node_get_row_data(ctree, row);
|
|
if (msginfo && msginfo->total_size != 0 &&
|
|
msginfo->size != (goffset)msginfo->total_size)
|
|
partial_mark_for_delete(msginfo);
|
|
}
|
|
|
|
main_window_cursor_wait(summaryview->mainwin);
|
|
|
|
/* next code sets current row focus right. We need to find a row
|
|
* that is not deleted. */
|
|
folder_item_set_batch(summaryview->folder_item, TRUE);
|
|
for (cur = GTK_CMCLIST(ctree)->selection; cur != NULL && cur->data != NULL; cur = cur->next) {
|
|
sel_last = GTK_CMCTREE_NODE(cur->data);
|
|
summary_delete_row(summaryview, sel_last);
|
|
}
|
|
folder_item_set_batch(summaryview->folder_item, FALSE);
|
|
END_LONG_OPERATION(summaryview);
|
|
|
|
if (summaryview->sort_type == SORT_ASCENDING) {
|
|
node = summary_find_next_msg(summaryview, sel_last, TRUE);
|
|
if (!node || prefs_common.next_on_delete == FALSE)
|
|
node = summary_find_prev_msg(summaryview, sel_last,TRUE);
|
|
} else {
|
|
node = summary_find_prev_msg(summaryview, sel_last,TRUE);
|
|
if (!node || prefs_common.next_on_delete == FALSE)
|
|
node = summary_find_next_msg(summaryview, sel_last,TRUE);
|
|
}
|
|
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);
|
|
/* after deleting, the anchor may be at an invalid row
|
|
* so reset it to the node we found earlier */
|
|
gtk_sctree_set_anchor_row(GTK_SCTREE(ctree), node);
|
|
} else
|
|
summary_status_show(summaryview);
|
|
|
|
|
|
main_window_cursor_normal(summaryview->mainwin);
|
|
}
|
|
|
|
void summary_delete_trash(SummaryView *summaryview)
|
|
{
|
|
FolderItem *to_folder = NULL;
|
|
PrefsAccount *ac;
|
|
if (!summaryview->folder_item ||
|
|
FOLDER_TYPE(summaryview->folder_item->folder) == F_NEWS) return;
|
|
|
|
if (NULL != (ac = account_find_from_item(summaryview->folder_item)))
|
|
to_folder = account_get_special_folder(ac, F_TRASH);
|
|
|
|
if (to_folder == NULL)
|
|
to_folder = summaryview->folder_item->folder->trash;
|
|
|
|
if (to_folder == NULL || to_folder == summaryview->folder_item
|
|
|| folder_has_parent_of_type(summaryview->folder_item, F_TRASH))
|
|
summary_delete(summaryview);
|
|
else
|
|
summary_move_selected_to(summaryview, to_folder);
|
|
}
|
|
|
|
|
|
static void summary_unmark_row(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))
|
|
summaryview->deleted--;
|
|
if (MSG_IS_MOVE(msginfo->flags))
|
|
summaryview->moved--;
|
|
if (MSG_IS_COPY(msginfo->flags))
|
|
summaryview->copied--;
|
|
|
|
procmsg_msginfo_set_to_folder(msginfo, NULL);
|
|
summary_msginfo_unset_flags(msginfo, MSG_MARKED | MSG_DELETED,
|
|
MSG_MOVE | MSG_COPY | MSG_MOVE_DONE);
|
|
summary_set_row_marks(summaryview, row);
|
|
|
|
debug_print("Message %s/%d is unmarked\n",
|
|
msginfo->folder->path, msginfo->msgnum);
|
|
}
|
|
|
|
void summary_unmark(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GList *cur;
|
|
gboolean froze = FALSE;
|
|
|
|
if (summary_is_locked(summaryview))
|
|
return;
|
|
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_unmark_row(summaryview, GTK_CMCTREE_NODE(cur->data));
|
|
folder_item_set_batch(summaryview->folder_item, FALSE);
|
|
END_LONG_OPERATION(summaryview);
|
|
|
|
summary_status_show(summaryview);
|
|
}
|
|
|
|
static void summary_move_row_to(SummaryView *summaryview, GtkCMCTreeNode *row,
|
|
FolderItem *to_folder)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
MsgInfo *msginfo;
|
|
|
|
cm_return_if_fail(to_folder != NULL);
|
|
|
|
msginfo = gtk_cmctree_node_get_row_data(ctree, row);
|
|
cm_return_if_fail(msginfo);
|
|
if (MSG_IS_LOCKED(msginfo->flags))
|
|
return;
|
|
|
|
procmsg_msginfo_set_to_folder(msginfo, to_folder);
|
|
if (MSG_IS_DELETED(msginfo->flags))
|
|
summaryview->deleted--;
|
|
if (MSG_IS_COPY(msginfo->flags)) {
|
|
summaryview->copied--;
|
|
}
|
|
if (!MSG_IS_MOVE(msginfo->flags)) {
|
|
summary_msginfo_change_flags(msginfo, 0, MSG_MOVE, MSG_DELETED,
|
|
MSG_COPY | MSG_MOVE_DONE);
|
|
summaryview->moved++;
|
|
} else {
|
|
summary_msginfo_unset_flags(msginfo, MSG_DELETED, MSG_COPY);
|
|
}
|
|
|
|
if (!prefs_common.immediate_exec) {
|
|
summary_set_row_marks(summaryview, row);
|
|
}
|
|
|
|
debug_print("Message %d is set to move to %s\n",
|
|
msginfo->msgnum, to_folder->path);
|
|
}
|
|
|
|
void summary_move_selected_to(SummaryView *summaryview, FolderItem *to_folder)
|
|
{
|
|
GList *cur;
|
|
GtkCMCTreeNode *sel_last = NULL;
|
|
gboolean froze = FALSE;
|
|
|
|
if (!to_folder) return;
|
|
if (!summaryview->folder_item ||
|
|
FOLDER_TYPE(summaryview->folder_item->folder) == F_NEWS) return;
|
|
|
|
if (summary_is_locked(summaryview)) return;
|
|
|
|
if (summaryview->folder_item == to_folder) {
|
|
alertpanel_error(_("Destination is same as current folder."));
|
|
return;
|
|
}
|
|
|
|
if (to_folder->no_select) {
|
|
alertpanel_error(_("The destination folder can only be used to "
|
|
"store subfolders."));
|
|
return;
|
|
}
|
|
|
|
START_LONG_OPERATION(summaryview, FALSE);
|
|
|
|
for (cur = GTK_CMCLIST(summaryview->ctree)->selection;
|
|
cur != NULL && cur->data != NULL; cur = cur->next) {
|
|
sel_last = GTK_CMCTREE_NODE(cur->data);
|
|
summary_move_row_to
|
|
(summaryview, GTK_CMCTREE_NODE(cur->data), to_folder);
|
|
}
|
|
END_LONG_OPERATION(summaryview);
|
|
|
|
if (prefs_common.immediate_exec) {
|
|
summary_execute(summaryview);
|
|
} else {
|
|
GtkCMCTreeNode *node = NULL;
|
|
if (summaryview->sort_type == SORT_ASCENDING) {
|
|
node = summary_find_next_msg(summaryview, sel_last,TRUE);
|
|
if (!node || prefs_common.next_on_delete == FALSE)
|
|
node = summary_find_prev_msg(summaryview, sel_last,TRUE);
|
|
} else {
|
|
node = summary_find_prev_msg(summaryview, sel_last,TRUE);
|
|
if (!node || prefs_common.next_on_delete == FALSE)
|
|
node = summary_find_next_msg(summaryview, sel_last,TRUE);
|
|
}
|
|
summary_select_node(summaryview, node, OPEN_SELECTED_ON_DELETEMOVE);
|
|
summary_status_show(summaryview);
|
|
}
|
|
|
|
if (!summaryview->selected) { /* this was the last message */
|
|
GtkCMCTreeNode *node = gtk_cmctree_node_nth (GTK_CMCTREE(summaryview->ctree),
|
|
GTK_CMCLIST(summaryview->ctree)->rows - 1);
|
|
if (node)
|
|
summary_select_node(summaryview, node, OPEN_SELECTED_ON_DELETEMOVE);
|
|
}
|
|
|
|
}
|
|
|
|
void summary_move_to(SummaryView *summaryview)
|
|
{
|
|
FolderItem *to_folder;
|
|
|
|
if (!summaryview->folder_item ||
|
|
FOLDER_TYPE(summaryview->folder_item->folder) == F_NEWS) return;
|
|
|
|
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);
|
|
}
|
|
|
|
static void summary_copy_row_to(SummaryView *summaryview, GtkCMCTreeNode *row,
|
|
FolderItem *to_folder)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
MsgInfo *msginfo;
|
|
|
|
cm_return_if_fail(to_folder != NULL);
|
|
|
|
msginfo = gtk_cmctree_node_get_row_data(ctree, row);
|
|
cm_return_if_fail(msginfo);
|
|
procmsg_msginfo_set_to_folder(msginfo, to_folder);
|
|
if (MSG_IS_DELETED(msginfo->flags))
|
|
summaryview->deleted--;
|
|
if (MSG_IS_MOVE(msginfo->flags)) {
|
|
summaryview->moved--;
|
|
}
|
|
|
|
if (!MSG_IS_COPY(msginfo->flags)) {
|
|
summary_msginfo_change_flags(msginfo, 0, MSG_COPY, MSG_DELETED,
|
|
MSG_MOVE | MSG_MOVE_DONE);
|
|
summaryview->copied++;
|
|
} else {
|
|
summary_msginfo_unset_flags(msginfo, MSG_DELETED, MSG_MOVE);
|
|
}
|
|
if (!prefs_common.immediate_exec) {
|
|
summary_set_row_marks(summaryview, row);
|
|
}
|
|
|
|
debug_print("Message %d is set to copy to %s\n",
|
|
msginfo->msgnum, to_folder->path);
|
|
}
|
|
|
|
void summary_copy_selected_to(SummaryView *summaryview, FolderItem *to_folder)
|
|
{
|
|
GList *cur;
|
|
gboolean froze = FALSE;
|
|
|
|
if (!to_folder) return;
|
|
if (!summaryview->folder_item) return;
|
|
|
|
if (summary_is_locked(summaryview)) return;
|
|
|
|
if (summaryview->folder_item == to_folder) {
|
|
alertpanel_error
|
|
(_("Destination to copy is same as current folder."));
|
|
return;
|
|
}
|
|
|
|
if (to_folder->no_select) {
|
|
alertpanel_error(_("The destination folder can only be used to "
|
|
"store subfolders."));
|
|
return;
|
|
}
|
|
|
|
START_LONG_OPERATION(summaryview, FALSE);
|
|
|
|
for (cur = GTK_CMCLIST(summaryview->ctree)->selection;
|
|
cur != NULL && cur->data != NULL; cur = cur->next)
|
|
summary_copy_row_to
|
|
(summaryview, GTK_CMCTREE_NODE(cur->data), to_folder);
|
|
|
|
END_LONG_OPERATION(summaryview);
|
|
|
|
if (prefs_common.immediate_exec)
|
|
summary_execute(summaryview);
|
|
else {
|
|
summary_status_show(summaryview);
|
|
}
|
|
}
|
|
|
|
void summary_copy_to(SummaryView *summaryview)
|
|
{
|
|
FolderItem *to_folder;
|
|
|
|
if (!summaryview->folder_item) return;
|
|
|
|
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);
|
|
}
|
|
|
|
void summary_add_address(SummaryView *summaryview)
|
|
{
|
|
MsgInfo *msginfo, *full_msginfo;
|
|
gchar *from;
|
|
GdkPixbuf *picture = NULL;
|
|
AvatarRender *avatarr;
|
|
|
|
msginfo = gtk_cmctree_node_get_row_data(GTK_CMCTREE(summaryview->ctree),
|
|
summaryview->selected);
|
|
if (!msginfo || !msginfo->from)
|
|
return;
|
|
|
|
Xstrdup_a(from, msginfo->from, return);
|
|
eliminate_address_comment(from);
|
|
extract_address(from);
|
|
|
|
full_msginfo = procmsg_msginfo_get_full_info(msginfo);
|
|
|
|
avatarr = avatars_avatarrender_new(full_msginfo);
|
|
hooks_invoke(AVATAR_IMAGE_RENDER_HOOKLIST, avatarr);
|
|
|
|
procmsg_msginfo_free(&full_msginfo);
|
|
|
|
if (avatarr->image)
|
|
picture = gtk_image_get_pixbuf(GTK_IMAGE(avatarr->image));
|
|
|
|
#ifndef USE_ALT_ADDRBOOK
|
|
addressbook_add_contact(msginfo->fromname, from, NULL, picture);
|
|
#else
|
|
if (addressadd_selection(msginfo->fromname, from, NULL, picture)) {
|
|
debug_print( "addressbook_add_contact - added\n" );
|
|
}
|
|
#endif
|
|
avatars_avatarrender_free(avatarr);
|
|
}
|
|
|
|
void summary_select_all(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTreeNode *node;
|
|
|
|
if (!summaryview->folder_item) return;
|
|
|
|
if (GTK_CMCLIST(summaryview->ctree)->focus_row < 0) {
|
|
/* If no row is selected, select (but do not open) the first
|
|
* row, to get summaryview into correct state for selecting all. */
|
|
debug_print("summary_select_all: no row selected, selecting first one\n");
|
|
if (GTK_CMCLIST(summaryview->ctree)->row_list != NULL) {
|
|
node = gtk_cmctree_node_nth(GTK_CMCTREE(summaryview->ctree), 0);
|
|
summary_select_node(summaryview, node, FALSE);
|
|
}
|
|
}
|
|
|
|
/* Now select all rows while locking the summaryview for
|
|
* faster performance. */
|
|
summary_lock(summaryview);
|
|
gtk_cmclist_select_all(GTK_CMCLIST(summaryview->ctree));
|
|
summary_unlock(summaryview);
|
|
|
|
summary_status_show(summaryview);
|
|
}
|
|
|
|
void summary_unselect_all(SummaryView *summaryview)
|
|
{
|
|
summary_lock(summaryview);
|
|
gtk_sctree_unselect_all(GTK_SCTREE(summaryview->ctree));
|
|
summary_unlock(summaryview);
|
|
summary_status_show(summaryview);
|
|
}
|
|
|
|
void summary_select_thread(SummaryView *summaryview, gboolean delete_thread,
|
|
gboolean trash_thread)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GtkCMCTreeNode *node = NULL;
|
|
gboolean froze = FALSE;
|
|
GList *cur = NULL;
|
|
GList *copy = NULL;
|
|
if (!GTK_CMCLIST(summaryview->ctree)->selection)
|
|
return;
|
|
|
|
|
|
START_LONG_OPERATION(summaryview, FALSE);
|
|
copy = g_list_copy(GTK_CMCLIST(summaryview->ctree)->selection);
|
|
for (cur = copy; cur != NULL && cur->data != NULL;
|
|
cur = cur->next) {
|
|
node = GTK_CMCTREE_NODE(cur->data);
|
|
if (!node)
|
|
continue;
|
|
while (GTK_CMCTREE_ROW(node)->parent != NULL)
|
|
node = GTK_CMCTREE_ROW(node)->parent;
|
|
|
|
gtk_cmctree_select_recursive(ctree, node);
|
|
}
|
|
g_list_free(copy);
|
|
END_LONG_OPERATION(summaryview);
|
|
|
|
if (trash_thread) {
|
|
if (FOLDER_TYPE(summaryview->folder_item->folder) == F_NEWS)
|
|
summary_delete(summaryview);
|
|
else
|
|
summary_delete_trash(summaryview);
|
|
} else if (delete_thread)
|
|
summary_delete(summaryview);
|
|
|
|
summary_status_show(summaryview);
|
|
}
|
|
|
|
void summary_save_as(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
MsgInfo *msginfo;
|
|
gchar *filename = NULL;
|
|
gchar *src, *dest;
|
|
gchar *tmp;
|
|
gchar *filedir = NULL;
|
|
|
|
AlertValue aval = 0;
|
|
|
|
if (!summaryview->selected) return;
|
|
msginfo = gtk_cmctree_node_get_row_data(ctree, summaryview->selected);
|
|
if (!msginfo) return;
|
|
|
|
if (msginfo->subject) {
|
|
Xstrdup_a(filename, msginfo->subject, return);
|
|
subst_for_filename(filename);
|
|
}
|
|
|
|
manage_window_focus_in(summaryview->window, NULL, NULL);
|
|
|
|
if (filename && !g_utf8_validate(filename, -1, NULL)) {
|
|
gchar *oldstr = filename;
|
|
filename = conv_codeset_strdup(filename,
|
|
conv_get_locale_charset_str(),
|
|
CS_UTF_8);
|
|
if (!filename) {
|
|
g_warning("summary_save_as(): failed to convert character set.");
|
|
filename = g_strdup(oldstr);
|
|
}
|
|
dest = filename;
|
|
g_free(filename);
|
|
} else
|
|
dest = filename;
|
|
filename = NULL;
|
|
if (!dest) return;
|
|
if (prefs_common.attach_save_dir && *prefs_common.attach_save_dir)
|
|
dest = g_strconcat(prefs_common.attach_save_dir, G_DIR_SEPARATOR_S,
|
|
dest, NULL);
|
|
dest = filesel_select_file_save(_("Save as"), dest);
|
|
if (!dest) return;
|
|
|
|
if (is_file_exist(dest)) {
|
|
aval = alertpanel(_("Append or Overwrite"),
|
|
_("Append or overwrite existing file?"),
|
|
_("_Append"), _("_Overwrite"), GTK_STOCK_CANCEL,
|
|
ALERTFOCUS_FIRST);
|
|
if (aval != 0 && aval != 1)
|
|
return;
|
|
}
|
|
|
|
src = procmsg_get_message_file(msginfo);
|
|
tmp = g_path_get_basename(dest);
|
|
|
|
if ( aval==0 ) { /* append */
|
|
if (append_file(src, dest, TRUE) < 0)
|
|
alertpanel_error(_("Couldn't save the file '%s'."), tmp);
|
|
} else { /* overwrite */
|
|
if (copy_file(src, dest, TRUE) < 0)
|
|
alertpanel_error(_("Couldn't save the file '%s'."), tmp);
|
|
}
|
|
g_free(src);
|
|
|
|
/*
|
|
* If two or more msgs are selected,
|
|
* append them to the output file.
|
|
*/
|
|
if (GTK_CMCLIST(ctree)->selection->next) {
|
|
GList *item;
|
|
for (item = GTK_CMCLIST(ctree)->selection->next; item != NULL; item=item->next) {
|
|
msginfo = gtk_cmctree_node_get_row_data(ctree, GTK_CMCTREE_NODE(item->data));
|
|
if (!msginfo) break;
|
|
src = procmsg_get_message_file(msginfo);
|
|
if (append_file(src, dest, TRUE) < 0)
|
|
alertpanel_error(_("Couldn't save the file '%s'."), tmp);
|
|
}
|
|
g_free(src);
|
|
}
|
|
|
|
filedir = g_path_get_dirname(dest);
|
|
if (filedir && strcmp(filedir, ".")) {
|
|
g_free(prefs_common.attach_save_dir);
|
|
prefs_common.attach_save_dir = g_filename_to_utf8(filedir, -1, NULL, NULL, NULL);
|
|
}
|
|
|
|
g_free(dest);
|
|
g_free(tmp);
|
|
}
|
|
|
|
void summary_print(SummaryView *summaryview)
|
|
{
|
|
GtkCMCList *clist = GTK_CMCLIST(summaryview->ctree);
|
|
GList *cur;
|
|
gchar *msg = g_strdup_printf(_("You are about to print %d "
|
|
"messages, one by one. Do you "
|
|
"want to continue?"),
|
|
g_list_length(clist->selection));
|
|
if (g_list_length(clist->selection) > 9
|
|
&& alertpanel(_("Warning"), msg, GTK_STOCK_CANCEL, GTK_STOCK_YES,
|
|
NULL, ALERTFOCUS_SECOND) != G_ALERTALTERNATE) {
|
|
g_free(msg);
|
|
return;
|
|
}
|
|
g_free(msg);
|
|
|
|
if (clist->selection == NULL) return;
|
|
for (cur = clist->selection;
|
|
cur != NULL && cur->data != NULL;
|
|
cur = cur->next) {
|
|
GtkCMCTreeNode *node = GTK_CMCTREE_NODE(cur->data);
|
|
MsgInfo *msginfo = gtk_cmctree_node_get_row_data(
|
|
GTK_CMCTREE(summaryview->ctree),
|
|
node);
|
|
gint sel_start = -1, sel_end = -1, partnum = 0;
|
|
|
|
if (node == summaryview->displayed) {
|
|
partnum = mimeview_get_selected_part_num(summaryview->messageview->mimeview);
|
|
textview_get_selection_offsets(summaryview->messageview->mimeview->textview,
|
|
&sel_start, &sel_end);
|
|
}
|
|
messageview_print(msginfo, summaryview->messageview->all_headers,
|
|
sel_start, sel_end, partnum);
|
|
}
|
|
}
|
|
|
|
gboolean summary_execute(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GtkCMCList *clist = GTK_CMCLIST(summaryview->ctree);
|
|
GtkCMCTreeNode *node, *next;
|
|
GtkCMCTreeNode *new_selected = NULL;
|
|
gint move_val = -1;
|
|
|
|
if (!summaryview->folder_item) return FALSE;
|
|
|
|
if (summary_is_locked(summaryview)) return FALSE;
|
|
summary_lock(summaryview);
|
|
|
|
summary_freeze(summaryview);
|
|
|
|
main_window_cursor_wait(summaryview->mainwin);
|
|
|
|
if (summaryview->threaded)
|
|
summary_unthread_for_exec(summaryview);
|
|
|
|
folder_item_update_freeze();
|
|
move_val = summary_execute_move(summaryview);
|
|
summary_execute_copy(summaryview);
|
|
summary_execute_delete(summaryview);
|
|
|
|
node = GTK_CMCTREE_NODE(clist->row_list);
|
|
for (; node != NULL; node = next) {
|
|
next = gtkut_ctree_node_next(ctree, node);
|
|
if (gtk_cmctree_node_get_row_data(ctree, node) != NULL) continue;
|
|
|
|
if (node == summaryview->displayed) {
|
|
messageview_clear(summaryview->messageview);
|
|
summary_cancel_mark_read_timeout(summaryview);
|
|
summaryview->displayed = NULL;
|
|
}
|
|
if (GTK_CMCTREE_ROW(node)->children != NULL) {
|
|
next = NULL;
|
|
if (GTK_CMCTREE_ROW(node)->sibling) {
|
|
next = GTK_CMCTREE_ROW(node)->sibling;
|
|
} else {
|
|
GtkCMCTreeNode *parent = NULL;
|
|
for (parent = GTK_CMCTREE_ROW(node)->parent; parent != NULL;
|
|
parent = GTK_CMCTREE_ROW(parent)->parent) {
|
|
if (GTK_CMCTREE_ROW(parent)->sibling) {
|
|
next = GTK_CMCTREE_ROW(parent)->sibling;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!new_selected &&
|
|
gtkut_ctree_node_is_selected(ctree, node)) {
|
|
summary_unselect_all(summaryview);
|
|
if (summaryview->sort_type == SORT_ASCENDING) {
|
|
new_selected = summary_find_next_msg(summaryview, node,TRUE);
|
|
if (!new_selected || prefs_common.next_on_delete == FALSE)
|
|
new_selected = summary_find_prev_msg(summaryview, node,TRUE);
|
|
} else {
|
|
new_selected = summary_find_prev_msg(summaryview, node,TRUE);
|
|
if (!new_selected || prefs_common.next_on_delete == FALSE)
|
|
new_selected = summary_find_next_msg(summaryview, node,TRUE);
|
|
}
|
|
}
|
|
|
|
gtk_sctree_remove_node((GtkSCTree *)ctree, node);
|
|
}
|
|
|
|
folder_item_update_thaw();
|
|
|
|
if (new_selected) {
|
|
summary_unlock(summaryview);
|
|
summary_select_node(summaryview, new_selected, OPEN_SELECTED_ON_DELETEMOVE);
|
|
summary_lock(summaryview);
|
|
}
|
|
|
|
if (summaryview->threaded) {
|
|
summary_thread_build(summaryview);
|
|
summary_thread_init(summaryview);
|
|
}
|
|
|
|
summary_thaw(summaryview);
|
|
|
|
summaryview->selected = clist->selection ?
|
|
GTK_CMCTREE_NODE(clist->selection->data) : NULL;
|
|
|
|
if (!GTK_CMCLIST(summaryview->ctree)->row_list) {
|
|
menu_set_insensitive_all
|
|
(GTK_MENU_SHELL(summaryview->popupmenu));
|
|
folderview_grab_focus(summaryview->folderview);
|
|
} else {
|
|
menu_set_sensitive_all(GTK_MENU_SHELL(summaryview->popupmenu), TRUE);
|
|
gtk_widget_grab_focus(summaryview->ctree);
|
|
}
|
|
summary_update_status(summaryview);
|
|
summary_status_show(summaryview);
|
|
|
|
gtk_cmctree_node_moveto(ctree, summaryview->selected, 0, 0.5, 0);
|
|
|
|
summary_unlock(summaryview);
|
|
|
|
main_window_cursor_normal(summaryview->mainwin);
|
|
|
|
if (move_val < 0)
|
|
summary_show(summaryview, summaryview->folder_item);
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean summary_expunge(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GtkCMCList *clist = GTK_CMCLIST(summaryview->ctree);
|
|
GtkCMCTreeNode *node, *next;
|
|
GtkCMCTreeNode *new_selected = NULL;
|
|
|
|
if (!summaryview->folder_item) return FALSE;
|
|
|
|
if (summary_is_locked(summaryview)) return FALSE;
|
|
|
|
summary_lock(summaryview);
|
|
|
|
summary_freeze(summaryview);
|
|
|
|
main_window_cursor_wait(summaryview->mainwin);
|
|
|
|
if (summaryview->threaded)
|
|
summary_unthread_for_exec(summaryview);
|
|
|
|
folder_item_update_freeze();
|
|
summary_execute_expunge(summaryview);
|
|
|
|
node = GTK_CMCTREE_NODE(clist->row_list);
|
|
for (; node != NULL; node = next) {
|
|
next = gtkut_ctree_node_next(ctree, node);
|
|
if (gtk_cmctree_node_get_row_data(ctree, node) != NULL) continue;
|
|
|
|
if (node == summaryview->displayed) {
|
|
messageview_clear(summaryview->messageview);
|
|
summary_cancel_mark_read_timeout(summaryview);
|
|
summaryview->displayed = NULL;
|
|
}
|
|
if (GTK_CMCTREE_ROW(node)->children != NULL) {
|
|
next = NULL;
|
|
if (GTK_CMCTREE_ROW(node)->sibling) {
|
|
next = GTK_CMCTREE_ROW(node)->sibling;
|
|
} else {
|
|
GtkCMCTreeNode *parent = NULL;
|
|
for (parent = GTK_CMCTREE_ROW(node)->parent; parent != NULL;
|
|
parent = GTK_CMCTREE_ROW(parent)->parent) {
|
|
if (GTK_CMCTREE_ROW(parent)->sibling) {
|
|
next = GTK_CMCTREE_ROW(parent)->sibling;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!new_selected &&
|
|
gtkut_ctree_node_is_selected(ctree, node)) {
|
|
summary_unselect_all(summaryview);
|
|
new_selected = summary_find_next_msg(summaryview, node,TRUE);
|
|
if (!new_selected)
|
|
new_selected = summary_find_prev_msg
|
|
(summaryview, node,TRUE);
|
|
}
|
|
|
|
gtk_sctree_remove_node((GtkSCTree *)ctree, node);
|
|
}
|
|
|
|
folder_item_update_thaw();
|
|
|
|
if (new_selected) {
|
|
summary_unlock(summaryview);
|
|
summary_select_node(summaryview, new_selected, OPEN_SELECTED_ON_DELETEMOVE);
|
|
summary_lock(summaryview);
|
|
}
|
|
|
|
if (summaryview->threaded) {
|
|
summary_thread_build(summaryview);
|
|
summary_thread_init(summaryview);
|
|
}
|
|
|
|
summary_thaw(summaryview);
|
|
|
|
summaryview->selected = clist->selection ?
|
|
GTK_CMCTREE_NODE(clist->selection->data) : NULL;
|
|
|
|
if (!GTK_CMCLIST(summaryview->ctree)->row_list) {
|
|
menu_set_insensitive_all
|
|
(GTK_MENU_SHELL(summaryview->popupmenu));
|
|
folderview_grab_focus(summaryview->folderview);
|
|
} else {
|
|
menu_set_sensitive_all(GTK_MENU_SHELL(summaryview->popupmenu), TRUE);
|
|
gtk_widget_grab_focus(summaryview->ctree);
|
|
}
|
|
|
|
summary_update_status(summaryview);
|
|
summary_status_show(summaryview);
|
|
|
|
gtk_cmctree_node_moveto(ctree, summaryview->selected, 0, 0.5, 0);
|
|
|
|
summary_unlock(summaryview);
|
|
|
|
main_window_cursor_normal(summaryview->mainwin);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gint summary_execute_move(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GSList *cur;
|
|
gint val = -1;
|
|
/* search moving messages and execute */
|
|
|
|
gtk_cmctree_pre_recursive(ctree, NULL, summary_execute_move_func,
|
|
summaryview);
|
|
|
|
if (summaryview->mlist) {
|
|
hooks_unregister_hook(MSGINFO_UPDATE_HOOKLIST,
|
|
summaryview->msginfo_update_callback_id);
|
|
val = procmsg_move_messages(summaryview->mlist);
|
|
summaryview->msginfo_update_callback_id =
|
|
hooks_register_hook(MSGINFO_UPDATE_HOOKLIST,
|
|
summary_update_msg, (gpointer) summaryview);
|
|
|
|
for (cur = summaryview->mlist; cur != NULL && cur->data != NULL; cur = cur->next) {
|
|
procmsg_msginfo_free((MsgInfo **)&(cur->data));
|
|
}
|
|
|
|
g_slist_free(summaryview->mlist);
|
|
summaryview->mlist = NULL;
|
|
return val;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void summary_execute_move_func(GtkCMCTree *ctree, GtkCMCTreeNode *node,
|
|
gpointer data)
|
|
{
|
|
SummaryView *summaryview = data;
|
|
MsgInfo *msginfo;
|
|
|
|
msginfo = GTKUT_CTREE_NODE_GET_ROW_DATA(node);
|
|
|
|
if (msginfo && MSG_IS_MOVE(msginfo->flags) && msginfo->to_folder) {
|
|
summaryview->mlist =
|
|
g_slist_prepend(summaryview->mlist, msginfo);
|
|
gtk_cmctree_node_set_row_data(ctree, node, NULL);
|
|
|
|
if (msginfo->msgid && *msginfo->msgid &&
|
|
node == g_hash_table_lookup(summaryview->msgid_table,
|
|
msginfo->msgid))
|
|
g_hash_table_remove(summaryview->msgid_table,
|
|
msginfo->msgid);
|
|
if (prefs_common.thread_by_subject &&
|
|
msginfo->subject && *msginfo->subject &&
|
|
node == subject_table_lookup(summaryview->subject_table,
|
|
msginfo->subject)) {
|
|
subject_table_remove(summaryview->subject_table,
|
|
msginfo->subject);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void summary_execute_copy(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
|
|
/* search copying messages and execute */
|
|
hooks_unregister_hook(MSGINFO_UPDATE_HOOKLIST,
|
|
summaryview->msginfo_update_callback_id);
|
|
gtk_cmctree_pre_recursive(ctree, NULL, summary_execute_copy_func,
|
|
summaryview);
|
|
|
|
if (summaryview->mlist) {
|
|
summaryview->mlist = g_slist_reverse(summaryview->mlist);
|
|
procmsg_copy_messages(summaryview->mlist);
|
|
|
|
g_slist_free(summaryview->mlist);
|
|
summaryview->mlist = NULL;
|
|
}
|
|
summaryview->msginfo_update_callback_id =
|
|
hooks_register_hook(MSGINFO_UPDATE_HOOKLIST,
|
|
summary_update_msg, (gpointer) summaryview);
|
|
}
|
|
|
|
static void summary_execute_copy_func(GtkCMCTree *ctree, GtkCMCTreeNode *node,
|
|
gpointer data)
|
|
{
|
|
SummaryView *summaryview = data;
|
|
MsgInfo *msginfo;
|
|
|
|
msginfo = GTKUT_CTREE_NODE_GET_ROW_DATA(node);
|
|
|
|
if (msginfo && MSG_IS_COPY(msginfo->flags) && msginfo->to_folder) {
|
|
summaryview->mlist =
|
|
g_slist_prepend(summaryview->mlist, msginfo);
|
|
|
|
summary_msginfo_unset_flags(msginfo, 0, MSG_COPY);
|
|
summary_set_row_marks(summaryview, node);
|
|
}
|
|
}
|
|
|
|
static void summary_execute_delete(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GSList *cur;
|
|
|
|
/* search deleting messages and execute */
|
|
gtk_cmctree_pre_recursive
|
|
(ctree, NULL, summary_execute_delete_func, summaryview);
|
|
|
|
if (!summaryview->mlist) return;
|
|
|
|
hooks_unregister_hook(MSGINFO_UPDATE_HOOKLIST,
|
|
summaryview->msginfo_update_callback_id);
|
|
|
|
folder_item_remove_msgs(summaryview->folder_item,
|
|
summaryview->mlist);
|
|
|
|
summaryview->msginfo_update_callback_id =
|
|
hooks_register_hook(MSGINFO_UPDATE_HOOKLIST,
|
|
summary_update_msg, (gpointer) summaryview);
|
|
|
|
for (cur = summaryview->mlist; cur != NULL && cur->data != NULL; cur = cur->next) {
|
|
procmsg_msginfo_free((MsgInfo **)&(cur->data));
|
|
}
|
|
|
|
g_slist_free(summaryview->mlist);
|
|
summaryview->mlist = NULL;
|
|
}
|
|
|
|
static void summary_execute_delete_func(GtkCMCTree *ctree, GtkCMCTreeNode *node,
|
|
gpointer data)
|
|
{
|
|
SummaryView *summaryview = data;
|
|
MsgInfo *msginfo;
|
|
|
|
msginfo = GTKUT_CTREE_NODE_GET_ROW_DATA(node);
|
|
|
|
if (msginfo && MSG_IS_DELETED(msginfo->flags)) {
|
|
summaryview->mlist =
|
|
g_slist_prepend(summaryview->mlist, msginfo);
|
|
gtk_cmctree_node_set_row_data(ctree, node, NULL);
|
|
|
|
if (msginfo->msgid && *msginfo->msgid &&
|
|
node == g_hash_table_lookup(summaryview->msgid_table,
|
|
msginfo->msgid)) {
|
|
g_hash_table_remove(summaryview->msgid_table,
|
|
msginfo->msgid);
|
|
}
|
|
if (prefs_common.thread_by_subject &&
|
|
msginfo->subject && *msginfo->subject &&
|
|
node == subject_table_lookup(summaryview->subject_table,
|
|
msginfo->subject)) {
|
|
subject_table_remove(summaryview->subject_table,
|
|
msginfo->subject);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void summary_execute_expunge_func(GtkCMCTree *ctree, GtkCMCTreeNode *node,
|
|
gpointer data)
|
|
{
|
|
SummaryView *summaryview = data;
|
|
MsgInfo *msginfo;
|
|
|
|
msginfo = GTKUT_CTREE_NODE_GET_ROW_DATA(node);
|
|
|
|
if (msginfo && MSG_IS_DELETED(msginfo->flags)) {
|
|
summaryview->mlist =
|
|
g_slist_prepend(summaryview->mlist, msginfo);
|
|
gtk_cmctree_node_set_row_data(ctree, node, NULL);
|
|
|
|
if (msginfo->msgid && *msginfo->msgid &&
|
|
node == g_hash_table_lookup(summaryview->msgid_table,
|
|
msginfo->msgid)) {
|
|
g_hash_table_remove(summaryview->msgid_table,
|
|
msginfo->msgid);
|
|
}
|
|
if (prefs_common.thread_by_subject &&
|
|
msginfo->subject && *msginfo->subject &&
|
|
node == subject_table_lookup(summaryview->subject_table,
|
|
msginfo->subject)) {
|
|
subject_table_remove(summaryview->subject_table,
|
|
msginfo->subject);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void summary_execute_expunge(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GSList *cur;
|
|
|
|
gtk_cmctree_pre_recursive
|
|
(ctree, NULL, summary_execute_expunge_func, summaryview);
|
|
|
|
hooks_unregister_hook(MSGINFO_UPDATE_HOOKLIST,
|
|
summaryview->msginfo_update_callback_id);
|
|
|
|
folder_item_expunge(summaryview->folder_item);
|
|
|
|
summaryview->msginfo_update_callback_id =
|
|
hooks_register_hook(MSGINFO_UPDATE_HOOKLIST,
|
|
summary_update_msg, (gpointer) summaryview);
|
|
for (cur = summaryview->mlist; cur != NULL && cur->data != NULL; cur = cur->next)
|
|
procmsg_msginfo_free((MsgInfo **)&(cur->data));
|
|
|
|
g_slist_free(summaryview->mlist);
|
|
summaryview->mlist = NULL;
|
|
}
|
|
|
|
/* thread functions */
|
|
|
|
static void summary_thread_build(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GtkCMCTreeNode *node;
|
|
GtkCMCTreeNode *next;
|
|
GtkCMCTreeNode *parent;
|
|
MsgInfo *msginfo;
|
|
GSList *reflist;
|
|
|
|
summary_lock(summaryview);
|
|
|
|
debug_print("Building threads...\n");
|
|
STATUSBAR_PUSH(summaryview->mainwin, _("Building threads..."));
|
|
main_window_cursor_wait(summaryview->mainwin);
|
|
|
|
g_signal_handlers_block_by_func(G_OBJECT(ctree),
|
|
G_CALLBACK(summary_tree_expanded), summaryview);
|
|
summary_freeze(summaryview);
|
|
|
|
node = GTK_CMCTREE_NODE(GTK_CMCLIST(ctree)->row_list);
|
|
while (node) {
|
|
next = GTK_CMCTREE_ROW(node)->sibling;
|
|
|
|
msginfo = GTKUT_CTREE_NODE_GET_ROW_DATA(node);
|
|
|
|
parent = NULL;
|
|
|
|
if (msginfo && msginfo->inreplyto) {
|
|
parent = g_hash_table_lookup(summaryview->msgid_table,
|
|
msginfo->inreplyto);
|
|
|
|
if (!parent && msginfo->references) {
|
|
for (reflist = msginfo->references;
|
|
reflist != NULL; reflist = reflist->next)
|
|
if ((parent = g_hash_table_lookup
|
|
(summaryview->msgid_table,
|
|
reflist->data)))
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (msginfo && prefs_common.thread_by_subject && parent == NULL) {
|
|
parent = subject_table_lookup
|
|
(summaryview->subject_table,
|
|
msginfo->subject);
|
|
}
|
|
|
|
if (parent && parent != node && parent != GTK_CMCTREE_ROW(node)->parent) {
|
|
gtk_cmctree_move(ctree, node, parent, NULL);
|
|
}
|
|
|
|
node = next;
|
|
}
|
|
|
|
gtkut_ctree_set_focus_row(ctree, summaryview->selected);
|
|
|
|
summary_thaw(summaryview);
|
|
g_signal_handlers_unblock_by_func(G_OBJECT(ctree),
|
|
G_CALLBACK(summary_tree_expanded), summaryview);
|
|
|
|
debug_print("Building threads done.\n");
|
|
STATUSBAR_POP(summaryview->mainwin);
|
|
main_window_cursor_normal(summaryview->mainwin);
|
|
|
|
summaryview->threaded = TRUE;
|
|
|
|
summary_unlock(summaryview);
|
|
}
|
|
|
|
static void summary_thread_init(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GtkCMCTreeNode *node = GTK_CMCTREE_NODE(GTK_CMCLIST(ctree)->row_list);
|
|
GtkCMCTreeNode *next;
|
|
START_TIMING("");
|
|
if (!summaryview->thread_collapsed) {
|
|
g_signal_handlers_block_by_func(G_OBJECT(ctree),
|
|
G_CALLBACK(summary_tree_expanded), summaryview);
|
|
while (node) {
|
|
next = GTK_CMCTREE_ROW(node)->sibling;
|
|
if (GTK_CMCTREE_ROW(node)->children)
|
|
gtk_cmctree_expand_recursive(ctree, node);
|
|
node = next;
|
|
}
|
|
g_signal_handlers_unblock_by_func(G_OBJECT(ctree),
|
|
G_CALLBACK(summary_tree_expanded), summaryview);
|
|
}
|
|
END_TIMING();
|
|
}
|
|
|
|
static void summary_unthread_for_exec(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTreeNode *node;
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
gboolean froze = FALSE;
|
|
|
|
debug_print("Unthreading for execution...\n");
|
|
|
|
START_LONG_OPERATION(summaryview, TRUE);
|
|
for (node = GTK_CMCTREE_NODE(GTK_CMCLIST(ctree)->row_list);
|
|
node != NULL; node = GTK_CMCTREE_NODE_NEXT(node)) {
|
|
summary_unthread_for_exec_func(ctree, node, summaryview);
|
|
}
|
|
|
|
END_LONG_OPERATION(summaryview);
|
|
|
|
debug_print("Unthreading for execution done.\n");
|
|
}
|
|
|
|
static void summary_unthread_for_exec_func(GtkCMCTree *ctree, GtkCMCTreeNode *node,
|
|
gpointer data)
|
|
{
|
|
MsgInfo *msginfo;
|
|
GtkCMCTreeNode *top_parent;
|
|
GtkCMCTreeNode *child;
|
|
GtkCMCTreeNode *sibling;
|
|
SummaryView * summaryview = (SummaryView *)data;
|
|
msginfo = GTKUT_CTREE_NODE_GET_ROW_DATA(node);
|
|
|
|
if (!msginfo ||
|
|
(!MSG_IS_MOVE(msginfo->flags) &&
|
|
!MSG_IS_DELETED(msginfo->flags)))
|
|
return;
|
|
child = GTK_CMCTREE_ROW(node)->children;
|
|
if (!child) return;
|
|
|
|
if (node == summaryview->selected)
|
|
summaryview->selected = NULL;
|
|
if (node == summaryview->displayed)
|
|
summaryview->displayed = NULL;
|
|
|
|
summary_cancel_mark_read_timeout(summaryview);
|
|
|
|
for (top_parent = node;
|
|
GTK_CMCTREE_ROW(top_parent)->parent != NULL;
|
|
top_parent = GTK_CMCTREE_ROW(top_parent)->parent)
|
|
;
|
|
sibling = GTK_CMCTREE_ROW(top_parent)->sibling;
|
|
|
|
GTK_SCTREE(ctree)->sorting = TRUE;
|
|
while (child != NULL) {
|
|
GtkCMCTreeNode *next_child;
|
|
MsgInfo *cinfo = GTKUT_CTREE_NODE_GET_ROW_DATA(child);
|
|
|
|
next_child = GTK_CMCTREE_ROW(child)->sibling;
|
|
|
|
if (!MSG_IS_MOVE(cinfo->flags) && !MSG_IS_DELETED(cinfo->flags)) {
|
|
gtk_cmctree_move(ctree, child,
|
|
NULL,
|
|
sibling);
|
|
} else {
|
|
if (child == summaryview->displayed) {
|
|
messageview_clear(summaryview->messageview);
|
|
summaryview->displayed = NULL;
|
|
}
|
|
if (child == summaryview->selected) {
|
|
messageview_clear(summaryview->messageview);
|
|
summaryview->selected = NULL;
|
|
}
|
|
}
|
|
child = next_child;
|
|
}
|
|
GTK_SCTREE(ctree)->sorting = FALSE;
|
|
}
|
|
|
|
void summary_expand_threads(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GtkCMCTreeNode *node = GTK_CMCTREE_NODE(GTK_CMCLIST(ctree)->row_list);
|
|
GtkCMCTreeNode *focus_node = GTK_CMCTREE_NODE (g_list_nth (GTK_CMCLIST(ctree)->row_list, GTK_CMCLIST(ctree)->focus_row));
|
|
|
|
g_signal_handlers_block_by_func(G_OBJECT(ctree),
|
|
G_CALLBACK(summary_tree_expanded), summaryview);
|
|
summary_freeze(summaryview);
|
|
GTK_SCTREE(ctree)->sorting = TRUE;
|
|
|
|
while (node) {
|
|
if (GTK_CMCTREE_ROW(node)->children) {
|
|
gtk_cmctree_expand(ctree, node);
|
|
summary_set_row_marks(summaryview, node);
|
|
}
|
|
node = GTK_CMCTREE_NODE_NEXT(node);
|
|
}
|
|
|
|
GTK_SCTREE(ctree)->sorting = FALSE;
|
|
if (focus_node) {
|
|
GTK_CMCLIST(ctree)->focus_row = g_list_position (GTK_CMCLIST(ctree)->row_list,(GList *)focus_node);
|
|
}
|
|
summary_thaw(summaryview);
|
|
|
|
g_signal_handlers_unblock_by_func(G_OBJECT(ctree),
|
|
G_CALLBACK(summary_tree_expanded), summaryview);
|
|
|
|
summaryview->thread_collapsed = FALSE;
|
|
|
|
gtk_cmctree_node_moveto(ctree, summaryview->selected, 0, 0.5, 0);
|
|
}
|
|
|
|
void summary_collapse_threads(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GtkCMCTreeNode *node = NULL;
|
|
GtkCMCTreeNode *focus_node = GTK_CMCTREE_NODE (g_list_nth (GTK_CMCLIST(ctree)->row_list, GTK_CMCLIST(ctree)->focus_row));
|
|
|
|
g_signal_handlers_block_by_func(G_OBJECT(ctree),
|
|
G_CALLBACK(summary_tree_collapsed), summaryview);
|
|
summary_freeze(summaryview);
|
|
GTK_SCTREE(ctree)->sorting = TRUE;
|
|
|
|
node = focus_node;
|
|
while (node && GTK_CMCTREE_ROW(node)->parent) {
|
|
focus_node = node = GTK_CMCTREE_ROW(node)->parent;
|
|
}
|
|
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) {
|
|
gtk_cmctree_collapse(ctree, node);
|
|
summary_set_row_marks(summaryview, node);
|
|
}
|
|
node = GTK_CMCTREE_ROW(node)->sibling;
|
|
}
|
|
|
|
GTK_SCTREE(ctree)->sorting = FALSE;
|
|
if (focus_node) {
|
|
GTK_CMCLIST(ctree)->focus_row = g_list_position (GTK_CMCLIST(ctree)->row_list,(GList *)focus_node);
|
|
}
|
|
GTK_SCTREE(ctree)->anchor_row =
|
|
gtk_cmctree_node_nth(ctree, GTK_CMCLIST(ctree)->focus_row);
|
|
summary_thaw(summaryview);
|
|
g_signal_handlers_unblock_by_func(G_OBJECT(ctree),
|
|
G_CALLBACK(summary_tree_collapsed), summaryview);
|
|
|
|
summaryview->thread_collapsed = TRUE;
|
|
|
|
gtk_cmctree_node_moveto(ctree, summaryview->selected, 0, 0.5, 0);
|
|
}
|
|
|
|
static void account_rules_radio_button_toggled_cb(GtkToggleButton *btn, gpointer data)
|
|
{
|
|
prefs_common.apply_per_account_filtering_rules = GPOINTER_TO_INT(data);
|
|
}
|
|
|
|
static gboolean summary_filter_get_mode(void)
|
|
/* ask what to do w/ them: skip them, apply them regardless to the account,
|
|
use the current account */
|
|
{
|
|
/* TODO: eventually also propose to use the current folder's default account,
|
|
if it is set */
|
|
/* TODO: eventually allow to select the account to use from a optmenu */
|
|
|
|
GtkWidget *vbox;
|
|
GtkWidget *account_rules_skip;
|
|
GtkWidget *account_rules_force;
|
|
GtkWidget *account_rules_user_current;
|
|
AlertValue val;
|
|
|
|
vbox = gtk_vbox_new (FALSE, 0);
|
|
|
|
account_rules_skip = gtk_radio_button_new_with_label
|
|
(NULL, _("Skip these rules"));
|
|
account_rules_force = gtk_radio_button_new_with_label_from_widget
|
|
(GTK_RADIO_BUTTON(account_rules_skip),
|
|
_("Apply these rules regardless of the account they belong to"));
|
|
account_rules_user_current = gtk_radio_button_new_with_label_from_widget
|
|
(GTK_RADIO_BUTTON(account_rules_skip),
|
|
_("Apply these rules if they apply to the current account"));
|
|
gtk_box_pack_start (GTK_BOX (vbox), account_rules_skip, FALSE, FALSE, 0);
|
|
gtk_box_pack_start (GTK_BOX (vbox), account_rules_force, FALSE, FALSE, 0);
|
|
gtk_box_pack_start (GTK_BOX (vbox), account_rules_user_current, FALSE, FALSE, 0);
|
|
g_signal_connect(G_OBJECT(account_rules_skip), "toggled",
|
|
G_CALLBACK(account_rules_radio_button_toggled_cb),
|
|
GINT_TO_POINTER(FILTERING_ACCOUNT_RULES_SKIP));
|
|
g_signal_connect(G_OBJECT(account_rules_force), "toggled",
|
|
G_CALLBACK(account_rules_radio_button_toggled_cb),
|
|
GINT_TO_POINTER(FILTERING_ACCOUNT_RULES_FORCE));
|
|
g_signal_connect(G_OBJECT(account_rules_user_current), "toggled",
|
|
G_CALLBACK(account_rules_radio_button_toggled_cb),
|
|
GINT_TO_POINTER(FILTERING_ACCOUNT_RULES_USE_CURRENT));
|
|
switch (prefs_common.apply_per_account_filtering_rules) {
|
|
case FILTERING_ACCOUNT_RULES_SKIP:
|
|
gtk_toggle_button_set_active(
|
|
GTK_TOGGLE_BUTTON(account_rules_skip), TRUE);
|
|
break;
|
|
case FILTERING_ACCOUNT_RULES_FORCE:
|
|
gtk_toggle_button_set_active(
|
|
GTK_TOGGLE_BUTTON(account_rules_force), TRUE);
|
|
break;
|
|
case FILTERING_ACCOUNT_RULES_USE_CURRENT:
|
|
gtk_toggle_button_set_active(
|
|
GTK_TOGGLE_BUTTON(account_rules_user_current), TRUE);
|
|
break;
|
|
}
|
|
|
|
val = alertpanel_with_widget(
|
|
_("Filtering"),
|
|
_("There are some filtering rules that belong to an account.\n"
|
|
"Please choose what to do with these rules:"),
|
|
GTK_STOCK_CANCEL, _("_Filter"), NULL, ALERTFOCUS_SECOND,
|
|
TRUE, vbox);
|
|
|
|
if ((val & ~G_ALERTDISABLE) != G_ALERTALTERNATE) {
|
|
return FALSE;
|
|
} else if (val & G_ALERTDISABLE)
|
|
prefs_common.ask_apply_per_account_filtering_rules = FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void summary_filter(SummaryView *summaryview, gboolean selected_only)
|
|
{
|
|
GSList *mlist = NULL, *cur_list;
|
|
PrefsAccount *ac_prefs = NULL;
|
|
summary_lock(summaryview);
|
|
|
|
/* are there any per-account filtering rules? */
|
|
if (prefs_common.ask_apply_per_account_filtering_rules == TRUE &&
|
|
filtering_peek_per_account_rules(filtering_rules)) {
|
|
|
|
if (summary_filter_get_mode() == FALSE) {
|
|
summary_unlock(summaryview);
|
|
return;
|
|
}
|
|
}
|
|
|
|
folder_item_update_freeze();
|
|
|
|
debug_print("filtering...\n");
|
|
STATUSBAR_PUSH(summaryview->mainwin, _("Filtering..."));
|
|
main_window_cursor_wait(summaryview->mainwin);
|
|
|
|
summary_freeze(summaryview);
|
|
|
|
if (selected_only) {
|
|
GList *cur;
|
|
|
|
for (cur = GTK_CMCLIST(summaryview->ctree)->selection;
|
|
cur != NULL && cur->data != NULL; cur = cur->next) {
|
|
mlist = g_slist_prepend(mlist,
|
|
procmsg_msginfo_new_ref(
|
|
GTKUT_CTREE_NODE_GET_ROW_DATA(cur->data)));
|
|
}
|
|
mlist = g_slist_reverse(mlist);
|
|
} else {
|
|
mlist = folder_item_get_msg_list(summaryview->folder_item);
|
|
}
|
|
|
|
ac_prefs = ((summaryview->folder_item->folder != NULL) &&
|
|
(summaryview->folder_item->folder->account != NULL))
|
|
? summaryview->folder_item->folder->account : NULL;
|
|
|
|
folder_item_set_batch(summaryview->folder_item, TRUE);
|
|
for (cur_list = mlist; cur_list; cur_list = cur_list->next) {
|
|
summary_filter_func((MsgInfo *)cur_list->data, ac_prefs);
|
|
}
|
|
folder_item_set_batch(summaryview->folder_item, FALSE);
|
|
|
|
filtering_move_and_copy_msgs(mlist);
|
|
|
|
for (cur_list = mlist; cur_list; cur_list = cur_list->next) {
|
|
procmsg_msginfo_free((MsgInfo **)&(cur_list->data));
|
|
}
|
|
g_slist_free(mlist);
|
|
|
|
summary_thaw(summaryview);
|
|
|
|
folder_item_update_thaw();
|
|
debug_print("filtering done.\n");
|
|
STATUSBAR_POP(summaryview->mainwin);
|
|
main_window_cursor_normal(summaryview->mainwin);
|
|
|
|
summary_unlock(summaryview);
|
|
|
|
/*
|
|
* CLAWS: summary_show() only valid after having a lock. ideally
|
|
* we want the lock to be context aware...
|
|
*/
|
|
summary_show(summaryview, summaryview->folder_item);
|
|
}
|
|
|
|
static void summary_filter_func(MsgInfo *msginfo, PrefsAccount *ac_prefs)
|
|
{
|
|
MailFilteringData mail_filtering_data;
|
|
|
|
mail_filtering_data.msginfo = msginfo;
|
|
mail_filtering_data.msglist = NULL;
|
|
mail_filtering_data.filtered = NULL;
|
|
mail_filtering_data.unfiltered = NULL;
|
|
if (hooks_invoke(MAIL_MANUAL_FILTERING_HOOKLIST, &mail_filtering_data))
|
|
return;
|
|
|
|
filter_message_by_msginfo(filtering_rules, msginfo, ac_prefs,
|
|
FILTERING_MANUALLY, NULL);
|
|
}
|
|
|
|
void summary_msginfo_filter_open(FolderItem * item, MsgInfo *msginfo,
|
|
PrefsFilterType type, gint processing_rule)
|
|
{
|
|
gchar *header = NULL;
|
|
gchar *key = NULL;
|
|
|
|
procmsg_get_filter_keyword(msginfo, &header, &key, type);
|
|
|
|
if (processing_rule) {
|
|
if (item == NULL)
|
|
prefs_filtering_open(&pre_global_processing,
|
|
_("Processing rules to apply before folder rules"),
|
|
MANUAL_ANCHOR_PROCESSING,
|
|
header, key, FALSE);
|
|
else
|
|
prefs_filtering_open(&item->prefs->processing,
|
|
_("Processing configuration"),
|
|
MANUAL_ANCHOR_PROCESSING,
|
|
header, key, FALSE);
|
|
}
|
|
else {
|
|
prefs_filtering_open(&filtering_rules,
|
|
_("Filtering configuration"),
|
|
MANUAL_ANCHOR_FILTERING,
|
|
header, key, TRUE);
|
|
}
|
|
|
|
g_free(header);
|
|
g_free(key);
|
|
}
|
|
|
|
void summary_filter_open(SummaryView *summaryview, PrefsFilterType type,
|
|
gint processing_rule)
|
|
{
|
|
MsgInfo *msginfo;
|
|
FolderItem * item;
|
|
|
|
if (!summaryview->selected) return;
|
|
|
|
msginfo = gtk_cmctree_node_get_row_data(GTK_CMCTREE(summaryview->ctree),
|
|
summaryview->selected);
|
|
if (!msginfo) return;
|
|
|
|
item = summaryview->folder_item;
|
|
summary_msginfo_filter_open(item, msginfo, type, processing_rule);
|
|
}
|
|
|
|
/* color label */
|
|
|
|
#define N_COLOR_LABELS colorlabel_get_color_count()
|
|
|
|
static void summary_colorlabel_menu_item_activate_cb(GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
guint color = GPOINTER_TO_UINT(data);
|
|
SummaryView *summaryview;
|
|
|
|
summaryview = g_object_get_data(G_OBJECT(widget), "summaryview");
|
|
cm_return_if_fail(summaryview != NULL);
|
|
|
|
/* "dont_toggle" state set? */
|
|
if (g_object_get_data(G_OBJECT(summaryview->colorlabel_menu),
|
|
"dont_toggle"))
|
|
return;
|
|
|
|
summary_set_colorlabel(summaryview, color, NULL);
|
|
}
|
|
|
|
/* summary_set_colorlabel_color() - labelcolor parameter is the color *flag*
|
|
* for the message; not the color index */
|
|
void summary_set_colorlabel_color(GtkCMCTree *ctree, GtkCMCTreeNode *node,
|
|
guint labelcolor)
|
|
{
|
|
GdkColor color;
|
|
GdkRGBA rgba;
|
|
GtkStyle *style, *prev_style, *ctree_style;
|
|
MsgInfo *msginfo;
|
|
gint color_index;
|
|
|
|
msginfo = gtk_cmctree_node_get_row_data(ctree, node);
|
|
cm_return_if_fail(msginfo);
|
|
|
|
color_index = labelcolor == 0 ? -1 : (gint)labelcolor - 1;
|
|
ctree_style = gtk_widget_get_style(GTK_WIDGET(ctree));
|
|
prev_style = gtk_cmctree_node_get_row_style(ctree, node);
|
|
|
|
if (color_index < 0 || color_index >= N_COLOR_LABELS) {
|
|
if (!prev_style) return;
|
|
style = gtk_style_copy(prev_style);
|
|
color = ctree_style->text[GTK_STATE_NORMAL];
|
|
style->text[GTK_STATE_NORMAL] = color;
|
|
color = ctree_style->text[GTK_STATE_SELECTED];
|
|
style->text[GTK_STATE_SELECTED] = color;
|
|
} else {
|
|
if (prev_style)
|
|
style = gtk_style_copy(prev_style);
|
|
else
|
|
style = gtk_style_copy(ctree_style);
|
|
rgba = colorlabel_get_color(color_index);
|
|
GTKUT_GDKRGBA_TO_GDKCOLOR(rgba, color);
|
|
style->text[GTK_STATE_NORMAL] = color;
|
|
/* get the average of label color and selected fg color
|
|
for visibility */
|
|
style->text[GTK_STATE_SELECTED].red = (color.red + 3*ctree_style->text[GTK_STATE_SELECTED].red ) / 4;
|
|
style->text[GTK_STATE_SELECTED].green = (color.green + 3*ctree_style->text[GTK_STATE_SELECTED].green) / 4;
|
|
style->text[GTK_STATE_SELECTED].blue = (color.blue + 3*ctree_style->text[GTK_STATE_SELECTED].blue ) / 4;
|
|
}
|
|
|
|
gtk_cmctree_node_set_row_style(ctree, node, style);
|
|
g_object_unref(style);
|
|
}
|
|
|
|
static void summary_set_row_colorlabel(SummaryView *summaryview, GtkCMCTreeNode *row, guint labelcolor)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
MsgInfo *msginfo;
|
|
|
|
msginfo = gtk_cmctree_node_get_row_data(ctree, row);
|
|
cm_return_if_fail(msginfo);
|
|
|
|
summary_msginfo_change_flags(msginfo, MSG_COLORLABEL_TO_FLAGS(labelcolor), 0,
|
|
MSG_CLABEL_FLAG_MASK, 0);
|
|
summary_set_row_marks(summaryview, row);
|
|
}
|
|
|
|
void summary_set_colorlabel(SummaryView *summaryview, guint labelcolor,
|
|
GtkWidget *widget)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GList *cur;
|
|
gboolean froze = FALSE;
|
|
|
|
if (prefs_common.ask_override_colorlabel) {
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
gboolean ask = FALSE;
|
|
AlertValue val;
|
|
guint color;
|
|
gboolean already_this_color_everywhere = TRUE;
|
|
|
|
/* if clearing color labels (applying 'none', 0):
|
|
- ask if at least one message has a non-0 color label set
|
|
if applying a non-0 color label:
|
|
- ask if at least one of the selected messages has a non-0 color label different
|
|
from the one we want to apply.
|
|
- don't ask if all messages have the same color label as the one we're applying
|
|
*/
|
|
for (cur = GTK_CMCLIST(ctree)->selection;
|
|
!ask && cur != NULL && cur->data != NULL;
|
|
cur = cur->next) {
|
|
MsgInfo *msginfo = gtk_cmctree_node_get_row_data(ctree, GTK_CMCTREE_NODE(cur->data));
|
|
if (msginfo) {
|
|
color = MSG_GET_COLORLABEL_VALUE(msginfo->flags);
|
|
if (labelcolor == 0) {
|
|
/* clearing color labels */
|
|
ask = (color != 0);
|
|
} else {
|
|
already_this_color_everywhere &= (color == labelcolor);
|
|
ask = ((color != 0) && (color != labelcolor)) && !already_this_color_everywhere;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ask) {
|
|
gchar *msg;
|
|
|
|
if (labelcolor == 0)
|
|
msg = _("Do you really want to reset the color label of all selected messages?");
|
|
else
|
|
msg = _("Do you really want to apply this color label to all selected messages?");
|
|
val = alertpanel_full(labelcolor == 0? _("Reset color label"): _("Set color label"), msg,
|
|
GTK_STOCK_NO, GTK_STOCK_YES, NULL, ALERTFOCUS_FIRST,
|
|
TRUE, NULL, ALERT_QUESTION);
|
|
|
|
if ((val & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
|
|
return;
|
|
else if (val & G_ALERTDISABLE)
|
|
prefs_common.ask_override_colorlabel = FALSE;
|
|
}
|
|
}
|
|
|
|
START_LONG_OPERATION(summaryview, FALSE);
|
|
for (cur = GTK_CMCLIST(ctree)->selection; cur != NULL && cur->data != NULL; cur = cur->next)
|
|
summary_set_row_colorlabel(summaryview,
|
|
GTK_CMCTREE_NODE(cur->data), labelcolor);
|
|
END_LONG_OPERATION(summaryview);
|
|
}
|
|
|
|
static gboolean summary_set_row_tag(SummaryView *summaryview, GtkCMCTreeNode *row, gboolean refresh, gboolean set, gint id)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
MsgInfo *msginfo;
|
|
gchar *tags_str = NULL;
|
|
msginfo = gtk_cmctree_node_get_row_data(ctree, row);
|
|
cm_return_val_if_fail(msginfo, FALSE);
|
|
|
|
procmsg_msginfo_update_tags(msginfo, set, id);
|
|
|
|
if (summaryview->col_state[summaryview->col_pos[S_COL_TAGS]].visible) {
|
|
tags_str = procmsg_msginfo_get_tags_str(msginfo);
|
|
gtk_cmctree_node_set_text(ctree, row,
|
|
summaryview->col_pos[S_COL_TAGS],
|
|
tags_str?tags_str:"-");
|
|
g_free(tags_str);
|
|
}
|
|
|
|
summary_set_row_marks(summaryview, row);
|
|
if (row == summaryview->displayed) {
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void summary_set_tag(SummaryView *summaryview, gint tag_id,
|
|
GtkWidget *widget)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GList *cur;
|
|
gboolean set = tag_id > 0;
|
|
gint real_id = set? tag_id:-tag_id;
|
|
gboolean froze = FALSE;
|
|
gboolean redisplay = FALSE;
|
|
|
|
if (summary_is_locked(summaryview))
|
|
return;
|
|
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) {
|
|
redisplay |= summary_set_row_tag(summaryview,
|
|
GTK_CMCTREE_NODE(cur->data), FALSE, set, real_id);
|
|
}
|
|
folder_item_set_batch(summaryview->folder_item, FALSE);
|
|
END_LONG_OPERATION(summaryview);
|
|
if (redisplay)
|
|
summary_redisplay_msg(summaryview);
|
|
}
|
|
|
|
static void summary_tags_menu_item_activate_cb(GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
gint id = GPOINTER_TO_INT(data);
|
|
gboolean set = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget));
|
|
SummaryView *summaryview;
|
|
|
|
summaryview = g_object_get_data(G_OBJECT(widget), "summaryview");
|
|
cm_return_if_fail(summaryview != NULL);
|
|
|
|
/* "dont_toggle" state set? */
|
|
if (g_object_get_data(G_OBJECT(summaryview->tags_menu),
|
|
"dont_toggle"))
|
|
return;
|
|
|
|
if (!set)
|
|
id = -id;
|
|
summary_set_tag(summaryview, id, NULL);
|
|
}
|
|
|
|
static void summary_colorlabel_menu_item_activate_item_cb(GtkMenuItem *menu_item,
|
|
gpointer data)
|
|
{
|
|
SummaryView *summaryview;
|
|
GtkMenuShell *menu;
|
|
GtkCheckMenuItem **items;
|
|
gint n;
|
|
GList *children, *cur, *sel;
|
|
|
|
summaryview = (SummaryView *)data;
|
|
cm_return_if_fail(summaryview != NULL);
|
|
|
|
sel = GTK_CMCLIST(summaryview->ctree)->selection;
|
|
if (!sel) return;
|
|
|
|
menu = GTK_MENU_SHELL(summaryview->colorlabel_menu);
|
|
|
|
cm_return_if_fail(menu != NULL);
|
|
|
|
Xalloca(items, (N_COLOR_LABELS + 1) * sizeof(GtkWidget *), return);
|
|
|
|
/* NOTE: don't return prematurely because we set the "dont_toggle"
|
|
* state for check menu items */
|
|
g_object_set_data(G_OBJECT(menu), "dont_toggle",
|
|
GINT_TO_POINTER(1));
|
|
|
|
/* clear items. get item pointers. */
|
|
children = gtk_container_get_children(GTK_CONTAINER(menu));
|
|
for (n = 0, cur = children; cur != NULL && cur->data != NULL; cur = cur->next) {
|
|
if (GTK_IS_CHECK_MENU_ITEM(cur->data)) {
|
|
gtk_check_menu_item_set_active
|
|
(GTK_CHECK_MENU_ITEM(cur->data), FALSE);
|
|
items[n] = GTK_CHECK_MENU_ITEM(cur->data);
|
|
n++;
|
|
}
|
|
}
|
|
|
|
g_list_free(children);
|
|
|
|
if (n == (N_COLOR_LABELS + 1)) {
|
|
/* iterate all messages and set the state of the appropriate
|
|
* items */
|
|
for (; sel != NULL; sel = sel->next) {
|
|
MsgInfo *msginfo;
|
|
gint clabel;
|
|
|
|
msginfo = gtk_cmctree_node_get_row_data
|
|
(GTK_CMCTREE(summaryview->ctree),
|
|
GTK_CMCTREE_NODE(sel->data));
|
|
if (msginfo) {
|
|
clabel = MSG_GET_COLORLABEL_VALUE(msginfo->flags);
|
|
if (!gtk_check_menu_item_get_active(items[clabel]))
|
|
gtk_check_menu_item_set_active
|
|
(items[clabel], TRUE);
|
|
}
|
|
}
|
|
} else
|
|
g_warning("invalid number of color elements (%d)", n);
|
|
|
|
/* reset "dont_toggle" state */
|
|
g_object_set_data(G_OBJECT(menu), "dont_toggle",
|
|
GINT_TO_POINTER(0));
|
|
}
|
|
|
|
static void summary_colorlabel_menu_create(SummaryView *summaryview, gboolean refresh)
|
|
{
|
|
GtkWidget *label_menuitem;
|
|
GtkWidget *menu;
|
|
GtkWidget *item;
|
|
gint i;
|
|
gchar *accel_path = NULL;
|
|
|
|
label_menuitem = gtk_ui_manager_get_widget(summaryview->mainwin->ui_manager, "/Menus/SummaryViewPopup/ColorLabel");
|
|
g_signal_connect(G_OBJECT(label_menuitem), "activate",
|
|
G_CALLBACK(summary_colorlabel_menu_item_activate_item_cb),
|
|
summaryview);
|
|
gtk_widget_show(label_menuitem);
|
|
|
|
menu = gtk_menu_new();
|
|
|
|
gtk_menu_set_accel_group (GTK_MENU (menu),
|
|
gtk_ui_manager_get_accel_group(mainwindow_get_mainwindow()->ui_manager));
|
|
|
|
/* create sub items. for the menu item activation callback we pass the
|
|
* index of label_colors[] as data parameter. for the None color we
|
|
* pass an invalid (high) value. also we attach a data pointer so we
|
|
* can always get back the SummaryView pointer. */
|
|
|
|
item = gtk_check_menu_item_new_with_label(_("None"));
|
|
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
|
|
g_signal_connect(G_OBJECT(item), "activate",
|
|
G_CALLBACK(summary_colorlabel_menu_item_activate_cb),
|
|
GUINT_TO_POINTER(0));
|
|
g_object_set_data(G_OBJECT(item), "summaryview", summaryview);
|
|
gtk_widget_show(item);
|
|
|
|
accel_path = g_strdup_printf("<ClawsColorLabels>/None");
|
|
gtk_menu_item_set_accel_path(GTK_MENU_ITEM(item), accel_path);
|
|
g_free(accel_path);
|
|
gtk_accel_map_add_entry("<ClawsColorLabels>/None", GDK_KEY_0, GDK_CONTROL_MASK);
|
|
|
|
item = gtk_menu_item_new();
|
|
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
|
|
gtk_widget_show(item);
|
|
|
|
/* create pixmap/label menu items */
|
|
for (i = 0; i < N_COLOR_LABELS; i++) {
|
|
item = colorlabel_create_check_color_menu_item(
|
|
i, refresh, SUMMARY_COLORMENU);
|
|
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
|
|
g_signal_connect(G_OBJECT(item), "activate",
|
|
G_CALLBACK(summary_colorlabel_menu_item_activate_cb),
|
|
GUINT_TO_POINTER(i + 1));
|
|
g_object_set_data(G_OBJECT(item), "summaryview",
|
|
summaryview);
|
|
gtk_widget_show(item);
|
|
accel_path = g_strdup_printf("<ClawsColorLabels>/%d", i+1);
|
|
gtk_menu_item_set_accel_path(GTK_MENU_ITEM(item), accel_path);
|
|
if (i < 9)
|
|
gtk_accel_map_add_entry(accel_path, GDK_KEY_1+i, GDK_CONTROL_MASK);
|
|
g_free(accel_path);
|
|
g_signal_connect (gtk_ui_manager_get_accel_group(mainwindow_get_mainwindow()->ui_manager),
|
|
"accel-changed", G_CALLBACK (mainwin_accel_changed_cb), item);
|
|
}
|
|
|
|
gtk_widget_show(menu);
|
|
gtk_menu_item_set_submenu(GTK_MENU_ITEM(label_menuitem), menu);
|
|
summaryview->colorlabel_menu = menu;
|
|
}
|
|
|
|
static void summary_tags_menu_item_activate_item_cb(GtkMenuItem *menu_item,
|
|
gpointer data)
|
|
{
|
|
GtkMenuShell *menu;
|
|
GList *children, *cur;
|
|
GList *sel;
|
|
GHashTable *menu_table = g_hash_table_new_full(
|
|
g_direct_hash,
|
|
g_direct_equal,
|
|
NULL, NULL);
|
|
GHashTable *menu_allsel_table = g_hash_table_new_full(
|
|
g_direct_hash,
|
|
g_direct_equal,
|
|
NULL, NULL);
|
|
gint sel_len;
|
|
SummaryView *summaryview = (SummaryView *)data;
|
|
cm_return_if_fail(summaryview != NULL);
|
|
|
|
sel = GTK_CMCLIST(summaryview->ctree)->selection;
|
|
if (!sel) return;
|
|
|
|
menu = GTK_MENU_SHELL(summaryview->tags_menu);
|
|
cm_return_if_fail(menu != NULL);
|
|
|
|
/* NOTE: don't return prematurely because we set the "dont_toggle"
|
|
* state for check menu items */
|
|
g_object_set_data(G_OBJECT(menu), "dont_toggle",
|
|
GINT_TO_POINTER(1));
|
|
|
|
/* clear items. get item pointers. */
|
|
children = gtk_container_get_children(GTK_CONTAINER(menu));
|
|
for (cur = children; cur != NULL && cur->data != NULL; cur = cur->next) {
|
|
if (GTK_IS_CHECK_MENU_ITEM(cur->data)) {
|
|
gint id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cur->data),
|
|
"tag_id"));
|
|
gtk_check_menu_item_set_active
|
|
(GTK_CHECK_MENU_ITEM(cur->data), FALSE);
|
|
|
|
g_hash_table_insert(menu_table, GINT_TO_POINTER(id), GTK_CHECK_MENU_ITEM(cur->data));
|
|
g_hash_table_insert(menu_allsel_table, GINT_TO_POINTER(id), GINT_TO_POINTER(0));
|
|
}
|
|
}
|
|
|
|
g_list_free(children);
|
|
|
|
/* iterate all messages and set the state of the appropriate
|
|
* items */
|
|
sel_len = 0;
|
|
for (; sel != NULL; sel = sel->next) {
|
|
MsgInfo *msginfo;
|
|
GSList *tags = NULL;
|
|
GtkCheckMenuItem *item;
|
|
msginfo = gtk_cmctree_node_get_row_data
|
|
(GTK_CMCTREE(summaryview->ctree),
|
|
GTK_CMCTREE_NODE(sel->data));
|
|
sel_len++;
|
|
if (msginfo) {
|
|
tags = msginfo->tags;
|
|
if (!tags)
|
|
continue;
|
|
|
|
for (; tags; tags = tags->next) {
|
|
gint num_checked = GPOINTER_TO_INT(g_hash_table_lookup(menu_allsel_table, tags->data));
|
|
item = g_hash_table_lookup(menu_table, GINT_TO_POINTER(tags->data));
|
|
if (item && !gtk_check_menu_item_get_active(item)) {
|
|
gtk_check_menu_item_set_active
|
|
(item, TRUE);
|
|
}
|
|
num_checked++;
|
|
g_hash_table_replace(menu_allsel_table, tags->data, GINT_TO_POINTER(num_checked));
|
|
}
|
|
}
|
|
}
|
|
|
|
children = gtk_container_get_children(GTK_CONTAINER(menu));
|
|
for (cur = children; cur != NULL && cur->data != NULL; cur = cur->next) {
|
|
if (GTK_IS_CHECK_MENU_ITEM(cur->data)) {
|
|
gint id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cur->data),
|
|
"tag_id"));
|
|
gint num_checked = GPOINTER_TO_INT(g_hash_table_lookup(menu_allsel_table, GINT_TO_POINTER(id)));
|
|
if (num_checked < sel_len && num_checked > 0)
|
|
gtk_check_menu_item_set_inconsistent(GTK_CHECK_MENU_ITEM(cur->data), TRUE);
|
|
else
|
|
gtk_check_menu_item_set_inconsistent(GTK_CHECK_MENU_ITEM(cur->data), FALSE);
|
|
}
|
|
}
|
|
g_list_free(children);
|
|
g_hash_table_destroy(menu_table);
|
|
g_hash_table_destroy(menu_allsel_table);
|
|
/* reset "dont_toggle" state */
|
|
g_object_set_data(G_OBJECT(menu), "dont_toggle",
|
|
GINT_TO_POINTER(0));
|
|
}
|
|
|
|
void summaryview_destroy(SummaryView *summaryview)
|
|
{
|
|
if(summaryview->simplify_subject_preg) {
|
|
regfree(summaryview->simplify_subject_preg);
|
|
g_free(summaryview->simplify_subject_preg);
|
|
summaryview->simplify_subject_preg = NULL;
|
|
}
|
|
}
|
|
static void summary_tags_menu_item_apply_tags_activate_cb(GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
SummaryView *summaryview;
|
|
|
|
summaryview = g_object_get_data(G_OBJECT(widget), "summaryview");
|
|
cm_return_if_fail(summaryview != NULL);
|
|
|
|
/* "dont_toggle" state set? */
|
|
if (g_object_get_data(G_OBJECT(summaryview->tags_menu),
|
|
"dont_toggle"))
|
|
return;
|
|
|
|
tag_apply_open(summary_get_selection(summaryview));
|
|
}
|
|
|
|
static gint summary_tag_cmp_list(gconstpointer a, gconstpointer b)
|
|
{
|
|
gint id_a = GPOINTER_TO_INT(a);
|
|
gint id_b = GPOINTER_TO_INT(b);
|
|
const gchar *tag_a = tags_get_tag(id_a);
|
|
const gchar *tag_b = tags_get_tag(id_b);
|
|
|
|
if (tag_a == NULL)
|
|
return tag_b == NULL ? 0:1;
|
|
|
|
if (tag_b == NULL)
|
|
return 1;
|
|
|
|
return g_utf8_collate(tag_a, tag_b);
|
|
}
|
|
|
|
static void summary_tags_menu_create(SummaryView *summaryview, gboolean refresh)
|
|
{
|
|
|
|
GtkWidget *label_menuitem;
|
|
GtkWidget *menu;
|
|
GtkWidget *item;
|
|
GSList *cur = tags_get_list();
|
|
GSList *orig = NULL;
|
|
gboolean existing_tags = FALSE;
|
|
gchar *accel_path = NULL;
|
|
|
|
cur = orig = g_slist_sort(cur, summary_tag_cmp_list);
|
|
label_menuitem = gtk_ui_manager_get_widget(summaryview->mainwin->ui_manager, "/Menus/SummaryViewPopup/Tags");
|
|
g_signal_connect(G_OBJECT(label_menuitem), "activate",
|
|
G_CALLBACK(summary_tags_menu_item_activate_item_cb),
|
|
summaryview);
|
|
|
|
gtk_widget_show(label_menuitem);
|
|
|
|
menu = gtk_menu_new();
|
|
|
|
gtk_menu_set_accel_group (GTK_MENU (menu),
|
|
gtk_ui_manager_get_accel_group(summaryview->mainwin->ui_manager));
|
|
|
|
/* create tags menu items */
|
|
for (; cur; cur = cur->next) {
|
|
gint id = GPOINTER_TO_INT(cur->data);
|
|
const gchar *tag = tags_get_tag(id);
|
|
item = gtk_check_menu_item_new_with_label(tag);
|
|
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
|
|
g_signal_connect(G_OBJECT(item), "activate",
|
|
G_CALLBACK(summary_tags_menu_item_activate_cb),
|
|
GINT_TO_POINTER(id));
|
|
g_object_set_data(G_OBJECT(item), "summaryview",
|
|
summaryview);
|
|
g_object_set_data(G_OBJECT(item), "tag_id",
|
|
GINT_TO_POINTER(id));
|
|
gtk_widget_show(item);
|
|
accel_path = g_strconcat("<ClawsTags>/",tag, NULL);
|
|
gtk_menu_item_set_accel_path(GTK_MENU_ITEM(item), accel_path);
|
|
g_free(accel_path);
|
|
existing_tags = TRUE;
|
|
}
|
|
if (existing_tags) {
|
|
/* separator */
|
|
item = gtk_menu_item_new();
|
|
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
|
|
gtk_widget_show(item);
|
|
}
|
|
|
|
item = gtk_menu_item_new_with_label(_("Apply tags..."));
|
|
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
|
|
g_signal_connect(G_OBJECT(item), "activate",
|
|
G_CALLBACK(summary_tags_menu_item_apply_tags_activate_cb),
|
|
NULL);
|
|
g_object_set_data(G_OBJECT(item), "summaryview",
|
|
summaryview);
|
|
gtk_widget_show(item);
|
|
accel_path = g_strdup_printf("<ClawsTags>/ApplyTags");
|
|
gtk_menu_item_set_accel_path(GTK_MENU_ITEM(item), accel_path);
|
|
g_free(accel_path);
|
|
|
|
g_slist_free(orig);
|
|
gtk_widget_show(menu);
|
|
gtk_menu_item_set_submenu(GTK_MENU_ITEM(label_menuitem), menu);
|
|
summaryview->tags_menu = menu;
|
|
}
|
|
|
|
static gboolean summary_popup_menu(GtkWidget *widget, gpointer data)
|
|
{
|
|
SummaryView *summaryview = (SummaryView *)data;
|
|
summaryview->display_msg = messageview_is_visible(summaryview->messageview);
|
|
|
|
gtk_menu_popup(GTK_MENU(summaryview->popupmenu),
|
|
NULL, NULL, NULL, NULL,
|
|
3, gtk_get_current_event_time());
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#if !GENERIC_UMPC
|
|
static gchar *summaryview_get_tooltip_text(SummaryView *summaryview, MsgInfo *info, gint column)
|
|
{
|
|
MsgFlags flags;
|
|
if (!info)
|
|
return NULL;
|
|
|
|
flags = info->flags;
|
|
|
|
switch(summaryview->col_state[column].type) {
|
|
case S_COL_STATUS:
|
|
if (MSG_IS_IGNORE_THREAD(flags)) {
|
|
return _("Ignored thread");
|
|
} else if (MSG_IS_WATCH_THREAD(flags)) {
|
|
return _("Watched thread");
|
|
} else if (MSG_IS_SPAM(flags)) {
|
|
return _("Spam");
|
|
} else if (MSG_IS_NEW(flags)) {
|
|
return _("New");
|
|
} else if (MSG_IS_UNREAD(flags)) {
|
|
return _("Unread");
|
|
} else if (MSG_IS_REPLIED(flags) && MSG_IS_FORWARDED(flags)) {
|
|
return _("Replied but also forwarded - click to see reply");
|
|
} else if (MSG_IS_REPLIED(flags)) {
|
|
return _("Replied - click to see reply");
|
|
} else if (MSG_IS_FORWARDED(flags)) {
|
|
return _("Forwarded");
|
|
} else {
|
|
return NULL;
|
|
}
|
|
case S_COL_MARK:
|
|
if (MSG_IS_DELETED(flags)) {
|
|
return _("Deleted");
|
|
} else if (MSG_IS_MARKED(flags)) {
|
|
return _("Marked");
|
|
} else if (MSG_IS_MOVE(flags)) {
|
|
return _("To be moved");
|
|
} else if (MSG_IS_COPY(flags)) {
|
|
return _("To be copied");
|
|
} else {
|
|
return NULL;
|
|
}
|
|
case S_COL_LOCKED:
|
|
if (MSG_IS_LOCKED(flags)) {
|
|
return _("Locked");
|
|
} else {
|
|
return NULL;
|
|
}
|
|
case S_COL_MIME:
|
|
if (MSG_IS_WITH_ATTACHMENT(flags) && MSG_IS_SIGNED(flags)) {
|
|
return _("Signed, has attachment(s)");
|
|
} else if (MSG_IS_SIGNED(flags)) {
|
|
return _("Signed");
|
|
} else if (MSG_IS_WITH_ATTACHMENT(flags) && MSG_IS_ENCRYPTED(flags)) {
|
|
return _("Encrypted, has attachment(s)");
|
|
} else if (MSG_IS_ENCRYPTED(flags)) {
|
|
return _("Encrypted");
|
|
} else if (MSG_IS_WITH_ATTACHMENT(flags)) {
|
|
return _("Has attachment(s)");
|
|
} else {
|
|
return NULL;
|
|
}
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
static gboolean tooltip_cb (GtkWidget *widget,
|
|
gint x,
|
|
gint y,
|
|
gboolean keyboard_mode,
|
|
GtkTooltip *tooltip,
|
|
gpointer user_data)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(widget);
|
|
SummaryView *summaryview = (SummaryView *)user_data;
|
|
gint row = -1, column = -1;
|
|
int offset = prefs_common.show_col_headers ? 24:0;
|
|
GtkCMCTreeNode *node = NULL;
|
|
gchar *text = NULL;
|
|
gchar *formatted = NULL;
|
|
MsgInfo *info = NULL;
|
|
GdkRectangle rect;
|
|
gboolean vert_layout = (prefs_common.layout_mode == VERTICAL_LAYOUT);
|
|
gboolean small_layout = (prefs_common.layout_mode == SMALL_LAYOUT);
|
|
if (!prefs_common.show_tooltips)
|
|
return FALSE;
|
|
|
|
if (y - offset < 0)
|
|
return FALSE;
|
|
|
|
if (!gtk_cmclist_get_selection_info(GTK_CMCLIST(ctree), x, y - offset,
|
|
&row, &column))
|
|
return FALSE;
|
|
|
|
if ((node = gtk_cmctree_node_nth(ctree, row)) == NULL)
|
|
return FALSE;
|
|
|
|
if ((info = gtk_cmctree_node_get_row_data(ctree, node)) == NULL)
|
|
return FALSE;
|
|
|
|
switch (gtk_cmctree_node_get_cell_type(ctree, node, column)) {
|
|
case GTK_CMCELL_TEXT:
|
|
if (gtk_cmctree_node_get_text(ctree, node, column, &text) != TRUE)
|
|
return FALSE;
|
|
break;
|
|
case GTK_CMCELL_PIXTEXT:
|
|
if (gtk_cmctree_node_get_pixtext(ctree, node, column, &text,
|
|
NULL, NULL) != TRUE)
|
|
return FALSE;
|
|
break;
|
|
default:
|
|
if ((text = summaryview_get_tooltip_text(summaryview, info, column)) == NULL)
|
|
return FALSE;
|
|
}
|
|
|
|
if (!text || !*text)
|
|
return FALSE;
|
|
|
|
formatted = g_strdup(text);
|
|
g_strstrip(formatted);
|
|
|
|
if ((vert_layout || small_layout) && prefs_common.two_line_vert)
|
|
gtk_tooltip_set_markup (tooltip, formatted);
|
|
else
|
|
gtk_tooltip_set_text (tooltip, formatted);
|
|
g_free(formatted);
|
|
|
|
rect.x = x - 2;
|
|
rect.y = y - 2;
|
|
rect.width = 12;
|
|
rect.height= 12;
|
|
gtk_tooltip_set_tip_area(tooltip, &rect);
|
|
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
|
|
static gboolean summary_header_button_pressed(GtkWidget *widget,
|
|
GdkEvent *_event,
|
|
gpointer user_data)
|
|
{
|
|
GdkEventButton *event = (GdkEventButton *)_event;
|
|
SummaryView *summaryview = (SummaryView *)user_data;
|
|
|
|
cm_return_val_if_fail(summaryview != NULL, FALSE);
|
|
|
|
/* Only handle single button presses. */
|
|
if (event->type == GDK_2BUTTON_PRESS ||
|
|
event->type == GDK_3BUTTON_PRESS)
|
|
return FALSE;
|
|
|
|
/* Handle right-click for context menu */
|
|
if (event->button == 3) {
|
|
/* Set up any menu items that need setting up. */
|
|
summaryview->header_menu_lock = TRUE;
|
|
cm_toggle_menu_set_active_full(summaryview->mainwin->ui_manager,
|
|
"Menus/SummaryViewHeaderPopup/LockColumnHeaders",
|
|
prefs_common_get_prefs()->summary_col_lock);
|
|
summaryview->header_menu_lock = FALSE;
|
|
|
|
gtk_menu_popup(GTK_MENU(summaryview->headerpopupmenu),
|
|
NULL, NULL, NULL, NULL, 3, event->time);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static GtkWidget *summary_ctree_create(SummaryView *summaryview)
|
|
{
|
|
GtkWidget *ctree;
|
|
gint *col_pos = summaryview->col_pos;
|
|
SummaryColumnState *col_state;
|
|
gchar *titles[N_SUMMARY_COLS];
|
|
SummaryColumnType type;
|
|
gint pos;
|
|
gboolean vert_layout = (prefs_common.layout_mode == VERTICAL_LAYOUT);
|
|
gboolean small_layout = (prefs_common.layout_mode == SMALL_LAYOUT);
|
|
memset(titles, 0, sizeof(titles));
|
|
|
|
col_state = prefs_summary_column_get_config();
|
|
for (pos = 0; pos < N_SUMMARY_COLS; pos++) {
|
|
summaryview->col_state[pos] = col_state[pos];
|
|
type = col_state[pos].type;
|
|
col_pos[type] = pos;
|
|
titles[pos] = "dummy";
|
|
}
|
|
col_state = summaryview->col_state;
|
|
|
|
ctree = gtk_sctree_new_with_titles
|
|
(N_SUMMARY_COLS, col_pos[S_COL_SUBJECT], titles);
|
|
|
|
if (prefs_common.show_col_headers == FALSE)
|
|
gtk_cmclist_column_titles_hide(GTK_CMCLIST(ctree));
|
|
|
|
gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree), GTK_SELECTION_MULTIPLE);
|
|
gtk_cmclist_set_column_justification(GTK_CMCLIST(ctree), col_pos[S_COL_MARK],
|
|
GTK_JUSTIFY_CENTER);
|
|
gtk_cmclist_set_column_justification(GTK_CMCLIST(ctree), col_pos[S_COL_STATUS],
|
|
GTK_JUSTIFY_CENTER);
|
|
gtk_cmclist_set_column_justification(GTK_CMCLIST(ctree), col_pos[S_COL_LOCKED],
|
|
GTK_JUSTIFY_CENTER);
|
|
gtk_cmclist_set_column_justification(GTK_CMCLIST(ctree), col_pos[S_COL_MIME],
|
|
GTK_JUSTIFY_CENTER);
|
|
gtk_cmclist_set_column_justification(GTK_CMCLIST(ctree), col_pos[S_COL_SIZE],
|
|
GTK_JUSTIFY_RIGHT);
|
|
gtk_cmclist_set_column_justification(GTK_CMCLIST(ctree), col_pos[S_COL_NUMBER],
|
|
GTK_JUSTIFY_RIGHT);
|
|
gtk_cmclist_set_column_justification(GTK_CMCLIST(ctree), col_pos[S_COL_SCORE],
|
|
GTK_JUSTIFY_RIGHT);
|
|
gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), col_pos[S_COL_MARK],
|
|
prefs_common.summary_col_size[S_COL_MARK]);
|
|
gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), col_pos[S_COL_STATUS],
|
|
prefs_common.summary_col_size[S_COL_STATUS]);
|
|
gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), col_pos[S_COL_LOCKED],
|
|
prefs_common.summary_col_size[S_COL_LOCKED]);
|
|
gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), col_pos[S_COL_MIME],
|
|
prefs_common.summary_col_size[S_COL_MIME]);
|
|
gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), col_pos[S_COL_SUBJECT],
|
|
prefs_common.summary_col_size[S_COL_SUBJECT]);
|
|
gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), col_pos[S_COL_FROM],
|
|
prefs_common.summary_col_size[S_COL_FROM]);
|
|
gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), col_pos[S_COL_TO],
|
|
prefs_common.summary_col_size[S_COL_TO]);
|
|
gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), col_pos[S_COL_DATE],
|
|
prefs_common.summary_col_size[S_COL_DATE]);
|
|
gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), col_pos[S_COL_SIZE],
|
|
prefs_common.summary_col_size[S_COL_SIZE]);
|
|
gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), col_pos[S_COL_NUMBER],
|
|
prefs_common.summary_col_size[S_COL_NUMBER]);
|
|
gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), col_pos[S_COL_SCORE],
|
|
prefs_common.summary_col_size[S_COL_SCORE]);
|
|
gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), col_pos[S_COL_TAGS],
|
|
prefs_common.summary_col_size[S_COL_TAGS]);
|
|
|
|
gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
|
|
GTK_CMCTREE_EXPANDER_TRIANGLE);
|
|
|
|
gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
|
|
|
|
gtk_cmctree_set_indent(GTK_CMCTREE(ctree), 12);
|
|
g_object_set_data(G_OBJECT(ctree), "summaryview", (gpointer)summaryview);
|
|
|
|
for (pos = 0; pos < N_SUMMARY_COLS; pos++) {
|
|
gtk_widget_set_can_focus(GTK_CMCLIST(ctree)->column[pos].button,
|
|
FALSE);
|
|
if (((pos == summaryview->col_pos[S_COL_FROM] && !FOLDER_SHOWS_TO_HDR(summaryview->folder_item)) ||
|
|
(pos == summaryview->col_pos[S_COL_TO] && FOLDER_SHOWS_TO_HDR(summaryview->folder_item)) ||
|
|
pos == summaryview->col_pos[S_COL_DATE]) && (vert_layout || small_layout) &&
|
|
prefs_common.two_line_vert)
|
|
gtk_cmclist_set_column_visibility
|
|
(GTK_CMCLIST(ctree), pos, FALSE);
|
|
else
|
|
gtk_cmclist_set_column_visibility
|
|
(GTK_CMCLIST(ctree), pos, col_state[pos].visible);
|
|
}
|
|
if (prefs_common.two_line_vert)
|
|
gtk_sctree_set_use_markup(GTK_SCTREE(ctree), summaryview->col_pos[S_COL_SUBJECT], vert_layout||small_layout);
|
|
|
|
/* connect signal to the buttons for sorting */
|
|
#define CLIST_BUTTON_SIGNAL_CONNECT(col, func) \
|
|
g_signal_connect \
|
|
(G_OBJECT(GTK_CMCLIST(ctree)->column[col_pos[col]].button), \
|
|
"button-press-event", \
|
|
G_CALLBACK(summary_header_button_pressed), \
|
|
summaryview); \
|
|
g_signal_connect \
|
|
(G_OBJECT(GTK_CMCLIST(ctree)->column[col_pos[col]].button), \
|
|
"clicked", \
|
|
G_CALLBACK(func), \
|
|
summaryview);
|
|
|
|
CLIST_BUTTON_SIGNAL_CONNECT(S_COL_MARK , summary_mark_clicked)
|
|
CLIST_BUTTON_SIGNAL_CONNECT(S_COL_STATUS , summary_status_clicked)
|
|
CLIST_BUTTON_SIGNAL_CONNECT(S_COL_MIME , summary_mime_clicked)
|
|
CLIST_BUTTON_SIGNAL_CONNECT(S_COL_NUMBER , summary_num_clicked)
|
|
CLIST_BUTTON_SIGNAL_CONNECT(S_COL_SIZE , summary_size_clicked)
|
|
CLIST_BUTTON_SIGNAL_CONNECT(S_COL_DATE , summary_date_clicked)
|
|
CLIST_BUTTON_SIGNAL_CONNECT(S_COL_FROM , summary_from_clicked)
|
|
CLIST_BUTTON_SIGNAL_CONNECT(S_COL_TO , summary_to_clicked)
|
|
CLIST_BUTTON_SIGNAL_CONNECT(S_COL_SUBJECT, summary_subject_clicked)
|
|
CLIST_BUTTON_SIGNAL_CONNECT(S_COL_SCORE , summary_score_clicked)
|
|
CLIST_BUTTON_SIGNAL_CONNECT(S_COL_LOCKED , summary_locked_clicked)
|
|
CLIST_BUTTON_SIGNAL_CONNECT(S_COL_TAGS , summary_tags_clicked)
|
|
|
|
#undef CLIST_BUTTON_SIGNAL_CONNECT
|
|
|
|
g_signal_connect(G_OBJECT(ctree), "tree_select_row",
|
|
G_CALLBACK(summary_selected), summaryview);
|
|
g_signal_connect(G_OBJECT(ctree), "tree_unselect_row",
|
|
G_CALLBACK(summary_unselected), summaryview);
|
|
g_signal_connect(G_OBJECT(ctree), "button_press_event",
|
|
G_CALLBACK(summary_button_pressed),
|
|
summaryview);
|
|
g_signal_connect(G_OBJECT(ctree), "popup-menu",
|
|
G_CALLBACK(summary_popup_menu), summaryview);
|
|
g_signal_connect(G_OBJECT(ctree), "button_release_event",
|
|
G_CALLBACK(summary_button_released),
|
|
summaryview);
|
|
g_signal_connect(G_OBJECT(ctree), "key_press_event",
|
|
G_CALLBACK(summary_key_pressed), summaryview);
|
|
g_signal_connect(G_OBJECT(ctree), "resize_column",
|
|
G_CALLBACK(summary_col_resized), summaryview);
|
|
g_signal_connect(G_OBJECT(ctree), "open_row",
|
|
G_CALLBACK(summary_open_row), summaryview);
|
|
|
|
g_signal_connect_after(G_OBJECT(ctree), "tree_expand",
|
|
G_CALLBACK(summary_tree_expanded),
|
|
summaryview);
|
|
g_signal_connect_after(G_OBJECT(ctree), "tree_collapse",
|
|
G_CALLBACK(summary_tree_collapsed),
|
|
summaryview);
|
|
|
|
g_signal_connect(G_OBJECT(ctree), "start_drag",
|
|
G_CALLBACK(summary_start_drag),
|
|
summaryview);
|
|
g_signal_connect(G_OBJECT(ctree), "drag_data_get",
|
|
G_CALLBACK(summary_drag_data_get),
|
|
summaryview);
|
|
g_signal_connect(G_OBJECT(ctree), "drag_end",
|
|
G_CALLBACK(summary_drag_end),
|
|
summaryview);
|
|
|
|
gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
|
|
summary_drag_types, 3,
|
|
GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
|
|
|
|
g_signal_connect(G_OBJECT(ctree), "drag_data_received",
|
|
G_CALLBACK(summary_drag_data_received),
|
|
summaryview);
|
|
|
|
g_signal_connect(G_OBJECT(ctree), "drag_motion",
|
|
G_CALLBACK(summary_drag_motion_cb),
|
|
summaryview);
|
|
|
|
#if !GENERIC_UMPC
|
|
g_object_set (G_OBJECT(ctree), "has-tooltip", TRUE, NULL);
|
|
g_signal_connect(G_OBJECT(ctree), "query-tooltip",
|
|
G_CALLBACK(tooltip_cb),
|
|
summaryview);
|
|
#endif
|
|
return ctree;
|
|
}
|
|
|
|
void summary_set_column_order(SummaryView *summaryview)
|
|
{
|
|
GtkWidget *ctree;
|
|
GtkWidget *scrolledwin = summaryview->scrolledwin;
|
|
FolderItem *item;
|
|
guint selected_msgnum = summary_get_msgnum(summaryview, summaryview->selected);
|
|
guint displayed_msgnum = summary_get_msgnum(summaryview, summaryview->displayed);
|
|
|
|
item = summaryview->folder_item;
|
|
|
|
summary_clear_all(summaryview);
|
|
gtk_widget_destroy(summaryview->ctree);
|
|
|
|
summaryview->ctree = ctree = summary_ctree_create(summaryview);
|
|
summary_set_fonts(summaryview);
|
|
summary_set_column_titles(summaryview);
|
|
gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
|
|
GTK_CMCLIST(ctree)->hadjustment);
|
|
gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
|
|
GTK_CMCLIST(ctree)->vadjustment);
|
|
gtk_container_add(GTK_CONTAINER(scrolledwin), ctree);
|
|
gtk_widget_show(ctree);
|
|
|
|
summary_show(summaryview, item);
|
|
|
|
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);
|
|
if (!summaryview->displayed)
|
|
messageview_clear(summaryview->messageview);
|
|
else
|
|
summary_redisplay_msg(summaryview);
|
|
|
|
/* get normal row height */
|
|
gtk_cmclist_set_row_height(GTK_CMCLIST(ctree), 0);
|
|
normal_row_height = GTK_CMCLIST(ctree)->row_height;
|
|
|
|
if ((prefs_common.layout_mode == SMALL_LAYOUT || prefs_common.layout_mode == VERTICAL_LAYOUT) &&
|
|
prefs_common.two_line_vert) {
|
|
gtk_cmclist_set_row_height(GTK_CMCLIST(summaryview->ctree), 2*normal_row_height + 2);
|
|
}
|
|
}
|
|
|
|
|
|
/* callback functions */
|
|
|
|
static gint summary_folder_eventbox_pressed(GtkWidget *eventbox, GdkEventButton *event,
|
|
SummaryView *summaryview)
|
|
{
|
|
if (event) {
|
|
folderview_grab_focus(summaryview->folderview);
|
|
mainwindow_exit_folder(summaryview->mainwin);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static gint summary_toggle_pressed(GtkWidget *eventbox, GdkEventButton *event,
|
|
SummaryView *summaryview)
|
|
{
|
|
if (event)
|
|
summary_toggle_view(summaryview);
|
|
return TRUE;
|
|
}
|
|
#ifdef GENERIC_UMPC
|
|
static void summary_toggle_multiple_pressed(GtkWidget *widget,
|
|
SummaryView *summaryview)
|
|
{
|
|
GTK_SCTREE(summaryview->ctree)->force_additive_sel =
|
|
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
|
|
}
|
|
#endif
|
|
static gboolean summary_button_pressed(GtkWidget *ctree, GdkEventButton *event,
|
|
SummaryView *summaryview)
|
|
{
|
|
if (!event) return FALSE;
|
|
if (event->window != GTK_CMCLIST(ctree)->clist_window) return FALSE;
|
|
|
|
if (event->button == 3) {
|
|
/* right clicked */
|
|
summary_set_menu_sensitive(summaryview);
|
|
gtk_menu_popup(GTK_MENU(summaryview->popupmenu), NULL, NULL,
|
|
NULL, NULL, event->button, event->time);
|
|
} else if (event->button == 2) {
|
|
summaryview->display_msg = messageview_is_visible(summaryview->messageview);
|
|
} else if (event->button == 1) {
|
|
if (!prefs_common.emulate_emacs &&
|
|
messageview_is_visible(summaryview->messageview))
|
|
summaryview->display_msg = TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean summary_button_released(GtkWidget *ctree, GdkEventButton *event,
|
|
SummaryView *summaryview)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
gboolean summary_pass_key_press_event(SummaryView *summaryview, GdkEventKey *event)
|
|
{
|
|
if (!summaryview)
|
|
return FALSE;
|
|
if (summary_is_list(summaryview))
|
|
return summary_key_pressed(summaryview->ctree, event, summaryview);
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
#define BREAK_ON_MODIFIER_KEY() \
|
|
if ((event->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK)) != 0) break
|
|
|
|
/* Copied from gtkcmclist.c, if it changes there, it has to change
|
|
* here as well. This is an ugly hack, there must be a better way to
|
|
* find out how much to move for page up/down. */
|
|
#define CELL_SPACING 1
|
|
static gboolean summary_key_pressed(GtkWidget *widget, GdkEventKey *event,
|
|
SummaryView *summaryview)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(widget);
|
|
GtkCMCTreeNode *node;
|
|
MessageView *messageview;
|
|
GtkAdjustment *adj;
|
|
gboolean mod_pressed;
|
|
|
|
if (!event)
|
|
return TRUE;
|
|
|
|
if (quicksearch_has_focus(summaryview->quicksearch))
|
|
return FALSE;
|
|
|
|
messageview = summaryview->messageview;
|
|
|
|
mod_pressed =
|
|
((event->state & (GDK_SHIFT_MASK|GDK_MOD1_MASK)) != 0);
|
|
|
|
if (summaryview->selected) {
|
|
gboolean handled = FALSE;
|
|
switch (event->keyval) {
|
|
case GDK_KEY_space: /* Page down or go to the next */
|
|
handled = TRUE;
|
|
if (event->state & GDK_CONTROL_MASK) {
|
|
handled = FALSE;
|
|
break;
|
|
}
|
|
if (event->state & GDK_SHIFT_MASK)
|
|
mimeview_scroll_page(messageview->mimeview, TRUE);
|
|
else {
|
|
if (summaryview->displayed != summaryview->selected) {
|
|
summary_display_msg(summaryview,
|
|
summaryview->selected);
|
|
break;
|
|
}
|
|
if (mod_pressed) {
|
|
if (!mimeview_scroll_page(messageview->mimeview, TRUE))
|
|
summary_select_prev_unread(summaryview);
|
|
} else {
|
|
if (!mimeview_scroll_page(messageview->mimeview, FALSE))
|
|
summary_select_next_unread(summaryview);
|
|
}
|
|
}
|
|
break;
|
|
case GDK_KEY_BackSpace: /* Page up */
|
|
handled = TRUE;
|
|
mimeview_scroll_page(messageview->mimeview, TRUE);
|
|
break;
|
|
case GDK_KEY_Return: /* Scroll up/down one line */
|
|
case GDK_KEY_KP_Enter:
|
|
handled = TRUE;
|
|
if (summaryview->displayed != summaryview->selected) {
|
|
#ifndef GENERIC_UMPC
|
|
summary_display_msg(summaryview,
|
|
summaryview->selected);
|
|
#else
|
|
summary_open_row(NULL, summaryview);
|
|
#endif
|
|
break;
|
|
}
|
|
mimeview_scroll_one_line(messageview->mimeview, mod_pressed);
|
|
break;
|
|
}
|
|
|
|
if (handled)
|
|
return FALSE;
|
|
}
|
|
if (summary_is_locked(summaryview))
|
|
return TRUE;
|
|
|
|
switch (event->keyval) {
|
|
case GDK_KEY_Left: /* Move focus */
|
|
adj = gtk_scrolled_window_get_hadjustment
|
|
(GTK_SCROLLED_WINDOW(summaryview->scrolledwin));
|
|
if (gtk_adjustment_get_lower(adj) != gtk_adjustment_get_value(adj))
|
|
break;
|
|
/* FALLTHROUGH */
|
|
case GDK_KEY_Escape:
|
|
folderview_grab_focus(summaryview->folderview);
|
|
mainwindow_exit_folder(summaryview->mainwin);
|
|
return TRUE;
|
|
case GDK_KEY_Home: case GDK_KEY_KP_Home:
|
|
case GDK_KEY_End: case GDK_KEY_KP_End:
|
|
case GDK_KEY_Up: case GDK_KEY_KP_Up:
|
|
case GDK_KEY_Down: case GDK_KEY_KP_Down:
|
|
case GDK_KEY_Page_Up: case GDK_KEY_KP_Page_Up:
|
|
case GDK_KEY_Page_Down: case GDK_KEY_KP_Page_Down:
|
|
if ((node = summaryview->selected) != NULL) {
|
|
GtkCMCTreeNode *next = NULL;
|
|
switch (event->keyval) {
|
|
case GDK_KEY_Home: case GDK_KEY_KP_Home:
|
|
next = gtk_cmctree_node_nth(ctree, 0);
|
|
break;
|
|
case GDK_KEY_End: case GDK_KEY_KP_End:
|
|
next = gtk_cmctree_node_nth(ctree,
|
|
g_list_length(GTK_CMCLIST(ctree)->row_list)-1);
|
|
break;
|
|
case GDK_KEY_Up: case GDK_KEY_KP_Up:
|
|
next = gtk_cmctree_node_nth(ctree,
|
|
MAX(0, GTK_CMCLIST(ctree)->focus_row - 1));
|
|
break;
|
|
case GDK_KEY_Down: case GDK_KEY_KP_Down:
|
|
next = gtk_cmctree_node_nth(ctree,
|
|
MIN(GTK_CMCLIST(ctree)->focus_row + 1, GTK_CMCLIST(ctree)->rows - 1));
|
|
break;
|
|
case GDK_KEY_Page_Up: case GDK_KEY_KP_Page_Up:
|
|
next = gtk_cmctree_node_nth(ctree,
|
|
MAX(0, GTK_CMCLIST(ctree)->focus_row -
|
|
(2 * GTK_CMCLIST(ctree)->clist_window_height -
|
|
GTK_CMCLIST(ctree)->row_height - CELL_SPACING) /
|
|
(2 * (GTK_CMCLIST(ctree)->row_height + CELL_SPACING))));
|
|
break;
|
|
case GDK_KEY_Page_Down: case GDK_KEY_KP_Page_Down:
|
|
next = gtk_cmctree_node_nth(ctree,
|
|
MIN(GTK_CMCLIST(ctree)->rows - 1, GTK_CMCLIST(ctree)->focus_row +
|
|
(2 * GTK_CMCLIST(ctree)->clist_window_height -
|
|
GTK_CMCLIST(ctree)->row_height - CELL_SPACING) /
|
|
(2 * (GTK_CMCLIST(ctree)->row_height + CELL_SPACING))));
|
|
break;
|
|
}
|
|
|
|
if (next != NULL &&
|
|
next != gtk_cmctree_node_nth(ctree, GTK_CMCLIST(ctree)->focus_row)) {
|
|
gtk_sctree_select_with_state
|
|
(GTK_SCTREE(ctree), next, (event->state & ~GDK_CONTROL_MASK) );
|
|
|
|
/* Deprecated - what are the non-deprecated equivalents? */
|
|
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, OPEN_SELECTED_ON_DIRECTIONAL);
|
|
summaryview->selected = next;
|
|
}
|
|
}
|
|
return TRUE;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (!summaryview->selected) {
|
|
node = gtk_cmctree_node_nth(ctree, 0);
|
|
if (node)
|
|
gtk_sctree_select(GTK_SCTREE(ctree), node);
|
|
else
|
|
return TRUE;
|
|
}
|
|
|
|
switch (event->keyval) {
|
|
case GDK_KEY_Delete:
|
|
BREAK_ON_MODIFIER_KEY();
|
|
summary_delete_trash(summaryview);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return FALSE;
|
|
}
|
|
#undef CELL_SPACING
|
|
|
|
static void quicksearch_execute_cb(QuickSearch *quicksearch, gpointer data)
|
|
{
|
|
SummaryView *summaryview = data;
|
|
|
|
summaryview_reset_recursive_folder_match(summaryview);
|
|
if (summary_show(summaryview, summaryview->folder_item))
|
|
summaryview_quicksearch_recurse(summaryview);
|
|
else
|
|
summaryview_reset_recursive_folder_match(summaryview);
|
|
}
|
|
|
|
static void tog_searchbar_cb(GtkWidget *w, gpointer data)
|
|
{
|
|
SummaryView *summaryview = (SummaryView *)data;
|
|
|
|
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) {
|
|
prefs_common.show_searchbar = TRUE;
|
|
quicksearch_show(summaryview->quicksearch);
|
|
} else {
|
|
prefs_common.show_searchbar = FALSE;
|
|
quicksearch_hide(summaryview->quicksearch);
|
|
}
|
|
}
|
|
|
|
void summaryview_activate_quicksearch(SummaryView *summaryview, gboolean show)
|
|
{
|
|
prefs_common.show_searchbar = show;
|
|
gtk_toggle_button_set_active(
|
|
GTK_TOGGLE_BUTTON(summaryview->toggle_search),
|
|
show);
|
|
if (show) {
|
|
quicksearch_show(summaryview->quicksearch);
|
|
} else {
|
|
quicksearch_hide(summaryview->quicksearch);
|
|
summary_grab_focus(summaryview);
|
|
}
|
|
}
|
|
|
|
void summary_open_row(GtkSCTree *sctree, SummaryView *summaryview)
|
|
{
|
|
if (FOLDER_SHOWS_TO_HDR(summaryview->folder_item))
|
|
summary_reedit(summaryview);
|
|
else
|
|
summary_open_msg(summaryview);
|
|
|
|
summaryview->display_msg = FALSE;
|
|
}
|
|
|
|
static void summary_tree_expanded(GtkCMCTree *ctree, GtkCMCTreeNode *node,
|
|
SummaryView *summaryview)
|
|
{
|
|
summary_set_row_marks(summaryview, node);
|
|
if (prefs_common.bold_unread) {
|
|
while (node) {
|
|
GtkCMCTreeNode *next = GTK_CMCTREE_NODE_NEXT(node);
|
|
if (GTK_CMCTREE_ROW(node)->children)
|
|
summary_set_row_marks(summaryview, node);
|
|
node = next;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void summary_tree_collapsed(GtkCMCTree *ctree, GtkCMCTreeNode *node,
|
|
SummaryView *summaryview)
|
|
{
|
|
gtk_sctree_select(GTK_SCTREE(ctree), node);
|
|
summary_set_row_marks(summaryview, node);
|
|
}
|
|
|
|
static void summary_unselected(GtkCMCTree *ctree, GtkCMCTreeNode *row,
|
|
gint column, SummaryView *summaryview)
|
|
{
|
|
if (summary_is_locked(summaryview)
|
|
|| GTK_SCTREE(ctree)->selecting_range) {
|
|
return;
|
|
}
|
|
|
|
summary_status_show(summaryview);
|
|
}
|
|
|
|
static void summary_selected(GtkCMCTree *ctree, GtkCMCTreeNode *row,
|
|
gint column, SummaryView *summaryview)
|
|
{
|
|
const GList *list, *cur;
|
|
MessageView *msgview;
|
|
MsgInfo *msginfo;
|
|
gboolean marked_unread = FALSE;
|
|
|
|
if (summary_is_locked(summaryview)
|
|
&& !GTK_SCTREE(ctree)->selecting_range
|
|
&& summaryview->messageview
|
|
&& summaryview->messageview->mimeview
|
|
&& summaryview->messageview->mimeview->type == MIMEVIEW_TEXT
|
|
&& summaryview->messageview->mimeview->textview->loading) {
|
|
PostponedSelectData *data = g_new0(PostponedSelectData, 1);
|
|
summaryview->messageview->mimeview->textview->stop_loading = TRUE;
|
|
|
|
data->ctree = ctree;
|
|
data->row = row;
|
|
data->node = NULL;
|
|
data->column = column;
|
|
data->summaryview = summaryview;
|
|
debug_print("postponing open of message till end of load\n");
|
|
g_timeout_add(100, summary_select_retry, data);
|
|
return;
|
|
}
|
|
if (summary_is_locked(summaryview)
|
|
|| GTK_SCTREE(ctree)->selecting_range) {
|
|
return;
|
|
}
|
|
|
|
summary_status_show(summaryview);
|
|
|
|
if (GTK_CMCLIST(ctree)->selection &&
|
|
GTK_CMCLIST(ctree)->selection->next) {
|
|
summaryview->display_msg = FALSE;
|
|
summary_set_menu_sensitive(summaryview);
|
|
toolbar_main_set_sensitive(summaryview->mainwin);
|
|
return;
|
|
}
|
|
|
|
summaryview->selected = row;
|
|
|
|
msginfo = gtk_cmctree_node_get_row_data(ctree, row);
|
|
cm_return_if_fail(msginfo != NULL);
|
|
|
|
main_create_mailing_list_menu (summaryview->mainwin, msginfo);
|
|
toolbar_set_learn_button
|
|
(summaryview->mainwin->toolbar,
|
|
MSG_IS_SPAM(msginfo->flags)?LEARN_HAM:LEARN_SPAM);
|
|
|
|
switch (column < 0 ? column : summaryview->col_state[column].type) {
|
|
case S_COL_MARK:
|
|
if (!MSG_IS_DELETED(msginfo->flags) &&
|
|
!MSG_IS_MOVE(msginfo->flags) &&
|
|
!MSG_IS_COPY(msginfo->flags)) {
|
|
if (MSG_IS_MARKED(msginfo->flags)) {
|
|
summary_unmark_row(summaryview, row);
|
|
summary_status_show(summaryview);
|
|
} else {
|
|
summary_mark_row(summaryview, row);
|
|
summary_status_show(summaryview);
|
|
}
|
|
}
|
|
break;
|
|
case S_COL_STATUS:
|
|
if (MSG_IS_UNREAD(msginfo->flags)) {
|
|
summary_mark_row_as_read(summaryview, row);
|
|
summary_status_show(summaryview);
|
|
} else if (MSG_IS_SPAM(msginfo->flags)) {
|
|
if (procmsg_spam_learner_learn(msginfo, NULL, FALSE) == 0)
|
|
summary_msginfo_unset_flags(msginfo, MSG_SPAM, 0);
|
|
else
|
|
log_error(LOG_PROTOCOL, _("An error happened while learning.\n"));
|
|
} else if (!MSG_IS_REPLIED(msginfo->flags) &&
|
|
!MSG_IS_FORWARDED(msginfo->flags)) {
|
|
marked_unread = TRUE;
|
|
} else if (MSG_IS_REPLIED(msginfo->flags)) {
|
|
summary_find_answers(summaryview, msginfo);
|
|
return;
|
|
}
|
|
break;
|
|
case S_COL_LOCKED:
|
|
if (MSG_IS_LOCKED(msginfo->flags)) {
|
|
summary_unlock_row(summaryview, row);
|
|
summary_status_show(summaryview);
|
|
}
|
|
else {
|
|
summary_lock_row(summaryview, row);
|
|
summary_status_show(summaryview);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
list = messageview_get_msgview_list();
|
|
for (cur = list; cur != NULL; cur = cur->next) {
|
|
msgview = (MessageView *) cur->data;
|
|
|
|
if (msgview->new_window && msgview->update_needed) {
|
|
MsgInfo *new_msginfo = summary_get_selected_msg(summaryview);
|
|
messageview_show(msgview, new_msginfo, msgview->all_headers);
|
|
msgview->update_needed = FALSE;
|
|
}
|
|
}
|
|
|
|
if (summaryview->display_msg) {
|
|
summaryview->display_msg = FALSE;
|
|
if (summaryview->displayed != row) {
|
|
summary_display_msg(summaryview, row);
|
|
if (marked_unread) {
|
|
summary_mark_row_as_unread(summaryview, row);
|
|
summary_status_show(summaryview);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (marked_unread) {
|
|
summary_mark_row_as_unread(summaryview, row);
|
|
summary_status_show(summaryview);
|
|
}
|
|
|
|
summary_set_menu_sensitive(summaryview);
|
|
toolbar_main_set_sensitive(summaryview->mainwin);
|
|
}
|
|
|
|
static void summary_col_resized(GtkCMCList *clist, gint column, gint width,
|
|
SummaryView *summaryview)
|
|
{
|
|
SummaryColumnType type = summaryview->col_state[column].type;
|
|
|
|
prefs_common.summary_col_size[type] = width;
|
|
}
|
|
|
|
|
|
/*
|
|
* \brief get List of msginfo selected in SummaryView
|
|
*
|
|
* \param summaryview
|
|
*
|
|
* \return GSList holding MsgInfo
|
|
*/
|
|
GSList *summary_get_selection(SummaryView *summaryview)
|
|
{
|
|
GList *sel = NULL;
|
|
GSList *msginfo_list = NULL;
|
|
|
|
cm_return_val_if_fail(summaryview != NULL, NULL);
|
|
|
|
sel = GTK_CMCLIST(summaryview->ctree)->selection;
|
|
|
|
cm_return_val_if_fail(sel != NULL, NULL);
|
|
|
|
for ( ; sel != NULL; sel = sel->next)
|
|
msginfo_list =
|
|
g_slist_prepend(msginfo_list,
|
|
gtk_cmctree_node_get_row_data(GTK_CMCTREE(summaryview->ctree),
|
|
GTK_CMCTREE_NODE(sel->data)));
|
|
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)
|
|
{
|
|
if (prefs_common.summary_col_lock) {
|
|
debug_print("summaryview columns locked, ignoring\n");
|
|
return;
|
|
}
|
|
|
|
GtkCMCTreeNode *node = NULL;
|
|
START_TIMING("");
|
|
if (summaryview->sort_key == sort_key)
|
|
summary_sort(summaryview, sort_key,
|
|
summaryview->sort_type == SORT_ASCENDING
|
|
? SORT_DESCENDING : SORT_ASCENDING);
|
|
else
|
|
summary_sort(summaryview, sort_key, summaryview->sort_type);
|
|
|
|
node = GTK_CMCTREE_NODE(GTK_CMCLIST(summaryview->ctree)->row_list);
|
|
|
|
summary_freeze(summaryview);
|
|
if (prefs_common.bold_unread) {
|
|
while (node) {
|
|
GtkCMCTreeNode *next = GTK_CMCTREE_NODE_NEXT(node);
|
|
if (GTK_CMCTREE_ROW(node)->children)
|
|
summary_set_row_marks(summaryview, node);
|
|
node = next;
|
|
}
|
|
}
|
|
summary_thaw(summaryview);
|
|
END_TIMING();
|
|
}
|
|
|
|
static void summary_mark_clicked(GtkWidget *button, SummaryView *summaryview)
|
|
{
|
|
summary_sort_by_column_click(summaryview, SORT_BY_MARK);
|
|
}
|
|
|
|
static void summary_status_clicked(GtkWidget *button, SummaryView *summaryview)
|
|
{
|
|
summary_sort_by_column_click(summaryview, SORT_BY_STATUS);
|
|
}
|
|
|
|
static void summary_mime_clicked(GtkWidget *button, SummaryView *summaryview)
|
|
{
|
|
summary_sort_by_column_click(summaryview, SORT_BY_MIME);
|
|
}
|
|
|
|
static void summary_num_clicked(GtkWidget *button, SummaryView *summaryview)
|
|
{
|
|
summary_sort_by_column_click(summaryview, SORT_BY_NUMBER);
|
|
}
|
|
|
|
static void summary_size_clicked(GtkWidget *button, SummaryView *summaryview)
|
|
{
|
|
summary_sort_by_column_click(summaryview, SORT_BY_SIZE);
|
|
}
|
|
|
|
static void summary_date_clicked(GtkWidget *button, SummaryView *summaryview)
|
|
{
|
|
if (summaryview->sort_key == SORT_BY_THREAD_DATE)
|
|
summary_sort_by_column_click(summaryview, SORT_BY_THREAD_DATE);
|
|
else
|
|
summary_sort_by_column_click(summaryview, SORT_BY_DATE);
|
|
}
|
|
|
|
static void summary_from_clicked(GtkWidget *button, SummaryView *summaryview)
|
|
{
|
|
if (summaryview->col_state[summaryview->col_pos[S_COL_FROM]].visible)
|
|
summary_sort_by_column_click(summaryview, SORT_BY_FROM);
|
|
else
|
|
summary_sort_by_column_click(summaryview, SORT_BY_TO);
|
|
}
|
|
|
|
static void summary_to_clicked(GtkWidget *button, SummaryView *summaryview)
|
|
{
|
|
if (summaryview->col_state[summaryview->col_pos[S_COL_TO]].visible)
|
|
summary_sort_by_column_click(summaryview, SORT_BY_TO);
|
|
else
|
|
summary_sort_by_column_click(summaryview, SORT_BY_FROM);
|
|
}
|
|
|
|
static void summary_subject_clicked(GtkWidget *button,
|
|
SummaryView *summaryview)
|
|
{
|
|
summary_sort_by_column_click(summaryview, SORT_BY_SUBJECT);
|
|
}
|
|
|
|
static void summary_score_clicked(GtkWidget *button,
|
|
SummaryView *summaryview)
|
|
{
|
|
summary_sort_by_column_click(summaryview, SORT_BY_SCORE);
|
|
}
|
|
|
|
static void summary_locked_clicked(GtkWidget *button,
|
|
SummaryView *summaryview)
|
|
{
|
|
summary_sort_by_column_click(summaryview, SORT_BY_LOCKED);
|
|
}
|
|
|
|
static void summary_tags_clicked(GtkWidget *button,
|
|
SummaryView *summaryview)
|
|
{
|
|
summary_sort_by_column_click(summaryview, SORT_BY_TAGS);
|
|
}
|
|
|
|
static void summary_start_drag(GtkWidget *widget, gint button, GdkEvent *event,
|
|
SummaryView *summaryview)
|
|
{
|
|
GdkDragContext *context;
|
|
|
|
cm_return_if_fail(summaryview != NULL);
|
|
cm_return_if_fail(summaryview->folder_item != NULL);
|
|
cm_return_if_fail(summaryview->folder_item->folder != NULL);
|
|
|
|
if (summaryview->selected == NULL) return;
|
|
|
|
context = gtk_drag_begin(widget, summaryview->target_list,
|
|
GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
|
|
gtk_drag_set_icon_default(context);
|
|
if (prefs_common.layout_mode == SMALL_LAYOUT) {
|
|
GtkWidget *paned = gtk_widget_get_parent(GTK_WIDGET_PTR(summaryview));
|
|
if (paned && GTK_IS_PANED(paned)) {
|
|
mainwindow_reset_paned(GTK_PANED(paned));
|
|
}
|
|
}
|
|
}
|
|
|
|
static gboolean summary_return_to_list(void *data)
|
|
{
|
|
SummaryView *summaryview = (SummaryView *)data;
|
|
mainwindow_enter_folder(summaryview->mainwin);
|
|
return FALSE;
|
|
}
|
|
|
|
static void summary_drag_end (GtkWidget *widget,
|
|
GdkDragContext *drag_context,
|
|
SummaryView *summaryview)
|
|
{
|
|
if (prefs_common.layout_mode == SMALL_LAYOUT) {
|
|
g_timeout_add(250, summary_return_to_list, summaryview);
|
|
}
|
|
}
|
|
|
|
static void summary_drag_data_get(GtkWidget *widget,
|
|
GdkDragContext *drag_context,
|
|
GtkSelectionData *selection_data,
|
|
guint info,
|
|
guint time,
|
|
SummaryView *summaryview)
|
|
{
|
|
if (info == TARGET_MAIL_URI_LIST) {
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GList *cur;
|
|
MsgInfo *msginfo;
|
|
gchar *mail_list = NULL, *tmp1, *tmp2;
|
|
|
|
for (cur = GTK_CMCLIST(ctree)->selection;
|
|
cur != NULL && cur->data != NULL; cur = cur->next) {
|
|
msginfo = gtk_cmctree_node_get_row_data
|
|
(ctree, GTK_CMCTREE_NODE(cur->data));
|
|
tmp2 = procmsg_get_message_file(msginfo);
|
|
if (!tmp2) continue;
|
|
if (msginfo->subject) {
|
|
gchar *san_subject = g_strdup(msginfo->subject);
|
|
gchar *dest = NULL;
|
|
subst_for_filename(san_subject);
|
|
dest = g_strdup_printf("%s%s%s.%d.txt",
|
|
get_tmp_dir(),
|
|
G_DIR_SEPARATOR_S,
|
|
san_subject, msginfo->msgnum);
|
|
g_free(san_subject);
|
|
san_subject = g_filename_from_utf8(dest, -1, NULL, NULL, NULL);
|
|
g_free(dest);
|
|
dest = san_subject;
|
|
if (copy_file(tmp2, dest, TRUE) == 0) {
|
|
g_free(tmp2);
|
|
tmp2 = dest;
|
|
}
|
|
}
|
|
tmp1 = g_filename_to_uri(tmp2, NULL, NULL);
|
|
g_free(tmp2);
|
|
tmp2 = g_strconcat(tmp1, "\r\n", NULL);
|
|
g_free(tmp1);
|
|
tmp1 = tmp2;
|
|
|
|
if (!mail_list) {
|
|
mail_list = tmp1;
|
|
} else {
|
|
tmp2 = g_strconcat(mail_list, tmp1, NULL);
|
|
g_free(mail_list);
|
|
g_free(tmp1);
|
|
mail_list = tmp2;
|
|
}
|
|
}
|
|
|
|
if (mail_list != NULL) {
|
|
gtk_selection_data_set(selection_data,
|
|
gtk_selection_data_get_target(selection_data), 8,
|
|
mail_list, strlen(mail_list));
|
|
g_free(mail_list);
|
|
}
|
|
} else if (info == TARGET_DUMMY) {
|
|
if (GTK_CMCLIST(summaryview->ctree)->selection)
|
|
gtk_selection_data_set(selection_data,
|
|
gtk_selection_data_get_target(selection_data), 8,
|
|
"Dummy-Summaryview",
|
|
strlen("Dummy-Summaryview")+1);
|
|
} else if (info == TARGET_MAIL_CM_PATH_LIST) {
|
|
/* content: folder_item_identifier\nmsgid1\nmsgid2\nmsgid3 */
|
|
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GList *cur;
|
|
MsgInfo *msginfo;
|
|
gchar *path_list = NULL;
|
|
|
|
/* identifier */
|
|
if(GTK_CMCLIST(ctree)->selection != NULL) {
|
|
msginfo = gtk_cmctree_node_get_row_data(ctree, GTK_CMCTREE_NODE(GTK_CMCLIST(ctree)->selection->data));
|
|
if(msginfo && msginfo->folder)
|
|
path_list = folder_item_get_identifier(msginfo->folder);
|
|
}
|
|
|
|
for (cur = GTK_CMCLIST(ctree)->selection;
|
|
cur != NULL && cur->data != NULL; cur = cur->next) {
|
|
gchar *tmp;
|
|
|
|
msginfo = gtk_cmctree_node_get_row_data(ctree, GTK_CMCTREE_NODE(cur->data));
|
|
if(!msginfo)
|
|
continue;
|
|
tmp = path_list;
|
|
path_list = g_strconcat(path_list, "\n", (msginfo->msgid ? msginfo->msgid : "unknown"), NULL);
|
|
g_free(tmp);
|
|
}
|
|
|
|
if (path_list != NULL) {
|
|
gtk_selection_data_set(selection_data,
|
|
gtk_selection_data_get_target(selection_data), 8,
|
|
path_list, strlen(path_list));
|
|
g_free(path_list);
|
|
}
|
|
}
|
|
}
|
|
|
|
static gboolean summary_drag_motion_cb(GtkWidget *widget,
|
|
GdkDragContext *context,
|
|
gint x,
|
|
gint y,
|
|
guint time,
|
|
SummaryView *summaryview)
|
|
{
|
|
FolderItem *item = summaryview->folder_item;
|
|
if (!(item && item->folder && folder_item_parent(item) != NULL
|
|
&& FOLDER_CLASS(item->folder)->add_msg != NULL)) {
|
|
gdk_drag_status(context, 0, time);
|
|
return FALSE;
|
|
} else if (gtk_drag_get_source_widget(context) ==
|
|
mainwindow_get_mainwindow()->folderview->ctree) {
|
|
/* no folders */
|
|
gdk_drag_status(context, 0, time);
|
|
return FALSE;
|
|
} else if (gtk_drag_get_source_widget(context) ==
|
|
summaryview->ctree) {
|
|
/* not from same folder */
|
|
gdk_drag_status(context, 0, time);
|
|
return FALSE;
|
|
} else {
|
|
gdk_drag_status(context, GDK_ACTION_COPY, time);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
static void summary_drag_data_received(GtkWidget *widget,
|
|
GdkDragContext *drag_context,
|
|
gint x,
|
|
gint y,
|
|
GtkSelectionData *data,
|
|
guint info,
|
|
guint time,
|
|
SummaryView *summaryview)
|
|
{
|
|
if (info == TARGET_MAIL_URI_LIST) {
|
|
FolderItem *item = summaryview->folder_item;
|
|
if (!item) {
|
|
gtk_drag_finish(drag_context, FALSE, FALSE, time);
|
|
return;
|
|
} else {
|
|
folderview_finish_dnd(gtk_selection_data_get_data(data),
|
|
drag_context, time, item);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* custom compare functions for sorting */
|
|
|
|
static gint summary_cmp_by_date(GtkCMCList *clist,
|
|
gconstpointer ptr1, gconstpointer ptr2)
|
|
{
|
|
MsgInfo *msginfo1 = ((GtkCMCListRow *)ptr1)->data;
|
|
MsgInfo *msginfo2 = ((GtkCMCListRow *)ptr2)->data;
|
|
gint res;
|
|
if (!msginfo1 || !msginfo2)
|
|
return -1;
|
|
|
|
res = (msginfo1->date_t - msginfo2->date_t);
|
|
if (res == 0)
|
|
res = msginfo1->msgnum - msginfo2->msgnum;
|
|
return res;
|
|
}
|
|
|
|
#define CMP_FUNC_DEF(func_name, val) \
|
|
static gint func_name(GtkCMCList *clist, \
|
|
gconstpointer ptr1, gconstpointer ptr2) \
|
|
{ \
|
|
MsgInfo *msginfo1 = ((GtkCMCListRow *)ptr1)->data; \
|
|
MsgInfo *msginfo2 = ((GtkCMCListRow *)ptr2)->data; \
|
|
gint res; \
|
|
if (!msginfo1 || !msginfo2) \
|
|
return -1; \
|
|
\
|
|
res = (val); \
|
|
return (res != 0) ? res:summary_cmp_by_date(clist, ptr1, ptr2); \
|
|
}
|
|
|
|
CMP_FUNC_DEF(summary_cmp_by_mark,
|
|
MSG_IS_MARKED(msginfo1->flags) - MSG_IS_MARKED(msginfo2->flags))
|
|
CMP_FUNC_DEF(summary_cmp_by_status,
|
|
(-(MSG_IS_SPAM(msginfo1->flags))+(MSG_IS_UNREAD(msginfo1->flags)<<1)+(MSG_IS_NEW(msginfo1->flags)<<2))
|
|
- (-(MSG_IS_SPAM(msginfo2->flags))+(MSG_IS_UNREAD(msginfo2->flags)<<1)+(MSG_IS_NEW(msginfo2->flags)<<2)) )
|
|
CMP_FUNC_DEF(summary_cmp_by_mime,
|
|
MSG_IS_WITH_ATTACHMENT(msginfo1->flags) - MSG_IS_WITH_ATTACHMENT(msginfo2->flags))
|
|
CMP_FUNC_DEF(summary_cmp_by_label,
|
|
MSG_GET_COLORLABEL(msginfo1->flags) -
|
|
MSG_GET_COLORLABEL(msginfo2->flags))
|
|
CMP_FUNC_DEF(summary_cmp_by_locked,
|
|
MSG_IS_LOCKED(msginfo1->flags) - MSG_IS_LOCKED(msginfo2->flags))
|
|
|
|
CMP_FUNC_DEF(summary_cmp_by_num, msginfo1->msgnum - msginfo2->msgnum)
|
|
CMP_FUNC_DEF(summary_cmp_by_size, msginfo1->size - msginfo2->size)
|
|
|
|
#undef CMP_FUNC_DEF
|
|
|
|
static gint summary_cmp_by_subject(GtkCMCList *clist,
|
|
gconstpointer ptr1,
|
|
gconstpointer ptr2)
|
|
{
|
|
MsgInfo *msginfo1 = ((GtkCMCListRow *)ptr1)->data;
|
|
MsgInfo *msginfo2 = ((GtkCMCListRow *)ptr2)->data;
|
|
gint res;
|
|
|
|
if (!msginfo1->subject)
|
|
return (msginfo2->subject != NULL);
|
|
if (!msginfo2->subject)
|
|
return -1;
|
|
|
|
res = subject_compare_for_sort
|
|
(msginfo1->subject, msginfo2->subject);
|
|
return (res != 0)? res: summary_cmp_by_date(clist, ptr1, ptr2);
|
|
}
|
|
|
|
static gint summary_cmp_by_thread_date(GtkCMCList *clist,
|
|
gconstpointer ptr1,
|
|
gconstpointer ptr2)
|
|
{
|
|
MsgInfo *msginfo1 = ((GtkCMCListRow *)ptr1)->data;
|
|
MsgInfo *msginfo2 = ((GtkCMCListRow *)ptr2)->data;
|
|
gint thread_diff = msginfo1->thread_date - msginfo2->thread_date;
|
|
|
|
if (msginfo1->thread_date > 0 && msginfo2->thread_date > 0)
|
|
return thread_diff;
|
|
else
|
|
return msginfo1->date_t - msginfo2->date_t;
|
|
}
|
|
|
|
static gint summary_cmp_by_from(GtkCMCList *clist, gconstpointer ptr1,
|
|
gconstpointer ptr2)
|
|
{
|
|
const gchar *str1, *str2;
|
|
const GtkCMCListRow *r1 = (const GtkCMCListRow *) ptr1;
|
|
const GtkCMCListRow *r2 = (const GtkCMCListRow *) ptr2;
|
|
MsgInfo *msginfo1 = ((GtkCMCListRow *)ptr1)->data;
|
|
MsgInfo *msginfo2 = ((GtkCMCListRow *)ptr2)->data;
|
|
const SummaryView *sv = g_object_get_data(G_OBJECT(clist), "summaryview");
|
|
gint res;
|
|
|
|
cm_return_val_if_fail(sv, -1);
|
|
if (sv->col_state[sv->col_pos[S_COL_FROM]].visible) {
|
|
str1 = GTK_CMCELL_TEXT(r1->cell[sv->col_pos[S_COL_FROM]])->text;
|
|
str2 = GTK_CMCELL_TEXT(r2->cell[sv->col_pos[S_COL_FROM]])->text;
|
|
} else {
|
|
str1 = msginfo1->from;
|
|
str2 = msginfo2->from;
|
|
}
|
|
|
|
if (!str1)
|
|
return str2 != NULL;
|
|
|
|
if (!str2)
|
|
return -1;
|
|
|
|
res = g_utf8_collate(str1, str2);
|
|
return (res != 0)? res: summary_cmp_by_date(clist, ptr1, ptr2);
|
|
}
|
|
|
|
static gint summary_cmp_by_to(GtkCMCList *clist, gconstpointer ptr1,
|
|
gconstpointer ptr2)
|
|
{
|
|
const gchar *str1, *str2;
|
|
const GtkCMCListRow *r1 = (const GtkCMCListRow *) ptr1;
|
|
const GtkCMCListRow *r2 = (const GtkCMCListRow *) ptr2;
|
|
MsgInfo *msginfo1 = ((GtkCMCListRow *)ptr1)->data;
|
|
MsgInfo *msginfo2 = ((GtkCMCListRow *)ptr2)->data;
|
|
const SummaryView *sv = g_object_get_data(G_OBJECT(clist), "summaryview");
|
|
gint res;
|
|
cm_return_val_if_fail(sv, -1);
|
|
|
|
if (sv->col_state[sv->col_pos[S_COL_TO]].visible) {
|
|
str1 = GTK_CMCELL_TEXT(r1->cell[sv->col_pos[S_COL_TO]])->text;
|
|
str2 = GTK_CMCELL_TEXT(r2->cell[sv->col_pos[S_COL_TO]])->text;
|
|
} else {
|
|
str1 = msginfo1->to;
|
|
str2 = msginfo2->to;
|
|
}
|
|
|
|
if (!str1)
|
|
return str2 != NULL;
|
|
|
|
if (!str2)
|
|
return -1;
|
|
|
|
res = g_utf8_collate(str1, str2);
|
|
return (res != 0)? res: summary_cmp_by_date(clist, ptr1, ptr2);
|
|
}
|
|
|
|
static gint summary_cmp_by_tags(GtkCMCList *clist, gconstpointer ptr1,
|
|
gconstpointer ptr2)
|
|
{
|
|
gchar *str1, *str2;
|
|
const GtkCMCListRow *r1 = (const GtkCMCListRow *) ptr1;
|
|
const GtkCMCListRow *r2 = (const GtkCMCListRow *) ptr2;
|
|
const SummaryView *sv = g_object_get_data(G_OBJECT(clist), "summaryview");
|
|
MsgInfo *msginfo1 = ((GtkCMCListRow *)ptr1)->data;
|
|
MsgInfo *msginfo2 = ((GtkCMCListRow *)ptr2)->data;
|
|
gint res;
|
|
cm_return_val_if_fail(sv, -1);
|
|
|
|
if (sv->col_state[sv->col_pos[S_COL_TAGS]].visible) {
|
|
str1 = g_strdup(GTK_CMCELL_TEXT(r1->cell[sv->col_pos[S_COL_TAGS]])->text);
|
|
str2 = g_strdup(GTK_CMCELL_TEXT(r2->cell[sv->col_pos[S_COL_TAGS]])->text);
|
|
} else {
|
|
str1 = procmsg_msginfo_get_tags_str(msginfo1);
|
|
str2 = procmsg_msginfo_get_tags_str(msginfo2);
|
|
}
|
|
|
|
if (!str1) {
|
|
res = (str2 != NULL);
|
|
g_free(str2);
|
|
return res;
|
|
}
|
|
if (!str2) {
|
|
g_free(str1);
|
|
return -1;
|
|
}
|
|
|
|
res = g_utf8_collate(str1, str2);
|
|
g_free(str1);
|
|
g_free(str2);
|
|
return (res != 0)? res: summary_cmp_by_date(clist, ptr1, ptr2);
|
|
}
|
|
|
|
static gint summary_cmp_by_simplified_subject
|
|
(GtkCMCList *clist, gconstpointer ptr1, gconstpointer ptr2)
|
|
{
|
|
const FolderItemPrefs *prefs;
|
|
const gchar *str1, *str2;
|
|
const GtkCMCListRow *r1 = (const GtkCMCListRow *) ptr1;
|
|
const GtkCMCListRow *r2 = (const GtkCMCListRow *) ptr2;
|
|
const MsgInfo *msginfo1 = r1->data;
|
|
const MsgInfo *msginfo2 = r2->data;
|
|
const SummaryView *sv = g_object_get_data(G_OBJECT(clist), "summaryview");
|
|
gint res;
|
|
|
|
cm_return_val_if_fail(sv, -1);
|
|
cm_return_val_if_fail(msginfo1 != NULL && msginfo2 != NULL, -1);
|
|
|
|
if (sv->col_state[sv->col_pos[S_COL_SUBJECT]].visible) {
|
|
str1 = GTK_CMCELL_TEXT(r1->cell[sv->col_pos[S_COL_SUBJECT]])->text;
|
|
str2 = GTK_CMCELL_TEXT(r2->cell[sv->col_pos[S_COL_SUBJECT]])->text;
|
|
} else {
|
|
str1 = msginfo1->subject;
|
|
str2 = msginfo2->subject;
|
|
}
|
|
|
|
if (!str1)
|
|
return str2 != NULL;
|
|
|
|
if (!str2)
|
|
return -1;
|
|
|
|
prefs = msginfo1->folder->prefs;
|
|
if (!prefs)
|
|
prefs = msginfo2->folder->prefs;
|
|
if (!prefs)
|
|
return -1;
|
|
|
|
res = subject_compare_for_sort(str1, str2);
|
|
return (res != 0)? res: summary_cmp_by_date(clist, ptr1, ptr2);
|
|
}
|
|
|
|
static gint summary_cmp_by_score(GtkCMCList *clist,
|
|
gconstpointer ptr1, gconstpointer ptr2)
|
|
{
|
|
MsgInfo *msginfo1 = ((GtkCMCListRow *)ptr1)->data;
|
|
MsgInfo *msginfo2 = ((GtkCMCListRow *)ptr2)->data;
|
|
int diff;
|
|
|
|
/* if score are equal, sort by date */
|
|
|
|
diff = msginfo1->score - msginfo2->score;
|
|
if (diff != 0)
|
|
return diff;
|
|
else
|
|
return summary_cmp_by_date(clist, ptr1, ptr2);
|
|
}
|
|
|
|
static void summary_ignore_thread_func_mark_unread(GtkCMCTree *ctree, GtkCMCTreeNode *row, gpointer data)
|
|
{
|
|
MsgInfo *msginfo;
|
|
|
|
msginfo = gtk_cmctree_node_get_row_data(ctree, row);
|
|
cm_return_if_fail(msginfo);
|
|
|
|
summary_msginfo_unset_flags(msginfo, MSG_WATCH_THREAD, 0);
|
|
summary_msginfo_change_flags(msginfo, MSG_IGNORE_THREAD, 0, MSG_NEW | MSG_UNREAD, 0);
|
|
|
|
debug_print("Message %d is marked as ignore thread\n", msginfo->msgnum);
|
|
}
|
|
|
|
static void summary_ignore_thread_func_set_row(GtkCMCTree *ctree, GtkCMCTreeNode *row, gpointer data)
|
|
{
|
|
SummaryView *summaryview = (SummaryView *) data;
|
|
MsgInfo *msginfo;
|
|
|
|
msginfo = gtk_cmctree_node_get_row_data(ctree, row);
|
|
cm_return_if_fail(msginfo);
|
|
|
|
summary_set_row_marks(summaryview, row);
|
|
debug_print("Message %d update in row view\n", msginfo->msgnum);
|
|
}
|
|
|
|
void summary_ignore_thread(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GList *cur;
|
|
gboolean froze = FALSE;
|
|
|
|
START_LONG_OPERATION(summaryview, FALSE);
|
|
for (cur = GTK_CMCLIST(ctree)->selection; cur != NULL && cur->data != NULL; cur = cur->next)
|
|
gtk_cmctree_pre_recursive(ctree, GTK_CMCTREE_NODE(cur->data),
|
|
GTK_CMCTREE_FUNC(summary_ignore_thread_func_mark_unread),
|
|
summaryview);
|
|
|
|
for (cur = GTK_CMCLIST(ctree)->selection; cur != NULL && cur->data != NULL; cur = cur->next)
|
|
gtk_cmctree_pre_recursive(ctree, GTK_CMCTREE_NODE(cur->data),
|
|
GTK_CMCTREE_FUNC(summary_ignore_thread_func_set_row),
|
|
summaryview);
|
|
|
|
END_LONG_OPERATION(summaryview);
|
|
|
|
summary_status_show(summaryview);
|
|
}
|
|
|
|
static void summary_unignore_thread_func(GtkCMCTree *ctree, GtkCMCTreeNode *row, gpointer data)
|
|
{
|
|
SummaryView *summaryview = (SummaryView *) data;
|
|
MsgInfo *msginfo;
|
|
|
|
msginfo = gtk_cmctree_node_get_row_data(ctree, row);
|
|
cm_return_if_fail(msginfo);
|
|
|
|
summary_msginfo_unset_flags(msginfo, MSG_IGNORE_THREAD, 0);
|
|
|
|
summary_set_row_marks(summaryview, row);
|
|
debug_print("Message %d is marked as unignore thread\n",
|
|
msginfo->msgnum);
|
|
}
|
|
|
|
void summary_unignore_thread(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GList *cur;
|
|
gboolean froze = FALSE;
|
|
|
|
START_LONG_OPERATION(summaryview, FALSE);
|
|
for (cur = GTK_CMCLIST(ctree)->selection; cur != NULL && cur->data != NULL; cur = cur->next)
|
|
gtk_cmctree_pre_recursive(ctree, GTK_CMCTREE_NODE(cur->data),
|
|
GTK_CMCTREE_FUNC(summary_unignore_thread_func),
|
|
summaryview);
|
|
|
|
END_LONG_OPERATION(summaryview);
|
|
|
|
summary_status_show(summaryview);
|
|
}
|
|
|
|
static void summary_check_ignore_thread_func
|
|
(GtkCMCTree *ctree, GtkCMCTreeNode *row, gpointer data)
|
|
{
|
|
MsgInfo *msginfo;
|
|
gint *found_ignore = (gint *) data;
|
|
|
|
if (*found_ignore) return;
|
|
else {
|
|
msginfo = gtk_cmctree_node_get_row_data(ctree, row);
|
|
*found_ignore = msginfo && MSG_IS_IGNORE_THREAD(msginfo->flags);
|
|
}
|
|
}
|
|
|
|
void summary_toggle_ignore_thread(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GList *cur;
|
|
gint found_ignore = 0;
|
|
|
|
for (cur = GTK_CMCLIST(ctree)->selection; cur != NULL && cur->data != NULL; cur = cur->next)
|
|
gtk_cmctree_pre_recursive(ctree, GTK_CMCTREE_NODE(cur->data),
|
|
GTK_CMCTREE_FUNC(summary_check_ignore_thread_func),
|
|
&found_ignore);
|
|
|
|
if (found_ignore)
|
|
summary_unignore_thread(summaryview);
|
|
else
|
|
summary_ignore_thread(summaryview);
|
|
}
|
|
|
|
static void summary_watch_thread_func(GtkCMCTree *ctree, GtkCMCTreeNode *row, gpointer data)
|
|
{
|
|
SummaryView *summaryview = (SummaryView *) data;
|
|
MsgInfo *msginfo;
|
|
|
|
msginfo = gtk_cmctree_node_get_row_data(ctree, row);
|
|
cm_return_if_fail(msginfo);
|
|
|
|
summary_msginfo_change_flags(msginfo, MSG_WATCH_THREAD, 0, MSG_IGNORE_THREAD, 0);
|
|
|
|
summary_set_row_marks(summaryview, row);
|
|
debug_print("Message %d is marked as watch thread\n",
|
|
msginfo->msgnum);
|
|
}
|
|
|
|
void summary_watch_thread(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GList *cur;
|
|
gboolean froze = FALSE;
|
|
|
|
START_LONG_OPERATION(summaryview, FALSE);
|
|
for (cur = GTK_CMCLIST(ctree)->selection; cur != NULL && cur->data != NULL; cur = cur->next)
|
|
gtk_cmctree_pre_recursive(ctree, GTK_CMCTREE_NODE(cur->data),
|
|
GTK_CMCTREE_FUNC(summary_watch_thread_func),
|
|
summaryview);
|
|
|
|
END_LONG_OPERATION(summaryview);
|
|
|
|
summary_status_show(summaryview);
|
|
}
|
|
|
|
static void summary_unwatch_thread_func(GtkCMCTree *ctree, GtkCMCTreeNode *row, gpointer data)
|
|
{
|
|
SummaryView *summaryview = (SummaryView *) data;
|
|
MsgInfo *msginfo;
|
|
|
|
msginfo = gtk_cmctree_node_get_row_data(ctree, row);
|
|
cm_return_if_fail(msginfo);
|
|
|
|
summary_msginfo_unset_flags(msginfo, MSG_WATCH_THREAD, 0);
|
|
|
|
summary_set_row_marks(summaryview, row);
|
|
debug_print("Message %d is marked as unwatch thread\n",
|
|
msginfo->msgnum);
|
|
}
|
|
|
|
void summary_unwatch_thread(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GList *cur;
|
|
gboolean froze = FALSE;
|
|
|
|
START_LONG_OPERATION(summaryview, FALSE);
|
|
for (cur = GTK_CMCLIST(ctree)->selection; cur != NULL && cur->data != NULL; cur = cur->next)
|
|
gtk_cmctree_pre_recursive(ctree, GTK_CMCTREE_NODE(cur->data),
|
|
GTK_CMCTREE_FUNC(summary_unwatch_thread_func),
|
|
summaryview);
|
|
|
|
END_LONG_OPERATION(summaryview);
|
|
|
|
summary_status_show(summaryview);
|
|
}
|
|
|
|
static void summary_check_watch_thread_func
|
|
(GtkCMCTree *ctree, GtkCMCTreeNode *row, gpointer data)
|
|
{
|
|
MsgInfo *msginfo;
|
|
gint *found_watch = (gint *) data;
|
|
|
|
if (*found_watch) return;
|
|
else {
|
|
msginfo = gtk_cmctree_node_get_row_data(ctree, row);
|
|
*found_watch = msginfo && MSG_IS_WATCH_THREAD(msginfo->flags);
|
|
}
|
|
}
|
|
|
|
void summary_toggle_watch_thread(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
|
|
GList *cur;
|
|
gint found_watch = 0;
|
|
|
|
for (cur = GTK_CMCLIST(ctree)->selection; cur != NULL && cur->data != NULL; cur = cur->next)
|
|
gtk_cmctree_pre_recursive(ctree, GTK_CMCTREE_NODE(cur->data),
|
|
GTK_CMCTREE_FUNC(summary_check_watch_thread_func),
|
|
&found_watch);
|
|
|
|
if (found_watch)
|
|
summary_unwatch_thread(summaryview);
|
|
else
|
|
summary_watch_thread(summaryview);
|
|
}
|
|
|
|
|
|
void summary_toggle_show_read_messages(SummaryView *summaryview)
|
|
{
|
|
FolderItemUpdateData source;
|
|
if (summaryview->folder_item->hide_read_msgs)
|
|
summaryview->folder_item->hide_read_msgs = 0;
|
|
else
|
|
summaryview->folder_item->hide_read_msgs = 1;
|
|
|
|
source.item = summaryview->folder_item;
|
|
source.update_flags = F_ITEM_UPDATE_NAME;
|
|
source.msg = NULL;
|
|
hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &source);
|
|
summary_show(summaryview, summaryview->folder_item);
|
|
}
|
|
|
|
void summary_toggle_show_del_messages(SummaryView *summaryview)
|
|
{
|
|
FolderItemUpdateData source;
|
|
if (summaryview->folder_item->hide_del_msgs)
|
|
summaryview->folder_item->hide_del_msgs = 0;
|
|
else
|
|
summaryview->folder_item->hide_del_msgs = 1;
|
|
|
|
source.item = summaryview->folder_item;
|
|
source.update_flags = F_ITEM_UPDATE_NAME;
|
|
source.msg = NULL;
|
|
hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &source);
|
|
summary_show(summaryview, summaryview->folder_item);
|
|
}
|
|
|
|
void summary_toggle_show_read_threads(SummaryView *summaryview)
|
|
{
|
|
FolderItemUpdateData source;
|
|
if (summaryview->folder_item->hide_read_threads)
|
|
summaryview->folder_item->hide_read_threads = 0;
|
|
else
|
|
summaryview->folder_item->hide_read_threads = 1;
|
|
|
|
source.item = summaryview->folder_item;
|
|
source.update_flags = F_ITEM_UPDATE_NAME;
|
|
source.msg = NULL;
|
|
hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &source);
|
|
summary_show(summaryview, summaryview->folder_item);
|
|
}
|
|
|
|
static void summary_set_hide_menu (SummaryView *summaryview,
|
|
const gchar *menu_item,
|
|
guint action)
|
|
{
|
|
GtkWidget *widget;
|
|
|
|
widget = gtk_ui_manager_get_widget(summaryview->mainwin->ui_manager, menu_item);
|
|
cm_return_if_fail(widget != NULL);
|
|
|
|
g_object_set_data(G_OBJECT(widget), "dont_toggle",
|
|
GINT_TO_POINTER(1));
|
|
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM(widget), action);
|
|
g_object_set_data(G_OBJECT(widget), "dont_toggle",
|
|
GINT_TO_POINTER(0));
|
|
}
|
|
|
|
void summary_reflect_prefs_pixmap_theme(SummaryView *summaryview)
|
|
{
|
|
GtkWidget *pixmap;
|
|
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_MARK, &markxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_DELETED, &deletedxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_NEW, &newxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_UNREAD, &unreadxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_REPLIED, &repliedxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_FORWARDED, &forwardedxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_REPLIED_AND_FORWARDED, &repliedandforwardedxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_CLIP, &clipxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_LOCKED, &lockedxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_IGNORETHREAD, &ignorethreadxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_WATCHTHREAD, &watchthreadxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_CLIP_KEY, &clipkeyxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_KEY, &keyxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_KEY_SIGN, &keysignxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_GPG_SIGNED, &gpgsignedxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_CLIP_GPG_SIGNED, &clipgpgsignedxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_SPAM, &spamxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_MOVED, &movedxpm);
|
|
stock_pixbuf_gdk(STOCK_PIXMAP_COPIED, &copiedxpm);
|
|
|
|
summary_set_folder_pixmap(summaryview, STOCK_PIXMAP_DIR_OPEN);
|
|
|
|
pixmap = stock_pixmap_widget(STOCK_PIXMAP_QUICKSEARCH);
|
|
gtk_container_remove (GTK_CONTAINER(summaryview->toggle_search),
|
|
summaryview->quick_search_pixmap);
|
|
gtk_container_add(GTK_CONTAINER(summaryview->toggle_search), pixmap);
|
|
gtk_widget_show(pixmap);
|
|
summaryview->quick_search_pixmap = pixmap;
|
|
|
|
#ifdef GENERIC_UMPC
|
|
pixmap = stock_pixmap_widget(STOCK_PIXMAP_SELECTION);
|
|
gtk_container_remove (GTK_CONTAINER(summaryview->multiple_sel_togbtn),
|
|
summaryview->multiple_sel_image);
|
|
gtk_container_add(GTK_CONTAINER(summaryview->multiple_sel_togbtn), pixmap);
|
|
gtk_widget_show(pixmap);
|
|
summaryview->multiple_sel_togbtn = pixmap;
|
|
#endif
|
|
|
|
folderview_unselect(summaryview->folderview);
|
|
folderview_select(summaryview->folderview, summaryview->folder_item);
|
|
summary_set_column_titles(summaryview);
|
|
}
|
|
|
|
void summary_reflect_prefs_custom_colors(SummaryView *summaryview)
|
|
{
|
|
GtkMenuShell *menu;
|
|
GList *children, *cur;
|
|
|
|
/* re-create colorlabel submenu */
|
|
menu = GTK_MENU_SHELL(summaryview->colorlabel_menu);
|
|
cm_return_if_fail(menu != NULL);
|
|
|
|
/* clear items. get item pointers. */
|
|
children = gtk_container_get_children(GTK_CONTAINER(menu));
|
|
for (cur = children; cur != NULL && cur->data != NULL; cur = cur->next) {
|
|
g_signal_handlers_disconnect_matched
|
|
(gtk_ui_manager_get_accel_group(summaryview->mainwin->ui_manager),
|
|
G_SIGNAL_MATCH_DATA|G_SIGNAL_MATCH_FUNC,
|
|
0, 0, NULL, mainwin_accel_changed_cb, cur->data);
|
|
gtk_menu_item_set_submenu(GTK_MENU_ITEM(cur->data), NULL);
|
|
}
|
|
g_list_free(children);
|
|
summary_colorlabel_menu_create(summaryview, TRUE);
|
|
}
|
|
|
|
/*
|
|
* Harvest addresses for selected messages in summary view.
|
|
*/
|
|
void summary_harvest_address(SummaryView *summaryview)
|
|
{
|
|
GtkCMCTree *ctree = GTK_CMCTREE( summaryview->ctree );
|
|
GList *cur;
|
|
GList *msgList;
|
|
MsgInfo *msginfo;
|
|
|
|
msgList = NULL;
|
|
for( cur = GTK_CMCLIST(ctree)->selection; cur != NULL && cur->data != NULL; cur = cur->next ) {
|
|
msginfo = gtk_cmctree_node_get_row_data( ctree, GTK_CMCTREE_NODE(cur->data) );
|
|
if (!msginfo)
|
|
continue;
|
|
msgList = g_list_append( msgList, GUINT_TO_POINTER( msginfo->msgnum ) );
|
|
}
|
|
|
|
addressbook_harvest( summaryview->folder_item, TRUE, msgList );
|
|
|
|
g_list_free( msgList );
|
|
}
|
|
|
|
static regex_t *summary_compile_simplify_regexp(gchar *simplify_subject_regexp)
|
|
{
|
|
int err;
|
|
gchar buf[BUFFSIZE];
|
|
regex_t *preg = NULL;
|
|
|
|
preg = g_new0(regex_t, 1);
|
|
|
|
err = string_match_precompile(simplify_subject_regexp,
|
|
preg, REG_EXTENDED);
|
|
if (err) {
|
|
regerror(err, preg, buf, BUFFSIZE);
|
|
alertpanel_error(_("Regular expression (regexp) error:\n%s"), buf);
|
|
g_free(preg);
|
|
preg = NULL;
|
|
}
|
|
|
|
return preg;
|
|
}
|
|
void summary_set_prefs_from_folderitem(SummaryView *summaryview, FolderItem *item)
|
|
{
|
|
FolderSortKey sort_key;
|
|
FolderSortType sort_type;
|
|
cm_return_if_fail(summaryview != NULL);
|
|
cm_return_if_fail(item != NULL);
|
|
|
|
/* Subject simplification */
|
|
if(summaryview->simplify_subject_preg) {
|
|
regfree(summaryview->simplify_subject_preg);
|
|
g_free(summaryview->simplify_subject_preg);
|
|
summaryview->simplify_subject_preg = NULL;
|
|
}
|
|
if(item->prefs && item->prefs->simplify_subject_regexp &&
|
|
item->prefs->simplify_subject_regexp[0] && item->prefs->enable_simplify_subject)
|
|
summaryview->simplify_subject_preg = summary_compile_simplify_regexp(item->prefs->simplify_subject_regexp);
|
|
|
|
/* Sorting */
|
|
sort_key = item->sort_key;
|
|
sort_type = item->sort_type;
|
|
|
|
folder_get_sort_type(item->folder, &sort_key, &sort_type);
|
|
|
|
summaryview->sort_key = sort_key;
|
|
summaryview->sort_type = sort_type;
|
|
|
|
/* Threading */
|
|
summaryview->threaded = item->threaded;
|
|
summaryview->thread_collapsed = item->thread_collapsed;
|
|
|
|
/* Scoring */
|
|
}
|
|
|
|
void summary_save_prefs_to_folderitem(SummaryView *summaryview, FolderItem *item)
|
|
{
|
|
/* Sorting */
|
|
item->sort_key = summaryview->sort_key;
|
|
item->sort_type = summaryview->sort_type;
|
|
|
|
/* Threading */
|
|
item->threaded = summaryview->threaded;
|
|
item->thread_collapsed = summaryview->thread_collapsed;
|
|
}
|
|
|
|
static gboolean summary_update_msg(gpointer source, gpointer data)
|
|
{
|
|
MsgInfoUpdate *msginfo_update = (MsgInfoUpdate *) source;
|
|
SummaryView *summaryview = (SummaryView *)data;
|
|
GtkCMCTreeNode *node;
|
|
|
|
cm_return_val_if_fail(msginfo_update != NULL, TRUE);
|
|
cm_return_val_if_fail(summaryview != NULL, FALSE);
|
|
|
|
if (msginfo_update->msginfo->folder != summaryview->folder_item)
|
|
return FALSE;
|
|
|
|
if (msginfo_update->flags & MSGINFO_UPDATE_FLAGS) {
|
|
node = gtk_cmctree_find_by_row_data(
|
|
GTK_CMCTREE(summaryview->ctree), NULL,
|
|
msginfo_update->msginfo);
|
|
|
|
if (node)
|
|
summary_set_row_marks(summaryview, node);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void summary_update_unread(SummaryView *summaryview, FolderItem *removed_item)
|
|
{
|
|
guint new, unread, unreadmarked, marked, total;
|
|
guint replied, forwarded, locked, ignored, watched;
|
|
static gboolean tips_initialized = FALSE;
|
|
|
|
if (prefs_common.layout_mode != SMALL_LAYOUT) {
|
|
if (tips_initialized) {
|
|
summary_set_folder_pixmap(summaryview, STOCK_PIXMAP_DIR_OPEN);
|
|
CLAWS_SET_TIP(summaryview->folder_pixmap_eventbox,
|
|
NULL);
|
|
tips_initialized = FALSE;
|
|
}
|
|
return;
|
|
}
|
|
folder_count_total_msgs(&new, &unread, &unreadmarked, &marked, &total,
|
|
&replied, &forwarded, &locked, &ignored,
|
|
&watched);
|
|
if (removed_item) {
|
|
total -= removed_item->total_msgs;
|
|
new -= removed_item->new_msgs;
|
|
unread -= removed_item->unread_msgs;
|
|
}
|
|
|
|
if (new > 0 || unread > 0) {
|
|
tips_initialized = TRUE;
|
|
summary_set_folder_pixmap(summaryview, STOCK_PIXMAP_DIR_OPEN_HRM);
|
|
CLAWS_SET_TIP(summaryview->folder_pixmap_eventbox,
|
|
_("Go back to the folder list (You have unread messages)"));
|
|
} else {
|
|
tips_initialized = TRUE;
|
|
summary_set_folder_pixmap(summaryview, STOCK_PIXMAP_DIR_OPEN);
|
|
CLAWS_SET_TIP(summaryview->folder_pixmap_eventbox,
|
|
_("Go back to the folder list"));
|
|
}
|
|
}
|
|
|
|
static gboolean summary_update_folder_item_hook(gpointer source, gpointer data)
|
|
{
|
|
FolderItemUpdateData *hookdata = (FolderItemUpdateData *)source;
|
|
SummaryView *summaryview = (SummaryView *)data;
|
|
|
|
cm_return_val_if_fail(hookdata != NULL, FALSE);
|
|
cm_return_val_if_fail(hookdata->item != NULL, FALSE);
|
|
cm_return_val_if_fail(summaryview != NULL, FALSE);
|
|
|
|
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);
|
|
}
|
|
summary_update_unread(summaryview, NULL);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean summary_update_folder_hook(gpointer source, gpointer data)
|
|
{
|
|
FolderUpdateData *hookdata;
|
|
SummaryView *summaryview = (SummaryView *)data;
|
|
hookdata = source;
|
|
if (hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM) {
|
|
summary_update_unread(summaryview, hookdata->item);
|
|
} else
|
|
summary_update_unread(summaryview, NULL);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*!
|
|
*\brief change summaryview to display your answer(s) to a message
|
|
*
|
|
*\param summaryview The SummaryView ;)
|
|
*\param msginfo The message for which answers are searched
|
|
*
|
|
*/
|
|
static void summary_find_answers (SummaryView *summaryview, MsgInfo *msg)
|
|
{
|
|
FolderItem *sent_folder = NULL;
|
|
PrefsAccount *account = NULL;
|
|
GtkCMCTreeNode *node = NULL;
|
|
char *buf = NULL;
|
|
if (msg == NULL || msg->msgid == NULL)
|
|
return;
|
|
|
|
account = account_get_reply_account(msg, prefs_common.reply_account_autosel);
|
|
if (account == NULL)
|
|
return;
|
|
sent_folder = account_get_special_folder
|
|
(account, F_OUTBOX);
|
|
|
|
buf = g_strdup_printf("inreplyto matchcase \"%s\"", msg->msgid);
|
|
|
|
if (sent_folder != summaryview->folder_item) {
|
|
folderview_select(summaryview->mainwin->folderview, sent_folder);
|
|
}
|
|
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(summaryview->toggle_search), TRUE);
|
|
|
|
quicksearch_set(summaryview->quicksearch, ADVANCED_SEARCH_EXTENDED, buf);
|
|
g_free(buf);
|
|
|
|
node = gtk_cmctree_node_nth(GTK_CMCTREE(summaryview->ctree), 0);
|
|
if (node)
|
|
summary_select_node(summaryview, node, OPEN_SELECTED_ON_SEARCH_RESULTS);
|
|
}
|
|
|
|
gint summaryview_export_mbox_list(SummaryView *summaryview)
|
|
/* return values: -2 skipped, -1 error, 0 OK */
|
|
{
|
|
GSList *list = summary_get_selected_msg_list(summaryview);
|
|
gchar *mbox = filesel_select_file_save(_("Export to mbox file"), NULL);
|
|
gint ret;
|
|
|
|
if (mbox == NULL)
|
|
return -2;
|
|
if (list == NULL)
|
|
return -1;
|
|
|
|
ret = export_list_to_mbox(list, mbox);
|
|
|
|
g_slist_free(list);
|
|
g_free(mbox);
|
|
|
|
return ret;
|
|
}
|
|
|
|
void summaryview_lock(SummaryView *summaryview, FolderItem *item)
|
|
{
|
|
if (!summaryview || !summaryview->folder_item || !item) {
|
|
return;
|
|
}
|
|
|
|
if (summaryview->folder_item->folder == item->folder) {
|
|
gtk_widget_set_sensitive(summaryview->ctree, FALSE);
|
|
}
|
|
}
|
|
void summaryview_unlock(SummaryView *summaryview, FolderItem *item)
|
|
{
|
|
gtk_widget_set_sensitive(summaryview->ctree, TRUE);
|
|
}
|
|
|
|
#define DO_ACTION(name, act) { if (!strcmp(a_name, name)) action = act; }
|
|
static void summary_reply_cb(GtkAction *gaction, gpointer data)
|
|
{
|
|
SummaryView *summaryview = (SummaryView *)data;
|
|
GSList *msginfo_list = NULL;
|
|
gint action = COMPOSE_REPLY;
|
|
const gchar *a_name = gtk_action_get_name(gaction);
|
|
|
|
DO_ACTION("SummaryViewPopup/Reply", COMPOSE_REPLY);
|
|
DO_ACTION("SummaryViewPopup/ReplyTo/All", COMPOSE_REPLY_TO_ALL);
|
|
DO_ACTION("SummaryViewPopup/ReplyTo/Sender", COMPOSE_REPLY_TO_SENDER);
|
|
DO_ACTION("SummaryViewPopup/ReplyTo/List", COMPOSE_REPLY_TO_LIST);
|
|
DO_ACTION("SummaryViewPopup/Forward", COMPOSE_FORWARD_INLINE);
|
|
DO_ACTION("SummaryViewPopup/ForwardAtt", COMPOSE_FORWARD_AS_ATTACH);
|
|
DO_ACTION("SummaryViewPopup/Redirect", COMPOSE_REDIRECT);
|
|
|
|
msginfo_list = summary_get_selection(summaryview);
|
|
cm_return_if_fail(msginfo_list != NULL);
|
|
compose_reply_from_messageview(NULL, msginfo_list, action);
|
|
g_slist_free(msginfo_list);
|
|
}
|
|
|
|
gboolean summary_is_opened_message_selected(SummaryView *summaryview)
|
|
{
|
|
GList *sel = NULL;
|
|
|
|
cm_return_val_if_fail(summaryview != NULL, FALSE);
|
|
|
|
sel = GTK_CMCLIST(summaryview->ctree)->selection;
|
|
|
|
if (summaryview->displayed == NULL || sel == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
for ( ; sel != NULL; sel = sel->next) {
|
|
if (summaryview->displayed == GTK_CMCTREE_NODE(sel->data)) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
gboolean summary_has_opened_message(SummaryView *summaryview)
|
|
{
|
|
cm_return_val_if_fail(summaryview != NULL, FALSE);
|
|
|
|
return (summaryview->displayed != NULL);
|
|
}
|
|
|
|
static void summary_header_lock_sorting_cb(GtkAction *gaction, gpointer data)
|
|
{
|
|
SummaryView *summaryview = (SummaryView *)data;
|
|
gboolean sorting_lock = prefs_common_get_prefs()->summary_col_lock;
|
|
|
|
if (summaryview->header_menu_lock)
|
|
return;
|
|
|
|
debug_print("%slocking summaryview columns\n",
|
|
sorting_lock ? "un" : "");
|
|
prefs_common_get_prefs()->summary_col_lock = !sorting_lock;
|
|
}
|
|
|
|
static void summary_header_set_displayed_columns_cb(GtkAction *gaction,
|
|
gpointer data)
|
|
{
|
|
SummaryView *summaryview = (SummaryView *)data;
|
|
|
|
if (summaryview->header_menu_lock)
|
|
return;
|
|
|
|
prefs_summary_column_open();
|
|
}
|