2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2006 Hiroyuki Yamamoto and the Sylpheed-Claws team
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 #include <glib/gi18n.h>
24 #include <gdk/gdkkeysyms.h>
25 #include <gtk/gtkwidget.h>
26 #include <gtk/gtkscrolledwindow.h>
27 #include <gtk/gtkctree.h>
28 #include <gtk/gtkcontainer.h>
29 #include <gtk/gtkclist.h>
30 #include <gtk/gtkstyle.h>
31 #include <gtk/gtksignal.h>
32 #include <gtk/gtkmain.h>
33 #include <gtk/gtkstatusbar.h>
34 #include <gtk/gtkmenu.h>
35 #include <gtk/gtkmenuitem.h>
36 #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 "manage_window.h"
48 #include "alertpanel.h"
50 #include "stock_pixmap.h"
54 #include "prefs_common.h"
55 #include "prefs_account.h"
56 #include "prefs_filtering.h"
57 #include "prefs_folder_item.h"
60 #include "foldersel.h"
62 #include "statusbar.h"
64 #include "folderutils.h"
65 #include "partial_download.h"
66 #include "prefs_folder_column.h"
67 #include "filtering.h"
68 #include "quicksearch.h"
72 #define COL_FOLDER_WIDTH 150
73 #define COL_NUM_WIDTH 32
75 static GList *folderview_list = NULL;
77 static GtkStyle *normal_style;
78 static GtkStyle *normal_color_style;
79 static GtkStyle *bold_style;
80 static GtkStyle *bold_color_style;
81 static GtkStyle *bold_tgtfold_style;
83 static GdkPixmap *inboxxpm;
84 static GdkBitmap *inboxxpmmask;
85 static GdkPixmap *inboxhrmxpm;
86 static GdkBitmap *inboxhrmxpmmask;
87 static GdkPixmap *inboxopenxpm;
88 static GdkBitmap *inboxopenxpmmask;
89 static GdkPixmap *inboxopenhrmxpm;
90 static GdkBitmap *inboxopenhrmxpmmask;
91 static GdkPixmap *outboxxpm;
92 static GdkBitmap *outboxxpmmask;
93 static GdkPixmap *outboxhrmxpm;
94 static GdkBitmap *outboxhrmxpmmask;
95 static GdkPixmap *outboxopenxpm;
96 static GdkBitmap *outboxopenxpmmask;
97 static GdkPixmap *outboxopenhrmxpm;
98 static GdkBitmap *outboxopenhrmxpmmask;
99 static GdkPixmap *folderxpm;
100 static GdkBitmap *folderxpmmask;
101 static GdkPixmap *folderhrmxpm;
102 static GdkBitmap *folderhrmxpmmask;
103 static GdkPixmap *folderopenxpm;
104 static GdkBitmap *folderopenxpmmask;
105 static GdkPixmap *folderopenhrmxpm;
106 static GdkBitmap *folderopenhrmxpmmask;
107 static GdkPixmap *trashopenxpm;
108 static GdkBitmap *trashopenxpmmask;
109 static GdkPixmap *trashopenhrmxpm;
110 static GdkBitmap *trashopenhrmxpmmask;
111 static GdkPixmap *trashxpm;
112 static GdkBitmap *trashxpmmask;
113 static GdkPixmap *trashhrmxpm;
114 static GdkBitmap *trashhrmxpmmask;
115 static GdkPixmap *queuexpm;
116 static GdkBitmap *queuexpmmask;
117 static GdkPixmap *queuehrmxpm;
118 static GdkBitmap *queuehrmxpmmask;
119 static GdkPixmap *queueopenxpm;
120 static GdkBitmap *queueopenxpmmask;
121 static GdkPixmap *queueopenhrmxpm;
122 static GdkBitmap *queueopenhrmxpmmask;
123 static GdkPixmap *draftsxpm;
124 static GdkBitmap *draftsxpmmask;
125 static GdkPixmap *draftsopenxpm;
126 static GdkBitmap *draftsopenxpmmask;
127 static GdkPixmap *noselectxpm;
128 static GdkBitmap *noselectxpmmask;
130 static GdkPixmap *m_inboxxpm;
131 static GdkBitmap *m_inboxxpmmask;
132 static GdkPixmap *m_inboxhrmxpm;
133 static GdkBitmap *m_inboxhrmxpmmask;
134 static GdkPixmap *m_inboxopenxpm;
135 static GdkBitmap *m_inboxopenxpmmask;
136 static GdkPixmap *m_inboxopenhrmxpm;
137 static GdkBitmap *m_inboxopenhrmxpmmask;
138 static GdkPixmap *m_outboxxpm;
139 static GdkBitmap *m_outboxxpmmask;
140 static GdkPixmap *m_outboxhrmxpm;
141 static GdkBitmap *m_outboxhrmxpmmask;
142 static GdkPixmap *m_outboxopenxpm;
143 static GdkBitmap *m_outboxopenxpmmask;
144 static GdkPixmap *m_outboxopenhrmxpm;
145 static GdkBitmap *m_outboxopenhrmxpmmask;
146 static GdkPixmap *m_folderxpm;
147 static GdkBitmap *m_folderxpmmask;
148 static GdkPixmap *m_folderhrmxpm;
149 static GdkBitmap *m_folderhrmxpmmask;
150 static GdkPixmap *m_folderopenxpm;
151 static GdkBitmap *m_folderopenxpmmask;
152 static GdkPixmap *m_folderopenhrmxpm;
153 static GdkBitmap *m_folderopenhrmxpmmask;
154 static GdkPixmap *m_trashopenxpm;
155 static GdkBitmap *m_trashopenxpmmask;
156 static GdkPixmap *m_trashopenhrmxpm;
157 static GdkBitmap *m_trashopenhrmxpmmask;
158 static GdkPixmap *m_trashxpm;
159 static GdkBitmap *m_trashxpmmask;
160 static GdkPixmap *m_trashhrmxpm;
161 static GdkBitmap *m_trashhrmxpmmask;
162 static GdkPixmap *m_queuexpm;
163 static GdkBitmap *m_queuexpmmask;
164 static GdkPixmap *m_queuehrmxpm;
165 static GdkBitmap *m_queuehrmxpmmask;
166 static GdkPixmap *m_queueopenxpm;
167 static GdkBitmap *m_queueopenxpmmask;
168 static GdkPixmap *m_queueopenhrmxpm;
169 static GdkBitmap *m_queueopenhrmxpmmask;
170 static GdkPixmap *m_draftsxpm;
171 static GdkBitmap *m_draftsxpmmask;
172 static GdkPixmap *m_draftsopenxpm;
173 static GdkBitmap *m_draftsopenxpmmask;
175 static GdkPixmap *newxpm;
176 static GdkBitmap *newxpmmask;
177 static GdkPixmap *unreadxpm;
178 static GdkBitmap *unreadxpmmask;
179 static GdkPixmap *readxpm;
180 static GdkBitmap *readxpmmask;
183 static void folderview_select_node (FolderView *folderview,
185 static void folderview_set_folders (FolderView *folderview);
186 static void folderview_sort_folders (FolderView *folderview,
189 static void folderview_append_folder (FolderView *folderview,
191 static void folderview_update_node (FolderView *folderview,
194 static gint folderview_clist_compare (GtkCList *clist,
198 /* callback functions */
199 static gboolean folderview_button_pressed (GtkWidget *ctree,
200 GdkEventButton *event,
201 FolderView *folderview);
202 static gboolean folderview_button_released (GtkWidget *ctree,
203 GdkEventButton *event,
204 FolderView *folderview);
205 static gboolean folderview_key_pressed (GtkWidget *widget,
207 FolderView *folderview);
208 static void folderview_selected (GtkCTree *ctree,
211 FolderView *folderview);
212 static void folderview_tree_expanded (GtkCTree *ctree,
214 FolderView *folderview);
215 static void folderview_tree_collapsed (GtkCTree *ctree,
217 FolderView *folderview);
218 static void folderview_popup_close (GtkMenuShell *menu_shell,
219 FolderView *folderview);
220 static void folderview_col_resized (GtkCList *clist,
223 FolderView *folderview);
225 static void mark_all_read_cb (FolderView *folderview,
229 static void folderview_empty_trash_cb (FolderView *folderview,
233 static void folderview_send_queue_cb (FolderView *folderview,
237 static void folderview_search_cb (FolderView *folderview,
241 static void folderview_property_cb (FolderView *folderview,
245 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
246 GdkDragContext *context,
250 FolderView *folderview);
251 static void folderview_drag_leave_cb (GtkWidget *widget,
252 GdkDragContext *context,
254 FolderView *folderview);
255 static void folderview_drag_received_cb (GtkWidget *widget,
256 GdkDragContext *drag_context,
259 GtkSelectionData *data,
262 FolderView *folderview);
263 static void folderview_start_drag (GtkWidget *widget, gint button, GdkEvent *event,
264 FolderView *folderview);
265 static void folderview_drag_data_get (GtkWidget *widget,
266 GdkDragContext *drag_context,
267 GtkSelectionData *selection_data,
270 FolderView *folderview);
271 static void folderview_drag_end_cb (GtkWidget *widget,
272 GdkDragContext *drag_context,
273 FolderView *folderview);
275 void folderview_create_folder_node (FolderView *folderview,
277 gboolean folderview_update_folder (gpointer source,
279 gboolean folderview_update_item_claws (gpointer source,
281 static void folderview_processing_cb(FolderView *folderview, guint action,
283 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
284 GdkEventButton *event);
286 GHashTable *folderview_popups;
288 static GtkItemFactoryEntry folderview_common_popup_entries[] =
290 {N_("/Mark all re_ad"), NULL, mark_all_read_cb, 0, NULL},
291 {N_("/_Search folder..."), NULL, folderview_search_cb, 0, NULL},
292 {N_("/_Properties..."), NULL, folderview_property_cb, 0, NULL},
293 {N_("/Process_ing..."), NULL, folderview_processing_cb, 0, NULL},
296 static GtkItemFactoryEntry folder_view_trash_popup_entries[] = {
297 {"/------trashsep", NULL, NULL, 0, "<Separator>"},
298 {N_("/Empty _trash..."), NULL, folderview_empty_trash_cb, 0, NULL},
301 static GtkItemFactoryEntry folder_view_queue_popup_entries[] = {
302 {"/------queuesep", NULL, NULL, 0, "<Separator>"},
303 {N_("/Send _queue..."), NULL, folderview_send_queue_cb, 0, NULL},
307 GtkTargetEntry folderview_drag_types[] =
309 {"sylpheed-claws/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY},
310 {"text/uri-list", 0, TARGET_MAIL_URI_LIST}
313 void folderview_initialize(void)
315 FolderViewPopup *fpopup;
317 GSList *entries = NULL;
319 fpopup = g_new0(FolderViewPopup, 1);
321 n_entries = sizeof(folderview_common_popup_entries) /
322 sizeof(folderview_common_popup_entries[0]);
323 for (i = 0; i < n_entries; i++)
324 entries = g_slist_append(entries, &folderview_common_popup_entries[i]);
326 fpopup->klass = "common";
327 fpopup->path = "<CommonFolder>";
328 fpopup->entries = entries;
329 fpopup->set_sensitivity = NULL;
331 folderview_popups = g_hash_table_new(g_str_hash, g_str_equal);
332 g_hash_table_insert(folderview_popups, "common", fpopup);
335 static GtkItemFactory *create_ifactory(FolderView *folderview, FolderViewPopup *fpopup)
338 GtkItemFactory *factory;
339 FolderViewPopup *fpopup_common;
342 factory = gtk_item_factory_new(GTK_TYPE_MENU, fpopup->path, NULL);
343 gtk_item_factory_set_translate_func(factory, menu_translate,
346 for (entries = fpopup->entries; entries != NULL; entries = g_slist_next(entries))
347 gtk_item_factory_create_item(factory, entries->data, folderview, 1);
349 fpopup_common = g_hash_table_lookup(folderview_popups, "common");
350 if (fpopup_common != fpopup)
351 for (entries = fpopup_common->entries; entries != NULL; entries = g_slist_next(entries))
352 gtk_item_factory_create_item(factory, entries->data, folderview, 1);
354 popup = gtk_item_factory_get_widget(factory, fpopup->path);
355 g_signal_connect(G_OBJECT(popup), "selection_done",
356 G_CALLBACK(folderview_popup_close),
362 static void create_ifactories(gpointer key, gpointer value, gpointer data)
364 FolderView *folderview = data;
365 FolderViewPopup *fpopup = value;
366 GtkItemFactory *factory;
368 factory = create_ifactory(folderview, fpopup);
369 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
372 static void folderview_column_set_titles(FolderView *folderview)
374 GtkWidget *ctree = folderview->ctree;
375 GtkWidget *label_new;
376 GtkWidget *label_unread;
377 GtkWidget *label_total;
379 GtkWidget *hbox_unread;
380 GtkWidget *hbox_total;
381 gint *col_pos = folderview->col_pos;
383 debug_print("setting titles...\n");
384 gtk_widget_realize(folderview->ctree);
385 gtk_widget_show_all(folderview->scrolledwin);
387 /* CLAWS: titles for "New" and "Unread" show new & unread pixmaps
388 * instead text (text overflows making them unreadable and ugly) */
389 stock_pixmap_gdk(ctree, STOCK_PIXMAP_NEW,
390 &newxpm, &newxpmmask);
391 stock_pixmap_gdk(ctree, STOCK_PIXMAP_UNREAD,
392 &unreadxpm, &unreadxpmmask);
393 stock_pixmap_gdk(ctree, STOCK_PIXMAP_READ,
394 &readxpm, &readxpmmask);
396 label_new = gtk_pixmap_new(newxpm, newxpmmask);
397 label_unread = gtk_pixmap_new(unreadxpm, unreadxpmmask);
398 label_total = gtk_pixmap_new(readxpm, readxpmmask);
400 hbox_new = gtk_hbox_new(FALSE, 4);
401 hbox_unread = gtk_hbox_new(FALSE, 4);
402 hbox_total = gtk_hbox_new(FALSE, 4);
405 gtk_box_pack_start(GTK_BOX(hbox_new), label_new, TRUE, TRUE, 0);
406 gtk_misc_set_alignment (GTK_MISC (label_new), 1, 0.5);
407 gtk_box_pack_start(GTK_BOX(hbox_unread), label_unread, TRUE, TRUE, 0);
408 gtk_misc_set_alignment (GTK_MISC (label_unread), 1, 0.5);
409 gtk_box_pack_start(GTK_BOX(hbox_total), label_total, TRUE, TRUE, 0);
410 gtk_misc_set_alignment (GTK_MISC (label_total), 1, 0.5);
412 gtk_widget_show_all(hbox_new);
413 gtk_widget_show_all(hbox_unread);
414 gtk_widget_show_all(hbox_total);
416 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_NEW],hbox_new);
417 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_UNREAD],hbox_unread);
418 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_TOTAL],hbox_total);
421 static gboolean folderview_popup_menu(GtkWidget *widget, gpointer data)
423 FolderView *folderview = (FolderView *)data;
424 GdkEventButton event;
425 if (folderview_get_selected_item(folderview) == NULL)
429 event.time = gtk_get_current_event_time();
431 folderview_set_sens_and_popup_menu(folderview, -1,
438 GtkWidget *folderview_ctree_create(FolderView *folderview)
442 FolderColumnState *col_state;
443 FolderColumnType type;
444 gchar *titles[N_FOLDER_COLS];
446 GtkWidget *scrolledwin = folderview->scrolledwin;
448 debug_print("creating tree...\n");
449 memset(titles, 0, sizeof(titles));
451 col_state = prefs_folder_column_get_config();
452 memset(titles, 0, sizeof(titles));
454 col_pos = folderview->col_pos;
456 for (i = 0; i < N_FOLDER_COLS; i++) {
457 folderview->col_state[i] = col_state[i];
458 type = col_state[i].type;
462 titles[col_pos[F_COL_FOLDER]] = _("Folder");
463 titles[col_pos[F_COL_NEW]] = _("New");
464 titles[col_pos[F_COL_UNREAD]] = _("Unread");
465 /* TRANSLATORS: This in Number sign in American style */
466 titles[col_pos[F_COL_TOTAL]] = _("#");
468 ctree = gtk_sctree_new_with_titles(N_FOLDER_COLS, col_pos[F_COL_FOLDER],
471 gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
472 gtk_clist_set_column_justification(GTK_CLIST(ctree), col_pos[F_COL_NEW],
474 gtk_clist_set_column_justification(GTK_CLIST(ctree),
475 col_pos[F_COL_UNREAD],
477 gtk_clist_set_column_justification(GTK_CLIST(ctree),
478 col_pos[F_COL_TOTAL],
480 if (prefs_common.enable_dotted_lines) {
481 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
482 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
483 GTK_CTREE_EXPANDER_SQUARE);
485 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_NONE);
486 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
487 GTK_CTREE_EXPANDER_TRIANGLE);
489 gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
490 gtk_clist_set_compare_func(GTK_CLIST(ctree), folderview_clist_compare);
492 /* don't let title buttons take key focus */
493 for (i = 0; i < N_FOLDER_COLS; i++) {
494 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(ctree)->column[i].button,
496 gtk_clist_set_column_width(GTK_CLIST(ctree), col_pos[i],
497 prefs_common.folder_col_size[i]);
498 gtk_clist_set_column_visibility
499 (GTK_CLIST(ctree), i, col_state[i].visible);
502 g_signal_connect(G_OBJECT(ctree), "key_press_event",
503 G_CALLBACK(folderview_key_pressed),
505 g_signal_connect(G_OBJECT(ctree), "button_press_event",
506 G_CALLBACK(folderview_button_pressed),
508 g_signal_connect(G_OBJECT(ctree), "popup-menu",
509 G_CALLBACK(folderview_popup_menu), folderview);
510 g_signal_connect(G_OBJECT(ctree), "button_release_event",
511 G_CALLBACK(folderview_button_released),
513 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
514 G_CALLBACK(folderview_selected), folderview);
515 g_signal_connect(G_OBJECT(ctree), "start_drag",
516 G_CALLBACK(folderview_start_drag), folderview);
517 g_signal_connect(G_OBJECT(ctree), "drag_data_get",
518 G_CALLBACK(folderview_drag_data_get),
521 g_signal_connect_after(G_OBJECT(ctree), "tree_expand",
522 G_CALLBACK(folderview_tree_expanded),
524 g_signal_connect_after(G_OBJECT(ctree), "tree_collapse",
525 G_CALLBACK(folderview_tree_collapsed),
528 g_signal_connect(G_OBJECT(ctree), "resize_column",
529 G_CALLBACK(folderview_col_resized),
533 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
534 folderview_drag_types, 2,
535 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
536 g_signal_connect(G_OBJECT(ctree), "drag_motion",
537 G_CALLBACK(folderview_drag_motion_cb),
539 g_signal_connect(G_OBJECT(ctree), "drag_leave",
540 G_CALLBACK(folderview_drag_leave_cb),
542 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
543 G_CALLBACK(folderview_drag_received_cb),
545 g_signal_connect(G_OBJECT(ctree), "drag_end",
546 G_CALLBACK(folderview_drag_end_cb),
549 gtk_container_add(GTK_CONTAINER(scrolledwin), ctree);
554 void folderview_set_column_order(FolderView *folderview)
557 FolderItem *item = folderview_get_selected_item(folderview);
558 GtkWidget *scrolledwin = folderview->scrolledwin;
560 debug_print("recreating tree...\n");
561 gtk_widget_destroy(folderview->ctree);
563 folderview->ctree = ctree = folderview_ctree_create(folderview);
564 gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
565 GTK_CLIST(ctree)->hadjustment);
566 gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
567 GTK_CLIST(ctree)->vadjustment);
568 gtk_widget_show(ctree);
570 folderview_set(folderview);
571 folderview_column_set_titles(folderview);
573 folderview_select(folderview,item);
576 FolderView *folderview_create(void)
578 FolderView *folderview;
579 GtkWidget *scrolledwin;
582 debug_print("Creating folder view...\n");
583 folderview = g_new0(FolderView, 1);
585 scrolledwin = gtk_scrolled_window_new(NULL, NULL);
586 gtk_scrolled_window_set_policy
587 (GTK_SCROLLED_WINDOW(scrolledwin),
588 GTK_POLICY_AUTOMATIC,
589 prefs_common.folderview_vscrollbar_policy);
590 gtk_widget_set_size_request(scrolledwin,
591 prefs_common.folderview_width,
592 prefs_common.folderview_height);
594 folderview->scrolledwin = scrolledwin;
595 ctree = folderview_ctree_create(folderview);
597 /* create popup factories */
598 folderview->popups = g_hash_table_new(g_str_hash, g_str_equal);
599 g_hash_table_foreach(folderview_popups, create_ifactories, folderview);
601 folderview->ctree = ctree;
603 folderview->folder_update_callback_id =
604 hooks_register_hook(FOLDER_UPDATE_HOOKLIST, folderview_update_folder, (gpointer) folderview);
605 folderview->folder_item_update_callback_id =
606 hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST, folderview_update_item_claws, (gpointer) folderview);
608 gtk_widget_show_all(scrolledwin);
610 folderview->target_list = gtk_target_list_new(folderview_drag_types, 2);
611 folderview_list = g_list_append(folderview_list, folderview);
616 void folderview_init(FolderView *folderview)
618 GtkWidget *ctree = folderview->ctree;
621 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE, &inboxxpm, &inboxxpmmask);
622 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM, &inboxhrmxpm, &inboxhrmxpmmask);
623 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN, &inboxopenxpm, &inboxopenxpmmask);
624 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM, &inboxopenhrmxpm, &inboxopenhrmxpmmask);
625 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE, &outboxxpm, &outboxxpmmask);
626 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM, &outboxhrmxpm, &outboxhrmxpmmask);
627 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN, &outboxopenxpm, &outboxopenxpmmask);
628 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM, &outboxopenhrmxpm, &outboxopenhrmxpmmask);
629 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
630 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM, &folderhrmxpm, &folderhrmxpmmask);
631 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
632 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM, &folderopenhrmxpm, &folderopenhrmxpmmask);
633 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN, &trashopenxpm, &trashopenxpmmask);
634 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM, &trashopenhrmxpm, &trashopenhrmxpmmask);
635 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE, &trashxpm, &trashxpmmask);
636 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM, &trashhrmxpm, &trashhrmxpmmask);
637 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE, &queuexpm, &queuexpmmask);
638 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM, &queuehrmxpm, &queuehrmxpmmask);
639 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN, &queueopenxpm, &queueopenxpmmask);
640 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM, &queueopenhrmxpm, &queueopenhrmxpmmask);
641 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE, &draftsxpm, &draftsxpmmask);
642 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN, &draftsopenxpm, &draftsopenxpmmask);
643 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_NOSELECT, &noselectxpm, &noselectxpmmask);
645 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_MARK, &m_inboxxpm, &m_inboxxpmmask);
646 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM_MARK, &m_inboxhrmxpm, &m_inboxhrmxpmmask);
647 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_MARK, &m_inboxopenxpm, &m_inboxopenxpmmask);
648 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM_MARK, &m_inboxopenhrmxpm, &m_inboxopenhrmxpmmask);
649 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_MARK, &m_outboxxpm, &m_outboxxpmmask);
650 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM_MARK, &m_outboxhrmxpm, &m_outboxhrmxpmmask);
651 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_MARK, &m_outboxopenxpm, &m_outboxopenxpmmask);
652 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM_MARK, &m_outboxopenhrmxpm, &m_outboxopenhrmxpmmask);
653 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_MARK, &m_folderxpm, &m_folderxpmmask);
654 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM_MARK, &m_folderhrmxpm, &m_folderhrmxpmmask);
655 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_MARK, &m_folderopenxpm, &m_folderopenxpmmask);
656 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM_MARK, &m_folderopenhrmxpm, &m_folderopenhrmxpmmask);
657 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_MARK, &m_trashopenxpm, &m_trashopenxpmmask);
658 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM_MARK, &m_trashopenhrmxpm, &m_trashopenhrmxpmmask);
659 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_MARK, &m_trashxpm, &m_trashxpmmask);
660 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM_MARK, &m_trashhrmxpm, &m_trashhrmxpmmask);
661 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_MARK, &m_queuexpm, &m_queuexpmmask);
662 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM_MARK, &m_queuehrmxpm, &m_queuehrmxpmmask);
663 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_MARK, &m_queueopenxpm, &m_queueopenxpmmask);
664 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM_MARK, &m_queueopenhrmxpm, &m_queueopenhrmxpmmask);
665 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE_MARK, &m_draftsxpm, &m_draftsxpmmask);
666 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN_MARK, &m_draftsopenxpm, &m_draftsopenxpmmask);
669 PangoFontDescription *font_desc;
670 normal_style = gtk_style_copy(gtk_widget_get_style(ctree));
671 font_desc = pango_font_description_from_string(NORMAL_FONT);
673 if (normal_style->font_desc)
674 pango_font_description_free
675 (normal_style->font_desc);
676 normal_style->font_desc = font_desc;
678 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
679 normal_color_style = gtk_style_copy(normal_style);
680 normal_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
682 gtk_widget_set_style(ctree, normal_style);
686 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
687 bold_style = gtk_style_copy(gtk_widget_get_style(ctree));
688 pango_font_description_set_weight
689 (bold_style->font_desc, PANGO_WEIGHT_BOLD);
690 bold_color_style = gtk_style_copy(bold_style);
691 bold_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
693 bold_tgtfold_style = gtk_style_copy(bold_style);
694 bold_tgtfold_style->fg[GTK_STATE_NORMAL] = folderview->color_op;
698 void folderview_set(FolderView *folderview)
700 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
701 MainWindow *mainwin = folderview->mainwin;
706 debug_print("Setting folder info...\n");
707 STATUSBAR_PUSH(mainwin, _("Setting folder info..."));
709 main_window_cursor_wait(mainwin);
711 folderview->selected = NULL;
712 folderview->opened = NULL;
714 gtk_clist_freeze(GTK_CLIST(ctree));
715 gtk_clist_clear(GTK_CLIST(ctree));
716 gtk_clist_thaw(GTK_CLIST(ctree));
717 gtk_clist_freeze(GTK_CLIST(ctree));
719 folderview_set_folders(folderview);
721 gtk_clist_thaw(GTK_CLIST(ctree));
722 main_window_cursor_normal(mainwin);
723 STATUSBAR_POP(mainwin);
726 void folderview_set_all(void)
730 for (list = folderview_list; list != NULL; list = list->next)
731 folderview_set((FolderView *)list->data);
734 void folderview_select(FolderView *folderview, FolderItem *item)
736 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
738 GtkCTreeNode *old_selected = folderview->selected;
742 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
743 if (node) folderview_select_node(folderview, node);
745 if (old_selected != node)
746 folder_update_op_count();
749 static void mark_all_read_cb(FolderView *folderview, guint action,
755 item = folderview_get_selected_item(folderview);
759 if (folderview->summaryview->folder_item != item
760 && prefs_common.ask_mark_all_read) {
761 val = alertpanel_full(_("Mark all as read"),
762 _("Do you really want to mark all mails in this "
763 "folder as read ?"), GTK_STOCK_NO, GTK_STOCK_YES, NULL,
764 TRUE, NULL, ALERT_QUESTION, G_ALERTDEFAULT);
766 if ((val & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
768 else if (val & G_ALERTDISABLE)
769 prefs_common.ask_mark_all_read = FALSE;
772 summary_lock(folderview->summaryview);
773 folder_item_update_freeze();
774 if (folderview->summaryview->folder_item == item)
775 gtk_clist_freeze(GTK_CLIST(folderview->summaryview->ctree));
776 folderutils_mark_all_read(item);
777 if (folderview->summaryview->folder_item == item)
778 gtk_clist_thaw(GTK_CLIST(folderview->summaryview->ctree));
779 folder_item_update_thaw();
780 summary_unlock(folderview->summaryview);
783 static void folderview_select_node(FolderView *folderview, GtkCTreeNode *node)
785 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
787 g_return_if_fail(node != NULL);
789 folderview->open_folder = TRUE;
790 gtkut_ctree_set_focus_row(ctree, node);
791 gtk_ctree_select(ctree, node);
792 if (folderview->summaryview->folder_item &&
793 folderview->summaryview->folder_item->total_msgs > 0)
794 gtk_widget_grab_focus(folderview->summaryview->ctree);
796 gtk_widget_grab_focus(folderview->ctree);
798 gtkut_ctree_expand_parent_all(ctree, node);
801 void folderview_unselect(FolderView *folderview)
803 if (folderview->opened && !GTK_CTREE_ROW(folderview->opened)->children)
805 (GTK_CTREE(folderview->ctree), folderview->opened);
807 folderview->selected = folderview->opened = NULL;
810 static GtkCTreeNode *folderview_find_next_marked(GtkCTree *ctree,
816 node = gtkut_ctree_node_next(ctree, node);
818 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
820 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
821 item = gtk_ctree_node_get_row_data(ctree, node);
822 if (item && item->marked_msgs > 0 && item->stype != F_TRASH)
829 void folderview_select_next_marked(FolderView *folderview)
831 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
832 GtkCTreeNode *node = NULL;
833 SelectOnEntry last_sel = prefs_common.select_on_entry;
834 gboolean last_open = prefs_common.always_show_msg;
836 prefs_common.select_on_entry = SELECTONENTRY_MNU;
837 prefs_common.always_show_msg = TRUE;
839 if ((node = folderview_find_next_marked(ctree, folderview->opened))
841 folderview_select_node(folderview, node);
845 if (!folderview->opened ||
846 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
849 /* search again from the first node */
850 if ((node = folderview_find_next_marked(ctree, NULL)) != NULL)
851 folderview_select_node(folderview, node);
854 prefs_common.select_on_entry = last_sel;
855 prefs_common.always_show_msg = last_open;
858 static GtkCTreeNode *folderview_find_next_unread(GtkCTree *ctree,
864 node = gtkut_ctree_node_next(ctree, node);
866 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
868 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
869 item = gtk_ctree_node_get_row_data(ctree, node);
870 if (item && item->unread_msgs > 0 && item->stype != F_TRASH)
877 void folderview_select_next_unread(FolderView *folderview)
879 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
880 GtkCTreeNode *node = NULL;
881 SelectOnEntry last_sel = prefs_common.select_on_entry;
882 gboolean last_open = prefs_common.always_show_msg;
884 prefs_common.select_on_entry = SELECTONENTRY_UNM;
885 prefs_common.always_show_msg = TRUE;
887 if ((node = folderview_find_next_unread(ctree, folderview->opened))
889 folderview_select_node(folderview, node);
893 if (!folderview->opened ||
894 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
897 /* search again from the first node */
898 if ((node = folderview_find_next_unread(ctree, NULL)) != NULL)
899 folderview_select_node(folderview, node);
902 prefs_common.select_on_entry = last_sel;
903 prefs_common.always_show_msg = last_open;
906 static GtkCTreeNode *folderview_find_next_new(GtkCTree *ctree,
912 node = gtkut_ctree_node_next(ctree, node);
914 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
916 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
917 item = gtk_ctree_node_get_row_data(ctree, node);
918 if (item && item->new_msgs > 0 && item->stype != F_TRASH)
925 void folderview_select_next_new(FolderView *folderview)
927 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
928 GtkCTreeNode *node = NULL;
929 SelectOnEntry last_sel = prefs_common.select_on_entry;
930 gboolean last_open = prefs_common.always_show_msg;
932 prefs_common.select_on_entry = SELECTONENTRY_NUM;
933 prefs_common.always_show_msg = TRUE;
935 if ((node = folderview_find_next_new(ctree, folderview->opened))
937 folderview_select_node(folderview, node);
941 if (!folderview->opened ||
942 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
945 /* search again from the first node */
946 if ((node = folderview_find_next_new(ctree, NULL)) != NULL)
947 folderview_select_node(folderview, node);
950 prefs_common.select_on_entry = last_sel;
951 prefs_common.always_show_msg = last_open;
954 FolderItem *folderview_get_selected_item(FolderView *folderview)
956 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
958 if (!folderview->selected) return NULL;
959 return gtk_ctree_node_get_row_data(ctree, folderview->selected);
962 void folderview_update_msg_num(FolderView *folderview, GtkCTreeNode *row)
964 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
965 static GtkCTreeNode *prev_row = NULL;
967 gint new, unread, total;
968 gchar *new_str, *unread_str, *total_str;
969 gint *col_pos = folderview->col_pos;
973 item = gtk_ctree_node_get_row_data(ctree, row);
976 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_NEW], &new_str);
977 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_UNREAD], &unread_str);
978 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_TOTAL], &total_str);
980 unread = atoi(unread_str);
981 total = atoi(total_str);
985 folderview_update_node(folderview, row);
988 void folderview_append_item(FolderItem *item)
992 g_return_if_fail(item != NULL);
993 g_return_if_fail(item->folder != NULL);
994 if (folder_item_parent(item)) return;
996 for (list = folderview_list; list != NULL; list = list->next) {
997 FolderView *folderview = (FolderView *)list->data;
998 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
999 GtkCTreeNode *node, *child;
1000 gint *col_pos = folderview->col_pos;
1002 node = gtk_ctree_find_by_row_data(ctree, NULL,
1003 folder_item_parent(item));
1005 child = gtk_ctree_find_by_row_data(ctree, node, item);
1007 gchar *text[N_FOLDER_COLS] =
1008 {NULL, "0", "0", "0"};
1010 gtk_clist_freeze(GTK_CLIST(ctree));
1012 text[col_pos[F_COL_FOLDER]] = item->name;
1013 child = gtk_sctree_insert_node
1014 (ctree, node, NULL, text,
1016 folderxpm, folderxpmmask,
1017 folderopenxpm, folderopenxpmmask,
1019 gtk_ctree_node_set_row_data(ctree, child, item);
1020 gtk_ctree_expand(ctree, node);
1021 folderview_update_node(folderview, child);
1022 folderview_sort_folders(folderview, node,
1025 gtk_clist_thaw(GTK_CLIST(ctree));
1031 static void folderview_set_folders(FolderView *folderview)
1034 #ifndef HAVE_LIBETPAN
1035 static gboolean missing_imap_warning = TRUE;
1037 list = folder_get_list();
1039 for (; list != NULL; list = list->next) {
1040 #ifndef HAVE_LIBETPAN
1041 if ((FOLDER(list->data))
1042 && (FOLDER(list->data))->klass
1043 && (FOLDER(list->data))->klass->type == F_IMAP
1044 && missing_imap_warning) {
1045 missing_imap_warning = FALSE;
1047 _("You have one or more IMAP accounts "
1048 "defined. However this version of "
1049 "Sylpheed-Claws has been built without "
1050 "IMAP support; your IMAP account(s) are "
1052 "You probably need to "
1053 "install libetpan and recompile "
1054 "Sylpheed-Claws."));
1057 folderview_append_folder(folderview, FOLDER(list->data));
1061 static gchar *get_scan_str(FolderItem *item)
1064 return g_strdup_printf(_("Scanning folder %s%c%s ..."),
1065 item->folder->name, G_DIR_SEPARATOR,
1068 return g_strdup_printf(_("Scanning folder %s ..."),
1069 item->folder->name);
1071 static void folderview_scan_tree_func(Folder *folder, FolderItem *item,
1075 for (list = folderview_list; list != NULL; list = list->next) {
1076 FolderView *folderview = (FolderView *)list->data;
1077 MainWindow *mainwin = folderview->mainwin;
1078 gchar *str = get_scan_str(item);
1080 STATUSBAR_PUSH(mainwin, str);
1081 STATUSBAR_POP(mainwin);
1086 void folderview_rescan_tree(Folder *folder, gboolean rebuild)
1090 g_return_if_fail(folder != NULL);
1092 if (!folder->klass->scan_tree) return;
1095 alertpanel_full(_("Rebuild folder tree"),
1096 _("Rebuilding the folder tree will remove "
1097 "local caches. Do you want to continue?"),
1098 GTK_STOCK_NO, GTK_STOCK_YES, NULL, FALSE,
1099 NULL, ALERT_WARNING, G_ALERTDEFAULT)
1100 != G_ALERTALTERNATE) {
1106 window = label_window_create(_("Rebuilding folder tree..."));
1108 window = label_window_create(_("Scanning folder tree..."));
1110 folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
1111 folder_scan_tree(folder, rebuild);
1112 folder_set_ui_func(folder, NULL, NULL);
1114 folderview_set_all();
1116 gtk_widget_destroy(window);
1120 /** folderview_check_new()
1121 * Scan and update the folder and return the
1122 * count the number of new messages since last check.
1123 * \param folder the folder to check for new messages
1124 * \return the number of new messages since last check
1126 gint folderview_check_new(Folder *folder)
1130 FolderView *folderview;
1134 gint former_new_msgs = 0;
1135 gint former_new = 0, former_unread = 0, former_total;
1137 for (list = folderview_list; list != NULL; list = list->next) {
1138 folderview = (FolderView *)list->data;
1139 ctree = GTK_CTREE(folderview->ctree);
1142 main_window_lock(folderview->mainwin);
1144 for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
1145 node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
1147 item = gtk_ctree_node_get_row_data(ctree, node);
1148 if (!item || !item->path || !item->folder) continue;
1149 if (item->no_select) continue;
1150 if (folder && folder != item->folder) continue;
1151 if (!folder && !FOLDER_IS_LOCAL(item->folder)) continue;
1152 if (!item->prefs->newmailcheck) continue;
1153 if (item->processing_pending == TRUE) {
1154 debug_print("skipping %s, processing pending\n",
1155 item->path ? item->path : item->name);
1159 str = get_scan_str(item);
1161 STATUSBAR_PUSH(folderview->mainwin, str);
1165 folderview_scan_tree_func(item->folder, item, NULL);
1166 former_new = item->new_msgs;
1167 former_unread = item->unread_msgs;
1168 former_total = item->total_msgs;
1170 if (item->folder->klass->scan_required &&
1171 (item->folder->klass->scan_required(item->folder, item) ||
1172 item->folder->inbox == item ||
1173 item->opened == TRUE ||
1174 item->processing_pending == TRUE)) {
1175 if (folder_item_scan(item) < 0) {
1176 summaryview_unlock(folderview->summaryview, item);
1177 if (folder && !FOLDER_IS_LOCAL(folder)) {
1178 STATUSBAR_POP(folderview->mainwin);
1182 } else if (!item->folder->klass->scan_required) {
1183 if (folder_item_scan(item) < 0) {
1184 summaryview_unlock(folderview->summaryview, item);
1185 if (folder && !FOLDER_IS_LOCAL(folder)) {
1186 STATUSBAR_POP(folderview->mainwin);
1191 if (former_new != item->new_msgs ||
1192 former_unread != item->unread_msgs ||
1193 former_total != item->total_msgs)
1194 folderview_update_node(folderview, node);
1196 new_msgs += item->new_msgs;
1197 former_new_msgs += former_new;
1198 STATUSBAR_POP(folderview->mainwin);
1201 main_window_unlock(folderview->mainwin);
1205 folder_write_list();
1206 /* Number of new messages since last check is the just the difference
1207 * between former_new_msgs and new_msgs. If new_msgs is less than
1208 * former_new_msgs, that would mean another session accessed the folder
1209 * and the result is not well defined.
1211 new_msgs = (former_new_msgs < new_msgs ? new_msgs - former_new_msgs : 0);
1215 void folderview_check_new_all(void)
1219 FolderView *folderview;
1221 folderview = (FolderView *)folderview_list->data;
1224 main_window_lock(folderview->mainwin);
1225 window = label_window_create
1226 (_("Checking for new messages in all folders..."));
1228 list = folder_get_list();
1229 for (; list != NULL; list = list->next) {
1230 Folder *folder = list->data;
1232 folderview_check_new(folder);
1235 folder_write_list();
1236 folderview_set_all();
1238 gtk_widget_destroy(window);
1239 main_window_unlock(folderview->mainwin);
1243 static gboolean folderview_have_new_children_sub(FolderView *folderview,
1249 if (!item || !item->folder || !item->folder->node)
1252 node = item->folder->node;
1254 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1255 node = node->children;
1258 (item->new_msgs > 0 ||
1259 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1263 while (node != NULL) {
1264 if (node && node->data) {
1265 FolderItem *next_item = (FolderItem*) node->data;
1267 if (folderview_have_new_children_sub(folderview,
1276 static gboolean folderview_have_new_children(FolderView *folderview,
1279 return folderview_have_new_children_sub(folderview, item, FALSE);
1282 static gboolean folderview_have_unread_children_sub(FolderView *folderview,
1288 if (!item || !item->folder || !item->folder->node)
1291 node = item->folder->node;
1293 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1294 node = node->children;
1297 (item->unread_msgs > 0 ||
1298 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1302 while (node != NULL) {
1303 if (node && node->data) {
1304 FolderItem *next_item = (FolderItem*) node->data;
1306 if (folderview_have_unread_children_sub(folderview,
1316 static gboolean folderview_have_unread_children(FolderView *folderview,
1319 return folderview_have_unread_children_sub(folderview, item, FALSE);
1322 static gboolean folderview_have_matching_children_sub(FolderView *folderview,
1328 if (!item || !item->folder || !item->folder->node)
1331 node = item->folder->node;
1333 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1334 node = node->children;
1336 if (in_sub && item->search_match){
1340 while (node != NULL) {
1341 if (node && node->data) {
1342 FolderItem *next_item = (FolderItem*) node->data;
1344 if (folderview_have_matching_children_sub(folderview,
1354 static gboolean folderview_have_matching_children(FolderView *folderview,
1357 return folderview_have_matching_children_sub(folderview, item, FALSE);
1360 static gboolean folderview_have_marked_children_sub(FolderView *folderview,
1366 if (!item || !item->folder || !item->folder->node)
1369 node = item->folder->node;
1371 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1372 node = node->children;
1374 if (item->marked_msgs != 0) {
1378 while (node != NULL) {
1379 if (node && node->data) {
1380 FolderItem *next_item = (FolderItem*) node->data;
1382 if (folderview_have_marked_children_sub(folderview,
1391 static gboolean folderview_have_marked_children(FolderView *folderview,
1394 return folderview_have_marked_children_sub(folderview, item, FALSE);
1397 static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node)
1399 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1400 GtkStyle *style = NULL;
1401 GtkStyle *color_style = NULL;
1403 GdkPixmap *xpm, *openxpm;
1404 GdkBitmap *mask, *openmask;
1405 static GdkPixmap *searchicon;
1406 static GdkBitmap *searchmask;
1407 gboolean mark = FALSE;
1410 gboolean add_unread_mark;
1411 gboolean add_sub_match_mark;
1412 gboolean use_bold, use_color;
1413 gint *col_pos = folderview->col_pos;
1414 SpecialFolderItemType stype;
1416 item = gtk_ctree_node_get_row_data(ctree, node);
1417 g_return_if_fail(item != NULL);
1419 if (!GTK_CTREE_ROW(node)->expanded)
1420 mark = folderview_have_marked_children(folderview, item);
1422 mark = (item->marked_msgs != 0);
1424 stype = item->stype;
1425 if (stype == F_NORMAL) {
1426 if (folder_has_parent_of_type(item, F_TRASH))
1428 else if (folder_has_parent_of_type(item, F_DRAFT))
1430 else if (folder_has_parent_of_type(item, F_OUTBOX))
1432 else if (folder_has_parent_of_type(item, F_QUEUE))
1437 if (item->hide_read_msgs) {
1438 xpm = mark?m_inboxhrmxpm:inboxhrmxpm;
1439 mask = mark?m_inboxhrmxpmmask:inboxhrmxpmmask;
1440 openxpm = mark?m_inboxopenhrmxpm:inboxopenhrmxpm;
1441 openmask = mark?m_inboxopenhrmxpmmask:inboxopenhrmxpmmask;
1443 xpm = mark?m_inboxxpm:inboxxpm;
1444 mask = mark?m_inboxxpmmask:inboxxpmmask;
1445 openxpm = mark?m_inboxopenxpm:inboxopenxpm;
1446 openmask = mark?m_inboxopenxpmmask:inboxopenxpmmask;
1450 if (item->hide_read_msgs) {
1451 xpm = mark?m_outboxhrmxpm:outboxhrmxpm;
1452 mask = mark?m_outboxhrmxpmmask:outboxhrmxpmmask;
1453 openxpm = mark?m_outboxopenhrmxpm:outboxopenhrmxpm;
1454 openmask = mark?m_outboxopenhrmxpmmask:outboxopenhrmxpmmask;
1456 xpm = mark?m_outboxxpm:outboxxpm;
1457 mask = mark?m_outboxxpmmask:outboxxpmmask;
1458 openxpm = mark?m_outboxopenxpm:outboxopenxpm;
1459 openmask = mark?m_outboxopenxpmmask:outboxopenxpmmask;
1463 if (item->hide_read_msgs) {
1464 xpm = mark?m_queuehrmxpm:queuehrmxpm;
1465 mask = mark?m_queuehrmxpmmask:queuehrmxpmmask;
1466 openxpm = mark?m_queueopenhrmxpm:queueopenhrmxpm;
1467 openmask = mark?m_queueopenhrmxpmmask:queueopenhrmxpmmask;
1469 xpm = mark?m_queuexpm:queuexpm;
1470 mask = mark?m_queuexpmmask:queuexpmmask;
1471 openxpm = mark?m_queueopenxpm:queueopenxpm;
1472 openmask = mark?m_queueopenxpmmask:queueopenxpmmask;
1476 if (item->hide_read_msgs) {
1477 xpm = mark?m_trashhrmxpm:trashhrmxpm;
1478 mask = mark?m_trashhrmxpmmask:trashhrmxpmmask;
1479 openxpm = mark?m_trashopenhrmxpm:trashopenhrmxpm;
1480 openmask = mark?m_trashopenhrmxpmmask:trashopenhrmxpmmask;
1482 xpm = mark?m_trashxpm:trashxpm;
1483 mask = mark?m_trashxpmmask:trashxpmmask;
1484 openxpm = mark?m_trashopenxpm:trashopenxpm;
1485 openmask = mark?m_trashopenxpmmask:trashopenxpmmask;
1489 xpm = mark?m_draftsxpm:draftsxpm;
1490 mask = mark?m_draftsxpmmask:draftsxpmmask;
1491 openxpm = mark?m_draftsopenxpm:draftsopenxpm;
1492 openmask = mark?m_draftsopenxpmmask:draftsopenxpmmask;
1495 if (item->hide_read_msgs) {
1496 xpm = mark?m_folderhrmxpm:folderhrmxpm;
1497 mask = mark?m_folderhrmxpmmask:folderhrmxpmmask;
1498 openxpm = mark?m_folderopenhrmxpm:folderopenhrmxpm;
1499 openmask = mark?m_folderopenhrmxpmmask:folderopenhrmxpmmask;
1501 xpm = mark?m_folderxpm:folderxpm;
1502 mask = mark?m_folderxpmmask:folderxpmmask;
1503 openxpm = mark?m_folderopenxpm:folderopenxpm;
1504 openmask = mark?m_folderopenxpmmask:folderopenxpmmask;
1508 if (item->no_select) {
1509 xpm = openxpm = noselectxpm;
1510 mask = openmask = noselectxpmmask;
1513 name = folder_item_get_name(item);
1515 if (!GTK_CTREE_ROW(node)->expanded) {
1516 add_unread_mark = folderview_have_unread_children(
1518 add_sub_match_mark = folderview_have_matching_children(
1521 add_unread_mark = FALSE;
1522 add_sub_match_mark = FALSE;
1525 if (item->search_match) {
1527 stock_pixmap_gdk(folderview->ctree, STOCK_PIXMAP_QUICKSEARCH,
1528 &searchicon, &searchmask);
1530 xpm = openxpm = searchicon;
1531 mask = openmask = searchmask;
1534 if (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0 &&
1535 prefs_common.display_folder_unread) {
1536 str = g_strdup_printf("%s (%d%s)", name, item->total_msgs,
1537 add_unread_mark ? "+" : "");
1538 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1539 xpm, mask, openxpm, openmask,
1540 FALSE, GTK_CTREE_ROW(node)->expanded);
1542 } else if (((item->unread_msgs > 0 || add_unread_mark) &&
1543 prefs_common.display_folder_unread)
1544 || add_sub_match_mark) {
1546 if (item->unread_msgs > 0)
1547 str = g_strdup_printf("%s (%d%s%s)", name, item->unread_msgs,
1548 add_unread_mark || add_sub_match_mark ? "+" : "",
1549 item->unreadmarked_msgs > 0 ? "!":"");
1551 str = g_strdup_printf("%s (+)", name);
1552 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1553 xpm, mask, openxpm, openmask,
1554 FALSE, GTK_CTREE_ROW(node)->expanded);
1557 str = g_strdup_printf("%s%s", name,
1558 item->unreadmarked_msgs > 0 ? " (!)":"");
1560 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1561 xpm, mask, openxpm, openmask,
1562 FALSE, GTK_CTREE_ROW(node)->expanded);
1567 if (!folder_item_parent(item)) {
1568 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], "-");
1569 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], "-");
1570 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], "-");
1572 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], itos(item->new_msgs));
1573 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], itos(item->unread_msgs));
1574 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], itos(item->total_msgs));
1577 if (folder_has_parent_of_type(item, F_OUTBOX) ||
1578 folder_has_parent_of_type(item, F_DRAFT) ||
1579 folder_has_parent_of_type(item, F_TRASH)) {
1580 use_bold = use_color = FALSE;
1581 } else if (folder_has_parent_of_type(item, F_QUEUE)) {
1582 /* highlight queue folder if there are any messages */
1583 use_bold = use_color = (item->total_msgs > 0);
1585 /* if unread messages exist, print with bold font */
1586 use_bold = (item->unread_msgs > 0|| item->new_msgs > 0)
1588 /* if new messages exist, print with colored letter */
1590 (item->new_msgs > 0) ||
1592 folderview_have_new_children(folderview, item));
1595 gtk_ctree_node_set_foreground(ctree, node, NULL);
1600 if (item->prefs->color > 0 && !use_color) {
1601 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1602 color_style = gtk_style_copy(bold_style);
1603 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1604 style = color_style;
1605 } else if (use_color) {
1606 style = bold_color_style;
1609 if (item->op_count > 0) {
1610 style = bold_tgtfold_style;
1612 } else if (use_color) {
1613 style = normal_color_style;
1614 gtk_ctree_node_set_foreground(ctree, node,
1615 &folderview->color_new);
1616 } else if (item->op_count > 0) {
1617 style = bold_tgtfold_style;
1618 } else if (item->prefs->color > 0) {
1620 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1621 color_style = gtk_style_copy(normal_style);
1622 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1623 style = color_style;
1625 style = normal_style;
1628 gtk_ctree_node_set_row_style(ctree, node, style);
1630 if ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
1631 folderview_update_node(folderview, node);
1634 #if !CLAWS /* keep it here for syncs */
1635 void folderview_update_item(FolderItem *item, gboolean update_summary)
1638 FolderView *folderview;
1642 g_return_if_fail(item != NULL);
1644 for (list = folderview_list; list != NULL; list = list->next) {
1645 folderview = (FolderView *)list->data;
1646 ctree = GTK_CTREE(folderview->ctree);
1648 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1650 folderview_update_node(folderview, node);
1651 if (update_summary && folderview->opened == node)
1652 summary_show(folderview->summaryview,
1659 void folderview_update_search_icon(FolderItem *item, gboolean matches)
1662 FolderView *folderview;
1666 g_return_if_fail(item != NULL);
1668 for (list = folderview_list; list != NULL; list = list->next) {
1669 folderview = (FolderView *)list->data;
1670 ctree = GTK_CTREE(folderview->ctree);
1672 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1674 item->search_match = matches;
1675 folderview_update_node(folderview, node);
1680 gboolean folderview_update_item_claws(gpointer source, gpointer data)
1682 FolderItemUpdateData *update_info = (FolderItemUpdateData *)source;
1683 FolderView *folderview = (FolderView *)data;
1686 g_return_val_if_fail(update_info != NULL, TRUE);
1687 g_return_val_if_fail(update_info->item != NULL, TRUE);
1688 g_return_val_if_fail(folderview != NULL, FALSE);
1690 ctree = GTK_CTREE(folderview->ctree);
1692 node = gtk_ctree_find_by_row_data(ctree, NULL, update_info->item);
1694 if (update_info->update_flags & (F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_NAME))
1695 folderview_update_node(folderview, node);
1696 if ((update_info->update_flags & F_ITEM_UPDATE_CONTENT) && (folderview->opened == node))
1697 if (!quicksearch_is_active(folderview->summaryview->quicksearch))
1698 summary_show(folderview->summaryview, update_info->item);
1704 static void folderview_update_item_foreach_func(gpointer key, gpointer val,
1707 /* CLAWS: share this joy with other hook functions ... */
1708 folder_item_update((FolderItem *)key,
1709 (FolderItemUpdateFlags)GPOINTER_TO_INT(data));
1712 void folderview_update_item_foreach(GHashTable *table, gboolean update_summary)
1715 FolderItemUpdateFlags flags;
1717 flags = update_summary ? F_ITEM_UPDATE_CONTENT | F_ITEM_UPDATE_MSGCNT
1719 for (list = folderview_list; list != NULL; list = list->next)
1720 g_hash_table_foreach(table, folderview_update_item_foreach_func,
1721 GINT_TO_POINTER(flags));
1724 static gboolean folderview_gnode_func(GtkCTree *ctree, guint depth,
1725 GNode *gnode, GtkCTreeNode *cnode,
1728 FolderView *folderview = (FolderView *)data;
1729 FolderItem *item = FOLDER_ITEM(gnode->data);
1731 g_return_val_if_fail(item != NULL, FALSE);
1733 gtk_ctree_node_set_row_data(ctree, cnode, item);
1734 folderview_update_node(folderview, cnode);
1739 static void folderview_expand_func(GtkCTree *ctree, GtkCTreeNode *node,
1742 FolderView *folderview = (FolderView *)data;
1745 if (GTK_CTREE_ROW(node)->children) {
1746 item = gtk_ctree_node_get_row_data(ctree, node);
1747 g_return_if_fail(item != NULL);
1749 if (!item->collapsed)
1750 gtk_ctree_expand(ctree, node);
1752 folderview_update_node(folderview, node);
1756 static void set_special_folder(GtkCTree *ctree, FolderItem *item,
1757 GtkCTreeNode *root, GtkCTreeNode **prev)
1760 GtkCTreeNode *node, *parent, *sibling;
1762 node = gtk_ctree_find_by_row_data(ctree, root, item);
1764 g_warning("%s not found.\n", item->path);
1766 parent = GTK_CTREE_ROW(node)->parent;
1767 if (*prev && parent == GTK_CTREE_ROW(*prev)->parent)
1768 sibling = GTK_CTREE_ROW(*prev)->sibling;
1770 sibling = GTK_CTREE_ROW(parent)->children;
1774 tmp = gtk_ctree_node_get_row_data
1776 if (tmp->stype != F_NORMAL)
1777 sibling = GTK_CTREE_ROW(sibling)->sibling;
1781 if (node != sibling)
1782 gtk_ctree_move(ctree, node, parent, sibling);
1789 static void folderview_sort_folders(FolderView *folderview, GtkCTreeNode *root,
1792 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1793 GtkCTreeNode *prev = NULL;
1795 gtk_sctree_sort_recursive(ctree, root);
1797 if (root && GTK_CTREE_ROW(root)->parent) return;
1799 set_special_folder(ctree, folder->inbox, root, &prev);
1800 set_special_folder(ctree, folder->outbox, root, &prev);
1801 set_special_folder(ctree, folder->draft, root, &prev);
1802 set_special_folder(ctree, folder->queue, root, &prev);
1803 set_special_folder(ctree, folder->trash, root, &prev);
1806 static void folderview_append_folder(FolderView *folderview, Folder *folder)
1808 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1811 g_return_if_fail(folder != NULL);
1813 root = gtk_sctree_insert_gnode(ctree, NULL, NULL, folder->node,
1814 folderview_gnode_func, folderview);
1815 gtk_ctree_pre_recursive(ctree, root, folderview_expand_func,
1817 folderview_sort_folders(folderview, root, folder);
1820 /* callback functions */
1821 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
1822 GdkEventButton *event)
1824 GtkCList *clist = GTK_CLIST(folderview->ctree);
1827 FolderViewPopup *fpopup;
1828 GtkItemFactory *fpopup_factory;
1830 FolderItem *special_trash = NULL, *special_queue = NULL;
1834 item = gtk_clist_get_row_data(clist, row);
1836 item = folderview_get_selected_item(folderview);
1838 g_return_if_fail(item != NULL);
1839 g_return_if_fail(item->folder != NULL);
1840 folder = item->folder;
1842 fpopup = g_hash_table_lookup(folderview_popups, folder->klass->idstr);
1844 fpopup_factory = g_hash_table_lookup(folderview->popups, folder->klass->idstr);
1846 fpopup = g_hash_table_lookup(folderview_popups, "common");
1847 fpopup_factory = g_hash_table_lookup(folderview->popups, "common");
1850 if (fpopup->set_sensitivity != NULL)
1851 fpopup->set_sensitivity(fpopup_factory, item);
1853 if (NULL != (ac = account_find_from_item(item))) {
1854 special_trash = account_get_special_folder(ac, F_TRASH);
1855 special_queue = account_get_special_folder(ac, F_QUEUE);
1858 if ((item == folder->trash || item == special_trash
1859 || folder_has_parent_of_type(item, F_TRASH)) &&
1860 gtk_item_factory_get_item(fpopup_factory, "/Empty trash...") == NULL) {
1861 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[0], folderview, 1);
1862 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[1], folderview, 1);
1863 } else if (item != folder->trash && (special_trash == NULL || item != special_trash)
1864 && !folder_has_parent_of_type(item, F_TRASH)) {
1865 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[0]);
1866 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[1]);
1869 if ((item == folder->queue || item == special_queue
1870 || folder_has_parent_of_type(item, F_QUEUE)) &&
1871 gtk_item_factory_get_item(fpopup_factory, "/Send queue...") == NULL) {
1872 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[0], folderview, 1);
1873 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[1], folderview, 1);
1874 } else if (item != folder->queue && (special_queue == NULL || item != special_queue)
1875 && !folder_has_parent_of_type(item, F_QUEUE)) {
1876 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[0]);
1877 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[1]);
1880 #define SET_SENS(name, sens) \
1881 menu_set_sensitive(fpopup_factory, name, sens)
1883 SET_SENS("/Mark all read", item->unread_msgs >= 1);
1884 SET_SENS("/Search folder...", item->total_msgs >= 1 &&
1885 folderview->selected == folderview->opened);
1886 SET_SENS("/Properties...", TRUE);
1887 SET_SENS("/Processing...", item->node->parent != NULL);
1888 if (item == folder->trash || item == special_trash
1889 || folder_has_parent_of_type(item, F_TRASH)) {
1890 GSList *msglist = folder_item_get_msg_list(item);
1891 SET_SENS("/Empty trash...", msglist != NULL);
1892 procmsg_msg_list_free(msglist);
1894 if (item == folder->queue || item == special_queue
1895 || folder_has_parent_of_type(item, F_QUEUE)) {
1896 GSList *msglist = folder_item_get_msg_list(item);
1897 SET_SENS("/Send queue...", msglist != NULL);
1898 procmsg_msg_list_free(msglist);
1902 popup = gtk_item_factory_get_widget(fpopup_factory, fpopup->path);
1903 gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
1904 event->button, event->time);
1909 static gboolean folderview_button_pressed(GtkWidget *ctree, GdkEventButton *event,
1910 FolderView *folderview)
1912 GtkCList *clist = GTK_CLIST(ctree);
1913 gint prev_row = -1, row = -1, column = -1;
1915 if (!event) return FALSE;
1917 if (event->button == 1 || event->button == 2) {
1918 folderview->open_folder = TRUE;
1920 if (event->type == GDK_2BUTTON_PRESS) {
1921 if (clist->selection) {
1924 node = GTK_CTREE_NODE(clist->selection->data);
1926 gtk_ctree_toggle_expansion(
1934 if (event->button == 2 || event->button == 3) {
1936 if (clist->selection) {
1939 node = GTK_CTREE_NODE(clist->selection->data);
1941 prev_row = gtkut_ctree_get_nth_from_node
1942 (GTK_CTREE(ctree), node);
1945 if (!gtk_clist_get_selection_info(clist, event->x, event->y,
1948 if (prev_row != row) {
1949 gtk_clist_unselect_all(clist);
1950 if (event->button == 2)
1951 folderview_select_node
1953 gtk_ctree_node_nth(GTK_CTREE(ctree),
1956 gtk_clist_select_row(clist, row, column);
1960 if (event->button != 3) return FALSE;
1962 folderview_set_sens_and_popup_menu(folderview, row, event);
1966 static gboolean folderview_button_released(GtkWidget *ctree, GdkEventButton *event,
1967 FolderView *folderview)
1969 if (!event) return FALSE;
1971 if (event->button == 1 && folderview->open_folder == FALSE &&
1972 folderview->opened != NULL) {
1973 gtkut_ctree_set_focus_row(GTK_CTREE(ctree),
1974 folderview->opened);
1975 gtk_ctree_select(GTK_CTREE(ctree), folderview->opened);
1981 static gboolean folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
1982 FolderView *folderview)
1984 if (!event) return FALSE;
1986 if (quicksearch_has_focus(folderview->summaryview->quicksearch))
1989 switch (event->keyval) {
1991 if (folderview->selected) {
1992 folderview_select_node(folderview,
1993 folderview->selected);
1997 if (folderview->selected) {
1998 if (folderview->opened == folderview->selected &&
1999 (!folderview->summaryview->folder_item ||
2000 folderview->summaryview->folder_item->total_msgs == 0))
2001 folderview_select_next_unread(folderview);
2003 folderview_select_node(folderview,
2004 folderview->selected);
2014 typedef struct _PostponedSelectData
2019 FolderView *folderview;
2020 } PostponedSelectData;
2022 static gboolean postpone_select(void *data)
2024 PostponedSelectData *psdata = (PostponedSelectData *)data;
2025 debug_print("trying again\n");
2026 psdata->folderview->open_folder = TRUE;
2027 main_window_cursor_normal(psdata->folderview->mainwin);
2028 STATUSBAR_POP(psdata->folderview->mainwin);
2029 folderview_selected(psdata->ctree, psdata->row,
2030 psdata->column, psdata->folderview);
2035 static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row,
2036 gint column, FolderView *folderview)
2038 static gboolean can_select = TRUE; /* exclusive lock */
2043 START_TIMING("--- folderview_selected");
2044 folderview->selected = row;
2046 if (folderview->opened == row) {
2047 folderview->open_folder = FALSE;
2052 if (!can_select || summary_is_locked(folderview->summaryview)) {
2053 if (folderview->opened) {
2054 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2055 gtk_ctree_select(ctree, folderview->opened);
2061 if (!folderview->open_folder) {
2065 item = gtk_ctree_node_get_row_data(ctree, row);
2066 if (!item || item->no_select) {
2073 /* Save cache for old folder */
2074 /* We don't want to lose all caches if sylpheed crashed */
2075 if (folderview->opened) {
2076 FolderItem *olditem;
2078 olditem = gtk_ctree_node_get_row_data(ctree, folderview->opened);
2080 buf = g_strdup_printf(_("Closing Folder %s..."),
2081 olditem->path ? olditem->path:olditem->name);
2082 /* will be null if we just moved the previously opened folder */
2083 STATUSBAR_PUSH(folderview->mainwin, buf);
2084 main_window_cursor_wait(folderview->mainwin);
2086 summary_save_prefs_to_folderitem(folderview->summaryview, olditem);
2087 summary_show(folderview->summaryview, NULL);
2088 folder_item_close(olditem);
2089 main_window_cursor_normal(folderview->mainwin);
2090 STATUSBAR_POP(folderview->mainwin);
2094 /* CLAWS: set compose button type: news folder items
2095 * always have a news folder as parent */
2097 toolbar_set_compose_button
2098 (folderview->mainwin->toolbar,
2099 FOLDER_TYPE(item->folder) == F_NEWS ?
2100 COMPOSEBUTTON_NEWS : COMPOSEBUTTON_MAIL);
2103 debug_print("Folder %s is selected\n", item->path);
2105 if (!GTK_CTREE_ROW(row)->children)
2106 gtk_ctree_expand(ctree, row);
2107 if (folderview->opened &&
2108 !GTK_CTREE_ROW(folderview->opened)->children)
2109 gtk_ctree_collapse(ctree, folderview->opened);
2111 /* ungrab the mouse event */
2112 if (GTK_WIDGET_HAS_GRAB(ctree)) {
2113 gtk_grab_remove(GTK_WIDGET(ctree));
2114 if (gdk_pointer_is_grabbed())
2115 gdk_pointer_ungrab(GDK_CURRENT_TIME);
2119 buf = g_strdup_printf(_("Opening Folder %s..."), item->path ?
2120 item->path : "(null)");
2121 debug_print("%s\n", buf);
2122 STATUSBAR_PUSH(folderview->mainwin, buf);
2125 main_window_cursor_wait(folderview->mainwin);
2127 res = folder_item_open(item);
2129 main_window_cursor_normal(folderview->mainwin);
2130 STATUSBAR_POP(folderview->mainwin);
2132 alertpanel_error(_("Folder could not be opened."));
2134 folderview->open_folder = FALSE;
2138 } else if (res == -2) {
2139 PostponedSelectData *data = g_new0(PostponedSelectData, 1);
2140 data->ctree = ctree;
2142 data->column = column;
2143 data->folderview = folderview;
2144 debug_print("postponing open of %s till end of scan\n",
2145 item->path ? item->path:item->name);
2146 folderview->open_folder = FALSE;
2148 g_timeout_add(500, postpone_select, data);
2153 main_window_cursor_normal(folderview->mainwin);
2156 summary_set_prefs_from_folderitem(folderview->summaryview, item);
2157 opened = summary_show(folderview->summaryview, item);
2159 folder_clean_cache_memory(item);
2162 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2163 gtk_ctree_select(ctree, folderview->opened);
2165 folderview->opened = row;
2166 if (gtk_ctree_node_is_visible(ctree, row)
2167 != GTK_VISIBILITY_FULL)
2168 gtk_ctree_node_moveto(ctree, row, -1, 0.5, 0);
2171 STATUSBAR_POP(folderview->mainwin);
2173 folderview->open_folder = FALSE;
2178 static void folderview_tree_expanded(GtkCTree *ctree, GtkCTreeNode *node,
2179 FolderView *folderview)
2183 item = gtk_ctree_node_get_row_data(ctree, node);
2184 g_return_if_fail(item != NULL);
2185 item->collapsed = FALSE;
2186 folderview_update_node(folderview, node);
2189 static void folderview_tree_collapsed(GtkCTree *ctree, GtkCTreeNode *node,
2190 FolderView *folderview)
2194 item = gtk_ctree_node_get_row_data(ctree, node);
2195 g_return_if_fail(item != NULL);
2196 item->collapsed = TRUE;
2197 folderview_update_node(folderview, node);
2200 static void folderview_popup_close(GtkMenuShell *menu_shell,
2201 FolderView *folderview)
2203 if (!folderview->opened) return;
2205 gtk_ctree_select(GTK_CTREE(folderview->ctree), folderview->opened);
2208 static void folderview_col_resized(GtkCList *clist, gint column, gint width,
2209 FolderView *folderview)
2211 FolderColumnType type = folderview->col_state[column].type;
2213 prefs_common.folder_col_size[type] = width;
2216 void folderview_create_folder_node_recursive(FolderView *folderview, FolderItem *item)
2220 folderview_create_folder_node(folderview, item);
2222 if (!item || !item->folder || !item->folder->node)
2225 srcnode = item->folder->node;
2226 srcnode = g_node_find(srcnode, G_PRE_ORDER, G_TRAVERSE_ALL, item);
2227 srcnode = srcnode->children;
2228 while (srcnode != NULL) {
2229 if (srcnode && srcnode->data) {
2230 FolderItem *next_item = (FolderItem*) srcnode->data;
2231 folderview_create_folder_node_recursive(folderview, next_item);
2233 srcnode = srcnode->next;
2237 void folderview_create_folder_node(FolderView *folderview, FolderItem *item)
2239 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2240 gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
2241 GtkCTreeNode *node, *parent_node;
2242 gint *col_pos = folderview->col_pos;
2243 FolderItemUpdateData hookdata;
2245 parent_node = gtk_ctree_find_by_row_data(ctree, NULL, folder_item_parent(item));
2246 if (parent_node == NULL)
2249 gtk_clist_freeze(GTK_CLIST(ctree));
2251 text[col_pos[F_COL_FOLDER]] = item->name;
2252 node = gtk_sctree_insert_node(ctree, parent_node, NULL, text,
2254 folderxpm, folderxpmmask,
2255 folderopenxpm, folderopenxpmmask,
2257 gtk_ctree_expand(ctree, parent_node);
2258 gtk_ctree_node_set_row_data(ctree, node, item);
2260 gtk_ctree_node_set_row_style(ctree, node, normal_style);
2261 folderview_sort_folders(folderview, parent_node, item->folder);
2263 hookdata.item = item;
2264 hookdata.update_flags = F_ITEM_UPDATE_NAME;
2265 hookdata.msg = NULL;
2266 hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &hookdata);
2268 gtk_clist_thaw(GTK_CLIST(ctree));
2271 static void folderview_empty_trash_cb(FolderView *folderview, guint action,
2274 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2276 GSList *mlist = NULL;
2278 FolderItem *special_trash = NULL;
2281 if (!folderview->selected) return;
2282 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2283 g_return_if_fail(item != NULL);
2284 g_return_if_fail(item->folder != NULL);
2286 if (NULL != (ac = account_find_from_item(item)))
2287 special_trash = account_get_special_folder(ac, F_TRASH);
2289 if (item != item->folder->trash && item != special_trash
2290 && !folder_has_parent_of_type(item, F_TRASH)) return;
2292 if (prefs_common.ask_on_clean) {
2293 if (alertpanel(_("Empty trash"),
2294 _("Delete all messages in trash?"),
2295 GTK_STOCK_CANCEL, _("+_Empty trash"), NULL) != G_ALERTALTERNATE)
2299 mlist = folder_item_get_msg_list(item);
2301 for (cur = mlist ; cur != NULL ; cur = cur->next) {
2302 MsgInfo * msginfo = (MsgInfo *) cur->data;
2303 if (MSG_IS_LOCKED(msginfo->flags))
2305 /* is it partially received? (partial_recv isn't cached) */
2306 if (msginfo->total_size != 0 &&
2307 msginfo->size != (off_t)msginfo->total_size)
2308 partial_mark_for_delete(msginfo);
2310 procmsg_msg_list_free(mlist);
2312 folder_item_remove_all_msg(item);
2315 static void folderview_send_queue_cb(FolderView *folderview, guint action,
2318 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2320 FolderItem *special_queue = NULL;
2322 gchar *errstr = NULL;
2324 if (!folderview->selected) return;
2325 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2326 g_return_if_fail(item != NULL);
2327 g_return_if_fail(item->folder != NULL);
2329 if (NULL != (ac = account_find_from_item(item)))
2330 special_queue = account_get_special_folder(ac, F_QUEUE);
2332 if (item != item->folder->queue && item != special_queue
2333 && !folder_has_parent_of_type(item, F_QUEUE)) return;
2335 if (procmsg_queue_is_empty(item))
2338 if (prefs_common.work_offline)
2339 if (alertpanel(_("Offline warning"),
2340 _("You're working offline. Override?"),
2341 GTK_STOCK_NO, GTK_STOCK_YES,
2342 NULL) != G_ALERTALTERNATE)
2345 /* ask for confirmation before sending queued messages only
2346 in online mode and if there is at least one message queued
2347 in any of the folder queue
2349 if (prefs_common.confirm_send_queued_messages) {
2350 if (!prefs_common.work_offline) {
2351 if (alertpanel(_("Send queued messages"),
2352 _("Send all queued messages?"),
2353 GTK_STOCK_CANCEL, _("_Send"),
2354 NULL) != G_ALERTALTERNATE)
2359 if (procmsg_send_queue(item, prefs_common.savemsg, &errstr) < 0) {
2361 alertpanel_error_log(_("Some errors occurred while "
2362 "sending queued messages."));
2364 gchar *tmp = g_strdup_printf(_("Some errors occurred "
2365 "while sending queued messages:\n%s"), errstr);
2367 alertpanel_error_log(tmp);
2373 static void folderview_search_cb(FolderView *folderview, guint action,
2376 summary_search(folderview->summaryview);
2379 static void folderview_property_cb(FolderView *folderview, guint action,
2382 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2385 if (!folderview->selected) return;
2387 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2388 g_return_if_fail(item != NULL);
2389 g_return_if_fail(item->folder != NULL);
2391 prefs_folder_item_open(item);
2394 static void folderview_recollapse_nodes(FolderView *folderview, GtkCTreeNode *node)
2396 GSList *list = NULL;
2397 GSList *done = NULL;
2398 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2400 for (list = folderview->nodes_to_recollapse; list != NULL; list = g_slist_next(list)) {
2401 if (!gtkut_ctree_node_is_parent(GTK_CTREE_NODE(list->data), node)
2402 && list->data != node) {
2403 gtk_ctree_collapse(ctree, GTK_CTREE_NODE(list->data));
2404 done = g_slist_append(done, GTK_CTREE_NODE(list->data));
2407 for (list = done; list != NULL; list = g_slist_next(list)) {
2408 folderview->nodes_to_recollapse = g_slist_remove(folderview->nodes_to_recollapse,
2414 void folderview_move_folder(FolderView *folderview, FolderItem *from_folder,
2415 FolderItem *to_folder)
2417 FolderItem *from_parent = NULL;
2418 FolderItem *new_folder = NULL;
2419 GtkCTreeNode *src_node = NULL;
2423 g_return_if_fail(folderview != NULL);
2424 g_return_if_fail(from_folder != NULL);
2425 g_return_if_fail(to_folder != NULL);
2427 src_node = gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree), NULL, from_folder);
2428 from_parent = folder_item_parent(from_folder);
2430 if (prefs_common.warn_dnd) {
2431 buf = g_strdup_printf(_("Do you really want to make folder '%s' a "
2432 "sub-folder of '%s' ?"), from_folder->name,
2434 status = alertpanel_full(_("Move folder"), buf,
2435 GTK_STOCK_NO, GTK_STOCK_YES, NULL, TRUE,
2436 NULL, ALERT_QUESTION, G_ALERTDEFAULT);
2439 if ((status & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
2441 else if (status & G_ALERTDISABLE)
2442 prefs_common.warn_dnd = FALSE;
2445 buf = g_strdup_printf(_("Moving %s to %s..."), from_folder->name, to_folder->name);
2446 STATUSBAR_PUSH(folderview->mainwin, buf);
2448 summary_clear_all(folderview->summaryview);
2449 folderview->opened = NULL;
2450 folderview->selected = NULL;
2451 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), FALSE);
2453 main_window_cursor_wait(folderview->mainwin);
2454 statusbar_verbosity_set(TRUE);
2455 folder_item_update_freeze();
2456 if ((status = folder_item_move_to(from_folder, to_folder, &new_folder)) == F_MOVE_OK) {
2457 statusbar_verbosity_set(FALSE);
2458 main_window_cursor_normal(folderview->mainwin);
2459 STATUSBAR_POP(folderview->mainwin);
2460 folder_item_update_thaw();
2461 folder_item_update_recursive(new_folder, F_ITEM_UPDATE_MSGCNT);
2463 folderview_sort_folders(folderview,
2464 gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree),
2465 NULL, to_folder), new_folder->folder);
2466 folderview_select(folderview, new_folder);
2468 statusbar_verbosity_set(FALSE);
2469 main_window_cursor_normal(folderview->mainwin);
2470 STATUSBAR_POP(folderview->mainwin);
2471 folder_item_update_thaw();
2473 case F_MOVE_FAILED_DEST_IS_PARENT:
2474 alertpanel_error(_("Source and destination are the same."));
2476 case F_MOVE_FAILED_DEST_IS_CHILD:
2477 alertpanel_error(_("Can't move a folder to one of its children."));
2479 case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX:
2480 alertpanel_error(_("Folder moving cannot be done between different mailboxes."));
2483 alertpanel_error(_("Move failed!"));
2488 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), TRUE);
2491 static gint folderview_clist_compare(GtkCList *clist,
2492 gconstpointer ptr1, gconstpointer ptr2)
2494 FolderItem *item1 = ((GtkCListRow *)ptr1)->data;
2495 FolderItem *item2 = ((GtkCListRow *)ptr2)->data;
2498 return (item2->name != NULL);
2502 return g_utf8_collate(item1->name, item2->name);
2505 static void folderview_processing_cb(FolderView *folderview, guint action,
2508 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2512 if (!folderview->selected) return;
2514 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2515 g_return_if_fail(item != NULL);
2516 g_return_if_fail(item->folder != NULL);
2518 id = folder_item_get_identifier(item);
2519 title = g_strdup_printf (_("Processing configuration for folder %s"), id);
2522 prefs_filtering_open(&item->prefs->processing, title,
2523 MANUAL_ANCHOR_PROCESSING, NULL, NULL, FALSE);
2527 void folderview_set_target_folder_color(gint color_op)
2531 FolderView *folderview;
2533 for (list = folderview_list; list != NULL; list = list->next) {
2534 folderview = (FolderView *)list->data;
2535 gtkut_convert_int_to_gdk_color(color_op, &folderview->color_op);
2537 bold_tgtfold_style->fg[GTK_STATE_NORMAL] =
2538 folderview->color_op;
2544 static gchar *last_font = NULL;
2545 void folderview_reflect_prefs_pixmap_theme(FolderView *folderview)
2553 void folderview_reflect_prefs(void)
2555 gboolean update_font = TRUE;
2556 FolderView *folderview = mainwindow_get_mainwindow()->folderview;
2557 FolderItem *item = folderview_get_selected_item(folderview);
2558 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2559 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2560 gint height = pos->value;
2562 if (last_font && !strcmp(last_font, NORMAL_FONT))
2563 update_font = FALSE;
2566 last_font = g_strdup(NORMAL_FONT);
2569 normal_style = normal_color_style = bold_style =
2570 bold_color_style = bold_tgtfold_style = NULL;
2572 folderview_init(folderview);
2574 gtk_clist_freeze(GTK_CLIST(folderview->ctree));
2575 folderview_column_set_titles(folderview);
2576 folderview_set_all();
2578 g_signal_handlers_block_by_func
2579 (G_OBJECT(folderview->ctree),
2580 G_CALLBACK(folderview_selected), folderview);
2583 GtkCTreeNode *node = gtk_ctree_find_by_row_data(
2584 GTK_CTREE(folderview->ctree), NULL, item);
2586 folderview_select(folderview, item);
2587 folderview->selected = node;
2590 g_signal_handlers_unblock_by_func
2591 (G_OBJECT(folderview->ctree),
2592 G_CALLBACK(folderview_selected), folderview);
2594 pos = gtk_scrolled_window_get_vadjustment(
2595 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2596 gtk_adjustment_set_value(pos, height);
2597 gtk_clist_thaw(GTK_CLIST(folderview->ctree));
2600 static void drag_state_stop(FolderView *folderview)
2602 if (folderview->drag_timer)
2603 gtk_timeout_remove(folderview->drag_timer);
2604 folderview->drag_timer = 0;
2605 folderview->drag_node = NULL;
2608 static gint folderview_defer_expand(FolderView *folderview)
2610 if (folderview->drag_node) {
2611 folderview_recollapse_nodes(folderview, folderview->drag_node);
2612 if (folderview->drag_item->collapsed) {
2613 gtk_ctree_expand(GTK_CTREE(folderview->ctree), folderview->drag_node);
2614 folderview->nodes_to_recollapse = g_slist_append
2615 (folderview->nodes_to_recollapse, folderview->drag_node);
2618 folderview->drag_item = NULL;
2619 folderview->drag_timer = 0;
2623 static void drag_state_start(FolderView *folderview, GtkCTreeNode *node, FolderItem *item)
2625 /* the idea is that we call drag_state_start() whenever we want expansion to
2626 * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
2627 * we need to call drag_state_stop() */
2628 drag_state_stop(folderview);
2629 /* request expansion */
2630 if (0 != (folderview->drag_timer = gtk_timeout_add
2631 (prefs_common.hover_timeout,
2632 (GtkFunction)folderview_defer_expand,
2634 folderview->drag_node = node;
2635 folderview->drag_item = item;
2639 static void folderview_start_drag(GtkWidget *widget, gint button, GdkEvent *event,
2640 FolderView *folderview)
2642 GdkDragContext *context;
2644 g_return_if_fail(folderview != NULL);
2645 if (folderview->selected == NULL) return;
2646 if (folderview->nodes_to_recollapse)
2647 g_slist_free(folderview->nodes_to_recollapse);
2648 folderview->nodes_to_recollapse = NULL;
2649 context = gtk_drag_begin(widget, folderview->target_list,
2650 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
2651 gtk_drag_set_icon_default(context);
2654 static void folderview_drag_data_get(GtkWidget *widget,
2655 GdkDragContext *drag_context,
2656 GtkSelectionData *selection_data,
2659 FolderView *folderview)
2663 gchar *source = NULL;
2664 if (info == TARGET_DUMMY) {
2665 for (cur = GTK_CLIST(folderview->ctree)->selection;
2666 cur != NULL; cur = cur->next) {
2667 item = gtk_ctree_node_get_row_data
2668 (GTK_CTREE(folderview->ctree),
2669 GTK_CTREE_NODE(cur->data));
2671 source = g_strdup_printf ("FROM_OTHER_FOLDER%s", folder_item_get_identifier(item));
2672 gtk_selection_data_set(selection_data,
2673 selection_data->target, 8,
2674 source, strlen(source));
2680 g_warning("unknown info %d\n", info);
2684 gboolean folderview_update_folder(gpointer source, gpointer userdata)
2686 FolderUpdateData *hookdata;
2687 FolderView *folderview;
2691 folderview = (FolderView *) userdata;
2692 g_return_val_if_fail(hookdata != NULL, FALSE);
2693 g_return_val_if_fail(folderview != NULL, FALSE);
2695 ctree = folderview->ctree;
2696 g_return_val_if_fail(ctree != NULL, FALSE);
2698 if (hookdata->update_flags & FOLDER_ADD_FOLDERITEM)
2699 folderview_create_folder_node(folderview, hookdata->item);
2700 else if (hookdata->update_flags & FOLDER_RENAME_FOLDERITEM) {
2701 GtkCTreeNode *node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree),
2702 NULL, folder_item_parent(hookdata->item));
2703 folderview_sort_folders(folderview, node, hookdata->folder);
2704 } else if (hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM) {
2707 node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree), NULL, hookdata->item);
2709 gtk_ctree_remove_node(GTK_CTREE(ctree), node);
2710 } else if (hookdata->update_flags & (FOLDER_TREE_CHANGED | FOLDER_ADD_FOLDER | FOLDER_REMOVE_FOLDER))
2711 folderview_set(folderview);
2716 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
2717 GdkDragContext *context,
2721 FolderView *folderview)
2724 FolderItem *item = NULL, *src_item = NULL;
2725 GtkCTreeNode *node = NULL;
2726 gboolean acceptable = FALSE;
2727 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2728 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2729 int height = (int)pos->page_size;
2730 int total_height = (int)pos->upper;
2731 int vpos = (int) pos->value;
2733 if (gtk_clist_get_selection_info
2734 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
2735 GtkWidget *srcwidget;
2737 if (y > height - 24 && height + vpos < total_height)
2738 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
2740 if (y < 48 && y > 0)
2741 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
2743 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2744 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2745 src_item = folderview->summaryview->folder_item;
2747 srcwidget = gtk_drag_get_source_widget(context);
2748 if (srcwidget == folderview->summaryview->ctree) {
2749 /* comes from summaryview */
2750 /* we are copying messages, so only accept folder items that are not
2751 the source item, are no root items and can copy messages */
2752 if (item && item->folder && folder_item_parent(item) != NULL && src_item &&
2753 src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)
2755 } else if (srcwidget == folderview->ctree) {
2756 /* comes from folderview */
2757 /* we are moving folder items, only accept folders that are not
2758 the source items and can copy messages and create folder items */
2759 if (item && item->folder && src_item && src_item != item &&
2760 FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2761 FOLDER_CLASS(item->folder)->create_folder != NULL)
2764 /* comes from another app */
2765 /* we are adding messages, so only accept folder items that are
2766 no root items and can copy messages */
2767 if (item && item->folder && folder_item_parent(item) != NULL
2768 && FOLDER_CLASS(item->folder)->add_msg != NULL)
2773 if (acceptable || (src_item && src_item == item))
2774 drag_state_start(folderview, node, item);
2777 g_signal_handlers_block_by_func
2779 G_CALLBACK(folderview_selected), folderview);
2780 gtk_ctree_select(GTK_CTREE(widget), node);
2781 g_signal_handlers_unblock_by_func
2783 G_CALLBACK(folderview_selected), folderview);
2784 gdk_drag_status(context,
2785 (context->actions == GDK_ACTION_COPY ?
2786 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
2788 if (folderview->opened)
2789 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2790 gdk_drag_status(context, 0, time);
2796 static void folderview_drag_leave_cb(GtkWidget *widget,
2797 GdkDragContext *context,
2799 FolderView *folderview)
2801 drag_state_stop(folderview);
2802 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2805 static void free_info (gpointer stuff, gpointer data)
2810 void folderview_finish_dnd(const gchar *data, GdkDragContext *drag_context,
2811 guint time, FolderItem *item)
2814 GSList *msglist = NULL;
2815 list = uri_list_extract_filenames(data);
2816 if (!(item && item->folder && folder_item_parent(item) != NULL
2817 && FOLDER_CLASS(item->folder)->add_msg != NULL))
2819 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2823 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2826 for (tmp = list; tmp != NULL; tmp = tmp->next) {
2827 MsgFileInfo *info = NULL;
2829 if (file_is_email((gchar *)tmp->data)) {
2830 info = g_new0(MsgFileInfo, 1);
2831 info->msginfo = NULL;
2832 info->file = (gchar *)tmp->data;
2833 msglist = g_slist_prepend(msglist, info);
2837 msglist = g_slist_reverse(msglist);
2838 folder_item_add_msgs(item, msglist, FALSE);
2839 g_slist_foreach(msglist, free_info, NULL);
2840 g_slist_free(msglist);
2841 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2843 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2845 list_free_strings(list);
2849 static void folderview_drag_received_cb(GtkWidget *widget,
2850 GdkDragContext *drag_context,
2853 GtkSelectionData *data,
2856 FolderView *folderview)
2859 FolderItem *item = NULL, *src_item;
2862 if (info == TARGET_DUMMY) {
2863 drag_state_stop(folderview);
2864 if ((void *)strstr(data->data, "FROM_OTHER_FOLDER") != (void *)data->data) {
2865 /* comes from summaryview */
2866 if (gtk_clist_get_selection_info
2867 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2870 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2871 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2872 src_item = folderview->summaryview->folder_item;
2874 /* re-check (due to acceptable possibly set for folder moves */
2875 if (!(item && item->folder && item->path && !item->no_select &&
2876 src_item && src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)) {
2879 if (item && src_item) {
2880 switch (drag_context->action) {
2881 case GDK_ACTION_COPY:
2882 summary_copy_selected_to(folderview->summaryview, item);
2883 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2885 case GDK_ACTION_MOVE:
2886 case GDK_ACTION_DEFAULT:
2888 if (FOLDER_CLASS(src_item->folder)->remove_msg == NULL)
2889 summary_copy_selected_to(folderview->summaryview, item);
2891 summary_move_selected_to(folderview->summaryview, item);
2892 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2895 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2897 /* comes from folderview */
2899 gboolean folder_is_normal = TRUE;
2901 source = data->data + 17;
2902 if (gtk_clist_get_selection_info
2903 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0
2905 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2908 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2909 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2910 src_item = folder_find_item_from_identifier(source);
2914 src_item->stype == F_NORMAL &&
2915 !folder_has_parent_of_type(src_item, F_OUTBOX) &&
2916 !folder_has_parent_of_type(src_item, F_DRAFT) &&
2917 !folder_has_parent_of_type(src_item, F_QUEUE) &&
2918 !folder_has_parent_of_type(src_item, F_TRASH);
2919 if (!item || item->no_select || !src_item
2920 || !folder_is_normal) {
2921 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2925 folderview_move_folder(folderview, src_item, item);
2926 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2928 folderview->nodes_to_recollapse = NULL;
2929 } else if (info == TARGET_MAIL_URI_LIST) {
2930 if (gtk_clist_get_selection_info
2931 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2934 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2936 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2939 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2941 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2944 folderview_finish_dnd(data->data, drag_context, time, item);
2948 static void folderview_drag_end_cb(GtkWidget *widget,
2949 GdkDragContext *drag_context,
2950 FolderView *folderview)
2952 drag_state_stop(folderview);
2953 g_slist_free(folderview->nodes_to_recollapse);
2954 folderview->nodes_to_recollapse = NULL;
2957 void folderview_register_popup(FolderViewPopup *fpopup)
2961 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2962 FolderView *folderview = folderviews->data;
2963 GtkItemFactory *factory;
2965 factory = create_ifactory(folderview, fpopup);
2966 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
2968 g_hash_table_insert(folderview_popups, fpopup->klass, fpopup);
2971 void folderview_unregister_popup(FolderViewPopup *fpopup)
2975 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2976 FolderView *folderview = folderviews->data;
2978 g_hash_table_remove(folderview->popups, fpopup->klass);
2980 g_hash_table_remove(folderview_popups, fpopup->klass);