Statistics
| Revision:

root / src / summaryview.c @ 880

History | View | Annotate | Download (145.6 kB)

1 1 hiro
/*
2 1 hiro
 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 135 hiro
 * Copyright (C) 1999-2005 Hiroyuki Yamamoto
4 1 hiro
 *
5 1 hiro
 * This program is free software; you can redistribute it and/or modify
6 1 hiro
 * it under the terms of the GNU General Public License as published by
7 1 hiro
 * the Free Software Foundation; either version 2 of the License, or
8 1 hiro
 * (at your option) any later version.
9 1 hiro
 *
10 1 hiro
 * This program is distributed in the hope that it will be useful,
11 1 hiro
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 1 hiro
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 1 hiro
 * GNU General Public License for more details.
14 1 hiro
 *
15 1 hiro
 * You should have received a copy of the GNU General Public License
16 1 hiro
 * along with this program; if not, write to the Free Software
17 1 hiro
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 1 hiro
 */
19 1 hiro
20 1 hiro
#include "defs.h"
21 1 hiro
22 1 hiro
#include <glib.h>
23 92 hiro
#include <glib/gi18n.h>
24 1 hiro
#include <gdk/gdkkeysyms.h>
25 851 hiro
#include <gtk/gtkversion.h>
26 237 hiro
#include <gtk/gtkwidget.h>
27 1 hiro
#include <gtk/gtkscrolledwindow.h>
28 237 hiro
#include <gtk/gtktreestore.h>
29 237 hiro
#include <gtk/gtktreeview.h>
30 237 hiro
#include <gtk/gtktreeselection.h>
31 237 hiro
#include <gtk/gtkcellrendererpixbuf.h>
32 237 hiro
#include <gtk/gtkcellrenderertext.h>
33 1 hiro
#include <gtk/gtksignal.h>
34 1 hiro
#include <gtk/gtkmenu.h>
35 1 hiro
#include <gtk/gtkmenuitem.h>
36 237 hiro
#include <gtk/gtkcheckmenuitem.h>
37 1 hiro
#include <gtk/gtkitemfactory.h>
38 1 hiro
#include <gtk/gtkvbox.h>
39 1 hiro
#include <gtk/gtkhbox.h>
40 1 hiro
#include <gtk/gtkwindow.h>
41 741 hiro
#include <gtk/gtkhseparator.h>
42 1 hiro
#include <gtk/gtkarrow.h>
43 1 hiro
#include <gtk/gtkeventbox.h>
44 1 hiro
#include <gtk/gtkstatusbar.h>
45 237 hiro
#include <gtk/gtkstock.h>
46 527 hiro
#include <gtk/gtknotebook.h>
47 1 hiro
48 1 hiro
#include <stdio.h>
49 1 hiro
#include <stdlib.h>
50 1 hiro
#include <string.h>
51 1 hiro
#include <ctype.h>
52 1 hiro
#include <unistd.h>
53 1 hiro
54 1 hiro
#include "main.h"
55 1 hiro
#include "menu.h"
56 1 hiro
#include "mainwindow.h"
57 1 hiro
#include "folderview.h"
58 1 hiro
#include "summaryview.h"
59 1 hiro
#include "messageview.h"
60 1 hiro
#include "foldersel.h"
61 1 hiro
#include "procmsg.h"
62 1 hiro
#include "procheader.h"
63 1 hiro
#include "sourcewindow.h"
64 1 hiro
#include "prefs_common.h"
65 1 hiro
#include "prefs_summary_column.h"
66 1 hiro
#include "prefs_filter.h"
67 1 hiro
#include "account.h"
68 1 hiro
#include "compose.h"
69 1 hiro
#include "utils.h"
70 1 hiro
#include "gtkutils.h"
71 1 hiro
#include "stock_pixmap.h"
72 1 hiro
#include "filesel.h"
73 1 hiro
#include "alertpanel.h"
74 1 hiro
#include "inputdialog.h"
75 1 hiro
#include "statusbar.h"
76 1 hiro
#include "filter.h"
77 1 hiro
#include "folder.h"
78 1 hiro
#include "colorlabel.h"
79 1 hiro
#include "inc.h"
80 1 hiro
#include "imap.h"
81 1 hiro
82 1 hiro
#define STATUSBAR_PUSH(mainwin, str) \
83 1 hiro
{ \
84 1 hiro
        gtk_statusbar_push(GTK_STATUSBAR(mainwin->statusbar), \
85 1 hiro
                           mainwin->summaryview_cid, str); \
86 227 hiro
        gtkut_widget_draw_now(mainwin->statusbar); \
87 1 hiro
}
88 1 hiro
89 1 hiro
#define STATUSBAR_POP(mainwin) \
90 1 hiro
{ \
91 1 hiro
        gtk_statusbar_pop(GTK_STATUSBAR(mainwin->statusbar), \
92 1 hiro
                          mainwin->summaryview_cid); \
93 1 hiro
}
94 1 hiro
95 237 hiro
#define GET_MSG_INFO(msginfo, iter__) \
96 237 hiro
{ \
97 237 hiro
        gtk_tree_model_get(GTK_TREE_MODEL(summaryview->store), iter__, \
98 237 hiro
                           S_COL_MSG_INFO, &msginfo, -1); \
99 237 hiro
}
100 1 hiro
101 751 hiro
#define SORT_BLOCK(key)                                                         \
102 751 hiro
        if (summaryview->folder_item->sort_key == key) {                 \
103 751 hiro
                sort_key = key;                                                 \
104 751 hiro
                sort_type = summaryview->folder_item->sort_type;         \
105 751 hiro
                summary_sort(summaryview, SORT_BY_NONE, SORT_ASCENDING); \
106 751 hiro
        }
107 751 hiro
108 751 hiro
#define SORT_UNBLOCK(key)                                        \
109 751 hiro
        if (sort_key == key)                                        \
110 751 hiro
                summary_sort(summaryview, sort_key, sort_type);
111 751 hiro
112 249 hiro
#define SUMMARY_COL_MARK_WIDTH                21
113 249 hiro
#define SUMMARY_COL_UNREAD_WIDTH        24
114 237 hiro
#define SUMMARY_COL_MIME_WIDTH                17
115 1 hiro
116 237 hiro
static GdkPixbuf *mark_pixbuf;
117 237 hiro
static GdkPixbuf *deleted_pixbuf;
118 1 hiro
119 237 hiro
static GdkPixbuf *mail_pixbuf;
120 237 hiro
static GdkPixbuf *new_pixbuf;
121 237 hiro
static GdkPixbuf *unread_pixbuf;
122 237 hiro
static GdkPixbuf *replied_pixbuf;
123 237 hiro
static GdkPixbuf *forwarded_pixbuf;
124 1 hiro
125 237 hiro
static GdkPixbuf *clip_pixbuf;
126 1 hiro
127 297 hiro
static GList *summary_get_selected_rows        (SummaryView                *summaryview);
128 297 hiro
static void summary_selection_list_free        (SummaryView                *summaryview);
129 297 hiro
130 237 hiro
static void summary_msgid_table_create        (SummaryView                *summaryview);
131 237 hiro
static void summary_msgid_table_destroy        (SummaryView                *summaryview);
132 1 hiro
133 1 hiro
static void summary_set_menu_sensitive        (SummaryView                *summaryview);
134 1 hiro
135 322 hiro
static void summary_scroll_to_selected        (SummaryView                *summaryview,
136 322 hiro
                                         gboolean                 align_center);
137 244 hiro
138 598 hiro
static MsgInfo *summary_get_msginfo        (SummaryView                *summaryview,
139 598 hiro
                                         GtkTreeRowReference        *row);
140 1 hiro
static guint summary_get_msgnum                (SummaryView                *summaryview,
141 237 hiro
                                         GtkTreeRowReference        *row);
142 1 hiro
143 237 hiro
static gboolean summary_find_prev_msg        (SummaryView                *summaryview,
144 237 hiro
                                         GtkTreeIter                *prev,
145 237 hiro
                                         GtkTreeIter                *iter);
146 237 hiro
static gboolean summary_find_next_msg        (SummaryView                *summaryview,
147 237 hiro
                                         GtkTreeIter                *next,
148 237 hiro
                                         GtkTreeIter                *iter);
149 1 hiro
150 265 hiro
static gboolean summary_find_nearest_msg(SummaryView                *summaryview,
151 265 hiro
                                         GtkTreeIter                *target,
152 265 hiro
                                         GtkTreeIter                *iter);
153 265 hiro
154 237 hiro
static gboolean summary_find_prev_flagged_msg
155 1 hiro
                                        (SummaryView        *summaryview,
156 237 hiro
                                         GtkTreeIter        *prev,
157 237 hiro
                                         GtkTreeIter        *iter,
158 1 hiro
                                         MsgPermFlags         flags,
159 1 hiro
                                         gboolean         start_from_prev);
160 237 hiro
static gboolean summary_find_next_flagged_msg
161 1 hiro
                                        (SummaryView        *summaryview,
162 237 hiro
                                         GtkTreeIter        *next,
163 237 hiro
                                         GtkTreeIter        *iter,
164 1 hiro
                                         MsgPermFlags         flags,
165 1 hiro
                                         gboolean         start_from_next);
166 1 hiro
167 237 hiro
static gboolean summary_find_msg_by_msgnum
168 1 hiro
                                        (SummaryView                *summaryview,
169 237 hiro
                                         guint                         msgnum,
170 237 hiro
                                         GtkTreeIter                *found);
171 1 hiro
172 1 hiro
static void summary_update_status        (SummaryView                *summaryview);
173 1 hiro
174 1 hiro
/* display functions */
175 1 hiro
static void summary_status_show                (SummaryView                *summaryview);
176 237 hiro
static void summary_set_tree_model_from_list
177 237 hiro
                                        (SummaryView                *summaryview,
178 1 hiro
                                         GSList                        *mlist);
179 335 hiro
static gboolean summary_row_is_displayed(SummaryView                *summaryview,
180 335 hiro
                                         GtkTreeIter                *iter);
181 1 hiro
static void summary_display_msg                (SummaryView                *summaryview,
182 237 hiro
                                         GtkTreeIter                *iter);
183 1 hiro
static void summary_display_msg_full        (SummaryView                *summaryview,
184 237 hiro
                                         GtkTreeIter                *iter,
185 1 hiro
                                         gboolean                 new_window,
186 237 hiro
                                         gboolean                 all_headers,
187 237 hiro
                                         gboolean                 redisplay);
188 1 hiro
189 250 hiro
static void summary_activate_selected        (SummaryView                *summaryview);
190 250 hiro
191 1 hiro
/* message handling */
192 1 hiro
static void summary_mark_row                (SummaryView                *summaryview,
193 237 hiro
                                         GtkTreeIter                *iter);
194 1 hiro
static void summary_mark_row_as_read        (SummaryView                *summaryview,
195 237 hiro
                                         GtkTreeIter                *iter);
196 1 hiro
static void summary_mark_row_as_unread        (SummaryView                *summaryview,
197 237 hiro
                                         GtkTreeIter                *iter);
198 1 hiro
static void summary_delete_row                (SummaryView                *summaryview,
199 237 hiro
                                         GtkTreeIter                *iter);
200 1 hiro
static void summary_unmark_row                (SummaryView                *summaryview,
201 237 hiro
                                         GtkTreeIter                *iter);
202 1 hiro
static void summary_move_row_to                (SummaryView                *summaryview,
203 237 hiro
                                         GtkTreeIter                *iter,
204 1 hiro
                                         FolderItem                *to_folder);
205 1 hiro
static void summary_copy_row_to                (SummaryView                *summaryview,
206 237 hiro
                                         GtkTreeIter                *iter,
207 1 hiro
                                         FolderItem                *to_folder);
208 1 hiro
209 1 hiro
static void summary_remove_invalid_messages
210 1 hiro
                                        (SummaryView                *summaryview);
211 1 hiro
212 1 hiro
static gint summary_execute_move        (SummaryView                *summaryview);
213 1 hiro
static gint summary_execute_copy        (SummaryView                *summaryview);
214 1 hiro
static gint summary_execute_delete        (SummaryView                *summaryview);
215 1 hiro
216 237 hiro
static void summary_modify_threads        (SummaryView                *summaryview);
217 1 hiro
218 1 hiro
static void summary_colorlabel_menu_item_activate_cb
219 237 hiro
                                        (GtkWidget        *widget,
220 237 hiro
                                         gpointer         data);
221 1 hiro
static void summary_colorlabel_menu_item_activate_item_cb
222 237 hiro
                                        (GtkMenuItem        *label_menu_item,
223 237 hiro
                                         gpointer         data);
224 237 hiro
static void summary_colorlabel_menu_create
225 237 hiro
                                        (SummaryView        *summaryview);
226 1 hiro
227 237 hiro
static GtkWidget *summary_tree_view_create
228 237 hiro
                                        (SummaryView        *summaryview);
229 1 hiro
230 1 hiro
/* callback functions */
231 1 hiro
static gboolean summary_toggle_pressed        (GtkWidget                *eventbox,
232 1 hiro
                                         GdkEventButton                *event,
233 1 hiro
                                         SummaryView                *summaryview);
234 237 hiro
static gboolean summary_button_pressed        (GtkWidget                *treeview,
235 1 hiro
                                         GdkEventButton                *event,
236 1 hiro
                                         SummaryView                *summaryview);
237 237 hiro
static gboolean summary_button_released        (GtkWidget                *treeview,
238 1 hiro
                                         GdkEventButton                *event,
239 1 hiro
                                         SummaryView                *summaryview);
240 237 hiro
static gboolean summary_key_pressed        (GtkWidget                *treeview,
241 1 hiro
                                         GdkEventKey                *event,
242 1 hiro
                                         SummaryView                *summaryview);
243 237 hiro
244 237 hiro
static void summary_row_expanded        (GtkTreeView                *treeview,
245 237 hiro
                                         GtkTreeIter                *iter,
246 237 hiro
                                         GtkTreePath                *path,
247 1 hiro
                                         SummaryView                *summaryview);
248 237 hiro
static void summary_row_collapsed        (GtkTreeView                *treeview,
249 237 hiro
                                         GtkTreeIter                *iter,
250 237 hiro
                                         GtkTreePath                *path,
251 1 hiro
                                         SummaryView                *summaryview);
252 237 hiro
253 363 hiro
static void summary_columns_changed        (GtkTreeView                *treeview,
254 363 hiro
                                         SummaryView                *summaryview);
255 363 hiro
256 237 hiro
static gboolean summary_select_func        (GtkTreeSelection        *treeview,
257 237 hiro
                                         GtkTreeModel                *model,
258 237 hiro
                                         GtkTreePath                *path,
259 237 hiro
                                         gboolean                 cur_selected,
260 237 hiro
                                         gpointer                 data);
261 237 hiro
262 237 hiro
static void summary_selection_changed        (GtkTreeSelection        *selection,
263 1 hiro
                                         SummaryView                *summaryview);
264 237 hiro
265 237 hiro
static void summary_col_resized                (GtkWidget                *widget,
266 237 hiro
                                         GtkAllocation                *allocation,
267 1 hiro
                                         SummaryView                *summaryview);
268 237 hiro
269 1 hiro
static void summary_reply_cb                (SummaryView                *summaryview,
270 1 hiro
                                         guint                         action,
271 1 hiro
                                         GtkWidget                *widget);
272 1 hiro
static void summary_show_all_header_cb        (SummaryView                *summaryview,
273 1 hiro
                                         guint                         action,
274 1 hiro
                                         GtkWidget                *widget);
275 1 hiro
276 1 hiro
static void summary_add_address_cb        (SummaryView                *summaryview,
277 1 hiro
                                         guint                         action,
278 1 hiro
                                         GtkWidget                *widget);
279 635 hiro
static void summary_create_filter_cb        (SummaryView                *summaryview,
280 635 hiro
                                         guint                         action,
281 635 hiro
                                         GtkWidget                *widget);
282 1 hiro
283 237 hiro
static void summary_column_clicked        (GtkWidget                *button,
284 1 hiro
                                         SummaryView                *summaryview);
285 1 hiro
286 237 hiro
static void summary_drag_begin                (GtkWidget          *widget,
287 237 hiro
                                         GdkDragContext          *drag_context,
288 237 hiro
                                         SummaryView          *summaryview);
289 291 hiro
static void summary_drag_end                (GtkWidget          *widget,
290 291 hiro
                                         GdkDragContext          *drag_context,
291 291 hiro
                                         SummaryView          *summaryview);
292 1 hiro
static void summary_drag_data_get       (GtkWidget        *widget,
293 1 hiro
                                         GdkDragContext   *drag_context,
294 1 hiro
                                         GtkSelectionData *selection_data,
295 1 hiro
                                         guint             info,
296 1 hiro
                                         guint             time,
297 1 hiro
                                         SummaryView      *summaryview);
298 1 hiro
299 1 hiro
/* custom compare functions for sorting */
300 237 hiro
static gint summary_cmp_by_mark                (GtkTreeModel                *model,
301 237 hiro
                                         GtkTreeIter                *a,
302 237 hiro
                                         GtkTreeIter                *b,
303 237 hiro
                                         gpointer                 data);
304 237 hiro
static gint summary_cmp_by_unread        (GtkTreeModel                *model,
305 237 hiro
                                         GtkTreeIter                *a,
306 237 hiro
                                         GtkTreeIter                *b,
307 237 hiro
                                         gpointer                 data);
308 237 hiro
static gint summary_cmp_by_mime                (GtkTreeModel                *model,
309 237 hiro
                                         GtkTreeIter                *a,
310 237 hiro
                                         GtkTreeIter                *b,
311 237 hiro
                                         gpointer                 data);
312 237 hiro
static gint summary_cmp_by_num                (GtkTreeModel                *model,
313 237 hiro
                                         GtkTreeIter                *a,
314 237 hiro
                                         GtkTreeIter                *b,
315 237 hiro
                                         gpointer                 data);
316 237 hiro
static gint summary_cmp_by_size                (GtkTreeModel                *model,
317 237 hiro
                                         GtkTreeIter                *a,
318 237 hiro
                                         GtkTreeIter                *b,
319 237 hiro
                                         gpointer                 data);
320 237 hiro
static gint summary_cmp_by_date                (GtkTreeModel                *model,
321 237 hiro
                                         GtkTreeIter                *a,
322 237 hiro
                                         GtkTreeIter                *b,
323 237 hiro
                                         gpointer                 data);
324 574 hiro
static gint summary_cmp_by_thread_date        (GtkTreeModel                *model,
325 574 hiro
                                         GtkTreeIter                *a,
326 574 hiro
                                         GtkTreeIter                *b,
327 574 hiro
                                         gpointer                 data);
328 237 hiro
static gint summary_cmp_by_from                (GtkTreeModel                *model,
329 237 hiro
                                         GtkTreeIter                *a,
330 237 hiro
                                         GtkTreeIter                *b,
331 237 hiro
                                         gpointer                 data);
332 237 hiro
static gint summary_cmp_by_label        (GtkTreeModel                *model,
333 237 hiro
                                         GtkTreeIter                *a,
334 237 hiro
                                         GtkTreeIter                *b,
335 237 hiro
                                         gpointer                 data);
