2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2007 Hiroyuki Yamamoto and the Claws Mail team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 #include <glib/gi18n.h>
24 #include <gdk/gdkkeysyms.h>
25 #include <gtk/gtkscrolledwindow.h>
26 #include <gtk/gtkwidget.h>
27 #include <gtk/gtkpixmap.h>
28 #include <gtk/gtkctree.h>
29 #include <gtk/gtkcontainer.h>
30 #include <gtk/gtksignal.h>
31 #include <gtk/gtktext.h>
32 #include <gtk/gtkmenu.h>
33 #include <gtk/gtkmenuitem.h>
34 #include <gtk/gtkitemfactory.h>
35 #include <gtk/gtkvbox.h>
36 #include <gtk/gtkhbox.h>
37 #include <gtk/gtkwindow.h>
38 #include <gtk/gtkstyle.h>
39 #include <gtk/gtkarrow.h>
40 #include <gtk/gtkeventbox.h>
41 #include <gtk/gtkstatusbar.h>
42 #include <gtk/gtkmenuitem.h>
52 #include "mainwindow.h"
53 #include "folderview.h"
54 #include "summaryview.h"
55 #include "messageview.h"
56 #include "foldersel.h"
58 #include "procheader.h"
59 #include "sourcewindow.h"
60 #include "prefs_common.h"
61 #include "prefs_summary_column.h"
62 #include "prefs_filtering.h"
67 #include "stock_pixmap.h"
69 #include "alertpanel.h"
70 #include "inputdialog.h"
71 #include "statusbar.h"
73 #include "colorlabel.h"
76 #include "addressbook.h"
77 #include "addr_compl.h"
78 #include "folder_item_prefs.h"
79 #include "filtering.h"
80 #include "string_match.h"
84 #include "description_window.h"
85 #include "folderutils.h"
86 #include "quicksearch.h"
87 #include "partial_download.h"
89 #include "gedit-print.h"
93 #define SUMMARY_COL_MARK_WIDTH 10
94 #define SUMMARY_COL_STATUS_WIDTH 13
95 #define SUMMARY_COL_LOCKED_WIDTH 13
96 #define SUMMARY_COL_MIME_WIDTH 11
99 static GtkStyle
*bold_style
;
100 static GtkStyle
*bold_marked_style
;
101 static GtkStyle
*bold_deleted_style
;
102 static GtkStyle
*small_style
;
103 static GtkStyle
*small_marked_style
;
104 static GtkStyle
*small_deleted_style
;
106 static GdkPixmap
*markxpm
;
107 static GdkBitmap
*markxpmmask
;
108 static GdkPixmap
*deletedxpm
;
109 static GdkBitmap
*deletedxpmmask
;
110 static GdkPixmap
*movedxpm
;
111 static GdkBitmap
*movedxpmmask
;
112 static GdkPixmap
*copiedxpm
;
113 static GdkBitmap
*copiedxpmmask
;
115 static GdkPixmap
*newxpm
;
116 static GdkBitmap
*newxpmmask
;
117 static GdkPixmap
*unreadxpm
;
118 static GdkBitmap
*unreadxpmmask
;
119 static GdkPixmap
*repliedxpm
;
120 static GdkBitmap
*repliedxpmmask
;
121 static GdkPixmap
*forwardedxpm
;
122 static GdkBitmap
*forwardedxpmmask
;
123 static GdkPixmap
*ignorethreadxpm
;
124 static GdkBitmap
*ignorethreadxpmmask
;
125 static GdkPixmap
*lockedxpm
;
126 static GdkBitmap
*lockedxpmmask
;
127 static GdkPixmap
*spamxpm
;
128 static GdkBitmap
*spamxpmmask
;
130 static GdkPixmap
*clipxpm
;
131 static GdkBitmap
*clipxpmmask
;
132 static GdkPixmap
*keyxpm
;
133 static GdkBitmap
*keyxpmmask
;
134 static GdkPixmap
*clipkeyxpm
;
135 static GdkBitmap
*clipkeyxpmmask
;
136 static GdkPixmap
*gpgsignedxpm
;
137 static GdkBitmap
*gpgsignedxpmmask
;
138 static GdkPixmap
*clipgpgsignedxpm
;
139 static GdkBitmap
*clipgpgsignedxpmmask
;
141 static void summary_free_msginfo_func (GtkCTree
*ctree
,
144 static void summary_set_marks_func (GtkCTree
*ctree
,
148 void summary_set_menu_sensitive (SummaryView
*summaryview
);
149 guint
summary_get_msgnum (SummaryView
*summaryview
,
153 static void summary_set_hide_read_msgs_menu (SummaryView
*summaryview
,
156 static GtkCTreeNode
*summary_find_prev_msg
157 (SummaryView
*summaryview
,
158 GtkCTreeNode
*current_node
);
159 static GtkCTreeNode
*summary_find_next_msg
160 (SummaryView
*summaryview
,
161 GtkCTreeNode
*current_node
);
163 static GtkCTreeNode
*summary_find_prev_flagged_msg
164 (SummaryView
*summaryview
,
165 GtkCTreeNode
*current_node
,
167 gboolean start_from_prev
);
168 static GtkCTreeNode
*summary_find_next_flagged_msg
169 (SummaryView
*summaryview
,
170 GtkCTreeNode
*current_node
,
172 gboolean start_from_next
);
174 static GtkCTreeNode
*summary_find_msg_by_msgnum
175 (SummaryView
*summaryview
,
178 static void summary_update_status (SummaryView
*summaryview
);
180 /* display functions */
181 static void summary_status_show (SummaryView
*summaryview
);
182 static void summary_set_column_titles (SummaryView
*summaryview
);
183 static void summary_set_ctree_from_list (SummaryView
*summaryview
,
185 static void summary_set_header (SummaryView
*summaryview
,
188 static void summary_display_msg (SummaryView
*summaryview
,
190 static void summary_display_msg_full (SummaryView
*summaryview
,
193 gboolean all_headers
);
194 static void summary_set_row_marks (SummaryView
*summaryview
,
197 /* message handling */
198 static void summary_mark_row (SummaryView
*summaryview
,
200 static void summary_lock_row (SummaryView
*summaryview
,
202 static void summary_unlock_row (SummaryView
*summaryview
,
204 static void summary_mark_row_as_read (SummaryView
*summaryview
,
206 static void summary_mark_row_as_unread (SummaryView
*summaryview
,
208 static void summary_delete_row (SummaryView
*summaryview
,
210 static void summary_unmark_row (SummaryView
*summaryview
,
212 static void summary_move_row_to (SummaryView
*summaryview
,
214 FolderItem
*to_folder
);
215 static void summary_copy_row_to (SummaryView
*summaryview
,
217 FolderItem
*to_folder
);
219 static gint
summary_execute_move (SummaryView
*summaryview
);
220 static void summary_execute_move_func (GtkCTree
*ctree
,
223 static void summary_execute_copy (SummaryView
*summaryview
);
224 static void summary_execute_copy_func (GtkCTree
*ctree
,
227 static void summary_execute_delete (SummaryView
*summaryview
);
228 static void summary_execute_delete_func (GtkCTree
*ctree
,
232 static void summary_thread_init (SummaryView
*summaryview
);
234 static void summary_unthread_for_exec (SummaryView
*summaryview
);
235 static void summary_unthread_for_exec_func (GtkCTree
*ctree
,
239 void summary_simplify_subject(SummaryView
*summaryview
, gchar
* rexp
,
242 static void summary_filter_func (MsgInfo
*msginfo
);
244 static void summary_colorlabel_menu_item_activate_cb
247 static void summary_colorlabel_menu_item_activate_item_cb
248 (GtkMenuItem
*label_menu_item
,
250 static void summary_colorlabel_menu_create(SummaryView
*summaryview
,
253 static GtkWidget
*summary_ctree_create (SummaryView
*summaryview
);
255 /* callback functions */
256 static gint
summary_toggle_pressed (GtkWidget
*eventbox
,
257 GdkEventButton
*event
,
258 SummaryView
*summaryview
);
259 static gint summary_folder_eventbox_pressed
260 (GtkWidget
*eventbox
,
261 GdkEventButton
*event
,
262 SummaryView
*summaryview
);
263 static gboolean
summary_button_pressed (GtkWidget
*ctree
,
264 GdkEventButton
*event
,
265 SummaryView
*summaryview
);
266 static gboolean
summary_button_released (GtkWidget
*ctree
,
267 GdkEventButton
*event
,
268 SummaryView
*summaryview
);
269 static gboolean
summary_key_pressed (GtkWidget
*ctree
,
271 SummaryView
*summaryview
);
272 static void summary_open_row (GtkSCTree
*sctree
,
273 SummaryView
*summaryview
);
274 static void summary_tree_expanded (GtkCTree
*ctree
,
276 SummaryView
*summaryview
);
277 static void summary_tree_collapsed (GtkCTree
*ctree
,
279 SummaryView
*summaryview
);
280 static void summary_selected (GtkCTree
*ctree
,
283 SummaryView
*summaryview
);
284 static void summary_unselected (GtkCTree
*ctree
,
287 SummaryView
*summaryview
);
288 static void summary_col_resized (GtkCList
*clist
,
291 SummaryView
*summaryview
);
292 static void summary_reply_cb (SummaryView
*summaryview
,
295 static void summary_show_all_header_cb (SummaryView
*summaryview
,
299 static void summary_add_address_cb (SummaryView
*summaryview
,
302 static void summary_create_filter_cb (SummaryView
*summaryview
,
305 static void summary_create_processing_cb(SummaryView
*summaryview
,
309 static void summary_mark_clicked (GtkWidget
*button
,
310 SummaryView
*summaryview
);
311 static void summary_status_clicked (GtkWidget
*button
,
312 SummaryView
*summaryview
);
313 static void summary_mime_clicked (GtkWidget
*button
,
314 SummaryView
*summaryview
);
315 static void summary_num_clicked (GtkWidget
*button
,
316 SummaryView
*summaryview
);
317 static void summary_score_clicked (GtkWidget
*button
,
318 SummaryView
*summaryview
);
319 static void summary_size_clicked (GtkWidget
*button
,
320 SummaryView
*summaryview
);
321 static void summary_date_clicked (GtkWidget
*button
,
322 SummaryView
*summaryview
);
323 static void summary_from_clicked (GtkWidget
*button
,
324 SummaryView
*summaryview
);
325 static void summary_to_clicked (GtkWidget
*button
,
326 SummaryView
*summaryview
);
327 static void summary_subject_clicked (GtkWidget
*button
,
328 SummaryView
*summaryview
);
329 static void summary_score_clicked (GtkWidget
*button
,
330 SummaryView
*summaryview
);
331 static void summary_locked_clicked (GtkWidget
*button
,
332 SummaryView
*summaryview
);
334 static void summary_start_drag (GtkWidget
*widget
,
337 SummaryView
*summaryview
);
338 static void summary_drag_data_get (GtkWidget
*widget
,
339 GdkDragContext
*drag_context
,
340 GtkSelectionData
*selection_data
,
343 SummaryView
*summaryview
);
344 static void summary_drag_data_received(GtkWidget
*widget
,
345 GdkDragContext
*drag_context
,
348 GtkSelectionData
*data
,
351 SummaryView
*summaryview
);
352 static gboolean
summary_drag_motion_cb(GtkWidget
*widget
,
353 GdkDragContext
*context
,
357 SummaryView
*summaryview
);
358 static void summary_drag_end(GtkWidget
*widget
,
359 GdkDragContext
*drag_context
,
360 SummaryView
*summaryview
);
361 /* custom compare functions for sorting */
363 static gint
summary_cmp_by_mark (GtkCList
*clist
,
366 static gint
summary_cmp_by_status (GtkCList
*clist
,
369 static gint
summary_cmp_by_mime (GtkCList
*clist
,
372 static gint
summary_cmp_by_num (GtkCList
*clist
,
375 static gint
summary_cmp_by_size (GtkCList
*clist
,
378 static gint
summary_cmp_by_date (GtkCList
*clist
,
381 static gint
summary_cmp_by_from (GtkCList
*clist
,
384 static gint summary_cmp_by_simplified_subject
388 static gint
summary_cmp_by_score (GtkCList
*clist
,
391 static gint
summary_cmp_by_label (GtkCList
*clist
,
394 static gint
summary_cmp_by_to (GtkCList
*clist
,
397 static gint
summary_cmp_by_subject (GtkCList
*clist
,
400 static gint
summary_cmp_by_locked (GtkCList
*clist
,
404 static void quicksearch_execute_cb (QuickSearch
*quicksearch
,
406 static void tog_searchbar_cb (GtkWidget
*w
,
409 static void summary_find_answers (SummaryView
*summaryview
,
412 static gboolean
summary_update_msg (gpointer source
, gpointer data
);
413 static gboolean
summary_update_folder_item_hook(gpointer source
, gpointer data
);
414 static gboolean
summary_update_folder_hook(gpointer source
, gpointer data
);
416 GtkTargetEntry summary_drag_types
[2] =
418 {"text/uri-list", 0, TARGET_MAIL_URI_LIST
},
419 {"claws-mail/internal", GTK_TARGET_SAME_APP
, TARGET_DUMMY
}
422 static GtkItemFactoryEntry summary_popup_entries
[] =
424 {N_("/_Reply"), "<control>R", summary_reply_cb
, COMPOSE_REPLY
, NULL
},
425 {N_("/Repl_y to"), NULL
, NULL
, 0, "<Branch>"},
426 {N_("/Repl_y to/_all"), "<shift><control>R", summary_reply_cb
, COMPOSE_REPLY_TO_ALL
, NULL
},
427 {N_("/Repl_y to/_sender"), NULL
, summary_reply_cb
, COMPOSE_REPLY_TO_SENDER
, NULL
},
428 {N_("/Repl_y to/mailing _list"),
429 "<control>L", summary_reply_cb
, COMPOSE_REPLY_TO_LIST
, NULL
},
430 {"/---", NULL
, NULL
, 0, "<Separator>"},
431 {N_("/_Forward"), "<control><alt>F", summary_reply_cb
, COMPOSE_FORWARD_INLINE
, NULL
},
432 {N_("/For_ward as attachment"), NULL
, summary_reply_cb
, COMPOSE_FORWARD_AS_ATTACH
, NULL
},
433 {N_("/Redirect"), NULL
, summary_reply_cb
, COMPOSE_REDIRECT
, NULL
},
434 {"/---", NULL
, NULL
, 0, "<Separator>"},
435 {N_("/M_ove..."), "<control>O", summary_move_to
, 0, NULL
},
436 {N_("/_Copy..."), "<shift><control>O", summary_copy_to
, 0, NULL
},
437 {N_("/Move to _trash"), "<control>D", summary_delete_trash
, 0, NULL
},
438 {N_("/_Delete..."), NULL
, summary_delete
, 0, NULL
},
439 {"/---", NULL
, NULL
, 0, "<Separator>"},
440 {N_("/_Mark"), NULL
, NULL
, 0, "<Branch>"},
441 {N_("/_Mark/_Mark"), NULL
, summary_mark
, 0, NULL
},
442 {N_("/_Mark/_Unmark"), NULL
, summary_unmark
, 0, NULL
},
443 {N_("/_Mark/---"), NULL
, NULL
, 0, "<Separator>"},
444 {N_("/_Mark/Mark as unr_ead"), NULL
, summary_mark_as_unread
, 0, NULL
},
445 {N_("/_Mark/Mark as rea_d"), NULL
, summary_mark_as_read
, 0, NULL
},
446 {N_("/_Mark/Mark all read"), NULL
, summary_mark_all_read
, 0, NULL
},
447 {N_("/_Mark/Ignore thread"), NULL
, summary_ignore_thread
, 0, NULL
},
448 {N_("/_Mark/Unignore thread"), NULL
, summary_unignore_thread
, 0, NULL
},
449 {N_("/_Mark/---"), NULL
, NULL
, 0, "<Separator>"},
450 {N_("/_Mark/Mark as _spam"), NULL
, summary_mark_as_spam
, 1, NULL
},
451 {N_("/_Mark/Mark as _ham"), NULL
, summary_mark_as_spam
, 0, NULL
},
452 {N_("/_Mark/---"), NULL
, NULL
, 0, "<Separator>"},
453 {N_("/_Mark/Lock"), NULL
, summary_msgs_lock
, 0, NULL
},
454 {N_("/_Mark/Unlock"), NULL
, summary_msgs_unlock
, 0, NULL
},
455 {N_("/Color la_bel"), NULL
, NULL
, 0, NULL
},
457 {"/---", NULL
, NULL
, 0, "<Separator>"},
458 {N_("/Add sender to address boo_k"),
459 NULL
, summary_add_address_cb
, 0, NULL
},
460 {N_("/Create f_ilter rule"), NULL
, NULL
, 0, "<Branch>"},
461 {N_("/Create f_ilter rule/_Automatically"),
462 NULL
, summary_create_filter_cb
, FILTER_BY_AUTO
, NULL
},
463 {N_("/Create f_ilter rule/by _From"),
464 NULL
, summary_create_filter_cb
, FILTER_BY_FROM
, NULL
},
465 {N_("/Create f_ilter rule/by _To"),
466 NULL
, summary_create_filter_cb
, FILTER_BY_TO
, NULL
},
467 {N_("/Create f_ilter rule/by _Subject"),
468 NULL
, summary_create_filter_cb
, FILTER_BY_SUBJECT
, NULL
},
469 {N_("/Create processing rule"), NULL
, NULL
, 0, "<Branch>"},
470 {N_("/Create processing rule/_Automatically"),
471 NULL
, summary_create_processing_cb
, FILTER_BY_AUTO
, NULL
},
472 {N_("/Create processing rule/by _From"),
473 NULL
, summary_create_processing_cb
, FILTER_BY_FROM
, NULL
},
474 {N_("/Create processing rule/by _To"),
475 NULL
, summary_create_processing_cb
, FILTER_BY_TO
, NULL
},
476 {N_("/Create processing rule/by _Subject"),
477 NULL
, summary_create_processing_cb
, FILTER_BY_SUBJECT
, NULL
},
478 {"/---", NULL
, NULL
, 0, "<Separator>"},
479 {N_("/_View"), NULL
, NULL
, 0, "<Branch>"},
480 {N_("/_View/Open in new _window"),
481 "<control><alt>N", summary_open_msg
, 0, NULL
},
482 {N_("/_View/Message _source"), "<control>U", summary_view_source
, 0, NULL
},
483 {N_("/_View/All _headers"), "<control>H", summary_show_all_header_cb
, 0, "<ToggleItem>"},
484 {"/---", NULL
, NULL
, 0, "<Separator>"},
485 {N_("/_Save as..."), "<control>S", summary_save_as
, 0, NULL
},
486 {N_("/_Print..."), "<control>P", summary_print
, 0, NULL
},
487 }; /* see also list in menu_connect_identical_items() in menu.c if this changes */
489 static const gchar
*const col_label
[N_SUMMARY_COLS
] = {
491 N_("S"), /* S_COL_STATUS */
493 N_("Subject"), /* S_COL_SUBJECT */
494 N_("From"), /* S_COL_FROM */
495 N_("To"), /* S_COL_TO */
496 N_("Date"), /* S_COL_DATE */
497 N_("Size"), /* S_COL_SIZE */
498 N_("#"), /* S_COL_NUMBER */
499 N_("Score"), /* S_COL_SCORE */
500 "", /* S_COL_LOCKED */
503 void summary_freeze(SummaryView
*summaryview
)
506 gtk_clist_freeze(GTK_CLIST(summaryview
->ctree
));
509 void summary_thaw(SummaryView
*summaryview
)
512 gtk_clist_thaw(GTK_CLIST(summaryview
->ctree
));
515 void summary_grab_focus(SummaryView
*summaryview
)
518 gtk_widget_grab_focus(summaryview
->ctree
);
521 GtkWidget
*summary_get_main_widget(SummaryView
*summaryview
)
524 return summaryview
->ctree
;
529 #define START_LONG_OPERATION(summaryview,force_freeze) { \
530 summary_lock(summaryview); \
531 main_window_cursor_wait(summaryview->mainwin); \
532 if (force_freeze || sc_g_list_bigger(GTK_CLIST(summaryview->ctree)->selection, 1)) {\
534 summary_freeze(summaryview); \
536 folder_item_update_freeze(); \
538 hooks_unregister_hook(MSGINFO_UPDATE_HOOKLIST, \
539 summaryview->msginfo_update_callback_id); \
541 #define END_LONG_OPERATION(summaryview) { \
543 folder_item_update_thaw(); \
545 summary_thaw(summaryview); \
546 main_window_cursor_normal(summaryview->mainwin); \
547 summary_unlock(summaryview); \
548 summaryview->msginfo_update_callback_id = \
549 hooks_register_hook(MSGINFO_UPDATE_HOOKLIST, \
550 summary_update_msg, (gpointer) summaryview); \
553 SummaryView
*summary_create(void)
555 SummaryView
*summaryview
;
557 GtkWidget
*scrolledwin
;
562 GtkWidget
*stat_box2
;
563 GtkWidget
*stat_vbox
;
564 GtkWidget
*statlabel_folder
;
565 GtkWidget
*statlabel_select
;
566 GtkWidget
*statlabel_msgs
;
568 GtkWidget
*toggle_eventbox
;
569 GtkWidget
*toggle_arrow
;
570 GtkWidget
*popupmenu
;
571 GtkWidget
*toggle_search
;
572 GtkItemFactory
*popupfactory
;
574 QuickSearch
*quicksearch
;
576 debug_print("Creating summary view...\n");
577 summaryview
= g_new0(SummaryView
, 1);
579 summaryview
->tips
= gtk_tooltips_new();
580 #define SUMMARY_VBOX_SPACING 3
581 vbox
= gtk_vbox_new(FALSE
, SUMMARY_VBOX_SPACING
);
583 /* create status label */
584 hbox
= gtk_hbox_new(FALSE
, 0);
585 gtk_widget_show(hbox
);
587 stat_vbox
= gtk_vbox_new(FALSE
, 0);
588 gtk_widget_show(stat_vbox
);
590 stat_box
= gtk_hbox_new(FALSE
, 0);
591 gtk_widget_show(stat_box
);
593 stat_box2
= gtk_hbox_new(FALSE
, 0);
594 gtk_widget_show(stat_box2
);
596 toggle_search
= gtk_toggle_button_new();
597 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle_search
),
598 prefs_common
.show_searchbar
);
599 gtk_widget_show(toggle_search
);
601 gtk_tooltips_set_tip(GTK_TOOLTIPS(summaryview
->tips
),
603 _("Toggle quick search bar"), NULL
);
605 gtk_box_pack_start(GTK_BOX(hbox
), toggle_search
, FALSE
, FALSE
, 2);
607 gtk_box_pack_start(GTK_BOX(hbox
), stat_vbox
, TRUE
, TRUE
, 0);
608 gtk_box_pack_start(GTK_BOX(stat_vbox
), stat_box
, TRUE
, TRUE
, 0);
609 gtk_box_pack_start(GTK_BOX(stat_vbox
), stat_box2
, TRUE
, TRUE
, 0);
611 hbox_l
= gtk_hbox_new(FALSE
, 0);
612 gtk_widget_show(hbox_l
);
613 gtk_box_pack_start(GTK_BOX(stat_box
), hbox_l
, TRUE
, TRUE
, 0);
615 statlabel_folder
= gtk_label_new("");
616 gtk_widget_show(statlabel_folder
);
617 gtk_box_pack_start(GTK_BOX(hbox_l
), statlabel_folder
, FALSE
, FALSE
, 2);
618 statlabel_select
= gtk_label_new("");
619 gtk_widget_show(statlabel_select
);
620 gtk_box_pack_start(GTK_BOX(hbox_l
), statlabel_select
, FALSE
, FALSE
, 12);
622 /* toggle view button */
623 toggle_eventbox
= gtk_event_box_new();
624 gtk_widget_show(toggle_eventbox
);
625 gtk_box_pack_end(GTK_BOX(hbox
), toggle_eventbox
, FALSE
, FALSE
, 4);
626 toggle_arrow
= gtk_arrow_new(GTK_ARROW_DOWN
, GTK_SHADOW_OUT
);
627 gtk_widget_show(toggle_arrow
);
628 gtk_container_add(GTK_CONTAINER(toggle_eventbox
), toggle_arrow
);
629 g_signal_connect(G_OBJECT(toggle_eventbox
), "button_press_event",
630 G_CALLBACK(summary_toggle_pressed
),
634 statlabel_msgs
= gtk_label_new("");
635 gtk_widget_show(statlabel_msgs
);
636 gtk_box_pack_end(GTK_BOX(stat_box
), statlabel_msgs
, FALSE
, FALSE
, 4);
638 hbox_spc
= gtk_hbox_new(FALSE
, 0);
639 gtk_widget_show(hbox_spc
);
640 gtk_box_pack_end(GTK_BOX(hbox
), hbox_spc
, FALSE
, FALSE
, 6);
642 scrolledwin
= gtk_scrolled_window_new(NULL
, NULL
);
643 gtk_widget_show(scrolledwin
);
644 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin
),
645 GTK_POLICY_AUTOMATIC
,
646 GTK_POLICY_AUTOMATIC
);
647 gtk_box_pack_start(GTK_BOX(vbox
), scrolledwin
, TRUE
, TRUE
, 0);
648 gtk_widget_set_size_request(vbox
,
649 prefs_common
.summaryview_width
,
650 prefs_common
.summaryview_height
);
652 ctree
= summary_ctree_create(summaryview
);
653 gtk_widget_show(ctree
);
655 gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(scrolledwin
),
656 GTK_CLIST(ctree
)->hadjustment
);
657 gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(scrolledwin
),
658 GTK_CLIST(ctree
)->vadjustment
);
659 gtk_container_add(GTK_CONTAINER(scrolledwin
), ctree
);
662 gtk_widget_show_all(stat_vbox
);
663 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, FALSE
, FALSE
, 0);
666 quicksearch
= quicksearch_new();
667 gtk_box_pack_start(GTK_BOX(vbox
), quicksearch_get_widget(quicksearch
), FALSE
, FALSE
, 0);
669 quicksearch_set_execute_callback(quicksearch
, quicksearch_execute_cb
, summaryview
);
671 g_signal_connect (G_OBJECT(toggle_search
), "toggled",
672 G_CALLBACK(tog_searchbar_cb
), summaryview
);
674 /* create popup menu */
675 n_entries
= sizeof(summary_popup_entries
) /
676 sizeof(summary_popup_entries
[0]);
677 popupmenu
= menu_create_items(summary_popup_entries
, n_entries
,
678 "<SummaryView>", &popupfactory
,
681 summaryview
->vbox
= vbox
;
682 summaryview
->scrolledwin
= scrolledwin
;
683 summaryview
->ctree
= ctree
;
684 summaryview
->hbox
= hbox
;
685 summaryview
->hbox_l
= hbox_l
;
686 summaryview
->hbox_spc
= hbox_spc
;
687 summaryview
->stat_box
= stat_box
;
688 summaryview
->stat_box2
= stat_box2
;
689 summaryview
->statlabel_folder
= statlabel_folder
;
690 summaryview
->statlabel_select
= statlabel_select
;
691 summaryview
->statlabel_msgs
= statlabel_msgs
;
692 summaryview
->toggle_eventbox
= toggle_eventbox
;
693 summaryview
->toggle_arrow
= toggle_arrow
;
694 summaryview
->toggle_search
= toggle_search
;
695 summaryview
->popupmenu
= popupmenu
;
696 summaryview
->popupfactory
= popupfactory
;
697 summaryview
->lock_count
= 0;
698 summaryview
->msginfo_update_callback_id
=
699 hooks_register_hook(MSGINFO_UPDATE_HOOKLIST
, summary_update_msg
, (gpointer
) summaryview
);
700 summaryview
->folder_item_update_callback_id
=
701 hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST
,
702 summary_update_folder_item_hook
,
703 (gpointer
) summaryview
);
704 summaryview
->folder_update_callback_id
=
705 hooks_register_hook(FOLDER_UPDATE_HOOKLIST
,
706 summary_update_folder_hook
,
707 (gpointer
) summaryview
);
709 summaryview
->target_list
= gtk_target_list_new(summary_drag_types
, 2);
711 summaryview
->quicksearch
= quicksearch
;
713 /* CLAWS: need this to get the SummaryView * from
715 g_object_set_data(G_OBJECT(ctree
), "summaryview", (gpointer
)summaryview
);
717 gtk_widget_show_all(vbox
);
719 gtk_widget_show(vbox
);
721 if (prefs_common
.show_searchbar
)
722 quicksearch_show(quicksearch
);
724 quicksearch_hide(quicksearch
);
726 if (prefs_common
.layout_mode
== WIDE_MSGLIST_LAYOUT
||
727 prefs_common
.layout_mode
== SMALL_LAYOUT
)
728 gtk_widget_hide(summaryview
->toggle_eventbox
);
733 void summary_relayout(SummaryView
*summaryview
)
735 gtk_widget_realize(summaryview
->stat_box
);
737 gtk_widget_ref(summaryview
->hbox_l
);
738 gtk_widget_ref(summaryview
->statlabel_msgs
);
740 gtkut_container_remove(GTK_CONTAINER(summaryview
->hbox_l
->parent
), summaryview
->hbox_l
);
741 gtkut_container_remove(GTK_CONTAINER(summaryview
->statlabel_msgs
->parent
), summaryview
->statlabel_msgs
);
743 switch (prefs_common
.layout_mode
) {
746 case WIDE_MSGLIST_LAYOUT
:
747 gtk_box_pack_start(GTK_BOX(summaryview
->stat_box
), summaryview
->hbox_l
, TRUE
, TRUE
, 0);
748 gtk_box_pack_end(GTK_BOX(summaryview
->stat_box
), summaryview
->statlabel_msgs
, FALSE
, FALSE
, 4);
749 gtk_widget_show_all(summaryview
->stat_box
);
750 gtk_widget_show_all(summaryview
->stat_box2
);
751 if (prefs_common
.layout_mode
== WIDE_MSGLIST_LAYOUT
||
752 prefs_common
.layout_mode
== SMALL_LAYOUT
)
753 gtk_widget_hide(summaryview
->toggle_eventbox
);
755 gtk_widget_show(summaryview
->toggle_eventbox
);
757 case VERTICAL_LAYOUT
:
759 gtk_box_pack_start(GTK_BOX(summaryview
->stat_box
), summaryview
->hbox_l
, TRUE
, TRUE
, 0);
760 gtk_box_pack_start(GTK_BOX(summaryview
->stat_box2
), summaryview
->statlabel_msgs
, FALSE
, FALSE
, 4);
761 gtk_widget_show_all(summaryview
->stat_box
);
762 gtk_widget_show_all(summaryview
->stat_box2
);
763 if (prefs_common
.layout_mode
== SMALL_LAYOUT
)
764 gtk_widget_hide(summaryview
->toggle_eventbox
);
766 gtk_widget_show(summaryview
->toggle_eventbox
);
770 gtk_widget_unref(summaryview
->hbox_l
);
771 gtk_widget_unref(summaryview
->statlabel_msgs
);
772 quicksearch_relayout(summaryview
->quicksearch
);
775 static void summary_set_fonts(SummaryView
*summaryview
)
777 PangoFontDescription
*font_desc
;
780 font_desc
= pango_font_description_from_string(NORMAL_FONT
);
781 gtk_widget_modify_font(summaryview
->ctree
, font_desc
);
782 pango_font_description_free(font_desc
);
785 bold_style
= gtk_style_copy
786 (gtk_widget_get_style(summaryview
->ctree
));
787 font_desc
= pango_font_description_from_string(NORMAL_FONT
);
789 pango_font_description_free(bold_style
->font_desc
);
790 bold_style
->font_desc
= font_desc
;
793 pango_font_description_set_weight
794 (bold_style
->font_desc
, PANGO_WEIGHT_BOLD
);
795 bold_marked_style
= gtk_style_copy(bold_style
);
796 bold_marked_style
->fg
[GTK_STATE_NORMAL
] =
797 summaryview
->color_marked
;
798 bold_deleted_style
= gtk_style_copy(bold_style
);
799 bold_deleted_style
->fg
[GTK_STATE_NORMAL
] =
800 summaryview
->color_dim
;
803 font_desc
= pango_font_description_new();
804 size
= pango_font_description_get_size
805 (summaryview
->ctree
->style
->font_desc
);
806 pango_font_description_set_size(font_desc
, size
* PANGO_SCALE_SMALL
);
807 gtk_widget_modify_font(summaryview
->statlabel_folder
, font_desc
);
808 gtk_widget_modify_font(summaryview
->statlabel_select
, font_desc
);
809 gtk_widget_modify_font(summaryview
->statlabel_msgs
, font_desc
);
810 pango_font_description_free(font_desc
);
813 static void summary_set_folder_pixmap(SummaryView
*summaryview
, StockPixmap icon
)
816 if (!summaryview
->folder_pixmap_eventbox
) {
817 summaryview
->folder_pixmap_eventbox
= gtk_event_box_new();
818 gtk_widget_show(summaryview
->folder_pixmap_eventbox
);
819 gtk_box_pack_start(GTK_BOX(summaryview
->hbox_l
), summaryview
->folder_pixmap_eventbox
, FALSE
, FALSE
, 4);
820 gtk_box_reorder_child(GTK_BOX(summaryview
->hbox_l
), summaryview
->folder_pixmap_eventbox
, 0); /* search_toggle before */
821 g_signal_connect(G_OBJECT(summaryview
->folder_pixmap_eventbox
), "button_press_event",
822 G_CALLBACK(summary_folder_eventbox_pressed
),
825 if (summaryview
->folder_pixmap
)
826 gtk_widget_destroy(summaryview
->folder_pixmap
);
828 pixmap
= stock_pixmap_widget(summaryview
->hbox_l
, icon
);
829 gtk_container_add(GTK_CONTAINER(summaryview
->folder_pixmap_eventbox
), pixmap
);
830 gtk_widget_show(pixmap
);
831 summaryview
->folder_pixmap
= pixmap
;
834 void summary_init(SummaryView
*summaryview
)
838 gtk_widget_realize(summaryview
->ctree
);
839 stock_pixmap_gdk(summaryview
->ctree
, STOCK_PIXMAP_MARK
,
840 &markxpm
, &markxpmmask
);
841 stock_pixmap_gdk(summaryview
->ctree
, STOCK_PIXMAP_DELETED
,
842 &deletedxpm
, &deletedxpmmask
);
843 stock_pixmap_gdk(summaryview
->ctree
, STOCK_PIXMAP_NEW
,
844 &newxpm
, &newxpmmask
);
845 stock_pixmap_gdk(summaryview
->ctree
, STOCK_PIXMAP_UNREAD
,
846 &unreadxpm
, &unreadxpmmask
);
847 stock_pixmap_gdk(summaryview
->ctree
, STOCK_PIXMAP_REPLIED
,
848 &repliedxpm
, &repliedxpmmask
);
849 stock_pixmap_gdk(summaryview
->ctree
, STOCK_PIXMAP_FORWARDED
,
850 &forwardedxpm
, &forwardedxpmmask
);
851 stock_pixmap_gdk(summaryview
->ctree
, STOCK_PIXMAP_CLIP
,
852 &clipxpm
, &clipxpmmask
);
853 stock_pixmap_gdk(summaryview
->ctree
, STOCK_PIXMAP_LOCKED
,
854 &lockedxpm
, &lockedxpmmask
);
855 stock_pixmap_gdk(summaryview
->ctree
, STOCK_PIXMAP_IGNORETHREAD
,
856 &ignorethreadxpm
, &ignorethreadxpmmask
);
857 stock_pixmap_gdk(summaryview
->ctree
, STOCK_PIXMAP_CLIP_KEY
,
858 &clipkeyxpm
, &clipkeyxpmmask
);
859 stock_pixmap_gdk(summaryview
->ctree
, STOCK_PIXMAP_KEY
,
860 &keyxpm
, &keyxpmmask
);
861 stock_pixmap_gdk(summaryview
->ctree
, STOCK_PIXMAP_GPG_SIGNED
,
862 &gpgsignedxpm
, &gpgsignedxpmmask
);
863 stock_pixmap_gdk(summaryview
->ctree
, STOCK_PIXMAP_CLIP_GPG_SIGNED
,
864 &clipgpgsignedxpm
, &clipgpgsignedxpmmask
);
865 stock_pixmap_gdk(summaryview
->ctree
, STOCK_PIXMAP_SPAM
,
866 &spamxpm
, &spamxpmmask
);
867 stock_pixmap_gdk(summaryview
->ctree
, STOCK_PIXMAP_MOVED
,
868 &movedxpm
, &movedxpmmask
);
869 stock_pixmap_gdk(summaryview
->ctree
, STOCK_PIXMAP_COPIED
,
870 &copiedxpm
, &copiedxpmmask
);
872 summary_set_fonts(summaryview
);
874 summary_set_folder_pixmap(summaryview
, STOCK_PIXMAP_DIR_OPEN
);
876 pixmap
= stock_pixmap_widget(summaryview
->hbox
, STOCK_PIXMAP_QUICKSEARCH
);
877 gtk_container_add (GTK_CONTAINER(summaryview
->toggle_search
), pixmap
);
878 gtk_widget_show(pixmap
);
879 summaryview
->quick_search_pixmap
= pixmap
;
881 /* Init summaryview prefs */
882 summaryview
->sort_key
= SORT_BY_NONE
;
883 summaryview
->sort_type
= SORT_ASCENDING
;
885 /* Init summaryview extra data */
886 summaryview
->simplify_subject_preg
= NULL
;
888 summary_clear_list(summaryview
);
889 summary_set_column_titles(summaryview
);
890 summary_colorlabel_menu_create(summaryview
, FALSE
);
891 main_create_mailing_list_menu (summaryview
->mainwin
, NULL
);
892 summary_set_menu_sensitive(summaryview
);
896 #define CURRENTLY_DISPLAYED(m) \
897 ( (m->msgnum == displayed_msgnum) \
898 && (!g_ascii_strcasecmp(m->folder->name,item->name)) )
900 #define FOLDER_SHOWS_TO_HDR(i) \
901 ( folder_has_parent_of_type(i, F_OUTBOX) \
902 || folder_has_parent_of_type(i, F_DRAFT) \
903 || folder_has_parent_of_type(i, F_QUEUE) )
905 static void summary_switch_from_to(SummaryView
*summaryview
, FolderItem
*item
)
907 gboolean show_from
= FALSE
, show_to
= FALSE
;
908 gboolean showing_from
= FALSE
, showing_to
= FALSE
;
909 gint from_pos
= 0, to_pos
= 0;
910 SummaryColumnState
*col_state
= summaryview
->col_state
;
911 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
915 if (FOLDER_SHOWS_TO_HDR(item
))
920 from_pos
= summaryview
->col_pos
[S_COL_FROM
];
921 to_pos
= summaryview
->col_pos
[S_COL_TO
];
922 showing_from
= col_state
[from_pos
].visible
;
923 showing_to
= col_state
[to_pos
].visible
;
925 if (showing_from
&& showing_to
) {
926 debug_print("showing both\n");
930 if (!showing_from
&& !showing_to
) {
931 debug_print("showing none\n");
935 debug_print("showing %s %s, must show %s %s\n",
936 showing_from
?"From":"",
941 if (showing_from
== show_from
&& showing_to
== show_to
)
943 /* else we'll switch both */
945 debug_print("switching columns\n");
946 col_state
[from_pos
].type
= S_COL_TO
;
947 col_state
[from_pos
].visible
= show_to
;
949 col_state
[to_pos
].type
= S_COL_FROM
;
950 col_state
[to_pos
].visible
= show_from
;
952 summaryview
->col_pos
[S_COL_TO
] = from_pos
;
953 summaryview
->col_pos
[S_COL_FROM
] = to_pos
;
955 gtk_clist_set_column_visibility
956 (GTK_CLIST(ctree
), from_pos
, col_state
[from_pos
].visible
);
957 gtk_clist_set_column_visibility
958 (GTK_CLIST(ctree
), to_pos
, col_state
[to_pos
].visible
);
960 summary_set_column_titles(summaryview
);
963 static gboolean
summaryview_quicksearch_recurse(gpointer data
)
965 SummaryView
*summaryview
= (SummaryView
*)data
;
966 main_window_cursor_wait(summaryview
->mainwin
);
967 quicksearch_reset_cur_folder_item(summaryview
->quicksearch
);
968 quicksearch_search_subfolders(summaryview
->quicksearch
,
969 summaryview
->folderview
,
970 summaryview
->folder_item
);
971 main_window_cursor_normal(summaryview
->mainwin
);
975 static gboolean
summary_check_consistency(FolderItem
*item
, GSList
*mlist
)
977 int u
= 0, n
= 0, m
= 0, t
= 0;
980 for(cur
= mlist
; cur
!= NULL
&& cur
->data
!= NULL
; cur
= g_slist_next(cur
)) {
981 MsgInfo
* msginfo
= (MsgInfo
*) cur
->data
;
983 if (MSG_IS_NEW(msginfo
->flags
))
985 if (MSG_IS_UNREAD(msginfo
->flags
))
987 if (MSG_IS_MARKED(msginfo
->flags
))
990 if (t
!= item
->total_msgs
991 || n
!= item
->new_msgs
992 || u
!= item
->unread_msgs
993 || m
!= item
->marked_msgs
994 || (m
== 0 && item
->unreadmarked_msgs
!= 0)
995 || item
->unreadmarked_msgs
< 0) {
996 debug_print("Inconsistency\n");
997 folder_item_scan_full(item
, FALSE
);
1005 gboolean
summary_show(SummaryView
*summaryview
, FolderItem
*item
)
1007 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
1008 GtkCTreeNode
*node
= NULL
;
1009 GSList
*mlist
= NULL
;
1011 gboolean is_refresh
;
1012 guint selected_msgnum
= 0;
1013 guint displayed_msgnum
= 0;
1016 gboolean hidden_removed
= FALSE
;
1018 if (summary_is_locked(summaryview
)) return FALSE
;
1020 if (!summaryview
->mainwin
)
1023 summaryview
->last_displayed
= NULL
;
1024 summary_switch_from_to(summaryview
, item
);
1027 summary_lock(summaryview
);
1029 is_refresh
= (item
== summaryview
->folder_item
) ? TRUE
: FALSE
;
1032 main_create_mailing_list_menu (summaryview
->mainwin
, NULL
);
1033 if (prefs_common
.layout_mode
== SMALL_LAYOUT
) {
1035 mainwindow_enter_folder(summaryview
->mainwin
);
1036 gtk_widget_grab_focus(summaryview
->ctree
);
1040 if (!prefs_common
.summary_quicksearch_sticky
1041 && !prefs_common
.summary_quicksearch_recurse
1042 && !quicksearch_is_running(summaryview
->quicksearch
)
1044 quicksearch_set(summaryview
->quicksearch
, prefs_common
.summary_quicksearch_type
, "");
1047 /* STATUSBAR_POP(summaryview->mainwin); */
1050 selected_msgnum
= summary_get_msgnum(summaryview
,
1051 summaryview
->selected
);
1052 displayed_msgnum
= summary_get_msgnum(summaryview
,
1053 summaryview
->displayed
);
1056 /* process the marks if any */
1057 if (summaryview
->mainwin
->lock_count
== 0 &&
1058 (summaryview
->moved
> 0 || summaryview
->copied
> 0)) {
1060 gboolean changed
= FALSE
;
1062 val
= alertpanel(_("Process mark"),
1063 _("Some marks are left. Process them?"),
1064 GTK_STOCK_NO
, GTK_STOCK_YES
, GTK_STOCK_CANCEL
);
1065 if (G_ALERTALTERNATE
== val
) {
1066 summary_unlock(summaryview
);
1067 summary_execute(summaryview
);
1068 summary_lock(summaryview
);
1070 } else if (G_ALERTDEFAULT
== val
) {
1073 summary_unlock(summaryview
);
1078 if (changed
|| !quicksearch_is_active(summaryview
->quicksearch
))
1079 folder_update_op_count();
1082 summary_freeze(summaryview
);
1084 summary_clear_list(summaryview
);
1087 if (!item
|| !item
->path
|| !folder_item_parent(item
) || item
->no_select
) {
1089 debug_print("empty folder (%p %s %p %d)\n\n",
1091 item
?item
->path
:"NULL",
1092 item
?folder_item_parent(item
):0x0,
1093 item
?item
->no_select
:FALSE
);
1094 summary_set_hide_read_msgs_menu(summaryview
, FALSE
);
1095 summary_clear_all(summaryview
);
1096 summaryview
->folder_item
= item
;
1097 summary_thaw(summaryview
);
1098 summary_unlock(summaryview
);
1100 if (item
&& quicksearch_is_running(summaryview
->quicksearch
)) {
1101 main_window_cursor_wait(summaryview
->mainwin
);
1102 quicksearch_reset_cur_folder_item(summaryview
->quicksearch
);
1103 if (quicksearch_is_active(summaryview
->quicksearch
))
1104 quicksearch_search_subfolders(summaryview
->quicksearch
,
1105 summaryview
->folderview
,
1106 summaryview
->folder_item
);
1107 main_window_cursor_normal(summaryview
->mainwin
);
1115 messageview_clear(summaryview
->messageview
);
1117 summaryview
->folder_item
= item
;
1118 item
->opened
= TRUE
;
1120 buf
= g_strdup_printf(_("Scanning folder (%s)..."), item
->path
);
1121 debug_print("%s\n", buf
);
1122 STATUSBAR_PUSH(summaryview
->mainwin
, buf
);
1125 main_window_cursor_wait(summaryview
->mainwin
);
1127 mlist
= folder_item_get_msg_list(item
);
1129 if (!summary_check_consistency(item
, mlist
)) {
1130 debug_print("reloading due to inconsistency\n");
1131 procmsg_msg_list_free(mlist
);
1132 mlist
= folder_item_get_msg_list(item
);
1135 if (summaryview
->folder_item
->hide_read_msgs
&&
1136 quicksearch_is_active(summaryview
->quicksearch
) == FALSE
) {
1139 summary_set_hide_read_msgs_menu(summaryview
, TRUE
);
1141 for(cur
= mlist
; cur
!= NULL
&& cur
->data
!= NULL
; cur
= g_slist_next(cur
)) {
1142 MsgInfo
* msginfo
= (MsgInfo
*) cur
->data
;
1144 if (!msginfo
->hidden
) {
1145 if (MSG_IS_UNREAD(msginfo
->flags
) &&
1146 !MSG_IS_IGNORE_THREAD(msginfo
->flags
))
1147 not_killed
= g_slist_prepend(not_killed
, msginfo
);
1148 else if (MSG_IS_MARKED(msginfo
->flags
) ||
1149 MSG_IS_LOCKED(msginfo
->flags
))
1150 not_killed
= g_slist_prepend(not_killed
, msginfo
);
1151 else if (is_refresh
&&
1152 (msginfo
->msgnum
== selected_msgnum
||
1153 msginfo
->msgnum
== displayed_msgnum
))
1154 not_killed
= g_slist_prepend(not_killed
, msginfo
);
1156 procmsg_msginfo_free(msginfo
);
1158 procmsg_msginfo_free(msginfo
);
1160 hidden_removed
= TRUE
;
1161 g_slist_free(mlist
);
1164 summary_set_hide_read_msgs_menu(summaryview
, FALSE
);
1167 if (quicksearch_is_active(summaryview
->quicksearch
)) {
1169 gint interval
= quicksearch_is_fast(summaryview
->quicksearch
) ? 5000:100;
1170 START_TIMING("quicksearch");
1171 gint num
= 0, total
= summaryview
->folder_item
->total_msgs
;
1172 statusbar_print_all(_("Searching in %s... \n"),
1173 summaryview
->folder_item
->path
?
1174 summaryview
->folder_item
->path
: "(null)");
1176 folder_item_update_freeze();
1177 for (cur
= mlist
; cur
!= NULL
&& cur
->data
!= NULL
; cur
= g_slist_next(cur
)) {
1178 MsgInfo
* msginfo
= (MsgInfo
*) cur
->data
;
1180 statusbar_progress_all(num
++,total
, interval
);
1182 if (!msginfo
->hidden
&& quicksearch_match(summaryview
->quicksearch
, msginfo
))
1183 not_killed
= g_slist_prepend(not_killed
, msginfo
);
1185 procmsg_msginfo_free(msginfo
);
1186 if (num
% interval
== 0)
1188 if (!quicksearch_is_active(summaryview
->quicksearch
)) {
1192 folder_item_update_thaw();
1193 statusbar_progress_all(0,0,0);
1194 statusbar_pop_all();
1196 hidden_removed
= TRUE
;
1197 if (!quicksearch_is_active(summaryview
->quicksearch
)) {
1198 debug_print("search cancelled!\n");
1199 summary_thaw(summaryview
);
1200 STATUSBAR_POP(summaryview
->mainwin
);
1201 main_window_cursor_normal(summaryview
->mainwin
);
1202 summary_unlock(summaryview
);
1204 summary_show(summaryview
, summaryview
->folder_item
);
1208 g_slist_free(mlist
);
1213 if (!hidden_removed
) {
1214 START_TIMING("removing hidden");
1216 for(cur
= mlist
; cur
!= NULL
&& cur
->data
!= NULL
; cur
= g_slist_next(cur
)) {
1217 MsgInfo
* msginfo
= (MsgInfo
*) cur
->data
;
1219 if (!msginfo
->hidden
)
1220 not_killed
= g_slist_prepend(not_killed
, msginfo
);
1222 procmsg_msginfo_free(msginfo
);
1224 g_slist_free(mlist
);
1229 STATUSBAR_POP(summaryview
->mainwin
);
1231 /* set ctree and hash table from the msginfo list, and
1232 create the thread */
1233 summary_set_ctree_from_list(summaryview
, mlist
);
1235 g_slist_free(mlist
);
1237 if (quicksearch_is_active(summaryview
->quicksearch
) &&
1238 quicksearch_is_running(summaryview
->quicksearch
)) {
1239 /* only scan subfolders when quicksearch changed,
1240 * not when search is the same and folder changed */
1241 g_timeout_add(100, summaryview_quicksearch_recurse
, summaryview
);
1245 if (!quicksearch_is_in_typing(summaryview
->quicksearch
)) {
1246 summaryview
->last_displayed
= summaryview
->displayed
;
1247 summaryview
->displayed
=
1248 summary_find_msg_by_msgnum(summaryview
,
1250 if (!summaryview
->displayed
)
1251 messageview_clear(summaryview
->messageview
);
1252 summary_unlock(summaryview
);
1253 summary_select_by_msgnum(summaryview
, selected_msgnum
);
1254 summary_lock(summaryview
);
1255 if (!summaryview
->selected
) {
1256 /* no selected message - select first unread
1257 message, but do not display it */
1258 node
= summary_find_next_flagged_msg(summaryview
, NULL
,
1260 if (node
== NULL
&& GTK_CLIST(ctree
)->row_list
!= NULL
)
1261 node
= gtk_ctree_node_nth
1263 item
->sort_type
== SORT_DESCENDING
1264 ? 0 : GTK_CLIST(ctree
)->rows
- 1);
1265 summary_unlock(summaryview
);
1266 summary_select_node(summaryview
, node
, FALSE
, TRUE
);
1267 summary_lock(summaryview
);
1270 /* just select first/last */
1271 if (GTK_CLIST(ctree
)->row_list
!= NULL
)
1272 node
= gtk_ctree_node_nth
1274 item
->sort_type
== SORT_DESCENDING
1275 ? 0 : GTK_CLIST(ctree
)->rows
- 1);
1276 gtk_sctree_select(GTK_SCTREE(ctree
), node
);
1277 gtk_ctree_node_moveto(ctree
, node
, 0, 0.5, 0);
1280 switch (prefs_common
.select_on_entry
) {
1281 case SELECTONENTRY_MNU
:
1282 node
= summary_find_next_flagged_msg(summaryview
, NULL
,
1285 node
= summary_find_next_flagged_msg(summaryview
, NULL
,
1288 node
= summary_find_next_flagged_msg(summaryview
, NULL
,
1291 case SELECTONENTRY_MUN
:
1292 node
= summary_find_next_flagged_msg(summaryview
, NULL
,
1295 node
= summary_find_next_flagged_msg(summaryview
, NULL
,
1298 node
= summary_find_next_flagged_msg(summaryview
, NULL
,
1301 case SELECTONENTRY_NMU
:
1302 node
= summary_find_next_flagged_msg(summaryview
, NULL
,
1305 node
= summary_find_next_flagged_msg(summaryview
, NULL
,
1308 node
= summary_find_next_flagged_msg(summaryview
, NULL
,
1311 case SELECTONENTRY_NUM
:
1312 node
= summary_find_next_flagged_msg(summaryview
, NULL
,
1315 node
= summary_find_next_flagged_msg(summaryview
, NULL
,
1318 node
= summary_find_next_flagged_msg(summaryview
, NULL
,
1321 case SELECTONENTRY_UNM
:
1322 node
= summary_find_next_flagged_msg(summaryview
, NULL
,
1325 node
= summary_find_next_flagged_msg(summaryview
, NULL
,
1328 node
= summary_find_next_flagged_msg(summaryview
, NULL
,
1331 case SELECTONENTRY_UMN
:
1332 node
= summary_find_next_flagged_msg(summaryview
, NULL
,
1335 node
= summary_find_next_flagged_msg(summaryview
, NULL
,
1338 node
= summary_find_next_flagged_msg(summaryview
, NULL
,
1345 if (node
== NULL
&& GTK_CLIST(ctree
)->row_list
!= NULL
) {
1346 node
= gtk_ctree_node_nth
1348 item
->sort_type
== SORT_DESCENDING
1349 ? 0 : GTK_CLIST(ctree
)->rows
- 1);
1351 summary_unlock(summaryview
);
1352 summary_select_node(summaryview
, node
,
1353 prefs_common
.always_show_msg
,
1355 summary_lock(summaryview
);
1358 summary_status_show(summaryview
);
1359 summary_set_menu_sensitive(summaryview
);
1360 toolbar_main_set_sensitive(summaryview
->mainwin
);
1362 summary_thaw(summaryview
);
1364 STATUSBAR_PUSH(summaryview
->mainwin
, _("Done."));
1365 STATUSBAR_POP(summaryview
->mainwin
);
1366 main_window_cursor_normal(summaryview
->mainwin
);
1367 summary_unlock(summaryview
);
1373 #undef CURRENTLY_DISPLAYED
1376 void summary_clear_list(SummaryView
*summaryview
)
1378 GtkCList
*clist
= GTK_CLIST(summaryview
->ctree
);
1381 summary_freeze(summaryview
);
1383 gtk_ctree_pre_recursive(GTK_CTREE(summaryview
->ctree
),
1384 NULL
, summary_free_msginfo_func
, NULL
);
1386 if (summaryview
->folder_item
) {
1387 summaryview
->folder_item
->opened
= FALSE
;
1388 summaryview
->folder_item
= NULL
;
1391 summaryview
->display_msg
= FALSE
;
1393 summaryview
->selected
= NULL
;
1394 summaryview
->displayed
= NULL
;
1395 summaryview
->total_size
= 0;
1396 summaryview
->deleted
= summaryview
->moved
= 0;
1397 summaryview
->copied
= 0;
1398 if (summaryview
->msgid_table
) {
1399 g_hash_table_destroy(summaryview
->msgid_table
);
1400 summaryview
->msgid_table
= NULL
;
1402 if (summaryview
->subject_table
) {
1403 g_hash_table_destroy(summaryview
->subject_table
);
1404 summaryview
->subject_table
= NULL
;
1406 summaryview
->mlist
= NULL
;
1408 gtk_clist_clear(clist
);
1409 if (summaryview
->col_pos
[S_COL_SUBJECT
] == N_SUMMARY_COLS
- 1) {
1410 optimal_width
= gtk_clist_optimal_column_width
1411 (clist
, summaryview
->col_pos
[S_COL_SUBJECT
]);
1412 gtk_clist_set_column_width
1413 (clist
, summaryview
->col_pos
[S_COL_SUBJECT
],
1417 summary_thaw(summaryview
);
1420 void summary_clear_all(SummaryView
*summaryview
)
1422 messageview_clear(summaryview
->messageview
);
1423 summary_clear_list(summaryview
);
1424 summary_set_menu_sensitive(summaryview
);
1425 toolbar_main_set_sensitive(summaryview
->mainwin
);
1426 summary_status_show(summaryview
);
1429 void summary_lock(SummaryView
*summaryview
)
1431 summaryview
->lock_count
++;
1434 void summary_unlock(SummaryView
*summaryview
)
1436 if (summaryview
->lock_count
)
1437 summaryview
->lock_count
--;
1440 gboolean
summary_is_locked(SummaryView
*summaryview
)
1442 return summaryview
->lock_count
> 0;
1445 SummarySelection
summary_get_selection_type(SummaryView
*summaryview
)
1447 GtkCList
*clist
= GTK_CLIST(summaryview
->ctree
);
1448 SummarySelection selection
;
1450 if (!clist
->row_list
)
1451 selection
= SUMMARY_NONE
;
1452 else if (!clist
->selection
)
1453 selection
= SUMMARY_SELECTED_NONE
;
1454 else if (!clist
->selection
->next
)
1455 selection
= SUMMARY_SELECTED_SINGLE
;
1457 selection
= SUMMARY_SELECTED_MULTIPLE
;
1463 *\return MsgInfo * Selected message if there's one selected;
1464 * if multiple selected, or none, return NULL.
1466 MsgInfo
*summary_get_selected_msg(SummaryView
*summaryview
)
1468 /* summaryview->selected may be valid when multiple
1469 * messages were selected */
1470 GList
*sellist
= GTK_CLIST(summaryview
->ctree
)->selection
;
1472 if (sellist
== NULL
|| sellist
->next
)
1475 return GTKUT_CTREE_NODE_GET_ROW_DATA(sellist
->data
);
1478 GSList
*summary_get_selected_msg_list(SummaryView
*summaryview
)
1480 GSList
*mlist
= NULL
;
1484 for (cur
= GTK_CLIST(summaryview
->ctree
)->selection
; cur
!= NULL
&& cur
->data
!= NULL
;
1486 msginfo
= GTKUT_CTREE_NODE_GET_ROW_DATA(cur
->data
);
1487 mlist
= g_slist_prepend(mlist
, msginfo
);
1490 mlist
= g_slist_reverse(mlist
);
1495 void summary_set_menu_sensitive(SummaryView
*summaryview
)
1497 GtkItemFactory
*ifactory
= summaryview
->popupfactory
;
1498 SensitiveCond state
;
1500 GtkWidget
*menuitem
;
1503 static const struct {
1507 {"/Reply" , M_HAVE_ACCOUNT
|M_TARGET_EXIST
},
1508 {"/Reply to" , M_HAVE_ACCOUNT
|M_TARGET_EXIST
},
1509 {"/Reply to/all" , M_HAVE_ACCOUNT
|M_TARGET_EXIST
},
1510 {"/Reply to/sender" , M_HAVE_ACCOUNT
|M_TARGET_EXIST
},
1511 {"/Reply to/mailing list" , M_HAVE_ACCOUNT
|M_TARGET_EXIST
},
1513 {"/Forward" , M_HAVE_ACCOUNT
|M_TARGET_EXIST
},
1514 {"/Forward as attachment" , M_HAVE_ACCOUNT
|M_TARGET_EXIST
},
1515 {"/Redirect" , M_HAVE_ACCOUNT
|M_TARGET_EXIST
},
1517 {"/Move..." , M_TARGET_EXIST
|M_ALLOW_DELETE
|M_NOT_NEWS
},
1518 {"/Copy..." , M_TARGET_EXIST
|M_EXEC
},
1519 {"/Move to trash" , M_TARGET_EXIST
|M_ALLOW_DELETE
|M_NOT_NEWS
},
1520 {"/Delete..." , M_TARGET_EXIST
|M_ALLOW_DELETE
},
1522 {"/Mark" , M_TARGET_EXIST
},
1523 {"/Mark/Mark" , M_TARGET_EXIST
},
1524 {"/Mark/Unmark" , M_TARGET_EXIST
},
1525 {"/Mark/Mark as unread" , M_TARGET_EXIST
},
1526 {"/Mark/Mark all read" , M_TARGET_EXIST
},
1527 {"/Mark/Ignore thread" , M_TARGET_EXIST
},
1528 {"/Mark/Unignore thread" , M_TARGET_EXIST
},
1529 {"/Mark/Lock" , M_TARGET_EXIST
},
1530 {"/Mark/Unlock" , M_TARGET_EXIST
},
1531 {"/Mark/Mark as spam" , M_TARGET_EXIST
|M_CAN_LEARN_SPAM
},
1532 {"/Mark/Mark as ham" , M_TARGET_EXIST
|M_CAN_LEARN_SPAM
},
1533 {"/Color label" , M_TARGET_EXIST
},
1535 {"/Add sender to address book" , M_SINGLE_TARGET_EXIST
},
1536 {"/Create filter rule" , M_SINGLE_TARGET_EXIST
|M_UNLOCKED
},
1537 {"/Create processing rule" , M_SINGLE_TARGET_EXIST
|M_UNLOCKED
},
1539 {"/View" , M_SINGLE_TARGET_EXIST
},
1540 {"/View/Open in new window" , M_SINGLE_TARGET_EXIST
},
1541 {"/View/Message source" , M_SINGLE_TARGET_EXIST
},
1542 {"/View/All headers" , M_SINGLE_TARGET_EXIST
},
1543 {"/Save as..." , M_TARGET_EXIST
},
1544 {"/Print..." , M_TARGET_EXIST
},
1548 main_window_set_menu_sensitive(summaryview
->mainwin
);
1550 state
= main_window_get_current_state(summaryview
->mainwin
);
1552 for (i
= 0; entry
[i
].entry
!= NULL
; i
++) {
1553 sensitive
= ((entry
[i
].cond
& state
) == entry
[i
].cond
);
1554 menu_set_sensitive(ifactory
, entry
[i
].entry
, sensitive
);
1558 summary_lock(summaryview
);
1559 menuitem
= gtk_item_factory_get_widget(ifactory
, "/View/All headers");
1560 if (summaryview
->messageview
1561 && summaryview
->messageview
->mimeview
1562 && summaryview
->messageview
->mimeview
->textview
)
1563 gtk_check_menu_item_set_active
1564 (GTK_CHECK_MENU_ITEM(menuitem
),
1565 summaryview
->messageview
->mimeview
->textview
->show_all_headers
);
1566 summary_unlock(summaryview
);
1569 void summary_select_prev_unread(SummaryView
*summaryview
)
1572 gboolean skip_cur
= FALSE
;
1574 if (summaryview
->displayed
1575 && summaryview
->selected
== summaryview
->displayed
) {
1576 debug_print("skipping current\n");
1580 node
= summary_find_prev_flagged_msg
1581 (summaryview
, summaryview
->selected
, MSG_UNREAD
, skip_cur
);
1583 if (!node
|| node
== summaryview
->selected
) {
1586 switch (prefs_common
.next_unread_msg_dialog
) {
1587 case NEXTUNREADMSGDIALOG_ALWAYS
:
1588 val
= alertpanel(_("No more unread messages"),
1589 _("No unread message found. "
1590 "Search from the end?"),
1591 GTK_STOCK_NO
, "+"GTK_STOCK_YES
, NULL
);
1593 case NEXTUNREADMSGDIALOG_ASSUME_YES
:
1594 val
= G_ALERTALTERNATE
;
1596 case NEXTUNREADMSGDIALOG_ASSUME_NO
:
1597 val
= !G_ALERTALTERNATE
;
1601 _("Internal error: unexpected value for prefs_common.next_unread_msg_dialog\n"));
1603 if (val
!= G_ALERTALTERNATE
) return;
1604 node
= summary_find_prev_flagged_msg(summaryview
, NULL
,
1609 alertpanel_notice(_("No unread messages."));
1611 summary_select_node(summaryview
, node
, TRUE
, FALSE
);
1614 void summary_select_next_unread(SummaryView
*summaryview
)
1616 GtkCTreeNode
*node
= summaryview
->selected
;
1617 gboolean skip_cur
= FALSE
;
1619 if (summaryview
->displayed
1620 && summaryview
->selected
== summaryview
->displayed
) {
1621 debug_print("skipping cur (%p %p)\n",
1622 summaryview
->displayed
, summaryview
->selected
);
1627 node
= summary_find_next_flagged_msg
1628 (summaryview
, node
, MSG_UNREAD
, skip_cur
);
1631 summary_select_node(summaryview
, node
, TRUE
, FALSE
);
1633 node
= summary_find_next_flagged_msg
1634 (summaryview
, NULL
, MSG_UNREAD
, FALSE
);
1635 if (node
== NULL
|| node
== summaryview
->selected
) {
1638 switch (prefs_common
.next_unread_msg_dialog
) {
1639 case NEXTUNREADMSGDIALOG_ALWAYS
:
1640 val
= alertpanel(_("No more unread messages"),
1641 _("No unread message found. "
1642 "Go to next folder?"),
1643 GTK_STOCK_NO
, "+"GTK_STOCK_YES
, NULL
);
1645 case NEXTUNREADMSGDIALOG_ASSUME_YES
:
1646 val
= G_ALERTALTERNATE
;
1648 case NEXTUNREADMSGDIALOG_ASSUME_NO
:
1653 _("Internal error: unexpected value for prefs_common.next_unread_msg_dialog\n"));
1656 if (val
== G_ALERTALTERNATE
) {
1657 folderview_select_next_unread(summaryview
->folderview
, TRUE
);
1663 summary_select_node(summaryview
, node
, TRUE
, FALSE
);
1668 void summary_select_prev_new(SummaryView
*summaryview
)
1671 gboolean skip_cur
= FALSE
;
1673 if (summaryview
->displayed
1674 && summaryview
->selected
== summaryview
->displayed
) {
1675 debug_print("skipping current\n");
1679 node
= summary_find_prev_flagged_msg
1680 (summaryview
, summaryview
->selected
, MSG_NEW
, skip_cur
);
1682 if (!node
|| node
== summaryview
->selected
) {
1685 switch (prefs_common
.next_unread_msg_dialog
) {
1686 case NEXTUNREADMSGDIALOG_ALWAYS
:
1687 val
= alertpanel(_("No more new messages"),
1688 _("No new message found. "
1689 "Search from the end?"),
1690 GTK_STOCK_NO
, "+"GTK_STOCK_YES
, NULL
);
1692 case NEXTUNREADMSGDIALOG_ASSUME_YES
:
1693 val
= G_ALERTALTERNATE
;
1695 case NEXTUNREADMSGDIALOG_ASSUME_NO
:
1696 val
= !G_ALERTALTERNATE
;
1700 _("Internal error: unexpected value for prefs_common.next_unread_msg_dialog\n"));
1702 if (val
!= G_ALERTALTERNATE
) return;
1703 node
= summary_find_prev_flagged_msg(summaryview
, NULL
,
1708 alertpanel_notice(_("No new messages."));
1710 summary_select_node(summaryview
, node
, TRUE
, FALSE
);
1713 void summary_select_next_new(SummaryView
*summaryview
)
1715 GtkCTreeNode
*node
= summaryview
->selected
;
1716 gboolean skip_cur
= FALSE
;
1718 if (summaryview
->displayed
1719 && summaryview
->selected
== summaryview
->displayed
) {
1720 debug_print("skipping cur (%p %p)\n",
1721 summaryview
->displayed
, summaryview
->selected
);
1726 node
= summary_find_next_flagged_msg
1727 (summaryview
, node
, MSG_NEW
, skip_cur
);
1730 summary_select_node(summaryview
, node
, TRUE
, FALSE
);
1732 node
= summary_find_next_flagged_msg
1733 (summaryview
, NULL
, MSG_NEW
, FALSE
);
1734 if (node
== NULL
|| node
== summaryview
->selected
) {
1737 switch (prefs_common
.next_unread_msg_dialog
) {
1738 case NEXTUNREADMSGDIALOG_ALWAYS
:
1739 val
= alertpanel(_("No more new messages"),
1740 _("No new message found. "
1741 "Go to next folder?"),
1742 GTK_STOCK_NO
, "+"GTK_STOCK_YES
, NULL
);
1744 case NEXTUNREADMSGDIALOG_ASSUME_YES
:
1745 val
= G_ALERTALTERNATE
;
1747 case NEXTUNREADMSGDIALOG_ASSUME_NO
:
1752 _("Internal error: unexpected value for prefs_common.next_unread_msg_dialog\n"));
1755 if (val
== G_ALERTALTERNATE
) {
1756 folderview_select_next_new(summaryview
->folderview
);
1762 summary_select_node(summaryview
, node
, TRUE
, FALSE
);
1767 void summary_select_prev_marked(SummaryView
*summaryview
)
1771 node
= summary_find_prev_flagged_msg
1772 (summaryview
, summaryview
->selected
, MSG_MARKED
, TRUE
);
1777 val
= alertpanel(_("No more marked messages"),
1778 _("No marked message found. "
1779 "Search from the end?"),
1780 GTK_STOCK_NO
, "+"GTK_STOCK_YES
, NULL
);
1781 if (val
!= G_ALERTALTERNATE
) return;
1782 node
= summary_find_prev_flagged_msg(summaryview
, NULL
,
1787 alertpanel_notice(_("No marked messages."));
1789 summary_select_node(summaryview
, node
, TRUE
, FALSE
);
1792 void summary_select_next_marked(SummaryView
*summaryview
)
1794 GtkCTreeNode
*node
= summaryview
->selected
;
1795 gboolean skip_cur
= FALSE
;
1797 if (summaryview
->displayed
1798 && summaryview
->selected
== summaryview
->displayed
) {
1799 debug_print("skipping cur (%p %p)\n",
1800 summaryview
->displayed
, summaryview
->selected
);
1805 node
= summary_find_next_flagged_msg
1806 (summaryview
, node
, MSG_MARKED
, skip_cur
);
1809 summary_select_node(summaryview
, node
, TRUE
, FALSE
);
1811 node
= summary_find_next_flagged_msg
1812 (summaryview
, NULL
, MSG_MARKED
, FALSE
);
1813 if (node
== NULL
|| node
== summaryview
->selected
) {
1816 switch (prefs_common
.next_unread_msg_dialog
) {
1817 case NEXTUNREADMSGDIALOG_ALWAYS
:
1818 val
= alertpanel(_("No more marked messages"),
1819 _("No marked message found. "
1820 "Go to next folder?"),
1821 GTK_STOCK_NO
, "+"GTK_STOCK_YES
, NULL
);
1823 case NEXTUNREADMSGDIALOG_ASSUME_YES
:
1824 val
= G_ALERTALTERNATE
;
1826 case NEXTUNREADMSGDIALOG_ASSUME_NO
:
1831 _("Internal error: unexpected value for prefs_common.next_unread_msg_dialog\n"));
1834 if (val
== G_ALERTALTERNATE
) {
1835 folderview_select_next_marked(summaryview
->folderview
);
1841 summary_select_node(summaryview
, node
, TRUE
, FALSE
);
1846 void summary_select_prev_labeled(SummaryView
*summaryview
)
1850 node
= summary_find_prev_flagged_msg
1851 (summaryview
, summaryview
->selected
, MSG_CLABEL_FLAG_MASK
, TRUE
);
1856 val
= alertpanel(_("No more labeled messages"),
1857 _("No labeled message found. "
1858 "Search from the end?"),
1859 GTK_STOCK_NO
, "+"GTK_STOCK_YES
, NULL
);
1860 if (val
!= G_ALERTALTERNATE
) return;
1861 node
= summary_find_prev_flagged_msg(summaryview
, NULL
,
1862 MSG_CLABEL_FLAG_MASK
, TRUE
);
1866 alertpanel_notice(_("No labeled messages."));
1868 summary_select_node(summaryview
, node
, TRUE
, FALSE
);
1871 void summary_select_next_labeled(SummaryView
*summaryview
)
1875 node
= summary_find_next_flagged_msg
1876 (summaryview
, summaryview
->selected
, MSG_CLABEL_FLAG_MASK
, TRUE
);
1881 val
= alertpanel(_("No more labeled messages"),
1882 _("No labeled message found. "
1883 "Search from the beginning?"),
1884 GTK_STOCK_NO
, "+"GTK_STOCK_YES
, NULL
);
1885 if (val
!= G_ALERTALTERNATE
) return;
1886 node
= summary_find_next_flagged_msg(summaryview
, NULL
,
1887 MSG_CLABEL_FLAG_MASK
, TRUE
);
1891 alertpanel_notice(_("No labeled messages."));
1893 summary_select_node(summaryview
, node
, TRUE
, FALSE
);
1896 void summary_select_last_read(SummaryView
*summaryview
)
1898 if (summaryview
->last_displayed
)
1899 summary_select_node(summaryview
, summaryview
->last_displayed
, TRUE
, FALSE
);
1902 void summary_select_parent(SummaryView
*summaryview
)
1904 GtkCTreeNode
*node
= NULL
;
1906 if (summaryview
->selected
)
1907 node
= GTK_CTREE_ROW(summaryview
->selected
)->parent
;
1909 summary_select_node(summaryview
, node
, TRUE
, FALSE
);
1912 void summary_select_by_msgnum(SummaryView
*summaryview
, guint msgnum
)
1916 node
= summary_find_msg_by_msgnum(summaryview
, msgnum
);
1917 summary_select_node(summaryview
, node
, FALSE
, TRUE
);
1920 typedef struct _PostponedSelectData
1927 SummaryView
*summaryview
;
1928 gboolean display_msg
;
1929 gboolean do_refresh
;
1930 } PostponedSelectData
;
1932 static gboolean
summary_select_retry(void *data
)
1934 PostponedSelectData
*psdata
= (PostponedSelectData
*)data
;
1935 debug_print("trying again\n");
1937 summary_selected(psdata
->ctree
, psdata
->row
,
1938 psdata
->column
, psdata
->summaryview
);
1939 else if (psdata
->node
)
1940 summary_select_node(psdata
->summaryview
, psdata
->node
,
1941 psdata
->display_msg
, psdata
->do_refresh
);
1943 summary_step(psdata
->summaryview
, psdata
->type
);
1949 * summary_select_node:
1950 * @summaryview: Summary view.
1951 * @node: Summary tree node.
1952 * @display_msg: TRUE to display the selected message.
1953 * @do_refresh: TRUE to refresh the widget.
1955 * Select @node (bringing it into view by scrolling and expanding its
1956 * thread, if necessary) and unselect all others. If @display_msg is
1957 * TRUE, display the corresponding message in the message view.
1958 * If @do_refresh is TRUE, the widget is refreshed.
1960 void summary_select_node(SummaryView
*summaryview
, GtkCTreeNode
*node
,
1961 gboolean display_msg
, gboolean do_refresh
)
1963 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
1965 if (summary_is_locked(summaryview
)
1966 && !GTK_SCTREE(ctree
)->selecting_range
1967 && summaryview
->messageview
->mimeview
1968 && summaryview
->messageview
->mimeview
->type
== MIMEVIEW_TEXT
1969 && summaryview
->messageview
->mimeview
->textview
->loading
) {
1970 PostponedSelectData
*data
= g_new0(PostponedSelectData
, 1);
1971 summaryview
->messageview
->mimeview
->textview
->stop_loading
= TRUE
;
1973 data
->ctree
= ctree
;
1976 data
->summaryview
= summaryview
;
1977 data
->display_msg
= display_msg
;
1978 data
->do_refresh
= do_refresh
;
1979 debug_print("postponing open of message till end of load\n");
1980 g_timeout_add(100, summary_select_retry
, data
);
1983 if (summary_is_locked(summaryview
)) {
1986 if (!summaryview
->folder_item
)
1989 gtkut_ctree_expand_parent_all(ctree
, node
);
1991 summary_lock(summaryview
);
1993 summary_unlock(summaryview
);
1994 gtk_widget_grab_focus(GTK_WIDGET(ctree
));
1995 gtk_ctree_node_moveto(ctree
, node
, 0, 0.5, 0);
1997 if (display_msg
&& summaryview
->displayed
== node
)
1998 summaryview
->displayed
= NULL
;
1999 summaryview
->display_msg
= display_msg
;
2000 gtk_sctree_select(GTK_SCTREE(ctree
), node
);
2001 if (summaryview
->selected
== NULL
)
2002 summaryview
->selected
= node
;
2006 guint
summary_get_msgnum(SummaryView
*summaryview
, GtkCTreeNode
*node
)
2008 GtkCTree
*ctree
=NULL
;
2013 ctree
= GTK_CTREE(summaryview
->ctree
);
2016 msginfo
= gtk_ctree_node_get_row_data(ctree
, node
);
2018 return msginfo
->msgnum
;
2023 static GtkCTreeNode
*summary_find_prev_msg(SummaryView
*summaryview
,
2024 GtkCTreeNode
*current_node
)
2026 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
2031 node
= current_node
;
2033 node
= gtk_ctree_node_nth(ctree
, GTK_CLIST(ctree
)->rows
- 1);
2035 for (; node
!= NULL
; node
= GTK_CTREE_NODE_PREV(node
)) {
2036 msginfo
= gtk_ctree_node_get_row_data(ctree
, node
);
2037 if (msginfo
&& !MSG_IS_DELETED(msginfo
->flags
)) break;
2043 static GtkCTreeNode
*summary_find_next_msg(SummaryView
*summaryview
,
2044 GtkCTreeNode
*current_node
)
2046 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
2051 node
= current_node
;
2053 node
= GTK_CTREE_NODE(GTK_CLIST(ctree
)->row_list
);
2055 for (; node
!= NULL
; node
= gtkut_ctree_node_next(ctree
, node
)) {
2056 msginfo
= gtk_ctree_node_get_row_data(ctree
, node
);
2057 if (msginfo
&& !MSG_IS_DELETED(msginfo
->flags
)
2058 && !MSG_IS_MOVE(msginfo
->flags
)) break;
2064 static GtkCTreeNode
*summary_find_prev_flagged_msg(SummaryView
*summaryview
,
2065 GtkCTreeNode
*current_node
,
2067 gboolean start_from_prev
)
2069 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
2074 if (start_from_prev
)
2075 node
= GTK_CTREE_NODE_PREV(current_node
);
2077 node
= current_node
;
2079 node
= gtk_ctree_node_nth(ctree
, GTK_CLIST(ctree
)->rows
- 1);
2081 for (; node
!= NULL
; node
= GTK_CTREE_NODE_PREV(node
)) {
2082 msginfo
= gtk_ctree_node_get_row_data(ctree
, node
);
2083 if (msginfo
&& (msginfo
->flags
.perm_flags
& flags
) != 0) break;
2089 static GtkCTreeNode
*summary_find_next_flagged_msg(SummaryView
*summaryview
,
2090 GtkCTreeNode
*current_node
,
2092 gboolean start_from_next
)
2094 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
2099 if (start_from_next
)
2100 node
= gtkut_ctree_node_next(ctree
, current_node
);
2102 node
= current_node
;
2104 node
= GTK_CTREE_NODE(GTK_CLIST(ctree
)->row_list
);
2106 for (; node
!= NULL
; node
= gtkut_ctree_node_next(ctree
, node
)) {
2107 msginfo
= gtk_ctree_node_get_row_data(ctree
, node
);
2108 /* Find msg with matching flags but ignore messages with
2109 ignore flags, if searching for new or unread messages */
2110 if ((msginfo
&& (msginfo
->flags
.perm_flags
& flags
) != 0) &&
2111 !(((flags
& (MSG_NEW
| MSG_UNREAD
)) != 0) && MSG_IS_IGNORE_THREAD(msginfo
->flags
))
2119 static GtkCTreeNode
*summary_find_msg_by_msgnum(SummaryView
*summaryview
,
2122 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
2126 node
= GTK_CTREE_NODE(GTK_CLIST(ctree
)->row_list
);
2128 for (; node
!= NULL
; node
= gtkut_ctree_node_next(ctree
, node
)) {
2129 msginfo
= gtk_ctree_node_get_row_data(ctree
, node
);
2130 if (msginfo
&& msginfo
->msgnum
== msgnum
) break;
2136 static guint
attract_hash_func(gconstpointer key
)
2142 Xstrdup_a(str
, (const gchar
*)key
, return 0);
2149 for (p
+= 1; *p
!= '\0'; p
++)
2150 h
= (h
<< 5) - h
+ *p
;
2156 static gint
attract_compare_func(gconstpointer a
, gconstpointer b
)
2158 return subject_compare((const gchar
*)a
, (const gchar
*)b
) == 0;
2161 void summary_attract_by_subject(SummaryView
*summaryview
)
2163 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
2164 GtkCList
*clist
= GTK_CLIST(ctree
);
2165 GtkCTreeNode
*src_node
;
2166 GtkCTreeNode
*dst_node
, *sibling
;
2168 MsgInfo
*src_msginfo
, *dst_msginfo
;
2169 GHashTable
*subject_table
;
2171 debug_print("Attracting messages by subject...");
2172 STATUSBAR_PUSH(summaryview
->mainwin
,
2173 _("Attracting messages by subject..."));
2175 main_window_cursor_wait(summaryview
->mainwin
);
2176 summary_freeze(summaryview
);
2178 subject_table
= g_hash_table_new(attract_hash_func
,
2179 attract_compare_func
);
2181 for (src_node
= GTK_CTREE_NODE(clist
->row_list
);
2184 tmp
= GTK_CTREE_ROW(src_node
)->sibling
;
2185 src_msginfo
= GTKUT_CTREE_NODE_GET_ROW_DATA(src_node
);
2186 if (!src_msginfo
) continue;
2187 if (!src_msginfo
->subject
) continue;
2189 /* find attracting node */
2190 dst_node
= g_hash_table_lookup(subject_table
,
2191 src_msginfo
->subject
);
2194 dst_msginfo
= GTKUT_CTREE_NODE_GET_ROW_DATA(dst_node
);
2196 /* if the time difference is more than 20 days,
2198 if (ABS(src_msginfo
->date_t
- dst_msginfo
->date_t
)
2199 > 60 * 60 * 24 * 20)
2202 sibling
= GTK_CTREE_ROW(dst_node
)->sibling
;
2203 if (src_node
!= sibling
)
2204 gtk_ctree_move(ctree
, src_node
, NULL
, sibling
);
2207 g_hash_table_insert(subject_table
,
2208 src_msginfo
->subject
, src_node
);
2211 g_hash_table_destroy(subject_table
);
2213 gtk_ctree_node_moveto(ctree
, summaryview
->selected
, 0, 0.5, 0);
2215 summary_thaw(summaryview
);
2217 debug_print("done.\n");
2218 STATUSBAR_POP(summaryview
->mainwin
);
2220 main_window_cursor_normal(summaryview
->mainwin
);
2223 static void summary_free_msginfo_func(GtkCTree
*ctree
, GtkCTreeNode
*node
,
2226 MsgInfo
*msginfo
= gtk_ctree_node_get_row_data(ctree
, node
);
2229 procmsg_msginfo_free(msginfo
);
2232 static void summary_set_marks_func(GtkCTree
*ctree
, GtkCTreeNode
*node
,
2235 SummaryView
*summaryview
= data
;
2238 msginfo
= gtk_ctree_node_get_row_data(ctree
, node
);
2240 if (MSG_IS_DELETED(msginfo
->flags
))
2241 summaryview
->deleted
++;
2243 summaryview
->total_size
+= msginfo
->size
;
2245 summary_set_row_marks(summaryview
, node
);
2248 static void summary_update_status(SummaryView
*summaryview
)
2250 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
2254 summaryview
->total_size
=
2255 summaryview
->deleted
= summaryview
->moved
= summaryview
->copied
= 0;
2257 for (node
= GTK_CTREE_NODE(GTK_CLIST(ctree
)->row_list
);
2258 node
!= NULL
; node
= gtkut_ctree_node_next(ctree
, node
)) {
2259 msginfo
= GTKUT_CTREE_NODE_GET_ROW_DATA(node
);
2261 if (MSG_IS_DELETED(msginfo
->flags
))
2262 summaryview
->deleted
++;
2263 if (MSG_IS_MOVE(msginfo
->flags
))
2264 summaryview
->moved
++;
2265 if (MSG_IS_COPY(msginfo
->flags
))
2266 summaryview
->copied
++;
2267 summaryview
->total_size
+= msginfo
->size
;
2271 static void summary_status_show(SummaryView
*summaryview
)
2274 gchar
*del
, *mv
, *cp
;
2278 GList
*rowlist
, *cur
;
2279 guint n_selected
= 0, n_new
= 0, n_unread
= 0, n_total
= 0;
2280 off_t sel_size
= 0, n_size
= 0;
2284 if (!summaryview
->folder_item
) {
2285 gtk_label_set_text(GTK_LABEL(summaryview
->statlabel_folder
), "");
2286 gtk_label_set_text(GTK_LABEL(summaryview
->statlabel_select
), "");
2287 gtk_label_set_text(GTK_LABEL(summaryview
->statlabel_msgs
), "");
2288 toolbar_main_set_sensitive(summaryview
->mainwin
);
2292 rowlist
= GTK_CLIST(summaryview
->ctree
)->selection
;
2293 for (cur
= rowlist
; cur
!= NULL
&& cur
->data
!= NULL
; cur
= cur
->next
) {
2294 msginfo
= gtk_ctree_node_get_row_data
2295 (GTK_CTREE(summaryview
->ctree
),
2296 GTK_CTREE_NODE(cur
->data
));
2298 sel_size
+= msginfo
->size
;
2303 if (summaryview
->folder_item
->hide_read_msgs
2304 || quicksearch_is_active(summaryview
->quicksearch
)) {
2305 rowlist
= GTK_CLIST(summaryview
->ctree
)->row_list
;
2306 for (cur
= rowlist
; cur
!= NULL
&& cur
->data
!= NULL
; cur
= cur
->next
) {
2307 msginfo
= gtk_ctree_node_get_row_data
2308 (GTK_CTREE(summaryview
->ctree
),
2309 GTK_CTREE_NODE(cur
));
2311 n_size
+= msginfo
->size
;
2313 if (MSG_IS_NEW(msginfo
->flags
))
2315 if (MSG_IS_UNREAD(msginfo
->flags
))
2320 n_new
= summaryview
->folder_item
->new_msgs
;
2321 n_unread
= summaryview
->folder_item
->unread_msgs
;
2322 n_total
= summaryview
->folder_item
->total_msgs
;
2323 n_size
= summaryview
->total_size
;
2326 name
= folder_item_get_name(summaryview
->folder_item
);
2327 gtk_label_set_text(GTK_LABEL(summaryview
->statlabel_folder
), name
);
2330 if (summaryview
->deleted
)
2331 del
= g_strdup_printf(_("%d deleted"), summaryview
->deleted
);
2334 if (summaryview
->moved
)
2335 mv
= g_strdup_printf(_("%s%d moved"),
2336 summaryview
->deleted
? _(", ") : "",
2337 summaryview
->moved
);
2340 if (summaryview
->copied
)
2341 cp
= g_strdup_printf(_("%s%d copied"),
2342 summaryview
->deleted
||
2343 summaryview
->moved
? _(", ") : "",
2344 summaryview
->copied
);
2348 if (summaryview
->deleted
|| summaryview
->moved
|| summaryview
->copied
)
2354 sel
= g_strdup_printf(" (%s)", to_human_readable(sel_size
));
2355 if (n_selected
== 1)
2356 itstr
= g_strdup(_(" item selected"));
2358 itstr
= g_strdup(_(" items selected"));
2361 itstr
= g_strdup("");
2364 str
= g_strconcat(n_selected
? itos(n_selected
) : "",
2365 itstr
, sel
, spc
, del
, mv
, cp
, NULL
);
2366 gtk_label_set_text(GTK_LABEL(summaryview
->statlabel_select
), str
);
2374 str
= g_strdup_printf(_("%d new, %d unread, %d total (%s)"),
2376 n_new
, n_unread
, n_total
,
2377 to_human_readable(n_size
));
2378 gtk_label_set_text(GTK_LABEL(summaryview
->statlabel_msgs
), str
);
2380 toolbar_main_set_sensitive(summaryview
->mainwin
);
2383 static void summary_set_column_titles(SummaryView
*summaryview
)
2385 GtkCList
*clist
= GTK_CLIST(summaryview
->ctree
);
2386 FolderItem
*item
= summaryview
->folder_item
;
2392 SummaryColumnType type
;
2393 GtkJustification justify
;
2395 static FolderSortKey sort_by
[N_SUMMARY_COLS
] = {
2409 for (pos
= 0; pos
< N_SUMMARY_COLS
; pos
++) {
2410 type
= summaryview
->col_state
[pos
].type
;
2412 /* CLAWS: mime and unread are single char headers */
2413 justify
= (type
== S_COL_NUMBER
|| type
== S_COL_SIZE
)
2414 ? GTK_JUSTIFY_RIGHT
: GTK_JUSTIFY_LEFT
;
2422 if(type
== S_COL_FROM
&& item
!= NULL
&&
2423 FOLDER_SHOWS_TO_HDR(item
) &&
2424 !summaryview
->col_state
[summaryview
->col_pos
[S_COL_TO
]].visible
)
2426 if (prefs_common
.trans_hdr
)
2427 title
= gettext(col_label
[type
]);
2429 title
= col_label
[type
];
2432 title
= gettext(col_label
[type
]);
2435 if (type
== S_COL_MIME
) {
2436 label
= gtk_image_new_from_pixmap(clipxpm
, clipxpmmask
);
2437 gtk_widget_show(label
);
2438 gtk_clist_set_column_widget(clist
, pos
, label
);
2439 gtk_sctree_set_column_tooltip(GTK_SCTREE(clist
), pos
, _("Attachment"));
2441 } else if (type
== S_COL_MARK
) {
2442 label
= gtk_image_new_from_pixmap(markxpm
, markxpmmask
);
2443 gtk_widget_show(label
);
2444 gtk_clist_set_column_widget(clist
, pos
, label
);
2445 gtk_sctree_set_column_tooltip(GTK_SCTREE(clist
), pos
, _("Mark"));
2447 } else if (type
== S_COL_LOCKED
) {
2448 label
= gtk_image_new_from_pixmap(lockedxpm
, lockedxpmmask
);
2449 gtk_widget_show(label
);
2450 gtk_clist_set_column_widget(clist
, pos
, label
);
2451 gtk_sctree_set_column_tooltip(GTK_SCTREE(clist
), pos
, _("Locked"));
2453 } else if (type
== S_COL_STATUS
) {
2454 gtk_clist_set_column_title(clist
, pos
, title
);
2455 gtk_sctree_set_column_tooltip(GTK_SCTREE(clist
), pos
, _("Status"));
2459 hbox
= gtk_hbox_new(FALSE
, 4);
2460 label
= gtk_label_new(title
);
2462 if (justify
== GTK_JUSTIFY_RIGHT
)
2463 gtk_box_pack_end(GTK_BOX(hbox
), label
,
2466 gtk_box_pack_start(GTK_BOX(hbox
), label
,
2469 if (summaryview
->sort_key
== sort_by
[type
]) {
2470 arrow
= gtk_arrow_new
2471 (summaryview
->sort_type
== SORT_ASCENDING
2472 ? GTK_ARROW_DOWN
: GTK_ARROW_UP
,
2474 if (justify
== GTK_JUSTIFY_RIGHT
)
2475 gtk_box_pack_start(GTK_BOX(hbox
), arrow
,
2478 gtk_box_pack_end(GTK_BOX(hbox
), arrow
,
2482 gtk_widget_show_all(hbox
);
2483 gtk_clist_set_column_widget(clist
, pos
, hbox
);
2487 void summary_reflect_prefs(void)
2489 static gchar
*last_font
= NULL
;
2490 gboolean update_font
= TRUE
;
2491 SummaryView
*summaryview
= NULL
;
2493 if (!mainwindow_get_mainwindow())
2495 summaryview
= mainwindow_get_mainwindow()->summaryview
;
2497 if (last_font
&& !strcmp(last_font
, NORMAL_FONT
))
2498 update_font
= FALSE
;
2502 last_font
= g_strdup(NORMAL_FONT
);
2505 bold_style
= bold_marked_style
= bold_deleted_style
=
2506 small_style
= small_marked_style
= small_deleted_style
= NULL
;
2507 summary_set_fonts(summaryview
);
2510 summary_set_column_titles(summaryview
);
2511 summary_show(summaryview
, summaryview
->folder_item
);
2514 void summary_sort(SummaryView
*summaryview
,
2515 FolderSortKey sort_key
, FolderSortType sort_type
)
2517 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
2518 GtkCList
*clist
= GTK_CLIST(summaryview
->ctree
);
2519 GtkCListCompareFunc cmp_func
= NULL
;
2521 g_signal_handlers_block_by_func(G_OBJECT(summaryview
->ctree
),
2522 G_CALLBACK(summary_tree_expanded
), summaryview
);
2523 summary_freeze(summaryview
);
2527 cmp_func
= (GtkCListCompareFunc
)summary_cmp_by_mark
;
2529 case SORT_BY_STATUS
:
2530 cmp_func
= (GtkCListCompareFunc
)summary_cmp_by_status
;
2533 cmp_func
= (GtkCListCompareFunc
)summary_cmp_by_mime
;
2535 case SORT_BY_NUMBER
:
2536 cmp_func
= (GtkCListCompareFunc
)summary_cmp_by_num
;
2539 cmp_func
= (GtkCListCompareFunc
)summary_cmp_by_size
;
2542 cmp_func
= (GtkCListCompareFunc
)summary_cmp_by_date
;
2545 cmp_func
= (GtkCListCompareFunc
)summary_cmp_by_from
;
2547 case SORT_BY_SUBJECT
:
2548 if (summaryview
->simplify_subject_preg
)
2549 cmp_func
= (GtkCListCompareFunc
)summary_cmp_by_simplified_subject
;
2551 cmp_func
= (GtkCListCompareFunc
)summary_cmp_by_subject
;
2554 cmp_func
= (GtkCListCompareFunc
)summary_cmp_by_score
;
2557 cmp_func
= (GtkCListCompareFunc
)summary_cmp_by_label
;
2560 cmp_func
= (GtkCListCompareFunc
)summary_cmp_by_to
;
2562 case SORT_BY_LOCKED
:
2563 cmp_func
= (GtkCListCompareFunc
)summary_cmp_by_locked
;
2571 summaryview
->sort_key
= sort_key
;
2572 summaryview
->sort_type
= sort_type
;
2574 summary_set_column_titles(summaryview
);
2575 summary_set_menu_sensitive(summaryview
);
2577 /* allow fallback to don't sort */
2578 if (summaryview
->sort_key
== SORT_BY_NONE
)
2581 if (cmp_func
!= NULL
) {
2582 debug_print("Sorting summary...");
2583 STATUSBAR_PUSH(summaryview
->mainwin
, _("Sorting summary..."));
2585 main_window_cursor_wait(summaryview
->mainwin
);
2587 gtk_clist_set_compare_func(clist
, cmp_func
);
2589 gtk_clist_set_sort_type(clist
, (GtkSortType
)sort_type
);
2590 gtk_sctree_sort_recursive(ctree
, NULL
);
2592 gtk_ctree_node_moveto(ctree
, summaryview
->selected
, 0, 0.5, 0);
2594 main_window_cursor_normal(summaryview
->mainwin
);
2596 debug_print("done.\n");
2597 STATUSBAR_POP(summaryview
->mainwin
);
2600 summary_thaw(summaryview
);
2601 g_signal_handlers_unblock_by_func(G_OBJECT(summaryview
->ctree
),
2602 G_CALLBACK(summary_tree_expanded
), summaryview
);
2606 static gboolean
summary_insert_gnode_func(GtkCTree
*ctree
, guint depth
, GNode
*gnode
,
2607 GtkCTreeNode
*cnode
, gpointer data
)
2609 SummaryView
*summaryview
= (SummaryView
*)data
;
2610 MsgInfo
*msginfo
= (MsgInfo
*)gnode
->data
;
2611 gchar
*text
[N_SUMMARY_COLS
];
2612 gint
*col_pos
= summaryview
->col_pos
;
2613 const gchar
*msgid
= msginfo
->msgid
;
2614 GHashTable
*msgid_table
= summaryview
->msgid_table
;
2616 summary_set_header(summaryview
, text
, msginfo
);
2618 gtk_sctree_set_node_info(ctree
, cnode
, text
[col_pos
[S_COL_SUBJECT
]], 2,
2619 NULL
, NULL
, NULL
, NULL
, FALSE
, summaryview
->threaded
&& !summaryview
->thread_collapsed
);
2620 #define SET_TEXT(col) { \
2621 gtk_ctree_node_set_text(ctree, cnode, col_pos[col], \
2622 text[col_pos[col]]); \
2625 if (summaryview
->col_state
[summaryview
->col_pos
[S_COL_NUMBER
]].visible
)
2626 SET_TEXT(S_COL_NUMBER
);
2627 if (summaryview
->col_state
[summaryview
->col_pos
[S_COL_SCORE
]].visible
)
2628 SET_TEXT(S_COL_SCORE
);
2629 if (summaryview
->col_state
[summaryview
->col_pos
[S_COL_SIZE
]].visible
)
2630 SET_TEXT(S_COL_SIZE
);
2631 if (summaryview
->col_state
[summaryview
->col_pos
[S_COL_DATE
]].visible
)
2632 SET_TEXT(S_COL_DATE
);
2633 if (summaryview
->col_state
[summaryview
->col_pos
[S_COL_FROM
]].visible
)
2634 SET_TEXT(S_COL_FROM
);
2635 if (summaryview
->col_state
[summaryview
->col_pos
[S_COL_TO
]].visible
)
2640 GTKUT_CTREE_NODE_SET_ROW_DATA(cnode
, msginfo
);
2641 summary_set_marks_func(ctree
, cnode
, summaryview
);
2643 if (msgid
&& msgid
[0] != '\0')
2644 g_hash_table_insert(msgid_table
, (gchar
*)msgid
, cnode
);
2649 static void summary_set_ctree_from_list(SummaryView
*summaryview
,
2652 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
2654 GtkCTreeNode
*node
= NULL
;
2655 GHashTable
*msgid_table
;
2656 GHashTable
*subject_table
= NULL
;
2662 debug_print("\tSetting summary from message data...\n");
2663 STATUSBAR_PUSH(summaryview
->mainwin
,
2664 _("Setting summary from message data..."));
2667 g_signal_handlers_block_by_func(G_OBJECT(ctree
),
2668 G_CALLBACK(summary_tree_expanded
), summaryview
);
2670 msgid_table
= g_hash_table_new(g_str_hash
, g_str_equal
);
2671 summaryview
->msgid_table
= msgid_table
;
2673 if (prefs_common
.thread_by_subject
) {
2674 subject_table
= g_hash_table_new(g_str_hash
, g_str_equal
);
2675 summaryview
->subject_table
= subject_table
;
2677 summaryview
->subject_table
= NULL
;
2680 if (prefs_common
.use_addr_book
)
2681 start_address_completion(NULL
);
2683 if (summaryview
->threaded
) {
2684 GNode
*root
, *gnode
;
2685 START_TIMING("threaded");
2686 root
= procmsg_get_thread_tree(mlist
);
2688 for (gnode
= root
->children
; gnode
!= NULL
;
2689 gnode
= gnode
->next
) {
2690 node
= gtk_sctree_insert_gnode
2691 (ctree
, NULL
, node
, gnode
,
2692 summary_insert_gnode_func
, summaryview
);
2695 g_node_destroy(root
);
2699 gchar
*text
[N_SUMMARY_COLS
];
2700 START_TIMING("unthreaded");
2702 for (; mlist
!= NULL
; mlist
= mlist
->next
) {
2703 msginfo
= (MsgInfo
*)mlist
->data
;
2705 summary_set_header(summaryview
, text
, msginfo
);
2707 node
= gtk_sctree_insert_node
2708 (ctree
, NULL
, node
, text
, 2,
2709 NULL
, NULL
, NULL
, NULL
,
2712 GTKUT_CTREE_NODE_SET_ROW_DATA(node
, msginfo
);
2713 summary_set_marks_func(ctree
, node
, summaryview
);
2715 if (msginfo
->msgid
&& msginfo
->msgid
[0] != '\0')
2716 g_hash_table_insert(msgid_table
,
2717 msginfo
->msgid
, node
);
2719 if (prefs_common
.thread_by_subject
)
2720 subject_table_insert(subject_table
,
2728 if (prefs_common
.enable_hscrollbar
&&
2729 summaryview
->col_pos
[S_COL_SUBJECT
] == N_SUMMARY_COLS
- 1) {
2732 optimal_width
= gtk_clist_optimal_column_width
2733 (GTK_CLIST(ctree
), summaryview
->col_pos
[S_COL_SUBJECT
]);
2734 gtk_clist_set_column_width(GTK_CLIST(ctree
),
2735 summaryview
->col_pos
[S_COL_SUBJECT
],
2739 if (prefs_common
.use_addr_book
)
2740 end_address_completion();
2742 debug_print("done.\n");
2743 STATUSBAR_POP(summaryview
->mainwin
);
2744 if (debug_get_mode()) {
2745 debug_print("\tmsgid hash table size = %d\n",
2746 g_hash_table_size(msgid_table
));
2747 if (prefs_common
.thread_by_subject
)
2748 debug_print("\tsubject hash table size = %d\n",
2749 g_hash_table_size(subject_table
));
2752 summary_sort(summaryview
, summaryview
->sort_key
, summaryview
->sort_type
);
2754 node
= GTK_CTREE_NODE(GTK_CLIST(ctree
)->row_list
);
2756 if (prefs_common
.bold_unread
) {
2757 START_TIMING("bold_unread");
2759 GtkCTreeNode
*next
= GTK_CTREE_NODE_NEXT(node
);
2760 if (GTK_CTREE_ROW(node
)->children
)
2761 summary_set_row_marks(summaryview
, node
);
2767 g_signal_handlers_unblock_by_func(G_OBJECT(ctree
),
2768 G_CALLBACK(summary_tree_expanded
), summaryview
);
2772 static gchar
*summary_complete_address(const gchar
*addr
)
2775 gchar
*res
, *tmp
, *email_addr
;
2780 Xstrdup_a(email_addr
, addr
, return NULL
);
2781 extract_address(email_addr
);
2786 * completion stuff must be already initialized
2789 if (1 < (count
= complete_address(email_addr
))) {
2790 tmp
= get_complete_address(1);
2791 res
= procheader_get_fromname(tmp
);
2798 static void summary_set_header(SummaryView
*summaryview
, gchar
*text
[],
2801 static gchar date_modified
[80];
2802 static gchar col_score
[11];
2803 static gchar buf
[BUFFSIZE
];
2804 gint
*col_pos
= summaryview
->col_pos
;
2805 gchar
*from_text
= NULL
, *to_text
= NULL
;
2806 gboolean should_swap
= FALSE
;
2808 text
[col_pos
[S_COL_FROM
]] = "";
2809 text
[col_pos
[S_COL_TO
]] = "";
2810 text
[col_pos
[S_COL_SUBJECT
]]= "";
2811 text
[col_pos
[S_COL_MARK
]] = "";
2812 text
[col_pos
[S_COL_STATUS
]] = "";
2813 text
[col_pos
[S_COL_MIME
]] = "";
2814 text
[col_pos
[S_COL_LOCKED
]] = "";
2815 text
[col_pos
[S_COL_DATE
]] = "";
2816 if (summaryview
->col_state
[summaryview
->col_pos
[S_COL_NUMBER
]].visible
)
2817 text
[col_pos
[S_COL_NUMBER
]] = itos(msginfo
->msgnum
);
2819 text
[col_pos
[S_COL_NUMBER
]] = "";
2822 if (summaryview
->col_state
[summaryview
->col_pos
[S_COL_SIZE
]].visible
)
2823 text
[col_pos
[S_COL_SIZE
]] = to_human_readable(msginfo
->size
);
2825 text
[col_pos
[S_COL_SIZE
]] = "";
2827 if (summaryview
->col_state
[summaryview
->col_pos
[S_COL_SCORE
]].visible
)
2828 text
[col_pos
[S_COL_SCORE
]] = itos_buf(col_score
, msginfo
->score
);
2830 text
[col_pos
[S_COL_SCORE
]] = "";
2833 if (summaryview
->col_state
[summaryview
->col_pos
[S_COL_DATE
]].visible
) {
2834 if (msginfo
->date_t
) {
2835 procheader_date_get_localtime(date_modified
,
2836 sizeof(date_modified
),
2838 text
[col_pos
[S_COL_DATE
]] = date_modified
;
2839 } else if (msginfo
->date
)
2840 text
[col_pos
[S_COL_DATE
]] = msginfo
->date
;
2842 text
[col_pos
[S_COL_DATE
]] = _("(No Date)");
2845 if (prefs_common
.swap_from
&& msginfo
->from
&& msginfo
->to
2846 && !summaryview
->col_state
[summaryview
->col_pos
[S_COL_TO
]].visible
) {
2849 addr
= g_strdup(msginfo
->from
);
2852 extract_address(addr
);
2853 if (account_find_from_address(addr
)) {
2860 if (!prefs_common
.use_addr_book
) {
2861 from_text
= msginfo
->fromname
?
2865 gchar buf
[BUFFSIZE
];
2866 gchar
*tmp
= summary_complete_address(msginfo
->from
);
2868 strncpy2(buf
, tmp
, sizeof(buf
));
2872 from_text
= (msginfo
->fromname
) ?
2878 to_text
= msginfo
->to
? msginfo
->to
:
2879 (msginfo
->cc
? msginfo
->cc
:
2880 (msginfo
->newsgroups
? msginfo
->newsgroups
: _("(No Recipient)")
2884 text
[col_pos
[S_COL_TO
]] = to_text
;
2886 text
[col_pos
[S_COL_FROM
]] = from_text
;
2888 gchar tmp
[BUFFSIZE
];
2889 snprintf(tmp
, BUFFSIZE
-1, "--> %s", to_text
);
2890 tmp
[BUFFSIZE
-1]='\0';
2891 text
[col_pos
[S_COL_FROM
]] = tmp
;
2894 if (summaryview
->simplify_subject_preg
!= NULL
)
2895 text
[col_pos
[S_COL_SUBJECT
]] = msginfo
->subject
?
2896 string_remove_match(buf
, BUFFSIZE
, msginfo
->subject
,
2897 summaryview
->simplify_subject_preg
) :
2900 text
[col_pos
[S_COL_SUBJECT
]] = msginfo
->subject
? msginfo
->subject
:
2904 static void summary_display_msg(SummaryView
*summaryview
, GtkCTreeNode
*row
)
2906 summary_display_msg_full(summaryview
, row
, FALSE
, FALSE
);
2909 static gboolean
defer_change(gpointer data
);
2910 typedef struct _ChangeData
{
2912 gint op
; /* 0, 1, 2 for unset, set, change */
2913 MsgPermFlags set_flags
;
2914 MsgTmpFlags set_tmp_flags
;
2915 MsgPermFlags unset_flags
;
2916 MsgTmpFlags unset_tmp_flags
;
2919 static void summary_msginfo_unset_flags(MsgInfo
*msginfo
, MsgPermFlags flags
, MsgTmpFlags tmp_flags
)
2921 if (!msginfo
->folder
|| !msginfo
->folder
->processing_pending
) {
2922 debug_print("flags: doing unset now\n");
2923 procmsg_msginfo_unset_flags(msginfo
, flags
, tmp_flags
);
2925 ChangeData
*unset_data
= g_new0(ChangeData
, 1);
2926 unset_data
->info
= msginfo
;
2928 unset_data
->unset_flags
= flags
;
2929 unset_data
->unset_tmp_flags
= tmp_flags
;
2930 debug_print("flags: deferring unset\n");
2931 g_timeout_add(100, defer_change
, unset_data
);
2935 static void summary_msginfo_set_flags(MsgInfo
*msginfo
, MsgPermFlags flags
, MsgTmpFlags tmp_flags
)
2937 if (!msginfo
->folder
|| !msginfo
->folder
->processing_pending
) {
2938 debug_print("flags: doing set now\n");
2939 procmsg_msginfo_set_flags(msginfo
, flags
, tmp_flags
);
2941 ChangeData
*set_data
= g_new0(ChangeData
, 1);
2942 set_data
->info
= msginfo
;
2944 set_data
->set_flags
= flags
;
2945 set_data
->set_tmp_flags
= tmp_flags
;
2946 debug_print("flags: deferring set\n");
2947 g_timeout_add(100, defer_change
, set_data
);
2951 static void summary_msginfo_change_flags(MsgInfo
*msginfo
,
2952 MsgPermFlags add_flags
, MsgTmpFlags add_tmp_flags
,
2953 MsgPermFlags rem_flags
, MsgTmpFlags rem_tmp_flags
)
2955 if (!msginfo
->folder
|| !msginfo
->folder
->processing_pending
) {
2956 debug_print("flags: doing change now\n");
2957 procmsg_msginfo_change_flags(msginfo
, add_flags
, add_tmp_flags
,
2958 rem_flags
, rem_tmp_flags
);
2960 ChangeData
*change_data
= g_new0(ChangeData
, 1);
2961 change_data
->info
= msginfo
;
2962 change_data
->op
= 2;
2963 change_data
->set_flags
= add_flags
;
2964 change_data
->set_tmp_flags
= add_tmp_flags
;
2965 change_data
->unset_flags
= rem_flags
;
2966 change_data
->unset_tmp_flags
= rem_tmp_flags
;
2967 debug_print("flags: deferring change\n");
2968 g_timeout_add(100, defer_change
, change_data
);
2972 gboolean
defer_change(gpointer data
)
2974 ChangeData
*chg
= (ChangeData
*)data
;
2975 if (chg
->info
->folder
&& chg
->info
->folder
->processing_pending
) {
2976 debug_print("flags: trying later\n");
2977 return TRUE
; /* try again */
2979 debug_print("flags: finally doing it\n");
2982 procmsg_msginfo_unset_flags(chg
->info
, chg
->unset_flags
, chg
->unset_tmp_flags
);
2985 procmsg_msginfo_set_flags(chg
->info
, chg
->set_flags
, chg
->set_tmp_flags
);
2988 procmsg_msginfo_change_flags(chg
->info
, chg
->set_flags
, chg
->set_tmp_flags
,
2989 chg
->unset_flags
, chg
->unset_tmp_flags
);
2992 g_warning("shouldn't happen\n");
2999 static void msginfo_mark_as_read (SummaryView
*summaryview
, MsgInfo
*msginfo
,
3002 g_return_if_fail(summaryview
!= NULL
);
3003 g_return_if_fail(msginfo
!= NULL
);
3004 g_return_if_fail(row
!= NULL
);
3006 if (MSG_IS_NEW(msginfo
->flags
) || MSG_IS_UNREAD(msginfo
->flags
)) {
3007 summary_msginfo_unset_flags
3008 (msginfo
, MSG_NEW
| MSG_UNREAD
, 0);
3009 summary_set_row_marks(summaryview
, row
);
3010 summary_status_show(summaryview
);
3016 SummaryView
*summaryview
;
3019 static int msginfo_mark_as_read_timeout(void *data
)
3021 MarkAsReadData
*mdata
= (MarkAsReadData
*)data
;
3025 if (mdata
->msginfo
== summary_get_selected_msg(mdata
->summaryview
))
3026 msginfo_mark_as_read(mdata
->summaryview
, mdata
->msginfo
,
3027 mdata
->summaryview
->selected
);
3034 static void summary_display_msg_full(SummaryView
*summaryview
,
3036 gboolean new_window
, gboolean all_headers
)
3038 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
3043 if (summaryview
->displayed
== row
)
3045 else if (summaryview
->messageview
)
3046 summaryview
->messageview
->filtered
= FALSE
;
3048 g_return_if_fail(row
!= NULL
);
3050 if (summary_is_locked(summaryview
)) return;
3051 summary_lock(summaryview
);
3053 STATUSBAR_POP(summaryview
->mainwin
);
3056 msginfo
= gtk_ctree_node_get_row_data(ctree
, row
);
3058 g_return_if_fail(msginfo
);
3060 if (new_window
&& prefs_common
.layout_mode
!= SMALL_LAYOUT
) {
3061 MessageView
*msgview
;
3063 msgview
= messageview_create_with_new_window(summaryview
->mainwin
);
3064 val
= messageview_show(msgview
, msginfo
, all_headers
);
3066 MessageView
*msgview
;
3068 if (prefs_common
.layout_mode
== SMALL_LAYOUT
) {
3069 if (summaryview
->ext_messageview
== NULL
)
3070 summaryview
->ext_messageview
= messageview_create_with_new_window(summaryview
->mainwin
);
3072 gtkut_window_popup(summaryview
->ext_messageview
->window
);
3073 msgview
= summaryview
->ext_messageview
;
3074 summaryview
->last_displayed
= summaryview
->displayed
;
3075 summaryview
->displayed
= row
;
3076 val
= messageview_show(msgview
, msginfo
, all_headers
);
3077 if (GTK_CLIST(msgview
->mimeview
->ctree
)->row_list
== NULL
)
3078 gtk_widget_grab_focus(summaryview
->ctree
);
3079 gtkut_ctree_node_move_if_on_the_edge(ctree
, row
,
3080 GTK_CLIST(summaryview
->ctree
)->focus_row
);
3082 msgview
= summaryview
->messageview
;
3083 summaryview
->last_displayed
= summaryview
->displayed
;
3084 summaryview
->displayed
= row
;
3085 if (!messageview_is_visible(msgview
)) {
3086 main_window_toggle_message_view(summaryview
->mainwin
);
3089 val
= messageview_show(msgview
, msginfo
, all_headers
);
3090 if (GTK_CLIST(msgview
->mimeview
->ctree
)->row_list
== NULL
)
3091 gtk_widget_grab_focus(summaryview
->ctree
);
3092 gtkut_ctree_node_move_if_on_the_edge(ctree
, row
,
3093 GTK_CLIST(summaryview
->ctree
)->focus_row
);
3097 if (val
== 0 && MSG_IS_UNREAD(msginfo
->flags
)) {
3098 if (prefs_common
.mark_as_read_delay
) {
3099 MarkAsReadData
*data
= g_new0(MarkAsReadData
, 1);
3100 data
->summaryview
= summaryview
;
3101 data
->msginfo
= msginfo
;
3102 g_timeout_add(prefs_common
.mark_as_read_delay
* 1000,
3103 msginfo_mark_as_read_timeout
, data
);
3104 } else if (new_window
|| !prefs_common
.mark_as_read_on_new_window
) {
3105 msginfo_mark_as_read(summaryview
, msginfo
, row
);
3109 summary_set_menu_sensitive(summaryview
);
3110 toolbar_main_set_sensitive(summaryview
->mainwin
);
3111 messageview_set_menu_sensitive(summaryview
->messageview
);
3113 summary_unlock(summaryview
);
3117 void summary_display_msg_selected(SummaryView
*summaryview
,
3118 gboolean all_headers
)
3120 if (summary_is_locked(summaryview
)) return;
3121 summaryview
->displayed
= NULL
;
3122 summary_display_msg_full(summaryview
, summaryview
->selected
, FALSE
,
3126 void summary_redisplay_msg(SummaryView
*summaryview
)
3130 if (summaryview
->displayed
) {
3131 node
= summaryview
->displayed
;
3132 summaryview
->displayed
= NULL
;
3133 summary_display_msg(summaryview
, node
);
3137 void summary_open_msg(SummaryView
*summaryview
)
3139 if (!summaryview
->selected
) return;
3141 /* CLAWS: if separate message view, don't open a new window
3142 * but rather use the current separated message view */
3143 summary_display_msg_full(summaryview
, summaryview
->selected
,
3147 void summary_view_source(SummaryView
* summaryview
)
3149 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
3151 SourceWindow
*srcwin
;
3153 if (!summaryview
->selected
) return;
3155 srcwin
= source_window_create();
3156 msginfo
= gtk_ctree_node_get_row_data(ctree
, summaryview
->selected
);
3157 source_window_show_msg(srcwin
, msginfo
);
3158 source_window_show(srcwin
);
3160 maemo_window_full_screen_if_needed(GTK_WINDOW(srcwin
->window
));
3161 maemo_connect_key_press_to_mainwindow(GTK_WINDOW(srcwin
->window
));
3165 void summary_reedit(SummaryView
*summaryview
)
3169 if (!summaryview
->selected
) return;
3170 if (!summaryview
->folder_item
) return;
3171 if (!FOLDER_SHOWS_TO_HDR(summaryview
->folder_item
))
3174 msginfo
= gtk_ctree_node_get_row_data(GTK_CTREE(summaryview
->ctree
),
3175 summaryview
->selected
);
3176 if (!msginfo
) return;
3178 compose_reedit(msginfo
, FALSE
);
3181 gboolean
summary_step(SummaryView
*summaryview
, GtkScrollType type
)
3183 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
3186 if (summary_is_locked(summaryview
)
3187 && !GTK_SCTREE(ctree
)->selecting_range
3188 && summaryview
->messageview
->mimeview
3189 && summaryview
->messageview
->mimeview
->type
== MIMEVIEW_TEXT
3190 && summaryview
->messageview
->mimeview
->textview
->loading
) {
3191 PostponedSelectData
*data
= g_new0(PostponedSelectData
, 1);
3192 summaryview
->messageview
->mimeview
->textview
->stop_loading
= TRUE
;
3194 data
->ctree
= ctree
;
3198 data
->summaryview
= summaryview
;
3199 debug_print("postponing open of message till end of load\n");
3200 g_timeout_add(100, summary_select_retry
, data
);
3203 if (summary_is_locked(summaryview
))
3205 if (type
== GTK_SCROLL_STEP_FORWARD
) {
3206 node
= gtkut_ctree_node_next(ctree
, summaryview
->selected
);
3208 gtkut_ctree_expand_parent_all(ctree
, node
);
3212 if (summaryview
->selected
) {
3213 node
= GTK_CTREE_NODE_PREV(summaryview
->selected
);
3214 if (!node
) return FALSE
;
3218 if (messageview_is_visible(summaryview
->messageview
))
3219 summaryview
->display_msg
= TRUE
;
3221 g_signal_emit_by_name(G_OBJECT(ctree
), "scroll_vertical", type
, 0.0);
3223 if (GTK_CLIST(ctree
)->selection
)
3224 gtk_sctree_set_anchor_row
3226 GTK_CTREE_NODE(GTK_CLIST(ctree
)->selection
->data
));
3231 void summary_toggle_view(SummaryView
*summaryview
)
3233 if (prefs_common
.layout_mode
== SMALL_LAYOUT
)
3235 if (!messageview_is_visible(summaryview
->messageview
) &&
3236 summaryview
->selected
)
3237 summary_display_msg(summaryview
,
3238 summaryview
->selected
);
3240 main_window_toggle_message_view(summaryview
->mainwin
);
3243 static gboolean
summary_search_unread_recursive(GtkCTree
*ctree
,
3249 msginfo
= gtk_ctree_node_get_row_data(ctree
, node
);
3250 if (msginfo
&& MSG_IS_UNREAD(msginfo
->flags
) && !MSG_IS_IGNORE_THREAD(msginfo
->flags
))
3252 node
= GTK_CTREE_ROW(node
)->children
;
3254 node
= GTK_CTREE_NODE(GTK_CLIST(ctree
)->row_list
);
3257 if (summary_search_unread_recursive(ctree
, node
) == TRUE
)
3259 node
= GTK_CTREE_ROW(node
)->sibling
;
3265 static gboolean
summary_have_unread_children(SummaryView
*summaryview
,
3268 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
3270 if (!node
) return FALSE
;
3272 node
= GTK_CTREE_ROW(node
)->children
;
3275 if (summary_search_unread_recursive(ctree
, node
) == TRUE
)
3277 node
= GTK_CTREE_ROW(node
)->sibling
;
3282 static void summary_set_row_marks(SummaryView
*summaryview
, GtkCTreeNode
*row
)
3284 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
3285 GtkStyle
*style
= NULL
;
3288 gint
*col_pos
= summaryview
->col_pos
;
3290 msginfo
= gtk_ctree_node_get_row_data(ctree
, row
);
3291 if (!msginfo
) return;
3293 flags
= msginfo
->flags
;
3295 gtk_ctree_node_set_foreground(ctree
, row
, NULL
);
3297 /* set new/unread column */
3298 if (MSG_IS_IGNORE_THREAD(flags
)) {
3299 gtk_ctree_node_set_pixmap(ctree
, row
, col_pos
[S_COL_STATUS
],
3300 ignorethreadxpm
, ignorethreadxpmmask
);
3301 } else if (MSG_IS_SPAM(flags
)) {
3302 gtk_ctree_node_set_pixmap(ctree
, row
, col_pos
[S_COL_STATUS
],
3303 spamxpm
, spamxpmmask
);
3304 } else if (MSG_IS_NEW(flags
)) {
3305 gtk_ctree_node_set_pixmap(ctree
, row
, col_pos
[S_COL_STATUS
],
3306 newxpm
, newxpmmask
);
3307 } else if (MSG_IS_UNREAD(flags
)) {
3308 gtk_ctree_node_set_pixmap(ctree
, row
, col_pos
[S_COL_STATUS
],
3309 unreadxpm
, unreadxpmmask
);
3310 } else if (MSG_IS_REPLIED(flags
)) {
3311 gtk_ctree_node_set_pixmap(ctree
, row
, col_pos
[S_COL_STATUS
],
3312 repliedxpm
, repliedxpmmask
);
3313 } else if (MSG_IS_FORWARDED(flags
)) {
3314 gtk_ctree_node_set_pixmap(ctree
, row
, col_pos
[S_COL_STATUS
],
3315 forwardedxpm
, forwardedxpmmask
);
3317 gtk_ctree_node_set_text(ctree
, row
, col_pos
[S_COL_STATUS
],
3321 if (prefs_common
.bold_unread
&&
3322 ((MSG_IS_UNREAD(flags
) && !MSG_IS_IGNORE_THREAD(flags
)) ||
3323 (!GTK_CTREE_ROW(row
)->expanded
&&
3324 GTK_CTREE_ROW(row
)->children
&&
3325 summary_have_unread_children(summaryview
, row
))))
3328 /* set mark column */
3329 if (MSG_IS_DELETED(flags
)) {
3330 gtk_ctree_node_set_pixmap(ctree
, row
, col_pos
[S_COL_MARK
],
3331 deletedxpm
, deletedxpmmask
);
3333 style
= bold_deleted_style
;
3335 style
= small_deleted_style
;
3337 gtk_ctree_node_set_foreground
3338 (ctree
, row
, &summaryview
->color_dim
);
3339 } else if (MSG_IS_MARKED(flags
)) {
3340 gtk_ctree_node_set_pixmap(ctree
, row
, col_pos
[S_COL_MARK
],
3341 markxpm
, markxpmmask
);
3342 } else if (MSG_IS_MOVE(flags
)) {
3343 gtk_ctree_node_set_pixmap(ctree
, row
, col_pos
[S_COL_MARK
],
3344 movedxpm
, movedxpmmask
);
3346 style
= bold_marked_style
;
3348 style
= small_marked_style
;
3350 gtk_ctree_node_set_foreground
3351 (ctree
, row
, &summaryview
->color_marked
);
3352 } else if (MSG_IS_COPY(flags
)) {
3353 gtk_ctree_node_set_pixmap(ctree
, row
, col_pos
[S_COL_MARK
],
3354 copiedxpm
, copiedxpmmask
);
3356 style
= bold_marked_style
;
3358 style
= small_marked_style
;
3360 gtk_ctree_node_set_foreground
3361 (ctree
, row
, &summaryview
->color_marked
);
3363 gtk_ctree_node_set_text(ctree
, row
, col_pos
[S_COL_MARK
], "");
3366 if (MSG_IS_LOCKED(flags
)) {
3367 gtk_ctree_node_set_pixmap(ctree
, row
, col_pos
[S_COL_LOCKED
],
3368 lockedxpm
, lockedxpmmask
);
3371 gtk_ctree_node_set_text(ctree
, row
, col_pos
[S_COL_LOCKED
], "");
3374 if (MSG_IS_WITH_ATTACHMENT(flags
) && MSG_IS_SIGNED(flags
)) {
3375 gtk_ctree_node_set_pixmap(ctree
, row
, col_pos
[S_COL_MIME
],
3376 clipgpgsignedxpm
, clipgpgsignedxpmmask
);
3377 } else if (MSG_IS_SIGNED(flags
)) {
3378 gtk_ctree_node_set_pixmap(ctree
, row
, col_pos
[S_COL_MIME
],
3379 gpgsignedxpm
, gpgsignedxpmmask
);
3380 } else if (MSG_IS_WITH_ATTACHMENT(flags
) && MSG_IS_ENCRYPTED(flags
)) {
3381 gtk_ctree_node_set_pixmap(ctree
, row
, col_pos
[S_COL_MIME
],
3382 clipkeyxpm
, clipkeyxpmmask
);
3383 } else if (MSG_IS_ENCRYPTED(flags
)) {
3384 gtk_ctree_node_set_pixmap(ctree
, row
, col_pos
[S_COL_MIME
],
3385 keyxpm
, keyxpmmask
);
3386 } else if (MSG_IS_WITH_ATTACHMENT(flags
)) {
3387 gtk_ctree_node_set_pixmap(ctree
, row
, col_pos
[S_COL_MIME
],
3388 clipxpm
, clipxpmmask
);
3390 gtk_ctree_node_set_text(ctree
, row
, col_pos
[S_COL_MIME
], "");
3393 style
= small_style
;
3395 gtk_ctree_node_set_row_style(ctree
, row
, style
);
3397 if (MSG_GET_COLORLABEL(flags
))
3398 summary_set_colorlabel_color(ctree
, row
, MSG_GET_COLORLABEL_VALUE(flags
));
3401 static void summary_mark_row(SummaryView
*summaryview
, GtkCTreeNode
*row
)
3403 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
3406 msginfo
= gtk_ctree_node_get_row_data(ctree
, row
);
3407 g_return_if_fail(msginfo
);
3408 if (MSG_IS_DELETED(msginfo
->flags
))
3409 summaryview
->deleted
--;
3410 if (MSG_IS_MOVE(msginfo
->flags
))
3411 summaryview
->moved
--;
3412 if (MSG_IS_COPY(msginfo
->flags
))
3413 summaryview
->copied
--;
3415 procmsg_msginfo_set_to_folder(msginfo
, NULL
);
3416 summary_msginfo_change_flags(msginfo
, MSG_MARKED
, 0, MSG_DELETED
,
3417 MSG_MOVE
| MSG_COPY
| MSG_MOVE_DONE
);
3418 summary_set_row_marks(summaryview
, row
);
3419 debug_print("Message %s/%d is marked\n", msginfo
->folder
->path
, msginfo
->msgnum
);
3422 static void summary_lock_row(SummaryView
*summaryview
, GtkCTreeNode
*row
)
3424 gboolean changed
= FALSE
;
3425 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
3428 msginfo
= gtk_ctree_node_get_row_data(ctree
, row
);
3429 g_return_if_fail(msginfo
);
3430 if (MSG_IS_DELETED(msginfo
->flags
))
3431 summaryview
->deleted
--;
3432 if (MSG_IS_MOVE(msginfo
->flags
)) {
3433 summaryview
->moved
--;
3436 if (MSG_IS_COPY(msginfo
->flags
)) {
3437 summaryview
->copied
--;
3440 procmsg_msginfo_set_to_folder(msginfo
, NULL
);
3441 summary_msginfo_change_flags(msginfo
, MSG_LOCKED
, 0, MSG_DELETED
,
3442 MSG_MOVE
| MSG_COPY
| MSG_MOVE_DONE
);
3444 summary_set_row_marks(summaryview
, row
);
3445 debug_print("Message %d is locked\n", msginfo
->msgnum
);
3448 static void summary_unlock_row(SummaryView
*summaryview
, GtkCTreeNode
*row
)
3450 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
3453 msginfo
= gtk_ctree_node_get_row_data(ctree
, row
);
3454 g_return_if_fail(msginfo
);
3455 if (!MSG_IS_LOCKED(msginfo
->flags
))
3457 procmsg_msginfo_set_to_folder(msginfo
, NULL
);
3458 summary_msginfo_unset_flags(msginfo
, MSG_LOCKED
, 0);
3459 summary_set_row_marks(summaryview
, row
);
3460 debug_print("Message %d is unlocked\n", msginfo
->msgnum
);
3463 void summary_mark(SummaryView
*summaryview
)
3465 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
3467 gboolean froze
= FALSE
;
3469 START_LONG_OPERATION(summaryview
, FALSE
);
3470 folder_item_set_batch(summaryview
->folder_item
, TRUE
);
3471 for (cur
= GTK_CLIST(ctree
)->selection
; cur
!= NULL
&& cur
->data
!= NULL
; cur
= cur
->next
)
3472 summary_mark_row(summaryview
, GTK_CTREE_NODE(cur
->data
));
3473 folder_item_set_batch(summaryview
->folder_item
, FALSE
);
3474 END_LONG_OPERATION(summaryview
);
3476 summary_status_show(summaryview
);
3479 static void summary_mark_row_as_read(SummaryView
*summaryview
,
3482 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
3485 msginfo
= gtk_ctree_node_get_row_data(ctree
, row
);
3486 g_return_if_fail(msginfo
);
3488 if(!(MSG_IS_NEW(msginfo
->flags
) || MSG_IS_UNREAD(msginfo
->flags
)))
3491 summary_msginfo_unset_flags(msginfo
, MSG_NEW
| MSG_UNREAD
, 0);
3492 summary_set_row_marks(summaryview
, row
);
3493 debug_print("Message %d is marked as read\n",
3497 void summary_mark_as_read(SummaryView
*summaryview
)
3499 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
3501 gboolean froze
= FALSE
;
3503 START_LONG_OPERATION(summaryview
, FALSE
);
3504 folder_item_set_batch(summaryview
->folder_item
, TRUE
);
3505 for (cur
= GTK_CLIST(ctree
)->selection
; cur
!= NULL
&& cur
->data
!= NULL
; cur
= cur
->next
)
3506 summary_mark_row_as_read(summaryview
,
3507 GTK_CTREE_NODE(cur
->data
));
3508 folder_item_set_batch(summaryview
->folder_item
, FALSE
);
3509 END_LONG_OPERATION(summaryview
);
3511 summary_status_show(summaryview
);
3514 void summary_msgs_lock(SummaryView
*summaryview
)
3516 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
3518 gboolean froze
= FALSE
;
3520 START_LONG_OPERATION(summaryview
, FALSE
);
3521 for (cur
= GTK_CLIST(ctree
)->selection
; cur
!= NULL
&& cur
->data
!= NULL
; cur
= cur
->next
)
3522 summary_lock_row(summaryview
,
3523 GTK_CTREE_NODE(cur
->data
));
3524 END_LONG_OPERATION(summaryview
);
3526 summary_status_show(summaryview
);
3529 void summary_msgs_unlock(SummaryView
*summaryview
)
3531 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
3533 gboolean froze
= FALSE
;
3535 START_LONG_OPERATION(summaryview
, FALSE
);
3536 for (cur
= GTK_CLIST(ctree
)->selection
; cur
!= NULL
&& cur
->data
!= NULL
; cur
= cur
->next
)
3537 summary_unlock_row(summaryview
,
3538 GTK_CTREE_NODE(cur
->data
));
3539 END_LONG_OPERATION(summaryview
);
3541 summary_status_show(summaryview
);
3544 void summary_mark_all_read(SummaryView
*summaryview
)
3546 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
3549 gboolean froze
= FALSE
;
3551 if (prefs_common
.ask_mark_all_read
) {
3552 val
= alertpanel_full(_("Mark all as read"),
3553 _("Do you really want to mark all mails in this "
3554 "folder as read ?"), GTK_STOCK_NO
, GTK_STOCK_YES
, NULL
,
3555 TRUE
, NULL
, ALERT_QUESTION
, G_ALERTDEFAULT
);
3557 if ((val
& ~G_ALERTDISABLE
) != G_ALERTALTERNATE
)
3559 else if (val
& G_ALERTDISABLE
)
3560 prefs_common
.ask_mark_all_read
= FALSE
;
3563 START_LONG_OPERATION(summaryview
, TRUE
);
3564 folder_item_set_batch(summaryview
->folder_item
, TRUE
);
3565 for (node
= GTK_CTREE_NODE(GTK_CLIST(ctree
)->row_list
); node
!= NULL
;
3566 node
= gtkut_ctree_node_next(ctree
, node
))
3567 summary_mark_row_as_read(summaryview
, node
);
3568 folder_item_set_batch(summaryview
->folder_item
, FALSE
);
3569 for (node
= GTK_CTREE_NODE(GTK_CLIST(ctree
)->row_list
); node
!= NULL
;
3570 node
= gtkut_ctree_node_next(ctree
, node
)) {
3571 if (!GTK_CTREE_ROW(node
)->expanded
)
3572 summary_set_row_marks(summaryview
, node
);
3574 END_LONG_OPERATION(summaryview
);
3576 summary_status_show(summaryview
);
3579 void summary_mark_as_spam(SummaryView
*summaryview
, guint action
, GtkWidget
*widget
)
3581 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
3583 gboolean is_spam
= action
;
3584 GSList
*msgs
= NULL
;
3585 gboolean immediate_exec
= prefs_common
.immediate_exec
;
3586 gboolean moved
= FALSE
;
3587 gboolean froze
= FALSE
;
3589 prefs_common
.immediate_exec
= FALSE
;
3591 START_LONG_OPERATION(summaryview
, FALSE
);
3593 for (cur
= GTK_CLIST(ctree
)->selection
; cur
!= NULL
&& cur
->data
!= NULL
; cur
= cur
->next
) {
3594 GtkCTreeNode
*row
= GTK_CTREE_NODE(cur
->data
);
3595 MsgInfo
*msginfo
= gtk_ctree_node_get_row_data(ctree
, row
);
3597 msgs
= g_slist_prepend(msgs
, msginfo
);
3600 if (procmsg_spam_learner_learn(NULL
, msgs
, is_spam
) == 0) {
3601 for (cur
= GTK_CLIST(ctree
)->selection
; cur
!= NULL
&& cur
->data
!= NULL
; cur
= cur
->next
) {
3602 GtkCTreeNode
*row
= GTK_CTREE_NODE(cur
->data
);
3603 MsgInfo
*msginfo
= gtk_ctree_node_get_row_data(ctree
, row
);
3607 summary_msginfo_change_flags(msginfo
, MSG_SPAM
, 0, MSG_NEW
|MSG_UNREAD
, 0);
3608 if (procmsg_spam_get_folder(msginfo
) != summaryview
->folder_item
) {
3609 summary_move_row_to(summaryview
, row
,
3610 procmsg_spam_get_folder(msginfo
));
3614 summary_msginfo_unset_flags(msginfo
, MSG_SPAM
, 0);
3616 summaryview
->display_msg
= prefs_common
.always_show_msg
;
3618 summary_set_row_marks(summaryview
, row
);
3621 log_error(LOG_PROTOCOL
, _("An error happened while learning.\n"));
3624 prefs_common
.immediate_exec
= immediate_exec
;
3626 END_LONG_OPERATION(summaryview
);
3628 if (prefs_common
.immediate_exec
&& moved
) {
3629 summary_execute(summaryview
);
3632 if (!moved
&& msgs
) {
3633 MsgInfo
*msginfo
= (MsgInfo
*)msgs
->data
;
3634 toolbar_set_learn_button
3635 (summaryview
->mainwin
->toolbar
,
3636 MSG_IS_SPAM(msginfo
->flags
)?LEARN_HAM
:LEARN_SPAM
);
3640 summary_status_show(summaryview
);
3644 static void summary_mark_row_as_unread(SummaryView
*summaryview
,
3647 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
3650 msginfo
= gtk_ctree_node_get_row_data(ctree
, row
);
3651 g_return_if_fail(msginfo
);
3652 if (MSG_IS_DELETED(msginfo
->flags
)) {
3653 procmsg_msginfo_set_to_folder(msginfo
, NULL
);
3654 summary_msginfo_unset_flags(msginfo
, MSG_DELETED
, 0);
3655 summaryview
->deleted
--;
3658 summary_msginfo_set_flags(msginfo
, MSG_UNREAD
, 0);
3659 debug_print("Message %d is marked as unread\n",
3662 summary_set_row_marks(summaryview
, row
);
3665 void summary_mark_as_unread(SummaryView
*summaryview
)
3667 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
3669 gboolean froze
= FALSE
;
3671 START_LONG_OPERATION(summaryview
, FALSE
);
3672 folder_item_set_batch(summaryview
->folder_item
, TRUE
);
3673 for (cur
= GTK_CLIST(ctree
)->selection
; cur
!= NULL
&& cur
->data
!= NULL
;
3675 summary_mark_row_as_unread(summaryview
,
3676 GTK_CTREE_NODE(cur
->data
));
3677 folder_item_set_batch(summaryview
->folder_item
, FALSE
);
3678 END_LONG_OPERATION(summaryview
);
3680 summary_status_show(summaryview
);
3683 static gboolean
check_permission(SummaryView
*summaryview
, MsgInfo
* msginfo
)
3688 switch (FOLDER_TYPE(summaryview
->folder_item
->folder
)) {
3693 security : checks if one the accounts correspond to
3694 the author of the post
3698 for(cur
= account_get_list() ; cur
!= NULL
; cur
= cur
->next
) {
3699 PrefsAccount
* account
;
3702 account
= cur
->data
;
3703 if (account
->name
&& *account
->name
)
3705 g_strdup_printf("%s <%s>",
3710 g_strdup_printf("%s",
3713 if (g_utf8_collate(from_name
, msginfo
->from
) == 0) {
3722 alertpanel_error(_("You're not the author of the article.\n"));
3732 static void summary_delete_row(SummaryView
*summaryview
, GtkCTreeNode
*row
)
3734 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
3737 msginfo
= gtk_ctree_node_get_row_data(ctree
, row
);
3738 g_return_if_fail(msginfo
);
3740 if (MSG_IS_LOCKED(msginfo
->flags
)) return;
3742 if (MSG_IS_DELETED(msginfo
->flags
)) return;
3744 if (MSG_IS_MOVE(msginfo
->flags
))
3745 summaryview
->moved
--;
3746 if (MSG_IS_COPY(msginfo
->flags
))
3747 summaryview
->copied
--;
3749 procmsg_msginfo_set_to_folder(msginfo
, NULL
);
3750 summary_msginfo_change_flags(msginfo
, MSG_DELETED
, 0, MSG_MARKED
,
3751 MSG_MOVE
| MSG_COPY
| MSG_MOVE_DONE
);
3752 summaryview
->deleted
++;
3754 if (!prefs_common
.immediate_exec
&&
3755 !folder_has_parent_of_type(summaryview
->folder_item
, F_TRASH
))
3756 summary_set_row_marks(summaryview
, row
);
3758 debug_print("Message %s/%d is set to delete\n",
3759 msginfo
->folder
->path
, msginfo
->msgnum
);
3762 void summary_cancel(SummaryView
*summaryview
)
3766 msginfo
= gtk_ctree_node_get_row_data(GTK_CTREE(summaryview
->ctree
),
3767 summaryview
->selected
);
3768 if (!msginfo
) return;
3770 if (!check_permission(summaryview
, msginfo
))
3773 news_cancel_article(summaryview
->folder_item
->folder
, msginfo
);
3775 if (summary_is_locked(summaryview
)) return;
3777 summary_lock(summaryview
);
3779 summary_freeze(summaryview
);
3781 summary_update_status(summaryview
);
3782 summary_status_show(summaryview
);
3784 summary_thaw(summaryview
);
3786 summary_unlock(summaryview
);
3789 void summary_delete(SummaryView
*summaryview
)
3791 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
3792 FolderItem
*item
= summaryview
->folder_item
;
3794 GtkCTreeNode
*sel_last
= NULL
;
3798 gboolean froze
= FALSE
;
3802 if (summary_is_locked(summaryview
)) return;
3804 if (!summaryview
->folder_item
) return;
3806 if (!prefs_common
.live_dangerously
) {
3808 int num
= g_list_length(GTK_CLIST(summaryview
->ctree
)->selection
);
3810 buf
= g_strdup_printf(_(
3811 "Do you really want to delete the selected message?"));
3813 buf
= g_strdup_printf(_(
3814 "Do you really want to delete the %d selected messages?"),
3816 aval
= alertpanel(_("Delete message(s)"),
3818 GTK_STOCK_CANCEL
, "+"GTK_STOCK_DELETE
, NULL
);
3820 if (aval
!= G_ALERTALTERNATE
) return;
3823 for (cur
= GTK_CLIST(ctree
)->selection
; cur
!= NULL
&& cur
->data
!= NULL
;
3825 GtkCTreeNode
*row
= GTK_CTREE_NODE(cur
->data
);
3826 msginfo
= gtk_ctree_node_get_row_data(ctree
, row
);
3827 if (msginfo
&& msginfo
->total_size
!= 0 &&
3828 msginfo
->size
!= (off_t
)msginfo
->total_size
)
3829 partial_mark_for_delete(msginfo
);
3832 main_window_cursor_wait(summaryview
->mainwin
);
3834 /* next code sets current row focus right. We need to find a row
3835 * that is not deleted. */
3836 START_LONG_OPERATION(summaryview
, FALSE
);
3837 folder_item_set_batch(summaryview
->folder_item
, TRUE
);
3838 for (cur
= GTK_CLIST(ctree
)->selection
; cur
!= NULL
&& cur
->data
!= NULL
; cur
= cur
->next
) {
3839 sel_last
= GTK_CTREE_NODE(cur
->data
);
3840 summary_delete_row(summaryview
, sel_last
);
3842 folder_item_set_batch(summaryview
->folder_item
, FALSE
);
3843 END_LONG_OPERATION(summaryview
);
3845 node
= summary_find_next_msg(summaryview
, sel_last
);
3847 node
= summary_find_prev_msg(summaryview
, sel_last
);
3849 summary_select_node(summaryview
, node
, prefs_common
.always_show_msg
, TRUE
);
3851 if (prefs_common
.immediate_exec
|| folder_has_parent_of_type(item
, F_TRASH
)) {
3852 summary_execute(summaryview
);
3853 /* after deleting, the anchor may be at an invalid row
3854 * so reset it to the node we found earlier */
3855 gtk_sctree_set_anchor_row(GTK_SCTREE(ctree
), node
);
3857 summary_status_show(summaryview
);
3860 main_window_cursor_normal(summaryview
->mainwin
);
3863 void summary_delete_trash(SummaryView
*summaryview
)
3865 FolderItem
*to_folder
= NULL
;
3867 if (!summaryview
->folder_item
||
3868 FOLDER_TYPE(summaryview
->folder_item
->folder
) == F_NEWS
) return;
3870 if (NULL
!= (ac
= account_find_from_item(summaryview
->folder_item
)))
3871 to_folder
= account_get_special_folder(ac
, F_TRASH
);
3873 if (to_folder
== NULL
)
3874 to_folder
= summaryview
->folder_item
->folder
->trash
;
3876 if (to_folder
== NULL
|| to_folder
== summaryview
->folder_item
3877 || folder_has_parent_of_type(summaryview
->folder_item
, F_TRASH
))
3878 summary_delete(summaryview
);
3880 summary_move_selected_to(summaryview
, to_folder
);
3884 static void summary_unmark_row(SummaryView
*summaryview
, GtkCTreeNode
*row
)
3886 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
3889 msginfo
= gtk_ctree_node_get_row_data(ctree
, row
);
3890 g_return_if_fail(msginfo
);
3891 if (MSG_IS_DELETED(msginfo
->flags
))
3892 summaryview
->deleted
--;
3893 if (MSG_IS_MOVE(msginfo
->flags
))
3894 summaryview
->moved
--;
3895 if (MSG_IS_COPY(msginfo
->flags
))
3896 summaryview
->copied
--;
3898 procmsg_msginfo_set_to_folder(msginfo
, NULL
);
3899 summary_msginfo_unset_flags(msginfo
, MSG_MARKED
| MSG_DELETED
,
3900 MSG_MOVE
| MSG_COPY
| MSG_MOVE_DONE
);
3901 summary_set_row_marks(summaryview
, row
);
3903 debug_print("Message %s/%d is unmarked\n",
3904 msginfo
->folder
->path
, msginfo
->msgnum
);
3907 void summary_unmark(SummaryView
*summaryview
)
3909 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
3911 gboolean froze
= FALSE
;
3913 START_LONG_OPERATION(summaryview
, FALSE
);
3914 folder_item_set_batch(summaryview
->folder_item
, TRUE
);
3915 for (cur
= GTK_CLIST(ctree
)->selection
; cur
!= NULL
&& cur
->data
!= NULL
; cur
= cur
->next
)
3916 summary_unmark_row(summaryview
, GTK_CTREE_NODE(cur
->data
));
3917 folder_item_set_batch(summaryview
->folder_item
, FALSE
);
3918 END_LONG_OPERATION(summaryview
);
3920 summary_status_show(summaryview
);
3923 static void summary_move_row_to(SummaryView
*summaryview
, GtkCTreeNode
*row
,
3924 FolderItem
*to_folder
)
3926 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
3929 g_return_if_fail(to_folder
!= NULL
);
3931 msginfo
= gtk_ctree_node_get_row_data(ctree
, row
);
3932 g_return_if_fail(msginfo
);
3933 if (MSG_IS_LOCKED(msginfo
->flags
))
3936 procmsg_msginfo_set_to_folder(msginfo
, to_folder
);
3937 if (MSG_IS_DELETED(msginfo
->flags
))
3938 summaryview
->deleted
--;
3939 if (MSG_IS_COPY(msginfo
->flags
)) {
3940 summaryview
->copied
--;
3942 if (!MSG_IS_MOVE(msginfo
->flags
)) {
3943 summary_msginfo_change_flags(msginfo
, 0, MSG_MOVE
, MSG_DELETED
,
3944 MSG_COPY
| MSG_MOVE_DONE
);
3945 summaryview
->moved
++;
3947 summary_msginfo_unset_flags(msginfo
, MSG_DELETED
, MSG_COPY
);
3950 if (!prefs_common
.immediate_exec
) {
3951 summary_set_row_marks(summaryview
, row
);
3954 debug_print("Message %d is set to move to %s\n",
3955 msginfo
->msgnum
, to_folder
->path
);
3958 void summary_move_selected_to(SummaryView
*summaryview
, FolderItem
*to_folder
)
3961 GtkCTreeNode
*sel_last
= NULL
;
3962 gboolean froze
= FALSE
;
3964 if (!to_folder
) return;
3965 if (!summaryview
->folder_item
||
3966 FOLDER_TYPE(summaryview
->folder_item
->folder
) == F_NEWS
) return;
3968 if (summary_is_locked(summaryview
)) return;
3970 if (summaryview
->folder_item
== to_folder
) {
3971 alertpanel_error(_("Destination is same as current folder."));
3975 START_LONG_OPERATION(summaryview
, FALSE
);
3977 for (cur
= GTK_CLIST(summaryview
->ctree
)->selection
;
3978 cur
!= NULL
&& cur
->data
!= NULL
; cur
= cur
->next
) {
3979 sel_last
= GTK_CTREE_NODE(cur
->data
);
3981 (summaryview
, GTK_CTREE_NODE(cur
->data
), to_folder
);
3983 END_LONG_OPERATION(summaryview
);
3985 summaryview
->display_msg
= prefs_common
.always_show_msg
;
3987 if (prefs_common
.immediate_exec
) {
3988 summary_execute(summaryview
);
3990 GtkCTreeNode
*node
= summary_find_next_msg(summaryview
, sel_last
);
3992 node
= summary_find_prev_msg(summaryview
, sel_last
);
3993 summary_select_node(summaryview
, node
, prefs_common
.always_show_msg
, TRUE
);
3994 summary_status_show(summaryview
);
3997 if (!summaryview
->selected
) { /* this was the last message */
3998 GtkCTreeNode
*node
= gtk_ctree_node_nth (GTK_CTREE(summaryview
->ctree
),
3999 GTK_CLIST(summaryview
->ctree
)->rows
- 1);
4001 summary_select_node(summaryview
, node
, prefs_common
.always_show_msg
, TRUE
);
4006 void summary_move_to(SummaryView
*summaryview
)
4008 FolderItem
*to_folder
;
4010 if (!summaryview
->folder_item
||
4011 FOLDER_TYPE(summaryview
->folder_item
->folder
) == F_NEWS
) return;
4013 to_folder
= foldersel_folder_sel(summaryview
->folder_item
->folder
,
4014 FOLDER_SEL_MOVE
, NULL
);
4015 summary_move_selected_to(summaryview
, to_folder
);
4018 static void summary_copy_row_to(SummaryView
*summaryview
, GtkCTreeNode
*row
,
4019 FolderItem
*to_folder
)
4021 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
4024 g_return_if_fail(to_folder
!= NULL
);
4026 msginfo
= gtk_ctree_node_get_row_data(ctree
, row
);
4027 g_return_if_fail(msginfo
);
4028 procmsg_msginfo_set_to_folder(msginfo
, to_folder
);
4029 if (MSG_IS_DELETED(msginfo
->flags
))
4030 summaryview
->deleted
--;
4031 if (MSG_IS_MOVE(msginfo
->flags
)) {
4032 summaryview
->moved
--;
4035 if (!MSG_IS_COPY(msginfo
->flags
)) {
4036 summary_msginfo_change_flags(msginfo
, 0, MSG_COPY
, MSG_DELETED
,
4037 MSG_MOVE
| MSG_MOVE_DONE
);
4038 summaryview
->copied
++;
4040 summary_msginfo_unset_flags(msginfo
, MSG_DELETED
, MSG_MOVE
);
4042 if (!prefs_common
.immediate_exec
) {
4043 summary_set_row_marks(summaryview
, row
);
4046 debug_print("Message %d is set to copy to %s\n",
4047 msginfo
->msgnum
, to_folder
->path
);
4050 void summary_copy_selected_to(SummaryView
*summaryview
, FolderItem
*to_folder
)
4053 gboolean froze
= FALSE
;
4055 if (!to_folder
) return;
4056 if (!summaryview
->folder_item
) return;
4058 if (summary_is_locked(summaryview
)) return;
4060 if (summaryview
->folder_item
== to_folder
) {
4062 (_("Destination to copy is same as current folder."));
4066 START_LONG_OPERATION(summaryview
, FALSE
);
4068 for (cur
= GTK_CLIST(summaryview
->ctree
)->selection
;
4069 cur
!= NULL
&& cur
->data
!= NULL
; cur
= cur
->next
)
4071 (summaryview
, GTK_CTREE_NODE(cur
->data
), to_folder
);
4073 END_LONG_OPERATION(summaryview
);
4075 if (prefs_common
.immediate_exec
)
4076 summary_execute(summaryview
);
4078 summary_status_show(summaryview
);
4082 void summary_copy_to(SummaryView
*summaryview
)
4084 FolderItem
*to_folder
;
4086 if (!summaryview
->folder_item
) return;
4088 to_folder
= foldersel_folder_sel(summaryview
->folder_item
->folder
,
4089 FOLDER_SEL_COPY
, NULL
);
4090 summary_copy_selected_to(summaryview
, to_folder
);
4093 void summary_add_address(SummaryView
*summaryview
)
4098 msginfo
= gtk_ctree_node_get_row_data(GTK_CTREE(summaryview
->ctree
),
4099 summaryview
->selected
);
4100 if (!msginfo
) return;
4102 Xstrdup_a(from
, msginfo
->from
, return);
4103 eliminate_address_comment(from
);
4104 extract_address(from
);
4105 addressbook_add_contact(msginfo
->fromname
, from
, NULL
);
4108 void summary_select_all(SummaryView
*summaryview
)
4110 if (!summaryview
->folder_item
) return;
4112 summary_lock(summaryview
);
4113 gtk_clist_select_all(GTK_CLIST(summaryview
->ctree
));
4114 summary_unlock(summaryview
);
4115 summary_status_show(summaryview
);
4118 void summary_unselect_all(SummaryView
*summaryview
)
4120 summary_lock(summaryview
);
4121 gtk_sctree_unselect_all(GTK_SCTREE(summaryview
->ctree
));
4122 summary_unlock(summaryview
);
4123 summary_status_show(summaryview
);
4126 void summary_select_thread(SummaryView
*summaryview
, gboolean delete_thread
)
4128 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
4129 GtkCTreeNode
*node
= summaryview
->selected
;
4130 gboolean froze
= FALSE
;
4134 while (GTK_CTREE_ROW(node
)->parent
!= NULL
)
4135 node
= GTK_CTREE_ROW(node
)->parent
;
4137 START_LONG_OPERATION(summaryview
, FALSE
);
4138 if (node
!= summaryview
->selected
)
4141 messageview_is_visible(summaryview
->messageview
),
4144 gtk_ctree_select_recursive(ctree
, node
);
4145 END_LONG_OPERATION(summaryview
);
4147 if (delete_thread
) {
4148 if (FOLDER_TYPE(summaryview
->folder_item
->folder
) == F_NEWS
)
4149 summary_delete(summaryview
);
4151 summary_delete_trash(summaryview
);
4153 summary_status_show(summaryview
);
4156 void summary_save_as(SummaryView
*summaryview
)
4158 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
4160 gchar
*filename
= NULL
;
4164 AlertValue aval
= 0;
4166 if (!summaryview
->selected
) return;
4167 msginfo
= gtk_ctree_node_get_row_data(ctree
, summaryview
->selected
);
4168 if (!msginfo
) return;
4170 if (msginfo
->subject
) {
4171 Xstrdup_a(filename
, msginfo
->subject
, return);
4172 subst_for_filename(filename
);
4174 if (g_getenv ("G_BROKEN_FILENAMES") &&
4175 filename
&& !g_utf8_validate(filename
, -1, NULL
)) {
4176 gchar
*oldstr
= filename
;
4177 filename
= conv_codeset_strdup(filename
,
4178 conv_get_locale_charset_str(),
4181 g_warning("summary_save_as(): faild to convert character set.");
4182 filename
= g_strdup(oldstr
);
4184 dest
= filesel_select_file_save(_("Save as"), filename
);
4187 dest
= filesel_select_file_save(_("Save as"), filename
);
4190 if (is_file_exist(dest
)) {
4191 aval
= alertpanel(_("Append or Overwrite"),
4192 _("Append or overwrite existing file?"),
4193 _("_Append"), _("_Overwrite"),
4195 if (aval
!= 0 && aval
!= 1)
4199 src
= procmsg_get_message_file(msginfo
);
4200 tmp
= g_path_get_basename(dest
);
4202 if ( aval
==0 ) { /* append */
4203 if (append_file(src
, dest
, TRUE
) < 0)
4204 alertpanel_error(_("Couldn't save the file '%s'."), tmp
);
4205 } else { /* overwrite */
4206 if (copy_file(src
, dest
, TRUE
) < 0)
4207 alertpanel_error(_("Couldn't save the file '%s'."), tmp
);
4212 * If two or more msgs are selected,
4213 * append them to the output file.
4215 if (GTK_CLIST(ctree
)->selection
->next
) {
4217 for (item
= GTK_CLIST(ctree
)->selection
->next
; item
!= NULL
; item
=item
->next
) {
4218 msginfo
= gtk_ctree_node_get_row_data(ctree
, GTK_CTREE_NODE(item
->data
));
4219 if (!msginfo
) break;
4220 src
= procmsg_get_message_file(msginfo
);
4221 if (append_file(src
, dest
, TRUE
) < 0)
4222 alertpanel_error(_("Couldn't save the file '%s'."), tmp
);
4230 void summary_print(SummaryView
*summaryview
)
4232 GtkCList
*clist
= GTK_CLIST(summaryview
->ctree
);
4233 #ifndef USE_GNOMEPRINT
4234 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
4236 gchar
*cmdline
= NULL
;
4241 if (clist
->selection
== NULL
) return;
4242 #ifndef USE_GNOMEPRINT
4243 cmdline
= input_dialog(_("Print"),
4244 _("Enter the print command line:\n"
4245 "('%s' will be replaced with file name)"),
4246 prefs_common
.print_cmd
);
4247 if (!cmdline
) return;
4248 if (!(p
= strchr(cmdline
, '%')) || *(p
+ 1) != 's' ||
4249 strchr(p
+ 2, '%')) {
4250 alertpanel_error(_("Print command line is invalid:\n'%s'"),
4255 for (cur
= clist
->selection
;
4256 cur
!= NULL
&& cur
->data
!= NULL
;
4258 msginfo
= gtk_ctree_node_get_row_data
4259 (ctree
, GTK_CTREE_NODE(cur
->data
));
4261 procmsg_print_message(msginfo
, cmdline
);
4266 for (cur
= clist
->selection
;
4267 cur
!= NULL
&& cur
->data
!= NULL
;
4269 GtkCTreeNode
*node
= GTK_CTREE_NODE(cur
->data
);
4270 MsgInfo
*msginfo
= gtk_ctree_node_get_row_data(
4271 GTK_CTREE(summaryview
->ctree
),
4273 gint sel_start
= -1, sel_end
= -1, partnum
= 0;
4275 if (node
== summaryview
->displayed
) {
4276 partnum
= mimeview_get_selected_part_num(summaryview
->messageview
->mimeview
);
4277 textview_get_selection_offsets(summaryview
->messageview
->mimeview
->textview
,
4278 &sel_start
, &sel_end
);
4280 messageview_print(msginfo
, summaryview
->messageview
->all_headers
,
4281 sel_start
, sel_end
, partnum
);
4286 gboolean
summary_execute(SummaryView
*summaryview
)
4288 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
4289 GtkCList
*clist
= GTK_CLIST(summaryview
->ctree
);
4290 GtkCTreeNode
*node
, *next
;
4291 GtkCTreeNode
*new_selected
= NULL
;
4294 if (!summaryview
->folder_item
) return FALSE
;
4296 if (summary_is_locked(summaryview
)) return FALSE
;
4297 summary_lock(summaryview
);
4299 summary_freeze(summaryview
);
4301 main_window_cursor_wait(summaryview
->mainwin
);
4303 if (summaryview
->threaded
)
4304 summary_unthread_for_exec(summaryview
);
4306 folder_item_update_freeze();
4307 move_val
= summary_execute_move(summaryview
);
4308 summary_execute_copy(summaryview
);
4309 summary_execute_delete(summaryview
);
4311 node
= GTK_CTREE_NODE(clist
->row_list
);
4312 for (; node
!= NULL
; node
= next
) {
4313 next
= gtkut_ctree_node_next(ctree
, node
);
4314 if (gtk_ctree_node_get_row_data(ctree
, node
) != NULL
) continue;
4316 if (node
== summaryview
->displayed
) {
4317 messageview_clear(summaryview
->messageview
);
4318 summaryview
->displayed
= NULL
;
4320 if (GTK_CTREE_ROW(node
)->children
!= NULL
) {
4322 if (GTK_CTREE_ROW(node
)->sibling
) {
4323 next
= GTK_CTREE_ROW(node
)->sibling
;
4325 GtkCTreeNode
*parent
= NULL
;
4326 for (parent
= GTK_CTREE_ROW(node
)->parent
; parent
!= NULL
;
4327 parent
= GTK_CTREE_ROW(parent
)->parent
) {
4328 if (GTK_CTREE_ROW(parent
)->sibling
) {
4329 next
= GTK_CTREE_ROW(parent
)->sibling
;
4335 if (!new_selected
&&
4336 gtkut_ctree_node_is_selected(ctree
, node
)) {
4337 summary_unselect_all(summaryview
);
4338 new_selected
= summary_find_next_msg(summaryview
, node
);
4340 new_selected
= summary_find_prev_msg
4341 (summaryview
, node
);
4344 gtk_sctree_remove_node((GtkSCTree
*)ctree
, node
);
4347 folder_item_update_thaw();
4350 summary_unlock(summaryview
);
4352 (GTK_SCTREE(ctree
), new_selected
);
4353 summary_lock(summaryview
);
4356 if (summaryview
->threaded
) {
4357 summary_thread_build(summaryview
);
4358 summary_thread_init(summaryview
);
4361 summary_thaw(summaryview
);
4363 summaryview
->selected
= clist
->selection
?
4364 GTK_CTREE_NODE(clist
->selection
->data
) : NULL
;
4366 if (!GTK_CLIST(summaryview
->ctree
)->row_list
) {
4367 menu_set_insensitive_all
4368 (GTK_MENU_SHELL(summaryview
->popupmenu
));
4369 gtk_widget_grab_focus(summaryview
->folderview
->ctree
);
4371 gtk_widget_grab_focus(summaryview
->ctree
);
4373 summary_update_status(summaryview
);
4374 summary_status_show(summaryview
);
4376 gtk_ctree_node_moveto(ctree
, summaryview
->selected
, 0, 0.5, 0);
4378 summary_unlock(summaryview
);
4380 main_window_cursor_normal(summaryview
->mainwin
);
4383 summary_show(summaryview
, summaryview
->folder_item
);
4387 static gint
summary_execute_move(SummaryView
*summaryview
)
4389 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
4392 /* search moving messages and execute */
4393 gtk_ctree_pre_recursive(ctree
, NULL
, summary_execute_move_func
,
4396 if (summaryview
->mlist
) {
4397 hooks_unregister_hook(MSGINFO_UPDATE_HOOKLIST
,
4398 summaryview
->msginfo_update_callback_id
);
4399 val
= procmsg_move_messages(summaryview
->mlist
);
4400 summaryview
->msginfo_update_callback_id
=
4401 hooks_register_hook(MSGINFO_UPDATE_HOOKLIST
,
4402 summary_update_msg
, (gpointer
) summaryview
);
4404 for (cur
= summaryview
->mlist
; cur
!= NULL
&& cur
->data
!= NULL
; cur
= cur
->next
)
4405 procmsg_msginfo_free((MsgInfo
*)cur
->data
);
4406 g_slist_free(summaryview
->mlist
);
4407 summaryview
->mlist
= NULL
;
4413 static void summary_execute_move_func(GtkCTree
*ctree
, GtkCTreeNode
*node
,
4416 SummaryView
*summaryview
= data
;
4419 msginfo
= GTKUT_CTREE_NODE_GET_ROW_DATA(node
);
4421 if (msginfo
&& MSG_IS_MOVE(msginfo
->flags
) && msginfo
->to_folder
) {
4422 summaryview
->mlist
=
4423 g_slist_prepend(summaryview
->mlist
, msginfo
);
4424 gtk_ctree_node_set_row_data(ctree
, node
, NULL
);
4426 if (msginfo
->msgid
&& *msginfo
->msgid
&&
4427 node
== g_hash_table_lookup(summaryview
->msgid_table
,
4429 g_hash_table_remove(summaryview
->msgid_table
,
4431 if (prefs_common
.thread_by_subject
&&
4432 msginfo
->subject
&& *msginfo
->subject
&&
4433 node
== subject_table_lookup(summaryview
->subject_table
,
4434 msginfo
->subject
)) {
4435 subject_table_remove(summaryview
->subject_table
,
4441 static void summary_execute_copy(SummaryView
*summaryview
)
4443 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
4445 /* search copying messages and execute */
4446 hooks_unregister_hook(MSGINFO_UPDATE_HOOKLIST
,
4447 summaryview
->msginfo_update_callback_id
);
4448 gtk_ctree_pre_recursive(ctree
, NULL
, summary_execute_copy_func
,
4451 if (summaryview
->mlist
) {
4452 summaryview
->mlist
= g_slist_reverse(summaryview
->mlist
);
4453 procmsg_copy_messages(summaryview
->mlist
);
4455 g_slist_free(summaryview
->mlist
);
4456 summaryview
->mlist
= NULL
;
4458 summaryview
->msginfo_update_callback_id
=
4459 hooks_register_hook(MSGINFO_UPDATE_HOOKLIST
,
4460 summary_update_msg
, (gpointer
) summaryview
);
4463 static void summary_execute_copy_func(GtkCTree
*ctree
, GtkCTreeNode
*node
,
4466 SummaryView
*summaryview
= data
;
4469 msginfo
= GTKUT_CTREE_NODE_GET_ROW_DATA(node
);
4471 if (msginfo
&& MSG_IS_COPY(msginfo
->flags
) && msginfo
->to_folder
) {
4472 summaryview
->mlist
=
4473 g_slist_prepend(summaryview
->mlist
, msginfo
);
4475 summary_msginfo_unset_flags(msginfo
, 0, MSG_COPY
);
4476 summary_set_row_marks(summaryview
, node
);
4480 static void summary_execute_delete(SummaryView
*summaryview
)
4482 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
4485 /* search deleting messages and execute */
4486 gtk_ctree_pre_recursive
4487 (ctree
, NULL
, summary_execute_delete_func
, summaryview
);
4489 if (!summaryview
->mlist
) return;
4491 hooks_unregister_hook(MSGINFO_UPDATE_HOOKLIST
,
4492 summaryview
->msginfo_update_callback_id
);
4494 folder_item_remove_msgs(summaryview
->folder_item
,
4495 summaryview
->mlist
);
4497 summaryview
->msginfo_update_callback_id
=
4498 hooks_register_hook(MSGINFO_UPDATE_HOOKLIST
,
4499 summary_update_msg
, (gpointer
) summaryview
);
4500 for (cur
= summaryview
->mlist
; cur
!= NULL
&& cur
->data
!= NULL
; cur
= cur
->next
)
4501 procmsg_msginfo_free((MsgInfo
*)cur
->data
);
4503 g_slist_free(summaryview
->mlist
);
4504 summaryview
->mlist
= NULL
;
4507 static void summary_execute_delete_func(GtkCTree
*ctree
, GtkCTreeNode
*node
,
4510 SummaryView
*summaryview
= data
;
4513 msginfo
= GTKUT_CTREE_NODE_GET_ROW_DATA(node
);
4515 if (msginfo
&& MSG_IS_DELETED(msginfo
->flags
)) {
4516 summaryview
->mlist
=
4517 g_slist_prepend(summaryview
->mlist
, msginfo
);
4518 gtk_ctree_node_set_row_data(ctree
, node
, NULL
);
4520 if (msginfo
->msgid
&& *msginfo
->msgid
&&
4521 node
== g_hash_table_lookup(summaryview
->msgid_table
,
4523 g_hash_table_remove(summaryview
->msgid_table
,
4526 if (prefs_common
.thread_by_subject
&&
4527 msginfo
->subject
&& *msginfo
->subject
&&
4528 node
== subject_table_lookup(summaryview
->subject_table
,
4529 msginfo
->subject
)) {
4530 subject_table_remove(summaryview
->subject_table
,
4536 /* thread functions */
4538 void summary_thread_build(SummaryView
*summaryview
)
4540 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
4543 GtkCTreeNode
*parent
;
4547 summary_lock(summaryview
);
4549 debug_print("Building threads...");
4550 STATUSBAR_PUSH(summaryview
->mainwin
, _("Building threads..."));
4551 main_window_cursor_wait(summaryview
->mainwin
);
4553 g_signal_handlers_block_by_func(G_OBJECT(ctree
),
4554 G_CALLBACK(summary_tree_expanded
), summaryview
);
4555 summary_freeze(summaryview
);
4557 node
= GTK_CTREE_NODE(GTK_CLIST(ctree
)->row_list
);
4559 next
= GTK_CTREE_ROW(node
)->sibling
;
4561 msginfo
= GTKUT_CTREE_NODE_GET_ROW_DATA(node
);
4565 if (msginfo
&& msginfo
->inreplyto
) {
4566 parent
= g_hash_table_lookup(summaryview
->msgid_table
,
4567 msginfo
->inreplyto
);
4569 if (!parent
&& msginfo
->references
) {
4570 for (reflist
= msginfo
->references
;
4571 reflist
!= NULL
; reflist
= reflist
->next
)
4572 if ((parent
= g_hash_table_lookup
4573 (summaryview
->msgid_table
,
4579 if (prefs_common
.thread_by_subject
&& parent
== NULL
) {
4580 parent
= subject_table_lookup
4581 (summaryview
->subject_table
,
4585 if (parent
&& parent
!= node
&& parent
!= GTK_CTREE_ROW(node
)->parent
) {
4586 gtk_ctree_move(ctree
, node
, parent
, NULL
);
4592 gtkut_ctree_set_focus_row(ctree
, summaryview
->selected
);
4594 summary_thaw(summaryview
);
4595 g_signal_handlers_unblock_by_func(G_OBJECT(ctree
),
4596 G_CALLBACK(summary_tree_expanded
), summaryview
);
4598 debug_print("done.\n");
4599 STATUSBAR_POP(summaryview
->mainwin
);
4600 main_window_cursor_normal(summaryview
->mainwin
);
4602 summaryview
->threaded
= TRUE
;
4604 summary_unlock(summaryview
);
4607 static void summary_thread_init(SummaryView
*summaryview
)
4609 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
4610 GtkCTreeNode
*node
= GTK_CTREE_NODE(GTK_CLIST(ctree
)->row_list
);
4613 if (!summaryview
->thread_collapsed
) {
4614 g_signal_handlers_block_by_func(G_OBJECT(ctree
),
4615 G_CALLBACK(summary_tree_expanded
), summaryview
);
4617 next
= GTK_CTREE_ROW(node
)->sibling
;
4618 if (GTK_CTREE_ROW(node
)->children
)
4619 gtk_ctree_expand_recursive(ctree
, node
);
4622 g_signal_handlers_unblock_by_func(G_OBJECT(ctree
),
4623 G_CALLBACK(summary_tree_expanded
), summaryview
);
4628 static void summary_unthread_for_exec(SummaryView
*summaryview
)
4631 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
4632 gboolean froze
= FALSE
;
4634 debug_print("Unthreading for execution...");
4636 START_LONG_OPERATION(summaryview
, TRUE
);
4637 for (node
= GTK_CTREE_NODE(GTK_CLIST(ctree
)->row_list
);
4638 node
!= NULL
; node
= GTK_CTREE_NODE_NEXT(node
)) {
4639 summary_unthread_for_exec_func(ctree
, node
, summaryview
);
4642 END_LONG_OPERATION(summaryview
);
4644 debug_print("done.\n");
4647 static void summary_unthread_for_exec_func(GtkCTree
*ctree
, GtkCTreeNode
*node
,
4651 GtkCTreeNode
*top_parent
;
4652 GtkCTreeNode
*child
;
4653 GtkCTreeNode
*sibling
;
4654 SummaryView
* summaryview
= (SummaryView
*)data
;
4655 msginfo
= GTKUT_CTREE_NODE_GET_ROW_DATA(node
);
4658 (!MSG_IS_MOVE(msginfo
->flags
) &&
4659 !MSG_IS_DELETED(msginfo
->flags
)))
4661 child
= GTK_CTREE_ROW(node
)->children
;
4664 if (node
== summaryview
->selected
)
4665 summaryview
->selected
= NULL
;
4666 if (node
== summaryview
->displayed
)
4667 summaryview
->displayed
= NULL
;
4669 for (top_parent
= node
;
4670 GTK_CTREE_ROW(top_parent
)->parent
!= NULL
;
4671 top_parent
= GTK_CTREE_ROW(top_parent
)->parent
)
4673 sibling
= GTK_CTREE_ROW(top_parent
)->sibling
;
4675 GTK_SCTREE(ctree
)->sorting
= TRUE
;
4676 while (child
!= NULL
) {
4677 GtkCTreeNode
*next_child
;
4678 MsgInfo
*cinfo
= GTKUT_CTREE_NODE_GET_ROW_DATA(child
);
4680 next_child
= GTK_CTREE_ROW(child
)->sibling
;
4682 if (!MSG_IS_MOVE(cinfo
->flags
) && !MSG_IS_DELETED(cinfo
->flags
)) {
4683 gtk_ctree_move(ctree
, child
,
4687 if (child
== summaryview
->displayed
) {
4688 messageview_clear(summaryview
->messageview
);
4689 summaryview
->displayed
= NULL
;
4691 if (child
== summaryview
->selected
) {
4692 messageview_clear(summaryview
->messageview
);
4693 summaryview
->selected
= NULL
;
4698 GTK_SCTREE(ctree
)->sorting
= FALSE
;
4701 void summary_expand_threads(SummaryView
*summaryview
)
4703 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
4704 GtkCTreeNode
*node
= GTK_CTREE_NODE(GTK_CLIST(ctree
)->row_list
);
4706 g_signal_handlers_block_by_func(G_OBJECT(ctree
),
4707 G_CALLBACK(summary_tree_expanded
), summaryview
);
4708 summary_freeze(summaryview
);
4711 if (GTK_CTREE_ROW(node
)->children
) {
4712 gtk_ctree_expand(ctree
, node
);
4713 summary_set_row_marks(summaryview
, node
);
4715 node
= GTK_CTREE_NODE_NEXT(node
);
4718 summary_thaw(summaryview
);
4719 g_signal_handlers_unblock_by_func(G_OBJECT(ctree
),
4720 G_CALLBACK(summary_tree_expanded
), summaryview
);
4722 summaryview
->thread_collapsed
= FALSE
;
4724 gtk_ctree_node_moveto(ctree
, summaryview
->selected
, 0, 0.5, 0);
4727 void summary_collapse_threads(SummaryView
*summaryview
)
4729 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
4730 GtkCTreeNode
*node
= GTK_CTREE_NODE(GTK_CLIST(ctree
)->row_list
);
4732 summary_freeze(summaryview
);
4735 if (GTK_CTREE_ROW(node
)->children
)
4736 gtk_ctree_collapse(ctree
, node
);
4737 node
= GTK_CTREE_ROW(node
)->sibling
;
4740 summary_thaw(summaryview
);
4742 summaryview
->thread_collapsed
= TRUE
;
4744 gtk_ctree_node_moveto(ctree
, summaryview
->selected
, 0, 0.5, 0);
4747 static void account_rules_radio_button_toggled_cb(GtkToggleButton
*btn
, gpointer data
)
4749 prefs_common
.apply_per_account_filtering_rules
= GPOINTER_TO_INT(data
);
4752 static gboolean
summary_filter_get_mode(void)
4753 /* ask what to do w/ them: skip them, apply them regardless to the account,
4754 use the current account */
4756 /* TODO: eventually also propose to use the current folder's default account,
4758 /* TODO: eventually allow to select the account to use from a optmenu */
4761 GtkWidget
*account_rules_skip
;
4762 GtkWidget
*account_rules_force
;
4763 GtkWidget
*account_rules_user_current
;
4766 vbox
= gtk_vbox_new (FALSE
, 0);
4768 account_rules_skip
= gtk_radio_button_new_with_label
4769 (NULL
, _("Skip these rules"));
4770 account_rules_force
= gtk_radio_button_new_with_label_from_widget
4771 (GTK_RADIO_BUTTON(account_rules_skip
),
4772 _("Apply these rules regardless of the account they belong to"));
4773 account_rules_user_current
= gtk_radio_button_new_with_label_from_widget
4774 (GTK_RADIO_BUTTON(account_rules_skip
),
4775 _("Apply these rules if they apply to the current account"));
4776 gtk_box_pack_start (GTK_BOX (vbox
), account_rules_skip
, FALSE
, FALSE
, 0);
4777 gtk_box_pack_start (GTK_BOX (vbox
), account_rules_force
, FALSE
, FALSE
, 0);
4778 gtk_box_pack_start (GTK_BOX (vbox
), account_rules_user_current
, FALSE
, FALSE
, 0);
4779 g_signal_connect(G_OBJECT(account_rules_skip
), "toggled",
4780 G_CALLBACK(account_rules_radio_button_toggled_cb
),
4781 GINT_TO_POINTER(FILTERING_ACCOUNT_RULES_SKIP
));
4782 g_signal_connect(G_OBJECT(account_rules_force
), "toggled",
4783 G_CALLBACK(account_rules_radio_button_toggled_cb
),
4784 GINT_TO_POINTER(FILTERING_ACCOUNT_RULES_FORCE
));
4785 g_signal_connect(G_OBJECT(account_rules_user_current
), "toggled",
4786 G_CALLBACK(account_rules_radio_button_toggled_cb
),
4787 GINT_TO_POINTER(FILTERING_ACCOUNT_RULES_USE_CURRENT
));
4788 switch (prefs_common
.apply_per_account_filtering_rules
) {
4789 case FILTERING_ACCOUNT_RULES_SKIP
:
4790 gtk_toggle_button_set_active(
4791 GTK_TOGGLE_BUTTON(account_rules_skip
), TRUE
);
4793 case FILTERING_ACCOUNT_RULES_FORCE
:
4794 gtk_toggle_button_set_active(
4795 GTK_TOGGLE_BUTTON(account_rules_force
), TRUE
);
4797 case FILTERING_ACCOUNT_RULES_USE_CURRENT
:
4798 gtk_toggle_button_set_active(
4799 GTK_TOGGLE_BUTTON(account_rules_user_current
), TRUE
);
4803 val
= alertpanel_with_widget(
4805 _("There are some filtering rules that belong to an account.\n"
4806 "Please choose what to do with these rules:"),
4807 GTK_STOCK_CANCEL
, _("+_Filter"), NULL
, TRUE
, vbox
);
4808 if ((val
& ~G_ALERTDISABLE
) == G_ALERTDEFAULT
) {
4810 } else if (val
& G_ALERTDISABLE
)
4811 prefs_common
.ask_apply_per_account_filtering_rules
= FALSE
;
4816 void summary_filter(SummaryView
*summaryview
, gboolean selected_only
)
4818 GSList
*mlist
= NULL
, *cur_list
;
4819 summary_lock(summaryview
);
4821 /* are there any per-account filtering rules? */
4822 if (prefs_common
.ask_apply_per_account_filtering_rules
== TRUE
&&
4823 filtering_peek_per_account_rules(filtering_rules
)) {
4825 if (summary_filter_get_mode() == FALSE
) {
4826 summary_unlock(summaryview
);
4831 folder_item_update_freeze();
4833 debug_print("filtering...");
4834 STATUSBAR_PUSH(summaryview
->mainwin
, _("Filtering..."));
4835 main_window_cursor_wait(summaryview
->mainwin
);
4837 summary_freeze(summaryview
);
4839 if (selected_only
) {
4842 for (cur
= GTK_CLIST(summaryview
->ctree
)->selection
;
4843 cur
!= NULL
&& cur
->data
!= NULL
; cur
= cur
->next
) {
4844 mlist
= g_slist_prepend(mlist
,
4845 procmsg_msginfo_new_ref(
4846 GTKUT_CTREE_NODE_GET_ROW_DATA(cur
->data
)));
4848 mlist
= g_slist_reverse(mlist
);
4850 mlist
= folder_item_get_msg_list(summaryview
->folder_item
);
4852 for (cur_list
= mlist
; cur_list
; cur_list
= cur_list
->next
) {
4853 summary_filter_func((MsgInfo
*)cur_list
->data
);
4855 filtering_move_and_copy_msgs(mlist
);
4856 for (cur_list
= mlist
; cur_list
; cur_list
= cur_list
->next
) {
4857 procmsg_msginfo_free((MsgInfo
*)cur_list
->data
);
4859 g_slist_free(mlist
);
4861 summary_thaw(summaryview
);
4863 folder_item_update_thaw();
4864 debug_print("done.\n");
4865 STATUSBAR_POP(summaryview
->mainwin
);
4866 main_window_cursor_normal(summaryview
->mainwin
);
4868 summary_unlock(summaryview
);
4871 * CLAWS: summary_show() only valid after having a lock. ideally
4872 * we want the lock to be context aware...
4874 summary_show(summaryview
, summaryview
->folder_item
);
4877 static void summary_filter_func(MsgInfo
*msginfo
)
4879 MailFilteringData mail_filtering_data
;
4881 mail_filtering_data
.msginfo
= msginfo
;
4882 mail_filtering_data
.msglist
= NULL
;
4883 mail_filtering_data
.filtered
= NULL
;
4884 mail_filtering_data
.unfiltered
= NULL
;
4885 if (hooks_invoke(MAIL_MANUAL_FILTERING_HOOKLIST
, &mail_filtering_data
))
4888 filter_message_by_msginfo(filtering_rules
, msginfo
, NULL
,
4889 FILTERING_MANUALLY
, NULL
);
4892 void summary_msginfo_filter_open(FolderItem
* item
, MsgInfo
*msginfo
,
4893 PrefsFilterType type
, gint processing_rule
)
4895 gchar
*header
= NULL
;
4898 procmsg_get_filter_keyword(msginfo
, &header
, &key
, type
);
4900 if (processing_rule
) {
4902 prefs_filtering_open(&pre_global_processing
,
4903 _("Processing rules to apply before folder rules"),
4904 MANUAL_ANCHOR_PROCESSING
,
4905 header
, key
, FALSE
);
4907 prefs_filtering_open(&item
->prefs
->processing
,
4908 _("Processing configuration"),
4909 MANUAL_ANCHOR_PROCESSING
,
4910 header
, key
, FALSE
);
4913 prefs_filtering_open(&filtering_rules
,
4914 _("Filtering configuration"),
4915 MANUAL_ANCHOR_FILTERING
,
4923 void summary_filter_open(SummaryView
*summaryview
, PrefsFilterType type
,
4924 gint processing_rule
)
4929 if (!summaryview
->selected
) return;
4931 msginfo
= gtk_ctree_node_get_row_data(GTK_CTREE(summaryview
->ctree
),
4932 summaryview
->selected
);
4933 if (!msginfo
) return;
4935 item
= summaryview
->folder_item
;
4936 summary_msginfo_filter_open(item
, msginfo
, type
, processing_rule
);
4941 #define N_COLOR_LABELS colorlabel_get_color_count()
4943 static void summary_colorlabel_menu_item_activate_cb(GtkWidget
*widget
,
4946 guint color
= GPOINTER_TO_UINT(data
);
4947 SummaryView
*summaryview
;
4949 summaryview
= g_object_get_data(G_OBJECT(widget
), "summaryview");
4950 g_return_if_fail(summaryview
!= NULL
);
4952 /* "dont_toggle" state set? */
4953 if (g_object_get_data(G_OBJECT(summaryview
->colorlabel_menu
),
4957 summary_set_colorlabel(summaryview
, color
, NULL
);
4960 /* summary_set_colorlabel_color() - labelcolor parameter is the color *flag*
4961 * for the messsage; not the color index */
4962 void summary_set_colorlabel_color(GtkCTree
*ctree
, GtkCTreeNode
*node
,
4966 GtkStyle
*style
, *prev_style
, *ctree_style
;
4970 msginfo
= gtk_ctree_node_get_row_data(ctree
, node
);
4971 g_return_if_fail(msginfo
);
4973 color_index
= labelcolor
== 0 ? -1 : (gint
)labelcolor
- 1;
4974 ctree_style
= gtk_widget_get_style(GTK_WIDGET(ctree
));
4975 prev_style
= gtk_ctree_node_get_row_style(ctree
, node
);
4977 if (color_index
< 0 || color_index
>= N_COLOR_LABELS
) {
4978 if (!prev_style
) return;
4979 style
= gtk_style_copy(prev_style
);
4980 color
= ctree_style
->fg
[GTK_STATE_NORMAL
];
4981 style
->fg
[GTK_STATE_NORMAL
] = color
;
4982 color
= ctree_style
->fg
[GTK_STATE_SELECTED
];
4983 style
->fg
[GTK_STATE_SELECTED
] = color
;
4986 style
= gtk_style_copy(prev_style
);
4988 style
= gtk_style_copy(ctree_style
);
4989 color
= colorlabel_get_color(color_index
);
4990 style
->fg
[GTK_STATE_NORMAL
] = color
;
4991 /* get the average of label color and selected fg color
4993 style
->fg
[GTK_STATE_SELECTED
].red
= (color
.red
+ 3*ctree_style
->fg
[GTK_STATE_SELECTED
].red
) / 4;
4994 style
->fg
[GTK_STATE_SELECTED
].green
= (color
.green
+ 3*ctree_style
->fg
[GTK_STATE_SELECTED
].green
) / 4;
4995 style
->fg
[GTK_STATE_SELECTED
].blue
= (color
.blue
+ 3*ctree_style
->fg
[GTK_STATE_SELECTED
].blue
) / 4;
4998 gtk_ctree_node_set_row_style(ctree
, node
, style
);
4999 gtk_style_unref(style
);
5002 static void summary_set_row_colorlabel(SummaryView
*summaryview
, GtkCTreeNode
*row
, guint labelcolor
)
5004 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
5007 msginfo
= gtk_ctree_node_get_row_data(ctree
, row
);
5008 g_return_if_fail(msginfo
);
5010 summary_msginfo_change_flags(msginfo
, MSG_COLORLABEL_TO_FLAGS(labelcolor
), 0,
5011 MSG_CLABEL_FLAG_MASK
, 0);
5012 summary_set_row_marks(summaryview
, row
);
5015 void summary_set_colorlabel(SummaryView
*summaryview
, guint labelcolor
,
5018 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
5020 gboolean froze
= FALSE
;
5022 START_LONG_OPERATION(summaryview
, FALSE
);
5023 for (cur
= GTK_CLIST(ctree
)->selection
; cur
!= NULL
&& cur
->data
!= NULL
; cur
= cur
->next
)
5024 summary_set_row_colorlabel(summaryview
,
5025 GTK_CTREE_NODE(cur
->data
), labelcolor
);
5026 END_LONG_OPERATION(summaryview
);
5029 static void summary_colorlabel_menu_item_activate_item_cb(GtkMenuItem
*menu_item
,
5032 SummaryView
*summaryview
;
5034 GtkCheckMenuItem
**items
;
5038 summaryview
= (SummaryView
*)data
;
5039 g_return_if_fail(summaryview
!= NULL
);
5041 sel
= GTK_CLIST(summaryview
->ctree
)->selection
;
5044 menu
= GTK_MENU_SHELL(summaryview
->colorlabel_menu
);
5046 g_return_if_fail(menu
!= NULL
);
5048 Xalloca(items
, (N_COLOR_LABELS
+ 1) * sizeof(GtkWidget
*), return);
5050 /* NOTE: don't return prematurely because we set the "dont_toggle"
5051 * state for check menu items */
5052 g_object_set_data(G_OBJECT(menu
), "dont_toggle",
5053 GINT_TO_POINTER(1));
5055 /* clear items. get item pointers. */
5056 for (n
= 0, cur
= menu
->children
; cur
!= NULL
&& cur
->data
!= NULL
; cur
= cur
->next
) {
5057 if (GTK_IS_CHECK_MENU_ITEM(cur
->data
)) {
5058 gtk_check_menu_item_set_active
5059 (GTK_CHECK_MENU_ITEM(cur
->data
), FALSE
);
5060 items
[n
] = GTK_CHECK_MENU_ITEM(cur
->data
);
5065 if (n
== (N_COLOR_LABELS
+ 1)) {
5066 /* iterate all messages and set the state of the appropriate
5068 for (; sel
!= NULL
; sel
= sel
->next
) {
5072 msginfo
= gtk_ctree_node_get_row_data
5073 (GTK_CTREE(summaryview
->ctree
),
5074 GTK_CTREE_NODE(sel
->data
));
5076 clabel
= MSG_GET_COLORLABEL_VALUE(msginfo
->flags
);
5077 if (!items
[clabel
]->active
)
5078 gtk_check_menu_item_set_active
5079 (items
[clabel
], TRUE
);
5083 g_warning("invalid number of color elements (%d)\n", n
);
5085 /* reset "dont_toggle" state */
5086 g_object_set_data(G_OBJECT(menu
), "dont_toggle",
5087 GINT_TO_POINTER(0));
5090 static void summary_colorlabel_menu_create(SummaryView
*summaryview
, gboolean refresh
)
5092 GtkWidget
*label_menuitem
;
5097 label_menuitem
= gtk_item_factory_get_item(summaryview
->popupfactory
,
5099 g_signal_connect(G_OBJECT(label_menuitem
), "activate",
5100 G_CALLBACK(summary_colorlabel_menu_item_activate_item_cb
),
5102 gtk_widget_show(label_menuitem
);
5104 menu
= gtk_menu_new();
5106 /* create sub items. for the menu item activation callback we pass the
5107 * index of label_colors[] as data parameter. for the None color we
5108 * pass an invalid (high) value. also we attach a data pointer so we
5109 * can always get back the SummaryView pointer. */
5111 item
= gtk_check_menu_item_new_with_label(_("None"));
5112 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
5113 g_signal_connect(G_OBJECT(item
), "activate",
5114 G_CALLBACK(summary_colorlabel_menu_item_activate_cb
),
5115 GUINT_TO_POINTER(0));
5116 g_object_set_data(G_OBJECT(item
), "summaryview", summaryview
);
5117 gtk_widget_show(item
);
5119 gtk_widget_add_accelerator(item
, "activate",
5120 summaryview
->popupfactory
->accel_group
,
5121 GDK_0
, GDK_CONTROL_MASK
,
5122 GTK_ACCEL_LOCKED
| GTK_ACCEL_VISIBLE
);
5124 item
= gtk_menu_item_new();
5125 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
5126 gtk_widget_show(item
);
5128 /* create pixmap/label menu items */
5129 for (i
= 0; i
< N_COLOR_LABELS
; i
++) {
5130 item
= colorlabel_create_check_color_menu_item(
5131 i
, refresh
, SUMMARY_COLORMENU
);
5132 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
5133 g_signal_connect(G_OBJECT(item
), "activate",
5134 G_CALLBACK(summary_colorlabel_menu_item_activate_cb
),
5135 GUINT_TO_POINTER(i
+ 1));
5136 g_object_set_data(G_OBJECT(item
), "summaryview",
5138 gtk_widget_show(item
);
5141 gtk_widget_show(menu
);
5142 gtk_menu_item_set_submenu(GTK_MENU_ITEM(label_menuitem
), menu
);
5143 summaryview
->colorlabel_menu
= menu
;
5146 static gboolean
summary_popup_menu(GtkWidget
*widget
, gpointer data
)
5148 SummaryView
*summaryview
= (SummaryView
*)data
;
5149 summaryview
->display_msg
= messageview_is_visible(summaryview
->messageview
);
5151 gtk_menu_popup(GTK_MENU(summaryview
->popupmenu
), NULL
, NULL
,
5152 NULL
, NULL
, 0, gtk_get_current_event_time());
5156 static GtkWidget
*summary_ctree_create(SummaryView
*summaryview
)
5159 gint
*col_pos
= summaryview
->col_pos
;
5160 SummaryColumnState
*col_state
;
5161 gchar
*titles
[N_SUMMARY_COLS
];
5162 SummaryColumnType type
;
5165 memset(titles
, 0, sizeof(titles
));
5167 col_state
= prefs_summary_column_get_config();
5168 for (pos
= 0; pos
< N_SUMMARY_COLS
; pos
++) {
5169 summaryview
->col_state
[pos
] = col_state
[pos
];
5170 type
= col_state
[pos
].type
;
5171 col_pos
[type
] = pos
;
5172 titles
[pos
] = "dummy";
5174 col_state
= summaryview
->col_state
;
5176 ctree
= gtk_sctree_new_with_titles
5177 (N_SUMMARY_COLS
, col_pos
[S_COL_SUBJECT
], titles
);
5179 gtk_clist_set_selection_mode(GTK_CLIST(ctree
), GTK_SELECTION_EXTENDED
);
5180 gtk_clist_set_column_justification(GTK_CLIST(ctree
), col_pos
[S_COL_MARK
],
5181 GTK_JUSTIFY_CENTER
);
5182 gtk_clist_set_column_justification(GTK_CLIST(ctree
), col_pos
[S_COL_STATUS
],
5183 GTK_JUSTIFY_CENTER
);
5184 gtk_clist_set_column_justification(GTK_CLIST(ctree
), col_pos
[S_COL_LOCKED
],
5185 GTK_JUSTIFY_CENTER
);
5186 gtk_clist_set_column_justification(GTK_CLIST(ctree
), col_pos
[S_COL_MIME
],
5187 GTK_JUSTIFY_CENTER
);
5188 gtk_clist_set_column_justification(GTK_CLIST(ctree
), col_pos
[S_COL_SIZE
],
5190 gtk_clist_set_column_justification(GTK_CLIST(ctree
), col_pos
[S_COL_NUMBER
],
5192 gtk_clist_set_column_justification(GTK_CLIST(ctree
), col_pos
[S_COL_SCORE
],
5194 gtk_clist_set_column_width(GTK_CLIST(ctree
), col_pos
[S_COL_MARK
],
5195 SUMMARY_COL_MARK_WIDTH
);
5196 gtk_clist_set_column_width(GTK_CLIST(ctree
), col_pos
[S_COL_STATUS
],
5197 SUMMARY_COL_STATUS_WIDTH
);
5198 gtk_clist_set_column_width(GTK_CLIST(ctree
), col_pos
[S_COL_LOCKED
],
5199 SUMMARY_COL_LOCKED_WIDTH
);
5200 gtk_clist_set_column_width(GTK_CLIST(ctree
), col_pos
[S_COL_MIME
],
5201 SUMMARY_COL_MIME_WIDTH
);
5202 gtk_clist_set_column_width(GTK_CLIST(ctree
), col_pos
[S_COL_SUBJECT
],
5203 prefs_common
.summary_col_size
[S_COL_SUBJECT
]);
5204 gtk_clist_set_column_width(GTK_CLIST(ctree
), col_pos
[S_COL_FROM
],
5205 prefs_common
.summary_col_size
[S_COL_FROM
]);
5206 gtk_clist_set_column_width(GTK_CLIST(ctree
), col_pos
[S_COL_TO
],
5207 prefs_common
.summary_col_size
[S_COL_TO
]);
5208 gtk_clist_set_column_width(GTK_CLIST(ctree
), col_pos
[S_COL_DATE
],
5209 prefs_common
.summary_col_size
[S_COL_DATE
]);
5210 gtk_clist_set_column_width(GTK_CLIST(ctree
), col_pos
[S_COL_SIZE
],
5211 prefs_common
.summary_col_size
[S_COL_SIZE
]);
5212 gtk_clist_set_column_width(GTK_CLIST(ctree
), col_pos
[S_COL_NUMBER
],
5213 prefs_common
.summary_col_size
[S_COL_NUMBER
]);
5214 gtk_clist_set_column_width(GTK_CLIST(ctree
), col_pos
[S_COL_SCORE
],
5215 prefs_common
.summary_col_size
[S_COL_SCORE
]);
5217 if (prefs_common
.enable_dotted_lines
) {
5218 gtk_ctree_set_line_style(GTK_CTREE(ctree
), GTK_CTREE_LINES_DOTTED
);
5219 gtk_ctree_set_expander_style(GTK_CTREE(ctree
),
5220 GTK_CTREE_EXPANDER_SQUARE
);
5222 gtk_ctree_set_line_style(GTK_CTREE(ctree
), GTK_CTREE_LINES_NONE
);
5223 gtk_ctree_set_expander_style(GTK_CTREE(ctree
),
5224 GTK_CTREE_EXPANDER_TRIANGLE
);
5227 gtk_sctree_set_stripes(GTK_SCTREE(ctree
), prefs_common
.use_stripes_in_summaries
);
5229 gtk_ctree_set_indent(GTK_CTREE(ctree
), 12);
5230 g_object_set_data(G_OBJECT(ctree
), "summaryview", (gpointer
)summaryview
);
5232 for (pos
= 0; pos
< N_SUMMARY_COLS
; pos
++) {
5233 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(ctree
)->column
[pos
].button
,
5235 gtk_clist_set_column_visibility
5236 (GTK_CLIST(ctree
), pos
, col_state
[pos
].visible
);
5239 /* connect signal to the buttons for sorting */
5240 #define CLIST_BUTTON_SIGNAL_CONNECT(col, func) \
5242 (G_OBJECT(GTK_CLIST(ctree)->column[col_pos[col]].button), \
5247 CLIST_BUTTON_SIGNAL_CONNECT(S_COL_MARK
, summary_mark_clicked
);
5248 CLIST_BUTTON_SIGNAL_CONNECT(S_COL_STATUS
, summary_status_clicked
);
5249 CLIST_BUTTON_SIGNAL_CONNECT(S_COL_MIME
, summary_mime_clicked
);
5250 CLIST_BUTTON_SIGNAL_CONNECT(S_COL_NUMBER
, summary_num_clicked
);
5251 CLIST_BUTTON_SIGNAL_CONNECT(S_COL_SIZE
, summary_size_clicked
);
5252 CLIST_BUTTON_SIGNAL_CONNECT(S_COL_DATE
, summary_date_clicked
);
5253 CLIST_BUTTON_SIGNAL_CONNECT(S_COL_FROM
, summary_from_clicked
);
5254 CLIST_BUTTON_SIGNAL_CONNECT(S_COL_TO
, summary_to_clicked
);
5255 CLIST_BUTTON_SIGNAL_CONNECT(S_COL_SUBJECT
, summary_subject_clicked
);
5256 CLIST_BUTTON_SIGNAL_CONNECT(S_COL_SCORE
, summary_score_clicked
);
5257 CLIST_BUTTON_SIGNAL_CONNECT(S_COL_LOCKED
, summary_locked_clicked
);
5259 #undef CLIST_BUTTON_SIGNAL_CONNECT
5261 g_signal_connect(G_OBJECT(ctree
), "tree_select_row",
5262 G_CALLBACK(summary_selected
), summaryview
);
5263 g_signal_connect(G_OBJECT(ctree
), "tree_unselect_row",
5264 G_CALLBACK(summary_unselected
), summaryview
);
5265 g_signal_connect(G_OBJECT(ctree
), "button_press_event",
5266 G_CALLBACK(summary_button_pressed
),
5268 g_signal_connect(G_OBJECT(ctree
), "popup-menu",
5269 G_CALLBACK(summary_popup_menu
), summaryview
);
5270 g_signal_connect(G_OBJECT(ctree
), "button_release_event",
5271 G_CALLBACK(summary_button_released
),
5273 g_signal_connect(G_OBJECT(ctree
), "key_press_event",
5274 G_CALLBACK(summary_key_pressed
), summaryview
);
5275 g_signal_connect(G_OBJECT(ctree
), "resize_column",
5276 G_CALLBACK(summary_col_resized
), summaryview
);
5277 g_signal_connect(G_OBJECT(ctree
), "open_row",
5278 G_CALLBACK(summary_open_row
), summaryview
);
5280 g_signal_connect_after(G_OBJECT(ctree
), "tree_expand",
5281 G_CALLBACK(summary_tree_expanded
),
5283 g_signal_connect_after(G_OBJECT(ctree
), "tree_collapse",
5284 G_CALLBACK(summary_tree_collapsed
),
5287 g_signal_connect(G_OBJECT(ctree
), "start_drag",
5288 G_CALLBACK(summary_start_drag
),
5290 g_signal_connect(G_OBJECT(ctree
), "drag_data_get",
5291 G_CALLBACK(summary_drag_data_get
),
5293 g_signal_connect(G_OBJECT(ctree
), "drag_end",
5294 G_CALLBACK(summary_drag_end
),
5297 gtk_drag_dest_set(ctree
, GTK_DEST_DEFAULT_ALL
& ~GTK_DEST_DEFAULT_HIGHLIGHT
,
5298 summary_drag_types
, 2,
5299 GDK_ACTION_MOVE
| GDK_ACTION_COPY
| GDK_ACTION_DEFAULT
);
5301 g_signal_connect(G_OBJECT(ctree
), "drag_data_received",
5302 G_CALLBACK(summary_drag_data_received
),
5305 g_signal_connect(G_OBJECT(ctree
), "drag_motion",
5306 G_CALLBACK(summary_drag_motion_cb
),
5312 void summary_set_column_order(SummaryView
*summaryview
)
5315 GtkWidget
*scrolledwin
= summaryview
->scrolledwin
;
5317 guint selected_msgnum
= summary_get_msgnum(summaryview
, summaryview
->selected
);
5318 guint displayed_msgnum
= summary_get_msgnum(summaryview
, summaryview
->displayed
);
5320 item
= summaryview
->folder_item
;
5322 summary_clear_all(summaryview
);
5323 gtk_widget_destroy(summaryview
->ctree
);
5325 summaryview
->ctree
= ctree
= summary_ctree_create(summaryview
);
5326 summary_set_fonts(summaryview
);
5327 summary_set_column_titles(summaryview
);
5328 gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(scrolledwin
),
5329 GTK_CLIST(ctree
)->hadjustment
);
5330 gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(scrolledwin
),
5331 GTK_CLIST(ctree
)->vadjustment
);
5332 gtk_container_add(GTK_CONTAINER(scrolledwin
), ctree
);
5333 gtk_widget_show(ctree
);
5335 summary_show(summaryview
, item
);
5337 summary_select_by_msgnum(summaryview
, selected_msgnum
);
5339 summaryview
->displayed
= summary_find_msg_by_msgnum(summaryview
, displayed_msgnum
);
5340 summaryview
->last_displayed
= summaryview
->displayed
;
5341 if (!summaryview
->displayed
)
5342 messageview_clear(summaryview
->messageview
);
5344 summary_redisplay_msg(summaryview
);
5348 /* callback functions */
5350 static gint
summary_folder_eventbox_pressed(GtkWidget
*eventbox
, GdkEventButton
*event
,
5351 SummaryView
*summaryview
)
5354 gtk_widget_grab_focus(summaryview
->folderview
->ctree
);
5355 mainwindow_exit_folder(summaryview
->mainwin
);
5360 static gint
summary_toggle_pressed(GtkWidget
*eventbox
, GdkEventButton
*event
,
5361 SummaryView
*summaryview
)
5364 summary_toggle_view(summaryview
);
5368 static gboolean
summary_button_pressed(GtkWidget
*ctree
, GdkEventButton
*event
,
5369 SummaryView
*summaryview
)
5371 if (!event
) return FALSE
;
5373 if (event
->button
== 3) {
5374 summaryview
->display_msg
= messageview_is_visible(summaryview
->messageview
);
5376 gtk_menu_popup(GTK_MENU(summaryview
->popupmenu
), NULL
, NULL
,
5377 NULL
, NULL
, event
->button
, event
->time
);
5378 } else if (event
->button
== 2) {
5379 summaryview
->display_msg
= messageview_is_visible(summaryview
->messageview
);
5380 } else if (event
->button
== 1) {
5381 if (!prefs_common
.emulate_emacs
&&
5382 messageview_is_visible(summaryview
->messageview
))
5383 summaryview
->display_msg
= TRUE
;
5389 static gboolean
summary_button_released(GtkWidget
*ctree
, GdkEventButton
*event
,
5390 SummaryView
*summaryview
)
5395 gboolean
summary_pass_key_press_event(SummaryView
*summaryview
, GdkEventKey
*event
)
5397 return summary_key_pressed(summaryview
->ctree
, event
, summaryview
);
5400 #define BREAK_ON_MODIFIER_KEY() \
5401 if ((event->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK)) != 0) break
5403 static gboolean
summary_key_pressed(GtkWidget
*widget
, GdkEventKey
*event
,
5404 SummaryView
*summaryview
)
5406 GtkCTree
*ctree
= GTK_CTREE(widget
);
5408 MessageView
*messageview
;
5411 gboolean mod_pressed
;
5416 if (quicksearch_has_focus(summaryview
->quicksearch
))
5419 messageview
= summaryview
->messageview
;
5420 textview
= messageview
->mimeview
->textview
;
5423 ((event
->state
& (GDK_SHIFT_MASK
|GDK_MOD1_MASK
)) != 0);
5425 if (summaryview
->selected
) {
5426 gboolean handled
= FALSE
;
5427 switch (event
->keyval
) {
5428 case GDK_space
: /* Page down or go to the next */
5430 if (event
->state
& GDK_CONTROL_MASK
)
5431 event
->state
&= ~GDK_CONTROL_MASK
;
5432 if (event
->state
& GDK_SHIFT_MASK
)
5433 mimeview_scroll_page(messageview
->mimeview
, TRUE
);
5435 if (summaryview
->displayed
!= summaryview
->selected
) {
5436 summary_display_msg(summaryview
,
5437 summaryview
->selected
);
5441 if (!mimeview_scroll_page(messageview
->mimeview
, TRUE
))
5442 summary_select_prev_unread(summaryview
);
5444 if (!mimeview_scroll_page(messageview
->mimeview
, FALSE
))
5445 summary_select_next_unread(summaryview
);
5449 case GDK_BackSpace
: /* Page up */
5451 mimeview_scroll_page(messageview
->mimeview
, TRUE
);
5453 case GDK_Return
: /* Scroll up/down one line */
5455 if (summaryview
->displayed
!= summaryview
->selected
) {
5456 summary_display_msg(summaryview
,
5457 summaryview
->selected
);
5460 mimeview_scroll_one_line(messageview
->mimeview
, mod_pressed
);
5467 if (summary_is_locked(summaryview
))
5470 switch (event
->keyval
) {
5471 case GDK_Left
: /* Move focus */
5472 adj
= gtk_scrolled_window_get_hadjustment
5473 (GTK_SCROLLED_WINDOW(summaryview
->scrolledwin
));
5474 if (adj
->lower
!= adj
->value
)
5478 gtk_widget_grab_focus(summaryview
->folderview
->ctree
);
5479 mainwindow_exit_folder(summaryview
->mainwin
);
5483 if ((node
= summaryview
->selected
) != NULL
) {
5484 GtkCTreeNode
*next
= NULL
;
5485 next
= (event
->keyval
== GDK_Home
)
5486 ? gtk_ctree_node_nth(ctree
, 0)
5487 : gtk_ctree_node_nth(ctree
,
5488 g_list_length(GTK_CLIST(ctree
)->row_list
)-1);
5490 gtk_sctree_select_with_state
5491 (GTK_SCTREE(ctree
), next
, (event
->state
& ~GDK_CONTROL_MASK
) );
5493 /* Deprecated - what are the non-deprecated equivalents? */
5494 if (gtk_ctree_node_is_visible(GTK_CTREE(ctree
), next
) != GTK_VISIBILITY_FULL
)
5495 gtk_ctree_node_moveto(GTK_CTREE(ctree
), next
, 0, 0, 0);
5496 summaryview
->selected
= next
;
5504 if (!summaryview
->selected
) {
5505 node
= gtk_ctree_node_nth(ctree
, 0);
5507 gtk_sctree_select(GTK_SCTREE(ctree
), node
);
5512 switch (event
->keyval
) {
5514 BREAK_ON_MODIFIER_KEY();
5515 summary_delete_trash(summaryview
);
5521 if ((event
->state
& (GDK_MOD1_MASK
|GDK_CONTROL_MASK
)) == 0) {
5522 g_signal_stop_emission_by_name(G_OBJECT(widget
),
5524 mimeview_pass_key_press_event(messageview
->mimeview
,
5534 static void quicksearch_execute_cb(QuickSearch
*quicksearch
, gpointer data
)
5536 SummaryView
*summaryview
= data
;
5538 summary_show(summaryview
, summaryview
->folder_item
);
5541 static void tog_searchbar_cb(GtkWidget
*w
, gpointer data
)
5543 SummaryView
*summaryview
= (SummaryView
*)data
;
5545 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w
))) {
5546 prefs_common
.show_searchbar
= TRUE
;
5547 quicksearch_show(summaryview
->quicksearch
);
5549 prefs_common
.show_searchbar
= FALSE
;
5550 quicksearch_hide(summaryview
->quicksearch
);
5554 void summaryview_activate_quicksearch(SummaryView
*summaryview
, gboolean show
)
5556 prefs_common
.show_searchbar
= show
;
5557 gtk_toggle_button_set_active(
5558 GTK_TOGGLE_BUTTON(summaryview
->toggle_search
),
5561 quicksearch_show(summaryview
->quicksearch
);
5563 quicksearch_hide(summaryview
->quicksearch
);
5564 summary_grab_focus(summaryview
);
5568 static void summary_open_row(GtkSCTree
*sctree
, SummaryView
*summaryview
)
5570 if (FOLDER_SHOWS_TO_HDR(summaryview
->folder_item
))
5571 summary_reedit(summaryview
);
5573 summary_open_msg(summaryview
);
5575 summaryview
->display_msg
= FALSE
;
5578 static void summary_tree_expanded(GtkCTree
*ctree
, GtkCTreeNode
*node
,
5579 SummaryView
*summaryview
)
5581 summary_set_row_marks(summaryview
, node
);
5582 if (prefs_common
.bold_unread
) {
5584 GtkCTreeNode
*next
= GTK_CTREE_NODE_NEXT(node
);
5585 if (GTK_CTREE_ROW(node
)->children
)
5586 summary_set_row_marks(summaryview
, node
);
5592 static void summary_tree_collapsed(GtkCTree
*ctree
, GtkCTreeNode
*node
,
5593 SummaryView
*summaryview
)
5595 summary_set_row_marks(summaryview
, node
);
5598 static void summary_unselected(GtkCTree
*ctree
, GtkCTreeNode
*row
,
5599 gint column
, SummaryView
*summaryview
)
5601 if (summary_is_locked(summaryview
)
5602 || GTK_SCTREE(ctree
)->selecting_range
) {
5606 summary_status_show(summaryview
);
5609 static void summary_selected(GtkCTree
*ctree
, GtkCTreeNode
*row
,
5610 gint column
, SummaryView
*summaryview
)
5613 gboolean marked_unread
= FALSE
;
5615 if (summary_is_locked(summaryview
)
5616 && !GTK_SCTREE(ctree
)->selecting_range
5617 && summaryview
->messageview
5618 && summaryview
->messageview
->mimeview
5619 && summaryview
->messageview
->mimeview
->type
== MIMEVIEW_TEXT
5620 && summaryview
->messageview
->mimeview
->textview
->loading
) {
5621 PostponedSelectData
*data
= g_new0(PostponedSelectData
, 1);
5622 summaryview
->messageview
->mimeview
->textview
->stop_loading
= TRUE
;
5624 data
->ctree
= ctree
;
5627 data
->column
= column
;
5628 data
->summaryview
= summaryview
;
5629 debug_print("postponing open of message till end of load\n");
5630 g_timeout_add(100, summary_select_retry
, data
);
5633 if (summary_is_locked(summaryview
)
5634 || GTK_SCTREE(ctree
)->selecting_range
) {
5638 summary_status_show(summaryview
);
5640 if (GTK_CLIST(ctree
)->selection
&&
5641 GTK_CLIST(ctree
)->selection
->next
) {
5642 summaryview
->display_msg
= FALSE
;
5643 summary_set_menu_sensitive(summaryview
);
5644 toolbar_main_set_sensitive(summaryview
->mainwin
);
5648 summaryview
->selected
= row
;
5650 msginfo
= gtk_ctree_node_get_row_data(ctree
, row
);
5651 g_return_if_fail(msginfo
!= NULL
);
5653 main_create_mailing_list_menu (summaryview
->mainwin
, msginfo
);
5654 toolbar_set_learn_button
5655 (summaryview
->mainwin
->toolbar
,
5656 MSG_IS_SPAM(msginfo
->flags
)?LEARN_HAM
:LEARN_SPAM
);
5658 switch (column
< 0 ? column
: summaryview
->col_state
[column
].type
) {
5660 if (!MSG_IS_DELETED(msginfo
->flags
) &&
5661 !MSG_IS_MOVE(msginfo
->flags
) &&
5662 !MSG_IS_COPY(msginfo
->flags
)) {
5663 if (MSG_IS_MARKED(msginfo
->flags
)) {
5664 summary_unmark_row(summaryview
, row
);
5666 summary_mark_row(summaryview
, row
);
5671 if (MSG_IS_UNREAD(msginfo
->flags
)) {
5672 summary_mark_row_as_read(summaryview
, row
);
5673 summary_status_show(summaryview
);
5674 } else if (MSG_IS_SPAM(msginfo
->flags
)) {
5675 if (procmsg_spam_learner_learn(msginfo
, NULL
, FALSE
) == 0)
5676 summary_msginfo_unset_flags(msginfo
, MSG_SPAM
, 0);
5678 log_error(LOG_PROTOCOL
, _("An error happened while learning.\n"));
5679 } else if (!MSG_IS_REPLIED(msginfo
->flags
) &&
5680 !MSG_IS_FORWARDED(msginfo
->flags
)) {
5681 marked_unread
= TRUE
;
5682 } else if (MSG_IS_REPLIED(msginfo
->flags
)) {
5683 summary_find_answers(summaryview
, msginfo
);
5688 if (MSG_IS_LOCKED(msginfo
->flags
)) {
5689 summary_msginfo_unset_flags(msginfo
, MSG_LOCKED
, 0);
5690 summary_set_row_marks(summaryview
, row
);
5693 summary_lock_row(summaryview
, row
);
5699 if (summaryview
->display_msg
||
5700 (prefs_common
.always_show_msg
&&
5701 messageview_is_visible(summaryview
->messageview
))) {
5702 summaryview
->display_msg
= FALSE
;
5703 if (summaryview
->displayed
!= row
) {
5704 summary_display_msg(summaryview
, row
);
5705 if (marked_unread
) {
5706 summary_mark_row_as_unread(summaryview
, row
);
5707 summary_status_show(summaryview
);
5713 if (marked_unread
) {
5714 summary_mark_row_as_unread(summaryview
, row
);
5715 summary_status_show(summaryview
);
5718 summary_set_menu_sensitive(summaryview
);
5719 toolbar_main_set_sensitive(summaryview
->mainwin
);
5722 static void summary_col_resized(GtkCList
*clist
, gint column
, gint width
,
5723 SummaryView
*summaryview
)
5725 SummaryColumnType type
= summaryview
->col_state
[column
].type
;
5727 prefs_common
.summary_col_size
[type
] = width
;
5732 * \brief get List of msginfo selected in SummaryView
5734 * \param summaryview
5736 * \return GSList holding MsgInfo
5738 GSList
*summary_get_selection(SummaryView
*summaryview
)
5741 GSList
*msginfo_list
= NULL
;
5743 g_return_val_if_fail(summaryview
!= NULL
, NULL
);
5745 sel
= GTK_CLIST(summaryview
->ctree
)->selection
;
5747 g_return_val_if_fail(sel
!= NULL
, NULL
);
5749 for ( ; sel
!= NULL
; sel
= sel
->next
)
5751 g_slist_prepend(msginfo_list
,
5752 gtk_ctree_node_get_row_data(GTK_CTREE(summaryview
->ctree
),
5753 GTK_CTREE_NODE(sel
->data
)));
5754 return g_slist_reverse(msginfo_list
);
5757 static void summary_reply_cb(SummaryView
*summaryview
, guint action
,
5760 MessageView
*msgview
= (MessageView
*)summaryview
->messageview
;
5761 GSList
*msginfo_list
;
5763 g_return_if_fail(msgview
!= NULL
);
5765 msginfo_list
= summary_get_selection(summaryview
);
5766 g_return_if_fail(msginfo_list
!= NULL
);
5767 compose_reply_from_messageview(msgview
, msginfo_list
, action
);
5768 g_slist_free(msginfo_list
);
5771 static void summary_show_all_header_cb(SummaryView
*summaryview
,
5772 guint action
, GtkWidget
*widget
)
5774 summaryview
->messageview
->all_headers
=
5775 GTK_CHECK_MENU_ITEM(widget
)->active
;
5776 summary_display_msg_selected(summaryview
,
5777 GTK_CHECK_MENU_ITEM(widget
)->active
);
5780 static void summary_add_address_cb(SummaryView
*summaryview
,
5781 guint action
, GtkWidget
*widget
)
5783 summary_add_address(summaryview
);
5786 static void summary_create_filter_cb(SummaryView
*summaryview
,
5787 guint action
, GtkWidget
*widget
)
5789 summary_filter_open(summaryview
, (PrefsFilterType
)action
, 0);
5792 static void summary_create_processing_cb(SummaryView
*summaryview
,
5793 guint action
, GtkWidget
*widget
)
5795 summary_filter_open(summaryview
, (PrefsFilterType
)action
, 1);
5798 static void summary_sort_by_column_click(SummaryView
*summaryview
,
5799 FolderSortKey sort_key
)
5801 GtkCTreeNode
*node
= NULL
;
5803 if (summaryview
->sort_key
== sort_key
)
5804 summary_sort(summaryview
, sort_key
,
5805 summaryview
->sort_type
== SORT_ASCENDING
5806 ? SORT_DESCENDING
: SORT_ASCENDING
);
5808 summary_sort(summaryview
, sort_key
, SORT_ASCENDING
);
5810 node
= GTK_CTREE_NODE(GTK_CLIST(summaryview
->ctree
)->row_list
);
5812 summary_freeze(summaryview
);
5813 if (prefs_common
.bold_unread
) {
5815 GtkCTreeNode
*next
= GTK_CTREE_NODE_NEXT(node
);
5816 if (GTK_CTREE_ROW(node
)->children
)
5817 summary_set_row_marks(summaryview
, node
);
5821 summary_thaw(summaryview
);
5825 static void summary_mark_clicked(GtkWidget
*button
, SummaryView
*summaryview
)
5827 summary_sort_by_column_click(summaryview
, SORT_BY_MARK
);
5830 static void summary_status_clicked(GtkWidget
*button
, SummaryView
*summaryview
)
5832 summary_sort_by_column_click(summaryview
, SORT_BY_STATUS
);
5835 static void summary_mime_clicked(GtkWidget
*button
, SummaryView
*summaryview
)
5837 summary_sort_by_column_click(summaryview
, SORT_BY_MIME
);
5840 static void summary_num_clicked(GtkWidget
*button
, SummaryView
*summaryview
)
5842 summary_sort_by_column_click(summaryview
, SORT_BY_NUMBER
);
5845 static void summary_size_clicked(GtkWidget
*button
, SummaryView
*summaryview
)
5847 summary_sort_by_column_click(summaryview
, SORT_BY_SIZE
);
5850 static void summary_date_clicked(GtkWidget
*button
, SummaryView
*summaryview
)
5852 summary_sort_by_column_click(summaryview
, SORT_BY_DATE
);
5855 static void summary_from_clicked(GtkWidget
*button
, SummaryView
*summaryview
)
5857 if (summaryview
->col_state
[summaryview
->col_pos
[S_COL_FROM
]].visible
)
5858 summary_sort_by_column_click(summaryview
, SORT_BY_FROM
);
5860 summary_sort_by_column_click(summaryview
, SORT_BY_TO
);
5863 static void summary_to_clicked(GtkWidget
*button
, SummaryView
*summaryview
)
5865 if (summaryview
->col_state
[summaryview
->col_pos
[S_COL_TO
]].visible
)
5866 summary_sort_by_column_click(summaryview
, SORT_BY_TO
);
5868 summary_sort_by_column_click(summaryview
, SORT_BY_FROM
);
5871 static void summary_subject_clicked(GtkWidget
*button
,
5872 SummaryView
*summaryview
)
5874 summary_sort_by_column_click(summaryview
, SORT_BY_SUBJECT
);
5877 static void summary_score_clicked(GtkWidget
*button
,
5878 SummaryView
*summaryview
)
5880 summary_sort_by_column_click(summaryview
, SORT_BY_SCORE
);
5883 static void summary_locked_clicked(GtkWidget
*button
,
5884 SummaryView
*summaryview
)
5886 summary_sort_by_column_click(summaryview
, SORT_BY_LOCKED
);
5889 static void summary_start_drag(GtkWidget
*widget
, gint button
, GdkEvent
*event
,
5890 SummaryView
*summaryview
)
5892 GdkDragContext
*context
;
5894 g_return_if_fail(summaryview
!= NULL
);
5895 g_return_if_fail(summaryview
->folder_item
!= NULL
);
5896 g_return_if_fail(summaryview
->folder_item
->folder
!= NULL
);
5897 if (summaryview
->selected
== NULL
) return;
5899 context
= gtk_drag_begin(widget
, summaryview
->target_list
,
5900 GDK_ACTION_MOVE
|GDK_ACTION_COPY
|GDK_ACTION_DEFAULT
, button
, event
);
5901 gtk_drag_set_icon_default(context
);
5902 if (prefs_common
.layout_mode
== SMALL_LAYOUT
) {
5904 GtkWidget
*paned
= GTK_WIDGET_PTR(summaryview
)->parent
;
5905 if (paned
&& GTK_IS_PANED(paned
)) {
5906 mainwindow_reset_paned(GTK_PANED(paned
));
5911 static gboolean
summary_return_to_list(void *data
)
5913 SummaryView
*summaryview
= (SummaryView
*)data
;
5914 mainwindow_enter_folder(summaryview
->mainwin
);
5918 static void summary_drag_end (GtkWidget
*widget
,
5919 GdkDragContext
*drag_context
,
5920 SummaryView
*summaryview
)
5922 if (prefs_common
.layout_mode
== SMALL_LAYOUT
) {
5923 g_timeout_add(250, summary_return_to_list
, summaryview
);
5927 static void summary_drag_data_get(GtkWidget
*widget
,
5928 GdkDragContext
*drag_context
,
5929 GtkSelectionData
*selection_data
,
5932 SummaryView
*summaryview
)
5934 if (info
== TARGET_MAIL_URI_LIST
) {
5935 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
5938 gchar
*mail_list
= NULL
, *tmp1
, *tmp2
;
5940 for (cur
= GTK_CLIST(ctree
)->selection
;
5941 cur
!= NULL
&& cur
->data
!= NULL
; cur
= cur
->next
) {
5942 msginfo
= gtk_ctree_node_get_row_data
5943 (ctree
, GTK_CTREE_NODE(cur
->data
));
5944 tmp2
= procmsg_get_message_file(msginfo
);
5945 if (!tmp2
) continue;
5946 if (msginfo
->subject
) {
5947 gchar
*san_subject
= g_strdup(msginfo
->subject
);
5949 subst_for_filename(san_subject
);
5950 dest
= g_strdup_printf("%s%s%s.%d.txt",
5953 san_subject
, msginfo
->msgnum
);
5954 g_free(san_subject
);
5955 san_subject
= g_filename_from_utf8(dest
, -1, NULL
, NULL
, NULL
);
5958 if (copy_file(tmp2
, dest
, TRUE
) == 0) {
5963 tmp1
= g_strconcat("file://", tmp2
, "\r\n", NULL
);
5969 tmp2
= g_strconcat(mail_list
, tmp1
, NULL
);
5976 if (mail_list
!= NULL
) {
5977 gtk_selection_data_set(selection_data
,
5978 selection_data
->target
, 8,
5979 mail_list
, strlen(mail_list
));
5982 } else if (info
== TARGET_DUMMY
) {
5983 if (GTK_CLIST(summaryview
->ctree
)->selection
)
5984 gtk_selection_data_set(selection_data
,
5985 selection_data
->target
, 8,
5986 "Dummy-Summaryview",
5987 strlen("Dummy-Summaryview")+1);
5991 static gboolean
summary_drag_motion_cb(GtkWidget
*widget
,
5992 GdkDragContext
*context
,
5996 SummaryView
*summaryview
)
5998 FolderItem
*item
= summaryview
->folder_item
;
5999 if (!(item
&& item
->folder
&& folder_item_parent(item
) != NULL
6000 && FOLDER_CLASS(item
->folder
)->add_msg
!= NULL
)) {
6001 gdk_drag_status(context
, 0, time
);
6003 } else if (gtk_drag_get_source_widget(context
) ==
6004 mainwindow_get_mainwindow()->folderview
->ctree
) {
6006 gdk_drag_status(context
, 0, time
);
6008 } else if (gtk_drag_get_source_widget(context
) ==
6009 summaryview
->ctree
) {
6010 /* not from same folder */
6011 gdk_drag_status(context
, 0, time
);
6014 gdk_drag_status(context
, GDK_ACTION_COPY
, time
);
6019 static void summary_drag_data_received(GtkWidget
*widget
,
6020 GdkDragContext
*drag_context
,
6023 GtkSelectionData
*data
,
6026 SummaryView
*summaryview
)
6028 if (info
== TARGET_MAIL_URI_LIST
) {
6029 FolderItem
*item
= summaryview
->folder_item
;
6031 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
6034 folderview_finish_dnd(data
->data
, drag_context
, time
, item
);
6040 /* custom compare functions for sorting */
6042 #define CMP_FUNC_DEF(func_name, val) \
6043 static gint func_name(GtkCList *clist, \
6044 gconstpointer ptr1, gconstpointer ptr2) \
6046 MsgInfo *msginfo1 = ((GtkCListRow *)ptr1)->data; \
6047 MsgInfo *msginfo2 = ((GtkCListRow *)ptr2)->data; \
6048 if (!msginfo1 || !msginfo2) \
6054 CMP_FUNC_DEF(summary_cmp_by_mark
,
6055 MSG_IS_MARKED(msginfo1
->flags
) - MSG_IS_MARKED(msginfo2
->flags
))
6056 CMP_FUNC_DEF(summary_cmp_by_status
,
6057 (-(MSG_IS_SPAM(msginfo1
->flags
))+(MSG_IS_UNREAD(msginfo1
->flags
)<<1)+(MSG_IS_NEW(msginfo1
->flags
)<<2))
6058 - (-(MSG_IS_SPAM(msginfo2
->flags
))+(MSG_IS_UNREAD(msginfo2
->flags
)<<1)+(MSG_IS_NEW(msginfo2
->flags
)<<2)) )
6059 CMP_FUNC_DEF(summary_cmp_by_mime
,
6060 MSG_IS_WITH_ATTACHMENT(msginfo1
->flags
) - MSG_IS_WITH_ATTACHMENT(msginfo2
->flags
))
6061 CMP_FUNC_DEF(summary_cmp_by_label
,
6062 MSG_GET_COLORLABEL(msginfo1
->flags
) -
6063 MSG_GET_COLORLABEL(msginfo2
->flags
))
6064 CMP_FUNC_DEF(summary_cmp_by_locked
,
6065 MSG_IS_LOCKED(msginfo1
->flags
) - MSG_IS_LOCKED(msginfo2
->flags
))
6067 CMP_FUNC_DEF(summary_cmp_by_num
, msginfo1
->msgnum
- msginfo2
->msgnum
)
6068 CMP_FUNC_DEF(summary_cmp_by_size
, msginfo1
->size
- msginfo2
->size
)
6069 CMP_FUNC_DEF(summary_cmp_by_date
, msginfo1
->date_t
- msginfo2
->date_t
)
6073 static gint
summary_cmp_by_subject(GtkCList
*clist
,
6077 MsgInfo
*msginfo1
= ((GtkCListRow
*)ptr1
)->data
;
6078 MsgInfo
*msginfo2
= ((GtkCListRow
*)ptr2
)->data
;
6080 if (!msginfo1
->subject
)
6081 return (msginfo2
->subject
!= NULL
);
6082 if (!msginfo2
->subject
)
6085 return subject_compare_for_sort
6086 (msginfo1
->subject
, msginfo2
->subject
);
6089 static gint
summary_cmp_by_from(GtkCList
*clist
, gconstpointer ptr1
,
6092 const gchar
*str1
, *str2
;
6093 const GtkCListRow
*r1
= (const GtkCListRow
*) ptr1
;
6094 const GtkCListRow
*r2
= (const GtkCListRow
*) ptr2
;
6095 const SummaryView
*sv
= g_object_get_data(G_OBJECT(clist
), "summaryview");
6097 g_return_val_if_fail(sv
, -1);
6099 str1
= GTK_CELL_TEXT(r1
->cell
[sv
->col_pos
[S_COL_FROM
]])->text
;
6100 str2
= GTK_CELL_TEXT(r2
->cell
[sv
->col_pos
[S_COL_FROM
]])->text
;
6103 return str2
!= NULL
;
6108 return g_utf8_collate(str1
, str2
);
6111 static gint
summary_cmp_by_to(GtkCList
*clist
, gconstpointer ptr1
,
6114 const gchar
*str1
, *str2
;
6115 const GtkCListRow
*r1
= (const GtkCListRow
*) ptr1
;
6116 const GtkCListRow
*r2
= (const GtkCListRow
*) ptr2
;
6117 const SummaryView
*sv
= g_object_get_data(G_OBJECT(clist
), "summaryview");
6119 g_return_val_if_fail(sv
, -1);
6121 str1
= GTK_CELL_TEXT(r1
->cell
[sv
->col_pos
[S_COL_TO
]])->text
;
6122 str2
= GTK_CELL_TEXT(r2
->cell
[sv
->col_pos
[S_COL_TO
]])->text
;
6125 return str2
!= NULL
;
6130 return g_utf8_collate(str1
, str2
);
6133 static gint summary_cmp_by_simplified_subject
6134 (GtkCList
*clist
, gconstpointer ptr1
, gconstpointer ptr2
)
6136 const FolderItemPrefs
*prefs
;
6137 const gchar
*str1
, *str2
;
6138 const GtkCListRow
*r1
= (const GtkCListRow
*) ptr1
;
6139 const GtkCListRow
*r2
= (const GtkCListRow
*) ptr2
;
6140 const MsgInfo
*msginfo1
= r1
->data
;
6141 const MsgInfo
*msginfo2
= r2
->data
;
6142 const SummaryView
*sv
= g_object_get_data(G_OBJECT(clist
), "summaryview");
6144 g_return_val_if_fail(sv
, -1);
6145 g_return_val_if_fail(msginfo1
!= NULL
&& msginfo2
!= NULL
, -1);
6147 str1
= GTK_CELL_TEXT(r1
->cell
[sv
->col_pos
[S_COL_SUBJECT
]])->text
;
6148 str2
= GTK_CELL_TEXT(r2
->cell
[sv
->col_pos
[S_COL_SUBJECT
]])->text
;
6151 return str2
!= NULL
;
6156 prefs
= msginfo1
->folder
->prefs
;
6158 prefs
= msginfo2
->folder
->prefs
;
6162 return subject_compare_for_sort(str1
, str2
);
6165 static gint
summary_cmp_by_score(GtkCList
*clist
,
6166 gconstpointer ptr1
, gconstpointer ptr2
)
6168 MsgInfo
*msginfo1
= ((GtkCListRow
*)ptr1
)->data
;
6169 MsgInfo
*msginfo2
= ((GtkCListRow
*)ptr2
)->data
;
6172 /* if score are equal, sort by date */
6174 diff
= msginfo1
->score
- msginfo2
->score
;
6178 return summary_cmp_by_date(clist
, ptr1
, ptr2
);
6181 static void summary_ignore_thread_func(GtkCTree
*ctree
, GtkCTreeNode
*row
, gpointer data
)
6183 SummaryView
*summaryview
= (SummaryView
*) data
;
6186 msginfo
= gtk_ctree_node_get_row_data(ctree
, row
);
6187 g_return_if_fail(msginfo
);
6189 summary_msginfo_change_flags(msginfo
, MSG_IGNORE_THREAD
, 0, MSG_NEW
| MSG_UNREAD
, 0);
6191 summary_set_row_marks(summaryview
, row
);
6192 debug_print("Message %d is marked as ignore thread\n",
6196 void summary_ignore_thread(SummaryView
*summaryview
)
6198 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
6200 gboolean froze
= FALSE
;
6202 START_LONG_OPERATION(summaryview
, FALSE
);
6203 for (cur
= GTK_CLIST(ctree
)->selection
; cur
!= NULL
&& cur
->data
!= NULL
; cur
= cur
->next
)
6204 gtk_ctree_pre_recursive(ctree
, GTK_CTREE_NODE(cur
->data
),
6205 GTK_CTREE_FUNC(summary_ignore_thread_func
),
6208 END_LONG_OPERATION(summaryview
);
6210 summary_status_show(summaryview
);
6213 static void summary_unignore_thread_func(GtkCTree
*ctree
, GtkCTreeNode
*row
, gpointer data
)
6215 SummaryView
*summaryview
= (SummaryView
*) data
;
6218 msginfo
= gtk_ctree_node_get_row_data(ctree
, row
);
6219 g_return_if_fail(msginfo
);
6221 summary_msginfo_unset_flags(msginfo
, MSG_IGNORE_THREAD
, 0);
6223 summary_set_row_marks(summaryview
, row
);
6224 debug_print("Message %d is marked as unignore thread\n",
6228 void summary_unignore_thread(SummaryView
*summaryview
)
6230 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
6232 gboolean froze
= FALSE
;
6234 START_LONG_OPERATION(summaryview
, FALSE
);
6235 for (cur
= GTK_CLIST(ctree
)->selection
; cur
!= NULL
&& cur
->data
!= NULL
; cur
= cur
->next
)
6236 gtk_ctree_pre_recursive(ctree
, GTK_CTREE_NODE(cur
->data
),
6237 GTK_CTREE_FUNC(summary_unignore_thread_func
),
6240 END_LONG_OPERATION(summaryview
);
6242 summary_status_show(summaryview
);
6245 static void summary_check_ignore_thread_func
6246 (GtkCTree
*ctree
, GtkCTreeNode
*row
, gpointer data
)
6249 gint
*found_ignore
= (gint
*) data
;
6251 if (*found_ignore
) return;
6253 msginfo
= gtk_ctree_node_get_row_data(ctree
, row
);
6254 *found_ignore
= msginfo
&& MSG_IS_IGNORE_THREAD(msginfo
->flags
);
6258 void summary_toggle_ignore_thread(SummaryView
*summaryview
)
6260 GtkCTree
*ctree
= GTK_CTREE(summaryview
->ctree
);
6262 gint found_ignore
= 0;
6264 for (cur
= GTK_CLIST(ctree
)->selection
; cur
!= NULL
&& cur
->data
!= NULL
; cur
= cur
->next
)
6265 gtk_ctree_pre_recursive(ctree
, GTK_CTREE_NODE(cur
->data
),
6266 GTK_CTREE_FUNC(summary_check_ignore_thread_func
),
6270 summary_unignore_thread(summaryview
);
6272 summary_ignore_thread(summaryview
);
6275 void summary_toggle_show_read_messages(SummaryView
*summaryview
)
6277 FolderItemUpdateData source
;
6278 if (summaryview
->folder_item
->hide_read_msgs
)
6279 summaryview
->folder_item
->hide_read_msgs
= 0;
6281 summaryview
->folder_item
->hide_read_msgs
= 1;
6283 source
.item
= summaryview
->folder_item
;
6284 source
.update_flags
= F_ITEM_UPDATE_NAME
;
6286 hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST
, &source
);
6287 summary_show(summaryview
, summaryview
->folder_item
);
6290 static void summary_set_hide_read_msgs_menu (SummaryView
*summaryview
,
6295 widget
= gtk_item_factory_get_item(gtk_item_factory_from_widget(summaryview
->mainwin
->menubar
),
6296 "/View/Hide read messages");
6297 g_object_set_data(G_OBJECT(widget
), "dont_toggle",
6298 GINT_TO_POINTER(1));
6299 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM(widget
), action
);
6300 g_object_set_data(G_OBJECT(widget
), "dont_toggle",
6301 GINT_TO_POINTER(0));
6304 void summary_reflect_prefs_pixmap_theme(SummaryView
*summaryview
)
6306 GtkWidget
*ctree
= summaryview
->ctree
;
6309 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_MARK
, &markxpm
, &markxpmmask
);
6310 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_DELETED
, &deletedxpm
, &deletedxpmmask
);
6311 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_NEW
, &newxpm
, &newxpmmask
);
6312 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_UNREAD
, &unreadxpm
, &unreadxpmmask
);
6313 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_REPLIED
, &repliedxpm
, &repliedxpmmask
);
6314 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_FORWARDED
, &forwardedxpm
, &forwardedxpmmask
);
6315 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_CLIP
, &clipxpm
, &clipxpmmask
);
6316 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_LOCKED
, &lockedxpm
, &lockedxpmmask
);
6317 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_IGNORETHREAD
, &ignorethreadxpm
, &ignorethreadxpmmask
);
6318 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_CLIP_KEY
, &clipkeyxpm
, &clipkeyxpmmask
);
6319 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_KEY
, &keyxpm
, &keyxpmmask
);
6320 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_GPG_SIGNED
, &gpgsignedxpm
, &gpgsignedxpmmask
);
6321 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_CLIP_GPG_SIGNED
, &clipgpgsignedxpm
, &clipgpgsignedxpmmask
);
6322 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_SPAM
, &spamxpm
, &spamxpmmask
);
6323 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_MOVED
, &movedxpm
, &movedxpmmask
);
6324 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_COPIED
, &copiedxpm
, &copiedxpmmask
);
6326 summary_set_folder_pixmap(summaryview
, STOCK_PIXMAP_DIR_OPEN
);
6328 pixmap
= stock_pixmap_widget(summaryview
->hbox
, STOCK_PIXMAP_QUICKSEARCH
);
6329 gtk_container_remove (GTK_CONTAINER(summaryview
->toggle_search
),
6330 summaryview
->quick_search_pixmap
);
6331 gtk_container_add(GTK_CONTAINER(summaryview
->toggle_search
), pixmap
);
6332 gtk_widget_show(pixmap
);
6333 summaryview
->quick_search_pixmap
= pixmap
;
6335 folderview_unselect(summaryview
->folderview
);
6336 folderview_select(summaryview
->folderview
, summaryview
->folder_item
);
6337 summary_set_column_titles(summaryview
);
6340 void summary_reflect_prefs_custom_colors(SummaryView
*summaryview
)
6345 /* re-create colorlabel submenu */
6346 menu
= GTK_MENU_SHELL(summaryview
->colorlabel_menu
);
6347 g_return_if_fail(menu
!= NULL
);
6349 /* clear items. get item pointers. */
6350 for (cur
= menu
->children
; cur
!= NULL
&& cur
->data
!= NULL
; cur
= cur
->next
) {
6351 gtk_menu_item_remove_submenu(GTK_MENU_ITEM(cur
->data
));
6353 summary_colorlabel_menu_create(summaryview
, TRUE
);
6357 * Harvest addresses for selected messages in summary view.
6359 void summary_harvest_address(SummaryView
*summaryview
)
6361 GtkCTree
*ctree
= GTK_CTREE( summaryview
->ctree
);
6367 for( cur
= GTK_CLIST(ctree
)->selection
; cur
!= NULL
&& cur
->data
!= NULL
; cur
= cur
->next
) {
6368 msginfo
= gtk_ctree_node_get_row_data( ctree
, GTK_CTREE_NODE(cur
->data
) );
6371 msgList
= g_list_append( msgList
, GUINT_TO_POINTER( msginfo
->msgnum
) );
6373 addressbook_harvest( summaryview
->folder_item
, TRUE
, msgList
);
6374 g_list_free( msgList
);
6377 static regex_t
*summary_compile_simplify_regexp(gchar
*simplify_subject_regexp
)
6380 gchar buf
[BUFFSIZE
];
6381 regex_t
*preg
= NULL
;
6383 preg
= g_new0(regex_t
, 1);
6385 err
= string_match_precompile(simplify_subject_regexp
,
6386 preg
, REG_EXTENDED
);
6388 regerror(err
, preg
, buf
, BUFFSIZE
);
6389 alertpanel_error(_("Regular expression (regexp) error:\n%s"), buf
);
6397 void summary_set_prefs_from_folderitem(SummaryView
*summaryview
, FolderItem
*item
)
6399 FolderSortKey sort_key
;
6400 FolderSortType sort_type
;
6401 g_return_if_fail(summaryview
!= NULL
);
6402 g_return_if_fail(item
!= NULL
);
6404 /* Subject simplification */
6405 if(summaryview
->simplify_subject_preg
) {
6406 regfree(summaryview
->simplify_subject_preg
);
6407 g_free(summaryview
->simplify_subject_preg
);
6408 summaryview
->simplify_subject_preg
= NULL
;
6410 if(item
->prefs
&& item
->prefs
->simplify_subject_regexp
&&
6411 item
->prefs
->simplify_subject_regexp
[0] && item
->prefs
->enable_simplify_subject
)
6412 summaryview
->simplify_subject_preg
= summary_compile_simplify_regexp(item
->prefs
->simplify_subject_regexp
);
6415 sort_key
= item
->sort_key
;
6416 sort_type
= item
->sort_type
;
6418 folder_get_sort_type(item
->folder
, &sort_key
, &sort_type
);
6420 summaryview
->sort_key
= sort_key
;
6421 summaryview
->sort_type
= sort_type
;
6424 summaryview
->threaded
= item
->threaded
;
6425 summaryview
->thread_collapsed
= item
->thread_collapsed
;
6430 void summary_save_prefs_to_folderitem(SummaryView
*summaryview
, FolderItem
*item
)
6433 item
->sort_key
= summaryview
->sort_key
;
6434 item
->sort_type
= summaryview
->sort_type
;
6437 item
->threaded
= summaryview
->threaded
;
6438 item
->thread_collapsed
= summaryview
->thread_collapsed
;
6441 static gboolean
summary_update_msg(gpointer source
, gpointer data
)
6443 MsgInfoUpdate
*msginfo_update
= (MsgInfoUpdate
*) source
;
6444 SummaryView
*summaryview
= (SummaryView
*)data
;
6447 g_return_val_if_fail(msginfo_update
!= NULL
, TRUE
);
6448 g_return_val_if_fail(summaryview
!= NULL
, FALSE
);
6450 if (msginfo_update
->msginfo
->folder
!= summaryview
->folder_item
)
6453 if (msginfo_update
->flags
& MSGINFO_UPDATE_FLAGS
) {
6454 node
= gtk_ctree_find_by_row_data(
6455 GTK_CTREE(summaryview
->ctree
), NULL
,
6456 msginfo_update
->msginfo
);
6459 summary_set_row_marks(summaryview
, node
);
6465 static void summary_update_unread(SummaryView
*summaryview
, FolderItem
*removed_item
)
6467 guint
new, unread
, unreadmarked
, marked
, total
;
6468 static gboolean tips_initialized
= FALSE
;
6470 if (prefs_common
.layout_mode
!= SMALL_LAYOUT
) {
6471 if (tips_initialized
) {
6472 summary_set_folder_pixmap(summaryview
, STOCK_PIXMAP_DIR_OPEN
);
6473 gtk_tooltips_set_tip(GTK_TOOLTIPS(summaryview
->tips
),
6474 summaryview
->folder_pixmap_eventbox
,
6476 tips_initialized
= FALSE
;
6480 folder_count_total_msgs(&new, &unread
, &unreadmarked
, &marked
, &total
);
6482 total
-= removed_item
->total_msgs
;
6483 new -= removed_item
->new_msgs
;
6484 unread
-= removed_item
->unread_msgs
;
6487 if (new > 0 || unread
> 0) {
6488 tips_initialized
= TRUE
;
6489 summary_set_folder_pixmap(summaryview
, STOCK_PIXMAP_DIR_OPEN_HRM
);
6490 gtk_tooltips_set_tip(GTK_TOOLTIPS(summaryview
->tips
),
6491 summaryview
->folder_pixmap_eventbox
,
6492 _("Go back to the folder list (You have unread messages)"), NULL
);
6494 tips_initialized
= TRUE
;
6495 summary_set_folder_pixmap(summaryview
, STOCK_PIXMAP_DIR_OPEN
);
6496 gtk_tooltips_set_tip(GTK_TOOLTIPS(summaryview
->tips
),
6497 summaryview
->folder_pixmap_eventbox
,
6498 _("Go back to the folder list"), NULL
);
6502 static gboolean
summary_update_folder_item_hook(gpointer source
, gpointer data
)
6504 FolderItemUpdateData
*hookdata
= (FolderItemUpdateData
*)source
;
6505 SummaryView
*summaryview
= (SummaryView
*)data
;
6507 g_return_val_if_fail(hookdata
!= NULL
, FALSE
);
6508 g_return_val_if_fail(hookdata
->item
!= NULL
, FALSE
);
6509 g_return_val_if_fail(summaryview
!= NULL
, FALSE
);
6511 if (hookdata
->update_flags
& F_ITEM_UPDATE_NAME
) {
6512 gchar
*name
= folder_item_get_name(hookdata
->item
);
6513 gtk_label_set_text(GTK_LABEL(summaryview
->statlabel_folder
), name
);
6516 summary_update_unread(summaryview
, NULL
);
6521 static gboolean
summary_update_folder_hook(gpointer source
, gpointer data
)
6523 FolderUpdateData
*hookdata
;
6524 SummaryView
*summaryview
= (SummaryView
*)data
;
6526 if (hookdata
->update_flags
& FOLDER_REMOVE_FOLDERITEM
)
6527 summary_update_unread(summaryview
, hookdata
->item
);
6529 summary_update_unread(summaryview
, NULL
);
6535 *\brief change summaryview to display your answer(s) to a message
6537 *\param summaryview The SummaryView ;)
6538 *\param msginfo The message for which answers are searched
6541 static void summary_find_answers (SummaryView
*summaryview
, MsgInfo
*msg
)
6543 FolderItem
*sent_folder
= NULL
;
6544 PrefsAccount
*account
= NULL
;
6545 GtkCTreeNode
*node
= NULL
;
6547 if (msg
== NULL
|| msg
->msgid
== NULL
)
6550 account
= account_get_reply_account(msg
, prefs_common
.reply_account_autosel
);
6551 if (account
== NULL
)
6553 sent_folder
= account_get_special_folder
6554 (account
, F_OUTBOX
);
6556 buf
= g_strdup_printf("inreplyto matchcase \"%s\"", msg
->msgid
);
6558 if (sent_folder
!= summaryview
->folder_item
) {
6559 folderview_select(summaryview
->mainwin
->folderview
, sent_folder
);
6562 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(summaryview
->toggle_search
), TRUE
);
6564 quicksearch_set(summaryview
->quicksearch
, QUICK_SEARCH_EXTENDED
, buf
);
6567 node
= gtk_ctree_node_nth(GTK_CTREE(summaryview
->ctree
), 0);
6569 summary_select_node(summaryview
, node
, TRUE
, TRUE
);
6572 gint
summaryview_export_mbox_list(SummaryView
*summaryview
)
6573 /* return values: -2 skipped, -1 error, 0 OK */
6575 GSList
*list
= summary_get_selected_msg_list(summaryview
);
6576 gchar
*mbox
= filesel_select_file_save(_("Export to mbox file"), NULL
);
6579 if (mbox
== NULL
|| list
== NULL
)
6582 ret
= export_list_to_mbox(list
, mbox
);
6590 void summaryview_lock(SummaryView
*summaryview
, FolderItem
*item
)
6592 if (!summaryview
|| !summaryview
->folder_item
|| !item
) {
6596 if (summaryview
->folder_item
->folder
== item
->folder
) {
6597 gtk_widget_set_sensitive(summaryview
->ctree
, FALSE
);
6600 void summaryview_unlock(SummaryView
*summaryview
, FolderItem
*item
)
6602 gtk_widget_set_sensitive(summaryview
->ctree
, TRUE
);