2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2007 Hiroyuki Yamamoto and the Claws Mail 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"
73 #define COL_FOLDER_WIDTH 150
74 #define COL_NUM_WIDTH 32
76 static GList *folderview_list = NULL;
78 static GtkStyle *normal_style;
79 static GtkStyle *normal_color_style;
80 static GtkStyle *bold_style;
81 static GtkStyle *bold_color_style;
82 static GtkStyle *bold_tgtfold_style;
84 static GdkPixmap *inboxxpm;
85 static GdkBitmap *inboxxpmmask;
86 static GdkPixmap *inboxhrmxpm;
87 static GdkBitmap *inboxhrmxpmmask;
88 static GdkPixmap *inboxopenxpm;
89 static GdkBitmap *inboxopenxpmmask;
90 static GdkPixmap *inboxopenhrmxpm;
91 static GdkBitmap *inboxopenhrmxpmmask;
92 static GdkPixmap *outboxxpm;
93 static GdkBitmap *outboxxpmmask;
94 static GdkPixmap *outboxhrmxpm;
95 static GdkBitmap *outboxhrmxpmmask;
96 static GdkPixmap *outboxopenxpm;
97 static GdkBitmap *outboxopenxpmmask;
98 static GdkPixmap *outboxopenhrmxpm;
99 static GdkBitmap *outboxopenhrmxpmmask;
100 static GdkPixmap *folderxpm;
101 static GdkBitmap *folderxpmmask;
102 static GdkPixmap *folderhrmxpm;
103 static GdkBitmap *folderhrmxpmmask;
104 static GdkPixmap *folderopenxpm;
105 static GdkBitmap *folderopenxpmmask;
106 static GdkPixmap *folderopenhrmxpm;
107 static GdkBitmap *folderopenhrmxpmmask;
108 static GdkPixmap *trashopenxpm;
109 static GdkBitmap *trashopenxpmmask;
110 static GdkPixmap *trashopenhrmxpm;
111 static GdkBitmap *trashopenhrmxpmmask;
112 static GdkPixmap *trashxpm;
113 static GdkBitmap *trashxpmmask;
114 static GdkPixmap *trashhrmxpm;
115 static GdkBitmap *trashhrmxpmmask;
116 static GdkPixmap *queuexpm;
117 static GdkBitmap *queuexpmmask;
118 static GdkPixmap *queuehrmxpm;
119 static GdkBitmap *queuehrmxpmmask;
120 static GdkPixmap *queueopenxpm;
121 static GdkBitmap *queueopenxpmmask;
122 static GdkPixmap *queueopenhrmxpm;
123 static GdkBitmap *queueopenhrmxpmmask;
124 static GdkPixmap *draftsxpm;
125 static GdkBitmap *draftsxpmmask;
126 static GdkPixmap *draftsopenxpm;
127 static GdkBitmap *draftsopenxpmmask;
128 static GdkPixmap *noselectxpm;
129 static GdkBitmap *noselectxpmmask;
131 static GdkPixmap *m_inboxxpm;
132 static GdkBitmap *m_inboxxpmmask;
133 static GdkPixmap *m_inboxhrmxpm;
134 static GdkBitmap *m_inboxhrmxpmmask;
135 static GdkPixmap *m_inboxopenxpm;
136 static GdkBitmap *m_inboxopenxpmmask;
137 static GdkPixmap *m_inboxopenhrmxpm;
138 static GdkBitmap *m_inboxopenhrmxpmmask;
139 static GdkPixmap *m_outboxxpm;
140 static GdkBitmap *m_outboxxpmmask;
141 static GdkPixmap *m_outboxhrmxpm;
142 static GdkBitmap *m_outboxhrmxpmmask;
143 static GdkPixmap *m_outboxopenxpm;
144 static GdkBitmap *m_outboxopenxpmmask;
145 static GdkPixmap *m_outboxopenhrmxpm;
146 static GdkBitmap *m_outboxopenhrmxpmmask;
147 static GdkPixmap *m_folderxpm;
148 static GdkBitmap *m_folderxpmmask;
149 static GdkPixmap *m_folderhrmxpm;
150 static GdkBitmap *m_folderhrmxpmmask;
151 static GdkPixmap *m_folderopenxpm;
152 static GdkBitmap *m_folderopenxpmmask;
153 static GdkPixmap *m_folderopenhrmxpm;
154 static GdkBitmap *m_folderopenhrmxpmmask;
155 static GdkPixmap *m_trashopenxpm;
156 static GdkBitmap *m_trashopenxpmmask;
157 static GdkPixmap *m_trashopenhrmxpm;
158 static GdkBitmap *m_trashopenhrmxpmmask;
159 static GdkPixmap *m_trashxpm;
160 static GdkBitmap *m_trashxpmmask;
161 static GdkPixmap *m_trashhrmxpm;
162 static GdkBitmap *m_trashhrmxpmmask;
163 static GdkPixmap *m_queuexpm;
164 static GdkBitmap *m_queuexpmmask;
165 static GdkPixmap *m_queuehrmxpm;
166 static GdkBitmap *m_queuehrmxpmmask;
167 static GdkPixmap *m_queueopenxpm;
168 static GdkBitmap *m_queueopenxpmmask;
169 static GdkPixmap *m_queueopenhrmxpm;
170 static GdkBitmap *m_queueopenhrmxpmmask;
171 static GdkPixmap *m_draftsxpm;
172 static GdkBitmap *m_draftsxpmmask;
173 static GdkPixmap *m_draftsopenxpm;
174 static GdkBitmap *m_draftsopenxpmmask;
176 static GdkPixmap *newxpm;
177 static GdkBitmap *newxpmmask;
178 static GdkPixmap *unreadxpm;
179 static GdkBitmap *unreadxpmmask;
180 static GdkPixmap *readxpm;
181 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 static void folderview_create_folder_node (FolderView *folderview,
277 static gboolean folderview_update_folder (gpointer source,
279 static 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 {"/---", NULL, NULL, 0, "<Separator>"},
292 {N_("/_Search folder..."), NULL, folderview_search_cb, 0, NULL},
293 {N_("/_Properties..."), NULL, folderview_property_cb, 0, NULL},
294 {N_("/Process_ing..."), NULL, folderview_processing_cb, 0, NULL},
297 static GtkItemFactoryEntry folder_view_trash_popup_entries[] = {
298 {"/------trashsep", NULL, NULL, 0, "<Separator>"},
299 {N_("/Empty _trash..."), NULL, folderview_empty_trash_cb, 0, NULL},
302 static GtkItemFactoryEntry folder_view_queue_popup_entries[] = {
303 {"/------queuesep", NULL, NULL, 0, "<Separator>"},
304 {N_("/Send _queue..."), NULL, folderview_send_queue_cb, 0, NULL},
308 GtkTargetEntry folderview_drag_types[] =
310 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY},
311 {"text/uri-list", 0, TARGET_MAIL_URI_LIST}
314 void folderview_initialize(void)
316 FolderViewPopup *fpopup;
318 GSList *entries = NULL;
320 fpopup = g_new0(FolderViewPopup, 1);
322 n_entries = sizeof(folderview_common_popup_entries) /
323 sizeof(folderview_common_popup_entries[0]);
324 for (i = 0; i < n_entries; i++)
325 entries = g_slist_append(entries, &folderview_common_popup_entries[i]);
327 fpopup->klass = "common";
328 fpopup->path = "<CommonFolder>";
329 fpopup->entries = entries;
330 fpopup->set_sensitivity = NULL;
332 folderview_popups = g_hash_table_new(g_str_hash, g_str_equal);
333 g_hash_table_insert(folderview_popups, "common", fpopup);
336 static GtkItemFactory *create_ifactory(FolderView *folderview, FolderViewPopup *fpopup)
339 GtkItemFactory *factory;
340 FolderViewPopup *fpopup_common;
343 factory = gtk_item_factory_new(GTK_TYPE_MENU, fpopup->path, NULL);
344 gtk_item_factory_set_translate_func(factory, menu_translate,
347 for (entries = fpopup->entries; entries != NULL; entries = g_slist_next(entries))
348 gtk_item_factory_create_item(factory, entries->data, folderview, 1);
350 fpopup_common = g_hash_table_lookup(folderview_popups, "common");
351 if (fpopup_common != fpopup)
352 for (entries = fpopup_common->entries; entries != NULL; entries = g_slist_next(entries))
353 gtk_item_factory_create_item(factory, entries->data, folderview, 1);
355 popup = gtk_item_factory_get_widget(factory, fpopup->path);
356 g_signal_connect(G_OBJECT(popup), "selection_done",
357 G_CALLBACK(folderview_popup_close),
363 static void create_ifactories(gpointer key, gpointer value, gpointer data)
365 FolderView *folderview = data;
366 FolderViewPopup *fpopup = value;
367 GtkItemFactory *factory;
369 factory = create_ifactory(folderview, fpopup);
370 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
373 static void folderview_column_set_titles(FolderView *folderview)
375 GtkWidget *ctree = folderview->ctree;
376 GtkWidget *label_new;
377 GtkWidget *label_unread;
378 GtkWidget *label_total;
380 GtkWidget *hbox_unread;
381 GtkWidget *hbox_total;
382 gint *col_pos = folderview->col_pos;
384 debug_print("setting titles...\n");
385 gtk_widget_realize(folderview->ctree);
386 gtk_widget_show_all(folderview->scrolledwin);
388 /* CLAWS: titles for "New" and "Unread" show new & unread pixmaps
389 * instead text (text overflows making them unreadable and ugly) */
390 stock_pixmap_gdk(ctree, STOCK_PIXMAP_NEW,
391 &newxpm, &newxpmmask);
392 stock_pixmap_gdk(ctree, STOCK_PIXMAP_UNREAD,
393 &unreadxpm, &unreadxpmmask);
394 stock_pixmap_gdk(ctree, STOCK_PIXMAP_READ,
395 &readxpm, &readxpmmask);
397 label_new = gtk_image_new_from_pixmap(newxpm, newxpmmask);
398 label_unread = gtk_image_new_from_pixmap(unreadxpm, unreadxpmmask);
399 label_total = gtk_image_new_from_pixmap(readxpm, readxpmmask);
401 gtk_clist_column_titles_active(GTK_CLIST(ctree));
403 hbox_new = gtk_hbox_new(FALSE, 4);
404 hbox_unread = gtk_hbox_new(FALSE, 4);
405 hbox_total = gtk_hbox_new(FALSE, 4);
408 gtk_box_pack_start(GTK_BOX(hbox_new), label_new, TRUE, TRUE, 0);
409 gtk_misc_set_alignment (GTK_MISC (label_new), 1, 0.5);
410 gtk_box_pack_start(GTK_BOX(hbox_unread), label_unread, TRUE, TRUE, 0);
411 gtk_misc_set_alignment (GTK_MISC (label_unread), 1, 0.5);
412 gtk_box_pack_start(GTK_BOX(hbox_total), label_total, TRUE, TRUE, 0);
413 gtk_misc_set_alignment (GTK_MISC (label_total), 1, 0.5);
415 gtk_widget_show_all(hbox_new);
416 gtk_widget_show_all(hbox_unread);
417 gtk_widget_show_all(hbox_total);
419 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_NEW],hbox_new);
420 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_UNREAD],hbox_unread);
421 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_TOTAL],hbox_total);
423 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree), col_pos[F_COL_NEW], _("New"));
424 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree), col_pos[F_COL_UNREAD], _("Unread"));
425 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree), col_pos[F_COL_TOTAL], _("Total"));
428 static gboolean folderview_popup_menu(GtkWidget *widget, gpointer data)
430 FolderView *folderview = (FolderView *)data;
431 GdkEventButton event;
432 if (folderview_get_selected_item(folderview) == NULL)
436 event.time = gtk_get_current_event_time();
438 folderview_set_sens_and_popup_menu(folderview, -1,
445 static GtkWidget *folderview_ctree_create(FolderView *folderview)
449 FolderColumnState *col_state;
450 FolderColumnType type;
451 gchar *titles[N_FOLDER_COLS];
453 GtkWidget *scrolledwin = folderview->scrolledwin;
455 debug_print("creating tree...\n");
456 memset(titles, 0, sizeof(titles));
458 col_state = prefs_folder_column_get_config();
459 memset(titles, 0, sizeof(titles));
461 col_pos = folderview->col_pos;
463 for (i = 0; i < N_FOLDER_COLS; i++) {
464 folderview->col_state[i] = col_state[i];
465 type = col_state[i].type;
469 titles[col_pos[F_COL_FOLDER]] = _("Folder");
470 titles[col_pos[F_COL_NEW]] = _("New");
471 titles[col_pos[F_COL_UNREAD]] = _("Unread");
472 /* TRANSLATORS: This in Number sign in American style */
473 titles[col_pos[F_COL_TOTAL]] = _("#");
475 ctree = gtk_sctree_new_with_titles(N_FOLDER_COLS, col_pos[F_COL_FOLDER],
478 gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
479 gtk_clist_set_column_justification(GTK_CLIST(ctree), col_pos[F_COL_NEW],
481 gtk_clist_set_column_justification(GTK_CLIST(ctree),
482 col_pos[F_COL_UNREAD],
484 gtk_clist_set_column_justification(GTK_CLIST(ctree),
485 col_pos[F_COL_TOTAL],
487 if (prefs_common.enable_dotted_lines) {
488 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
489 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
490 GTK_CTREE_EXPANDER_SQUARE);
492 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_NONE);
493 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
494 GTK_CTREE_EXPANDER_TRIANGLE);
497 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
498 gtk_sctree_set_recursive_expand(GTK_SCTREE(ctree), FALSE);
500 gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
501 gtk_clist_set_compare_func(GTK_CLIST(ctree), folderview_clist_compare);
503 /* don't let title buttons take key focus */
504 for (i = 0; i < N_FOLDER_COLS; i++) {
505 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(ctree)->column[i].button,
507 gtk_clist_set_column_width(GTK_CLIST(ctree), col_pos[i],
508 prefs_common.folder_col_size[i]);
509 gtk_clist_set_column_visibility
510 (GTK_CLIST(ctree), i, col_state[i].visible);
513 g_signal_connect(G_OBJECT(ctree), "key_press_event",
514 G_CALLBACK(folderview_key_pressed),
516 g_signal_connect(G_OBJECT(ctree), "button_press_event",
517 G_CALLBACK(folderview_button_pressed),
519 g_signal_connect(G_OBJECT(ctree), "popup-menu",
520 G_CALLBACK(folderview_popup_menu), folderview);
521 g_signal_connect(G_OBJECT(ctree), "button_release_event",
522 G_CALLBACK(folderview_button_released),
524 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
525 G_CALLBACK(folderview_selected), folderview);
526 g_signal_connect(G_OBJECT(ctree), "start_drag",
527 G_CALLBACK(folderview_start_drag), folderview);
528 g_signal_connect(G_OBJECT(ctree), "drag_data_get",
529 G_CALLBACK(folderview_drag_data_get),
532 g_signal_connect_after(G_OBJECT(ctree), "tree_expand",
533 G_CALLBACK(folderview_tree_expanded),
535 g_signal_connect_after(G_OBJECT(ctree), "tree_collapse",
536 G_CALLBACK(folderview_tree_collapsed),
539 g_signal_connect(G_OBJECT(ctree), "resize_column",
540 G_CALLBACK(folderview_col_resized),
544 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
545 folderview_drag_types, 2,
546 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
547 g_signal_connect(G_OBJECT(ctree), "drag_motion",
548 G_CALLBACK(folderview_drag_motion_cb),
550 g_signal_connect(G_OBJECT(ctree), "drag_leave",
551 G_CALLBACK(folderview_drag_leave_cb),
553 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
554 G_CALLBACK(folderview_drag_received_cb),
556 g_signal_connect(G_OBJECT(ctree), "drag_end",
557 G_CALLBACK(folderview_drag_end_cb),
560 gtk_container_add(GTK_CONTAINER(scrolledwin), ctree);
565 void folderview_set_column_order(FolderView *folderview)
568 FolderItem *item = folderview_get_selected_item(folderview);
569 GtkWidget *scrolledwin = folderview->scrolledwin;
571 debug_print("recreating tree...\n");
572 gtk_widget_destroy(folderview->ctree);
574 folderview->ctree = ctree = folderview_ctree_create(folderview);
575 gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
576 GTK_CLIST(ctree)->hadjustment);
577 gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
578 GTK_CLIST(ctree)->vadjustment);
579 gtk_widget_show(ctree);
581 folderview_set(folderview);
582 folderview_column_set_titles(folderview);
584 folderview_select(folderview,item);
587 FolderView *folderview_create(void)
589 FolderView *folderview;
590 GtkWidget *scrolledwin;
593 debug_print("Creating folder view...\n");
594 folderview = g_new0(FolderView, 1);
596 scrolledwin = gtk_scrolled_window_new(NULL, NULL);
597 gtk_scrolled_window_set_policy
598 (GTK_SCROLLED_WINDOW(scrolledwin),
599 GTK_POLICY_AUTOMATIC,
600 prefs_common.folderview_vscrollbar_policy);
601 gtk_widget_set_size_request(scrolledwin,
602 prefs_common.folderview_width,
603 prefs_common.folderview_height);
605 folderview->scrolledwin = scrolledwin;
606 ctree = folderview_ctree_create(folderview);
608 /* create popup factories */
609 folderview->popups = g_hash_table_new(g_str_hash, g_str_equal);
610 g_hash_table_foreach(folderview_popups, create_ifactories, folderview);
612 folderview->ctree = ctree;
614 folderview->folder_update_callback_id =
615 hooks_register_hook(FOLDER_UPDATE_HOOKLIST, folderview_update_folder, (gpointer) folderview);
616 folderview->folder_item_update_callback_id =
617 hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST, folderview_update_item_claws, (gpointer) folderview);
619 gtk_widget_show_all(scrolledwin);
621 folderview->target_list = gtk_target_list_new(folderview_drag_types, 2);
622 folderview_list = g_list_append(folderview_list, folderview);
627 void folderview_init(FolderView *folderview)
629 GtkWidget *ctree = folderview->ctree;
632 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE, &inboxxpm, &inboxxpmmask);
633 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM, &inboxhrmxpm, &inboxhrmxpmmask);
634 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN, &inboxopenxpm, &inboxopenxpmmask);
635 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM, &inboxopenhrmxpm, &inboxopenhrmxpmmask);
636 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE, &outboxxpm, &outboxxpmmask);
637 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM, &outboxhrmxpm, &outboxhrmxpmmask);
638 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN, &outboxopenxpm, &outboxopenxpmmask);
639 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM, &outboxopenhrmxpm, &outboxopenhrmxpmmask);
640 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
641 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM, &folderhrmxpm, &folderhrmxpmmask);
642 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
643 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM, &folderopenhrmxpm, &folderopenhrmxpmmask);
644 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN, &trashopenxpm, &trashopenxpmmask);
645 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM, &trashopenhrmxpm, &trashopenhrmxpmmask);
646 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE, &trashxpm, &trashxpmmask);
647 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM, &trashhrmxpm, &trashhrmxpmmask);
648 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE, &queuexpm, &queuexpmmask);
649 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM, &queuehrmxpm, &queuehrmxpmmask);
650 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN, &queueopenxpm, &queueopenxpmmask);
651 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM, &queueopenhrmxpm, &queueopenhrmxpmmask);
652 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE, &draftsxpm, &draftsxpmmask);
653 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN, &draftsopenxpm, &draftsopenxpmmask);
654 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_NOSELECT, &noselectxpm, &noselectxpmmask);
656 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_MARK, &m_inboxxpm, &m_inboxxpmmask);
657 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM_MARK, &m_inboxhrmxpm, &m_inboxhrmxpmmask);
658 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_MARK, &m_inboxopenxpm, &m_inboxopenxpmmask);
659 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM_MARK, &m_inboxopenhrmxpm, &m_inboxopenhrmxpmmask);
660 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_MARK, &m_outboxxpm, &m_outboxxpmmask);
661 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM_MARK, &m_outboxhrmxpm, &m_outboxhrmxpmmask);
662 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_MARK, &m_outboxopenxpm, &m_outboxopenxpmmask);
663 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM_MARK, &m_outboxopenhrmxpm, &m_outboxopenhrmxpmmask);
664 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_MARK, &m_folderxpm, &m_folderxpmmask);
665 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM_MARK, &m_folderhrmxpm, &m_folderhrmxpmmask);
666 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_MARK, &m_folderopenxpm, &m_folderopenxpmmask);
667 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM_MARK, &m_folderopenhrmxpm, &m_folderopenhrmxpmmask);
668 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_MARK, &m_trashopenxpm, &m_trashopenxpmmask);
669 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM_MARK, &m_trashopenhrmxpm, &m_trashopenhrmxpmmask);
670 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_MARK, &m_trashxpm, &m_trashxpmmask);
671 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM_MARK, &m_trashhrmxpm, &m_trashhrmxpmmask);
672 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_MARK, &m_queuexpm, &m_queuexpmmask);
673 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM_MARK, &m_queuehrmxpm, &m_queuehrmxpmmask);
674 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_MARK, &m_queueopenxpm, &m_queueopenxpmmask);
675 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM_MARK, &m_queueopenhrmxpm, &m_queueopenhrmxpmmask);
676 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE_MARK, &m_draftsxpm, &m_draftsxpmmask);
677 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN_MARK, &m_draftsopenxpm, &m_draftsopenxpmmask);
680 PangoFontDescription *font_desc;
681 normal_style = gtk_style_copy(gtk_widget_get_style(ctree));
682 font_desc = pango_font_description_from_string(NORMAL_FONT);
684 if (normal_style->font_desc)
685 pango_font_description_free
686 (normal_style->font_desc);
687 normal_style->font_desc = font_desc;
689 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
690 normal_color_style = gtk_style_copy(normal_style);
691 normal_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
693 gtk_widget_set_style(ctree, normal_style);
697 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
698 bold_style = gtk_style_copy(gtk_widget_get_style(ctree));
699 pango_font_description_set_weight
700 (bold_style->font_desc, PANGO_WEIGHT_BOLD);
701 bold_color_style = gtk_style_copy(bold_style);
702 bold_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
704 bold_tgtfold_style = gtk_style_copy(bold_style);
705 bold_tgtfold_style->fg[GTK_STATE_NORMAL] = folderview->color_op;
709 void folderview_set(FolderView *folderview)
711 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
712 MainWindow *mainwin = folderview->mainwin;
713 FolderItem *sel_item = NULL, *op_item = NULL;
718 debug_print("Setting folder info...\n");
719 STATUSBAR_PUSH(mainwin, _("Setting folder info..."));
721 main_window_cursor_wait(mainwin);
723 if (folderview->selected)
724 sel_item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
725 if (folderview->opened)
726 op_item = gtk_ctree_node_get_row_data(ctree, folderview->opened);
728 folderview->selected = NULL;
729 folderview->opened = NULL;
731 gtk_clist_freeze(GTK_CLIST(ctree));
732 gtk_clist_clear(GTK_CLIST(ctree));
734 folderview_set_folders(folderview);
737 folderview->selected = gtk_ctree_find_by_row_data(ctree, NULL, sel_item);
739 folderview->opened = gtk_ctree_find_by_row_data(ctree, NULL, op_item);
741 gtk_clist_thaw(GTK_CLIST(ctree));
742 main_window_cursor_normal(mainwin);
743 STATUSBAR_POP(mainwin);
746 void folderview_set_all(void)
750 for (list = folderview_list; list != NULL; list = list->next)
751 folderview_set((FolderView *)list->data);
754 void folderview_select(FolderView *folderview, FolderItem *item)
756 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
758 GtkCTreeNode *old_selected = folderview->selected;
762 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
763 if (node) folderview_select_node(folderview, node);
765 if (old_selected != node)
766 folder_update_op_count();
769 static void mark_all_read_cb(FolderView *folderview, guint action,
775 item = folderview_get_selected_item(folderview);
779 if (folderview->summaryview->folder_item != item
780 && prefs_common.ask_mark_all_read) {
781 val = alertpanel_full(_("Mark all as read"),
782 _("Do you really want to mark all mails in this "
783 "folder as read ?"), GTK_STOCK_NO, GTK_STOCK_YES, NULL,
784 TRUE, NULL, ALERT_QUESTION, G_ALERTDEFAULT);
786 if ((val & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
788 else if (val & G_ALERTDISABLE)
789 prefs_common.ask_mark_all_read = FALSE;
792 summary_lock(folderview->summaryview);
793 folder_item_update_freeze();
794 if (folderview->summaryview->folder_item == item)
795 summary_freeze(folderview->summaryview);
796 folderutils_mark_all_read(item);
797 if (folderview->summaryview->folder_item == item)
798 summary_thaw(folderview->summaryview);
799 folder_item_update_thaw();
800 summary_unlock(folderview->summaryview);
803 static void folderview_select_node(FolderView *folderview, GtkCTreeNode *node)
805 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
807 g_return_if_fail(node != NULL);
809 if (folderview->open_folder) {
813 folderview->open_folder = TRUE;
814 gtkut_ctree_set_focus_row(ctree, node);
815 gtk_ctree_select(ctree, node);
816 if (folderview->summaryview->folder_item &&
817 folderview->summaryview->folder_item->total_msgs > 0)
818 summary_grab_focus(folderview->summaryview);
820 gtk_widget_grab_focus(folderview->ctree);
822 gtkut_ctree_expand_parent_all(ctree, node);
825 void folderview_unselect(FolderView *folderview)
827 if (folderview->opened && !GTK_CTREE_ROW(folderview->opened)->children)
829 (GTK_CTREE(folderview->ctree), folderview->opened);
831 folderview->selected = folderview->opened = NULL;
834 static GtkCTreeNode *folderview_find_next_marked(GtkCTree *ctree,
840 node = gtkut_ctree_node_next(ctree, node);
842 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
844 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
845 item = gtk_ctree_node_get_row_data(ctree, node);
846 if (item && item->marked_msgs > 0 && item->stype != F_TRASH)
853 void folderview_select_next_marked(FolderView *folderview)
855 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
856 GtkCTreeNode *node = NULL;
857 SelectOnEntry last_sel = prefs_common.select_on_entry;
858 gboolean last_open = prefs_common.always_show_msg;
860 prefs_common.select_on_entry = SELECTONENTRY_MNU;
861 prefs_common.always_show_msg = TRUE;
863 if ((node = folderview_find_next_marked(ctree, folderview->opened))
865 folderview_select_node(folderview, node);
869 if (!folderview->opened ||
870 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
873 /* search again from the first node */
874 if ((node = folderview_find_next_marked(ctree, NULL)) != NULL)
875 folderview_select_node(folderview, node);
878 prefs_common.select_on_entry = last_sel;
879 prefs_common.always_show_msg = last_open;
882 static GtkCTreeNode *folderview_find_next_unread(GtkCTree *ctree,
888 node = gtkut_ctree_node_next(ctree, node);
890 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
892 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
893 item = gtk_ctree_node_get_row_data(ctree, node);
894 if (item && item->unread_msgs > 0 && item->stype != F_TRASH)
901 void folderview_select_next_unread(FolderView *folderview, gboolean force_open)
903 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
904 GtkCTreeNode *node = NULL;
905 SelectOnEntry last_sel = prefs_common.select_on_entry;
906 gboolean last_open = prefs_common.always_show_msg;
908 prefs_common.select_on_entry = SELECTONENTRY_UNM;
909 prefs_common.always_show_msg = force_open ? TRUE : last_open;
911 if ((node = folderview_find_next_unread(ctree, folderview->opened))
913 folderview_select_node(folderview, node);
917 if (!folderview->opened ||
918 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
921 /* search again from the first node */
922 if ((node = folderview_find_next_unread(ctree, NULL)) != NULL)
923 folderview_select_node(folderview, node);
926 prefs_common.select_on_entry = last_sel;
927 prefs_common.always_show_msg = last_open;
930 static GtkCTreeNode *folderview_find_next_new(GtkCTree *ctree,
936 node = gtkut_ctree_node_next(ctree, node);
938 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
940 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
941 item = gtk_ctree_node_get_row_data(ctree, node);
942 if (item && item->new_msgs > 0 && item->stype != F_TRASH)
949 void folderview_select_next_new(FolderView *folderview)
951 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
952 GtkCTreeNode *node = NULL;
953 SelectOnEntry last_sel = prefs_common.select_on_entry;
954 gboolean last_open = prefs_common.always_show_msg;
956 prefs_common.select_on_entry = SELECTONENTRY_NUM;
957 prefs_common.always_show_msg = TRUE;
959 if ((node = folderview_find_next_new(ctree, folderview->opened))
961 folderview_select_node(folderview, node);
965 if (!folderview->opened ||
966 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
969 /* search again from the first node */
970 if ((node = folderview_find_next_new(ctree, NULL)) != NULL)
971 folderview_select_node(folderview, node);
974 prefs_common.select_on_entry = last_sel;
975 prefs_common.always_show_msg = last_open;
978 FolderItem *folderview_get_selected_item(FolderView *folderview)
980 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
982 if (!folderview->selected) return NULL;
983 return gtk_ctree_node_get_row_data(ctree, folderview->selected);
986 static void folderview_set_folders(FolderView *folderview)
989 list = folder_get_list();
991 for (; list != NULL; list = list->next) {
992 folderview_append_folder(folderview, FOLDER(list->data));
996 static gchar *get_scan_str(FolderItem *item)
999 return g_strdup_printf(_("Scanning folder %s%c%s ..."),
1000 item->folder->name, G_DIR_SEPARATOR,
1003 return g_strdup_printf(_("Scanning folder %s ..."),
1004 item->folder->name);
1006 static void folderview_scan_tree_func(Folder *folder, FolderItem *item,
1010 for (list = folderview_list; list != NULL; list = list->next) {
1011 FolderView *folderview = (FolderView *)list->data;
1012 MainWindow *mainwin = folderview->mainwin;
1013 gchar *str = get_scan_str(item);
1015 STATUSBAR_PUSH(mainwin, str);
1016 STATUSBAR_POP(mainwin);
1021 void folderview_rescan_tree(Folder *folder, gboolean rebuild)
1024 MainWindow *mainwin = mainwindow_get_mainwindow();
1025 FolderView *folderview = NULL;
1026 GtkAdjustment *pos = NULL;
1029 g_return_if_fail(folder != NULL);
1031 if (!folder->klass->scan_tree) return;
1034 alertpanel_full(_("Rebuild folder tree"),
1035 _("Rebuilding the folder tree will remove "
1036 "local caches. Do you want to continue?"),
1037 GTK_STOCK_NO, GTK_STOCK_YES, NULL, FALSE,
1038 NULL, ALERT_WARNING, G_ALERTDEFAULT)
1039 != G_ALERTALTERNATE) {
1045 window = label_window_create(_("Rebuilding folder tree..."));
1047 window = label_window_create(_("Scanning folder tree..."));
1050 folderview = mainwin->folderview;
1053 pos = gtk_scrolled_window_get_vadjustment(
1054 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
1055 height = pos->value;
1058 folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
1059 folder_scan_tree(folder, rebuild);
1060 folder_set_ui_func(folder, NULL, NULL);
1062 folderview_set_all();
1065 pos = gtk_scrolled_window_get_vadjustment(
1066 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
1067 gtk_adjustment_set_value(pos, height);
1069 gtk_widget_destroy(window);
1073 void folderview_fast_rescan_tree(Folder *folder)
1076 MainWindow *mainwin = mainwindow_get_mainwindow();
1077 FolderView *folderview = NULL;
1078 GtkAdjustment *pos = NULL;
1081 g_return_if_fail(folder != NULL);
1083 if (!folder->klass->scan_tree) return;
1087 window = label_window_create(_("Scanning folder tree..."));
1090 folderview = mainwin->folderview;
1093 pos = gtk_scrolled_window_get_vadjustment(
1094 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
1095 height = pos->value;
1098 folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
1099 folder_fast_scan_tree(folder);
1100 folder_set_ui_func(folder, NULL, NULL);
1102 folderview_set_all();
1105 pos = gtk_scrolled_window_get_vadjustment(
1106 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
1107 gtk_adjustment_set_value(pos, height);
1109 gtk_widget_destroy(window);
1113 /** folderview_check_new()
1114 * Scan and update the folder and return the
1115 * count the number of new messages since last check.
1116 * \param folder the folder to check for new messages
1117 * \return the number of new messages since last check
1119 gint folderview_check_new(Folder *folder)
1123 FolderView *folderview;
1127 gint former_new_msgs = 0;
1128 gint former_new = 0, former_unread = 0, former_total;
1130 for (list = folderview_list; list != NULL; list = list->next) {
1131 folderview = (FolderView *)list->data;
1132 ctree = GTK_CTREE(folderview->ctree);
1135 main_window_lock(folderview->mainwin);
1137 for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
1138 node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
1140 item = gtk_ctree_node_get_row_data(ctree, node);
1141 if (!item || !item->path || !item->folder) continue;
1142 if (item->no_select) continue;
1143 if (folder && folder != item->folder) continue;
1144 if (!folder && !FOLDER_IS_LOCAL(item->folder)) continue;
1145 if (!item->prefs->newmailcheck) continue;
1146 if (item->processing_pending == TRUE) {
1147 debug_print("skipping %s, processing pending\n",
1148 item->path ? item->path : item->name);
1152 str = get_scan_str(item);
1154 STATUSBAR_PUSH(folderview->mainwin, str);
1158 folderview_scan_tree_func(item->folder, item, NULL);
1159 former_new = item->new_msgs;
1160 former_unread = item->unread_msgs;
1161 former_total = item->total_msgs;
1163 if (item->folder->klass->scan_required &&
1164 (item->folder->klass->scan_required(item->folder, item) ||
1165 item->folder->inbox == item ||
1166 item->opened == TRUE ||
1167 item->processing_pending == TRUE)) {
1168 if (folder_item_scan(item) < 0) {
1170 summaryview_unlock(folderview->summaryview, item);
1171 if (FOLDER_TYPE(item->folder) == F_NEWS || FOLDER_IS_LOCAL(folder)) {
1172 log_error(_("Couldn't scan folder %s\n"),
1173 item->path ? item->path:item->name);
1175 } else if (!FOLDER_IS_LOCAL(folder)) {
1176 STATUSBAR_POP(folderview->mainwin);
1181 } else if (!item->folder->klass->scan_required) {
1182 if (folder_item_scan(item) < 0) {
1183 summaryview_unlock(folderview->summaryview, item);
1184 if (folder && !FOLDER_IS_LOCAL(folder)) {
1185 STATUSBAR_POP(folderview->mainwin);
1190 if (former_new != item->new_msgs ||
1191 former_unread != item->unread_msgs ||
1192 former_total != item->total_msgs)
1193 folderview_update_node(folderview, node);
1195 new_msgs += item->new_msgs;
1196 former_new_msgs += former_new;
1197 STATUSBAR_POP(folderview->mainwin);
1200 main_window_unlock(folderview->mainwin);
1204 folder_write_list();
1205 /* Number of new messages since last check is the just the difference
1206 * between former_new_msgs and new_msgs. If new_msgs is less than
1207 * former_new_msgs, that would mean another session accessed the folder
1208 * and the result is not well defined.
1210 new_msgs = (former_new_msgs < new_msgs ? new_msgs - former_new_msgs : 0);
1214 void folderview_check_new_all(void)
1218 FolderView *folderview;
1220 folderview = (FolderView *)folderview_list->data;
1223 main_window_lock(folderview->mainwin);
1224 window = label_window_create
1225 (_("Checking for new messages in all folders..."));
1227 list = folder_get_list();
1228 for (; list != NULL; list = list->next) {
1229 Folder *folder = list->data;
1231 folderview_check_new(folder);
1234 folder_write_list();
1235 folderview_set_all();
1237 gtk_widget_destroy(window);
1238 main_window_unlock(folderview->mainwin);
1242 static gboolean folderview_have_new_children_sub(FolderView *folderview,
1248 if (!item || !item->folder || !item->folder->node)
1251 node = item->folder->node;
1253 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1254 node = node->children;
1257 (item->new_msgs > 0 ||
1258 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1262 while (node != NULL) {
1263 if (node && node->data) {
1264 FolderItem *next_item = (FolderItem*) node->data;
1266 if (folderview_have_new_children_sub(folderview,
1275 static gboolean folderview_have_new_children(FolderView *folderview,
1278 return folderview_have_new_children_sub(folderview, item, FALSE);
1281 static gboolean folderview_have_unread_children_sub(FolderView *folderview,
1287 if (!item || !item->folder || !item->folder->node)
1290 node = item->folder->node;
1292 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1293 node = node->children;
1296 (item->unread_msgs > 0 ||
1297 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1301 while (node != NULL) {
1302 if (node && node->data) {
1303 FolderItem *next_item = (FolderItem*) node->data;
1305 if (folderview_have_unread_children_sub(folderview,
1315 static gboolean folderview_have_unread_children(FolderView *folderview,
1318 return folderview_have_unread_children_sub(folderview, item, FALSE);
1321 static gboolean folderview_have_matching_children_sub(FolderView *folderview,
1327 if (!item || !item->folder || !item->folder->node)
1330 node = item->folder->node;
1332 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1333 node = node->children;
1335 if (in_sub && item->search_match){
1339 while (node != NULL) {
1340 if (node && node->data) {
1341 FolderItem *next_item = (FolderItem*) node->data;
1343 if (folderview_have_matching_children_sub(folderview,
1353 static gboolean folderview_have_matching_children(FolderView *folderview,
1356 return folderview_have_matching_children_sub(folderview, item, FALSE);
1359 static gboolean folderview_have_marked_children_sub(FolderView *folderview,
1365 if (!item || !item->folder || !item->folder->node)
1368 node = item->folder->node;
1370 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1371 node = node->children;
1373 if (item->marked_msgs != 0) {
1377 while (node != NULL) {
1378 if (node && node->data) {
1379 FolderItem *next_item = (FolderItem*) node->data;
1381 if (folderview_have_marked_children_sub(folderview,
1390 static gboolean folderview_have_marked_children(FolderView *folderview,
1393 return folderview_have_marked_children_sub(folderview, item, FALSE);
1396 static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node)
1398 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1399 GtkStyle *style = NULL;
1400 GtkStyle *color_style = NULL;
1402 GdkPixmap *xpm, *openxpm;
1403 GdkBitmap *mask, *openmask;
1404 static GdkPixmap *searchicon;
1405 static GdkBitmap *searchmask;
1406 gboolean mark = FALSE;
1409 gboolean add_unread_mark;
1410 gboolean add_sub_match_mark;
1411 gboolean use_bold, use_color;
1412 gint *col_pos = folderview->col_pos;
1413 SpecialFolderItemType stype;
1415 item = gtk_ctree_node_get_row_data(ctree, node);
1416 g_return_if_fail(item != NULL);
1418 if (!GTK_CTREE_ROW(node)->expanded)
1419 mark = folderview_have_marked_children(folderview, item);
1421 mark = (item->marked_msgs != 0);
1423 stype = item->stype;
1424 if (stype == F_NORMAL) {
1425 if (folder_has_parent_of_type(item, F_TRASH))
1427 else if (folder_has_parent_of_type(item, F_DRAFT))
1429 else if (folder_has_parent_of_type(item, F_OUTBOX))
1431 else if (folder_has_parent_of_type(item, F_QUEUE))
1436 if (item->hide_read_msgs) {
1437 xpm = mark?m_inboxhrmxpm:inboxhrmxpm;
1438 mask = mark?m_inboxhrmxpmmask:inboxhrmxpmmask;
1439 openxpm = mark?m_inboxopenhrmxpm:inboxopenhrmxpm;
1440 openmask = mark?m_inboxopenhrmxpmmask:inboxopenhrmxpmmask;
1442 xpm = mark?m_inboxxpm:inboxxpm;
1443 mask = mark?m_inboxxpmmask:inboxxpmmask;
1444 openxpm = mark?m_inboxopenxpm:inboxopenxpm;
1445 openmask = mark?m_inboxopenxpmmask:inboxopenxpmmask;
1449 if (item->hide_read_msgs) {
1450 xpm = mark?m_outboxhrmxpm:outboxhrmxpm;
1451 mask = mark?m_outboxhrmxpmmask:outboxhrmxpmmask;
1452 openxpm = mark?m_outboxopenhrmxpm:outboxopenhrmxpm;
1453 openmask = mark?m_outboxopenhrmxpmmask:outboxopenhrmxpmmask;
1455 xpm = mark?m_outboxxpm:outboxxpm;
1456 mask = mark?m_outboxxpmmask:outboxxpmmask;
1457 openxpm = mark?m_outboxopenxpm:outboxopenxpm;
1458 openmask = mark?m_outboxopenxpmmask:outboxopenxpmmask;
1462 if (item->hide_read_msgs) {
1463 xpm = mark?m_queuehrmxpm:queuehrmxpm;
1464 mask = mark?m_queuehrmxpmmask:queuehrmxpmmask;
1465 openxpm = mark?m_queueopenhrmxpm:queueopenhrmxpm;
1466 openmask = mark?m_queueopenhrmxpmmask:queueopenhrmxpmmask;
1468 xpm = mark?m_queuexpm:queuexpm;
1469 mask = mark?m_queuexpmmask:queuexpmmask;
1470 openxpm = mark?m_queueopenxpm:queueopenxpm;
1471 openmask = mark?m_queueopenxpmmask:queueopenxpmmask;
1475 if (item->hide_read_msgs) {
1476 xpm = mark?m_trashhrmxpm:trashhrmxpm;
1477 mask = mark?m_trashhrmxpmmask:trashhrmxpmmask;
1478 openxpm = mark?m_trashopenhrmxpm:trashopenhrmxpm;
1479 openmask = mark?m_trashopenhrmxpmmask:trashopenhrmxpmmask;
1481 xpm = mark?m_trashxpm:trashxpm;
1482 mask = mark?m_trashxpmmask:trashxpmmask;
1483 openxpm = mark?m_trashopenxpm:trashopenxpm;
1484 openmask = mark?m_trashopenxpmmask:trashopenxpmmask;
1488 xpm = mark?m_draftsxpm:draftsxpm;
1489 mask = mark?m_draftsxpmmask:draftsxpmmask;
1490 openxpm = mark?m_draftsopenxpm:draftsopenxpm;
1491 openmask = mark?m_draftsopenxpmmask:draftsopenxpmmask;
1494 if (item->hide_read_msgs) {
1495 xpm = mark?m_folderhrmxpm:folderhrmxpm;
1496 mask = mark?m_folderhrmxpmmask:folderhrmxpmmask;
1497 openxpm = mark?m_folderopenhrmxpm:folderopenhrmxpm;
1498 openmask = mark?m_folderopenhrmxpmmask:folderopenhrmxpmmask;
1500 xpm = mark?m_folderxpm:folderxpm;
1501 mask = mark?m_folderxpmmask:folderxpmmask;
1502 openxpm = mark?m_folderopenxpm:folderopenxpm;
1503 openmask = mark?m_folderopenxpmmask:folderopenxpmmask;
1507 if (item->no_select) {
1508 xpm = openxpm = noselectxpm;
1509 mask = openmask = noselectxpmmask;
1512 name = folder_item_get_name(item);
1514 if (!GTK_CTREE_ROW(node)->expanded) {
1515 add_unread_mark = folderview_have_unread_children(
1517 add_sub_match_mark = folderview_have_matching_children(
1520 add_unread_mark = FALSE;
1521 add_sub_match_mark = FALSE;
1524 if (item->search_match) {
1526 stock_pixmap_gdk(folderview->ctree, STOCK_PIXMAP_QUICKSEARCH,
1527 &searchicon, &searchmask);
1529 xpm = openxpm = searchicon;
1530 mask = openmask = searchmask;
1533 if (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0 &&
1534 prefs_common.display_folder_unread) {
1535 str = g_strdup_printf("%s (%d%s)", name, item->total_msgs,
1536 add_unread_mark ? "+" : "");
1537 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1538 xpm, mask, openxpm, openmask,
1539 FALSE, GTK_CTREE_ROW(node)->expanded);
1541 } else if (((item->unread_msgs > 0 || add_unread_mark) &&
1542 prefs_common.display_folder_unread)
1543 || add_sub_match_mark) {
1545 if (item->unread_msgs > 0)
1546 str = g_strdup_printf("%s (%d%s%s)", name, item->unread_msgs,
1547 add_unread_mark || add_sub_match_mark ? "+" : "",
1548 item->unreadmarked_msgs > 0 ? "!":"");
1550 str = g_strdup_printf("%s (+)", name);
1551 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1552 xpm, mask, openxpm, openmask,
1553 FALSE, GTK_CTREE_ROW(node)->expanded);
1556 str = g_strdup_printf("%s%s", name,
1557 item->unreadmarked_msgs > 0 ? " (!)":"");
1559 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1560 xpm, mask, openxpm, openmask,
1561 FALSE, GTK_CTREE_ROW(node)->expanded);
1566 if (!folder_item_parent(item)) {
1567 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], "-");
1568 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], "-");
1569 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], "-");
1571 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], itos(item->new_msgs));
1572 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], itos(item->unread_msgs));
1573 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], itos(item->total_msgs));
1576 if (folder_has_parent_of_type(item, F_OUTBOX) ||
1577 folder_has_parent_of_type(item, F_DRAFT) ||
1578 folder_has_parent_of_type(item, F_TRASH)) {
1579 use_bold = use_color = FALSE;
1580 } else if (folder_has_parent_of_type(item, F_QUEUE)) {
1581 /* highlight queue folder if there are any messages */
1582 use_bold = use_color = (item->total_msgs > 0);
1584 /* if unread messages exist, print with bold font */
1585 use_bold = (item->unread_msgs > 0|| item->new_msgs > 0)
1587 /* if new messages exist, print with colored letter */
1589 (item->new_msgs > 0) ||
1591 folderview_have_new_children(folderview, item));
1594 gtk_ctree_node_set_foreground(ctree, node, NULL);
1599 if (item->prefs->color > 0 && !use_color) {
1600 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1601 color_style = gtk_style_copy(bold_style);
1602 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1603 style = color_style;
1604 } else if (use_color) {
1605 style = bold_color_style;
1608 if (item->op_count > 0) {
1609 style = bold_tgtfold_style;
1611 } else if (use_color) {
1612 style = normal_color_style;
1613 gtk_ctree_node_set_foreground(ctree, node,
1614 &folderview->color_new);
1615 } else if (item->op_count > 0) {
1616 style = bold_tgtfold_style;
1617 } else if (item->prefs->color > 0) {
1619 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1620 color_style = gtk_style_copy(normal_style);
1621 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1622 style = color_style;
1624 style = normal_style;
1627 gtk_ctree_node_set_row_style(ctree, node, style);
1629 if ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
1630 folderview_update_node(folderview, node);
1633 void folderview_update_search_icon(FolderItem *item, gboolean matches)
1636 FolderView *folderview;
1640 g_return_if_fail(item != NULL);
1642 for (list = folderview_list; list != NULL; list = list->next) {
1643 folderview = (FolderView *)list->data;
1644 ctree = GTK_CTREE(folderview->ctree);
1646 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1648 item->search_match = matches;
1649 folderview_update_node(folderview, node);
1654 static gboolean folderview_update_item_claws(gpointer source, gpointer data)
1656 FolderItemUpdateData *update_info = (FolderItemUpdateData *)source;
1657 FolderView *folderview = (FolderView *)data;
1660 g_return_val_if_fail(update_info != NULL, TRUE);
1661 g_return_val_if_fail(update_info->item != NULL, TRUE);
1662 g_return_val_if_fail(folderview != NULL, FALSE);
1664 ctree = GTK_CTREE(folderview->ctree);
1666 node = gtk_ctree_find_by_row_data(ctree, NULL, update_info->item);
1669 if (update_info->update_flags & (F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_NAME))
1670 folderview_update_node(folderview, node);
1672 if ((update_info->update_flags & F_ITEM_UPDATE_CONTENT) && (folderview->opened == node))
1673 if (!quicksearch_is_active(folderview->summaryview->quicksearch))
1674 summary_show(folderview->summaryview, update_info->item);
1680 static gboolean folderview_gnode_func(GtkCTree *ctree, guint depth,
1681 GNode *gnode, GtkCTreeNode *cnode,
1684 FolderView *folderview = (FolderView *)data;
1685 FolderItem *item = FOLDER_ITEM(gnode->data);
1687 g_return_val_if_fail(item != NULL, FALSE);
1689 gtk_ctree_node_set_row_data(ctree, cnode, item);
1690 folderview_update_node(folderview, cnode);
1695 static void folderview_expand_func(GtkCTree *ctree, GtkCTreeNode *node,
1698 FolderView *folderview = (FolderView *)data;
1701 if (GTK_CTREE_ROW(node)->children) {
1702 item = gtk_ctree_node_get_row_data(ctree, node);
1703 g_return_if_fail(item != NULL);
1705 if (!item->collapsed)
1706 gtk_ctree_expand(ctree, node);
1708 folderview_update_node(folderview, node);
1712 static void set_special_folder(GtkCTree *ctree, FolderItem *item,
1713 GtkCTreeNode *root, GtkCTreeNode **prev)
1716 GtkCTreeNode *node, *parent, *sibling;
1718 node = gtk_ctree_find_by_row_data(ctree, root, item);
1720 g_warning("%s not found.\n", item->path);
1722 parent = GTK_CTREE_ROW(node)->parent;
1723 if (*prev && parent == GTK_CTREE_ROW(*prev)->parent)
1724 sibling = GTK_CTREE_ROW(*prev)->sibling;
1726 sibling = GTK_CTREE_ROW(parent)->children;
1730 tmp = gtk_ctree_node_get_row_data
1732 if (tmp->stype != F_NORMAL)
1733 sibling = GTK_CTREE_ROW(sibling)->sibling;
1737 if (node != sibling)
1738 gtk_ctree_move(ctree, node, parent, sibling);
1745 static void folderview_sort_folders(FolderView *folderview, GtkCTreeNode *root,
1748 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1749 GtkCTreeNode *prev = NULL;
1751 gtk_clist_freeze(GTK_CLIST(ctree));
1752 gtk_sctree_sort_recursive(ctree, root);
1753 if (root && GTK_CTREE_ROW(root)->parent) {
1754 gtk_clist_thaw(GTK_CLIST(ctree));
1757 set_special_folder(ctree, folder->inbox, root, &prev);
1758 set_special_folder(ctree, folder->outbox, root, &prev);
1759 set_special_folder(ctree, folder->draft, root, &prev);
1760 set_special_folder(ctree, folder->queue, root, &prev);
1761 set_special_folder(ctree, folder->trash, root, &prev);
1762 gtk_clist_thaw(GTK_CLIST(ctree));
1765 static void folderview_append_folder(FolderView *folderview, Folder *folder)
1767 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1770 g_return_if_fail(folder != NULL);
1772 root = gtk_sctree_insert_gnode(ctree, NULL, NULL, folder->node,
1773 folderview_gnode_func, folderview);
1774 gtk_ctree_pre_recursive(ctree, root, folderview_expand_func,
1776 folderview_sort_folders(folderview, root, folder);
1779 /* callback functions */
1780 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
1781 GdkEventButton *event)
1783 GtkCList *clist = GTK_CLIST(folderview->ctree);
1786 FolderViewPopup *fpopup;
1787 GtkItemFactory *fpopup_factory;
1789 FolderItem *special_trash = NULL, *special_queue = NULL;
1793 item = gtk_clist_get_row_data(clist, row);
1795 item = folderview_get_selected_item(folderview);
1797 g_return_if_fail(item != NULL);
1798 g_return_if_fail(item->folder != NULL);
1799 folder = item->folder;
1801 fpopup = g_hash_table_lookup(folderview_popups, folder->klass->idstr);
1803 fpopup_factory = g_hash_table_lookup(folderview->popups, folder->klass->idstr);
1805 fpopup = g_hash_table_lookup(folderview_popups, "common");
1806 fpopup_factory = g_hash_table_lookup(folderview->popups, "common");
1809 if (fpopup->set_sensitivity != NULL)
1810 fpopup->set_sensitivity(fpopup_factory, item);
1812 if (NULL != (ac = account_find_from_item(item))) {
1813 special_trash = account_get_special_folder(ac, F_TRASH);
1814 special_queue = account_get_special_folder(ac, F_QUEUE);
1817 if ((item == folder->trash || item == special_trash
1818 || folder_has_parent_of_type(item, F_TRASH)) &&
1819 gtk_item_factory_get_item(fpopup_factory, "/Empty trash...") == NULL) {
1820 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[0], folderview, 1);
1821 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[1], folderview, 1);
1822 } else if (item != folder->trash && (special_trash == NULL || item != special_trash)
1823 && !folder_has_parent_of_type(item, F_TRASH)) {
1824 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[0]);
1825 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[1]);
1828 if ((item == folder->queue || item == special_queue
1829 || folder_has_parent_of_type(item, F_QUEUE)) &&
1830 gtk_item_factory_get_item(fpopup_factory, "/Send queue...") == NULL) {
1831 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[0], folderview, 1);
1832 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[1], folderview, 1);
1833 } else if (item != folder->queue && (special_queue == NULL || item != special_queue)
1834 && !folder_has_parent_of_type(item, F_QUEUE)) {
1835 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[0]);
1836 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[1]);
1839 #define SET_SENS(name, sens) \
1840 menu_set_sensitive(fpopup_factory, name, sens)
1842 SET_SENS("/Mark all read", item->unread_msgs >= 1);
1843 SET_SENS("/Search folder...", item->total_msgs >= 1 &&
1844 folderview->selected == folderview->opened);
1845 SET_SENS("/Properties...", TRUE);
1846 SET_SENS("/Processing...", item->node->parent != NULL);
1847 if (item == folder->trash || item == special_trash
1848 || folder_has_parent_of_type(item, F_TRASH)) {
1849 GSList *msglist = folder_item_get_msg_list(item);
1850 SET_SENS("/Empty trash...", msglist != NULL);
1851 procmsg_msg_list_free(msglist);
1853 if (item == folder->queue || item == special_queue
1854 || folder_has_parent_of_type(item, F_QUEUE)) {
1855 GSList *msglist = folder_item_get_msg_list(item);
1856 SET_SENS("/Send queue...", msglist != NULL);
1857 procmsg_msg_list_free(msglist);
1861 popup = gtk_item_factory_get_widget(fpopup_factory, fpopup->path);
1862 gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
1863 event->button, event->time);
1868 static gboolean folderview_button_pressed(GtkWidget *ctree, GdkEventButton *event,
1869 FolderView *folderview)
1871 GtkCList *clist = GTK_CLIST(ctree);
1872 gint prev_row = -1, row = -1, column = -1;
1874 if (!event) return FALSE;
1876 if (event->button == 1 || event->button == 2) {
1877 if (!gtk_ctree_is_hot_spot (GTK_CTREE(clist), event->x, event->y))
1878 folderview->open_folder = TRUE;
1880 if (event->type == GDK_2BUTTON_PRESS) {
1881 if (clist->selection) {
1884 node = GTK_CTREE_NODE(clist->selection->data);
1886 gtk_ctree_toggle_expansion(
1889 folderview->open_folder = FALSE;
1896 if (event->button == 2 || event->button == 3) {
1898 if (clist->selection) {
1901 node = GTK_CTREE_NODE(clist->selection->data);
1903 prev_row = gtkut_ctree_get_nth_from_node
1904 (GTK_CTREE(ctree), node);
1907 if (!gtk_clist_get_selection_info(clist, event->x, event->y,
1910 if (prev_row != row) {
1911 gtk_clist_unselect_all(clist);
1912 if (event->button == 2)
1913 folderview_select_node
1915 gtk_ctree_node_nth(GTK_CTREE(ctree),
1918 gtk_clist_select_row(clist, row, column);
1922 if (event->button != 3) return FALSE;
1924 folderview_set_sens_and_popup_menu(folderview, row, event);
1928 static gboolean folderview_button_released(GtkWidget *ctree, GdkEventButton *event,
1929 FolderView *folderview)
1931 if (!event) return FALSE;
1933 if (event->button == 1 && folderview->open_folder == FALSE &&
1934 folderview->opened != NULL) {
1935 gtkut_ctree_set_focus_row(GTK_CTREE(ctree),
1936 folderview->opened);
1937 gtk_ctree_select(GTK_CTREE(ctree), folderview->opened);
1943 static gboolean folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
1944 FolderView *folderview)
1946 if (!event) return FALSE;
1948 if (quicksearch_has_focus(folderview->summaryview->quicksearch))
1951 switch (event->keyval) {
1953 if (folderview->selected) {
1954 folderview_select_node(folderview,
1955 folderview->selected);
1959 if (folderview->selected) {
1960 if (folderview->opened == folderview->selected &&
1961 (!folderview->summaryview->folder_item ||
1962 folderview->summaryview->folder_item->total_msgs == 0))
1963 folderview_select_next_unread(folderview, TRUE);
1965 folderview_select_node(folderview,
1966 folderview->selected);
1976 typedef struct _PostponedSelectData
1981 FolderView *folderview;
1982 } PostponedSelectData;
1984 static gboolean postpone_select(void *data)
1986 PostponedSelectData *psdata = (PostponedSelectData *)data;
1987 debug_print("trying again\n");
1988 psdata->folderview->open_folder = TRUE;
1989 main_window_cursor_normal(psdata->folderview->mainwin);
1990 STATUSBAR_POP(psdata->folderview->mainwin);
1991 folderview_selected(psdata->ctree, psdata->row,
1992 psdata->column, psdata->folderview);
1997 static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row,
1998 gint column, FolderView *folderview)
2000 static gboolean can_select = TRUE; /* exclusive lock */
2006 folderview->selected = row;
2008 if (folderview->opened == row) {
2009 folderview->open_folder = FALSE;
2014 if (!can_select || summary_is_locked(folderview->summaryview)) {
2015 if (folderview->opened) {
2016 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2017 gtk_ctree_select(ctree, folderview->opened);
2023 if (!folderview->open_folder) {
2027 item = gtk_ctree_node_get_row_data(ctree, row);
2028 if (!item || item->no_select) {
2030 folderview->open_folder = FALSE;
2036 /* Save cache for old folder */
2037 /* We don't want to lose all caches if sylpheed crashed */
2038 if (folderview->opened) {
2039 FolderItem *olditem;
2041 olditem = gtk_ctree_node_get_row_data(ctree, folderview->opened);
2043 buf = g_strdup_printf(_("Closing Folder %s..."),
2044 olditem->path ? olditem->path:olditem->name);
2045 /* will be null if we just moved the previously opened folder */
2046 STATUSBAR_PUSH(folderview->mainwin, buf);
2047 main_window_cursor_wait(folderview->mainwin);
2049 summary_save_prefs_to_folderitem(folderview->summaryview, olditem);
2050 summary_show(folderview->summaryview, NULL);
2051 folder_item_close(olditem);
2052 main_window_cursor_normal(folderview->mainwin);
2053 STATUSBAR_POP(folderview->mainwin);
2057 /* CLAWS: set compose button type: news folder items
2058 * always have a news folder as parent */
2060 toolbar_set_compose_button
2061 (folderview->mainwin->toolbar,
2062 FOLDER_TYPE(item->folder) == F_NEWS ?
2063 COMPOSEBUTTON_NEWS : COMPOSEBUTTON_MAIL);
2066 debug_print("Folder %s is selected\n", item->path);
2068 if (!GTK_CTREE_ROW(row)->children)
2069 gtk_ctree_expand(ctree, row);
2070 if (folderview->opened &&
2071 !GTK_CTREE_ROW(folderview->opened)->children)
2072 gtk_ctree_collapse(ctree, folderview->opened);
2074 /* ungrab the mouse event */
2075 if (GTK_WIDGET_HAS_GRAB(ctree)) {
2076 gtk_grab_remove(GTK_WIDGET(ctree));
2077 if (gdk_pointer_is_grabbed())
2078 gdk_pointer_ungrab(GDK_CURRENT_TIME);
2082 buf = g_strdup_printf(_("Opening Folder %s..."), item->path ?
2083 item->path : "(null)");
2084 debug_print("%s\n", buf);
2085 STATUSBAR_PUSH(folderview->mainwin, buf);
2088 main_window_cursor_wait(folderview->mainwin);
2090 res = folder_item_open(item);
2092 main_window_cursor_normal(folderview->mainwin);
2093 STATUSBAR_POP(folderview->mainwin);
2095 alertpanel_error(_("Folder could not be opened."));
2097 folderview->open_folder = FALSE;
2101 } else if (res == -2) {
2102 PostponedSelectData *data = g_new0(PostponedSelectData, 1);
2103 data->ctree = ctree;
2105 data->column = column;
2106 data->folderview = folderview;
2107 debug_print("postponing open of %s till end of scan\n",
2108 item->path ? item->path:item->name);
2109 folderview->open_folder = FALSE;
2111 g_timeout_add(500, postpone_select, data);
2116 main_window_cursor_normal(folderview->mainwin);
2119 summary_set_prefs_from_folderitem(folderview->summaryview, item);
2120 opened = summary_show(folderview->summaryview, item);
2122 folder_clean_cache_memory(item);
2125 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2126 gtk_ctree_select(ctree, folderview->opened);
2128 folderview->opened = row;
2129 if (gtk_ctree_node_is_visible(ctree, row)
2130 != GTK_VISIBILITY_FULL)
2131 gtk_ctree_node_moveto(ctree, row, -1, 0.5, 0);
2134 STATUSBAR_POP(folderview->mainwin);
2136 folderview->open_folder = FALSE;
2141 static void folderview_tree_expanded(GtkCTree *ctree, GtkCTreeNode *node,
2142 FolderView *folderview)
2146 item = gtk_ctree_node_get_row_data(ctree, node);
2147 g_return_if_fail(item != NULL);
2148 item->collapsed = FALSE;
2149 folderview_update_node(folderview, node);
2152 static void folderview_tree_collapsed(GtkCTree *ctree, GtkCTreeNode *node,
2153 FolderView *folderview)
2157 item = gtk_ctree_node_get_row_data(ctree, node);
2158 g_return_if_fail(item != NULL);
2159 item->collapsed = TRUE;
2160 folderview_update_node(folderview, node);
2163 static void folderview_popup_close(GtkMenuShell *menu_shell,
2164 FolderView *folderview)
2166 if (!folderview->opened) return;
2168 gtk_ctree_select(GTK_CTREE(folderview->ctree), folderview->opened);
2171 static void folderview_col_resized(GtkCList *clist, gint column, gint width,
2172 FolderView *folderview)
2174 FolderColumnType type = folderview->col_state[column].type;
2176 prefs_common.folder_col_size[type] = width;
2179 static void folderview_create_folder_node_recursive(FolderView *folderview, FolderItem *item)
2183 folderview_create_folder_node(folderview, item);
2185 if (!item || !item->folder || !item->folder->node)
2188 srcnode = item->folder->node;
2189 srcnode = g_node_find(srcnode, G_PRE_ORDER, G_TRAVERSE_ALL, item);
2190 srcnode = srcnode->children;
2191 while (srcnode != NULL) {
2192 if (srcnode && srcnode->data) {
2193 FolderItem *next_item = (FolderItem*) srcnode->data;
2194 folderview_create_folder_node_recursive(folderview, next_item);
2196 srcnode = srcnode->next;
2200 static void folderview_create_folder_node(FolderView *folderview, FolderItem *item)
2202 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2203 gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
2204 GtkCTreeNode *node, *parent_node;
2205 gint *col_pos = folderview->col_pos;
2206 FolderItemUpdateData hookdata;
2208 parent_node = gtk_ctree_find_by_row_data(ctree, NULL, folder_item_parent(item));
2209 if (parent_node == NULL)
2212 gtk_clist_freeze(GTK_CLIST(ctree));
2214 text[col_pos[F_COL_FOLDER]] = item->name;
2215 node = gtk_sctree_insert_node(ctree, parent_node, NULL, text,
2217 folderxpm, folderxpmmask,
2218 folderopenxpm, folderopenxpmmask,
2220 gtk_ctree_expand(ctree, parent_node);
2221 gtk_ctree_node_set_row_data(ctree, node, item);
2223 gtk_ctree_node_set_row_style(ctree, node, normal_style);
2224 folderview_sort_folders(folderview, parent_node, item->folder);
2226 hookdata.item = item;
2227 hookdata.update_flags = F_ITEM_UPDATE_NAME;
2228 hookdata.msg = NULL;
2229 hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &hookdata);
2231 gtk_clist_thaw(GTK_CLIST(ctree));
2234 static void folderview_empty_trash_cb(FolderView *folderview, guint action,
2237 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2239 GSList *mlist = NULL;
2241 FolderItem *special_trash = NULL;
2244 if (!folderview->selected) return;
2245 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2246 g_return_if_fail(item != NULL);
2247 g_return_if_fail(item->folder != NULL);
2249 if (NULL != (ac = account_find_from_item(item)))
2250 special_trash = account_get_special_folder(ac, F_TRASH);
2252 if (item != item->folder->trash && item != special_trash
2253 && !folder_has_parent_of_type(item, F_TRASH)) return;
2255 if (prefs_common.ask_on_clean) {
2256 if (alertpanel(_("Empty trash"),
2257 _("Delete all messages in trash?"),
2258 GTK_STOCK_CANCEL, _("+_Empty trash"), NULL) != G_ALERTALTERNATE)
2262 mlist = folder_item_get_msg_list(item);
2264 for (cur = mlist ; cur != NULL ; cur = cur->next) {
2265 MsgInfo * msginfo = (MsgInfo *) cur->data;
2266 if (MSG_IS_LOCKED(msginfo->flags))
2268 /* is it partially received? (partial_recv isn't cached) */
2269 if (msginfo->total_size != 0 &&
2270 msginfo->size != (off_t)msginfo->total_size)
2271 partial_mark_for_delete(msginfo);
2273 procmsg_msg_list_free(mlist);
2275 folder_item_remove_all_msg(item);
2278 static void folderview_send_queue_cb(FolderView *folderview, guint action,
2281 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2283 FolderItem *special_queue = NULL;
2285 gchar *errstr = NULL;
2287 if (!folderview->selected) return;
2288 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2289 g_return_if_fail(item != NULL);
2290 g_return_if_fail(item->folder != NULL);
2292 if (NULL != (ac = account_find_from_item(item)))
2293 special_queue = account_get_special_folder(ac, F_QUEUE);
2295 if (item != item->folder->queue && item != special_queue
2296 && !folder_has_parent_of_type(item, F_QUEUE)) return;
2298 if (procmsg_queue_is_empty(item))
2301 if (prefs_common.work_offline)
2302 if (alertpanel(_("Offline warning"),
2303 _("You're working offline. Override?"),
2304 GTK_STOCK_NO, GTK_STOCK_YES,
2305 NULL) != G_ALERTALTERNATE)
2308 /* ask for confirmation before sending queued messages only
2309 in online mode and if there is at least one message queued
2310 in any of the folder queue
2312 if (prefs_common.confirm_send_queued_messages) {
2313 if (!prefs_common.work_offline) {
2314 if (alertpanel(_("Send queued messages"),
2315 _("Send all queued messages?"),
2316 GTK_STOCK_CANCEL, _("_Send"),
2317 NULL) != G_ALERTALTERNATE)
2322 if (procmsg_send_queue(item, prefs_common.savemsg, &errstr) < 0) {
2324 alertpanel_error_log(_("Some errors occurred while "
2325 "sending queued messages."));
2327 gchar *tmp = g_strdup_printf(_("Some errors occurred "
2328 "while sending queued messages:\n%s"), errstr);
2330 alertpanel_error_log(tmp);
2336 static void folderview_search_cb(FolderView *folderview, guint action,
2339 summary_search(folderview->summaryview);
2342 static void folderview_property_cb(FolderView *folderview, guint action,
2345 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2348 if (!folderview->selected) return;
2350 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2351 g_return_if_fail(item != NULL);
2352 g_return_if_fail(item->folder != NULL);
2354 prefs_folder_item_open(item);
2357 static void folderview_recollapse_nodes(FolderView *folderview, GtkCTreeNode *node)
2359 GSList *list = NULL;
2360 GSList *done = NULL;
2361 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2363 for (list = folderview->nodes_to_recollapse; list != NULL; list = g_slist_next(list)) {
2364 if (!gtkut_ctree_node_is_parent(GTK_CTREE_NODE(list->data), node)
2365 && list->data != node) {
2366 gtk_ctree_collapse(ctree, GTK_CTREE_NODE(list->data));
2367 done = g_slist_append(done, GTK_CTREE_NODE(list->data));
2370 for (list = done; list != NULL; list = g_slist_next(list)) {
2371 folderview->nodes_to_recollapse = g_slist_remove(folderview->nodes_to_recollapse,
2377 void folderview_move_folder(FolderView *folderview, FolderItem *from_folder,
2378 FolderItem *to_folder, gboolean copy)
2380 FolderItem *from_parent = NULL;
2381 FolderItem *new_folder = NULL;
2382 GtkCTreeNode *src_node = NULL;
2386 g_return_if_fail(folderview != NULL);
2387 g_return_if_fail(from_folder != NULL);
2388 g_return_if_fail(to_folder != NULL);
2390 src_node = gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree), NULL, from_folder);
2391 from_parent = folder_item_parent(from_folder);
2393 if (prefs_common.warn_dnd) {
2394 buf = g_strdup_printf(copy ? _("Do you really want to copy folder '%s' in '%s' ?"):
2395 _("Do you really want to make folder '%s' a sub-folder of '%s' ?"),
2396 from_folder->name, to_folder->name);
2397 status = alertpanel_full(copy ? _("Copy folder"):_("Move folder"), buf,
2398 GTK_STOCK_NO, GTK_STOCK_YES, NULL, TRUE,
2399 NULL, ALERT_QUESTION, G_ALERTDEFAULT);
2402 if ((status & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
2404 else if (status & G_ALERTDISABLE)
2405 prefs_common.warn_dnd = FALSE;
2408 buf = g_strdup_printf(copy ? _("Copying %s to %s..."):_("Moving %s to %s..."),
2409 from_folder->name, to_folder->name);
2410 STATUSBAR_PUSH(folderview->mainwin, buf);
2412 summary_clear_all(folderview->summaryview);
2413 folderview->opened = NULL;
2414 folderview->selected = NULL;
2415 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), FALSE);
2417 main_window_cursor_wait(folderview->mainwin);
2419 statusbar_verbosity_set(FALSE);
2420 folder_item_update_freeze();
2421 if ((status = folder_item_move_to(from_folder, to_folder, &new_folder, copy)) == F_MOVE_OK) {
2422 statusbar_verbosity_set(FALSE);
2423 main_window_cursor_normal(folderview->mainwin);
2424 STATUSBAR_POP(folderview->mainwin);
2425 folder_item_update_thaw();
2426 folder_item_update_recursive(new_folder, F_ITEM_UPDATE_MSGCNT);
2428 folderview_sort_folders(folderview,
2429 gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree),
2430 NULL, to_folder), new_folder->folder);
2431 folderview_select(folderview, new_folder);
2433 statusbar_verbosity_set(FALSE);
2434 main_window_cursor_normal(folderview->mainwin);
2435 STATUSBAR_POP(folderview->mainwin);
2436 folder_item_update_thaw();
2438 case F_MOVE_FAILED_DEST_IS_PARENT:
2439 alertpanel_error(_("Source and destination are the same."));
2441 case F_MOVE_FAILED_DEST_IS_CHILD:
2442 alertpanel_error(copy ? _("Can't copy a folder to one of its children."):
2443 _("Can't move a folder to one of its children."));
2445 case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX:
2446 alertpanel_error(_("Folder moving cannot be done between different mailboxes."));
2449 alertpanel_error(copy ? _("Copy failed!"):_("Move failed!"));
2454 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), TRUE);
2457 static gint folderview_clist_compare(GtkCList *clist,
2458 gconstpointer ptr1, gconstpointer ptr2)
2460 FolderItem *item1 = ((GtkCListRow *)ptr1)->data;
2461 FolderItem *item2 = ((GtkCListRow *)ptr2)->data;
2464 return (item2->name != NULL);
2468 return g_utf8_collate(item1->name, item2->name);
2471 static void folderview_processing_cb(FolderView *folderview, guint action,
2474 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2478 if (!folderview->selected) return;
2480 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2481 g_return_if_fail(item != NULL);
2482 g_return_if_fail(item->folder != NULL);
2484 id = folder_item_get_identifier(item);
2485 title = g_strdup_printf (_("Processing configuration for folder %s"), id);
2488 prefs_filtering_open(&item->prefs->processing, title,
2489 MANUAL_ANCHOR_PROCESSING, NULL, NULL, FALSE);
2493 void folderview_set_target_folder_color(gint color_op)
2497 FolderView *folderview;
2499 for (list = folderview_list; list != NULL; list = list->next) {
2500 folderview = (FolderView *)list->data;
2501 gtkut_convert_int_to_gdk_color(color_op, &folderview->color_op);
2503 bold_tgtfold_style->fg[GTK_STATE_NORMAL] =
2504 folderview->color_op;
2510 static gchar *last_font = NULL;
2511 void folderview_reflect_prefs_pixmap_theme(FolderView *folderview)
2519 void folderview_reflect_prefs(void)
2521 gboolean update_font = TRUE;
2522 FolderView *folderview = mainwindow_get_mainwindow()->folderview;
2523 FolderItem *item = folderview_get_selected_item(folderview);
2524 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2525 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2526 gint height = pos->value;
2528 if (last_font && !strcmp(last_font, NORMAL_FONT))
2529 update_font = FALSE;
2532 last_font = g_strdup(NORMAL_FONT);
2535 normal_style = normal_color_style = bold_style =
2536 bold_color_style = bold_tgtfold_style = NULL;
2538 folderview_init(folderview);
2540 gtk_clist_freeze(GTK_CLIST(folderview->ctree));
2541 folderview_column_set_titles(folderview);
2542 folderview_set_all();
2544 g_signal_handlers_block_by_func
2545 (G_OBJECT(folderview->ctree),
2546 G_CALLBACK(folderview_selected), folderview);
2549 GtkCTreeNode *node = gtk_ctree_find_by_row_data(
2550 GTK_CTREE(folderview->ctree), NULL, item);
2552 folderview_select(folderview, item);
2553 folderview->open_folder = FALSE;
2554 folderview->selected = node;
2557 g_signal_handlers_unblock_by_func
2558 (G_OBJECT(folderview->ctree),
2559 G_CALLBACK(folderview_selected), folderview);
2561 pos = gtk_scrolled_window_get_vadjustment(
2562 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2563 gtk_adjustment_set_value(pos, height);
2564 gtk_clist_thaw(GTK_CLIST(folderview->ctree));
2567 static void drag_state_stop(FolderView *folderview)
2569 if (folderview->drag_timer)
2570 g_source_remove(folderview->drag_timer);
2571 folderview->drag_timer = 0;
2572 folderview->drag_node = NULL;
2575 static gint folderview_defer_expand(FolderView *folderview)
2577 if (folderview->drag_node) {
2578 folderview_recollapse_nodes(folderview, folderview->drag_node);
2579 if (folderview->drag_item->collapsed) {
2580 gtk_ctree_expand(GTK_CTREE(folderview->ctree), folderview->drag_node);
2581 folderview->nodes_to_recollapse = g_slist_append
2582 (folderview->nodes_to_recollapse, folderview->drag_node);
2585 folderview->drag_item = NULL;
2586 folderview->drag_timer = 0;
2590 static void drag_state_start(FolderView *folderview, GtkCTreeNode *node, FolderItem *item)
2592 /* the idea is that we call drag_state_start() whenever we want expansion to
2593 * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
2594 * we need to call drag_state_stop() */
2595 drag_state_stop(folderview);
2596 /* request expansion */
2597 if (0 != (folderview->drag_timer = g_timeout_add
2598 (prefs_common.hover_timeout,
2599 (GtkFunction)folderview_defer_expand,
2601 folderview->drag_node = node;
2602 folderview->drag_item = item;
2606 static void folderview_start_drag(GtkWidget *widget, gint button, GdkEvent *event,
2607 FolderView *folderview)
2609 GdkDragContext *context;
2611 g_return_if_fail(folderview != NULL);
2612 if (folderview->selected == NULL) return;
2613 if (folderview->nodes_to_recollapse)
2614 g_slist_free(folderview->nodes_to_recollapse);
2615 folderview->nodes_to_recollapse = NULL;
2616 context = gtk_drag_begin(widget, folderview->target_list,
2617 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
2618 gtk_drag_set_icon_default(context);
2621 static void folderview_drag_data_get(GtkWidget *widget,
2622 GdkDragContext *drag_context,
2623 GtkSelectionData *selection_data,
2626 FolderView *folderview)
2630 gchar *source = NULL;
2631 if (info == TARGET_DUMMY) {
2632 for (cur = GTK_CLIST(folderview->ctree)->selection;
2633 cur != NULL; cur = cur->next) {
2634 item = gtk_ctree_node_get_row_data
2635 (GTK_CTREE(folderview->ctree),
2636 GTK_CTREE_NODE(cur->data));
2638 source = g_strdup_printf ("FROM_OTHER_FOLDER%s", folder_item_get_identifier(item));
2639 gtk_selection_data_set(selection_data,
2640 selection_data->target, 8,
2641 source, strlen(source));
2647 g_warning("unknown info %d\n", info);
2651 static gboolean folderview_update_folder(gpointer source, gpointer userdata)
2653 FolderUpdateData *hookdata;
2654 FolderView *folderview;
2658 folderview = (FolderView *) userdata;
2659 g_return_val_if_fail(hookdata != NULL, FALSE);
2660 g_return_val_if_fail(folderview != NULL, FALSE);
2662 ctree = folderview->ctree;
2663 g_return_val_if_fail(ctree != NULL, FALSE);
2665 if (hookdata->update_flags & FOLDER_ADD_FOLDERITEM)
2666 folderview_create_folder_node(folderview, hookdata->item);
2667 else if (hookdata->update_flags & FOLDER_RENAME_FOLDERITEM) {
2668 GtkCTreeNode *node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree),
2669 NULL, folder_item_parent(hookdata->item));
2670 folderview_sort_folders(folderview, node, hookdata->folder);
2671 } else if (hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM) {
2674 node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree), NULL, hookdata->item);
2676 gtk_ctree_remove_node(GTK_CTREE(ctree), node);
2677 } else if (hookdata->update_flags & (FOLDER_TREE_CHANGED | FOLDER_ADD_FOLDER | FOLDER_REMOVE_FOLDER))
2678 folderview_set(folderview);
2683 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
2684 GdkDragContext *context,
2688 FolderView *folderview)
2691 FolderItem *item = NULL, *src_item = NULL;
2692 GtkCTreeNode *node = NULL;
2693 gboolean acceptable = FALSE;
2694 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2695 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2696 int height = (int)pos->page_size;
2697 int total_height = (int)pos->upper;
2698 int vpos = (int) pos->value;
2700 if (gtk_clist_get_selection_info
2701 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
2702 GtkWidget *srcwidget;
2704 if (y > height - 24 && height + vpos < total_height)
2705 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
2707 if (y < 48 && y > 0)
2708 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
2710 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2711 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2712 src_item = folderview->summaryview->folder_item;
2714 srcwidget = gtk_drag_get_source_widget(context);
2715 if (srcwidget == summary_get_main_widget(folderview->summaryview)) {
2716 /* comes from summaryview */
2717 /* we are copying messages, so only accept folder items that are not
2718 the source item, are no root items and can copy messages */
2719 if (item && item->folder && folder_item_parent(item) != NULL && src_item &&
2720 src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2721 FOLDER_TYPE(item->folder) != F_UNKNOWN)
2723 } else if (srcwidget == folderview->ctree) {
2724 /* comes from folderview */
2725 /* we are moving folder items, only accept folders that are not
2726 the source items and can copy messages and create folder items */
2727 if (item && item->folder && src_item && src_item != item &&
2728 FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2729 FOLDER_CLASS(item->folder)->create_folder != NULL &&
2730 ((FOLDER_TYPE(item->folder) != F_UNKNOWN && FOLDER_TYPE(src_item->folder) != F_UNKNOWN)
2731 || item->folder == src_item->folder))
2734 /* comes from another app */
2735 /* we are adding messages, so only accept folder items that are
2736 no root items and can copy messages */
2737 if (item && item->folder && folder_item_parent(item) != NULL
2738 && FOLDER_CLASS(item->folder)->add_msg != NULL &&
2739 FOLDER_TYPE(item->folder) != F_UNKNOWN)
2744 if (acceptable || (src_item && src_item == item))
2745 drag_state_start(folderview, node, item);
2748 g_signal_handlers_block_by_func
2750 G_CALLBACK(folderview_selected), folderview);
2751 gtk_ctree_select(GTK_CTREE(widget), node);
2752 g_signal_handlers_unblock_by_func
2754 G_CALLBACK(folderview_selected), folderview);
2755 gdk_drag_status(context,
2756 (context->actions == GDK_ACTION_COPY ?
2757 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
2759 if (folderview->opened)
2760 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2761 gdk_drag_status(context, 0, time);
2767 static void folderview_drag_leave_cb(GtkWidget *widget,
2768 GdkDragContext *context,
2770 FolderView *folderview)
2772 drag_state_stop(folderview);
2773 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2776 static void free_info (gpointer stuff, gpointer data)
2781 void folderview_finish_dnd(const gchar *data, GdkDragContext *drag_context,
2782 guint time, FolderItem *item)
2785 GSList *msglist = NULL;
2786 list = uri_list_extract_filenames(data);
2787 if (!(item && item->folder && folder_item_parent(item) != NULL
2788 && FOLDER_CLASS(item->folder)->add_msg != NULL))
2790 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2791 debug_print("item doesn't fit\n");
2795 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2796 debug_print("list is empty\n");
2799 for (tmp = list; tmp != NULL; tmp = tmp->next) {
2800 MsgFileInfo *info = NULL;
2802 if (file_is_email((gchar *)tmp->data)) {
2803 info = g_new0(MsgFileInfo, 1);
2804 info->msginfo = NULL;
2805 info->file = (gchar *)tmp->data;
2806 msglist = g_slist_prepend(msglist, info);
2807 debug_print("file is a mail\n");
2809 debug_print("file isn't a mail\n");
2813 msglist = g_slist_reverse(msglist);
2814 folder_item_add_msgs(item, msglist, FALSE);
2815 g_slist_foreach(msglist, free_info, NULL);
2816 g_slist_free(msglist);
2817 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2819 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2821 list_free_strings(list);
2825 static void folderview_drag_received_cb(GtkWidget *widget,
2826 GdkDragContext *drag_context,
2829 GtkSelectionData *data,
2832 FolderView *folderview)
2835 FolderItem *item = NULL, *src_item;
2838 if (info == TARGET_DUMMY) {
2839 drag_state_stop(folderview);
2840 if ((void *)strstr(data->data, "FROM_OTHER_FOLDER") != (void *)data->data) {
2841 /* comes from summaryview */
2842 if (gtk_clist_get_selection_info
2843 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2846 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2847 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2848 src_item = folderview->summaryview->folder_item;
2850 /* re-check (due to acceptable possibly set for folder moves */
2851 if (!(item && item->folder && item->path && !item->no_select &&
2852 src_item && src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)) {
2855 if (item && src_item) {
2856 switch (drag_context->action) {
2857 case GDK_ACTION_COPY:
2858 summary_copy_selected_to(folderview->summaryview, item);
2859 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2861 case GDK_ACTION_MOVE:
2862 case GDK_ACTION_DEFAULT:
2864 if (FOLDER_CLASS(src_item->folder)->remove_msg == NULL)
2865 summary_copy_selected_to(folderview->summaryview, item);
2867 summary_move_selected_to(folderview->summaryview, item);
2868 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2871 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2873 /* comes from folderview */
2875 gboolean folder_is_normal = TRUE;
2876 gboolean copy = (drag_context->action == GDK_ACTION_COPY);
2878 source = data->data + 17;
2879 if (gtk_clist_get_selection_info
2880 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0
2882 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2885 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2886 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2887 src_item = folder_find_item_from_identifier(source);
2891 src_item->stype == F_NORMAL &&
2892 !folder_has_parent_of_type(src_item, F_OUTBOX) &&
2893 !folder_has_parent_of_type(src_item, F_DRAFT) &&
2894 !folder_has_parent_of_type(src_item, F_QUEUE) &&
2895 !folder_has_parent_of_type(src_item, F_TRASH);
2896 if (!item || item->no_select || !src_item
2897 || !folder_is_normal) {
2898 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2902 folderview_move_folder(folderview, src_item, item, copy);
2903 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2905 folderview->nodes_to_recollapse = NULL;
2906 } else if (info == TARGET_MAIL_URI_LIST) {
2907 if (gtk_clist_get_selection_info
2908 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2911 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2913 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2914 debug_print("no node\n");
2917 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2919 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2920 debug_print("no item\n");
2923 folderview_finish_dnd(data->data, drag_context, time, item);
2927 static void folderview_drag_end_cb(GtkWidget *widget,
2928 GdkDragContext *drag_context,
2929 FolderView *folderview)
2931 drag_state_stop(folderview);
2932 g_slist_free(folderview->nodes_to_recollapse);
2933 folderview->nodes_to_recollapse = NULL;
2936 void folderview_register_popup(FolderViewPopup *fpopup)
2940 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2941 FolderView *folderview = folderviews->data;
2942 GtkItemFactory *factory;
2944 factory = create_ifactory(folderview, fpopup);
2945 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
2947 g_hash_table_insert(folderview_popups, fpopup->klass, fpopup);
2950 void folderview_unregister_popup(FolderViewPopup *fpopup)
2954 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2955 FolderView *folderview = folderviews->data;
2957 g_hash_table_remove(folderview->popups, fpopup->klass);
2959 g_hash_table_remove(folderview_popups, fpopup->klass);