336 237 hiro
static gint summary_cmp_by_to                (GtkTreeModel                *model,
337 237 hiro
                                         GtkTreeIter                *a,
338 237 hiro
                                         GtkTreeIter                *b,
339 237 hiro
                                         gpointer                 data);
340 237 hiro
static gint summary_cmp_by_subject        (GtkTreeModel                *model,
341 237 hiro
                                         GtkTreeIter                *a,
342 237 hiro
                                         GtkTreeIter                *b,
343 237 hiro
                                         gpointer                 data);
344 1 hiro
345 1 hiro
346 237 hiro
/* must be synched with FolderSortKey */
347 237 hiro
static SummaryColumnType sort_key_to_col[] = {
348 237 hiro
        -1,
349 237 hiro
        S_COL_NUMBER,
350 237 hiro
        S_COL_SIZE,
351 237 hiro
        S_COL_DATE,
352 574 hiro
        S_COL_TDATE,
353 237 hiro
        S_COL_FROM,
354 237 hiro
        S_COL_SUBJECT,
355 237 hiro
        -1,
356 237 hiro
        S_COL_LABEL,
357 237 hiro
        S_COL_MARK,
358 237 hiro
        S_COL_UNREAD,
359 237 hiro
        S_COL_MIME,
360 237 hiro
        S_COL_TO
361 237 hiro
};
362 237 hiro
363 237 hiro
/* must be synched with SummaryColumnType */
364 237 hiro
static FolderSortKey col_to_sort_key[] = {
365 237 hiro
        SORT_BY_MARK,
366 237 hiro
        SORT_BY_UNREAD,
367 237 hiro
        SORT_BY_MIME,
368 237 hiro
        SORT_BY_SUBJECT,
369 237 hiro
        SORT_BY_FROM,
370 237 hiro
        SORT_BY_DATE,
371 237 hiro
        SORT_BY_SIZE,
372 237 hiro
        SORT_BY_NUMBER,
373 237 hiro
};
374 237 hiro
375 310 hiro
enum
376 1 hiro
{
377 310 hiro
        DRAG_TYPE_TEXT,
378 310 hiro
        DRAG_TYPE_RFC822,
379 310 hiro
        DRAG_TYPE_URI_LIST,
380 310 hiro
381 310 hiro
        N_DRAG_TYPES
382 1 hiro
};
383 1 hiro
384 435 hiro
static GtkTargetEntry summary_drag_types[] =
385 310 hiro
{
386 310 hiro
        {"text/plain", GTK_TARGET_SAME_APP, DRAG_TYPE_TEXT},
387 310 hiro
        {"message/rfc822", GTK_TARGET_SAME_APP, DRAG_TYPE_RFC822},
388 310 hiro
        {"text/uri-list", 0, DRAG_TYPE_URI_LIST}
389 310 hiro
};
390 310 hiro
391 1 hiro
static GtkItemFactoryEntry summary_popup_entries[] =
392 1 hiro
{
393 1 hiro
        {N_("/_Reply"),                        NULL, summary_reply_cb,        COMPOSE_REPLY, NULL},
394 1 hiro
        {N_("/Repl_y to"),                NULL, NULL,                0, "<Branch>"},
395 1 hiro
        {N_("/Repl_y to/_all"),                NULL, summary_reply_cb,        COMPOSE_REPLY_TO_ALL, NULL},
396 1 hiro
        {N_("/Repl_y to/_sender"),        NULL, summary_reply_cb,        COMPOSE_REPLY_TO_SENDER, NULL},
397 1 hiro
        {N_("/Repl_y to/mailing _list"),
398 1 hiro
                                        NULL, summary_reply_cb,        COMPOSE_REPLY_TO_LIST, NULL},
399 1 hiro
        {N_("/---"),                        NULL, NULL,                0, "<Separator>"},
400 1 hiro
        {N_("/_Forward"),                NULL, summary_reply_cb, COMPOSE_FORWARD, NULL},
401 1 hiro
        {N_("/For_ward as attachment"),        NULL, summary_reply_cb, COMPOSE_FORWARD_AS_ATTACH, NULL},
402 1 hiro
        {N_("/Redirec_t"),                NULL, summary_reply_cb, COMPOSE_REDIRECT, NULL},
403 1 hiro
        {N_("/---"),                        NULL, NULL,                0, "<Separator>"},
404 1 hiro
        {N_("/M_ove..."),                NULL, summary_move_to,        0, NULL},
405 1 hiro
        {N_("/_Copy..."),                NULL, summary_copy_to,        0, NULL},
406 1 hiro
        {N_("/_Delete"),                NULL, summary_delete,        0, NULL},
407 1 hiro
        {N_("/---"),                        NULL, NULL,                0, "<Separator>"},
408 1 hiro
        {N_("/_Mark"),                        NULL, NULL,                0, "<Branch>"},
409 1 hiro
        {N_("/_Mark/_Mark"),                NULL, summary_mark,        0, NULL},
410 1 hiro
        {N_("/_Mark/_Unmark"),                NULL, summary_unmark,        0, NULL},
411 1 hiro
        {N_("/_Mark/---"),                NULL, NULL,                0, "<Separator>"},
412 1 hiro
        {N_("/_Mark/Mark as unr_ead"),        NULL, summary_mark_as_unread, 0, NULL},
413 1 hiro
        {N_("/_Mark/Mark as rea_d"),
414 1 hiro
                                        NULL, summary_mark_as_read, 0, NULL},
415 1 hiro
        {N_("/_Mark/Mark all _read"),        NULL, summary_mark_all_read, 0, NULL},
416 1 hiro
        {N_("/Color la_bel"),                NULL, NULL,                0, NULL},
417 1 hiro
        {N_("/---"),                        NULL, NULL,                0, "<Separator>"},
418 1 hiro
        {N_("/Re-_edit"),                NULL, summary_reedit,   0, NULL},
419 1 hiro
        {N_("/---"),                        NULL, NULL,                0, "<Separator>"},
420 352 hiro
        {N_("/Add sender to address boo_k..."),
421 1 hiro
                                        NULL, summary_add_address_cb, 0, NULL},
422 635 hiro
        {N_("/Create f_ilter rule"),        NULL, NULL,                0, "<Branch>"},
423 635 hiro
        {N_("/Create f_ilter rule/_Automatically"),
424 635 hiro
                                        NULL, summary_create_filter_cb, FLT_BY_AUTO, NULL},
425 635 hiro
        {N_("/Create f_ilter rule/by _From"),
426 635 hiro
                                        NULL, summary_create_filter_cb, FLT_BY_FROM, NULL},
427 635 hiro
        {N_("/Create f_ilter rule/by _To"),
428 635 hiro
                                        NULL, summary_create_filter_cb, FLT_BY_TO, NULL},
429 635 hiro
        {N_("/Create f_ilter rule/by _Subject"),
430 635 hiro
                                        NULL, summary_create_filter_cb, FLT_BY_SUBJECT, NULL},
431 1 hiro
        {N_("/---"),                        NULL, NULL,                0, "<Separator>"},
432 1 hiro
        {N_("/_View"),                        NULL, NULL,                0, "<Branch>"},
433 1 hiro
        {N_("/_View/Open in new _window"),
434 1 hiro
                                        NULL, summary_open_msg,        0, NULL},
435 1 hiro
        {N_("/_View/_Source"),                NULL, summary_view_source, 0, NULL},
436 1 hiro
        {N_("/_View/All _header"),        NULL, summary_show_all_header_cb, 0, "<ToggleItem>"},
437 1 hiro
        {N_("/---"),                        NULL, NULL,                0, "<Separator>"},
438 1 hiro
        {N_("/_Print..."),                NULL, summary_print,        0, NULL}
439 1 hiro
};
440 1 hiro
441 1 hiro
SummaryView *summary_create(void)
442 1 hiro
{
443 1 hiro
        SummaryView *summaryview;
444 1 hiro
        GtkWidget *vbox;
445 1 hiro
        GtkWidget *scrolledwin;
446 237 hiro
        GtkWidget *treeview;
447 237 hiro
        GtkTreeStore *store;
448 237 hiro
        GtkTreeSelection *selection;
449 741 hiro
        GtkWidget *hseparator;
450 1 hiro
        GtkWidget *hbox;
451 1 hiro
        GtkWidget *hbox_l;
452 1 hiro
        GtkWidget *statlabel_folder;
453 1 hiro
        GtkWidget *statlabel_select;
454 1 hiro
        GtkWidget *statlabel_msgs;
455 1 hiro
        GtkWidget *hbox_spc;
456 1 hiro
        GtkWidget *toggle_eventbox;
457 1 hiro
        GtkWidget *toggle_arrow;
458 1 hiro
        GtkWidget *popupmenu;
459 1 hiro
        GtkItemFactory *popupfactory;
460 1 hiro
        gint n_entries;
461 1 hiro
        GList *child;
462 1 hiro
463 1 hiro
        debug_print(_("Creating summary view...\n"));
464 1 hiro
        summaryview = g_new0(SummaryView, 1);
465 1 hiro
466 741 hiro
        vbox = gtk_vbox_new(FALSE, 1);
467 1 hiro
468 1 hiro
        scrolledwin = gtk_scrolled_window_new(NULL, NULL);
469 1 hiro
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
470 1 hiro
                                       GTK_POLICY_AUTOMATIC,
471 1 hiro
                                       GTK_POLICY_ALWAYS);
472 237 hiro
        gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwin),
473 237 hiro
                                            GTK_SHADOW_IN);
474 1 hiro
        gtk_box_pack_start(GTK_BOX(vbox), scrolledwin, TRUE, TRUE, 0);
475 1 hiro
        gtk_widget_set_size_request(vbox,
476 1 hiro
                                    prefs_common.summaryview_width,
477 1 hiro
                                    prefs_common.summaryview_height);
478 1 hiro
479 237 hiro
        treeview = summary_tree_view_create(summaryview);
480 237 hiro
        gtk_container_add(GTK_CONTAINER(scrolledwin), treeview);
481 1 hiro
482 237 hiro
        store = GTK_TREE_STORE
483 237 hiro
                (gtk_tree_view_get_model(GTK_TREE_VIEW(treeview)));
484 237 hiro
        selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
485 1 hiro
486 1 hiro
        /* create status label */
487 741 hiro
        hseparator = gtk_hseparator_new();
488 741 hiro
        gtk_box_pack_end(GTK_BOX(vbox), hseparator, FALSE, FALSE, 0);
489 741 hiro
490 1 hiro
        hbox = gtk_hbox_new(FALSE, 0);
491 1 hiro
        gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
492 1 hiro
493 1 hiro
        hbox_l = gtk_hbox_new(FALSE, 0);
494 1 hiro
        gtk_box_pack_start(GTK_BOX(hbox), hbox_l, TRUE, TRUE, 0);
495 1 hiro
496 1 hiro
        statlabel_folder = gtk_label_new("");
497 1 hiro
        gtk_box_pack_start(GTK_BOX(hbox_l), statlabel_folder, FALSE, FALSE, 2);
498 1 hiro
        statlabel_select = gtk_label_new("");
499 1 hiro
        gtk_box_pack_start(GTK_BOX(hbox_l), statlabel_select, FALSE, FALSE, 12);
500 1 hiro
501 1 hiro
        /* toggle view button */
502 1 hiro
        toggle_eventbox = gtk_event_box_new();
503 1 hiro
        gtk_box_pack_end(GTK_BOX(hbox), toggle_eventbox, FALSE, FALSE, 4);
504 1 hiro
        toggle_arrow = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT);
505 1 hiro
        gtk_container_add(GTK_CONTAINER(toggle_eventbox), toggle_arrow);
506 1 hiro
        g_signal_connect(G_OBJECT(toggle_eventbox), "button_press_event",
507 1 hiro
                         G_CALLBACK(summary_toggle_pressed), summaryview);
508 1 hiro
509 1 hiro
        statlabel_msgs = gtk_label_new("");
510 1 hiro
        gtk_box_pack_end(GTK_BOX(hbox), statlabel_msgs, FALSE, FALSE, 4);
511 1 hiro
512 1 hiro
        hbox_spc = gtk_hbox_new(FALSE, 0);
513 1 hiro
        gtk_box_pack_end(GTK_BOX(hbox), hbox_spc, FALSE, FALSE, 6);
514 1 hiro
515 1 hiro
        /* create popup menu */
516 1 hiro
        n_entries = sizeof(summary_popup_entries) /
517 1 hiro
                sizeof(summary_popup_entries[0]);
518 1 hiro
        popupmenu = menu_create_items(summary_popup_entries, n_entries,
519 1 hiro
                                      "<SummaryView>", &popupfactory,
520 1 hiro
                                      summaryview);
521 1 hiro
522 1 hiro
        summaryview->vbox = vbox;
523 1 hiro
        summaryview->scrolledwin = scrolledwin;
524 237 hiro
        summaryview->treeview = treeview;
525 237 hiro
        summaryview->store = store;
526 237 hiro
        summaryview->selection = selection;
527 741 hiro
        summaryview->hseparator = hseparator;
528 1 hiro
        summaryview->hbox = hbox;
529 1 hiro
        summaryview->hbox_l = hbox_l;
530 1 hiro
        summaryview->statlabel_folder = statlabel_folder;
531 1 hiro
        summaryview->statlabel_select = statlabel_select;
532 1 hiro
        summaryview->statlabel_msgs = statlabel_msgs;
533 1 hiro
        summaryview->toggle_eventbox = toggle_eventbox;
534 1 hiro
        summaryview->toggle_arrow = toggle_arrow;
535 1 hiro
        summaryview->popupmenu = popupmenu;
536 1 hiro
        summaryview->popupfactory = popupfactory;
537 1 hiro
        summaryview->lock_count = 0;
538 1 hiro
539 1 hiro
        summaryview->reedit_menuitem =
540 1 hiro
                gtk_item_factory_get_widget(popupfactory, "/Re-edit");
541 1 hiro
        child = g_list_find(GTK_MENU_SHELL(popupmenu)->children,
542 1 hiro
                            summaryview->reedit_menuitem);
543 1 hiro
        summaryview->reedit_separator = GTK_WIDGET(child->next->data);
544 1 hiro
545 1 hiro
        gtk_widget_show_all(vbox);
546 1 hiro
547 1 hiro
        return summaryview;
548 1 hiro
}
549 1 hiro
550 1 hiro
void summary_init(SummaryView *summaryview)
551 1 hiro
{
552 1 hiro
        GtkWidget *pixmap;
553 39 hiro
        PangoFontDescription *font_desc;
554 39 hiro
        gint size;
555 1 hiro
556 237 hiro
        stock_pixbuf_gdk(summaryview->treeview, STOCK_PIXMAP_MARK,
557 237 hiro
                         &mark_pixbuf);
558 237 hiro
        stock_pixbuf_gdk(summaryview->treeview, STOCK_PIXMAP_DELETED,
559 237 hiro
                         &deleted_pixbuf);
560 237 hiro
        stock_pixbuf_gdk(summaryview->treeview, STOCK_PIXMAP_MAIL_SMALL,
561 237 hiro
                         &mail_pixbuf);
562 237 hiro
        stock_pixbuf_gdk(summaryview->treeview, STOCK_PIXMAP_NEW,
563 237 hiro
                         &new_pixbuf);
564 237 hiro
        stock_pixbuf_gdk(summaryview->treeview, STOCK_PIXMAP_UNREAD,
565 237 hiro
                         &unread_pixbuf);
566 237 hiro
        stock_pixbuf_gdk(summaryview->treeview, STOCK_PIXMAP_REPLIED,
567 237 hiro
                         &replied_pixbuf);
568 237 hiro
        stock_pixbuf_gdk(summaryview->treeview, STOCK_PIXMAP_FORWARDED,
569 237 hiro
                         &forwarded_pixbuf);
570 237 hiro
        stock_pixbuf_gdk(summaryview->treeview, STOCK_PIXMAP_CLIP,
571 237 hiro
                         &clip_pixbuf);
572 1 hiro
573 39 hiro
        font_desc = pango_font_description_new();
574 39 hiro
        size = pango_font_description_get_size
575 39 hiro
                (summaryview->statlabel_folder->style->font_desc);
576 39 hiro
        pango_font_description_set_size(font_desc, size * PANGO_SCALE_SMALL);
577 39 hiro
        gtk_widget_modify_font(summaryview->statlabel_folder, font_desc);
578 39 hiro
        gtk_widget_modify_font(summaryview->statlabel_select, font_desc);
579 39 hiro
        gtk_widget_modify_font(summaryview->statlabel_msgs, font_desc);
580 39 hiro
        pango_font_description_free(font_desc);
581 1 hiro
582 503 hiro
        pixmap = stock_pixbuf_widget(summaryview->hbox_l,
583 503 hiro
                                     STOCK_PIXMAP_DIR_OPEN);
584 1 hiro
        gtk_box_pack_start(GTK_BOX(summaryview->hbox_l), pixmap, FALSE, FALSE, 4);
585 1 hiro
        gtk_box_reorder_child(GTK_BOX(summaryview->hbox_l), pixmap, 0);
586 1 hiro
        gtk_widget_show(pixmap);
587 1 hiro
588 1 hiro
        summary_clear_list(summaryview);
589 237 hiro
        summary_set_column_order(summaryview);
590 1 hiro
        summary_colorlabel_menu_create(summaryview);
591 1 hiro
        summary_set_menu_sensitive(summaryview);
592 1 hiro
}
593 1 hiro
594 1 hiro
gboolean summary_show(SummaryView *summaryview, FolderItem *item,
595 1 hiro
                      gboolean update_cache)
