2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2006 Hiroyuki Yamamoto and the Sylpheed-Claws team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 #include <glib/gi18n.h>
24 #include <gdk/gdkkeysyms.h>
25 #include <gtk/gtkwidget.h>
26 #include <gtk/gtkscrolledwindow.h>
27 #include <gtk/gtkctree.h>
28 #include <gtk/gtkcontainer.h>
29 #include <gtk/gtkclist.h>
30 #include <gtk/gtkstyle.h>
31 #include <gtk/gtksignal.h>
32 #include <gtk/gtkmain.h>
33 #include <gtk/gtkstatusbar.h>
34 #include <gtk/gtkmenu.h>
35 #include <gtk/gtkmenuitem.h>
36 #include <gtk/gtkitemfactory.h>
42 #include "mainwindow.h"
43 #include "folderview.h"
44 #include "summaryview.h"
45 #include "summary_search.h"
46 #include "inputdialog.h"
47 #include "manage_window.h"
48 #include "alertpanel.h"
50 #include "stock_pixmap.h"
54 #include "prefs_common.h"
55 #include "prefs_account.h"
56 #include "prefs_filtering.h"
57 #include "prefs_folder_item.h"
60 #include "foldersel.h"
62 #include "statusbar.h"
64 #include "folderutils.h"
65 #include "partial_download.h"
66 #include "prefs_folder_column.h"
67 #include "filtering.h"
68 #include "quicksearch.h"
72 #define COL_FOLDER_WIDTH 150
73 #define COL_NUM_WIDTH 32
75 static GList *folderview_list = NULL;
77 static GtkStyle *normal_style;
78 static GtkStyle *normal_color_style;
79 static GtkStyle *bold_style;
80 static GtkStyle *bold_color_style;
81 static GtkStyle *bold_tgtfold_style;
83 static GdkPixmap *inboxxpm;
84 static GdkBitmap *inboxxpmmask;
85 static GdkPixmap *inboxhrmxpm;
86 static GdkBitmap *inboxhrmxpmmask;
87 static GdkPixmap *inboxopenxpm;
88 static GdkBitmap *inboxopenxpmmask;
89 static GdkPixmap *inboxopenhrmxpm;
90 static GdkBitmap *inboxopenhrmxpmmask;
91 static GdkPixmap *outboxxpm;
92 static GdkBitmap *outboxxpmmask;
93 static GdkPixmap *outboxhrmxpm;
94 static GdkBitmap *outboxhrmxpmmask;
95 static GdkPixmap *outboxopenxpm;
96 static GdkBitmap *outboxopenxpmmask;
97 static GdkPixmap *outboxopenhrmxpm;
98 static GdkBitmap *outboxopenhrmxpmmask;
99 static GdkPixmap *folderxpm;
100 static GdkBitmap *folderxpmmask;
101 static GdkPixmap *folderhrmxpm;
102 static GdkBitmap *folderhrmxpmmask;
103 static GdkPixmap *folderopenxpm;
104 static GdkBitmap *folderopenxpmmask;
105 static GdkPixmap *folderopenhrmxpm;
106 static GdkBitmap *folderopenhrmxpmmask;
107 static GdkPixmap *trashopenxpm;
108 static GdkBitmap *trashopenxpmmask;
109 static GdkPixmap *trashopenhrmxpm;
110 static GdkBitmap *trashopenhrmxpmmask;
111 static GdkPixmap *trashxpm;
112 static GdkBitmap *trashxpmmask;
113 static GdkPixmap *trashhrmxpm;
114 static GdkBitmap *trashhrmxpmmask;
115 static GdkPixmap *queuexpm;
116 static GdkBitmap *queuexpmmask;
117 static GdkPixmap *queuehrmxpm;
118 static GdkBitmap *queuehrmxpmmask;
119 static GdkPixmap *queueopenxpm;
120 static GdkBitmap *queueopenxpmmask;
121 static GdkPixmap *queueopenhrmxpm;
122 static GdkBitmap *queueopenhrmxpmmask;
123 static GdkPixmap *draftsxpm;
124 static GdkBitmap *draftsxpmmask;
125 static GdkPixmap *draftsopenxpm;
126 static GdkBitmap *draftsopenxpmmask;
127 static GdkPixmap *noselectxpm;
128 static GdkBitmap *noselectxpmmask;
130 static GdkPixmap *m_inboxxpm;
131 static GdkBitmap *m_inboxxpmmask;
132 static GdkPixmap *m_inboxhrmxpm;
133 static GdkBitmap *m_inboxhrmxpmmask;
134 static GdkPixmap *m_inboxopenxpm;
135 static GdkBitmap *m_inboxopenxpmmask;
136 static GdkPixmap *m_inboxopenhrmxpm;
137 static GdkBitmap *m_inboxopenhrmxpmmask;
138 static GdkPixmap *m_outboxxpm;
139 static GdkBitmap *m_outboxxpmmask;
140 static GdkPixmap *m_outboxhrmxpm;
141 static GdkBitmap *m_outboxhrmxpmmask;
142 static GdkPixmap *m_outboxopenxpm;
143 static GdkBitmap *m_outboxopenxpmmask;
144 static GdkPixmap *m_outboxopenhrmxpm;
145 static GdkBitmap *m_outboxopenhrmxpmmask;
146 static GdkPixmap *m_folderxpm;
147 static GdkBitmap *m_folderxpmmask;
148 static GdkPixmap *m_folderhrmxpm;
149 static GdkBitmap *m_folderhrmxpmmask;
150 static GdkPixmap *m_folderopenxpm;
151 static GdkBitmap *m_folderopenxpmmask;
152 static GdkPixmap *m_folderopenhrmxpm;
153 static GdkBitmap *m_folderopenhrmxpmmask;
154 static GdkPixmap *m_trashopenxpm;
155 static GdkBitmap *m_trashopenxpmmask;
156 static GdkPixmap *m_trashopenhrmxpm;
157 static GdkBitmap *m_trashopenhrmxpmmask;
158 static GdkPixmap *m_trashxpm;
159 static GdkBitmap *m_trashxpmmask;
160 static GdkPixmap *m_trashhrmxpm;
161 static GdkBitmap *m_trashhrmxpmmask;
162 static GdkPixmap *m_queuexpm;
163 static GdkBitmap *m_queuexpmmask;
164 static GdkPixmap *m_queuehrmxpm;
165 static GdkBitmap *m_queuehrmxpmmask;
166 static GdkPixmap *m_queueopenxpm;
167 static GdkBitmap *m_queueopenxpmmask;
168 static GdkPixmap *m_queueopenhrmxpm;
169 static GdkBitmap *m_queueopenhrmxpmmask;
170 static GdkPixmap *m_draftsxpm;
171 static GdkBitmap *m_draftsxpmmask;
172 static GdkPixmap *m_draftsopenxpm;
173 static GdkBitmap *m_draftsopenxpmmask;
175 static GdkPixmap *newxpm;
176 static GdkBitmap *newxpmmask;
177 static GdkPixmap *unreadxpm;
178 static GdkBitmap *unreadxpmmask;
179 static GdkPixmap *readxpm;
180 static GdkBitmap *readxpmmask;
183 static void folderview_select_node (FolderView *folderview,
185 static void folderview_set_folders (FolderView *folderview);
186 static void folderview_sort_folders (FolderView *folderview,
189 static void folderview_append_folder (FolderView *folderview,
191 static void folderview_update_node (FolderView *folderview,
194 static gint folderview_clist_compare (GtkCList *clist,
198 /* callback functions */
199 static gboolean folderview_button_pressed (GtkWidget *ctree,
200 GdkEventButton *event,
201 FolderView *folderview);
202 static gboolean folderview_button_released (GtkWidget *ctree,
203 GdkEventButton *event,
204 FolderView *folderview);
205 static gboolean folderview_key_pressed (GtkWidget *widget,
207 FolderView *folderview);
208 static void folderview_selected (GtkCTree *ctree,
211 FolderView *folderview);
212 static void folderview_tree_expanded (GtkCTree *ctree,
214 FolderView *folderview);
215 static void folderview_tree_collapsed (GtkCTree *ctree,
217 FolderView *folderview);
218 static void folderview_popup_close (GtkMenuShell *menu_shell,
219 FolderView *folderview);
220 static void folderview_col_resized (GtkCList *clist,
223 FolderView *folderview);
225 static void mark_all_read_cb (FolderView *folderview,
229 static void folderview_empty_trash_cb (FolderView *folderview,
233 static void folderview_send_queue_cb (FolderView *folderview,
237 static void folderview_search_cb (FolderView *folderview,
241 static void folderview_property_cb (FolderView *folderview,
245 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
246 GdkDragContext *context,
250 FolderView *folderview);
251 static void folderview_drag_leave_cb (GtkWidget *widget,
252 GdkDragContext *context,
254 FolderView *folderview);
255 static void folderview_drag_received_cb (GtkWidget *widget,
256 GdkDragContext *drag_context,
259 GtkSelectionData *data,
262 FolderView *folderview);
263 static void folderview_start_drag (GtkWidget *widget, gint button, GdkEvent *event,
264 FolderView *folderview);
265 static void folderview_drag_data_get (GtkWidget *widget,
266 GdkDragContext *drag_context,
267 GtkSelectionData *selection_data,
270 FolderView *folderview);
271 static void folderview_drag_end_cb (GtkWidget *widget,
272 GdkDragContext *drag_context,
273 FolderView *folderview);
275 void folderview_create_folder_node (FolderView *folderview,
277 gboolean folderview_update_folder (gpointer source,
279 gboolean folderview_update_item_claws (gpointer source,
281 static void folderview_processing_cb(FolderView *folderview, guint action,
283 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
284 GdkEventButton *event);
286 GHashTable *folderview_popups;
288 static GtkItemFactoryEntry folderview_common_popup_entries[] =
290 {N_("/Mark all re_ad"), NULL, mark_all_read_cb, 0, NULL},
291 {N_("/_Search folder..."), NULL, folderview_search_cb, 0, NULL},
292 {N_("/_Properties..."), NULL, folderview_property_cb, 0, NULL},
293 {N_("/Process_ing..."), NULL, folderview_processing_cb, 0, NULL},
296 static GtkItemFactoryEntry folder_view_trash_popup_entries[] = {
297 {"/------trashsep", NULL, NULL, 0, "<Separator>"},
298 {N_("/Empty _trash..."), NULL, folderview_empty_trash_cb, 0, NULL},
301 static GtkItemFactoryEntry folder_view_queue_popup_entries[] = {
302 {"/------queuesep", NULL, NULL, 0, "<Separator>"},
303 {N_("/Send _queue..."), NULL, folderview_send_queue_cb, 0, NULL},
307 GtkTargetEntry folderview_drag_types[] =
309 {"sylpheed-claws/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY},
310 {"text/uri-list", 0, TARGET_MAIL_URI_LIST}
313 void folderview_initialize(void)
315 FolderViewPopup *fpopup;
317 GSList *entries = NULL;
319 fpopup = g_new0(FolderViewPopup, 1);
321 n_entries = sizeof(folderview_common_popup_entries) /
322 sizeof(folderview_common_popup_entries[0]);
323 for (i = 0; i < n_entries; i++)
324 entries = g_slist_append(entries, &folderview_common_popup_entries[i]);
326 fpopup->klass = "common";
327 fpopup->path = "<CommonFolder>";
328 fpopup->entries = entries;
329 fpopup->set_sensitivity = NULL;
331 folderview_popups = g_hash_table_new(g_str_hash, g_str_equal);
332 g_hash_table_insert(folderview_popups, "common", fpopup);
335 static GtkItemFactory *create_ifactory(FolderView *folderview, FolderViewPopup *fpopup)
338 GtkItemFactory *factory;
339 FolderViewPopup *fpopup_common;
342 factory = gtk_item_factory_new(GTK_TYPE_MENU, fpopup->path, NULL);
343 gtk_item_factory_set_translate_func(factory, menu_translate,
346 for (entries = fpopup->entries; entries != NULL; entries = g_slist_next(entries))
347 gtk_item_factory_create_item(factory, entries->data, folderview, 1);
349 fpopup_common = g_hash_table_lookup(folderview_popups, "common");
350 if (fpopup_common != fpopup)
351 for (entries = fpopup_common->entries; entries != NULL; entries = g_slist_next(entries))
352 gtk_item_factory_create_item(factory, entries->data, folderview, 1);
354 popup = gtk_item_factory_get_widget(factory, fpopup->path);
355 g_signal_connect(G_OBJECT(popup), "selection_done",
356 G_CALLBACK(folderview_popup_close),
362 static void create_ifactories(gpointer key, gpointer value, gpointer data)
364 FolderView *folderview = data;
365 FolderViewPopup *fpopup = value;
366 GtkItemFactory *factory;
368 factory = create_ifactory(folderview, fpopup);
369 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
372 static void folderview_column_set_titles(FolderView *folderview)
374 GtkWidget *ctree = folderview->ctree;
375 GtkWidget *label_new;
376 GtkWidget *label_unread;
377 GtkWidget *label_total;
379 GtkWidget *hbox_unread;
380 GtkWidget *hbox_total;
381 gint *col_pos = folderview->col_pos;
383 debug_print("setting titles...\n");
384 gtk_widget_realize(folderview->ctree);
385 gtk_widget_show_all(folderview->scrolledwin);
387 /* CLAWS: titles for "New" and "Unread" show new & unread pixmaps
388 * instead text (text overflows making them unreadable and ugly) */
389 stock_pixmap_gdk(ctree, STOCK_PIXMAP_NEW,
390 &newxpm, &newxpmmask);
391 stock_pixmap_gdk(ctree, STOCK_PIXMAP_UNREAD,
392 &unreadxpm, &unreadxpmmask);
393 stock_pixmap_gdk(ctree, STOCK_PIXMAP_READ,
394 &readxpm, &readxpmmask);
396 label_new = gtk_pixmap_new(newxpm, newxpmmask);
397 label_unread = gtk_pixmap_new(unreadxpm, unreadxpmmask);
398 label_total = gtk_pixmap_new(readxpm, readxpmmask);
400 hbox_new = gtk_hbox_new(FALSE, 4);
401 hbox_unread = gtk_hbox_new(FALSE, 4);
402 hbox_total = gtk_hbox_new(FALSE, 4);
405 gtk_box_pack_start(GTK_BOX(hbox_new), label_new, TRUE, TRUE, 0);
406 gtk_misc_set_alignment (GTK_MISC (label_new), 1, 0.5);
407 gtk_box_pack_start(GTK_BOX(hbox_unread), label_unread, TRUE, TRUE, 0);
408 gtk_misc_set_alignment (GTK_MISC (label_unread), 1, 0.5);
409 gtk_box_pack_start(GTK_BOX(hbox_total), label_total, TRUE, TRUE, 0);
410 gtk_misc_set_alignment (GTK_MISC (label_total), 1, 0.5);
412 gtk_widget_show_all(hbox_new);
413 gtk_widget_show_all(hbox_unread);
414 gtk_widget_show_all(hbox_total);
416 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_NEW],hbox_new);
417 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_UNREAD],hbox_unread);
418 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_TOTAL],hbox_total);
421 static gboolean folderview_popup_menu(GtkWidget *widget, gpointer data)
423 FolderView *folderview = (FolderView *)data;
424 GdkEventButton event;
425 if (folderview_get_selected_item(folderview) == NULL)
429 event.time = gtk_get_current_event_time();
431 folderview_set_sens_and_popup_menu(folderview, -1,
438 GtkWidget *folderview_ctree_create(FolderView *folderview)
442 FolderColumnState *col_state;
443 FolderColumnType type;
444 gchar *titles[N_FOLDER_COLS];
446 GtkWidget *scrolledwin = folderview->scrolledwin;
448 debug_print("creating tree...\n");
449 memset(titles, 0, sizeof(titles));
451 col_state = prefs_folder_column_get_config();
452 memset(titles, 0, sizeof(titles));
454 col_pos = folderview->col_pos;
456 for (i = 0; i < N_FOLDER_COLS; i++) {
457 folderview->col_state[i] = col_state[i];
458 type = col_state[i].type;
462 titles[col_pos[F_COL_FOLDER]] = _("Folder");
463 titles[col_pos[F_COL_NEW]] = _("New");
464 titles[col_pos[F_COL_UNREAD]] = _("Unread");
465 /* TRANSLATORS: This in Number sign in American style */
466 titles[col_pos[F_COL_TOTAL]] = _("#");
468 ctree = gtk_sctree_new_with_titles(N_FOLDER_COLS, col_pos[F_COL_FOLDER],
471 gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
472 gtk_clist_set_column_justification(GTK_CLIST(ctree), col_pos[F_COL_NEW],
474 gtk_clist_set_column_justification(GTK_CLIST(ctree),
475 col_pos[F_COL_UNREAD],
477 gtk_clist_set_column_justification(GTK_CLIST(ctree),
478 col_pos[F_COL_TOTAL],
480 if (prefs_common.enable_dotted_lines) {
481 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
482 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
483 GTK_CTREE_EXPANDER_SQUARE);
485 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_NONE);
486 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
487 GTK_CTREE_EXPANDER_TRIANGLE);
489 gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
490 gtk_clist_set_compare_func(GTK_CLIST(ctree), folderview_clist_compare);
492 /* don't let title buttons take key focus */
493 for (i = 0; i < N_FOLDER_COLS; i++) {
494 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(ctree)->column[i].button,
496 gtk_clist_set_column_width(GTK_CLIST(ctree), col_pos[i],
497 prefs_common.folder_col_size[i]);
498 gtk_clist_set_column_visibility
499 (GTK_CLIST(ctree), i, col_state[i].visible);
502 g_signal_connect(G_OBJECT(ctree), "key_press_event",
503 G_CALLBACK(folderview_key_pressed),
505 g_signal_connect(G_OBJECT(ctree), "button_press_event",
506 G_CALLBACK(folderview_button_pressed),
508 g_signal_connect(G_OBJECT(ctree), "popup-menu",
509 G_CALLBACK(folderview_popup_menu), folderview);
510 g_signal_connect(G_OBJECT(ctree), "button_release_event",
511 G_CALLBACK(folderview_button_released),
513 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
514 G_CALLBACK(folderview_selected), folderview);
515 g_signal_connect(G_OBJECT(ctree), "start_drag",
516 G_CALLBACK(folderview_start_drag), folderview);
517 g_signal_connect(G_OBJECT(ctree), "drag_data_get",
518 G_CALLBACK(folderview_drag_data_get),
521 g_signal_connect_after(G_OBJECT(ctree), "tree_expand",
522 G_CALLBACK(folderview_tree_expanded),
524 g_signal_connect_after(G_OBJECT(ctree), "tree_collapse",
525 G_CALLBACK(folderview_tree_collapsed),
528 g_signal_connect(G_OBJECT(ctree), "resize_column",
529 G_CALLBACK(folderview_col_resized),
533 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
534 folderview_drag_types, 2,
535 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
536 g_signal_connect(G_OBJECT(ctree), "drag_motion",
537 G_CALLBACK(folderview_drag_motion_cb),
539 g_signal_connect(G_OBJECT(ctree), "drag_leave",
540 G_CALLBACK(folderview_drag_leave_cb),
542 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
543 G_CALLBACK(folderview_drag_received_cb),
545 g_signal_connect(G_OBJECT(ctree), "drag_end",
546 G_CALLBACK(folderview_drag_end_cb),
549 gtk_container_add(GTK_CONTAINER(scrolledwin), ctree);
554 void folderview_set_column_order(FolderView *folderview)
557 FolderItem *item = folderview_get_selected_item(folderview);
558 GtkWidget *scrolledwin = folderview->scrolledwin;
560 debug_print("recreating tree...\n");
561 gtk_widget_destroy(folderview->ctree);
563 folderview->ctree = ctree = folderview_ctree_create(folderview);
564 gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
565 GTK_CLIST(ctree)->hadjustment);
566 gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
567 GTK_CLIST(ctree)->vadjustment);
568 gtk_widget_show(ctree);
570 folderview_set(folderview);
571 folderview_column_set_titles(folderview);
573 folderview_select(folderview,item);
576 FolderView *folderview_create(void)
578 FolderView *folderview;
579 GtkWidget *scrolledwin;
582 debug_print("Creating folder view...\n");
583 folderview = g_new0(FolderView, 1);
585 scrolledwin = gtk_scrolled_window_new(NULL, NULL);
586 gtk_scrolled_window_set_policy
587 (GTK_SCROLLED_WINDOW(scrolledwin),
588 GTK_POLICY_AUTOMATIC,
589 prefs_common.folderview_vscrollbar_policy);
590 gtk_widget_set_size_request(scrolledwin,
591 prefs_common.folderview_width,
592 prefs_common.folderview_height);
594 folderview->scrolledwin = scrolledwin;
595 ctree = folderview_ctree_create(folderview);
597 /* create popup factories */
598 folderview->popups = g_hash_table_new(g_str_hash, g_str_equal);
599 g_hash_table_foreach(folderview_popups, create_ifactories, folderview);
601 folderview->ctree = ctree;
603 folderview->folder_update_callback_id =
604 hooks_register_hook(FOLDER_UPDATE_HOOKLIST, folderview_update_folder, (gpointer) folderview);
605 folderview->folder_item_update_callback_id =
606 hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST, folderview_update_item_claws, (gpointer) folderview);
608 gtk_widget_show_all(scrolledwin);
610 folderview->target_list = gtk_target_list_new(folderview_drag_types, 2);
611 folderview_list = g_list_append(folderview_list, folderview);
616 void folderview_init(FolderView *folderview)
618 GtkWidget *ctree = folderview->ctree;
621 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE, &inboxxpm, &inboxxpmmask);
622 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM, &inboxhrmxpm, &inboxhrmxpmmask);
623 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN, &inboxopenxpm, &inboxopenxpmmask);
624 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM, &inboxopenhrmxpm, &inboxopenhrmxpmmask);
625 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE, &outboxxpm, &outboxxpmmask);
626 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM, &outboxhrmxpm, &outboxhrmxpmmask);
627 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN, &outboxopenxpm, &outboxopenxpmmask);
628 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM, &outboxopenhrmxpm, &outboxopenhrmxpmmask);
629 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
630 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM, &folderhrmxpm, &folderhrmxpmmask);
631 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
632 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM, &folderopenhrmxpm, &folderopenhrmxpmmask);
633 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN, &trashopenxpm, &trashopenxpmmask);
634 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM, &trashopenhrmxpm, &trashopenhrmxpmmask);
635 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE, &trashxpm, &trashxpmmask);
636 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM, &trashhrmxpm, &trashhrmxpmmask);
637 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE, &queuexpm, &queuexpmmask);
638 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM, &queuehrmxpm, &queuehrmxpmmask);
639 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN, &queueopenxpm, &queueopenxpmmask);
640 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM, &queueopenhrmxpm, &queueopenhrmxpmmask);
641 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE, &draftsxpm, &draftsxpmmask);
642 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN, &draftsopenxpm, &draftsopenxpmmask);
643 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_NOSELECT, &noselectxpm, &noselectxpmmask);
645 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_MARK, &m_inboxxpm, &m_inboxxpmmask);
646 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM_MARK, &m_inboxhrmxpm, &m_inboxhrmxpmmask);
647 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_MARK, &m_inboxopenxpm, &m_inboxopenxpmmask);
648 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM_MARK, &m_inboxopenhrmxpm, &m_inboxopenhrmxpmmask);
649 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_MARK, &m_outboxxpm, &m_outboxxpmmask);
650 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM_MARK, &m_outboxhrmxpm, &m_outboxhrmxpmmask);
651 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_MARK, &m_outboxopenxpm, &m_outboxopenxpmmask);
652 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM_MARK, &m_outboxopenhrmxpm, &m_outboxopenhrmxpmmask);
653 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_MARK, &m_folderxpm, &m_folderxpmmask);
654 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM_MARK, &m_folderhrmxpm, &m_folderhrmxpmmask);
655 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_MARK, &m_folderopenxpm, &m_folderopenxpmmask);
656 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM_MARK, &m_folderopenhrmxpm, &m_folderopenhrmxpmmask);
657 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_MARK, &m_trashopenxpm, &m_trashopenxpmmask);
658 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM_MARK, &m_trashopenhrmxpm, &m_trashopenhrmxpmmask);
659 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_MARK, &m_trashxpm, &m_trashxpmmask);
660 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM_MARK, &m_trashhrmxpm, &m_trashhrmxpmmask);
661 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_MARK, &m_queuexpm, &m_queuexpmmask);
662 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM_MARK, &m_queuehrmxpm, &m_queuehrmxpmmask);
663 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_MARK, &m_queueopenxpm, &m_queueopenxpmmask);
664 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM_MARK, &m_queueopenhrmxpm, &m_queueopenhrmxpmmask);
665 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE_MARK, &m_draftsxpm, &m_draftsxpmmask);
666 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN_MARK, &m_draftsopenxpm, &m_draftsopenxpmmask);
669 PangoFontDescription *font_desc;
670 normal_style = gtk_style_copy(gtk_widget_get_style(ctree));
671 font_desc = pango_font_description_from_string(NORMAL_FONT);
673 if (normal_style->font_desc)
674 pango_font_description_free
675 (normal_style->font_desc);
676 normal_style->font_desc = font_desc;
678 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
679 normal_color_style = gtk_style_copy(normal_style);
680 normal_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
682 gtk_widget_set_style(ctree, normal_style);
686 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
687 bold_style = gtk_style_copy(gtk_widget_get_style(ctree));
688 pango_font_description_set_weight
689 (bold_style->font_desc, PANGO_WEIGHT_BOLD);
690 bold_color_style = gtk_style_copy(bold_style);
691 bold_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
693 bold_tgtfold_style = gtk_style_copy(bold_style);
694 bold_tgtfold_style->fg[GTK_STATE_NORMAL] = folderview->color_op;
698 void folderview_set(FolderView *folderview)
700 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
701 MainWindow *mainwin = folderview->mainwin;
706 debug_print("Setting folder info...\n");
707 STATUSBAR_PUSH(mainwin, _("Setting folder info..."));
709 main_window_cursor_wait(mainwin);
711 folderview->selected = NULL;
712 folderview->opened = NULL;
714 gtk_clist_freeze(GTK_CLIST(ctree));
715 gtk_clist_clear(GTK_CLIST(ctree));
716 gtk_clist_thaw(GTK_CLIST(ctree));
717 gtk_clist_freeze(GTK_CLIST(ctree));
719 folderview_set_folders(folderview);
721 gtk_clist_thaw(GTK_CLIST(ctree));
722 main_window_cursor_normal(mainwin);
723 STATUSBAR_POP(mainwin);
726 void folderview_set_all(void)
730 for (list = folderview_list; list != NULL; list = list->next)
731 folderview_set((FolderView *)list->data);
734 void folderview_select(FolderView *folderview, FolderItem *item)
736 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
738 GtkCTreeNode *old_selected = folderview->selected;
742 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
743 if (node) folderview_select_node(folderview, node);
745 if (old_selected != node)
746 folder_update_op_count();
749 static void mark_all_read_cb(FolderView *folderview, guint action,
755 item = folderview_get_selected_item(folderview);
759 if (folderview->summaryview->folder_item != item
760 && prefs_common.ask_mark_all_read) {
761 val = alertpanel_full(_("Mark all as read"),
762 _("Do you really want to mark all mails in this "
763 "folder as read ?"), GTK_STOCK_NO, GTK_STOCK_YES, NULL,
764 TRUE, NULL, ALERT_QUESTION, G_ALERTDEFAULT);
766 if ((val & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
768 else if (val & G_ALERTDISABLE)
769 prefs_common.ask_mark_all_read = FALSE;
772 summary_lock(folderview->summaryview);
773 folder_item_update_freeze();
774 if (folderview->summaryview->folder_item == item)
775 gtk_clist_freeze(GTK_CLIST(folderview->summaryview->ctree));
776 folderutils_mark_all_read(item);
777 if (folderview->summaryview->folder_item == item)
778 gtk_clist_thaw(GTK_CLIST(folderview->summaryview->ctree));
779 folder_item_update_thaw();
780 summary_unlock(folderview->summaryview);
783 static void folderview_select_node(FolderView *folderview, GtkCTreeNode *node)
785 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
787 g_return_if_fail(node != NULL);
789 folderview->open_folder = TRUE;
790 gtkut_ctree_set_focus_row(ctree, node);
791 gtk_ctree_select(ctree, node);
792 if (folderview->summaryview->folder_item &&
793 folderview->summaryview->folder_item->total_msgs > 0)
794 gtk_widget_grab_focus(folderview->summaryview->ctree);
796 gtk_widget_grab_focus(folderview->ctree);
798 gtkut_ctree_expand_parent_all(ctree, node);
801 void folderview_unselect(FolderView *folderview)
803 if (folderview->opened && !GTK_CTREE_ROW(folderview->opened)->children)
805 (GTK_CTREE(folderview->ctree), folderview->opened);
807 folderview->selected = folderview->opened = NULL;
810 static GtkCTreeNode *folderview_find_next_marked(GtkCTree *ctree,
816 node = gtkut_ctree_node_next(ctree, node);
818 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
820 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
821 item = gtk_ctree_node_get_row_data(ctree, node);
822 if (item && item->marked_msgs > 0 && item->stype != F_TRASH)
829 void folderview_select_next_marked(FolderView *folderview)
831 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
832 GtkCTreeNode *node = NULL;
833 SelectOnEntry last_sel = prefs_common.select_on_entry;
834 gboolean last_open = prefs_common.always_show_msg;
836 prefs_common.select_on_entry = SELECTONENTRY_MNU;
837 prefs_common.always_show_msg = TRUE;
839 if ((node = folderview_find_next_marked(ctree, folderview->opened))
841 folderview_select_node(folderview, node);
845 if (!folderview->opened ||
846 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
849 /* search again from the first node */
850 if ((node = folderview_find_next_marked(ctree, NULL)) != NULL)
851 folderview_select_node(folderview, node);
854 prefs_common.select_on_entry = last_sel;
855 prefs_common.always_show_msg = last_open;
858 static GtkCTreeNode *folderview_find_next_unread(GtkCTree *ctree,
864 node = gtkut_ctree_node_next(ctree, node);
866 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
868 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
869 item = gtk_ctree_node_get_row_data(ctree, node);
870 if (item && item->unread_msgs > 0 && item->stype != F_TRASH)
877 void folderview_select_next_unread(FolderView *folderview)
879 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
880 GtkCTreeNode *node = NULL;
881 gboolean last_open = prefs_common.always_show_msg;
883 prefs_common.select_on_entry = SELECTONENTRY_UNM;
885 if ((node = folderview_find_next_unread(ctree, folderview->opened))
887 folderview_select_node(folderview, node);
891 if (!folderview->opened ||
892 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
895 /* search again from the first node */
896 if ((node = folderview_find_next_unread(ctree, NULL)) != NULL)
897 folderview_select_node(folderview, node);
900 prefs_common.always_show_msg = last_open;
903 static GtkCTreeNode *folderview_find_next_new(GtkCTree *ctree,
909 node = gtkut_ctree_node_next(ctree, node);
911 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
913 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
914 item = gtk_ctree_node_get_row_data(ctree, node);
915 if (item && item->new_msgs > 0 && item->stype != F_TRASH)
922 void folderview_select_next_new(FolderView *folderview)
924 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
925 GtkCTreeNode *node = NULL;
926 SelectOnEntry last_sel = prefs_common.select_on_entry;
927 gboolean last_open = prefs_common.always_show_msg;
929 prefs_common.select_on_entry = SELECTONENTRY_NUM;
930 prefs_common.always_show_msg = TRUE;
932 if ((node = folderview_find_next_new(ctree, folderview->opened))
934 folderview_select_node(folderview, node);
938 if (!folderview->opened ||
939 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
942 /* search again from the first node */
943 if ((node = folderview_find_next_new(ctree, NULL)) != NULL)
944 folderview_select_node(folderview, node);
947 prefs_common.select_on_entry = last_sel;
948 prefs_common.always_show_msg = last_open;
951 FolderItem *folderview_get_selected_item(FolderView *folderview)
953 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
955 if (!folderview->selected) return NULL;
956 return gtk_ctree_node_get_row_data(ctree, folderview->selected);
959 void folderview_update_msg_num(FolderView *folderview, GtkCTreeNode *row)
961 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
962 static GtkCTreeNode *prev_row = NULL;
964 gint new, unread, total;
965 gchar *new_str, *unread_str, *total_str;
966 gint *col_pos = folderview->col_pos;
970 item = gtk_ctree_node_get_row_data(ctree, row);
973 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_NEW], &new_str);
974 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_UNREAD], &unread_str);
975 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_TOTAL], &total_str);
977 unread = atoi(unread_str);
978 total = atoi(total_str);
982 folderview_update_node(folderview, row);
985 void folderview_append_item(FolderItem *item)
989 g_return_if_fail(item != NULL);
990 g_return_if_fail(item->folder != NULL);
991 if (folder_item_parent(item)) return;
993 for (list = folderview_list; list != NULL; list = list->next) {
994 FolderView *folderview = (FolderView *)list->data;
995 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
996 GtkCTreeNode *node, *child;
997 gint *col_pos = folderview->col_pos;
999 node = gtk_ctree_find_by_row_data(ctree, NULL,
1000 folder_item_parent(item));
1002 child = gtk_ctree_find_by_row_data(ctree, node, item);
1004 gchar *text[N_FOLDER_COLS] =
1005 {NULL, "0", "0", "0"};
1007 gtk_clist_freeze(GTK_CLIST(ctree));
1009 text[col_pos[F_COL_FOLDER]] = item->name;
1010 child = gtk_sctree_insert_node
1011 (ctree, node, NULL, text,
1013 folderxpm, folderxpmmask,
1014 folderopenxpm, folderopenxpmmask,
1016 gtk_ctree_node_set_row_data(ctree, child, item);
1017 gtk_ctree_expand(ctree, node);
1018 folderview_update_node(folderview, child);
1019 folderview_sort_folders(folderview, node,
1022 gtk_clist_thaw(GTK_CLIST(ctree));
1028 static void folderview_set_folders(FolderView *folderview)
1031 #ifndef HAVE_LIBETPAN
1032 static gboolean missing_imap_warning = TRUE;
1034 list = folder_get_list();
1036 for (; list != NULL; list = list->next) {
1037 #ifndef HAVE_LIBETPAN
1038 if ((FOLDER(list->data))
1039 && (FOLDER(list->data))->klass
1040 && (FOLDER(list->data))->klass->type == F_IMAP
1041 && missing_imap_warning) {
1042 missing_imap_warning = FALSE;
1044 _("You have one or more IMAP accounts "
1045 "defined. However this version of "
1046 "Sylpheed-Claws has been built without "
1047 "IMAP support; your IMAP account(s) are "
1049 "You probably need to "
1050 "install libetpan and recompile "
1051 "Sylpheed-Claws."));
1054 folderview_append_folder(folderview, FOLDER(list->data));
1058 static gchar *get_scan_str(FolderItem *item)
1061 return g_strdup_printf(_("Scanning folder %s%c%s ..."),
1062 item->folder->name, G_DIR_SEPARATOR,
1065 return g_strdup_printf(_("Scanning folder %s ..."),
1066 item->folder->name);
1068 static void folderview_scan_tree_func(Folder *folder, FolderItem *item,
1072 for (list = folderview_list; list != NULL; list = list->next) {
1073 FolderView *folderview = (FolderView *)list->data;
1074 MainWindow *mainwin = folderview->mainwin;
1075 gchar *str = get_scan_str(item);
1077 STATUSBAR_PUSH(mainwin, str);
1078 STATUSBAR_POP(mainwin);
1083 void folderview_rescan_tree(Folder *folder, gboolean rebuild)
1087 g_return_if_fail(folder != NULL);
1089 if (!folder->klass->scan_tree) return;
1092 alertpanel_full(_("Rebuild folder tree"),
1093 _("Rebuilding the folder tree will remove "
1094 "local caches. Do you want to continue?"),
1095 GTK_STOCK_NO, GTK_STOCK_YES, NULL, FALSE,
1096 NULL, ALERT_WARNING, G_ALERTDEFAULT)
1097 != G_ALERTALTERNATE) {
1103 window = label_window_create(_("Rebuilding folder tree..."));
1105 window = label_window_create(_("Scanning folder tree..."));
1107 folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
1108 folder_scan_tree(folder, rebuild);
1109 folder_set_ui_func(folder, NULL, NULL);
1111 folderview_set_all();
1113 gtk_widget_destroy(window);
1117 /** folderview_check_new()
1118 * Scan and update the folder and return the
1119 * count the number of new messages since last check.
1120 * \param folder the folder to check for new messages
1121 * \return the number of new messages since last check
1123 gint folderview_check_new(Folder *folder)
1127 FolderView *folderview;
1131 gint former_new_msgs = 0;
1132 gint former_new = 0, former_unread = 0, former_total;
1134 for (list = folderview_list; list != NULL; list = list->next) {
1135 folderview = (FolderView *)list->data;
1136 ctree = GTK_CTREE(folderview->ctree);
1139 main_window_lock(folderview->mainwin);
1141 for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
1142 node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
1144 item = gtk_ctree_node_get_row_data(ctree, node);
1145 if (!item || !item->path || !item->folder) continue;
1146 if (item->no_select) continue;
1147 if (folder && folder != item->folder) continue;
1148 if (!folder && !FOLDER_IS_LOCAL(item->folder)) continue;
1149 if (!item->prefs->newmailcheck) continue;
1150 if (item->processing_pending == TRUE) {
1151 debug_print("skipping %s, processing pending\n",
1152 item->path ? item->path : item->name);
1156 str = get_scan_str(item);
1158 STATUSBAR_PUSH(folderview->mainwin, str);
1162 folderview_scan_tree_func(item->folder, item, NULL);
1163 former_new = item->new_msgs;
1164 former_unread = item->unread_msgs;
1165 former_total = item->total_msgs;
1167 if (item->folder->klass->scan_required &&
1168 (item->folder->klass->scan_required(item->folder, item) ||
1169 item->folder->inbox == item ||
1170 item->opened == TRUE ||
1171 item->processing_pending == TRUE)) {
1172 if (folder_item_scan(item) < 0) {
1173 summaryview_unlock(folderview->summaryview, item);
1174 if (folder && !FOLDER_IS_LOCAL(folder)) {
1175 STATUSBAR_POP(folderview->mainwin);
1179 } else if (!item->folder->klass->scan_required) {
1180 if (folder_item_scan(item) < 0) {
1181 summaryview_unlock(folderview->summaryview, item);
1182 if (folder && !FOLDER_IS_LOCAL(folder)) {
1183 STATUSBAR_POP(folderview->mainwin);
1188 if (former_new != item->new_msgs ||
1189 former_unread != item->unread_msgs ||
1190 former_total != item->total_msgs)
1191 folderview_update_node(folderview, node);
1193 new_msgs += item->new_msgs;
1194 former_new_msgs += former_new;
1195 STATUSBAR_POP(folderview->mainwin);
1198 main_window_unlock(folderview->mainwin);
1202 folder_write_list();
1203 /* Number of new messages since last check is the just the difference
1204 * between former_new_msgs and new_msgs. If new_msgs is less than
1205 * former_new_msgs, that would mean another session accessed the folder
1206 * and the result is not well defined.
1208 new_msgs = (former_new_msgs < new_msgs ? new_msgs - former_new_msgs : 0);
1212 void folderview_check_new_all(void)
1216 FolderView *folderview;
1218 folderview = (FolderView *)folderview_list->data;
1221 main_window_lock(folderview->mainwin);
1222 window = label_window_create
1223 (_("Checking for new messages in all folders..."));
1225 list = folder_get_list();
1226 for (; list != NULL; list = list->next) {
1227 Folder *folder = list->data;
1229 folderview_check_new(folder);
1232 folder_write_list();
1233 folderview_set_all();
1235 gtk_widget_destroy(window);
1236 main_window_unlock(folderview->mainwin);
1240 static gboolean folderview_have_new_children_sub(FolderView *folderview,
1246 if (!item || !item->folder || !item->folder->node)
1249 node = item->folder->node;
1251 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1252 node = node->children;
1255 (item->new_msgs > 0 ||
1256 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1260 while (node != NULL) {
1261 if (node && node->data) {
1262 FolderItem *next_item = (FolderItem*) node->data;
1264 if (folderview_have_new_children_sub(folderview,
1273 static gboolean folderview_have_new_children(FolderView *folderview,
1276 return folderview_have_new_children_sub(folderview, item, FALSE);
1279 static gboolean folderview_have_unread_children_sub(FolderView *folderview,
1285 if (!item || !item->folder || !item->folder->node)
1288 node = item->folder->node;
1290 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1291 node = node->children;
1294 (item->unread_msgs > 0 ||
1295 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1299 while (node != NULL) {
1300 if (node && node->data) {
1301 FolderItem *next_item = (FolderItem*) node->data;
1303 if (folderview_have_unread_children_sub(folderview,
1313 static gboolean folderview_have_unread_children(FolderView *folderview,
1316 return folderview_have_unread_children_sub(folderview, item, FALSE);
1319 static gboolean folderview_have_matching_children_sub(FolderView *folderview,
1325 if (!item || !item->folder || !item->folder->node)
1328 node = item->folder->node;
1330 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1331 node = node->children;
1333 if (in_sub && item->search_match){
1337 while (node != NULL) {
1338 if (node && node->data) {
1339 FolderItem *next_item = (FolderItem*) node->data;
1341 if (folderview_have_matching_children_sub(folderview,
1351 static gboolean folderview_have_matching_children(FolderView *folderview,
1354 return folderview_have_matching_children_sub(folderview, item, FALSE);
1357 static gboolean folderview_have_marked_children_sub(FolderView *folderview,
1363 if (!item || !item->folder || !item->folder->node)
1366 node = item->folder->node;
1368 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1369 node = node->children;
1371 if (item->marked_msgs != 0) {
1375 while (node != NULL) {
1376 if (node && node->data) {
1377 FolderItem *next_item = (FolderItem*) node->data;
1379 if (folderview_have_marked_children_sub(folderview,
1388 static gboolean folderview_have_marked_children(FolderView *folderview,
1391 return folderview_have_marked_children_sub(folderview, item, FALSE);
1394 static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node)
1396 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1397 GtkStyle *style = NULL;
1398 GtkStyle *color_style = NULL;
1400 GdkPixmap *xpm, *openxpm;
1401 GdkBitmap *mask, *openmask;
1402 static GdkPixmap *searchicon;
1403 static GdkBitmap *searchmask;
1404 gboolean mark = FALSE;
1407 gboolean add_unread_mark;
1408 gboolean add_sub_match_mark;
1409 gboolean use_bold, use_color;
1410 gint *col_pos = folderview->col_pos;
1411 SpecialFolderItemType stype;
1413 item = gtk_ctree_node_get_row_data(ctree, node);
1414 g_return_if_fail(item != NULL);
1416 if (!GTK_CTREE_ROW(node)->expanded)
1417 mark = folderview_have_marked_children(folderview, item);
1419 mark = (item->marked_msgs != 0);
1421 stype = item->stype;
1422 if (stype == F_NORMAL) {
1423 if (folder_has_parent_of_type(item, F_TRASH))
1425 else if (folder_has_parent_of_type(item, F_DRAFT))
1427 else if (folder_has_parent_of_type(item, F_OUTBOX))
1429 else if (folder_has_parent_of_type(item, F_QUEUE))
1434 if (item->hide_read_msgs) {
1435 xpm = mark?m_inboxhrmxpm:inboxhrmxpm;
1436 mask = mark?m_inboxhrmxpmmask:inboxhrmxpmmask;
1437 openxpm = mark?m_inboxopenhrmxpm:inboxopenhrmxpm;
1438 openmask = mark?m_inboxopenhrmxpmmask:inboxopenhrmxpmmask;
1440 xpm = mark?m_inboxxpm:inboxxpm;
1441 mask = mark?m_inboxxpmmask:inboxxpmmask;
1442 openxpm = mark?m_inboxopenxpm:inboxopenxpm;
1443 openmask = mark?m_inboxopenxpmmask:inboxopenxpmmask;
1447 if (item->hide_read_msgs) {
1448 xpm = mark?m_outboxhrmxpm:outboxhrmxpm;
1449 mask = mark?m_outboxhrmxpmmask:outboxhrmxpmmask;
1450 openxpm = mark?m_outboxopenhrmxpm:outboxopenhrmxpm;
1451 openmask = mark?m_outboxopenhrmxpmmask:outboxopenhrmxpmmask;
1453 xpm = mark?m_outboxxpm:outboxxpm;
1454 mask = mark?m_outboxxpmmask:outboxxpmmask;
1455 openxpm = mark?m_outboxopenxpm:outboxopenxpm;
1456 openmask = mark?m_outboxopenxpmmask:outboxopenxpmmask;
1460 if (item->hide_read_msgs) {
1461 xpm = mark?m_queuehrmxpm:queuehrmxpm;
1462 mask = mark?m_queuehrmxpmmask:queuehrmxpmmask;
1463 openxpm = mark?m_queueopenhrmxpm:queueopenhrmxpm;
1464 openmask = mark?m_queueopenhrmxpmmask:queueopenhrmxpmmask;
1466 xpm = mark?m_queuexpm:queuexpm;
1467 mask = mark?m_queuexpmmask:queuexpmmask;
1468 openxpm = mark?m_queueopenxpm:queueopenxpm;
1469 openmask = mark?m_queueopenxpmmask:queueopenxpmmask;
1473 if (item->hide_read_msgs) {
1474 xpm = mark?m_trashhrmxpm:trashhrmxpm;
1475 mask = mark?m_trashhrmxpmmask:trashhrmxpmmask;
1476 openxpm = mark?m_trashopenhrmxpm:trashopenhrmxpm;
1477 openmask = mark?m_trashopenhrmxpmmask:trashopenhrmxpmmask;
1479 xpm = mark?m_trashxpm:trashxpm;
1480 mask = mark?m_trashxpmmask:trashxpmmask;
1481 openxpm = mark?m_trashopenxpm:trashopenxpm;
1482 openmask = mark?m_trashopenxpmmask:trashopenxpmmask;
1486 xpm = mark?m_draftsxpm:draftsxpm;
1487 mask = mark?m_draftsxpmmask:draftsxpmmask;
1488 openxpm = mark?m_draftsopenxpm:draftsopenxpm;
1489 openmask = mark?m_draftsopenxpmmask:draftsopenxpmmask;
1492 if (item->hide_read_msgs) {
1493 xpm = mark?m_folderhrmxpm:folderhrmxpm;
1494 mask = mark?m_folderhrmxpmmask:folderhrmxpmmask;
1495 openxpm = mark?m_folderopenhrmxpm:folderopenhrmxpm;
1496 openmask = mark?m_folderopenhrmxpmmask:folderopenhrmxpmmask;
1498 xpm = mark?m_folderxpm:folderxpm;
1499 mask = mark?m_folderxpmmask:folderxpmmask;
1500 openxpm = mark?m_folderopenxpm:folderopenxpm;
1501 openmask = mark?m_folderopenxpmmask:folderopenxpmmask;
1505 if (item->no_select) {
1506 xpm = openxpm = noselectxpm;
1507 mask = openmask = noselectxpmmask;
1510 name = folder_item_get_name(item);
1512 if (!GTK_CTREE_ROW(node)->expanded) {
1513 add_unread_mark = folderview_have_unread_children(
1515 add_sub_match_mark = folderview_have_matching_children(
1518 add_unread_mark = FALSE;
1519 add_sub_match_mark = FALSE;
1522 if (item->search_match) {
1524 stock_pixmap_gdk(folderview->ctree, STOCK_PIXMAP_QUICKSEARCH,
1525 &searchicon, &searchmask);
1527 xpm = openxpm = searchicon;
1528 mask = openmask = searchmask;
1531 if (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0 &&
1532 prefs_common.display_folder_unread) {
1533 str = g_strdup_printf("%s (%d%s)", name, item->total_msgs,
1534 add_unread_mark ? "+" : "");
1535 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1536 xpm, mask, openxpm, openmask,
1537 FALSE, GTK_CTREE_ROW(node)->expanded);
1539 } else if (((item->unread_msgs > 0 || add_unread_mark) &&
1540 prefs_common.display_folder_unread)
1541 || add_sub_match_mark) {
1543 if (item->unread_msgs > 0)
1544 str = g_strdup_printf("%s (%d%s%s)", name, item->unread_msgs,
1545 add_unread_mark || add_sub_match_mark ? "+" : "",
1546 item->unreadmarked_msgs > 0 ? "!":"");
1548 str = g_strdup_printf("%s (+)", name);
1549 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1550 xpm, mask, openxpm, openmask,
1551 FALSE, GTK_CTREE_ROW(node)->expanded);
1554 str = g_strdup_printf("%s%s", name,
1555 item->unreadmarked_msgs > 0 ? " (!)":"");
1557 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1558 xpm, mask, openxpm, openmask,
1559 FALSE, GTK_CTREE_ROW(node)->expanded);
1564 if (!folder_item_parent(item)) {
1565 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], "-");
1566 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], "-");
1567 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], "-");
1569 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], itos(item->new_msgs));
1570 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], itos(item->unread_msgs));
1571 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], itos(item->total_msgs));
1574 if (folder_has_parent_of_type(item, F_OUTBOX) ||
1575 folder_has_parent_of_type(item, F_DRAFT) ||
1576 folder_has_parent_of_type(item, F_TRASH)) {
1577 use_bold = use_color = FALSE;
1578 } else if (folder_has_parent_of_type(item, F_QUEUE)) {
1579 /* highlight queue folder if there are any messages */
1580 use_bold = use_color = (item->total_msgs > 0);
1582 /* if unread messages exist, print with bold font */
1583 use_bold = (item->unread_msgs > 0|| item->new_msgs > 0)
1585 /* if new messages exist, print with colored letter */
1587 (item->new_msgs > 0) ||
1589 folderview_have_new_children(folderview, item));
1592 gtk_ctree_node_set_foreground(ctree, node, NULL);
1597 if (item->prefs->color > 0 && !use_color) {
1598 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1599 color_style = gtk_style_copy(bold_style);
1600 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1601 style = color_style;
1602 } else if (use_color) {
1603 style = bold_color_style;
1606 if (item->op_count > 0) {
1607 style = bold_tgtfold_style;
1609 } else if (use_color) {
1610 style = normal_color_style;
1611 gtk_ctree_node_set_foreground(ctree, node,
1612 &folderview->color_new);
1613 } else if (item->op_count > 0) {
1614 style = bold_tgtfold_style;
1615 } else if (item->prefs->color > 0) {
1617 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1618 color_style = gtk_style_copy(normal_style);
1619 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1620 style = color_style;
1622 style = normal_style;
1625 gtk_ctree_node_set_row_style(ctree, node, style);
1627 if ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
1628 folderview_update_node(folderview, node);
1631 #if !CLAWS /* keep it here for syncs */
1632 void folderview_update_item(FolderItem *item, gboolean update_summary)
1635 FolderView *folderview;
1639 g_return_if_fail(item != NULL);
1641 for (list = folderview_list; list != NULL; list = list->next) {
1642 folderview = (FolderView *)list->data;
1643 ctree = GTK_CTREE(folderview->ctree);
1645 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1647 folderview_update_node(folderview, node);
1648 if (update_summary && folderview->opened == node)
1649 summary_show(folderview->summaryview,
1656 void folderview_update_search_icon(FolderItem *item, gboolean matches)
1659 FolderView *folderview;
1663 g_return_if_fail(item != NULL);
1665 for (list = folderview_list; list != NULL; list = list->next) {
1666 folderview = (FolderView *)list->data;
1667 ctree = GTK_CTREE(folderview->ctree);
1669 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1671 item->search_match = matches;
1672 folderview_update_node(folderview, node);
1677 gboolean folderview_update_item_claws(gpointer source, gpointer data)
1679 FolderItemUpdateData *update_info = (FolderItemUpdateData *)source;
1680 FolderView *folderview = (FolderView *)data;
1683 g_return_val_if_fail(update_info != NULL, TRUE);
1684 g_return_val_if_fail(update_info->item != NULL, TRUE);
1685 g_return_val_if_fail(folderview != NULL, FALSE);
1687 ctree = GTK_CTREE(folderview->ctree);
1689 node = gtk_ctree_find_by_row_data(ctree, NULL, update_info->item);
1691 if (update_info->update_flags & (F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_NAME))
1692 folderview_update_node(folderview, node);
1693 if ((update_info->update_flags & F_ITEM_UPDATE_CONTENT) && (folderview->opened == node))
1694 if (!quicksearch_is_active(folderview->summaryview->quicksearch))
1695 summary_show(folderview->summaryview, update_info->item);
1701 static void folderview_update_item_foreach_func(gpointer key, gpointer val,
1704 /* CLAWS: share this joy with other hook functions ... */
1705 folder_item_update((FolderItem *)key,
1706 (FolderItemUpdateFlags)GPOINTER_TO_INT(data));
1709 void folderview_update_item_foreach(GHashTable *table, gboolean update_summary)
1712 FolderItemUpdateFlags flags;
1714 flags = update_summary ? F_ITEM_UPDATE_CONTENT | F_ITEM_UPDATE_MSGCNT
1716 for (list = folderview_list; list != NULL; list = list->next)
1717 g_hash_table_foreach(table, folderview_update_item_foreach_func,
1718 GINT_TO_POINTER(flags));
1721 static gboolean folderview_gnode_func(GtkCTree *ctree, guint depth,
1722 GNode *gnode, GtkCTreeNode *cnode,
1725 FolderView *folderview = (FolderView *)data;
1726 FolderItem *item = FOLDER_ITEM(gnode->data);
1728 g_return_val_if_fail(item != NULL, FALSE);
1730 gtk_ctree_node_set_row_data(ctree, cnode, item);
1731 folderview_update_node(folderview, cnode);
1736 static void folderview_expand_func(GtkCTree *ctree, GtkCTreeNode *node,
1739 FolderView *folderview = (FolderView *)data;
1742 if (GTK_CTREE_ROW(node)->children) {
1743 item = gtk_ctree_node_get_row_data(ctree, node);
1744 g_return_if_fail(item != NULL);
1746 if (!item->collapsed)
1747 gtk_ctree_expand(ctree, node);
1749 folderview_update_node(folderview, node);
1753 static void set_special_folder(GtkCTree *ctree, FolderItem *item,
1754 GtkCTreeNode *root, GtkCTreeNode **prev)
1757 GtkCTreeNode *node, *parent, *sibling;
1759 node = gtk_ctree_find_by_row_data(ctree, root, item);
1761 g_warning("%s not found.\n", item->path);
1763 parent = GTK_CTREE_ROW(node)->parent;
1764 if (*prev && parent == GTK_CTREE_ROW(*prev)->parent)
1765 sibling = GTK_CTREE_ROW(*prev)->sibling;
1767 sibling = GTK_CTREE_ROW(parent)->children;
1771 tmp = gtk_ctree_node_get_row_data
1773 if (tmp->stype != F_NORMAL)
1774 sibling = GTK_CTREE_ROW(sibling)->sibling;
1778 if (node != sibling)
1779 gtk_ctree_move(ctree, node, parent, sibling);
1786 static void folderview_sort_folders(FolderView *folderview, GtkCTreeNode *root,
1789 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1790 GtkCTreeNode *prev = NULL;
1792 gtk_sctree_sort_recursive(ctree, root);
1794 if (root && GTK_CTREE_ROW(root)->parent) return;
1796 set_special_folder(ctree, folder->inbox, root, &prev);
1797 set_special_folder(ctree, folder->outbox, root, &prev);
1798 set_special_folder(ctree, folder->draft, root, &prev);
1799 set_special_folder(ctree, folder->queue, root, &prev);
1800 set_special_folder(ctree, folder->trash, root, &prev);
1803 static void folderview_append_folder(FolderView *folderview, Folder *folder)
1805 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1808 g_return_if_fail(folder != NULL);
1810 root = gtk_sctree_insert_gnode(ctree, NULL, NULL, folder->node,
1811 folderview_gnode_func, folderview);
1812 gtk_ctree_pre_recursive(ctree, root, folderview_expand_func,
1814 folderview_sort_folders(folderview, root, folder);
1817 /* callback functions */
1818 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
1819 GdkEventButton *event)
1821 GtkCList *clist = GTK_CLIST(folderview->ctree);
1824 FolderViewPopup *fpopup;
1825 GtkItemFactory *fpopup_factory;
1827 FolderItem *special_trash = NULL, *special_queue = NULL;
1831 item = gtk_clist_get_row_data(clist, row);
1833 item = folderview_get_selected_item(folderview);
1835 g_return_if_fail(item != NULL);
1836 g_return_if_fail(item->folder != NULL);
1837 folder = item->folder;
1839 fpopup = g_hash_table_lookup(folderview_popups, folder->klass->idstr);
1841 fpopup_factory = g_hash_table_lookup(folderview->popups, folder->klass->idstr);
1843 fpopup = g_hash_table_lookup(folderview_popups, "common");
1844 fpopup_factory = g_hash_table_lookup(folderview->popups, "common");
1847 if (fpopup->set_sensitivity != NULL)
1848 fpopup->set_sensitivity(fpopup_factory, item);
1850 if (NULL != (ac = account_find_from_item(item))) {
1851 special_trash = account_get_special_folder(ac, F_TRASH);
1852 special_queue = account_get_special_folder(ac, F_QUEUE);
1855 if ((item == folder->trash || item == special_trash
1856 || folder_has_parent_of_type(item, F_TRASH)) &&
1857 gtk_item_factory_get_item(fpopup_factory, "/Empty trash...") == NULL) {
1858 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[0], folderview, 1);
1859 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[1], folderview, 1);
1860 } else if (item != folder->trash && (special_trash == NULL || item != special_trash)
1861 && !folder_has_parent_of_type(item, F_TRASH)) {
1862 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[0]);
1863 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[1]);
1866 if ((item == folder->queue || item == special_queue
1867 || folder_has_parent_of_type(item, F_QUEUE)) &&
1868 gtk_item_factory_get_item(fpopup_factory, "/Send queue...") == NULL) {
1869 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[0], folderview, 1);
1870 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[1], folderview, 1);
1871 } else if (item != folder->queue && (special_queue == NULL || item != special_queue)
1872 && !folder_has_parent_of_type(item, F_QUEUE)) {
1873 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[0]);
1874 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[1]);
1877 #define SET_SENS(name, sens) \
1878 menu_set_sensitive(fpopup_factory, name, sens)
1880 SET_SENS("/Mark all read", item->unread_msgs >= 1);
1881 SET_SENS("/Search folder...", item->total_msgs >= 1 &&
1882 folderview->selected == folderview->opened);
1883 SET_SENS("/Properties...", TRUE);
1884 SET_SENS("/Processing...", item->node->parent != NULL);
1885 if (item == folder->trash || item == special_trash
1886 || folder_has_parent_of_type(item, F_TRASH)) {
1887 GSList *msglist = folder_item_get_msg_list(item);
1888 SET_SENS("/Empty trash...", msglist != NULL);
1889 procmsg_msg_list_free(msglist);
1891 if (item == folder->queue || item == special_queue
1892 || folder_has_parent_of_type(item, F_QUEUE)) {
1893 GSList *msglist = folder_item_get_msg_list(item);
1894 SET_SENS("/Send queue...", msglist != NULL);
1895 procmsg_msg_list_free(msglist);
1899 popup = gtk_item_factory_get_widget(fpopup_factory, fpopup->path);
1900 gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
1901 event->button, event->time);
1906 static gboolean folderview_button_pressed(GtkWidget *ctree, GdkEventButton *event,
1907 FolderView *folderview)
1909 GtkCList *clist = GTK_CLIST(ctree);
1910 gint prev_row = -1, row = -1, column = -1;
1912 if (!event) return FALSE;
1914 if (event->button == 1 || event->button == 2) {
1915 folderview->open_folder = TRUE;
1917 if (event->type == GDK_2BUTTON_PRESS) {
1918 if (clist->selection) {
1921 node = GTK_CTREE_NODE(clist->selection->data);
1923 gtk_ctree_toggle_expansion(
1931 if (event->button == 2 || event->button == 3) {
1933 if (clist->selection) {
1936 node = GTK_CTREE_NODE(clist->selection->data);
1938 prev_row = gtkut_ctree_get_nth_from_node
1939 (GTK_CTREE(ctree), node);
1942 if (!gtk_clist_get_selection_info(clist, event->x, event->y,
1945 if (prev_row != row) {
1946 gtk_clist_unselect_all(clist);
1947 if (event->button == 2)
1948 folderview_select_node
1950 gtk_ctree_node_nth(GTK_CTREE(ctree),
1953 gtk_clist_select_row(clist, row, column);
1957 if (event->button != 3) return FALSE;
1959 folderview_set_sens_and_popup_menu(folderview, row, event);
1963 static gboolean folderview_button_released(GtkWidget *ctree, GdkEventButton *event,
1964 FolderView *folderview)
1966 if (!event) return FALSE;
1968 if (event->button == 1 && folderview->open_folder == FALSE &&
1969 folderview->opened != NULL) {
1970 gtkut_ctree_set_focus_row(GTK_CTREE(ctree),
1971 folderview->opened);
1972 gtk_ctree_select(GTK_CTREE(ctree), folderview->opened);
1978 static gboolean folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
1979 FolderView *folderview)
1981 if (!event) return FALSE;
1983 if (quicksearch_has_focus(folderview->summaryview->quicksearch))
1986 switch (event->keyval) {
1988 if (folderview->selected) {
1989 folderview_select_node(folderview,
1990 folderview->selected);
1994 if (folderview->selected) {
1995 if (folderview->opened == folderview->selected &&
1996 (!folderview->summaryview->folder_item ||
1997 folderview->summaryview->folder_item->total_msgs == 0))
1998 folderview_select_next_unread(folderview);
2000 folderview_select_node(folderview,
2001 folderview->selected);
2011 typedef struct _PostponedSelectData
2016 FolderView *folderview;
2017 } PostponedSelectData;
2019 static gboolean postpone_select(void *data)
2021 PostponedSelectData *psdata = (PostponedSelectData *)data;
2022 debug_print("trying again\n");
2023 psdata->folderview->open_folder = TRUE;
2024 main_window_cursor_normal(psdata->folderview->mainwin);
2025 STATUSBAR_POP(psdata->folderview->mainwin);
2026 folderview_selected(psdata->ctree, psdata->row,
2027 psdata->column, psdata->folderview);
2032 static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row,
2033 gint column, FolderView *folderview)
2035 static gboolean can_select = TRUE; /* exclusive lock */
2040 START_TIMING("--- folderview_selected");
2041 folderview->selected = row;
2043 if (folderview->opened == row) {
2044 folderview->open_folder = FALSE;
2049 if (!can_select || summary_is_locked(folderview->summaryview)) {
2050 if (folderview->opened) {
2051 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2052 gtk_ctree_select(ctree, folderview->opened);
2058 if (!folderview->open_folder) {
2062 item = gtk_ctree_node_get_row_data(ctree, row);
2063 if (!item || item->no_select) {
2070 /* Save cache for old folder */
2071 /* We don't want to lose all caches if sylpheed crashed */
2072 if (folderview->opened) {
2073 FolderItem *olditem;
2075 olditem = gtk_ctree_node_get_row_data(ctree, folderview->opened);
2077 buf = g_strdup_printf(_("Closing Folder %s..."),
2078 olditem->path ? olditem->path:olditem->name);
2079 /* will be null if we just moved the previously opened folder */
2080 STATUSBAR_PUSH(folderview->mainwin, buf);
2081 main_window_cursor_wait(folderview->mainwin);
2083 summary_save_prefs_to_folderitem(folderview->summaryview, olditem);
2084 summary_show(folderview->summaryview, NULL);
2085 folder_item_close(olditem);
2086 main_window_cursor_normal(folderview->mainwin);
2087 STATUSBAR_POP(folderview->mainwin);
2091 /* CLAWS: set compose button type: news folder items
2092 * always have a news folder as parent */
2094 toolbar_set_compose_button
2095 (folderview->mainwin->toolbar,
2096 FOLDER_TYPE(item->folder) == F_NEWS ?
2097 COMPOSEBUTTON_NEWS : COMPOSEBUTTON_MAIL);
2100 debug_print("Folder %s is selected\n", item->path);
2102 if (!GTK_CTREE_ROW(row)->children)
2103 gtk_ctree_expand(ctree, row);
2104 if (folderview->opened &&
2105 !GTK_CTREE_ROW(folderview->opened)->children)
2106 gtk_ctree_collapse(ctree, folderview->opened);
2108 /* ungrab the mouse event */
2109 if (GTK_WIDGET_HAS_GRAB(ctree)) {
2110 gtk_grab_remove(GTK_WIDGET(ctree));
2111 if (gdk_pointer_is_grabbed())
2112 gdk_pointer_ungrab(GDK_CURRENT_TIME);
2116 buf = g_strdup_printf(_("Opening Folder %s..."), item->path ?
2117 item->path : "(null)");
2118 debug_print("%s\n", buf);
2119 STATUSBAR_PUSH(folderview->mainwin, buf);
2122 main_window_cursor_wait(folderview->mainwin);
2124 res = folder_item_open(item);
2126 main_window_cursor_normal(folderview->mainwin);
2127 STATUSBAR_POP(folderview->mainwin);
2129 alertpanel_error(_("Folder could not be opened."));
2131 folderview->open_folder = FALSE;
2135 } else if (res == -2) {
2136 PostponedSelectData *data = g_new0(PostponedSelectData, 1);
2137 data->ctree = ctree;
2139 data->column = column;
2140 data->folderview = folderview;
2141 debug_print("postponing open of %s till end of scan\n",
2142 item->path ? item->path:item->name);
2143 folderview->open_folder = FALSE;
2145 g_timeout_add(500, postpone_select, data);
2150 main_window_cursor_normal(folderview->mainwin);
2153 summary_set_prefs_from_folderitem(folderview->summaryview, item);
2154 opened = summary_show(folderview->summaryview, item);
2156 folder_clean_cache_memory(item);
2159 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2160 gtk_ctree_select(ctree, folderview->opened);
2162 folderview->opened = row;
2163 if (gtk_ctree_node_is_visible(ctree, row)
2164 != GTK_VISIBILITY_FULL)
2165 gtk_ctree_node_moveto(ctree, row, -1, 0.5, 0);
2168 STATUSBAR_POP(folderview->mainwin);
2170 folderview->open_folder = FALSE;
2175 static void folderview_tree_expanded(GtkCTree *ctree, GtkCTreeNode *node,
2176 FolderView *folderview)
2180 item = gtk_ctree_node_get_row_data(ctree, node);
2181 g_return_if_fail(item != NULL);
2182 item->collapsed = FALSE;
2183 folderview_update_node(folderview, node);
2186 static void folderview_tree_collapsed(GtkCTree *ctree, GtkCTreeNode *node,
2187 FolderView *folderview)
2191 item = gtk_ctree_node_get_row_data(ctree, node);
2192 g_return_if_fail(item != NULL);
2193 item->collapsed = TRUE;
2194 folderview_update_node(folderview, node);
2197 static void folderview_popup_close(GtkMenuShell *menu_shell,
2198 FolderView *folderview)
2200 if (!folderview->opened) return;
2202 gtk_ctree_select(GTK_CTREE(folderview->ctree), folderview->opened);
2205 static void folderview_col_resized(GtkCList *clist, gint column, gint width,
2206 FolderView *folderview)
2208 FolderColumnType type = folderview->col_state[column].type;
2210 prefs_common.folder_col_size[type] = width;
2213 void folderview_create_folder_node_recursive(FolderView *folderview, FolderItem *item)
2217 folderview_create_folder_node(folderview, item);
2219 if (!item || !item->folder || !item->folder->node)
2222 srcnode = item->folder->node;
2223 srcnode = g_node_find(srcnode, G_PRE_ORDER, G_TRAVERSE_ALL, item);
2224 srcnode = srcnode->children;
2225 while (srcnode != NULL) {
2226 if (srcnode && srcnode->data) {
2227 FolderItem *next_item = (FolderItem*) srcnode->data;
2228 folderview_create_folder_node_recursive(folderview, next_item);
2230 srcnode = srcnode->next;
2234 void folderview_create_folder_node(FolderView *folderview, FolderItem *item)
2236 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2237 gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
2238 GtkCTreeNode *node, *parent_node;
2239 gint *col_pos = folderview->col_pos;
2240 FolderItemUpdateData hookdata;
2242 parent_node = gtk_ctree_find_by_row_data(ctree, NULL, folder_item_parent(item));
2243 if (parent_node == NULL)
2246 gtk_clist_freeze(GTK_CLIST(ctree));
2248 text[col_pos[F_COL_FOLDER]] = item->name;
2249 node = gtk_sctree_insert_node(ctree, parent_node, NULL, text,
2251 folderxpm, folderxpmmask,
2252 folderopenxpm, folderopenxpmmask,
2254 gtk_ctree_expand(ctree, parent_node);
2255 gtk_ctree_node_set_row_data(ctree, node, item);
2257 gtk_ctree_node_set_row_style(ctree, node, normal_style);
2258 folderview_sort_folders(folderview, parent_node, item->folder);
2260 hookdata.item = item;
2261 hookdata.update_flags = F_ITEM_UPDATE_NAME;
2262 hookdata.msg = NULL;
2263 hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &hookdata);
2265 gtk_clist_thaw(GTK_CLIST(ctree));
2268 static void folderview_empty_trash_cb(FolderView *folderview, guint action,
2271 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2273 GSList *mlist = NULL;
2275 FolderItem *special_trash = NULL;
2278 if (!folderview->selected) return;
2279 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2280 g_return_if_fail(item != NULL);
2281 g_return_if_fail(item->folder != NULL);
2283 if (NULL != (ac = account_find_from_item(item)))
2284 special_trash = account_get_special_folder(ac, F_TRASH);
2286 if (item != item->folder->trash && item != special_trash
2287 && !folder_has_parent_of_type(item, F_TRASH)) return;
2289 if (prefs_common.ask_on_clean) {
2290 if (alertpanel(_("Empty trash"),
2291 _("Delete all messages in trash?"),
2292 GTK_STOCK_CANCEL, _("+_Empty trash"), NULL) != G_ALERTALTERNATE)
2296 mlist = folder_item_get_msg_list(item);
2298 for (cur = mlist ; cur != NULL ; cur = cur->next) {
2299 MsgInfo * msginfo = (MsgInfo *) cur->data;
2300 if (MSG_IS_LOCKED(msginfo->flags))
2302 /* is it partially received? (partial_recv isn't cached) */
2303 if (msginfo->total_size != 0 &&
2304 msginfo->size != (off_t)msginfo->total_size)
2305 partial_mark_for_delete(msginfo);
2307 procmsg_msg_list_free(mlist);
2309 folder_item_remove_all_msg(item);
2312 static void folderview_send_queue_cb(FolderView *folderview, guint action,
2315 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2317 FolderItem *special_queue = NULL;
2319 gchar *errstr = NULL;
2321 if (!folderview->selected) return;
2322 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2323 g_return_if_fail(item != NULL);
2324 g_return_if_fail(item->folder != NULL);
2326 if (NULL != (ac = account_find_from_item(item)))
2327 special_queue = account_get_special_folder(ac, F_QUEUE);
2329 if (item != item->folder->queue && item != special_queue
2330 && !folder_has_parent_of_type(item, F_QUEUE)) return;
2332 if (procmsg_queue_is_empty(item))
2335 if (prefs_common.work_offline)
2336 if (alertpanel(_("Offline warning"),
2337 _("You're working offline. Override?"),
2338 GTK_STOCK_NO, GTK_STOCK_YES,
2339 NULL) != G_ALERTALTERNATE)
2342 /* ask for confirmation before sending queued messages only
2343 in online mode and if there is at least one message queued
2344 in any of the folder queue
2346 if (prefs_common.confirm_send_queued_messages) {
2347 if (!prefs_common.work_offline) {
2348 if (alertpanel(_("Send queued messages"),
2349 _("Send all queued messages?"),
2350 GTK_STOCK_CANCEL, _("_Send"),
2351 NULL) != G_ALERTALTERNATE)
2356 if (procmsg_send_queue(item, prefs_common.savemsg, &errstr) < 0) {
2358 alertpanel_error_log(_("Some errors occurred while "
2359 "sending queued messages."));
2361 gchar *tmp = g_strdup_printf(_("Some errors occurred "
2362 "while sending queued messages:\n%s"), errstr);
2364 alertpanel_error_log(tmp);
2370 static void folderview_search_cb(FolderView *folderview, guint action,
2373 summary_search(folderview->summaryview);
2376 static void folderview_property_cb(FolderView *folderview, guint action,
2379 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2382 if (!folderview->selected) return;
2384 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2385 g_return_if_fail(item != NULL);
2386 g_return_if_fail(item->folder != NULL);
2388 prefs_folder_item_open(item);
2391 static void folderview_recollapse_nodes(FolderView *folderview, GtkCTreeNode *node)
2393 GSList *list = NULL;
2394 GSList *done = NULL;
2395 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2397 for (list = folderview->nodes_to_recollapse; list != NULL; list = g_slist_next(list)) {
2398 if (!gtkut_ctree_node_is_parent(GTK_CTREE_NODE(list->data), node)
2399 && list->data != node) {
2400 gtk_ctree_collapse(ctree, GTK_CTREE_NODE(list->data));
2401 done = g_slist_append(done, GTK_CTREE_NODE(list->data));
2404 for (list = done; list != NULL; list = g_slist_next(list)) {
2405 folderview->nodes_to_recollapse = g_slist_remove(folderview->nodes_to_recollapse,
2411 void folderview_move_folder(FolderView *folderview, FolderItem *from_folder,
2412 FolderItem *to_folder)
2414 FolderItem *from_parent = NULL;
2415 FolderItem *new_folder = NULL;
2416 GtkCTreeNode *src_node = NULL;
2420 g_return_if_fail(folderview != NULL);
2421 g_return_if_fail(from_folder != NULL);
2422 g_return_if_fail(to_folder != NULL);
2424 src_node = gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree), NULL, from_folder);
2425 from_parent = folder_item_parent(from_folder);
2427 if (prefs_common.warn_dnd) {
2428 buf = g_strdup_printf(_("Do you really want to make folder '%s' a "
2429 "sub-folder of '%s' ?"), from_folder->name,
2431 status = alertpanel_full(_("Move folder"), buf,
2432 GTK_STOCK_NO, GTK_STOCK_YES, NULL, TRUE,
2433 NULL, ALERT_QUESTION, G_ALERTDEFAULT);
2436 if ((status & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
2438 else if (status & G_ALERTDISABLE)
2439 prefs_common.warn_dnd = FALSE;
2442 buf = g_strdup_printf(_("Moving %s to %s..."), from_folder->name, to_folder->name);
2443 STATUSBAR_PUSH(folderview->mainwin, buf);
2445 summary_clear_all(folderview->summaryview);
2446 folderview->opened = NULL;
2447 folderview->selected = NULL;
2448 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), FALSE);
2450 main_window_cursor_wait(folderview->mainwin);
2451 statusbar_verbosity_set(TRUE);
2452 folder_item_update_freeze();
2453 if ((status = folder_item_move_to(from_folder, to_folder, &new_folder)) == F_MOVE_OK) {
2454 statusbar_verbosity_set(FALSE);
2455 main_window_cursor_normal(folderview->mainwin);
2456 STATUSBAR_POP(folderview->mainwin);
2457 folder_item_update_thaw();
2458 folder_item_update_recursive(new_folder, F_ITEM_UPDATE_MSGCNT);
2460 folderview_sort_folders(folderview,
2461 gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree),
2462 NULL, to_folder), new_folder->folder);
2463 folderview_select(folderview, new_folder);
2465 statusbar_verbosity_set(FALSE);
2466 main_window_cursor_normal(folderview->mainwin);
2467 STATUSBAR_POP(folderview->mainwin);
2468 folder_item_update_thaw();
2470 case F_MOVE_FAILED_DEST_IS_PARENT:
2471 alertpanel_error(_("Source and destination are the same."));
2473 case F_MOVE_FAILED_DEST_IS_CHILD:
2474 alertpanel_error(_("Can't move a folder to one of its children."));
2476 case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX:
2477 alertpanel_error(_("Folder moving cannot be done between different mailboxes."));
2480 alertpanel_error(_("Move failed!"));
2485 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), TRUE);
2488 static gint folderview_clist_compare(GtkCList *clist,
2489 gconstpointer ptr1, gconstpointer ptr2)
2491 FolderItem *item1 = ((GtkCListRow *)ptr1)->data;
2492 FolderItem *item2 = ((GtkCListRow *)ptr2)->data;
2495 return (item2->name != NULL);
2499 return g_utf8_collate(item1->name, item2->name);
2502 static void folderview_processing_cb(FolderView *folderview, guint action,
2505 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2509 if (!folderview->selected) return;
2511 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2512 g_return_if_fail(item != NULL);
2513 g_return_if_fail(item->folder != NULL);
2515 id = folder_item_get_identifier(item);
2516 title = g_strdup_printf (_("Processing configuration for folder %s"), id);
2519 prefs_filtering_open(&item->prefs->processing, title,
2520 MANUAL_ANCHOR_PROCESSING, NULL, NULL, FALSE);
2524 void folderview_set_target_folder_color(gint color_op)
2528 FolderView *folderview;
2530 for (list = folderview_list; list != NULL; list = list->next) {
2531 folderview = (FolderView *)list->data;
2532 gtkut_convert_int_to_gdk_color(color_op, &folderview->color_op);
2534 bold_tgtfold_style->fg[GTK_STATE_NORMAL] =
2535 folderview->color_op;
2541 static gchar *last_font = NULL;
2542 void folderview_reflect_prefs_pixmap_theme(FolderView *folderview)
2550 void folderview_reflect_prefs(void)
2552 gboolean update_font = TRUE;
2553 FolderView *folderview = mainwindow_get_mainwindow()->folderview;
2554 FolderItem *item = folderview_get_selected_item(folderview);
2555 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2556 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2557 gint height = pos->value;
2559 if (last_font && !strcmp(last_font, NORMAL_FONT))
2560 update_font = FALSE;
2563 last_font = g_strdup(NORMAL_FONT);
2566 normal_style = normal_color_style = bold_style =
2567 bold_color_style = bold_tgtfold_style = NULL;
2569 folderview_init(folderview);
2571 gtk_clist_freeze(GTK_CLIST(folderview->ctree));
2572 folderview_column_set_titles(folderview);
2573 folderview_set_all();
2575 g_signal_handlers_block_by_func
2576 (G_OBJECT(folderview->ctree),
2577 G_CALLBACK(folderview_selected), folderview);
2580 GtkCTreeNode *node = gtk_ctree_find_by_row_data(
2581 GTK_CTREE(folderview->ctree), NULL, item);
2583 folderview_select(folderview, item);
2584 folderview->selected = node;
2587 g_signal_handlers_unblock_by_func
2588 (G_OBJECT(folderview->ctree),
2589 G_CALLBACK(folderview_selected), folderview);
2591 pos = gtk_scrolled_window_get_vadjustment(
2592 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2593 gtk_adjustment_set_value(pos, height);
2594 gtk_clist_thaw(GTK_CLIST(folderview->ctree));
2597 static void drag_state_stop(FolderView *folderview)
2599 if (folderview->drag_timer)
2600 gtk_timeout_remove(folderview->drag_timer);
2601 folderview->drag_timer = 0;
2602 folderview->drag_node = NULL;
2605 static gint folderview_defer_expand(FolderView *folderview)
2607 if (folderview->drag_node) {
2608 folderview_recollapse_nodes(folderview, folderview->drag_node);
2609 if (folderview->drag_item->collapsed) {
2610 gtk_ctree_expand(GTK_CTREE(folderview->ctree), folderview->drag_node);
2611 folderview->nodes_to_recollapse = g_slist_append
2612 (folderview->nodes_to_recollapse, folderview->drag_node);
2615 folderview->drag_item = NULL;
2616 folderview->drag_timer = 0;
2620 static void drag_state_start(FolderView *folderview, GtkCTreeNode *node, FolderItem *item)
2622 /* the idea is that we call drag_state_start() whenever we want expansion to
2623 * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
2624 * we need to call drag_state_stop() */
2625 drag_state_stop(folderview);
2626 /* request expansion */
2627 if (0 != (folderview->drag_timer = gtk_timeout_add
2628 (prefs_common.hover_timeout,
2629 (GtkFunction)folderview_defer_expand,
2631 folderview->drag_node = node;
2632 folderview->drag_item = item;
2636 static void folderview_start_drag(GtkWidget *widget, gint button, GdkEvent *event,
2637 FolderView *folderview)
2639 GdkDragContext *context;
2641 g_return_if_fail(folderview != NULL);
2642 if (folderview->selected == NULL) return;
2643 if (folderview->nodes_to_recollapse)
2644 g_slist_free(folderview->nodes_to_recollapse);
2645 folderview->nodes_to_recollapse = NULL;
2646 context = gtk_drag_begin(widget, folderview->target_list,
2647 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
2648 gtk_drag_set_icon_default(context);
2651 static void folderview_drag_data_get(GtkWidget *widget,
2652 GdkDragContext *drag_context,
2653 GtkSelectionData *selection_data,
2656 FolderView *folderview)
2660 gchar *source = NULL;
2661 if (info == TARGET_DUMMY) {
2662 for (cur = GTK_CLIST(folderview->ctree)->selection;
2663 cur != NULL; cur = cur->next) {
2664 item = gtk_ctree_node_get_row_data
2665 (GTK_CTREE(folderview->ctree),
2666 GTK_CTREE_NODE(cur->data));
2668 source = g_strdup_printf ("FROM_OTHER_FOLDER%s", folder_item_get_identifier(item));
2669 gtk_selection_data_set(selection_data,
2670 selection_data->target, 8,
2671 source, strlen(source));
2677 g_warning("unknown info %d\n", info);
2681 gboolean folderview_update_folder(gpointer source, gpointer userdata)
2683 FolderUpdateData *hookdata;
2684 FolderView *folderview;
2688 folderview = (FolderView *) userdata;
2689 g_return_val_if_fail(hookdata != NULL, FALSE);
2690 g_return_val_if_fail(folderview != NULL, FALSE);
2692 ctree = folderview->ctree;
2693 g_return_val_if_fail(ctree != NULL, FALSE);
2695 if (hookdata->update_flags & FOLDER_ADD_FOLDERITEM)
2696 folderview_create_folder_node(folderview, hookdata->item);
2697 else if (hookdata->update_flags & FOLDER_RENAME_FOLDERITEM) {
2698 GtkCTreeNode *node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree),
2699 NULL, folder_item_parent(hookdata->item));
2700 folderview_sort_folders(folderview, node, hookdata->folder);
2701 } else if (hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM) {
2704 node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree), NULL, hookdata->item);
2706 gtk_ctree_remove_node(GTK_CTREE(ctree), node);
2707 } else if (hookdata->update_flags & (FOLDER_TREE_CHANGED | FOLDER_ADD_FOLDER | FOLDER_REMOVE_FOLDER))
2708 folderview_set(folderview);
2713 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
2714 GdkDragContext *context,
2718 FolderView *folderview)
2721 FolderItem *item = NULL, *src_item = NULL;
2722 GtkCTreeNode *node = NULL;
2723 gboolean acceptable = FALSE;
2724 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2725 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2726 int height = (int)pos->page_size;
2727 int total_height = (int)pos->upper;
2728 int vpos = (int) pos->value;
2730 if (gtk_clist_get_selection_info
2731 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
2732 GtkWidget *srcwidget;
2734 if (y > height - 24 && height + vpos < total_height)
2735 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
2737 if (y < 48 && y > 0)
2738 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
2740 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2741 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2742 src_item = folderview->summaryview->folder_item;
2744 srcwidget = gtk_drag_get_source_widget(context);
2745 if (srcwidget == folderview->summaryview->ctree) {
2746 /* comes from summaryview */
2747 /* we are copying messages, so only accept folder items that are not
2748 the source item, are no root items and can copy messages */
2749 if (item && item->folder && folder_item_parent(item) != NULL && src_item &&
2750 src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)
2752 } else if (srcwidget == folderview->ctree) {
2753 /* comes from folderview */
2754 /* we are moving folder items, only accept folders that are not
2755 the source items and can copy messages and create folder items */
2756 if (item && item->folder && src_item && src_item != item &&
2757 FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2758 FOLDER_CLASS(item->folder)->create_folder != NULL)
2761 /* comes from another app */
2762 /* we are adding messages, so only accept folder items that are
2763 no root items and can copy messages */
2764 if (item && item->folder && folder_item_parent(item) != NULL
2765 && FOLDER_CLASS(item->folder)->add_msg != NULL)
2770 if (acceptable || (src_item && src_item == item))
2771 drag_state_start(folderview, node, item);
2774 g_signal_handlers_block_by_func
2776 G_CALLBACK(folderview_selected), folderview);
2777 gtk_ctree_select(GTK_CTREE(widget), node);
2778 g_signal_handlers_unblock_by_func
2780 G_CALLBACK(folderview_selected), folderview);
2781 gdk_drag_status(context,
2782 (context->actions == GDK_ACTION_COPY ?
2783 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
2785 if (folderview->opened)
2786 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2787 gdk_drag_status(context, 0, time);
2793 static void folderview_drag_leave_cb(GtkWidget *widget,
2794 GdkDragContext *context,
2796 FolderView *folderview)
2798 drag_state_stop(folderview);
2799 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2802 static void free_info (gpointer stuff, gpointer data)
2807 void folderview_finish_dnd(const gchar *data, GdkDragContext *drag_context,
2808 guint time, FolderItem *item)
2811 GSList *msglist = NULL;
2812 list = uri_list_extract_filenames(data);
2813 if (!(item && item->folder && folder_item_parent(item) != NULL
2814 && FOLDER_CLASS(item->folder)->add_msg != NULL))
2816 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2820 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2823 for (tmp = list; tmp != NULL; tmp = tmp->next) {
2824 MsgFileInfo *info = NULL;
2826 if (file_is_email((gchar *)tmp->data)) {
2827 info = g_new0(MsgFileInfo, 1);
2828 info->msginfo = NULL;
2829 info->file = (gchar *)tmp->data;
2830 msglist = g_slist_prepend(msglist, info);
2834 msglist = g_slist_reverse(msglist);
2835 folder_item_add_msgs(item, msglist, FALSE);
2836 g_slist_foreach(msglist, free_info, NULL);
2837 g_slist_free(msglist);
2838 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2840 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2842 list_free_strings(list);
2846 static void folderview_drag_received_cb(GtkWidget *widget,
2847 GdkDragContext *drag_context,
2850 GtkSelectionData *data,
2853 FolderView *folderview)
2856 FolderItem *item = NULL, *src_item;
2859 if (info == TARGET_DUMMY) {
2860 drag_state_stop(folderview);
2861 if ((void *)strstr(data->data, "FROM_OTHER_FOLDER") != (void *)data->data) {
2862 /* comes from summaryview */
2863 if (gtk_clist_get_selection_info
2864 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2867 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2868 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2869 src_item = folderview->summaryview->folder_item;
2871 /* re-check (due to acceptable possibly set for folder moves */
2872 if (!(item && item->folder && item->path && !item->no_select &&
2873 src_item && src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)) {
2876 if (item && src_item) {
2877 switch (drag_context->action) {
2878 case GDK_ACTION_COPY:
2879 summary_copy_selected_to(folderview->summaryview, item);
2880 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2882 case GDK_ACTION_MOVE:
2883 case GDK_ACTION_DEFAULT:
2885 if (FOLDER_CLASS(src_item->folder)->remove_msg == NULL)
2886 summary_copy_selected_to(folderview->summaryview, item);
2888 summary_move_selected_to(folderview->summaryview, item);
2889 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2892 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2894 /* comes from folderview */
2896 gboolean folder_is_normal = TRUE;
2898 source = data->data + 17;
2899 if (gtk_clist_get_selection_info
2900 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0
2902 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2905 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2906 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2907 src_item = folder_find_item_from_identifier(source);
2911 src_item->stype == F_NORMAL &&
2912 !folder_has_parent_of_type(src_item, F_OUTBOX) &&
2913 !folder_has_parent_of_type(src_item, F_DRAFT) &&
2914 !folder_has_parent_of_type(src_item, F_QUEUE) &&
2915 !folder_has_parent_of_type(src_item, F_TRASH);
2916 if (!item || item->no_select || !src_item
2917 || !folder_is_normal) {
2918 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2922 folderview_move_folder(folderview, src_item, item);
2923 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2925 folderview->nodes_to_recollapse = NULL;
2926 } else if (info == TARGET_MAIL_URI_LIST) {
2927 if (gtk_clist_get_selection_info
2928 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2931 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2933 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2936 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2938 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2941 folderview_finish_dnd(data->data, drag_context, time, item);
2945 static void folderview_drag_end_cb(GtkWidget *widget,
2946 GdkDragContext *drag_context,
2947 FolderView *folderview)
2949 drag_state_stop(folderview);
2950 g_slist_free(folderview->nodes_to_recollapse);
2951 folderview->nodes_to_recollapse = NULL;
2954 void folderview_register_popup(FolderViewPopup *fpopup)
2958 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2959 FolderView *folderview = folderviews->data;
2960 GtkItemFactory *factory;
2962 factory = create_ifactory(folderview, fpopup);
2963 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
2965 g_hash_table_insert(folderview_popups, fpopup->klass, fpopup);
2968 void folderview_unregister_popup(FolderViewPopup *fpopup)
2972 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2973 FolderView *folderview = folderviews->data;
2975 g_hash_table_remove(folderview->popups, fpopup->klass);
2977 g_hash_table_remove(folderview_popups, fpopup->klass);