2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2006 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"
72 #define COL_FOLDER_WIDTH 150
73 #define COL_NUM_WIDTH 32
75 static GList *folderview_list = NULL;
77 static GtkStyle *normal_style;
78 static GtkStyle *normal_color_style;
79 static GtkStyle *bold_style;
80 static GtkStyle *bold_color_style;
81 static GtkStyle *bold_tgtfold_style;
83 static GdkPixmap *inboxxpm;
84 static GdkBitmap *inboxxpmmask;
85 static GdkPixmap *inboxhrmxpm;
86 static GdkBitmap *inboxhrmxpmmask;
87 static GdkPixmap *inboxopenxpm;
88 static GdkBitmap *inboxopenxpmmask;
89 static GdkPixmap *inboxopenhrmxpm;
90 static GdkBitmap *inboxopenhrmxpmmask;
91 static GdkPixmap *outboxxpm;
92 static GdkBitmap *outboxxpmmask;
93 static GdkPixmap *outboxhrmxpm;
94 static GdkBitmap *outboxhrmxpmmask;
95 static GdkPixmap *outboxopenxpm;
96 static GdkBitmap *outboxopenxpmmask;
97 static GdkPixmap *outboxopenhrmxpm;
98 static GdkBitmap *outboxopenhrmxpmmask;
99 static GdkPixmap *folderxpm;
100 static GdkBitmap *folderxpmmask;
101 static GdkPixmap *folderhrmxpm;
102 static GdkBitmap *folderhrmxpmmask;
103 static GdkPixmap *folderopenxpm;
104 static GdkBitmap *folderopenxpmmask;
105 static GdkPixmap *folderopenhrmxpm;
106 static GdkBitmap *folderopenhrmxpmmask;
107 static GdkPixmap *trashopenxpm;
108 static GdkBitmap *trashopenxpmmask;
109 static GdkPixmap *trashopenhrmxpm;
110 static GdkBitmap *trashopenhrmxpmmask;
111 static GdkPixmap *trashxpm;
112 static GdkBitmap *trashxpmmask;
113 static GdkPixmap *trashhrmxpm;
114 static GdkBitmap *trashhrmxpmmask;
115 static GdkPixmap *queuexpm;
116 static GdkBitmap *queuexpmmask;
117 static GdkPixmap *queuehrmxpm;
118 static GdkBitmap *queuehrmxpmmask;
119 static GdkPixmap *queueopenxpm;
120 static GdkBitmap *queueopenxpmmask;
121 static GdkPixmap *queueopenhrmxpm;
122 static GdkBitmap *queueopenhrmxpmmask;
123 static GdkPixmap *draftsxpm;
124 static GdkBitmap *draftsxpmmask;
125 static GdkPixmap *draftsopenxpm;
126 static GdkBitmap *draftsopenxpmmask;
127 static GdkPixmap *noselectxpm;
128 static GdkBitmap *noselectxpmmask;
130 static GdkPixmap *m_inboxxpm;
131 static GdkBitmap *m_inboxxpmmask;
132 static GdkPixmap *m_inboxhrmxpm;
133 static GdkBitmap *m_inboxhrmxpmmask;
134 static GdkPixmap *m_inboxopenxpm;
135 static GdkBitmap *m_inboxopenxpmmask;
136 static GdkPixmap *m_inboxopenhrmxpm;
137 static GdkBitmap *m_inboxopenhrmxpmmask;
138 static GdkPixmap *m_outboxxpm;
139 static GdkBitmap *m_outboxxpmmask;
140 static GdkPixmap *m_outboxhrmxpm;
141 static GdkBitmap *m_outboxhrmxpmmask;
142 static GdkPixmap *m_outboxopenxpm;
143 static GdkBitmap *m_outboxopenxpmmask;
144 static GdkPixmap *m_outboxopenhrmxpm;
145 static GdkBitmap *m_outboxopenhrmxpmmask;
146 static GdkPixmap *m_folderxpm;
147 static GdkBitmap *m_folderxpmmask;
148 static GdkPixmap *m_folderhrmxpm;
149 static GdkBitmap *m_folderhrmxpmmask;
150 static GdkPixmap *m_folderopenxpm;
151 static GdkBitmap *m_folderopenxpmmask;
152 static GdkPixmap *m_folderopenhrmxpm;
153 static GdkBitmap *m_folderopenhrmxpmmask;
154 static GdkPixmap *m_trashopenxpm;
155 static GdkBitmap *m_trashopenxpmmask;
156 static GdkPixmap *m_trashopenhrmxpm;
157 static GdkBitmap *m_trashopenhrmxpmmask;
158 static GdkPixmap *m_trashxpm;
159 static GdkBitmap *m_trashxpmmask;
160 static GdkPixmap *m_trashhrmxpm;
161 static GdkBitmap *m_trashhrmxpmmask;
162 static GdkPixmap *m_queuexpm;
163 static GdkBitmap *m_queuexpmmask;
164 static GdkPixmap *m_queuehrmxpm;
165 static GdkBitmap *m_queuehrmxpmmask;
166 static GdkPixmap *m_queueopenxpm;
167 static GdkBitmap *m_queueopenxpmmask;
168 static GdkPixmap *m_queueopenhrmxpm;
169 static GdkBitmap *m_queueopenhrmxpmmask;
170 static GdkPixmap *m_draftsxpm;
171 static GdkBitmap *m_draftsxpmmask;
172 static GdkPixmap *m_draftsopenxpm;
173 static GdkBitmap *m_draftsopenxpmmask;
175 static GdkPixmap *newxpm;
176 static GdkBitmap *newxpmmask;
177 static GdkPixmap *unreadxpm;
178 static GdkBitmap *unreadxpmmask;
179 static GdkPixmap *readxpm;
180 static GdkBitmap *readxpmmask;
183 static void folderview_select_node (FolderView *folderview,
185 static void folderview_set_folders (FolderView *folderview);
186 static void folderview_sort_folders (FolderView *folderview,
189 static void folderview_append_folder (FolderView *folderview,
191 static void folderview_update_node (FolderView *folderview,
194 static gint folderview_clist_compare (GtkCList *clist,
198 /* callback functions */
199 static gboolean folderview_button_pressed (GtkWidget *ctree,
200 GdkEventButton *event,
201 FolderView *folderview);
202 static gboolean folderview_button_released (GtkWidget *ctree,
203 GdkEventButton *event,
204 FolderView *folderview);
205 static gboolean folderview_key_pressed (GtkWidget *widget,
207 FolderView *folderview);
208 static void folderview_selected (GtkCTree *ctree,
211 FolderView *folderview);
212 static void folderview_tree_expanded (GtkCTree *ctree,
214 FolderView *folderview);
215 static void folderview_tree_collapsed (GtkCTree *ctree,
217 FolderView *folderview);
218 static void folderview_popup_close (GtkMenuShell *menu_shell,
219 FolderView *folderview);
220 static void folderview_col_resized (GtkCList *clist,
223 FolderView *folderview);
225 static void mark_all_read_cb (FolderView *folderview,
229 static void folderview_empty_trash_cb (FolderView *folderview,
233 static void folderview_send_queue_cb (FolderView *folderview,
237 static void folderview_search_cb (FolderView *folderview,
241 static void folderview_property_cb (FolderView *folderview,
245 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
246 GdkDragContext *context,
250 FolderView *folderview);
251 static void folderview_drag_leave_cb (GtkWidget *widget,
252 GdkDragContext *context,
254 FolderView *folderview);
255 static void folderview_drag_received_cb (GtkWidget *widget,
256 GdkDragContext *drag_context,
259 GtkSelectionData *data,
262 FolderView *folderview);
263 static void folderview_start_drag (GtkWidget *widget, gint button, GdkEvent *event,
264 FolderView *folderview);
265 static void folderview_drag_data_get (GtkWidget *widget,
266 GdkDragContext *drag_context,
267 GtkSelectionData *selection_data,
270 FolderView *folderview);
271 static void folderview_drag_end_cb (GtkWidget *widget,
272 GdkDragContext *drag_context,
273 FolderView *folderview);
275 void folderview_create_folder_node (FolderView *folderview,
277 gboolean folderview_update_folder (gpointer source,
279 gboolean folderview_update_item_claws (gpointer source,
281 static void folderview_processing_cb(FolderView *folderview, guint action,
283 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
284 GdkEventButton *event);
286 GHashTable *folderview_popups;
288 static GtkItemFactoryEntry folderview_common_popup_entries[] =
290 {N_("/Mark all re_ad"), NULL, mark_all_read_cb, 0, NULL},
291 {"/---", 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 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;
717 debug_print("Setting folder info...\n");
718 STATUSBAR_PUSH(mainwin, _("Setting folder info..."));
720 main_window_cursor_wait(mainwin);
722 folderview->selected = NULL;
723 folderview->opened = NULL;
725 gtk_clist_freeze(GTK_CLIST(ctree));
726 gtk_clist_clear(GTK_CLIST(ctree));
727 gtk_clist_thaw(GTK_CLIST(ctree));
728 gtk_clist_freeze(GTK_CLIST(ctree));
730 folderview_set_folders(folderview);
732 gtk_clist_thaw(GTK_CLIST(ctree));
733 main_window_cursor_normal(mainwin);
734 STATUSBAR_POP(mainwin);
737 void folderview_set_all(void)
741 for (list = folderview_list; list != NULL; list = list->next)
742 folderview_set((FolderView *)list->data);
745 void folderview_select(FolderView *folderview, FolderItem *item)
747 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
749 GtkCTreeNode *old_selected = folderview->selected;
753 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
754 if (node) folderview_select_node(folderview, node);
756 if (old_selected != node)
757 folder_update_op_count();
760 static void mark_all_read_cb(FolderView *folderview, guint action,
766 item = folderview_get_selected_item(folderview);
770 if (folderview->summaryview->folder_item != item
771 && prefs_common.ask_mark_all_read) {
772 val = alertpanel_full(_("Mark all as read"),
773 _("Do you really want to mark all mails in this "
774 "folder as read ?"), GTK_STOCK_NO, GTK_STOCK_YES, NULL,
775 TRUE, NULL, ALERT_QUESTION, G_ALERTDEFAULT);
777 if ((val & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
779 else if (val & G_ALERTDISABLE)
780 prefs_common.ask_mark_all_read = FALSE;
783 summary_lock(folderview->summaryview);
784 folder_item_update_freeze();
785 if (folderview->summaryview->folder_item == item)
786 summary_freeze(folderview->summaryview);
787 folderutils_mark_all_read(item);
788 if (folderview->summaryview->folder_item == item)
789 summary_thaw(folderview->summaryview);
790 folder_item_update_thaw();
791 summary_unlock(folderview->summaryview);
794 static void folderview_select_node(FolderView *folderview, GtkCTreeNode *node)
796 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
798 g_return_if_fail(node != NULL);
800 if (folderview->open_folder) {
804 folderview->open_folder = TRUE;
805 gtkut_ctree_set_focus_row(ctree, node);
806 gtk_ctree_select(ctree, node);
807 if (folderview->summaryview->folder_item &&
808 folderview->summaryview->folder_item->total_msgs > 0)
809 summary_grab_focus(folderview->summaryview);
811 gtk_widget_grab_focus(folderview->ctree);
813 gtkut_ctree_expand_parent_all(ctree, node);
816 void folderview_unselect(FolderView *folderview)
818 if (folderview->opened && !GTK_CTREE_ROW(folderview->opened)->children)
820 (GTK_CTREE(folderview->ctree), folderview->opened);
822 folderview->selected = folderview->opened = NULL;
825 static GtkCTreeNode *folderview_find_next_marked(GtkCTree *ctree,
831 node = gtkut_ctree_node_next(ctree, node);
833 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
835 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
836 item = gtk_ctree_node_get_row_data(ctree, node);
837 if (item && item->marked_msgs > 0 && item->stype != F_TRASH)
844 void folderview_select_next_marked(FolderView *folderview)
846 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
847 GtkCTreeNode *node = NULL;
848 SelectOnEntry last_sel = prefs_common.select_on_entry;
849 gboolean last_open = prefs_common.always_show_msg;
851 prefs_common.select_on_entry = SELECTONENTRY_MNU;
852 prefs_common.always_show_msg = TRUE;
854 if ((node = folderview_find_next_marked(ctree, folderview->opened))
856 folderview_select_node(folderview, node);
860 if (!folderview->opened ||
861 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
864 /* search again from the first node */
865 if ((node = folderview_find_next_marked(ctree, NULL)) != NULL)
866 folderview_select_node(folderview, node);
869 prefs_common.select_on_entry = last_sel;
870 prefs_common.always_show_msg = last_open;
873 static GtkCTreeNode *folderview_find_next_unread(GtkCTree *ctree,
879 node = gtkut_ctree_node_next(ctree, node);
881 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
883 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
884 item = gtk_ctree_node_get_row_data(ctree, node);
885 if (item && item->unread_msgs > 0 && item->stype != F_TRASH)
892 void folderview_select_next_unread(FolderView *folderview, gboolean force_open)
894 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
895 GtkCTreeNode *node = NULL;
896 SelectOnEntry last_sel = prefs_common.select_on_entry;
897 gboolean last_open = prefs_common.always_show_msg;
899 prefs_common.select_on_entry = SELECTONENTRY_UNM;
900 prefs_common.always_show_msg = force_open ? TRUE : last_open;
902 if ((node = folderview_find_next_unread(ctree, folderview->opened))
904 folderview_select_node(folderview, node);
908 if (!folderview->opened ||
909 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
912 /* search again from the first node */
913 if ((node = folderview_find_next_unread(ctree, NULL)) != NULL)
914 folderview_select_node(folderview, node);
917 prefs_common.select_on_entry = last_sel;
918 prefs_common.always_show_msg = last_open;
921 static GtkCTreeNode *folderview_find_next_new(GtkCTree *ctree,
927 node = gtkut_ctree_node_next(ctree, node);
929 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
931 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
932 item = gtk_ctree_node_get_row_data(ctree, node);
933 if (item && item->new_msgs > 0 && item->stype != F_TRASH)
940 void folderview_select_next_new(FolderView *folderview)
942 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
943 GtkCTreeNode *node = NULL;
944 SelectOnEntry last_sel = prefs_common.select_on_entry;
945 gboolean last_open = prefs_common.always_show_msg;
947 prefs_common.select_on_entry = SELECTONENTRY_NUM;
948 prefs_common.always_show_msg = TRUE;
950 if ((node = folderview_find_next_new(ctree, folderview->opened))
952 folderview_select_node(folderview, node);
956 if (!folderview->opened ||
957 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
960 /* search again from the first node */
961 if ((node = folderview_find_next_new(ctree, NULL)) != NULL)
962 folderview_select_node(folderview, node);
965 prefs_common.select_on_entry = last_sel;
966 prefs_common.always_show_msg = last_open;
969 FolderItem *folderview_get_selected_item(FolderView *folderview)
971 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
973 if (!folderview->selected) return NULL;
974 return gtk_ctree_node_get_row_data(ctree, folderview->selected);
977 void folderview_update_msg_num(FolderView *folderview, GtkCTreeNode *row)
979 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
980 static GtkCTreeNode *prev_row = NULL;
982 gint new, unread, total;
983 gchar *new_str, *unread_str, *total_str;
984 gint *col_pos = folderview->col_pos;
988 item = gtk_ctree_node_get_row_data(ctree, row);
991 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_NEW], &new_str);
992 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_UNREAD], &unread_str);
993 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_TOTAL], &total_str);
995 unread = atoi(unread_str);
996 total = atoi(total_str);
1000 folderview_update_node(folderview, row);
1003 void folderview_append_item(FolderItem *item)
1007 g_return_if_fail(item != NULL);
1008 g_return_if_fail(item->folder != NULL);
1009 if (folder_item_parent(item)) return;
1011 for (list = folderview_list; list != NULL; list = list->next) {
1012 FolderView *folderview = (FolderView *)list->data;
1013 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1014 GtkCTreeNode *node, *child;
1015 gint *col_pos = folderview->col_pos;
1017 node = gtk_ctree_find_by_row_data(ctree, NULL,
1018 folder_item_parent(item));
1020 child = gtk_ctree_find_by_row_data(ctree, node, item);
1022 gchar *text[N_FOLDER_COLS] =
1023 {NULL, "0", "0", "0"};
1025 gtk_clist_freeze(GTK_CLIST(ctree));
1027 text[col_pos[F_COL_FOLDER]] = item->name;
1028 child = gtk_sctree_insert_node
1029 (ctree, node, NULL, text,
1031 folderxpm, folderxpmmask,
1032 folderopenxpm, folderopenxpmmask,
1034 gtk_ctree_node_set_row_data(ctree, child, item);
1035 gtk_ctree_expand(ctree, node);
1036 folderview_update_node(folderview, child);
1037 folderview_sort_folders(folderview, node,
1040 gtk_clist_thaw(GTK_CLIST(ctree));
1046 static void folderview_set_folders(FolderView *folderview)
1049 list = folder_get_list();
1051 for (; list != NULL; list = list->next) {
1052 folderview_append_folder(folderview, FOLDER(list->data));
1056 static gchar *get_scan_str(FolderItem *item)
1059 return g_strdup_printf(_("Scanning folder %s%c%s ..."),
1060 item->folder->name, G_DIR_SEPARATOR,
1063 return g_strdup_printf(_("Scanning folder %s ..."),
1064 item->folder->name);
1066 static void folderview_scan_tree_func(Folder *folder, FolderItem *item,
1070 for (list = folderview_list; list != NULL; list = list->next) {
1071 FolderView *folderview = (FolderView *)list->data;
1072 MainWindow *mainwin = folderview->mainwin;
1073 gchar *str = get_scan_str(item);
1075 STATUSBAR_PUSH(mainwin, str);
1076 STATUSBAR_POP(mainwin);
1081 void folderview_rescan_tree(Folder *folder, gboolean rebuild)
1085 g_return_if_fail(folder != NULL);
1087 if (!folder->klass->scan_tree) return;
1090 alertpanel_full(_("Rebuild folder tree"),
1091 _("Rebuilding the folder tree will remove "
1092 "local caches. Do you want to continue?"),
1093 GTK_STOCK_NO, GTK_STOCK_YES, NULL, FALSE,
1094 NULL, ALERT_WARNING, G_ALERTDEFAULT)
1095 != G_ALERTALTERNATE) {
1101 window = label_window_create(_("Rebuilding folder tree..."));
1103 window = label_window_create(_("Scanning folder tree..."));
1105 folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
1106 folder_scan_tree(folder, rebuild);
1107 folder_set_ui_func(folder, NULL, NULL);
1109 folderview_set_all();
1111 gtk_widget_destroy(window);
1115 /** folderview_check_new()
1116 * Scan and update the folder and return the
1117 * count the number of new messages since last check.
1118 * \param folder the folder to check for new messages
1119 * \return the number of new messages since last check
1121 gint folderview_check_new(Folder *folder)
1125 FolderView *folderview;
1129 gint former_new_msgs = 0;
1130 gint former_new = 0, former_unread = 0, former_total;
1132 for (list = folderview_list; list != NULL; list = list->next) {
1133 folderview = (FolderView *)list->data;
1134 ctree = GTK_CTREE(folderview->ctree);
1137 main_window_lock(folderview->mainwin);
1139 for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
1140 node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
1142 item = gtk_ctree_node_get_row_data(ctree, node);
1143 if (!item || !item->path || !item->folder) continue;
1144 if (item->no_select) continue;
1145 if (folder && folder != item->folder) continue;
1146 if (!folder && !FOLDER_IS_LOCAL(item->folder)) continue;
1147 if (!item->prefs->newmailcheck) continue;
1148 if (item->processing_pending == TRUE) {
1149 debug_print("skipping %s, processing pending\n",
1150 item->path ? item->path : item->name);
1154 str = get_scan_str(item);
1156 STATUSBAR_PUSH(folderview->mainwin, str);
1160 folderview_scan_tree_func(item->folder, item, NULL);
1161 former_new = item->new_msgs;
1162 former_unread = item->unread_msgs;
1163 former_total = item->total_msgs;
1165 if (item->folder->klass->scan_required &&
1166 (item->folder->klass->scan_required(item->folder, item) ||
1167 item->folder->inbox == item ||
1168 item->opened == TRUE ||
1169 item->processing_pending == TRUE)) {
1170 if (folder_item_scan(item) < 0) {
1172 summaryview_unlock(folderview->summaryview, item);
1173 if (FOLDER_TYPE(item->folder) == F_NEWS || FOLDER_IS_LOCAL(folder)) {
1174 log_error(_("Couldn't scan folder %s\n"),
1175 item->path ? item->path:item->name);
1177 } else if (!FOLDER_IS_LOCAL(folder)) {
1178 STATUSBAR_POP(folderview->mainwin);
1183 } else if (!item->folder->klass->scan_required) {
1184 if (folder_item_scan(item) < 0) {
1185 summaryview_unlock(folderview->summaryview, item);
1186 if (folder && !FOLDER_IS_LOCAL(folder)) {
1187 STATUSBAR_POP(folderview->mainwin);
1192 if (former_new != item->new_msgs ||
1193 former_unread != item->unread_msgs ||
1194 former_total != item->total_msgs)
1195 folderview_update_node(folderview, node);
1197 new_msgs += item->new_msgs;
1198 former_new_msgs += former_new;
1199 STATUSBAR_POP(folderview->mainwin);
1202 main_window_unlock(folderview->mainwin);
1206 folder_write_list();
1207 /* Number of new messages since last check is the just the difference
1208 * between former_new_msgs and new_msgs. If new_msgs is less than
1209 * former_new_msgs, that would mean another session accessed the folder
1210 * and the result is not well defined.
1212 new_msgs = (former_new_msgs < new_msgs ? new_msgs - former_new_msgs : 0);
1216 void folderview_check_new_all(void)
1220 FolderView *folderview;
1222 folderview = (FolderView *)folderview_list->data;
1225 main_window_lock(folderview->mainwin);
1226 window = label_window_create
1227 (_("Checking for new messages in all folders..."));
1229 list = folder_get_list();
1230 for (; list != NULL; list = list->next) {
1231 Folder *folder = list->data;
1233 folderview_check_new(folder);
1236 folder_write_list();
1237 folderview_set_all();
1239 gtk_widget_destroy(window);
1240 main_window_unlock(folderview->mainwin);
1244 static gboolean folderview_have_new_children_sub(FolderView *folderview,
1250 if (!item || !item->folder || !item->folder->node)
1253 node = item->folder->node;
1255 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1256 node = node->children;
1259 (item->new_msgs > 0 ||
1260 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1264 while (node != NULL) {
1265 if (node && node->data) {
1266 FolderItem *next_item = (FolderItem*) node->data;
1268 if (folderview_have_new_children_sub(folderview,
1277 static gboolean folderview_have_new_children(FolderView *folderview,
1280 return folderview_have_new_children_sub(folderview, item, FALSE);
1283 static gboolean folderview_have_unread_children_sub(FolderView *folderview,
1289 if (!item || !item->folder || !item->folder->node)
1292 node = item->folder->node;
1294 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1295 node = node->children;
1298 (item->unread_msgs > 0 ||
1299 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1303 while (node != NULL) {
1304 if (node && node->data) {
1305 FolderItem *next_item = (FolderItem*) node->data;
1307 if (folderview_have_unread_children_sub(folderview,
1317 static gboolean folderview_have_unread_children(FolderView *folderview,
1320 return folderview_have_unread_children_sub(folderview, item, FALSE);
1323 static gboolean folderview_have_matching_children_sub(FolderView *folderview,
1329 if (!item || !item->folder || !item->folder->node)
1332 node = item->folder->node;
1334 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1335 node = node->children;
1337 if (in_sub && item->search_match){
1341 while (node != NULL) {
1342 if (node && node->data) {
1343 FolderItem *next_item = (FolderItem*) node->data;
1345 if (folderview_have_matching_children_sub(folderview,
1355 static gboolean folderview_have_matching_children(FolderView *folderview,
1358 return folderview_have_matching_children_sub(folderview, item, FALSE);
1361 static gboolean folderview_have_marked_children_sub(FolderView *folderview,
1367 if (!item || !item->folder || !item->folder->node)
1370 node = item->folder->node;
1372 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1373 node = node->children;
1375 if (item->marked_msgs != 0) {
1379 while (node != NULL) {
1380 if (node && node->data) {
1381 FolderItem *next_item = (FolderItem*) node->data;
1383 if (folderview_have_marked_children_sub(folderview,
1392 static gboolean folderview_have_marked_children(FolderView *folderview,
1395 return folderview_have_marked_children_sub(folderview, item, FALSE);
1398 static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node)
1400 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1401 GtkStyle *style = NULL;
1402 GtkStyle *color_style = NULL;
1404 GdkPixmap *xpm, *openxpm;
1405 GdkBitmap *mask, *openmask;
1406 static GdkPixmap *searchicon;
1407 static GdkBitmap *searchmask;
1408 gboolean mark = FALSE;
1411 gboolean add_unread_mark;
1412 gboolean add_sub_match_mark;
1413 gboolean use_bold, use_color;
1414 gint *col_pos = folderview->col_pos;
1415 SpecialFolderItemType stype;
1417 item = gtk_ctree_node_get_row_data(ctree, node);
1418 g_return_if_fail(item != NULL);
1420 if (!GTK_CTREE_ROW(node)->expanded)
1421 mark = folderview_have_marked_children(folderview, item);
1423 mark = (item->marked_msgs != 0);
1425 stype = item->stype;
1426 if (stype == F_NORMAL) {
1427 if (folder_has_parent_of_type(item, F_TRASH))
1429 else if (folder_has_parent_of_type(item, F_DRAFT))
1431 else if (folder_has_parent_of_type(item, F_OUTBOX))
1433 else if (folder_has_parent_of_type(item, F_QUEUE))
1438 if (item->hide_read_msgs) {
1439 xpm = mark?m_inboxhrmxpm:inboxhrmxpm;
1440 mask = mark?m_inboxhrmxpmmask:inboxhrmxpmmask;
1441 openxpm = mark?m_inboxopenhrmxpm:inboxopenhrmxpm;
1442 openmask = mark?m_inboxopenhrmxpmmask:inboxopenhrmxpmmask;
1444 xpm = mark?m_inboxxpm:inboxxpm;
1445 mask = mark?m_inboxxpmmask:inboxxpmmask;
1446 openxpm = mark?m_inboxopenxpm:inboxopenxpm;
1447 openmask = mark?m_inboxopenxpmmask:inboxopenxpmmask;
1451 if (item->hide_read_msgs) {
1452 xpm = mark?m_outboxhrmxpm:outboxhrmxpm;
1453 mask = mark?m_outboxhrmxpmmask:outboxhrmxpmmask;
1454 openxpm = mark?m_outboxopenhrmxpm:outboxopenhrmxpm;
1455 openmask = mark?m_outboxopenhrmxpmmask:outboxopenhrmxpmmask;
1457 xpm = mark?m_outboxxpm:outboxxpm;
1458 mask = mark?m_outboxxpmmask:outboxxpmmask;
1459 openxpm = mark?m_outboxopenxpm:outboxopenxpm;
1460 openmask = mark?m_outboxopenxpmmask:outboxopenxpmmask;
1464 if (item->hide_read_msgs) {
1465 xpm = mark?m_queuehrmxpm:queuehrmxpm;
1466 mask = mark?m_queuehrmxpmmask:queuehrmxpmmask;
1467 openxpm = mark?m_queueopenhrmxpm:queueopenhrmxpm;
1468 openmask = mark?m_queueopenhrmxpmmask:queueopenhrmxpmmask;
1470 xpm = mark?m_queuexpm:queuexpm;
1471 mask = mark?m_queuexpmmask:queuexpmmask;
1472 openxpm = mark?m_queueopenxpm:queueopenxpm;
1473 openmask = mark?m_queueopenxpmmask:queueopenxpmmask;
1477 if (item->hide_read_msgs) {
1478 xpm = mark?m_trashhrmxpm:trashhrmxpm;
1479 mask = mark?m_trashhrmxpmmask:trashhrmxpmmask;
1480 openxpm = mark?m_trashopenhrmxpm:trashopenhrmxpm;
1481 openmask = mark?m_trashopenhrmxpmmask:trashopenhrmxpmmask;
1483 xpm = mark?m_trashxpm:trashxpm;
1484 mask = mark?m_trashxpmmask:trashxpmmask;
1485 openxpm = mark?m_trashopenxpm:trashopenxpm;
1486 openmask = mark?m_trashopenxpmmask:trashopenxpmmask;
1490 xpm = mark?m_draftsxpm:draftsxpm;
1491 mask = mark?m_draftsxpmmask:draftsxpmmask;
1492 openxpm = mark?m_draftsopenxpm:draftsopenxpm;
1493 openmask = mark?m_draftsopenxpmmask:draftsopenxpmmask;
1496 if (item->hide_read_msgs) {
1497 xpm = mark?m_folderhrmxpm:folderhrmxpm;
1498 mask = mark?m_folderhrmxpmmask:folderhrmxpmmask;
1499 openxpm = mark?m_folderopenhrmxpm:folderopenhrmxpm;
1500 openmask = mark?m_folderopenhrmxpmmask:folderopenhrmxpmmask;
1502 xpm = mark?m_folderxpm:folderxpm;
1503 mask = mark?m_folderxpmmask:folderxpmmask;
1504 openxpm = mark?m_folderopenxpm:folderopenxpm;
1505 openmask = mark?m_folderopenxpmmask:folderopenxpmmask;
1509 if (item->no_select) {
1510 xpm = openxpm = noselectxpm;
1511 mask = openmask = noselectxpmmask;
1514 name = folder_item_get_name(item);
1516 if (!GTK_CTREE_ROW(node)->expanded) {
1517 add_unread_mark = folderview_have_unread_children(
1519 add_sub_match_mark = folderview_have_matching_children(
1522 add_unread_mark = FALSE;
1523 add_sub_match_mark = FALSE;
1526 if (item->search_match) {
1528 stock_pixmap_gdk(folderview->ctree, STOCK_PIXMAP_QUICKSEARCH,
1529 &searchicon, &searchmask);
1531 xpm = openxpm = searchicon;
1532 mask = openmask = searchmask;
1535 if (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0 &&
1536 prefs_common.display_folder_unread) {
1537 str = g_strdup_printf("%s (%d%s)", name, item->total_msgs,
1538 add_unread_mark ? "+" : "");
1539 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1540 xpm, mask, openxpm, openmask,
1541 FALSE, GTK_CTREE_ROW(node)->expanded);
1543 } else if (((item->unread_msgs > 0 || add_unread_mark) &&
1544 prefs_common.display_folder_unread)
1545 || add_sub_match_mark) {
1547 if (item->unread_msgs > 0)
1548 str = g_strdup_printf("%s (%d%s%s)", name, item->unread_msgs,
1549 add_unread_mark || add_sub_match_mark ? "+" : "",
1550 item->unreadmarked_msgs > 0 ? "!":"");
1552 str = g_strdup_printf("%s (+)", name);
1553 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1554 xpm, mask, openxpm, openmask,
1555 FALSE, GTK_CTREE_ROW(node)->expanded);
1558 str = g_strdup_printf("%s%s", name,
1559 item->unreadmarked_msgs > 0 ? " (!)":"");
1561 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1562 xpm, mask, openxpm, openmask,
1563 FALSE, GTK_CTREE_ROW(node)->expanded);
1568 if (!folder_item_parent(item)) {
1569 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], "-");
1570 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], "-");
1571 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], "-");
1573 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], itos(item->new_msgs));
1574 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], itos(item->unread_msgs));
1575 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], itos(item->total_msgs));
1578 if (folder_has_parent_of_type(item, F_OUTBOX) ||
1579 folder_has_parent_of_type(item, F_DRAFT) ||
1580 folder_has_parent_of_type(item, F_TRASH)) {
1581 use_bold = use_color = FALSE;
1582 } else if (folder_has_parent_of_type(item, F_QUEUE)) {
1583 /* highlight queue folder if there are any messages */
1584 use_bold = use_color = (item->total_msgs > 0);
1586 /* if unread messages exist, print with bold font */
1587 use_bold = (item->unread_msgs > 0|| item->new_msgs > 0)
1589 /* if new messages exist, print with colored letter */
1591 (item->new_msgs > 0) ||
1593 folderview_have_new_children(folderview, item));
1596 gtk_ctree_node_set_foreground(ctree, node, NULL);
1601 if (item->prefs->color > 0 && !use_color) {
1602 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1603 color_style = gtk_style_copy(bold_style);
1604 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1605 style = color_style;
1606 } else if (use_color) {
1607 style = bold_color_style;
1610 if (item->op_count > 0) {
1611 style = bold_tgtfold_style;
1613 } else if (use_color) {
1614 style = normal_color_style;
1615 gtk_ctree_node_set_foreground(ctree, node,
1616 &folderview->color_new);
1617 } else if (item->op_count > 0) {
1618 style = bold_tgtfold_style;
1619 } else if (item->prefs->color > 0) {
1621 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1622 color_style = gtk_style_copy(normal_style);
1623 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1624 style = color_style;
1626 style = normal_style;
1629 gtk_ctree_node_set_row_style(ctree, node, style);
1631 if ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
1632 folderview_update_node(folderview, node);
1635 #if !CLAWS /* keep it here for syncs */
1636 void folderview_update_item(FolderItem *item, gboolean update_summary)
1639 FolderView *folderview;
1643 g_return_if_fail(item != NULL);
1645 for (list = folderview_list; list != NULL; list = list->next) {
1646 folderview = (FolderView *)list->data;
1647 ctree = GTK_CTREE(folderview->ctree);
1649 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1651 folderview_update_node(folderview, node);
1652 if (update_summary && folderview->opened == node)
1653 summary_show(folderview->summaryview,
1660 void folderview_update_search_icon(FolderItem *item, gboolean matches)
1663 FolderView *folderview;
1667 g_return_if_fail(item != NULL);
1669 for (list = folderview_list; list != NULL; list = list->next) {
1670 folderview = (FolderView *)list->data;
1671 ctree = GTK_CTREE(folderview->ctree);
1673 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1675 item->search_match = matches;
1676 folderview_update_node(folderview, node);
1681 gboolean folderview_update_item_claws(gpointer source, gpointer data)
1683 FolderItemUpdateData *update_info = (FolderItemUpdateData *)source;
1684 FolderView *folderview = (FolderView *)data;
1687 g_return_val_if_fail(update_info != NULL, TRUE);
1688 g_return_val_if_fail(update_info->item != NULL, TRUE);
1689 g_return_val_if_fail(folderview != NULL, FALSE);
1691 ctree = GTK_CTREE(folderview->ctree);
1693 node = gtk_ctree_find_by_row_data(ctree, NULL, update_info->item);
1696 if (update_info->update_flags & (F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_NAME))
1697 folderview_update_node(folderview, node);
1698 if ((update_info->update_flags & F_ITEM_UPDATE_CONTENT) && (folderview->opened == node))
1699 if (!quicksearch_is_active(folderview->summaryview->quicksearch))
1700 summary_show(folderview->summaryview, update_info->item);
1706 static void folderview_update_item_foreach_func(gpointer key, gpointer val,
1709 /* CLAWS: share this joy with other hook functions ... */
1710 folder_item_update((FolderItem *)key,
1711 (FolderItemUpdateFlags)GPOINTER_TO_INT(data));
1714 void folderview_update_item_foreach(GHashTable *table, gboolean update_summary)
1717 FolderItemUpdateFlags flags;
1719 flags = update_summary ? F_ITEM_UPDATE_CONTENT | F_ITEM_UPDATE_MSGCNT
1721 for (list = folderview_list; list != NULL; list = list->next)
1722 g_hash_table_foreach(table, folderview_update_item_foreach_func,
1723 GINT_TO_POINTER(flags));
1726 static gboolean folderview_gnode_func(GtkCTree *ctree, guint depth,
1727 GNode *gnode, GtkCTreeNode *cnode,
1730 FolderView *folderview = (FolderView *)data;
1731 FolderItem *item = FOLDER_ITEM(gnode->data);
1733 g_return_val_if_fail(item != NULL, FALSE);
1735 gtk_ctree_node_set_row_data(ctree, cnode, item);
1736 folderview_update_node(folderview, cnode);
1741 static void folderview_expand_func(GtkCTree *ctree, GtkCTreeNode *node,
1744 FolderView *folderview = (FolderView *)data;
1747 if (GTK_CTREE_ROW(node)->children) {
1748 item = gtk_ctree_node_get_row_data(ctree, node);
1749 g_return_if_fail(item != NULL);
1751 if (!item->collapsed)
1752 gtk_ctree_expand(ctree, node);
1754 folderview_update_node(folderview, node);
1758 static void set_special_folder(GtkCTree *ctree, FolderItem *item,
1759 GtkCTreeNode *root, GtkCTreeNode **prev)
1762 GtkCTreeNode *node, *parent, *sibling;
1764 node = gtk_ctree_find_by_row_data(ctree, root, item);
1766 g_warning("%s not found.\n", item->path);
1768 parent = GTK_CTREE_ROW(node)->parent;
1769 if (*prev && parent == GTK_CTREE_ROW(*prev)->parent)
1770 sibling = GTK_CTREE_ROW(*prev)->sibling;
1772 sibling = GTK_CTREE_ROW(parent)->children;
1776 tmp = gtk_ctree_node_get_row_data
1778 if (tmp->stype != F_NORMAL)
1779 sibling = GTK_CTREE_ROW(sibling)->sibling;
1783 if (node != sibling)
1784 gtk_ctree_move(ctree, node, parent, sibling);
1791 static void folderview_sort_folders(FolderView *folderview, GtkCTreeNode *root,
1794 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1795 GtkCTreeNode *prev = NULL;
1797 gtk_clist_freeze(GTK_CLIST(ctree));
1798 gtk_sctree_sort_recursive(ctree, root);
1799 if (root && GTK_CTREE_ROW(root)->parent) {
1800 gtk_clist_thaw(GTK_CLIST(ctree));
1803 set_special_folder(ctree, folder->inbox, root, &prev);
1804 set_special_folder(ctree, folder->outbox, root, &prev);
1805 set_special_folder(ctree, folder->draft, root, &prev);
1806 set_special_folder(ctree, folder->queue, root, &prev);
1807 set_special_folder(ctree, folder->trash, root, &prev);
1808 gtk_clist_thaw(GTK_CLIST(ctree));
1811 static void folderview_append_folder(FolderView *folderview, Folder *folder)
1813 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1816 g_return_if_fail(folder != NULL);
1818 root = gtk_sctree_insert_gnode(ctree, NULL, NULL, folder->node,
1819 folderview_gnode_func, folderview);
1820 gtk_ctree_pre_recursive(ctree, root, folderview_expand_func,
1822 folderview_sort_folders(folderview, root, folder);
1825 /* callback functions */
1826 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
1827 GdkEventButton *event)
1829 GtkCList *clist = GTK_CLIST(folderview->ctree);
1832 FolderViewPopup *fpopup;
1833 GtkItemFactory *fpopup_factory;
1835 FolderItem *special_trash = NULL, *special_queue = NULL;
1839 item = gtk_clist_get_row_data(clist, row);
1841 item = folderview_get_selected_item(folderview);
1843 g_return_if_fail(item != NULL);
1844 g_return_if_fail(item->folder != NULL);
1845 folder = item->folder;
1847 fpopup = g_hash_table_lookup(folderview_popups, folder->klass->idstr);
1849 fpopup_factory = g_hash_table_lookup(folderview->popups, folder->klass->idstr);
1851 fpopup = g_hash_table_lookup(folderview_popups, "common");
1852 fpopup_factory = g_hash_table_lookup(folderview->popups, "common");
1855 if (fpopup->set_sensitivity != NULL)
1856 fpopup->set_sensitivity(fpopup_factory, item);
1858 if (NULL != (ac = account_find_from_item(item))) {
1859 special_trash = account_get_special_folder(ac, F_TRASH);
1860 special_queue = account_get_special_folder(ac, F_QUEUE);
1863 if ((item == folder->trash || item == special_trash
1864 || folder_has_parent_of_type(item, F_TRASH)) &&
1865 gtk_item_factory_get_item(fpopup_factory, "/Empty trash...") == NULL) {
1866 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[0], folderview, 1);
1867 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[1], folderview, 1);
1868 } else if (item != folder->trash && (special_trash == NULL || item != special_trash)
1869 && !folder_has_parent_of_type(item, F_TRASH)) {
1870 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[0]);
1871 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[1]);
1874 if ((item == folder->queue || item == special_queue
1875 || folder_has_parent_of_type(item, F_QUEUE)) &&
1876 gtk_item_factory_get_item(fpopup_factory, "/Send queue...") == NULL) {
1877 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[0], folderview, 1);
1878 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[1], folderview, 1);
1879 } else if (item != folder->queue && (special_queue == NULL || item != special_queue)
1880 && !folder_has_parent_of_type(item, F_QUEUE)) {
1881 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[0]);
1882 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[1]);
1885 #define SET_SENS(name, sens) \
1886 menu_set_sensitive(fpopup_factory, name, sens)
1888 SET_SENS("/Mark all read", item->unread_msgs >= 1);
1889 SET_SENS("/Search folder...", item->total_msgs >= 1 &&
1890 folderview->selected == folderview->opened);
1891 SET_SENS("/Properties...", TRUE);
1892 SET_SENS("/Processing...", item->node->parent != NULL);
1893 if (item == folder->trash || item == special_trash
1894 || folder_has_parent_of_type(item, F_TRASH)) {
1895 GSList *msglist = folder_item_get_msg_list(item);
1896 SET_SENS("/Empty trash...", msglist != NULL);
1897 procmsg_msg_list_free(msglist);
1899 if (item == folder->queue || item == special_queue
1900 || folder_has_parent_of_type(item, F_QUEUE)) {
1901 GSList *msglist = folder_item_get_msg_list(item);
1902 SET_SENS("/Send queue...", msglist != NULL);
1903 procmsg_msg_list_free(msglist);
1907 popup = gtk_item_factory_get_widget(fpopup_factory, fpopup->path);
1908 gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
1909 event->button, event->time);
1914 static gboolean folderview_button_pressed(GtkWidget *ctree, GdkEventButton *event,
1915 FolderView *folderview)
1917 GtkCList *clist = GTK_CLIST(ctree);
1918 gint prev_row = -1, row = -1, column = -1;
1920 if (!event) return FALSE;
1922 if (event->button == 1 || event->button == 2) {
1923 if (!gtk_ctree_is_hot_spot (GTK_CTREE(clist), event->x, event->y))
1924 folderview->open_folder = TRUE;
1926 if (event->type == GDK_2BUTTON_PRESS) {
1927 if (clist->selection) {
1930 node = GTK_CTREE_NODE(clist->selection->data);
1932 gtk_ctree_toggle_expansion(
1935 folderview->open_folder = FALSE;
1942 if (event->button == 2 || event->button == 3) {
1944 if (clist->selection) {
1947 node = GTK_CTREE_NODE(clist->selection->data);
1949 prev_row = gtkut_ctree_get_nth_from_node
1950 (GTK_CTREE(ctree), node);
1953 if (!gtk_clist_get_selection_info(clist, event->x, event->y,
1956 if (prev_row != row) {
1957 gtk_clist_unselect_all(clist);
1958 if (event->button == 2)
1959 folderview_select_node
1961 gtk_ctree_node_nth(GTK_CTREE(ctree),
1964 gtk_clist_select_row(clist, row, column);
1968 if (event->button != 3) return FALSE;
1970 folderview_set_sens_and_popup_menu(folderview, row, event);
1974 static gboolean folderview_button_released(GtkWidget *ctree, GdkEventButton *event,
1975 FolderView *folderview)
1977 if (!event) return FALSE;
1979 if (event->button == 1 && folderview->open_folder == FALSE &&
1980 folderview->opened != NULL) {
1981 gtkut_ctree_set_focus_row(GTK_CTREE(ctree),
1982 folderview->opened);
1983 gtk_ctree_select(GTK_CTREE(ctree), folderview->opened);
1989 static gboolean folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
1990 FolderView *folderview)
1992 if (!event) return FALSE;
1994 if (quicksearch_has_focus(folderview->summaryview->quicksearch))
1997 switch (event->keyval) {
1999 if (folderview->selected) {
2000 folderview_select_node(folderview,
2001 folderview->selected);
2005 if (folderview->selected) {
2006 if (folderview->opened == folderview->selected &&
2007 (!folderview->summaryview->folder_item ||
2008 folderview->summaryview->folder_item->total_msgs == 0))
2009 folderview_select_next_unread(folderview, TRUE);
2011 folderview_select_node(folderview,
2012 folderview->selected);
2022 typedef struct _PostponedSelectData
2027 FolderView *folderview;
2028 } PostponedSelectData;
2030 static gboolean postpone_select(void *data)
2032 PostponedSelectData *psdata = (PostponedSelectData *)data;
2033 debug_print("trying again\n");
2034 psdata->folderview->open_folder = TRUE;
2035 main_window_cursor_normal(psdata->folderview->mainwin);
2036 STATUSBAR_POP(psdata->folderview->mainwin);
2037 folderview_selected(psdata->ctree, psdata->row,
2038 psdata->column, psdata->folderview);
2043 static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row,
2044 gint column, FolderView *folderview)
2046 static gboolean can_select = TRUE; /* exclusive lock */
2052 folderview->selected = row;
2054 if (folderview->opened == row) {
2055 folderview->open_folder = FALSE;
2060 if (!can_select || summary_is_locked(folderview->summaryview)) {
2061 if (folderview->opened) {
2062 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2063 gtk_ctree_select(ctree, folderview->opened);
2069 if (!folderview->open_folder) {
2073 item = gtk_ctree_node_get_row_data(ctree, row);
2074 if (!item || item->no_select) {
2076 folderview->open_folder = FALSE;
2082 /* Save cache for old folder */
2083 /* We don't want to lose all caches if sylpheed crashed */
2084 if (folderview->opened) {
2085 FolderItem *olditem;
2087 olditem = gtk_ctree_node_get_row_data(ctree, folderview->opened);
2089 buf = g_strdup_printf(_("Closing Folder %s..."),
2090 olditem->path ? olditem->path:olditem->name);
2091 /* will be null if we just moved the previously opened folder */
2092 STATUSBAR_PUSH(folderview->mainwin, buf);
2093 main_window_cursor_wait(folderview->mainwin);
2095 summary_save_prefs_to_folderitem(folderview->summaryview, olditem);
2096 summary_show(folderview->summaryview, NULL);
2097 folder_item_close(olditem);
2098 main_window_cursor_normal(folderview->mainwin);
2099 STATUSBAR_POP(folderview->mainwin);
2103 /* CLAWS: set compose button type: news folder items
2104 * always have a news folder as parent */
2106 toolbar_set_compose_button
2107 (folderview->mainwin->toolbar,
2108 FOLDER_TYPE(item->folder) == F_NEWS ?
2109 COMPOSEBUTTON_NEWS : COMPOSEBUTTON_MAIL);
2112 debug_print("Folder %s is selected\n", item->path);
2114 if (!GTK_CTREE_ROW(row)->children)
2115 gtk_ctree_expand(ctree, row);
2116 if (folderview->opened &&
2117 !GTK_CTREE_ROW(folderview->opened)->children)
2118 gtk_ctree_collapse(ctree, folderview->opened);
2120 /* ungrab the mouse event */
2121 if (GTK_WIDGET_HAS_GRAB(ctree)) {
2122 gtk_grab_remove(GTK_WIDGET(ctree));
2123 if (gdk_pointer_is_grabbed())
2124 gdk_pointer_ungrab(GDK_CURRENT_TIME);
2128 buf = g_strdup_printf(_("Opening Folder %s..."), item->path ?
2129 item->path : "(null)");
2130 debug_print("%s\n", buf);
2131 STATUSBAR_PUSH(folderview->mainwin, buf);
2134 main_window_cursor_wait(folderview->mainwin);
2136 res = folder_item_open(item);
2138 main_window_cursor_normal(folderview->mainwin);
2139 STATUSBAR_POP(folderview->mainwin);
2141 alertpanel_error(_("Folder could not be opened."));
2143 folderview->open_folder = FALSE;
2147 } else if (res == -2) {
2148 PostponedSelectData *data = g_new0(PostponedSelectData, 1);
2149 data->ctree = ctree;
2151 data->column = column;
2152 data->folderview = folderview;
2153 debug_print("postponing open of %s till end of scan\n",
2154 item->path ? item->path:item->name);
2155 folderview->open_folder = FALSE;
2157 g_timeout_add(500, postpone_select, data);
2162 main_window_cursor_normal(folderview->mainwin);
2165 summary_set_prefs_from_folderitem(folderview->summaryview, item);
2166 opened = summary_show(folderview->summaryview, item);
2168 folder_clean_cache_memory(item);
2171 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2172 gtk_ctree_select(ctree, folderview->opened);
2174 folderview->opened = row;
2175 if (gtk_ctree_node_is_visible(ctree, row)
2176 != GTK_VISIBILITY_FULL)
2177 gtk_ctree_node_moveto(ctree, row, -1, 0.5, 0);
2180 STATUSBAR_POP(folderview->mainwin);
2182 folderview->open_folder = FALSE;
2187 static void folderview_tree_expanded(GtkCTree *ctree, GtkCTreeNode *node,
2188 FolderView *folderview)
2192 item = gtk_ctree_node_get_row_data(ctree, node);
2193 g_return_if_fail(item != NULL);
2194 item->collapsed = FALSE;
2195 folderview_update_node(folderview, node);
2198 static void folderview_tree_collapsed(GtkCTree *ctree, GtkCTreeNode *node,
2199 FolderView *folderview)
2203 item = gtk_ctree_node_get_row_data(ctree, node);
2204 g_return_if_fail(item != NULL);
2205 item->collapsed = TRUE;
2206 folderview_update_node(folderview, node);
2209 static void folderview_popup_close(GtkMenuShell *menu_shell,
2210 FolderView *folderview)
2212 if (!folderview->opened) return;
2214 gtk_ctree_select(GTK_CTREE(folderview->ctree), folderview->opened);
2217 static void folderview_col_resized(GtkCList *clist, gint column, gint width,
2218 FolderView *folderview)
2220 FolderColumnType type = folderview->col_state[column].type;
2222 prefs_common.folder_col_size[type] = width;
2225 void folderview_create_folder_node_recursive(FolderView *folderview, FolderItem *item)
2229 folderview_create_folder_node(folderview, item);
2231 if (!item || !item->folder || !item->folder->node)
2234 srcnode = item->folder->node;
2235 srcnode = g_node_find(srcnode, G_PRE_ORDER, G_TRAVERSE_ALL, item);
2236 srcnode = srcnode->children;
2237 while (srcnode != NULL) {
2238 if (srcnode && srcnode->data) {
2239 FolderItem *next_item = (FolderItem*) srcnode->data;
2240 folderview_create_folder_node_recursive(folderview, next_item);
2242 srcnode = srcnode->next;
2246 void folderview_create_folder_node(FolderView *folderview, FolderItem *item)
2248 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2249 gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
2250 GtkCTreeNode *node, *parent_node;
2251 gint *col_pos = folderview->col_pos;
2252 FolderItemUpdateData hookdata;
2254 parent_node = gtk_ctree_find_by_row_data(ctree, NULL, folder_item_parent(item));
2255 if (parent_node == NULL)
2258 gtk_clist_freeze(GTK_CLIST(ctree));
2260 text[col_pos[F_COL_FOLDER]] = item->name;
2261 node = gtk_sctree_insert_node(ctree, parent_node, NULL, text,
2263 folderxpm, folderxpmmask,
2264 folderopenxpm, folderopenxpmmask,
2266 gtk_ctree_expand(ctree, parent_node);
2267 gtk_ctree_node_set_row_data(ctree, node, item);
2269 gtk_ctree_node_set_row_style(ctree, node, normal_style);
2270 folderview_sort_folders(folderview, parent_node, item->folder);
2272 hookdata.item = item;
2273 hookdata.update_flags = F_ITEM_UPDATE_NAME;
2274 hookdata.msg = NULL;
2275 hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &hookdata);
2277 gtk_clist_thaw(GTK_CLIST(ctree));
2280 static void folderview_empty_trash_cb(FolderView *folderview, guint action,
2283 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2285 GSList *mlist = NULL;
2287 FolderItem *special_trash = NULL;
2290 if (!folderview->selected) return;
2291 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2292 g_return_if_fail(item != NULL);
2293 g_return_if_fail(item->folder != NULL);
2295 if (NULL != (ac = account_find_from_item(item)))
2296 special_trash = account_get_special_folder(ac, F_TRASH);
2298 if (item != item->folder->trash && item != special_trash
2299 && !folder_has_parent_of_type(item, F_TRASH)) return;
2301 if (prefs_common.ask_on_clean) {
2302 if (alertpanel(_("Empty trash"),
2303 _("Delete all messages in trash?"),
2304 GTK_STOCK_CANCEL, _("+_Empty trash"), NULL) != G_ALERTALTERNATE)
2308 mlist = folder_item_get_msg_list(item);
2310 for (cur = mlist ; cur != NULL ; cur = cur->next) {
2311 MsgInfo * msginfo = (MsgInfo *) cur->data;
2312 if (MSG_IS_LOCKED(msginfo->flags))
2314 /* is it partially received? (partial_recv isn't cached) */
2315 if (msginfo->total_size != 0 &&
2316 msginfo->size != (off_t)msginfo->total_size)
2317 partial_mark_for_delete(msginfo);
2319 procmsg_msg_list_free(mlist);
2321 folder_item_remove_all_msg(item);
2324 static void folderview_send_queue_cb(FolderView *folderview, guint action,
2327 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2329 FolderItem *special_queue = NULL;
2331 gchar *errstr = NULL;
2333 if (!folderview->selected) return;
2334 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2335 g_return_if_fail(item != NULL);
2336 g_return_if_fail(item->folder != NULL);
2338 if (NULL != (ac = account_find_from_item(item)))
2339 special_queue = account_get_special_folder(ac, F_QUEUE);
2341 if (item != item->folder->queue && item != special_queue
2342 && !folder_has_parent_of_type(item, F_QUEUE)) return;
2344 if (procmsg_queue_is_empty(item))
2347 if (prefs_common.work_offline)
2348 if (alertpanel(_("Offline warning"),
2349 _("You're working offline. Override?"),
2350 GTK_STOCK_NO, GTK_STOCK_YES,
2351 NULL) != G_ALERTALTERNATE)
2354 /* ask for confirmation before sending queued messages only
2355 in online mode and if there is at least one message queued
2356 in any of the folder queue
2358 if (prefs_common.confirm_send_queued_messages) {
2359 if (!prefs_common.work_offline) {
2360 if (alertpanel(_("Send queued messages"),
2361 _("Send all queued messages?"),
2362 GTK_STOCK_CANCEL, _("_Send"),
2363 NULL) != G_ALERTALTERNATE)
2368 if (procmsg_send_queue(item, prefs_common.savemsg, &errstr) < 0) {
2370 alertpanel_error_log(_("Some errors occurred while "
2371 "sending queued messages."));
2373 gchar *tmp = g_strdup_printf(_("Some errors occurred "
2374 "while sending queued messages:\n%s"), errstr);
2376 alertpanel_error_log(tmp);
2382 static void folderview_search_cb(FolderView *folderview, guint action,
2385 summary_search(folderview->summaryview);
2388 static void folderview_property_cb(FolderView *folderview, guint action,
2391 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2394 if (!folderview->selected) return;
2396 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2397 g_return_if_fail(item != NULL);
2398 g_return_if_fail(item->folder != NULL);
2400 prefs_folder_item_open(item);
2403 static void folderview_recollapse_nodes(FolderView *folderview, GtkCTreeNode *node)
2405 GSList *list = NULL;
2406 GSList *done = NULL;
2407 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2409 for (list = folderview->nodes_to_recollapse; list != NULL; list = g_slist_next(list)) {
2410 if (!gtkut_ctree_node_is_parent(GTK_CTREE_NODE(list->data), node)
2411 && list->data != node) {
2412 gtk_ctree_collapse(ctree, GTK_CTREE_NODE(list->data));
2413 done = g_slist_append(done, GTK_CTREE_NODE(list->data));
2416 for (list = done; list != NULL; list = g_slist_next(list)) {
2417 folderview->nodes_to_recollapse = g_slist_remove(folderview->nodes_to_recollapse,
2423 void folderview_move_folder(FolderView *folderview, FolderItem *from_folder,
2424 FolderItem *to_folder)
2426 FolderItem *from_parent = NULL;
2427 FolderItem *new_folder = NULL;
2428 GtkCTreeNode *src_node = NULL;
2432 g_return_if_fail(folderview != NULL);
2433 g_return_if_fail(from_folder != NULL);
2434 g_return_if_fail(to_folder != NULL);
2436 src_node = gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree), NULL, from_folder);
2437 from_parent = folder_item_parent(from_folder);
2439 if (prefs_common.warn_dnd) {
2440 buf = g_strdup_printf(_("Do you really want to make folder '%s' a "
2441 "sub-folder of '%s' ?"), from_folder->name,
2443 status = alertpanel_full(_("Move folder"), buf,
2444 GTK_STOCK_NO, GTK_STOCK_YES, NULL, TRUE,
2445 NULL, ALERT_QUESTION, G_ALERTDEFAULT);
2448 if ((status & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
2450 else if (status & G_ALERTDISABLE)
2451 prefs_common.warn_dnd = FALSE;
2454 buf = g_strdup_printf(_("Moving %s to %s..."), from_folder->name, to_folder->name);
2455 STATUSBAR_PUSH(folderview->mainwin, buf);
2457 summary_clear_all(folderview->summaryview);
2458 folderview->opened = NULL;
2459 folderview->selected = NULL;
2460 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), FALSE);
2462 main_window_cursor_wait(folderview->mainwin);
2463 statusbar_verbosity_set(TRUE);
2464 folder_item_update_freeze();
2465 if ((status = folder_item_move_to(from_folder, to_folder, &new_folder)) == F_MOVE_OK) {
2466 statusbar_verbosity_set(FALSE);
2467 main_window_cursor_normal(folderview->mainwin);
2468 STATUSBAR_POP(folderview->mainwin);
2469 folder_item_update_thaw();
2470 folder_item_update_recursive(new_folder, F_ITEM_UPDATE_MSGCNT);
2472 folderview_sort_folders(folderview,
2473 gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree),
2474 NULL, to_folder), new_folder->folder);
2475 folderview_select(folderview, new_folder);
2477 statusbar_verbosity_set(FALSE);
2478 main_window_cursor_normal(folderview->mainwin);
2479 STATUSBAR_POP(folderview->mainwin);
2480 folder_item_update_thaw();
2482 case F_MOVE_FAILED_DEST_IS_PARENT:
2483 alertpanel_error(_("Source and destination are the same."));
2485 case F_MOVE_FAILED_DEST_IS_CHILD:
2486 alertpanel_error(_("Can't move a folder to one of its children."));
2488 case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX:
2489 alertpanel_error(_("Folder moving cannot be done between different mailboxes."));
2492 alertpanel_error(_("Move failed!"));
2497 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), TRUE);
2500 static gint folderview_clist_compare(GtkCList *clist,
2501 gconstpointer ptr1, gconstpointer ptr2)
2503 FolderItem *item1 = ((GtkCListRow *)ptr1)->data;
2504 FolderItem *item2 = ((GtkCListRow *)ptr2)->data;
2507 return (item2->name != NULL);
2511 return g_utf8_collate(item1->name, item2->name);
2514 static void folderview_processing_cb(FolderView *folderview, guint action,
2517 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2521 if (!folderview->selected) return;
2523 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2524 g_return_if_fail(item != NULL);
2525 g_return_if_fail(item->folder != NULL);
2527 id = folder_item_get_identifier(item);
2528 title = g_strdup_printf (_("Processing configuration for folder %s"), id);
2531 prefs_filtering_open(&item->prefs->processing, title,
2532 MANUAL_ANCHOR_PROCESSING, NULL, NULL, FALSE);
2536 void folderview_set_target_folder_color(gint color_op)
2540 FolderView *folderview;
2542 for (list = folderview_list; list != NULL; list = list->next) {
2543 folderview = (FolderView *)list->data;
2544 gtkut_convert_int_to_gdk_color(color_op, &folderview->color_op);
2546 bold_tgtfold_style->fg[GTK_STATE_NORMAL] =
2547 folderview->color_op;
2553 static gchar *last_font = NULL;
2554 void folderview_reflect_prefs_pixmap_theme(FolderView *folderview)
2562 void folderview_reflect_prefs(void)
2564 gboolean update_font = TRUE;
2565 FolderView *folderview = mainwindow_get_mainwindow()->folderview;
2566 FolderItem *item = folderview_get_selected_item(folderview);
2567 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2568 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2569 gint height = pos->value;
2571 if (last_font && !strcmp(last_font, NORMAL_FONT))
2572 update_font = FALSE;
2575 last_font = g_strdup(NORMAL_FONT);
2578 normal_style = normal_color_style = bold_style =
2579 bold_color_style = bold_tgtfold_style = NULL;
2581 folderview_init(folderview);
2583 gtk_clist_freeze(GTK_CLIST(folderview->ctree));
2584 folderview_column_set_titles(folderview);
2585 folderview_set_all();
2587 g_signal_handlers_block_by_func
2588 (G_OBJECT(folderview->ctree),
2589 G_CALLBACK(folderview_selected), folderview);
2592 GtkCTreeNode *node = gtk_ctree_find_by_row_data(
2593 GTK_CTREE(folderview->ctree), NULL, item);
2595 folderview_select(folderview, item);
2596 folderview->open_folder = FALSE;
2597 folderview->selected = node;
2600 g_signal_handlers_unblock_by_func
2601 (G_OBJECT(folderview->ctree),
2602 G_CALLBACK(folderview_selected), folderview);
2604 pos = gtk_scrolled_window_get_vadjustment(
2605 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2606 gtk_adjustment_set_value(pos, height);
2607 gtk_clist_thaw(GTK_CLIST(folderview->ctree));
2610 static void drag_state_stop(FolderView *folderview)
2612 if (folderview->drag_timer)
2613 g_source_remove(folderview->drag_timer);
2614 folderview->drag_timer = 0;
2615 folderview->drag_node = NULL;
2618 static gint folderview_defer_expand(FolderView *folderview)
2620 if (folderview->drag_node) {
2621 folderview_recollapse_nodes(folderview, folderview->drag_node);
2622 if (folderview->drag_item->collapsed) {
2623 gtk_ctree_expand(GTK_CTREE(folderview->ctree), folderview->drag_node);
2624 folderview->nodes_to_recollapse = g_slist_append
2625 (folderview->nodes_to_recollapse, folderview->drag_node);
2628 folderview->drag_item = NULL;
2629 folderview->drag_timer = 0;
2633 static void drag_state_start(FolderView *folderview, GtkCTreeNode *node, FolderItem *item)
2635 /* the idea is that we call drag_state_start() whenever we want expansion to
2636 * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
2637 * we need to call drag_state_stop() */
2638 drag_state_stop(folderview);
2639 /* request expansion */
2640 if (0 != (folderview->drag_timer = g_timeout_add
2641 (prefs_common.hover_timeout,
2642 (GtkFunction)folderview_defer_expand,
2644 folderview->drag_node = node;
2645 folderview->drag_item = item;
2649 static void folderview_start_drag(GtkWidget *widget, gint button, GdkEvent *event,
2650 FolderView *folderview)
2652 GdkDragContext *context;
2654 g_return_if_fail(folderview != NULL);
2655 if (folderview->selected == NULL) return;
2656 if (folderview->nodes_to_recollapse)
2657 g_slist_free(folderview->nodes_to_recollapse);
2658 folderview->nodes_to_recollapse = NULL;
2659 context = gtk_drag_begin(widget, folderview->target_list,
2660 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
2661 gtk_drag_set_icon_default(context);
2664 static void folderview_drag_data_get(GtkWidget *widget,
2665 GdkDragContext *drag_context,
2666 GtkSelectionData *selection_data,
2669 FolderView *folderview)
2673 gchar *source = NULL;
2674 if (info == TARGET_DUMMY) {
2675 for (cur = GTK_CLIST(folderview->ctree)->selection;
2676 cur != NULL; cur = cur->next) {
2677 item = gtk_ctree_node_get_row_data
2678 (GTK_CTREE(folderview->ctree),
2679 GTK_CTREE_NODE(cur->data));
2681 source = g_strdup_printf ("FROM_OTHER_FOLDER%s", folder_item_get_identifier(item));
2682 gtk_selection_data_set(selection_data,
2683 selection_data->target, 8,
2684 source, strlen(source));
2690 g_warning("unknown info %d\n", info);
2694 gboolean folderview_update_folder(gpointer source, gpointer userdata)
2696 FolderUpdateData *hookdata;
2697 FolderView *folderview;
2701 folderview = (FolderView *) userdata;
2702 g_return_val_if_fail(hookdata != NULL, FALSE);
2703 g_return_val_if_fail(folderview != NULL, FALSE);
2705 ctree = folderview->ctree;
2706 g_return_val_if_fail(ctree != NULL, FALSE);
2708 if (hookdata->update_flags & FOLDER_ADD_FOLDERITEM)
2709 folderview_create_folder_node(folderview, hookdata->item);
2710 else if (hookdata->update_flags & FOLDER_RENAME_FOLDERITEM) {
2711 GtkCTreeNode *node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree),
2712 NULL, folder_item_parent(hookdata->item));
2713 folderview_sort_folders(folderview, node, hookdata->folder);
2714 } else if (hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM) {
2717 node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree), NULL, hookdata->item);
2719 gtk_ctree_remove_node(GTK_CTREE(ctree), node);
2720 } else if (hookdata->update_flags & (FOLDER_TREE_CHANGED | FOLDER_ADD_FOLDER | FOLDER_REMOVE_FOLDER))
2721 folderview_set(folderview);
2726 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
2727 GdkDragContext *context,
2731 FolderView *folderview)
2734 FolderItem *item = NULL, *src_item = NULL;
2735 GtkCTreeNode *node = NULL;
2736 gboolean acceptable = FALSE;
2737 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2738 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2739 int height = (int)pos->page_size;
2740 int total_height = (int)pos->upper;
2741 int vpos = (int) pos->value;
2743 if (gtk_clist_get_selection_info
2744 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
2745 GtkWidget *srcwidget;
2747 if (y > height - 24 && height + vpos < total_height)
2748 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
2750 if (y < 48 && y > 0)
2751 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
2753 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2754 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2755 src_item = folderview->summaryview->folder_item;
2757 srcwidget = gtk_drag_get_source_widget(context);
2758 if (srcwidget == summary_get_main_widget(folderview->summaryview)) {
2759 /* comes from summaryview */
2760 /* we are copying messages, so only accept folder items that are not
2761 the source item, are no root items and can copy messages */
2762 if (item && item->folder && folder_item_parent(item) != NULL && src_item &&
2763 src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2764 FOLDER_TYPE(item->folder) != F_UNKNOWN)
2766 } else if (srcwidget == folderview->ctree) {
2767 /* comes from folderview */
2768 /* we are moving folder items, only accept folders that are not
2769 the source items and can copy messages and create folder items */
2770 if (item && item->folder && src_item && src_item != item &&
2771 FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2772 FOLDER_CLASS(item->folder)->create_folder != NULL &&
2773 ((FOLDER_TYPE(item->folder) != F_UNKNOWN && FOLDER_TYPE(src_item->folder) != F_UNKNOWN)
2774 || item->folder == src_item->folder))
2777 /* comes from another app */
2778 /* we are adding messages, so only accept folder items that are
2779 no root items and can copy messages */
2780 if (item && item->folder && folder_item_parent(item) != NULL
2781 && FOLDER_CLASS(item->folder)->add_msg != NULL &&
2782 FOLDER_TYPE(item->folder) != F_UNKNOWN)
2787 if (acceptable || (src_item && src_item == item))
2788 drag_state_start(folderview, node, item);
2791 g_signal_handlers_block_by_func
2793 G_CALLBACK(folderview_selected), folderview);
2794 gtk_ctree_select(GTK_CTREE(widget), node);
2795 g_signal_handlers_unblock_by_func
2797 G_CALLBACK(folderview_selected), folderview);
2798 gdk_drag_status(context,
2799 (context->actions == GDK_ACTION_COPY ?
2800 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
2802 if (folderview->opened)
2803 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2804 gdk_drag_status(context, 0, time);
2810 static void folderview_drag_leave_cb(GtkWidget *widget,
2811 GdkDragContext *context,
2813 FolderView *folderview)
2815 drag_state_stop(folderview);
2816 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2819 static void free_info (gpointer stuff, gpointer data)
2824 void folderview_finish_dnd(const gchar *data, GdkDragContext *drag_context,
2825 guint time, FolderItem *item)
2828 GSList *msglist = NULL;
2829 list = uri_list_extract_filenames(data);
2830 if (!(item && item->folder && folder_item_parent(item) != NULL
2831 && FOLDER_CLASS(item->folder)->add_msg != NULL))
2833 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2837 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2840 for (tmp = list; tmp != NULL; tmp = tmp->next) {
2841 MsgFileInfo *info = NULL;
2843 if (file_is_email((gchar *)tmp->data)) {
2844 info = g_new0(MsgFileInfo, 1);
2845 info->msginfo = NULL;
2846 info->file = (gchar *)tmp->data;
2847 msglist = g_slist_prepend(msglist, info);
2851 msglist = g_slist_reverse(msglist);
2852 folder_item_add_msgs(item, msglist, FALSE);
2853 g_slist_foreach(msglist, free_info, NULL);
2854 g_slist_free(msglist);
2855 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2857 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2859 list_free_strings(list);
2863 static void folderview_drag_received_cb(GtkWidget *widget,
2864 GdkDragContext *drag_context,
2867 GtkSelectionData *data,
2870 FolderView *folderview)
2873 FolderItem *item = NULL, *src_item;
2876 if (info == TARGET_DUMMY) {
2877 drag_state_stop(folderview);
2878 if ((void *)strstr(data->data, "FROM_OTHER_FOLDER") != (void *)data->data) {
2879 /* comes from summaryview */
2880 if (gtk_clist_get_selection_info
2881 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2884 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2885 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2886 src_item = folderview->summaryview->folder_item;
2888 /* re-check (due to acceptable possibly set for folder moves */
2889 if (!(item && item->folder && item->path && !item->no_select &&
2890 src_item && src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)) {
2893 if (item && src_item) {
2894 switch (drag_context->action) {
2895 case GDK_ACTION_COPY:
2896 summary_copy_selected_to(folderview->summaryview, item);
2897 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2899 case GDK_ACTION_MOVE:
2900 case GDK_ACTION_DEFAULT:
2902 if (FOLDER_CLASS(src_item->folder)->remove_msg == NULL)
2903 summary_copy_selected_to(folderview->summaryview, item);
2905 summary_move_selected_to(folderview->summaryview, item);
2906 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2909 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2911 /* comes from folderview */
2913 gboolean folder_is_normal = TRUE;
2915 source = data->data + 17;
2916 if (gtk_clist_get_selection_info
2917 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0
2919 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2922 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2923 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2924 src_item = folder_find_item_from_identifier(source);
2928 src_item->stype == F_NORMAL &&
2929 !folder_has_parent_of_type(src_item, F_OUTBOX) &&
2930 !folder_has_parent_of_type(src_item, F_DRAFT) &&
2931 !folder_has_parent_of_type(src_item, F_QUEUE) &&
2932 !folder_has_parent_of_type(src_item, F_TRASH);
2933 if (!item || item->no_select || !src_item
2934 || !folder_is_normal) {
2935 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2939 folderview_move_folder(folderview, src_item, item);
2940 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2942 folderview->nodes_to_recollapse = NULL;
2943 } else if (info == TARGET_MAIL_URI_LIST) {
2944 if (gtk_clist_get_selection_info
2945 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2948 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2950 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2953 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2955 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2958 folderview_finish_dnd(data->data, drag_context, time, item);
2962 static void folderview_drag_end_cb(GtkWidget *widget,
2963 GdkDragContext *drag_context,
2964 FolderView *folderview)
2966 drag_state_stop(folderview);
2967 g_slist_free(folderview->nodes_to_recollapse);
2968 folderview->nodes_to_recollapse = NULL;
2971 void folderview_register_popup(FolderViewPopup *fpopup)
2975 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2976 FolderView *folderview = folderviews->data;
2977 GtkItemFactory *factory;
2979 factory = create_ifactory(folderview, fpopup);
2980 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
2982 g_hash_table_insert(folderview_popups, fpopup->klass, fpopup);
2985 void folderview_unregister_popup(FolderViewPopup *fpopup)
2989 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2990 FolderView *folderview = folderviews->data;
2992 g_hash_table_remove(folderview->popups, fpopup->klass);
2994 g_hash_table_remove(folderview_popups, fpopup->klass);