596 1 hiro
{
597 237 hiro
        GtkTreeView *treeview = GTK_TREE_VIEW(summaryview->treeview);
598 274 hiro
        GtkTreeModel *model = GTK_TREE_MODEL(summaryview->store);
599 237 hiro
        GtkTreeIter iter;
600 1 hiro
        GSList *mlist = NULL;
601 1 hiro
        gchar *buf;
602 1 hiro
        gboolean is_refresh;
603 1 hiro
        guint selected_msgnum = 0;
604 1 hiro
        guint displayed_msgnum = 0;
605 237 hiro
        gboolean moved;
606 1 hiro
607 1 hiro
        if (summary_is_locked(summaryview)) return FALSE;
608 1 hiro
609 1 hiro
        inc_lock();
610 1 hiro
        summary_lock(summaryview);
611 1 hiro
612 1 hiro
        STATUSBAR_POP(summaryview->mainwin);
613 1 hiro
614 1 hiro
        is_refresh = (item == summaryview->folder_item &&
615 1 hiro
                      update_cache == FALSE) ? TRUE : FALSE;
616 1 hiro
        if (is_refresh) {
617 1 hiro
                selected_msgnum = summary_get_msgnum(summaryview,
618 1 hiro
                                                     summaryview->selected);
619 1 hiro
                displayed_msgnum = summary_get_msgnum(summaryview,
620 1 hiro
                                                      summaryview->displayed);
621 1 hiro
        }
622 1 hiro
623 1 hiro
        /* process the marks if any */
624 1 hiro
        if (summaryview->mainwin->lock_count == 0 &&
625 1 hiro
            (summaryview->moved > 0 || summaryview->copied > 0)) {
626 1 hiro
                AlertValue val;
627 1 hiro
628 1 hiro
                val = alertpanel(_("Process mark"),
629 1 hiro
                                 _("Some marks are left. Process it?"),
630 30 hiro
                                 GTK_STOCK_YES, GTK_STOCK_NO, GTK_STOCK_CANCEL);
631 1 hiro
                if (G_ALERTDEFAULT == val) {
632 1 hiro
                        summary_unlock(summaryview);
633 1 hiro
                        summary_execute(summaryview);
634 1 hiro
                        summary_lock(summaryview);
635 270 hiro
                        GTK_EVENTS_FLUSH();
636 270 hiro
                } else if (G_ALERTALTERNATE == val) {
637 1 hiro
                        summary_write_cache(summaryview);
638 270 hiro
                        GTK_EVENTS_FLUSH();
639 270 hiro
                } else {
640 1 hiro
                        summary_unlock(summaryview);
641 1 hiro
                        inc_unlock();
642 1 hiro
                        return FALSE;
643 1 hiro
                }
644 1 hiro
        } else
645 1 hiro
                summary_write_cache(summaryview);
646 1 hiro
647 301 hiro
        folderview_set_opened_item(summaryview->folderview, item);
648 1 hiro
649 1 hiro
        summary_clear_list(summaryview);
650 1 hiro
651 1 hiro
        buf = NULL;
652 1 hiro
        if (!item || !item->path || !item->parent || item->no_select ||
653 836 hiro
            (FOLDER_TYPE(item->folder) == F_MH && item->stype != F_VIRTUAL &&
654 1 hiro
             ((buf = folder_item_get_path(item)) == NULL ||
655 1 hiro
              change_dir(buf) < 0))) {
656 1 hiro
                g_free(buf);
657 1 hiro
                debug_print("empty folder\n\n");
658 1 hiro
                summary_clear_all(summaryview);
659 1 hiro
                summaryview->folder_item = item;
660 1 hiro
                summary_unlock(summaryview);
661 1 hiro
                inc_unlock();
662 1 hiro
                return TRUE;
663 1 hiro
        }
664 1 hiro
        g_free(buf);
665 1 hiro
666 1 hiro
        if (!is_refresh)
667 1 hiro
                messageview_clear(summaryview->messageview);
668 1 hiro
669 1 hiro
        summaryview->folder_item = item;
670 1 hiro
671 237 hiro
        g_signal_handlers_block_matched(G_OBJECT(treeview),
672 1 hiro
                                        (GSignalMatchType)G_SIGNAL_MATCH_DATA,
673 1 hiro
                                        0, 0, NULL, NULL, summaryview);
674 1 hiro
675 1 hiro
        buf = g_strdup_printf(_("Scanning folder (%s)..."), item->path);
676 1 hiro
        debug_print("%s\n", buf);
677 1 hiro
        STATUSBAR_PUSH(summaryview->mainwin, buf);
678 1 hiro
        g_free(buf);
679 1 hiro
680 1 hiro
        main_window_cursor_wait(summaryview->mainwin);
681 1 hiro
682 1 hiro
        mlist = folder_item_get_msg_list(item, !update_cache);
683 1 hiro
684 1 hiro
        statusbar_pop_all();
685 1 hiro
        STATUSBAR_POP(summaryview->mainwin);
686 1 hiro
687 237 hiro
        /* set tree store and hash table from the msginfo list, and
688 1 hiro
           create the thread */
689 237 hiro
        summary_set_tree_model_from_list(summaryview, mlist);
690 1 hiro
691 237 hiro
        if (mlist)
692 237 hiro
                gtk_widget_grab_focus(GTK_WIDGET(treeview));
693 237 hiro
694 1 hiro
        g_slist_free(mlist);
695 1 hiro
696 1 hiro
        summary_write_cache(summaryview);
697 1 hiro
698 1 hiro
        item->opened = TRUE;
699 1 hiro
700 237 hiro
        g_signal_handlers_unblock_matched(G_OBJECT(treeview),
701 1 hiro
                                          (GSignalMatchType)G_SIGNAL_MATCH_DATA,
702 1 hiro
                                          0, 0, NULL, NULL, summaryview);
703 1 hiro
704 1 hiro
        if (is_refresh) {
705 237 hiro
                if (summary_find_msg_by_msgnum(summaryview, displayed_msgnum,
706 274 hiro
                                               &iter)) {
707 274 hiro
                        GtkTreePath *path;
708 274 hiro
709 274 hiro
                        path = gtk_tree_model_get_path(model, &iter);
710 274 hiro
                        gtk_tree_row_reference_free(summaryview->displayed);
711 274 hiro
                        summaryview->displayed =
712 274 hiro
                                gtk_tree_row_reference_new(model, path);
713 274 hiro
                        gtk_tree_path_free(path);
714 274 hiro
                } else
715 1 hiro
                        messageview_clear(summaryview->messageview);
716 237 hiro
717 274 hiro
                summary_select_by_msgnum(summaryview, selected_msgnum);
718 274 hiro
719 1 hiro
                if (!summaryview->selected) {
720 1 hiro
                        /* no selected message - select first unread
721 1 hiro
                           message, but do not display it */
722 240 hiro
                        if (summary_find_next_flagged_msg
723 240 hiro
                                (summaryview, &iter, NULL, MSG_UNREAD, FALSE)) {
724 240 hiro
                                summary_select_row(summaryview, &iter,
725 240 hiro
                                                   FALSE, TRUE);
726 240 hiro
                        } else if (item->total > 0) {
727 237 hiro
                                g_signal_emit_by_name
728 237 hiro
                                        (treeview, "move-cursor",
729 237 hiro
                                         GTK_MOVEMENT_BUFFER_ENDS,
730 237 hiro
                                         item->sort_type == SORT_DESCENDING ?
731 237 hiro
                                         -1 : 1, &moved);
732 330 hiro
                                GTK_EVENTS_FLUSH();
733 322 hiro
                                summary_scroll_to_selected(summaryview, TRUE);
734 237 hiro
                        }
735 1 hiro
                }
736 1 hiro
        } else {
737 1 hiro
                /* select first unread message */
738 237 hiro
                if (summary_find_next_flagged_msg(summaryview, &iter, NULL,
739 237 hiro
                                                  MSG_UNREAD, FALSE)) {
740 237 hiro
                        if (prefs_common.open_unread_on_enter ||
741 237 hiro
                            prefs_common.always_show_msg) {
742 237 hiro
                                summary_unlock(summaryview);
743 237 hiro
                                summary_select_row(summaryview, &iter,
744 237 hiro
                                                   TRUE, TRUE);
745 237 hiro
                                summary_lock(summaryview);
746 237 hiro
                        } else
747 237 hiro
                                summary_select_row(summaryview, &iter,
748 237 hiro
                                                   FALSE, TRUE);
749 237 hiro
                } else {
750 240 hiro
                        summary_unlock(summaryview);
751 237 hiro
                        g_signal_emit_by_name
752 237 hiro
                                (treeview, "move-cursor",
753 237 hiro
                                 GTK_MOVEMENT_BUFFER_ENDS,
754 237 hiro
                                 item->sort_type == SORT_DESCENDING ?
755 237 hiro
                                 -1 : 1, &moved);
756 240 hiro
                        summary_lock(summaryview);
757 330 hiro
                        GTK_EVENTS_FLUSH();
758 322 hiro
                        summary_scroll_to_selected(summaryview, TRUE);
759 1 hiro
                }
760 1 hiro
        }
761 1 hiro
762 1 hiro
        summary_status_show(summaryview);
763 1 hiro
        summary_set_menu_sensitive(summaryview);
764 1 hiro
        main_window_set_toolbar_sensitive(summaryview->mainwin);
765 1 hiro
766 1 hiro
        debug_print("\n");
767 1 hiro
        STATUSBAR_PUSH(summaryview->mainwin, _("Done."));
768 1 hiro
769 1 hiro
        main_window_cursor_normal(summaryview->mainwin);
770 1 hiro
        summary_unlock(summaryview);
771 1 hiro
        inc_unlock();
772 1 hiro
773 1 hiro
        return TRUE;
774 1 hiro
}
775 1 hiro
776 237 hiro
static gboolean summary_free_msginfo_func(GtkTreeModel *model,
777 237 hiro
                                          GtkTreePath *path, GtkTreeIter *iter,
778 237 hiro
                                          gpointer data)
779 237 hiro
{
780 237 hiro
        MsgInfo *msginfo;
781 237 hiro
782 237 hiro
        gtk_tree_model_get(model, iter, S_COL_MSG_INFO, &msginfo, -1);
783 237 hiro
        procmsg_msginfo_free(msginfo);
784 237 hiro
785 237 hiro
        return FALSE;
786 237 hiro
}
787 237 hiro
788 1 hiro
void summary_clear_list(SummaryView *summaryview)
789 1 hiro
{
790 237 hiro
        GtkTreeView *treeview = GTK_TREE_VIEW(summaryview->treeview);
791 273 hiro
        GtkAdjustment *adj;
792 1 hiro
793 237 hiro
        gtk_tree_model_foreach(GTK_TREE_MODEL(summaryview->store),
794 237 hiro
                               summary_free_msginfo_func, NULL);
795 1 hiro
796 1 hiro
        if (summaryview->folder_item) {
797 1 hiro
                folder_item_close(summaryview->folder_item);
798 1 hiro
                summaryview->folder_item = NULL;
799 1 hiro
        }
800 1 hiro
801 1 hiro
        summaryview->display_msg = FALSE;
802 1 hiro
803 1 hiro
        summaryview->selected = NULL;
804 1 hiro
        summaryview->displayed = NULL;
805 297 hiro
806 297 hiro
        summary_selection_list_free(summaryview);
807 297 hiro
808 1 hiro
        summaryview->total_size = 0;
809 1 hiro
        summaryview->deleted = summaryview->moved = 0;
810 1 hiro
        summaryview->copied = 0;
811 237 hiro
812 237 hiro
        summary_msgid_table_destroy(summaryview);
813 237 hiro
814 1 hiro
        summaryview->mlist = NULL;
815 1 hiro
        if (summaryview->folder_table) {
816 1 hiro
                g_hash_table_destroy(summaryview->folder_table);
817 1 hiro
                summaryview->folder_table = NULL;
818 1 hiro
        }
819 237 hiro
        summaryview->filtered = 0;
820 792 hiro
        summaryview->flt_count = 0;
821 792 hiro
        summaryview->flt_total = 0;
822 1 hiro
823 600 hiro
        summaryview->on_button_press = FALSE;
824 237 hiro
        summaryview->can_toggle_selection = TRUE;
825 237 hiro
        summaryview->on_drag = FALSE;
826 237 hiro
        if (summaryview->pressed_path) {
827 237 hiro
                gtk_tree_path_free(summaryview->pressed_path);
828 237 hiro
                summaryview->pressed_path = NULL;
829 1 hiro
        }
830 291 hiro
        if (summaryview->drag_list) {
831 291 hiro
                g_free(summaryview->drag_list);
832 291 hiro
                summaryview->drag_list = NULL;
833 291 hiro
        }
834 1 hiro
835 237 hiro
        gtk_tree_view_set_model(treeview, NULL);
836 237 hiro
        gtk_tree_store_clear(summaryview->store);
837 237 hiro
        gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(summaryview->store));
838 237 hiro
839 273 hiro
        /* ensure that the "value-changed" signal is always emitted */
840 273 hiro
        adj = gtk_tree_view_get_vadjustment(treeview);
841 273 hiro
        adj->value = 0.0;
842 273 hiro
843 239 hiro
        gtkut_tree_sortable_unset_sort_column_id
844 239 hiro
                (GTK_TREE_SORTABLE(summaryview->store));
845 1 hiro
}
846 1 hiro
847 1 hiro
void summary_clear_all(SummaryView *summaryview)
848 1 hiro
{
849 1 hiro
        messageview_clear(summaryview->messageview);
850 1 hiro
        summary_clear_list(summaryview);
851 1 hiro
        summary_set_menu_sensitive(summaryview);
852 1 hiro
        main_window_set_toolbar_sensitive(summaryview->mainwin);
853 1 hiro
        summary_status_show(summaryview);
854 1 hiro
}
855 1 hiro
856 1 hiro
void summary_lock(SummaryView *summaryview)
857 1 hiro
{
858 1 hiro
        summaryview->lock_count++;
859 1 hiro
}
860 1 hiro
861 1 hiro
void summary_unlock(SummaryView *summaryview)
862 1 hiro
{
863 1 hiro
        if (summaryview->lock_count)
864 1 hiro
                summaryview->lock_count--;
865 1 hiro
}
866 1 hiro
867 1 hiro
gboolean summary_is_locked(SummaryView *summaryview)
868 1 hiro
{
869 1 hiro
        return summaryview->lock_count > 0;
870 1 hiro
}
871 1 hiro
872 1 hiro
SummarySelection summary_get_selection_type(SummaryView *summaryview)
873 1 hiro
{
874 1 hiro
        SummarySelection selection;
875 306 hiro
        GList *rows;
876 1 hiro
877 306 hiro
        rows = summary_get_selected_rows(summaryview);
878 237 hiro
879 237 hiro
        if (!summaryview->folder_item || summaryview->folder_item->total == 0)
880 1 hiro
                selection = SUMMARY_NONE;
881 306 hiro
        else if (!rows)
882 1 hiro
                selection = SUMMARY_SELECTED_NONE;
883 306 hiro
        else if (rows && !rows->next)
884 1 hiro
                selection = SUMMARY_SELECTED_SINGLE;
885 1 hiro
        else
886 1 hiro
                selection = SUMMARY_SELECTED_MULTIPLE;
887 1 hiro
888 1 hiro
        return selection;
889 1 hiro
}
890 1 hiro
891 297 hiro
static GList *summary_get_selected_rows(SummaryView *summaryview)
892 297 hiro
{
893 297 hiro
        if (!summaryview->selection_list)
894 297 hiro
                summaryview->selection_list =
895 297 hiro
                        gtk_tree_selection_get_selected_rows
896 297 hiro
                                (summaryview->selection, NULL);
897 297 hiro
898 297 hiro
        return summaryview->selection_list;
899 297 hiro
}
900 297 hiro
901 297 hiro
static void summary_selection_list_free(SummaryView *summaryview)
902 297 hiro
{
903 297 hiro
        if (summaryview->selection_list) {
904 297 hiro
                g_list_foreach(summaryview->selection_list,
905 297 hiro
                               (GFunc)gtk_tree_path_free, NULL);
906 297 hiro
                g_list_free(summaryview->selection_list);
907 297 hiro
                summaryview->selection_list = NULL;
908 297 hiro
        }
909 297 hiro
}
910 297 hiro
911 1 hiro
GSList *summary_get_selected_msg_list(SummaryView *summaryview)
912 1 hiro
{
913 1 hiro
        GSList *mlist = NULL;
914 237 hiro
        GList *rows;
915 1 hiro
        GList *cur;
916 237 hiro
        GtkTreeModel *model = GTK_TREE_MODEL(summaryview->store);
917 237 hiro
        GtkTreeIter iter;
918 1 hiro
        MsgInfo *msginfo;
919 1 hiro
920 297 hiro
        rows = summary_get_selected_rows(summaryview);
921 237 hiro
        for (cur = rows; cur != NULL; cur = cur->next) {
922 237 hiro
                gtk_tree_model_get_iter(model, &iter, (GtkTreePath *)cur->data);
923 237 hiro
                gtk_tree_model_get(model, &iter, S_COL_MSG_INFO, &msginfo, -1);
924 1 hiro
                mlist = g_slist_prepend(mlist, msginfo);
925 1 hiro
        }
926 1 hiro
927 1 hiro
        mlist = g_slist_reverse(mlist);
928 1 hiro
929 1 hiro
        return mlist;
930 1 hiro
}
931 1 hiro
932 850 hiro
GSList *summary_get_changed_msg_list(SummaryView *summaryview)
933 850 hiro
{
934 850 hiro
        GtkTreeModel *model = GTK_TREE_MODEL(summaryview->store);
935 850 hiro
        GtkTreeIter iter;
936 850 hiro
        GSList *mlist = NULL;
937 850 hiro
        MsgInfo *msginfo;
938 850 hiro
        gboolean valid;
939 850 hiro
940 850 hiro
        valid = gtk_tree_model_get_iter_first(model, &iter);
941 850 hiro
942 850 hiro
        while (valid) {
943 850 hiro
                gtk_tree_model_get(model, &iter, S_COL_MSG_INFO, &msginfo, -1);
944 850 hiro
                if (MSG_IS_FLAG_CHANGED(msginfo->flags))
945 850 hiro
                        mlist = g_slist_prepend(mlist, msginfo);
946 850 hiro
                valid = gtkut_tree_model_next(model, &iter);
947 850 hiro
        }
948 850 hiro
949 850 hiro
        return g_slist_reverse(mlist);
950 850 hiro
}
951 850 hiro
952 1 hiro
GSList *summary_get_msg_list(SummaryView *summaryview)
953 1 hiro
{
954 237 hiro
        GtkTreeModel *model = GTK_TREE_MODEL(summaryview->store);
955 237 hiro
        GtkTreeIter iter;
956 1 hiro
        GSList *mlist = NULL;
957 1 hiro
        MsgInfo *msginfo;
958 237 hiro
        gboolean valid;
959 1 hiro
960 237 hiro
        valid = gtk_tree_model_get_iter_first(model, &iter);
961 1 hiro
962 237 hiro
        while (valid) {
963 237 hiro
                gtk_tree_model_get(model, &iter, S_COL_MSG_INFO, &msginfo, -1);
964 1 hiro
                mlist = g_slist_prepend(mlist, msginfo);
965 237 hiro
                valid = gtkut_tree_model_next(model, &iter);
966 1 hiro
        }
967 1 hiro
968 237 hiro
        return g_slist_reverse(mlist);
969 237 hiro
}
970 1 hiro
971 237 hiro
static gboolean summary_msgid_table_create_func(GtkTreeModel *model,
972 237 hiro
                                                GtkTreePath *path,
973 237 hiro
                                                GtkTreeIter *iter,
974 237 hiro
                                                gpointer data)
975 237 hiro
{
976 237 hiro
        GHashTable *msgid_table = (GHashTable *)data;
977 237 hiro
        MsgInfo *msginfo;
978 237 hiro
        GtkTreeIter *iter_;
979 237 hiro
980 237 hiro
        gtk_tree_model_get(model, iter, S_COL_MSG_INFO, &msginfo, -1);
981 237 hiro
982 305 hiro
        if (msginfo && !MSG_IS_INVALID(msginfo->flags) &&
983 305 hiro
            !MSG_IS_DELETED(msginfo->flags) &&
984 305 hiro
            msginfo->msgid && msginfo->msgid[0] != '\0') {
985 237 hiro
                iter_ = gtk_tree_iter_copy(iter);
986 237 hiro
                g_hash_table_replace(msgid_table, msginfo->msgid, iter_);
987 237 hiro
        }
988 237 hiro
989 237 hiro
        return FALSE;
990 1 hiro
}
991 1 hiro
992 237 hiro
static void summary_msgid_table_create(SummaryView *summaryview)
993 237 hiro
{
994 237 hiro
        GHashTable *msgid_table;
995 237 hiro
996 237 hiro
        g_return_if_fail(summaryview->msgid_table == NULL);
997 237 hiro
998 237 hiro
        msgid_table = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
999 237 hiro
                                            (GDestroyNotify)gtk_tree_iter_free);
