1 /*
2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2014 Hiroyuki Yamamoto
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 #include "defs.h"
21
22 #include <glib.h>
23 #include <glib/gi18n.h>
24 #include <gdk/gdkkeysyms.h>
25 #include <gtk/gtkwidget.h>
26 #include <gtk/gtkvbox.h>
27 #include <gtk/gtkscrolledwindow.h>
28 #include <gtk/gtktreestore.h>
29 #include <gtk/gtktreeview.h>
30 #include <gtk/gtktreeselection.h>
31 #include <gtk/gtkcellrendererpixbuf.h>
32 #include <gtk/gtkcellrenderertext.h>
33 #include <gtk/gtksignal.h>
34 #include <gtk/gtkmain.h>
35 #include <gtk/gtkstatusbar.h>
36 #include <gtk/gtkmenu.h>
37 #include <gtk/gtkmenuitem.h>
38 #include <gtk/gtkitemfactory.h>
39 #include <gtk/gtkstock.h>
40 #include <gtk/gtkversion.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <stdlib.h>
44
45 #include "main.h"
46 #include "mainwindow.h"
47 #include "folderview.h"
48 #include "summaryview.h"
49 #include "query_search.h"
50 #include "inputdialog.h"
51 #include "subscribedialog.h"
52 #include "foldersel.h"
53 #include "manage_window.h"
54 #include "alertpanel.h"
55 #include "menu.h"
56 #include "stock_pixmap.h"
57 #include "statusbar.h"
58 #include "procmsg.h"
59 #include "utils.h"
60 #include "gtkutils.h"
61 #include "trayicon.h"
62 #include "prefs_common.h"
63 #include "prefs_account.h"
64 #include "prefs_folder_item.h"
65 #include "prefs_search_folder.h"
66 #include "filter.h"
67 #include "account.h"
68 #include "account_dialog.h"
69 #include "folder.h"
70 #include "inc.h"
71 #include "send_message.h"
72 #include "virtual.h"
73 #include "plugin.h"
74
75 enum
76 {
77 COL_FOLDER_NAME,
78 COL_NEW,
79 COL_UNREAD,
80 COL_TOTAL,
81 COL_FOLDER_ITEM,
82 COL_PIXBUF,
83 COL_PIXBUF_OPEN,
84 COL_FOREGROUND,
85 COL_BOLD,
86 N_COLS
87 };
88
89 #define COL_FOLDER_WIDTH 150
90 #define COL_NUM_WIDTH 32
91
92 #define STATUSBAR_PUSH(mainwin, str) \
93 { \
94 gtk_statusbar_push(GTK_STATUSBAR(mainwin->statusbar), \
95 mainwin->folderview_cid, str); \
96 gtkut_widget_draw_now(mainwin->statusbar); \
97 }
98
99 #define STATUSBAR_POP(mainwin) \
100 { \
101 gtk_statusbar_pop(GTK_STATUSBAR(mainwin->statusbar), \
102 mainwin->folderview_cid); \
103 }
104
105 static GList *folderview_list = NULL;
106
107 static GdkPixbuf *inbox_pixbuf;
108 static GdkPixbuf *outbox_pixbuf;
109 static GdkPixbuf *folder_pixbuf;
110 static GdkPixbuf *folderopen_pixbuf;
111 static GdkPixbuf *foldernoselect_pixbuf;
112 static GdkPixbuf *draft_pixbuf;
113 static GdkPixbuf *trash_pixbuf;
114 static GdkPixbuf *junk_pixbuf;
115 static GdkPixbuf *virtual_pixbuf;
116
117 static void folderview_set_columns (FolderView *folderview);
118
119 static void folderview_select_row (FolderView *folderview,
120 GtkTreeIter *iter);
121 static void folderview_select_row_ref (FolderView *folderview,
122 GtkTreeRowReference *row);
123
124 static void folderview_set_folders (FolderView *folderview);
125 static void folderview_append_folder (FolderView *folderview,
126 Folder *folder);
127
128 static void folderview_update_row (FolderView *folderview,
129 GtkTreeIter *iter);
130 static void folderview_update_row_all (FolderView *folderview);
131
132 static gint folderview_folder_name_compare (GtkTreeModel *model,
133 GtkTreeIter *a,
134 GtkTreeIter *b,
135 gpointer data);
136
137 /* callback functions */
138 static gboolean folderview_button_pressed (GtkWidget *treeview,
139 GdkEventButton *event,
140 FolderView *folderview);
141 static gboolean folderview_button_released (GtkWidget *treeview,
142 GdkEventButton *event,
143 FolderView *folderview);
144
145 static gboolean folderview_key_pressed (GtkWidget *widget,
146 GdkEventKey *event,
147 FolderView *folderview);
148
149 static void folderview_selection_changed(GtkTreeSelection *selection,
150 FolderView *folderview);
151
152 static void folderview_row_expanded (GtkTreeView *treeview,
153 GtkTreeIter *iter,
154 GtkTreePath *path,
155 FolderView *folderview);
156 static void folderview_row_collapsed (GtkTreeView *treeview,
157 GtkTreeIter *iter,
158 GtkTreePath *path,
159 FolderView *folderview);
160
161 static void folderview_popup_close (GtkMenuShell *menu_shell,
162 FolderView *folderview);
163
164 static void folderview_col_resized (GtkWidget *widget,
165 GtkAllocation *allocation,
166 FolderView *folderview);
167
168 static void folderview_download_cb (FolderView *folderview,
169 guint action,
170 GtkWidget *widget);
171
172 static void folderview_update_tree_cb (FolderView *folderview,
173 guint action,
174 GtkWidget *widget);
175
176 static void folderview_update_summary_cb(FolderView *folderview,
177 guint action,
178 GtkWidget *widget);
179
180 static void folderview_mark_all_read_cb (FolderView *folderview,
181 guint action,
182 GtkWidget *widget);
183 static void folderview_send_queue_cb (FolderView *folderview,
184 guint action,
185 GtkWidget *widget);
186
187 static void folderview_new_folder_cb (FolderView *folderview,
188 guint action,
189 GtkWidget *widget);
190 static void folderview_rename_folder_cb (FolderView *folderview,
191 guint action,
192 GtkWidget *widget);
193 static void folderview_move_folder_cb (FolderView *folderview,
194 guint action,
195 GtkWidget *widget);
196 static void folderview_delete_folder_cb (FolderView *folderview,
197 guint action,
198 GtkWidget *widget);
199 static void folderview_empty_trash_cb (FolderView *folderview,
200 guint action,
201 GtkWidget *widget);
202 static void folderview_remove_mailbox_cb(FolderView *folderview,
203 guint action,
204 GtkWidget *widget);
205
206 static void folderview_rm_imap_server_cb (FolderView *folderview,
207 guint action,
208 GtkWidget *widget);
209
210 static void folderview_new_news_group_cb(FolderView *folderview,
211 guint action,
212 GtkWidget *widget);
213 static void folderview_rm_news_group_cb (FolderView *folderview,
214 guint action,
215 GtkWidget *widget);
216 static void folderview_rm_news_server_cb(FolderView *folderview,
217 guint action,
218 GtkWidget *widget);
219
220 static void folderview_search_cb (FolderView *folderview,
221 guint action,
222 GtkWidget *widget);
223
224 static void folderview_property_cb (FolderView *folderview,
225 guint action,
226 GtkWidget *widget);
227
228 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
229 GdkDragContext *context,
230 gint x,
231 gint y,
232 guint time,
233 FolderView *folderview);
234 static void folderview_drag_leave_cb (GtkWidget *widget,
235 GdkDragContext *context,
236 guint time,
237 FolderView *folderview);
238 static void folderview_drag_received_cb (GtkWidget *widget,
239 GdkDragContext *context,
240 gint x,
241 gint y,
242 GtkSelectionData *data,
243 guint info,
244 guint time,
245 FolderView *folderview);
246
247 static GtkTargetEntry folderview_drag_types[] =
248 {
249 {"text/plain", GTK_TARGET_SAME_APP, 0}
250 };
251
252 static GtkItemFactoryEntry folderview_mail_popup_entries[] =
253 {
254 {N_("/Create _new folder..."), NULL, folderview_new_folder_cb, 0, NULL},
255 {N_("/_Rename folder..."), NULL, folderview_rename_folder_cb, 0, NULL},
256 {N_("/_Move folder..."), NULL, folderview_move_folder_cb, 0, NULL},
257 {N_("/_Delete folder"), NULL, folderview_delete_folder_cb, 0, NULL},
258 {N_("/---"), NULL, NULL, 0, "<Separator>"},
259 {N_("/Empty _junk"), NULL, folderview_empty_trash_cb, 0, NULL},
260 {N_("/Empty _trash"), NULL, folderview_empty_trash_cb, 0, NULL},
261 {N_("/---"), NULL, NULL, 0, "<Separator>"},
262 {N_("/_Check for new messages"),
263 NULL, folderview_update_tree_cb, 0, NULL},
264 {N_("/R_ebuild folder tree"), NULL, folderview_update_tree_cb, 1, NULL},
265 {N_("/_Update summary"), NULL, folderview_update_summary_cb, 0, NULL},
266 {N_("/---"), NULL, NULL, 0, "<Separator>"},
267 {N_("/Mar_k all read"), NULL, folderview_mark_all_read_cb, 0, NULL},
268 {N_("/Send _queued messages"), NULL, folderview_send_queue_cb, 0, NULL},
269 {N_("/---"), NULL, NULL, 0, "<Separator>"},
270 {N_("/_Search messages..."), NULL, folderview_search_cb, 0, NULL},
271 {N_("/Ed_it search condition..."),
272 NULL, folderview_search_cb, 0, NULL},
273 {N_("/_Properties..."), NULL, folderview_property_cb, 0, NULL}
274 };
275
276 static GtkItemFactoryEntry folderview_imap_popup_entries[] =
277 {
278 {N_("/Create _new folder..."), NULL, folderview_new_folder_cb, 0, NULL},
279 {N_("/_Rename folder..."), NULL, folderview_rename_folder_cb, 0, NULL},
280 {N_("/_Move folder..."), NULL, folderview_move_folder_cb, 0, NULL},
281 {N_("/_Delete folder"), NULL, folderview_delete_folder_cb, 0, NULL},
282 {N_("/---"), NULL, NULL, 0, "<Separator>"},
283 {N_("/Empty _junk"), NULL, folderview_empty_trash_cb, 0, NULL},
284 {N_("/Empty _trash"), NULL, folderview_empty_trash_cb, 0, NULL},
285 {N_("/---"), NULL, NULL, 0, "<Separator>"},
286 {N_("/Down_load"), NULL, folderview_download_cb, 0, NULL},
287 {N_("/---"), NULL, NULL, 0, "<Separator>"},
288 {N_("/_Check for new messages"),
289 NULL, folderview_update_tree_cb, 0, NULL},
290 {N_("/R_ebuild folder tree"), NULL, folderview_update_tree_cb, 1, NULL},
291 {N_("/_Update summary"), NULL, folderview_update_summary_cb, 0, NULL},
292 {N_("/---"), NULL, NULL, 0, "<Separator>"},
293 {N_("/Mar_k all read"), NULL, folderview_mark_all_read_cb, 0, NULL},
294 {N_("/Send _queued messages"), NULL, folderview_send_queue_cb, 0, NULL},
295 {N_("/---"), NULL, NULL, 0, "<Separator>"},
296 {N_("/_Search messages..."), NULL, folderview_search_cb, 0, NULL},
297 {N_("/Ed_it search condition..."),
298 NULL, folderview_search_cb, 0, NULL},
299 {N_("/_Properties..."), NULL, folderview_property_cb, 0, NULL}
300 };
301
302 static GtkItemFactoryEntry folderview_news_popup_entries[] =
303 {
304 {N_("/Su_bscribe to newsgroup..."),
305 NULL, folderview_new_news_group_cb, 0, NULL},
306 {N_("/_Remove newsgroup"), NULL, folderview_rm_news_group_cb, 0, NULL},
307 {N_("/_Rename folder..."), NULL, folderview_rename_folder_cb, 0, NULL},
308 {N_("/_Delete folder"), NULL, folderview_delete_folder_cb, 0, NULL},
309 {N_("/---"), NULL, NULL, 0, "<Separator>"},
310 {N_("/Down_load"), NULL, folderview_download_cb, 0, NULL},
311 {N_("/---"), NULL, NULL, 0, "<Separator>"},
312 {N_("/_Check for new messages"),
313 NULL, folderview_update_tree_cb, 0, NULL},
314 {N_("/_Update summary"), NULL, folderview_update_summary_cb, 0, NULL},
315 {N_("/---"), NULL, NULL, 0, "<Separator>"},
316 {N_("/Mar_k all read"), NULL, folderview_mark_all_read_cb, 0, NULL},
317 {N_("/---"), NULL, NULL, 0, "<Separator>"},
318 {N_("/_Search messages..."), NULL, folderview_search_cb, 0, NULL},
319 {N_("/Ed_it search condition..."),
320 NULL, folderview_search_cb, 0, NULL},
321 {N_("/_Properties..."), NULL, folderview_property_cb, 0, NULL}
322 };
323
324
folderview_create(void)325 FolderView *folderview_create(void)
326 {
327 FolderView *folderview;
328 GtkWidget *vbox;
329 GtkWidget *scrolledwin;
330 GtkWidget *treeview;
331 GtkTreeStore *store;
332 GtkTreeSelection *selection;
333 GtkTreeViewColumn *column;
334 GtkCellRenderer *renderer;
335 GtkWidget *mail_popup;
336 GtkWidget *news_popup;
337 GtkWidget *imap_popup;
338 GtkItemFactory *mail_factory;
339 GtkItemFactory *news_factory;
340 GtkItemFactory *imap_factory;
341 gint n_entries;
342
343 debug_print(_("Creating folder view...\n"));
344 folderview = g_new0(FolderView, 1);
345
346 vbox = gtk_vbox_new(FALSE, 1);
347
348 scrolledwin = gtk_scrolled_window_new(NULL, NULL);
349 gtk_scrolled_window_set_policy
350 (GTK_SCROLLED_WINDOW(scrolledwin),
351 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
352 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwin),
353 GTK_SHADOW_IN);
354 gtk_box_pack_start(GTK_BOX(vbox), scrolledwin, TRUE, TRUE, 0);
355 gtk_widget_set_size_request(scrolledwin,
356 prefs_common.folderview_width,
357 prefs_common.folderview_height);
358
359 store = gtk_tree_store_new(N_COLS, G_TYPE_STRING, G_TYPE_STRING,
360 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER,
361 GDK_TYPE_PIXBUF, GDK_TYPE_PIXBUF,
362 GDK_TYPE_COLOR, G_TYPE_INT);
363 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store),
364 COL_FOLDER_NAME,
365 folderview_folder_name_compare,
366 NULL, NULL);
367
368 treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
369 g_object_unref(G_OBJECT(store));
370 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), TRUE);
371 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), FALSE);
372 gtk_tree_view_set_search_column(GTK_TREE_VIEW(treeview),
373 COL_FOLDER_NAME);
374 gtk_tree_view_set_reorderable(GTK_TREE_VIEW(treeview), FALSE);
375 #if GTK_CHECK_VERSION(2, 12, 0)
376 g_object_set(treeview, "fixed-height-mode", TRUE, NULL);
377 #endif
378
379 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
380 gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
381
382 gtk_container_add(GTK_CONTAINER(scrolledwin), treeview);
383
384 /* create folder icon + name column */
385 column = gtk_tree_view_column_new();
386 gtk_tree_view_column_set_spacing(column, 1);
387 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
388 gtk_tree_view_column_set_fixed_width
389 (column, prefs_common.folder_col_folder);
390 gtk_tree_view_column_set_resizable(column, TRUE);
391 #if GTK_CHECK_VERSION(2, 14, 0)
392 gtk_tree_view_column_set_expand(column, TRUE);
393 #endif
394
395 renderer = gtk_cell_renderer_pixbuf_new();
396 g_object_set(renderer, "ypad", 0, NULL);
397 gtk_tree_view_column_pack_start(column, renderer, FALSE);
398 gtk_tree_view_column_set_title(column, _("Folder"));
399 gtk_tree_view_column_set_attributes
400 (column, renderer,
401 "pixbuf", COL_PIXBUF,
402 "pixbuf-expander-open", COL_PIXBUF_OPEN,
403 "pixbuf-expander-closed", COL_PIXBUF,
404 NULL);
405
406 renderer = gtk_cell_renderer_text_new();
407 #if GTK_CHECK_VERSION(2, 6, 0)
408 g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, "ypad", 0,
409 NULL);
410 #else
411 g_object_set(renderer, "ypad", 0, NULL);
412 #endif
413 gtk_tree_view_column_pack_start(column, renderer, TRUE);
414 gtk_tree_view_column_set_attributes(column, renderer,
415 "text", COL_FOLDER_NAME,
416 "foreground-gdk", COL_FOREGROUND,
417 "weight", COL_BOLD,
418 NULL);
419
420 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
421 gtk_tree_view_set_expander_column(GTK_TREE_VIEW(treeview), column);
422 g_signal_connect(G_OBJECT(column->button), "size-allocate",
423 G_CALLBACK(folderview_col_resized), folderview);
424
425 renderer = gtk_cell_renderer_text_new();
426 g_object_set(renderer, "xalign", 1.0, "ypad", 0, NULL);
427 column = gtk_tree_view_column_new_with_attributes
428 (_("New"), renderer, "text", COL_NEW,
429 "foreground-gdk", COL_FOREGROUND,
430 "weight", COL_BOLD, NULL);
431 gtk_tree_view_column_set_alignment(column, 1.0);
432 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
433 gtk_tree_view_column_set_fixed_width
434 (column, prefs_common.folder_col_new);
435 gtk_tree_view_column_set_min_width(column, 8);
436 gtk_tree_view_column_set_resizable(column, TRUE);
437 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
438 g_signal_connect(G_OBJECT(column->button), "size-allocate",
439 G_CALLBACK(folderview_col_resized), folderview);
440
441 renderer = gtk_cell_renderer_text_new();
442 g_object_set(renderer, "xalign", 1.0, "ypad", 0, NULL);
443 column = gtk_tree_view_column_new_with_attributes
444 (_("Unread"), renderer, "text", COL_UNREAD,
445 "foreground-gdk", COL_FOREGROUND,
446 "weight", COL_BOLD, NULL);
447 gtk_tree_view_column_set_alignment(column, 1.0);
448 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
449 gtk_tree_view_column_set_fixed_width
450 (column, prefs_common.folder_col_unread);
451 gtk_tree_view_column_set_min_width(column, 8);
452 gtk_tree_view_column_set_resizable(column, TRUE);
453 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
454 g_signal_connect(G_OBJECT(column->button), "size-allocate",
455 G_CALLBACK(folderview_col_resized), folderview);
456
457 renderer = gtk_cell_renderer_text_new();
458 g_object_set(renderer, "xalign", 1.0, "ypad", 0, NULL);
459 column = gtk_tree_view_column_new_with_attributes
460 (_("Total"), renderer, "text", COL_TOTAL,
461 "foreground-gdk", COL_FOREGROUND,
462 "weight", COL_BOLD, NULL);
463 gtk_tree_view_column_set_alignment(column, 1.0);
464 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
465 gtk_tree_view_column_set_fixed_width
466 (column, prefs_common.folder_col_total);
467 gtk_tree_view_column_set_min_width(column, 8);
468 gtk_tree_view_column_set_resizable(column, TRUE);
469 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
470 g_signal_connect(G_OBJECT(column->button), "size-allocate",
471 G_CALLBACK(folderview_col_resized), folderview);
472
473 /* add rightmost empty column */
474 column = gtk_tree_view_column_new();
475 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
476 gtk_tree_view_column_set_min_width(column, 0);
477 gtk_tree_view_column_set_max_width(column, 0);
478 gtk_tree_view_column_set_clickable(column, FALSE);
479 gtk_tree_view_column_set_reorderable(column, FALSE);
480 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
481
482 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store),
483 COL_FOLDER_NAME,
484 GTK_SORT_ASCENDING);
485
486 /* popup menu */
487 n_entries = sizeof(folderview_mail_popup_entries) /
488 sizeof(folderview_mail_popup_entries[0]);
489 mail_popup = menu_create_items(folderview_mail_popup_entries,
490 n_entries,
491 "<MailFolder>", &mail_factory,
492 folderview);
493 n_entries = sizeof(folderview_imap_popup_entries) /
494 sizeof(folderview_imap_popup_entries[0]);
495 imap_popup = menu_create_items(folderview_imap_popup_entries,
496 n_entries,
497 "<IMAPFolder>", &imap_factory,
498 folderview);
499 n_entries = sizeof(folderview_news_popup_entries) /
500 sizeof(folderview_news_popup_entries[0]);
501 news_popup = menu_create_items(folderview_news_popup_entries,
502 n_entries,
503 "<NewsFolder>", &news_factory,
504 folderview);
505
506 g_signal_connect(G_OBJECT(treeview), "button_press_event",
507 G_CALLBACK(folderview_button_pressed), folderview);
508 g_signal_connect(G_OBJECT(treeview), "button_release_event",
509 G_CALLBACK(folderview_button_released), folderview);
510 g_signal_connect(G_OBJECT(treeview), "key_press_event",
511 G_CALLBACK(folderview_key_pressed), folderview);
512
513 g_signal_connect(G_OBJECT(selection), "changed",
514 G_CALLBACK(folderview_selection_changed), folderview);
515
516 g_signal_connect_after(G_OBJECT(treeview), "row-expanded",
517 G_CALLBACK(folderview_row_expanded),
518 folderview);
519 g_signal_connect_after(G_OBJECT(treeview), "row-collapsed",
520 G_CALLBACK(folderview_row_collapsed),
521 folderview);
522
523 g_signal_connect(G_OBJECT(mail_popup), "selection_done",
524 G_CALLBACK(folderview_popup_close), folderview);
525 g_signal_connect(G_OBJECT(imap_popup), "selection_done",
526 G_CALLBACK(folderview_popup_close), folderview);
527 g_signal_connect(G_OBJECT(news_popup), "selection_done",
528 G_CALLBACK(folderview_popup_close), folderview);
529
530 /* drop callback */
531 gtk_drag_dest_set(treeview, GTK_DEST_DEFAULT_ALL,
532 folderview_drag_types, 1,
533 GDK_ACTION_MOVE | GDK_ACTION_COPY);
534 g_signal_connect(G_OBJECT(treeview), "drag-motion",
535 G_CALLBACK(folderview_drag_motion_cb),
536 folderview);
537 g_signal_connect(G_OBJECT(treeview), "drag-leave",
538 G_CALLBACK(folderview_drag_leave_cb),
539 folderview);
540 g_signal_connect(G_OBJECT(treeview), "drag-data-received",
541 G_CALLBACK(folderview_drag_received_cb),
542 folderview);
543
544 folderview->vbox = vbox;
545 folderview->scrolledwin = scrolledwin;
546 folderview->treeview = treeview;
547 folderview->store = store;
548 folderview->selection = selection;
549 folderview->mail_popup = mail_popup;
550 folderview->mail_factory = mail_factory;
551 folderview->imap_popup = imap_popup;
552 folderview->imap_factory = imap_factory;
553 folderview->news_popup = news_popup;
554 folderview->news_factory = news_factory;
555
556 folderview->display_folder_unread = prefs_common.display_folder_unread;
557
558 folderview_set_columns(folderview);
559
560 gtk_widget_show_all(vbox);
561
562 folderview_list = g_list_append(folderview_list, folderview);
563
564 return folderview;
565 }
566
folderview_init(FolderView * folderview)567 void folderview_init(FolderView *folderview)
568 {
569 GtkWidget *treeview = folderview->treeview;
570
571 stock_pixbuf_gdk(treeview, STOCK_PIXMAP_INBOX, &inbox_pixbuf);
572 stock_pixbuf_gdk(treeview, STOCK_PIXMAP_OUTBOX, &outbox_pixbuf);
573 stock_pixbuf_gdk(treeview, STOCK_PIXMAP_FOLDER_CLOSE, &folder_pixbuf);
574 stock_pixbuf_gdk(treeview, STOCK_PIXMAP_FOLDER_OPEN, &folderopen_pixbuf);
575 stock_pixbuf_gdk(treeview, STOCK_PIXMAP_FOLDER_NOSELECT,
576 &foldernoselect_pixbuf);
577 stock_pixbuf_gdk(treeview, STOCK_PIXMAP_DRAFT, &draft_pixbuf);
578 stock_pixbuf_gdk(treeview, STOCK_PIXMAP_TRASH, &trash_pixbuf);
579 stock_pixbuf_gdk(treeview, STOCK_PIXMAP_SPAM_SMALL, &junk_pixbuf);
580 stock_pixbuf_gdk(treeview, STOCK_PIXMAP_FOLDER_SEARCH, &virtual_pixbuf);
581 }
582
folderview_reflect_prefs(FolderView * folderview)583 void folderview_reflect_prefs(FolderView *folderview)
584 {
585 folderview_set_columns(folderview);
586 if (folderview->display_folder_unread !=
587 prefs_common.display_folder_unread) {
588 folderview->display_folder_unread =
589 prefs_common.display_folder_unread;
590 folderview_update_row_all(folderview);
591 }
592 }
593
folderview_add_sub_widget(FolderView * folderview,GtkWidget * widget)594 void folderview_add_sub_widget(FolderView *folderview, GtkWidget *widget)
595 {
596 g_return_if_fail(folderview != NULL);
597 g_return_if_fail(widget != NULL);
598
599 debug_print("folderview_add_sub_widget: adding sub widget\n");
600
601 gtk_box_pack_start(GTK_BOX(folderview->vbox), widget, FALSE, FALSE, 0);
602 }
603
folderview_get(void)604 FolderView *folderview_get(void)
605 {
606 return (FolderView *)folderview_list->data;
607 }
608
folderview_set(FolderView * folderview)609 void folderview_set(FolderView *folderview)
610 {
611 MainWindow *mainwin = folderview->mainwin;
612 GtkTreeIter iter;
613
614 debug_print(_("Setting folder info...\n"));
615 STATUSBAR_PUSH(mainwin, _("Setting folder info..."));
616
617 main_window_cursor_wait(mainwin);
618
619 folderview_unselect(folderview);
620
621 gtk_tree_store_clear(folderview->store);
622
623 folderview_set_folders(folderview);
624
625 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(folderview->store),
626 &iter))
627 folderview_select_row(folderview, &iter);
628
629 main_window_cursor_normal(mainwin);
630 STATUSBAR_POP(mainwin);
631 }
632
folderview_set_all(void)633 void folderview_set_all(void)
634 {
635 GList *list;
636
637 for (list = folderview_list; list != NULL; list = list->next)
638 folderview_set((FolderView *)list->data);
639 }
640
folderview_set_columns(FolderView * folderview)641 static void folderview_set_columns(FolderView *folderview)
642 {
643 GtkTreeView *treeview = GTK_TREE_VIEW(folderview->treeview);
644 GtkTreeViewColumn *column;
645
646 column = gtk_tree_view_get_column(treeview, COL_NEW);
647 gtk_tree_view_column_set_visible
648 (column, prefs_common.folder_col_visible[COL_NEW]);
649 column = gtk_tree_view_get_column(treeview, COL_UNREAD);
650 gtk_tree_view_column_set_visible
651 (column, prefs_common.folder_col_visible[COL_UNREAD]);
652 column = gtk_tree_view_get_column(treeview, COL_TOTAL);
653 gtk_tree_view_column_set_visible
654 (column, prefs_common.folder_col_visible[COL_TOTAL]);
655 column = gtk_tree_view_get_column(treeview, COL_TOTAL + 1);
656 gtk_tree_view_column_set_visible
657 (column, prefs_common.folder_col_visible[COL_NEW] ||
658 prefs_common.folder_col_visible[COL_UNREAD] ||
659 prefs_common.folder_col_visible[COL_TOTAL]);
660 }
661
folderview_select(FolderView * folderview,FolderItem * item)662 void folderview_select(FolderView *folderview, FolderItem *item)
663 {
664 GtkTreeIter iter;
665
666 if (!item) return;
667
668 if (gtkut_tree_model_find_by_column_data
669 (GTK_TREE_MODEL(folderview->store), &iter, NULL,
670 COL_FOLDER_ITEM, item))
671 folderview_select_row(folderview, &iter);
672 }
673
folderview_select_row(FolderView * folderview,GtkTreeIter * iter)674 static void folderview_select_row(FolderView *folderview, GtkTreeIter *iter)
675 {
676 GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
677 GtkTreePath *path;
678
679 g_return_if_fail(iter != NULL);
680
681 path = gtk_tree_model_get_path(model, iter);
682
683 gtkut_tree_view_expand_parent_all(GTK_TREE_VIEW(folderview->treeview),
684 iter);
685
686 folderview->open_folder = TRUE;
687 gtk_tree_view_set_cursor(GTK_TREE_VIEW(folderview->treeview), path,
688 NULL, FALSE);
689 if (folderview->summaryview->folder_item &&
690 folderview->summaryview->folder_item->total > 0)
691 gtk_widget_grab_focus(folderview->summaryview->treeview);
692 else
693 gtk_widget_grab_focus(folderview->treeview);
694
695 gtk_tree_path_free(path);
696 }
697
folderview_select_row_ref(FolderView * folderview,GtkTreeRowReference * row)698 static void folderview_select_row_ref(FolderView *folderview,
699 GtkTreeRowReference *row)
700 {
701 GtkTreePath *path;
702 GtkTreeIter iter;
703
704 if (!row) return;
705
706 path = gtk_tree_row_reference_get_path(row);
707 if (!path)
708 return;
709 gtk_tree_model_get_iter(GTK_TREE_MODEL(folderview->store), &iter, path);
710 gtk_tree_path_free(path);
711
712 folderview_select_row(folderview, &iter);
713 }
714
folderview_unselect(FolderView * folderview)715 void folderview_unselect(FolderView *folderview)
716 {
717 if (folderview->selected) {
718 gtk_tree_row_reference_free(folderview->selected);
719 folderview->selected = NULL;
720 }
721 if (folderview->opened) {
722 gtk_tree_row_reference_free(folderview->opened);
723 folderview->opened = NULL;
724 }
725 }
726
folderview_find_next_unread(GtkTreeModel * model,GtkTreeIter * next,GtkTreeIter * iter)727 static gboolean folderview_find_next_unread(GtkTreeModel *model,
728 GtkTreeIter *next,
729 GtkTreeIter *iter)
730 {
731 FolderItem *item;
732 GtkTreeIter iter_;
733 gboolean valid;
734
735 if (iter) {
736 iter_ = *iter;
737 valid = gtkut_tree_model_next(model, &iter_);
738 } else
739 valid = gtk_tree_model_get_iter_first(model, &iter_);
740
741 while (valid) {
742 item = NULL;
743 gtk_tree_model_get(model, &iter_, COL_FOLDER_ITEM, &item, -1);
744 if (item && item->unread > 0 && item->stype != F_TRASH) {
745 if (next)
746 *next = iter_;
747 return TRUE;
748 }
749
750 valid = gtkut_tree_model_next(model, &iter_);
751 }
752
753 return FALSE;
754 }
755
folderview_select_next_unread(FolderView * folderview)756 void folderview_select_next_unread(FolderView *folderview)
757 {
758 GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
759 GtkTreeIter iter, next;
760 gboolean remember_last;
761
762 if (folderview->opened) {
763 GtkTreePath *path;
764
765 path = gtk_tree_row_reference_get_path(folderview->opened);
766 if (!path)
767 return;
768 gtk_tree_model_get_iter(model, &iter, path);
769 gtk_tree_path_free(path);
770 } else {
771 if (!gtk_tree_model_get_iter_first(model, &iter))
772 return;
773 }
774 if (folderview_find_next_unread(model, &next, &iter)) {
775 remember_last = prefs_common.remember_last_selected;
776 prefs_common.remember_last_selected = FALSE;
777 folderview_select_row(folderview, &next);
778 prefs_common.remember_last_selected = remember_last;
779 return;
780 }
781
782 if (!folderview->opened)
783 return;
784
785 /* search again from the first row */
786 if (folderview_find_next_unread(model, &next, NULL)) {
787 remember_last = prefs_common.remember_last_selected;
788 prefs_common.remember_last_selected = FALSE;
789 folderview_select_row(folderview, &next);
790 prefs_common.remember_last_selected = remember_last;
791 }
792 }
793
folderview_get_selected_item(FolderView * folderview)794 FolderItem *folderview_get_selected_item(FolderView *folderview)
795 {
796 GtkTreePath *path;
797 GtkTreeIter iter;
798 FolderItem *item = NULL;
799
800 if (!folderview->selected)
801 return NULL;
802
803 path = gtk_tree_row_reference_get_path(folderview->selected);
804 if (!path)
805 return NULL;
806 gtk_tree_model_get_iter(GTK_TREE_MODEL(folderview->store), &iter, path);
807 gtk_tree_path_free(path);
808 gtk_tree_model_get(GTK_TREE_MODEL(folderview->store), &iter,
809 COL_FOLDER_ITEM, &item, -1);
810
811 return item;
812 }
813
folderview_set_opened_item(FolderView * folderview,FolderItem * item)814 void folderview_set_opened_item(FolderView *folderview, FolderItem *item)
815 {
816 GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
817 GtkTreeIter iter;
818 GtkTreePath *path;
819
820 gtk_tree_row_reference_free(folderview->opened);
821 folderview->opened = NULL;
822
823 if (!item)
824 return;
825
826 if (gtkut_tree_model_find_by_column_data
827 (model, &iter, NULL, COL_FOLDER_ITEM, item)) {
828 path = gtk_tree_model_get_path(model, &iter);
829 folderview->opened = gtk_tree_row_reference_new(model, path);
830 gtk_tree_path_free(path);
831 }
832 }
833
folderview_update_opened_msg_num(FolderView * folderview)834 void folderview_update_opened_msg_num(FolderView *folderview)
835 {
836 GtkTreePath *path;
837 GtkTreeIter iter;
838
839 if (!folderview->opened)
840 return;
841
842 path = gtk_tree_row_reference_get_path(folderview->opened);
843 if (!path)
844 return;
845 gtk_tree_model_get_iter(GTK_TREE_MODEL(folderview->store), &iter, path);
846 gtk_tree_path_free(path);
847
848 folderview_update_row(folderview, &iter);
849 }
850
folderview_append_item(FolderView * folderview,GtkTreeIter * iter,FolderItem * item,gboolean expand_parent)851 gboolean folderview_append_item(FolderView *folderview, GtkTreeIter *iter,
852 FolderItem *item, gboolean expand_parent)
853 {
854 FolderItem *parent_item;
855 GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
856 GtkTreeIter iter_, child;
857 GtkTreeIter *iter_p = &iter_;
858
859 g_return_val_if_fail(item != NULL, FALSE);
860 g_return_val_if_fail(item->folder != NULL, FALSE);
861
862 parent_item = item->parent;
863
864 if (!parent_item)
865 iter_p = NULL;
866 else if (!gtkut_tree_model_find_by_column_data
867 (model, iter_p, NULL, COL_FOLDER_ITEM, parent_item))
868 return FALSE;
869
870 if (!gtkut_tree_model_find_by_column_data
871 (model, &child, iter_p, COL_FOLDER_ITEM, item)) {
872 gtk_tree_store_append(folderview->store, &child, iter_p);
873 gtk_tree_store_set(folderview->store, &child,
874 COL_FOLDER_NAME, item->name,
875 COL_FOLDER_ITEM, item,
876 -1);
877 folderview_update_row(folderview, &child);
878 if (iter)
879 *iter = child;
880 if (expand_parent && iter_p) {
881 GtkTreePath *path;
882
883 path = gtk_tree_model_get_path(model, iter_p);
884 gtk_tree_view_expand_row
885 (GTK_TREE_VIEW(folderview->treeview),
886 path, FALSE);
887 gtk_tree_path_free(path);
888 }
889 return TRUE;
890 }
891
892 return FALSE;
893 }
894
folderview_set_folders(FolderView * folderview)895 static void folderview_set_folders(FolderView *folderview)
896 {
897 GList *list;
898
899 list = folder_get_list();
900
901 for (; list != NULL; list = list->next)
902 folderview_append_folder(folderview, FOLDER(list->data));
903 }
904
folderview_scan_tree_func(Folder * folder,FolderItem * item,gpointer data)905 static void folderview_scan_tree_func(Folder *folder, FolderItem *item,
906 gpointer data)
907 {
908 GList *list;
909 gchar *rootpath;
910
911 if (FOLDER_IS_LOCAL(folder))
912 rootpath = LOCAL_FOLDER(folder)->rootpath;
913 else if (FOLDER_TYPE(folder) == F_IMAP && folder->account &&
914 folder->account->recv_server)
915 rootpath = folder->account->recv_server;
916 else if (FOLDER_TYPE(folder) == F_NEWS && folder->account &&
917 folder->account->nntp_server)
918 rootpath = folder->account->nntp_server;
919 else
920 return;
921
922 for (list = folderview_list; list != NULL; list = list->next) {
923 FolderView *folderview = (FolderView *)list->data;
924 MainWindow *mainwin = folderview->mainwin;
925 gchar *str;
926
927 if (item->path)
928 str = g_strdup_printf(_("Scanning folder %s%c%s ..."),
929 rootpath, G_DIR_SEPARATOR,
930 item->path);
931 else
932 str = g_strdup_printf(_("Scanning folder %s ..."),
933 rootpath);
934
935 STATUSBAR_PUSH(mainwin, str);
936 STATUSBAR_POP(mainwin);
937 g_free(str);
938 }
939 }
940
label_window_create(const gchar * str)941 static GtkWidget *label_window_create(const gchar *str)
942 {
943 GtkWidget *window;
944 GtkWidget *label;
945
946 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
947 gtk_widget_set_size_request(window, 380, 60);
948 gtk_container_set_border_width(GTK_CONTAINER(window), 8);
949 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
950 gtk_window_set_title(GTK_WINDOW(window), str);
951 gtk_window_set_modal(GTK_WINDOW(window), TRUE);
952 gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, FALSE);
953 manage_window_set_transient(GTK_WINDOW(window));
954 g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(gtk_true),
955 NULL);
956
957 label = gtk_label_new(str);
958 gtk_container_add(GTK_CONTAINER(window), label);
959 gtk_widget_show(label);
960
961 gtk_widget_show(window);
962
963 return window;
964 }
965
folderview_rescan_tree(FolderView * folderview,Folder * folder)966 static void folderview_rescan_tree(FolderView *folderview, Folder *folder)
967 {
968 GtkWidget *window;
969 AlertValue avalue;
970
971 g_return_if_fail(folder != NULL);
972
973 if (!folder->klass->scan_tree) return;
974
975 avalue = alertpanel
976 (_("Rebuild folder tree"),
977 _("The folder tree will be rebuilt. Continue?"),
978 GTK_STOCK_YES, GTK_STOCK_NO, NULL);
979 if (avalue != G_ALERTDEFAULT) return;
980
981 if (!FOLDER_IS_LOCAL(folder) &&
982 !main_window_toggle_online_if_offline(folderview->mainwin))
983 return;
984
985 inc_lock();
986 window = label_window_create(_("Rebuilding folder tree..."));
987
988 summary_show(folderview->summaryview, NULL, FALSE);
989 GTK_EVENTS_FLUSH();
990
991 folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
992 if (folder->klass->scan_tree(folder) < 0)
993 alertpanel_error(_("Rebuilding of the folder tree failed."));
994 folder_set_ui_func(folder, NULL, NULL);
995
996 folder_write_list();
997 folderview_set_all();
998 statusbar_pop_all();
999
1000 gtk_widget_destroy(window);
1001 inc_unlock();
1002 }
1003
folderview_check_new(Folder * folder)1004 gint folderview_check_new(Folder *folder)
1005 {
1006 FolderItem *item;
1007 FolderView *folderview;
1008 GtkTreeModel *model;
1009 GtkTreeIter iter;
1010 gboolean valid;
1011 gint prev_new, prev_unread, n_updated = 0;
1012
1013 folderview = (FolderView *)folderview_list->data;
1014 model = GTK_TREE_MODEL(folderview->store);
1015
1016 if (folder && FOLDER_IS_REMOTE(folder)) {
1017 if (!main_window_toggle_online_if_offline(folderview->mainwin))
1018 return 0;
1019 }
1020
1021 inc_lock();
1022 main_window_lock(folderview->mainwin);
1023 gtk_widget_set_sensitive(folderview->treeview, FALSE);
1024 GTK_EVENTS_FLUSH();
1025
1026 for (valid = gtk_tree_model_get_iter_first(model, &iter);
1027 valid; valid = gtkut_tree_model_next(model, &iter)) {
1028 item = NULL;
1029 gtk_tree_model_get(model, &iter,
1030 COL_FOLDER_ITEM, &item, -1);
1031 if (!item || !item->path || !item->folder) continue;
1032 if (item->stype == F_VIRTUAL) continue;
1033 if (item->no_select) continue;
1034 if (folder && folder != item->folder) continue;
1035 if (!folder && FOLDER_IS_REMOTE(item->folder)) continue;
1036
1037 prev_new = item->new;
1038 prev_unread = item->unread;
1039 folderview_scan_tree_func(item->folder, item, NULL);
1040 if (folder_item_scan(item) < 0) {
1041 if (folder && FOLDER_IS_REMOTE(folder) &&
1042 REMOTE_FOLDER(folder)->session == NULL)
1043 break;
1044 }
1045 folderview_update_row(folderview, &iter);
1046 if (item->stype != F_TRASH && item->stype != F_JUNK) {
1047 if (prev_unread < item->unread)
1048 n_updated += item->unread - prev_unread;
1049 else if (prev_new < item->new)
1050 n_updated += item->new - prev_new;
1051 }
1052 }
1053
1054 gtk_widget_set_sensitive(folderview->treeview, TRUE);
1055 main_window_unlock(folderview->mainwin);
1056 inc_unlock();
1057 statusbar_pop_all();
1058
1059 folder_write_list();
1060
1061 return n_updated;
1062 }
1063
folderview_check_new_item(FolderItem * item)1064 gint folderview_check_new_item(FolderItem *item)
1065 {
1066 Folder *folder;
1067 FolderView *folderview;
1068 GtkTreeModel *model;
1069 GtkTreeIter iter;
1070 gint prev_new, prev_unread, n_updated = 0;
1071
1072 g_return_val_if_fail(item != NULL, 0);
1073 g_return_val_if_fail(item->folder != NULL, 0);
1074
1075 if (!item->path || item->no_select)
1076 return 0;
1077
1078 folderview = (FolderView *)folderview_list->data;
1079 model = GTK_TREE_MODEL(folderview->store);
1080
1081 folder = item->folder;
1082
1083 if (!FOLDER_IS_LOCAL(folder)) {
1084 if (!main_window_toggle_online_if_offline(folderview->mainwin))
1085 return 0;
1086 }
1087
1088 if (!gtkut_tree_model_find_by_column_data
1089 (model, &iter, NULL, COL_FOLDER_ITEM, item))
1090 return 0;
1091
1092 inc_lock();
1093 main_window_lock(folderview->mainwin);
1094 gtk_widget_set_sensitive(folderview->treeview, FALSE);
1095 GTK_EVENTS_FLUSH();
1096
1097 prev_new = item->new;
1098 prev_unread = item->unread;
1099 folderview_scan_tree_func(folder, item, NULL);
1100 folder_item_scan(item);
1101 folderview_update_row(folderview, &iter);
1102 if (item->stype != F_TRASH && item->stype != F_JUNK) {
1103 if (prev_unread < item->unread)
1104 n_updated = item->unread - prev_unread;
1105 else if (prev_new < item->new)
1106 n_updated = item->new - prev_new;
1107 }
1108
1109 gtk_widget_set_sensitive(folderview->treeview, TRUE);
1110 main_window_unlock(folderview->mainwin);
1111 inc_unlock();
1112 statusbar_pop_all();
1113
1114 folder_write_list();
1115
1116 return n_updated;
1117 }
1118
folderview_check_new_all(void)1119 gint folderview_check_new_all(void)
1120 {
1121 GList *list;
1122 GtkWidget *window;
1123 FolderView *folderview;
1124 gint n_updated = 0;
1125
1126 folderview = (FolderView *)folderview_list->data;
1127
1128 inc_lock();
1129 main_window_lock(folderview->mainwin);
1130 window = label_window_create
1131 (_("Checking for new messages in all folders..."));
1132
1133 list = folder_get_list();
1134 for (; list != NULL; list = list->next) {
1135 Folder *folder = list->data;
1136
1137 n_updated += folderview_check_new(folder);
1138 }
1139
1140 gtk_widget_destroy(window);
1141 main_window_unlock(folderview->mainwin);
1142 inc_unlock();
1143
1144 return n_updated;
1145 }
1146
folderview_search_new_recursive(GtkTreeModel * model,GtkTreeIter * iter)1147 static gboolean folderview_search_new_recursive(GtkTreeModel *model,
1148 GtkTreeIter *iter)
1149 {
1150 FolderItem *item = NULL;
1151 GtkTreeIter iter_;
1152 gboolean valid;
1153
1154 if (iter) {
1155 gtk_tree_model_get(model, iter, COL_FOLDER_ITEM, &item, -1);
1156 if (item) {
1157 if (item->new > 0 ||
1158 (item->stype == F_QUEUE && item->total > 0))
1159 return TRUE;
1160 }
1161 valid = gtk_tree_model_iter_children(model, &iter_, iter);
1162 } else
1163 valid = gtk_tree_model_get_iter_first(model, &iter_);
1164
1165 while (valid) {
1166 if (folderview_search_new_recursive(model, &iter_) == TRUE)
1167 return TRUE;
1168 valid = gtk_tree_model_iter_next(model, &iter_);
1169 }
1170
1171 return FALSE;
1172 }
1173
folderview_have_new_children(FolderView * folderview,GtkTreeIter * iter)1174 static gboolean folderview_have_new_children(FolderView *folderview,
1175 GtkTreeIter *iter)
1176 {
1177 GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
1178 GtkTreeIter iter_;
1179 gboolean valid;
1180
1181 if (iter)
1182 valid = gtk_tree_model_iter_children(model, &iter_, iter);
1183 else
1184 valid = gtk_tree_model_get_iter_first(model, &iter_);
1185
1186 while (valid) {
1187 if (folderview_search_new_recursive(model, &iter_) == TRUE)
1188 return TRUE;
1189 valid = gtk_tree_model_iter_next(model, &iter_);
1190 }
1191
1192 return FALSE;
1193 }
1194
folderview_search_unread_recursive(GtkTreeModel * model,GtkTreeIter * iter)1195 static gboolean folderview_search_unread_recursive(GtkTreeModel *model,
1196 GtkTreeIter *iter)
1197 {
1198 FolderItem *item = NULL;
1199 GtkTreeIter iter_;
1200 gboolean valid;
1201
1202 if (iter) {
1203 gtk_tree_model_get(model, iter, COL_FOLDER_ITEM, &item, -1);
1204 if (item) {
1205 if (item->stype == F_TRASH)
1206 return FALSE;
1207 if (item->unread > 0 ||
1208 (item->stype == F_QUEUE && item->total > 0))
1209 return TRUE;
1210 }
1211 valid = gtk_tree_model_iter_children(model, &iter_, iter);
1212 } else
1213 valid = gtk_tree_model_get_iter_first(model, &iter_);
1214
1215 while (valid) {
1216 if (folderview_search_unread_recursive(model, &iter_) == TRUE)
1217 return TRUE;
1218 valid = gtk_tree_model_iter_next(model, &iter_);
1219 }
1220
1221 return FALSE;
1222 }
1223
folderview_have_unread_children(FolderView * folderview,GtkTreeIter * iter)1224 static gboolean folderview_have_unread_children(FolderView *folderview,
1225 GtkTreeIter *iter)
1226 {
1227 GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
1228 GtkTreeIter iter_;
1229 gboolean valid;
1230
1231 if (iter)
1232 valid = gtk_tree_model_iter_children(model, &iter_, iter);
1233 else
1234 valid = gtk_tree_model_get_iter_first(model, &iter_);
1235
1236 while (valid) {
1237 if (folderview_search_unread_recursive(model, &iter_) == TRUE)
1238 return TRUE;
1239 valid = gtk_tree_model_iter_next(model, &iter_);
1240 }
1241
1242 return FALSE;
1243 }
1244
folderview_update_row(FolderView * folderview,GtkTreeIter * iter)1245 static void folderview_update_row(FolderView *folderview, GtkTreeIter *iter)
1246 {
1247 GtkTreeStore *store = folderview->store;
1248 GtkTreeModel *model = GTK_TREE_MODEL(store);
1249 GtkTreePath *path;
1250 GtkTreeIter parent;
1251 FolderItem *item = NULL;
1252 GdkPixbuf *pixbuf, *open_pixbuf;
1253 gchar *name, *str;
1254 gchar new_s[11], unread_s[11], total_s[11];
1255 gboolean add_unread_mark;
1256 gboolean use_color;
1257 PangoWeight weight = PANGO_WEIGHT_NORMAL;
1258 GdkColor *foreground = NULL;
1259
1260 gtk_tree_model_get(model, iter, COL_FOLDER_ITEM, &item, -1);
1261 g_return_if_fail(item != NULL);
1262
1263 switch (item->stype) {
1264 case F_INBOX:
1265 pixbuf = open_pixbuf = inbox_pixbuf;
1266 name = g_strdup(FOLDER_IS_LOCAL(item->folder) &&
1267 !strcmp2(item->name, INBOX_DIR) ? _("Inbox") :
1268 item->name);
1269 break;
1270 case F_OUTBOX:
1271 pixbuf = open_pixbuf = outbox_pixbuf;
1272 name = g_strdup(FOLDER_IS_LOCAL(item->folder) &&
1273 !strcmp2(item->name, OUTBOX_DIR) ? _("Sent") :
1274 item->name);
1275 break;
1276 case F_QUEUE:
1277 pixbuf = open_pixbuf = outbox_pixbuf;
1278 name = g_strdup(FOLDER_IS_LOCAL(item->folder) &&
1279 !strcmp2(item->name, QUEUE_DIR) ? _("Queue") :
1280 item->name);
1281 break;
1282 case F_TRASH:
1283 pixbuf = open_pixbuf = trash_pixbuf;
1284 name = g_strdup(FOLDER_IS_LOCAL(item->folder) &&
1285 !strcmp2(item->name, TRASH_DIR) ? _("Trash") :
1286 item->name);
1287 break;
1288 case F_DRAFT:
1289 pixbuf = open_pixbuf = draft_pixbuf;
1290 name = g_strdup(FOLDER_IS_LOCAL(item->folder) &&
1291 !strcmp2(item->name, DRAFT_DIR) ? _("Drafts") :
1292 item->name);
1293 break;
1294 case F_JUNK:
1295 pixbuf = open_pixbuf = junk_pixbuf;
1296 name = g_strdup(FOLDER_IS_LOCAL(item->folder) &&
1297 !strcmp2(item->name, JUNK_DIR) ? _("Junk") :
1298 item->name);
1299 break;
1300 case F_VIRTUAL:
1301 pixbuf = open_pixbuf = virtual_pixbuf;
1302 name = g_strdup(item->name);
1303 break;
1304 default:
1305 if (item->no_select) {
1306 pixbuf = open_pixbuf = foldernoselect_pixbuf;
1307 } else {
1308 pixbuf = folder_pixbuf;
1309 open_pixbuf = folderopen_pixbuf;
1310 }
1311
1312 if (!item->parent) {
1313 switch (FOLDER_TYPE(item->folder)) {
1314 case F_MH:
1315 name = " (MH)"; break;
1316 case F_IMAP:
1317 name = " (IMAP4)"; break;
1318 case F_NEWS:
1319 name = " (News)"; break;
1320 default:
1321 name = "";
1322 }
1323 name = g_strconcat(item->name, name, NULL);
1324 } else {
1325 if (FOLDER_TYPE(item->folder) == F_NEWS &&
1326 item->path &&
1327 !strcmp2(item->name, item->path))
1328 name = get_abbrev_newsgroup_name
1329 (item->path,
1330 prefs_common.ng_abbrev_len);
1331 else
1332 name = g_strdup(item->name);
1333 }
1334 }
1335
1336 path = gtk_tree_model_get_path(model, iter);
1337 if (!gtk_tree_view_row_expanded
1338 (GTK_TREE_VIEW(folderview->treeview), path) &&
1339 folderview_have_unread_children(folderview, iter))
1340 add_unread_mark = TRUE;
1341 else
1342 add_unread_mark = FALSE;
1343 gtk_tree_path_free(path);
1344
1345 if (item->stype == F_QUEUE && item->total > 0 &&
1346 folderview->display_folder_unread) {
1347 str = g_strdup_printf("%s (%d%s)", name, item->total,
1348 add_unread_mark ? "+" : "");
1349 g_free(name);
1350 name = str;
1351 } else if ((item->unread > 0 || add_unread_mark) &&
1352 folderview->display_folder_unread) {
1353 if (item->unread > 0)
1354 str = g_strdup_printf("%s (%d%s)", name, item->unread,
1355 add_unread_mark ? "+" : "");
1356 else
1357 str = g_strdup_printf("%s (+)", name);
1358 g_free(name);
1359 name = str;
1360 }
1361
1362 if (!item->parent) {
1363 strcpy(new_s, "-");
1364 strcpy(unread_s, "-");
1365 strcpy(total_s, "-");
1366 } else {
1367 itos_buf(new_s, item->new);
1368 itos_buf(unread_s, item->unread);
1369 itos_buf(total_s, item->total);
1370 }
1371
1372 if (item->stype == F_OUTBOX || item->stype == F_DRAFT ||
1373 item->stype == F_TRASH || item->stype == F_JUNK) {
1374 use_color = FALSE;
1375 if (item->stype == F_JUNK) {
1376 if ((item->unread > 0) || add_unread_mark)
1377 weight = PANGO_WEIGHT_BOLD;
1378 }
1379 } else if (item->stype == F_QUEUE) {
1380 /* highlight queue folder if there are any messages */
1381 use_color = (item->total > 0);
1382 if (item->total > 0)
1383 weight = PANGO_WEIGHT_BOLD;
1384 } else {
1385 /* if unread messages exist, print with bold font */
1386 if ((item->unread > 0) || add_unread_mark)
1387 weight = PANGO_WEIGHT_BOLD;
1388 /* if new messages exist, print with colored letter */
1389 use_color =
1390 (item->new > 0) ||
1391 (add_unread_mark &&
1392 folderview_have_new_children(folderview, iter));
1393 }
1394
1395 if (item->no_select)
1396 foreground = &folderview->color_noselect;
1397 else if (use_color)
1398 foreground = &folderview->color_new;
1399
1400 gtk_tree_store_set(store, iter,
1401 COL_FOLDER_NAME, name,
1402 COL_NEW, new_s,
1403 COL_UNREAD, unread_s,
1404 COL_TOTAL, total_s,
1405 COL_FOLDER_ITEM, item,
1406 COL_PIXBUF, pixbuf,
1407 COL_PIXBUF_OPEN, open_pixbuf,
1408 COL_FOREGROUND, foreground,
1409 COL_BOLD, weight,
1410 -1);
1411 /* g_print("folderview_update_row: %s: %s\n", item->path, name); */
1412 g_free(name);
1413
1414 item->updated = FALSE;
1415
1416 if (gtkut_tree_view_find_collapsed_parent
1417 (GTK_TREE_VIEW(folderview->treeview), &parent, iter))
1418 folderview_update_row(folderview, &parent);
1419 }
1420
folderview_update_row_all(FolderView * folderview)1421 static void folderview_update_row_all(FolderView *folderview)
1422 {
1423 GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
1424 GtkTreeIter iter;
1425 gboolean valid;
1426
1427 valid = gtk_tree_model_get_iter_first(model, &iter);
1428
1429 while (valid) {
1430 folderview_update_row(folderview, &iter);
1431 valid = gtkut_tree_model_next(model, &iter);
1432 }
1433 }
1434
folderview_update_item(FolderItem * item,gboolean update_summary)1435 void folderview_update_item(FolderItem *item, gboolean update_summary)
1436 {
1437 FolderView *folderview;
1438 GtkTreeIter iter;
1439
1440 g_return_if_fail(item != NULL);
1441
1442 folderview = folderview_get();
1443
1444 if (gtkut_tree_model_find_by_column_data
1445 (GTK_TREE_MODEL(folderview->store), &iter, NULL,
1446 COL_FOLDER_ITEM, item)) {
1447 folderview_update_row(folderview, &iter);
1448 if (update_summary &&
1449 folderview->summaryview->folder_item == item)
1450 summary_show(folderview->summaryview, item, FALSE);
1451 }
1452 }
1453
folderview_update_item_foreach_func(gpointer key,gpointer val,gpointer data)1454 static void folderview_update_item_foreach_func(gpointer key, gpointer val,
1455 gpointer data)
1456 {
1457 folderview_update_item((FolderItem *)key, GPOINTER_TO_INT(data));
1458 }
1459
folderview_update_item_foreach(GHashTable * table,gboolean update_summary)1460 void folderview_update_item_foreach(GHashTable *table, gboolean update_summary)
1461 {
1462 g_hash_table_foreach(table, folderview_update_item_foreach_func,
1463 GINT_TO_POINTER(update_summary));
1464 }
1465
folderview_update_all_updated_func(GNode * node,gpointer data)1466 static gboolean folderview_update_all_updated_func(GNode *node, gpointer data)
1467 {
1468 FolderItem *item;
1469
1470 item = FOLDER_ITEM(node->data);
1471 if (item->updated) {
1472 debug_print("folderview_update_all_updated(): '%s' is updated\n", item->path);
1473 folderview_update_item(item, GPOINTER_TO_INT(data));
1474 }
1475
1476 return FALSE;
1477 }
1478
folderview_update_all_updated(gboolean update_summary)1479 void folderview_update_all_updated(gboolean update_summary)
1480 {
1481 GList *list;
1482 Folder *folder;
1483
1484 for (list = folder_get_list(); list != NULL; list = list->next) {
1485 folder = (Folder *)list->data;
1486 g_node_traverse(folder->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
1487 folderview_update_all_updated_func,
1488 GINT_TO_POINTER(update_summary));
1489 }
1490 }
1491
folderview_insert_item_recursive(FolderView * folderview,FolderItem * item,GtkTreeIter * iter)1492 static gboolean folderview_insert_item_recursive(FolderView *folderview,
1493 FolderItem *item,
1494 GtkTreeIter *iter)
1495 {
1496 GNode *node;
1497 GtkTreeIter iter_;
1498 gboolean valid;
1499
1500 g_return_val_if_fail(item != NULL, FALSE);
1501
1502 valid = folderview_append_item(folderview, &iter_, item, FALSE);
1503 g_return_val_if_fail(valid == TRUE, FALSE);
1504
1505 for (node = item->node->children; node != NULL; node = node->next) {
1506 FolderItem *child_item = FOLDER_ITEM(node->data);
1507 folderview_insert_item_recursive(folderview, child_item, NULL);
1508 }
1509
1510 if (item->node->children && !item->collapsed) {
1511 GtkTreePath *path;
1512
1513 path = gtk_tree_model_get_path
1514 (GTK_TREE_MODEL(folderview->store), &iter_);
1515 gtk_tree_view_expand_row(GTK_TREE_VIEW(folderview->treeview),
1516 path, FALSE);
1517 gtk_tree_path_free(path);
1518 }
1519
1520 if (iter)
1521 *iter = iter_;
1522 return TRUE;
1523 }
1524
folderview_append_folder(FolderView * folderview,Folder * folder)1525 static void folderview_append_folder(FolderView *folderview, Folder *folder)
1526 {
1527 g_return_if_fail(folder != NULL);
1528
1529 folderview_insert_item_recursive
1530 (folderview, FOLDER_ITEM(folder->node->data), NULL);
1531 }
1532
folderview_new_folder(FolderView * folderview)1533 void folderview_new_folder(FolderView *folderview)
1534 {
1535 FolderItem *item;
1536
1537 item = folderview_get_selected_item(folderview);
1538 if (!item)
1539 return;
1540
1541 g_return_if_fail(item->folder != NULL);
1542
1543 if (item->folder->klass->create_folder)
1544 folderview_new_folder_cb(folderview, 0, NULL);
1545 else if (FOLDER_TYPE(item->folder) == F_NEWS)
1546 folderview_new_news_group_cb(folderview, 0, NULL);
1547 }
1548
folderview_rename_folder(FolderView * folderview)1549 void folderview_rename_folder(FolderView *folderview)
1550 {
1551 FolderItem *item;
1552
1553 item = folderview_get_selected_item(folderview);
1554 if (!item)
1555 return;
1556
1557 g_return_if_fail(item->folder != NULL);
1558
1559 if (!item->path) return;
1560 if (item->stype != F_NORMAL) return;
1561
1562 if (item->folder->klass->rename_folder)
1563 folderview_rename_folder_cb(folderview, 0, NULL);
1564 }
1565
folderview_move_folder(FolderView * folderview)1566 void folderview_move_folder(FolderView *folderview)
1567 {
1568 FolderItem *item;
1569
1570 item = folderview_get_selected_item(folderview);
1571 if (!item)
1572 return;
1573
1574 g_return_if_fail(item->folder != NULL);
1575
1576 if (!item->path) return;
1577 if (item->stype != F_NORMAL && item->stype != F_VIRTUAL) return;
1578
1579 if (item->folder->klass->move_folder)
1580 folderview_move_folder_cb(folderview, 0, NULL);
1581 }
1582
folderview_delete_folder(FolderView * folderview)1583 void folderview_delete_folder(FolderView *folderview)
1584 {
1585 FolderItem *item;
1586
1587 item = folderview_get_selected_item(folderview);
1588 if (!item)
1589 return;
1590
1591 g_return_if_fail(item->folder != NULL);
1592
1593 if (!item->path) return;
1594 if (item->stype != F_NORMAL) return;
1595
1596 if (item->folder->klass->remove_folder)
1597 folderview_delete_folder_cb(folderview, 0, NULL);
1598 else if (FOLDER_TYPE(item->folder) == F_NEWS)
1599 folderview_rm_news_group_cb(folderview, 0, NULL);
1600 }
1601
folderview_check_new_selected(FolderView * folderview)1602 void folderview_check_new_selected(FolderView *folderview)
1603 {
1604 FolderItem *item;
1605
1606 item = folderview_get_selected_item(folderview);
1607 if (!item)
1608 return;
1609
1610 g_return_if_fail(item->folder != NULL);
1611 if (item->parent != NULL) return;
1612
1613 folderview_check_new(item->folder);
1614 }
1615
folderview_remove_mailbox(FolderView * folderview)1616 void folderview_remove_mailbox(FolderView *folderview)
1617 {
1618 FolderItem *item;
1619
1620 item = folderview_get_selected_item(folderview);
1621 if (!item)
1622 return;
1623
1624 g_return_if_fail(item->folder != NULL);
1625 if (item->parent != NULL) return;
1626
1627 switch (FOLDER_TYPE(item->folder)) {
1628 case F_MH:
1629 case F_MBOX:
1630 case F_MAILDIR:
1631 folderview_remove_mailbox_cb(folderview, 0, NULL);
1632 break;
1633 case F_IMAP:
1634 folderview_rm_imap_server_cb(folderview, 0, NULL);
1635 break;
1636 case F_NEWS:
1637 folderview_rm_news_server_cb(folderview, 0, NULL);
1638 break;
1639 default:
1640 break;
1641 }
1642 }
1643
folderview_rebuild_tree(FolderView * folderview)1644 void folderview_rebuild_tree(FolderView *folderview)
1645 {
1646 FolderItem *item;
1647
1648 item = folderview_get_selected_item(folderview);
1649 if (!item)
1650 return;
1651
1652 g_return_if_fail(item->folder != NULL);
1653 if (item->parent != NULL) return;
1654
1655 folderview_rescan_tree(folderview, item->folder);
1656 }
1657
folderview_menu_popup(FolderView * folderview,GdkEventButton * event)1658 static gboolean folderview_menu_popup(FolderView *folderview,
1659 GdkEventButton *event)
1660 {
1661 FolderItem *item = NULL;
1662 Folder *folder;
1663 GtkWidget *popup;
1664 GtkItemFactory *ifactory;
1665 GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
1666 GtkTreeIter iter;
1667 gboolean new_folder = FALSE;
1668 gboolean rename_folder = FALSE;
1669 gboolean move_folder = FALSE;
1670 gboolean delete_folder = FALSE;
1671 gboolean empty_junk = FALSE;
1672 gboolean empty_trash = FALSE;
1673 gboolean download_msg = FALSE;
1674 gboolean update_tree = FALSE;
1675 gboolean update_summary = FALSE;
1676 gboolean mark_all_read = FALSE;
1677 gboolean send_queue = FALSE;
1678 gboolean rescan_tree = FALSE;
1679 gboolean remove_tree = FALSE;
1680 gboolean search_folder = FALSE;
1681 gboolean folder_property = FALSE;
1682
1683 if (!gtk_tree_selection_get_selected
1684 (folderview->selection, NULL, &iter))
1685 return FALSE;
1686
1687 gtk_tree_model_get(model, &iter, COL_FOLDER_ITEM, &item, -1);
1688 g_return_val_if_fail(item != NULL, FALSE);
1689 g_return_val_if_fail(item->folder != NULL, FALSE);
1690 folder = item->folder;
1691
1692 if (folderview->mainwin->lock_count == 0) {
1693 new_folder = TRUE;
1694 folder_property = TRUE;
1695 search_folder = TRUE;
1696 if (item->parent == NULL) {
1697 update_tree = remove_tree = TRUE;
1698 } else {
1699 if (FOLDER_TYPE(folder) != F_IMAP)
1700 mark_all_read = TRUE;
1701 if (gtkut_tree_row_reference_equal
1702 (folderview->selected, folderview->opened)) {
1703 update_summary = TRUE;
1704 mark_all_read = TRUE;
1705 }
1706 }
1707 if (FOLDER_IS_LOCAL(folder) || FOLDER_TYPE(folder) == F_IMAP) {
1708 if (item->parent == NULL)
1709 update_tree = rescan_tree = TRUE;
1710 else if (item->stype == F_NORMAL) {
1711 rename_folder = delete_folder = TRUE;
1712 if (folder->klass->move_folder)
1713 move_folder = TRUE;
1714 } else if (item->stype == F_TRASH) {
1715 if (item->total > 0)
1716 empty_trash = TRUE;
1717 } else if (item->stype == F_JUNK) {
1718 if (item->total > 0)
1719 empty_junk = TRUE;
1720 } else if (item->stype == F_QUEUE) {
1721 if (item->total > 0)
1722 send_queue = TRUE;
1723 }
1724 } else if (FOLDER_TYPE(folder) == F_NEWS) {
1725 if (item->parent != NULL)
1726 delete_folder = TRUE;
1727 }
1728 if (item->stype == F_VIRTUAL) {
1729 new_folder = FALSE;
1730 move_folder = rename_folder = delete_folder = TRUE;
1731 }
1732 if (FOLDER_TYPE(folder) == F_IMAP ||
1733 FOLDER_TYPE(folder) == F_NEWS) {
1734 if (item->no_select == FALSE &&
1735 item->stype != F_VIRTUAL)
1736 download_msg = TRUE;
1737 }
1738 } else {
1739 search_folder = TRUE;
1740 if (item->parent) {
1741 if (FOLDER_TYPE(folder) != F_IMAP)
1742 mark_all_read = TRUE;
1743 if (gtkut_tree_row_reference_equal
1744 (folderview->selected, folderview->opened)) {
1745 update_summary = TRUE;
1746 mark_all_read = TRUE;
1747 }
1748 if (item->stype == F_TRASH) {
1749 if (item->total > 0)
1750 empty_trash = TRUE;
1751 } else if (item->stype == F_JUNK) {
1752 if (item->total > 0)
1753 empty_junk = TRUE;
1754 }
1755 }
1756 }
1757
1758 #define SET_SENS(factory, name, sens) \
1759 { \
1760 GtkWidget *widget; \
1761 widget = gtk_item_factory_get_item(factory, name); \
1762 if (widget) \
1763 gtk_widget_set_sensitive(widget, sens); \
1764 }
1765
1766 #define SET_VISIBILITY(factory, name, visible) \
1767 { \
1768 GtkWidget *widget; \
1769 widget = gtk_item_factory_get_item(factory, name); \
1770 if (widget) { \
1771 if (visible) \
1772 gtk_widget_show(widget); \
1773 else \
1774 gtk_widget_hide(widget); \
1775 } \
1776 }
1777
1778 #define SET_VISIBILITY2(factory, name, visible) \
1779 { \
1780 GtkWidget *widget; \
1781 widget = gtk_item_factory_get_item(factory, name); \
1782 if (widget) { \
1783 GList *child; \
1784 GtkWidget *sep = NULL; \
1785 \
1786 child = g_list_find \
1787 (GTK_MENU_SHELL(popup)->children, widget); \
1788 if (child && child->next) \
1789 sep = GTK_WIDGET(child->next->data); \
1790 if (visible) { \
1791 gtk_widget_show(widget); \
1792 gtk_widget_show(sep); \
1793 } else { \
1794 gtk_widget_hide(widget); \
1795 gtk_widget_hide(sep); \
1796 } \
1797 } \
1798 }
1799
1800 if (FOLDER_IS_LOCAL(folder)) {
1801 popup = folderview->mail_popup;
1802 ifactory = folderview->mail_factory;
1803 } else if (FOLDER_TYPE(folder) == F_IMAP) {
1804 popup = folderview->imap_popup;
1805 ifactory = folderview->imap_factory;
1806 } else if (FOLDER_TYPE(folder) == F_NEWS) {
1807 popup = folderview->news_popup;
1808 ifactory = folderview->news_factory;
1809 } else
1810 return FALSE;
1811
1812 menu_set_insensitive_all(GTK_MENU_SHELL(popup));
1813
1814 SET_SENS(ifactory, "/Create new folder...", new_folder);
1815 SET_SENS(ifactory, "/Rename folder...", rename_folder);
1816 SET_SENS(ifactory, "/Move folder...", move_folder);
1817 SET_SENS(ifactory, "/Delete folder", delete_folder);
1818 SET_SENS(ifactory, "/Empty junk", empty_junk);
1819 SET_SENS(ifactory, "/Empty trash", empty_trash);
1820 SET_SENS(ifactory, "/Download", download_msg);
1821 SET_SENS(ifactory, "/Check for new messages", update_tree);
1822 SET_SENS(ifactory, "/Rebuild folder tree", rescan_tree);
1823 SET_SENS(ifactory, "/Update summary", update_summary);
1824 SET_SENS(ifactory, "/Mark all read", mark_all_read);
1825 SET_SENS(ifactory, "/Send queued messages", send_queue);
1826 SET_SENS(ifactory, "/Search messages...", search_folder);
1827 SET_SENS(ifactory, "/Edit search condition...", search_folder);
1828 SET_SENS(ifactory, "/Properties...", folder_property);
1829
1830 if (FOLDER_TYPE(folder) == F_NEWS) {
1831 SET_SENS(ifactory, "/Subscribe to newsgroup...", new_folder);
1832 SET_SENS(ifactory, "/Remove newsgroup", delete_folder);
1833 SET_VISIBILITY(ifactory, "/Remove newsgroup",
1834 item->stype != F_VIRTUAL);
1835 SET_VISIBILITY(ifactory, "/Rename folder...",
1836 item->stype == F_VIRTUAL);
1837 SET_VISIBILITY(ifactory, "/Delete folder",
1838 item->stype == F_VIRTUAL);
1839 }
1840
1841 if (item->stype == F_JUNK) {
1842 SET_VISIBILITY(ifactory, "/Empty junk", TRUE);
1843 SET_VISIBILITY2(ifactory, "/Empty trash", TRUE);
1844 SET_VISIBILITY(ifactory, "/Empty trash", FALSE);
1845 } else {
1846 SET_VISIBILITY(ifactory, "/Empty junk", FALSE);
1847 SET_VISIBILITY2(ifactory, "/Empty trash",
1848 item->stype == F_TRASH);
1849 }
1850
1851 SET_VISIBILITY(ifactory, "/Check for new messages",
1852 item->parent == NULL);
1853 SET_VISIBILITY(ifactory, "/Rebuild folder tree", item->parent == NULL);
1854 SET_VISIBILITY(ifactory, "/Update summary", item->parent != NULL);
1855
1856 if (FOLDER_TYPE(folder) == F_NEWS) {
1857 SET_VISIBILITY2(ifactory, "/Mark all read",
1858 item->parent != NULL && item->stype != F_QUEUE);
1859 } else {
1860 SET_VISIBILITY(ifactory, "/Mark all read",
1861 item->parent != NULL && item->stype != F_QUEUE);
1862 if (item->parent != NULL) {
1863 SET_VISIBILITY2(ifactory, "/Send queued messages", TRUE);
1864 SET_VISIBILITY(ifactory, "/Send queued messages",
1865 item->stype == F_QUEUE);
1866 } else {
1867 SET_VISIBILITY2(ifactory, "/Send queued messages",
1868 item->stype == F_QUEUE);
1869 }
1870 }
1871
1872 SET_VISIBILITY(ifactory, "/Search messages...",
1873 item->stype != F_VIRTUAL);
1874 SET_VISIBILITY(ifactory, "/Edit search condition...",
1875 item->stype == F_VIRTUAL);
1876
1877 #undef SET_SENS
1878 #undef SET_VISIBILITY
1879 #undef SET_VISIBILITY2
1880
1881 syl_plugin_signal_emit("folderview-menu-popup", ifactory);
1882
1883 if (event)
1884 gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
1885 event->button, event->time);
1886 else
1887 gtk_menu_popup(GTK_MENU(popup), NULL, NULL,
1888 menu_widget_position, folderview->treeview,
1889 0, GDK_CURRENT_TIME);
1890
1891 return FALSE;
1892 }
1893
1894
1895 /* callback functions */
1896
folderview_button_pressed(GtkWidget * widget,GdkEventButton * event,FolderView * folderview)1897 static gboolean folderview_button_pressed(GtkWidget *widget,
1898 GdkEventButton *event,
1899 FolderView *folderview)
1900 {
1901 GtkTreeView *treeview = GTK_TREE_VIEW(widget);
1902 GtkTreePath *path;
1903
1904 if (!event)
1905 return FALSE;
1906
1907 if (!gtk_tree_view_get_path_at_pos(treeview, event->x, event->y,
1908 &path, NULL, NULL, NULL))
1909 return TRUE;
1910
1911 if (folderview->selection_locked ||
1912 summary_is_locked(folderview->summaryview))
1913 return TRUE;
1914
1915 if (event->button == 1 || event->button == 2) {
1916 if (event->type == GDK_2BUTTON_PRESS) {
1917 if (gtk_tree_view_row_expanded(treeview, path))
1918 gtk_tree_view_collapse_row(treeview, path);
1919 else
1920 gtk_tree_view_expand_row(treeview, path, FALSE);
1921 }
1922 folderview->open_folder = TRUE;
1923 } else if (event->button == 3) {
1924 if (folderview->selected) {
1925 folderview->prev_selected =
1926 gtk_tree_row_reference_copy
1927 (folderview->selected);
1928 }
1929 gtk_tree_selection_select_path(folderview->selection, path);
1930 folderview_menu_popup(folderview, event);
1931 gtk_tree_path_free(path);
1932 return TRUE;
1933 }
1934
1935 gtk_tree_path_free(path);
1936 return FALSE;
1937 }
1938
folderview_button_released(GtkWidget * treeview,GdkEventButton * event,FolderView * folderview)1939 static gboolean folderview_button_released(GtkWidget *treeview,
1940 GdkEventButton *event,
1941 FolderView *folderview)
1942 {
1943 folderview->open_folder = FALSE;
1944 return FALSE;
1945 }
1946
folderview_key_pressed(GtkWidget * widget,GdkEventKey * event,FolderView * folderview)1947 static gboolean folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
1948 FolderView *folderview)
1949 {
1950 GtkTreeView *treeview = GTK_TREE_VIEW(widget);
1951 GtkTreePath *opened = NULL, *selected = NULL;
1952 GtkAdjustment *adj;
1953 gboolean moved;
1954
1955 if (!event) return FALSE;
1956
1957 if (folderview->selection_locked ||
1958 summary_is_locked(folderview->summaryview))
1959 return TRUE;
1960
1961 switch (event->keyval) {
1962 case GDK_Return:
1963 case GDK_KP_Enter:
1964 if (folderview->selected) {
1965 folderview_select_row_ref(folderview,
1966 folderview->selected);
1967 }
1968 return TRUE;
1969 case GDK_space:
1970 case GDK_KP_Space:
1971 if (folderview->selected) {
1972 if (folderview->opened)
1973 opened = gtk_tree_row_reference_get_path
1974 (folderview->opened);
1975 selected = gtk_tree_row_reference_get_path
1976 (folderview->selected);
1977 if (opened && selected &&
1978 gtk_tree_path_compare(opened, selected) == 0 &&
1979 (!folderview->summaryview->folder_item ||
1980 folderview->summaryview->folder_item->total == 0))
1981 folderview_select_next_unread(folderview);
1982 else
1983 folderview_select_row_ref(folderview,
1984 folderview->selected);
1985 gtk_tree_path_free(selected);
1986 gtk_tree_path_free(opened);
1987 return TRUE;
1988 }
1989 break;
1990 case GDK_Left:
1991 case GDK_KP_Left:
1992 if ((event->state &
1993 (GDK_SHIFT_MASK|GDK_MOD1_MASK|GDK_CONTROL_MASK)) != 0)
1994 return FALSE;
1995 adj = gtk_scrolled_window_get_hadjustment
1996 (GTK_SCROLLED_WINDOW(folderview->scrolledwin));
1997 if (adj->lower < adj->value)
1998 return FALSE;
1999 if (folderview->selected) {
2000 selected = gtk_tree_row_reference_get_path
2001 (folderview->selected);
2002 if (selected) {
2003 if (gtk_tree_view_row_expanded(treeview, selected)) {
2004 gtk_tree_view_collapse_row(treeview, selected);
2005 gtk_tree_path_free(selected);
2006 return TRUE;
2007 }
2008 gtk_tree_path_free(selected);
2009 }
2010 }
2011 g_signal_emit_by_name(G_OBJECT(treeview),
2012 "select-cursor-parent", &moved);
2013 return TRUE;
2014 case GDK_Right:
2015 case GDK_KP_Right:
2016 if ((event->state &
2017 (GDK_SHIFT_MASK|GDK_MOD1_MASK|GDK_CONTROL_MASK)) != 0)
2018 return FALSE;
2019 adj = gtk_scrolled_window_get_hadjustment
2020 (GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2021 if (adj->upper - adj->page_size > adj->value)
2022 return FALSE;
2023 if (folderview->selected) {
2024 selected = gtk_tree_row_reference_get_path
2025 (folderview->selected);
2026 if (selected) {
2027 if (!gtk_tree_view_row_expanded(treeview, selected)) {
2028 gtk_tree_view_expand_row(treeview, selected, FALSE);
2029 gtk_tree_path_free(selected);
2030 return TRUE;
2031 }
2032 gtk_tree_path_free(selected);
2033 }
2034 }
2035 break;
2036 case GDK_F10:
2037 if ((event->state & GDK_SHIFT_MASK) != 0) {
2038 folderview_menu_popup(folderview, NULL);
2039 return TRUE;
2040 }
2041 break;
2042 case GDK_Menu:
2043 folderview_menu_popup(folderview, NULL);
2044 return TRUE;
2045 default:
2046 break;
2047 }
2048
2049 return FALSE;
2050 }
2051
folderview_focus_idle_func(gpointer data)2052 static gboolean folderview_focus_idle_func(gpointer data)
2053 {
2054 FolderView *folderview = (FolderView *)data;
2055
2056 gdk_threads_enter();
2057 GTK_WIDGET_SET_FLAGS(folderview->treeview, GTK_CAN_FOCUS);
2058 gdk_threads_leave();
2059
2060 return FALSE;
2061 }
2062
folderview_selection_changed(GtkTreeSelection * selection,FolderView * folderview)2063 static void folderview_selection_changed(GtkTreeSelection *selection,
2064 FolderView *folderview)
2065 {
2066 GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
2067 FolderItem *item = NULL;
2068 GtkTreeIter iter;
2069 GtkTreePath *path;
2070 gboolean opened;
2071
2072 if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) {
2073 if (folderview->selected) {
2074 gtk_tree_row_reference_free(folderview->selected);
2075 folderview->selected = NULL;
2076 }
2077 return;
2078 }
2079
2080 path = gtk_tree_model_get_path(model, &iter);
2081
2082 gtk_tree_row_reference_free(folderview->selected);
2083 folderview->selected = gtk_tree_row_reference_new(model, path);
2084
2085 main_window_set_menu_sensitive(folderview->mainwin);
2086
2087 if (!folderview->open_folder) {
2088 gtk_tree_path_free(path);
2089 return;
2090 }
2091 folderview->open_folder = FALSE;
2092
2093 gtk_tree_model_get(model, &iter, COL_FOLDER_ITEM, &item, -1);
2094 if (!item) {
2095 gtk_tree_path_free(path);
2096 return;
2097 }
2098
2099 if (item->path)
2100 debug_print(_("Folder %s is selected\n"), item->path);
2101
2102 if (summary_is_locked(folderview->summaryview)) {
2103 gtk_tree_path_free(path);
2104 return;
2105 }
2106
2107 if (folderview->opened) {
2108 GtkTreePath *open_path = NULL;
2109
2110 open_path = gtk_tree_row_reference_get_path(folderview->opened);
2111 if (open_path && gtk_tree_path_compare(open_path, path) == 0) {
2112 gtk_tree_path_free(open_path);
2113 gtk_tree_path_free(path);
2114 return;
2115 }
2116 gtk_tree_path_free(open_path);
2117 }
2118
2119 folderview->selection_locked = TRUE;
2120
2121 GTK_EVENTS_FLUSH();
2122 opened = summary_show(folderview->summaryview, item, FALSE);
2123
2124 if (opened) {
2125 gtk_tree_row_reference_free(folderview->opened);
2126 folderview->opened = gtk_tree_row_reference_new(model, path);
2127 gtk_tree_view_scroll_to_cell
2128 (GTK_TREE_VIEW(folderview->treeview), path, NULL, FALSE,
2129 0.0, 0.0);
2130 if (item->total > 0) {
2131 /* don't let GtkTreeView::gtk_tree_view_button_press()
2132 * grab focus */
2133 GTK_WIDGET_UNSET_FLAGS(folderview->treeview,
2134 GTK_CAN_FOCUS);
2135 g_idle_add(folderview_focus_idle_func, folderview);
2136 }
2137 } else
2138 folderview_select_row_ref(folderview, folderview->opened);
2139
2140 gtk_tree_path_free(path);
2141
2142 folderview->selection_locked = FALSE;
2143
2144 if (prefs_common.change_account_on_folder_sel) {
2145 PrefsAccount *account;
2146
2147 account = account_find_from_item_property(item);
2148 if (!account && item->folder)
2149 account = item->folder->account;
2150 if (!account)
2151 account = account_get_default();
2152 if (account && account != cur_account) {
2153 cur_account = account;
2154 main_window_change_cur_account();
2155 }
2156 }
2157 }
2158
folderview_row_expanded(GtkTreeView * treeview,GtkTreeIter * iter,GtkTreePath * path,FolderView * folderview)2159 static void folderview_row_expanded(GtkTreeView *treeview, GtkTreeIter *iter,
2160 GtkTreePath *path, FolderView *folderview)
2161 {
2162 GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
2163 FolderItem *item = NULL;
2164 GtkTreeIter iter_;
2165 gboolean valid;
2166
2167 folderview->open_folder = FALSE;
2168
2169 gtk_tree_model_get(GTK_TREE_MODEL(folderview->store), iter,
2170 COL_FOLDER_ITEM, &item, -1);
2171 g_return_if_fail(item != NULL);
2172 item->collapsed = FALSE;
2173 folderview_update_row(folderview, iter);
2174
2175 valid = gtk_tree_model_iter_children(model, &iter_, iter);
2176
2177 while (valid) {
2178 FolderItem *child_item = NULL;
2179
2180 gtk_tree_model_get(model, &iter_, COL_FOLDER_ITEM, &child_item,
2181 -1);
2182 if (child_item && child_item->node->children &&
2183 !child_item->collapsed) {
2184 GtkTreePath *path;
2185
2186 path = gtk_tree_model_get_path(model, &iter_);
2187 gtk_tree_view_expand_row
2188 (GTK_TREE_VIEW(folderview->treeview),
2189 path, FALSE);
2190 gtk_tree_path_free(path);
2191 }
2192 valid = gtk_tree_model_iter_next(model, &iter_);
2193 }
2194 }
2195
folderview_row_collapsed(GtkTreeView * treeview,GtkTreeIter * iter,GtkTreePath * path,FolderView * folderview)2196 static void folderview_row_collapsed(GtkTreeView *treeview, GtkTreeIter *iter,
2197 GtkTreePath *path, FolderView *folderview)
2198 {
2199 FolderItem *item = NULL;
2200
2201 folderview->open_folder = FALSE;
2202
2203 gtk_tree_model_get(GTK_TREE_MODEL(folderview->store), iter,
2204 COL_FOLDER_ITEM, &item, -1);
2205 g_return_if_fail(item != NULL);
2206 item->collapsed = TRUE;
2207 folderview_update_row(folderview, iter);
2208 }
2209
folderview_popup_close(GtkMenuShell * menu_shell,FolderView * folderview)2210 static void folderview_popup_close(GtkMenuShell *menu_shell,
2211 FolderView *folderview)
2212 {
2213 GtkTreePath *path;
2214
2215 if (!folderview->prev_selected) return;
2216
2217 path = gtk_tree_row_reference_get_path(folderview->prev_selected);
2218 gtk_tree_row_reference_free(folderview->prev_selected);
2219 folderview->prev_selected = NULL;
2220 if (!path)
2221 return;
2222 gtk_tree_selection_select_path(folderview->selection, path);
2223 gtk_tree_path_free(path);
2224 }
2225
folderview_col_resized(GtkWidget * widget,GtkAllocation * allocation,FolderView * folderview)2226 static void folderview_col_resized(GtkWidget *widget, GtkAllocation *allocation,
2227 FolderView *folderview)
2228 {
2229 GtkTreeViewColumn *column;
2230 gint type;
2231 gint width = allocation->width;
2232
2233 for (type = 0; type <= COL_TOTAL; type++) {
2234 column = gtk_tree_view_get_column
2235 (GTK_TREE_VIEW(folderview->treeview), type);
2236 if (column && column->button == widget) {
2237 switch (type) {
2238 case COL_FOLDER_NAME:
2239 prefs_common.folder_col_folder = width;
2240 break;
2241 case COL_NEW:
2242 prefs_common.folder_col_new = width;
2243 break;
2244 case COL_UNREAD:
2245 prefs_common.folder_col_unread = width;
2246 break;
2247 case COL_TOTAL:
2248 prefs_common.folder_col_total = width;
2249 break;
2250 default:
2251 break;
2252 }
2253 break;
2254 }
2255 }
2256 }
2257
folderview_download_func(Folder * folder,FolderItem * item,gpointer data)2258 static void folderview_download_func(Folder *folder, FolderItem *item,
2259 gpointer data)
2260 {
2261 GList *list;
2262
2263 for (list = folderview_list; list != NULL; list = list->next) {
2264 FolderView *folderview = (FolderView *)list->data;
2265 MainWindow *mainwin = folderview->mainwin;
2266 gchar *str;
2267
2268 str = g_strdup_printf
2269 (_("Downloading messages in %s ..."), item->path);
2270 main_window_progress_set(mainwin,
2271 GPOINTER_TO_INT(data), item->total);
2272 STATUSBAR_PUSH(mainwin, str);
2273 STATUSBAR_POP(mainwin);
2274 g_free(str);
2275 }
2276 }
2277
folderview_download_cb(FolderView * folderview,guint action,GtkWidget * widget)2278 static void folderview_download_cb(FolderView *folderview, guint action,
2279 GtkWidget *widget)
2280 {
2281 MainWindow *mainwin = folderview->mainwin;
2282 FolderItem *item;
2283 gint ret = 0;
2284
2285 item = folderview_get_selected_item(folderview);
2286 if (!item)
2287 return;
2288 if (item->stype == F_VIRTUAL)
2289 return;
2290
2291 g_return_if_fail(item->folder != NULL);
2292
2293 if (item->parent == NULL) {
2294 gchar *name, *msg;
2295
2296 name = trim_string(item->name, 32);
2297 msg = g_strdup_printf(_("Download all messages under '%s' ?"),
2298 name);
2299 g_free(name);
2300 if (alertpanel(_("Download all messages"), msg,
2301 GTK_STOCK_YES, GTK_STOCK_NO, NULL)
2302 != G_ALERTDEFAULT) {
2303 g_free(msg);
2304 return;
2305 }
2306 g_free(msg);
2307 }
2308
2309 if (!main_window_toggle_online_if_offline(folderview->mainwin))
2310 return;
2311
2312 main_window_cursor_wait(mainwin);
2313 inc_lock();
2314 main_window_lock(mainwin);
2315 gtk_widget_set_sensitive(folderview->treeview, FALSE);
2316 main_window_progress_on(mainwin);
2317 GTK_EVENTS_FLUSH();
2318 folder_set_ui_func(item->folder, folderview_download_func, NULL);
2319
2320 if (item->parent == NULL) {
2321 GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
2322 GtkTreeIter iter;
2323 gboolean valid;
2324 FolderItem *cur_item;
2325
2326 valid = gtkut_tree_model_find_by_column_data
2327 (model, &iter, NULL, COL_FOLDER_ITEM, item);
2328 while ((valid = gtkut_tree_model_next(model, &iter)) == TRUE) {
2329 cur_item = NULL;
2330 gtk_tree_model_get(model, &iter, COL_FOLDER_ITEM,
2331 &cur_item, -1);
2332 if (!cur_item || cur_item->folder != item->folder)
2333 break;
2334 if (!cur_item->no_select &&
2335 cur_item->stype != F_VIRTUAL &&
2336 cur_item->stype != F_TRASH) {
2337 ret = folder_item_fetch_all_msg(cur_item);
2338 if (ret < 0)
2339 break;
2340 }
2341 }
2342 } else
2343 ret = folder_item_fetch_all_msg(item);
2344
2345 if (ret < 0) {
2346 gchar *name;
2347
2348 name = trim_string(item->name, 32);
2349 alertpanel_error(_("Error occurred while downloading messages in `%s'."), name);
2350 g_free(name);
2351 }
2352
2353 folder_set_ui_func(item->folder, NULL, NULL);
2354 main_window_progress_off(mainwin);
2355 gtk_widget_set_sensitive(folderview->treeview, TRUE);
2356 main_window_unlock(mainwin);
2357 inc_unlock();
2358 main_window_cursor_normal(mainwin);
2359 statusbar_pop_all();
2360 }
2361
folderview_update_tree_cb(FolderView * folderview,guint action,GtkWidget * widget)2362 static void folderview_update_tree_cb(FolderView *folderview, guint action,
2363 GtkWidget *widget)
2364 {
2365 FolderItem *item;
2366
2367 item = folderview_get_selected_item(folderview);
2368 if (!item)
2369 return;
2370
2371 g_return_if_fail(item->folder != NULL);
2372
2373 if (action == 0)
2374 folderview_check_new(item->folder);
2375 else
2376 folderview_rescan_tree(folderview, item->folder);
2377 }
2378
folderview_update_summary_cb(FolderView * folderview,guint action,GtkWidget * widget)2379 static void folderview_update_summary_cb(FolderView *folderview, guint action,
2380 GtkWidget *widget)
2381 {
2382 if (!folderview->summaryview->folder_item)
2383 return;
2384
2385 GTK_EVENTS_FLUSH();
2386 summary_show(folderview->summaryview,
2387 folderview->summaryview->folder_item, TRUE);
2388 }
2389
folderview_mark_all_read_cb(FolderView * folderview,guint action,GtkWidget * widget)2390 static void folderview_mark_all_read_cb(FolderView *folderview, guint action,
2391 GtkWidget *widget)
2392 {
2393 FolderItem *item;
2394
2395 item = folderview_get_selected_item(folderview);
2396 if (!item)
2397 return;
2398
2399 if (item == folderview->summaryview->folder_item)
2400 summary_mark_all_read(folderview->summaryview);
2401 else {
2402 procmsg_mark_all_read(item);
2403 folderview_update_item(item, FALSE);
2404 trayicon_set_tooltip(NULL);
2405 trayicon_set_notify(FALSE);
2406 }
2407 }
2408
folderview_send_queue_cb(FolderView * folderview,guint action,GtkWidget * widget)2409 static void folderview_send_queue_cb(FolderView *folderview, guint action,
2410 GtkWidget *widget)
2411 {
2412 FolderItem *item;
2413 gint ret;
2414
2415 if (!main_window_toggle_online_if_offline(folderview->mainwin))
2416 return;
2417
2418 item = folderview_get_selected_item(folderview);
2419 if (!item || item->stype != F_QUEUE)
2420 return;
2421
2422 ret = send_message_queue_all(item, prefs_common.savemsg,
2423 prefs_common.filter_sent);
2424 statusbar_pop_all();
2425 if (ret > 0)
2426 folder_item_scan(item);
2427
2428 folderview_update_item(item, TRUE);
2429 main_window_set_menu_sensitive(folderview->mainwin);
2430 main_window_set_toolbar_sensitive(folderview->mainwin);
2431 }
2432
folderview_new_folder_cb(FolderView * folderview,guint action,GtkWidget * widget)2433 static void folderview_new_folder_cb(FolderView *folderview, guint action,
2434 GtkWidget *widget)
2435 {
2436 FolderItem *item;
2437 FolderItem *new_item;
2438 gchar *new_folder;
2439 gchar *name;
2440 gchar *p;
2441
2442 item = folderview_get_selected_item(folderview);
2443 if (!item)
2444 return;
2445
2446 g_return_if_fail(item->folder != NULL);
2447
2448 if (FOLDER_TYPE(item->folder) == F_IMAP)
2449 g_return_if_fail(item->folder->account != NULL);
2450
2451 if (FOLDER_TYPE(item->folder) == F_IMAP) {
2452 new_folder = input_dialog
2453 (_("New folder"),
2454 _("Input the name of new folder:\n"
2455 "(if you want to create a folder to store subfolders,\n"
2456 " append `/' at the end of the name)"),
2457 _("NewFolder"));
2458 } else {
2459 new_folder = input_dialog(_("New folder"),
2460 _("Input the name of new folder:"),
2461 _("NewFolder"));
2462 }
2463 if (!new_folder) return;
2464 AUTORELEASE_STR(new_folder, {g_free(new_folder); return;});
2465
2466 #ifdef G_OS_WIN32
2467 p = strpbrk(new_folder, "\\/:*?\"<>|");
2468 if ((p && FOLDER_TYPE(item->folder) != F_IMAP) || (p && *p != '/') ||
2469 (p && *p == '/' &&
2470 FOLDER_TYPE(item->folder) == F_IMAP && *(p + 1) != '\0')) {
2471 alertpanel_error(_("`%c' can't be included in folder name."),
2472 *p);
2473 return;
2474 }
2475 #else
2476 p = strchr(new_folder, G_DIR_SEPARATOR);
2477 if ((p && FOLDER_TYPE(item->folder) != F_IMAP) ||
2478 (p && FOLDER_TYPE(item->folder) == F_IMAP && *(p + 1) != '\0')) {
2479 alertpanel_error(_("`%c' can't be included in folder name."),
2480 G_DIR_SEPARATOR);
2481 return;
2482 }
2483 #endif
2484
2485 name = trim_string(new_folder, 32);
2486 AUTORELEASE_STR(name, {g_free(name); return;});
2487
2488 /* find whether the directory already exists */
2489 if (folder_find_child_item_by_name(item, new_folder)) {
2490 alertpanel_error(_("The folder `%s' already exists."), name);
2491 return;
2492 }
2493
2494 new_item = item->folder->klass->create_folder(item->folder, item,
2495 new_folder);
2496 if (!new_item) {
2497 alertpanel_error(_("Can't create the folder `%s'."), name);
2498 return;
2499 }
2500
2501 folderview_append_item(folderview, NULL, new_item, TRUE);
2502 folder_write_list();
2503 }
2504
folderview_rename_folder_cb(FolderView * folderview,guint action,GtkWidget * widget)2505 static void folderview_rename_folder_cb(FolderView *folderview, guint action,
2506 GtkWidget *widget)
2507 {
2508 FolderItem *item;
2509 gchar *new_folder;
2510 gchar *name;
2511 gchar *message;
2512 gchar *old_path;
2513 gchar *old_id;
2514 gchar *new_id;
2515 GtkTreePath *sel_path;
2516 GtkTreePath *open_path = NULL;
2517 GtkTreeIter iter;
2518
2519 item = folderview_get_selected_item(folderview);
2520 if (!item)
2521 return;
2522
2523 g_return_if_fail(item->path != NULL);
2524 g_return_if_fail(item->folder != NULL);
2525
2526 sel_path = gtk_tree_row_reference_get_path(folderview->selected);
2527
2528 name = trim_string(item->name, 32);
2529 message = g_strdup_printf(_("Input new name for `%s':"), name);
2530 new_folder = input_dialog(_("Rename folder"), message,
2531 g_basename(item->path));
2532 g_free(message);
2533 g_free(name);
2534 if (!new_folder) {
2535 gtk_tree_path_free(sel_path);
2536 return;
2537 }
2538 AUTORELEASE_STR(new_folder, {g_free(new_folder); gtk_tree_path_free(sel_path); return;});
2539
2540 if (strchr(new_folder, G_DIR_SEPARATOR) != NULL) {
2541 alertpanel_error(_("`%c' can't be included in folder name."),
2542 G_DIR_SEPARATOR);
2543 gtk_tree_path_free(sel_path);
2544 return;
2545 }
2546
2547 if (folder_find_child_item_by_name(item->parent, new_folder)) {
2548 name = trim_string(new_folder, 32);
2549 alertpanel_error(_("The folder `%s' already exists."), name);
2550 g_free(name);
2551 gtk_tree_path_free(sel_path);
2552 return;
2553 }
2554
2555 old_path = g_strdup(item->path);
2556 old_id = folder_item_get_identifier(item);
2557
2558 if (item->stype == F_VIRTUAL) {
2559 if (virtual_get_class()->rename_folder(item->folder, item,
2560 new_folder) < 0) {
2561 alertpanel_error(_("Can't rename the folder '%s'."),
2562 item->name);
2563 g_free(old_id);
2564 g_free(old_path);
2565 gtk_tree_path_free(sel_path);
2566 return;
2567 }
2568 } else if (item->folder->klass->rename_folder(item->folder, item,
2569 new_folder) < 0) {
2570 alertpanel_error(_("Can't rename the folder '%s'."),
2571 item->name);
2572 g_free(old_id);
2573 g_free(old_path);
2574 gtk_tree_path_free(sel_path);
2575 return;
2576 }
2577
2578 if (folder_get_default_folder() == item->folder) {
2579 filter_list_rename_path(old_path, item->path);
2580 prefs_common_junk_folder_rename_path(old_path, item->path);
2581 }
2582 new_id = folder_item_get_identifier(item);
2583 filter_list_rename_path(old_id, new_id);
2584 prefs_common_junk_folder_rename_path(old_id, new_id);
2585 g_free(new_id);
2586 g_free(old_id);
2587 g_free(old_path);
2588
2589 if (folderview->opened)
2590 open_path = gtk_tree_row_reference_get_path(folderview->opened);
2591 if (sel_path) {
2592 gtk_tree_model_get_iter(GTK_TREE_MODEL(folderview->store),
2593 &iter, sel_path);
2594 folderview_update_row(folderview, &iter);
2595 }
2596 if (sel_path && open_path &&
2597 (gtk_tree_path_compare(open_path, sel_path) == 0 ||
2598 gtk_tree_path_is_ancestor(sel_path, open_path))) {
2599 GtkTreeRowReference *row;
2600
2601 row = gtk_tree_row_reference_copy(folderview->opened);
2602 folderview_unselect(folderview);
2603 folderview_select_row_ref(folderview, row);
2604 gtk_tree_row_reference_free(row);
2605 }
2606 gtk_tree_path_free(open_path);
2607 gtk_tree_path_free(sel_path);
2608
2609 folder_write_list();
2610 }
2611
folderview_move_folder_cb(FolderView * folderview,guint action,GtkWidget * widget)2612 static void folderview_move_folder_cb(FolderView *folderview, guint action,
2613 GtkWidget *widget)
2614 {
2615 FolderItem *item;
2616 FolderItem *new_parent;
2617 GtkTreePath *sel_path;
2618 GtkTreePath *open_path = NULL;
2619 GtkTreeIter iter;
2620 gchar *old_path, *old_id, *new_id;
2621
2622 item = folderview_get_selected_item(folderview);
2623 if (!item)
2624 return;
2625
2626 g_return_if_fail(item->path != NULL);
2627 g_return_if_fail(item->folder != NULL);
2628
2629 sel_path = gtk_tree_row_reference_get_path(folderview->selected);
2630 g_return_if_fail(sel_path != NULL);
2631
2632 new_parent = foldersel_folder_sel(item->folder, FOLDER_SEL_MOVE_FOLDER,
2633 NULL);
2634 if (!new_parent || new_parent->folder != item->folder ||
2635 new_parent == item->parent || new_parent->stype == F_VIRTUAL) {
2636 gtk_tree_path_free(sel_path);
2637 return;
2638 }
2639
2640 old_path = g_strdup(item->path);
2641 old_id = folder_item_get_identifier(item);
2642
2643 if (item->folder->klass->move_folder
2644 (item->folder, item, new_parent) < 0) {
2645 alertpanel_error(_("Can't move the folder `%s'."), item->name);
2646 g_free(old_id);
2647 g_free(old_path);
2648 gtk_tree_path_free(sel_path);
2649 return;
2650 }
2651
2652 if (folder_get_default_folder() == item->folder) {
2653 filter_list_rename_path(old_path, item->path);
2654 prefs_common_junk_folder_rename_path(old_path, item->path);
2655 }
2656 new_id = folder_item_get_identifier(item);
2657 filter_list_rename_path(old_id, new_id);
2658 prefs_common_junk_folder_rename_path(old_id, new_id);
2659 g_free(new_id);
2660 g_free(old_id);
2661 g_free(old_path);
2662
2663 if (folderview->opened)
2664 open_path = gtk_tree_row_reference_get_path(folderview->opened);
2665 gtk_tree_model_get_iter(GTK_TREE_MODEL(folderview->store), &iter,
2666 sel_path);
2667 if (sel_path && open_path &&
2668 (gtk_tree_path_compare(open_path, sel_path) == 0 ||
2669 gtk_tree_path_is_ancestor(sel_path, open_path))) {
2670 summary_clear_all(folderview->summaryview);
2671 gtk_tree_row_reference_free(folderview->opened);
2672 folderview->opened = NULL;
2673 }
2674 gtk_tree_path_free(open_path);
2675 gtk_tree_path_free(sel_path);
2676
2677 gtk_tree_store_remove(folderview->store, &iter);
2678 if (folderview_insert_item_recursive(folderview, item, &iter)) {
2679 gtkut_tree_view_expand_parent_all
2680 (GTK_TREE_VIEW(folderview->treeview), &iter);
2681 }
2682
2683 folder_write_list();
2684 }
2685
folderview_delete_folder_cb(FolderView * folderview,guint action,GtkWidget * widget)2686 static void folderview_delete_folder_cb(FolderView *folderview, guint action,
2687 GtkWidget *widget)
2688 {
2689 Folder *folder;
2690 FolderItem *item;
2691 gchar *message, *name;
2692 AlertValue avalue;
2693 gchar *old_path;
2694 gchar *old_id;
2695 GtkTreePath *sel_path, *open_path = NULL;
2696 GtkTreeIter iter;
2697
2698 item = folderview_get_selected_item(folderview);
2699 if (!item)
2700 return;
2701
2702 g_return_if_fail(item->path != NULL);
2703 g_return_if_fail(item->folder != NULL);
2704
2705 sel_path = gtk_tree_row_reference_get_path(folderview->selected);
2706 g_return_if_fail(sel_path != NULL);
2707
2708 folder = item->folder;
2709
2710 name = trim_string(item->name, 32);
2711 AUTORELEASE_STR(name, {g_free(name); gtk_tree_path_free(sel_path); return;});
2712 if (item->stype == F_VIRTUAL) {
2713 message = g_strdup_printf
2714 (_("Delete the search folder '%s' ?\n"
2715 "The real messages are not deleted."), name);
2716 avalue = alertpanel_full(_("Delete search folder"), message,
2717 ALERT_WARNING, G_ALERTALTERNATE, FALSE,
2718 GTK_STOCK_YES, GTK_STOCK_NO, NULL);
2719 } else {
2720 message = g_strdup_printf
2721 (_("All folders and messages under '%s' will be permanently deleted.\n"
2722 "Recovery will not be possible.\n\n"
2723 "Do you really want to delete?"), name);
2724 avalue = alertpanel_full(_("Delete folder"), message,
2725 ALERT_WARNING, G_ALERTALTERNATE, FALSE,
2726 GTK_STOCK_YES, GTK_STOCK_NO, NULL);
2727 }
2728 g_free(message);
2729 if (avalue != G_ALERTDEFAULT) {
2730 gtk_tree_path_free(sel_path);
2731 return;
2732 }
2733
2734 old_path = g_strdup(item->path);
2735 old_id = folder_item_get_identifier(item);
2736
2737 if (folderview->opened)
2738 open_path = gtk_tree_row_reference_get_path(folderview->opened);
2739 gtk_tree_model_get_iter(GTK_TREE_MODEL(folderview->store), &iter,
2740 sel_path);
2741 if (sel_path && open_path &&
2742 (gtk_tree_path_compare(open_path, sel_path) == 0 ||
2743 gtk_tree_path_is_ancestor(sel_path, open_path))) {
2744 summary_clear_all(folderview->summaryview);
2745 gtk_tree_row_reference_free(folderview->opened);
2746 folderview->opened = NULL;
2747 }
2748 gtk_tree_path_free(open_path);
2749 gtk_tree_path_free(sel_path);
2750
2751 if (item->stype == F_VIRTUAL) {
2752 if (virtual_get_class()->remove_folder(folder, item) < 0) {
2753 alertpanel_error(_("Can't remove the folder '%s'."),
2754 name);
2755 g_free(old_id);
2756 g_free(old_path);
2757 return;
2758 }
2759 } else if (folder->klass->remove_folder(folder, item) < 0) {
2760 alertpanel_error(_("Can't remove the folder '%s'."), name);
2761 g_free(old_id);
2762 g_free(old_path);
2763 return;
2764 }
2765
2766 if (folder_get_default_folder() == folder)
2767 filter_list_delete_path(old_path);
2768 filter_list_delete_path(old_id);
2769 g_free(old_id);
2770 g_free(old_path);
2771
2772 gtk_tree_store_remove(folderview->store, &iter);
2773
2774 folder_write_list();
2775 }
2776
folderview_empty_trash_cb(FolderView * folderview,guint action,GtkWidget * widget)2777 static void folderview_empty_trash_cb(FolderView *folderview, guint action,
2778 GtkWidget *widget)
2779 {
2780 FolderItem *item;
2781 Folder *folder;
2782 GtkTreePath *sel_path, *open_path;
2783
2784 item = folderview_get_selected_item(folderview);
2785 if (!item)
2786 return;
2787
2788 g_return_if_fail(item->path != NULL);
2789 g_return_if_fail(item->folder != NULL);
2790
2791 folder = item->folder;
2792
2793 if (item->stype != F_TRASH && item->stype != F_JUNK) return;
2794
2795 if (folderview->selection_locked ||
2796 summary_is_locked(folderview->summaryview)) return;
2797 folderview->selection_locked = TRUE;
2798
2799 sel_path = gtk_tree_row_reference_get_path(folderview->selected);
2800
2801 if (item->stype == F_TRASH) {
2802 if (alertpanel(_("Empty trash"),
2803 _("Delete all messages in the trash folder?"),
2804 GTK_STOCK_YES, GTK_STOCK_NO, NULL) != G_ALERTDEFAULT) {
2805 gtk_tree_path_free(sel_path);
2806 folderview->selection_locked = FALSE;
2807 return;
2808 }
2809 } else {
2810 if (alertpanel(_("Empty junk"),
2811 _("Delete all messages in the junk folder?"),
2812 GTK_STOCK_YES, GTK_STOCK_NO, NULL) != G_ALERTDEFAULT) {
2813 gtk_tree_path_free(sel_path);
2814 folderview->selection_locked = FALSE;
2815 return;
2816 }
2817 }
2818
2819 summary_lock(folderview->summaryview);
2820 procmsg_empty_trash(item);
2821 summary_unlock(folderview->summaryview);
2822 statusbar_pop_all();
2823 folderview_update_item(item, TRUE);
2824 trayicon_set_tooltip(NULL);
2825 trayicon_set_notify(FALSE);
2826
2827 open_path = gtk_tree_row_reference_get_path(folderview->opened);
2828 if (open_path && sel_path &&
2829 gtk_tree_path_compare(open_path, sel_path) == 0)
2830 gtk_widget_grab_focus(folderview->treeview);
2831 gtk_tree_path_free(open_path);
2832 gtk_tree_path_free(sel_path);
2833
2834 folderview->selection_locked = FALSE;
2835 }
2836
folderview_remove_mailbox_cb(FolderView * folderview,guint action,GtkWidget * widget)2837 static void folderview_remove_mailbox_cb(FolderView *folderview, guint action,
2838 GtkWidget *widget)
2839 {
2840 FolderItem *item;
2841 gchar *name;
2842 gchar *message;
2843 AlertValue avalue;
2844 GtkTreePath *sel_path;
2845 GtkTreeIter iter;
2846
2847 item = folderview_get_selected_item(folderview);
2848 if (!item)
2849 return;
2850
2851 g_return_if_fail(item->folder != NULL);
2852 if (item->parent) return;
2853
2854 sel_path = gtk_tree_row_reference_get_path(folderview->selected);
2855
2856 name = trim_string(item->folder->name, 32);
2857 message = g_strdup_printf
2858 (_("Really remove the mailbox `%s' ?\n"
2859 "(The messages are NOT deleted from the disk)"), name);
2860 avalue = alertpanel_full(_("Remove mailbox"), message,
2861 ALERT_WARNING, G_ALERTALTERNATE, FALSE,
2862 GTK_STOCK_YES, GTK_STOCK_NO, NULL);
2863 g_free(message);
2864 g_free(name);
2865 if (avalue != G_ALERTDEFAULT) {
2866 gtk_tree_path_free(sel_path);
2867 return;
2868 }
2869
2870 if (folderview->summaryview->folder_item &&
2871 folderview->summaryview->folder_item->folder == item->folder) {
2872 summary_clear_all(folderview->summaryview);
2873 gtk_tree_row_reference_free(folderview->opened);
2874 folderview->opened = NULL;
2875 }
2876 folder_destroy(item->folder);
2877
2878 if (sel_path) {
2879 gtk_tree_model_get_iter(GTK_TREE_MODEL(folderview->store),
2880 &iter, sel_path);
2881 gtk_tree_path_free(sel_path);
2882 gtk_tree_store_remove(folderview->store, &iter);
2883 }
2884
2885 folder_write_list();
2886 }
2887
folderview_rm_imap_server_cb(FolderView * folderview,guint action,GtkWidget * widget)2888 static void folderview_rm_imap_server_cb(FolderView *folderview, guint action,
2889 GtkWidget *widget)
2890 {
2891 FolderItem *item;
2892 PrefsAccount *account;
2893 gchar *name;
2894 gchar *message;
2895 AlertValue avalue;
2896 GtkTreePath *sel_path;
2897 GtkTreeIter iter;
2898
2899 item = folderview_get_selected_item(folderview);
2900 if (!item)
2901 return;
2902
2903 g_return_if_fail(item->folder != NULL);
2904 g_return_if_fail(FOLDER_TYPE(item->folder) == F_IMAP);
2905 g_return_if_fail(item->folder->account != NULL);
2906
2907 sel_path = gtk_tree_row_reference_get_path(folderview->selected);
2908
2909 name = trim_string(item->folder->name, 32);
2910 message = g_strdup_printf(_("Really delete IMAP4 account `%s'?"), name);
2911 avalue = alertpanel_full(_("Delete IMAP4 account"), message,
2912 ALERT_WARNING, G_ALERTALTERNATE, FALSE,
2913 GTK_STOCK_YES, GTK_STOCK_NO, NULL);
2914 g_free(message);
2915 g_free(name);
2916
2917 if (avalue != G_ALERTDEFAULT) {
2918 gtk_tree_path_free(sel_path);
2919 return;
2920 }
2921
2922 if (folderview->summaryview->folder_item &&
2923 folderview->summaryview->folder_item->folder == item->folder) {
2924 summary_clear_all(folderview->summaryview);
2925 gtk_tree_row_reference_free(folderview->opened);
2926 folderview->opened = NULL;
2927 }
2928
2929 account = item->folder->account;
2930 folder_destroy(item->folder);
2931 account_destroy(account);
2932 account_write_config_all();
2933
2934 if (sel_path) {
2935 gtk_tree_model_get_iter(GTK_TREE_MODEL(folderview->store),
2936 &iter, sel_path);
2937 gtk_tree_path_free(sel_path);
2938 gtk_tree_store_remove(folderview->store, &iter);
2939 }
2940
2941 account_set_menu();
2942 main_window_reflect_prefs_all();
2943 folder_write_list();
2944 }
2945
folderview_new_news_group_cb(FolderView * folderview,guint action,GtkWidget * widget)2946 static void folderview_new_news_group_cb(FolderView *folderview, guint action,
2947 GtkWidget *widget)
2948 {
2949 GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
2950 Folder *folder;
2951 FolderItem *item;
2952 FolderItem *rootitem = NULL;
2953 FolderItem *newitem;
2954 GSList *new_subscr;
2955 GSList *cur;
2956 GNode *gnode;
2957 GtkTreePath *server_path;
2958 GtkTreeIter iter, root;
2959
2960 item = folderview_get_selected_item(folderview);
2961 if (!item)
2962 return;
2963
2964 folder = item->folder;
2965 g_return_if_fail(folder != NULL);
2966 g_return_if_fail(FOLDER_TYPE(folder) == F_NEWS);
2967 g_return_if_fail(folder->account != NULL);
2968
2969 server_path = gtk_tree_row_reference_get_path(folderview->selected);
2970 g_return_if_fail(server_path != NULL);
2971 gtk_tree_model_get_iter(model, &iter, server_path);
2972 gtk_tree_path_free(server_path);
2973
2974 if (!gtk_tree_model_iter_parent(model, &root, &iter))
2975 root = iter;
2976
2977 gtk_tree_model_get(model, &root, COL_FOLDER_ITEM, &rootitem, -1);
2978
2979 new_subscr = subscribe_dialog(folder);
2980
2981 /* remove unsubscribed newsgroups */
2982 for (gnode = folder->node->children; gnode != NULL; ) {
2983 GNode *next = gnode->next;
2984 GtkTreeIter found;
2985
2986 item = FOLDER_ITEM(gnode->data);
2987 if (g_slist_find_custom(new_subscr, item->path,
2988 (GCompareFunc)g_ascii_strcasecmp)
2989 != NULL) {
2990 gnode = next;
2991 continue;
2992 }
2993
2994 if (!gtkut_tree_model_find_by_column_data
2995 (model, &found, &root, COL_FOLDER_ITEM, item)) {
2996 gnode = next;
2997 continue;
2998 }
2999
3000 if (folderview->summaryview->folder_item == item) {
3001 summary_clear_all(folderview->summaryview);
3002 gtk_tree_row_reference_free(folderview->opened);
3003 folderview->opened = NULL;
3004 }
3005
3006 folder_item_remove(item);
3007 gtk_tree_store_remove(folderview->store, &found);
3008
3009 gnode = next;
3010 }
3011
3012 /* add subscribed newsgroups */
3013 for (cur = new_subscr; cur != NULL; cur = cur->next) {
3014 gchar *name = (gchar *)cur->data;
3015
3016 if (folder_find_child_item_by_name(rootitem, name) != NULL)
3017 continue;
3018
3019 newitem = folder_item_new(name, name);
3020 folder_item_append(rootitem, newitem);
3021 folderview_append_item(folderview, NULL, newitem, TRUE);
3022 }
3023
3024 if (new_subscr) {
3025 server_path = gtk_tree_model_get_path(model, &root);
3026 gtk_tree_view_expand_row(GTK_TREE_VIEW(folderview->treeview),
3027 server_path, FALSE);
3028 gtk_tree_path_free(server_path);
3029 }
3030
3031 slist_free_strings(new_subscr);
3032 g_slist_free(new_subscr);
3033
3034 folder_write_list();
3035 }
3036
folderview_rm_news_group_cb(FolderView * folderview,guint action,GtkWidget * widget)3037 static void folderview_rm_news_group_cb(FolderView *folderview, guint action,
3038 GtkWidget *widget)
3039 {
3040 FolderItem *item;
3041 gchar *name;
3042 gchar *message;
3043 AlertValue avalue;
3044 GtkTreePath *sel_path, *open_path = NULL;
3045 GtkTreeIter iter;
3046
3047 item = folderview_get_selected_item(folderview);
3048 if (!item)
3049 return;
3050
3051 if (item->stype == F_VIRTUAL) {
3052 folderview_delete_folder_cb(folderview, 0, widget);
3053 return;
3054 }
3055
3056 g_return_if_fail(item->folder != NULL);
3057 g_return_if_fail(FOLDER_TYPE(item->folder) == F_NEWS);
3058 g_return_if_fail(item->folder->account != NULL);
3059
3060 sel_path = gtk_tree_row_reference_get_path(folderview->selected);
3061 g_return_if_fail(sel_path != NULL);
3062
3063 name = trim_string_before(item->path, 32);
3064 message = g_strdup_printf(_("Really delete newsgroup `%s'?"), name);
3065 avalue = alertpanel_full(_("Delete newsgroup"), message,
3066 ALERT_WARNING, G_ALERTALTERNATE, FALSE,
3067 GTK_STOCK_YES, GTK_STOCK_NO, NULL);
3068 g_free(message);
3069 g_free(name);
3070 if (avalue != G_ALERTDEFAULT) {
3071 gtk_tree_path_free(sel_path);
3072 return;
3073 }
3074
3075 if (folderview->opened)
3076 open_path = gtk_tree_row_reference_get_path(folderview->opened);
3077 gtk_tree_model_get_iter(GTK_TREE_MODEL(folderview->store), &iter,
3078 sel_path);
3079 if (open_path && sel_path &&
3080 gtk_tree_path_compare(open_path, sel_path) == 0) {
3081 summary_clear_all(folderview->summaryview);
3082 gtk_tree_row_reference_free(folderview->opened);
3083 folderview->opened = NULL;
3084 }
3085 gtk_tree_path_free(open_path);
3086 gtk_tree_path_free(sel_path);
3087
3088 folder_item_remove(item);
3089 gtk_tree_store_remove(folderview->store, &iter);
3090 folder_write_list();
3091 }
3092
folderview_rm_news_server_cb(FolderView * folderview,guint action,GtkWidget * widget)3093 static void folderview_rm_news_server_cb(FolderView *folderview, guint action,
3094 GtkWidget *widget)
3095 {
3096 FolderItem *item;
3097 PrefsAccount *account;
3098 gchar *name;
3099 gchar *message;
3100 AlertValue avalue;
3101 GtkTreePath *sel_path;
3102 GtkTreeIter iter;
3103
3104 item = folderview_get_selected_item(folderview);
3105 if (!item)
3106 return;
3107
3108 g_return_if_fail(item->folder != NULL);
3109 g_return_if_fail(FOLDER_TYPE(item->folder) == F_NEWS);
3110 g_return_if_fail(item->folder->account != NULL);
3111
3112 sel_path = gtk_tree_row_reference_get_path(folderview->selected);
3113
3114 name = trim_string(item->folder->name, 32);
3115 message = g_strdup_printf(_("Really delete news account `%s'?"), name);
3116 avalue = alertpanel_full(_("Delete news account"), message,
3117 ALERT_WARNING, G_ALERTALTERNATE, FALSE,
3118 GTK_STOCK_YES, GTK_STOCK_NO, NULL);
3119 g_free(message);
3120 g_free(name);
3121
3122 if (avalue != G_ALERTDEFAULT) {
3123 gtk_tree_path_free(sel_path);
3124 return;
3125 }
3126
3127 if (folderview->summaryview->folder_item &&
3128 folderview->summaryview->folder_item->folder == item->folder) {
3129 summary_clear_all(folderview->summaryview);
3130 gtk_tree_row_reference_free(folderview->opened);
3131 folderview->opened = NULL;
3132 }
3133
3134 account = item->folder->account;
3135 folder_destroy(item->folder);
3136 account_destroy(account);
3137 account_write_config_all();
3138
3139 if (sel_path) {
3140 gtk_tree_model_get_iter(GTK_TREE_MODEL(folderview->store),
3141 &iter, sel_path);
3142 gtk_tree_path_free(sel_path);
3143 gtk_tree_store_remove(folderview->store, &iter);
3144 }
3145
3146 account_set_menu();
3147 main_window_reflect_prefs_all();
3148 folder_write_list();
3149 }
3150
folderview_search_cb(FolderView * folderview,guint action,GtkWidget * widget)3151 static void folderview_search_cb(FolderView *folderview, guint action,
3152 GtkWidget *widget)
3153 {
3154 FolderItem *item;
3155
3156 item = folderview_get_selected_item(folderview);
3157 if (!item)
3158 return;
3159
3160 if (item->stype == F_VIRTUAL) {
3161 GtkTreePath *sel_path, *open_path;
3162
3163 sel_path = gtk_tree_row_reference_get_path
3164 (folderview->selected);
3165 open_path = gtk_tree_row_reference_get_path(folderview->opened);
3166
3167 if (prefs_search_folder_open(item)) {
3168 if (sel_path && open_path &&
3169 gtk_tree_path_compare(open_path, sel_path) == 0) {
3170 GtkTreeRowReference *row;
3171 row = gtk_tree_row_reference_copy(folderview->opened);
3172 folderview_unselect(folderview);
3173 summary_clear_all(folderview->summaryview);
3174 folderview_select_row_ref(folderview, row);
3175 gtk_tree_row_reference_free(row);
3176 }
3177 }
3178
3179 gtk_tree_path_free(open_path);
3180 gtk_tree_path_free(sel_path);
3181 } else
3182 query_search(item);
3183 }
3184
folderview_property_cb(FolderView * folderview,guint action,GtkWidget * widget)3185 static void folderview_property_cb(FolderView *folderview, guint action,
3186 GtkWidget *widget)
3187 {
3188 FolderItem *item;
3189
3190 item = folderview_get_selected_item(folderview);
3191 if (!item)
3192 return;
3193
3194 g_return_if_fail(item->folder != NULL);
3195
3196 if (item->parent == NULL && item->folder->account)
3197 account_open(item->folder->account);
3198 else
3199 prefs_folder_item_open(item);
3200 }
3201
auto_expand_timeout(gpointer data)3202 static gint auto_expand_timeout(gpointer data)
3203 {
3204 FolderView *folderview = data;
3205 GtkTreeView *treeview = GTK_TREE_VIEW(folderview->treeview);
3206 GtkTreePath *path = NULL;
3207 gint ret;
3208
3209 gdk_threads_enter();
3210
3211 gtk_tree_view_get_drag_dest_row(treeview, &path, NULL);
3212
3213 if (path) {
3214 gtk_tree_view_expand_row(treeview, path, FALSE);
3215 gtk_tree_path_free(path);
3216 folderview->expand_timeout = 0;
3217
3218 ret = FALSE;
3219 } else
3220 ret = TRUE;
3221
3222 gdk_threads_leave();
3223
3224 return ret;
3225 }
3226
remove_auto_expand_timeout(FolderView * folderview)3227 static void remove_auto_expand_timeout(FolderView *folderview)
3228 {
3229 if (folderview->expand_timeout != 0) {
3230 g_source_remove(folderview->expand_timeout);
3231 folderview->expand_timeout = 0;
3232 }
3233 }
3234
auto_scroll_timeout(gpointer data)3235 static gint auto_scroll_timeout(gpointer data)
3236 {
3237 FolderView *folderview = data;
3238
3239 gdk_threads_enter();
3240
3241 gtkut_tree_view_vertical_autoscroll
3242 (GTK_TREE_VIEW(folderview->treeview));
3243
3244 gdk_threads_leave();
3245
3246 return TRUE;
3247 }
3248
remove_auto_scroll_timeout(FolderView * folderview)3249 static void remove_auto_scroll_timeout(FolderView *folderview)
3250 {
3251 if (folderview->scroll_timeout != 0) {
3252 g_source_remove(folderview->scroll_timeout);
3253 folderview->scroll_timeout = 0;
3254 }
3255 }
3256
folderview_drag_motion_cb(GtkWidget * widget,GdkDragContext * context,gint x,gint y,guint time,FolderView * folderview)3257 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
3258 GdkDragContext *context,
3259 gint x,
3260 gint y,
3261 guint time,
3262 FolderView *folderview)
3263 {
3264 GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
3265 GtkTreePath *path = NULL, *prev_path = NULL;
3266 GtkTreeIter iter;
3267 FolderItem *item = NULL, *src_item = NULL;
3268 gboolean acceptable = FALSE;
3269
3270 if (gtk_tree_view_get_dest_row_at_pos
3271 (GTK_TREE_VIEW(widget), x, y, &path, NULL)) {
3272 gtk_tree_model_get_iter(model, &iter, path);
3273 gtk_tree_model_get(model, &iter, COL_FOLDER_ITEM, &item, -1);
3274 src_item = folderview->summaryview->folder_item;
3275 if (src_item && src_item != item &&
3276 src_item->stype != F_QUEUE && item->stype != F_QUEUE &&
3277 item->stype != F_VIRTUAL)
3278 acceptable = FOLDER_ITEM_CAN_ADD(item);
3279 } else
3280 remove_auto_expand_timeout(folderview);
3281
3282 if (summary_is_locked(folderview->summaryview))
3283 acceptable = FALSE;
3284
3285 gtk_tree_view_get_drag_dest_row(GTK_TREE_VIEW(widget),
3286 &prev_path, NULL);
3287 if (!path || (prev_path && gtk_tree_path_compare(path, prev_path) != 0))
3288 remove_auto_expand_timeout(folderview);
3289 if (prev_path)
3290 gtk_tree_path_free(prev_path);
3291
3292 gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW(widget), path,
3293 GTK_TREE_VIEW_DROP_INTO_OR_AFTER);
3294
3295 if (path) {
3296 if (folderview->expand_timeout == 0) {
3297 folderview->expand_timeout =
3298 g_timeout_add(1000, auto_expand_timeout,
3299 folderview);
3300 } else if (folderview->scroll_timeout == 0) {
3301 folderview->scroll_timeout =
3302 g_timeout_add(150, auto_scroll_timeout,
3303 folderview);
3304 }
3305 }
3306
3307 #ifdef G_OS_WIN32
3308 /* Win32 hack: somehow context->actions is not properly set on Win32 */
3309 {
3310 GdkWindow *rootwin;
3311 GdkModifierType state;
3312
3313 rootwin = gtk_widget_get_root_window(widget);
3314 gdk_window_get_pointer(rootwin, NULL, NULL, &state);
3315 if ((state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) == 0)
3316 context->actions = GDK_ACTION_MOVE | GDK_ACTION_COPY;
3317 }
3318 #endif
3319
3320 if (acceptable) {
3321 if ((context->actions & GDK_ACTION_MOVE) != 0 &&
3322 FOLDER_ITEM_CAN_ADD(src_item))
3323 gdk_drag_status(context, GDK_ACTION_MOVE, time);
3324 else if ((context->actions & GDK_ACTION_COPY) != 0)
3325 gdk_drag_status(context, GDK_ACTION_COPY, time);
3326 else if ((context->actions & GDK_ACTION_LINK) != 0)
3327 gdk_drag_status(context, GDK_ACTION_LINK, time);
3328 else
3329 gdk_drag_status(context, 0, time);
3330 } else
3331 gdk_drag_status(context, 0, time);
3332
3333 if (path)
3334 gtk_tree_path_free(path);
3335
3336 return TRUE;
3337 }
3338
folderview_drag_leave_cb(GtkWidget * widget,GdkDragContext * context,guint time,FolderView * folderview)3339 static void folderview_drag_leave_cb(GtkWidget *widget,
3340 GdkDragContext *context,
3341 guint time,
3342 FolderView *folderview)
3343 {
3344 remove_auto_expand_timeout(folderview);
3345 remove_auto_scroll_timeout(folderview);
3346
3347 gtk_tree_view_set_drag_dest_row
3348 (GTK_TREE_VIEW(widget), NULL, GTK_TREE_VIEW_DROP_INTO_OR_AFTER);
3349 }
3350
folderview_drag_received_cb(GtkWidget * widget,GdkDragContext * context,gint x,gint y,GtkSelectionData * data,guint info,guint time,FolderView * folderview)3351 static void folderview_drag_received_cb(GtkWidget *widget,
3352 GdkDragContext *context,
3353 gint x,
3354 gint y,
3355 GtkSelectionData *data,
3356 guint info,
3357 guint time,
3358 FolderView *folderview)
3359 {
3360 GtkTreeModel *model = GTK_TREE_MODEL(folderview->store);
3361 GtkTreePath *path = NULL;
3362 GtkTreeIter iter;
3363 FolderItem *item = NULL, *src_item;
3364
3365 remove_auto_expand_timeout(folderview);
3366 remove_auto_scroll_timeout(folderview);
3367
3368 if (!gtk_tree_view_get_dest_row_at_pos
3369 (GTK_TREE_VIEW(widget), x, y, &path, NULL))
3370 return;
3371
3372 gtk_tree_model_get_iter(model, &iter, path);
3373 gtk_tree_model_get(model, &iter, COL_FOLDER_ITEM, &item, -1);
3374 src_item = folderview->summaryview->folder_item;
3375
3376 if (FOLDER_ITEM_CAN_ADD(item) && src_item && src_item != item &&
3377 src_item->stype != F_QUEUE && item->stype != F_QUEUE &&
3378 item->stype != F_VIRTUAL) {
3379 if ((context->actions & GDK_ACTION_MOVE) != 0 &&
3380 FOLDER_ITEM_CAN_ADD(src_item)) {
3381 summary_move_selected_to(folderview->summaryview, item);
3382 context->action = 0;
3383 gtk_drag_finish(context, TRUE, FALSE, time);
3384 } else if ((context->actions & GDK_ACTION_COPY) != 0) {
3385 summary_copy_selected_to(folderview->summaryview, item);
3386 gtk_drag_finish(context, TRUE, FALSE, time);
3387 } else
3388 gtk_drag_finish(context, FALSE, FALSE, time);
3389 } else
3390 gtk_drag_finish(context, FALSE, FALSE, time);
3391
3392 gtk_tree_path_free(path);
3393 }
3394
folderview_folder_name_compare(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer data)3395 static gint folderview_folder_name_compare(GtkTreeModel *model,
3396 GtkTreeIter *a, GtkTreeIter *b,
3397 gpointer data)
3398 {
3399 FolderItem *item_a = NULL, *item_b = NULL;
3400
3401 gtk_tree_model_get(model, a, COL_FOLDER_ITEM, &item_a, -1);
3402 gtk_tree_model_get(model, b, COL_FOLDER_ITEM, &item_b, -1);
3403
3404 return folder_item_compare(item_a, item_b);
3405 }
3406