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) &&
1673 update_info->item == folderview->summaryview->folder_item &&
1674 update_info->item != NULL)
1675 if (!quicksearch_is_active(folderview->summaryview->quicksearch))
1676 summary_show(folderview->summaryview, update_info->item);
1682 static gboolean folderview_gnode_func(GtkCTree *ctree, guint depth,
1683 GNode *gnode, GtkCTreeNode *cnode,
1686 FolderView *folderview = (FolderView *)data;
1687 FolderItem *item = FOLDER_ITEM(gnode->data);
1689 g_return_val_if_fail(item != NULL, FALSE);
1691 gtk_ctree_node_set_row_data(ctree, cnode, item);
1692 folderview_update_node(folderview, cnode);
1697 static void folderview_expand_func(GtkCTree *ctree, GtkCTreeNode *node,
1700 FolderView *folderview = (FolderView *)data;
1703 if (GTK_CTREE_ROW(node)->children) {
1704 item = gtk_ctree_node_get_row_data(ctree, node);
1705 g_return_if_fail(item != NULL);
1707 if (!item->collapsed)
1708 gtk_ctree_expand(ctree, node);
1710 folderview_update_node(folderview, node);
1714 static void set_special_folder(GtkCTree *ctree, FolderItem *item,
1715 GtkCTreeNode *root, GtkCTreeNode **prev)
1718 GtkCTreeNode *node, *parent, *sibling;
1720 node = gtk_ctree_find_by_row_data(ctree, root, item);
1722 g_warning("%s not found.\n", item->path);
1724 parent = GTK_CTREE_ROW(node)->parent;
1725 if (*prev && parent == GTK_CTREE_ROW(*prev)->parent)
1726 sibling = GTK_CTREE_ROW(*prev)->sibling;
1728 sibling = GTK_CTREE_ROW(parent)->children;
1732 tmp = gtk_ctree_node_get_row_data
1734 if (tmp->stype != F_NORMAL)
1735 sibling = GTK_CTREE_ROW(sibling)->sibling;
1739 if (node != sibling)
1740 gtk_ctree_move(ctree, node, parent, sibling);
1747 static void folderview_sort_folders(FolderView *folderview, GtkCTreeNode *root,
1750 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1751 GtkCTreeNode *prev = NULL;
1753 gtk_clist_freeze(GTK_CLIST(ctree));
1754 gtk_sctree_sort_recursive(ctree, root);
1755 if (root && GTK_CTREE_ROW(root)->parent) {
1756 gtk_clist_thaw(GTK_CLIST(ctree));
1759 set_special_folder(ctree, folder->inbox, root, &prev);
1760 set_special_folder(ctree, folder->outbox, root, &prev);
1761 set_special_folder(ctree, folder->draft, root, &prev);
1762 set_special_folder(ctree, folder->queue, root, &prev);
1763 set_special_folder(ctree, folder->trash, root, &prev);
1764 gtk_clist_thaw(GTK_CLIST(ctree));
1767 static void folderview_append_folder(FolderView *folderview, Folder *folder)
1769 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1772 g_return_if_fail(folder != NULL);
1774 root = gtk_sctree_insert_gnode(ctree, NULL, NULL, folder->node,
1775 folderview_gnode_func, folderview);
1776 gtk_ctree_pre_recursive(ctree, root, folderview_expand_func,
1778 folderview_sort_folders(folderview, root, folder);
1781 /* callback functions */
1782 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
1783 GdkEventButton *event)
1785 GtkCList *clist = GTK_CLIST(folderview->ctree);
1788 FolderViewPopup *fpopup;
1789 GtkItemFactory *fpopup_factory;
1791 FolderItem *special_trash = NULL, *special_queue = NULL;
1795 item = gtk_clist_get_row_data(clist, row);
1797 item = folderview_get_selected_item(folderview);
1799 g_return_if_fail(item != NULL);
1800 g_return_if_fail(item->folder != NULL);
1801 folder = item->folder;
1803 fpopup = g_hash_table_lookup(folderview_popups, folder->klass->idstr);
1805 fpopup_factory = g_hash_table_lookup(folderview->popups, folder->klass->idstr);
1807 fpopup = g_hash_table_lookup(folderview_popups, "common");
1808 fpopup_factory = g_hash_table_lookup(folderview->popups, "common");
1811 if (fpopup->set_sensitivity != NULL)
1812 fpopup->set_sensitivity(fpopup_factory, item);
1814 if (NULL != (ac = account_find_from_item(item))) {
1815 special_trash = account_get_special_folder(ac, F_TRASH);
1816 special_queue = account_get_special_folder(ac, F_QUEUE);
1819 if ((item == folder->trash || item == special_trash
1820 || folder_has_parent_of_type(item, F_TRASH)) &&
1821 gtk_item_factory_get_item(fpopup_factory, "/Empty trash...") == NULL) {
1822 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[0], folderview, 1);
1823 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[1], folderview, 1);
1824 } else if (item != folder->trash && (special_trash == NULL || item != special_trash)
1825 && !folder_has_parent_of_type(item, F_TRASH)) {
1826 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[0]);
1827 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[1]);
1830 if ((item == folder->queue || item == special_queue
1831 || folder_has_parent_of_type(item, F_QUEUE)) &&
1832 gtk_item_factory_get_item(fpopup_factory, "/Send queue...") == NULL) {
1833 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[0], folderview, 1);
1834 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[1], folderview, 1);
1835 } else if (item != folder->queue && (special_queue == NULL || item != special_queue)
1836 && !folder_has_parent_of_type(item, F_QUEUE)) {
1837 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[0]);
1838 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[1]);
1841 #define SET_SENS(name, sens) \
1842 menu_set_sensitive(fpopup_factory, name, sens)
1844 SET_SENS("/Mark all read", item->unread_msgs >= 1);
1845 SET_SENS("/Search folder...", item->total_msgs >= 1 &&
1846 folderview->selected == folderview->opened);
1847 SET_SENS("/Properties...", TRUE);
1848 SET_SENS("/Processing...", item->node->parent != NULL);
1849 if (item == folder->trash || item == special_trash
1850 || folder_has_parent_of_type(item, F_TRASH)) {
1851 GSList *msglist = folder_item_get_msg_list(item);
1852 SET_SENS("/Empty trash...", msglist != NULL);
1853 procmsg_msg_list_free(msglist);
1855 if (item == folder->queue || item == special_queue
1856 || folder_has_parent_of_type(item, F_QUEUE)) {
1857 GSList *msglist = folder_item_get_msg_list(item);
1858 SET_SENS("/Send queue...", msglist != NULL);
1859 procmsg_msg_list_free(msglist);
1863 popup = gtk_item_factory_get_widget(fpopup_factory, fpopup->path);
1864 gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
1865 event->button, event->time);
1870 static gboolean folderview_button_pressed(GtkWidget *ctree, GdkEventButton *event,
1871 FolderView *folderview)
1873 GtkCList *clist = GTK_CLIST(ctree);
1874 gint prev_row = -1, row = -1, column = -1;
1876 if (!event) return FALSE;
1878 if (event->button == 1 || event->button == 2) {
1879 if (!gtk_ctree_is_hot_spot (GTK_CTREE(clist), event->x, event->y))
1880 folderview->open_folder = TRUE;
1882 if (event->type == GDK_2BUTTON_PRESS) {
1883 if (clist->selection) {
1886 node = GTK_CTREE_NODE(clist->selection->data);
1888 gtk_ctree_toggle_expansion(
1891 folderview->open_folder = FALSE;
1898 if (event->button == 2 || event->button == 3) {
1900 if (clist->selection) {
1903 node = GTK_CTREE_NODE(clist->selection->data);
1905 prev_row = gtkut_ctree_get_nth_from_node
1906 (GTK_CTREE(ctree), node);
1909 if (!gtk_clist_get_selection_info(clist, event->x, event->y,
1912 if (prev_row != row) {
1913 gtk_clist_unselect_all(clist);
1914 if (event->button == 2)
1915 folderview_select_node
1917 gtk_ctree_node_nth(GTK_CTREE(ctree),
1920 gtk_clist_select_row(clist, row, column);
1924 if (event->button != 3) return FALSE;
1926 folderview_set_sens_and_popup_menu(folderview, row, event);
1930 static gboolean folderview_button_released(GtkWidget *ctree, GdkEventButton *event,
1931 FolderView *folderview)
1933 if (!event) return FALSE;
1935 if (event->button == 1 && folderview->open_folder == FALSE &&
1936 folderview->opened != NULL) {
1937 gtkut_ctree_set_focus_row(GTK_CTREE(ctree),
1938 folderview->opened);
1939 gtk_ctree_select(GTK_CTREE(ctree), folderview->opened);
1945 static gboolean folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
1946 FolderView *folderview)
1948 if (!event) return FALSE;
1950 if (quicksearch_has_focus(folderview->summaryview->quicksearch))
1953 switch (event->keyval) {
1955 if (folderview->selected) {
1956 folderview_select_node(folderview,
1957 folderview->selected);
1961 if (folderview->selected) {
1962 if (folderview->opened == folderview->selected &&
1963 (!folderview->summaryview->folder_item ||
1964 folderview->summaryview->folder_item->total_msgs == 0))
1965 folderview_select_next_unread(folderview, TRUE);
1967 folderview_select_node(folderview,
1968 folderview->selected);
1978 typedef struct _PostponedSelectData
1983 FolderView *folderview;
1984 } PostponedSelectData;
1986 static gboolean postpone_select(void *data)
1988 PostponedSelectData *psdata = (PostponedSelectData *)data;
1989 debug_print("trying again\n");
1990 psdata->folderview->open_folder = TRUE;
1991 main_window_cursor_normal(psdata->folderview->mainwin);
1992 STATUSBAR_POP(psdata->folderview->mainwin);
1993 folderview_selected(psdata->ctree, psdata->row,
1994 psdata->column, psdata->folderview);
1999 static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row,
2000 gint column, FolderView *folderview)
2002 static gboolean can_select = TRUE; /* exclusive lock */
2008 folderview->selected = row;
2010 debug_print("newly selected %p, opened %p\n", folderview->selected,
2011 folderview->opened);
2012 if (folderview->opened == row) {
2013 folderview->open_folder = FALSE;
2018 if (!can_select || summary_is_locked(folderview->summaryview)) {
2019 if (folderview->opened) {
2020 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2021 gtk_ctree_select(ctree, folderview->opened);
2023 folderview->open_folder = FALSE;
2028 if (!folderview->open_folder) {
2032 item = gtk_ctree_node_get_row_data(ctree, row);
2033 if (!item || item->no_select) {
2035 folderview->open_folder = FALSE;
2041 /* Save cache for old folder */
2042 /* We don't want to lose all caches if sylpheed crashed */
2043 if (folderview->opened) {
2044 FolderItem *olditem;
2046 olditem = gtk_ctree_node_get_row_data(ctree, folderview->opened);
2048 buf = g_strdup_printf(_("Closing Folder %s..."),
2049 olditem->path ? olditem->path:olditem->name);
2050 /* will be null if we just moved the previously opened folder */
2051 STATUSBAR_PUSH(folderview->mainwin, buf);
2052 main_window_cursor_wait(folderview->mainwin);
2054 summary_save_prefs_to_folderitem(folderview->summaryview, olditem);
2055 summary_show(folderview->summaryview, NULL);
2056 folder_item_close(olditem);
2057 main_window_cursor_normal(folderview->mainwin);
2058 STATUSBAR_POP(folderview->mainwin);
2062 /* CLAWS: set compose button type: news folder items
2063 * always have a news folder as parent */
2065 toolbar_set_compose_button
2066 (folderview->mainwin->toolbar,
2067 FOLDER_TYPE(item->folder) == F_NEWS ?
2068 COMPOSEBUTTON_NEWS : COMPOSEBUTTON_MAIL);
2071 debug_print("Folder %s is selected\n", item->path);
2073 if (!GTK_CTREE_ROW(row)->children)
2074 gtk_ctree_expand(ctree, row);
2075 if (folderview->opened &&
2076 !GTK_CTREE_ROW(folderview->opened)->children)
2077 gtk_ctree_collapse(ctree, folderview->opened);
2079 /* ungrab the mouse event */
2080 if (GTK_WIDGET_HAS_GRAB(ctree)) {
2081 gtk_grab_remove(GTK_WIDGET(ctree));
2082 if (gdk_pointer_is_grabbed())
2083 gdk_pointer_ungrab(GDK_CURRENT_TIME);
2087 buf = g_strdup_printf(_("Opening Folder %s..."), item->path ?
2088 item->path : "(null)");
2089 debug_print("%s\n", buf);
2090 STATUSBAR_PUSH(folderview->mainwin, buf);
2093 main_window_cursor_wait(folderview->mainwin);
2095 res = folder_item_open(item);
2097 main_window_cursor_normal(folderview->mainwin);
2098 STATUSBAR_POP(folderview->mainwin);
2100 alertpanel_error(_("Folder could not be opened."));
2102 folderview->open_folder = FALSE;
2106 } else if (res == -2) {
2107 PostponedSelectData *data = g_new0(PostponedSelectData, 1);
2108 data->ctree = ctree;
2110 data->column = column;
2111 data->folderview = folderview;
2112 debug_print("postponing open of %s till end of scan\n",
2113 item->path ? item->path:item->name);
2114 folderview->open_folder = FALSE;
2116 g_timeout_add(500, postpone_select, data);
2121 main_window_cursor_normal(folderview->mainwin);
2124 summary_set_prefs_from_folderitem(folderview->summaryview, item);
2125 opened = summary_show(folderview->summaryview, item);
2127 folder_clean_cache_memory(item);
2130 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2131 gtk_ctree_select(ctree, folderview->opened);
2133 folderview->opened = row;
2134 if (gtk_ctree_node_is_visible(ctree, row)
2135 != GTK_VISIBILITY_FULL)
2136 gtk_ctree_node_moveto(ctree, row, -1, 0.5, 0);
2139 STATUSBAR_POP(folderview->mainwin);
2141 folderview->open_folder = FALSE;
2146 static void folderview_tree_expanded(GtkCTree *ctree, GtkCTreeNode *node,
2147 FolderView *folderview)
2151 item = gtk_ctree_node_get_row_data(ctree, node);
2152 g_return_if_fail(item != NULL);
2153 item->collapsed = FALSE;
2154 folderview_update_node(folderview, node);
2157 static void folderview_tree_collapsed(GtkCTree *ctree, GtkCTreeNode *node,
2158 FolderView *folderview)
2162 item = gtk_ctree_node_get_row_data(ctree, node);
2163 g_return_if_fail(item != NULL);
2164 item->collapsed = TRUE;
2165 folderview_update_node(folderview, node);
2168 static void folderview_popup_close(GtkMenuShell *menu_shell,
2169 FolderView *folderview)
2171 if (!folderview->opened) return;
2173 gtk_ctree_select(GTK_CTREE(folderview->ctree), folderview->opened);
2176 static void folderview_col_resized(GtkCList *clist, gint column, gint width,
2177 FolderView *folderview)
2179 FolderColumnType type = folderview->col_state[column].type;
2181 prefs_common.folder_col_size[type] = width;
2184 static void folderview_create_folder_node_recursive(FolderView *folderview, FolderItem *item)
2188 folderview_create_folder_node(folderview, item);
2190 if (!item || !item->folder || !item->folder->node)
2193 srcnode = item->folder->node;
2194 srcnode = g_node_find(srcnode, G_PRE_ORDER, G_TRAVERSE_ALL, item);
2195 srcnode = srcnode->children;
2196 while (srcnode != NULL) {
2197 if (srcnode && srcnode->data) {
2198 FolderItem *next_item = (FolderItem*) srcnode->data;
2199 folderview_create_folder_node_recursive(folderview, next_item);
2201 srcnode = srcnode->next;
2205 static void folderview_create_folder_node(FolderView *folderview, FolderItem *item)
2207 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2208 gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
2209 GtkCTreeNode *node, *parent_node;
2210 gint *col_pos = folderview->col_pos;
2211 FolderItemUpdateData hookdata;
2213 parent_node = gtk_ctree_find_by_row_data(ctree, NULL, folder_item_parent(item));
2214 if (parent_node == NULL)
2217 gtk_clist_freeze(GTK_CLIST(ctree));
2219 text[col_pos[F_COL_FOLDER]] = item->name;
2220 node = gtk_sctree_insert_node(ctree, parent_node, NULL, text,
2222 folderxpm, folderxpmmask,
2223 folderopenxpm, folderopenxpmmask,
2225 gtk_ctree_expand(ctree, parent_node);
2226 gtk_ctree_node_set_row_data(ctree, node, item);
2228 gtk_ctree_node_set_row_style(ctree, node, normal_style);
2229 folderview_sort_folders(folderview, parent_node, item->folder);
2231 hookdata.item = item;
2232 hookdata.update_flags = F_ITEM_UPDATE_NAME;
2233 hookdata.msg = NULL;
2234 hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &hookdata);
2236 gtk_clist_thaw(GTK_CLIST(ctree));
2239 static void folderview_empty_trash_cb(FolderView *folderview, guint action,
2242 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2244 GSList *mlist = NULL;
2246 FolderItem *special_trash = NULL;
2249 if (!folderview->selected) return;
2250 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2251 g_return_if_fail(item != NULL);
2252 g_return_if_fail(item->folder != NULL);
2254 if (NULL != (ac = account_find_from_item(item)))
2255 special_trash = account_get_special_folder(ac, F_TRASH);
2257 if (item != item->folder->trash && item != special_trash
2258 && !folder_has_parent_of_type(item, F_TRASH)) return;
2260 if (prefs_common.ask_on_clean) {
2261 if (alertpanel(_("Empty trash"),
2262 _("Delete all messages in trash?"),
2263 GTK_STOCK_CANCEL, _("+_Empty trash"), NULL) != G_ALERTALTERNATE)
2267 mlist = folder_item_get_msg_list(item);
2269 for (cur = mlist ; cur != NULL ; cur = cur->next) {
2270 MsgInfo * msginfo = (MsgInfo *) cur->data;
2271 if (MSG_IS_LOCKED(msginfo->flags))
2273 /* is it partially received? (partial_recv isn't cached) */
2274 if (msginfo->total_size != 0 &&
2275 msginfo->size != (off_t)msginfo->total_size)
2276 partial_mark_for_delete(msginfo);
2278 procmsg_msg_list_free(mlist);
2280 folder_item_remove_all_msg(item);
2283 static void folderview_send_queue_cb(FolderView *folderview, guint action,
2286 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2288 FolderItem *special_queue = NULL;
2290 gchar *errstr = NULL;
2292 if (!folderview->selected) return;
2293 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2294 g_return_if_fail(item != NULL);
2295 g_return_if_fail(item->folder != NULL);
2297 if (NULL != (ac = account_find_from_item(item)))
2298 special_queue = account_get_special_folder(ac, F_QUEUE);
2300 if (item != item->folder->queue && item != special_queue
2301 && !folder_has_parent_of_type(item, F_QUEUE)) return;
2303 if (procmsg_queue_is_empty(item))
2306 if (prefs_common.work_offline)
2307 if (alertpanel(_("Offline warning"),
2308 _("You're working offline. Override?"),
2309 GTK_STOCK_NO, GTK_STOCK_YES,
2310 NULL) != G_ALERTALTERNATE)
2313 /* ask for confirmation before sending queued messages only
2314 in online mode and if there is at least one message queued
2315 in any of the folder queue
2317 if (prefs_common.confirm_send_queued_messages) {
2318 if (!prefs_common.work_offline) {
2319 if (alertpanel(_("Send queued messages"),
2320 _("Send all queued messages?"),
2321 GTK_STOCK_CANCEL, _("_Send"),
2322 NULL) != G_ALERTALTERNATE)
2327 if (procmsg_send_queue(item, prefs_common.savemsg, &errstr) < 0) {
2329 alertpanel_error_log(_("Some errors occurred while "
2330 "sending queued messages."));
2332 gchar *tmp = g_strdup_printf(_("Some errors occurred "
2333 "while sending queued messages:\n%s"), errstr);
2335 alertpanel_error_log(tmp);
2341 static void folderview_search_cb(FolderView *folderview, guint action,
2344 summary_search(folderview->summaryview);
2347 static void folderview_property_cb(FolderView *folderview, guint action,
2350 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2353 if (!folderview->selected) return;
2355 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2356 g_return_if_fail(item != NULL);
2357 g_return_if_fail(item->folder != NULL);
2359 prefs_folder_item_open(item);
2362 static void folderview_recollapse_nodes(FolderView *folderview, GtkCTreeNode *node)
2364 GSList *list = NULL;
2365 GSList *done = NULL;
2366 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2368 for (list = folderview->nodes_to_recollapse; list != NULL; list = g_slist_next(list)) {
2369 if (!gtkut_ctree_node_is_parent(GTK_CTREE_NODE(list->data), node)
2370 && list->data != node) {
2371 gtk_ctree_collapse(ctree, GTK_CTREE_NODE(list->data));
2372 done = g_slist_append(done, GTK_CTREE_NODE(list->data));
2375 for (list = done; list != NULL; list = g_slist_next(list)) {
2376 folderview->nodes_to_recollapse = g_slist_remove(folderview->nodes_to_recollapse,
2382 void folderview_move_folder(FolderView *folderview, FolderItem *from_folder,
2383 FolderItem *to_folder, gboolean copy)
2385 FolderItem *from_parent = NULL;
2386 FolderItem *new_folder = NULL;
2387 GtkCTreeNode *src_node = NULL;
2391 g_return_if_fail(folderview != NULL);
2392 g_return_if_fail(from_folder != NULL);
2393 g_return_if_fail(to_folder != NULL);
2395 src_node = gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree), NULL, from_folder);
2396 from_parent = folder_item_parent(from_folder);
2398 if (prefs_common.warn_dnd) {
2399 buf = g_strdup_printf(copy ? _("Do you really want to copy folder '%s' in '%s' ?"):
2400 _("Do you really want to make folder '%s' a sub-folder of '%s' ?"),
2401 from_folder->name, to_folder->name);
2402 status = alertpanel_full(copy ? _("Copy folder"):_("Move folder"), buf,
2403 GTK_STOCK_NO, GTK_STOCK_YES, NULL, TRUE,
2404 NULL, ALERT_QUESTION, G_ALERTDEFAULT);
2407 if ((status & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
2409 else if (status & G_ALERTDISABLE)
2410 prefs_common.warn_dnd = FALSE;
2413 buf = g_strdup_printf(copy ? _("Copying %s to %s..."):_("Moving %s to %s..."),
2414 from_folder->name, to_folder->name);
2415 STATUSBAR_PUSH(folderview->mainwin, buf);
2417 summary_clear_all(folderview->summaryview);
2418 folderview->opened = NULL;
2419 folderview->selected = NULL;
2420 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), FALSE);
2422 main_window_cursor_wait(folderview->mainwin);
2424 statusbar_verbosity_set(FALSE);
2425 folder_item_update_freeze();
2426 if ((status = folder_item_move_to(from_folder, to_folder, &new_folder, copy)) == F_MOVE_OK) {
2427 statusbar_verbosity_set(FALSE);
2428 main_window_cursor_normal(folderview->mainwin);
2429 STATUSBAR_POP(folderview->mainwin);
2430 folder_item_update_thaw();
2431 folder_item_update_recursive(new_folder, F_ITEM_UPDATE_MSGCNT);
2433 folderview_sort_folders(folderview,
2434 gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree),
2435 NULL, to_folder), new_folder->folder);
2436 folderview_select(folderview, new_folder);
2438 statusbar_verbosity_set(FALSE);
2439 main_window_cursor_normal(folderview->mainwin);
2440 STATUSBAR_POP(folderview->mainwin);
2441 folder_item_update_thaw();
2443 case F_MOVE_FAILED_DEST_IS_PARENT:
2444 alertpanel_error(_("Source and destination are the same."));
2446 case F_MOVE_FAILED_DEST_IS_CHILD:
2447 alertpanel_error(copy ? _("Can't copy a folder to one of its children."):
2448 _("Can't move a folder to one of its children."));
2450 case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX:
2451 alertpanel_error(_("Folder moving cannot be done between different mailboxes."));
2454 alertpanel_error(copy ? _("Copy failed!"):_("Move failed!"));
2459 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), TRUE);
2462 static gint folderview_clist_compare(GtkCList *clist,
2463 gconstpointer ptr1, gconstpointer ptr2)
2465 FolderItem *item1 = ((GtkCListRow *)ptr1)->data;
2466 FolderItem *item2 = ((GtkCListRow *)ptr2)->data;
2469 return (item2->name != NULL);
2473 return g_utf8_collate(item1->name, item2->name);
2476 static void folderview_processing_cb(FolderView *folderview, guint action,
2479 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2483 if (!folderview->selected) return;
2485 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2486 g_return_if_fail(item != NULL);
2487 g_return_if_fail(item->folder != NULL);
2489 id = folder_item_get_identifier(item);
2490 title = g_strdup_printf (_("Processing configuration for folder %s"), id);
2493 prefs_filtering_open(&item->prefs->processing, title,
2494 MANUAL_ANCHOR_PROCESSING, NULL, NULL, FALSE);
2498 void folderview_set_target_folder_color(gint color_op)
2502 FolderView *folderview;
2504 for (list = folderview_list; list != NULL; list = list->next) {
2505 folderview = (FolderView *)list->data;
2506 gtkut_convert_int_to_gdk_color(color_op, &folderview->color_op);
2508 bold_tgtfold_style->fg[GTK_STATE_NORMAL] =
2509 folderview->color_op;
2515 static gchar *last_font = NULL;
2516 void folderview_reflect_prefs_pixmap_theme(FolderView *folderview)
2524 void folderview_reflect_prefs(void)
2526 gboolean update_font = TRUE;
2527 FolderView *folderview = mainwindow_get_mainwindow()->folderview;
2528 FolderItem *item = folderview_get_selected_item(folderview);
2529 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2530 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2531 gint height = pos->value;
2533 if (last_font && !strcmp(last_font, NORMAL_FONT))
2534 update_font = FALSE;
2537 last_font = g_strdup(NORMAL_FONT);
2540 normal_style = normal_color_style = bold_style =
2541 bold_color_style = bold_tgtfold_style = NULL;
2543 folderview_init(folderview);
2545 gtk_clist_freeze(GTK_CLIST(folderview->ctree));
2546 folderview_column_set_titles(folderview);
2547 folderview_set_all();
2549 g_signal_handlers_block_by_func
2550 (G_OBJECT(folderview->ctree),
2551 G_CALLBACK(folderview_selected), folderview);
2554 GtkCTreeNode *node = gtk_ctree_find_by_row_data(
2555 GTK_CTREE(folderview->ctree), NULL, item);
2557 folderview_select(folderview, item);
2558 folderview->open_folder = FALSE;
2559 folderview->selected = node;
2562 g_signal_handlers_unblock_by_func
2563 (G_OBJECT(folderview->ctree),
2564 G_CALLBACK(folderview_selected), folderview);
2566 pos = gtk_scrolled_window_get_vadjustment(
2567 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2568 gtk_adjustment_set_value(pos, height);
2569 gtk_clist_thaw(GTK_CLIST(folderview->ctree));
2572 static void drag_state_stop(FolderView *folderview)
2574 if (folderview->drag_timer)
2575 g_source_remove(folderview->drag_timer);
2576 folderview->drag_timer = 0;
2577 folderview->drag_node = NULL;
2580 static gint folderview_defer_expand(FolderView *folderview)
2582 if (folderview->drag_node) {
2583 folderview_recollapse_nodes(folderview, folderview->drag_node);
2584 if (folderview->drag_item->collapsed) {
2585 gtk_ctree_expand(GTK_CTREE(folderview->ctree), folderview->drag_node);
2586 folderview->nodes_to_recollapse = g_slist_append
2587 (folderview->nodes_to_recollapse, folderview->drag_node);
2590 folderview->drag_item = NULL;
2591 folderview->drag_timer = 0;
2595 static void drag_state_start(FolderView *folderview, GtkCTreeNode *node, FolderItem *item)
2597 /* the idea is that we call drag_state_start() whenever we want expansion to
2598 * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
2599 * we need to call drag_state_stop() */
2600 drag_state_stop(folderview);
2601 /* request expansion */
2602 if (0 != (folderview->drag_timer = g_timeout_add
2603 (prefs_common.hover_timeout,
2604 (GtkFunction)folderview_defer_expand,
2606 folderview->drag_node = node;
2607 folderview->drag_item = item;
2611 static void folderview_start_drag(GtkWidget *widget, gint button, GdkEvent *event,
2612 FolderView *folderview)
2614 GdkDragContext *context;
2616 g_return_if_fail(folderview != NULL);
2617 if (folderview->selected == NULL) return;
2618 if (folderview->nodes_to_recollapse)
2619 g_slist_free(folderview->nodes_to_recollapse);
2620 folderview->nodes_to_recollapse = NULL;
2621 context = gtk_drag_begin(widget, folderview->target_list,
2622 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
2623 gtk_drag_set_icon_default(context);
2626 static void folderview_drag_data_get(GtkWidget *widget,
2627 GdkDragContext *drag_context,
2628 GtkSelectionData *selection_data,
2631 FolderView *folderview)
2635 gchar *source = NULL;
2636 if (info == TARGET_DUMMY) {
2637 for (cur = GTK_CLIST(folderview->ctree)->selection;
2638 cur != NULL; cur = cur->next) {
2639 item = gtk_ctree_node_get_row_data
2640 (GTK_CTREE(folderview->ctree),
2641 GTK_CTREE_NODE(cur->data));
2643 source = g_strdup_printf ("FROM_OTHER_FOLDER%s", folder_item_get_identifier(item));
2644 gtk_selection_data_set(selection_data,
2645 selection_data->target, 8,
2646 source, strlen(source));
2652 g_warning("unknown info %d\n", info);
2656 static gboolean folderview_update_folder(gpointer source, gpointer userdata)
2658 FolderUpdateData *hookdata;
2659 FolderView *folderview;
2663 folderview = (FolderView *) userdata;
2664 g_return_val_if_fail(hookdata != NULL, FALSE);
2665 g_return_val_if_fail(folderview != NULL, FALSE);
2667 ctree = folderview->ctree;
2668 g_return_val_if_fail(ctree != NULL, FALSE);
2670 if (hookdata->update_flags & FOLDER_ADD_FOLDERITEM)
2671 folderview_create_folder_node(folderview, hookdata->item);
2672 else if (hookdata->update_flags & FOLDER_RENAME_FOLDERITEM) {
2673 GtkCTreeNode *node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree),
2674 NULL, folder_item_parent(hookdata->item));
2675 folderview_sort_folders(folderview, node, hookdata->folder);
2676 } else if (hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM) {
2679 node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree), NULL, hookdata->item);
2681 gtk_ctree_remove_node(GTK_CTREE(ctree), node);
2682 } else if (hookdata->update_flags & (FOLDER_TREE_CHANGED | FOLDER_ADD_FOLDER | FOLDER_REMOVE_FOLDER))
2683 folderview_set(folderview);
2688 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
2689 GdkDragContext *context,
2693 FolderView *folderview)
2696 FolderItem *item = NULL, *src_item = NULL;
2697 GtkCTreeNode *node = NULL;
2698 gboolean acceptable = FALSE;
2699 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2700 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2701 int height = (int)pos->page_size;
2702 int total_height = (int)pos->upper;
2703 int vpos = (int) pos->value;
2705 if (gtk_clist_get_selection_info
2706 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
2707 GtkWidget *srcwidget;
2709 if (y > height - 24 && height + vpos < total_height)
2710 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
2712 if (y < 48 && y > 0)
2713 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
2715 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2716 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2717 src_item = folderview->summaryview->folder_item;
2719 srcwidget = gtk_drag_get_source_widget(context);
2720 if (srcwidget == summary_get_main_widget(folderview->summaryview)) {
2721 /* comes from summaryview */
2722 /* we are copying messages, so only accept folder items that are not
2723 the source item, are no root items and can copy messages */
2724 if (item && item->folder && folder_item_parent(item) != NULL && src_item &&
2725 src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2726 FOLDER_TYPE(item->folder) != F_UNKNOWN)
2728 } else if (srcwidget == folderview->ctree) {
2729 /* comes from folderview */
2730 /* we are moving folder items, only accept folders that are not
2731 the source items and can copy messages and create folder items */
2732 if (item && item->folder && src_item && src_item != item &&
2733 FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2734 FOLDER_CLASS(item->folder)->create_folder != NULL &&
2735 ((FOLDER_TYPE(item->folder) != F_UNKNOWN && FOLDER_TYPE(src_item->folder) != F_UNKNOWN)
2736 || item->folder == src_item->folder))
2739 /* comes from another app */
2740 /* we are adding messages, so only accept folder items that are
2741 no root items and can copy messages */
2742 if (item && item->folder && folder_item_parent(item) != NULL
2743 && FOLDER_CLASS(item->folder)->add_msg != NULL &&
2744 FOLDER_TYPE(item->folder) != F_UNKNOWN)
2749 if (acceptable || (src_item && src_item == item))
2750 drag_state_start(folderview, node, item);
2753 g_signal_handlers_block_by_func
2755 G_CALLBACK(folderview_selected), folderview);
2756 gtk_ctree_select(GTK_CTREE(widget), node);
2757 g_signal_handlers_unblock_by_func
2759 G_CALLBACK(folderview_selected), folderview);
2760 gdk_drag_status(context,
2761 (context->actions == GDK_ACTION_COPY ?
2762 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
2764 if (folderview->opened)
2765 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2766 gdk_drag_status(context, 0, time);
2772 static void folderview_drag_leave_cb(GtkWidget *widget,
2773 GdkDragContext *context,
2775 FolderView *folderview)
2777 drag_state_stop(folderview);
2778 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2781 static void free_info (gpointer stuff, gpointer data)
2786 void folderview_finish_dnd(const gchar *data, GdkDragContext *drag_context,
2787 guint time, FolderItem *item)
2790 GSList *msglist = NULL;
2791 list = uri_list_extract_filenames(data);
2792 if (!(item && item->folder && folder_item_parent(item) != NULL
2793 && FOLDER_CLASS(item->folder)->add_msg != NULL))
2795 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2796 debug_print("item doesn't fit\n");
2800 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2801 debug_print("list is empty\n");
2804 for (tmp = list; tmp != NULL; tmp = tmp->next) {
2805 MsgFileInfo *info = NULL;
2807 if (file_is_email((gchar *)tmp->data)) {
2808 info = g_new0(MsgFileInfo, 1);
2809 info->msginfo = NULL;
2810 info->file = (gchar *)tmp->data;
2811 msglist = g_slist_prepend(msglist, info);
2812 debug_print("file is a mail\n");
2814 debug_print("file isn't a mail\n");
2818 msglist = g_slist_reverse(msglist);
2819 folder_item_add_msgs(item, msglist, FALSE);
2820 g_slist_foreach(msglist, free_info, NULL);
2821 g_slist_free(msglist);
2822 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2824 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2826 list_free_strings(list);
2830 static void folderview_drag_received_cb(GtkWidget *widget,
2831 GdkDragContext *drag_context,
2834 GtkSelectionData *data,
2837 FolderView *folderview)
2840 FolderItem *item = NULL, *src_item;
2843 if (info == TARGET_DUMMY) {
2844 drag_state_stop(folderview);
2845 if ((void *)strstr(data->data, "FROM_OTHER_FOLDER") != (void *)data->data) {
2846 /* comes from summaryview */
2847 if (gtk_clist_get_selection_info
2848 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2851 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2852 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2853 src_item = folderview->summaryview->folder_item;
2855 /* re-check (due to acceptable possibly set for folder moves */
2856 if (!(item && item->folder && item->path && !item->no_select &&
2857 src_item && src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)) {
2860 if (item && src_item) {
2861 switch (drag_context->action) {
2862 case GDK_ACTION_COPY:
2863 summary_copy_selected_to(folderview->summaryview, item);
2864 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2866 case GDK_ACTION_MOVE:
2867 case GDK_ACTION_DEFAULT:
2869 if (FOLDER_CLASS(src_item->folder)->remove_msg == NULL)
2870 summary_copy_selected_to(folderview->summaryview, item);
2872 summary_move_selected_to(folderview->summaryview, item);
2873 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2876 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2878 /* comes from folderview */
2880 gboolean folder_is_normal = TRUE;
2881 gboolean copy = (drag_context->action == GDK_ACTION_COPY);
2883 source = data->data + 17;
2884 if (gtk_clist_get_selection_info
2885 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0
2887 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2890 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2891 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2892 src_item = folder_find_item_from_identifier(source);
2896 src_item->stype == F_NORMAL &&
2897 !folder_has_parent_of_type(src_item, F_OUTBOX) &&
2898 !folder_has_parent_of_type(src_item, F_DRAFT) &&
2899 !folder_has_parent_of_type(src_item, F_QUEUE) &&
2900 !folder_has_parent_of_type(src_item, F_TRASH);
2901 if (!item || item->no_select || !src_item
2902 || !folder_is_normal) {
2903 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2907 folderview_move_folder(folderview, src_item, item, copy);
2908 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2910 folderview->nodes_to_recollapse = NULL;
2911 } else if (info == TARGET_MAIL_URI_LIST) {
2912 if (gtk_clist_get_selection_info
2913 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2916 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2918 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2919 debug_print("no node\n");
2922 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2924 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2925 debug_print("no item\n");
2928 folderview_finish_dnd(data->data, drag_context, time, item);
2932 static void folderview_drag_end_cb(GtkWidget *widget,
2933 GdkDragContext *drag_context,
2934 FolderView *folderview)
2936 drag_state_stop(folderview);
2937 g_slist_free(folderview->nodes_to_recollapse);
2938 folderview->nodes_to_recollapse = NULL;
2941 void folderview_register_popup(FolderViewPopup *fpopup)
2945 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2946 FolderView *folderview = folderviews->data;
2947 GtkItemFactory *factory;
2949 factory = create_ifactory(folderview, fpopup);
2950 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
2952 g_hash_table_insert(folderview_popups, fpopup->klass, fpopup);
2955 void folderview_unregister_popup(FolderViewPopup *fpopup)
2959 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2960 FolderView *folderview = folderviews->data;
2962 g_hash_table_remove(folderview->popups, fpopup->klass);
2964 g_hash_table_remove(folderview_popups, fpopup->klass);