1000 237 hiro
1001 237 hiro
        gtk_tree_model_foreach(GTK_TREE_MODEL(summaryview->store),
1002 237 hiro
                               summary_msgid_table_create_func, msgid_table);
1003 237 hiro
1004 237 hiro
        summaryview->msgid_table = msgid_table;
1005 237 hiro
}
1006 237 hiro
1007 237 hiro
static void summary_msgid_table_destroy(SummaryView *summaryview)
1008 237 hiro
{
1009 237 hiro
        if (!summaryview->msgid_table)
1010 237 hiro
                return;
1011 237 hiro
1012 237 hiro
        g_hash_table_destroy(summaryview->msgid_table);
1013 237 hiro
        summaryview->msgid_table = NULL;
1014 237 hiro
}
1015 237 hiro
1016 1 hiro
static void summary_set_menu_sensitive(SummaryView *summaryview)
1017 1 hiro
{
1018 1 hiro
        GtkItemFactory *ifactory = summaryview->popupfactory;
1019 1 hiro
        SummarySelection selection;
1020 1 hiro
        GtkWidget *menuitem;
1021 1 hiro
        gboolean sens;
1022 1 hiro
1023 1 hiro
        selection = summary_get_selection_type(summaryview);
1024 1 hiro
        sens = (selection == SUMMARY_SELECTED_MULTIPLE) ? FALSE : TRUE;
1025 1 hiro
1026 1 hiro
        main_window_set_menu_sensitive(summaryview->mainwin);
1027 1 hiro
1028 1 hiro
        if (summaryview->folder_item &&
1029 1 hiro
            (summaryview->folder_item->stype == F_OUTBOX ||
1030 1 hiro
             summaryview->folder_item->stype == F_DRAFT  ||
1031 1 hiro
             summaryview->folder_item->stype == F_QUEUE)) {
1032 1 hiro
                gtk_widget_show(summaryview->reedit_menuitem);
1033 1 hiro
                gtk_widget_show(summaryview->reedit_separator);
1034 1 hiro
                menu_set_sensitive(ifactory, "/Re-edit", sens);
1035 1 hiro
        } else {
1036 1 hiro
                gtk_widget_hide(summaryview->reedit_menuitem);
1037 1 hiro
                gtk_widget_hide(summaryview->reedit_separator);
1038 1 hiro
                menu_set_sensitive(ifactory, "/Re-edit", FALSE);
1039 1 hiro
        }
1040 1 hiro
1041 1 hiro
        if (selection == SUMMARY_NONE) {
1042 1 hiro
                menu_set_insensitive_all
1043 1 hiro
                        (GTK_MENU_SHELL(summaryview->popupmenu));
1044 1 hiro
                return;
1045 1 hiro
        }
1046 1 hiro
1047 237 hiro
        if (summaryview->folder_item &&
1048 237 hiro
            FOLDER_TYPE(summaryview->folder_item->folder) != F_NEWS) {
1049 1 hiro
                menu_set_sensitive(ifactory, "/Move...", TRUE);
1050 1 hiro
                menu_set_sensitive(ifactory, "/Delete", TRUE);
1051 1 hiro
        } else {
1052 1 hiro
                menu_set_sensitive(ifactory, "/Move...", FALSE);
1053 1 hiro
                menu_set_sensitive(ifactory, "/Delete", FALSE);
1054 1 hiro
        }
1055 1 hiro
1056 1 hiro
        menu_set_sensitive(ifactory, "/Copy...", TRUE);
1057 1 hiro
1058 1 hiro
        menu_set_sensitive(ifactory, "/Mark", TRUE);
1059 1 hiro
        menu_set_sensitive(ifactory, "/Mark/Mark",   TRUE);
1060 1 hiro
        menu_set_sensitive(ifactory, "/Mark/Unmark", TRUE);
1061 1 hiro
1062 1 hiro
        menu_set_sensitive(ifactory, "/Mark/Mark as unread", TRUE);
1063 1 hiro
        menu_set_sensitive(ifactory, "/Mark/Mark as read",   TRUE);
1064 1 hiro
        menu_set_sensitive(ifactory, "/Mark/Mark all read",  TRUE);
1065 1 hiro
1066 1 hiro
        menu_set_sensitive(ifactory, "/Color label", TRUE);
1067 1 hiro
1068 1 hiro
        menu_set_sensitive(ifactory, "/Reply",                          sens);
1069 1 hiro
        menu_set_sensitive(ifactory, "/Reply to",                  sens);
1070 1 hiro
        menu_set_sensitive(ifactory, "/Reply to/all",                  sens);
1071 1 hiro
        menu_set_sensitive(ifactory, "/Reply to/sender",          sens);
1072 1 hiro
        menu_set_sensitive(ifactory, "/Reply to/mailing list",          sens);
1073 1 hiro
        menu_set_sensitive(ifactory, "/Forward",                  TRUE);
1074 1 hiro
        menu_set_sensitive(ifactory, "/Forward as attachment",          TRUE);
1075 1 hiro
        menu_set_sensitive(ifactory, "/Redirect",                  sens);
1076 1 hiro
1077 352 hiro
        menu_set_sensitive(ifactory, "/Add sender to address book...", sens);
1078 635 hiro
        menu_set_sensitive(ifactory, "/Create filter rule", sens);
1079 1 hiro
1080 1 hiro
        menu_set_sensitive(ifactory, "/View", sens);
1081 1 hiro
        menu_set_sensitive(ifactory, "/View/Open in new window", sens);
1082 1 hiro
        menu_set_sensitive(ifactory, "/View/Source", sens);
1083 1 hiro
        menu_set_sensitive(ifactory, "/View/All header", sens);
1084 1 hiro
1085 1 hiro
        menu_set_sensitive(ifactory, "/Print...",   TRUE);
1086 1 hiro
1087 1 hiro
        summary_lock(summaryview);
1088 1 hiro
        menuitem = gtk_item_factory_get_widget(ifactory, "/View/All header");
1089 1 hiro
        gtk_check_menu_item_set_active
1090 1 hiro
                (GTK_CHECK_MENU_ITEM(menuitem),
1091 1 hiro
                 summaryview->messageview->textview->show_all_headers);
1092 1 hiro
        summary_unlock(summaryview);
1093 1 hiro
}
1094 1 hiro
1095 237 hiro
static void summary_select_prev_flagged(SummaryView *summaryview,
1096 237 hiro
                                        MsgPermFlags flags,
1097 237 hiro
                                        const gchar *title,
1098 237 hiro
                                        const gchar *ask_msg,
1099 237 hiro
                                        const gchar *notice)
1100 1 hiro
{
1101 237 hiro
        GtkTreeModel *model = GTK_TREE_MODEL(summaryview->store);
1102 237 hiro
        GtkTreeIter prev, iter;
1103 335 hiro
        gboolean start_from_prev = FALSE;
1104 237 hiro
        gboolean found;
1105 1 hiro
1106 237 hiro
        if (!gtkut_tree_row_reference_get_iter(model, summaryview->selected,
1107 237 hiro
                                               &iter))
1108 237 hiro
                return;
1109 1 hiro
1110 335 hiro
        if (!messageview_is_visible(summaryview->messageview) ||
1111 335 hiro
            summary_row_is_displayed(summaryview, &iter))
1112 335 hiro
                start_from_prev = TRUE;
1113 335 hiro
1114 237 hiro
        found = summary_find_prev_flagged_msg
1115 237 hiro
                (summaryview, &prev, &iter, flags, start_from_prev);
1116 237 hiro
1117 237 hiro
        if (!found) {
1118 1 hiro
                AlertValue val;
1119 1 hiro
1120 237 hiro
                val = alertpanel(title, ask_msg, GTK_STOCK_YES, GTK_STOCK_NO,
1121 237 hiro
                                 NULL);
1122 1 hiro
                if (val != G_ALERTDEFAULT) return;
1123 237 hiro
                found = summary_find_prev_flagged_msg(summaryview, &prev, NULL,
1124 237 hiro
                                                      flags, start_from_prev);
1125 1 hiro
        }
1126 1 hiro
1127 237 hiro
        if (!found) {
1128 237 hiro
                if (notice)
1129 237 hiro
                        alertpanel_notice(notice);
1130 237 hiro
        } else
1131 251 hiro
                summary_select_row
1132 251 hiro
                        (summaryview, &prev,
1133 251 hiro
                         messageview_is_visible(summaryview->messageview),
1134 251 hiro
                         FALSE);
1135 1 hiro
}
1136 1 hiro
1137 237 hiro
static void summary_select_next_flagged(SummaryView *summaryview,
1138 237 hiro
                                        MsgPermFlags flags,
1139 237 hiro
                                        const gchar *title,
1140 237 hiro
                                        const gchar *ask_msg,
1141 237 hiro
                                        const gchar *notice)
1142 1 hiro
{
1143 237 hiro
        GtkTreeModel *model = GTK_TREE_MODEL(summaryview->store);
1144 237 hiro
        GtkTreeIter next, iter;
1145 335 hiro
        gboolean start_from_next = FALSE;
1146 237 hiro
        gboolean found;
1147 1 hiro
1148 237 hiro
        if (!gtkut_tree_row_reference_get_iter(model, summaryview->selected,
1149 237 hiro
                                               &iter)) {
1150 237 hiro
                if (!gtk_tree_model_get_iter_first(model, &iter))
1151 1 hiro
                        return;
1152 1 hiro
        }
1153 1 hiro
1154 335 hiro
        if (!messageview_is_visible(summaryview->messageview) ||
1155 335 hiro
            summary_row_is_displayed(summaryview, &iter))
1156 335 hiro
                start_from_next = TRUE;
1157 335 hiro
1158 237 hiro
        found = summary_find_next_flagged_msg
1159 237 hiro
                (summaryview, &next, &iter, flags, start_from_next);
1160 1 hiro
1161 237 hiro
        if (!found) {
1162 1 hiro
                AlertValue val;
1163 1 hiro
1164 237 hiro
                val = alertpanel(title, ask_msg, GTK_STOCK_YES, GTK_STOCK_NO,
1165 237 hiro
                                 NULL);
1166 1 hiro
                if (val != G_ALERTDEFAULT) return;
1167 237 hiro
                found = summary_find_next_flagged_msg(summaryview, &next, NULL,
1168 237 hiro
                                                      flags, start_from_next);
1169 1 hiro
        }
1170 1 hiro
1171 237 hiro
        if (!found) {
1172 237 hiro
                if (notice)
1173 237 hiro
                        alertpanel_notice(notice);
1174 237 hiro
        } else
1175 251 hiro
                summary_select_row
1176 251 hiro
                        (summaryview, &next,
1177 251 hiro
                         messageview_is_visible(summaryview->messageview),
1178 251 hiro
                         FALSE);
1179 1 hiro
}
1180 1 hiro
1181 237 hiro
static void summary_select_next_flagged_or_folder(SummaryView *summaryview,
1182 237 hiro
                                                  MsgPermFlags flags,
1183 237 hiro
                                                  const gchar *title,
1184 237 hiro
                                                  const gchar *ask_msg,
1185 237 hiro
                                                  const gchar *notice)
1186 1 hiro
{
1187 237 hiro
        GtkTreeModel *model = GTK_TREE_MODEL(summaryview->store);
1188 237 hiro
        GtkTreeIter iter, next;
1189 335 hiro
        gboolean start_from_next = FALSE;
1190 1 hiro
1191 237 hiro
        if (!gtkut_tree_row_reference_get_iter(model, summaryview->selected,
1192 237 hiro
                                               &iter)) {
1193 237 hiro
                if (!gtk_tree_model_get_iter_first(model, &iter))
1194 237 hiro
                        return;
1195 237 hiro
        }
1196 237 hiro
1197 335 hiro
        if (!messageview_is_visible(summaryview->messageview) ||
1198 335 hiro
            summary_row_is_displayed(summaryview, &iter))
1199 335 hiro
                start_from_next = TRUE;
1200 335 hiro
1201 237 hiro
        while (summary_find_next_flagged_msg
1202 303 hiro
                (summaryview, &next, &iter, flags, start_from_next) == FALSE) {
1203 1 hiro
                AlertValue val;
1204 1 hiro
1205 237 hiro
                val = alertpanel(title, ask_msg,
1206 407 hiro
                                 GTK_STOCK_YES, GTK_STOCK_NO,
1207 421 hiro
                                 _("_Search again"));
1208 237 hiro
1209 1 hiro
                if (val == G_ALERTDEFAULT) {
1210 1 hiro
                        folderview_select_next_unread(summaryview->folderview);
1211 1 hiro
                        return;
1212 407 hiro
                } else if (val == G_ALERTOTHER) {
1213 303 hiro
                        start_from_next = FALSE;
1214 237 hiro
                        if (!gtk_tree_model_get_iter_first(model, &iter))
1215 237 hiro
                                return;
1216 237 hiro
                } else
1217 1 hiro
                        return;
1218 1 hiro
        }
1219 1 hiro
1220 251 hiro
        summary_select_row(summaryview, &next,
1221 251 hiro
                           messageview_is_visible(summaryview->messageview),
1222 251 hiro
                           FALSE);
1223 1 hiro
}
1224 1 hiro
1225 237 hiro
void summary_select_prev_unread(SummaryView *summaryview)
1226 1 hiro
{
1227 335 hiro
        summary_select_prev_flagged(summaryview, MSG_UNREAD,
1228 237 hiro
                                    _("No more unread messages"),
1229 237 hiro
                                    _("No unread message found. "
1230 237 hiro
                                      "Search from the end?"),
1231 237 hiro
                                    _("No unread messages."));
1232 237 hiro
}
1233 1 hiro
1234 237 hiro
void summary_select_next_unread(SummaryView *summaryview)
1235 237 hiro
{
1236 335 hiro
        summary_select_next_flagged_or_folder(summaryview, MSG_UNREAD,
1237 237 hiro
                                              _("No more unread messages"),
1238 237 hiro
                                              _("No unread message found. "
1239 237 hiro
                                                "Go to next folder?"),
1240 237 hiro
                                              NULL);
1241 237 hiro
}
1242 1 hiro
1243 237 hiro
void summary_select_prev_new(SummaryView *summaryview)
1244 237 hiro
{
1245 335 hiro
        summary_select_prev_flagged(summaryview, MSG_NEW,
1246 237 hiro
                                    _("No more new messages"),
1247 237 hiro
                                    _("No new message found. "
1248 237 hiro
                                      "Search from the end?"),
1249 237 hiro
                                    _("No new messages."));
1250 237 hiro
}
1251 1 hiro
1252 237 hiro
void summary_select_next_new(SummaryView *summaryview)
1253 237 hiro
{
1254 335 hiro
        summary_select_next_flagged_or_folder(summaryview, MSG_NEW,
1255 237 hiro
                                              _("No more new messages"),
1256 237 hiro
                                              _("No new message found. "
1257 237 hiro
                                                "Go to next folder?"),
1258 237 hiro
                                              NULL);
1259 237 hiro
}
1260 1 hiro
1261 237 hiro
void summary_select_prev_marked(SummaryView *summaryview)
1262 237 hiro
{
1263 335 hiro
        summary_select_prev_flagged(summaryview, MSG_MARKED,
1264 237 hiro
                                    _("No more marked messages"),
1265 237 hiro
                                    _("No marked message found. "
1266 237 hiro
                                      "Search from the end?"),
1267 237 hiro
                                    _("No marked messages."));
1268 1 hiro
}
1269 1 hiro
1270 1 hiro
void summary_select_next_marked(SummaryView *summaryview)
1271 1 hiro
{
1272 335 hiro
        summary_select_next_flagged(summaryview, MSG_MARKED,
1273 237 hiro
                                    _("No more marked messages"),
1274 237 hiro
                                    _("No marked message found. "
1275 237 hiro
                                      "Search from the beginning?"),
1276 237 hiro
                                    _("No marked messages."));
1277 1 hiro
}
1278 1 hiro
1279 1 hiro
void summary_select_prev_labeled(SummaryView *summaryview)
1280 1 hiro
{
1281 335 hiro
        summary_select_prev_flagged(summaryview, MSG_CLABEL_FLAG_MASK,
1282 237 hiro
                                    _("No more labeled messages"),
1283 237 hiro
                                    _("No labeled message found. "
1284 237 hiro
                                      "Search from the end?"),
1285 237 hiro
                                    _("No labeled messages."));
1286 1 hiro
}
1287 1 hiro
1288 1 hiro
void summary_select_next_labeled(SummaryView *summaryview)
1289 1 hiro
{
1290 335 hiro
        summary_select_next_flagged(summaryview, MSG_CLABEL_FLAG_MASK,
1291 237 hiro
                                    _("No more labeled messages"),
1292 237 hiro
                                    _("No labeled message found. "
1293 237 hiro
                                      "Search from the beginning?"),
1294 237 hiro
                                    _("No labeled messages."));
1295 1 hiro
}
1296 1 hiro
1297 1 hiro
void summary_select_by_msgnum(SummaryView *summaryview, guint msgnum)
1298 1 hiro
{
1299 237 hiro
        GtkTreeIter iter;
1300 1 hiro
1301 237 hiro
        if (summary_find_msg_by_msgnum(summaryview, msgnum, &iter))
1302 237 hiro
                summary_select_row(summaryview, &iter, FALSE, TRUE);
1303 1 hiro
}
1304 1 hiro
1305 852 hiro
gboolean summary_select_by_msginfo(SummaryView *summaryview, MsgInfo *msginfo)
1306 852 hiro
{
1307 852 hiro
        GtkTreeIter iter;
1308 852 hiro
1309 852 hiro
        if (summaryview->folder_item != msginfo->folder)
1310 852 hiro
                return FALSE;
1311 852 hiro
1312 852 hiro
        if (summary_find_msg_by_msgnum(summaryview, msginfo->msgnum, &iter)) {
1313 852 hiro
                summary_select_row(summaryview, &iter,
1314 852 hiro
                           messageview_is_visible(summaryview->messageview),
1315 852 hiro
                           TRUE);
1316 852 hiro
                return TRUE;
1317 852 hiro
        }
1318 852 hiro
1319 852 hiro
        return FALSE;
1320 852 hiro
}
1321 852 hiro
1322 1 hiro
/**
1323 237 hiro
 * summary_select_row:
1324 1 hiro
 * @summaryview: Summary view.
1325 1 hiro
 * @node: Summary tree node.
1326 1 hiro
 * @display_msg: TRUE to display the selected message.
1327 1 hiro
 * @do_refresh: TRUE to refresh the widget.
1328 1 hiro
 *
1329 1 hiro
 * Select @node (bringing it into view by scrolling and expanding its
1330 1 hiro
 * thread, if necessary) and unselect all others.  If @display_msg is
1331 1 hiro
 * TRUE, display the corresponding message in the message view.
1332 1 hiro
 * If @do_refresh is TRUE, the widget is refreshed.
1333 1 hiro
 **/
1334 237 hiro
void summary_select_row(SummaryView *summaryview, GtkTreeIter *iter,
1335 1 hiro
                         gboolean display_msg, gboolean do_refresh)
