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"
51 #include "stock_pixmap.h"
55 #include "prefs_common.h"
56 #include "prefs_account.h"
69 #define N_FOLDER_COLS 4
70 #define COL_FOLDER_WIDTH 150
71 #define COL_NUM_WIDTH 32
73 #define STATUSBAR_PUSH(mainwin, str) \
75 gtk_statusbar_push(GTK_STATUSBAR(mainwin->statusbar), \
76 mainwin->folderview_cid, str); \
77 gtkut_widget_wait_for_draw(mainwin->hbox_stat); \
80 #define STATUSBAR_POP(mainwin) \
82 gtk_statusbar_pop(GTK_STATUSBAR(mainwin->statusbar), \
83 mainwin->folderview_cid); \
86 static GList *folderview_list = NULL;
88 static GdkFont *normalfont;
89 static GdkFont *boldfont;
91 static GtkStyle *normal_style;
92 static GtkStyle *normal_color_style;
93 static GtkStyle *bold_style;
94 static GtkStyle *bold_color_style;
95 static GtkStyle *bold_tgtfold_style;
97 static GdkPixmap *inboxxpm;
98 static GdkBitmap *inboxxpmmask;
99 static GdkPixmap *inboxhrmxpm;
100 static GdkBitmap *inboxhrmxpmmask;
101 static GdkPixmap *outboxxpm;
102 static GdkBitmap *outboxxpmmask;
103 static GdkPixmap *outboxhrmxpm;
104 static GdkBitmap *outboxhrmxpmmask;
105 static GdkPixmap *folderxpm;
106 static GdkBitmap *folderxpmmask;
107 static GdkPixmap *folderopenxpm;
108 static GdkBitmap *folderopenxpmmask;
109 static GdkPixmap *folderopenhrmxpm;
110 static GdkBitmap *folderopenhrmxpmmask;
111 static GdkPixmap *trashxpm;
112 static GdkBitmap *trashxpmmask;
113 static GdkPixmap *trashhrmxpm;
114 static GdkBitmap *trashhrmxpmmask;
116 static void folderview_select_node (FolderView *folderview,
118 static void folderview_set_folders (FolderView *folderview);
119 static void folderview_sort_folders (FolderView *folderview,
122 static void folderview_append_folder (FolderView *folderview,
124 static void folderview_update_node (FolderView *folderview,
127 static GtkCTreeNode *folderview_find_by_name (GtkCTree *ctree,
131 static gint folderview_compare_name (gconstpointer a,
134 /* callback functions */
135 static void folderview_button_pressed (GtkWidget *ctree,
136 GdkEventButton *event,
137 FolderView *folderview);
138 static void folderview_button_released (GtkWidget *ctree,
139 GdkEventButton *event,
140 FolderView *folderview);
141 static void folderview_key_pressed (GtkWidget *widget,
143 FolderView *folderview);
144 static void folderview_selected (GtkCTree *ctree,
147 FolderView *folderview);
148 static void folderview_tree_expanded (GtkCTree *ctree,
150 FolderView *folderview);
151 static void folderview_tree_collapsed (GtkCTree *ctree,
153 FolderView *folderview);
154 static void folderview_popup_close (GtkMenuShell *menu_shell,
155 FolderView *folderview);
156 static void folderview_col_resized (GtkCList *clist,
159 FolderView *folderview);
161 static void folderview_update_tree_cb (FolderView *folderview,
165 static void folderview_new_folder_cb (FolderView *folderview,
168 static void folderview_new_mbox_folder_cb(FolderView *folderview,
171 static void folderview_rename_folder_cb (FolderView *folderview,
174 static void folderview_rename_mbox_folder_cb(FolderView *folderview,
177 static void folderview_delete_folder_cb (FolderView *folderview,
180 static void folderview_remove_mailbox_cb(FolderView *folderview,
184 static void folderview_new_imap_folder_cb(FolderView *folderview,
187 static void folderview_rm_imap_folder_cb (FolderView *folderview,
190 static void folderview_rm_imap_server_cb (FolderView *folderview,
194 static void folderview_new_news_group_cb(FolderView *folderview,
197 static void folderview_rm_news_group_cb (FolderView *folderview,
200 static void folderview_rm_news_server_cb(FolderView *folderview,
204 static void folderview_search_cb (FolderView *folderview,
208 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
209 GdkDragContext *context,
213 FolderView *folderview);
214 static void folderview_drag_leave_cb (GtkWidget *widget,
215 GdkDragContext *context,
217 FolderView *folderview);
218 static void folderview_drag_received_cb (GtkWidget *widget,
219 GdkDragContext *drag_context,
222 GtkSelectionData *data,
225 FolderView *folderview);
226 static void folderview_scoring_cb(FolderView *folderview, guint action,
228 static void folderview_processing_cb(FolderView *folderview, guint action,
230 static void folderview_property_cb(FolderView *folderview, guint action, GtkWidget *widget);
232 static GtkItemFactoryEntry folderview_mbox_popup_entries[] =
234 {N_("/Create _new folder..."), NULL, folderview_new_mbox_folder_cb, 0, NULL},
235 {N_("/_Rename folder..."), NULL, folderview_rename_mbox_folder_cb, 0, NULL},
236 {N_("/_Delete folder"), NULL, folderview_delete_folder_cb, 0, NULL},
237 {N_("/---"), NULL, NULL, 0, "<Separator>"},
238 {N_("/Remove _mailbox"), NULL, folderview_remove_mailbox_cb, 0, NULL},
239 {N_("/---"), NULL, NULL, 0, "<Separator>"},
240 {N_("/_Property..."), NULL, NULL, 0, NULL},
241 {N_("/_Processing..."), NULL, folderview_processing_cb, 0, NULL},
242 {N_("/_Scoring..."), NULL, folderview_scoring_cb, 0, NULL}
245 static GtkItemFactoryEntry folderview_mail_popup_entries[] =
247 {N_("/Create _new folder..."), NULL, folderview_new_folder_cb, 0, NULL},
248 {N_("/_Rename folder..."), NULL, folderview_rename_folder_cb, 0, NULL},
249 {N_("/_Delete folder"), NULL, folderview_delete_folder_cb, 0, NULL},
250 {N_("/---"), NULL, NULL, 0, "<Separator>"},
251 {N_("/_Check for new messages"),
252 NULL, folderview_update_tree_cb, 0, NULL},
253 {N_("/R_escan folder tree"), NULL, folderview_update_tree_cb, 1, NULL},
254 {N_("/---"), NULL, NULL, 0, "<Separator>"},
255 {N_("/Remove _mailbox"), NULL, folderview_remove_mailbox_cb, 0, NULL},
256 {N_("/---"), NULL, NULL, 0, "<Separator>"},
257 {N_("/_Search folder..."), NULL, folderview_search_cb, 0, NULL},
258 {N_("/_Property..."), NULL, folderview_property_cb, 0, NULL},
259 {N_("/_Processing..."), NULL, folderview_processing_cb, 0, NULL},
260 {N_("/S_coring..."), NULL, folderview_scoring_cb, 0, NULL}
263 static GtkItemFactoryEntry folderview_imap_popup_entries[] =
265 {N_("/Create _new folder..."), NULL, folderview_new_imap_folder_cb, 0, NULL},
266 {N_("/_Rename folder..."), NULL, NULL, 0, NULL},
267 {N_("/_Delete folder"), NULL, folderview_rm_imap_folder_cb, 0, NULL},
268 {N_("/---"), NULL, NULL, 0, "<Separator>"},
269 {N_("/_Check for new messages"),
270 NULL, folderview_update_tree_cb, 0, NULL},
271 {N_("/R_escan folder tree"), NULL, folderview_update_tree_cb, 1, NULL},
272 {N_("/---"), NULL, NULL, 0, "<Separator>"},
273 {N_("/Remove _IMAP4 account"), NULL, folderview_rm_imap_server_cb, 0, NULL},
274 {N_("/---"), NULL, NULL, 0, "<Separator>"},
275 {N_("/_Search folder..."), NULL, folderview_search_cb, 0, NULL},
276 {N_("/_Property..."), NULL, NULL, 0, NULL},
277 {N_("/_Processing..."), NULL, folderview_processing_cb, 0, NULL},
278 {N_("/S_coring..."), NULL, folderview_scoring_cb, 0, NULL}
281 static GtkItemFactoryEntry folderview_news_popup_entries[] =
283 {N_("/_Subscribe to newsgroup..."),
284 NULL, folderview_new_news_group_cb, 0, NULL},
285 {N_("/_Remove newsgroup"), NULL, folderview_rm_news_group_cb, 0, NULL},
286 {N_("/---"), NULL, NULL, 0, "<Separator>"},
287 {N_("/Remove _news account"), NULL, folderview_rm_news_server_cb, 0, NULL},
288 {N_("/---"), NULL, NULL, 0, "<Separator>"},
289 {N_("/_Search folder..."), NULL, folderview_search_cb, 0, NULL},
290 {N_("/_Property..."), NULL, NULL, 0, NULL},
291 {N_("/_Processing..."), NULL, folderview_processing_cb, 0, NULL},
292 {N_("/S_coring..."), NULL, folderview_scoring_cb, 0, NULL}
296 FolderView *folderview_create(void)
298 FolderView *folderview;
299 GtkWidget *scrolledwin;
301 gchar *titles[N_FOLDER_COLS] = {_("Folder"), _("New"),
302 _("Unread"), _("#")};
303 GtkWidget *mail_popup;
304 GtkWidget *news_popup;
305 GtkWidget *imap_popup;
306 GtkWidget *mbox_popup;
307 GtkItemFactory *mail_factory;
308 GtkItemFactory *news_factory;
309 GtkItemFactory *imap_factory;
310 GtkItemFactory *mbox_factory;
314 debug_print(_("Creating folder view...\n"));
315 folderview = g_new0(FolderView, 1);
317 scrolledwin = gtk_scrolled_window_new(NULL, NULL);
318 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
319 GTK_POLICY_AUTOMATIC,
321 gtk_widget_set_usize(scrolledwin,
322 prefs_common.folderview_width,
323 prefs_common.folderview_height);
325 ctree = gtk_ctree_new_with_titles(N_FOLDER_COLS, COL_FOLDER, titles);
326 gtk_container_add(GTK_CONTAINER(scrolledwin), ctree);
327 gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
328 gtk_clist_set_column_justification(GTK_CLIST(ctree), COL_NEW,
330 gtk_clist_set_column_justification(GTK_CLIST(ctree), COL_UNREAD,
332 gtk_clist_set_column_justification(GTK_CLIST(ctree), COL_TOTAL,
334 gtk_clist_set_column_width(GTK_CLIST(ctree), COL_FOLDER,
335 prefs_common.folder_col_folder);
336 gtk_clist_set_column_width(GTK_CLIST(ctree), COL_NEW,
337 prefs_common.folder_col_new);
338 gtk_clist_set_column_width(GTK_CLIST(ctree), COL_UNREAD,
339 prefs_common.folder_col_unread);
340 gtk_clist_set_column_width(GTK_CLIST(ctree), COL_TOTAL,
341 prefs_common.folder_col_total);
342 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
343 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
344 GTK_CTREE_EXPANDER_SQUARE);
345 gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
347 /* don't let title buttons take key focus */
348 for (i = 0; i < N_FOLDER_COLS; i++)
349 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(ctree)->column[i].button,
353 n_entries = sizeof(folderview_mail_popup_entries) /
354 sizeof(folderview_mail_popup_entries[0]);
355 mail_popup = menu_create_items(folderview_mail_popup_entries,
357 "<MailFolder>", &mail_factory,
359 n_entries = sizeof(folderview_imap_popup_entries) /
360 sizeof(folderview_imap_popup_entries[0]);
361 imap_popup = menu_create_items(folderview_imap_popup_entries,
363 "<IMAPFolder>", &imap_factory,
365 n_entries = sizeof(folderview_news_popup_entries) /
366 sizeof(folderview_news_popup_entries[0]);
367 news_popup = menu_create_items(folderview_news_popup_entries,
369 "<NewsFolder>", &news_factory,
371 n_entries = sizeof(folderview_mbox_popup_entries) /
372 sizeof(folderview_mbox_popup_entries[0]);
373 mbox_popup = menu_create_items(folderview_mbox_popup_entries,
375 "<MailFolder>", &mbox_factory,
378 gtk_signal_connect(GTK_OBJECT(ctree), "key_press_event",
379 GTK_SIGNAL_FUNC(folderview_key_pressed),
381 gtk_signal_connect(GTK_OBJECT(ctree), "button_press_event",
382 GTK_SIGNAL_FUNC(folderview_button_pressed),
384 gtk_signal_connect(GTK_OBJECT(ctree), "button_release_event",
385 GTK_SIGNAL_FUNC(folderview_button_released),
387 gtk_signal_connect(GTK_OBJECT(ctree), "tree_select_row",
388 GTK_SIGNAL_FUNC(folderview_selected), folderview);
390 gtk_signal_connect_after(GTK_OBJECT(ctree), "tree_expand",
391 GTK_SIGNAL_FUNC(folderview_tree_expanded),
393 gtk_signal_connect_after(GTK_OBJECT(ctree), "tree_collapse",
394 GTK_SIGNAL_FUNC(folderview_tree_collapsed),
397 gtk_signal_connect(GTK_OBJECT(ctree), "resize_column",
398 GTK_SIGNAL_FUNC(folderview_col_resized),
401 gtk_signal_connect(GTK_OBJECT(mail_popup), "selection_done",
402 GTK_SIGNAL_FUNC(folderview_popup_close),
404 gtk_signal_connect(GTK_OBJECT(imap_popup), "selection_done",
405 GTK_SIGNAL_FUNC(folderview_popup_close),
407 gtk_signal_connect(GTK_OBJECT(news_popup), "selection_done",
408 GTK_SIGNAL_FUNC(folderview_popup_close),
410 gtk_signal_connect(GTK_OBJECT(mbox_popup), "selection_done",
411 GTK_SIGNAL_FUNC(folderview_popup_close),
415 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL &
416 ~GTK_DEST_DEFAULT_HIGHLIGHT,
417 summary_drag_types, 1,
418 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT);
419 gtk_signal_connect(GTK_OBJECT(ctree), "drag_motion",
420 GTK_SIGNAL_FUNC(folderview_drag_motion_cb),
422 gtk_signal_connect(GTK_OBJECT(ctree), "drag_leave",
423 GTK_SIGNAL_FUNC(folderview_drag_leave_cb),
425 gtk_signal_connect(GTK_OBJECT(ctree), "drag_data_received",
426 GTK_SIGNAL_FUNC(folderview_drag_received_cb),
429 folderview->scrolledwin = scrolledwin;
430 folderview->ctree = ctree;
431 folderview->mail_popup = mail_popup;
432 folderview->mail_factory = mail_factory;
433 folderview->imap_popup = imap_popup;
434 folderview->imap_factory = imap_factory;
435 folderview->news_popup = news_popup;
436 folderview->news_factory = news_factory;
437 folderview->mbox_popup = mbox_popup;
438 folderview->mbox_factory = mbox_factory;
440 gtk_widget_show_all(scrolledwin);
442 folderview_list = g_list_append(folderview_list, folderview);
447 void folderview_init(FolderView *folderview)
449 GtkWidget *ctree = folderview->ctree;
451 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX, &inboxxpm, &inboxxpmmask);
452 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX,
453 &outboxxpm, &outboxxpmmask);
454 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE,
455 &folderxpm, &folderxpmmask);
456 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN,
457 &folderopenxpm, &folderopenxpmmask);
458 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH, &trashxpm, &trashxpmmask);
459 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_HRM,
460 &inboxhrmxpm, &inboxhrmxpmmask);
461 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_HRM,
462 &outboxhrmxpm, &outboxhrmxpmmask);
463 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM,
464 &folderopenhrmxpm, &folderopenhrmxpmmask);
465 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_HRM,
466 &trashhrmxpm, &trashhrmxpmmask);
471 normalfont = gdk_fontset_load(NORMAL_FONT);
473 boldfont = gdk_fontset_load(BOLD_FONT);
476 bold_style = gtk_style_copy(gtk_widget_get_style(ctree));
477 bold_style->font = boldfont;
478 bold_color_style = gtk_style_copy(bold_style);
479 bold_color_style->fg[GTK_STATE_NORMAL] = folderview->color_new;
481 bold_tgtfold_style = gtk_style_copy(bold_style);
482 bold_tgtfold_style->fg[GTK_STATE_NORMAL] = folderview->color_op;
485 normal_style = gtk_style_copy(gtk_widget_get_style(ctree));
486 normal_style->font = normalfont;
487 normal_color_style = gtk_style_copy(normal_style);
488 normal_color_style->fg[GTK_STATE_NORMAL] = folderview->color_new;
492 void folderview_set(FolderView *folderview)
494 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
495 MainWindow *mainwin = folderview->mainwin;
497 debug_print(_("Setting folder info...\n"));
498 STATUSBAR_PUSH(mainwin, _("Setting folder info..."));
500 main_window_cursor_wait(mainwin);
502 folderview->selected = NULL;
503 folderview->opened = NULL;
505 gtk_clist_freeze(GTK_CLIST(ctree));
506 gtk_clist_clear(GTK_CLIST(ctree));
507 gtk_clist_thaw(GTK_CLIST(ctree));
508 gtk_clist_freeze(GTK_CLIST(ctree));
510 folderview_set_folders(folderview);
512 gtk_clist_thaw(GTK_CLIST(ctree));
513 main_window_cursor_normal(mainwin);
514 STATUSBAR_POP(mainwin);
517 void folderview_set_all(void)
521 for (list = folderview_list; list != NULL; list = list->next)
522 folderview_set((FolderView *)list->data);
525 void folderview_select(FolderView *folderview, FolderItem *item)
527 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
529 GtkCTreeNode *old_selected = folderview->selected;
533 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
534 if (node) folderview_select_node(folderview, node);
536 if (old_selected != node)
537 folder_update_op_count();
540 static void folderview_select_node(FolderView *folderview, GtkCTreeNode *node)
542 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
544 g_return_if_fail(node != NULL);
546 folderview->open_folder = TRUE;
547 gtk_ctree_select(ctree, node);
548 gtkut_ctree_set_focus_row(ctree, node);
549 if (folderview->summaryview->messages > 0)
550 gtk_widget_grab_focus(folderview->summaryview->ctree);
552 gtk_widget_grab_focus(folderview->ctree);
554 gtkut_ctree_expand_parent_all(ctree, node);
557 void folderview_unselect(FolderView *folderview)
559 if (folderview->opened && !GTK_CTREE_ROW(folderview->opened)->children)
561 (GTK_CTREE(folderview->ctree), folderview->opened);
563 folderview->selected = folderview->opened = NULL;
566 static GtkCTreeNode *folderview_find_next_unread(GtkCTree *ctree,
572 node = gtkut_ctree_node_next(ctree, node);
574 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
576 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
577 item = gtk_ctree_node_get_row_data(ctree, node);
578 if (item && item->unread > 0 && item->stype != F_TRASH)
585 void folderview_select_next_unread(FolderView *folderview)
587 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
588 GtkCTreeNode *node = NULL;
590 if ((node = folderview_find_next_unread(ctree, folderview->opened))
592 folderview_select_node(folderview, node);
596 if (!folderview->opened ||
597 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list))
599 /* search again from the first node */
600 if ((node = folderview_find_next_unread(ctree, NULL)) != NULL)
601 folderview_select_node(folderview, node);
604 void folderview_update_msg_num(FolderView *folderview, GtkCTreeNode *row,
605 gint new, gint unread, gint total)
607 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
608 static GtkCTreeNode *prev_row = NULL;
613 item = gtk_ctree_node_get_row_data(ctree, row);
616 /* CLAWS: don't know why but this always seems to be true
617 * when deleting messages. Somewhere claws does a folder
618 * scan which sets all new, unread & total to the correct
619 * values. It then enters this function, but leaves it
620 * because new, unread and total are the same... */
622 if (prev_row == row &&
624 item->unread == unread &&
625 item->total == total)
632 item->unread = unread;
635 folderview_update_node(folderview, row);
638 static void folderview_set_folders(FolderView *folderview)
642 list = folder_get_list();
644 for (; list != NULL; list = list->next)
645 folderview_append_folder(folderview, FOLDER(list->data));
648 static void folderview_scan_tree_func(Folder *folder, FolderItem *item,
654 if (FOLDER_IS_LOCAL(folder))
655 rootpath = LOCAL_FOLDER(folder)->rootpath;
656 else if (folder->type == F_IMAP && folder->account &&
657 folder->account->recv_server)
658 rootpath = folder->account->recv_server;
662 for (list = folderview_list; list != NULL; list = list->next) {
663 FolderView *folderview = (FolderView *)list->data;
664 MainWindow *mainwin = folderview->mainwin;
668 str = g_strdup_printf(_("Scanning folder %s%c%s ..."),
669 rootpath, G_DIR_SEPARATOR,
672 str = g_strdup_printf(_("Scanning folder %s ..."),
675 STATUSBAR_PUSH(mainwin, str);
676 STATUSBAR_POP(mainwin);
681 static GtkWidget *label_window_create(const gchar *str)
686 window = gtk_window_new(GTK_WINDOW_DIALOG);
687 gtk_widget_set_usize(window, 380, 60);
688 gtk_container_set_border_width(GTK_CONTAINER(window), 8);
689 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
690 gtk_window_set_title(GTK_WINDOW(window), str);
691 gtk_window_set_modal(GTK_WINDOW(window), TRUE);
692 gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, FALSE);
693 manage_window_set_transient(GTK_WINDOW(window));
695 label = gtk_label_new(str);
696 gtk_container_add(GTK_CONTAINER(window), label);
697 gtk_widget_show(label);
699 gtk_widget_show_now(window);
704 void folderview_update_tree(Folder *folder)
708 g_return_if_fail(folder != NULL);
710 if (!folder->scan_tree) return;
713 window = label_window_create(_("Rescanning folder tree..."));
715 folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
716 folder->scan_tree(folder);
717 folder_set_ui_func(folder, NULL, NULL);
720 folderview_set_all();
722 gtk_widget_destroy(window);
726 void folderview_update_all(void)
732 window = label_window_create(_("Rescanning all folder trees..."));
734 list = folder_get_list();
735 for (; list != NULL; list = list->next) {
736 Folder *folder = list->data;
738 if (!folder->scan_tree) continue;
739 folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
740 folder->scan_tree(folder);
741 folder_set_ui_func(folder, NULL, NULL);
745 folderview_set_all();
746 gtk_widget_destroy(window);
750 void folderview_update_all_node(void)
754 FolderView *folderview;
758 for (list = folderview_list; list != NULL; list = list->next) {
759 folderview = (FolderView *)list->data;
760 ctree = GTK_CTREE(folderview->ctree);
763 main_window_lock(folderview->mainwin);
764 gtk_widget_set_sensitive(folderview->ctree, FALSE);
766 for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
767 node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
768 item = gtk_ctree_node_get_row_data(ctree, node);
769 if (!item || !FOLDER_IS_LOCAL(item->folder) ||
772 folderview_scan_tree_func(item->folder, item, NULL);
773 folder_item_scan(item);
774 folderview_update_node(folderview, node);
777 gtk_widget_set_sensitive(folderview->ctree, TRUE);
778 main_window_unlock(folderview->mainwin);
785 static gboolean folderview_search_new_recursive(GtkCTree *ctree,
791 item = gtk_ctree_node_get_row_data(ctree, node);
794 (item->stype == F_QUEUE && item->total > 0))
797 node = GTK_CTREE_ROW(node)->children;
799 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
802 if (folderview_search_new_recursive(ctree, node) == TRUE)
804 node = GTK_CTREE_ROW(node)->sibling;
810 static gboolean folderview_have_new_children(FolderView *folderview,
813 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
816 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
820 node = GTK_CTREE_ROW(node)->children;
823 if (folderview_search_new_recursive(ctree, node) == TRUE)
825 node = GTK_CTREE_ROW(node)->sibling;
831 static gboolean folderview_search_unread_recursive(GtkCTree *ctree,
837 item = gtk_ctree_node_get_row_data(ctree, node);
839 if (item->unread > 0 ||
840 (item->stype == F_QUEUE && item->total > 0))
843 node = GTK_CTREE_ROW(node)->children;
845 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
848 if (folderview_search_unread_recursive(ctree, node) == TRUE)
850 node = GTK_CTREE_ROW(node)->sibling;
856 static gboolean folderview_have_unread_children(FolderView *folderview,
859 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
862 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
866 node = GTK_CTREE_ROW(node)->children;
869 if (folderview_search_unread_recursive(ctree, node) == TRUE)
871 node = GTK_CTREE_ROW(node)->sibling;
877 static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node)
879 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
880 GtkStyle *style = NULL;
882 GdkPixmap *xpm, *openxpm;
883 GdkBitmap *mask, *openmask;
886 gboolean add_unread_mark;
887 gboolean use_bold, use_color;
889 item = gtk_ctree_node_get_row_data(ctree, node);
890 g_return_if_fail(item != NULL);
892 switch (item->stype) {
896 if (item->hide_read_msgs) {
897 openxpm = inboxhrmxpm;
898 openmask = inboxhrmxpmmask;
901 openmask = inboxxpmmask;
903 name = g_strdup(_("Inbox"));
908 if (item->hide_read_msgs) {
909 openxpm = outboxhrmxpm;
910 openmask = outboxhrmxpmmask;
913 openmask = outboxxpmmask;
915 name = g_strdup(_("Outbox"));
920 if (item->hide_read_msgs) {
921 openxpm = outboxhrmxpm;
922 openmask = outboxhrmxpmmask;
925 openmask = outboxxpmmask;
927 name = g_strdup(_("Queue"));
932 if (item->hide_read_msgs) {
933 openxpm = trashhrmxpm;
934 openmask = trashhrmxpmmask;
937 openmask = trashxpmmask;
939 name = g_strdup(_("Trash"));
943 mask = folderxpmmask;
944 if (item->hide_read_msgs) {
945 openxpm = folderopenhrmxpm;
946 openmask = folderopenhrmxpmmask;
948 openxpm = folderopenxpm;
949 openmask = folderopenxpmmask;
951 name = g_strdup(_("Draft"));
955 mask = folderxpmmask;
956 if (item->hide_read_msgs) {
957 openxpm = folderopenhrmxpm;
958 openmask = folderopenhrmxpmmask;
960 openxpm = folderopenxpm;
961 openmask = folderopenxpmmask;
964 switch (item->folder->type) {
966 name = " (MH)"; break;
968 name = " (mbox)"; break;
970 name = " (IMAP4)"; break;
972 name = " (News)"; break;
976 name = g_strconcat(item->name, name, NULL);
978 name = g_strdup(item->name);
981 if (!GTK_CTREE_ROW(node)->expanded &&
982 folderview_have_unread_children(folderview, node))
983 add_unread_mark = TRUE;
985 add_unread_mark = FALSE;
987 if (item->stype == F_QUEUE && item->total > 0 &&
988 prefs_common.display_folder_unread) {
989 str = g_strdup_printf("%s (%d%s)", name, item->total,
990 add_unread_mark ? "+" : "");
991 gtk_ctree_set_node_info(ctree, node, str, FOLDER_SPACING,
992 xpm, mask, openxpm, openmask,
993 FALSE, GTK_CTREE_ROW(node)->expanded);
995 } else if ((item->unread > 0 || add_unread_mark) &&
996 prefs_common.display_folder_unread) {
998 if (item->unread > 0)
999 str = g_strdup_printf("%s (%d%s)", name, item->unread,
1000 add_unread_mark ? "+" : "");
1002 str = g_strdup_printf("%s (+)", name);
1003 gtk_ctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1004 xpm, mask, openxpm, openmask,
1005 FALSE, GTK_CTREE_ROW(node)->expanded);
1008 gtk_ctree_set_node_info(ctree, node, name, FOLDER_SPACING,
1009 xpm, mask, openxpm, openmask,
1010 FALSE, GTK_CTREE_ROW(node)->expanded);
1013 if (!item->parent) {
1014 gtk_ctree_node_set_text(ctree, node, COL_NEW, "-");
1015 gtk_ctree_node_set_text(ctree, node, COL_UNREAD, "-");
1016 gtk_ctree_node_set_text(ctree, node, COL_TOTAL, "-");
1018 gtk_ctree_node_set_text(ctree, node, COL_NEW, itos(item->new));
1019 gtk_ctree_node_set_text(ctree, node, COL_UNREAD, itos(item->unread));
1020 gtk_ctree_node_set_text(ctree, node, COL_TOTAL, itos(item->total));
1023 if (item->stype == F_TRASH)
1024 use_bold = use_color = FALSE;
1025 if (item->stype == F_QUEUE) {
1026 /* highlight queue folder if there are any messages */
1027 use_bold = use_color = (item->total > 0);
1029 /* if unread messages exist, print with bold font */
1030 use_bold = (item->unread > 0) || add_unread_mark;
1031 /* if new messages exist, print with colored letter */
1035 folderview_have_new_children(folderview, node));
1038 gtk_ctree_node_set_foreground(ctree, node, NULL);
1040 if (use_bold && use_color)
1041 style = bold_color_style;
1042 else if (use_bold) {
1044 if (item->op_count > 0) {
1045 style = bold_tgtfold_style;
1048 else if (use_color) {
1049 style = normal_color_style;
1050 gtk_ctree_node_set_foreground(ctree, node,
1051 &folderview->color_new);
1053 else if (item->op_count > 0) {
1054 style = bold_tgtfold_style;
1056 style = normal_style;
1059 gtk_ctree_node_set_row_style(ctree, node, style);
1061 if ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
1062 folderview_update_node(folderview, node);
1065 void folderview_update_item(FolderItem *item, gboolean update_summary)
1068 FolderView *folderview;
1072 g_return_if_fail(item != NULL);
1074 for (list = folderview_list; list != NULL; list = list->next) {
1075 folderview = (FolderView *)list->data;
1076 ctree = GTK_CTREE(folderview->ctree);
1078 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1080 folderview_update_node(folderview, node);
1081 if (update_summary && folderview->opened == node)
1082 summary_show(folderview->summaryview,
1088 static void folderview_update_item_foreach_func(gpointer key, gpointer val,
1091 folderview_update_item((FolderItem *)key, FALSE);
1094 void folderview_update_item_foreach(GHashTable *table)
1096 g_hash_table_foreach(table, folderview_update_item_foreach_func, NULL);
1099 static gboolean folderview_gnode_func(GtkCTree *ctree, guint depth,
1100 GNode *gnode, GtkCTreeNode *cnode,
1103 FolderView *folderview = (FolderView *)data;
1104 FolderItem *item = FOLDER_ITEM(gnode->data);
1106 g_return_val_if_fail(item != NULL, FALSE);
1108 gtk_ctree_node_set_row_data(ctree, cnode, item);
1109 folderview_update_node(folderview, cnode);
1114 static void folderview_expand_func(GtkCTree *ctree, GtkCTreeNode *node,
1117 FolderView *folderview = (FolderView *)data;
1120 if (GTK_CTREE_ROW(node)->children) {
1121 item = gtk_ctree_node_get_row_data(ctree, node);
1122 g_return_if_fail(item != NULL);
1124 if (!item->collapsed)
1125 gtk_ctree_expand(ctree, node);
1127 folderview_update_node(folderview, node);
1131 #define SET_SPECIAL_FOLDER(ctree, item) \
1134 GtkCTreeNode *node, *sibling; \
1136 node = gtk_ctree_find_by_row_data(ctree, root, item); \
1138 g_warning("%s not found.\n", item->path); \
1141 sibling = GTK_CTREE_ROW(root)->children; \
1143 sibling = GTK_CTREE_ROW(prev)->sibling; \
1144 if (node != sibling) \
1145 gtk_ctree_move(ctree, node, root, sibling); \
1152 static void folderview_sort_folders(FolderView *folderview, GtkCTreeNode *root,
1155 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1156 GtkCTreeNode *prev = NULL;
1158 gtk_ctree_sort_recursive(ctree, root);
1160 if (GTK_CTREE_ROW(root)->parent) return;
1162 SET_SPECIAL_FOLDER(ctree, folder->inbox);
1163 SET_SPECIAL_FOLDER(ctree, folder->outbox);
1164 SET_SPECIAL_FOLDER(ctree, folder->draft);
1165 SET_SPECIAL_FOLDER(ctree, folder->queue);
1166 SET_SPECIAL_FOLDER(ctree, folder->trash);
1169 static void folderview_append_folder(FolderView *folderview, Folder *folder)
1171 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1174 g_return_if_fail(folder != NULL);
1176 root = gtk_ctree_insert_gnode(ctree, NULL, NULL, folder->node,
1177 folderview_gnode_func, folderview);
1178 gtk_ctree_pre_recursive(ctree, root, folderview_expand_func,
1180 folderview_sort_folders(folderview, root, folder);
1183 void folderview_new_folder(FolderView *folderview)
1185 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1188 if (!folderview->selected) return;
1190 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1191 g_return_if_fail(item != NULL);
1192 g_return_if_fail(item->folder != NULL);
1194 switch (item->folder->type) {
1196 folderview_new_mbox_folder_cb(folderview, 0, NULL);
1200 folderview_new_folder_cb(folderview, 0, NULL);
1203 folderview_new_imap_folder_cb(folderview, 0, NULL);
1211 void folderview_rename_folder(FolderView *folderview)
1213 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1216 if (!folderview->selected) return;
1218 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1219 g_return_if_fail(item != NULL);
1220 g_return_if_fail(item->folder != NULL);
1221 if (!item->path) return;
1222 if (item->stype != F_NORMAL) return;
1224 switch (item->folder->type) {
1226 folderview_rename_mbox_folder_cb(folderview, 0, NULL);
1229 folderview_rename_folder_cb(folderview, 0, NULL);
1238 void folderview_delete_folder(FolderView *folderview)
1240 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1243 if (!folderview->selected) return;
1245 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1246 g_return_if_fail(item != NULL);
1247 g_return_if_fail(item->folder != NULL);
1248 if (!item->path) return;
1249 if (item->stype != F_NORMAL) return;
1251 switch (item->folder->type) {
1255 folderview_delete_folder_cb(folderview, 0, NULL);
1258 folderview_rm_imap_folder_cb(folderview, 0, NULL);
1266 /* callback functions */
1268 static void folderview_button_pressed(GtkWidget *ctree, GdkEventButton *event,
1269 FolderView *folderview)
1271 GtkCList *clist = GTK_CLIST(ctree);
1272 gint prev_row = -1, row = -1, column = -1;
1276 gboolean new_folder = FALSE;
1277 gboolean rename_folder = FALSE;
1278 gboolean delete_folder = FALSE;
1279 gboolean update_tree = FALSE;
1280 gboolean rescan_tree = FALSE;
1281 gboolean remove_tree = FALSE;
1282 gboolean folder_property = FALSE;
1283 gboolean folder_processing = FALSE;
1284 gboolean folder_scoring = FALSE;
1285 gboolean search_folder = FALSE;
1289 if (event->button == 1) {
1290 folderview->open_folder = TRUE;
1294 if (event->button == 2 || event->button == 3) {
1296 if (clist->selection) {
1299 node = GTK_CTREE_NODE(clist->selection->data);
1301 prev_row = gtkut_ctree_get_nth_from_node
1302 (GTK_CTREE(ctree), node);
1305 if (!gtk_clist_get_selection_info(clist, event->x, event->y,
1308 if (prev_row != row) {
1309 gtk_clist_unselect_all(clist);
1310 if (event->button == 2)
1311 folderview_select_node
1313 gtk_ctree_node_nth(GTK_CTREE(ctree),
1316 gtk_clist_select_row(clist, row, column);
1320 if (event->button != 3) return;
1322 item = gtk_clist_get_row_data(clist, row);
1323 g_return_if_fail(item != NULL);
1324 g_return_if_fail(item->folder != NULL);
1325 folder = item->folder;
1327 if (folderview->mainwin->lock_count == 0) {
1329 if (item->parent == NULL)
1330 update_tree = remove_tree = TRUE;
1332 search_folder = TRUE;
1333 if (FOLDER_IS_LOCAL(folder) || FOLDER_TYPE(folder) == F_IMAP || FOLDER_TYPE(folder) == F_MBOX) {
1334 if (item->parent == NULL)
1335 update_tree = rescan_tree = TRUE;
1336 else if (item->stype == F_NORMAL)
1337 rename_folder = delete_folder = folder_property = folder_scoring = folder_processing = TRUE;
1338 else if (item->stype == F_INBOX)
1339 folder_property = folder_scoring = folder_processing = TRUE;
1340 else if (item->stype == F_TRASH)
1341 folder_processing = TRUE;
1342 else if (item->stype == F_OUTBOX)
1343 folder_processing = TRUE;
1344 } else if (FOLDER_TYPE(folder) == F_NEWS) {
1345 if (item->parent != NULL)
1346 delete_folder = folder_scoring = folder_processing = TRUE;
1350 #define SET_SENS(factory, name, sens) \
1351 menu_set_sensitive(folderview->factory, name, sens)
1353 if (FOLDER_IS_LOCAL(folder)) {
1354 popup = folderview->mail_popup;
1355 menu_set_insensitive_all(GTK_MENU_SHELL(popup));
1356 SET_SENS(mail_factory, "/Create new folder...", new_folder);
1357 SET_SENS(mail_factory, "/Rename folder...", rename_folder);
1358 SET_SENS(mail_factory, "/Delete folder", delete_folder);
1359 SET_SENS(mail_factory, "/Check for new messages", update_tree);
1360 SET_SENS(mail_factory, "/Rescan folder tree", rescan_tree);
1361 SET_SENS(mail_factory, "/Remove mailbox", remove_tree);
1362 SET_SENS(mail_factory, "/Property...", folder_property);
1363 SET_SENS(mail_factory, "/Processing...", folder_processing);
1364 SET_SENS(mail_factory, "/Scoring...", folder_scoring);
1365 SET_SENS(mail_factory, "/Search folder...", search_folder);
1366 } else if (FOLDER_TYPE(folder) == F_IMAP) {
1367 popup = folderview->imap_popup;
1368 menu_set_insensitive_all(GTK_MENU_SHELL(popup));
1369 SET_SENS(imap_factory, "/Create new folder...", new_folder);
1370 SET_SENS(imap_factory, "/Rename folder...", rename_folder);
1371 SET_SENS(imap_factory, "/Delete folder", delete_folder);
1372 SET_SENS(imap_factory, "/Check for new messages", update_tree);
1373 SET_SENS(imap_factory, "/Rescan folder tree", rescan_tree);
1374 SET_SENS(imap_factory, "/Remove IMAP4 account", remove_tree);
1375 SET_SENS(imap_factory, "/Processing...", folder_processing);
1376 SET_SENS(imap_factory, "/Scoring...", folder_scoring);
1377 SET_SENS(imap_factory, "/Search folder...", search_folder);
1378 } else if (FOLDER_TYPE(folder) == F_NEWS) {
1379 popup = folderview->news_popup;
1380 menu_set_insensitive_all(GTK_MENU_SHELL(popup));
1381 SET_SENS(news_factory, "/Subscribe to newsgroup...", new_folder);
1382 SET_SENS(news_factory, "/Remove newsgroup", delete_folder);
1384 SET_SENS(news_factory, "/Check for new messages", update_tree);
1386 SET_SENS(news_factory, "/Remove news account", remove_tree);
1387 SET_SENS(news_factory, "/Search folder...", search_folder);
1388 SET_SENS(news_factory, "/Processing...", folder_processing);
1389 SET_SENS(news_factory, "/Scoring...", folder_scoring);
1390 } else if (FOLDER_TYPE(folder) == F_MBOX) {
1391 popup = folderview->mbox_popup;
1392 menu_set_insensitive_all(GTK_MENU_SHELL(popup));
1393 SET_SENS(mbox_factory, "/Create new folder...", new_folder);
1394 SET_SENS(mbox_factory, "/Rename folder...", rename_folder);
1395 SET_SENS(mbox_factory, "/Delete folder", delete_folder);
1396 SET_SENS(mbox_factory, "/Processing...", folder_processing);
1397 SET_SENS(mbox_factory, "/Scoring...", folder_scoring);
1403 gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
1404 event->button, event->time);
1407 static void folderview_button_released(GtkWidget *ctree, GdkEventButton *event,
1408 FolderView *folderview)
1412 if (event->button == 1 && folderview->open_folder == FALSE &&
1413 folderview->opened != NULL) {
1414 gtk_ctree_select(GTK_CTREE(ctree), folderview->opened);
1415 gtkut_ctree_set_focus_row(GTK_CTREE(ctree),
1416 folderview->opened);
1420 #define BREAK_ON_MODIFIER_KEY() \
1421 if ((event->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK)) != 0) break
1423 static void folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
1424 FolderView *folderview)
1428 switch (event->keyval) {
1431 if (folderview->selected) {
1432 folderview_select_node(folderview,
1433 folderview->selected);
1445 BREAK_ON_MODIFIER_KEY();
1446 summary_pass_key_press_event(folderview->summaryview, event);
1451 static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row,
1452 gint column, FolderView *folderview)
1454 static gboolean can_select = TRUE; /* exclusive lock */
1458 folderview->selected = row;
1460 if (folderview->opened == row) {
1461 folderview->open_folder = FALSE;
1466 gtk_ctree_select(ctree, folderview->opened);
1467 gtkut_ctree_set_focus_row(ctree, folderview->opened);
1471 if (!folderview->open_folder) return;
1473 item = gtk_ctree_node_get_row_data(ctree, row);
1478 /* CLAWS: set compose button type: news folder items
1479 * always have a news folder as parent */
1481 main_window_toolbar_set_compose_button
1482 (folderview->mainwin,
1483 item->folder->type == F_NEWS ?
1484 COMPOSEBUTTON_NEWS : COMPOSEBUTTON_MAIL);
1487 debug_print(_("Folder %s is selected\n"), item->path);
1489 if (!GTK_CTREE_ROW(row)->children)
1490 gtk_ctree_expand(ctree, row);
1491 if (folderview->opened &&
1492 !GTK_CTREE_ROW(folderview->opened)->children)
1493 gtk_ctree_collapse(ctree, folderview->opened);
1495 /* ungrab the mouse event */
1496 if (GTK_WIDGET_HAS_GRAB(ctree)) {
1497 gtk_grab_remove(GTK_WIDGET(ctree));
1498 if (gdk_pointer_is_grabbed())
1499 gdk_pointer_ungrab(GDK_CURRENT_TIME);
1502 opened = summary_show(folderview->summaryview, item, FALSE);
1505 gtk_ctree_select(ctree, folderview->opened);
1506 gtkut_ctree_set_focus_row(ctree, folderview->opened);
1508 folderview->opened = row;
1510 folderview->open_folder = FALSE;
1514 static void folderview_tree_expanded(GtkCTree *ctree, GtkCTreeNode *node,
1515 FolderView *folderview)
1519 item = gtk_ctree_node_get_row_data(ctree, node);
1520 g_return_if_fail(item != NULL);
1521 item->collapsed = FALSE;
1522 folderview_update_node(folderview, node);
1525 static void folderview_tree_collapsed(GtkCTree *ctree, GtkCTreeNode *node,
1526 FolderView *folderview)
1530 item = gtk_ctree_node_get_row_data(ctree, node);
1531 g_return_if_fail(item != NULL);
1532 item->collapsed= TRUE;
1533 folderview_update_node(folderview, node);
1536 static void folderview_popup_close(GtkMenuShell *menu_shell,
1537 FolderView *folderview)
1539 if (!folderview->opened) return;
1541 gtk_ctree_select(GTK_CTREE(folderview->ctree), folderview->opened);
1542 gtkut_ctree_set_focus_row(GTK_CTREE(folderview->ctree),
1543 folderview->opened);
1546 static void folderview_col_resized(GtkCList *clist, gint column, gint width,
1547 FolderView *folderview)
1551 prefs_common.folder_col_folder = width;
1554 prefs_common.folder_col_new = width;
1557 prefs_common.folder_col_unread = width;
1560 prefs_common.folder_col_total = width;
1566 static GtkCTreeNode *folderview_find_by_name(GtkCTree *ctree,
1573 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
1577 node = GTK_CTREE_ROW(node)->children;
1580 item = gtk_ctree_node_get_row_data(ctree, node);
1581 if (!folderview_compare_name(item, name))
1583 node = GTK_CTREE_ROW(node)->sibling;
1589 static void folderview_update_tree_cb(FolderView *folderview, guint action,
1592 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1595 if (!folderview->selected) return;
1597 summary_show(folderview->summaryview, NULL, FALSE);
1599 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1600 g_return_if_fail(item != NULL);
1601 g_return_if_fail(item->folder != NULL);
1604 folderview_update_all_node();
1606 folderview_update_tree(item->folder);
1609 static void folderview_new_folder_cb(FolderView *folderview, guint action,
1612 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1613 gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
1615 FolderItem *new_item;
1619 if (!folderview->selected) return;
1621 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1622 g_return_if_fail(item != NULL);
1623 g_return_if_fail(item->folder != NULL);
1625 new_folder = input_dialog(_("New folder"),
1626 _("Input the name of new folder:"),
1628 if (!new_folder) return;
1630 if (item->folder->type != F_MBOX) {
1631 if (strchr(new_folder, G_DIR_SEPARATOR) != NULL) {
1632 alertpanel_error(_("`%c' can't be included in folder name."),
1639 /* find whether the directory already exists */
1640 if (folderview_find_by_name(ctree, folderview->selected, new_folder)) {
1641 alertpanel_error(_("The folder `%s' already exists."),
1647 new_item = item->folder->create_folder(item->folder, item, new_folder);
1649 alertpanel_error(_("The folder `%s' could not be created."),
1656 gtk_clist_freeze(GTK_CLIST(ctree));
1658 text[COL_FOLDER] = new_item->name;
1659 node = gtk_ctree_insert_node(ctree, folderview->selected, NULL, text,
1661 folderxpm, folderxpmmask,
1662 folderopenxpm, folderopenxpmmask,
1664 gtk_ctree_expand(ctree, folderview->selected);
1665 gtk_ctree_node_set_row_data(ctree, node, new_item);
1666 folderview_sort_folders(folderview, folderview->selected, item->folder);
1668 gtk_clist_thaw(GTK_CLIST(ctree));
1670 folder_write_list();
1673 static void folderview_new_mbox_folder_cb(FolderView *folderview, guint action,
1676 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1677 gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
1679 FolderItem *new_item;
1683 if (!folderview->selected) return;
1685 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1686 g_return_if_fail(item != NULL);
1687 g_return_if_fail(item->folder != NULL);
1689 new_folder = input_dialog(_("New folder"),
1690 _("Input the name of new folder:"),
1692 if (!new_folder) return;
1694 /* find whether the directory already exists */
1695 if (folderview_find_by_name(ctree, folderview->selected, new_folder)) {
1696 alertpanel_error(_("The folder `%s' already exists."),
1702 new_item = item->folder->create_folder(item->folder, item, new_folder);
1704 if (!new_item) return;
1706 gtk_clist_freeze(GTK_CLIST(ctree));
1708 text[COL_FOLDER] = new_item->name;
1709 node = gtk_ctree_insert_node(ctree, folderview->selected, NULL, text,
1711 folderxpm, folderxpmmask,
1712 folderopenxpm, folderopenxpmmask,
1714 gtk_ctree_expand(ctree, folderview->selected);
1715 gtk_ctree_node_set_row_data(ctree, node, new_item);
1716 folderview_sort_folders(folderview, folderview->selected, item->folder);
1718 gtk_clist_thaw(GTK_CLIST(ctree));
1720 folder_write_list();
1723 static void folderview_rename_folder_cb(FolderView *folderview, guint action,
1726 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1731 if (!folderview->selected) return;
1733 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1734 g_return_if_fail(item != NULL);
1735 g_return_if_fail(item->path != NULL);
1736 g_return_if_fail(item->folder != NULL);
1738 message = g_strdup_printf(_("Input new name for `%s':"),
1739 g_basename(item->path));
1740 new_folder = input_dialog(_("Rename folder"), message,
1741 g_basename(item->path));
1743 if (!new_folder) return;
1745 if (strchr(new_folder, G_DIR_SEPARATOR) != NULL) {
1746 alertpanel_error(_("`%c' can't be included in folder name."),
1752 if (folderview_find_by_name
1753 (ctree, GTK_CTREE_ROW(folderview->selected)->parent,
1755 alertpanel_error(_("The folder `%s' already exists."),
1761 if (item->folder->rename_folder(item->folder, item, new_folder) < 0) {
1767 gtk_clist_freeze(GTK_CLIST(ctree));
1769 folderview_update_node(folderview, folderview->selected);
1770 folderview_sort_folders(folderview,
1771 GTK_CTREE_ROW(folderview->selected)->parent,
1773 if (folderview->opened == folderview->selected) {
1774 if (!GTK_CTREE_ROW(folderview->opened)->children)
1775 gtk_ctree_expand(ctree, folderview->opened);
1776 summary_show(folderview->summaryview, item, FALSE);
1779 gtk_clist_thaw(GTK_CLIST(ctree));
1781 folder_write_list();
1784 static void folderview_rename_mbox_folder_cb(FolderView *folderview,
1788 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1793 if (!folderview->selected) return;
1795 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1796 g_return_if_fail(item != NULL);
1797 g_return_if_fail(item->path != NULL);
1798 g_return_if_fail(item->folder != NULL);
1800 message = g_strdup_printf(_("Input new name for `%s':"),
1801 g_basename(item->path));
1802 new_folder = input_dialog(_("Rename folder"), message,
1803 g_basename(item->path));
1805 if (!new_folder) return;
1807 if (folderview_find_by_name
1808 (ctree, GTK_CTREE_ROW(folderview->selected)->parent,
1810 alertpanel_error(_("The folder `%s' already exists."),
1816 if (item->folder->rename_folder(item->folder, item, new_folder) < 0) {
1822 gtk_clist_freeze(GTK_CLIST(ctree));
1824 folderview_update_node(folderview, folderview->selected);
1825 folderview_sort_folders(folderview,
1826 GTK_CTREE_ROW(folderview->selected)->parent,
1828 if (folderview->opened == folderview->selected) {
1829 if (!GTK_CTREE_ROW(folderview->opened)->children)
1830 gtk_ctree_expand(ctree, folderview->opened);
1831 summary_show(folderview->summaryview, item, FALSE);
1834 gtk_clist_thaw(GTK_CLIST(ctree));
1836 folder_write_list();
1839 static void folderview_delete_folder_cb(FolderView *folderview, guint action,
1842 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1847 if (!folderview->selected) return;
1849 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1850 g_return_if_fail(item != NULL);
1851 g_return_if_fail(item->path != NULL);
1852 g_return_if_fail(item->folder != NULL);
1854 message = g_strdup_printf
1855 (_("All folder(s) and message(s) under `%s' will be deleted.\n"
1856 "Do you really want to delete?"),
1857 g_basename(item->path));
1858 avalue = alertpanel(_("Delete folder"), message,
1859 _("Yes"), _("+No"), NULL);
1861 if (avalue != G_ALERTDEFAULT) return;
1863 if (item->folder->remove_folder(item->folder, item) < 0) {
1864 alertpanel_error(_("Can't remove the folder `%s'."),
1869 if (folderview->opened == folderview->selected ||
1870 gtk_ctree_is_ancestor(ctree,
1871 folderview->selected,
1872 folderview->opened)) {
1873 summary_clear_all(folderview->summaryview);
1874 folderview->opened = NULL;
1877 gtk_ctree_remove_node(ctree, folderview->selected);
1878 folder_write_list();
1881 static void folderview_remove_mailbox_cb(FolderView *folderview, guint action,
1884 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1890 if (!folderview->selected) return;
1891 node = folderview->selected;
1892 item = gtk_ctree_node_get_row_data(ctree, node);
1893 g_return_if_fail(item != NULL);
1894 g_return_if_fail(item->folder != NULL);
1895 if (item->parent) return;
1897 message = g_strdup_printf
1898 (_("Really remove the mailbox `%s' ?\n"
1899 "(The messages are NOT deleted from disk)"),
1900 item->folder->name);
1901 avalue = alertpanel(_("Remove folder"), message,
1902 _("Yes"), _("+No"), NULL);
1904 if (avalue != G_ALERTDEFAULT) return;
1906 folder_destroy(item->folder);
1907 summary_clear_all(folderview->summaryview);
1908 folderview_unselect(folderview);
1909 gtk_ctree_remove_node(ctree, node);
1910 folder_write_list();
1913 static void folderview_new_imap_folder_cb(FolderView *folderview, guint action,
1916 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1917 gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
1920 FolderItem *new_item;
1924 if (!folderview->selected) return;
1926 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1927 g_return_if_fail(item != NULL);
1928 g_return_if_fail(item->folder != NULL);
1929 g_return_if_fail(item->folder->type == F_IMAP);
1930 g_return_if_fail(item->folder->account != NULL);
1932 new_folder = input_dialog
1934 _("Input the name of new folder:\n"
1935 "(if you want to create a folder to store subfolders,\n"
1936 " append `/' at the end of the name)"),
1938 if (!new_folder) return;
1940 if ((p = strchr(new_folder, G_DIR_SEPARATOR)) != NULL &&
1942 alertpanel_error(_("`%c' can't be included in folder name."),
1948 /* find whether the directory already exists */
1949 if (folderview_find_by_name(ctree, folderview->selected, new_folder)) {
1950 alertpanel_error(_("The folder `%s' already exists."),
1956 new_item = item->folder->create_folder(item->folder, item, new_folder);
1958 alertpanel_error(_("Can't create the folder `%s'."),
1965 gtk_clist_freeze(GTK_CLIST(ctree));
1967 text[COL_FOLDER] = new_item->name;
1968 node = gtk_ctree_insert_node(ctree, folderview->selected, NULL, text,
1970 folderxpm, folderxpmmask,
1971 folderopenxpm, folderopenxpmmask,
1973 gtk_ctree_expand(ctree, folderview->selected);
1974 gtk_ctree_node_set_row_data(ctree, node, new_item);
1975 folderview_sort_folders(folderview, folderview->selected, item->folder);
1977 gtk_clist_thaw(GTK_CLIST(ctree));
1979 folder_write_list();
1982 static void folderview_rm_imap_folder_cb(FolderView *folderview, guint action,
1985 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1990 if (!folderview->selected) return;
1992 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
1993 g_return_if_fail(item != NULL);
1994 g_return_if_fail(item->folder != NULL);
1995 g_return_if_fail(item->folder->type == F_IMAP);
1996 g_return_if_fail(item->folder->account != NULL);
1998 message = g_strdup_printf(_("Really delete folder `%s'?"),
1999 g_basename(item->path));
2000 avalue = alertpanel(_("Delete folder"), message,
2001 _("Yes"), _("+No"), NULL);
2003 if (avalue != G_ALERTDEFAULT) return;
2005 if (item->folder->remove_folder(item->folder, item) < 0) {
2006 alertpanel_error(_("Can't remove the folder `%s'."),
2008 if (folderview->opened == folderview->selected)
2009 summary_show(folderview->summaryview,
2010 folderview->summaryview->folder_item,
2015 if (folderview->opened == folderview->selected ||
2016 gtk_ctree_is_ancestor(ctree,
2017 folderview->selected,
2018 folderview->opened)) {
2019 summary_clear_all(folderview->summaryview);
2020 folderview->opened = NULL;
2023 gtk_ctree_remove_node(ctree, folderview->selected);
2024 folder_write_list();
2027 static void folderview_rm_imap_server_cb(FolderView *folderview, guint action,
2030 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2035 if (!folderview->selected) return;
2037 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2038 g_return_if_fail(item != NULL);
2039 g_return_if_fail(item->folder != NULL);
2040 g_return_if_fail(item->folder->type == F_IMAP);
2041 g_return_if_fail(item->folder->account != NULL);
2043 message = g_strdup_printf(_("Really delete IMAP4 account `%s'?"),
2044 item->folder->name);
2045 avalue = alertpanel(_("Delete IMAP4 account"), message,
2046 _("Yes"), _("+No"), NULL);
2049 if (avalue != G_ALERTDEFAULT) return;
2051 if (folderview->opened == folderview->selected ||
2052 gtk_ctree_is_ancestor(ctree,
2053 folderview->selected,
2054 folderview->opened)) {
2055 summary_clear_all(folderview->summaryview);
2056 folderview->opened = NULL;
2059 account_destroy(item->folder->account);
2060 folder_destroy(item->folder);
2061 gtk_ctree_remove_node(ctree, folderview->selected);
2063 main_window_reflect_prefs_all();
2064 folder_write_list();
2067 static void folderview_new_news_group_cb(FolderView *folderview, guint action,
2070 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2071 gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
2072 GtkCTreeNode *servernode, *node;
2075 FolderItem *rootitem;
2076 FolderItem *newitem;
2081 if (!folderview->selected) return;
2083 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2084 g_return_if_fail(item != NULL);
2085 folder = item->folder;
2086 g_return_if_fail(folder != NULL);
2087 g_return_if_fail(folder->type == F_NEWS);
2088 g_return_if_fail(folder->account != NULL);
2090 if (GTK_CTREE_ROW(folderview->selected)->parent != NULL)
2091 servernode = GTK_CTREE_ROW(folderview->selected)->parent;
2093 servernode = folderview->selected;
2095 rootitem = gtk_ctree_node_get_row_data(ctree, servernode);
2097 new_subscr = grouplist_dialog(folder);
2099 /* remove unsubscribed newsgroups */
2100 for (gnode = folder->node->children; gnode != NULL; ) {
2101 GNode *next = gnode->next;
2103 item = FOLDER_ITEM(gnode->data);
2104 if (g_slist_find_custom(new_subscr, item->name,
2105 (GCompareFunc)g_strcasecmp) != NULL) {
2110 node = gtk_ctree_find_by_row_data(ctree, servernode, item);
2116 if (folderview->opened == node) {
2117 summary_clear_all(folderview->summaryview);
2118 folderview->opened = NULL;
2121 folder_item_remove(item);
2122 gtk_ctree_remove_node(ctree, node);
2127 gtk_clist_freeze(GTK_CLIST(ctree));
2129 /* add subscribed newsgroups */
2130 for (cur = new_subscr; cur != NULL; cur = cur->next) {
2131 gchar *name = (gchar *)cur->data;
2133 if (folderview_find_by_name(ctree, servernode, name) != NULL)
2136 text[COL_FOLDER] = name;
2137 node = gtk_ctree_insert_node(ctree, servernode, NULL, text,
2139 folderxpm, folderxpmmask,
2140 folderopenxpm, folderopenxpmmask,
2142 gtk_ctree_expand(ctree, servernode);
2144 newitem = folder_item_new(name, name);
2145 folder_item_append(rootitem, newitem);
2146 gtk_ctree_node_set_row_data(ctree, node, newitem);
2149 gtk_ctree_sort_node(ctree, servernode);
2150 gtk_clist_thaw(GTK_CLIST(ctree));
2152 slist_free_strings(new_subscr);
2153 g_slist_free(new_subscr);
2155 folder_write_list();
2158 static void folderview_rm_news_group_cb(FolderView *folderview, guint action,
2161 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2166 if (!folderview->selected) return;
2168 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2169 g_return_if_fail(item != NULL);
2170 g_return_if_fail(item->folder != NULL);
2171 g_return_if_fail(item->folder->type == F_NEWS);
2172 g_return_if_fail(item->folder->account != NULL);
2174 message = g_strdup_printf(_("Really delete newsgroup `%s'?"),
2175 g_basename(item->path));
2176 avalue = alertpanel(_("Delete newsgroup"), message,
2177 _("Yes"), _("+No"), NULL);
2179 if (avalue != G_ALERTDEFAULT) return;
2181 if (folderview->opened == folderview->selected) {
2182 summary_clear_all(folderview->summaryview);
2183 folderview->opened = NULL;
2186 folder_item_remove(item);
2187 gtk_ctree_remove_node(ctree, folderview->selected);
2188 folder_write_list();
2191 static void folderview_rm_news_server_cb(FolderView *folderview, guint action,
2194 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2199 if (!folderview->selected) return;
2201 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2202 g_return_if_fail(item != NULL);
2203 g_return_if_fail(item->folder != NULL);
2204 g_return_if_fail(item->folder->type == F_NEWS);
2205 g_return_if_fail(item->folder->account != NULL);
2207 message = g_strdup_printf(_("Really delete news account `%s'?"),
2208 item->folder->name);
2209 avalue = alertpanel(_("Delete news account"), message,
2210 _("Yes"), _("+No"), NULL);
2213 if (avalue != G_ALERTDEFAULT) return;
2215 if (folderview->opened == folderview->selected ||
2216 gtk_ctree_is_ancestor(ctree,
2217 folderview->selected,
2218 folderview->opened)) {
2219 summary_clear_all(folderview->summaryview);
2220 folderview->opened = NULL;
2223 account_destroy(item->folder->account);
2224 folder_destroy(item->folder);
2225 gtk_ctree_remove_node(ctree, folderview->selected);
2227 main_window_reflect_prefs_all();
2228 folder_write_list();
2231 static void folderview_search_cb(FolderView *folderview, guint action,
2234 summary_search(folderview->summaryview);
2237 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
2238 GdkDragContext *context,
2242 FolderView *folderview)
2245 FolderItem *item, *current_item;
2246 GtkCTreeNode *node = NULL;
2247 gboolean acceptable = FALSE;
2249 if (gtk_clist_get_selection_info(GTK_CLIST(widget),
2250 x - 24, y - 24, &row, &column)) {
2251 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2252 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2253 current_item = folderview->summaryview->folder_item;
2255 item->path != NULL &&
2256 current_item != NULL &&
2257 current_item != item) {
2258 switch (item->folder->type){
2260 if (current_item->folder->type == F_MH)
2264 if (current_item->folder->account == item->folder->account)
2273 gtk_signal_handler_block_by_func(GTK_OBJECT(widget),GTK_SIGNAL_FUNC(folderview_selected), folderview);
2274 gtk_ctree_select(GTK_CTREE(widget), node);
2275 gtk_signal_handler_unblock_by_func(GTK_OBJECT(widget),GTK_SIGNAL_FUNC(folderview_selected), folderview);
2276 gdk_drag_status(context,
2277 (context->actions == GDK_ACTION_COPY ?
2278 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
2280 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2281 gdk_drag_status(context, 0, time);
2287 static void folderview_drag_leave_cb(GtkWidget *widget,
2288 GdkDragContext *context,
2290 FolderView *folderview)
2292 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2295 static void folderview_drag_received_cb(GtkWidget *widget,
2296 GdkDragContext *drag_context,
2299 GtkSelectionData *data,
2302 FolderView *folderview)
2308 if (gtk_clist_get_selection_info(GTK_CLIST(widget),
2309 x - 24, y - 24, &row, &column) == 0)
2312 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2313 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2315 switch (drag_context->action) {
2316 case GDK_ACTION_COPY:
2317 summary_copy_selected_to(folderview->summaryview, item);
2318 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2320 case GDK_ACTION_MOVE:
2321 case GDK_ACTION_DEFAULT:
2323 summary_move_selected_to(folderview->summaryview, item);
2324 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2328 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2331 static gint folderview_compare_name(gconstpointer a, gconstpointer b)
2333 const FolderItem *item = a;
2334 const gchar *name = b;
2336 if (!item->path) return -1;
2337 return strcmp2(g_basename(item->path), name);
2340 static void folderview_scoring_cb(FolderView *folderview, guint action,
2343 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2346 if (!folderview->selected) return;
2348 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2349 g_return_if_fail(item != NULL);
2350 g_return_if_fail(item->folder != NULL);
2352 prefs_scoring_open(item);
2355 static void folderview_processing_cb(FolderView *folderview, guint action,
2358 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2361 if (!folderview->selected) return;
2363 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2364 g_return_if_fail(item != NULL);
2365 g_return_if_fail(item->folder != NULL);
2367 prefs_filtering_open(item);
2370 static void folderview_property_cb(FolderView *folderview, guint action,
2373 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2376 if (!folderview->selected) return;
2378 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2379 g_return_if_fail(item != NULL);
2380 g_return_if_fail(item->folder != NULL);
2382 prefs_folder_item_create(folderview, item);
2385 void folderview_set_target_folder_color(gint color_op)
2389 FolderView *folderview;
2391 for (list = folderview_list; list != NULL; list = list->next) {
2392 folderview = (FolderView *)list->data;
2393 gtkut_convert_int_to_gdk_color(color_op, &folderview->color_op);
2395 bold_tgtfold_style->fg[GTK_STATE_NORMAL] =
2396 folderview->color_op;