2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2006 Hiroyuki Yamamoto and the Sylpheed-Claws team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 #include <glib/gi18n.h>
24 #include <gdk/gdkkeysyms.h>
25 #include <gtk/gtkwidget.h>
26 #include <gtk/gtkscrolledwindow.h>
27 #include <gtk/gtkctree.h>
28 #include <gtk/gtkcontainer.h>
29 #include <gtk/gtkclist.h>
30 #include <gtk/gtkstyle.h>
31 #include <gtk/gtksignal.h>
32 #include <gtk/gtkmain.h>
33 #include <gtk/gtkstatusbar.h>
34 #include <gtk/gtkmenu.h>
35 #include <gtk/gtkmenuitem.h>
36 #include <gtk/gtkitemfactory.h>
42 #include "mainwindow.h"
43 #include "folderview.h"
44 #include "summaryview.h"
45 #include "summary_search.h"
46 #include "inputdialog.h"
47 #include "manage_window.h"
48 #include "alertpanel.h"
50 #include "stock_pixmap.h"
54 #include "prefs_common.h"
55 #include "prefs_account.h"
56 #include "prefs_filtering.h"
57 #include "prefs_folder_item.h"
60 #include "foldersel.h"
62 #include "statusbar.h"
64 #include "folderutils.h"
65 #include "partial_download.h"
66 #include "prefs_folder_column.h"
67 #include "filtering.h"
68 #include "quicksearch.h"
72 #define COL_FOLDER_WIDTH 150
73 #define COL_NUM_WIDTH 32
75 static GList *folderview_list = NULL;
77 static GtkStyle *normal_style;
78 static GtkStyle *normal_color_style;
79 static GtkStyle *bold_style;
80 static GtkStyle *bold_color_style;
81 static GtkStyle *bold_tgtfold_style;
83 static GdkPixmap *inboxxpm;
84 static GdkBitmap *inboxxpmmask;
85 static GdkPixmap *inboxhrmxpm;
86 static GdkBitmap *inboxhrmxpmmask;
87 static GdkPixmap *inboxopenxpm;
88 static GdkBitmap *inboxopenxpmmask;
89 static GdkPixmap *inboxopenhrmxpm;
90 static GdkBitmap *inboxopenhrmxpmmask;
91 static GdkPixmap *outboxxpm;
92 static GdkBitmap *outboxxpmmask;
93 static GdkPixmap *outboxhrmxpm;
94 static GdkBitmap *outboxhrmxpmmask;
95 static GdkPixmap *outboxopenxpm;
96 static GdkBitmap *outboxopenxpmmask;
97 static GdkPixmap *outboxopenhrmxpm;
98 static GdkBitmap *outboxopenhrmxpmmask;
99 static GdkPixmap *folderxpm;
100 static GdkBitmap *folderxpmmask;
101 static GdkPixmap *folderhrmxpm;
102 static GdkBitmap *folderhrmxpmmask;
103 static GdkPixmap *folderopenxpm;
104 static GdkBitmap *folderopenxpmmask;
105 static GdkPixmap *folderopenhrmxpm;
106 static GdkBitmap *folderopenhrmxpmmask;
107 static GdkPixmap *trashopenxpm;
108 static GdkBitmap *trashopenxpmmask;
109 static GdkPixmap *trashopenhrmxpm;
110 static GdkBitmap *trashopenhrmxpmmask;
111 static GdkPixmap *trashxpm;
112 static GdkBitmap *trashxpmmask;
113 static GdkPixmap *trashhrmxpm;
114 static GdkBitmap *trashhrmxpmmask;
115 static GdkPixmap *queuexpm;
116 static GdkBitmap *queuexpmmask;
117 static GdkPixmap *queuehrmxpm;
118 static GdkBitmap *queuehrmxpmmask;
119 static GdkPixmap *queueopenxpm;
120 static GdkBitmap *queueopenxpmmask;
121 static GdkPixmap *queueopenhrmxpm;
122 static GdkBitmap *queueopenhrmxpmmask;
123 static GdkPixmap *draftsxpm;
124 static GdkBitmap *draftsxpmmask;
125 static GdkPixmap *draftsopenxpm;
126 static GdkBitmap *draftsopenxpmmask;
127 static GdkPixmap *noselectxpm;
128 static GdkBitmap *noselectxpmmask;
130 static GdkPixmap *m_inboxxpm;
131 static GdkBitmap *m_inboxxpmmask;
132 static GdkPixmap *m_inboxhrmxpm;
133 static GdkBitmap *m_inboxhrmxpmmask;
134 static GdkPixmap *m_inboxopenxpm;
135 static GdkBitmap *m_inboxopenxpmmask;
136 static GdkPixmap *m_inboxopenhrmxpm;
137 static GdkBitmap *m_inboxopenhrmxpmmask;
138 static GdkPixmap *m_outboxxpm;
139 static GdkBitmap *m_outboxxpmmask;
140 static GdkPixmap *m_outboxhrmxpm;
141 static GdkBitmap *m_outboxhrmxpmmask;
142 static GdkPixmap *m_outboxopenxpm;
143 static GdkBitmap *m_outboxopenxpmmask;
144 static GdkPixmap *m_outboxopenhrmxpm;
145 static GdkBitmap *m_outboxopenhrmxpmmask;
146 static GdkPixmap *m_folderxpm;
147 static GdkBitmap *m_folderxpmmask;
148 static GdkPixmap *m_folderhrmxpm;
149 static GdkBitmap *m_folderhrmxpmmask;
150 static GdkPixmap *m_folderopenxpm;
151 static GdkBitmap *m_folderopenxpmmask;
152 static GdkPixmap *m_folderopenhrmxpm;
153 static GdkBitmap *m_folderopenhrmxpmmask;
154 static GdkPixmap *m_trashopenxpm;
155 static GdkBitmap *m_trashopenxpmmask;
156 static GdkPixmap *m_trashopenhrmxpm;
157 static GdkBitmap *m_trashopenhrmxpmmask;
158 static GdkPixmap *m_trashxpm;
159 static GdkBitmap *m_trashxpmmask;
160 static GdkPixmap *m_trashhrmxpm;
161 static GdkBitmap *m_trashhrmxpmmask;
162 static GdkPixmap *m_queuexpm;
163 static GdkBitmap *m_queuexpmmask;
164 static GdkPixmap *m_queuehrmxpm;
165 static GdkBitmap *m_queuehrmxpmmask;
166 static GdkPixmap *m_queueopenxpm;
167 static GdkBitmap *m_queueopenxpmmask;
168 static GdkPixmap *m_queueopenhrmxpm;
169 static GdkBitmap *m_queueopenhrmxpmmask;
170 static GdkPixmap *m_draftsxpm;
171 static GdkBitmap *m_draftsxpmmask;
172 static GdkPixmap *m_draftsopenxpm;
173 static GdkBitmap *m_draftsopenxpmmask;
175 static GdkPixmap *newxpm;
176 static GdkBitmap *newxpmmask;
177 static GdkPixmap *unreadxpm;
178 static GdkBitmap *unreadxpmmask;
179 static GdkPixmap *readxpm;
180 static GdkBitmap *readxpmmask;
183 static void folderview_select_node (FolderView *folderview,
185 static void folderview_set_folders (FolderView *folderview);
186 static void folderview_sort_folders (FolderView *folderview,
189 static void folderview_append_folder (FolderView *folderview,
191 static void folderview_update_node (FolderView *folderview,
194 static gint folderview_clist_compare (GtkCList *clist,
198 /* callback functions */
199 static gboolean folderview_button_pressed (GtkWidget *ctree,
200 GdkEventButton *event,
201 FolderView *folderview);
202 static gboolean folderview_button_released (GtkWidget *ctree,
203 GdkEventButton *event,
204 FolderView *folderview);
205 static gboolean folderview_key_pressed (GtkWidget *widget,
207 FolderView *folderview);
208 static void folderview_selected (GtkCTree *ctree,
211 FolderView *folderview);
212 static void folderview_tree_expanded (GtkCTree *ctree,
214 FolderView *folderview);
215 static void folderview_tree_collapsed (GtkCTree *ctree,
217 FolderView *folderview);
218 static void folderview_popup_close (GtkMenuShell *menu_shell,
219 FolderView *folderview);
220 static void folderview_col_resized (GtkCList *clist,
223 FolderView *folderview);
225 static void mark_all_read_cb (FolderView *folderview,
229 static void folderview_empty_trash_cb (FolderView *folderview,
233 static void folderview_send_queue_cb (FolderView *folderview,
237 static void folderview_search_cb (FolderView *folderview,
241 static void folderview_property_cb (FolderView *folderview,
245 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
246 GdkDragContext *context,
250 FolderView *folderview);
251 static void folderview_drag_leave_cb (GtkWidget *widget,
252 GdkDragContext *context,
254 FolderView *folderview);
255 static void folderview_drag_received_cb (GtkWidget *widget,
256 GdkDragContext *drag_context,
259 GtkSelectionData *data,
262 FolderView *folderview);
263 static void folderview_start_drag (GtkWidget *widget, gint button, GdkEvent *event,
264 FolderView *folderview);
265 static void folderview_drag_data_get (GtkWidget *widget,
266 GdkDragContext *drag_context,
267 GtkSelectionData *selection_data,
270 FolderView *folderview);
271 static void folderview_drag_end_cb (GtkWidget *widget,
272 GdkDragContext *drag_context,
273 FolderView *folderview);
275 void folderview_create_folder_node (FolderView *folderview,
277 gboolean folderview_update_folder (gpointer source,
279 gboolean folderview_update_item_claws (gpointer source,
281 static void folderview_processing_cb(FolderView *folderview, guint action,
283 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
284 GdkEventButton *event);
286 GHashTable *folderview_popups;
288 static GtkItemFactoryEntry folderview_common_popup_entries[] =
290 {N_("/Mark all re_ad"), NULL, mark_all_read_cb, 0, NULL},
291 {N_("/_Search folder..."), NULL, folderview_search_cb, 0, NULL},
292 {N_("/_Properties..."), NULL, folderview_property_cb, 0, NULL},
293 {N_("/Process_ing..."), NULL, folderview_processing_cb, 0, NULL},
296 static GtkItemFactoryEntry folder_view_trash_popup_entries[] = {
297 {"/------trashsep", NULL, NULL, 0, "<Separator>"},
298 {N_("/Empty _trash..."), NULL, folderview_empty_trash_cb, 0, NULL},
301 static GtkItemFactoryEntry folder_view_queue_popup_entries[] = {
302 {"/------queuesep", NULL, NULL, 0, "<Separator>"},
303 {N_("/Send _queue..."), NULL, folderview_send_queue_cb, 0, NULL},
307 GtkTargetEntry folderview_drag_types[] =
309 {"sylpheed-claws/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY},
310 {"text/uri-list", 0, TARGET_MAIL_URI_LIST}
313 void folderview_initialize(void)
315 FolderViewPopup *fpopup;
317 GSList *entries = NULL;
319 fpopup = g_new0(FolderViewPopup, 1);
321 n_entries = sizeof(folderview_common_popup_entries) /
322 sizeof(folderview_common_popup_entries[0]);
323 for (i = 0; i < n_entries; i++)
324 entries = g_slist_append(entries, &folderview_common_popup_entries[i]);
326 fpopup->klass = "common";
327 fpopup->path = "<CommonFolder>";
328 fpopup->entries = entries;
329 fpopup->set_sensitivity = NULL;
331 folderview_popups = g_hash_table_new(g_str_hash, g_str_equal);
332 g_hash_table_insert(folderview_popups, "common", fpopup);
335 static GtkItemFactory *create_ifactory(FolderView *folderview, FolderViewPopup *fpopup)
338 GtkItemFactory *factory;
339 FolderViewPopup *fpopup_common;
342 factory = gtk_item_factory_new(GTK_TYPE_MENU, fpopup->path, NULL);
343 gtk_item_factory_set_translate_func(factory, menu_translate,
346 for (entries = fpopup->entries; entries != NULL; entries = g_slist_next(entries))
347 gtk_item_factory_create_item(factory, entries->data, folderview, 1);
349 fpopup_common = g_hash_table_lookup(folderview_popups, "common");
350 if (fpopup_common != fpopup)
351 for (entries = fpopup_common->entries; entries != NULL; entries = g_slist_next(entries))
352 gtk_item_factory_create_item(factory, entries->data, folderview, 1);
354 popup = gtk_item_factory_get_widget(factory, fpopup->path);
355 g_signal_connect(G_OBJECT(popup), "selection_done",
356 G_CALLBACK(folderview_popup_close),
362 static void create_ifactories(gpointer key, gpointer value, gpointer data)
364 FolderView *folderview = data;
365 FolderViewPopup *fpopup = value;
366 GtkItemFactory *factory;
368 factory = create_ifactory(folderview, fpopup);
369 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
372 static void folderview_column_set_titles(FolderView *folderview)
374 GtkWidget *ctree = folderview->ctree;
375 GtkWidget *label_new;
376 GtkWidget *label_unread;
377 GtkWidget *label_total;
379 GtkWidget *hbox_unread;
380 GtkWidget *hbox_total;
381 gint *col_pos = folderview->col_pos;
383 debug_print("setting titles...\n");
384 gtk_widget_realize(folderview->ctree);
385 gtk_widget_show_all(folderview->scrolledwin);
387 /* CLAWS: titles for "New" and "Unread" show new & unread pixmaps
388 * instead text (text overflows making them unreadable and ugly) */
389 stock_pixmap_gdk(ctree, STOCK_PIXMAP_NEW,
390 &newxpm, &newxpmmask);
391 stock_pixmap_gdk(ctree, STOCK_PIXMAP_UNREAD,
392 &unreadxpm, &unreadxpmmask);
393 stock_pixmap_gdk(ctree, STOCK_PIXMAP_READ,
394 &readxpm, &readxpmmask);
396 label_new = gtk_pixmap_new(newxpm, newxpmmask);
397 label_unread = gtk_pixmap_new(unreadxpm, unreadxpmmask);
398 label_total = gtk_pixmap_new(readxpm, readxpmmask);
400 hbox_new = gtk_hbox_new(FALSE, 4);
401 hbox_unread = gtk_hbox_new(FALSE, 4);
402 hbox_total = gtk_hbox_new(FALSE, 4);
405 gtk_box_pack_start(GTK_BOX(hbox_new), label_new, TRUE, TRUE, 0);
406 gtk_misc_set_alignment (GTK_MISC (label_new), 1, 0.5);
407 gtk_box_pack_start(GTK_BOX(hbox_unread), label_unread, TRUE, TRUE, 0);
408 gtk_misc_set_alignment (GTK_MISC (label_unread), 1, 0.5);
409 gtk_box_pack_start(GTK_BOX(hbox_total), label_total, TRUE, TRUE, 0);
410 gtk_misc_set_alignment (GTK_MISC (label_total), 1, 0.5);
412 gtk_widget_show_all(hbox_new);
413 gtk_widget_show_all(hbox_unread);
414 gtk_widget_show_all(hbox_total);
416 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_NEW],hbox_new);
417 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_UNREAD],hbox_unread);
418 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_TOTAL],hbox_total);
421 static gboolean folderview_popup_menu(GtkWidget *widget, gpointer data)
423 FolderView *folderview = (FolderView *)data;
424 GdkEventButton event;
425 if (folderview_get_selected_item(folderview) == NULL)
429 event.time = gtk_get_current_event_time();
431 folderview_set_sens_and_popup_menu(folderview, -1,
438 GtkWidget *folderview_ctree_create(FolderView *folderview)
442 FolderColumnState *col_state;
443 FolderColumnType type;
444 gchar *titles[N_FOLDER_COLS];
446 GtkWidget *scrolledwin = folderview->scrolledwin;
448 debug_print("creating tree...\n");
449 memset(titles, 0, sizeof(titles));
451 col_state = prefs_folder_column_get_config();
452 memset(titles, 0, sizeof(titles));
454 col_pos = folderview->col_pos;
456 for (i = 0; i < N_FOLDER_COLS; i++) {
457 folderview->col_state[i] = col_state[i];
458 type = col_state[i].type;
462 titles[col_pos[F_COL_FOLDER]] = _("Folder");
463 titles[col_pos[F_COL_NEW]] = _("New");
464 titles[col_pos[F_COL_UNREAD]] = _("Unread");
465 /* TRANSLATORS: This in Number sign in American style */
466 titles[col_pos[F_COL_TOTAL]] = _("#");
468 ctree = gtk_sctree_new_with_titles(N_FOLDER_COLS, col_pos[F_COL_FOLDER],
471 gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
472 gtk_clist_set_column_justification(GTK_CLIST(ctree), col_pos[F_COL_NEW],
474 gtk_clist_set_column_justification(GTK_CLIST(ctree),
475 col_pos[F_COL_UNREAD],
477 gtk_clist_set_column_justification(GTK_CLIST(ctree),
478 col_pos[F_COL_TOTAL],
480 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
481 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
482 GTK_CTREE_EXPANDER_SQUARE);
483 gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
484 gtk_clist_set_compare_func(GTK_CLIST(ctree), folderview_clist_compare);
486 /* don't let title buttons take key focus */
487 for (i = 0; i < N_FOLDER_COLS; i++) {
488 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(ctree)->column[i].button,
490 gtk_clist_set_column_width(GTK_CLIST(ctree), col_pos[i],
491 prefs_common.folder_col_size[i]);
492 gtk_clist_set_column_visibility
493 (GTK_CLIST(ctree), i, col_state[i].visible);
496 g_signal_connect(G_OBJECT(ctree), "key_press_event",
497 G_CALLBACK(folderview_key_pressed),
499 g_signal_connect(G_OBJECT(ctree), "button_press_event",
500 G_CALLBACK(folderview_button_pressed),
502 g_signal_connect(G_OBJECT(ctree), "popup-menu",
503 G_CALLBACK(folderview_popup_menu), folderview);
504 g_signal_connect(G_OBJECT(ctree), "button_release_event",
505 G_CALLBACK(folderview_button_released),
507 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
508 G_CALLBACK(folderview_selected), folderview);
509 g_signal_connect(G_OBJECT(ctree), "start_drag",
510 G_CALLBACK(folderview_start_drag), folderview);
511 g_signal_connect(G_OBJECT(ctree), "drag_data_get",
512 G_CALLBACK(folderview_drag_data_get),
515 g_signal_connect_after(G_OBJECT(ctree), "tree_expand",
516 G_CALLBACK(folderview_tree_expanded),
518 g_signal_connect_after(G_OBJECT(ctree), "tree_collapse",
519 G_CALLBACK(folderview_tree_collapsed),
522 g_signal_connect(G_OBJECT(ctree), "resize_column",
523 G_CALLBACK(folderview_col_resized),
527 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
528 folderview_drag_types, 2,
529 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
530 g_signal_connect(G_OBJECT(ctree), "drag_motion",
531 G_CALLBACK(folderview_drag_motion_cb),
533 g_signal_connect(G_OBJECT(ctree), "drag_leave",
534 G_CALLBACK(folderview_drag_leave_cb),
536 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
537 G_CALLBACK(folderview_drag_received_cb),
539 g_signal_connect(G_OBJECT(ctree), "drag_end",
540 G_CALLBACK(folderview_drag_end_cb),
543 gtk_container_add(GTK_CONTAINER(scrolledwin), ctree);
548 void folderview_set_column_order(FolderView *folderview)
551 FolderItem *item = folderview_get_selected_item(folderview);
552 GtkWidget *scrolledwin = folderview->scrolledwin;
554 debug_print("recreating tree...\n");
555 gtk_widget_destroy(folderview->ctree);
557 folderview->ctree = ctree = folderview_ctree_create(folderview);
558 gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
559 GTK_CLIST(ctree)->hadjustment);
560 gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
561 GTK_CLIST(ctree)->vadjustment);
562 gtk_widget_show(ctree);
564 folderview_set(folderview);
565 folderview_column_set_titles(folderview);
567 folderview_select(folderview,item);
570 FolderView *folderview_create(void)
572 FolderView *folderview;
573 GtkWidget *scrolledwin;
576 debug_print("Creating folder view...\n");
577 folderview = g_new0(FolderView, 1);
579 scrolledwin = gtk_scrolled_window_new(NULL, NULL);
580 gtk_scrolled_window_set_policy
581 (GTK_SCROLLED_WINDOW(scrolledwin),
582 GTK_POLICY_AUTOMATIC,
583 prefs_common.folderview_vscrollbar_policy);
584 gtk_widget_set_size_request(scrolledwin,
585 prefs_common.folderview_width,
586 prefs_common.folderview_height);
588 folderview->scrolledwin = scrolledwin;
589 ctree = folderview_ctree_create(folderview);
591 /* create popup factories */
592 folderview->popups = g_hash_table_new(g_str_hash, g_str_equal);
593 g_hash_table_foreach(folderview_popups, create_ifactories, folderview);
595 folderview->ctree = ctree;
597 folderview->folder_update_callback_id =
598 hooks_register_hook(FOLDER_UPDATE_HOOKLIST, folderview_update_folder, (gpointer) folderview);
599 folderview->folder_item_update_callback_id =
600 hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST, folderview_update_item_claws, (gpointer) folderview);
602 gtk_widget_show_all(scrolledwin);
604 folderview->target_list = gtk_target_list_new(folderview_drag_types, 2);
605 folderview_list = g_list_append(folderview_list, folderview);
610 void folderview_init(FolderView *folderview)
612 GtkWidget *ctree = folderview->ctree;
615 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE, &inboxxpm, &inboxxpmmask);
616 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM, &inboxhrmxpm, &inboxhrmxpmmask);
617 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN, &inboxopenxpm, &inboxopenxpmmask);
618 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM, &inboxopenhrmxpm, &inboxopenhrmxpmmask);
619 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE, &outboxxpm, &outboxxpmmask);
620 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM, &outboxhrmxpm, &outboxhrmxpmmask);
621 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN, &outboxopenxpm, &outboxopenxpmmask);
622 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM, &outboxopenhrmxpm, &outboxopenhrmxpmmask);
623 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
624 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM, &folderhrmxpm, &folderhrmxpmmask);
625 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
626 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM, &folderopenhrmxpm, &folderopenhrmxpmmask);
627 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN, &trashopenxpm, &trashopenxpmmask);
628 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM, &trashopenhrmxpm, &trashopenhrmxpmmask);
629 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE, &trashxpm, &trashxpmmask);
630 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM, &trashhrmxpm, &trashhrmxpmmask);
631 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE, &queuexpm, &queuexpmmask);
632 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM, &queuehrmxpm, &queuehrmxpmmask);
633 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN, &queueopenxpm, &queueopenxpmmask);
634 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM, &queueopenhrmxpm, &queueopenhrmxpmmask);
635 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE, &draftsxpm, &draftsxpmmask);
636 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN, &draftsopenxpm, &draftsopenxpmmask);
637 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_NOSELECT, &noselectxpm, &noselectxpmmask);
639 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_MARK, &m_inboxxpm, &m_inboxxpmmask);
640 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM_MARK, &m_inboxhrmxpm, &m_inboxhrmxpmmask);
641 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_MARK, &m_inboxopenxpm, &m_inboxopenxpmmask);
642 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM_MARK, &m_inboxopenhrmxpm, &m_inboxopenhrmxpmmask);
643 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_MARK, &m_outboxxpm, &m_outboxxpmmask);
644 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM_MARK, &m_outboxhrmxpm, &m_outboxhrmxpmmask);
645 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_MARK, &m_outboxopenxpm, &m_outboxopenxpmmask);
646 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM_MARK, &m_outboxopenhrmxpm, &m_outboxopenhrmxpmmask);
647 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_MARK, &m_folderxpm, &m_folderxpmmask);
648 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM_MARK, &m_folderhrmxpm, &m_folderhrmxpmmask);
649 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_MARK, &m_folderopenxpm, &m_folderopenxpmmask);
650 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM_MARK, &m_folderopenhrmxpm, &m_folderopenhrmxpmmask);
651 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_MARK, &m_trashopenxpm, &m_trashopenxpmmask);
652 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM_MARK, &m_trashopenhrmxpm, &m_trashopenhrmxpmmask);
653 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_MARK, &m_trashxpm, &m_trashxpmmask);
654 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM_MARK, &m_trashhrmxpm, &m_trashhrmxpmmask);
655 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_MARK, &m_queuexpm, &m_queuexpmmask);
656 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM_MARK, &m_queuehrmxpm, &m_queuehrmxpmmask);
657 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_MARK, &m_queueopenxpm, &m_queueopenxpmmask);
658 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM_MARK, &m_queueopenhrmxpm, &m_queueopenhrmxpmmask);
659 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE_MARK, &m_draftsxpm, &m_draftsxpmmask);
660 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN_MARK, &m_draftsopenxpm, &m_draftsopenxpmmask);
663 PangoFontDescription *font_desc;
664 normal_style = gtk_style_copy(gtk_widget_get_style(ctree));
665 font_desc = pango_font_description_from_string(NORMAL_FONT);
667 if (normal_style->font_desc)
668 pango_font_description_free
669 (normal_style->font_desc);
670 normal_style->font_desc = font_desc;
672 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
673 normal_color_style = gtk_style_copy(normal_style);
674 normal_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
676 gtk_widget_set_style(ctree, normal_style);
680 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
681 bold_style = gtk_style_copy(gtk_widget_get_style(ctree));
682 pango_font_description_set_weight
683 (bold_style->font_desc, PANGO_WEIGHT_BOLD);
684 bold_color_style = gtk_style_copy(bold_style);
685 bold_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
687 bold_tgtfold_style = gtk_style_copy(bold_style);
688 bold_tgtfold_style->fg[GTK_STATE_NORMAL] = folderview->color_op;
692 void folderview_set(FolderView *folderview)
694 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
695 MainWindow *mainwin = folderview->mainwin;
700 debug_print("Setting folder info...\n");
701 STATUSBAR_PUSH(mainwin, _("Setting folder info..."));
703 main_window_cursor_wait(mainwin);
705 folderview->selected = NULL;
706 folderview->opened = NULL;
708 gtk_clist_freeze(GTK_CLIST(ctree));
709 gtk_clist_clear(GTK_CLIST(ctree));
710 gtk_clist_thaw(GTK_CLIST(ctree));
711 gtk_clist_freeze(GTK_CLIST(ctree));
713 folderview_set_folders(folderview);
715 gtk_clist_thaw(GTK_CLIST(ctree));
716 main_window_cursor_normal(mainwin);
717 STATUSBAR_POP(mainwin);
720 void folderview_set_all(void)
724 for (list = folderview_list; list != NULL; list = list->next)
725 folderview_set((FolderView *)list->data);
728 void folderview_select(FolderView *folderview, FolderItem *item)
730 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
732 GtkCTreeNode *old_selected = folderview->selected;
736 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
737 if (node) folderview_select_node(folderview, node);
739 if (old_selected != node)
740 folder_update_op_count();
743 static void mark_all_read_cb(FolderView *folderview, guint action,
749 item = folderview_get_selected_item(folderview);
753 if (folderview->summaryview->folder_item != item
754 && prefs_common.ask_mark_all_read) {
755 val = alertpanel_full(_("Mark all as read"),
756 _("Do you really want to mark all mails in this "
757 "folder as read ?"), GTK_STOCK_NO, GTK_STOCK_YES, NULL,
758 TRUE, NULL, ALERT_QUESTION, G_ALERTDEFAULT);
760 if ((val & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
762 else if (val & G_ALERTDISABLE)
763 prefs_common.ask_mark_all_read = FALSE;
766 summary_lock(folderview->summaryview);
767 folder_item_update_freeze();
768 if (folderview->summaryview->folder_item == item)
769 gtk_clist_freeze(GTK_CLIST(folderview->summaryview->ctree));
770 folderutils_mark_all_read(item);
771 if (folderview->summaryview->folder_item == item)
772 gtk_clist_thaw(GTK_CLIST(folderview->summaryview->ctree));
773 folder_item_update_thaw();
774 summary_unlock(folderview->summaryview);
777 static void folderview_select_node(FolderView *folderview, GtkCTreeNode *node)
779 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
781 g_return_if_fail(node != NULL);
783 folderview->open_folder = TRUE;
784 gtkut_ctree_set_focus_row(ctree, node);
785 gtk_ctree_select(ctree, node);
786 if (folderview->summaryview->folder_item &&
787 folderview->summaryview->folder_item->total_msgs > 0)
788 gtk_widget_grab_focus(folderview->summaryview->ctree);
790 gtk_widget_grab_focus(folderview->ctree);
792 gtkut_ctree_expand_parent_all(ctree, node);
795 void folderview_unselect(FolderView *folderview)
797 if (folderview->opened && !GTK_CTREE_ROW(folderview->opened)->children)
799 (GTK_CTREE(folderview->ctree), folderview->opened);
801 folderview->selected = folderview->opened = NULL;
804 static GtkCTreeNode *folderview_find_next_marked(GtkCTree *ctree,
810 node = gtkut_ctree_node_next(ctree, node);
812 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
814 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
815 item = gtk_ctree_node_get_row_data(ctree, node);
816 if (item && item->marked_msgs > 0 && item->stype != F_TRASH)
823 void folderview_select_next_marked(FolderView *folderview)
825 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
826 GtkCTreeNode *node = NULL;
827 SelectOnEntry last_sel = prefs_common.select_on_entry;
828 gboolean last_open = prefs_common.always_show_msg;
830 prefs_common.select_on_entry = SELECTONENTRY_MNU;
831 prefs_common.always_show_msg = TRUE;
833 if ((node = folderview_find_next_marked(ctree, folderview->opened))
835 folderview_select_node(folderview, node);
839 if (!folderview->opened ||
840 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
843 /* search again from the first node */
844 if ((node = folderview_find_next_marked(ctree, NULL)) != NULL)
845 folderview_select_node(folderview, node);
848 prefs_common.select_on_entry = last_sel;
849 prefs_common.always_show_msg = last_open;
852 static GtkCTreeNode *folderview_find_next_unread(GtkCTree *ctree,
858 node = gtkut_ctree_node_next(ctree, node);
860 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
862 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
863 item = gtk_ctree_node_get_row_data(ctree, node);
864 if (item && item->unread_msgs > 0 && item->stype != F_TRASH)
871 void folderview_select_next_unread(FolderView *folderview)
873 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
874 GtkCTreeNode *node = NULL;
875 SelectOnEntry last_sel = prefs_common.select_on_entry;
876 gboolean last_open = prefs_common.always_show_msg;
878 prefs_common.select_on_entry = SELECTONENTRY_UNM;
879 prefs_common.always_show_msg = TRUE;
881 if ((node = folderview_find_next_unread(ctree, folderview->opened))
883 folderview_select_node(folderview, node);
887 if (!folderview->opened ||
888 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
891 /* search again from the first node */
892 if ((node = folderview_find_next_unread(ctree, NULL)) != NULL)
893 folderview_select_node(folderview, node);
896 prefs_common.select_on_entry = last_sel;
897 prefs_common.always_show_msg = last_open;
900 static GtkCTreeNode *folderview_find_next_new(GtkCTree *ctree,
906 node = gtkut_ctree_node_next(ctree, node);
908 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
910 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
911 item = gtk_ctree_node_get_row_data(ctree, node);
912 if (item && item->new_msgs > 0 && item->stype != F_TRASH)
919 void folderview_select_next_new(FolderView *folderview)
921 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
922 GtkCTreeNode *node = NULL;
923 SelectOnEntry last_sel = prefs_common.select_on_entry;
924 gboolean last_open = prefs_common.always_show_msg;
926 prefs_common.select_on_entry = SELECTONENTRY_NUM;
927 prefs_common.always_show_msg = TRUE;
929 if ((node = folderview_find_next_new(ctree, folderview->opened))
931 folderview_select_node(folderview, node);
935 if (!folderview->opened ||
936 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
939 /* search again from the first node */
940 if ((node = folderview_find_next_new(ctree, NULL)) != NULL)
941 folderview_select_node(folderview, node);
944 prefs_common.select_on_entry = last_sel;
945 prefs_common.always_show_msg = last_open;
948 FolderItem *folderview_get_selected_item(FolderView *folderview)
950 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
952 if (!folderview->selected) return NULL;
953 return gtk_ctree_node_get_row_data(ctree, folderview->selected);
956 void folderview_update_msg_num(FolderView *folderview, GtkCTreeNode *row)
958 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
959 static GtkCTreeNode *prev_row = NULL;
961 gint new, unread, total;
962 gchar *new_str, *unread_str, *total_str;
963 gint *col_pos = folderview->col_pos;
967 item = gtk_ctree_node_get_row_data(ctree, row);
970 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_NEW], &new_str);
971 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_UNREAD], &unread_str);
972 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_TOTAL], &total_str);
974 unread = atoi(unread_str);
975 total = atoi(total_str);
979 folderview_update_node(folderview, row);
982 void folderview_append_item(FolderItem *item)
986 g_return_if_fail(item != NULL);
987 g_return_if_fail(item->folder != NULL);
988 if (folder_item_parent(item)) return;
990 for (list = folderview_list; list != NULL; list = list->next) {
991 FolderView *folderview = (FolderView *)list->data;
992 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
993 GtkCTreeNode *node, *child;
994 gint *col_pos = folderview->col_pos;
996 node = gtk_ctree_find_by_row_data(ctree, NULL,
997 folder_item_parent(item));
999 child = gtk_ctree_find_by_row_data(ctree, node, item);
1001 gchar *text[N_FOLDER_COLS] =
1002 {NULL, "0", "0", "0"};
1004 gtk_clist_freeze(GTK_CLIST(ctree));
1006 text[col_pos[F_COL_FOLDER]] = item->name;
1007 child = gtk_sctree_insert_node
1008 (ctree, node, NULL, text,
1010 folderxpm, folderxpmmask,
1011 folderopenxpm, folderopenxpmmask,
1013 gtk_ctree_node_set_row_data(ctree, child, item);
1014 gtk_ctree_expand(ctree, node);
1015 folderview_update_node(folderview, child);
1016 folderview_sort_folders(folderview, node,
1019 gtk_clist_thaw(GTK_CLIST(ctree));
1025 static void folderview_set_folders(FolderView *folderview)
1028 #ifndef HAVE_LIBETPAN
1029 static gboolean missing_imap_warning = TRUE;
1031 list = folder_get_list();
1033 for (; list != NULL; list = list->next) {
1034 #ifndef HAVE_LIBETPAN
1035 if ((FOLDER(list->data))
1036 && (FOLDER(list->data))->klass
1037 && (FOLDER(list->data))->klass->type == F_IMAP
1038 && missing_imap_warning) {
1039 missing_imap_warning = FALSE;
1041 _("You have one or more IMAP accounts "
1042 "defined. However this version of "
1043 "Sylpheed-Claws has been built without "
1044 "IMAP support; your IMAP account(s) are "
1046 "You probably need to "
1047 "install libetpan and recompile "
1048 "Sylpheed-Claws."));
1051 folderview_append_folder(folderview, FOLDER(list->data));
1055 static gchar *get_scan_str(FolderItem *item)
1058 return g_strdup_printf(_("Scanning folder %s%c%s ..."),
1059 item->folder->name, G_DIR_SEPARATOR,
1062 return g_strdup_printf(_("Scanning folder %s ..."),
1063 item->folder->name);
1065 static void folderview_scan_tree_func(Folder *folder, FolderItem *item,
1069 for (list = folderview_list; list != NULL; list = list->next) {
1070 FolderView *folderview = (FolderView *)list->data;
1071 MainWindow *mainwin = folderview->mainwin;
1072 gchar *str = get_scan_str(item);
1074 STATUSBAR_PUSH(mainwin, str);
1075 STATUSBAR_POP(mainwin);
1080 void folderview_rescan_tree(Folder *folder, gboolean rebuild)
1084 g_return_if_fail(folder != NULL);
1086 if (!folder->klass->scan_tree) return;
1089 alertpanel_full(_("Rebuild folder tree"),
1090 _("Rebuilding the folder tree will remove "
1091 "local caches. Do you want to continue?"),
1092 GTK_STOCK_NO, GTK_STOCK_YES, NULL, FALSE,
1093 NULL, ALERT_WARNING, G_ALERTDEFAULT)
1094 != G_ALERTALTERNATE) {
1100 window = label_window_create(_("Rebuilding folder tree..."));
1102 window = label_window_create(_("Scanning folder tree..."));
1104 folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
1105 folder_scan_tree(folder, rebuild);
1106 folder_set_ui_func(folder, NULL, NULL);
1108 folderview_set_all();
1110 gtk_widget_destroy(window);
1114 /** folderview_check_new()
1115 * Scan and update the folder and return the
1116 * count the number of new messages since last check.
1117 * \param folder the folder to check for new messages
1118 * \return the number of new messages since last check
1120 gint folderview_check_new(Folder *folder)
1124 FolderView *folderview;
1128 gint former_new_msgs = 0;
1129 gint former_new = 0, former_unread = 0, former_total;
1131 for (list = folderview_list; list != NULL; list = list->next) {
1132 folderview = (FolderView *)list->data;
1133 ctree = GTK_CTREE(folderview->ctree);
1136 main_window_lock(folderview->mainwin);
1138 for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
1139 node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
1141 item = gtk_ctree_node_get_row_data(ctree, node);
1142 if (!item || !item->path || !item->folder) continue;
1143 if (item->no_select) continue;
1144 if (folder && folder != item->folder) continue;
1145 if (!folder && !FOLDER_IS_LOCAL(item->folder)) continue;
1146 if (!item->prefs->newmailcheck) continue;
1147 if (item->processing_pending == TRUE) {
1148 debug_print("skipping %s, processing pending\n",
1149 item->path ? item->path : item->name);
1153 str = get_scan_str(item);
1155 STATUSBAR_PUSH(folderview->mainwin, str);
1159 folderview_scan_tree_func(item->folder, item, NULL);
1160 former_new = item->new_msgs;
1161 former_unread = item->unread_msgs;
1162 former_total = item->total_msgs;
1164 if (item->folder->klass->scan_required &&
1165 (item->folder->klass->scan_required(item->folder, item) ||
1166 item->folder->inbox == item ||
1167 item->opened == TRUE ||
1168 item->processing_pending == TRUE)) {
1169 if (folder_item_scan(item) < 0) {
1170 summaryview_unlock(folderview->summaryview, item);
1171 if (folder && !FOLDER_IS_LOCAL(folder)) {
1172 STATUSBAR_POP(folderview->mainwin);
1176 } else if (!item->folder->klass->scan_required) {
1177 if (folder_item_scan(item) < 0) {
1178 summaryview_unlock(folderview->summaryview, item);
1179 if (folder && !FOLDER_IS_LOCAL(folder)) {
1180 STATUSBAR_POP(folderview->mainwin);
1185 if (former_new != item->new_msgs ||
1186 former_unread != item->unread_msgs ||
1187 former_total != item->total_msgs)
1188 folderview_update_node(folderview, node);
1190 new_msgs += item->new_msgs;
1191 former_new_msgs += former_new;
1192 STATUSBAR_POP(folderview->mainwin);
1195 main_window_unlock(folderview->mainwin);
1199 folder_write_list();
1200 /* Number of new messages since last check is the just the difference
1201 * between former_new_msgs and new_msgs. If new_msgs is less than
1202 * former_new_msgs, that would mean another session accessed the folder
1203 * and the result is not well defined.
1205 new_msgs = (former_new_msgs < new_msgs ? new_msgs - former_new_msgs : 0);
1209 void folderview_check_new_all(void)
1213 FolderView *folderview;
1215 folderview = (FolderView *)folderview_list->data;
1218 main_window_lock(folderview->mainwin);
1219 window = label_window_create
1220 (_("Checking for new messages in all folders..."));
1222 list = folder_get_list();
1223 for (; list != NULL; list = list->next) {
1224 Folder *folder = list->data;
1226 folderview_check_new(folder);
1229 folder_write_list();
1230 folderview_set_all();
1232 gtk_widget_destroy(window);
1233 main_window_unlock(folderview->mainwin);
1237 static gboolean folderview_have_new_children_sub(FolderView *folderview,
1243 if (!item || !item->folder || !item->folder->node)
1246 node = item->folder->node;
1248 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1249 node = node->children;
1252 (item->new_msgs > 0 ||
1253 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1257 while (node != NULL) {
1258 if (node && node->data) {
1259 FolderItem *next_item = (FolderItem*) node->data;
1261 if (folderview_have_new_children_sub(folderview,
1270 static gboolean folderview_have_new_children(FolderView *folderview,
1273 return folderview_have_new_children_sub(folderview, item, FALSE);
1276 static gboolean folderview_have_unread_children_sub(FolderView *folderview,
1282 if (!item || !item->folder || !item->folder->node)
1285 node = item->folder->node;
1287 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1288 node = node->children;
1291 (item->unread_msgs > 0 ||
1292 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1296 while (node != NULL) {
1297 if (node && node->data) {
1298 FolderItem *next_item = (FolderItem*) node->data;
1300 if (folderview_have_unread_children_sub(folderview,
1310 static gboolean folderview_have_unread_children(FolderView *folderview,
1313 return folderview_have_unread_children_sub(folderview, item, FALSE);
1316 static gboolean folderview_have_matching_children_sub(FolderView *folderview,
1322 if (!item || !item->folder || !item->folder->node)
1325 node = item->folder->node;
1327 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1328 node = node->children;
1330 if (in_sub && item->search_match){
1334 while (node != NULL) {
1335 if (node && node->data) {
1336 FolderItem *next_item = (FolderItem*) node->data;
1338 if (folderview_have_matching_children_sub(folderview,
1348 static gboolean folderview_have_matching_children(FolderView *folderview,
1351 return folderview_have_matching_children_sub(folderview, item, FALSE);
1354 static gboolean folderview_have_marked_children_sub(FolderView *folderview,
1360 if (!item || !item->folder || !item->folder->node)
1363 node = item->folder->node;
1365 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1366 node = node->children;
1368 if (item->marked_msgs != 0) {
1372 while (node != NULL) {
1373 if (node && node->data) {
1374 FolderItem *next_item = (FolderItem*) node->data;
1376 if (folderview_have_marked_children_sub(folderview,
1385 static gboolean folderview_have_marked_children(FolderView *folderview,
1388 return folderview_have_marked_children_sub(folderview, item, FALSE);
1391 static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node)
1393 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1394 GtkStyle *style = NULL;
1395 GtkStyle *color_style = NULL;
1397 GdkPixmap *xpm, *openxpm;
1398 GdkBitmap *mask, *openmask;
1399 static GdkPixmap *searchicon;
1400 static GdkBitmap *searchmask;
1401 gboolean mark = FALSE;
1404 gboolean add_unread_mark;
1405 gboolean add_sub_match_mark;
1406 gboolean use_bold, use_color;
1407 gint *col_pos = folderview->col_pos;
1408 SpecialFolderItemType stype;
1410 item = gtk_ctree_node_get_row_data(ctree, node);
1411 g_return_if_fail(item != NULL);
1413 if (!GTK_CTREE_ROW(node)->expanded)
1414 mark = folderview_have_marked_children(folderview, item);
1416 mark = (item->marked_msgs != 0);
1418 stype = item->stype;
1419 if (stype == F_NORMAL) {
1420 if (folder_has_parent_of_type(item, F_TRASH))
1422 else if (folder_has_parent_of_type(item, F_DRAFT))
1424 else if (folder_has_parent_of_type(item, F_OUTBOX))
1426 else if (folder_has_parent_of_type(item, F_QUEUE))
1431 if (item->hide_read_msgs) {
1432 xpm = mark?m_inboxhrmxpm:inboxhrmxpm;
1433 mask = mark?m_inboxhrmxpmmask:inboxhrmxpmmask;
1434 openxpm = mark?m_inboxopenhrmxpm:inboxopenhrmxpm;
1435 openmask = mark?m_inboxopenhrmxpmmask:inboxopenhrmxpmmask;
1437 xpm = mark?m_inboxxpm:inboxxpm;
1438 mask = mark?m_inboxxpmmask:inboxxpmmask;
1439 openxpm = mark?m_inboxopenxpm:inboxopenxpm;
1440 openmask = mark?m_inboxopenxpmmask:inboxopenxpmmask;
1444 if (item->hide_read_msgs) {
1445 xpm = mark?m_outboxhrmxpm:outboxhrmxpm;
1446 mask = mark?m_outboxhrmxpmmask:outboxhrmxpmmask;
1447 openxpm = mark?m_outboxopenhrmxpm:outboxopenhrmxpm;
1448 openmask = mark?m_outboxopenhrmxpmmask:outboxopenhrmxpmmask;
1450 xpm = mark?m_outboxxpm:outboxxpm;
1451 mask = mark?m_outboxxpmmask:outboxxpmmask;
1452 openxpm = mark?m_outboxopenxpm:outboxopenxpm;
1453 openmask = mark?m_outboxopenxpmmask:outboxopenxpmmask;
1457 if (item->hide_read_msgs) {
1458 xpm = mark?m_queuehrmxpm:queuehrmxpm;
1459 mask = mark?m_queuehrmxpmmask:queuehrmxpmmask;
1460 openxpm = mark?m_queueopenhrmxpm:queueopenhrmxpm;
1461 openmask = mark?m_queueopenhrmxpmmask:queueopenhrmxpmmask;
1463 xpm = mark?m_queuexpm:queuexpm;
1464 mask = mark?m_queuexpmmask:queuexpmmask;
1465 openxpm = mark?m_queueopenxpm:queueopenxpm;
1466 openmask = mark?m_queueopenxpmmask:queueopenxpmmask;
1470 if (item->hide_read_msgs) {
1471 xpm = mark?m_trashhrmxpm:trashhrmxpm;
1472 mask = mark?m_trashhrmxpmmask:trashhrmxpmmask;
1473 openxpm = mark?m_trashopenhrmxpm:trashopenhrmxpm;
1474 openmask = mark?m_trashopenhrmxpmmask:trashopenhrmxpmmask;
1476 xpm = mark?m_trashxpm:trashxpm;
1477 mask = mark?m_trashxpmmask:trashxpmmask;
1478 openxpm = mark?m_trashopenxpm:trashopenxpm;
1479 openmask = mark?m_trashopenxpmmask:trashopenxpmmask;
1483 xpm = mark?m_draftsxpm:draftsxpm;
1484 mask = mark?m_draftsxpmmask:draftsxpmmask;
1485 openxpm = mark?m_draftsopenxpm:draftsopenxpm;
1486 openmask = mark?m_draftsopenxpmmask:draftsopenxpmmask;
1489 if (item->hide_read_msgs) {
1490 xpm = mark?m_folderhrmxpm:folderhrmxpm;
1491 mask = mark?m_folderhrmxpmmask:folderhrmxpmmask;
1492 openxpm = mark?m_folderopenhrmxpm:folderopenhrmxpm;
1493 openmask = mark?m_folderopenhrmxpmmask:folderopenhrmxpmmask;
1495 xpm = mark?m_folderxpm:folderxpm;
1496 mask = mark?m_folderxpmmask:folderxpmmask;
1497 openxpm = mark?m_folderopenxpm:folderopenxpm;
1498 openmask = mark?m_folderopenxpmmask:folderopenxpmmask;
1502 if (item->no_select) {
1503 xpm = openxpm = noselectxpm;
1504 mask = openmask = noselectxpmmask;
1507 name = folder_item_get_name(item);
1509 if (!GTK_CTREE_ROW(node)->expanded) {
1510 add_unread_mark = folderview_have_unread_children(
1512 add_sub_match_mark = folderview_have_matching_children(
1515 add_unread_mark = FALSE;
1516 add_sub_match_mark = FALSE;
1519 if (item->search_match) {
1521 stock_pixmap_gdk(folderview->ctree, STOCK_PIXMAP_QUICKSEARCH,
1522 &searchicon, &searchmask);
1524 xpm = openxpm = searchicon;
1525 mask = openmask = searchmask;
1528 if (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0 &&
1529 prefs_common.display_folder_unread) {
1530 str = g_strdup_printf("%s (%d%s)", name, item->total_msgs,
1531 add_unread_mark ? "+" : "");
1532 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1533 xpm, mask, openxpm, openmask,
1534 FALSE, GTK_CTREE_ROW(node)->expanded);
1536 } else if (((item->unread_msgs > 0 || add_unread_mark) &&
1537 prefs_common.display_folder_unread)
1538 || add_sub_match_mark) {
1540 if (item->unread_msgs > 0)
1541 str = g_strdup_printf("%s (%d%s%s)", name, item->unread_msgs,
1542 add_unread_mark || add_sub_match_mark ? "+" : "",
1543 item->unreadmarked_msgs > 0 ? "!":"");
1545 str = g_strdup_printf("%s (+)", name);
1546 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1547 xpm, mask, openxpm, openmask,
1548 FALSE, GTK_CTREE_ROW(node)->expanded);
1551 str = g_strdup_printf("%s%s", name,
1552 item->unreadmarked_msgs > 0 ? " (!)":"");
1554 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1555 xpm, mask, openxpm, openmask,
1556 FALSE, GTK_CTREE_ROW(node)->expanded);
1561 if (!folder_item_parent(item)) {
1562 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], "-");
1563 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], "-");
1564 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], "-");
1566 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], itos(item->new_msgs));
1567 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], itos(item->unread_msgs));
1568 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], itos(item->total_msgs));
1571 if (folder_has_parent_of_type(item, F_OUTBOX) ||
1572 folder_has_parent_of_type(item, F_DRAFT) ||
1573 folder_has_parent_of_type(item, F_TRASH)) {
1574 use_bold = use_color = FALSE;
1575 } else if (folder_has_parent_of_type(item, F_QUEUE)) {
1576 /* highlight queue folder if there are any messages */
1577 use_bold = use_color = (item->total_msgs > 0);
1579 /* if unread messages exist, print with bold font */
1580 use_bold = (item->unread_msgs > 0|| item->new_msgs > 0)
1582 /* if new messages exist, print with colored letter */
1584 (item->new_msgs > 0) ||
1586 folderview_have_new_children(folderview, item));
1589 gtk_ctree_node_set_foreground(ctree, node, NULL);
1594 if (item->prefs->color > 0 && !use_color) {
1595 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1596 color_style = gtk_style_copy(bold_style);
1597 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1598 style = color_style;
1599 } else if (use_color) {
1600 style = bold_color_style;
1603 if (item->op_count > 0) {
1604 style = bold_tgtfold_style;
1606 } else if (use_color) {
1607 style = normal_color_style;
1608 gtk_ctree_node_set_foreground(ctree, node,
1609 &folderview->color_new);
1610 } else if (item->op_count > 0) {
1611 style = bold_tgtfold_style;
1612 } else if (item->prefs->color > 0) {
1614 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1615 color_style = gtk_style_copy(normal_style);
1616 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1617 style = color_style;
1619 style = normal_style;
1622 gtk_ctree_node_set_row_style(ctree, node, style);
1624 if ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
1625 folderview_update_node(folderview, node);
1628 #if !CLAWS /* keep it here for syncs */
1629 void folderview_update_item(FolderItem *item, gboolean update_summary)
1632 FolderView *folderview;
1636 g_return_if_fail(item != NULL);
1638 for (list = folderview_list; list != NULL; list = list->next) {
1639 folderview = (FolderView *)list->data;
1640 ctree = GTK_CTREE(folderview->ctree);
1642 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1644 folderview_update_node(folderview, node);
1645 if (update_summary && folderview->opened == node)
1646 summary_show(folderview->summaryview,
1653 void folderview_update_search_icon(FolderItem *item, gboolean matches)
1656 FolderView *folderview;
1660 g_return_if_fail(item != NULL);
1662 for (list = folderview_list; list != NULL; list = list->next) {
1663 folderview = (FolderView *)list->data;
1664 ctree = GTK_CTREE(folderview->ctree);
1666 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1668 item->search_match = matches;
1669 folderview_update_node(folderview, node);
1674 gboolean folderview_update_item_claws(gpointer source, gpointer data)
1676 FolderItemUpdateData *update_info = (FolderItemUpdateData *)source;
1677 FolderView *folderview = (FolderView *)data;
1680 g_return_val_if_fail(update_info != NULL, TRUE);
1681 g_return_val_if_fail(update_info->item != NULL, TRUE);
1682 g_return_val_if_fail(folderview != NULL, FALSE);
1684 ctree = GTK_CTREE(folderview->ctree);
1686 node = gtk_ctree_find_by_row_data(ctree, NULL, update_info->item);
1688 if (update_info->update_flags & (F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_NAME))
1689 folderview_update_node(folderview, node);
1690 if ((update_info->update_flags & F_ITEM_UPDATE_CONTENT) && (folderview->opened == node))
1691 if (!quicksearch_is_active(folderview->summaryview->quicksearch))
1692 summary_show(folderview->summaryview, update_info->item);
1698 static void folderview_update_item_foreach_func(gpointer key, gpointer val,
1701 /* CLAWS: share this joy with other hook functions ... */
1702 folder_item_update((FolderItem *)key,
1703 (FolderItemUpdateFlags)GPOINTER_TO_INT(data));
1706 void folderview_update_item_foreach(GHashTable *table, gboolean update_summary)
1709 FolderItemUpdateFlags flags;
1711 flags = update_summary ? F_ITEM_UPDATE_CONTENT | F_ITEM_UPDATE_MSGCNT
1713 for (list = folderview_list; list != NULL; list = list->next)
1714 g_hash_table_foreach(table, folderview_update_item_foreach_func,
1715 GINT_TO_POINTER(flags));
1718 static gboolean folderview_gnode_func(GtkCTree *ctree, guint depth,
1719 GNode *gnode, GtkCTreeNode *cnode,
1722 FolderView *folderview = (FolderView *)data;
1723 FolderItem *item = FOLDER_ITEM(gnode->data);
1725 g_return_val_if_fail(item != NULL, FALSE);
1727 gtk_ctree_node_set_row_data(ctree, cnode, item);
1728 folderview_update_node(folderview, cnode);
1733 static void folderview_expand_func(GtkCTree *ctree, GtkCTreeNode *node,
1736 FolderView *folderview = (FolderView *)data;
1739 if (GTK_CTREE_ROW(node)->children) {
1740 item = gtk_ctree_node_get_row_data(ctree, node);
1741 g_return_if_fail(item != NULL);
1743 if (!item->collapsed)
1744 gtk_ctree_expand(ctree, node);
1746 folderview_update_node(folderview, node);
1750 static void set_special_folder(GtkCTree *ctree, FolderItem *item,
1751 GtkCTreeNode *root, GtkCTreeNode **prev)
1754 GtkCTreeNode *node, *parent, *sibling;
1756 node = gtk_ctree_find_by_row_data(ctree, root, item);
1758 g_warning("%s not found.\n", item->path);
1760 parent = GTK_CTREE_ROW(node)->parent;
1761 if (*prev && parent == GTK_CTREE_ROW(*prev)->parent)
1762 sibling = GTK_CTREE_ROW(*prev)->sibling;
1764 sibling = GTK_CTREE_ROW(parent)->children;
1768 tmp = gtk_ctree_node_get_row_data
1770 if (tmp->stype != F_NORMAL)
1771 sibling = GTK_CTREE_ROW(sibling)->sibling;
1775 if (node != sibling)
1776 gtk_ctree_move(ctree, node, parent, sibling);
1783 static void folderview_sort_folders(FolderView *folderview, GtkCTreeNode *root,
1786 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1787 GtkCTreeNode *prev = NULL;
1789 gtk_sctree_sort_recursive(ctree, root);
1791 if (root && GTK_CTREE_ROW(root)->parent) return;
1793 set_special_folder(ctree, folder->inbox, root, &prev);
1794 set_special_folder(ctree, folder->outbox, root, &prev);
1795 set_special_folder(ctree, folder->draft, root, &prev);
1796 set_special_folder(ctree, folder->queue, root, &prev);
1797 set_special_folder(ctree, folder->trash, root, &prev);
1800 static void folderview_append_folder(FolderView *folderview, Folder *folder)
1802 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1805 g_return_if_fail(folder != NULL);
1807 root = gtk_sctree_insert_gnode(ctree, NULL, NULL, folder->node,
1808 folderview_gnode_func, folderview);
1809 gtk_ctree_pre_recursive(ctree, root, folderview_expand_func,
1811 folderview_sort_folders(folderview, root, folder);
1814 /* callback functions */
1815 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
1816 GdkEventButton *event)
1818 GtkCList *clist = GTK_CLIST(folderview->ctree);
1821 FolderViewPopup *fpopup;
1822 GtkItemFactory *fpopup_factory;
1824 FolderItem *special_trash = NULL, *special_queue = NULL;
1828 item = gtk_clist_get_row_data(clist, row);
1830 item = folderview_get_selected_item(folderview);
1832 g_return_if_fail(item != NULL);
1833 g_return_if_fail(item->folder != NULL);
1834 folder = item->folder;
1836 fpopup = g_hash_table_lookup(folderview_popups, folder->klass->idstr);
1838 fpopup_factory = g_hash_table_lookup(folderview->popups, folder->klass->idstr);
1840 fpopup = g_hash_table_lookup(folderview_popups, "common");
1841 fpopup_factory = g_hash_table_lookup(folderview->popups, "common");
1844 if (fpopup->set_sensitivity != NULL)
1845 fpopup->set_sensitivity(fpopup_factory, item);
1847 if (NULL != (ac = account_find_from_item(item))) {
1848 special_trash = account_get_special_folder(ac, F_TRASH);
1849 special_queue = account_get_special_folder(ac, F_QUEUE);
1852 if ((item == folder->trash || item == special_trash
1853 || folder_has_parent_of_type(item, F_TRASH)) &&
1854 gtk_item_factory_get_item(fpopup_factory, "/Empty trash...") == NULL) {
1855 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[0], folderview, 1);
1856 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[1], folderview, 1);
1857 } else if (item != folder->trash && (special_trash == NULL || item != special_trash)
1858 && !folder_has_parent_of_type(item, F_TRASH)) {
1859 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[0]);
1860 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[1]);
1863 if ((item == folder->queue || item == special_queue
1864 || folder_has_parent_of_type(item, F_QUEUE)) &&
1865 gtk_item_factory_get_item(fpopup_factory, "/Send queue...") == NULL) {
1866 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[0], folderview, 1);
1867 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[1], folderview, 1);
1868 } else if (item != folder->queue && (special_queue == NULL || item != special_queue)
1869 && !folder_has_parent_of_type(item, F_QUEUE)) {
1870 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[0]);
1871 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[1]);
1874 #define SET_SENS(name, sens) \
1875 menu_set_sensitive(fpopup_factory, name, sens)
1877 SET_SENS("/Mark all read", item->unread_msgs >= 1);
1878 SET_SENS("/Search folder...", item->total_msgs >= 1 &&
1879 folderview->selected == folderview->opened);
1880 SET_SENS("/Properties...", TRUE);
1881 SET_SENS("/Processing...", item->node->parent != NULL);
1882 if (item == folder->trash || item == special_trash
1883 || folder_has_parent_of_type(item, F_TRASH)) {
1884 GSList *msglist = folder_item_get_msg_list(item);
1885 SET_SENS("/Empty trash...", msglist != NULL);
1886 procmsg_msg_list_free(msglist);
1888 if (item == folder->queue || item == special_queue
1889 || folder_has_parent_of_type(item, F_QUEUE)) {
1890 GSList *msglist = folder_item_get_msg_list(item);
1891 SET_SENS("/Send queue...", msglist != NULL);
1892 procmsg_msg_list_free(msglist);
1896 popup = gtk_item_factory_get_widget(fpopup_factory, fpopup->path);
1897 gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
1898 event->button, event->time);
1903 static gboolean folderview_button_pressed(GtkWidget *ctree, GdkEventButton *event,
1904 FolderView *folderview)
1906 GtkCList *clist = GTK_CLIST(ctree);
1907 gint prev_row = -1, row = -1, column = -1;
1909 if (!event) return FALSE;
1911 if (event->button == 1 || event->button == 2) {
1912 folderview->open_folder = TRUE;
1914 if (event->type == GDK_2BUTTON_PRESS) {
1915 if (clist->selection) {
1918 node = GTK_CTREE_NODE(clist->selection->data);
1920 gtk_ctree_toggle_expansion(
1928 if (event->button == 2 || event->button == 3) {
1930 if (clist->selection) {
1933 node = GTK_CTREE_NODE(clist->selection->data);
1935 prev_row = gtkut_ctree_get_nth_from_node
1936 (GTK_CTREE(ctree), node);
1939 if (!gtk_clist_get_selection_info(clist, event->x, event->y,
1942 if (prev_row != row) {
1943 gtk_clist_unselect_all(clist);
1944 if (event->button == 2)
1945 folderview_select_node
1947 gtk_ctree_node_nth(GTK_CTREE(ctree),
1950 gtk_clist_select_row(clist, row, column);
1954 if (event->button != 3) return FALSE;
1956 folderview_set_sens_and_popup_menu(folderview, row, event);
1960 static gboolean folderview_button_released(GtkWidget *ctree, GdkEventButton *event,
1961 FolderView *folderview)
1963 if (!event) return FALSE;
1965 if (event->button == 1 && folderview->open_folder == FALSE &&
1966 folderview->opened != NULL) {
1967 gtkut_ctree_set_focus_row(GTK_CTREE(ctree),
1968 folderview->opened);
1969 gtk_ctree_select(GTK_CTREE(ctree), folderview->opened);
1975 static gboolean folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
1976 FolderView *folderview)
1978 if (!event) return FALSE;
1980 if (quicksearch_has_focus(folderview->summaryview->quicksearch))
1983 switch (event->keyval) {
1985 if (folderview->selected) {
1986 folderview_select_node(folderview,
1987 folderview->selected);
1991 if (folderview->selected) {
1992 if (folderview->opened == folderview->selected &&
1993 (!folderview->summaryview->folder_item ||
1994 folderview->summaryview->folder_item->total_msgs == 0))
1995 folderview_select_next_unread(folderview);
1997 folderview_select_node(folderview,
1998 folderview->selected);
2008 typedef struct _PostponedSelectData
2013 FolderView *folderview;
2014 } PostponedSelectData;
2016 static gboolean postpone_select(void *data)
2018 PostponedSelectData *psdata = (PostponedSelectData *)data;
2019 debug_print("trying again\n");
2020 psdata->folderview->open_folder = TRUE;
2021 main_window_cursor_normal(psdata->folderview->mainwin);
2022 STATUSBAR_POP(psdata->folderview->mainwin);
2023 folderview_selected(psdata->ctree, psdata->row,
2024 psdata->column, psdata->folderview);
2029 static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row,
2030 gint column, FolderView *folderview)
2032 static gboolean can_select = TRUE; /* exclusive lock */
2037 START_TIMING("--- folderview_selected");
2038 folderview->selected = row;
2040 if (folderview->opened == row) {
2041 folderview->open_folder = FALSE;
2046 if (!can_select || summary_is_locked(folderview->summaryview)) {
2047 if (folderview->opened) {
2048 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2049 gtk_ctree_select(ctree, folderview->opened);
2055 if (!folderview->open_folder) {
2059 item = gtk_ctree_node_get_row_data(ctree, row);
2060 if (!item || item->no_select) {
2067 /* Save cache for old folder */
2068 /* We don't want to lose all caches if sylpheed crashed */
2069 if (folderview->opened) {
2070 FolderItem *olditem;
2072 olditem = gtk_ctree_node_get_row_data(ctree, folderview->opened);
2074 buf = g_strdup_printf(_("Closing Folder %s..."),
2075 olditem->path ? olditem->path:olditem->name);
2076 /* will be null if we just moved the previously opened folder */
2077 STATUSBAR_PUSH(folderview->mainwin, buf);
2078 main_window_cursor_wait(folderview->mainwin);
2080 summary_save_prefs_to_folderitem(folderview->summaryview, olditem);
2081 summary_show(folderview->summaryview, NULL);
2082 folder_item_close(olditem);
2083 main_window_cursor_normal(folderview->mainwin);
2084 STATUSBAR_POP(folderview->mainwin);
2088 /* CLAWS: set compose button type: news folder items
2089 * always have a news folder as parent */
2091 toolbar_set_compose_button
2092 (folderview->mainwin->toolbar,
2093 FOLDER_TYPE(item->folder) == F_NEWS ?
2094 COMPOSEBUTTON_NEWS : COMPOSEBUTTON_MAIL);
2097 debug_print("Folder %s is selected\n", item->path);
2099 if (!GTK_CTREE_ROW(row)->children)
2100 gtk_ctree_expand(ctree, row);
2101 if (folderview->opened &&
2102 !GTK_CTREE_ROW(folderview->opened)->children)
2103 gtk_ctree_collapse(ctree, folderview->opened);
2105 /* ungrab the mouse event */
2106 if (GTK_WIDGET_HAS_GRAB(ctree)) {
2107 gtk_grab_remove(GTK_WIDGET(ctree));
2108 if (gdk_pointer_is_grabbed())
2109 gdk_pointer_ungrab(GDK_CURRENT_TIME);
2113 buf = g_strdup_printf(_("Opening Folder %s..."), item->path ?
2114 item->path : "(null)");
2115 debug_print("%s\n", buf);
2116 STATUSBAR_PUSH(folderview->mainwin, buf);
2119 main_window_cursor_wait(folderview->mainwin);
2121 res = folder_item_open(item);
2123 main_window_cursor_normal(folderview->mainwin);
2124 STATUSBAR_POP(folderview->mainwin);
2126 alertpanel_error(_("Folder could not be opened."));
2128 folderview->open_folder = FALSE;
2132 } else if (res == -2) {
2133 PostponedSelectData *data = g_new0(PostponedSelectData, 1);
2134 data->ctree = ctree;
2136 data->column = column;
2137 data->folderview = folderview;
2138 debug_print("postponing open of %s till end of scan\n",
2139 item->path ? item->path:item->name);
2140 folderview->open_folder = FALSE;
2142 g_timeout_add(500, postpone_select, data);
2147 main_window_cursor_normal(folderview->mainwin);
2150 summary_set_prefs_from_folderitem(folderview->summaryview, item);
2151 opened = summary_show(folderview->summaryview, item);
2153 folder_clean_cache_memory(item);
2156 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2157 gtk_ctree_select(ctree, folderview->opened);
2159 folderview->opened = row;
2160 if (gtk_ctree_node_is_visible(ctree, row)
2161 != GTK_VISIBILITY_FULL)
2162 gtk_ctree_node_moveto(ctree, row, -1, 0.5, 0);
2165 STATUSBAR_POP(folderview->mainwin);
2167 folderview->open_folder = FALSE;
2172 static void folderview_tree_expanded(GtkCTree *ctree, GtkCTreeNode *node,
2173 FolderView *folderview)
2177 item = gtk_ctree_node_get_row_data(ctree, node);
2178 g_return_if_fail(item != NULL);
2179 item->collapsed = FALSE;
2180 folderview_update_node(folderview, node);
2183 static void folderview_tree_collapsed(GtkCTree *ctree, GtkCTreeNode *node,
2184 FolderView *folderview)
2188 item = gtk_ctree_node_get_row_data(ctree, node);
2189 g_return_if_fail(item != NULL);
2190 item->collapsed = TRUE;
2191 folderview_update_node(folderview, node);
2194 static void folderview_popup_close(GtkMenuShell *menu_shell,
2195 FolderView *folderview)
2197 if (!folderview->opened) return;
2199 gtk_ctree_select(GTK_CTREE(folderview->ctree), folderview->opened);
2202 static void folderview_col_resized(GtkCList *clist, gint column, gint width,
2203 FolderView *folderview)
2205 FolderColumnType type = folderview->col_state[column].type;
2207 prefs_common.folder_col_size[type] = width;
2210 void folderview_create_folder_node_recursive(FolderView *folderview, FolderItem *item)
2214 folderview_create_folder_node(folderview, item);
2216 if (!item || !item->folder || !item->folder->node)
2219 srcnode = item->folder->node;
2220 srcnode = g_node_find(srcnode, G_PRE_ORDER, G_TRAVERSE_ALL, item);
2221 srcnode = srcnode->children;
2222 while (srcnode != NULL) {
2223 if (srcnode && srcnode->data) {
2224 FolderItem *next_item = (FolderItem*) srcnode->data;
2225 folderview_create_folder_node_recursive(folderview, next_item);
2227 srcnode = srcnode->next;
2231 void folderview_create_folder_node(FolderView *folderview, FolderItem *item)
2233 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2234 gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
2235 GtkCTreeNode *node, *parent_node;
2236 gint *col_pos = folderview->col_pos;
2237 FolderItemUpdateData hookdata;
2239 parent_node = gtk_ctree_find_by_row_data(ctree, NULL, folder_item_parent(item));
2240 if (parent_node == NULL)
2243 gtk_clist_freeze(GTK_CLIST(ctree));
2245 text[col_pos[F_COL_FOLDER]] = item->name;
2246 node = gtk_sctree_insert_node(ctree, parent_node, NULL, text,
2248 folderxpm, folderxpmmask,
2249 folderopenxpm, folderopenxpmmask,
2251 gtk_ctree_expand(ctree, parent_node);
2252 gtk_ctree_node_set_row_data(ctree, node, item);
2254 gtk_ctree_node_set_row_style(ctree, node, normal_style);
2255 folderview_sort_folders(folderview, parent_node, item->folder);
2257 hookdata.item = item;
2258 hookdata.update_flags = F_ITEM_UPDATE_NAME;
2259 hookdata.msg = NULL;
2260 hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &hookdata);
2262 gtk_clist_thaw(GTK_CLIST(ctree));
2265 static void folderview_empty_trash_cb(FolderView *folderview, guint action,
2268 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2270 GSList *mlist = NULL;
2272 FolderItem *special_trash = NULL;
2275 if (!folderview->selected) return;
2276 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2277 g_return_if_fail(item != NULL);
2278 g_return_if_fail(item->folder != NULL);
2280 if (NULL != (ac = account_find_from_item(item)))
2281 special_trash = account_get_special_folder(ac, F_TRASH);
2283 if (item != item->folder->trash && item != special_trash
2284 && !folder_has_parent_of_type(item, F_TRASH)) return;
2286 if (prefs_common.ask_on_clean) {
2287 if (alertpanel(_("Empty trash"),
2288 _("Delete all messages in trash?"),
2289 GTK_STOCK_CANCEL, _("+_Empty trash"), NULL) != G_ALERTALTERNATE)
2293 mlist = folder_item_get_msg_list(item);
2295 for (cur = mlist ; cur != NULL ; cur = cur->next) {
2296 MsgInfo * msginfo = (MsgInfo *) cur->data;
2297 if (MSG_IS_LOCKED(msginfo->flags))
2299 /* is it partially received? (partial_recv isn't cached) */
2300 if (msginfo->total_size != 0 &&
2301 msginfo->size != (off_t)msginfo->total_size)
2302 partial_mark_for_delete(msginfo);
2304 procmsg_msg_list_free(mlist);
2306 folder_item_remove_all_msg(item);
2309 static void folderview_send_queue_cb(FolderView *folderview, guint action,
2312 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2314 FolderItem *special_queue = NULL;
2316 gchar *errstr = NULL;
2318 if (!folderview->selected) return;
2319 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2320 g_return_if_fail(item != NULL);
2321 g_return_if_fail(item->folder != NULL);
2323 if (NULL != (ac = account_find_from_item(item)))
2324 special_queue = account_get_special_folder(ac, F_QUEUE);
2326 if (item != item->folder->queue && item != special_queue
2327 && !folder_has_parent_of_type(item, F_QUEUE)) return;
2329 if (procmsg_queue_is_empty(item))
2332 if (prefs_common.work_offline)
2333 if (alertpanel(_("Offline warning"),
2334 _("You're working offline. Override?"),
2335 GTK_STOCK_NO, GTK_STOCK_YES,
2336 NULL) != G_ALERTALTERNATE)
2339 /* ask for confirmation before sending queued messages only
2340 in online mode and if there is at least one message queued
2341 in any of the folder queue
2343 if (prefs_common.confirm_send_queued_messages) {
2344 if (!prefs_common.work_offline) {
2345 if (alertpanel(_("Send queued messages"),
2346 _("Send all queued messages?"),
2347 GTK_STOCK_CANCEL, _("_Send"),
2348 NULL) != G_ALERTALTERNATE)
2353 if (procmsg_send_queue(item, prefs_common.savemsg, &errstr) < 0) {
2355 alertpanel_error_log(_("Some errors occurred while "
2356 "sending queued messages."));
2358 gchar *tmp = g_strdup_printf(_("Some errors occurred "
2359 "while sending queued messages:\n%s"), errstr);
2361 alertpanel_error_log(tmp);
2367 static void folderview_search_cb(FolderView *folderview, guint action,
2370 summary_search(folderview->summaryview);
2373 static void folderview_property_cb(FolderView *folderview, guint action,
2376 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2379 if (!folderview->selected) return;
2381 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2382 g_return_if_fail(item != NULL);
2383 g_return_if_fail(item->folder != NULL);
2385 prefs_folder_item_open(item);
2388 static void folderview_recollapse_nodes(FolderView *folderview, GtkCTreeNode *node)
2390 GSList *list = NULL;
2391 GSList *done = NULL;
2392 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2394 for (list = folderview->nodes_to_recollapse; list != NULL; list = g_slist_next(list)) {
2395 if (!gtkut_ctree_node_is_parent(GTK_CTREE_NODE(list->data), node)
2396 && list->data != node) {
2397 gtk_ctree_collapse(ctree, GTK_CTREE_NODE(list->data));
2398 done = g_slist_append(done, GTK_CTREE_NODE(list->data));
2401 for (list = done; list != NULL; list = g_slist_next(list)) {
2402 folderview->nodes_to_recollapse = g_slist_remove(folderview->nodes_to_recollapse,
2408 void folderview_move_folder(FolderView *folderview, FolderItem *from_folder,
2409 FolderItem *to_folder)
2411 FolderItem *from_parent = NULL;
2412 FolderItem *new_folder = NULL;
2413 GtkCTreeNode *src_node = NULL;
2417 g_return_if_fail(folderview != NULL);
2418 g_return_if_fail(from_folder != NULL);
2419 g_return_if_fail(to_folder != NULL);
2421 src_node = gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree), NULL, from_folder);
2422 from_parent = folder_item_parent(from_folder);
2424 if (prefs_common.warn_dnd) {
2425 buf = g_strdup_printf(_("Do you really want to make folder '%s' a "
2426 "sub-folder of '%s' ?"), from_folder->name,
2428 status = alertpanel_full(_("Move folder"), buf,
2429 GTK_STOCK_NO, GTK_STOCK_YES, NULL, TRUE,
2430 NULL, ALERT_QUESTION, G_ALERTDEFAULT);
2433 if ((status & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
2435 else if (status & G_ALERTDISABLE)
2436 prefs_common.warn_dnd = FALSE;
2439 buf = g_strdup_printf(_("Moving %s to %s..."), from_folder->name, to_folder->name);
2440 STATUSBAR_PUSH(folderview->mainwin, buf);
2442 summary_clear_all(folderview->summaryview);
2443 folderview->opened = NULL;
2444 folderview->selected = NULL;
2445 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), FALSE);
2447 main_window_cursor_wait(folderview->mainwin);
2448 statusbar_verbosity_set(TRUE);
2449 folder_item_update_freeze();
2450 if ((status = folder_item_move_to(from_folder, to_folder, &new_folder)) == F_MOVE_OK) {
2451 statusbar_verbosity_set(FALSE);
2452 main_window_cursor_normal(folderview->mainwin);
2453 STATUSBAR_POP(folderview->mainwin);
2454 folder_item_update_thaw();
2455 folder_item_update_recursive(new_folder, F_ITEM_UPDATE_MSGCNT);
2457 folderview_sort_folders(folderview,
2458 gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree),
2459 NULL, to_folder), new_folder->folder);
2460 folderview_select(folderview, new_folder);
2462 statusbar_verbosity_set(FALSE);
2463 main_window_cursor_normal(folderview->mainwin);
2464 STATUSBAR_POP(folderview->mainwin);
2465 folder_item_update_thaw();
2467 case F_MOVE_FAILED_DEST_IS_PARENT:
2468 alertpanel_error(_("Source and destination are the same."));
2470 case F_MOVE_FAILED_DEST_IS_CHILD:
2471 alertpanel_error(_("Can't move a folder to one of its children."));
2473 case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX:
2474 alertpanel_error(_("Folder moving cannot be done between different mailboxes."));
2477 alertpanel_error(_("Move failed!"));
2482 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), TRUE);
2485 static gint folderview_clist_compare(GtkCList *clist,
2486 gconstpointer ptr1, gconstpointer ptr2)
2488 FolderItem *item1 = ((GtkCListRow *)ptr1)->data;
2489 FolderItem *item2 = ((GtkCListRow *)ptr2)->data;
2492 return (item2->name != NULL);
2496 return g_utf8_collate(item1->name, item2->name);
2499 static void folderview_processing_cb(FolderView *folderview, guint action,
2502 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2506 if (!folderview->selected) return;
2508 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2509 g_return_if_fail(item != NULL);
2510 g_return_if_fail(item->folder != NULL);
2512 id = folder_item_get_identifier(item);
2513 title = g_strdup_printf (_("Processing configuration for folder %s"), id);
2516 prefs_filtering_open(&item->prefs->processing, title,
2517 MANUAL_ANCHOR_PROCESSING, NULL, NULL, FALSE);
2521 void folderview_set_target_folder_color(gint color_op)
2525 FolderView *folderview;
2527 for (list = folderview_list; list != NULL; list = list->next) {
2528 folderview = (FolderView *)list->data;
2529 gtkut_convert_int_to_gdk_color(color_op, &folderview->color_op);
2531 bold_tgtfold_style->fg[GTK_STATE_NORMAL] =
2532 folderview->color_op;
2538 static gchar *last_font = NULL;
2539 void folderview_reflect_prefs_pixmap_theme(FolderView *folderview)
2547 void folderview_reflect_prefs(void)
2549 gboolean update_font = TRUE;
2550 FolderView *folderview = mainwindow_get_mainwindow()->folderview;
2551 FolderItem *item = folderview_get_selected_item(folderview);
2552 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2553 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2554 gint height = pos->value;
2556 if (last_font && !strcmp(last_font, NORMAL_FONT))
2557 update_font = FALSE;
2560 last_font = g_strdup(NORMAL_FONT);
2563 normal_style = normal_color_style = bold_style =
2564 bold_color_style = bold_tgtfold_style = NULL;
2566 folderview_init(folderview);
2568 gtk_clist_freeze(GTK_CLIST(folderview->ctree));
2569 folderview_column_set_titles(folderview);
2570 folderview_set_all();
2572 g_signal_handlers_block_by_func
2573 (G_OBJECT(folderview->ctree),
2574 G_CALLBACK(folderview_selected), folderview);
2577 GtkCTreeNode *node = gtk_ctree_find_by_row_data(
2578 GTK_CTREE(folderview->ctree), NULL, item);
2580 folderview_select(folderview, item);
2581 folderview->selected = node;
2584 g_signal_handlers_unblock_by_func
2585 (G_OBJECT(folderview->ctree),
2586 G_CALLBACK(folderview_selected), folderview);
2588 pos = gtk_scrolled_window_get_vadjustment(
2589 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2590 gtk_adjustment_set_value(pos, height);
2591 gtk_clist_thaw(GTK_CLIST(folderview->ctree));
2594 static void drag_state_stop(FolderView *folderview)
2596 if (folderview->drag_timer)
2597 gtk_timeout_remove(folderview->drag_timer);
2598 folderview->drag_timer = 0;
2599 folderview->drag_node = NULL;
2602 static gint folderview_defer_expand(FolderView *folderview)
2604 if (folderview->drag_node) {
2605 folderview_recollapse_nodes(folderview, folderview->drag_node);
2606 if (folderview->drag_item->collapsed) {
2607 gtk_ctree_expand(GTK_CTREE(folderview->ctree), folderview->drag_node);
2608 folderview->nodes_to_recollapse = g_slist_append
2609 (folderview->nodes_to_recollapse, folderview->drag_node);
2612 folderview->drag_item = NULL;
2613 folderview->drag_timer = 0;
2617 static void drag_state_start(FolderView *folderview, GtkCTreeNode *node, FolderItem *item)
2619 /* the idea is that we call drag_state_start() whenever we want expansion to
2620 * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
2621 * we need to call drag_state_stop() */
2622 drag_state_stop(folderview);
2623 /* request expansion */
2624 if (0 != (folderview->drag_timer = gtk_timeout_add
2625 (prefs_common.hover_timeout,
2626 (GtkFunction)folderview_defer_expand,
2628 folderview->drag_node = node;
2629 folderview->drag_item = item;
2633 static void folderview_start_drag(GtkWidget *widget, gint button, GdkEvent *event,
2634 FolderView *folderview)
2636 GdkDragContext *context;
2638 g_return_if_fail(folderview != NULL);
2639 if (folderview->selected == NULL) return;
2640 if (folderview->nodes_to_recollapse)
2641 g_slist_free(folderview->nodes_to_recollapse);
2642 folderview->nodes_to_recollapse = NULL;
2643 context = gtk_drag_begin(widget, folderview->target_list,
2644 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
2645 gtk_drag_set_icon_default(context);
2648 static void folderview_drag_data_get(GtkWidget *widget,
2649 GdkDragContext *drag_context,
2650 GtkSelectionData *selection_data,
2653 FolderView *folderview)
2657 gchar *source = NULL;
2658 if (info == TARGET_DUMMY) {
2659 for (cur = GTK_CLIST(folderview->ctree)->selection;
2660 cur != NULL; cur = cur->next) {
2661 item = gtk_ctree_node_get_row_data
2662 (GTK_CTREE(folderview->ctree),
2663 GTK_CTREE_NODE(cur->data));
2665 source = g_strdup_printf ("FROM_OTHER_FOLDER%s", folder_item_get_identifier(item));
2666 gtk_selection_data_set(selection_data,
2667 selection_data->target, 8,
2668 source, strlen(source));
2674 g_warning("unknown info %d\n", info);
2678 gboolean folderview_update_folder(gpointer source, gpointer userdata)
2680 FolderUpdateData *hookdata;
2681 FolderView *folderview;
2685 folderview = (FolderView *) userdata;
2686 g_return_val_if_fail(hookdata != NULL, FALSE);
2687 g_return_val_if_fail(folderview != NULL, FALSE);
2689 ctree = folderview->ctree;
2690 g_return_val_if_fail(ctree != NULL, FALSE);
2692 if (hookdata->update_flags & FOLDER_ADD_FOLDERITEM)
2693 folderview_create_folder_node(folderview, hookdata->item);
2694 else if (hookdata->update_flags & FOLDER_RENAME_FOLDERITEM) {
2695 GtkCTreeNode *node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree),
2696 NULL, folder_item_parent(hookdata->item));
2697 folderview_sort_folders(folderview, node, hookdata->folder);
2698 } else if (hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM) {
2701 node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree), NULL, hookdata->item);
2703 gtk_ctree_remove_node(GTK_CTREE(ctree), node);
2704 } else if (hookdata->update_flags & (FOLDER_TREE_CHANGED | FOLDER_ADD_FOLDER | FOLDER_REMOVE_FOLDER))
2705 folderview_set(folderview);
2710 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
2711 GdkDragContext *context,
2715 FolderView *folderview)
2718 FolderItem *item = NULL, *src_item = NULL;
2719 GtkCTreeNode *node = NULL;
2720 gboolean acceptable = FALSE;
2721 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2722 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2723 int height = (int)pos->page_size;
2724 int total_height = (int)pos->upper;
2725 int vpos = (int) pos->value;
2727 if (gtk_clist_get_selection_info
2728 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
2729 GtkWidget *srcwidget;
2731 if (y > height - 24 && height + vpos < total_height)
2732 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
2734 if (y < 48 && y > 0)
2735 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
2737 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2738 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2739 src_item = folderview->summaryview->folder_item;
2741 srcwidget = gtk_drag_get_source_widget(context);
2742 if (srcwidget == folderview->summaryview->ctree) {
2743 /* comes from summaryview */
2744 /* we are copying messages, so only accept folder items that are not
2745 the source item, are no root items and can copy messages */
2746 if (item && item->folder && folder_item_parent(item) != NULL && src_item &&
2747 src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)
2749 } else if (srcwidget == folderview->ctree) {
2750 /* comes from folderview */
2751 /* we are moving folder items, only accept folders that are not
2752 the source items and can copy messages and create folder items */
2753 if (item && item->folder && src_item && src_item != item &&
2754 FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2755 FOLDER_CLASS(item->folder)->create_folder != NULL)
2758 /* comes from another app */
2759 /* we are adding messages, so only accept folder items that are
2760 no root items and can copy messages */
2761 if (item && item->folder && folder_item_parent(item) != NULL
2762 && FOLDER_CLASS(item->folder)->add_msg != NULL)
2767 if (acceptable || (src_item && src_item == item))
2768 drag_state_start(folderview, node, item);
2771 g_signal_handlers_block_by_func
2773 G_CALLBACK(folderview_selected), folderview);
2774 gtk_ctree_select(GTK_CTREE(widget), node);
2775 g_signal_handlers_unblock_by_func
2777 G_CALLBACK(folderview_selected), folderview);
2778 gdk_drag_status(context,
2779 (context->actions == GDK_ACTION_COPY ?
2780 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
2782 if (folderview->opened)
2783 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2784 gdk_drag_status(context, 0, time);
2790 static void folderview_drag_leave_cb(GtkWidget *widget,
2791 GdkDragContext *context,
2793 FolderView *folderview)
2795 drag_state_stop(folderview);
2796 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2799 static void free_info (gpointer stuff, gpointer data)
2804 void folderview_finish_dnd(const gchar *data, GdkDragContext *drag_context,
2805 guint time, FolderItem *item)
2808 GSList *msglist = NULL;
2809 list = uri_list_extract_filenames(data);
2810 if (!(item && item->folder && folder_item_parent(item) != NULL
2811 && FOLDER_CLASS(item->folder)->add_msg != NULL))
2813 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2817 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2820 for (tmp = list; tmp != NULL; tmp = tmp->next) {
2821 MsgFileInfo *info = NULL;
2823 if (file_is_email((gchar *)tmp->data)) {
2824 info = g_new0(MsgFileInfo, 1);
2825 info->msginfo = NULL;
2826 info->file = (gchar *)tmp->data;
2827 msglist = g_slist_prepend(msglist, info);
2831 msglist = g_slist_reverse(msglist);
2832 folder_item_add_msgs(item, msglist, FALSE);
2833 g_slist_foreach(msglist, free_info, NULL);
2834 g_slist_free(msglist);
2835 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2837 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2839 list_free_strings(list);
2843 static void folderview_drag_received_cb(GtkWidget *widget,
2844 GdkDragContext *drag_context,
2847 GtkSelectionData *data,
2850 FolderView *folderview)
2853 FolderItem *item = NULL, *src_item;
2856 if (info == TARGET_DUMMY) {
2857 drag_state_stop(folderview);
2858 if ((void *)strstr(data->data, "FROM_OTHER_FOLDER") != (void *)data->data) {
2859 /* comes from summaryview */
2860 if (gtk_clist_get_selection_info
2861 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2864 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2865 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2866 src_item = folderview->summaryview->folder_item;
2868 /* re-check (due to acceptable possibly set for folder moves */
2869 if (!(item && item->folder && item->path && !item->no_select &&
2870 src_item && src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)) {
2873 if (item && src_item) {
2874 switch (drag_context->action) {
2875 case GDK_ACTION_COPY:
2876 summary_copy_selected_to(folderview->summaryview, item);
2877 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2879 case GDK_ACTION_MOVE:
2880 case GDK_ACTION_DEFAULT:
2882 if (FOLDER_CLASS(src_item->folder)->remove_msg == NULL)
2883 summary_copy_selected_to(folderview->summaryview, item);
2885 summary_move_selected_to(folderview->summaryview, item);
2886 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2889 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2891 /* comes from folderview */
2893 gboolean folder_is_normal = TRUE;
2895 source = data->data + 17;
2896 if (gtk_clist_get_selection_info
2897 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0
2899 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2902 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2903 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2904 src_item = folder_find_item_from_identifier(source);
2908 src_item->stype == F_NORMAL &&
2909 !folder_has_parent_of_type(src_item, F_OUTBOX) &&
2910 !folder_has_parent_of_type(src_item, F_DRAFT) &&
2911 !folder_has_parent_of_type(src_item, F_QUEUE) &&
2912 !folder_has_parent_of_type(src_item, F_TRASH);
2913 if (!item || item->no_select || !src_item
2914 || !folder_is_normal) {
2915 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2919 folderview_move_folder(folderview, src_item, item);
2920 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2922 folderview->nodes_to_recollapse = NULL;
2923 } else if (info == TARGET_MAIL_URI_LIST) {
2924 if (gtk_clist_get_selection_info
2925 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2928 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2930 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2933 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2935 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2938 folderview_finish_dnd(data->data, drag_context, time, item);
2942 static void folderview_drag_end_cb(GtkWidget *widget,
2943 GdkDragContext *drag_context,
2944 FolderView *folderview)
2946 drag_state_stop(folderview);
2947 g_slist_free(folderview->nodes_to_recollapse);
2948 folderview->nodes_to_recollapse = NULL;
2951 void folderview_register_popup(FolderViewPopup *fpopup)
2955 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2956 FolderView *folderview = folderviews->data;
2957 GtkItemFactory *factory;
2959 factory = create_ifactory(folderview, fpopup);
2960 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
2962 g_hash_table_insert(folderview_popups, fpopup->klass, fpopup);
2965 void folderview_unregister_popup(FolderViewPopup *fpopup)
2969 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2970 FolderView *folderview = folderviews->data;
2972 g_hash_table_remove(folderview->popups, fpopup->klass);
2974 g_hash_table_remove(folderview_popups, fpopup->klass);