1336 1 hiro
{
1337 237 hiro
        GtkTreePath *path;
1338 1 hiro
1339 237 hiro
        if (!iter)
1340 237 hiro
                return;
1341 237 hiro
1342 237 hiro
        gtkut_tree_view_expand_parent_all
1343 237 hiro
                (GTK_TREE_VIEW(summaryview->treeview), iter);
1344 237 hiro
1345 237 hiro
        if (do_refresh)
1346 237 hiro
                gtk_widget_grab_focus(summaryview->treeview);
1347 237 hiro
1348 237 hiro
        summaryview->display_msg = display_msg;
1349 237 hiro
        path = gtk_tree_model_get_path(GTK_TREE_MODEL(summaryview->store),
1350 237 hiro
                                       iter);
1351 237 hiro
        gtk_tree_view_set_cursor(GTK_TREE_VIEW(summaryview->treeview), path,
1352 237 hiro
                                 NULL, FALSE);
1353 330 hiro
        if (do_refresh) {
1354 330 hiro
                GTK_EVENTS_FLUSH();
1355 237 hiro
                gtk_tree_view_scroll_to_cell
1356 237 hiro
                        (GTK_TREE_VIEW(summaryview->treeview),
1357 237 hiro
                         path, NULL, TRUE, 0.5, 0.0);
1358 330 hiro
        } else {
1359 322 hiro
                gtkut_tree_view_scroll_to_cell
1360 600 hiro
                        (GTK_TREE_VIEW(summaryview->treeview), path,
1361 600 hiro
                         !summaryview->on_button_press);
1362 330 hiro
        }
1363 237 hiro
1364 237 hiro
        gtk_tree_path_free(path);
1365 1 hiro
}
1366 1 hiro
1367 322 hiro
static void summary_scroll_to_selected(SummaryView *summaryview,
1368 322 hiro
                                       gboolean align_center)
1369 244 hiro
{
1370 244 hiro
        GtkTreePath *path;
1371 244 hiro
1372 244 hiro
        if (!summaryview->selected)
1373 244 hiro
                return;
1374 244 hiro
1375 244 hiro
        path = gtk_tree_row_reference_get_path(summaryview->selected);
1376 244 hiro
        if (path) {
1377 322 hiro
                if (align_center)
1378 322 hiro
                        gtk_tree_view_scroll_to_cell
1379 322 hiro
                                (GTK_TREE_VIEW(summaryview->treeview),
1380 322 hiro
                                 path, NULL, TRUE, 0.5, 0.0);
1381 322 hiro
                else
1382 322 hiro
                        gtkut_tree_view_scroll_to_cell
1383 600 hiro
                                (GTK_TREE_VIEW(summaryview->treeview), path,
1384 600 hiro
                                 FALSE);
1385 244 hiro
                gtk_tree_path_free(path);
1386 244 hiro
        }
1387 244 hiro
}
1388 244 hiro
1389 598 hiro
static MsgInfo *summary_get_msginfo(SummaryView *summaryview,
1390 598 hiro
                                    GtkTreeRowReference *row)
1391 1 hiro
{
1392 237 hiro
        GtkTreeIter iter;
1393 237 hiro
        MsgInfo *msginfo = NULL;
1394 1 hiro
1395 237 hiro
        if (!row)
1396 1 hiro
                return 0;
1397 237 hiro
        if (!gtkut_tree_row_reference_get_iter
1398 237 hiro
                (GTK_TREE_MODEL(summaryview->store), row, &iter))
1399 237 hiro
                return 0;
1400 237 hiro
1401 237 hiro
        gtk_tree_model_get(GTK_TREE_MODEL(summaryview->store), &iter,
1402 237 hiro
                           S_COL_MSG_INFO, &msginfo, -1);
1403 237 hiro
1404 598 hiro
        return msginfo;
1405 598 hiro
}
1406 598 hiro
1407 598 hiro
static guint summary_get_msgnum(SummaryView *summaryview,
1408 598 hiro
                                GtkTreeRowReference *row)
1409 598 hiro
{
1410 598 hiro
        MsgInfo *msginfo;
1411 598 hiro
1412 598 hiro
        msginfo = summary_get_msginfo(summaryview, row);
1413 598 hiro
        if (!msginfo)
1414 598 hiro
                return 0;
1415 598 hiro
1416 1 hiro
        return msginfo->msgnum;
1417 1 hiro
}
1418 1 hiro
1419 237 hiro
static gboolean summary_find_prev_msg(SummaryView *summaryview,
1420 237 hiro
                                      GtkTreeIter *prev, GtkTreeIter *iter)
1421 1 hiro
{
1422 237 hiro
        GtkTreeIter iter_;
1423 1 hiro
        MsgInfo *msginfo;
1424 237 hiro
        gboolean valid = TRUE;
1425 1 hiro
1426 237 hiro
        if (!iter)
1427 237 hiro
                return FALSE;
1428 1 hiro
1429 237 hiro
        iter_ = *iter;
1430 237 hiro
1431 237 hiro
        while (valid) {
1432 237 hiro
                GET_MSG_INFO(msginfo, &iter_);
1433 1 hiro
                if (msginfo && !MSG_IS_INVALID(msginfo->flags) &&
1434 237 hiro
                    !MSG_IS_DELETED(msginfo->flags)) {
1435 237 hiro
                        *prev = iter_;
1436 237 hiro
                        return TRUE;
1437 237 hiro
                }
1438 237 hiro
                valid = gtkut_tree_model_prev
1439 237 hiro
                        (GTK_TREE_MODEL(summaryview->store), &iter_);
1440 1 hiro
        }
1441 1 hiro
1442 237 hiro
        return FALSE;
1443 1 hiro
}
1444 1 hiro
1445 237 hiro
static gboolean summary_find_next_msg(SummaryView *summaryview,
1446 237 hiro
                                      GtkTreeIter *next, GtkTreeIter *iter)
1447 1 hiro
{
1448 237 hiro
        GtkTreeIter iter_;
1449 1 hiro
        MsgInfo *msginfo;
1450 237 hiro
        gboolean valid = TRUE;
1451 1 hiro
1452 237 hiro
        if (!iter)
1453 237 hiro
                return FALSE;
1454 1 hiro
1455 237 hiro
        iter_ = *iter;
1456 237 hiro
1457 237 hiro
        while (valid) {
1458 237 hiro
                GET_MSG_INFO(msginfo, &iter_);
1459 1 hiro
                if (msginfo && !MSG_IS_INVALID(msginfo->flags) &&
1460 237 hiro
                    !MSG_IS_DELETED(msginfo->flags)) {
1461 237 hiro
                        *next = iter_;
1462 237 hiro
                        return TRUE;
1463 237 hiro
                }
1464 237 hiro
                valid = gtkut_tree_model_next
1465 237 hiro
                        (GTK_TREE_MODEL(summaryview->store), &iter_);
1466 1 hiro
        }
1467 1 hiro
1468 237 hiro
        return FALSE;
1469 1 hiro
}
1470 1 hiro
1471 265 hiro
static gboolean summary_find_nearest_msg(SummaryView *summaryview,
1472 265 hiro
                                         GtkTreeIter *target, GtkTreeIter *iter)
1473 265 hiro
{
1474 265 hiro
        gboolean valid;
1475 265 hiro
1476 265 hiro
        valid = summary_find_next_msg(summaryview, target, iter);
1477 265 hiro
        if (!valid)
1478 265 hiro
                valid = summary_find_prev_msg(summaryview, target, iter);
1479 265 hiro
1480 265 hiro
        return valid;
1481 265 hiro
}
1482 265 hiro
1483 237 hiro
static gboolean summary_find_prev_flagged_msg(SummaryView *summaryview,
1484 237 hiro
                                              GtkTreeIter *prev,
1485 237 hiro
                                              GtkTreeIter *iter,
1486 237 hiro
                                              MsgPermFlags flags,
1487 237 hiro
                                              gboolean start_from_prev)
1488 1 hiro
{
1489 237 hiro
        GtkTreeModel *model = GTK_TREE_MODEL(summaryview->store);
1490 237 hiro
        GtkTreeIter iter_;
1491 1 hiro
        MsgInfo *msginfo;
1492 237 hiro
        gboolean valid = TRUE;
1493 1 hiro
1494 237 hiro
        if (iter) {
1495 237 hiro
                iter_ = *iter;
1496 1 hiro
                if (start_from_prev)
1497 237 hiro
                        valid = gtkut_tree_model_prev(model, &iter_);
1498 1 hiro
        } else
1499 237 hiro
                valid = gtkut_tree_model_get_iter_last(model, &iter_);
1500 1 hiro
1501 237 hiro
        for (; valid == TRUE; valid = gtkut_tree_model_prev(model, &iter_)) {
1502 237 hiro
                GET_MSG_INFO(msginfo, &iter_);
1503 237 hiro
                if (msginfo && (msginfo->flags.perm_flags & flags) != 0) {
1504 237 hiro
                        *prev = iter_;
1505 237 hiro
                        return TRUE;
1506 237 hiro
                }
1507 1 hiro
        }
1508 1 hiro
1509 237 hiro
        return FALSE;
1510 1 hiro
}
1511 1 hiro
1512 237 hiro
static gboolean summary_find_next_flagged_msg(SummaryView *summaryview,
1513 237 hiro
                                              GtkTreeIter *next,
1514 237 hiro
                                              GtkTreeIter *iter,
1515 237 hiro
                                              MsgPermFlags flags,
1516 237 hiro
                                              gboolean start_from_next)
1517 1 hiro
{
1518 237 hiro
        GtkTreeModel *model = GTK_TREE_MODEL(summaryview->store);
1519 237 hiro
        GtkTreeIter iter_;
1520 1 hiro
        MsgInfo *msginfo;
1521 237 hiro
        gboolean valid = TRUE;
1522 1 hiro
1523 237 hiro
        if (iter) {
1524 237 hiro
                iter_ = *iter;
1525 1 hiro
                if (start_from_next)
1526 237 hiro
                        valid = gtkut_tree_model_next(model, &iter_);
1527 1 hiro
        } else
1528 237 hiro
                valid = gtk_tree_model_get_iter_first(model, &iter_);
1529 1 hiro
1530 237 hiro
        for (; valid == TRUE; valid = gtkut_tree_model_next(model, &iter_)) {
1531 237 hiro
                GET_MSG_INFO(msginfo, &iter_);
1532 237 hiro
                if (msginfo && (msginfo->flags.perm_flags & flags) != 0) {
1533 237 hiro
                        *next = iter_;
1534 237 hiro
                        return TRUE;
1535 237 hiro
                }
1536 1 hiro
        }
1537 1 hiro
1538 237 hiro
        return FALSE;
1539 1 hiro
}
1540 1 hiro
1541 237 hiro
static gboolean summary_find_msg_by_msgnum(SummaryView *summaryview,
1542 237 hiro
                                           guint msgnum, GtkTreeIter *found)
1543 1 hiro
{
1544 237 hiro
        GtkTreeModel *model = GTK_TREE_MODEL(summaryview->store);
1545 237 hiro
        GtkTreeIter iter;
1546 1 hiro
        MsgInfo *msginfo;
1547 237 hiro
        gboolean valid;
1548 1 hiro
1549 237 hiro
        for (valid = gtk_tree_model_get_iter_first(model, &iter);
1550 237 hiro
             valid == TRUE; valid = gtkut_tree_model_next(model, &iter)) {
1551 237 hiro
                gtk_tree_model_get(model, &iter, S_COL_MSG_INFO, &msginfo, -1);
1552 237 hiro
                if (msginfo && msginfo->msgnum == msgnum) {
1553 237 hiro
                        *found = iter;
1554 237 hiro
                        return TRUE;
1555 237 hiro
                }
1556 1 hiro
        }
1557 1 hiro
1558 237 hiro
        return FALSE;
1559 1 hiro
}
1560 1 hiro
1561 1 hiro
static guint attract_hash_func(gconstpointer key)
1562 1 hiro
{
1563 1 hiro
        gchar *str;
1564 1 hiro
        gchar *p;
1565 1 hiro
        guint h;
1566 1 hiro
1567 1 hiro
        Xstrdup_a(str, (const gchar *)key, return 0);
1568 1 hiro
        trim_subject_for_compare(str);
1569 1 hiro
1570 1 hiro
        p = str;
1571 1 hiro
        h = *p;
1572 1 hiro
1573 1 hiro
        if (h) {
1574 1 hiro
                for (p += 1; *p != '\0'; p++)
1575 1 hiro
                        h = (h << 5) - h + *p;
1576 1 hiro
        }
1577 1 hiro
1578 1 hiro
        return h;
1579 1 hiro
}
1580 1 hiro
1581 1 hiro
static gint attract_compare_func(gconstpointer a, gconstpointer b)
1582 1 hiro
{
1583 1 hiro
        return subject_compare((const gchar *)a, (const gchar *)b) == 0;
1584 1 hiro
}
1585 1 hiro
1586 1 hiro
void summary_attract_by_subject(SummaryView *summaryview)
1587 1 hiro
{
1588 237 hiro
        GtkTreeModel *model = GTK_TREE_MODEL(summaryview->store);
1589 247 hiro
        GtkTreeIter iter;
1590 247 hiro
        MsgInfo *msginfo, *dest_msginfo;
1591 247 hiro
        GHashTable *subject_table, *order_table;
1592 247 hiro
        GSList *mlist = NULL, *list, *dest, *last = NULL, *next = NULL;
1593 237 hiro
        gboolean valid;
1594 247 hiro
        gint count, i;
1595 247 hiro
        gint *new_order;
1596 1 hiro
1597 297 hiro
        if (!summaryview->folder_item)
1598 248 hiro
                return;
1599 297 hiro
        if (summaryview->folder_item->sort_key != SORT_BY_NONE)
1600 297 hiro
                return;
1601 248 hiro
1602 247 hiro
        valid = gtk_tree_model_get_iter_first(model, &iter);
1603 247 hiro
        if (!valid)
1604 247 hiro
                return;
1605 247 hiro
1606 237 hiro
        debug_print("Attracting messages by subject...");
1607 1 hiro
        STATUSBAR_PUSH(summaryview->mainwin,
1608 1 hiro
                       _("Attracting messages by subject..."));
1609 1 hiro
1610 1 hiro
        main_window_cursor_wait(summaryview->mainwin);
1611 1 hiro
1612 247 hiro
        order_table = g_hash_table_new(NULL, NULL);
1613 1 hiro
1614 247 hiro
        for (count = 1; valid == TRUE; ++count) {
1615 247 hiro
                gtk_tree_model_get(model, &iter, S_COL_MSG_INFO, &msginfo, -1);
1616 247 hiro
                g_hash_table_insert(order_table, msginfo,
1617 247 hiro
                                    GINT_TO_POINTER(count));
1618 247 hiro
                mlist = g_slist_prepend(mlist, msginfo);
1619 247 hiro
                valid = gtk_tree_model_iter_next(model, &iter);
1620 247 hiro
        }
1621 247 hiro
        --count;
1622 237 hiro
1623 247 hiro
        mlist = g_slist_reverse(mlist);
1624 1 hiro
1625 247 hiro
        subject_table = g_hash_table_new(attract_hash_func,
1626 247 hiro
                                         attract_compare_func);
1627 247 hiro
1628 247 hiro
        for (list = mlist; list != NULL; list = next) {
1629 247 hiro
                msginfo = (MsgInfo *)list->data;
1630 247 hiro
1631 247 hiro
                next = list->next;
1632 247 hiro
1633 247 hiro
                if (!msginfo->subject) {
1634 247 hiro
                        last = list;
1635 247 hiro
                        continue;
1636 247 hiro
                }
1637 247 hiro
1638 1 hiro
                /* find attracting node */
1639 247 hiro
                dest = g_hash_table_lookup(subject_table, msginfo->subject);
1640 1 hiro
1641 247 hiro
                if (dest) {
1642 247 hiro
                        dest_msginfo = (MsgInfo *)dest->data;
1643 1 hiro
1644 247 hiro
                        /* if the time difference is more than 30 days,
1645 1 hiro
                           don't attract */
1646 247 hiro
                        if (ABS(msginfo->date_t - dest_msginfo->date_t)
1647 247 hiro
                            > 60 * 60 * 24 * 30) {
1648 247 hiro
                                last = list;
1649 1 hiro
                                continue;
1650 247 hiro
                        }
1651 1 hiro
1652 247 hiro
                        if (dest->next != list) {
1653 247 hiro
                                last->next = list->next;
1654 247 hiro
                                list->next = dest->next;
1655 247 hiro
                                dest->next = list;
1656 247 hiro
                        } else
1657 247 hiro
                                last = list;
1658 247 hiro
                } else
1659 247 hiro
                        last = list;
1660 1 hiro
1661 247 hiro
                g_hash_table_replace(subject_table, msginfo->subject, list);
1662 1 hiro
        }
1663 1 hiro
1664 1 hiro
        g_hash_table_destroy(subject_table);
1665 1 hiro
1666 247 hiro
        new_order = g_new(gint, count);
1667 247 hiro
        for (list = mlist, i = 0; list != NULL; list = list->next, ++i) {
1668 247 hiro
                gint old_pos;
1669 247 hiro
1670 247 hiro
                msginfo = (MsgInfo *)list->data;
1671 247 hiro
1672 247 hiro
                old_pos = GPOINTER_TO_INT
1673 247 hiro
                        (g_hash_table_lookup(order_table, msginfo));
1674 247 hiro
                new_order[i] = old_pos - 1;
1675 247 hiro
        }
1676 247 hiro
        gtk_tree_store_reorder(GTK_TREE_STORE(model), NULL, new_order);
1677 247 hiro
        g_free(new_order);
1678 247 hiro
1679 247 hiro
        g_slist_free(mlist);
1680 247 hiro
        g_hash_table_destroy(order_table);
1681 247 hiro
1682 297 hiro
        summaryview->folder_item->cache_dirty = TRUE;
1683 314 hiro
        summary_selection_list_free(summaryview);
1684 297 hiro
1685 322 hiro
        summary_scroll_to_selected(summaryview, TRUE);
1686 1 hiro
1687 237 hiro
        debug_print("done.\n");
1688 1 hiro
        STATUSBAR_POP(summaryview->mainwin);
1689 1 hiro
1690 1 hiro
        main_window_cursor_normal(summaryview->mainwin);
1691 1 hiro
}
1692 1 hiro
1693 1 hiro
static void summary_update_status(SummaryView *summaryview)
1694 1 hiro
{
1695 237 hiro
        GtkTreeModel *model = GTK_TREE_MODEL(summaryview->store);
1696 237 hiro
        GtkTreeIter iter;
1697 237 hiro
        gboolean valid;
1698 1 hiro
        MsgInfo *msginfo;
1699 742 hiro
        gint64 total_size = 0;
1700 297 hiro
        gint deleted = 0, moved = 0, copied = 0;
1701 1 hiro
1702 237 hiro
        valid = gtk_tree_model_get_iter_first(model, &iter);
1703 1 hiro
1704 237 hiro
        while (valid) {
1705 237 hiro
                gtk_tree_model_get(model, &iter, S_COL_MSG_INFO, &msginfo, -1);
1706 237 hiro
1707 1 hiro
                if (MSG_IS_DELETED(msginfo->flags))
1708 297 hiro
                        deleted++;
1709 1 hiro
                if (MSG_IS_MOVE(msginfo->flags))
1710 297 hiro
                        moved++;
1711 1 hiro
                if (MSG_IS_COPY(msginfo->flags))
1712 297 hiro
                        copied++;
1713 297 hiro
                total_size += msginfo->size;
1714 237 hiro
1715 237 hiro
                valid = gtkut_tree_model_next(model, &iter);
1716 1 hiro
        }
1717 297 hiro
1718 297 hiro
        summaryview->total_size = total_size;
1719 297 hiro
        summaryview->deleted = deleted;
1720 297 hiro
        summaryview->moved = moved;
1721 297 hiro
        summaryview->copied = copied;
1722 1 hiro
}
1723 1 hiro
1724 1 hiro
static void summary_status_show(SummaryView *summaryview)
1725 1 hiro
{
1726 237 hiro
        GtkTreeModel *model = GTK_TREE_MODEL(summaryview->store);
1727 1 hiro
        gchar *str;
1728 1 hiro
        gchar *del, *mv, *cp;
1729 1 hiro
        gchar *sel;
1730 1 hiro
        gchar *spc;
1731 1 hiro
        GList *rowlist, *cur;
1732 1 hiro
        guint n_selected = 0;
1733 876 hiro
        gint64 sel_size = 0;
1734 1 hiro
        MsgInfo *msginfo;
1735 1 hiro
1736 1 hiro
        if (!summaryview->folder_item) {
1737 1 hiro
                gtk_label_set(GTK_LABEL(summaryview->statlabel_folder), "");
1738 1 hiro
                gtk_label_set(GTK_LABEL(summaryview->statlabel_select), "");
1739 1 hiro
                gtk_label_set(GTK_LABEL(summaryview->statlabel_msgs),   "");
1740 1 hiro
                return;
1741 1 hiro
        }
1742 1 hiro
1743 297 hiro
        rowlist = summary_get_selected_rows(summaryview);
1744 1 hiro
        for (cur = rowlist; cur != NULL; cur = cur->next) {
1745 237 hiro
                GtkTreeIter iter;
1746 237 hiro
                GtkTreePath *path = (GtkTreePath *)cur->data;
1747 237 hiro
1748 237 hiro
                gtk_tree_model_get_iter(model, &iter, path);
1749 237 hiro
                gtk_tree_model_get(model, &iter, S_COL_MSG_INFO, &msginfo, -1);
1750 297 hiro
                sel_size += msginfo->size;
1751 297 hiro
                n_selected++;
1752 1 hiro
        }
1753 1 hiro
1754 1 hiro
        if (FOLDER_TYPE(summaryview->folder_item->folder) == F_NEWS) {
1755 1 hiro
                gchar *group;
1756 1 hiro
                group = get_abbrev_newsgroup_name
1757 1 hiro
                        (g_basename(summaryview->folder_item->path),
1758 1 hiro
                         prefs_common.ng_abbrev_len);
1759 1 hiro
                str = trim_string_before(group, 32);
1760 1 hiro
                g_free(group);
1761 1 hiro
        } else
1762 1 hiro
                str = trim_string_before(summaryview->folder_item->path, 32);
1763 1 hiro
        gtk_label_set(GTK_LABEL(summaryview->statlabel_folder), str);
1764 1 hiro
        g_free(str);
1765 1 hiro
1766 1 hiro
        if (summaryview->deleted)
1767 1 hiro
                del = g_strdup_printf(_("%d deleted"), summaryview->deleted);
1768 1 hiro
        else
1769 1 hiro
                del = g_strdup("");
1770 1 hiro
        if (summaryview->moved)
1771 1 hiro
                mv = g_strdup_printf(_("%s%d moved"),
1772 1 hiro
                                     summaryview->deleted ? _(", ") : "",
1773 1 hiro
                                     summaryview->moved);
1774 1 hiro
        else
1775 1 hiro
                mv = g_strdup("");
1776 1 hiro
        if (summaryview->copied)
1777 1 hiro
                cp = g_strdup_printf(_("%s%d copied"),
1778 1 hiro
                                     summaryview->deleted ||
1779 1 hiro
                                     summaryview->moved ? _(", ") : "",
1780 1 hiro
                                     summaryview->copied);
1781 1 hiro
        else
1782 1 hiro
                cp = g_strdup("");
1783 1 hiro
1784 1 hiro
        if (summaryview->deleted || summaryview->moved || summaryview->copied)
1785 1 hiro
                spc = "    ";
1786 1 hiro
        else
1787 1 hiro
                spc = "";
1788 1 hiro
1789 1 hiro
        if (n_selected)
1790 1 hiro
                sel = g_strdup_printf(" (%s)", to_human_readable(sel_size));
1791 1 hiro
        else
1792 1 hiro
                sel = g_strdup("");
1793 1 hiro
        str = g_strconcat(n_selected ? itos(n_selected) : "",
1794 1 hiro
                          n_selected ? _(" item(s) selected") : "",
1795 1 hiro
                          sel, spc, del, mv, cp, NULL);
1796 1 hiro
        gtk_label_set(GTK_LABEL(summaryview->statlabel_select), str);
1797 1 hiro
        g_free(str);
1798 1 hiro
        g_free(sel);
1799 1 hiro
        g_free(del);
1800 1 hiro
        g_free(mv);
1801 1 hiro
        g_free(cp);
1802 1 hiro
1803 1 hiro
        if (FOLDER_IS_LOCAL(summaryview->folder_item->folder)) {
1804 1 hiro
                str = g_strdup_printf(_("%d new, %d unread, %d total (%s)"),
1805 1 hiro
                                      summaryview->folder_item->new,
1806 1 hiro
                                      summaryview->folder_item->unread,
1807 1 hiro
                                      summaryview->folder_item->total,
1808 1 hiro
                                      to_human_readable(summaryview->total_size));
1809 1 hiro
        } else {
1810 1 hiro
                str = g_strdup_printf(_("%d new, %d unread, %d total"),
1811 1 hiro
                                      summaryview->folder_item->new,
1812 1 hiro
                                      summaryview->folder_item->unread,
1813 1 hiro
                                      summaryview->folder_item->total);
1814 1 hiro
        }
1815 1 hiro
        gtk_label_set(GTK_LABEL(summaryview->statlabel_msgs), str);
1816 1 hiro
        g_free(str);
1817 1 hiro
1818 202 hiro
        folderview_update_opened_msg_num(summaryview->folderview);
1819 1 hiro
}
1820 1 hiro
1821 1 hiro
void summary_sort(SummaryView *summaryview,
1822 1 hiro
                  FolderSortKey sort_key, FolderSortType sort_type)
