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);
490 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
492 gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
493 gtk_clist_set_compare_func(GTK_CLIST(ctree), folderview_clist_compare);
495 /* don't let title buttons take key focus */
496 for (i = 0; i < N_FOLDER_COLS; i++) {
497 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(ctree)->column[i].button,
499 gtk_clist_set_column_width(GTK_CLIST(ctree), col_pos[i],
500 prefs_common.folder_col_size[i]);
501 gtk_clist_set_column_visibility
502 (GTK_CLIST(ctree), i, col_state[i].visible);
505 g_signal_connect(G_OBJECT(ctree), "key_press_event",
506 G_CALLBACK(folderview_key_pressed),
508 g_signal_connect(G_OBJECT(ctree), "button_press_event",
509 G_CALLBACK(folderview_button_pressed),
511 g_signal_connect(G_OBJECT(ctree), "popup-menu",
512 G_CALLBACK(folderview_popup_menu), folderview);
513 g_signal_connect(G_OBJECT(ctree), "button_release_event",
514 G_CALLBACK(folderview_button_released),
516 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
517 G_CALLBACK(folderview_selected), folderview);
518 g_signal_connect(G_OBJECT(ctree), "start_drag",
519 G_CALLBACK(folderview_start_drag), folderview);
520 g_signal_connect(G_OBJECT(ctree), "drag_data_get",
521 G_CALLBACK(folderview_drag_data_get),
524 g_signal_connect_after(G_OBJECT(ctree), "tree_expand",
525 G_CALLBACK(folderview_tree_expanded),
527 g_signal_connect_after(G_OBJECT(ctree), "tree_collapse",
528 G_CALLBACK(folderview_tree_collapsed),
531 g_signal_connect(G_OBJECT(ctree), "resize_column",
532 G_CALLBACK(folderview_col_resized),
536 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
537 folderview_drag_types, 2,
538 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
539 g_signal_connect(G_OBJECT(ctree), "drag_motion",
540 G_CALLBACK(folderview_drag_motion_cb),
542 g_signal_connect(G_OBJECT(ctree), "drag_leave",
543 G_CALLBACK(folderview_drag_leave_cb),
545 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
546 G_CALLBACK(folderview_drag_received_cb),
548 g_signal_connect(G_OBJECT(ctree), "drag_end",
549 G_CALLBACK(folderview_drag_end_cb),
552 gtk_container_add(GTK_CONTAINER(scrolledwin), ctree);
557 void folderview_set_column_order(FolderView *folderview)
560 FolderItem *item = folderview_get_selected_item(folderview);
561 GtkWidget *scrolledwin = folderview->scrolledwin;
563 debug_print("recreating tree...\n");
564 gtk_widget_destroy(folderview->ctree);
566 folderview->ctree = ctree = folderview_ctree_create(folderview);
567 gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
568 GTK_CLIST(ctree)->hadjustment);
569 gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
570 GTK_CLIST(ctree)->vadjustment);
571 gtk_widget_show(ctree);
573 folderview_set(folderview);
574 folderview_column_set_titles(folderview);
576 folderview_select(folderview,item);
579 FolderView *folderview_create(void)
581 FolderView *folderview;
582 GtkWidget *scrolledwin;
585 debug_print("Creating folder view...\n");
586 folderview = g_new0(FolderView, 1);
588 scrolledwin = gtk_scrolled_window_new(NULL, NULL);
589 gtk_scrolled_window_set_policy
590 (GTK_SCROLLED_WINDOW(scrolledwin),
591 GTK_POLICY_AUTOMATIC,
592 prefs_common.folderview_vscrollbar_policy);
593 gtk_widget_set_size_request(scrolledwin,
594 prefs_common.folderview_width,
595 prefs_common.folderview_height);
597 folderview->scrolledwin = scrolledwin;
598 ctree = folderview_ctree_create(folderview);
600 /* create popup factories */
601 folderview->popups = g_hash_table_new(g_str_hash, g_str_equal);
602 g_hash_table_foreach(folderview_popups, create_ifactories, folderview);
604 folderview->ctree = ctree;
606 folderview->folder_update_callback_id =
607 hooks_register_hook(FOLDER_UPDATE_HOOKLIST, folderview_update_folder, (gpointer) folderview);
608 folderview->folder_item_update_callback_id =
609 hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST, folderview_update_item_claws, (gpointer) folderview);
611 gtk_widget_show_all(scrolledwin);
613 folderview->target_list = gtk_target_list_new(folderview_drag_types, 2);
614 folderview_list = g_list_append(folderview_list, folderview);
619 void folderview_init(FolderView *folderview)
621 GtkWidget *ctree = folderview->ctree;
624 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE, &inboxxpm, &inboxxpmmask);
625 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM, &inboxhrmxpm, &inboxhrmxpmmask);
626 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN, &inboxopenxpm, &inboxopenxpmmask);
627 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM, &inboxopenhrmxpm, &inboxopenhrmxpmmask);
628 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE, &outboxxpm, &outboxxpmmask);
629 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM, &outboxhrmxpm, &outboxhrmxpmmask);
630 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN, &outboxopenxpm, &outboxopenxpmmask);
631 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM, &outboxopenhrmxpm, &outboxopenhrmxpmmask);
632 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
633 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM, &folderhrmxpm, &folderhrmxpmmask);
634 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
635 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM, &folderopenhrmxpm, &folderopenhrmxpmmask);
636 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN, &trashopenxpm, &trashopenxpmmask);
637 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM, &trashopenhrmxpm, &trashopenhrmxpmmask);
638 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE, &trashxpm, &trashxpmmask);
639 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM, &trashhrmxpm, &trashhrmxpmmask);
640 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE, &queuexpm, &queuexpmmask);
641 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM, &queuehrmxpm, &queuehrmxpmmask);
642 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN, &queueopenxpm, &queueopenxpmmask);
643 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM, &queueopenhrmxpm, &queueopenhrmxpmmask);
644 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE, &draftsxpm, &draftsxpmmask);
645 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN, &draftsopenxpm, &draftsopenxpmmask);
646 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_NOSELECT, &noselectxpm, &noselectxpmmask);
648 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_MARK, &m_inboxxpm, &m_inboxxpmmask);
649 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM_MARK, &m_inboxhrmxpm, &m_inboxhrmxpmmask);
650 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_MARK, &m_inboxopenxpm, &m_inboxopenxpmmask);
651 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM_MARK, &m_inboxopenhrmxpm, &m_inboxopenhrmxpmmask);
652 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_MARK, &m_outboxxpm, &m_outboxxpmmask);
653 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM_MARK, &m_outboxhrmxpm, &m_outboxhrmxpmmask);
654 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_MARK, &m_outboxopenxpm, &m_outboxopenxpmmask);
655 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM_MARK, &m_outboxopenhrmxpm, &m_outboxopenhrmxpmmask);
656 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_MARK, &m_folderxpm, &m_folderxpmmask);
657 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM_MARK, &m_folderhrmxpm, &m_folderhrmxpmmask);
658 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_MARK, &m_folderopenxpm, &m_folderopenxpmmask);
659 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM_MARK, &m_folderopenhrmxpm, &m_folderopenhrmxpmmask);
660 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_MARK, &m_trashopenxpm, &m_trashopenxpmmask);
661 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM_MARK, &m_trashopenhrmxpm, &m_trashopenhrmxpmmask);
662 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_MARK, &m_trashxpm, &m_trashxpmmask);
663 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM_MARK, &m_trashhrmxpm, &m_trashhrmxpmmask);
664 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_MARK, &m_queuexpm, &m_queuexpmmask);
665 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM_MARK, &m_queuehrmxpm, &m_queuehrmxpmmask);
666 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_MARK, &m_queueopenxpm, &m_queueopenxpmmask);
667 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM_MARK, &m_queueopenhrmxpm, &m_queueopenhrmxpmmask);
668 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE_MARK, &m_draftsxpm, &m_draftsxpmmask);
669 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN_MARK, &m_draftsopenxpm, &m_draftsopenxpmmask);
672 PangoFontDescription *font_desc;
673 normal_style = gtk_style_copy(gtk_widget_get_style(ctree));
674 font_desc = pango_font_description_from_string(NORMAL_FONT);
676 if (normal_style->font_desc)
677 pango_font_description_free
678 (normal_style->font_desc);
679 normal_style->font_desc = font_desc;
681 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
682 normal_color_style = gtk_style_copy(normal_style);
683 normal_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
685 gtk_widget_set_style(ctree, normal_style);
689 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
690 bold_style = gtk_style_copy(gtk_widget_get_style(ctree));
691 pango_font_description_set_weight
692 (bold_style->font_desc, PANGO_WEIGHT_BOLD);
693 bold_color_style = gtk_style_copy(bold_style);
694 bold_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
696 bold_tgtfold_style = gtk_style_copy(bold_style);
697 bold_tgtfold_style->fg[GTK_STATE_NORMAL] = folderview->color_op;
701 void folderview_set(FolderView *folderview)
703 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
704 MainWindow *mainwin = folderview->mainwin;
709 debug_print("Setting folder info...\n");
710 STATUSBAR_PUSH(mainwin, _("Setting folder info..."));
712 main_window_cursor_wait(mainwin);
714 folderview->selected = NULL;
715 folderview->opened = NULL;
717 gtk_clist_freeze(GTK_CLIST(ctree));
718 gtk_clist_clear(GTK_CLIST(ctree));
719 gtk_clist_thaw(GTK_CLIST(ctree));
720 gtk_clist_freeze(GTK_CLIST(ctree));
722 folderview_set_folders(folderview);
724 gtk_clist_thaw(GTK_CLIST(ctree));
725 main_window_cursor_normal(mainwin);
726 STATUSBAR_POP(mainwin);
729 void folderview_set_all(void)
733 for (list = folderview_list; list != NULL; list = list->next)
734 folderview_set((FolderView *)list->data);
737 void folderview_select(FolderView *folderview, FolderItem *item)
739 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
741 GtkCTreeNode *old_selected = folderview->selected;
745 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
746 if (node) folderview_select_node(folderview, node);
748 if (old_selected != node)
749 folder_update_op_count();
752 static void mark_all_read_cb(FolderView *folderview, guint action,
758 item = folderview_get_selected_item(folderview);
762 if (folderview->summaryview->folder_item != item
763 && prefs_common.ask_mark_all_read) {
764 val = alertpanel_full(_("Mark all as read"),
765 _("Do you really want to mark all mails in this "
766 "folder as read ?"), GTK_STOCK_NO, GTK_STOCK_YES, NULL,
767 TRUE, NULL, ALERT_QUESTION, G_ALERTDEFAULT);
769 if ((val & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
771 else if (val & G_ALERTDISABLE)
772 prefs_common.ask_mark_all_read = FALSE;
775 summary_lock(folderview->summaryview);
776 folder_item_update_freeze();
777 if (folderview->summaryview->folder_item == item)
778 gtk_clist_freeze(GTK_CLIST(folderview->summaryview->ctree));
779 folderutils_mark_all_read(item);
780 if (folderview->summaryview->folder_item == item)
781 gtk_clist_thaw(GTK_CLIST(folderview->summaryview->ctree));
782 folder_item_update_thaw();
783 summary_unlock(folderview->summaryview);
786 static void folderview_select_node(FolderView *folderview, GtkCTreeNode *node)
788 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
790 g_return_if_fail(node != NULL);
792 if (folderview->open_folder) {
796 folderview->open_folder = TRUE;
797 gtkut_ctree_set_focus_row(ctree, node);
798 gtk_ctree_select(ctree, node);
799 if (folderview->summaryview->folder_item &&
800 folderview->summaryview->folder_item->total_msgs > 0)
801 gtk_widget_grab_focus(folderview->summaryview->ctree);
803 gtk_widget_grab_focus(folderview->ctree);
805 gtkut_ctree_expand_parent_all(ctree, node);
808 void folderview_unselect(FolderView *folderview)
810 if (folderview->opened && !GTK_CTREE_ROW(folderview->opened)->children)
812 (GTK_CTREE(folderview->ctree), folderview->opened);
814 folderview->selected = folderview->opened = NULL;
817 static GtkCTreeNode *folderview_find_next_marked(GtkCTree *ctree,
823 node = gtkut_ctree_node_next(ctree, node);
825 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
827 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
828 item = gtk_ctree_node_get_row_data(ctree, node);
829 if (item && item->marked_msgs > 0 && item->stype != F_TRASH)
836 void folderview_select_next_marked(FolderView *folderview)
838 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
839 GtkCTreeNode *node = NULL;
840 SelectOnEntry last_sel = prefs_common.select_on_entry;
841 gboolean last_open = prefs_common.always_show_msg;
843 prefs_common.select_on_entry = SELECTONENTRY_MNU;
844 prefs_common.always_show_msg = TRUE;
846 if ((node = folderview_find_next_marked(ctree, folderview->opened))
848 folderview_select_node(folderview, node);
852 if (!folderview->opened ||
853 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
856 /* search again from the first node */
857 if ((node = folderview_find_next_marked(ctree, NULL)) != NULL)
858 folderview_select_node(folderview, node);
861 prefs_common.select_on_entry = last_sel;
862 prefs_common.always_show_msg = last_open;
865 static GtkCTreeNode *folderview_find_next_unread(GtkCTree *ctree,
871 node = gtkut_ctree_node_next(ctree, node);
873 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
875 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
876 item = gtk_ctree_node_get_row_data(ctree, node);
877 if (item && item->unread_msgs > 0 && item->stype != F_TRASH)
884 void folderview_select_next_unread(FolderView *folderview, gboolean force_open)
886 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
887 GtkCTreeNode *node = NULL;
888 SelectOnEntry last_sel = prefs_common.select_on_entry;
889 gboolean last_open = prefs_common.always_show_msg;
891 prefs_common.select_on_entry = SELECTONENTRY_UNM;
892 prefs_common.always_show_msg = force_open ? TRUE : last_open;
894 if ((node = folderview_find_next_unread(ctree, folderview->opened))
896 folderview_select_node(folderview, node);
900 if (!folderview->opened ||
901 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
904 /* search again from the first node */
905 if ((node = folderview_find_next_unread(ctree, NULL)) != NULL)
906 folderview_select_node(folderview, node);
909 prefs_common.select_on_entry = last_sel;
910 prefs_common.always_show_msg = last_open;
913 static GtkCTreeNode *folderview_find_next_new(GtkCTree *ctree,
919 node = gtkut_ctree_node_next(ctree, node);
921 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
923 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
924 item = gtk_ctree_node_get_row_data(ctree, node);
925 if (item && item->new_msgs > 0 && item->stype != F_TRASH)
932 void folderview_select_next_new(FolderView *folderview)
934 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
935 GtkCTreeNode *node = NULL;
936 SelectOnEntry last_sel = prefs_common.select_on_entry;
937 gboolean last_open = prefs_common.always_show_msg;
939 prefs_common.select_on_entry = SELECTONENTRY_NUM;
940 prefs_common.always_show_msg = TRUE;
942 if ((node = folderview_find_next_new(ctree, folderview->opened))
944 folderview_select_node(folderview, node);
948 if (!folderview->opened ||
949 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
952 /* search again from the first node */
953 if ((node = folderview_find_next_new(ctree, NULL)) != NULL)
954 folderview_select_node(folderview, node);
957 prefs_common.select_on_entry = last_sel;
958 prefs_common.always_show_msg = last_open;
961 FolderItem *folderview_get_selected_item(FolderView *folderview)
963 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
965 if (!folderview->selected) return NULL;
966 return gtk_ctree_node_get_row_data(ctree, folderview->selected);
969 void folderview_update_msg_num(FolderView *folderview, GtkCTreeNode *row)
971 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
972 static GtkCTreeNode *prev_row = NULL;
974 gint new, unread, total;
975 gchar *new_str, *unread_str, *total_str;
976 gint *col_pos = folderview->col_pos;
980 item = gtk_ctree_node_get_row_data(ctree, row);
983 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_NEW], &new_str);
984 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_UNREAD], &unread_str);
985 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_TOTAL], &total_str);
987 unread = atoi(unread_str);
988 total = atoi(total_str);
992 folderview_update_node(folderview, row);
995 void folderview_append_item(FolderItem *item)
999 g_return_if_fail(item != NULL);
1000 g_return_if_fail(item->folder != NULL);
1001 if (folder_item_parent(item)) return;
1003 for (list = folderview_list; list != NULL; list = list->next) {
1004 FolderView *folderview = (FolderView *)list->data;
1005 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1006 GtkCTreeNode *node, *child;
1007 gint *col_pos = folderview->col_pos;
1009 node = gtk_ctree_find_by_row_data(ctree, NULL,
1010 folder_item_parent(item));
1012 child = gtk_ctree_find_by_row_data(ctree, node, item);
1014 gchar *text[N_FOLDER_COLS] =
1015 {NULL, "0", "0", "0"};
1017 gtk_clist_freeze(GTK_CLIST(ctree));
1019 text[col_pos[F_COL_FOLDER]] = item->name;
1020 child = gtk_sctree_insert_node
1021 (ctree, node, NULL, text,
1023 folderxpm, folderxpmmask,
1024 folderopenxpm, folderopenxpmmask,
1026 gtk_ctree_node_set_row_data(ctree, child, item);
1027 gtk_ctree_expand(ctree, node);
1028 folderview_update_node(folderview, child);
1029 folderview_sort_folders(folderview, node,
1032 gtk_clist_thaw(GTK_CLIST(ctree));
1038 static void folderview_set_folders(FolderView *folderview)
1041 #ifndef HAVE_LIBETPAN
1042 static gboolean missing_imap_warning = TRUE;
1044 list = folder_get_list();
1046 for (; list != NULL; list = list->next) {
1047 #ifndef HAVE_LIBETPAN
1048 if ((FOLDER(list->data))
1049 && (FOLDER(list->data))->klass
1050 && (FOLDER(list->data))->klass->type == F_IMAP
1051 && missing_imap_warning) {
1052 missing_imap_warning = FALSE;
1054 _("You have one or more IMAP accounts "
1055 "defined. However this version of "
1056 "Sylpheed-Claws has been built without "
1057 "IMAP support; your IMAP account(s) are "
1059 "You probably need to "
1060 "install libetpan and recompile "
1061 "Sylpheed-Claws."));
1064 folderview_append_folder(folderview, FOLDER(list->data));
1068 static gchar *get_scan_str(FolderItem *item)
1071 return g_strdup_printf(_("Scanning folder %s%c%s ..."),
1072 item->folder->name, G_DIR_SEPARATOR,
1075 return g_strdup_printf(_("Scanning folder %s ..."),
1076 item->folder->name);
1078 static void folderview_scan_tree_func(Folder *folder, FolderItem *item,
1082 for (list = folderview_list; list != NULL; list = list->next) {
1083 FolderView *folderview = (FolderView *)list->data;
1084 MainWindow *mainwin = folderview->mainwin;
1085 gchar *str = get_scan_str(item);
1087 STATUSBAR_PUSH(mainwin, str);
1088 STATUSBAR_POP(mainwin);
1093 void folderview_rescan_tree(Folder *folder, gboolean rebuild)
1097 g_return_if_fail(folder != NULL);
1099 if (!folder->klass->scan_tree) return;
1102 alertpanel_full(_("Rebuild folder tree"),
1103 _("Rebuilding the folder tree will remove "
1104 "local caches. Do you want to continue?"),
1105 GTK_STOCK_NO, GTK_STOCK_YES, NULL, FALSE,
1106 NULL, ALERT_WARNING, G_ALERTDEFAULT)
1107 != G_ALERTALTERNATE) {
1113 window = label_window_create(_("Rebuilding folder tree..."));
1115 window = label_window_create(_("Scanning folder tree..."));
1117 folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
1118 folder_scan_tree(folder, rebuild);
1119 folder_set_ui_func(folder, NULL, NULL);
1121 folderview_set_all();
1123 gtk_widget_destroy(window);
1127 /** folderview_check_new()
1128 * Scan and update the folder and return the
1129 * count the number of new messages since last check.
1130 * \param folder the folder to check for new messages
1131 * \return the number of new messages since last check
1133 gint folderview_check_new(Folder *folder)
1137 FolderView *folderview;
1141 gint former_new_msgs = 0;
1142 gint former_new = 0, former_unread = 0, former_total;
1144 for (list = folderview_list; list != NULL; list = list->next) {
1145 folderview = (FolderView *)list->data;
1146 ctree = GTK_CTREE(folderview->ctree);
1149 main_window_lock(folderview->mainwin);
1151 for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
1152 node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
1154 item = gtk_ctree_node_get_row_data(ctree, node);
1155 if (!item || !item->path || !item->folder) continue;
1156 if (item->no_select) continue;
1157 if (folder && folder != item->folder) continue;
1158 if (!folder && !FOLDER_IS_LOCAL(item->folder)) continue;
1159 if (!item->prefs->newmailcheck) continue;
1160 if (item->processing_pending == TRUE) {
1161 debug_print("skipping %s, processing pending\n",
1162 item->path ? item->path : item->name);
1166 str = get_scan_str(item);
1168 STATUSBAR_PUSH(folderview->mainwin, str);
1172 folderview_scan_tree_func(item->folder, item, NULL);
1173 former_new = item->new_msgs;
1174 former_unread = item->unread_msgs;
1175 former_total = item->total_msgs;
1177 if (item->folder->klass->scan_required &&
1178 (item->folder->klass->scan_required(item->folder, item) ||
1179 item->folder->inbox == item ||
1180 item->opened == TRUE ||
1181 item->processing_pending == TRUE)) {
1182 if (folder_item_scan(item) < 0) {
1183 summaryview_unlock(folderview->summaryview, item);
1184 if (folder && !FOLDER_IS_LOCAL(folder)) {
1185 STATUSBAR_POP(folderview->mainwin);
1189 } else if (!item->folder->klass->scan_required) {
1190 if (folder_item_scan(item) < 0) {
1191 summaryview_unlock(folderview->summaryview, item);
1192 if (folder && !FOLDER_IS_LOCAL(folder)) {
1193 STATUSBAR_POP(folderview->mainwin);
1198 if (former_new != item->new_msgs ||
1199 former_unread != item->unread_msgs ||
1200 former_total != item->total_msgs)
1201 folderview_update_node(folderview, node);
1203 new_msgs += item->new_msgs;
1204 former_new_msgs += former_new;
1205 STATUSBAR_POP(folderview->mainwin);
1208 main_window_unlock(folderview->mainwin);
1212 folder_write_list();
1213 /* Number of new messages since last check is the just the difference
1214 * between former_new_msgs and new_msgs. If new_msgs is less than
1215 * former_new_msgs, that would mean another session accessed the folder
1216 * and the result is not well defined.
1218 new_msgs = (former_new_msgs < new_msgs ? new_msgs - former_new_msgs : 0);
1222 void folderview_check_new_all(void)
1226 FolderView *folderview;
1228 folderview = (FolderView *)folderview_list->data;
1231 main_window_lock(folderview->mainwin);
1232 window = label_window_create
1233 (_("Checking for new messages in all folders..."));
1235 list = folder_get_list();
1236 for (; list != NULL; list = list->next) {
1237 Folder *folder = list->data;
1239 folderview_check_new(folder);
1242 folder_write_list();
1243 folderview_set_all();
1245 gtk_widget_destroy(window);
1246 main_window_unlock(folderview->mainwin);
1250 static gboolean folderview_have_new_children_sub(FolderView *folderview,
1256 if (!item || !item->folder || !item->folder->node)
1259 node = item->folder->node;
1261 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1262 node = node->children;
1265 (item->new_msgs > 0 ||
1266 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1270 while (node != NULL) {
1271 if (node && node->data) {
1272 FolderItem *next_item = (FolderItem*) node->data;
1274 if (folderview_have_new_children_sub(folderview,
1283 static gboolean folderview_have_new_children(FolderView *folderview,
1286 return folderview_have_new_children_sub(folderview, item, FALSE);
1289 static gboolean folderview_have_unread_children_sub(FolderView *folderview,
1295 if (!item || !item->folder || !item->folder->node)
1298 node = item->folder->node;
1300 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1301 node = node->children;
1304 (item->unread_msgs > 0 ||
1305 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1309 while (node != NULL) {
1310 if (node && node->data) {
1311 FolderItem *next_item = (FolderItem*) node->data;
1313 if (folderview_have_unread_children_sub(folderview,
1323 static gboolean folderview_have_unread_children(FolderView *folderview,
1326 return folderview_have_unread_children_sub(folderview, item, FALSE);
1329 static gboolean folderview_have_matching_children_sub(FolderView *folderview,
1335 if (!item || !item->folder || !item->folder->node)
1338 node = item->folder->node;
1340 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1341 node = node->children;
1343 if (in_sub && item->search_match){
1347 while (node != NULL) {
1348 if (node && node->data) {
1349 FolderItem *next_item = (FolderItem*) node->data;
1351 if (folderview_have_matching_children_sub(folderview,
1361 static gboolean folderview_have_matching_children(FolderView *folderview,
1364 return folderview_have_matching_children_sub(folderview, item, FALSE);
1367 static gboolean folderview_have_marked_children_sub(FolderView *folderview,
1373 if (!item || !item->folder || !item->folder->node)
1376 node = item->folder->node;
1378 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1379 node = node->children;
1381 if (item->marked_msgs != 0) {
1385 while (node != NULL) {
1386 if (node && node->data) {
1387 FolderItem *next_item = (FolderItem*) node->data;
1389 if (folderview_have_marked_children_sub(folderview,
1398 static gboolean folderview_have_marked_children(FolderView *folderview,
1401 return folderview_have_marked_children_sub(folderview, item, FALSE);
1404 static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node)
1406 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1407 GtkStyle *style = NULL;
1408 GtkStyle *color_style = NULL;
1410 GdkPixmap *xpm, *openxpm;
1411 GdkBitmap *mask, *openmask;
1412 static GdkPixmap *searchicon;
1413 static GdkBitmap *searchmask;
1414 gboolean mark = FALSE;
1417 gboolean add_unread_mark;
1418 gboolean add_sub_match_mark;
1419 gboolean use_bold, use_color;
1420 gint *col_pos = folderview->col_pos;
1421 SpecialFolderItemType stype;
1423 item = gtk_ctree_node_get_row_data(ctree, node);
1424 g_return_if_fail(item != NULL);
1426 if (!GTK_CTREE_ROW(node)->expanded)
1427 mark = folderview_have_marked_children(folderview, item);
1429 mark = (item->marked_msgs != 0);
1431 stype = item->stype;
1432 if (stype == F_NORMAL) {
1433 if (folder_has_parent_of_type(item, F_TRASH))
1435 else if (folder_has_parent_of_type(item, F_DRAFT))
1437 else if (folder_has_parent_of_type(item, F_OUTBOX))
1439 else if (folder_has_parent_of_type(item, F_QUEUE))
1444 if (item->hide_read_msgs) {
1445 xpm = mark?m_inboxhrmxpm:inboxhrmxpm;
1446 mask = mark?m_inboxhrmxpmmask:inboxhrmxpmmask;
1447 openxpm = mark?m_inboxopenhrmxpm:inboxopenhrmxpm;
1448 openmask = mark?m_inboxopenhrmxpmmask:inboxopenhrmxpmmask;
1450 xpm = mark?m_inboxxpm:inboxxpm;
1451 mask = mark?m_inboxxpmmask:inboxxpmmask;
1452 openxpm = mark?m_inboxopenxpm:inboxopenxpm;
1453 openmask = mark?m_inboxopenxpmmask:inboxopenxpmmask;
1457 if (item->hide_read_msgs) {
1458 xpm = mark?m_outboxhrmxpm:outboxhrmxpm;
1459 mask = mark?m_outboxhrmxpmmask:outboxhrmxpmmask;
1460 openxpm = mark?m_outboxopenhrmxpm:outboxopenhrmxpm;
1461 openmask = mark?m_outboxopenhrmxpmmask:outboxopenhrmxpmmask;
1463 xpm = mark?m_outboxxpm:outboxxpm;
1464 mask = mark?m_outboxxpmmask:outboxxpmmask;
1465 openxpm = mark?m_outboxopenxpm:outboxopenxpm;
1466 openmask = mark?m_outboxopenxpmmask:outboxopenxpmmask;
1470 if (item->hide_read_msgs) {
1471 xpm = mark?m_queuehrmxpm:queuehrmxpm;
1472 mask = mark?m_queuehrmxpmmask:queuehrmxpmmask;
1473 openxpm = mark?m_queueopenhrmxpm:queueopenhrmxpm;
1474 openmask = mark?m_queueopenhrmxpmmask:queueopenhrmxpmmask;
1476 xpm = mark?m_queuexpm:queuexpm;
1477 mask = mark?m_queuexpmmask:queuexpmmask;
1478 openxpm = mark?m_queueopenxpm:queueopenxpm;
1479 openmask = mark?m_queueopenxpmmask:queueopenxpmmask;
1483 if (item->hide_read_msgs) {
1484 xpm = mark?m_trashhrmxpm:trashhrmxpm;
1485 mask = mark?m_trashhrmxpmmask:trashhrmxpmmask;
1486 openxpm = mark?m_trashopenhrmxpm:trashopenhrmxpm;
1487 openmask = mark?m_trashopenhrmxpmmask:trashopenhrmxpmmask;
1489 xpm = mark?m_trashxpm:trashxpm;
1490 mask = mark?m_trashxpmmask:trashxpmmask;
1491 openxpm = mark?m_trashopenxpm:trashopenxpm;
1492 openmask = mark?m_trashopenxpmmask:trashopenxpmmask;
1496 xpm = mark?m_draftsxpm:draftsxpm;
1497 mask = mark?m_draftsxpmmask:draftsxpmmask;
1498 openxpm = mark?m_draftsopenxpm:draftsopenxpm;
1499 openmask = mark?m_draftsopenxpmmask:draftsopenxpmmask;
1502 if (item->hide_read_msgs) {
1503 xpm = mark?m_folderhrmxpm:folderhrmxpm;
1504 mask = mark?m_folderhrmxpmmask:folderhrmxpmmask;
1505 openxpm = mark?m_folderopenhrmxpm:folderopenhrmxpm;
1506 openmask = mark?m_folderopenhrmxpmmask:folderopenhrmxpmmask;
1508 xpm = mark?m_folderxpm:folderxpm;
1509 mask = mark?m_folderxpmmask:folderxpmmask;
1510 openxpm = mark?m_folderopenxpm:folderopenxpm;
1511 openmask = mark?m_folderopenxpmmask:folderopenxpmmask;
1515 if (item->no_select) {
1516 xpm = openxpm = noselectxpm;
1517 mask = openmask = noselectxpmmask;
1520 name = folder_item_get_name(item);
1522 if (!GTK_CTREE_ROW(node)->expanded) {
1523 add_unread_mark = folderview_have_unread_children(
1525 add_sub_match_mark = folderview_have_matching_children(
1528 add_unread_mark = FALSE;
1529 add_sub_match_mark = FALSE;
1532 if (item->search_match) {
1534 stock_pixmap_gdk(folderview->ctree, STOCK_PIXMAP_QUICKSEARCH,
1535 &searchicon, &searchmask);
1537 xpm = openxpm = searchicon;
1538 mask = openmask = searchmask;
1541 if (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0 &&
1542 prefs_common.display_folder_unread) {
1543 str = g_strdup_printf("%s (%d%s)", name, item->total_msgs,
1544 add_unread_mark ? "+" : "");
1545 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1546 xpm, mask, openxpm, openmask,
1547 FALSE, GTK_CTREE_ROW(node)->expanded);
1549 } else if (((item->unread_msgs > 0 || add_unread_mark) &&
1550 prefs_common.display_folder_unread)
1551 || add_sub_match_mark) {
1553 if (item->unread_msgs > 0)
1554 str = g_strdup_printf("%s (%d%s%s)", name, item->unread_msgs,
1555 add_unread_mark || add_sub_match_mark ? "+" : "",
1556 item->unreadmarked_msgs > 0 ? "!":"");
1558 str = g_strdup_printf("%s (+)", name);
1559 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1560 xpm, mask, openxpm, openmask,
1561 FALSE, GTK_CTREE_ROW(node)->expanded);
1564 str = g_strdup_printf("%s%s", name,
1565 item->unreadmarked_msgs > 0 ? " (!)":"");
1567 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1568 xpm, mask, openxpm, openmask,
1569 FALSE, GTK_CTREE_ROW(node)->expanded);
1574 if (!folder_item_parent(item)) {
1575 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], "-");
1576 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], "-");
1577 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], "-");
1579 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], itos(item->new_msgs));
1580 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], itos(item->unread_msgs));
1581 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], itos(item->total_msgs));
1584 if (folder_has_parent_of_type(item, F_OUTBOX) ||
1585 folder_has_parent_of_type(item, F_DRAFT) ||
1586 folder_has_parent_of_type(item, F_TRASH)) {
1587 use_bold = use_color = FALSE;
1588 } else if (folder_has_parent_of_type(item, F_QUEUE)) {
1589 /* highlight queue folder if there are any messages */
1590 use_bold = use_color = (item->total_msgs > 0);
1592 /* if unread messages exist, print with bold font */
1593 use_bold = (item->unread_msgs > 0|| item->new_msgs > 0)
1595 /* if new messages exist, print with colored letter */
1597 (item->new_msgs > 0) ||
1599 folderview_have_new_children(folderview, item));
1602 gtk_ctree_node_set_foreground(ctree, node, NULL);
1607 if (item->prefs->color > 0 && !use_color) {
1608 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1609 color_style = gtk_style_copy(bold_style);
1610 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1611 style = color_style;
1612 } else if (use_color) {
1613 style = bold_color_style;
1616 if (item->op_count > 0) {
1617 style = bold_tgtfold_style;
1619 } else if (use_color) {
1620 style = normal_color_style;
1621 gtk_ctree_node_set_foreground(ctree, node,
1622 &folderview->color_new);
1623 } else if (item->op_count > 0) {
1624 style = bold_tgtfold_style;
1625 } else if (item->prefs->color > 0) {
1627 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1628 color_style = gtk_style_copy(normal_style);
1629 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1630 style = color_style;
1632 style = normal_style;
1635 gtk_ctree_node_set_row_style(ctree, node, style);
1637 if ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
1638 folderview_update_node(folderview, node);
1641 #if !CLAWS /* keep it here for syncs */
1642 void folderview_update_item(FolderItem *item, gboolean update_summary)
1645 FolderView *folderview;
1649 g_return_if_fail(item != NULL);
1651 for (list = folderview_list; list != NULL; list = list->next) {
1652 folderview = (FolderView *)list->data;
1653 ctree = GTK_CTREE(folderview->ctree);
1655 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1657 folderview_update_node(folderview, node);
1658 if (update_summary && folderview->opened == node)
1659 summary_show(folderview->summaryview,
1666 void folderview_update_search_icon(FolderItem *item, gboolean matches)
1669 FolderView *folderview;
1673 g_return_if_fail(item != NULL);
1675 for (list = folderview_list; list != NULL; list = list->next) {
1676 folderview = (FolderView *)list->data;
1677 ctree = GTK_CTREE(folderview->ctree);
1679 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1681 item->search_match = matches;
1682 folderview_update_node(folderview, node);
1687 gboolean folderview_update_item_claws(gpointer source, gpointer data)
1689 FolderItemUpdateData *update_info = (FolderItemUpdateData *)source;
1690 FolderView *folderview = (FolderView *)data;
1693 g_return_val_if_fail(update_info != NULL, TRUE);
1694 g_return_val_if_fail(update_info->item != NULL, TRUE);
1695 g_return_val_if_fail(folderview != NULL, FALSE);
1697 ctree = GTK_CTREE(folderview->ctree);
1699 node = gtk_ctree_find_by_row_data(ctree, NULL, update_info->item);
1701 if (update_info->update_flags & (F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_NAME))
1702 folderview_update_node(folderview, node);
1703 if ((update_info->update_flags & F_ITEM_UPDATE_CONTENT) && (folderview->opened == node))
1704 if (!quicksearch_is_active(folderview->summaryview->quicksearch))
1705 summary_show(folderview->summaryview, update_info->item);
1711 static void folderview_update_item_foreach_func(gpointer key, gpointer val,
1714 /* CLAWS: share this joy with other hook functions ... */
1715 folder_item_update((FolderItem *)key,
1716 (FolderItemUpdateFlags)GPOINTER_TO_INT(data));
1719 void folderview_update_item_foreach(GHashTable *table, gboolean update_summary)
1722 FolderItemUpdateFlags flags;
1724 flags = update_summary ? F_ITEM_UPDATE_CONTENT | F_ITEM_UPDATE_MSGCNT
1726 for (list = folderview_list; list != NULL; list = list->next)
1727 g_hash_table_foreach(table, folderview_update_item_foreach_func,
1728 GINT_TO_POINTER(flags));
1731 static gboolean folderview_gnode_func(GtkCTree *ctree, guint depth,
1732 GNode *gnode, GtkCTreeNode *cnode,
1735 FolderView *folderview = (FolderView *)data;
1736 FolderItem *item = FOLDER_ITEM(gnode->data);
1738 g_return_val_if_fail(item != NULL, FALSE);
1740 gtk_ctree_node_set_row_data(ctree, cnode, item);
1741 folderview_update_node(folderview, cnode);
1746 static void folderview_expand_func(GtkCTree *ctree, GtkCTreeNode *node,
1749 FolderView *folderview = (FolderView *)data;
1752 if (GTK_CTREE_ROW(node)->children) {
1753 item = gtk_ctree_node_get_row_data(ctree, node);
1754 g_return_if_fail(item != NULL);
1756 if (!item->collapsed)
1757 gtk_ctree_expand(ctree, node);
1759 folderview_update_node(folderview, node);
1763 static void set_special_folder(GtkCTree *ctree, FolderItem *item,
1764 GtkCTreeNode *root, GtkCTreeNode **prev)
1767 GtkCTreeNode *node, *parent, *sibling;
1769 node = gtk_ctree_find_by_row_data(ctree, root, item);
1771 g_warning("%s not found.\n", item->path);
1773 parent = GTK_CTREE_ROW(node)->parent;
1774 if (*prev && parent == GTK_CTREE_ROW(*prev)->parent)
1775 sibling = GTK_CTREE_ROW(*prev)->sibling;
1777 sibling = GTK_CTREE_ROW(parent)->children;
1781 tmp = gtk_ctree_node_get_row_data
1783 if (tmp->stype != F_NORMAL)
1784 sibling = GTK_CTREE_ROW(sibling)->sibling;
1788 if (node != sibling)
1789 gtk_ctree_move(ctree, node, parent, sibling);
1796 static void folderview_sort_folders(FolderView *folderview, GtkCTreeNode *root,
1799 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1800 GtkCTreeNode *prev = NULL;
1802 gtk_clist_freeze(GTK_CLIST(ctree));
1803 gtk_sctree_sort_recursive(ctree, root);
1804 if (root && GTK_CTREE_ROW(root)->parent) {
1805 gtk_clist_thaw(GTK_CLIST(ctree));
1808 set_special_folder(ctree, folder->inbox, root, &prev);
1809 set_special_folder(ctree, folder->outbox, root, &prev);
1810 set_special_folder(ctree, folder->draft, root, &prev);
1811 set_special_folder(ctree, folder->queue, root, &prev);
1812 set_special_folder(ctree, folder->trash, root, &prev);
1813 gtk_clist_thaw(GTK_CLIST(ctree));
1816 static void folderview_append_folder(FolderView *folderview, Folder *folder)
1818 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1821 g_return_if_fail(folder != NULL);
1823 root = gtk_sctree_insert_gnode(ctree, NULL, NULL, folder->node,
1824 folderview_gnode_func, folderview);
1825 gtk_ctree_pre_recursive(ctree, root, folderview_expand_func,
1827 folderview_sort_folders(folderview, root, folder);
1830 /* callback functions */
1831 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
1832 GdkEventButton *event)
1834 GtkCList *clist = GTK_CLIST(folderview->ctree);
1837 FolderViewPopup *fpopup;
1838 GtkItemFactory *fpopup_factory;
1840 FolderItem *special_trash = NULL, *special_queue = NULL;
1844 item = gtk_clist_get_row_data(clist, row);
1846 item = folderview_get_selected_item(folderview);
1848 g_return_if_fail(item != NULL);
1849 g_return_if_fail(item->folder != NULL);
1850 folder = item->folder;
1852 fpopup = g_hash_table_lookup(folderview_popups, folder->klass->idstr);
1854 fpopup_factory = g_hash_table_lookup(folderview->popups, folder->klass->idstr);
1856 fpopup = g_hash_table_lookup(folderview_popups, "common");
1857 fpopup_factory = g_hash_table_lookup(folderview->popups, "common");
1860 if (fpopup->set_sensitivity != NULL)
1861 fpopup->set_sensitivity(fpopup_factory, item);
1863 if (NULL != (ac = account_find_from_item(item))) {
1864 special_trash = account_get_special_folder(ac, F_TRASH);
1865 special_queue = account_get_special_folder(ac, F_QUEUE);
1868 if ((item == folder->trash || item == special_trash
1869 || folder_has_parent_of_type(item, F_TRASH)) &&
1870 gtk_item_factory_get_item(fpopup_factory, "/Empty trash...") == NULL) {
1871 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[0], folderview, 1);
1872 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[1], folderview, 1);
1873 } else if (item != folder->trash && (special_trash == NULL || item != special_trash)
1874 && !folder_has_parent_of_type(item, F_TRASH)) {
1875 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[0]);
1876 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[1]);
1879 if ((item == folder->queue || item == special_queue
1880 || folder_has_parent_of_type(item, F_QUEUE)) &&
1881 gtk_item_factory_get_item(fpopup_factory, "/Send queue...") == NULL) {
1882 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[0], folderview, 1);
1883 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[1], folderview, 1);
1884 } else if (item != folder->queue && (special_queue == NULL || item != special_queue)
1885 && !folder_has_parent_of_type(item, F_QUEUE)) {
1886 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[0]);
1887 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[1]);
1890 #define SET_SENS(name, sens) \
1891 menu_set_sensitive(fpopup_factory, name, sens)
1893 SET_SENS("/Mark all read", item->unread_msgs >= 1);
1894 SET_SENS("/Search folder...", item->total_msgs >= 1 &&
1895 folderview->selected == folderview->opened);
1896 SET_SENS("/Properties...", TRUE);
1897 SET_SENS("/Processing...", item->node->parent != NULL);
1898 if (item == folder->trash || item == special_trash
1899 || folder_has_parent_of_type(item, F_TRASH)) {
1900 GSList *msglist = folder_item_get_msg_list(item);
1901 SET_SENS("/Empty trash...", msglist != NULL);
1902 procmsg_msg_list_free(msglist);
1904 if (item == folder->queue || item == special_queue
1905 || folder_has_parent_of_type(item, F_QUEUE)) {
1906 GSList *msglist = folder_item_get_msg_list(item);
1907 SET_SENS("/Send queue...", msglist != NULL);
1908 procmsg_msg_list_free(msglist);
1912 popup = gtk_item_factory_get_widget(fpopup_factory, fpopup->path);
1913 gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
1914 event->button, event->time);
1919 static gboolean folderview_button_pressed(GtkWidget *ctree, GdkEventButton *event,
1920 FolderView *folderview)
1922 GtkCList *clist = GTK_CLIST(ctree);
1923 gint prev_row = -1, row = -1, column = -1;
1925 if (!event) return FALSE;
1927 if (event->button == 1 || event->button == 2) {
1928 folderview->open_folder = TRUE;
1930 if (event->type == GDK_2BUTTON_PRESS) {
1931 if (clist->selection) {
1934 node = GTK_CTREE_NODE(clist->selection->data);
1936 gtk_ctree_toggle_expansion(
1944 if (event->button == 2 || event->button == 3) {
1946 if (clist->selection) {
1949 node = GTK_CTREE_NODE(clist->selection->data);
1951 prev_row = gtkut_ctree_get_nth_from_node
1952 (GTK_CTREE(ctree), node);
1955 if (!gtk_clist_get_selection_info(clist, event->x, event->y,
1958 if (prev_row != row) {
1959 gtk_clist_unselect_all(clist);
1960 if (event->button == 2)
1961 folderview_select_node
1963 gtk_ctree_node_nth(GTK_CTREE(ctree),
1966 gtk_clist_select_row(clist, row, column);
1970 if (event->button != 3) return FALSE;
1972 folderview_set_sens_and_popup_menu(folderview, row, event);
1976 static gboolean folderview_button_released(GtkWidget *ctree, GdkEventButton *event,
1977 FolderView *folderview)
1979 if (!event) return FALSE;
1981 if (event->button == 1 && folderview->open_folder == FALSE &&
1982 folderview->opened != NULL) {
1983 gtkut_ctree_set_focus_row(GTK_CTREE(ctree),
1984 folderview->opened);
1985 gtk_ctree_select(GTK_CTREE(ctree), folderview->opened);
1991 static gboolean folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
1992 FolderView *folderview)
1994 if (!event) return FALSE;
1996 if (quicksearch_has_focus(folderview->summaryview->quicksearch))
1999 switch (event->keyval) {
2001 if (folderview->selected) {
2002 folderview_select_node(folderview,
2003 folderview->selected);
2007 if (folderview->selected) {
2008 if (folderview->opened == folderview->selected &&
2009 (!folderview->summaryview->folder_item ||
2010 folderview->summaryview->folder_item->total_msgs == 0))
2011 folderview_select_next_unread(folderview, TRUE);
2013 folderview_select_node(folderview,
2014 folderview->selected);
2024 typedef struct _PostponedSelectData
2029 FolderView *folderview;
2030 } PostponedSelectData;
2032 static gboolean postpone_select(void *data)
2034 PostponedSelectData *psdata = (PostponedSelectData *)data;
2035 debug_print("trying again\n");
2036 psdata->folderview->open_folder = TRUE;
2037 main_window_cursor_normal(psdata->folderview->mainwin);
2038 STATUSBAR_POP(psdata->folderview->mainwin);
2039 folderview_selected(psdata->ctree, psdata->row,
2040 psdata->column, psdata->folderview);
2045 static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row,
2046 gint column, FolderView *folderview)
2048 static gboolean can_select = TRUE; /* exclusive lock */
2053 START_TIMING("--- folderview_selected");
2054 folderview->selected = row;
2056 if (folderview->opened == row) {
2057 folderview->open_folder = FALSE;
2062 if (!can_select || summary_is_locked(folderview->summaryview)) {
2063 if (folderview->opened) {
2064 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2065 gtk_ctree_select(ctree, folderview->opened);
2071 if (!folderview->open_folder) {
2075 item = gtk_ctree_node_get_row_data(ctree, row);
2076 if (!item || item->no_select) {
2083 /* Save cache for old folder */
2084 /* We don't want to lose all caches if sylpheed crashed */
2085 if (folderview->opened) {
2086 FolderItem *olditem;
2088 olditem = gtk_ctree_node_get_row_data(ctree, folderview->opened);
2090 buf = g_strdup_printf(_("Closing Folder %s..."),
2091 olditem->path ? olditem->path:olditem->name);
2092 /* will be null if we just moved the previously opened folder */
2093 STATUSBAR_PUSH(folderview->mainwin, buf);
2094 main_window_cursor_wait(folderview->mainwin);
2096 summary_save_prefs_to_folderitem(folderview->summaryview, olditem);
2097 summary_show(folderview->summaryview, NULL);
2098 folder_item_close(olditem);
2099 main_window_cursor_normal(folderview->mainwin);
2100 STATUSBAR_POP(folderview->mainwin);
2104 /* CLAWS: set compose button type: news folder items
2105 * always have a news folder as parent */
2107 toolbar_set_compose_button
2108 (folderview->mainwin->toolbar,
2109 FOLDER_TYPE(item->folder) == F_NEWS ?
2110 COMPOSEBUTTON_NEWS : COMPOSEBUTTON_MAIL);
2113 debug_print("Folder %s is selected\n", item->path);
2115 if (!GTK_CTREE_ROW(row)->children)
2116 gtk_ctree_expand(ctree, row);
2117 if (folderview->opened &&
2118 !GTK_CTREE_ROW(folderview->opened)->children)
2119 gtk_ctree_collapse(ctree, folderview->opened);
2121 /* ungrab the mouse event */
2122 if (GTK_WIDGET_HAS_GRAB(ctree)) {
2123 gtk_grab_remove(GTK_WIDGET(ctree));
2124 if (gdk_pointer_is_grabbed())
2125 gdk_pointer_ungrab(GDK_CURRENT_TIME);
2129 buf = g_strdup_printf(_("Opening Folder %s..."), item->path ?
2130 item->path : "(null)");
2131 debug_print("%s\n", buf);
2132 STATUSBAR_PUSH(folderview->mainwin, buf);
2135 main_window_cursor_wait(folderview->mainwin);
2137 res = folder_item_open(item);
2139 main_window_cursor_normal(folderview->mainwin);
2140 STATUSBAR_POP(folderview->mainwin);
2142 alertpanel_error(_("Folder could not be opened."));
2144 folderview->open_folder = FALSE;
2148 } else if (res == -2) {
2149 PostponedSelectData *data = g_new0(PostponedSelectData, 1);
2150 data->ctree = ctree;
2152 data->column = column;
2153 data->folderview = folderview;
2154 debug_print("postponing open of %s till end of scan\n",
2155 item->path ? item->path:item->name);
2156 folderview->open_folder = FALSE;
2158 g_timeout_add(500, postpone_select, data);
2163 main_window_cursor_normal(folderview->mainwin);
2166 summary_set_prefs_from_folderitem(folderview->summaryview, item);
2167 opened = summary_show(folderview->summaryview, item);
2169 folder_clean_cache_memory(item);
2172 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2173 gtk_ctree_select(ctree, folderview->opened);
2175 folderview->opened = row;
2176 if (gtk_ctree_node_is_visible(ctree, row)
2177 != GTK_VISIBILITY_FULL)
2178 gtk_ctree_node_moveto(ctree, row, -1, 0.5, 0);
2181 STATUSBAR_POP(folderview->mainwin);
2183 folderview->open_folder = FALSE;
2188 static void folderview_tree_expanded(GtkCTree *ctree, GtkCTreeNode *node,
2189 FolderView *folderview)
2193 item = gtk_ctree_node_get_row_data(ctree, node);
2194 g_return_if_fail(item != NULL);
2195 item->collapsed = FALSE;
2196 folderview_update_node(folderview, node);
2199 static void folderview_tree_collapsed(GtkCTree *ctree, GtkCTreeNode *node,
2200 FolderView *folderview)
2204 item = gtk_ctree_node_get_row_data(ctree, node);
2205 g_return_if_fail(item != NULL);
2206 item->collapsed = TRUE;
2207 folderview_update_node(folderview, node);
2210 static void folderview_popup_close(GtkMenuShell *menu_shell,
2211 FolderView *folderview)
2213 if (!folderview->opened) return;
2215 gtk_ctree_select(GTK_CTREE(folderview->ctree), folderview->opened);
2218 static void folderview_col_resized(GtkCList *clist, gint column, gint width,
2219 FolderView *folderview)
2221 FolderColumnType type = folderview->col_state[column].type;
2223 prefs_common.folder_col_size[type] = width;
2226 void folderview_create_folder_node_recursive(FolderView *folderview, FolderItem *item)
2230 folderview_create_folder_node(folderview, item);
2232 if (!item || !item->folder || !item->folder->node)
2235 srcnode = item->folder->node;
2236 srcnode = g_node_find(srcnode, G_PRE_ORDER, G_TRAVERSE_ALL, item);
2237 srcnode = srcnode->children;
2238 while (srcnode != NULL) {
2239 if (srcnode && srcnode->data) {
2240 FolderItem *next_item = (FolderItem*) srcnode->data;
2241 folderview_create_folder_node_recursive(folderview, next_item);
2243 srcnode = srcnode->next;
2247 void folderview_create_folder_node(FolderView *folderview, FolderItem *item)
2249 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2250 gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
2251 GtkCTreeNode *node, *parent_node;
2252 gint *col_pos = folderview->col_pos;
2253 FolderItemUpdateData hookdata;
2255 parent_node = gtk_ctree_find_by_row_data(ctree, NULL, folder_item_parent(item));
2256 if (parent_node == NULL)
2259 gtk_clist_freeze(GTK_CLIST(ctree));
2261 text[col_pos[F_COL_FOLDER]] = item->name;
2262 node = gtk_sctree_insert_node(ctree, parent_node, NULL, text,
2264 folderxpm, folderxpmmask,
2265 folderopenxpm, folderopenxpmmask,
2267 gtk_ctree_expand(ctree, parent_node);
2268 gtk_ctree_node_set_row_data(ctree, node, item);
2270 gtk_ctree_node_set_row_style(ctree, node, normal_style);
2271 folderview_sort_folders(folderview, parent_node, item->folder);
2273 hookdata.item = item;
2274 hookdata.update_flags = F_ITEM_UPDATE_NAME;
2275 hookdata.msg = NULL;
2276 hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &hookdata);
2278 gtk_clist_thaw(GTK_CLIST(ctree));
2281 static void folderview_empty_trash_cb(FolderView *folderview, guint action,
2284 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2286 GSList *mlist = NULL;
2288 FolderItem *special_trash = NULL;
2291 if (!folderview->selected) return;
2292 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2293 g_return_if_fail(item != NULL);
2294 g_return_if_fail(item->folder != NULL);
2296 if (NULL != (ac = account_find_from_item(item)))
2297 special_trash = account_get_special_folder(ac, F_TRASH);
2299 if (item != item->folder->trash && item != special_trash
2300 && !folder_has_parent_of_type(item, F_TRASH)) return;
2302 if (prefs_common.ask_on_clean) {
2303 if (alertpanel(_("Empty trash"),
2304 _("Delete all messages in trash?"),
2305 GTK_STOCK_CANCEL, _("+_Empty trash"), NULL) != G_ALERTALTERNATE)
2309 mlist = folder_item_get_msg_list(item);
2311 for (cur = mlist ; cur != NULL ; cur = cur->next) {
2312 MsgInfo * msginfo = (MsgInfo *) cur->data;
2313 if (MSG_IS_LOCKED(msginfo->flags))
2315 /* is it partially received? (partial_recv isn't cached) */
2316 if (msginfo->total_size != 0 &&
2317 msginfo->size != (off_t)msginfo->total_size)
2318 partial_mark_for_delete(msginfo);
2320 procmsg_msg_list_free(mlist);
2322 folder_item_remove_all_msg(item);
2325 static void folderview_send_queue_cb(FolderView *folderview, guint action,
2328 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2330 FolderItem *special_queue = NULL;
2332 gchar *errstr = NULL;
2334 if (!folderview->selected) return;
2335 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2336 g_return_if_fail(item != NULL);
2337 g_return_if_fail(item->folder != NULL);
2339 if (NULL != (ac = account_find_from_item(item)))
2340 special_queue = account_get_special_folder(ac, F_QUEUE);
2342 if (item != item->folder->queue && item != special_queue
2343 && !folder_has_parent_of_type(item, F_QUEUE)) return;
2345 if (procmsg_queue_is_empty(item))
2348 if (prefs_common.work_offline)
2349 if (alertpanel(_("Offline warning"),
2350 _("You're working offline. Override?"),
2351 GTK_STOCK_NO, GTK_STOCK_YES,
2352 NULL) != G_ALERTALTERNATE)
2355 /* ask for confirmation before sending queued messages only
2356 in online mode and if there is at least one message queued
2357 in any of the folder queue
2359 if (prefs_common.confirm_send_queued_messages) {
2360 if (!prefs_common.work_offline) {
2361 if (alertpanel(_("Send queued messages"),
2362 _("Send all queued messages?"),
2363 GTK_STOCK_CANCEL, _("_Send"),
2364 NULL) != G_ALERTALTERNATE)
2369 if (procmsg_send_queue(item, prefs_common.savemsg, &errstr) < 0) {
2371 alertpanel_error_log(_("Some errors occurred while "
2372 "sending queued messages."));
2374 gchar *tmp = g_strdup_printf(_("Some errors occurred "
2375 "while sending queued messages:\n%s"), errstr);
2377 alertpanel_error_log(tmp);
2383 static void folderview_search_cb(FolderView *folderview, guint action,
2386 summary_search(folderview->summaryview);
2389 static void folderview_property_cb(FolderView *folderview, guint action,
2392 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2395 if (!folderview->selected) return;
2397 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2398 g_return_if_fail(item != NULL);
2399 g_return_if_fail(item->folder != NULL);
2401 prefs_folder_item_open(item);
2404 static void folderview_recollapse_nodes(FolderView *folderview, GtkCTreeNode *node)
2406 GSList *list = NULL;
2407 GSList *done = NULL;
2408 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2410 for (list = folderview->nodes_to_recollapse; list != NULL; list = g_slist_next(list)) {
2411 if (!gtkut_ctree_node_is_parent(GTK_CTREE_NODE(list->data), node)
2412 && list->data != node) {
2413 gtk_ctree_collapse(ctree, GTK_CTREE_NODE(list->data));
2414 done = g_slist_append(done, GTK_CTREE_NODE(list->data));
2417 for (list = done; list != NULL; list = g_slist_next(list)) {
2418 folderview->nodes_to_recollapse = g_slist_remove(folderview->nodes_to_recollapse,
2424 void folderview_move_folder(FolderView *folderview, FolderItem *from_folder,
2425 FolderItem *to_folder)
2427 FolderItem *from_parent = NULL;
2428 FolderItem *new_folder = NULL;
2429 GtkCTreeNode *src_node = NULL;
2433 g_return_if_fail(folderview != NULL);
2434 g_return_if_fail(from_folder != NULL);
2435 g_return_if_fail(to_folder != NULL);
2437 src_node = gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree), NULL, from_folder);
2438 from_parent = folder_item_parent(from_folder);
2440 if (prefs_common.warn_dnd) {
2441 buf = g_strdup_printf(_("Do you really want to make folder '%s' a "
2442 "sub-folder of '%s' ?"), from_folder->name,
2444 status = alertpanel_full(_("Move folder"), buf,
2445 GTK_STOCK_NO, GTK_STOCK_YES, NULL, TRUE,
2446 NULL, ALERT_QUESTION, G_ALERTDEFAULT);
2449 if ((status & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
2451 else if (status & G_ALERTDISABLE)
2452 prefs_common.warn_dnd = FALSE;
2455 buf = g_strdup_printf(_("Moving %s to %s..."), from_folder->name, to_folder->name);
2456 STATUSBAR_PUSH(folderview->mainwin, buf);
2458 summary_clear_all(folderview->summaryview);
2459 folderview->opened = NULL;
2460 folderview->selected = NULL;
2461 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), FALSE);
2463 main_window_cursor_wait(folderview->mainwin);
2464 statusbar_verbosity_set(TRUE);
2465 folder_item_update_freeze();
2466 if ((status = folder_item_move_to(from_folder, to_folder, &new_folder)) == F_MOVE_OK) {
2467 statusbar_verbosity_set(FALSE);
2468 main_window_cursor_normal(folderview->mainwin);
2469 STATUSBAR_POP(folderview->mainwin);
2470 folder_item_update_thaw();
2471 folder_item_update_recursive(new_folder, F_ITEM_UPDATE_MSGCNT);
2473 folderview_sort_folders(folderview,
2474 gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree),
2475 NULL, to_folder), new_folder->folder);
2476 folderview_select(folderview, new_folder);
2478 statusbar_verbosity_set(FALSE);
2479 main_window_cursor_normal(folderview->mainwin);
2480 STATUSBAR_POP(folderview->mainwin);
2481 folder_item_update_thaw();
2483 case F_MOVE_FAILED_DEST_IS_PARENT:
2484 alertpanel_error(_("Source and destination are the same."));
2486 case F_MOVE_FAILED_DEST_IS_CHILD:
2487 alertpanel_error(_("Can't move a folder to one of its children."));
2489 case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX:
2490 alertpanel_error(_("Folder moving cannot be done between different mailboxes."));
2493 alertpanel_error(_("Move failed!"));
2498 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), TRUE);
2501 static gint folderview_clist_compare(GtkCList *clist,
2502 gconstpointer ptr1, gconstpointer ptr2)
2504 FolderItem *item1 = ((GtkCListRow *)ptr1)->data;
2505 FolderItem *item2 = ((GtkCListRow *)ptr2)->data;
2508 return (item2->name != NULL);
2512 return g_utf8_collate(item1->name, item2->name);
2515 static void folderview_processing_cb(FolderView *folderview, guint action,
2518 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2522 if (!folderview->selected) return;
2524 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2525 g_return_if_fail(item != NULL);
2526 g_return_if_fail(item->folder != NULL);
2528 id = folder_item_get_identifier(item);
2529 title = g_strdup_printf (_("Processing configuration for folder %s"), id);
2532 prefs_filtering_open(&item->prefs->processing, title,
2533 MANUAL_ANCHOR_PROCESSING, NULL, NULL, FALSE);
2537 void folderview_set_target_folder_color(gint color_op)
2541 FolderView *folderview;
2543 for (list = folderview_list; list != NULL; list = list->next) {
2544 folderview = (FolderView *)list->data;
2545 gtkut_convert_int_to_gdk_color(color_op, &folderview->color_op);
2547 bold_tgtfold_style->fg[GTK_STATE_NORMAL] =
2548 folderview->color_op;
2554 static gchar *last_font = NULL;
2555 void folderview_reflect_prefs_pixmap_theme(FolderView *folderview)
2563 void folderview_reflect_prefs(void)
2565 gboolean update_font = TRUE;
2566 FolderView *folderview = mainwindow_get_mainwindow()->folderview;
2567 FolderItem *item = folderview_get_selected_item(folderview);
2568 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2569 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2570 gint height = pos->value;
2572 if (last_font && !strcmp(last_font, NORMAL_FONT))
2573 update_font = FALSE;
2576 last_font = g_strdup(NORMAL_FONT);
2579 normal_style = normal_color_style = bold_style =
2580 bold_color_style = bold_tgtfold_style = NULL;
2582 folderview_init(folderview);
2584 gtk_clist_freeze(GTK_CLIST(folderview->ctree));
2585 folderview_column_set_titles(folderview);
2586 folderview_set_all();
2588 g_signal_handlers_block_by_func
2589 (G_OBJECT(folderview->ctree),
2590 G_CALLBACK(folderview_selected), folderview);
2593 GtkCTreeNode *node = gtk_ctree_find_by_row_data(
2594 GTK_CTREE(folderview->ctree), NULL, item);
2596 folderview_select(folderview, item);
2597 folderview->selected = node;
2600 g_signal_handlers_unblock_by_func
2601 (G_OBJECT(folderview->ctree),
2602 G_CALLBACK(folderview_selected), folderview);
2604 pos = gtk_scrolled_window_get_vadjustment(
2605 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2606 gtk_adjustment_set_value(pos, height);
2607 gtk_clist_thaw(GTK_CLIST(folderview->ctree));
2610 static void drag_state_stop(FolderView *folderview)
2612 if (folderview->drag_timer)
2613 gtk_timeout_remove(folderview->drag_timer);
2614 folderview->drag_timer = 0;
2615 folderview->drag_node = NULL;
2618 static gint folderview_defer_expand(FolderView *folderview)
2620 if (folderview->drag_node) {
2621 folderview_recollapse_nodes(folderview, folderview->drag_node);
2622 if (folderview->drag_item->collapsed) {
2623 gtk_ctree_expand(GTK_CTREE(folderview->ctree), folderview->drag_node);
2624 folderview->nodes_to_recollapse = g_slist_append
2625 (folderview->nodes_to_recollapse, folderview->drag_node);
2628 folderview->drag_item = NULL;
2629 folderview->drag_timer = 0;
2633 static void drag_state_start(FolderView *folderview, GtkCTreeNode *node, FolderItem *item)
2635 /* the idea is that we call drag_state_start() whenever we want expansion to
2636 * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
2637 * we need to call drag_state_stop() */
2638 drag_state_stop(folderview);
2639 /* request expansion */
2640 if (0 != (folderview->drag_timer = gtk_timeout_add
2641 (prefs_common.hover_timeout,
2642 (GtkFunction)folderview_defer_expand,
2644 folderview->drag_node = node;
2645 folderview->drag_item = item;
2649 static void folderview_start_drag(GtkWidget *widget, gint button, GdkEvent *event,
2650 FolderView *folderview)
2652 GdkDragContext *context;
2654 g_return_if_fail(folderview != NULL);
2655 if (folderview->selected == NULL) return;
2656 if (folderview->nodes_to_recollapse)
2657 g_slist_free(folderview->nodes_to_recollapse);
2658 folderview->nodes_to_recollapse = NULL;
2659 context = gtk_drag_begin(widget, folderview->target_list,
2660 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
2661 gtk_drag_set_icon_default(context);
2664 static void folderview_drag_data_get(GtkWidget *widget,
2665 GdkDragContext *drag_context,
2666 GtkSelectionData *selection_data,
2669 FolderView *folderview)
2673 gchar *source = NULL;
2674 if (info == TARGET_DUMMY) {
2675 for (cur = GTK_CLIST(folderview->ctree)->selection;
2676 cur != NULL; cur = cur->next) {
2677 item = gtk_ctree_node_get_row_data
2678 (GTK_CTREE(folderview->ctree),
2679 GTK_CTREE_NODE(cur->data));
2681 source = g_strdup_printf ("FROM_OTHER_FOLDER%s", folder_item_get_identifier(item));
2682 gtk_selection_data_set(selection_data,
2683 selection_data->target, 8,
2684 source, strlen(source));
2690 g_warning("unknown info %d\n", info);
2694 gboolean folderview_update_folder(gpointer source, gpointer userdata)
2696 FolderUpdateData *hookdata;
2697 FolderView *folderview;
2701 folderview = (FolderView *) userdata;
2702 g_return_val_if_fail(hookdata != NULL, FALSE);
2703 g_return_val_if_fail(folderview != NULL, FALSE);
2705 ctree = folderview->ctree;
2706 g_return_val_if_fail(ctree != NULL, FALSE);
2708 if (hookdata->update_flags & FOLDER_ADD_FOLDERITEM)
2709 folderview_create_folder_node(folderview, hookdata->item);
2710 else if (hookdata->update_flags & FOLDER_RENAME_FOLDERITEM) {
2711 GtkCTreeNode *node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree),
2712 NULL, folder_item_parent(hookdata->item));
2713 folderview_sort_folders(folderview, node, hookdata->folder);
2714 } else if (hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM) {
2717 node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree), NULL, hookdata->item);
2719 gtk_ctree_remove_node(GTK_CTREE(ctree), node);
2720 } else if (hookdata->update_flags & (FOLDER_TREE_CHANGED | FOLDER_ADD_FOLDER | FOLDER_REMOVE_FOLDER))
2721 folderview_set(folderview);
2726 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
2727 GdkDragContext *context,
2731 FolderView *folderview)
2734 FolderItem *item = NULL, *src_item = NULL;
2735 GtkCTreeNode *node = NULL;
2736 gboolean acceptable = FALSE;
2737 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2738 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2739 int height = (int)pos->page_size;
2740 int total_height = (int)pos->upper;
2741 int vpos = (int) pos->value;
2743 if (gtk_clist_get_selection_info
2744 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
2745 GtkWidget *srcwidget;
2747 if (y > height - 24 && height + vpos < total_height)
2748 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
2750 if (y < 48 && y > 0)
2751 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
2753 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2754 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2755 src_item = folderview->summaryview->folder_item;
2757 srcwidget = gtk_drag_get_source_widget(context);
2758 if (srcwidget == folderview->summaryview->ctree) {
2759 /* comes from summaryview */
2760 /* we are copying messages, so only accept folder items that are not
2761 the source item, are no root items and can copy messages */
2762 if (item && item->folder && folder_item_parent(item) != NULL && src_item &&
2763 src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)
2765 } else if (srcwidget == folderview->ctree) {
2766 /* comes from folderview */
2767 /* we are moving folder items, only accept folders that are not
2768 the source items and can copy messages and create folder items */
2769 if (item && item->folder && src_item && src_item != item &&
2770 FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2771 FOLDER_CLASS(item->folder)->create_folder != NULL)
2774 /* comes from another app */
2775 /* we are adding messages, so only accept folder items that are
2776 no root items and can copy messages */
2777 if (item && item->folder && folder_item_parent(item) != NULL
2778 && FOLDER_CLASS(item->folder)->add_msg != NULL)
2783 if (acceptable || (src_item && src_item == item))
2784 drag_state_start(folderview, node, item);
2787 g_signal_handlers_block_by_func
2789 G_CALLBACK(folderview_selected), folderview);
2790 gtk_ctree_select(GTK_CTREE(widget), node);
2791 g_signal_handlers_unblock_by_func
2793 G_CALLBACK(folderview_selected), folderview);
2794 gdk_drag_status(context,
2795 (context->actions == GDK_ACTION_COPY ?
2796 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
2798 if (folderview->opened)
2799 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2800 gdk_drag_status(context, 0, time);
2806 static void folderview_drag_leave_cb(GtkWidget *widget,
2807 GdkDragContext *context,
2809 FolderView *folderview)
2811 drag_state_stop(folderview);
2812 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2815 static void free_info (gpointer stuff, gpointer data)
2820 void folderview_finish_dnd(const gchar *data, GdkDragContext *drag_context,
2821 guint time, FolderItem *item)
2824 GSList *msglist = NULL;
2825 list = uri_list_extract_filenames(data);
2826 if (!(item && item->folder && folder_item_parent(item) != NULL
2827 && FOLDER_CLASS(item->folder)->add_msg != NULL))
2829 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2833 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2836 for (tmp = list; tmp != NULL; tmp = tmp->next) {
2837 MsgFileInfo *info = NULL;
2839 if (file_is_email((gchar *)tmp->data)) {
2840 info = g_new0(MsgFileInfo, 1);
2841 info->msginfo = NULL;
2842 info->file = (gchar *)tmp->data;
2843 msglist = g_slist_prepend(msglist, info);
2847 msglist = g_slist_reverse(msglist);
2848 folder_item_add_msgs(item, msglist, FALSE);
2849 g_slist_foreach(msglist, free_info, NULL);
2850 g_slist_free(msglist);
2851 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2853 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2855 list_free_strings(list);
2859 static void folderview_drag_received_cb(GtkWidget *widget,
2860 GdkDragContext *drag_context,
2863 GtkSelectionData *data,
2866 FolderView *folderview)
2869 FolderItem *item = NULL, *src_item;
2872 if (info == TARGET_DUMMY) {
2873 drag_state_stop(folderview);
2874 if ((void *)strstr(data->data, "FROM_OTHER_FOLDER") != (void *)data->data) {
2875 /* comes from summaryview */
2876 if (gtk_clist_get_selection_info
2877 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2880 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2881 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2882 src_item = folderview->summaryview->folder_item;
2884 /* re-check (due to acceptable possibly set for folder moves */
2885 if (!(item && item->folder && item->path && !item->no_select &&
2886 src_item && src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)) {
2889 if (item && src_item) {
2890 switch (drag_context->action) {
2891 case GDK_ACTION_COPY:
2892 summary_copy_selected_to(folderview->summaryview, item);
2893 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2895 case GDK_ACTION_MOVE:
2896 case GDK_ACTION_DEFAULT:
2898 if (FOLDER_CLASS(src_item->folder)->remove_msg == NULL)
2899 summary_copy_selected_to(folderview->summaryview, item);
2901 summary_move_selected_to(folderview->summaryview, item);
2902 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2905 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2907 /* comes from folderview */
2909 gboolean folder_is_normal = TRUE;
2911 source = data->data + 17;
2912 if (gtk_clist_get_selection_info
2913 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0
2915 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2918 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2919 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2920 src_item = folder_find_item_from_identifier(source);
2924 src_item->stype == F_NORMAL &&
2925 !folder_has_parent_of_type(src_item, F_OUTBOX) &&
2926 !folder_has_parent_of_type(src_item, F_DRAFT) &&
2927 !folder_has_parent_of_type(src_item, F_QUEUE) &&
2928 !folder_has_parent_of_type(src_item, F_TRASH);
2929 if (!item || item->no_select || !src_item
2930 || !folder_is_normal) {
2931 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2935 folderview_move_folder(folderview, src_item, item);
2936 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2938 folderview->nodes_to_recollapse = NULL;
2939 } else if (info == TARGET_MAIL_URI_LIST) {
2940 if (gtk_clist_get_selection_info
2941 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2944 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2946 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2949 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2951 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2954 folderview_finish_dnd(data->data, drag_context, time, item);
2958 static void folderview_drag_end_cb(GtkWidget *widget,
2959 GdkDragContext *drag_context,
2960 FolderView *folderview)
2962 drag_state_stop(folderview);
2963 g_slist_free(folderview->nodes_to_recollapse);
2964 folderview->nodes_to_recollapse = NULL;
2967 void folderview_register_popup(FolderViewPopup *fpopup)
2971 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2972 FolderView *folderview = folderviews->data;
2973 GtkItemFactory *factory;
2975 factory = create_ifactory(folderview, fpopup);
2976 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
2978 g_hash_table_insert(folderview_popups, fpopup->klass, fpopup);
2981 void folderview_unregister_popup(FolderViewPopup *fpopup)
2985 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2986 FolderView *folderview = folderviews->data;
2988 g_hash_table_remove(folderview->popups, fpopup->klass);
2990 g_hash_table_remove(folderview_popups, fpopup->klass);