Statistics
| Revision:

root / src / summaryview.c @ 416

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