1823 1 hiro
{
1824 1 hiro
        FolderItem *item = summaryview->folder_item;
1825 237 hiro
        GtkTreeSortable *sortable = GTK_TREE_SORTABLE(summaryview->store);
1826 237 hiro
        SummaryColumnType col_type;
1827 1 hiro
1828 237 hiro
        g_return_if_fail(sort_key >= SORT_BY_NONE && sort_key <= SORT_BY_TO);
1829 237 hiro
1830 1 hiro
        if (!item || !item->path || !item->parent || item->no_select) return;
1831 1 hiro
1832 297 hiro
        if (item->sort_key != sort_key || item->sort_type != sort_type)
1833 297 hiro
                item->cache_dirty = TRUE;
1834 297 hiro
1835 237 hiro
        col_type = sort_key_to_col[sort_key];
1836 237 hiro
1837 237 hiro
        if (col_type == -1) {
1838 237 hiro
                item->sort_key = SORT_BY_NONE;
1839 1 hiro
                item->sort_type = SORT_ASCENDING;
1840 239 hiro
                gtkut_tree_sortable_unset_sort_column_id(sortable);
1841 1 hiro
                summary_set_menu_sensitive(summaryview);
1842 1 hiro
                return;
1843 1 hiro
        }
1844 1 hiro
1845 237 hiro
        debug_print("Sorting summary by key: %d...\n", sort_key);
1846 1 hiro
        STATUSBAR_PUSH(summaryview->mainwin, _("Sorting summary..."));
1847 1 hiro
1848 1 hiro
        main_window_cursor_wait(summaryview->mainwin);
1849 1 hiro
1850 1 hiro
        item->sort_key = sort_key;
1851 1 hiro
        item->sort_type = sort_type;
1852 1 hiro
1853 237 hiro
        gtk_tree_sortable_set_sort_column_id(sortable, col_type,
1854 237 hiro
                                             (GtkSortType)sort_type);
1855 237 hiro
1856 314 hiro
        summary_selection_list_free(summaryview);
1857 1 hiro
        summary_set_menu_sensitive(summaryview);
1858 1 hiro
1859 322 hiro
        summary_scroll_to_selected(summaryview, TRUE);
1860 322 hiro
1861 237 hiro
        debug_print("done.\n");
1862 1 hiro
        STATUSBAR_POP(summaryview->mainwin);
1863 1 hiro
1864 1 hiro
        main_window_cursor_normal(summaryview->mainwin);
1865 1 hiro
}
1866 1 hiro
1867 245 hiro
static gboolean summary_have_unread_children(SummaryView *summaryview,
1868 245 hiro
                                             GtkTreeIter *iter)
1869 245 hiro
{
1870 245 hiro
        GtkTreeModel *model = GTK_TREE_MODEL(summaryview->store);
1871 245 hiro
        GtkTreeIter iter_;
1872 245 hiro
        MsgInfo *msginfo;
1873 245 hiro
        gboolean valid;
1874 245 hiro
1875 245 hiro
        gtk_tree_model_get(model, iter, S_COL_MSG_INFO, &msginfo, -1);
1876 245 hiro
        if (MSG_IS_UNREAD(msginfo->flags))
1877 245 hiro
                return TRUE;
1878 245 hiro
1879 245 hiro
        valid = gtk_tree_model_iter_children(model, &iter_, iter);
1880 245 hiro
1881 245 hiro
        while (valid) {
1882 245 hiro
                if (summary_have_unread_children(summaryview, &iter_))
1883 245 hiro
                        return TRUE;
1884 245 hiro
1885 245 hiro
                valid = gtk_tree_model_iter_next(model, &iter_);
1886 245 hiro
        }
1887 245 hiro
1888 245 hiro
        return FALSE;
1889 245 hiro
}
1890 245 hiro
1891 237 hiro
static void summary_set_row(SummaryView *summaryview, GtkTreeIter *iter,
1892 237 hiro
                            MsgInfo *msginfo)
1893 1 hiro
{
1894 237 hiro
        GtkTreeStore *store = GTK_TREE_STORE(summaryview->store);
1895 237 hiro
        gchar date_modified[80];
1896 237 hiro
        const gchar *date_s;
1897 237 hiro
        gchar *sw_from_s = NULL;
1898 237 hiro
        gchar *subject_s = NULL;
1899 237 hiro
        GdkPixbuf *mark_pix = NULL;
1900 237 hiro
        GdkPixbuf *unread_pix = NULL;
1901 237 hiro
        GdkPixbuf *mime_pix = NULL;
1902 237 hiro
        GdkColor *foreground = NULL;
1903 237 hiro
        gboolean use_bold = FALSE;
1904 237 hiro
        MsgFlags flags;
1905 237 hiro
        GdkColor color;
1906 237 hiro
        gint color_val;
1907 1 hiro
1908 237 hiro
        if (!msginfo) {
1909 237 hiro
                GET_MSG_INFO(msginfo, iter);
1910 237 hiro
        }
1911 1 hiro
1912 237 hiro
        if (msginfo->date_t) {
1913 237 hiro
                procheader_date_get_localtime(date_modified,
1914 237 hiro
                                              sizeof(date_modified),
1915 237 hiro
                                              msginfo->date_t);
1916 237 hiro
                date_s = date_modified;
1917 237 hiro
        } else if (msginfo->date)
1918 237 hiro
                date_s = msginfo->date;
1919 237 hiro
        else
1920 237 hiro
                date_s = _("(No Date)");
1921 845 hiro
        if (prefs_common.swap_from && msginfo->from && msginfo->to) {
1922 237 hiro
                gchar *from;
1923 1 hiro
1924 237 hiro
                Xstrdup_a(from, msginfo->from, return);
1925 237 hiro
                extract_address(from);
1926 845 hiro
                if (account_address_exist(from))
1927 237 hiro
                        sw_from_s = g_strconcat("-->", msginfo->to, NULL);
1928 237 hiro
        }
1929 1 hiro
1930 237 hiro
        if (msginfo->subject) {
1931 237 hiro
                if (msginfo->folder && msginfo->folder->trim_summary_subject) {
1932 237 hiro
                        subject_s = g_strdup(msginfo->subject);
1933 237 hiro
                        trim_subject(subject_s);
1934 237 hiro
                }
1935 237 hiro
        }
1936 1 hiro
1937 237 hiro
        flags = msginfo->flags;
1938 1 hiro
1939 237 hiro
        /* set flag pixbufs */
1940 237 hiro
        if (MSG_IS_DELETED(flags)) {
1941 237 hiro
                mark_pix = deleted_pixbuf;
1942 237 hiro
                foreground = &summaryview->color_dim;
1943 237 hiro
        } else if (MSG_IS_MOVE(flags)) {
1944 253 hiro
                /* mark_pix = move_pixbuf; */
1945 237 hiro
                foreground = &summaryview->color_marked;
1946 237 hiro
        } else if (MSG_IS_COPY(flags)) {
1947 253 hiro
                /* mark_pix = copy_pixbuf; */
1948 237 hiro
                foreground = &summaryview->color_marked;
1949 237 hiro
        } else if (MSG_IS_MARKED(flags))
1950 237 hiro
                mark_pix = mark_pixbuf;
1951 1 hiro
1952 237 hiro
        if (MSG_IS_NEW(flags))
1953 237 hiro
                unread_pix = new_pixbuf;
1954 237 hiro
        else if (MSG_IS_UNREAD(flags))
1955 237 hiro
                unread_pix = unread_pixbuf;
1956 237 hiro
        else if (MSG_IS_REPLIED(flags))
1957 237 hiro
                unread_pix = replied_pixbuf;
1958 237 hiro
        else if (MSG_IS_FORWARDED(flags))
1959 237 hiro
                unread_pix = forwarded_pixbuf;
1960 237 hiro
1961 237 hiro
        if (MSG_IS_MIME(flags))
1962 237 hiro
                mime_pix = clip_pixbuf;
1963 237 hiro
1964 237 hiro
        if (prefs_common.bold_unread && MSG_IS_UNREAD(flags))
1965 237 hiro
                use_bold = TRUE;
1966 237 hiro
1967 237 hiro
        color_val = MSG_GET_COLORLABEL_VALUE(flags);
1968 237 hiro
        if (color_val != 0) {
1969 237 hiro
                color = colorlabel_get_color(color_val - 1);
1970 237 hiro
                foreground = &color;
1971 237 hiro
        }
1972 237 hiro
1973 237 hiro
        gtk_tree_store_set(store, iter,
1974 237 hiro
                           S_COL_MARK, mark_pix,
1975 237 hiro
                           S_COL_UNREAD, unread_pix,
1976 237 hiro
                           S_COL_MIME, mime_pix,
1977 237 hiro
                           S_COL_SUBJECT, subject_s ? subject_s :
1978 237 hiro
                                             msginfo->subject ? msginfo->subject :
1979 237 hiro
                                          _("(No Subject)"),
1980 237 hiro
                           S_COL_FROM, sw_from_s ? sw_from_s :
1981 237 hiro
                                          msginfo->fromname ? msginfo->fromname :
1982 237 hiro
                                       _("(No From)"),
1983 237 hiro
                           S_COL_DATE, date_s,
1984 237 hiro
                           S_COL_SIZE, to_human_readable(msginfo->size),
1985 237 hiro
                           S_COL_NUMBER, msginfo->msgnum,
1986 237 hiro
1987 237 hiro
                           S_COL_MSG_INFO, msginfo,
1988 237 hiro
1989 237 hiro
                           S_COL_LABEL, color_val,
1990 237 hiro
                           S_COL_TO, NULL,
1991 237 hiro
1992 237 hiro
                           S_COL_FOREGROUND, foreground,
1993 237 hiro
                           S_COL_BOLD, use_bold,
1994 237 hiro
                           -1);
1995 844 hiro
1996 844 hiro
        if (subject_s)
1997 844 hiro
                g_free(subject_s);
1998 844 hiro
        if (sw_from_s)
1999 844 hiro
                g_free(sw_from_s);
2000 1 hiro
}
2001 1 hiro
2002 237 hiro
static void summary_insert_gnode(SummaryView *summaryview, GtkTreeStore *store,
2003 237 hiro
                                 GtkTreeIter *iter, GtkTreeIter *parent,
2004 237 hiro
                                 GtkTreeIter *sibling, GNode *gnode)
2005 1 hiro
{
2006 237 hiro
        MsgInfo *msginfo = (MsgInfo *)gnode->data;
2007 237 hiro
2008 237 hiro
        if (parent && !sibling)
2009 237 hiro
                gtk_tree_store_append(store, iter, parent);
2010 237 hiro
        else
2011 237 hiro
                gtk_tree_store_insert_after(store, iter, parent, sibling);
2012 237 hiro
2013 237 hiro
        summary_set_row(summaryview, iter, msginfo);
2014 237 hiro
2015 574 hiro
        if (!parent) {
2016 574 hiro
                guint tdate;
2017 574 hiro
2018 574 hiro
                tdate = procmsg_get_thread_date(gnode);
2019 574 hiro
                gtk_tree_store_set(store, iter, S_COL_TDATE, tdate, -1);
2020 574 hiro
        }
2021 574 hiro
2022 237 hiro
        for (gnode = gnode->children; gnode != NULL; gnode = gnode->next) {
2023 237 hiro
                GtkTreeIter child;
2024 237 hiro
2025 237 hiro
                summary_insert_gnode(summaryview, store, &child, iter, NULL,
2026 237 hiro
                                     gnode);
2027 237 hiro
        }
2028 237 hiro
}
2029 237 hiro
2030 331 hiro
static void summary_insert_gnode_before(SummaryView *summaryview,
2031 331 hiro
                                        GtkTreeStore *store,
2032 331 hiro
                                        GtkTreeIter *iter, GtkTreeIter *parent,
2033 331 hiro
                                        GtkTreeIter *sibling, GNode *gnode)
2034 331 hiro
{
2035 331 hiro
        MsgInfo *msginfo = (MsgInfo *)gnode->data;
2036 331 hiro
2037 331 hiro
        gtk_tree_store_insert_before(store, iter, parent, sibling);
2038 331 hiro
2039 331 hiro
        summary_set_row(summaryview, iter, msginfo);
2040 331 hiro
2041 574 hiro
        if (!parent) {
2042 574 hiro
                guint tdate;
2043 574 hiro
2044 574 hiro
                tdate = procmsg_get_thread_date(gnode);
2045 574 hiro
                gtk_tree_store_set(store, iter, S_COL_TDATE, tdate, -1);
2046 574 hiro
        }
2047 574 hiro
2048 331 hiro
        for (gnode = gnode->children; gnode != NULL; gnode = gnode->next) {
2049 331 hiro
                GtkTreeIter child;
2050 331 hiro
2051 331 hiro
                summary_insert_gnode_before(summaryview, store, &child, iter,
2052 331 hiro
                                            NULL, gnode);
2053 331 hiro
        }
2054 331 hiro
}
2055 331 hiro
2056 237 hiro
static void summary_set_tree_model_from_list(SummaryView *summaryview,
2057 237 hiro
                                             GSList *mlist)
