2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2001 Hiroyuki Yamamoto
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 #include <gdk/gdkkeysyms.h>
24 #include <gtk/gtkwidget.h>
25 #include <gtk/gtkscrolledwindow.h>
26 #include <gtk/gtkctree.h>
27 #include <gtk/gtkcontainer.h>
28 #include <gtk/gtkclist.h>
29 #include <gtk/gtkstyle.h>
30 #include <gtk/gtksignal.h>
31 #include <gtk/gtkmain.h>
32 #include <gtk/gtkstatusbar.h>
33 #include <gtk/gtkmenu.h>
34 #include <gtk/gtkmenuitem.h>
35 #include <gtk/gtkitemfactory.h>
42 #include "mainwindow.h"
43 #include "folderview.h"
44 #include "summaryview.h"
45 #include "summary_search.h"
46 #include "inputdialog.h"
47 #include "grouplistdialog.h"
48 #include "manage_window.h"
49 #include "alertpanel.h"
54 #include "prefs_common.h"
55 #include "prefs_account.h"
60 #include "pixmaps/inbox.xpm"
61 #include "pixmaps/inbox-hrm.xpm"
62 #include "pixmaps/outbox.xpm"
63 #include "pixmaps/outbox-hrm.xpm"
64 #include "pixmaps/dir-close.xpm"
65 #include "pixmaps/dir-open.xpm"
66 #include "pixmaps/dir-open-hrm.xpm"
67 #include "pixmaps/trash.xpm"
68 #include "pixmaps/trash-hrm.xpm"
78 #define N_FOLDER_COLS 4
79 #define COL_FOLDER_WIDTH 150
80 #define COL_NUM_WIDTH 32
82 #define STATUSBAR_PUSH(mainwin, str) \
84 gtk_statusbar_push(GTK_STATUSBAR(mainwin->statusbar), \
85 mainwin->folderview_cid, str); \
86 gtkut_widget_wait_for_draw(mainwin->hbox_stat); \
89 #define STATUSBAR_POP(mainwin) \
91 gtk_statusbar_pop(GTK_STATUSBAR(mainwin->statusbar), \
92 mainwin->folderview_cid); \
95 static GList *folderview_list = NULL;
97 static GdkFont *normalfont;
98 static GdkFont *boldfont;
100 static GtkStyle *normal_style;
101 static GtkStyle *normal_color_style;
102 static GtkStyle *bold_style;
103 static GtkStyle *bold_color_style;
104 static GtkStyle *bold_tgtfold_style;
106 static GdkPixmap *inboxxpm;
107 static GdkBitmap *inboxxpmmask;
108 static GdkPixmap *inboxhrmxpm;
109 static GdkBitmap *inboxhrmxpmmask;
110 static GdkPixmap *outboxxpm;
111 static GdkBitmap *outboxxpmmask;
112 static GdkPixmap *outboxhrmxpm;
113 static GdkBitmap *outboxhrmxpmmask;
114 static GdkPixmap *folderxpm;
115 static GdkBitmap *folderxpmmask;
116 static GdkPixmap *folderopenxpm;
117 static GdkBitmap *folderopenxpmmask;
118 static GdkPixmap *folderopenhrmxpm;
119 static GdkBitmap *folderopenhrmxpmmask;
120 static GdkPixmap *trashxpm;
121 static GdkBitmap *trashxpmmask;
122 static GdkPixmap *trashhrmxpm;
123 static GdkBitmap *trashhrmxpmmask;
125 static void folderview_select_node (FolderView *folderview,
127 static void folderview_set_folders (FolderView *folderview);
128 static void folderview_sort_folders (FolderView *folderview,
131 static void folderview_append_folder (FolderView *folderview,
133 static void folderview_update_node (FolderView *folderview,
136 static GtkCTreeNode *folderview_find_by_name (GtkCTree *ctree,
140 static gint folderview_compare_name (gconstpointer a,
143 /* callback functions */
144 static void folderview_button_pressed (GtkWidget *ctree,
145 GdkEventButton *event,
146 FolderView *folderview);
147 static void folderview_button_released (GtkWidget *ctree,
148 GdkEventButton *event,
149 FolderView *folderview);
150 static void folderview_key_pressed (GtkWidget *widget,
152 FolderView *folderview);
153 static void folderview_selected (GtkCTree *ctree,
156 FolderView *folderview);
157 static void folderview_tree_expanded (GtkCTree *ctree,
159 FolderView *folderview);
160 static void folderview_tree_collapsed (GtkCTree *ctree,
162 FolderView *folderview);
163 static void folderview_popup_close (GtkMenuShell *menu_shell,
164 FolderView *folderview);
165 static void folderview_col_resized (GtkCList *clist,
168 FolderView *folderview);
170 static void folderview_update_tree_cb (FolderView *folderview,
174 static void folderview_new_folder_cb (FolderView *folderview,
177 static void folderview_new_mbox_folder_cb(FolderView *folderview,
180 static void folderview_rename_folder_cb (FolderView *folderview,
183 static void folderview_rename_mbox_folder_cb(FolderView *folderview,
186 static void folderview_delete_folder_cb (FolderView *folderview,
189 static void folderview_remove_mailbox_cb(FolderView *folderview,
193 static void folderview_new_imap_folder_cb(FolderView *folderview,
196 static void folderview_rm_imap_folder_cb (FolderView *folderview,
199 static void folderview_rm_imap_server_cb (FolderView *folderview,
203 static void folderview_new_news_group_cb(FolderView *folderview,
206 static void folderview_rm_news_group_cb (FolderView *folderview,
209 static void folderview_rm_news_server_cb(FolderView *folderview,
213 static void folderview_search_cb (FolderView *folderview,
217 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
218 GdkDragContext *context,
222 FolderView *folderview);
223 static void folderview_drag_leave_cb (GtkWidget *widget,
224 GdkDragContext *context,
226 FolderView *folderview);
227 static void folderview_drag_received_cb (GtkWidget *widget,
228 GdkDragContext *drag_context,
231 GtkSelectionData *data,
234 FolderView *folderview);
235 static void folderview_scoring_cb(FolderView *folderview, guint action,
237 static void folderview_processing_cb(FolderView *folderview, guint action,
239 static void folderview_property_cb(FolderView *folderview, guint action, GtkWidget *widget);
241 static GtkItemFactoryEntry folderview_mbox_popup_entries[] =
243 {N_("/Create _new folder..."), NULL, folderview_new_mbox_folder_cb, 0, NULL},
244 {N_("/_Rename folder..."), NULL, folderview_rename_mbox_folder_cb, 0, NULL},
245 {N_("/_Delete folder"), NULL, folderview_delete_folder_cb, 0, NULL},
246 {N_("/---"), NULL, NULL, 0, "<Separator>"},
247 {N_("/Remove _mailbox"), NULL, folderview_remove_mailbox_cb, 0, NULL},
248 {N_("/---"), NULL, NULL, 0, "<Separator>"},
249 {N_("/_Property..."), NULL, NULL, 0, NULL},
250 {N_("/_Processing..."), NULL, folderview_processing_cb, 0, NULL},
251 {N_("/_Scoring..."), NULL, folderview_scoring_cb, 0, NULL}
254 static GtkItemFactoryEntry folderview_mail_popup_entries[] =
256 {N_("/Create _new folder..."), NULL, folderview_new_folder_cb, 0, NULL},
257 {N_("/_Rename folder..."), NULL, folderview_rename_folder_cb, 0, NULL},
258 {N_("/_Delete folder"), NULL, folderview_delete_folder_cb, 0, NULL},
259 {N_("/---"), NULL, NULL, 0, "<Separator>"},
260 {N_("/_Update folder tree"), NULL, folderview_update_tree_cb, 0, NULL},
261 {N_("/R_escan folder tree"), NULL, folderview_update_tree_cb, 1, NULL},
262 {N_("/---"), NULL, NULL, 0, "<Separator>"},
263 {N_("/Remove _mailbox"), NULL, folderview_remove_mailbox_cb, 0, NULL},
264 {N_("/---"), NULL, NULL, 0, "<Separator>"},
265 {N_("/_Search folder..."), NULL, folderview_search_cb, 0, NULL},
266 {N_("/_Property..."), NULL, folderview_property_cb, 0, NULL},
267 {N_("/_Processing..."), NULL, folderview_processing_cb, 0, NULL},
268 {N_("/S_coring..."), NULL, folderview_scoring_cb, 0, NULL}
271 static GtkItemFactoryEntry folderview_imap_popup_entries[] =
273 {N_("/Create _new folder..."), NULL, folderview_new_imap_folder_cb, 0, NULL},
274 {N_("/_Rename folder..."), NULL, NULL, 0, NULL},
275 {N_("/_Delete folder"), NULL, folderview_rm_imap_folder_cb, 0, NULL},
276 {N_("/---"), NULL, NULL, 0, "<Separator>"},
277 {N_("/_Update folder tree"), NULL, folderview_update_tree_cb, 0, NULL},
278 {N_("/R_escan folder tree"), NULL, folderview_update_tree_cb, 1, NULL},
279 {N_("/---"), NULL, NULL, 0, "<Separator>"},
280 {N_("/Remove _IMAP4 account"), NULL, folderview_rm_imap_server_cb, 0, NULL},
281 {N_("/---"), NULL, NULL, 0, "<Separator>"},
282 {N_("/_Search folder..."), NULL, folderview_search_cb, 0, NULL},
283 {N_("/_Property..."), NULL, NULL, 0, NULL},
284 {N_("/_Processing..."), NULL, folderview_processing_cb, 0, NULL},
285 {N_("/S_coring..."), NULL, folderview_scoring_cb, 0, NULL}
288 static GtkItemFactoryEntry folderview_news_popup_entries[] =
290 {N_("/_Subscribe to newsgroup..."),
291 NULL, folderview_new_news_group_cb, 0, NULL},
292 {N_("/_Remove newsgroup"), NULL, folderview_rm_news_group_cb, 0, NULL},
293 {N_("/---"), NULL, NULL, 0, "<Separator>"},
294 {N_("/Remove _news account"), NULL, folderview_rm_news_server_cb, 0, NULL},
295 {N_("/---"), NULL, NULL, 0, "<Separator>"},
296 {N_("/_Search folder..."), NULL, folderview_search_cb, 0, NULL},
297 {N_("/_Property..."), NULL, NULL, 0, NULL},
298 {N_("/_Processing..."), NULL, folderview_processing_cb, 0, NULL},
299 {N_("/S_coring..."), NULL, folderview_scoring_cb, 0, NULL}
303 FolderView *folderview_create(void)
305 FolderView *folderview;
306 GtkWidget *scrolledwin;
308 gchar *titles[N_FOLDER_COLS] = {_("Folder"), _("New"),
309 _("Unread"), _("#")};
310 GtkWidget *mail_popup;
311 GtkWidget *news_popup;
312 GtkWidget *imap_popup;
313 GtkWidget *mbox_popup;
314 GtkItemFactory *mail_factory;
315 GtkItemFactory *news_factory;
316 GtkItemFactory *imap_factory;
317 GtkItemFactory *mbox_factory;
321 debug_print(_("Creating folder view...\n"));
322 folderview = g_new0(FolderView, 1);
324 scrolledwin = gtk_scrolled_window_new(NULL, NULL);
325 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
326 GTK_POLICY_AUTOMATIC,
328 gtk_widget_set_usize(scrolledwin,
329 prefs_common.folderview_width,
330 prefs_common.folderview_height);
332 ctree = gtk_ctree_new_with_titles(N_FOLDER_COLS, COL_FOLDER, titles);
333 gtk_container_add(GTK_CONTAINER(scrolledwin), ctree);
334 gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
335 gtk_clist_set_column_justification(GTK_CLIST(ctree), COL_NEW,
337 gtk_clist_set_column_justification(GTK_CLIST(ctree), COL_UNREAD,
339 gtk_clist_set_column_justification(GTK_CLIST(ctree), COL_TOTAL,
341 gtk_clist_set_column_width(GTK_CLIST(ctree), COL_FOLDER,
342 prefs_common.folder_col_folder);
343 gtk_clist_set_column_width(GTK_CLIST(ctree), COL_NEW,
344 prefs_common.folder_col_new);
345 gtk_clist_set_column_width(GTK_CLIST(ctree), COL_UNREAD,
346 prefs_common.folder_col_unread);
347 gtk_clist_set_column_width(GTK_CLIST(ctree), COL_TOTAL,
348 prefs_common.folder_col_total);
349 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
350 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
351 GTK_CTREE_EXPANDER_SQUARE);
352 gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
354 /* don't let title buttons take key focus */
355 for (i = 0; i < N_FOLDER_COLS; i++)
356 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(ctree)->column[i].button,
360 n_entries = sizeof(folderview_mail_popup_entries) /
361 sizeof(folderview_mail_popup_entries[0]);
362 mail_popup = menu_create_items(folderview_mail_popup_entries,
364 "<MailFolder>", &mail_factory,
366 n_entries = sizeof(folderview_imap_popup_entries) /
367 sizeof(folderview_imap_popup_entries[0]);
368 imap_popup = menu_create_items(folderview_imap_popup_entries,
370 "<IMAPFolder>", &imap_factory,
372 n_entries = sizeof(folderview_news_popup_entries) /
373 sizeof(folderview_news_popup_entries[0]);
374 news_popup = menu_create_items(folderview_news_popup_entries,
376 "<NewsFolder>", &news_factory,
378 n_entries = sizeof(folderview_mbox_popup_entries) /
379 sizeof(folderview_mbox_popup_entries[0]);
380 mbox_popup = menu_create_items(folderview_mbox_popup_entries,
382 "<MailFolder>", &mbox_factory,
385 gtk_signal_connect(GTK_OBJECT(ctree), "key_press_event",
386 GTK_SIGNAL_FUNC(folderview_key_pressed),
388 gtk_signal_connect(GTK_OBJECT(ctree), "button_press_event",
389 GTK_SIGNAL_FUNC(folderview_button_pressed),
391 gtk_signal_connect(GTK_OBJECT(ctree), "button_release_event",
392 GTK_SIGNAL_FUNC(folderview_button_released),
394 gtk_signal_connect(GTK_OBJECT(ctree), "tree_select_row",
395 GTK_SIGNAL_FUNC(folderview_selected), folderview);
397 gtk_signal_connect_after(GTK_OBJECT(ctree), "tree_expand",
398 GTK_SIGNAL_FUNC(folderview_tree_expanded),
400 gtk_signal_connect_after(GTK_OBJECT(ctree), "tree_collapse",
401 GTK_SIGNAL_FUNC(folderview_tree_collapsed),
404 gtk_signal_connect(GTK_OBJECT(ctree), "resize_column",
405 GTK_SIGNAL_FUNC(folderview_col_resized),
408 gtk_signal_connect(GTK_OBJECT(mail_popup), "selection_done",
409 GTK_SIGNAL_FUNC(folderview_popup_close),
411 gtk_signal_connect(GTK_OBJECT(imap_popup), "selection_done",
412 GTK_SIGNAL_FUNC(folderview_popup_close),
414 gtk_signal_connect(GTK_OBJECT(news_popup), "selection_done",
415 GTK_SIGNAL_FUNC(folderview_popup_close),
417 gtk_signal_connect(GTK_OBJECT(mbox_popup), "selection_done",
418 GTK_SIGNAL_FUNC(folderview_popup_close),
422 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL &
423 ~GTK_DEST_DEFAULT_HIGHLIGHT,
424 summary_drag_types, 1,
426 gtk_signal_connect(GTK_OBJECT(ctree), "drag_motion",
427 GTK_SIGNAL_FUNC(folderview_drag_motion_cb),
429 gtk_signal_connect(GTK_OBJECT(ctree), "drag_leave",
430 GTK_SIGNAL_FUNC(folderview_drag_leave_cb),
432 gtk_signal_connect(GTK_OBJECT(ctree), "drag_data_received",
433 GTK_SIGNAL_FUNC(folderview_drag_received_cb),
436 folderview->scrolledwin = scrolledwin;
437 folderview->ctree = ctree;
438 folderview->mail_popup = mail_popup;
439 folderview->mail_factory = mail_factory;
440 folderview->imap_popup = imap_popup;
441 folderview->imap_factory = imap_factory;
442 folderview->news_popup = news_popup;
443 folderview->news_factory = news_factory;
444 folderview->mbox_popup = mbox_popup;
445 folderview->mbox_factory = mbox_factory;
447 gtk_widget_show_all(scrolledwin);
449 folderview_list = g_list_append(folderview_list, folderview);
454 void folderview_init(FolderView *folderview)
456 GtkWidget *ctree = folderview->ctree;
458 PIXMAP_CREATE(ctree, inboxxpm, inboxxpmmask, inbox_xpm);
459 PIXMAP_CREATE(ctree, inboxhrmxpm, inboxhrmxpmmask, inbox_hrm_xpm);
460 PIXMAP_CREATE(ctree, outboxxpm, outboxxpmmask, outbox_xpm);
461 PIXMAP_CREATE(ctree, outboxhrmxpm, outboxhrmxpmmask, outbox_hrm_xpm);
462 PIXMAP_CREATE(ctree, folderxpm, folderxpmmask, dir_close_xpm);
463 PIXMAP_CREATE(ctree, folderopenxpm, folderopenxpmmask, dir_open_xpm);
464 PIXMAP_CREATE(ctree, folderopenhrmxpm, folderopenhrmxpmmask,
466 PIXMAP_CREATE(ctree, trashxpm, trashxpmmask, trash_xpm);
467 PIXMAP_CREATE(ctree, trashhrmxpm, trashhrmxpmmask, trash_hrm_xpm);
470 normalfont = gdk_fontset_load(NORMAL_FONT);
472 boldfont = gdk_fontset_load(BOLD_FONT);
475 bold_style = gtk_style_copy(gtk_widget_get_style(ctree));
476 bold_style->font = boldfont;
477 bold_color_style = gtk_style_copy(bold_style);
478 bold_color_style->fg[GTK_STATE_NORMAL] = folderview->color_new;
480 bold_tgtfold_style = gtk_style_copy(bold_style);
481 bold_tgtfold_style->fg[GTK_STATE_NORMAL] = folderview->color_op;
484 normal_style = gtk_style_copy(gtk_widget_get_style(ctree));
485 normal_style->font = normalfont;
486 normal_color_style = gtk_style_copy(normal_style);
487 normal_color_style->fg[GTK_STATE_NORMAL] = folderview->color_new;
491 void folderview_set(FolderView *folderview)
493 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
494 MainWindow *mainwin = folderview->mainwin;
496 debug_print(_("Setting folder info...\n"));
497 STATUSBAR_PUSH(mainwin, _("Setting folder info..."));
499 main_window_cursor_wait(mainwin);
501 folderview->selected = NULL;
502 folderview->opened = NULL;
504 gtk_clist_freeze(GTK_CLIST(ctree));
505 gtk_clist_clear(GTK_CLIST(ctree));
506 gtk_clist_thaw(GTK_CLIST(ctree));
507 gtk_clist_freeze(GTK_CLIST(ctree));
509 folderview_set_folders(folderview);
511 gtk_clist_thaw(GTK_CLIST(ctree));
512 main_window_cursor_normal(mainwin);
513 STATUSBAR_POP(mainwin);
516 void folderview_set_all(void)
520 for (list = folderview_list; list != NULL; list = list->next)
521 folderview_set((FolderView *)list->data);
524 void folderview_select(FolderView *folderview, FolderItem *item)
526 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
528 GtkCTreeNode *old_selected = folderview->selected;
532 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
533 if (node) folderview_select_node(folderview, node);
535 if (old_selected != node)
536 folder_update_op_count();
539 static void folderview_select_node(FolderView *folderview, GtkCTreeNode *node)
541 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
543 g_return_if_fail(node != NULL);
545 folderview->open_folder = TRUE;
546 gtk_ctree_select(ctree, node);
547 gtkut_ctree_set_focus_row(ctree, node);
548 if (folderview->summaryview->messages > 0)
549 gtk_widget_grab_focus(folderview->summaryview->ctree);
551 gtk_widget_grab_focus(folderview->ctree);
553 gtkut_ctree_expand_parent_all(ctree, node);
556 void folderview_unselect(FolderView *folderview)
558 if (folderview->opened && !GTK_CTREE_ROW(folderview->opened)->children)
560 (GTK_CTREE(folderview->ctree), folderview->opened);
562 folderview->selected = folderview->opened = NULL;
565 static GtkCTreeNode *folderview_find_next_unread(GtkCTree *ctree,
571 node = gtkut_ctree_node_next(ctree, node);
573 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
575 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
576 item = gtk_ctree_node_get_row_data(ctree, node);
577 if (item && item->unread > 0 && item->stype != F_TRASH)
584 void folderview_select_next_unread(FolderView *folderview)
586 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
587 GtkCTreeNode *node = NULL;
589 if ((node = folderview_find_next_unread(ctree, folderview->opened))
591 folderview_select_node(folderview, node);
595 if (!folderview->opened ||
596 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list))
598 /* search again from the first node */
599 if ((node = folderview_find_next_unread(ctree, NULL)) != NULL)
600 folderview_select_node(folderview, node);
603 void folderview_update_msg_num(FolderView *folderview, GtkCTreeNode *row,
604 gint new, gint unread, gint total)
606 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
607 static GtkCTreeNode *prev_row = NULL;
612 item = gtk_ctree_node_get_row_data(ctree, row);
615 /* CLAWS: don't know why but this always seems to be true
616 * when deleting messages. Somewhere claws does a folder
617 * scan which sets all new, unread & total to the correct
618 * values. It then enters this function, but leaves it
619 * because new, unread and total are the same... */
621 if (prev_row == row &&
623 item->unread == unread &&
624 item->total == total)
631 item->unread = unread;
634 folderview_update_node(folderview, row);
637 static void folderview_set_folders(FolderView *folderview)
641 list = folder_get_list();
643 for (; list != NULL; list = list->next)
644 folderview_append_folder(folderview, FOLDER(list->data));
647 static void folderview_scan_tree_func(Folder *folder, FolderItem *item,
653 if (FOLDER_IS_LOCAL(folder))
654 rootpath = LOCAL_FOLDER(folder)->rootpath;
655 else if (folder->type == F_IMAP && folder->account &&
656 folder->account->recv_server)
657 rootpath = folder->account->recv_server;
661 for (list = folderview_list; list != NULL; list = list->next) {
662 FolderView *folderview = (FolderView *)list->data;
663 MainWindow *mainwin = folderview->mainwin;
667 str = g_strdup_printf(_("Scanning folder %s%c%s ..."),
668 rootpath, G_DIR_SEPARATOR,
671 str = g_strdup_printf(_("Scanning folder %s ..."),
674 STATUSBAR_PUSH(mainwin, str);
675 STATUSBAR_POP(mainwin);
680 static GtkWidget *label_window_create(const gchar *str)
685 window = gtk_window_new(GTK_WINDOW_DIALOG);
686 gtk_widget_set_usize(window, 380, 60);
687 gtk_container_set_border_width(GTK_CONTAINER(window), 8);
688 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
689 gtk_window_set_title(GTK_WINDOW(window), str);
690 gtk_window_set_modal(GTK_WINDOW(window), TRUE);
691 gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, FALSE);
692 manage_window_set_transient(GTK_WINDOW(window));
694 label = gtk_label_new(str);
695 gtk_container_add(GTK_CONTAINER(window), label);
696 gtk_widget_show(label);
698 gtk_widget_show_now(window);
703 void folderview_update_tree(Folder *folder)
707 g_return_if_fail(folder != NULL);
709 if (!folder->scan_tree) return;
712 window = label_window_create(_("Rescanning folder tree..."));
714 folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
715 folder->scan_tree(folder);
716 folder_set_ui_func(folder, NULL, NULL);
719 folderview_set_all();
721 gtk_widget_destroy(window);
725 void folderview_update_all(void)
731 window = label_window_create(_("Rescanning all folder trees..."));
733 list = folder_get_list();
734 for (; list != NULL; list = list->next) {
735 Folder *folder = list->data;
737 if (!folder->scan_tree) continue;
738 folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
739 folder->scan_tree(folder);
740 folder_set_ui_func(folder, NULL, NULL);
744 folderview_set_all();
745 gtk_widget_destroy(window);
749 void folderview_update_all_node(void)
753 FolderView *folderview;
757 for (list = folderview_list; list != NULL; list = list->next) {
758 folderview = (FolderView *)list->data;
759 ctree = GTK_CTREE(folderview->ctree);
762 main_window_lock(folderview->mainwin);
763 gtk_widget_set_sensitive(folderview->ctree, FALSE);
765 for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
766 node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
767 item = gtk_ctree_node_get_row_data(ctree, node);
768 if (!item || !FOLDER_IS_LOCAL(item->folder) ||
771 folderview_scan_tree_func(item->folder, item, NULL);
772 folder_item_scan(item);
773 folderview_update_node(folderview, node);
776 gtk_widget_set_sensitive(folderview->ctree, TRUE);
777 main_window_unlock(folderview->mainwin);
784 static gboolean folderview_search_new_recursive(GtkCTree *ctree,
790 item = gtk_ctree_node_get_row_data(ctree, node);
793 (item->stype == F_QUEUE && item->total > 0))
796 node = GTK_CTREE_ROW(node)->children;
798 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
801 if (folderview_search_new_recursive(ctree, node) == TRUE)
803 node = GTK_CTREE_ROW(node)->sibling;
809 static gboolean folderview_have_new_children(FolderView *folderview,
812 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
815 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
819 node = GTK_CTREE_ROW(node)->children;
822 if (folderview_search_new_recursive(ctree, node) == TRUE)
824 node = GTK_CTREE_ROW(node)->sibling;
830 static gboolean folderview_search_unread_recursive(GtkCTree *ctree,
836 item = gtk_ctree_node_get_row_data(ctree, node);
838 if (item->unread > 0 ||
839 (item->stype == F_QUEUE && item->total > 0))
842 node = GTK_CTREE_ROW(node)->children;
844 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
847 if (folderview_search_unread_recursive(ctree, node) == TRUE)
849 node = GTK_CTREE_ROW(node)->sibling;
855 static gboolean folderview_have_unread_children(FolderView *folderview,
858 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
861 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
865 node = GTK_CTREE_ROW(node)->children;
868 if (folderview_search_unread_recursive(ctree, node) == TRUE)
870 node = GTK_CTREE_ROW(node)->sibling;
876 static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node)
878 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
879 GtkStyle *style = NULL;
881 GdkPixmap *xpm, *openxpm;
882 GdkBitmap *mask, *openmask;
885 gboolean add_unread_mark;
886 gboolean use_bold, use_color;
888 item = gtk_ctree_node_get_row_data(ctree, node);
889 g_return_if_fail(item != NULL);
891 switch (item->stype) {
895 if (item->hide_read_msgs) {
896 openxpm = inboxhrmxpm;
897 openmask = inboxhrmxpmmask;
900 openmask = inboxxpmmask;
902 name = g_strdup(_("Inbox"));
907 if (item->hide_read_msgs) {
908 openxpm = outboxhrmxpm;
909 openmask = outboxhrmxpmmask;
912 openmask = outboxxpmmask;
914 name = g_strdup(_("Outbox"));
919 if (item->hide_read_msgs) {
920 openxpm = outboxhrmxpm;
921 openmask = outboxhrmxpmmask;
924 openmask = outboxxpmmask;
926 name = g_strdup(_("Queue"));
931 if (item->hide_read_msgs) {
932 openxpm = trashhrmxpm;
933 openmask = trashhrmxpmmask;
936 openmask = trashxpmmask;
938 name = g_strdup(_("Trash"));
942 mask = folderxpmmask;
943 if (item->hide_read_msgs) {
944 openxpm = folderopenhrmxpm;
945 openmask = folderopenhrmxpmmask;
947 openxpm = folderopenxpm;
948 openmask = folderopenxpmmask;
950 name = g_strdup(_("Draft"));
954 mask = folderxpmmask;
955 if (item->hide_read_msgs) {
956 openxpm = folderopenhrmxpm;
957 openmask = folderopenhrmxpmmask;
959 openxpm = folderopenxpm;
960 openmask = folderopenxpmmask;
963 switch (item->folder->type) {
965 name = " (MH)"; break;
967 name = " (mbox)"; break;
969 name = " (IMAP4)"; break;
971 name = " (News)"; break;
975 name = g_strconcat(item->name, name, NULL);
977 name = g_strdup(item->name);
980 if (!GTK_CTREE_ROW(node)->expanded &&
981 folderview_have_unread_children(folderview, node))
982 add_unread_mark = TRUE;
984 add_unread_mark = FALSE;
986 if (item->stype == F_QUEUE && item->total > 0 &&
987 prefs_common.display_folder_unread) {
988 str = g_strdup_printf("%s (%d%s)", name, item->total,
989 add_unread_mark ? "+" : "");
990 gtk_ctree_set_node_info(ctree, node, str, FOLDER_SPACING,
991 xpm, mask, openxpm, openmask,
992 FALSE, GTK_CTREE_ROW(node)->expanded);
994 } else if ((item->unread > 0 || add_unread_mark) &&
995 prefs_common.display_folder_unread) {
997 if (item->unread > 0)
998 str = g_strdup_printf("%s (%d%s)", name, item->unread,
999 add_unread_mark ? "+" : "");
1001 str = g_strdup_printf("%s (+)", name);
1002 gtk_ctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1003 xpm, mask, openxpm, openmask,
1004 FALSE, GTK_CTREE_ROW(node)->expanded);
1007 gtk_ctree_set_node_info(ctree, node, name, FOLDER_SPACING,
1008 xpm, mask, openxpm, openmask,
1009 FALSE, GTK_CTREE_ROW(node)->expanded);
1012 if (!item->parent) {
1013 gtk_ctree_node_set_text(ctree, node, COL_NEW, "-");
1014 gtk_ctree_node_set_text(ctree, node, COL_UNREAD, "-");
1015 gtk_ctree_node_set_text(ctree, node, COL_TOTAL, "-");
1017 gtk_ctree_node_set_text(ctree, node, COL_NEW, itos(item->new));
1018 gtk_ctree_node_set_text(ctree, node, COL_UNREAD, itos(item->unread));
1019 gtk_ctree_node_set_text(ctree, node, COL_TOTAL, itos(item->total));
1022 if (item->stype == F_TRASH)
1023 use_bold = use_color = FALSE;
1024 if (item->stype == F_QUEUE) {
1025 /* highlight queue folder if there are any messages */
1026 use_bold = use_color = (item->total > 0);
1028 /* if unread messages exist, print with bold font */
1029 use_bold = (item->unread > 0) || add_unread_mark;
1030 /* if new messages exist, print with colored letter */
1034 folderview_have_new_children(folderview, node));
1037 gtk_ctree_node_set_foreground(ctree, node, NULL);
1039 if (use_bold && use_color)
1040 style = bold_color_style;
1041 else if (use_bold) {
1043 if (item->op_count > 0) {
1044 style = bold_tgtfold_style;
1047 else if (use_color) {
1048 style = normal_color_style;
1049 gtk_ctree_node_set_foreground(ctree, node,
1050 &folderview->color_new);
1052 else if (item->op_count > 0) {
1053 style = bold_tgtfold_style;
1055 style = normal_style;
1058 gtk_ctree_node_set_row_style(ctree, node, style);
1060 if ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
1061 folderview_update_node(folderview, node);
1064 void folderview_update_item(FolderItem *item, gboolean update_summary)
1067 FolderView *folderview;
1071 g_return_if_fail(item != NULL);
1073 for (list = folderview_list; list != NULL; list = list->next) {
1074 folderview = (FolderView *)list->data;
1075 ctree = GTK_CTREE(folderview->ctree);
1077 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1079 folderview_update_node(folderview, node);
1080 if (update_summary && folderview->opened == node)
1081 summary_show(folderview->summaryview,
1087 static void folderview_update_item_foreach_func(gpointer key, gpointer val,
1090 folderview_update_item((FolderItem *)key, FALSE);
1093 void folderview_update_item_foreach(GHashTable *table)
1095 g_hash_table_foreach(table, folderview_update_item_foreach_func, NULL);
1098 static gboolean folderview_gnode_func(GtkCTree *ctree, guint depth,
1099 GNode *gnode, GtkCTreeNode *cnode,
1102 FolderView *folderview = (FolderView *)data;
1103 FolderItem *item = FOLDER_ITEM(gnode->data);
1105 g_return_val_if_fail(item != NULL, FALSE);
1107 gtk_ctree_node_set_row_data(ctree, cnode, item);
1108 folderview_update_node(folderview, cnode);
1113 static void folderview_expand_func(GtkCTree *ctree, GtkCTreeNode *node,
1116 FolderView *folderview = (FolderView *)data;
1119 if (GTK_CTREE_ROW(node)->children) {
1120 item = gtk_ctree_node_get_row_data(ctree, node);
1121 g_return_if_fail(item != NULL);
1123 if (!item->collapsed)
1124 gtk_ctree_expand(ctree, node);
1126 folderview_update_node(folderview, node);
1130 #define SET_SPECIAL_FOLDER(ctree, item) \
1133 GtkCTreeNode *node, *sibling; \
1135 node = gtk_ctree_find_by_row_data(ctree, root, item); \
1137 g_warning("%s not found.\n", item->path); \
1140 sibling = GTK_CTREE_ROW(root)->children; \
1142 sibling = GTK_CTREE_ROW(prev)->sibling; \
1143 if (node != sibling) \
1144 gtk_ctree_move(ctree, node, root, sibling); \
1151 static void folderview_sort_folders(FolderView *folderview, GtkCTreeNode *root,
1154 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1155 GtkCTreeNode *prev = NULL;
1157 gtk_ctree_sort_recursive(ctree, root);
1159 if (GTK_CTREE_ROW(root)->parent) return;
1161 SET_SPECIAL_FOLDER(ctree, folder->inbox);
1162 SET_SPECIAL_FOLDER(ctree, folder->outbox);
1163 SET_SPECIAL_FOLDER(ctree, folder->draft);
1164 SET_SPECIAL_FOLDER(ctree, folder->queue);
1165 SET_SPECIAL_FOLDER(ctree, folder->trash);
1168 static void folderview_append_folder(FolderView *folderview, Folder *folder)
1170 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1173 g_return_if_fail(folder != NULL);
1175 root = gtk_ctree_insert_gnode(ctree, NULL, NULL, folder->node,
1176 folderview_gnode_func, folderview);
1177 gtk_ctree_pre_recursive(ctree, root, folderview_expand_func,
1179 folderview_sort_folders(folderview, root, folder);
1182 void folderview_new_folder(FolderView *folderview)
1184 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1187 if (!folderview->selected) return;
1189 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1190 g_return_if_fail(item != NULL);
1191 g_return_if_fail(item->folder != NULL);
1193 switch (item->folder->type) {
1195 folderview_new_mbox_folder_cb(folderview, 0, NULL);
1199 folderview_new_folder_cb(folderview, 0, NULL);
1202 folderview_new_imap_folder_cb(folderview, 0, NULL);
1210 void folderview_rename_folder(FolderView *folderview)
1212 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1215 if (!folderview->selected) return;
1217 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1218 g_return_if_fail(item != NULL);
1219 g_return_if_fail(item->folder != NULL);
1220 if (!item->path) return;
1221 if (item->stype != F_NORMAL) return;
1223 switch (item->folder->type) {
1225 folderview_rename_mbox_folder_cb(folderview, 0, NULL);
1228 folderview_rename_folder_cb(folderview, 0, NULL);
1237 void folderview_delete_folder(FolderView *folderview)
1239 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1242 if (!folderview->selected) return;
1244 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1245 g_return_if_fail(item != NULL);
1246 g_return_if_fail(item->folder != NULL);
1247 if (!item->path) return;
1248 if (item->stype != F_NORMAL) return;
1250 switch (item->folder->type) {
1254 folderview_delete_folder_cb(folderview, 0, NULL);
1257 folderview_rm_imap_folder_cb(folderview, 0, NULL);
1265 /* callback functions */
1267 static void folderview_button_pressed(GtkWidget *ctree, GdkEventButton *event,
1268 FolderView *folderview)
1270 GtkCList *clist = GTK_CLIST(ctree);
1271 gint prev_row = -1, row = -1, column = -1;
1275 gboolean new_folder = FALSE;
1276 gboolean rename_folder = FALSE;
1277 gboolean delete_folder = FALSE;
1278 gboolean update_tree = FALSE;
1279 gboolean rescan_tree = FALSE;
1280 gboolean remove_tree = FALSE;
1281 gboolean folder_property = FALSE;
1282 gboolean folder_processing = FALSE;
1283 gboolean folder_scoring = FALSE;
1284 gboolean search_folder = FALSE;
1288 if (event->button == 1) {
1289 folderview->open_folder = TRUE;
1293 if (event->button == 2 || event->button == 3) {
1295 if (clist->selection) {
1298 node = GTK_CTREE_NODE(clist->selection->data);
1300 prev_row = gtkut_ctree_get_nth_from_node
1301 (GTK_CTREE(ctree), node);
1304 if (!gtk_clist_get_selection_info(clist, event->x, event->y,
1307 if (prev_row != row) {
1308 gtk_clist_unselect_all(clist);
1309 if (event->button == 2)
1310 folderview_select_node
1312 gtk_ctree_node_nth(GTK_CTREE(ctree),
1315 gtk_clist_select_row(clist, row, column);
1319 if (event->button != 3) return;
1321 item = gtk_clist_get_row_data(clist, row);
1322 g_return_if_fail(item != NULL);
1323 g_return_if_fail(item->folder != NULL);
1324 folder = item->folder;
1326 if (folderview->mainwin->lock_count == 0) {
1328 if (item->parent == NULL)
1329 update_tree = remove_tree = TRUE;
1331 search_folder = TRUE;
1332 if (FOLDER_IS_LOCAL(folder) || FOLDER_TYPE(folder) == F_IMAP || FOLDER_TYPE(folder) == F_MBOX) {
1333 if (item->parent == NULL)
1334 update_tree = rescan_tree = TRUE;
1335 else if (item->stype == F_NORMAL)
1336 rename_folder = delete_folder = folder_property = folder_scoring = folder_processing = TRUE;
1337 else if (item->stype == F_INBOX)
1338 folder_property = folder_scoring = folder_processing = TRUE;
1339 else if (item->stype == F_TRASH)
1340 folder_processing = TRUE;
1341 else if (item->stype == F_OUTBOX)
1342 folder_processing = TRUE;
1343 } else if (FOLDER_TYPE(folder) == F_NEWS) {
1344 if (item->parent != NULL)
1345 delete_folder = folder_scoring = folder_processing = TRUE;
1349 #define SET_SENS(factory, name, sens) \
1350 menu_set_sensitive(folderview->factory, name, sens)
1352 if (FOLDER_IS_LOCAL(folder)) {
1353 popup = folderview->mail_popup;
1354 menu_set_insensitive_all(GTK_MENU_SHELL(popup));
1355 SET_SENS(mail_factory, "/Create new folder...", new_folder);
1356 SET_SENS(mail_factory, "/Rename folder...", rename_folder);
1357 SET_SENS(mail_factory, "/Delete folder", delete_folder);
1358 SET_SENS(mail_factory, "/Update folder tree", update_tree);
1359 SET_SENS(mail_factory, "/Rescan folder tree", rescan_tree);
1360 SET_SENS(mail_factory, "/Remove mailbox", remove_tree);
1361 SET_SENS(mail_factory, "/Property...", folder_property);
1362 SET_SENS(mail_factory, "/Processing...", folder_processing);
1363 SET_SENS(mail_factory, "/Scoring...", folder_scoring);
1364 SET_SENS(mail_factory, "/Search folder...", search_folder);
1365 } else if (FOLDER_TYPE(folder) == F_IMAP) {
1366 popup = folderview->imap_popup;
1367 menu_set_insensitive_all(GTK_MENU_SHELL(popup));
1368 SET_SENS(imap_factory, "/Create new folder...", new_folder);
1369 SET_SENS(imap_factory, "/Rename folder...", rename_folder);
1370 SET_SENS(imap_factory, "/Delete folder", delete_folder);
1371 SET_SENS(imap_factory, "/Update folder tree", update_tree);
1372 SET_SENS(imap_factory, "/Rescan folder tree", rescan_tree);
1373 SET_SENS(imap_factory, "/Remove IMAP4 account", remove_tree);
1374 SET_SENS(imap_factory, "/Processing...", folder_processing);
1375 SET_SENS(imap_factory, "/Scoring...", folder_scoring);
1376 SET_SENS(imap_factory, "/Search folder...", search_folder);
1377 } else if (FOLDER_TYPE(folder) == F_NEWS) {
1378 popup = folderview->news_popup;
1379 menu_set_insensitive_all(GTK_MENU_SHELL(popup));
1380 SET_SENS(news_factory, "/Subscribe to newsgroup...", new_folder);
1381 SET_SENS(news_factory, "/Remove newsgroup", delete_folder);
1382 SET_SENS(news_factory, "/Remove news account", remove_tree);
1383 SET_SENS(news_factory, "/Search folder...", search_folder);
1384 SET_SENS(news_factory, "/Processing...", folder_processing);
1385 SET_SENS(news_factory, "/Scoring...", folder_scoring);
1386 } else if (FOLDER_TYPE(folder) == F_MBOX) {
1387 popup = folderview->mbox_popup;
1388 menu_set_insensitive_all(GTK_MENU_SHELL(popup));
1389 SET_SENS(mbox_factory, "/Create new folder...", new_folder);
1390 SET_SENS(mbox_factory, "/Rename folder...", rename_folder);
1391 SET_SENS(mbox_factory, "/Delete folder", delete_folder);
1392 SET_SENS(mbox_factory, "/Processing...", folder_processing);
1393 SET_SENS(mbox_factory, "/Scoring...", folder_scoring);
1399 gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
1400 event->button, event->time);
1403 static void folderview_button_released(GtkWidget *ctree, GdkEventButton *event,
1404 FolderView *folderview)
1408 if (event->button == 1 && folderview->open_folder == FALSE &&
1409 folderview->opened != NULL) {
1410 gtk_ctree_select(GTK_CTREE(ctree), folderview->opened);
1411 gtkut_ctree_set_focus_row(GTK_CTREE(ctree),
1412 folderview->opened);
1416 #define BREAK_ON_MODIFIER_KEY() \
1417 if ((event->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK)) != 0) break
1419 static void folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
1420 FolderView *folderview)
1424 switch (event->keyval) {
1427 if (folderview->selected) {
1428 folderview_select_node(folderview,
1429 folderview->selected);
1441 BREAK_ON_MODIFIER_KEY();
1442 summary_pass_key_press_event(folderview->summaryview, event);
1447 static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row,
1448 gint column, FolderView *folderview)
1450 static gboolean can_select = TRUE; /* exclusive lock */
1454 folderview->selected = row;
1456 if (folderview->opened == row) {
1457 folderview->open_folder = FALSE;
1462 gtk_ctree_select(ctree, folderview->opened);
1463 gtkut_ctree_set_focus_row(ctree, folderview->opened);
1467 if (!folderview->open_folder) return;
1469 item = gtk_ctree_node_get_row_data(ctree, row);
1474 /* CLAWS: set compose button type: news folder items
1475 * always have a news folder as parent */
1477 main_window_toolbar_set_compose_button
1478 (folderview->mainwin,
1479 item->folder->type == F_NEWS ?
1480 COMPOSEBUTTON_NEWS : COMPOSEBUTTON_MAIL);
1483 debug_print(_("Folder %s is selected\n"), item->path);
1485 if (!GTK_CTREE_ROW(row)->children)
1486 gtk_ctree_expand(ctree, row);
1487 if (folderview->opened &&
1488 !GTK_CTREE_ROW(folderview->opened)->children)
1489 gtk_ctree_collapse(ctree, folderview->opened);
1491 /* ungrab the mouse event */
1492 if (GTK_WIDGET_HAS_GRAB(ctree)) {
1493 gtk_grab_remove(GTK_WIDGET(ctree));
1494 if (gdk_pointer_is_grabbed())
1495 gdk_pointer_ungrab(GDK_CURRENT_TIME);
1498 opened = summary_show(folderview->summaryview, item, FALSE);
1501 gtk_ctree_select(ctree, folderview->opened);
1502 gtkut_ctree_set_focus_row(ctree, folderview->opened);
1504 folderview->opened = row;
1506 folderview->open_folder = FALSE;
1510 static void folderview_tree_expanded(GtkCTree *ctree, GtkCTreeNode *node,
1511 FolderView *folderview)
1515 item = gtk_ctree_node_get_row_data(ctree, node);
1516 g_return_if_fail(item != NULL);
1517 item->collapsed = FALSE;
1518 folderview_update_node(folderview, node);
1521 static void folderview_tree_collapsed(GtkCTree *ctree, GtkCTreeNode *node,
1522 FolderView *folderview)
1526 item = gtk_ctree_node_get_row_data(ctree, node);
1527 g_return_if_fail(item != NULL);
1528 item->collapsed= TRUE;
1529 folderview_update_node(folderview, node);
1532 static void folderview_popup_close(GtkMenuShell *menu_shell,
1533 FolderView *folderview)
1535 if (!folderview->opened) return;
1537 gtk_ctree_select(GTK_CTREE(folderview->ctree), folderview->opened);
1538 gtkut_ctree_set_focus_row(GTK_CTREE(folderview->ctree),
1539 folderview->opened);
1542 static void folderview_col_resized(GtkCList *clist, gint column, gint width,
1543 FolderView *folderview)
1547 prefs_common.folder_col_folder = width;
1550 prefs_common.folder_col_new = width;
1553 prefs_common.folder_col_unread = width;
1556 prefs_common.folder_col_total = width;
1562 static GtkCTreeNode *folderview_find_by_name(GtkCTree *ctree,
1569 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
1573 node = GTK_CTREE_ROW(node)->children;
1576 item = gtk_ctree_node_get_row_data(ctree, node);
1577 if (!folderview_compare_name(item, name))
1579 node = GTK_CTREE_ROW(node)->sibling;
1585 static void folderview_update_tree_cb(FolderView *folderview, guint action,
1588 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1591 if (!folderview->selected) return;
1593 summary_show(folderview->summaryview, NULL, FALSE);
1595 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1596 g_return_if_fail(item != NULL);
1597 g_return_if_fail(item->folder != NULL);
1600 folderview_update_all_node();
1602 folderview_update_tree(item->folder);
1605 static void folderview_new_folder_cb(FolderView *folderview, guint action,
1608 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1609 gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
1611 FolderItem *new_item;
1615 if (!folderview->selected) return;
1617 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1618 g_return_if_fail(item != NULL);
1619 g_return_if_fail(item->folder != NULL);
1621 new_folder = input_dialog(_("New folder"),
1622 _("Input the name of new folder:"),
1624 if (!new_folder) return;
1626 if (item->folder->type != F_MBOX) {
1627 if (strchr(new_folder, G_DIR_SEPARATOR) != NULL) {
1628 alertpanel_error(_("`%c' can't be included in folder name."),
1635 /* find whether the directory already exists */
1636 if (folderview_find_by_name(ctree, folderview->selected, new_folder)) {
1637 alertpanel_error(_("The folder `%s' already exists."),
1643 new_item = item->folder->create_folder(item->folder, item, new_folder);
1645 alertpanel_error(_("The folder `%s' could not be created."),
1652 gtk_clist_freeze(GTK_CLIST(ctree));
1654 text[COL_FOLDER] = new_item->name;
1655 node = gtk_ctree_insert_node(ctree, folderview->selected, NULL, text,
1657 folderxpm, folderxpmmask,
1658 folderopenxpm, folderopenxpmmask,
1660 gtk_ctree_expand(ctree, folderview->selected);
1661 gtk_ctree_node_set_row_data(ctree, node, new_item);
1662 folderview_sort_folders(folderview, folderview->selected, item->folder);
1664 gtk_clist_thaw(GTK_CLIST(ctree));
1666 folder_write_list();
1669 static void folderview_new_mbox_folder_cb(FolderView *folderview, guint action,
1672 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1673 gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
1675 FolderItem *new_item;
1679 if (!folderview->selected) return;
1681 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1682 g_return_if_fail(item != NULL);
1683 g_return_if_fail(item->folder != NULL);
1685 new_folder = input_dialog(_("New folder"),
1686 _("Input the name of new folder:"),
1688 if (!new_folder) return;
1690 /* find whether the directory already exists */
1691 if (folderview_find_by_name(ctree, folderview->selected, new_folder)) {
1692 alertpanel_error(_("The folder `%s' already exists."),
1698 new_item = item->folder->create_folder(item->folder, item, new_folder);
1700 if (!new_item) return;
1702 gtk_clist_freeze(GTK_CLIST(ctree));
1704 text[COL_FOLDER] = new_item->name;
1705 node = gtk_ctree_insert_node(ctree, folderview->selected, NULL, text,
1707 folderxpm, folderxpmmask,
1708 folderopenxpm, folderopenxpmmask,
1710 gtk_ctree_expand(ctree, folderview->selected);
1711 gtk_ctree_node_set_row_data(ctree, node, new_item);
1712 folderview_sort_folders(folderview, folderview->selected, item->folder);
1714 gtk_clist_thaw(GTK_CLIST(ctree));
1716 folder_write_list();
1719 static void folderview_rename_folder_cb(FolderView *folderview, guint action,
1722 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1727 if (!folderview->selected) return;
1729 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1730 g_return_if_fail(item != NULL);
1731 g_return_if_fail(item->path != NULL);
1732 g_return_if_fail(item->folder != NULL);
1734 message = g_strdup_printf(_("Input new name for `%s':"),
1735 g_basename(item->path));
1736 new_folder = input_dialog(_("Rename folder"), message,
1737 g_basename(item->path));
1739 if (!new_folder) return;
1741 if (strchr(new_folder, G_DIR_SEPARATOR) != NULL) {
1742 alertpanel_error(_("`%c' can't be included in folder name."),
1748 if (folderview_find_by_name
1749 (ctree, GTK_CTREE_ROW(folderview->selected)->parent,
1751 alertpanel_error(_("The folder `%s' already exists."),
1757 if (item->folder->rename_folder(item->folder, item, new_folder) < 0) {
1763 gtk_clist_freeze(GTK_CLIST(ctree));
1765 folderview_update_node(folderview, folderview->selected);
1766 folderview_sort_folders(folderview,
1767 GTK_CTREE_ROW(folderview->selected)->parent,
1769 if (folderview->opened == folderview->selected) {
1770 if (!GTK_CTREE_ROW(folderview->opened)->children)
1771 gtk_ctree_expand(ctree, folderview->opened);
1772 summary_show(folderview->summaryview, item, FALSE);
1775 gtk_clist_thaw(GTK_CLIST(ctree));
1777 folder_write_list();
1780 static void folderview_rename_mbox_folder_cb(FolderView *folderview,
1784 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1789 if (!folderview->selected) return;
1791 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1792 g_return_if_fail(item != NULL);
1793 g_return_if_fail(item->path != NULL);
1794 g_return_if_fail(item->folder != NULL);
1796 message = g_strdup_printf(_("Input new name for `%s':"),
1797 g_basename(item->path));
1798 new_folder = input_dialog(_("Rename folder"), message,
1799 g_basename(item->path));
1801 if (!new_folder) return;
1803 if (folderview_find_by_name
1804 (ctree, GTK_CTREE_ROW(folderview->selected)->parent,
1806 alertpanel_error(_("The folder `%s' already exists."),
1812 if (item->folder->rename_folder(item->folder, item, new_folder) < 0) {
1818 gtk_clist_freeze(GTK_CLIST(ctree));
1820 folderview_update_node(folderview, folderview->selected);
1821 folderview_sort_folders(folderview,
1822 GTK_CTREE_ROW(folderview->selected)->parent,
1824 if (folderview->opened == folderview->selected) {
1825 if (!GTK_CTREE_ROW(folderview->opened)->children)
1826 gtk_ctree_expand(ctree, folderview->opened);
1827 summary_show(folderview->summaryview, item, FALSE);
1830 gtk_clist_thaw(GTK_CLIST(ctree));
1832 folder_write_list();
1835 static void folderview_delete_folder_cb(FolderView *folderview, guint action,
1838 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1843 if (!folderview->selected) return;
1845 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1846 g_return_if_fail(item != NULL);
1847 g_return_if_fail(item->path != NULL);
1848 g_return_if_fail(item->folder != NULL);
1850 message = g_strdup_printf
1851 (_("All folder(s) and message(s) under `%s' will be deleted.\n"
1852 "Do you really want to delete?"),
1853 g_basename(item->path));
1854 avalue = alertpanel(_("Delete folder"), message,
1855 _("Yes"), _("+No"), NULL);
1857 if (avalue != G_ALERTDEFAULT) return;
1859 if (item->folder->remove_folder(item->folder, item) < 0) {
1860 alertpanel_error(_("Can't remove the folder `%s'."),
1865 if (folderview->opened == folderview->selected ||
1866 gtk_ctree_is_ancestor(ctree,
1867 folderview->selected,
1868 folderview->opened)) {
1869 summary_clear_all(folderview->summaryview);
1870 folderview->opened = NULL;
1873 gtk_ctree_remove_node(ctree, folderview->selected);
1874 folder_write_list();
1877 static void folderview_remove_mailbox_cb(FolderView *folderview, guint action,
1880 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1886 if (!folderview->selected) return;
1887 node = folderview->selected;
1888 item = gtk_ctree_node_get_row_data(ctree, node);
1889 g_return_if_fail(item != NULL);
1890 g_return_if_fail(item->folder != NULL);
1891 if (item->parent) return;
1893 message = g_strdup_printf
1894 (_("Really remove the mailbox `%s' ?\n"
1895 "(The messages are NOT deleted from disk)"),
1896 item->folder->name);
1897 avalue = alertpanel(_("Remove folder"), message,
1898 _("Yes"), _("+No"), NULL);
1900 if (avalue != G_ALERTDEFAULT) return;
1902 folder_destroy(item->folder);
1903 summary_clear_all(folderview->summaryview);
1904 folderview_unselect(folderview);
1905 gtk_ctree_remove_node(ctree, node);
1906 folder_write_list();
1909 static void folderview_new_imap_folder_cb(FolderView *folderview, guint action,
1912 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1913 gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
1916 FolderItem *new_item;
1920 if (!folderview->selected) return;
1922 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1923 g_return_if_fail(item != NULL);
1924 g_return_if_fail(item->folder != NULL);
1925 g_return_if_fail(item->folder->type == F_IMAP);
1926 g_return_if_fail(item->folder->account != NULL);
1928 new_folder = input_dialog
1930 _("Input the name of new folder:\n"
1931 "(if you want to create a folder to store subfolders,\n"
1932 " append `/' at the end of the name)"),
1934 if (!new_folder) return;
1936 if ((p = strchr(new_folder, G_DIR_SEPARATOR)) != NULL &&
1938 alertpanel_error(_("`%c' can't be included in folder name."),
1944 /* find whether the directory already exists */
1945 if (folderview_find_by_name(ctree, folderview->selected, new_folder)) {
1946 alertpanel_error(_("The folder `%s' already exists."),
1952 new_item = item->folder->create_folder(item->folder, item, new_folder);
1954 alertpanel_error(_("Can't create the folder `%s'."),
1961 gtk_clist_freeze(GTK_CLIST(ctree));
1963 text[COL_FOLDER] = new_item->name;
1964 node = gtk_ctree_insert_node(ctree, folderview->selected, NULL, text,
1966 folderxpm, folderxpmmask,
1967 folderopenxpm, folderopenxpmmask,
1969 gtk_ctree_expand(ctree, folderview->selected);
1970 gtk_ctree_node_set_row_data(ctree, node, new_item);
1971 folderview_sort_folders(folderview, folderview->selected, item->folder);
1973 gtk_clist_thaw(GTK_CLIST(ctree));
1975 folder_write_list();
1978 static void folderview_rm_imap_folder_cb(FolderView *folderview, guint action,
1981 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1986 if (!folderview->selected) return;
1988 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1989 g_return_if_fail(item != NULL);
1990 g_return_if_fail(item->folder != NULL);
1991 g_return_if_fail(item->folder->type == F_IMAP);
1992 g_return_if_fail(item->folder->account != NULL);
1994 message = g_strdup_printf(_("Really delete folder `%s'?"),
1995 g_basename(item->path));
1996 avalue = alertpanel(_("Delete folder"), message,
1997 _("Yes"), _("+No"), NULL);
1999 if (avalue != G_ALERTDEFAULT) return;
2001 if (item->folder->remove_folder(item->folder, item) < 0) {
2002 alertpanel_error(_("Can't remove the folder `%s'."),
2004 if (folderview->opened == folderview->selected)
2005 summary_show(folderview->summaryview,
2006 folderview->summaryview->folder_item,
2011 if (folderview->opened == folderview->selected ||
2012 gtk_ctree_is_ancestor(ctree,
2013 folderview->selected,
2014 folderview->opened)) {
2015 summary_clear_all(folderview->summaryview);
2016 folderview->opened = NULL;
2019 gtk_ctree_remove_node(ctree, folderview->selected);
2020 folder_write_list();
2023 static void folderview_rm_imap_server_cb(FolderView *folderview, guint action,
2026 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2031 if (!folderview->selected) return;
2033 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2034 g_return_if_fail(item != NULL);
2035 g_return_if_fail(item->folder != NULL);
2036 g_return_if_fail(item->folder->type == F_IMAP);
2037 g_return_if_fail(item->folder->account != NULL);
2039 message = g_strdup_printf(_("Really delete IMAP4 account `%s'?"),
2040 item->folder->name);
2041 avalue = alertpanel(_("Delete IMAP4 account"), message,
2042 _("Yes"), _("+No"), NULL);
2045 if (avalue != G_ALERTDEFAULT) return;
2047 if (folderview->opened == folderview->selected ||
2048 gtk_ctree_is_ancestor(ctree,
2049 folderview->selected,
2050 folderview->opened)) {
2051 summary_clear_all(folderview->summaryview);
2052 folderview->opened = NULL;
2055 account_destroy(item->folder->account);
2056 folder_destroy(item->folder);
2057 gtk_ctree_remove_node(ctree, folderview->selected);
2059 main_window_reflect_prefs_all();
2060 folder_write_list();
2063 static void folderview_new_news_group_cb(FolderView *folderview, guint action,
2066 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2067 gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
2068 GtkCTreeNode *servernode, *node;
2071 FolderItem *rootitem;
2072 FolderItem *newitem;
2077 if (!folderview->selected) return;
2079 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2080 g_return_if_fail(item != NULL);
2081 folder = item->folder;
2082 g_return_if_fail(folder != NULL);
2083 g_return_if_fail(folder->type == F_NEWS);
2084 g_return_if_fail(folder->account != NULL);
2086 if (GTK_CTREE_ROW(folderview->selected)->parent != NULL)
2087 servernode = GTK_CTREE_ROW(folderview->selected)->parent;
2089 servernode = folderview->selected;
2091 rootitem = gtk_ctree_node_get_row_data(ctree, servernode);
2093 new_subscr = grouplist_dialog(folder);
2095 /* remove unsubscribed newsgroups */
2096 for (gnode = folder->node->children; gnode != NULL; ) {
2097 GNode *next = gnode->next;
2099 item = FOLDER_ITEM(gnode->data);
2100 if (g_slist_find_custom(new_subscr, item->name,
2101 (GCompareFunc)g_strcasecmp) != NULL) {
2106 node = gtk_ctree_find_by_row_data(ctree, servernode, item);
2112 if (folderview->opened == node) {
2113 summary_clear_all(folderview->summaryview);
2114 folderview->opened = NULL;
2117 folder_item_remove(item);
2118 gtk_ctree_remove_node(ctree, node);
2123 gtk_clist_freeze(GTK_CLIST(ctree));
2125 /* add subscribed newsgroups */
2126 for (cur = new_subscr; cur != NULL; cur = cur->next) {
2127 gchar *name = (gchar *)cur->data;
2129 if (folderview_find_by_name(ctree, servernode, name) != NULL)
2132 text[COL_FOLDER] = name;
2133 node = gtk_ctree_insert_node(ctree, servernode, NULL, text,
2135 folderxpm, folderxpmmask,
2136 folderopenxpm, folderopenxpmmask,
2138 gtk_ctree_expand(ctree, servernode);
2140 newitem = folder_item_new(name, name);
2141 folder_item_append(rootitem, newitem);
2142 gtk_ctree_node_set_row_data(ctree, node, newitem);
2145 gtk_ctree_sort_node(ctree, servernode);
2146 gtk_clist_thaw(GTK_CLIST(ctree));
2148 slist_free_strings(new_subscr);
2149 g_slist_free(new_subscr);
2151 folder_write_list();
2154 static void folderview_rm_news_group_cb(FolderView *folderview, guint action,
2157 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2162 if (!folderview->selected) return;
2164 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2165 g_return_if_fail(item != NULL);
2166 g_return_if_fail(item->folder != NULL);
2167 g_return_if_fail(item->folder->type == F_NEWS);
2168 g_return_if_fail(item->folder->account != NULL);
2170 message = g_strdup_printf(_("Really delete newsgroup `%s'?"),
2171 g_basename(item->path));
2172 avalue = alertpanel(_("Delete newsgroup"), message,
2173 _("Yes"), _("+No"), NULL);
2175 if (avalue != G_ALERTDEFAULT) return;
2177 if (folderview->opened == folderview->selected) {
2178 summary_clear_all(folderview->summaryview);
2179 folderview->opened = NULL;
2182 folder_item_remove(item);
2183 gtk_ctree_remove_node(ctree, folderview->selected);
2184 folder_write_list();
2187 static void folderview_rm_news_server_cb(FolderView *folderview, guint action,
2190 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2195 if (!folderview->selected) return;
2197 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2198 g_return_if_fail(item != NULL);
2199 g_return_if_fail(item->folder != NULL);
2200 g_return_if_fail(item->folder->type == F_NEWS);
2201 g_return_if_fail(item->folder->account != NULL);
2203 message = g_strdup_printf(_("Really delete news account `%s'?"),
2204 item->folder->name);
2205 avalue = alertpanel(_("Delete news account"), message,
2206 _("Yes"), _("+No"), NULL);
2209 if (avalue != G_ALERTDEFAULT) return;
2211 if (folderview->opened == folderview->selected ||
2212 gtk_ctree_is_ancestor(ctree,
2213 folderview->selected,
2214 folderview->opened)) {
2215 summary_clear_all(folderview->summaryview);
2216 folderview->opened = NULL;
2219 account_destroy(item->folder->account);
2220 folder_destroy(item->folder);
2221 gtk_ctree_remove_node(ctree, folderview->selected);
2223 main_window_reflect_prefs_all();
2224 folder_write_list();
2227 static void folderview_search_cb(FolderView *folderview, guint action,
2230 summary_search(folderview->summaryview);
2233 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
2234 GdkDragContext *context,
2238 FolderView *folderview)
2241 FolderItem *item, *current_item;
2242 GtkCTreeNode *node = NULL;
2243 gboolean acceptable = FALSE;
2245 if (gtk_clist_get_selection_info(GTK_CLIST(widget),
2246 x - 24, y - 24, &row, &column)) {
2247 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2248 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2249 current_item = folderview->summaryview->folder_item;
2251 item->path != NULL &&
2252 current_item != NULL &&
2253 current_item != item) {
2254 switch (item->folder->type){
2256 if (current_item->folder->type == F_MH)
2260 if (current_item->folder->account == item->folder->account)
2269 gtk_ctree_select(GTK_CTREE(widget), node);
2270 gdk_drag_status(context, context->suggested_action, time);
2272 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2273 gdk_drag_status(context, 0, time);
2279 static void folderview_drag_leave_cb(GtkWidget *widget,
2280 GdkDragContext *context,
2282 FolderView *folderview)
2284 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2287 static void folderview_drag_received_cb(GtkWidget *widget,
2288 GdkDragContext *drag_context,
2291 GtkSelectionData *data,
2294 FolderView *folderview)
2300 if (gtk_clist_get_selection_info(GTK_CLIST(widget),
2301 x - 24, y - 24, &row, &column) == 0)
2304 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2305 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2307 summary_move_selected_to(folderview->summaryview, item);
2308 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2310 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2313 static gint folderview_compare_name(gconstpointer a, gconstpointer b)
2315 const FolderItem *item = a;
2316 const gchar *name = b;
2318 if (!item->path) return -1;
2319 return strcmp2(g_basename(item->path), name);
2322 static void folderview_scoring_cb(FolderView *folderview, guint action,
2325 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2328 if (!folderview->selected) return;
2330 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2331 g_return_if_fail(item != NULL);
2332 g_return_if_fail(item->folder != NULL);
2334 prefs_scoring_open(item);
2337 static void folderview_processing_cb(FolderView *folderview, guint action,
2340 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2343 if (!folderview->selected) return;
2345 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2346 g_return_if_fail(item != NULL);
2347 g_return_if_fail(item->folder != NULL);
2349 prefs_filtering_open(item);
2352 static void folderview_property_cb(FolderView *folderview, guint action, GtkWidget *widget) {
2353 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2356 if (!folderview->selected) return;
2358 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2359 g_return_if_fail(item != NULL);
2360 g_return_if_fail(item->folder != NULL);
2362 prefs_folder_item_create(item);
2365 void folderview_set_target_folder_color(gint color_op) {
2368 FolderView *folderview;
2370 for (list = folderview_list; list != NULL; list = list->next) {
2371 folderview = (FolderView *)list->data;
2372 gtkut_convert_int_to_gdk_color(color_op, &folderview->color_op);
2374 bold_tgtfold_style->fg[GTK_STATE_NORMAL] =
2375 folderview->color_op;