2058 237 hiro
{
2059 237 hiro
        GtkTreeStore *store = GTK_TREE_STORE(summaryview->store);
2060 237 hiro
        GtkTreeIter iter;
2061 1 hiro
        MsgInfo *msginfo;
2062 237 hiro
        GSList *cur;
2063 1 hiro
2064 1 hiro
        if (!mlist) return;
2065 1 hiro
2066 1 hiro
        debug_print(_("\tSetting summary from message data..."));
2067 1 hiro
        STATUSBAR_PUSH(summaryview->mainwin,
2068 1 hiro
                       _("Setting summary from message data..."));
2069 1 hiro
        gdk_flush();
2070 1 hiro
2071 237 hiro
        /* temporarily remove the model for speed up */
2072 237 hiro
        gtk_tree_view_set_model(GTK_TREE_VIEW(summaryview->treeview), NULL);
2073 237 hiro
2074 1 hiro
        if (summaryview->folder_item->threaded) {
2075 1 hiro
                GNode *root, *gnode;
2076 1 hiro
2077 1 hiro
                root = procmsg_get_thread_tree(mlist);
2078 1 hiro
2079 1 hiro
                for (gnode = root->children; gnode != NULL;
2080 1 hiro
                     gnode = gnode->next) {
2081 237 hiro
                        summary_insert_gnode
2082 237 hiro
                                (summaryview, store, &iter, NULL, NULL, gnode);
2083 246 hiro
                        if (gnode->children && !prefs_common.expand_thread &&
2084 246 hiro
                            prefs_common.bold_unread &&
2085 246 hiro
                            summary_have_unread_children(summaryview, &iter)) {
2086 246 hiro
                                gtk_tree_store_set(store, &iter,
2087 246 hiro
                                                   S_COL_BOLD, TRUE, -1);
2088 246 hiro
                        }
2089 1 hiro
                }
2090 1 hiro
2091 1 hiro
                g_node_destroy(root);
2092 1 hiro
2093 237 hiro
                for (cur = mlist; cur != NULL; cur = cur->next) {
2094 237 hiro
                        msginfo = (MsgInfo *)cur->data;
2095 237 hiro
2096 237 hiro
                        if (MSG_IS_DELETED(msginfo->flags))
2097 237 hiro
                                summaryview->deleted++;
2098 237 hiro
                        summaryview->total_size += msginfo->size;
2099 237 hiro
                }
2100 1 hiro
        } else {
2101 237 hiro
                GtkTreeIter iter;
2102 1 hiro
2103 1 hiro
                mlist = g_slist_reverse(mlist);
2104 237 hiro
                for (cur = mlist; cur != NULL; cur = cur->next) {
2105 237 hiro
                        msginfo = (MsgInfo *)cur->data;
2106 1 hiro
2107 237 hiro
                        gtk_tree_store_prepend(store, &iter, NULL);
2108 237 hiro
                        summary_set_row(summaryview, &iter, msginfo);
2109 1 hiro
2110 237 hiro
                        if (MSG_IS_DELETED(msginfo->flags))
2111 237 hiro
                                summaryview->deleted++;
2112 237 hiro
                        summaryview->total_size += msginfo->size;
2113 1 hiro
                }
2114 253 hiro
                /* mlist = g_slist_reverse(mlist); */
2115 1 hiro
        }
2116 1 hiro
2117 237 hiro
        gtk_tree_view_set_model(GTK_TREE_VIEW(summaryview->treeview),
2118 237 hiro
                                GTK_TREE_MODEL(store));
2119 1 hiro
2120 237 hiro
        if (summaryview->folder_item->threaded && prefs_common.expand_thread)
2121 237 hiro
                gtk_tree_view_expand_all
2122 237 hiro
                        (GTK_TREE_VIEW(summaryview->treeview));
2123 237 hiro
2124 237 hiro
        if (summaryview->folder_item->sort_key != SORT_BY_NONE) {
2125 237 hiro
                summary_sort(summaryview, summaryview->folder_item->sort_key,
2126 237 hiro
                             summaryview->folder_item->sort_type);
2127 1 hiro
        }
2128 1 hiro
2129 1 hiro
        debug_print(_("done.\n"));
2130 1 hiro
        STATUSBAR_POP(summaryview->mainwin);
2131 1 hiro
}
2132 1 hiro
2133 1 hiro
struct wcachefp
2134 1 hiro
{
2135 1 hiro
        FILE *cache_fp;
2136 1 hiro
        FILE *mark_fp;
2137 1 hiro
};
2138 1 hiro
2139 237 hiro
static gboolean summary_write_cache_func(GtkTreeModel *model,
2140 237 hiro
                                         GtkTreePath *path, GtkTreeIter *iter,
2141 237 hiro
                                         gpointer data)
2142 237 hiro
{
2143 237 hiro
        struct wcachefp *fps = data;
2144 237 hiro
        MsgInfo *msginfo;
2145 237 hiro
2146 237 hiro
        gtk_tree_model_get(model, iter, S_COL_MSG_INFO, &msginfo, -1);
2147 237 hiro
2148 237 hiro
        if (msginfo->folder->mark_queue != NULL) {
2149 237 hiro
                MSG_UNSET_PERM_FLAGS(msginfo->flags, MSG_NEW);
2150 237 hiro
        }
2151 237 hiro
2152 285 hiro
        if (fps->cache_fp)
2153 285 hiro
                procmsg_write_cache(msginfo, fps->cache_fp);
2154 293 hiro
        if (fps->mark_fp)
2155 293 hiro
                procmsg_write_flags(msginfo, fps->mark_fp);
2156 237 hiro
2157 237 hiro
        return FALSE;
2158 237 hiro
}
2159 237 hiro
2160 1 hiro
gint summary_write_cache(SummaryView *summaryview)
2161 1 hiro
{
2162 1 hiro
        struct wcachefp fps;
2163 1 hiro
        FolderItem *item;
2164 1 hiro
        gchar *buf;
2165 1 hiro
2166 1 hiro
        item = summaryview->folder_item;
2167 1 hiro
        if (!item || !item->path)
2168 1 hiro
                return -1;
2169 293 hiro
        if (item->mark_queue)
2170 293 hiro
                item->mark_dirty = TRUE;
2171 293 hiro
        if (!item->cache_dirty && !item->mark_dirty)
2172 293 hiro
                return 0;
2173 1 hiro
2174 285 hiro
        if (item->cache_dirty) {
2175 285 hiro
                fps.cache_fp = procmsg_open_cache_file(item, DATA_WRITE);
2176 285 hiro
                if (fps.cache_fp == NULL)
2177 285 hiro
                        return -1;
2178 293 hiro
                item->mark_dirty = TRUE;
2179 285 hiro
        } else
2180 285 hiro
                fps.cache_fp = NULL;
2181 1 hiro
2182 850 hiro
        if (item->mark_dirty && item->stype != F_VIRTUAL) {
2183 293 hiro
                fps.mark_fp = procmsg_open_mark_file(item, DATA_WRITE);
2184 293 hiro
                if (fps.mark_fp == NULL) {
2185 293 hiro
                        if (fps.cache_fp)
2186 293 hiro
                                fclose(fps.cache_fp);
2187 293 hiro
                        return -1;
2188 293 hiro
                }
2189 293 hiro
        } else
2190 293 hiro
                fps.mark_fp = NULL;
2191 293 hiro
2192 285 hiro
        if (item->cache_dirty) {
2193 285 hiro
                buf = g_strdup_printf(_("Writing summary cache (%s)..."),
2194 285 hiro
                                      item->path);
2195 285 hiro
                debug_print(buf);
2196 285 hiro
                STATUSBAR_PUSH(summaryview->mainwin, buf);
2197 285 hiro
                gdk_flush();
2198 285 hiro
                g_free(buf);
2199 285 hiro
        }
2200 1 hiro
2201 237 hiro
        gtk_tree_model_foreach(GTK_TREE_MODEL(summaryview->store),
2202 237 hiro
                               summary_write_cache_func, &fps);
2203 1 hiro
2204 293 hiro
        if (item->mark_queue)
2205 293 hiro
                procmsg_flush_mark_queue(item, fps.mark_fp);
2206 293 hiro
2207 1 hiro
        item->unmarked_num = 0;
2208 1 hiro
2209 285 hiro
        if (fps.cache_fp)
2210 285 hiro
                fclose(fps.cache_fp);
2211 293 hiro
        if (fps.mark_fp)
2212 293 hiro
                fclose(fps.mark_fp);
2213 1 hiro
2214 850 hiro
        if (item->stype == F_VIRTUAL) {
2215 850 hiro
                GSList *mlist;
2216 850 hiro
2217 850 hiro
                mlist = summary_get_changed_msg_list(summaryview);
2218 850 hiro
                if (mlist) {
2219 850 hiro
                        procmsg_write_flags_for_multiple_folders(mlist);
2220 850 hiro
                        g_slist_free(mlist);
2221 850 hiro
                        folderview_update_all_updated(FALSE);
2222 850 hiro
                }
2223 850 hiro
        }
2224 850 hiro
2225 1 hiro
        debug_print(_("done.\n"));
2226 1 hiro
2227 285 hiro
        if (item->cache_dirty) {
2228 285 hiro
                STATUSBAR_POP(summaryview->mainwin);
2229 285 hiro
        }
2230 285 hiro
2231 293 hiro
        item->cache_dirty = item->mark_dirty = FALSE;
2232 285 hiro
2233 1 hiro
        return 0;
2234 1 hiro
}
2235 1 hiro
2236 237 hiro
static gboolean summary_row_is_displayed(SummaryView *summaryview,
2237 237 hiro
                                         GtkTreeIter *iter)
2238 1 hiro
{
2239 237 hiro
        GtkTreePath *disp_path, *path;
2240 237 hiro
        gint ret;
2241 1 hiro
2242 237 hiro
        if (!summaryview->displayed || !iter)
2243 237 hiro
                return FALSE;
2244 1 hiro
2245 237 hiro
        disp_path = gtk_tree_row_reference_get_path(summaryview->displayed);
2246 237 hiro
        if (!disp_path)
2247 237 hiro
                return FALSE;
2248 237 hiro
2249 237 hiro
        path = gtk_tree_model_get_path(GTK_TREE_MODEL(summaryview->store),
2250 237 hiro
                                       iter);
2251 237 hiro
        if (!path) {
2252 237 hiro
                gtk_tree_path_free(disp_path);
2253 237 hiro
                return FALSE;
2254 1 hiro
        }
2255 1 hiro
2256 237 hiro
        ret = gtk_tree_path_compare(disp_path, path);
2257 237 hiro
        gtk_tree_path_free(path);
2258 237 hiro
        gtk_tree_path_free(disp_path);
2259 1 hiro
2260 237 hiro
        return (ret == 0);
2261 1 hiro
}
2262 1 hiro
2263 237 hiro
static void summary_display_msg(SummaryView *summaryview, GtkTreeIter *iter)
2264 1 hiro
{
2265 237 hiro
        summary_display_msg_full(summaryview, iter, FALSE, FALSE, FALSE);
2266 1 hiro
}
2267 1 hiro
2268 1 hiro
static void summary_display_msg_full(SummaryView *summaryview,
2269 237 hiro
                                     GtkTreeIter *iter,
2270 237 hiro
                                     gboolean new_window, gboolean all_headers,
2271 237 hiro
                                     gboolean redisplay)
2272 1 hiro
{
2273 751 hiro
        GtkTreePath *path;
2274 237 hiro
        MsgInfo *msginfo = NULL;
2275 1 hiro
        gint val;
2276 1 hiro
2277 237 hiro
        g_return_if_fail(iter != NULL);
2278 1 hiro
2279 237 hiro
        if (!new_window && !redisplay &&
2280 237 hiro
            summary_row_is_displayed(summaryview, iter))
2281 237 hiro
                return;
2282 237 hiro
2283 1 hiro
        if (summary_is_locked(summaryview)) return;
2284 1 hiro
        summary_lock(summaryview);
2285 1 hiro
2286 1 hiro
        STATUSBAR_POP(summaryview->mainwin);
2287 1 hiro
2288 237 hiro
        gtk_tree_model_get(GTK_TREE_MODEL(summaryview->store), iter,
2289 237 hiro
                           S_COL_MSG_INFO, &msginfo, -1);
2290 1 hiro
2291 1 hiro
        if (new_window) {
2292 1 hiro
                MessageView *msgview;
2293 1 hiro
2294 1 hiro
                msgview = messageview_create_with_new_window();
2295 1 hiro
                val = messageview_show(msgview, msginfo, all_headers);
2296 1 hiro
        } else {
2297 751 hiro
                MessageView *msgview = summaryview->messageview;
2298 1 hiro
2299 154 hiro
                if (!messageview_is_visible(msgview)) {
2300 1 hiro
                        main_window_toggle_message_view(summaryview->mainwin);
2301 154 hiro
                        GTK_EVENTS_FLUSH();
2302 154 hiro
                }
2303 1 hiro
                val = messageview_show(msgview, msginfo, all_headers);
2304 1 hiro
                if (msgview->type == MVIEW_TEXT ||
2305 1 hiro
                    (msgview->type == MVIEW_MIME &&
2306 275 hiro
                     (msgview->mimeview->opened == NULL ||
2307 1 hiro
                      gtk_notebook_get_current_page
2308 154 hiro
                        (GTK_NOTEBOOK(msgview->notebook)) == 0)))
2309 237 hiro
                        gtk_widget_grab_focus(summaryview->treeview);
2310 1 hiro
        }
2311 1 hiro
2312 1 hiro
        if (val == 0 &&
2313 1 hiro
            (new_window || !prefs_common.mark_as_read_on_new_window)) {
2314 1 hiro
                if (MSG_IS_NEW(msginfo->flags))
2315 1 hiro
                        summaryview->folder_item->new--;
2316 1 hiro
                if (MSG_IS_UNREAD(msginfo->flags))
2317 1 hiro
                        summaryview->folder_item->unread--;
2318 850 hiro
2319 850 hiro
                if (summaryview->folder_item->stype == F_VIRTUAL) {
2320 850 hiro
                        if (MSG_IS_NEW(msginfo->flags))
2321 850 hiro
                                msginfo->folder->new--;
2322 850 hiro
                        if (MSG_IS_UNREAD(msginfo->flags))
2323 850 hiro
                                msginfo->folder->unread--;
2324 850 hiro
                        folderview_update_item(msginfo->folder, FALSE);
2325 850 hiro
                }
2326 850 hiro
2327 293 hiro
                if (MSG_IS_NEW(msginfo->flags) ||
2328 293 hiro
                    MSG_IS_UNREAD(msginfo->flags)) {
2329 1 hiro
                        MSG_UNSET_PERM_FLAGS
2330 1 hiro
                                (msginfo->flags, MSG_NEW | MSG_UNREAD);
2331 848 hiro
                        MSG_SET_TMP_FLAGS(msginfo->flags, MSG_FLAG_CHANGED);
2332 293 hiro
                        summaryview->folder_item->mark_dirty = TRUE;
2333 1 hiro
                        if (MSG_IS_IMAP(msginfo->flags))
2334 1 hiro
                                imap_msg_unset_perm_flags
2335 1 hiro
                                        (msginfo, MSG_NEW | MSG_UNREAD);
2336 237 hiro
                        summary_set_row(summaryview, iter, msginfo);
2337 1 hiro
                        summary_status_show(summaryview);
2338 1 hiro
                }
2339 1 hiro
        }
2340 1 hiro
2341 751 hiro
        path = gtk_tree_model_get_path
2342 751 hiro
                (GTK_TREE_MODEL(summaryview->store), iter);
2343 751 hiro
        if (!new_window) {
2344 751 hiro
                gtk_tree_row_reference_free(summaryview->displayed);
2345 751 hiro
                summaryview->displayed =
2346 751 hiro
                        gtk_tree_row_reference_new
2347 751 hiro
                                (GTK_TREE_MODEL(summaryview->store), path);
2348 751 hiro
        }
2349 751 hiro
        gtkut_tree_view_scroll_to_cell
2350 751 hiro
                (GTK_TREE_VIEW(summaryview->treeview), path,
2351 751 hiro
                 !summaryview->on_button_press);
2352 751 hiro
        gtk_tree_path_free(path);
2353 751 hiro
2354 751 hiro
        if (summaryview->folder_item->sort_key == SORT_BY_UNREAD)
2355 751 hiro
                summary_selection_list_free(summaryview);
2356 751 hiro
2357 1 hiro
        summary_set_menu_sensitive(summaryview);
2358 1 hiro
        main_window_set_toolbar_sensitive(summaryview->mainwin);
2359 1 hiro
2360 1 hiro
        statusbar_pop_all();
2361 1 hiro
2362 1 hiro
        summary_unlock(summaryview);
2363 1 hiro
}
2364 1 hiro
2365 1 hiro
void summary_display_msg_selected(SummaryView *summaryview,
2366 237 hiro
                                  gboolean new_window, gboolean all_headers)
2367 1 hiro
{
2368 237 hiro
        GtkTreeIter iter;
2369 237 hiro
2370 1 hiro
        if (summary_is_locked(summaryview)) return;
2371 237 hiro
2372 237 hiro
        if (summaryview->selected) {
2373 237 hiro
                if (gtkut_tree_row_reference_get_iter
2374 237 hiro
                        (GTK_TREE_MODEL(summaryview->store),
2375 237 hiro
                         summaryview->selected, &iter)) {
2376 237 hiro
                        summary_display_msg_full(summaryview, &iter,
2377 237 hiro
                                                 new_window, all_headers, TRUE);
2378 237 hiro
                }
2379 237 hiro
        }
2380 1 hiro
}
2381 1 hiro
2382 1 hiro
void summary_redisplay_msg(SummaryView *summaryview)
2383 1 hiro
{
2384 237 hiro
        GtkTreeIter iter;
2385 1 hiro
2386 1 hiro
        if (summaryview->displayed) {
2387 237 hiro
                if (gtkut_tree_row_reference_get_iter
2388 237 hiro
                        (GTK_TREE_MODEL(summaryview->store),
2389 237 hiro
                         summaryview->displayed, &iter)) {
2390 237 hiro
                        summary_display_msg_full(summaryview, &iter,
2391 237 hiro
                                                 FALSE, FALSE, TRUE);
2392 237 hiro
                }
2393 1 hiro
        }
2394 1 hiro
}
2395 1 hiro
2396 1 hiro
void summary_open_msg(SummaryView *summaryview)
2397 1 hiro
{
2398 237 hiro
        summary_display_msg_selected(summaryview, TRUE, FALSE);
2399 1 hiro
}
2400 1 hiro
2401 250 hiro
static void summary_activate_selected(SummaryView *summaryview)
2402 250 hiro
{
2403 250 hiro
        if (!summaryview->folder_item)
2404 250 hiro
                return;
2405 250 hiro
2406 250 hiro
        if (summaryview->folder_item->stype == F_OUTBOX ||
2407 250 hiro
            summaryview->folder_item->stype == F_DRAFT  ||
2408 250 hiro
            summaryview->folder_item->stype == F_QUEUE)
2409 250 hiro
                summary_reedit(summaryview);
2410 250 hiro
        else
2411 250 hiro
                summary_open_msg(summaryview);
2412 250 hiro
2413 250 hiro
        summaryview->display_msg = FALSE;
2414 250 hiro
}
2415 250 hiro
2416 237 hiro
void summary_view_source(SummaryView *summaryview)
2417 1 hiro
{
2418 237 hiro
        GtkTreeIter iter;
2419 1 hiro
        MsgInfo *msginfo;
2420 1 hiro
        SourceWindow *srcwin;
2421 1 hiro
2422 237 hiro
        if (summaryview->selected) {
2423 237 hiro
                if (gtkut_tree_row_reference_get_iter
2424 237 hiro
                        (GTK_TREE_MODEL(summaryview->store),
2425 237 hiro
                         summaryview->selected, &iter)) {
2426 237 hiro
                        GET_MSG_INFO(msginfo, &iter);
2427 1 hiro
2428 237 hiro
                        srcwin = source_window_create();
2429 237 hiro
                        source_window_show_msg(srcwin, msginfo);
2430 237 hiro
                        source_window_show(srcwin);
2431 237 hiro
                }
2432 237 hiro
        }
2433 1 hiro
}
2434 1 hiro
2435 1 hiro
void summary_reedit(SummaryView *summaryview)
2436 1 hiro
{
2437 237 hiro
        GtkTreeIter iter;
2438 1 hiro
        MsgInfo *msginfo;
2439 1 hiro
2440 1 hiro
        if (!summaryview->selected) return;
2441 1 hiro
        if (!summaryview->folder_item) return;
2442 1 hiro
        if (summaryview->folder_item->stype != F_OUTBOX &&
2443 1 hiro
            summaryview->folder_item->stype != F_DRAFT  &&
2444 1 hiro
            summaryview->folder_item->stype != F_QUEUE) return;
2445 1 hiro
2446 237 hiro
        if (gtkut_tree_row_reference_get_iter
2447 237 hiro
                (GTK_TREE_MODEL(summaryview->store),
2448 237 hiro
                 summaryview->selected, &iter)) {
2449 237 hiro
                GET_MSG_INFO(msginfo, &iter);
2450 237 hiro
                compose_reedit(msginfo);
2451 237 hiro
        }
2452 1 hiro
}
2453 1 hiro
2454 135 hiro
gboolean summary_step(SummaryView *summaryview, GtkScrollType type)
2455 1 hiro
{
2456 237 hiro
        GtkTreeModel *model = GTK_TREE_MODEL(summaryview->store);
2457 237 hiro
        GtkTreeIter iter;
2458 1 hiro
2459 135 hiro
        if (summary_is_locked(summaryview)) return FALSE;
2460 1 hiro
2461 277 hiro
        if (!gtkut_tree_row_reference_get_iter
2462 277 hiro
                (model, summaryview->selected, &iter))
2463 277 hiro
                return FALSE;
2464 277 hiro
2465 1 hiro
        if (type == GTK_SCROLL_STEP_FORWARD) {
2466 277 hiro
                if (!gtkut_tree_model_next(model, &iter))
2467 277 hiro
                        return FALSE;
2468 277 hiro
        } else {
2469 277 hiro
                if (!gtkut_tree_model_prev(model, &iter))
2470 277 hiro
                        return FALSE;
2471 1 hiro
        }
2472 1 hiro
2473 277 hiro
        summary_select_row(summaryview, &iter,
2474 277 hiro
                           messageview_is_visible(summaryview->messageview),
2475 277 hiro
                           FALSE);
2476 1 hiro
2477 135 hiro
        return TRUE;
2478 1 hiro
}
2479 1 hiro
2480 1 hiro
void summary_toggle_view(SummaryView *summaryview)
2481 1 hiro
{
2482 1 hiro
        if (!messageview_is_visible(summaryview->messageview) &&
2483 1 hiro
            summaryview->selected)
2484 237 hiro
                summary_display_msg_selected(summaryview, FALSE, FALSE);
2485 1 hiro
        else
2486 1 hiro
                main_window_toggle_message_view(summaryview->mainwin);
2487 1 hiro
}
2488 1 hiro
2489 237 hiro
void summary_update_selected_rows(SummaryView *summaryview)
2490 1 hiro
{
2491 237 hiro
        GList *rows, *cur;
2492 237 hiro
        GtkTreeModel *model = GTK_TREE_MODEL(summaryview->store);
2493 237 hiro
        GtkTreeIter iter;
2494 237 hiro
        GtkTreePath *path;
2495 1 hiro
2496 297 hiro
        rows = summary_get_selected_rows(summaryview);
2497 237 hiro
        for (cur = rows; cur != NULL; cur = cur->next) {
2498 237 hiro
                path = (GtkTreePath *)cur->data;
2499 237 hiro
                gtk_tree_model_get_iter(model, &iter, path);
2500 237 hiro
                summary_set_row(summaryview, &iter, NULL);
2501 1 hiro
        }
2502 1 hiro
}
2503 1 hiro
2504 237 hiro
static void summary_mark_row(SummaryView *summaryview, GtkTreeIter *iter)
2505 1 hiro
{
2506 237 hiro
        MsgInfo *msginfo = NULL;
2507 1 hiro
2508 237 hiro
        GET_MSG_INFO(msginfo, iter);
2509 1 hiro
2510 1 hiro
        msginfo->to_folder = NULL;
2511 848 hiro
        if (MSG_IS_DELETED(msginfo->flags)) {
2512 1 hiro
                summaryview->deleted--;
2513 848 hiro
                MSG_UNSET_PERM_FLAGS(msginfo->flags, MSG_DELETED);
2514 848 hiro
        }
2515 1 hiro
        if (MSG_IS_MOVE(msginfo->flags))
2516 1 hiro
                summaryview->moved--;
2517 1 hiro
        if (MSG_IS_COPY(msginfo->flags))
2518 1 hiro
                summaryview->copied--;
2519 1 hiro
        MSG_UNSET_TMP_FLAGS(msginfo->flags, MSG_MOVE | MSG_COPY);
2520 1 hiro
        MSG_SET_PERM_FLAGS(msginfo->flags, MSG_MARKED);
2521 848 hiro
        MSG_SET_TMP_FLAGS(msginfo->flags, MSG_FLAG_CHANGED);
2522 293 hiro
        summaryview->folder_item->mark_dirty = TRUE;
2523 237 hiro
        summary_set_row(summaryview, iter, msginfo);
2524 237 hiro
2525 1 hiro
        debug_print(_("Message %d is marked\n"), msginfo->msgnum);
2526 1 hiro
}
2527 1 hiro
2528 1 hiro
void summary_mark(SummaryView *summaryview)
2529 1 hiro
{
2530 237 hiro
        GList *rows, *cur;
2531 237 hiro
        GtkTreeModel *model = GTK_TREE_MODEL(summaryview->store);
2532 237 hiro
        GtkTreeIter iter;
2533 751 hiro
        FolderSortKey sort_key = SORT_BY_NONE;
2534 751 hiro
        FolderSortType sort_type = SORT_ASCENDING;
2535 1 hiro
2536 751 hiro
        SORT_BLOCK(SORT_BY_MARK);
2537 751 hiro
2538 297 hiro
        rows = summary_get_selected_rows(summaryview);
2539 237 hiro
        for (cur = rows; cur != NULL; cur = cur->next) {
2540 237 hiro
                GtkTreePath *path = (GtkTreePath *)cur->data;
2541 237 hiro
                gtk_tree_model_get_iter(model, &iter, path);
2542 237 hiro
                summary_mark_row(summaryview, &iter);
2543 237 hiro
        }
2544 237 hiro
2545 1 hiro
        if (FOLDER_TYPE(summaryview->folder_item->folder) == F_IMAP) {
2546 1 hiro
                GSList *msglist;
2547 237 hiro
2548 1 hiro
                msglist = summary_get_selected_msg_list(summaryview);
2549 1 hiro
                imap_msg_list_set_perm_flags(msglist, MSG_MARKED);
2550 1 hiro
                g_slist_free(msglist);
2551 1 hiro
        }
2552 1 hiro
2553 751 hiro
        SORT_UNBLOCK(SORT_BY_MARK);
2554 751 hiro
2555 237 hiro
        summary_status_show(summaryview);
2556 1 hiro
}
2557 1 hiro
2558 1 hiro
static void summary_mark_row_as_read(SummaryView *summaryview,
2559 237 hiro
                                     GtkTreeIter *iter)
2560 1 hiro
{
2561 237 hiro
        MsgInfo *msginfo = NULL;
2562 1 hiro
2563 237 hiro
        GET_MSG_INFO(msginfo, iter);
2564 237 hiro
2565 1 hiro
        if (MSG_IS_NEW(msginfo->flags))
2566 1 hiro
                summaryview->folder_item->new--;
2567 1 hiro
        if (MSG_IS_UNREAD(msginfo->flags))
2568 1 hiro
                summaryview->folder_item->unread--;
2569 850 hiro
2570 850 hiro
        if (summaryview->folder_item->stype == F_VIRTUAL) {
2571 850 hiro
                if (MSG_IS_NEW(msginfo->flags))
2572 850 hiro
                        msginfo->folder->new--;
2573 850 hiro
                if (MSG_IS_UNREAD(msginfo->flags))
2574 850 hiro
                        msginfo->folder->unread--;
2575 850 hiro
                folderview_update_item(msginfo->folder, FALSE);
2576 850 hiro
        }
2577 850 hiro
2578 237 hiro
        if (MSG_IS_NEW(msginfo->flags) || MSG_IS_UNREAD(msginfo->flags)) {
2579 1 hiro
                MSG_UNSET_PERM_FLAGS(msginfo->flags, MSG_NEW | MSG_UNREAD);
2580 848 hiro
                MSG_SET_TMP_FLAGS(msginfo->flags, MSG_FLAG_CHANGED);
2581 293 hiro
                summaryview->folder_item->mark_dirty = TRUE;
2582 237 hiro
                summary_set_row(summaryview, iter, msginfo);
2583 1 hiro
                debug_print(_("Message %d is marked as being read\n"),
2584 1 hiro
                            msginfo->msgnum);
2585 1 hiro
        }
2586 1 hiro
}
2587 1 hiro
2588 1 hiro
void summary_mark_as_read(SummaryView *summaryview)
2589 1 hiro
{
2590 237 hiro
        GList *rows, *cur;
2591 237 hiro
        GtkTreeModel *model = GTK_TREE_MODEL(summaryview->store);
2592 237 hiro
        GtkTreeIter iter;
2593 751 hiro
        FolderSortKey sort_key = SORT_BY_NONE;
2594 751 hiro
        FolderSortType sort_type = SORT_ASCENDING;
2595 1 hiro
2596 751 hiro
        SORT_BLOCK(SORT_BY_UNREAD);
2597 751 hiro
2598 297 hiro
        rows = summary_get_selected_rows(summaryview);
2599 237 hiro
2600 237 hiro
        for (cur = rows; cur != NULL; cur = cur->next) {
2601 237 hiro
                GtkTreePath *path = (GtkTreePath *)cur->data;
2602 237 hiro
2603 237 hiro
                gtk_tree_model_get_iter(model, &iter, path);
2604 237 hiro
                summary_mark_row_as_read(summaryview, &iter);
2605 237 hiro
        }
2606 237 hiro
2607 1 hiro
        if (FOLDER_TYPE(summaryview->folder_item->folder) == F_IMAP) {
2608 1 hiro
                GSList *msglist;
2609 237 hiro
2610 1 hiro
                msglist = summary_get_selected_msg_list(summaryview);
2611 1 hiro
                imap_msg_list_unset_perm_flags(msglist, MSG_NEW | MSG_UNREAD);
2612 1 hiro
                g_slist_free(msglist);
2613 1 hiro
        }
2614 1 hiro
2615 751 hiro
        SORT_UNBLOCK(SORT_BY_UNREAD);
2616 751 hiro
2617 1 hiro
        summary_status_show(summaryview);
2618 1 hiro
}
2619 1 hiro
2620 1 hiro
void summary_mark_all_read(SummaryView *summaryview)
2621 1 hiro
{
2622 237 hiro
        GtkTreeModel *model = GTK_TREE_MODEL(summaryview->store);
2623 237 hiro
        GtkTreeIter iter;
2624 237 hiro
        gboolean valid;
2625 751 hiro
        FolderSortKey sort_key = SORT_BY_NONE;
2626 751 hiro
        FolderSortType sort_type = SORT_ASCENDING;
2627 1 hiro
2628 751 hiro
        SORT_BLOCK(SORT_BY_UNREAD);
2629 751 hiro
2630 237 hiro
        valid = gtk_tree_model_get_iter_first(model, &iter);
2631 237 hiro
2632 237 hiro
        while (valid) {
2633 237 hiro
                summary_mark_row_as_read(summaryview, &iter);
2634 237 hiro
                valid = gtkut_tree_model_next(model, &iter);
2635 1 hiro
        }
2636 237 hiro
2637 1 hiro
        if (FOLDER_TYPE(summaryview->folder_item->folder) == F_IMAP) {
2638 1 hiro
                GSList *msglist;
2639 1 hiro
                msglist = summary_get_msg_list(summaryview);
2640 1 hiro
                imap_msg_list_unset_perm_flags(msglist, MSG_NEW | MSG_UNREAD);
2641 1 hiro
                g_slist_free(msglist);
2642 1 hiro
        }
2643 1 hiro
2644 751 hiro
        SORT_UNBLOCK(SORT_BY_UNREAD);
2645 751 hiro
2646 1 hiro
        summary_status_show(summaryview);
2647 1 hiro
}
2648 1 hiro
2649 1 hiro
static void summary_mark_row_as_unread(SummaryView *summaryview,
2650 237 hiro
                                       GtkTreeIter *iter)
2651 1 hiro
{
2652 237 hiro
        MsgInfo *msginfo = NULL;
2653 1 hiro
2654 237 hiro
        GET_MSG_INFO(msginfo, iter);
2655 237 hiro
2656 1 hiro
        if (MSG_IS_DELETED(msginfo->flags)) {
2657 1 hiro
                msginfo->to_folder = NULL;
2658 1 hiro
                MSG_UNSET_PERM_FLAGS(msginfo->flags, MSG_DELETED);
2659 1 hiro
                summaryview->deleted--;
2660 293 hiro
                summaryview->folder_item->mark_dirty = TRUE;
2661 1 hiro
        }
2662 1 hiro
        MSG_UNSET_PERM_FLAGS(msginfo->flags, MSG_REPLIED | MSG_FORWARDED);
2663 1 hiro
        if (!MSG_IS_UNREAD(msginfo->flags)) {
2664 1 hiro
                MSG_SET_PERM_FLAGS(msginfo->flags, MSG_UNREAD);
2665 1 hiro
                summaryview->folder_item->unread++;
2666 293 hiro
                summaryview->folder_item->mark_dirty = TRUE;
2667 850 hiro
                if (summaryview->folder_item->stype == F_VIRTUAL) {
2668 850 hiro
                        msginfo->folder->unread++;
2669 850 hiro
                        folderview_update_item(msginfo->folder, FALSE);
2670 850 hiro
                }
2671 1 hiro
                debug_print(_("Message %d is marked as unread\n"),
2672 1 hiro
                            msginfo->msgnum);
2673 1 hiro
        }
2674 848 hiro
        MSG_SET_TMP_FLAGS(msginfo->flags, MSG_FLAG_CHANGED);
2675 237 hiro
        summary_set_row(summaryview, iter, msginfo);
2676 1 hiro
}
2677 1 hiro
2678 1 hiro
void summary_mark_as_unread(SummaryView *summaryview)
2679 1 hiro
{
2680 237 hiro
        GList *rows, *cur;
2681 237 hiro
        GtkTreeModel *model = GTK_TREE_MODEL(summaryview->store);
2682 237 hiro
        GtkTreeIter iter;
2683 751 hiro
        FolderSortKey sort_key = SORT_BY_NONE;
2684 751 hiro
        FolderSortType sort_type = SORT_ASCENDING;
2685 1 hiro
2686 751 hiro
        SORT_BLOCK(SORT_BY_UNREAD);
2687 751 hiro
2688 297 hiro
        rows = summary_get_selected_rows(summaryview);
2689 237 hiro
        for (cur = rows; cur != NULL; cur = cur->next) {
2690 237 hiro
                GtkTreePath *path = (GtkTreePath *)cur->data;
2691 237 hiro
2692 237 hiro
                gtk_tree_model_get_iter(model, &iter, path);
2693 237 hiro
                summary_mark_row_as_unread(summaryview, &iter);
2694 237 hiro
        }
2695 237 hiro
2696 1 hiro
        if (FOLDER_TYPE(summaryview->folder_item->folder) == F_IMAP) {
2697 1 hiro
                GSList *msglist;
2698 1 hiro
                msglist = summary_get_selected_msg_list(summaryview);
2699 1 hiro
                imap_msg_list_unset_perm_flags(msglist, MSG_REPLIED);
2700 1 hiro
                imap_msg_list_set_perm_flags(msglist, MSG_UNREAD);
2701 1 hiro
                g_slist_free(msglist);
2702 1 hiro
        }
2703 1 hiro
2704 751 hiro
        SORT_UNBLOCK(SORT_BY_UNREAD);
2705 751 hiro
2706 1 hiro
        summary_status_show(summaryview);
2707 1 hiro
}
2708 1 hiro
2709 237 hiro
static void summary_delete_row(SummaryView *summaryview, GtkTreeIter *iter)
2710 1 hiro
{
2711 237 hiro
        MsgInfo *msginfo = NULL;
2712 1 hiro
2713 237 hiro
        GET_MSG_INFO(msginfo, iter);
2714 1 hiro
2715 1 hiro
        if (MSG_IS_DELETED(msginfo->flags)) return;
2716 1 hiro
2717 1 hiro
        msginfo->to_folder = NULL;
2718 1 hiro
        if (MSG_IS_MOVE(msginfo->flags))
2719 1 hiro
                summaryview->moved--;
2720 1 hiro
        if (MSG_IS_COPY(msginfo->flags))
2721 1 hiro
                summaryview->copied--;
2722 1 hiro
        MSG_UNSET_TMP_FLAGS(msginfo->flags, MSG_MOVE | MSG_COPY);
2723 1 hiro
        MSG_SET_PERM_FLAGS(msginfo->flags, MSG_DELETED);
2724 848 hiro
        MSG_SET_TMP_FLAGS(msginfo->flags, MSG_FLAG_CHANGED);
2725 1 hiro
        summaryview->deleted++;
2726 293 hiro
        summaryview->folder_item->mark_dirty = TRUE;
2727 1 hiro
2728 1 hiro
        if (!prefs_common.immediate_exec &&
2729 1 hiro
            summaryview->folder_item->stype != F_TRASH)
2730 237 hiro
                summary_set_row(summaryview, iter, msginfo);
2731 1 hiro
2732 1 hiro
        debug_print(_("Message %s/%d is set to delete\n"),
2733 1 hiro
                    msginfo->folder->path, msginfo->msgnum);
2734 1 hiro
}
2735 1 hiro
2736 1 hiro
void summary_delete(SummaryView *summaryview)
2737 1 hiro
{
2738 1 hiro
        FolderItem *item = summaryview->folder_item;
2739 237 hiro
        GList *rows, *cur;
2740 237 hiro
        GtkTreeIter last_sel, next;
2741 1 hiro
2742 1 hiro
        if (!item || FOLDER_TYPE(item->folder) == F_NEWS) return;
2743 1 hiro
<